当前位置: 首页 > news >正文

PDF文档中表格以及形状解析-后续处理(线段生成最小多边形)

我们根据线段打断处理得到了一组被打断的小线段,接下来我们将这些小线段生成多边形。

typedef struct _tagAssociatedLine
{Vertex pt;std::vector<Segment> vecLine;_tagAssociatedLine() : pt{ 0.,0. } {}
}AssociatedLine;//获取下一条线段
Segment  GetNextLine(const Segment& currentLine, std::vector<AssociatedLine>& vecAssociated, bool& bValuable)
{bValuable = true;Segment nextLine = {};nextLine.start = { 0., 0., };nextLine.end = { 0., 0., };for (int i = 0; i < vecAssociated.size(); i++){AssociatedLine& associatedLine = vecAssociated[i];if (currentLine.end == associatedLine.pt) //找到与当前线段终点相等的交点pt的关联对象{for (int j = 0; j < associatedLine.vecLine.size(); j++)  //遍历交点pt关联对象中的关联线段{std::vector<Segment>& lines = associatedLine.vecLine;if (lines[j].start ==  currentLine.end && lines[j].end == currentLine.start){//从象限角排序数组中找到方向线段的下一个位置的线段if (j == (lines.size() - 1))nextLine = lines[0];elsenextLine = lines[j + 1];return nextLine;}}}}bValuable = false;return nextLine;
}void RemoveisolatedLine(const std::vector<Segment>& input, std::vector<Segment>& output)
{//先处理两端都孤立的线段std::vector<Segment> vecTmp;if (input.size() < 2)return;for (int i = 0; i < input.size(); i++){for (int j = 0; j < input.size(); j++){if (i == j)continue;Vertex point;if (IsCross(input[i], input[j], point)) {vecTmp.push_back(input[i]);break;}}}//再处理一端孤立的线段for (int i = 0; i < vecTmp.size(); i++){std::vector<Vertex> crossPoint;for (int j = 0; j < vecTmp.size(); j++){Vertex point;if (IsCross(vecTmp[i], vecTmp[j], point)) {crossPoint.push_back(point);}}bool bEqual = false;for (int m = 0; m < crossPoint.size(); m++){if (vecTmp[i].start == crossPoint[m]){bEqual = true;break;}}if (bEqual){for (int n = 0; n < crossPoint.size(); n++){if (vecTmp[i].end == crossPoint[n]){output.push_back(vecTmp[i]);break;}}}}
}void GetCrossPoints(const std::vector<Segment>& input, std::vector<Vertex>& vecCrossPoint)
{for (int i = 0; i < input.size(); i++){vecCrossPoint.push_back(input[i].start);vecCrossPoint.push_back(input[i].end);}//去除重复的点int n = vecCrossPoint.size();for (int i = 0; i < n; i++) {for (int j = 0; j < i; j++) {if (vecCrossPoint[i] == vecCrossPoint[j]) {n--;for (int k = i; k < n; k++) {vecCrossPoint[k] = vecCrossPoint[k + 1];}i--;}}}vecCrossPoint.erase(vecCrossPoint.begin() + n, vecCrossPoint.end());
}void GetDirectedLine(const std::vector<Segment>& input, std::vector<Segment>& vecDirectedLine)
{for (int i = 0; i < input.size(); i++){vecDirectedLine.push_back(input[i]);Segment temp;temp.start = input[i].end;temp.end = input[i].start;vecDirectedLine.push_back(temp);}
}std::vector<Segment> SortLine(std::vector<Segment>& lines)
{if (lines.size() < 2)return lines;for (int i = 0; i < lines.size() - 1; i++){int minIndex = i;double dxmin = lines[i].end.x - lines[i].start.x;double dymin = lines[i].end.y - lines[i].start.y;double dAnglemin = atan2(dymin, dxmin);dAnglemin = (180. / 3.141592652589793) * dAnglemin;if (abs(dAnglemin) <= 0.1)dAnglemin = 0.;if (dAnglemin < -0.1)dAnglemin += 360;for (size_t j = i + 1; j < lines.size(); j++){double dx = lines[j].end.x - lines[j].start.x;double dy = lines[j].end.y - lines[j].start.y;double dAngle = atan2(dy, dx);dAngle = (180. / 3.141592652589793) * dAngle;if (abs(dAngle) <= 0.1)dAngle = 0.;if (dAngle < -0.1)dAngle += 360;if (dAngle < dAnglemin){minIndex = j;dAnglemin = dAngle;}}std::swap(lines[minIndex], lines[i]);}return lines;
}std::vector<Segment> GetAssociated(const std::vector<Segment>& DirectedLine, const Vertex& pt)
{std::vector<Segment> AssociatedLine;//找到与点pt关联的线段for (int j = 0; j < DirectedLine.size(); ++j){if (DirectedLine[j].start == pt){AssociatedLine.push_back(DirectedLine[j]);}}std::vector<Segment> vecSortedLine;//排序后的数组//对关联线段根据象限角大小进行排序vecSortedLine = SortLine(AssociatedLine);return vecSortedLine;
}void GetAssociatedLine(const std::vector<Segment>& DirectedLine, const std::vector<Vertex>& crossPoint, std::vector<AssociatedLine>& vecAssociatedLine)
{//找到每一个交点的关联线段for (int i = 0; i < crossPoint.size(); ++i){AssociatedLine AssociatedEnt;AssociatedEnt.pt = crossPoint[i]; AssociatedEnt.vecLine = GetAssociated(DirectedLine, crossPoint[i]);vecAssociatedLine.push_back(AssociatedEnt);}
}void GetClosedAreas(const std::vector<Segment>& DirectedLine, std::vector<AssociatedLine>& vecAssociated, std::vector<std::vector<Segment>>& vecAllClosedAreas)
{//提取任意一条有向线段作为提取封闭图形的第一条线段for (int i = 0; i < DirectedLine.size(); i++){bool bIsClosed = true;std::vector<Segment> vecClosedArea;vecClosedArea.push_back(DirectedLine[i]);bool bValuable = true;Segment m_nextLine;m_nextLine = GetNextLine(DirectedLine[i], vecAssociated, bValuable);if (!bValuable)continue;vecClosedArea.push_back(m_nextLine);while (m_nextLine.start != DirectedLine[i].start && m_nextLine.end != DirectedLine[i].end){m_nextLine = GetNextLine(m_nextLine, vecAssociated, bValuable);if (!bValuable){bIsClosed = false;break;}elsevecClosedArea.push_back(m_nextLine);}if (bIsClosed)vecAllClosedAreas.push_back(vecClosedArea);//获得以DirectedLine[i]为起始线段的封闭区域}
}bool IsOverlap(const std::vector<Segment>& AreaLeft, const std::vector<Segment>& AreaRight)
{//若两个闭合区域重叠,其size()必然相同if (AreaLeft.size() != AreaRight.size())return false;for (unsigned int i = 0; i < AreaLeft.size(); i++){Segment m_lineLeft = AreaLeft[i];bool bEqualLine = false;for (unsigned int j = 0; j < AreaRight.size(); j++){if (m_lineLeft.start == AreaRight[j].start && m_lineLeft.end == AreaRight[j].end ||m_lineLeft.start == AreaRight[j].end && m_lineLeft.end == AreaRight[j].start){bEqualLine = true;}}if (bEqualLine == false)return false; //只要有一条线段不相同,必然不重合}return true;
}std::vector<std::vector<Segment>>& RemoveOverlapArea(std::vector<std::vector<Segment>>& poly)
{int n = poly.size();if (n < 2) //只有一个闭合区域return poly;//去除重叠的区域for (int i = 0; i < n; i++){for (int j = 0; j < i; j++){if (IsOverlap(poly[i], poly[j])){n--;for (int k = i; k < n; k++){poly[k] = poly[k + 1];}i--;}}}std::vector<std::vector<Segment>>::iterator it1, it2;it1 = poly.begin() + n;it2 = poly.end();poly.erase(it1, it2);return poly;
}//判断点集合pointsA是否包含在点集合pointsB中(B的点数量大于A的点数量)
bool IsContainPoints(std::vector<Vertex>& pointsA, std::vector<Vertex>& pointsB)
{int nSizeA = pointsA.size();int nSizeB = pointsB.size();//若B中包含有A,B的顶点数量要大于A的顶点数量if (nSizeA >= nSizeB){return false;}for (int i = 0; i < nSizeA; i++) //遍历小区域A的顶点{bool isEqual = false;for (int j = 0; j < nSizeB; j++) //遍历大区域B的顶点{if (pointsA[i] == pointsB[j]){isEqual = true;break;}}if (!isEqual){return false; //只要A中的任意顶点,在B中找不到,则说明A不包含在B中}}return true; //在B中可以找到A中所有的顶点,说明A包含在B中
}//判断点是否在闭合区域内
bool IsPointInPolygon(const Vertex& p, std::vector<Vertex>& points, double des = 0.01)
{int nCount = points.size();// 交点个数  int nCross = 0;for (int i = 0; i < nCount; i++){Vertex p1 = points[i];Vertex p2 = points[(i + 1) % nCount];// 点P1与P2形成连线  Segment seg(p1, p2);if (IsPointOnSegment(p, seg))return false;if (abs(p1.y - p2.y) <= abs(des)) continue;if (p.y < min(p1.y, p2.y) && abs(p.y - min(p1.y, p2.y)) > abs(des))continue;if (p.y >= max(p1.y, p2.y) || abs(p.y - max(p1.y, p2.y)) <= abs(des))continue;// 求交点的x坐标(由直线两点式方程转化而来)   double x = (double)(p.y - p1.y) * (double)(p2.x - p1.x) / (double)(p2.y - p1.y) + p1.x;// 只统计p1p2与p向右射线的交点  if (x > p.x)nCross++;}if ((nCross % 2) == 1)return true;elsereturn false;
}//判断多边形B的所有边的中心点存在在区域A内部的情况(不在区域A边上)
bool IsContainLine(const std::vector<Segment>& linesA, const std::vector<Segment>& linesB)
{if (linesA.size() < linesB.size())return false;bool bIsContainLine = false;for (int i = 0; i < linesB.size(); i++){auto& lineB = linesB[i];Vertex centerPoint;centerPoint.x = (lineB.start.x + lineB.end.x) / 2.;centerPoint.y = (lineB.start.y + lineB.end.y) / 2.;std::vector<Vertex> PloyVertex;GetCrossPoints(linesA, PloyVertex);if (IsPointInPolygon(centerPoint, PloyVertex)){bIsContainLine = true;break;}}return bIsContainLine;
}//移除大区域包含小区域的图形
//只有一种情况:大区域的交点包含小区域所有的交点
std::vector<std::vector<Segment>> GetRemoveContainPoly(const std::vector<std::vector<Segment>>& InPolys, std::vector<std::vector<Segment>>& outPolys)
{int nSize = InPolys.size();for (int i = 0; i < nSize; i++){auto& m_AreaA = InPolys[i]; //获得区域Astd::vector<Vertex> m_PointsA;GetCrossPoints(m_AreaA, m_PointsA);//获得区域A所有的顶点bool m_bContain = false;for (int j = 0; j < nSize; j++){if (j == i)continue;auto& m_AreaB = InPolys[j]; //获得区域Bstd::vector<Vertex> m_PointsB;GetCrossPoints(m_AreaB, m_PointsB);//获得区域B的所有顶点//判断A中是否包含有其他区域B//判断方法:当A和B的顶点数不相同时,若区域A包含区域B的所有顶点,则可能包含,须进一步判断if (IsContainPoints(m_PointsB, m_PointsA)) //A中可能包含有B{//再判断区域B的所有边中点是否存在在区域A内部,如存在,删除Aif (IsContainLine(m_AreaA, m_AreaB)){m_bContain = true;break;}}}if (!m_bContain) //区域A中没有包含其他区域outPolys.push_back(m_AreaA);}return outPolys;
}//使用
//移除孤立的线段(两端孤立跟一端孤立)
std::vector<Segment> vecNonisolatedLines;
RemoveisolatedLine(vecSegments, vecNonisolatedLines);//获取所有的交点
std::vector<Vertex> vecCrossPoints;
GetCrossPoints(vecNonisolatedLines, vecCrossPoints);//生成有向线段
std::vector<Segment> vecDirectedLines;
GetDirectedLine(vecNonisolatedLines, vecDirectedLines);//交点与线段关联
std::vector<AssociatedLine> vecAssociatedLines;
GetAssociatedLine(vecDirectedLines, vecCrossPoints, vecAssociatedLines);//生成闭合区域
std::vector<std::vector<Segment>> vecPolys;
GetClosedAreas(vecDirectedLines, vecAssociatedLines, vecPolys);//去除重叠的区域
RemoveOverlapArea(vecPolys);//去除内部仍包含有图形的区域
std::vector<std::vector<Segment>> RemoveContainPoly;
GetRemoveContainPoly(vecPolys, RemoveContainPoly);
//去除包含内部顶点的多边形
std::vector<std::vector<Segment>> vecResultPolys;
for (int i = 0; i < RemoveContainPoly.size(); i++)
{bool bEnable = true;std::vector<Vertex> PloyVertex;GetCrossPoints(RemoveContainPoly[i], PloyVertex);for (int j = 0; j < vecCrossPoints.size(); j++){Vertex currentPoint = vecCrossPoints[j];if (IsPointInPolygon(currentPoint, PloyVertex)){bEnable = false;break;}}if (bEnable)vecResultPolys.push_back(RemoveContainPoly[i]);
}

通过上述代码即可将小段线段处理成最小多边形。
后续再根据多边形的共边关系将一个个的小多边形组合成一个表格。

http://www.dtcms.com/a/553317.html

相关文章:

  • 5G工业边缘计算网关,重构工业智能化
  • 网站中英文切换代码wordpress插件问题
  • 解析 Lua 虚拟机整数与浮解析 Lua 虚拟机整数与浮点数处理:类型转换与运算精度控制
  • 个人网站可以做充值工业设计网页
  • 【C/C++刷题集】二叉树算法题(一)
  • Java Stream 流式编程
  • 如何进入公司网站的后台怎样用vs做简单网站
  • 长春手机建站模板wordpress搜索页
  • 消除链上气泡图:为什么换仓正在成为新的链上生存策略?
  • 什么是TRS收益互换与场外个股期权:从金融逻辑到系统开发实践
  • ARM《8》_制作linux最小根文件系统
  • IntelliJ IDEA 如何全局配置 Maven?避免每次打开新项目重新配置 (适用于 2024~2025 版本)
  • vmware17安装ubuntu2204版本qemu运行armv8处理器uboot运行调试的一些工作
  • 【开题答辩全过程】以 二手房买卖与出租系统的设计与实现为例,包含答辩的问题和答案
  • 河池市城乡住房建设厅网站一人有限公司怎么注册
  • 边缘智能的创新:MLGO微算法科技推出基于QoS感知的边缘大模型自适应拆分推理编排技术
  • 前端面试题总结
  • UE5【插件】一键重命名蓝图变量、事件、函数、宏等(实现批量翻译)
  • UE5【C++】中文注释、编辑器乱码解决方法
  • 鸿蒙Flutter三方库适配指南:08.联合插件开发
  • node做网站怎么知道蜘蛛来过桂林人论坛app
  • 什么语言最适合开发 SaaS 系统:从架构视角的全面分析
  • liosam详解
  • 先知社区文章批量爬虫工具
  • 【STM32】电动车报警系统
  • linux kernel struct clk_init_data结构浅解
  • ▲各类通信算法的FPGA开发学习教程——总目录
  • 2025企业秋招:AI笔试监考如何重塑秋招公平性?
  • Rust开发之常用标准库Trait实践(Display、From/Into)
  • XML与HTML