admin 发表于 2024-2-26 09:33:03

[每日一码] (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;
}

admin 发表于 2024-2-26 09:33:25

这个代码用的是模拟点法计算包围盒,还是不太精确,计算量也比较大!
我写的这个既精确又快!
普通浏览复制代码
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();
}

admin 发表于 2024-2-26 09:33:38

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]
查看完整版本: [每日一码] (3)获得AcDbSpline准确的包围盒