cad中可以通过join命令合并多条首尾相连的多段线,但是arx中却没有提供相应方法,这为arx二次开发增加了一些困难。在此提供本人写的合并多段线的方法,以供参考。
主要思路为遍历要合并的多段线,获取起点、终点、以及其它所有顶点,然后存放到以起点和终点为key的multimap中,value为PointInfo结构的数据,PointInfo中存放有该起点或终点对应的多段线id以及多段线的所有顶点。
接下来就是查找multimap中相同的key,排除同一条多段线,就可以找到与多段线的起点或终点连在一起的另一条多段线,然后就把找到的多段线的所有顶点添加到AcGePoint2dArray中。
依次找下去,直到无法找到key值相同的多段线,再反向查找另一边的。
如此一来,AcGePoint2dArray中就是要合并的多段线从一端到另一端的所有顶点数据,根据AcGePoint2dArray生成合并的多段线即可。
关键代码如下:
#include "StdAfx.h"
#include "Common/Common.h"
struct PointInfo
{
PointInfo() = default;
PointInfo(const PointInfo&) = default;
PointInfo& operator=(const PointInfo&) = default;
PointInfo(const AcDbObjectId& id, const AcGePoint2dArray& ptArray)
:m_id(id), m_ptArray(ptArray) {}
AcDbObjectId m_id;
AcGePoint2dArray m_ptArray;
};
struct AcGePoint3d_Less
{
bool operator()(const AcGePoint3d& pt1, const AcGePoint3d& pt2) const
{
if (CMathUtil::IsLess(pt1.x, pt2.x))
{
return true;
}
else if (CMathUtil::IsEqual(pt1.x, pt2.x))
{
if (CMathUtil::IsLess(pt1.y, pt2.y))
{
return true;
}
else if (CMathUtil::IsEqual(pt1.y, pt2.y))
{
if (CMathUtil::IsLess(pt1.z, pt2.z))
{
return true;
}
else
{
return false;
}
}
else
{
return false;
}
}
else
{
return false;
}
}
};
AcDbObjectIdArray MergePolyline(const AcDbObjectIdArray& idArray, bool bRetainMergedMembers = true)
{
AcDbObjectIdArray idsPline;
std::multimap<AcGePoint3d, PointInfo, AcGePoint3d_Less> mmapPt2PointInfo;
for (const auto& id : idArray)
{
AcDbObjectPointer<AcDbPolyline> pPline(id);
if (pPline)
{
if (pPline->isClosed())
{
idsPline.append(id);
continue;
}
AcGePoint3d ptStart, ptEnd;
pPline->getStartPoint(ptStart);
pPline->getEndPoint(ptEnd);
AcGePoint2dArray ptArray;
for (uint nIndex = 0; nIndex < pPline->numVerts(); nIndex++)
{
AcGePoint2d ptVertex;
pPline->getPointAt(nIndex, ptVertex);
ptArray.append(ptVertex);
}
mmapPt2PointInfo.emplace(ptStart, PointInfo(id, ptArray));
mmapPt2PointInfo.emplace(ptEnd, PointInfo(id, ptArray.reverse()));
}
}
if (!mmapPt2PointInfo.size())
{
return idsPline;
}
while (mmapPt2PointInfo.size())
{
AcGePoint2dArray ptArray;
std::set<AcDbObjectId> setId;
auto iterFind = mmapPt2PointInfo.begin();
for (int iCount = 2; iCount > 0 && mmapPt2PointInfo.size(); --iCount)
{
// 反向添加另一边的多段线
ptArray.reverse();
if (ptArray.length())
{
iterFind = mmapPt2PointInfo.find(CConvertUtil::ToPoint3d(ptArray.last()));
}
while (iterFind != mmapPt2PointInfo.end())
{
if (setId.find(iterFind->second.m_id) == setId.end())
{
ptArray.append(iterFind->second.m_ptArray);
}
setId.insert(iterFind->second.m_id);
mmapPt2PointInfo.erase(iterFind);
iterFind = mmapPt2PointInfo.find(CConvertUtil::ToPoint3d(ptArray.last()));
}
// 删除已经添加点的线段
for (iterFind = mmapPt2PointInfo.begin(); iterFind != mmapPt2PointInfo.end(); )
{
if (setId.find(iterFind->second.m_id) != setId.end())
{
iterFind = mmapPt2PointInfo.erase(iterFind);
}
else
{
iterFind++;
}
}
}
if (setId.size() == 1)
{
// 未合并的多段线也需要返回
idsPline.append(*setId.begin());
}
else
{
AcDbObjectId idPline = CPolylineUtil::Add(ptArray);
if (!idPline.isNull())
{
idsPline.append(idPline);
}
if (ptArray.first() == ptArray.last())
{
AcDbObjectPointer<AcDbPolyline> pPline(idPline, AcDb::kForWrite);
if (pPline)
{
pPline->setClosed(true);
}
}
if (!bRetainMergedMembers)
{
CEntityUtil::Erase(setId);
}
}
}
return idsPline;
}
demo代码:
https://github.com/ChiuqiuA/ArxSample.git