程序运效果可以参考控件安装目录的sample\edit.sln工程。
.h 文件
// 计算直线与PL线组成的闭合区域的面积,和周长。
class CAreaCalculation
{
public:
CAreaCalculation(void);
virtual ~CAreaCalculation(void);
// 执行该功能。
void Do();
private:
// 跟用户交互,让用户在图上选择一个闭合区域的直线或PL线。
AcDbObjectId SelEntity();
// 搜索闭合区域的递归调用函数。
bool SearchClosePathCall(IN AcGePoint3d startPt, // 搜索的开始点。
IN AcGePoint3d curPt, // 当前搜索位置。
IN std::set<AcDbObjectId>& adyFindId, // 搜索过程中,已经发现的曲线ID.
IN OUT std::vector<AcDbObjectId>& aryPathId, // 搜索成功,返回的闭合区域ID。
IN double dSearchTol, // 搜索精度范围,在这个范围内的曲线是认为连接的。
IN struct resbuf* pRbFilter // 搜索实体的过滤条件。
);
};
.cpp文件:
#include "StdAfx.h"
#include "AreaCalculation.h"
#include "MxTools.h"
CAreaCalculation::CAreaCalculation(void)
{
}
CAreaCalculation::~CAreaCalculation(void)
{
}
void CAreaCalculation::Do()
{
MxDraw::StopAllTwinkeEnt(MxDraw::GetCurOcxHandle() );
// 让用户选择闭合区域中的某条线,然后由该条线搜索到整个闭合区域。
AcDbObjectId entId = CAreaCalculation::SelEntity();
if(entId.isNull() )
return;
// 由entId实体开始,搜索整个闭合区域。
AcDbObjectPointer<AcDbCurve> spCurve(entId,AcDb::kForRead);
if(spCurve.openStatus() != Acad::eOk)
{
ASSERT(0);
return ;
}
AcGePoint3d sPt;
spCurve->getStartPoint(sPt);
AcGePoint3d ePt;
spCurve->getEndPoint(ePt);
double dSeachTol = 3.0;
AcDbPolyline *pPl = AcDbPolyline::cast(spCurve.object() );
if(pPl != NULL)
{
bool isClose = pPl->isClosed();
if(!isClose)
{
// 看该曲线是不是首尾相连的.
if(sPt.distanceTo(ePt) < dSeachTol)
isClose = true;
}
if(isClose)
{
double dArea = 0.0;
pPl->getArea(dArea);
double dEndParam = 0.0;
pPl->getEndParam(dEndParam);
double dLen = 0.0;
pPl->getDistAtParam(dEndParam,dLen);
acutPrintf(_T("\n 面积为:%lf,周长为:%lf"),dArea,dLen);
spCurve->close();
MxDraw::TwinkeEnt(entId);
return ;
}
}
CString sLayerName = spCurve->layerEx();
spCurve->close();
if(sPt.distanceTo(ePt) < dSeachTol)
{
// 小短线。
acutPrintf(_T("\n 选择的曲线开始点与结束点相同"));
return ;
}
std::set<AcDbObjectId> adyFindId;
adyFindId.insert(entId);
// 把层名做为过滤条件。
struct resbuf* pRbFilter = acutBuildList(RTDXF0,_T("LINE,LWPOLYLINE,ARC"),8,sLayerName,0);
std::vector<AcDbObjectId> aryPathId;
if(!SearchClosePathCall(sPt,
ePt,adyFindId,aryPathId,dSeachTol,pRbFilter) )
{
acutPrintf(_T("\n 没有发现闭合区域"));
acutRelRb(pRbFilter);
return ;
}
acutRelRb(pRbFilter);
aryPathId.push_back(entId);
// 由闭合区域,构造一个临时的PL线,用于计算面积。
std::vector<AcDbObjectId>::reverse_iterator iter = aryPathId.rbegin();
bool isFirst = false;
AcGePoint3d curPt = sPt;
std::vector<AcGePoint2d> vecVertex;
std::vector<double> vecBulge;
vecVertex.push_back(sPt.convert2d(AcGePlane::kXYPlane));
vecBulge.push_back(0.0);
for(;iter != aryPathId.rend();++iter)
{
AcDbObjectPointer<AcDbCurve> spCurve(*iter,AcDb::kForRead);
if(spCurve.openStatus() != Acad::eOk)
{
ASSERT(0);
return ;
}
if(AcDbLine::cast(spCurve.object() ) != NULL)
{
AcDbLine* pLine = AcDbLine::cast(spCurve.object());
AcGePoint3d sPt;
pLine->getStartPoint(sPt);
AcGePoint3d ePt;
pLine->getEndPoint(ePt);
AcGePoint3d nextPt = sPt;
if(curPt.distanceTo(sPt) < curPt.distanceTo(ePt) )
nextPt = ePt;
vecVertex.push_back(nextPt.convert2d(AcGePlane::kXYPlane));
vecBulge.push_back(0.0);
curPt = nextPt;
}
else if(AcDbArc::cast(spCurve.object()) != NULL)
{
AcDbArc* pArc = AcDbArc::cast(spCurve.object());
AcGePoint3d sPt;
pArc->getStartPoint(sPt);
AcGePoint3d ePt;
pArc->getEndPoint(ePt);
if(curPt.distanceTo(sPt) > curPt.distanceTo(ePt) )
{
AcGePoint3d tmpPt = sPt;
sPt = ePt;
ePt = tmpPt;
}
curPt = ePt;
double dSParam = 0.0;
double dEParam = 1.0;
pArc->getStartParam(dSParam);
pArc->getEndParam(dEParam);
AcGePoint3d cenPt;
if(pArc->getPointAtParam(dSParam + (dEParam - dSParam) / 2.0,cenPt)
!= Acad::eOk)
{
ASSERT(0);
return;
}
// 计算圆弧的凸度。
double dBulge = 0.0;
if(MxTools::GetArcBulge(sPt,
cenPt,
ePt,
dBulge
) )
{
vecBulge[vecBulge.size() - 1] = dBulge;
vecVertex.push_back(ePt.convert2d(AcGePlane::kXYPlane));
vecBulge.push_back(0.0);
}
else
{
vecVertex.push_back(ePt.convert2d(AcGePlane::kXYPlane));
vecBulge.push_back(0.0);
}
}
else if(AcDbPolyline::cast(spCurve.object()) != NULL)
{
AcDbPolyline* pPolyline = AcDbPolyline::cast(spCurve.object());
std::vector<McGePoint2d> vecTmpPt;
std::vector<double> vecTmpBulge;
int iNum = pPolyline->numVerts();
for(int k = 0; k < iNum;k++)
{
AcGePoint2d pt;
pPolyline->getPointAt(k,pt);
double dBulge = 0.0;
pPolyline->getBulgeAt(k,dBulge);
vecTmpPt.push_back(pt);
vecTmpBulge.push_back(dBulge);
}
if(curPt.convert2d(AcGePlane::kXYPlane).distanceTo(vecTmpPt[0])
> curPt.convert2d(AcGePlane::kXYPlane).distanceTo(vecTmpPt[iNum - 1])
)
{
// 反向。
for(int j = iNum - 2; j >= 0 ;j--)
{
vecBulge[vecBulge.size() - 1] = -vecTmpBulge[j];
vecVertex.push_back(vecTmpPt[j]);
vecBulge.push_back(0.0);
}
curPt = vecTmpPt[0].Point3d();
}
else
{
//
for(int j = 1; j < iNum;j++)
{
vecBulge[vecBulge.size() - 1] = vecTmpBulge[j - 1];
vecVertex.push_back(vecTmpPt[j]);
vecBulge.push_back(0.0);
}
curPt = vecTmpPt[iNum - 1].Point3d();;
}
}
else
{
ASSERT(0);
}
}
// 构建PL线.
ASSERT(vecVertex.size() == vecBulge.size());
AcDbPolyline tmpPl;
for(unsigned int n = 0; n < vecVertex.size();n++)
{
tmpPl.addVertexAt(vecVertex[n],vecBulge[n]);
}
// 调用tmpPL计算面积,周长,函数。
double dArea = 0.0;
tmpPl.getArea(dArea);
double dEndParam = 0.0;
tmpPl.getEndParam(dEndParam);
double dLen = 0.0;
tmpPl.getDistAtParam(dEndParam,dLen);
acutPrintf(_T("\n 面积为:%lf,周长为:%lf"),dArea,dLen);
for(unsigned int nn = 0; nn < aryPathId.size();nn++)
{
MxDraw::TwinkeEnt(aryPathId[nn]);
}
}
bool CAreaCalculation::SearchClosePathCall(IN AcGePoint3d startPt,
IN AcGePoint3d curPt,
IN std::set<AcDbObjectId>& adyFindId,
IN OUT std::vector<AcDbObjectId>& aryPathId,
IN double dSearchTol,
IN struct resbuf* pRbFilter
)
{
AcDbObjectIdArray aryId;
if(!MxTools::FindEntAtPoint(curPt,pRbFilter,
dSearchTol * 10.0,aryId) )
{
return false;
}
// vecNextPos 需要搜索的下一个位置。
std::map<AcDbObjectId,AcGePoint3d> mapNextPos;
for(int i = 0; i < aryId.length();i++)
{
if(adyFindId.find(aryId) != adyFindId.end() )
continue;
AcDbObjectPointer<AcDbCurve> spCurve(aryId,AcDb::kForRead);
if(spCurve.openStatus() != Acad::eOk)
continue;
AcGePoint3d sPt;
spCurve->getStartPoint(sPt);
AcGePoint3d ePt;
spCurve->getEndPoint(ePt);
// 小短线。
if(sPt.distanceTo(ePt) < dSearchTol)
{
continue;
}
double dSDis = sPt.distanceTo(curPt);
double dEDis = ePt.distanceTo(curPt);
double dMinDis = dSDis;
if(dMinDis > dEDis)
dMinDis = dEDis;
if(dMinDis > dSearchTol)
{
// 认为两条线不连接.
continue;
}
adyFindId.insert(aryId);
AcGePoint3d nexPt = sPt;
if(dSDis < dEDis )
nexPt = ePt;
if(nexPt.distanceTo(startPt) < dSearchTol)
{
// 找到了闭合区域。
aryPathId.push_back(aryId);
return true;
}
mapNextPos.insert(std::make_pair(aryId,nexPt) );
}
std::map<AcDbObjectId,AcGePoint3d>::iterator iter = mapNextPos.begin();
for(;iter != mapNextPos.end();++iter)
{
if(SearchClosePathCall(startPt,
iter->second,
adyFindId,
aryPathId,
dSearchTol,pRbFilter
) )
{
aryPathId.push_back(iter->first);
return true;
}
}
return false;
}
AcDbObjectId CAreaCalculation::SelEntity()
{
struct resbuf* pRbFilter = acutBuildList(RTDXF0,_T("LINE,LWPOLYLINE,ARC"),0);
AcDbObjectId id;
AcGePoint3d ptPick;
if(MxTools::SelectEnt(_T("\n 选择闭合区域中的某条线:"),pRbFilter,id,ptPick) != RTNORM)
{
return id;
}
acutRelRb(pRbFilter);
return id;
}