找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
热搜: 活动 交友 discuz
查看: 206|回复: 2

[每日一码] (3)获得AcDbSpline准确的包围盒

[复制链接]

0

主题

0

回帖

26

积分

管理员

积分
26
发表于 2024-2-26 09:33:03 | 显示全部楼层 |阅读模式
  1. ///////////////////////////////////////////////////////////////////////////////////////////////
  2. //Description: fKeepExtremes
  3. //1) Function to check for the minimum/maximum X and Y.
  4. //2) mPtMin and mPtMax will have minimum/maximum X and Y
  5. ///////////////////////////////////////////////////////////////////////////////////////////////
  6. void fKeepExtremes(AcGePoint3d& mPtSample,AcGePoint3d& mPtMin,AcGePoint3d& mPtMax)
  7. {
  8. //test for max
  9. if(mPtSample.x > mPtMax.x) mPtMax.x = mPtSample.x;
  10. if(mPtSample.y > mPtMax.y) mPtMax.y = mPtSample.y;
  11. if(mPtSample.z > mPtMax.z) mPtMax.z = mPtSample.z;
  12. //test for min
  13. if(mPtSample.x < mPtMin.x) mPtMin.x = mPtSample.x;
  14. if(mPtSample.y < mPtMin.y) mPtMin.y = mPtSample.y;
  15. if(mPtSample.z > mPtMax.z) mPtMax.z = mPtSample.z;
  16. }
  17. ///////////////////////////////////////////////////////////////////////////////////////////////
  18. //Description: fGetBoundingBoxBySampling
  19. //1) Function to divide the AcDbSpline 1e6 times and check for points at each division
  20. ///////////////////////////////////////////////////////////////////////////////////////////////
  21. void fGetBoundingBoxBySampling(AcDbSpline *pSpline,AcGePoint3d& mPtMin, AcGePoint3d& mPtMax)
  22. {
  23. double mParam;
  24. double mIncr;
  25. double mStartParam;
  26. double mEndParam;
  27. AcGePoint3d mPtTemp;
  28. pSpline->getStartPoint(mPtTemp);
  29. pSpline->getParamAtPoint(mPtTemp,mStartParam);
  30. pSpline->getEndPoint(mPtTemp);
  31. pSpline->getParamAtPoint(mPtTemp,mEndParam);
  32. //calculate the division
  33. mIncr = (mEndParam - mStartParam)/1e6; //1e6 is the sampling tolerance
  34. //set the seed point for max and min. It is set to the start point
  35. mPtMax = mPtTemp;
  36. mPtMin = mPtTemp;
  37. for(mParam = mStartParam;mParam <= mEndParam;mParam +=mIncr)
  38. {
  39.   if(Acad::eOk == pSpline->getPointAtParam(mParam,mPtTemp))
  40.   {
  41.    fKeepExtremes(mPtTemp,mPtMin,mPtMax);
  42.   }
  43. }
  44. }
  45. ///////////////////////////////////////////////////////////////////////////////////////////////
  46. //Description: fDrawRect
  47. //1) Draws a LwPolyline rectangle given lower left and upper right corners
  48. ///////////////////////////////////////////////////////////////////////////////////////////////
  49. void fDrawRect(AcGePoint3d& mPtMin,AcGePoint3d& mPtMax,int mColor)
  50. {
  51. AcDbPolyline *pPline = new AcDbPolyline(4);
  52. pPline->addVertexAt(0, AcGePoint2d(mPtMin.x,mPtMin.y));
  53. pPline->addVertexAt(1,AcGePoint2d(mPtMax.x,mPtMin.y));
  54. pPline->addVertexAt(2,AcGePoint2d(mPtMax.x,mPtMax.y));
  55. pPline->addVertexAt(3,AcGePoint2d(mPtMin.x,mPtMax.y));
  56. pPline->setClosed(Adesk::kTrue);
  57. fAddEntToDwg(acdbHostApplicationServices()->workingDatabase(),pPline);
  58. pPline->setColorIndex(mColor);
  59. pPline->close();
  60. }
  61. ///////////////////////////////////////////////////////////////////////////////////////////////
  62. //Description: SplineBB
  63. //1) command 'SplineBB'
  64. ///////////////////////////////////////////////////////////////////////////////////////////////
  65. void SplineBB()
  66. {
  67. AcDbEntity *pEnt = NULL;
  68. AcDbObjectId mId;
  69. ads采用point mPt;
  70. ads采用name mEname;
  71. //select the entity
  72. if ( RTNORM == acedEntSel(L"Select a Spline", mEname, mPt))
  73. {
  74.   if ( Acad::eOk == acdbGetObjectId(mId, mEname ))
  75.   {
  76.    acdbOpenAcDbEntity(pEnt, mId, AcDb::kForRead);
  77.   }
  78. }
  79. else
  80. {
  81.   return;
  82. }
  83. //see if it is a spline
  84. AcDbSpline *pSpline = NULL;
  85. if (NULL != pEnt)
  86. {
  87.   pSpline = AcDbSpline::cast(pEnt);
  88.   if(NULL != pSpline)
  89.   {
  90.    AcGePoint3d mPtMin,mPtMax;
  91.    //draw the bounding box returned by spline's getGeomExtents
  92.    AcDbExtents mExts;
  93.    pSpline->getGeomExtents(mExts);
  94.    //draw bounding box returned by the spline in red
  95.    fDrawRect(mExts.minPoint(),mExts.maxPoint(),1);
  96.    //calculate the time taken
  97.    struct 采用timeb t1,t2;
  98.    采用ftime(&t1);
  99.    //calculate the bounding box
  100.    fGetBoundingBoxBySampling(pSpline,mPtMin,mPtMax);
  101.    采用ftime(&t2);
  102.    acutPrintf(L"\nMethod Time %6.2f seconds.\n", (t2.time + (double)(t2.millitm)/1000) - (t1.time + (double)(t1.millitm)/1000) );
  103.    //draw calculated bounding box in yellow
  104.    fDrawRect(mPtMin,mPtMax,2);
  105.    pSpline->close();
  106.   }
  107.   else
  108.   {
  109.    acutPrintf(L"\nEntity is not an Spline");
  110.    pEnt->close();
  111.   }
  112. }
  113. return;
  114. }
复制代码

0

主题

0

回帖

26

积分

管理员

积分
26
 楼主| 发表于 2024-2-26 09:33:25 | 显示全部楼层
  1. 这个代码用的是模拟点法计算包围盒,还是不太精确,计算量也比较大!
  2. 我写的这个既精确又快!
  3. 普通浏览复制代码
  4. void getSplineBox (const AcDbSpline *pSpline,AcGePoint3d &minPt,AcGePoint3d &maxPt)
  5. {
  6.         AcDbExtents Ext;
  7.         AcGePoint3d p0,p1,p2,p3;
  8.         AcDbIntArray osnapModes,geomIds;
  9.         AcGePoint3dArray pt3ds;
  10.         pSpline->getGripPoints(pt3ds,osnapModes,geomIds);
  11.         for (int k = 0;k<pt3ds.length();k++)
  12.         {
  13.                 Ext.addPoint(pt3ds.at(k));
  14.         }
  15.         p0 = Ext.minPoint();
  16.         p2 = Ext.maxPoint();       double dis = 0.5 * (p2-p0).length();
  17.         p0.x = p0.x - dis;
  18.         p0.y = p0.y - dis;
  19.         p2.x = p2.x + dis;
  20.         p2.y = p2.y + dis;
  21.         p1.x = p0.x;
  22.         p1.y = p2.y;
  23.         p1.z = p0.z;
  24.         p3.x = p2.x;
  25.         p3.y = p0.y;
  26.         p3.z = p2.z;
  27.         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);
  28.         pSpline->getClosestPointTo(p0,vec0,p0,Adesk::kTrue);               
  29.         pSpline->getClosestPointTo(p1,vec1,p1,Adesk::kTrue);
  30.         pSpline->getClosestPointTo(p2,vec2,p2,Adesk::kTrue);
  31.         pSpline->getClosestPointTo(p3,vec3,p3,Adesk::kTrue);
  32.         AcDbExtents Ext1;
  33.         Ext1.addPoint(p0);
  34.         Ext1.addPoint(p1);
  35.         Ext1.addPoint(p2);
  36.         Ext1.addPoint(p3);
  37.         minPt = Ext1.minPoint();
  38.         maxPt = Ext1.maxPoint();
  39. }
复制代码

0

主题

0

回帖

26

积分

管理员

积分
26
 楼主| 发表于 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[extend])
参数

curve-obj  要测量的 VLA 对象。
givenPnt   WCS 中的点,在曲线上寻找该点的最近点。
normal   WCS 中的法线矢量,指定投影平面。
extend   如果指定该参数且其值不为 nil,vlax-curve-getClosestPointToProjection 在搜索最近点时扩展曲线。

vlax-curve-getClosestPointToProjection 将曲线投影到由 givenPnt 和 normal 定义的平面上,然后在该平面上计算距 givenPnt 最近的点。然后,vlax-curve-getClosestPointToProjection 将结果点重新投影到原来的曲线上,并返回投影后的点。

返回值   如果成功,则返回表示曲线上一点的三维点表,否则返回 nil。
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

Archiver|手机版|小黑屋|膜结构网

GMT+8, 2024-12-28 13:34 , Processed in 0.129774 second(s), 23 queries .

Powered by Discuz! X3.5

© 2001-2024 Discuz! Team.

快速回复 返回顶部 返回列表