(3)获得AcDbSpline准确的包围盒
Obtaining the Bounding Box of an AcDbSpline using ObjectARX昨天贴了获得实体的包围盒的代码,今天贴个获得准确的SPLINE的ARX解决方案。
问题:
I want to get the bounding box of spline, but the getGeomExtents() functions does not return the expected results. How do I get a tighter bounding box for a spline?
解答:
The AcDbSpline does not return a "tight" bounding box when getGeomExtents() is used.
To get a tighter bounding box you need to calculate the bounding box yourself. You can make use of the function getPointAtParam() to traverse along the spline and check for the maximum/minimum x and y coordinates. The accuracy of the bounding box depends upon how finely the curve is divided and sampled. The division value of 1e6 gives a good accuracy and takes acceptable time to calculate. The functions pasted below shows how this can be done. The attached VC++ project has the complete code (with minimal error checking). Type command "SplineBB" and select a spline object. It will draw two bounding boxes. The red rectangle is the extents returned by the getGeomExtents() while the yellow rectangle is the calculated one.
Something like this:
**** Hidden Message *****
资料可能老了点,还不过时桌子的东西本来就云遮雾罩的 回复学习!{:soso_e179:}
spline是点描述实体,理论上应该是无限逼近,准确上没有极限 本帖最后由 牢固 于 2014-12-7 19:18 编辑
这个代码用的是模拟点法计算包围盒,还是不太精确,计算量也比较大!
我写的这个既精确又快!
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();
}
本帖最后由 st788796 于 2014-12-6 06:44 编辑
牢固 发表于 2014-12-5 22:12
这个代码用的是模拟点法计算包围盒,还是不太精确,计算量也比较大!
我写的这个既精确又快!
这个好,那个lisp版本也可以获取controlPoints求pnts:box用做投影面 st788796 发表于 2014-12-6 06:41
这个好,那个lisp版本也可以获取controlPoints求pnts:box用做投影面
大师,能讲讲什么原理吗?
本帖最后由 st788796 于 2014-12-6 13:22 编辑
Lisphk 发表于 2014-12-6 10:44
大师,能讲讲什么原理吗?
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。
到这儿来收获不小,感动 看看代码!!!!!!!!!!!!! 谢谢分享!
有什么好的方法,学习下。
我是来学习的,同志们
回复学习! 获得AcDbSpline准确的包围盒