多义线凸度
凸度值是多义线的当前顶点与下一个顶点之间的弧的1/4的正切。一个负的凸度值表示弧是以顺时针方向从选择的顶点至下一个顶点。反之,正的凸度值则是逆时针的方向。
直线的生成算法思路
凸度值为0的为直线段,直接两点生成直线即可
弧线的生成算法思路
假设第一点为A, 第二点为B, 第一点凸度为bulge
Bulge为0时,是直线,不用处理。
-
计算出圆弧弧度
弧度 = arctan( fabs(bulge)*4 ) -
计算圆弧法向量
If( 凸度 > 0 ) normal=(0,0,1)
else normal = (0,0,-1) -
弧度为180度,圆心为A、B两点中心,构造圆弧信息已够,不用进行后续步骤。否则进入以下步骤。
-
计算出圆弧圆心
大体思路是使用点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 * 偏移方向
-
求出圆弧
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; //绘制下一根线
}