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

0 Members and 1 Guest are viewing this topic.

highflyingbird

  • Bull Frog
  • Posts: 414
  • Later equals never.
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->radius(),
pDbArc->startAngle(),
pDbArc->endAngle());
}

AcDbCurve * AcGeCurveToAcDbCurve(const AcGeCircArc3d * pGe)
{
if (pGe->isClosed() == Adesk::kTrue)
{
return  new AcDbCircle(
pGe->center(),
pGe->normal(),
pGe->radius());
}
else
{
return  new AcDbArc(
pGe->center(),
pGe->normal(),
pGe->radius(),
pGe->startAng(),
pGe->endAng());
}
}


// CIRCLE
AcGeCircArc3d * AcDbCurveToAcGeCurve(const AcDbCircle * pDbCircle)
{
return new AcGeCircArc3d(pDbCircle->center(),pDbCircle->normal(),pDbCircle->radius());
}


// 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->majorAxis()*pGe->majorRadius(),
pGe->minorRadius()/pGe->majorRadius(),
pGe->startAng(),
pGe->endAng());
}

// SPLINE
AcGeNurbCurve3d * AcDbCurveToAcGeCurve(const AcDbSpline * pSpline)
{
Acad::ErrorStatus es = Acad::eOk;
AcGePoint3dArray fitPoints;
int degree;
double fitTolerance;
Adesk::Boolean tangentsExist;
Adesk::Boolean tangentStartDef;
Adesk::Boolean tangentEndDef;
AcGeVector3d startTangent;
AcGeVector3d endTangent;
Adesk::Boolean rational;
Adesk::Boolean closed;
Adesk::Boolean periodic;
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);
if (closed == Adesk::kTrue)
{
curv->makeClosed();
}
}
}
else
{
if ((es = pSpline->getNurbsData(degree,rational,closed,periodic,controlPoints,knots,weights,controlPtTol,knotTol)) == Acad::eOk)
{
if (rational==Adesk::kTrue)
{
curv = new AcGeNurbCurve3d(degree,knots,controlPoints,weights,periodic);
}
else
{
curv = new AcGeNurbCurve3d(degree,knots,controlPoints,periodic);
}
if (closed == Adesk::kTrue)
{
curv->makeClosed();
}
}
}
return curv;
}
AcDbSpline * AcGeCurveToAcDbCurve(const AcGeNurbCurve3d * pGe)
{
AcDbSpline *pSpline = NULL;
if (pGe->hasFitData())
{
AcGePoint3dArray fitPoints;
AcGeTol fitTolerance;
Adesk::Boolean tangentsExist;
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;
Adesk::Boolean rational;
Adesk::Boolean periodic;
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 ||
pGe->hasStartPoint(startPnt) == 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)
{
pPoly->addVertexAt(i,pt,-b);
}
else
{
pPoly->addVertexAt(i,pt,b);
}
}
else
{
pPoly->addVertexAt(i,pt);
}
}

if(!pGe->isClosed())
{
pt = endPnt.convert2d(plane);
pPoly->addVertexAt(i,pt);
}
else
{
pPoly->setClosed(Adesk::kTrue);
}

//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;
Acad::ErrorStatus es;
AcGeCompositeCurve3d * pGeCurve = NULL;
if ((type==AcDb::k2dSimplePoly)||(type==AcDb::k2dFitCurvePoly))
{
pLwpoly=new AcDbPolyline;
es = pLwpoly->convertFrom((AcDbEntity *&)pPoly2d,Adesk::kFalse);
if (es!=Acad::eOk)
{
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: 414
  • 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: 414
  • 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,
Adesk::Boolean startTangentDefined = Adesk::kTrue,
Adesk::Boolean endTangentDefined = Adesk::kTrue,
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: 414
  • 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

Sorry, I know nothing about nurbs, how they are made, ziltch.

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;
Adesk::Boolean rational;
Adesk::Boolean closed;
Adesk::Boolean periodic;
AcGePoint3dArray controlPoints;
AcGeDoubleArray knots;
AcGeDoubleArray weights;
double controlPtTol;
double knotTol;
AcGeTol tol;
es=pSpline->getNurbsData(degree,rational,closed,periodic,controlPoints,knots,weights,controlPtTol,knotTol);
if (es!=Acad::eOk)
return Acad::eNotImplemented;

if (rational==Adesk::kTrue)
{
acutPrintf(_T("\n*** Spline is Rational. "));

AcGeNurbCurve3d *pNurb=new AcGeNurbCurve3d(degree,knots,controlPoints,weights,periodic);
if (closed==Adesk::kTrue)
pNurb->makeClosed();
if (pSpline->hasFitData()==Adesk::kTrue)
{
AcGePoint3dArray fitPoints;
double fitTolerance;
Adesk::Boolean tangentsExist;
AcGeVector3d startTangent;
AcGeVector3d endTangent;
pSpline->getFitData(fitPoints,degree,fitTolerance,tangentsExist,startTangent,endTangent);
tol.setEqualPoint(fitTolerance);
if (tangentsExist==Adesk::kTrue)
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);
if (closed==Adesk::kTrue)
pNurb->makeClosed();
if (pSpline->hasFitData()==Adesk::kTrue)
{
AcGePoint3dArray fitPoints;
double fitTolerance;
Adesk::Boolean tangentsExist;
AcGeVector3d startTangent;
AcGeVector3d endTangent;
pSpline->getFitData(fitPoints,degree,fitTolerance,tangentsExist,startTangent,endTangent);
tol.setEqualPoint(fitTolerance);
if (tangentsExist==Adesk::kTrue)
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
if (pSpline->hasFitData()==Adesk::kTrue) { ... }
is duplicate code, which makes the function look more complicated than it is. Be much better to tightened up.

highflyingbird

  • Bull Frog
  • Posts: 414
  • 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.
Acad::ErrorStatus CreateEntity(AcDbEntity * pEnt,Adesk::UInt16 color = 256);code]
« 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
if (pSpline->hasFitData()==Adesk::kTrue) { ... }
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]
[quote author=highflybird link=topic=34229.msg395459#msg395459 date=1279960182]
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: 414
  • 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());
return Acad::eOk;
}
Acad::ErrorStatus AcGeCurveToAcDbCurve(AcDbCurve * &pDb,const AcGeLineSeg3d * pGe)
{
pDb= new AcDbLine(pGe->startPoint(),pGe->endPoint());
return Acad::eOk;
}

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

Acad::ErrorStatus AcGeCurveToAcDbCurve(AcDbCurve * &pDb,const AcGeCircArc3d * pGe)
{
if (pGe->isClosed())
{
pDb = new AcDbCircle(pGe->center(),pGe->normal(),pGe->radius());
}
else
{
pDb = new AcDbArc(pGe->center(),pGe->normal(),pGe->radius(),pGe->startAng(),pGe->endAng());
}
return Acad::eOk;
}


// CIRCLE
Acad::ErrorStatus  AcDbCurveToAcGeCurve(AcGeCurve3d * &pGe,const AcDbCircle * pDbCircle)
{
pGe =  new AcGeCircArc3d(pDbCircle->center(),pDbCircle->normal(),pDbCircle->radius());
return Acad::eOk;
}


// 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());
return Acad::eOk;
}
Acad::ErrorStatus  AcGeCurveToAcDbCurve(AcDbCurve * &pDb,const AcGeEllipArc3d * pGe)
{
pDb = new AcDbEllipse(
pGe->center(),
pGe->normal(),
pGe->majorAxis()*pGe->majorRadius(),
pGe->minorRadius()/pGe->majorRadius(),
pGe->startAng(),
pGe->endAng());
return Acad::eOk;
}

// SPLINE
Acad::ErrorStatus AcDbCurveToAcGeCurve(AcGeCurve3d * &pGe,const AcDbSpline * pSpline,bool isFit)
{
Acad::ErrorStatus es;
int degree;
double fitTolerance,controlPtTol,knotTol;
Adesk::Boolean tangentsExist,tangentStartDef,tangentEndDef,bIsRational,bIsPeriodic,bIsClosed;
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);
if (es == Acad::eOk)
{
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
{
return Acad::eNotImplementedYet;
}
}
else
{
es = pSpline->getNurbsData(degree,bIsRational,bIsClosed,bIsPeriodic,controlPoints,knots,weights,controlPtTol,knotTol);
if (es == Acad::eOk)
{
if (bIsRational)
{
pNurb = new AcGeNurbCurve3d(degree,knots,controlPoints,weights,bIsPeriodic);
}
else
{
pNurb = new AcGeNurbCurve3d(degree,knots,controlPoints,bIsPeriodic);
}
}
else
{
return Acad::eNotImplementedYet;
}
}
bIsClosed?pNurb->makeClosed():pNurb->makeOpen();
pGe = pNurb;
return es;
}
Acad::ErrorStatus AcGeCurveToAcDbCurve(AcDbCurve * &pDb,const AcGeNurbCurve3d * pGe)
{
if (pGe->hasFitData())
{
AcGePoint3dArray fitPoints;
AcGeTol fitTolerance;
Adesk::Boolean tangentsExist;
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;
Adesk::Boolean bIsRational,periodic;
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());
}
return Acad::eOk;
}

// 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);
return Acad::eOk;
}

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

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

//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 Acad::eNotImplementedYet;
}

//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())
{
pPoly->addVertexAt(i,pt,-b);
}
else
{
pPoly->addVertexAt(i,pt,b);
}
}
else
{
pPoly->addVertexAt(i,pt);
}
}

if(!pGe->isClosed())
{
pt = endPnt.convert2d(plane);
pPoly->addVertexAt(i,pt);
}
else
{
pPoly->setClosed(Adesk::kTrue);
}

//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;

return Acad::eOk;
}

// 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);
return Acad::eOk;
}

AcDbSpline *pSpline= NULL;
pPoly3d->getSpline(pSpline);
Acad::ErrorStatus es = AcDbCurveToAcGeCurve(pGe,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;
Adesk::Boolean bIsRational,periodic;
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;

return Acad::eOk;
*/
}
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());
return Acad::eOk;
}

// POLYLINE2D
Acad::ErrorStatus AcDbCurveToAcGeCurve(AcGeCurve3d * &pGe,const AcDb2dPolyline *pPoly2d,bool isFit)
{
AcDb::Poly2dType type;
type=pPoly2d->polyType();
AcDbPolyline * pLwpoly = NULL;
Acad::ErrorStatus es;
if ((type==AcDb::k2dSimplePoly)||(type==AcDb::k2dFitCurvePoly))
{
pLwpoly=new AcDbPolyline;
es = pLwpoly->convertFrom((AcDbEntity *&)pPoly2d,Adesk::kFalse);
if (es!=Acad::eOk)
{
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);
return Acad::eOk;
}
}

// 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);
}
return Acad::eNotImplementedYet;
}
Acad::ErrorStatus AcDbCurveToAcGeCurve(AcGeCurve3d * &pGe,const AcDbEntity *pEnt)
{
if (pEnt->isKindOf(AcDbCurve::desc()))
{
return AcDbCurveToAcGeCurve(pGe,(AcDbCurve *)pEnt);
}
return Acad::eNotImplementedYet;
}

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:
return Acad::eNotImplementedYet;
}
}

//创建实体
Acad::ErrorStatus CreateEntity(AcDbEntity * pEnt,Adesk::UInt16 color)
{
if (pEnt == NULL)
{
return Acad::eNullEntityPointer;
}
Acad::ErrorStatus es;
AcDbDatabase *pDb = acdbHostApplicationServices()->workingDatabase();
AcDbBlockTableRecord *pRec = NULL;
es = acdbOpenAcDbObject((AcDbObject *&)pRec,pDb->currentSpaceId(),AcDb::kForWrite);
if(es!=Acad::eOk)
return es;
es = pRec->appendAcDbEntity(pEnt);
if(es!=Acad::eOk)
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: 324
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
AutoCAD 2016 Mechanical