|
使用 ObjectARX 获取 AcDbSpline 的边界框
我想得到样条曲线的边界框,但是getGeomExtents()函数没有返回预期的结果。如何为样条曲线获得更紧密的边界框?
AcDbSpline 在使用 getGeomExtents() 时不会返回"紧密"边界框。
要获得更紧密的边界框,您需要自己计算边界框。您可以使用函数 getPointAtParam() 沿样条线遍历并检查最大/最小 x 和 y 坐标。边界框的精度取决于曲线的划分和采样程度。除法值 1e6 具有良好的精度,并且需要可接受的时间来计算。下面粘贴的函数显示了如何执行此操作。附加的 VC++ 项目具有完整的代码(具有最少的错误检查)。键入命令"SplineBB"并选择一个样条对象。它将绘制两个边界框。红色矩形是 getGeomExtents() 返回的范围,而黄色矩形是计算范围。
[code]///////////////////////////////////////////////////////////////////////////////////////////////
//Description: fKeepExtremes
//1) Function to check for the minimum/maximum X and Y.
//2) mPtMin and mPtMax will have minimum/maximum X and Y
///////////////////////////////////////////////////////////////////////////////////////////////
void fKeepExtremes(AcGePoint3d& mPtSample,AcGePoint3d& mPtMin,AcGePoint3d& mPtMax)
{
//test for max
if(mPtSample.x > mPtMax.x) mPtMax.x = mPtSample.x;
if(mPtSample.y > mPtMax.y) mPtMax.y = mPtSample.y;
if(mPtSample.z > mPtMax.z) mPtMax.z = mPtSample.z;
//test for min
if(mPtSample.x < mPtMin.x) mPtMin.x = mPtSample.x;
if(mPtSample.y < mPtMin.y) mPtMin.y = mPtSample.y;
if(mPtSample.z > mPtMax.z) mPtMax.z = mPtSample.z;
}
///////////////////////////////////////////////////////////////////////////////////////////////
//Description: fGetBoundingBoxBySampling
//1) Function to divide the AcDbSpline 1e6 times and check for points at each division
///////////////////////////////////////////////////////////////////////////////////////////////
void fGetBoundingBoxBySampling(AcDbSpline *pSpline,AcGePoint3d& mPtMin, AcGePoint3d& mPtMax)
{
double mParam;
double mIncr;
double mStartParam;
double mEndParam;
AcGePoint3d mPtTemp;
pSpline->getStartPoint(mPtTemp);
pSpline->getParamAtPoint(mPtTemp,mStartParam);
pSpline->getEndPoint(mPtTemp);
pSpline->getParamAtPoint(mPtTemp,mEndParam);
//calculate the division
mIncr = (mEndParam - mStartParam)/1e6; //1e6 is the sampling tolerance
//set the seed point for max and min. It is set to the start point
mPtMax = mPtTemp;
mPtMin = mPtTemp;
for(mParam = mStartParam;mParam <= mEndParam;mParam +=mIncr)
{
if(Acad::eOk == pSpline->getPointAtParam(mParam,mPtTemp))
{
fKeepExtremes(mPtTemp,mPtMin,mPtMax);
}
}
}
///////////////////////////////////////////////////////////////////////////////////////////////
//Description: fDrawRect
//1) Draws a LwPolyline rectangle given lower left and upper right corners
///////////////////////////////////////////////////////////////////////////////////////////////
void fDrawRect(AcGePoint3d& mPtMin,AcGePoint3d& mPtMax,int mColor)
{
AcDbPolyline *pPline = new AcDbPolyline(4);
pPline->addVertexAt(0, AcGePoint2d(mPtMin.x,mPtMin.y));
pPline->addVertexAt(1,AcGePoint2d(mPtMax.x,mPtMin.y));
pPline->addVertexAt(2,AcGePoint2d(mPtMax.x,mPtMax.y));
pPline->addVertexAt(3,AcGePoint2d(mPtMin.x,mPtMax.y));
pPline->setClosed(Adesk::kTrue);
fAddEntToDwg(acdbHostApplicationServices()->workingDatabase(),pPline);
pPline->setColorIndex(mColor);
pPline->close();
}
///////////////////////////////////////////////////////////////////////////////////////////////
//Description: SplineBB
//1) command 'SplineBB'
///////////////////////////////////////////////////////////////////////////////////////////////
void SplineBB()
{
AcDbEntity *pEnt = NULL;
AcDbObjectId mId;
ads_point mPt;
ads_name mEname;
//select the entity
if ( RTNORM == acedEntSel(L"Select a Spline", mEname, mPt))
{
if ( Acad::eOk == acdbGetObjectId(mId, mEname ))
{
acdbOpenAcDbEntity(pEnt, mId, AcDb::kForRead);
}
}
else
{
return;
}
//see if it is a spline
AcDbSpline *pSpline = NULL;
if (NULL != pEnt)
{
pSpline = AcDbSpline::cast(pEnt);
if(NULL != pSpline)
{
AcGePoint3d mPtMin,mPtMax;
//draw the bounding box returned by spline's getGeomExtents
AcDbExtents mExts;
pSpline->getGeomExtents(mExts);
//draw bounding box returned by the spline in red
fDrawRect(mExts.minPoint(),mExts.maxPoint(),1);
//calculate the time taken
struct _timeb t1,t2;
_ftime(&t1);
//calculate the bounding box
fGetBoundingBoxBySampling(pSpline,mPtMin,mPtMax);
_ftime(&t2);
acutPrintf(L"\nMethod Time %6.2f seconds.\n", (t2.time + (double)(t2.millitm)/1000) - (t1.time + (double)(t1.millitm)/1000) );
//draw calculated bounding box in yellow
fDrawRect(mPtMin,mPtMax,2);
pSpline->close();
}
else
{
acutPrintf(L"\nEntity is not an Spline");
pEnt->close();
}
}
return;
}[/code] |
|