highflyingbird 发表于 2010-7-23 10:04:57

两条曲线间getClosestPointTo的精确性。

我创建了AcDb到AcGe和AcGe到AcDb的转换。
我使用此转换来获得两条曲线之间的最近点,
大多数曲线的结果是准确的,但对于样条曲线,有时会与真实点略有不同。
所以问题是:我如何才能得到确切的答案?
另一个问题是:如何准确地将AcDb2dPolyline2d(或AcDb3dPolyline)转换为AcGePolyline2d?AcDb3dPolyline->getSpline?主代码:
// 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)
{
        returnnew AcGeCircArc3d(
                pDbArc->center(),
                pDbArc->normal(),
                pDbArc->normal().perpVector(),
                pDbArc->radius(),
                pDbArc->startAngle(),
                pDbArc->endAngle());
}
AcDbCurve * AcGeCurveToAcDbCurve(const AcGeCircArc3d * pGe)
{
        if (pGe->isClosed() == Adesk::kTrue)
        {
                returnnew AcDbCircle(
                        pGe->center(),
                        pGe->normal(),
                        pGe->radius());
        }
        else
        {
                returnnew 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;inumKnots();i++)
                {
                        knots.append(knots1);
                }
                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 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);
                }
        }
        returnnew 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 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 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 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 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;
}



**** Hidden Message *****

highflyingbird 发表于 2010-7-23 10:12:55

Alexander Rivilis,Gile,感谢您的代码和想法。
任何建议或错误发现欢迎和感谢。

pkohut 发表于 2010-7-23 10:35:29

从视觉上看,您的动画看起来是正确的。实际点和计算点之间有多大差异? 你是怎么走到这一步的?

highflyingbird 发表于 2010-7-23 11:32:12

有时这是错误的

pkohut 发表于 2010-7-23 18:57:09

有时它是错误的

好吧,所以有时它是错误的。查看代码,有很多,2个实体选择,其中一个可以是样条的组合。哪个实体组合不起作用?样条-样条,样条-弧等?此外,对于样条,有曲线拟合或苗圃。哪一个搞砸了,或者两者兼而有之?制作一个图表,显示成功和失败的实体组合,发布它,这将有助于任何测试人员。在图表中也包括两种不同类型的样条的通过/失败测试。问题与2d和3d实体类型相关,还是仅与一种特定类型相关。提供测试人员可以使用的绘图文件。告诉我们您怀疑哪个代码区域有问题。
我们这里只有少数人知道ARX,而那些可能在头脑中就知道样条特定答案的人,都在Autolisp论坛中。要获得尽可能多的帮助,请从上面的列表开始提供尽可能多的详细信息。

pkohut 发表于 2010-7-23 21:38:10

在玩了大约一个小时后,终于找到了答案
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;
}

基本上,您没有从原始样条曲线检索所有nurb数据,并且使用了错误的AcGeNurbCurve3d构造函数
因此,新样条曲线与旧样条曲线的几何图形不同
以下是ARX文档对您使用的构造函数的描述。

highflyingbird 发表于 2010-7-23 22:45:58

非常感谢,pkohut。
注意:
虽然用“getNurbsData”是对的,但是看数据:
阶数: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
另一个
在折线的构造中有一个错误

pkohut 发表于 2010-7-23 23:20:07


抱歉,我对婴儿床一无所知,它们是如何制作的,一无所知。
得走了,孩子们周末在这里。

LE3 发表于 2010-7-24 00:30:40

看看这是否有帮助:
        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 发表于 2010-7-24 02:35:47

这可能会起作用Luis。乍一看,
if(pSpline->hasFitData()==Adesk::kTrue){...}
是重复代码并不明显,这使得函数看起来比实际更复杂。收紧要好得多。
页: [1] 2
查看完整版本: 两条曲线间getClosestPointTo的精确性。