### Author Topic: The accurateness about getClosestPointTo between two Curves.  (Read 14236 times)

0 Members and 1 Guest are viewing this topic.

#### highflyingbird

• Bull Frog
• Posts: 415
• Later equals never.
##### The accurateness about getClosestPointTo between two Curves.
« on: July 23, 2010, 10:04:57 AM »
I created a conversion for AcDb to AcGe and AcGe to AcDb.
I used this conversion to get closet point between two curves,
the result for most of curve is accurate,but for spline,sometimes ,is a little different from the real point.

so the question is : How can I get the  exactly one?

another question is:  How can I convert a AcDb2dPolyline2d(or AcDb3dPolyline) to a AcGePolyline2d accurately?  AcDb3dPolyline->getSpline ?

main code:
Code: [Select]
// LINE
AcGeLineSeg3d * AcDbCurveToAcGeCurve(const AcDbLine * pLine)
{
return new AcGeLineSeg3d(pLine->startPoint(), pLine->endPoint());
}
AcDbLine * AcGeCurveToAcDbCurve(const AcGeLineSeg3d * pGe)
{
return new AcDbLine(pGe->startPoint(),pGe->endPoint());
}

// ARC
AcGeCircArc3d * AcDbCurveToAcGeCurve(const AcDbArc * pDbArc)
{
return  new AcGeCircArc3d(
pDbArc->center(),
pDbArc->normal(),
pDbArc->normal().perpVector(),
pDbArc->startAngle(),
pDbArc->endAngle());
}

AcDbCurve * AcGeCurveToAcDbCurve(const AcGeCircArc3d * pGe)
{
{
return  new AcDbCircle(
pGe->center(),
pGe->normal(),
}
else
{
return  new AcDbArc(
pGe->center(),
pGe->normal(),
pGe->startAng(),
pGe->endAng());
}
}

// CIRCLE
AcGeCircArc3d * AcDbCurveToAcGeCurve(const AcDbCircle * pDbCircle)
{
}

// ELLIPSE
AcGeEllipArc3d * AcDbCurveToAcGeCurve(const AcDbEllipse * pDbEllise)
{
return new AcGeEllipArc3d(
pDbEllise->center(),
pDbEllise->majorAxis(),
pDbEllise->minorAxis(),
pDbEllise->majorAxis().length(),
pDbEllise->minorAxis().length(),
pDbEllise->startAngle(),
pDbEllise->endAngle());
}
AcDbEllipse * AcGeCurveToAcDbCurve(const AcGeEllipArc3d * pGe)
{
return new AcDbEllipse(
pGe->center(),
pGe->normal(),
pGe->startAng(),
pGe->endAng());
}

// SPLINE
AcGeNurbCurve3d * AcDbCurveToAcGeCurve(const AcDbSpline * pSpline)
{
AcGePoint3dArray fitPoints;
int degree;
double fitTolerance;
AcGeVector3d startTangent;
AcGeVector3d endTangent;
AcGePoint3dArray controlPoints;
AcGeDoubleArray knots;
AcGeDoubleArray weights;
double controlPtTol;
double knotTol;
closed = pSpline->isClosed();
AcGeNurbCurve3d *curv = NULL;
if (0)//(pSpline->hasFitData())
{
AcGeTol tol;
if ((es = pSpline->getFitData(fitPoints,degree,fitTolerance,tangentsExist,startTangent,endTangent)) == Acad::eOk)
{
tangentStartDef = tangentsExist; //&& (startTangent != AcGeVector3d::kIdentity);
tangentEndDef   = tangentsExist; //&& (endTangent   != AcGeVector3d::kIdentity);
AcGeTol fitTol;
pSpline->fitTolerance();
fitTol.setEqualPoint(fitTolerance);
curv = new AcGeNurbCurve3d(fitPoints,startTangent,endTangent,tangentStartDef,tangentEndDef,fitTol);
{
curv->makeClosed();
}
}
}
else
{
if ((es = pSpline->getNurbsData(degree,rational,closed,periodic,controlPoints,knots,weights,controlPtTol,knotTol)) == Acad::eOk)
{
{
curv = new AcGeNurbCurve3d(degree,knots,controlPoints,weights,periodic);
}
else
{
curv = new AcGeNurbCurve3d(degree,knots,controlPoints,periodic);
}
{
curv->makeClosed();
}
}
}
return curv;
}
AcDbSpline * AcGeCurveToAcDbCurve(const AcGeNurbCurve3d * pGe)
{
AcDbSpline *pSpline = NULL;
if (pGe->hasFitData())
{
AcGePoint3dArray fitPoints;
AcGeTol fitTolerance;
AcGeVector3d startTangent;
AcGeVector3d endTangent;
double tol;
pGe->getFitData(fitPoints,fitTolerance,tangentsExist,startTangent,endTangent);
pSpline = new AcDbSpline(fitPoints,startTangent,endTangent,pGe->order(),fitTolerance.equalPoint());
}
else
{
int degree;
AcGePoint3dArray controlPoints;
AcGeKnotVector knots1;
AcGeDoubleArray weights;
pGe->getDefinitionData(degree,rational,periodic,knots1,controlPoints,weights);
AcGeDoubleArray knots;
for (int i = 0;i< pGe->numKnots();i++)
{
knots.append(knots1[i]);
}
pSpline = new AcDbSpline(degree,rational,pGe->isClosed(),periodic,controlPoints,knots,weights,0.0,pGe->knots().tolerance());
}
return pSpline;
}

// POLYLINE
AcGeCompositeCurve3d * AcDbCurveToAcGeCurve(const AcDbPolyline * pPoly)
{
AcGeLineSeg3d *pLine = NULL;
AcGeCircArc3d *pArc = NULL;
AcGeVoidPointerArray GeCurves;
for( int i = 0; i < pPoly->numVerts(); i++ )
{
if( pPoly->segType(i) == AcDbPolyline::kLine )
{
pLine = new AcGeLineSeg3d;
pPoly->getLineSegAt(i, *pLine);
GeCurves.append(pLine);
}
else if( pPoly->segType(i) == AcDbPolyline::kArc )
{
pArc = new AcGeCircArc3d;
pPoly->getArcSegAt(i, *pArc);
GeCurves.append(pArc);
}
}
return  new AcGeCompositeCurve3d(GeCurves);
}

AcDbPolyline * AcGeCurveToAcDbCurve(const AcGeCompositeCurve3d * pGe)
{
AcGePoint3d startPnt,endPnt;
if( pGe->hasEndPoint(endPnt) == Adesk ::kFalse ||
{
return NULL;
}

//get the plane of Curve3d
AcGePlane plane;
AcGeLine3d line;
AcGePoint3d p1,p2,p3;
if(pGe->isPlanar(plane))
{
if(pGe->isLinear(line))    //Oh,it's a little tricky!
{
line.getPerpPlane(startPnt,plane);
plane.get(p1,p2,p3);
plane.set(p2,p3-p2);
}
plane.get(p1,p2,p3);
}
else
{
return NULL;
}

//Creat a polyline
AcDbPolyline *pPoly = new AcDbPolyline();
AcGeVoidPointerArray curveList;
pGe->getCurveList(curveList);  //get all the segments
AcGeCurve3d *pCurve = NULL;
AcGeCircArc3d *pArc = NULL;

int i;
double b;
AcGePoint2d pt;
for(i = 0;i < curveList.length();i++)
{
pCurve  =  (AcGeCurve3d *) (curveList[i]);
pCurve->hasStartPoint(startPnt);
pt = startPnt.convert2d(plane);

if (pCurve->isKindOf(AcGe::kCircArc3d))
{
pArc = (AcGeCircArc3d *)(pCurve);
b = tan(0.25*(pArc->endAng() - pArc->startAng()));
if (pArc->normal().z < 0.0)
{
}
else
{
}
}
else
{
}
}

if(!pGe->isClosed())
{
pt = endPnt.convert2d(plane);
}
else
{
}

//the most important step;
AcGeMatrix3d xform;
AcGeVector3d XAxis = p1-p2;
AcGeVector3d YAxis = p3-p2;
AcGeVector3d ZAxis = XAxis.crossProduct(YAxis);
xform.setCoordSystem(p2,XAxis,YAxis,ZAxis);
pPoly->transformBy(xform);

return pPoly;
}

// POLYLINE3D
AcGeCompositeCurve3d * AcDbCurveToAcGeCurve(const AcDb3dPolyline * pPoly3d)
{
AcGeVoidPointerArray GeCurves;
AcGePoint3d pt1;
AcGePoint3d pt2;
double Param;
pPoly3d->getEndParam(Param);

AcGeLineSeg3d *pLine = NULL;
for (int i= 0; i < (int)Param;i++)
{
pPoly3d->getPointAtParam(i,pt1);
pPoly3d->getPointAtParam(i+1,pt2);
pLine = new AcGeLineSeg3d(pt1,pt2);
GeCurves.append(pLine);
}

//AcDbSpline *pSpline= NULL;
//pPoly3d->getSpline(pSpline);
//CreateEntity(pSpline,1);
AcGeCompositeCurve3d * pGePoly3d = new AcGeCompositeCurve3d(GeCurves);

return pGePoly3d;
}

// POLYLINE2D
AcGeCompositeCurve3d * AcDbCurveToAcGeCurve(const AcDb2dPolyline *pPoly2d)
{
AcDb::Poly2dType type;
type=pPoly2d->polyType();
AcDbPolyline * pLwpoly = NULL;
AcGeCompositeCurve3d * pGeCurve = NULL;
if ((type==AcDb::k2dSimplePoly)||(type==AcDb::k2dFitCurvePoly))
{
pLwpoly=new AcDbPolyline;
{
delete pLwpoly;
pLwpoly=NULL;
return NULL;
}
pGeCurve = AcDbCurveToAcGeCurve(pLwpoly);
pLwpoly->close();
}
else
{
AcGeVoidPointerArray GeCurves;
AcGePoint3d pt1;
AcGePoint3d pt2;
double Param;
pPoly2d->getEndParam(Param);

AcGeLineSeg3d *pLine = NULL;
for (int i= 0; i < (int)Param;i++)
{
pPoly2d->getPointAtParam(i,pt1);
pPoly2d->getPointAtParam(i+1,pt2);
pLine = new AcGeLineSeg3d(pt1,pt2);
GeCurves.append(pLine);
}
pGeCurve = new AcGeCompositeCurve3d(GeCurves);
}
return pGeCurve;
}

// catch all for all other entity types.
AcGeEntity3d * AcDbCurveToAcGeCurve(const AcDbEntity *pDbCurve)
{
if (pDbCurve == NULL)
{
return NULL;
}
if (pDbCurve->isKindOf(AcDbLine::desc()))
{
return AcDbCurveToAcGeCurve((AcDbLine *)pDbCurve);
}
if (pDbCurve->isKindOf(AcDbArc::desc()))
{
return AcDbCurveToAcGeCurve((AcDbArc *)pDbCurve);
}
if (pDbCurve->isKindOf(AcDbCircle::desc()))
{
return AcDbCurveToAcGeCurve((AcDbCircle *)pDbCurve);
}
if (pDbCurve->isKindOf(AcDbEllipse::desc()))
{
return AcDbCurveToAcGeCurve((AcDbEllipse *)pDbCurve);
}
if (pDbCurve->isKindOf(AcDbSpline::desc()))
{
return AcDbCurveToAcGeCurve((AcDbSpline *)pDbCurve);
}
if (pDbCurve->isKindOf(AcDbPolyline::desc()))
{
return AcDbCurveToAcGeCurve((AcDbPolyline *)pDbCurve);
}
if (pDbCurve->isKindOf(AcDb3dPolyline::desc()))
{
return AcDbCurveToAcGeCurve((AcDb3dPolyline *)pDbCurve);
}
if (pDbCurve->isKindOf(AcDb2dPolyline::desc()))
{
return AcDbCurveToAcGeCurve((AcDb2dPolyline *)pDbCurve);
}
return NULL;
}

AcDbEntity * AcGeCurveToAcDbCurve(const AcGeCurve3d * pGe)
{
if (pGe->isKindOf(AcGe::kCircArc3d))
{
return AcGeCurveToAcDbCurve((AcGeCircArc3d *) pGe);
}
if (pGe->isKindOf(AcGe::kEllipArc3d))
{
return AcGeCurveToAcDbCurve((AcGeEllipArc3d *) pGe);
}
if (pGe->isKindOf(AcGe::kLineSeg3d))
{
return AcGeCurveToAcDbCurve((AcGeLineSeg3d *) pGe);
}
if (pGe->isKindOf(AcGe::kNurbCurve3d))
{
return AcGeCurveToAcDbCurve((AcGeNurbCurve3d *) pGe);
}
if (pGe->isKindOf(AcGe::kCompositeCrv3d))
{
return AcGeCurveToAcDbCurve((AcGeCompositeCurve3d*) pGe);
}
return NULL;
}
« Last Edit: July 31, 2010, 07:09:01 PM by highflybird »
I am a bilingualist,Chinese and Chinglish.

#### highflyingbird

• Bull Frog
• Posts: 415
• Later equals never.
##### Re: The accurateness about getClosestPointTo between two Curves.
« Reply #1 on: July 23, 2010, 10:12:55 AM »
Alexander Rivilis,Gile,thank you for your codes and  thought.

any suggestion or bug finding welcome and thanks.
I am a bilingualist,Chinese and Chinglish.

#### pkohut

• Guest
##### Re: The accurateness about getClosestPointTo between two Curves.
« Reply #2 on: July 23, 2010, 10:35:29 AM »
Visually, your animation looks correct. How much difference between the real point and the computed point?  How, did you arrive at the real point?

#### highflyingbird

• Bull Frog
• Posts: 415
• Later equals never.
##### Re: The accurateness about getClosestPointTo between two Curves.
« Reply #3 on: July 23, 2010, 11:32:12 AM »
Visually, your animation looks correct. How much difference between the real point and the computed point?  How, did you arrive at the real point?
sometimes it's wrong
I am a bilingualist,Chinese and Chinglish.

#### pkohut

• Guest
##### Re: The accurateness about getClosestPointTo between two Curves.
« Reply #4 on: July 23, 2010, 06:57:09 PM »
Visually, your animation looks correct. How much difference between the real point and the computed point?  How, did you arrive at the real point?
sometimes it's wrong

Alright, so sometimes it's wrong. Looking at the code, there are many, 2 entity pick, combinations where one can be a spline. Which combination of entities does not work? Spline - Spline, Spline - Arc, etc?? Also, for a spline there is curve fit or nurbs. Which of these is messing up, or both? Make a chart that shows entity combinations that succeed and fail, post it, that will help anyone that tests. Include in the chart pass/fail test for the 2 different types of splines too. Is the issue relevant to 2d and 3d entity types, or just one particular type.  Provide a drawing file the tester can use.  Tell us which area of code you suspect being the problem.

There is only a handful of us here that know ARX, and the guys that probably know the spline specific answers off the top of their head, are in the Autolisp forum. To recruit as much help as possible, provide as many details as you can, starting with the above list.

#### pkohut

• Guest
##### Re: The accurateness about getClosestPointTo between two Curves.
« Reply #5 on: July 23, 2010, 09:38:10 PM »
After playing around for an hour or so 2 hours, finally figured it out.

Code: [Select]
AcGeNurbCurve3d * AcDbCurveToAcGeCurve(const AcDbSpline * pSpline)
{
AcGeNurbCurve3d *curv = NULL;
if (pSpline->hasFitData())
{
BOOL bIsRational, bIsPeriodic, bIsClosed;
AcGeDoubleArray knots;
AcGePoint3dArray controlPoints;
AcGeDoubleArray weights;
double controlPtTol, knotTol;
int nDegree;
pSpline->getNurbsData(nDegree, bIsRational, bIsClosed, bIsPeriodic, controlPoints, knots, weights, controlPtTol, knotTol);
if(weights.length())
curv = new AcGeNurbCurve3d(nDegree, knots, controlPoints, weights, bIsPeriodic);
else
curv = new AcGeNurbCurve3d(nDegree, knots, controlPoints, bIsPeriodic);
bIsClosed ? curv->makeClosed() : curv->makeOpen();
}
return curv;
}

Basically you didn't retrieve all the nurb data from the original spline, and used the wrong AcGeNurbCurve3d constructor.
So the new spline did not have the same geometry as the old spline.

Here is what the ARX docs say about the constructor you used.
Quote
AcGeNurbCurve3d(
const AcGePoint3dArray& fitPoints,
const AcGeVector3d& startTangent,
const AcGeVector3d& endTangent,
const AcGeTol& fitTolerance = AcGeContext::gTol);

Constructs a 3D polynomial spline interpolating a given array of 3D points within the given tolerance and having given derivatives at the start point and endpoint.

edit: removed enfasis on the word interpolating

« Last Edit: July 23, 2010, 10:32:20 PM by pkohut »

#### highflyingbird

• Bull Frog
• Posts: 415
• Later equals never.
##### Re: The accurateness about getClosestPointTo between two Curves.
« Reply #6 on: July 23, 2010, 10:45:58 PM »
After playing around for an hour or so 2 hours, finally figured it out.

edit: removed enfasis on the word interpolating
Thank you very much,pkohut.
notice that:
Although it's right with "getNurbsData", but see the data:

阶数: 4
特性: 平面， 非有理， 非周期
参数范围:  起点   0.0000
端点1203.6780
控制点数目: 7
控制点: X = 1747.8226, Y = 840.1270 , Z = 0.0000
X = 1883.3499, Y = 833.2746 , Z = 0.0000
X = 2159.7191, Y = 819.3010 , Z = 0.0000
X = 2054.1012, Y = 1336.1513, Z = 0.0000
X = 2465.0705, Y = 1316.6316, Z = 0.0000
X = 2622.7793, Y = 1252.1511, Z = 0.0000
X = 2669.6303, Y = 1232.9957, Z = 0.0000
it's different from the origin.

another

There is a bug in the construction of Polyline

« Last Edit: July 23, 2010, 10:51:32 PM by highflybird »
I am a bilingualist,Chinese and Chinglish.

#### pkohut

• Guest
##### Re: The accurateness about getClosestPointTo between two Curves.
« Reply #7 on: July 23, 2010, 11:20:07 PM »
Although it's right with "getNurbsData", but see the data:

阶数: 4
特性: 平面， 非有理， 非周期
参数范围:  起点   0.0000
端点1203.6780
控制点数目: 7
控制点: X = 1747.8226, Y = 840.1270 , Z = 0.0000
X = 1883.3499, Y = 833.2746 , Z = 0.0000
X = 2159.7191, Y = 819.3010 , Z = 0.0000
X = 2054.1012, Y = 1336.1513, Z = 0.0000
X = 2465.0705, Y = 1316.6316, Z = 0.0000
X = 2622.7793, Y = 1252.1511, Z = 0.0000
X = 2669.6303, Y = 1232.9957, Z = 0.0000
it's different from the origin.

another

There is a bug in the construction of Polyline

Gotta, go kids are here for the weekend.

#### LE3

• Guest
##### Re: The accurateness about getClosestPointTo between two Curves.
« Reply #8 on: July 24, 2010, 12:30:40 AM »
See if this helps:
Code: [Select]
int degree;
AcGePoint3dArray controlPoints;
AcGeDoubleArray knots;
AcGeDoubleArray weights;
double controlPtTol;
double knotTol;
AcGeTol tol;
es=pSpline->getNurbsData(degree,rational,closed,periodic,controlPoints,knots,weights,controlPtTol,knotTol);

{
acutPrintf(_T("\n*** Spline is Rational. "));

AcGeNurbCurve3d *pNurb=new AcGeNurbCurve3d(degree,knots,controlPoints,weights,periodic);
pNurb->makeClosed();
{
AcGePoint3dArray fitPoints;
double fitTolerance;
AcGeVector3d startTangent;
AcGeVector3d endTangent;
pSpline->getFitData(fitPoints,degree,fitTolerance,tangentsExist,startTangent,endTangent);
tol.setEqualPoint(fitTolerance);
pNurb->setFitData(fitPoints,startTangent,endTangent,tol);
else
pNurb->setFitData(degree,fitPoints,tol);
}
pGeCurve = (AcGeCurve3d *)pNurb;
}
else
{
acutPrintf(_T("\n*** Spline is Periodic. "));

AcGeNurbCurve3d *pNurb=new AcGeNurbCurve3d(degree,knots,controlPoints,periodic);
pNurb->makeClosed();
{
AcGePoint3dArray fitPoints;
double fitTolerance;
AcGeVector3d startTangent;
AcGeVector3d endTangent;
pSpline->getFitData(fitPoints,degree,fitTolerance,tangentsExist,startTangent,endTangent);
tol.setEqualPoint(fitTolerance);
pNurb->setFitData(fitPoints,startTangent,endTangent,tol);
else
pNurb->setFitData(degree,fitPoints,tol);
}
pGeCurve = (AcGeCurve3d *)pNurb;
}

#### pkohut

• Guest
##### Re: The accurateness about getClosestPointTo between two Curves.
« Reply #9 on: July 24, 2010, 02:35:47 AM »
That will probably work Luis. At first glance it's not apparent that
is duplicate code, which makes the function look more complicated than it is. Be much better to tightened up.

#### highflyingbird

• Bull Frog
• Posts: 415
• Later equals never.
##### Re: The accurateness about getClosestPointTo between two Curves.
« Reply #10 on: July 24, 2010, 04:29:42 AM »
See if this helps:
...

No,it doesn't work.Thank you anyway.
notice that: both of them can't get a right result.
by the way, I modified my code,I will post it later.
Code: [Select]
#include "StdAfx.h"

//Convert AcDb to AcGe;
Acad::ErrorStatus AcDbCurveToAcGeCurve(AcGeCurve3d * &pGe,const AcDbLine * pLine);
Acad::ErrorStatus AcDbCurveToAcGeCurve(AcGeCurve3d * &pGe,const AcDbArc * pDbArc);
Acad::ErrorStatus AcDbCurveToAcGeCurve(AcGeCurve3d * &pGe,const AcDbCircle * pDbCircle);
Acad::ErrorStatus AcDbCurveToAcGeCurve(AcGeCurve3d * &pGe,const AcDbEllipse * pDbEllise);
Acad::ErrorStatus AcDbCurveToAcGeCurve(AcGeCurve3d * &pGe,const AcDbSpline * pSpline,bool isFit = true);
Acad::ErrorStatus AcDbCurveToAcGeCurve(AcGeCurve3d * &pGe,const AcDbPolyline * pPoly);
Acad::ErrorStatus AcDbCurveToAcGeCurve(AcGeCurve3d * &pGe,const AcDb2dPolyline *pPoly2d,bool isFit = true);
Acad::ErrorStatus AcDbCurveToAcGeCurve(AcGeCurve3d * &pGe,const AcDb3dPolyline *pPoly3d,bool isFit = true);
Acad::ErrorStatus AcDbCurveToAcGeCurve(AcGeCurve3d * &pGe,const AcDbCurve *pDbCurve);
Acad::ErrorStatus AcDbCurveToAcGeCurve(AcGeCurve3d * &pGe,const AcDbEntity *pEnt);

//Convert AcGe to AcDb;
Acad::ErrorStatus AcGeCurveToAcDbCurve(AcDbCurve * &pDb,const AcGeLineSeg3d * pGe);
Acad::ErrorStatus AcGeCurveToAcDbCurve(AcDbCurve * &pDb,const AcGeCircArc3d * pGe);
Acad::ErrorStatus AcGeCurveToAcDbCurve(AcDbCurve * &pDb,const AcGeEllipArc3d * pGe);
Acad::ErrorStatus AcGeCurveToAcDbCurve(AcDbCurve * &pDb,const AcGeNurbCurve3d * pGe);
Acad::ErrorStatus AcGeCurveToAcDbCurve(AcDbCurve * &pDb,const AcGeCompositeCurve3d * pGe);
Acad::ErrorStatus AcGeCurveToAcDbCurve(AcDbCurve * &pDb,const AcGeCurve3d * pGe);
Acad::ErrorStatus AcGeCurveToAcDbCurve(AcDbCurve * &pDb,const AcGePolyline3d *pGe);

//This is for test.
« Last Edit: July 28, 2010, 08:34:38 PM by highflybird »
I am a bilingualist,Chinese and Chinglish.

#### LE3

• Guest
##### Re: The accurateness about getClosestPointTo between two Curves.
« Reply #11 on: July 24, 2010, 10:25:19 AM »
That will probably work Luis. At first glance it's not apparent that
is duplicate code, which makes the function look more complicated than it is. Be much better to tightened up.
Yes, it was just a quick post before going to bed, last night

#### LE3

• Guest
##### Re: The accurateness about getClosestPointTo between two Curves.
« Reply #12 on: July 24, 2010, 11:11:49 AM »
Code: [Select]
No,it doesn't work.Thank you anyway.
notice that: both of them can't get a right result.
by the way, I modified my code,I will post it later.
I see, have not look at your code, I tried to do something similar some time ago, never finished, also remember that Joe Burke wrote MinDist
a great gem to do exactly this, but don't know if he posted his code here (lisp/vlisp)
Quote
;; By Joe Burke, Charles Alan Butler and VovKa at theswamp.
;; Version 1.0 - 5/28/2008.
;; Find the minimum distance between two vlax-curve objects.
;; Supported object types: line, circle, arc, ellipse, polyline and spline.
;; Shortcut: MD
;;
;; Notes version 1.0:
;;  If two lines are parallel they are reported as such.
;;  If the Z values of the two points found are not equal,
;;  report at command line Z1 = x Z2 = x. When the objects
;;  are not coplanar, the apparent minimum distance will
;;  usually differ from the actual minimum distance.
;;  There's an option to add a line on the current layer
;;  drawn between the two closest points.
;;  The object types selected are reported at the command line.

;; Version history by Joe Burke:

;;  Version 1.2 beta - 5/31/2008
;;   Added the MinDistLine routine. Shortcut: MDL.
;;   Allows the user to place a line between the last two closest points
;;   calculated by MinDist after it ends. This avoids having to choose
;;   whether a line is placed within MinDist itself. The idea is MinDist
;;   is primarily a measuring tool. As such a minimum distance line is
;;   rarely needed. Note, If the line drawn by MDL is off-screen it is
;;   selected, otherwise it is not.

;;  Version 1.3 beta - 6/8/2008
;;   Added support for nested objects in blocks and xrefs.
;;   Added MD:GetXrefs, MD:GetObject, MD:UnlockLayers, MD:RelockLayers
;;   and MD:XMark sub-functions.
;;   The first object selected is highlighted until the the second
;;   object is selected similar to the fillet tool. If the first object
;;   is contained in an xref it is not highlighted. Rather a temporary
;;   X mark is placed where the object was selected to indicate the
;;   the object is contained in an xref.

;;  Version 1.4 beta - 6/10/2008
;;   Added error checking for non-uniformly scaled blocks.

#### highflyingbird

• Bull Frog
• Posts: 415
• Later equals never.
##### Re: The accurateness about getClosestPointTo between two Curves.
« Reply #13 on: July 28, 2010, 08:21:45 PM »
OK,I updated it.
Code: [Select]
#include "Conversion.h"

// LINE
Acad::ErrorStatus AcDbCurveToAcGeCurve(AcGeCurve3d * &pGe,const AcDbLine * pLine)
{
pGe = new AcGeLineSeg3d(pLine->startPoint(), pLine->endPoint());
}
Acad::ErrorStatus AcGeCurveToAcDbCurve(AcDbCurve * &pDb,const AcGeLineSeg3d * pGe)
{
pDb= new AcDbLine(pGe->startPoint(),pGe->endPoint());
}

// ARC
Acad::ErrorStatus  AcDbCurveToAcGeCurve(AcGeCurve3d * &pGe,const AcDbArc * pDbArc)
{
pGe =  new AcGeCircArc3d(
pDbArc->center(),
pDbArc->normal(),
pDbArc->normal().perpVector(),
pDbArc->startAngle(),
pDbArc->endAngle());
}

Acad::ErrorStatus AcGeCurveToAcDbCurve(AcDbCurve * &pDb,const AcGeCircArc3d * pGe)
{
if (pGe->isClosed())
{
}
else
{
}
}

// CIRCLE
Acad::ErrorStatus  AcDbCurveToAcGeCurve(AcGeCurve3d * &pGe,const AcDbCircle * pDbCircle)
{
}

// ELLIPSE
Acad::ErrorStatus  AcDbCurveToAcGeCurve(AcGeCurve3d * &pGe,const AcDbEllipse * pDb)
{
pGe =  new AcGeEllipArc3d(
pDb->center(),
pDb->majorAxis(),
pDb->minorAxis(),
pDb->majorAxis().length(),
pDb->minorAxis().length(),
pDb->startAngle(),
pDb->endAngle());
}
Acad::ErrorStatus  AcGeCurveToAcDbCurve(AcDbCurve * &pDb,const AcGeEllipArc3d * pGe)
{
pDb = new AcDbEllipse(
pGe->center(),
pGe->normal(),
pGe->startAng(),
pGe->endAng());
}

// SPLINE
Acad::ErrorStatus AcDbCurveToAcGeCurve(AcGeCurve3d * &pGe,const AcDbSpline * pSpline,bool isFit)
{
int degree;
double fitTolerance,controlPtTol,knotTol;
AcGeVector3d startTangent,endTangent;
AcGePoint3dArray controlPoints,fitPoints;
AcGeDoubleArray knots,weights;
bIsClosed = pSpline->isClosed();
AcGeNurbCurve3d *pNurb = NULL;
if (pSpline->hasFitData() && isFit)
{
AcGeTol tol;
es = pSpline->getFitData(fitPoints,degree,fitTolerance,tangentsExist,startTangent,endTangent);
{
tangentStartDef = tangentsExist;
tangentEndDef   = tangentsExist;
AcGeTol fitTol;
pSpline->fitTolerance();
fitTol.setEqualPoint(fitTolerance);
if (tangentsExist)
{
pNurb = new AcGeNurbCurve3d(fitPoints,startTangent,endTangent,tangentStartDef,tangentEndDef,fitTol);
}
else
{
pNurb = new AcGeNurbCurve3d(fitPoints,fitTol);
}
}
else
{
}
}
else
{
es = pSpline->getNurbsData(degree,bIsRational,bIsClosed,bIsPeriodic,controlPoints,knots,weights,controlPtTol,knotTol);
{
if (bIsRational)
{
pNurb = new AcGeNurbCurve3d(degree,knots,controlPoints,weights,bIsPeriodic);
}
else
{
pNurb = new AcGeNurbCurve3d(degree,knots,controlPoints,bIsPeriodic);
}
}
else
{
}
}
bIsClosed?pNurb->makeClosed():pNurb->makeOpen();
pGe = pNurb;
return es;
}
Acad::ErrorStatus AcGeCurveToAcDbCurve(AcDbCurve * &pDb,const AcGeNurbCurve3d * pGe)
{
if (pGe->hasFitData())
{
AcGePoint3dArray fitPoints;
AcGeTol fitTolerance;
AcGeVector3d startTangent;
AcGeVector3d endTangent;
double tol;
pGe->getFitData(fitPoints,fitTolerance,tangentsExist,startTangent,endTangent);
pDb = new AcDbSpline(fitPoints,startTangent,endTangent,pGe->order(),fitTolerance.equalPoint());
}
else
{
int degree;
AcGePoint3dArray controlPoints;
AcGeKnotVector knots1;
AcGeDoubleArray weights;
pGe->getDefinitionData(degree,bIsRational,periodic,knots1,controlPoints,weights);
AcGeDoubleArray knots;
for (int i = 0;i<knots1.length();i++)
{
knots.append(knots1[i]);
}
pDb =new AcDbSpline(degree,bIsRational,pGe->isClosed(),periodic,controlPoints,knots,weights,0.0,pGe->knots().tolerance());
}
}

// POLYLINE
Acad::ErrorStatus  AcDbCurveToAcGeCurve(AcGeCurve3d * &pGe,const AcDbPolyline * pPoly)
{
AcGeLineSeg3d *pLine = NULL;
AcGeCircArc3d *pArc = NULL;
AcGeVoidPointerArray GeCurves;
for( int i = 0; i < pPoly->numVerts(); i++ )
{
if( pPoly->segType(i) == AcDbPolyline::kLine )
{
pLine = new AcGeLineSeg3d;
pPoly->getLineSegAt(i, *pLine);
GeCurves.append(pLine);
}
else if( pPoly->segType(i) == AcDbPolyline::kArc )
{
pArc = new AcGeCircArc3d;
pPoly->getArcSegAt(i, *pArc);
GeCurves.append(pArc);
}
}
pGe =  new AcGeCompositeCurve3d(GeCurves);
}

Acad::ErrorStatus AcGeCurveToAcDbCurve(AcDbCurve * &pDb,const AcGeCompositeCurve3d * pGe)

AcGePoint3d startPnt,endPnt;
if( pGe->hasEndPoint(endPnt) == Adesk ::kFalse ||
{
}

//get the plane of Curve3d
AcGePlane plane;
AcGeLine3d line;
AcGePoint3d p1,p2,p3;
if(pGe->isPlanar(plane))
{
if(pGe->isLinear(line))    //Oh,it's a little tricky!
{
line.getPerpPlane(startPnt,plane);
plane.get(p1,p2,p3);
plane.set(p2,p3-p2);
}
plane.get(p1,p2,p3);
}
else
{
}

//Creat a polyline
AcDbPolyline *pPoly = new AcDbPolyline();
AcGeVoidPointerArray curveList;
pGe->getCurveList(curveList);  //get all the segments
AcGeCurve3d *pCurve = NULL;
AcGeCircArc3d *pArc = NULL;

int i;
double b;
AcGePoint2d pt;
for(i = 0;i < curveList.length();i++)
{
pCurve  =  (AcGeCurve3d *) (curveList[i]);
pCurve->hasStartPoint(startPnt);
pt = startPnt.convert2d(plane);

if (pCurve->isKindOf(AcGe::kCircArc3d))
{
pArc = (AcGeCircArc3d *)(pCurve);
b = tan(0.25 * pArc->endAng());
if (pArc->normal()!=plane.normal())
{
}
else
{
}
}
else
{
}
}

if(!pGe->isClosed())
{
pt = endPnt.convert2d(plane);
}
else
{
}

//the most important step;
AcGeMatrix3d xform;
AcGeVector3d XAxis = p1-p2;
AcGeVector3d YAxis = p3-p2;
AcGeVector3d ZAxis = XAxis.crossProduct(YAxis);
xform.setCoordSystem(p2,XAxis,YAxis,ZAxis);
pPoly->transformBy(xform);
pDb = pPoly;

}

// POLYLINE3D
Acad::ErrorStatus AcDbCurveToAcGeCurve(AcGeCurve3d * &pGe,const AcDb3dPolyline * pPoly3d,bool isFit)
{
AcGeVoidPointerArray GeCurves;
AcGePoint3d pt1;
AcGePoint3d pt2;
double Param;
pPoly3d->getEndParam(Param);
GeCurves.setLogicalLength((int)Param);
for (int i= 0; i < (int)Param;i++)
{
pPoly3d->getPointAtParam(i,pt1);
pPoly3d->getPointAtParam(i+1,pt2);
GeCurves[i] = new AcGeLineSeg3d(pt1,pt2);
}
if (!isFit)
{
pGe  = new AcGeCompositeCurve3d(GeCurves);
}

AcDbSpline *pSpline= NULL;
pPoly3d->getSpline(pSpline);
delete pSpline;
pSpline = NULL;
return es;

/* Actually, You can get a AcGePolyline3d,but sometimes it's wrong,I don't why,so gave up.See below:
AcGeNurbCurve3d * pGeSpline =(AcGeNurbCurve3d *)pCur;
int degree;
AcGePoint3dArray controlPoints;
AcGeKnotVector knots;
AcGeDoubleArray weights;

pGeSpline->getDefinitionData(degree,bIsRational,periodic,knots,controlPoints,weights);

CreateEntity(pSpline,1);
AcGePolyline3d *ppp;
ppp = new AcGePolyline3d(knots,controlPoints);
//ppp = new AcGePolyline3d(*pGeSpline,1);
//ppp = new AcGePolyline3d(controlPoints);
pGe =  ppp;

*/
}
Acad::ErrorStatus AcGeCurveToAcDbCurve(AcDbCurve * &pDb,const AcGePolyline3d *pGe)
{
AcGePoint3dArray pts;
for (int i = 0;i < pGe->numControlPoints();i++)
{
pts.append(pGe->controlPointAt(i));
}
pDb = new AcDb3dPolyline((AcDb::Poly3dType)pGe->type(),pts,pGe->isClosed());
}

// POLYLINE2D
Acad::ErrorStatus AcDbCurveToAcGeCurve(AcGeCurve3d * &pGe,const AcDb2dPolyline *pPoly2d,bool isFit)
{
AcDb::Poly2dType type;
type=pPoly2d->polyType();
AcDbPolyline * pLwpoly = NULL;
if ((type==AcDb::k2dSimplePoly)||(type==AcDb::k2dFitCurvePoly))
{
pLwpoly=new AcDbPolyline;
{
delete pLwpoly;
pLwpoly=NULL;
return es;
}
es = AcDbCurveToAcGeCurve(pGe,pLwpoly);
pLwpoly->close();
return es;
}
else
{
AcGeVoidPointerArray GeCurves;
AcGePoint3d pt1;
AcGePoint3d pt2;
double Param;
pPoly2d->getEndParam(Param);

AcGeLineSeg3d *pLine = NULL;
for (int i= 0; i < (int)Param;i++)
{
pPoly2d->getPointAtParam(i,pt1);
pPoly2d->getPointAtParam(i+1,pt2);
pLine = new AcGeLineSeg3d(pt1,pt2);
GeCurves.append(pLine);
}
pGe = new AcGeCompositeCurve3d(GeCurves);
}
}

// catch all for all other entity types.
Acad::ErrorStatus AcDbCurveToAcGeCurve(AcGeCurve3d * &pGe,const AcDbCurve *pDbCurve)
{
if (pDbCurve->isKindOf(AcDbLine::desc()))
{
return AcDbCurveToAcGeCurve(pGe,(AcDbLine *)pDbCurve);
}
if (pDbCurve->isKindOf(AcDbArc::desc()))
{
return AcDbCurveToAcGeCurve(pGe,(AcDbArc *)pDbCurve);
}
if (pDbCurve->isKindOf(AcDbCircle::desc()))
{
return AcDbCurveToAcGeCurve(pGe,(AcDbCircle *)pDbCurve);
}
if (pDbCurve->isKindOf(AcDbEllipse::desc()))
{
return AcDbCurveToAcGeCurve(pGe,(AcDbEllipse *)pDbCurve);
}
if (pDbCurve->isKindOf(AcDbSpline::desc()))
{
return AcDbCurveToAcGeCurve(pGe,(AcDbSpline *)pDbCurve);
}
if (pDbCurve->isKindOf(AcDbPolyline::desc()))
{
return AcDbCurveToAcGeCurve(pGe,(AcDbPolyline *)pDbCurve);
}
if (pDbCurve->isKindOf(AcDb3dPolyline::desc()))
{
return AcDbCurveToAcGeCurve(pGe,(AcDb3dPolyline *)pDbCurve);
}
if (pDbCurve->isKindOf(AcDb2dPolyline::desc()))
{
return AcDbCurveToAcGeCurve(pGe,(AcDb2dPolyline *)pDbCurve);
}
}
Acad::ErrorStatus AcDbCurveToAcGeCurve(AcGeCurve3d * &pGe,const AcDbEntity *pEnt)
{
if (pEnt->isKindOf(AcDbCurve::desc()))
{
return AcDbCurveToAcGeCurve(pGe,(AcDbCurve *)pEnt);
}
}

Acad::ErrorStatus AcGeCurveToAcDbCurve(AcDbCurve * &pDb,const AcGeCurve3d * pGe)
{
AcGe::EntityId type = pGe->type();
switch (type)
{
case AcGe::kLineSeg3d:
return AcGeCurveToAcDbCurve(pDb,(AcGeLineSeg3d *) pGe);
case AcGe::kCircArc3d:
return AcGeCurveToAcDbCurve(pDb,(AcGeCircArc3d *) pGe);
case AcGe::kEllipArc3d:
return AcGeCurveToAcDbCurve(pDb,(AcGeEllipArc3d *) pGe);
case AcGe::kNurbCurve3d:
return AcGeCurveToAcDbCurve(pDb,(AcGeNurbCurve3d *) pGe);
case AcGe::kCompositeCrv3d:
return AcGeCurveToAcDbCurve(pDb,(AcGeCompositeCurve3d*) pGe);
case AcGe::kPolyline3d:
return AcGeCurveToAcDbCurve(pDb,(AcGePolyline3d *) pGe);
default:
}
}

//创建实体
{
if (pEnt == NULL)
{
}
AcDbDatabase *pDb = acdbHostApplicationServices()->workingDatabase();
AcDbBlockTableRecord *pRec = NULL;
es = acdbOpenAcDbObject((AcDbObject *&)pRec,pDb->currentSpaceId(),AcDb::kForWrite);
return es;
es = pRec->appendAcDbEntity(pEnt);
return es;
pEnt->setColorIndex(color);
pRec->close();
pEnt->close();
return es;
}
for Polyline3d(or 2d)
if you want to get the closet point accurately, translate it into  AcGeCompositeCurve3d, if you jwant a same one,use getspline.
Actually,for fitting spline, getNurbsData for accurateness,getFitData for the same type.
« Last Edit: July 28, 2010, 08:33:27 PM by highflybird »
I am a bilingualist,Chinese and Chinglish.

#### SEANT

• Bull Frog
• Posts: 338
##### Re: The accurateness about getClosestPointTo between two Curves.
« Reply #14 on: July 29, 2010, 07:18:39 AM »
Nicely done.

This thread is interesting, even though I don’t currently use native ARX.  I have done something similar (DBCurve – Geometry Curve) project in .NET, though.

I did notice an Ellipse related situation in your program similar to what I had originally in mine.  Instead of –Angle, the Ellipse is recreated more accurately with the Start- and EndParameter (as informed to me by xsfhlzh in this thread:  http://www.theswamp.org/index.php?topic=29217.0)

I’ve also investigated the Curve3d.GetClosestPointTo(Curve3d, Tolerance), from the .NET side, and found the method to be a bit temperamental.  Does your updated code allow more consistent results?

I’ve had better performance by sub-dividing the NurbCurve (with the HardTrimByParams Method) at the Knot values.  getLocalClosestPoints may also have been useful for subdivision except that it is not available in the ManagedARX.

This subdivision seems quite accurate for all curves with one notable exception:  a NurbCurve3d/LineSegment analysis.  The PointOnCurve is not always located correctly for the LineSegment.
« Last Edit: July 29, 2010, 07:21:48 AM by SEANT »
Sean Tessier