本人想在自定义tool中,根据指定线串和点,获取线串上距离指定点最近位置的坐标,以下是调用代码:
double d; DPoint3d p1, p2; mdlElmdscr_distanceAtPoint(&d, &p1, &p2, eehRefLine.GetElementDescrP(), &pt, 1e-6 * UOR_PER_METER);
其中pt是_OnDynamicFrame(DgnButtonEventCR ev)中的ev.GetPoint()得来;
在计算得到参数3后,将结果向上下各延伸一定长度用于测试计算结果,最终测试得到了以下结果,
其中1是光标悬停的位置(未开启捕捉),2是根据计算结果动态绘制的线串,明显可以看出计算结果不正确,个人分析有两个可能的原因:
1._OnDynamicFrame(DgnButtonEventCR ev)中的ev.GetPoint()得到的坐标与我们主观感觉的坐标有偏差;
2.mdlElmdscr_distanceAtPoint方法有漏洞或者我调用方式错误;
请教,为什么会出现这种情况呢?
请先在二维模型中测试一下。
若线串是二维线串(所有端点Z值为0),即使在三维模型也能得到正确结果。但若线串是三维线串(所有端点Z值不相同),那么计算结果就不对。
郭工你好,以下是我的调用方法,其中mdlIntersect_closestBetweenElms方法一直返回非SUCCESS,能帮我分析一下吗:
DgnModelRefP modelP = mdlView_getRootModel(viewIndex);
//根据指定视图获取视图rotMatrix RotMatrixCP rMat = mdlView_getViewport(viewIndex)->GetRotMatrix();
//获取视图的各个轴分量 DVec3d dir[3]; rMat->GetRows(dir[0], dir[1], dir[2]);
//根据Z轴分量对pt进行延长生成一根射线 Point3dArray ptsRay; ptsRay.push_back(pt); ptsRay.push_back(pt + DVec3d::FromScale(dir[2], 30 * UOR_PER_METER)); EditElementHandle eehRay; DgnPlatform::LineStringHandler::CreateLineStringElement(eehRay, NULL, &ptsRay[0], ptsRay.size(), modelP->Is3d(), *modelP);
//计算射线与指定线串的最近点 DPoint3d pts1[10], pts2[12]; int cnt; if (SUCCESS == mdlIntersect_closestBetweenElms(pts1, pts2, &cnt, eehLine.GetElementDescrP(), eehRay.GetElementDescrP(), (RotMatrixP)rMat, (DPoint3dP)&pt, 1e-6 * UOR_PER_METER)) { snapPt = pts1[0]; return true; }
return false;
代码看不出来有什么问题,您可以弄个单独的测试项目,然后在dgn文件里边手动画几条线传给这个参数,各种情况测试一下就明白了,碰到问题最好是把关键的函数拿出来到一个专门的测试项目里边测试,函数搞明白怎么用了再放到实际项目里边去用。
既然都升级到MSCE编程了为何还要用这些老的C API?在新的C++类中有CurveVector表达任意曲线,调用其下的ClosestPointBounded应该就能得到距离一个空间点最近的线上的位置。
符老师您好,我使用您说的CurveVector::ClosestPointBounded方法,得到的结果和mdlElmdscr_distanceAtPoint方法得到的结果是一样的,mdlElmdscr_distanceAtPoint的结果题干中已经给出截图,和预期结果完全不符。
我现在就是已经把这个过程封装成一个单独的方法用来测试了,以上的代码就是方法体,但我还是测试不出来哪里有问题。
DPoint3d GetClosestPointInSpecifyView(EditElementHandleR eehTarget, int viewNum, DPoint3dR spacePt) { double uorperMer = mdlModelRef_getUorPerMeter(ACTIVEMODEL); DPoint3d rtnPt = DPoint3d::FromZero(); MSElementDescrP elmdscr2dTarget; if (SUCCESS != mdlElmdscr_convertTo2D(&elmdscr2dTarget, eehTarget.GetElementDescrP(), viewNum, NULL, ACTIVEMODEL, ACTIVEMODEL, false)) { return rtnPt; } EditElementHandle eeh2dTarget(elmdscr2dTarget, true, false, ACTIVEMODEL); MSElementDescrP elmdscr3dTarget; RotMatrix rMatrix; mdlRMatrix_fromView(&rMatrix, viewNum, false); DPoint3d viewVecZ, viewVecX; mdlVec_fromRotMatrixRow(&viewVecX, &rMatrix, 0); mdlVec_fromRotMatrixRow(&viewVecZ, &rMatrix, 2); mdlVec_normalize(&viewVecZ); mdlVec_normalize(&viewVecX); rMatrix.Invert(); Transform transform = Transform::FromIdentity(); transform.SetMatrix(rMatrix); if (SUCCESS != mdlElmdscr_convertTo3D(&elmdscr3dTarget, eeh2dTarget.GetElementDescrP(), FIXEDDEPTH, 0, &transform, ACTIVEMODEL, ACTIVEMODEL)) { return rtnPt; } EditElementHandle eeh3dTarget(elmdscr3dTarget, true, false, ACTIVEMODEL); mdlMeasure_closestPointOnElement(&rtnPt, &eeh3dTarget, NULL, &spacePt); DRange3d range1, range2; mdlElmdscr_computeRange(&range1.low, &range1.high, eehTarget.GetElementDescrP(), NULL); mdlElmdscr_computeRange(&range2.low, &range2.high, eeh3dTarget.GetElementDescrP(), NULL); range1.UnionOf(range1, range2); double maxLength = mdlVec_distance(&range1.low, &range1.high); DPoint3d linePtArr[2] = { rtnPt ,rtnPt }; if (viewVecZ.x == 0 && viewVecZ.y == 0) { linePtArr->x += uorperMer / 2; (linePtArr + 1)->x -= uorperMer / 2; MSElement lineEle; mdlLine_create(&lineEle, NULL, linePtArr); MSElementDescrP lineElmdscr; mdlElmdscr_new(&lineElmdscr, NULL, &lineEle); EditElementHandle eehLine(lineElmdscr, true, false, ACTIVEMODEL); const int intPtArrCnt = 10; Dpoint3d interPtArr1[intPtArrCnt]; Dpoint3d interPtArr2[intPtArrCnt]; RotMatrix rMatrixId = RotMatrix::FromIdentity(); int interCnt; if (SUCCESS == mdlIntersect_closestBetweenElms (interPtArr1, interPtArr2, &interCnt, eehLine.GetElementDescrP(), eehTarget.GetElementDescrP(), &rMatrixId, &rtnPt, 0.00001)) { rtnPt = interPtArr2[0]; } } else { mdlVec_addScaled(linePtArr, linePtArr, &viewVecZ, maxLength * 2); mdlVec_addScaled(linePtArr + 1, linePtArr + 1, &viewVecZ, -maxLength * 2); MSElement lineEle; mdlLine_create(&lineEle, NULL, linePtArr); MSElementDescrP lineElmdscr; mdlElmdscr_new(&lineElmdscr, NULL, &lineEle); EditElementHandle eehLine(lineElmdscr, true, false, ACTIVEMODEL); const int intPtArrCnt = 10; Dpoint3d interPtArr1[intPtArrCnt]; Dpoint3d interPtArr2[intPtArrCnt]; RotMatrix rMatrixId = RotMatrix::FromIdentity(); int interCnt = mdlIntersect_allBetweenElms(interPtArr1, interPtArr2, intPtArrCnt, eehLine.GetElementDescrP(), eehTarget.GetElementDescrP(), &rMatrixId, 0.00001); if (interCnt == 0) { return rtnPt; } for (int i = 0; i < (interCnt < intPtArrCnt ? interCnt : intPtArrCnt); i++) { if (abs(interPtArr1[i].z - interPtArr2[i].z) < 0.1) { rtnPt = interPtArr2[i]; break; } } } return rtnPt; }
试试我这个函数
Answer Verified By: Redrum Tan
如果您就想在工具执行过程中让用户点的点落在三维线的最近点处,其实完全可以不用编程,只需要如下图所示设置MS的捕捉方式为最近(Nearest)即可。
符老师您好,MS自身的Nearest捕捉机制存在两个不足,这是我们与用户确认之后他们所不能接受的:
1.Nearsest存在距离限制,当距离过大就无法捕捉了,而我们的实际用例中就会出现这种情况;
2.Nearest无法指定仅捕捉特定的某条线或者某个元素;
用我上边发的函数即可