DXF笔记:多义线的绘制

多义线凸度

凸度值是多义线的当前顶点与下一个顶点之间的弧的1/4的正切。一个负的凸度值表示弧是以顺时针方向从选择的顶点至下一个顶点。反之,正的凸度值则是逆时针的方向。

直线的生成算法思路

凸度值为0的为直线段,直接两点生成直线即可

弧线的生成算法思路

假设第一点为A, 第二点为B, 第一点凸度为bulge
Bulge为0时,是直线,不用处理。

  1. 计算出圆弧弧度
    弧度 = arctan( fabs(bulge)*4 )

  2. 计算圆弧法向量
    If( 凸度 > 0 ) normal=(0,0,1)
    else normal = (0,0,-1)

  3. 弧度为180度,圆心为A、B两点中心,构造圆弧信息已够,不用进行后续步骤。否则进入以下步骤。

  4. 计算出圆弧圆心
    大体思路是使用点A、B的中点,在AB的中垂线上偏移指定距离得到圆心,如下图:
    在这里插入图片描述

    求出A、B两点中点C
    若弧度大于180
    求出中点C到圆心的偏移距离Offset = distance(A,C) * cot(PI-弧度/2.0)
    求出偏移方向,(中点C-第一点A)绕轴normal旋转90度
    否则
    求出中点C到圆心的偏移距离Offset = distance(A,C) * cot(弧度/2.0)
    求出偏移方向,(中点C-第一点A)绕轴normal旋转-90度

    圆心 = 中点C + Offset * 偏移方向

  5. 求出圆弧
    ptCenter = 圆心
    vDir = normal
    dRadius = A.distanceTo(圆心)
    refVec = 点A - 圆心
    dAngleStart = 0
    dAngleEnd = 弧度

示例代码

使用osg绘制,使用objectArx的算法库

		AcGePoint3dArray& mGMPtArray = pGMSymbolPloyline->GetPointArray();
		if (mGMPtArray.length() <= 1)//至少要两个顶点
		{
			return;
		}

		AcGePoint3d ptFirst = mGMPtArray.at(0);
		for (int i = 1; i < mGMPtArray.length(); ++i)
		{
			double dBugle = pGMSymbolPloyline->GetPtBugleAt(i-1);
			const AcGePoint3d& ptSecond = mGMPtArray.at(i);
			if (UK_DOUBLE_EQ(dBugle, 0.0)) //凸度为0,直线
			{
				osg::ref_ptr<osg::Geometry> pGeomLine = new osg::Geometry();
				osg::ref_ptr<osg::Vec3dArray> pVertextArray = new osg::Vec3dArray();
				pVertextArray->push_back(osg::Vec3d(ptFirst.x, ptFirst.y, ptFirst.z));
				pVertextArray->push_back(osg::Vec3d(ptSecond.x, ptSecond.y, ptSecond.z));
				pGeomLine->setVertexArray(pVertextArray);
				pGeomLine->addPrimitiveSet(new osg::DrawArrays(osg::PrimitiveSet::LINES,
					0, pVertextArray->size()));
				pRtOsgGeode->addDrawable(pGeomLine);
			}
			else //弧线
			{
				double dRadian = atan( fabs(dBugle)) * 4.0; //圆弧的弧度值
				AcGeVector3d vecNormal = AcGeVector3d::kZAxis; //圆弧法向量
				AcGePoint3d ptMiddle = (ptFirst + ptSecond.asVector()) / 2.0;
				
				if (UK_DOUBLE_LT(dBugle, 0.0))//负的凸度值表示弧是以顺时针方向从选择的顶点至下一个顶点
				{
					vecNormal = -vecNormal;
				}

				if (UK_DOUBLE_EQ(dRadian, PI))//==180度 半圆
				{
					//创建圆弧
					AcGeVector3d refVec = ptFirst - ptMiddle;
					auto pGMArc = std::make_shared<GMArc>(ptMiddle, 
						vecNormal, 
						refVec,
						ptMiddle.distanceTo(ptFirst),
						0.0, 
						dRadian);
					this->Create(pGMArc, nModelFalg, pRtOsgGeode);
				}
				else
				{
					AcGeVector3d offsetDir = ptFirst - ptMiddle;
					offsetDir.normalize();
					double dOffsetValue = 0.0;
					if (UK_DOUBLE_GT(dRadian, PI)) //>180度,优弧
					{
						dOffsetValue = ptMiddle.distanceTo(ptFirst) / std::tan(PI - dRadian / 2.0);
						offsetDir.rotateBy(PI / 2.0, vecNormal);
					}
					else //< 180度
					{
						dOffsetValue = ptMiddle.distanceTo(ptFirst) / std::tan(dRadian / 2.0);
						offsetDir.rotateBy(-PI / 2.0, vecNormal);
					}

					//创建圆弧
					
					AcGePoint3d ptCenter = ptMiddle + dOffsetValue * offsetDir;
					AcGeVector3d refVec = ptFirst - ptCenter;
					auto pGMArc = std::make_shared<GMArc>(ptCenter, 
						vecNormal, 
						refVec,
						ptCenter.distanceTo(ptFirst),
						0.0, 
						dRadian);
					this->Create(pGMArc, nModelFalg, pRtOsgGeode);
				}
			}

			ptFirst = ptSecond; //绘制下一根线
		}

运行及对比

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值