[每日一码] (3)获得AcDbSpline准确的包围盒
/////////////////////////////////////////////////////////////////////////////////////////////////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;
} 这个代码用的是模拟点法计算包围盒,还是不太精确,计算量也比较大!
我写的这个既精确又快!
普通浏览复制代码
void getSplineBox (const AcDbSpline *pSpline,AcGePoint3d &minPt,AcGePoint3d &maxPt)
{
AcDbExtents Ext;
AcGePoint3d p0,p1,p2,p3;
AcDbIntArray osnapModes,geomIds;
AcGePoint3dArray pt3ds;
pSpline->getGripPoints(pt3ds,osnapModes,geomIds);
for (int k = 0;k<pt3ds.length();k++)
{
Ext.addPoint(pt3ds.at(k));
}
p0 = Ext.minPoint();
p2 = Ext.maxPoint(); double dis = 0.5 * (p2-p0).length();
p0.x = p0.x - dis;
p0.y = p0.y - dis;
p2.x = p2.x + dis;
p2.y = p2.y + dis;
p1.x = p0.x;
p1.y = p2.y;
p1.z = p0.z;
p3.x = p2.x;
p3.y = p0.y;
p3.z = p2.z;
AcGeVector3d vec0(1.0,0.0,0.0),vec1(0.0,-1.0,0.0),vec2(-1.0,0.0,0.0),vec3(0.0,1.0,0.0);
pSpline->getClosestPointTo(p0,vec0,p0,Adesk::kTrue);
pSpline->getClosestPointTo(p1,vec1,p1,Adesk::kTrue);
pSpline->getClosestPointTo(p2,vec2,p2,Adesk::kTrue);
pSpline->getClosestPointTo(p3,vec3,p3,Adesk::kTrue);
AcDbExtents Ext1;
Ext1.addPoint(p0);
Ext1.addPoint(p1);
Ext1.addPoint(p2);
Ext1.addPoint(p3);
minPt = Ext1.minPoint();
maxPt = Ext1.maxPoint();
} G 版用的是这个函数
AcDbCurve::getClosestPointTo 函数
virtual Acad::ErrorStatus
getClosestPointTo(
const AcGePoint3d& givenPnt,
const AcGeVector3d& direction,
AcGePoint3d& pointOnCurve,
Adesk::Boolean extend = Adesk::kFalse) const;
givenPnt 输入点(WCS坐标中),用于找出曲线上的最近点
direction 输入法向矢量(WCS坐标中),用于平面投影
pointOnCurve 返回曲线上与givenPnt最近的点(WCS坐标中)
extend 输入布尔值,表示在搜索最近点时是否延伸曲线
此函数将曲线投影至由givenPnt和normal定义的平面,找出曲线上与givenPnt最近的点,再将这个最近点投影回原始曲线上并在pointOnCurve中返回结果。
如果extend == Adesk::kTrue,则曲线沿它的路径延伸以找出最近点。
如果成功则返回Acad::eOk。根据执行返回错误值。
在派生类中,此函数必须可以投影至由一个点(givenPnt)和一个法向矢量(normal)定义的平面上,如果需要可延伸曲线的投影,找出与givenPnt最近的点,再将这个找到的点投影回原始曲线上(如果被延伸则在它的路径上)并设置pointOnCurve为最终结果。
使用AcGe类可执行一些投影和最近点计算的工作。
如果操作成功,此函数返回Acad::eOk。错误的返回值根据错误和执行器。关于可能的ErrorStatus值列表,参见头文件acdh.h。
默认执行返回Acad::eNotImplemented。
先用一个较大方框作投影面,用函数找出曲线上距离投影面最近的点,四个边就求出四个点,然后由这四个点载找个 BOX
vlisp 对应函数是
在将曲线投影到平面上之后,返回曲线上的最近点(在 WCS 上)
(vlax-curve-getClosestPointToProjection curve-obj givenPnt normal)
参数
curve-obj要测量的 VLA 对象。
givenPnt WCS 中的点,在曲线上寻找该点的最近点。
normal WCS 中的法线矢量,指定投影平面。
extend 如果指定该参数且其值不为 nil,vlax-curve-getClosestPointToProjection 在搜索最近点时扩展曲线。
vlax-curve-getClosestPointToProjection 将曲线投影到由 givenPnt 和 normal 定义的平面上,然后在该平面上计算距 givenPnt 最近的点。然后,vlax-curve-getClosestPointToProjection 将结果点重新投影到原来的曲线上,并返回投影后的点。
返回值 如果成功,则返回表示曲线上一点的三维点表,否则返回 nil。
页:
[1]