CAD开发__识别相交线之间闭合区域(二)

4 篇文章 6 订阅
4 篇文章 0 订阅

概述

上一版的算法(请参考作者的文章《CAD开发__识别相交线之间闭合区域》),在线比较多或者面域比较多时,识别效率会下降。为了在原有功能基础上实现性能的提升,准备在以下两个方面改进:1. 算法思路改进;
2. 实现方式改进。
算法思路改进,是指由原来的识别环–环扩展成外轮廓–外轮廓分解,调整为识别小环–小环能分解就分解,不能分解跳过–识别剩余内环、外环;实现方式改进,指的是由用c#基于CAD的开发包开发,调整为用C++基于Arx开发,Arx更底层,运行速度更快。经过这两方面调整,识别相交线间闭合区域功能的识别效率大大提升。
在这里插入图片描述

原理

    基本步骤,以及各步骤的意义:

  1. 曲线分组
        识别一组相交曲线间闭合区域,时间复杂度为O(n2)~O(n3)。在输入的曲线中存在多组相互不相交的曲线组的情况下,分组后消耗的时间远远小于不分组,特别是组数很多的场景下。
  2. 大坐标处理
        存在大坐标的情况下,坐标值整数部分位数较多,导致小数部分被截断,精度损失严重(double类型总共16位)。此时,两曲线求交时,拿到的交点再用于打断曲线,可能无法打断。因此,为了保证精度,成功打断曲线,必须间目标曲线组整体偏移到原点附近(识别出面域以后再偏移回来或者删除);
  3. 获取交点
        交点分两种类型,不同曲线相交的交点,自相交曲线的交点,通过合理的数据结构来存储交点信息,方便索引每个交点对应的曲线;
  4. 曲线打断
        要通过曲线生成面域,必须输入首尾相连且成环的一组曲线。因此,需要将原有曲线通过交点打断;
  5. 共用起终点线处理
        打断后,可能存在不同的线共用两个起终点的情况,这个一般算法很难处理,必须识别出来,然后在中点打断;
  6. 移除末端线
        末端线不参与生成闭合区域,它的存在反而会影响计算速度,增加出错概率,必须移除。剩余的线,用于识别环,每条线可以用两次(两个小环相邻时,存在共用线,共用的线用两次);
  7. 识别环
        从剩余线中,挑选未使用的线作为第一条线,然后用迪杰斯特拉算法就连接线两个端点的最短路径(第一条线不在选择范围内)。该方法会最大可能保证识别的环比较小(一次识别到位,减少分解环操作);
  8. 分解环
        识别环内部的曲线。如果存在,就以内部某条线为第一条线,识别环。已用过的线使用次数加一,直到找不到内部线为止;
  9. 识别内环
        从剩余线中,挑选使用过一次的线作为第一条线,识别环。如果环的包围盒,能覆盖任意一个相邻环,则该环是外环,跳过,挑选其他符合条件的线继续识别,直到线用完为止。如果取消该步骤,会导致识别出来的闭合区域可能存在若干个空洞(中间位置的一个或者多个闭合区域无法识别);
  10. 结果集成,偏移回原位
        开始进行了大坐标处理,因此识别的环在原点附近,必须偏移回原位
  11. 输出

关键步骤–识别环

识别环的方法,是先确定第一条线,然后用迪杰斯特拉算法求起点到终点最短路径(排除第一条线)。方法示意图如下:
在这里插入图片描述
方法的步骤:

  1. 确定第一条线;
  2. 定义已经过点集,最新经过点集,未经过点集,将起点添加到已经过点集和最新经过点集;
  3. 筛选线,标准是有个端点在未经过点集中,有个端点在最新经过点集中;
  4. 挑选出这些线的最末端点,并记录每个点对应的前一个点;
  5. 更新已经过点集,最新经过点集,未经过点集;
  6. 重复3~5步骤,直到最新经过点集包含第一条线的终点或者循环完毕;
  7. 从终点到起点找出环的路径;

结果

    对于任何形式相交的曲线(直线、圆弧、多段线、样条曲线),都能找出闭合的区域。效果如下:

识别前,白色相交线
在这里插入图片描述
识别后,红色轮廓线
在这里插入图片描述

部分代码

//识别内轮廓
void IdentifyClosedArea:: IdentifyInnerRegions()
{
	std::vector<AcDbCurve*> innerCurves= GetCurvesInCircle(this->OuterBoundary , this->UsefulCurveList );
	if(innerCurves.size()==0)
	{
		this-> InnerRegions.push_back(this->OuterBoundary);
		return;//没有内部线不需要处理
	}
	std::vector<AcDbCurve*> allCurves= GetAllCurves(this->OuterBoundary,innerCurves);//获取所有线
	std::vector<abstractPoint*> allPoints	= GetAbstractPoints( allCurves);//点列表
	std::vector<abstractCurve*> resultCurves=GetAbstractCurves(this-> OuterBoundary,innerCurves,allPoints);//线列表
	allPoints= RefreshAbstractPoints(resultCurves,allPoints);//刷新点列表

	int innerCurveStartIndex=0;//内部线起始编号
	for(int i=0;i<this->OuterBoundary.size();++i)
	{
		innerCurveStartIndex=i+1;
	}

	size_t count=allPoints.size()*4;
	for(int i=0;i<count;++i)
	{
		int firstCurveIndex= GetFirstCurveIndex(resultCurves,innerCurveStartIndex) ;//第一条线
		if(firstCurveIndex<0) break;//跳出
		std::vector<abstractCurve*> circle= GetSmallestCircle(resultCurves[firstCurveIndex],resultCurves,allPoints);//寻找环
		for(int j=0;j<circle.size();++j)
		{
			int index=circle[i]->CurveIndex;
			resultCurves[index]->UsedCount=resultCurves[index]->UsedCount+1;
		}

		std::vector<abstractCurve*> curvesInCircle= GetCurvesInCircle( circle ,  resultCurves,allPoints,innerCurveStartIndex );
		if(curvesInCircle.size()==0)
		{
			for(int j=0;j<circle.size();++j)
			{
				int index=circle[i]->CurveIndex;
				resultCurves[index]->UsedCount=resultCurves[index]->UsedCount+1;
			}
			this-> InnerRegions.push_back(GetCurvesFromCurveClses( circle));
		}
		else
		{
			std::vector<AcDbCurve*> circleCurves= GetCurvesFromCurveClses(circle);
			std::vector<AcDbCurve*> inCircleCurves= GetCurvesFromCurveClses(curvesInCircle);
			std::vector<AcDbCurve*> tempCurves;
			tempCurves.insert(tempCurves.end(),circleCurves.begin(),circleCurves.end());
			tempCurves.insert(tempCurves.end(),inCircleCurves.begin(),inCircleCurves.end());
			IdentifyClosedArea* newRegions=new IdentifyClosedArea();
			newRegions->OuterBoundary=circleCurves;
			newRegions->UsefulCurveList=tempCurves;
			newRegions->IdentifyInnerRegions();
			std::vector<std::vector<AcDbCurve*>> tempInnerRegions=newRegions->InnerRegions;

			for(int k=0;k<tempInnerRegions.size();++k)
			{
				for(int j=0;j<tempInnerRegions[k].size();++j)
				{
					int index=GetCurveClsIndexFromCurve(tempInnerRegions[k][j], resultCurves);
					if(index<0) continue;
					resultCurves[index]->UsedCount=resultCurves[index]->UsedCount+1;
				}
			}
			this-> InnerRegions.insert(this-> InnerRegions.end(),tempInnerRegions.begin(),tempInnerRegions.end());
		}
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

饮血太岁

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值