+//=============================================================================
+//function : isIsoLine
+//purpose :
+//=============================================================================
+Standard_Boolean Approx_CurveOnSurface::isIsoLine(const Handle(Adaptor2d_HCurve2d) theC2D,
+ Standard_Boolean& theIsU,
+ Standard_Real& theParam,
+ Standard_Boolean& theIsForward) const
+{
+ // These variables are used to check line state (vertical or horizontal).
+ Standard_Boolean isAppropriateType = Standard_False;
+ gp_Pnt2d aLoc2d;
+ gp_Dir2d aDir2d;
+
+ // Test type.
+ const GeomAbs_CurveType aType = theC2D->GetType();
+ if (aType == GeomAbs_Line)
+ {
+ gp_Lin2d aLin2d = theC2D->Line();
+ aLoc2d = aLin2d.Location();
+ aDir2d = aLin2d.Direction();
+ isAppropriateType = Standard_True;
+ }
+ else if (aType == GeomAbs_BSplineCurve)
+ {
+ Handle(Geom2d_BSplineCurve) aBSpline2d = theC2D->BSpline();
+ if (aBSpline2d->Degree() != 1 || aBSpline2d->NbPoles() != 2)
+ return Standard_False; // Not a line or uneven parameterization.
+
+ aLoc2d = aBSpline2d->Pole(1);
+
+ // Vector should be non-degenerated.
+ gp_Vec2d aVec2d(aBSpline2d->Pole(1), aBSpline2d->Pole(2));
+ if (aVec2d.SquareMagnitude() < Precision::Confusion())
+ return Standard_False; // Degenerated spline.
+ aDir2d = aVec2d;
+
+ isAppropriateType = Standard_True;
+ }
+ else if (aType == GeomAbs_BezierCurve)
+ {
+ Handle(Geom2d_BezierCurve) aBezier2d = theC2D->Bezier();
+ if (aBezier2d->Degree() != 1 || aBezier2d->NbPoles() != 2)
+ return Standard_False; // Not a line or uneven parameterization.
+
+ aLoc2d = aBezier2d->Pole(1);
+
+ // Vector should be non-degenerated.
+ gp_Vec2d aVec2d(aBezier2d->Pole(1), aBezier2d->Pole(2));
+ if (aVec2d.SquareMagnitude() < Precision::Confusion())
+ return Standard_False; // Degenerated spline.
+ aDir2d = aVec2d;
+
+ isAppropriateType = Standard_True;
+ }
+
+ if (!isAppropriateType)
+ return Standard_False;
+
+ // Check line to be vertical or horizontal.
+ if (aDir2d.IsParallel(gp::DX2d(), Precision::Angular()))
+ {
+ // Horizontal line. V = const.
+ theIsU = Standard_False;
+ theParam = aLoc2d.Y();
+ theIsForward = aDir2d.Dot(gp::DX2d()) > 0.0;
+ return Standard_True;
+ }
+ else if (aDir2d.IsParallel(gp::DY2d(), Precision::Angular()))
+ {
+ // Vertical line. U = const.
+ theIsU = Standard_True;
+ theParam = aLoc2d.X();
+ theIsForward = aDir2d.Dot(gp::DY2d()) > 0.0;
+ return Standard_True;
+ }
+
+ return Standard_False;
+}
+
+#include <GeomLib.hxx>
+
+//=============================================================================
+//function : buildC3dOnIsoLine
+//purpose :
+//=============================================================================
+Standard_Boolean Approx_CurveOnSurface::buildC3dOnIsoLine(const Handle(Adaptor2d_HCurve2d) theC2D,
+ const Standard_Boolean theIsU,
+ const Standard_Real theParam,
+ const Standard_Boolean theIsForward)
+{
+ // Convert adapter to the appropriate type.
+ Handle(GeomAdaptor_HSurface) aGeomAdapter = Handle(GeomAdaptor_HSurface)::DownCast(mySurf);
+ if (aGeomAdapter.IsNull())
+ return Standard_False;
+
+ if (mySurf->GetType() == GeomAbs_Sphere)
+ return Standard_False;
+
+ // Extract isoline
+ Handle(Geom_Surface) aSurf = aGeomAdapter->ChangeSurface().Surface();
+ Handle(Geom_Curve) aC3d;
+
+ gp_Pnt2d aF2d = theC2D->Value(theC2D->FirstParameter());
+ gp_Pnt2d aL2d = theC2D->Value(theC2D->LastParameter());
+
+ if (theIsU)
+ {
+ aC3d = aSurf->UIso(theParam);
+ aC3d = new Geom_TrimmedCurve(aC3d, aF2d.Y(), aL2d.Y());
+ }
+ else
+ {
+ aC3d = aSurf->VIso(theParam);
+ aC3d = new Geom_TrimmedCurve(aC3d, aF2d.X(), aL2d.X());
+ }
+
+ // Convert arbitrary curve type to the b-spline.
+ myCurve3d = GeomConvert::CurveToBSplineCurve(aC3d, Convert_QuasiAngular);
+ if (!theIsForward)
+ myCurve3d->Reverse();
+
+ // Rebuild parameterization for the 3d curve to have the same parameterization with
+ // a two-dimensional curve.
+ TColStd_Array1OfReal aKnots = myCurve3d->Knots();
+ BSplCLib::Reparametrize(theC2D->FirstParameter(), theC2D->LastParameter(), aKnots);
+ myCurve3d->SetKnots(aKnots);
+
+ // Evaluate error.
+ myError3d = 0.0;
+
+ const Standard_Real aParF = myFirst;
+ const Standard_Real aParL = myLast;
+ const Standard_Integer aNbPnt = 23;
+ for(Standard_Integer anIdx = 0; anIdx <= aNbPnt; ++anIdx)
+ {
+ const Standard_Real aPar = aParF + ((aParL - aParF) * anIdx) / aNbPnt;
+
+ const gp_Pnt2d aPnt2d = theC2D->Value(aPar);
+
+ const gp_Pnt aPntC3D = myCurve3d->Value(aPar);
+ const gp_Pnt aPntC2D = mySurf->Value(aPnt2d.X(), aPnt2d.Y());
+
+ const Standard_Real aSqDeviation = aPntC3D.SquareDistance(aPntC2D);
+ myError3d = Max(aSqDeviation, myError3d);
+ }
+
+ myError3d = Sqrt(myError3d);
+
+ // Target tolerance is not obtained. This situation happens for isolines on the sphere.
+ // OCCT is unable to convert it keeping original parameterization, while the geometric
+ // form of the result is entirely identical. In that case, it is better to utilize
+ // a general-purpose approach.
+ if (myError3d > myTol)
+ return Standard_False;
+
+ return Standard_True;
+}