// Alternatively, this file may be used under the terms of Open CASCADE
// commercial license or contractual agreement.
-#include <ProjLib_CompProjectedCurve.ixx>
-#include <ProjLib_HCompProjectedCurve.hxx>
-#include <gp_XY.hxx>
-#include <gp_Mat2d.hxx>
-#include <Extrema_ExtPS.hxx>
-#include <Precision.hxx>
+
+#include <algorithm>
+
+#include <Adaptor2d_HCurve2d.hxx>
+#include <Adaptor3d_HCurve.hxx>
+#include <Adaptor3d_HSurface.hxx>
#include <Extrema_ExtCS.hxx>
-#include <TColgp_HSequenceOfPnt.hxx>
+#include <Extrema_ExtPS.hxx>
#include <Extrema_GenLocateExtPS.hxx>
-#include <Extrema_POnSurf.hxx>
#include <Extrema_POnCurv.hxx>
-#include <ProjLib_PrjResolve.hxx>
+#include <Extrema_POnSurf.hxx>
#include <GeomAbs_CurveType.hxx>
#include <GeomLib.hxx>
+#include <gp_Mat2d.hxx>
+#include <gp_Pnt2d.hxx>
+#include <gp_Vec2d.hxx>
+#include <gp_XY.hxx>
+#include <Precision.hxx>
+#include <ProjLib_CompProjectedCurve.hxx>
+#include <ProjLib_HCompProjectedCurve.hxx>
+#include <ProjLib_PrjResolve.hxx>
+#include <Standard_DomainError.hxx>
+#include <Standard_NoSuchObject.hxx>
+#include <Standard_NotImplemented.hxx>
+#include <Standard_OutOfRange.hxx>
+#include <TColgp_HSequenceOfPnt.hxx>
+#include <Adaptor3d_CurveOnSurface.hxx>
+#include <Geom2d_Line.hxx>
+#include <Geom2dAdaptor_HCurve.hxx>
+#include <Extrema_ExtCC.hxx>
+#include <NCollection_Vector.hxx>
#define FuncTol 1.e-10
}
#endif
+// Structure to perform splits computation.
+// This structure is not thread-safe since operations under mySplits should be performed in a critical section.
+// myPeriodicDir - 0 for U periodicity and 1 for V periodicity.
+struct SplitDS
+{
+ SplitDS(const Handle(Adaptor3d_HCurve) &theCurve,
+ const Handle(Adaptor3d_HSurface) &theSurface,
+ NCollection_Vector<Standard_Real> &theSplits)
+ : myCurve(theCurve),
+ mySurface(theSurface),
+ mySplits(theSplits)
+ { }
+
+ // Assignment operator is forbidden.
+ void operator=(const SplitDS &theSplitDS);
+
+ const Handle(Adaptor3d_HCurve) myCurve;
+ const Handle(Adaptor3d_HSurface) mySurface;
+ NCollection_Vector<Standard_Real> &mySplits;
+
+ Standard_Real myPerMinParam;
+ Standard_Real myPerMaxParam;
+ Standard_Integer myPeriodicDir;
+
+ Extrema_ExtCC *myExtCC;
+ Extrema_ExtPS *myExtPS;
+};
+
+ //! Compute split points in the parameter space of the curve.
+ static void BuildCurveSplits(const Handle(Adaptor3d_HCurve) &theCurve,
+ const Handle(Adaptor3d_HSurface) &theSurface,
+ const Standard_Real theTolU,
+ const Standard_Real theTolV,
+ NCollection_Vector<Standard_Real> &theSplits);
+
+ //! Perform splitting on a specified direction. Sub-method in BuildCurveSplits.
+ static void SplitOnDirection(SplitDS & theSplitDS);
+
+ //! Perform recursive search of the split points.
+ static void FindSplitPoint(SplitDS & theSplitDS,
+ const Standard_Real theMinParam,
+ const Standard_Real theMaxParam);
+
+
+//=======================================================================
+//function : Comparator
+//purpose : used in sort algorithm
+//=======================================================================
+inline Standard_Boolean Comparator(const Standard_Real theA,
+ const Standard_Real theB)
+{
+ return theA < theB;
+}
//=======================================================================
//function : d1
void ProjLib_CompProjectedCurve::Init()
{
myTabInt.Nullify();
+ NCollection_Vector<Standard_Real> aSplits;
+ aSplits.Clear();
Standard_Real Tol;// Tolerance for ExactBound
- Standard_Integer i, Nend = 0;
- Standard_Boolean FromLastU=Standard_False;
-
- //new part (to discard far solutions)
- Standard_Real TolC = Precision::Confusion(), TolS = Precision::Confusion();
- Extrema_ExtCS CExt(myCurve->Curve(),
- mySurface->Surface(),
- TolC,
- TolS);
- if (CExt.IsDone() && CExt.NbExt())
+ Standard_Integer i, Nend = 0, aSplitIdx = 0;
+ Standard_Boolean FromLastU = Standard_False,
+ isSplitsComputed = Standard_False;
+
+ const Standard_Real aTol3D = Precision::Confusion();
+ Extrema_ExtCS CExt(myCurve->Curve(), mySurface->Surface(), aTol3D, aTol3D);
+ if (CExt.IsDone() && CExt.NbExt())
{
- // Search for the minimum solution
- Nend = CExt.NbExt();
+ // Search for the minimum solution.
+ // Avoid usage of extrema result that can be wrong for extrusion.
if(myMaxDist > 0 &&
- // Avoid usage of extrema result that can be wrong for extrusion
+
mySurface->GetType() != GeomAbs_SurfaceOfExtrusion)
{
Standard_Real min_val2;
min_val2 = CExt.SquareDistance(1);
+
+ Nend = CExt.NbExt();
for(i = 2; i <= Nend; i++)
- if (CExt.SquareDistance(i) < min_val2) min_val2 = CExt.SquareDistance(i);
+ {
+ if (CExt.SquareDistance(i) < min_val2)
+ min_val2 = CExt.SquareDistance(i);
+ }
if (min_val2 > myMaxDist * myMaxDist)
- return;
+ return; // No near solution -> exit.
}
}
- // end of new part
- Standard_Real FirstU, LastU, Step, DecStep, SearchStep, WalkStep, t;
+ Standard_Real FirstU, LastU, Step, SearchStep, WalkStep, t;
FirstU = myCurve->FirstParameter();
LastU = myCurve->LastParameter();
+ const Standard_Real GlobalMinStep = 1.e-4;
+ //<GlobalMinStep> is sufficiently small to provide solving from initial point
+ //and, on the other hand, it is sufficiently large to avoid too close solutions.
const Standard_Real MinStep = 0.01*(LastU - FirstU),
MaxStep = 0.1*(LastU - FirstU);
SearchStep = 10*MinStep;
Step = SearchStep;
- //Initialization of aPrjPS
- Standard_Real Uinf = mySurface->FirstUParameter();
- Standard_Real Usup = mySurface->LastUParameter();
- Standard_Real Vinf = mySurface->FirstVParameter();
- Standard_Real Vsup = mySurface->LastVParameter();
-
+ gp_Pnt2d aLowBorder(mySurface->FirstUParameter(),mySurface->FirstVParameter());
+ gp_Pnt2d aUppBorder(mySurface->LastUParameter(), mySurface->LastVParameter());
+ gp_Pnt2d aTol(myTolU, myTolV);
ProjLib_PrjResolve aPrjPS(myCurve->Curve(), mySurface->Surface(), 1);
t = FirstU;
gp_Pnt Triple, prevTriple;
- //Basic loop
+ //Basic loop
while(t <= LastU)
{
- //Search for the begining a new continuous part
- //To avoid infinite computation in some difficult cases
+ // Search for the beginning of a new continuous part
+ // to avoid infinite computation in some difficult cases.
new_part = Standard_False;
if(t > FirstU && Abs(t-prevDeb) <= Precision::PConfusion()) SameDeb=Standard_True;
while(t <= LastU && !new_part && !FromLastU && !SameDeb)
gp_Pnt CPoint;
Standard_Real ParT,ParU,ParV;
- // Search an initpoint in the list of Extrema Curve-Surface
+ // Search an initial point in the list of Extrema Curve-Surface
if(Nend != 0 && !CExt.IsParallel())
{
for (i=1;i<=Nend;i++)
ParT=P1.Parameter();
P2.Parameter(ParU, ParV);
- aPrjPS.Perform(ParT, ParU, ParV, gp_Pnt2d(myTolU, myTolV),
- gp_Pnt2d(mySurface->FirstUParameter(),mySurface->FirstVParameter()),
- gp_Pnt2d(mySurface->LastUParameter(), mySurface->LastVParameter()),
- FuncTol, Standard_True);
+ aPrjPS.Perform(ParT, ParU, ParV, aTol, aLowBorder, aUppBorder, FuncTol, Standard_True);
+
if ( aPrjPS.IsDone() && P1.Parameter() > Max(FirstU,t-Step+Precision::PConfusion())
&& P1.Parameter() <= t)
{
}
}
if (!initpoint)
- {
+ {
myCurve->D0(t,CPoint);
#ifdef OCCT_DEBUG_CHRONO
InitChron(chr_init_point);
#endif
- initpoint=InitialPoint(CPoint, t,myCurve,mySurface, myTolU, myTolV, U, V);
+ // PConfusion - use geometric tolerances in extrema / optimization.
+ initpoint=InitialPoint(CPoint, t,myCurve,mySurface, Precision::PConfusion(), Precision::PConfusion(), U, V);
#ifdef OCCT_DEBUG_CHRONO
ResultChron(chr_init_point,t_init_point);
init_point_count++;
// as initial point for aPrjPS, so we switch them
gp_Vec2d D;
- if((Abs(U - Uinf) < mySurface->UResolution(Precision::PConfusion())) &&
- mySurface->IsUPeriodic())
- {
- d1(t, U, V, D, myCurve, mySurface);
- if (D.X() < 0) U = Usup;
- }
- else if((Abs(U - Usup) < mySurface->UResolution(Precision::PConfusion())) &&
- mySurface->IsUPeriodic())
+ if ((mySurface->IsUPeriodic() &&
+ Abs(aUppBorder.X() - aLowBorder.X() - mySurface->UPeriod()) < Precision::Confusion()) ||
+ (mySurface->IsVPeriodic() &&
+ Abs(aUppBorder.Y() - aLowBorder.Y() - mySurface->VPeriod()) < Precision::Confusion()))
{
- d1(t, U, V, D, myCurve, mySurface);
- if (D.X() > 0) U = Uinf;
- }
+ if((Abs(U - aLowBorder.X()) < mySurface->UResolution(Precision::PConfusion())) &&
+ mySurface->IsUPeriodic())
+ {
+ d1(t, U, V, D, myCurve, mySurface);
+ if (D.X() < 0 ) U = aUppBorder.X();
+ }
+ else if((Abs(U - aUppBorder.X()) < mySurface->UResolution(Precision::PConfusion())) &&
+ mySurface->IsUPeriodic())
+ {
+ d1(t, U, V, D, myCurve, mySurface);
+ if (D.X() > 0) U = aLowBorder.X();
+ }
- if((Abs(V - Vinf) < mySurface->VResolution(Precision::PConfusion())) &&
- mySurface->IsVPeriodic())
- {
- d1(t, U, V, D, myCurve, mySurface);
- if (D.Y() < 0) V = Vsup;
- }
- else if((Abs(V - Vsup) <= mySurface->VResolution(Precision::PConfusion())) &&
- mySurface->IsVPeriodic())
- {
- d1(t, U, V, D, myCurve, mySurface);
- if (D.Y() > 0) V = Vinf;
+ if((Abs(V - aLowBorder.Y()) < mySurface->VResolution(Precision::PConfusion())) &&
+ mySurface->IsVPeriodic())
+ {
+ d1(t, U, V, D, myCurve, mySurface);
+ if (D.Y() < 0) V = aUppBorder.Y();
+ }
+ else if((Abs(V - aUppBorder.Y()) <= mySurface->VResolution(Precision::PConfusion())) &&
+ mySurface->IsVPeriodic())
+ {
+ d1(t, U, V, D, myCurve, mySurface);
+ if (D.Y() > 0) V = aLowBorder.Y();
+ }
}
-
if (myMaxDist > 0)
{
// Here we are going to stop if the distance between projection and
{
//Search for exact boundary point
Tol = Min(myTolU, myTolV);
- gp_Vec2d D;
- d1(Triple.X(), Triple.Y(), Triple.Z(), D, myCurve, mySurface);
- Tol /= Max(Abs(D.X()), Abs(D.Y()));
+ gp_Vec2d aD;
+ d1(Triple.X(), Triple.Y(), Triple.Z(), aD, myCurve, mySurface);
+ Tol /= Max(Abs(aD.X()), Abs(aD.Y()));
if(!ExactBound(Triple, t - Step, Tol,
myTolU, myTolV, myCurve, mySurface))
}
if (!new_part) break;
-
//We have found a new continuous part
Handle(TColgp_HSequenceOfPnt) hSeq = new TColgp_HSequenceOfPnt();
mySequence->Append(hSeq);
else WalkStep = Min(MaxStep, Max(MinStep, 0.1*MagnD1/MagnD2));
Step = WalkStep;
- DecStep = Step;;
t = Triple.X() + Step;
if (t > LastU) t = LastU;
Standard_Real prevStep = Step;
Standard_Real U0, V0;
- gp_Pnt2d aLowBorder(mySurface->FirstUParameter(),mySurface->FirstVParameter());
- gp_Pnt2d aUppBorder(mySurface->LastUParameter(), mySurface->LastVParameter());
- gp_Pnt2d aTol(myTolU, myTolV);
+
//Here we are trying to prolong continuous part
while (t <= LastU && new_part)
{
aLowBorder, aUppBorder, FuncTol, Standard_True);
if(!aPrjPS.IsDone())
{
-
- if (DecStep <= MinStep)
+ if (Step <= GlobalMinStep)
{
//Search for exact boundary point
Tol = Min(myTolU, myTolV);
Step =Step+LastU-t;
t = LastU;
}
- DecStep=Step;
new_part = Standard_False;
}
else
{
// decrease step
- DecStep=DecStep / 2.;
- Step = Max (MinStep , DecStep);
+ Standard_Real SaveStep = Step;
+ Step /= 2.;
t = Triple .X() + Step;
if (t > (LastU-MinStep/4) )
{
Step =Step+LastU-t;
+ if (Abs(Step - SaveStep) <= Precision::PConfusion())
+ Step = GlobalMinStep; //to avoid looping
t = LastU;
}
}
prevStep = Step;
Triple = gp_Pnt(t, aPrjPS.Solution().X(), aPrjPS.Solution().Y());
- if (mySurface->GetType() == GeomAbs_SurfaceOfRevolution &&
- (Abs (Triple.Z() - mySurface->FirstVParameter()) < Precision::Confusion() ||
- Abs (Triple.Z() - mySurface->LastVParameter() ) < Precision::Confusion() ))
+ // Check for possible local traps.
+ UpdateTripleByTrapCriteria(Triple);
+
+ // Protection from case when the whole curve lies on a seam.
+ if (!isSplitsComputed)
{
- // Go out from possible attraktor.
+ Standard_Boolean isUPossible = Standard_False;
+ if (mySurface->IsUPeriodic() &&
+ (Abs(Triple.Y() - mySurface->FirstUParameter() ) > Precision::PConfusion() &&
+ Abs(Triple.Y() - mySurface->LastUParameter() ) > Precision::PConfusion()))
+ {
+ isUPossible = Standard_True;
+ }
+
+ Standard_Boolean isVPossible = Standard_False;
+ if (mySurface->IsVPeriodic() &&
+ (Abs(Triple.Z() - mySurface->FirstVParameter() ) > Precision::PConfusion() &&
+ Abs(Triple.Z() - mySurface->LastVParameter() ) > Precision::PConfusion()))
+ {
+ isVPossible = Standard_True;
+ }
- Standard_Real U,V;
- InitialPoint(myCurve->Value(t), t, myCurve, mySurface, myTolU, myTolV, U, V);
- if (Abs (Abs(U - Triple.Y()) - mySurface->UPeriod()) < Precision::Confusion())
+ if (isUPossible || isVPossible)
{
- // Handle period jump.
- U = Triple.Y();
+ // When point is good conditioned.
+ BuildCurveSplits(myCurve, mySurface, myTolU, myTolV, aSplits);
+ isSplitsComputed = Standard_True;
}
- Triple.SetY(U);
- Triple.SetZ(V);
}
if((Triple.X() - mySequence->Value(myNbCurves)->Value(mySequence->Value(myNbCurves)->Length()).X()) > 1.e-10)
mySequence->Value(myNbCurves)->Append(Triple);
if (t == LastU) {t = LastU + 1; break;}//return;
-
//Computation of WalkStep
d2CurvOnSurf(Triple.X(), Triple.Y(), Triple.Z(), D1, D2, myCurve, mySurface);
MagnD1 = D1.Magnitude();
Step = WalkStep;
t += Step;
- if (t > (LastU-MinStep/2) )
+ if (t > (LastU-MinStep/2))
{
- Step =Step+LastU-t;
+ Step = Step + LastU - t;
t = LastU;
- }
- DecStep=Step;
+ }
+
+ // We assume at least one point of cache inside of a split.
+ const Standard_Integer aSize = aSplits.Size();
+ for(Standard_Integer anIdx = aSplitIdx; anIdx < aSize; ++anIdx)
+ {
+ const Standard_Real aParam = aSplits(anIdx);
+ if (Abs(aParam - Triple.X() ) < Precision::PConfusion())
+ {
+ // The current point is equal to a split point.
+ new_part = Standard_False;
+
+ // Move split index to avoid check of the whole list.
+ ++aSplitIdx;
+ break;
+ }
+ else if (aParam < t + Precision::PConfusion() )
+ {
+ // The next point crosses the split point.
+ t = aParam;
+ Step = t - prevTriple.X();
+ }
+ } // for(Standard_Integer anIdx = aSplitIdx; anIdx < aSize; ++anIdx)
}
}
}
- // Sequence postproceeding
+
+ // Sequence post-proceeding.
Standard_Integer j;
// 1. Removing poor parts
for(i = 1; i <= myNbCurves; i++)
for(j = 1; j <= mySequence->Value(i)->Length(); j++)
{
- gp_Pnt POnC, POnS, Triple;
+ gp_Pnt POnC, POnS, aTriple;
Standard_Real Distance;
- Triple = mySequence->Value(i)->Value(j);
- myCurve->D0(Triple.X(), POnC);
- mySurface->D0(Triple.Y(), Triple.Z(), POnS);
+ aTriple = mySequence->Value(i)->Value(j);
+ myCurve->D0(aTriple.X(), POnC);
+ mySurface->D0(aTriple.Y(), aTriple.Z(), POnS);
Distance = POnC.Distance(POnS);
if (myMaxDistance->Value(i) < Distance)
myMaxDistance->ChangeValue(i) = Distance;
aPrjPS.Perform(U, U0, V0, gp_Pnt2d(myTolU, myTolV),
gp_Pnt2d(mySurface->FirstUParameter(), mySurface->FirstVParameter()),
gp_Pnt2d(mySurface->LastUParameter(), mySurface->LastVParameter()));
- P = aPrjPS.Solution();
-
+ if (aPrjPS.IsDone())
+ P = aPrjPS.Solution();
+ else
+ {
+ gp_Pnt thePoint = myCurve->Value(U);
+ Extrema_ExtPS aExtPS(thePoint, mySurface->Surface(), myTolU, myTolV);
+ if (aExtPS.IsDone() && aExtPS.NbExt())
+ {
+ Standard_Integer k, Nend, imin = 1;
+ // Search for the nearest solution which is also a normal projection
+ Nend = aExtPS.NbExt();
+ for(k = 2; k <= Nend; k++)
+ if (aExtPS.SquareDistance(k) < aExtPS.SquareDistance(imin))
+ imin = k;
+ const Extrema_POnSurf& POnS = aExtPS.Point(imin);
+ Standard_Real ParU,ParV;
+ POnS.Parameter(ParU, ParV);
+ P.SetCoord(ParU, ParV);
+ }
+ else
+ P.SetCoord(U0,V0);
+ }
}
//=======================================================================
//function : D1
{
return GeomAbs_OtherCurve;
}
+
+//=======================================================================
+//function : UpdateTripleByTrapCriteria
+//purpose :
+//=======================================================================
+void ProjLib_CompProjectedCurve::UpdateTripleByTrapCriteria(gp_Pnt &thePoint) const
+{
+ Standard_Boolean isProblemsPossible = Standard_False;
+ // Check possible traps cases:
+
+ // 25892 bug.
+ if (mySurface->GetType() == GeomAbs_SurfaceOfRevolution)
+ {
+ // Compute maximal deviation from 3D and choose the biggest one.
+ Standard_Real aVRes = mySurface->VResolution(Precision::Confusion());
+ Standard_Real aMaxTol = Max(Precision::PConfusion(), aVRes);
+
+ if (Abs (thePoint.Z() - mySurface->FirstVParameter()) < aMaxTol ||
+ Abs (thePoint.Z() - mySurface->LastVParameter() ) < aMaxTol )
+ {
+ isProblemsPossible = Standard_True;
+ }
+ }
+
+ // 27135 bug. Trap on degenerated edge.
+ if (mySurface->GetType() == GeomAbs_Sphere &&
+ (Abs (thePoint.Z() - mySurface->FirstVParameter()) < Precision::PConfusion() ||
+ Abs (thePoint.Z() - mySurface->LastVParameter() ) < Precision::PConfusion() ||
+ Abs (thePoint.Y() - mySurface->FirstUParameter()) < Precision::PConfusion() ||
+ Abs (thePoint.Y() - mySurface->LastUParameter() ) < Precision::PConfusion() ))
+ {
+ isProblemsPossible = Standard_True;
+ }
+
+ if (!isProblemsPossible)
+ return;
+
+ Standard_Real U,V;
+ Standard_Boolean isDone =
+ InitialPoint(myCurve->Value(thePoint.X()), thePoint.X(), myCurve, mySurface,
+ Precision::PConfusion(), Precision::PConfusion(), U, V);
+
+ if (!isDone)
+ return;
+
+ // Restore original position in case of period jump.
+ if (mySurface->IsUPeriodic() &&
+ Abs (Abs(U - thePoint.Y()) - mySurface->UPeriod()) < Precision::PConfusion())
+ {
+ U = thePoint.Y();
+ }
+ if (mySurface->IsVPeriodic() &&
+ Abs (Abs(V - thePoint.Z()) - mySurface->VPeriod()) < Precision::PConfusion())
+ {
+ V = thePoint.Z();
+ }
+ thePoint.SetY(U);
+ thePoint.SetZ(V);
+}
+
+//=======================================================================
+//function : BuildCurveSplits
+//purpose :
+//=======================================================================
+void BuildCurveSplits(const Handle(Adaptor3d_HCurve) &theCurve,
+ const Handle(Adaptor3d_HSurface) &theSurface,
+ const Standard_Real theTolU,
+ const Standard_Real theTolV,
+ NCollection_Vector<Standard_Real> &theSplits)
+{
+ SplitDS aDS(theCurve, theSurface, theSplits);
+
+ Extrema_ExtPS anExtPS;
+ anExtPS.Initialize(theSurface->Surface(),
+ theSurface->FirstUParameter(), theSurface->LastUParameter(),
+ theSurface->FirstVParameter(), theSurface->LastVParameter(),
+ theTolU, theTolV);
+ aDS.myExtPS = &anExtPS;
+
+ if (theSurface->IsUPeriodic())
+ {
+ aDS.myPeriodicDir = 0;
+ SplitOnDirection(aDS);
+ }
+ if (theSurface->IsVPeriodic())
+ {
+ aDS.myPeriodicDir = 1;
+ SplitOnDirection(aDS);
+ }
+
+ std::sort(aDS.mySplits.begin(), aDS.mySplits.end(), Comparator);
+}
+
+//=======================================================================
+//function : SplitOnDirection
+//purpose : This method compute points in the parameter space of the curve
+// on which curve should be split since period jump is happen.
+//=======================================================================
+void SplitOnDirection(SplitDS & theSplitDS)
+{
+ // Algorithm:
+ // Create 3D curve which is correspond to the periodic bound in 2d space.
+ // Run curve / curve extrema and run extrema point / surface to check that
+ // the point will be projected to the periodic bound.
+ // In this method assumed that the points cannot be closer to each other that 1% of the parameter space.
+
+ gp_Pnt2d aStartPnt(theSplitDS.mySurface->FirstUParameter(), theSplitDS.mySurface->FirstVParameter());
+ gp_Dir2d aDir(theSplitDS.myPeriodicDir, (Standard_Integer)!theSplitDS.myPeriodicDir);
+
+ theSplitDS.myPerMinParam = !theSplitDS.myPeriodicDir ? theSplitDS.mySurface->FirstUParameter():
+ theSplitDS.mySurface->FirstVParameter();
+ theSplitDS.myPerMaxParam = !theSplitDS.myPeriodicDir ? theSplitDS.mySurface->LastUParameter():
+ theSplitDS.mySurface->LastVParameter();
+ Standard_Real aLast2DParam = theSplitDS.myPeriodicDir ?
+ theSplitDS.mySurface->LastUParameter() - theSplitDS.mySurface->FirstUParameter():
+ theSplitDS.mySurface->LastVParameter() - theSplitDS.mySurface->FirstVParameter();
+
+ // Create line which is represent periodic border.
+ Handle(Geom2d_Curve) aC2GC = new Geom2d_Line(aStartPnt, aDir);
+ Handle(Geom2dAdaptor_HCurve) aC = new Geom2dAdaptor_HCurve(aC2GC, 0, aLast2DParam);
+ Adaptor3d_CurveOnSurface aCOnS(aC, theSplitDS.mySurface);
+
+ Extrema_ExtCC anExtCC;
+ anExtCC.SetCurve(1, aCOnS);
+ anExtCC.SetCurve(2, theSplitDS.myCurve->Curve());
+ anExtCC.SetSingleSolutionFlag(Standard_True); // Search only one solution since multiple invocations are needed.
+ anExtCC.SetRange(1, 0, aLast2DParam);
+ theSplitDS.myExtCC = &anExtCC;
+
+ FindSplitPoint(theSplitDS,
+ theSplitDS.myCurve->FirstParameter(), // Initial curve range.
+ theSplitDS.myCurve->LastParameter());
+}
+
+
+//=======================================================================
+//function : FindSplitPoint
+//purpose :
+//=======================================================================
+void FindSplitPoint(SplitDS &theSplitDS,
+ const Standard_Real theMinParam,
+ const Standard_Real theMaxParam)
+{
+ // Make extrema copy to avoid dependencies between different levels of the recursion.
+ Extrema_ExtCC anExtCC(*theSplitDS.myExtCC);
+ anExtCC.SetRange(2, theMinParam, theMaxParam);
+ anExtCC.Perform();
+
+ if (anExtCC.IsDone())
+ {
+ const Standard_Integer aNbExt = anExtCC.NbExt();
+ for (Standard_Integer anIdx = 1; anIdx <= aNbExt; ++anIdx)
+ {
+ Extrema_POnCurv aPOnC1, aPOnC2;
+ anExtCC.Points(anIdx, aPOnC1, aPOnC2);
+
+ theSplitDS.myExtPS->Perform(aPOnC2.Value());
+ if (!theSplitDS.myExtPS->IsDone())
+ return;
+
+ // Find point with the minimal Euclidean distance to avoid
+ // false positive points detection.
+ Standard_Integer aMinIdx = -1;
+ Standard_Real aMinSqDist = RealLast();
+ const Standard_Integer aNbPext = theSplitDS.myExtPS->NbExt();
+ for(Standard_Integer aPIdx = 1; aPIdx <= aNbPext; ++aPIdx)
+ {
+ const Standard_Real aCurrSqDist = theSplitDS.myExtPS->SquareDistance(aPIdx);
+
+ if (aCurrSqDist < aMinSqDist)
+ {
+ aMinSqDist = aCurrSqDist;
+ aMinIdx = aPIdx;
+ }
+ }
+
+ // Check that is point will be projected to the periodic border.
+ const Extrema_POnSurf &aPOnS = theSplitDS.myExtPS->Point(aMinIdx);
+ Standard_Real U, V, aProjParam;
+ aPOnS.Parameter(U, V);
+ aProjParam = theSplitDS.myPeriodicDir ? V : U;
+
+
+ if (Abs(aProjParam - theSplitDS.myPerMinParam) < Precision::PConfusion() ||
+ Abs(aProjParam - theSplitDS.myPerMaxParam) < Precision::PConfusion() )
+ {
+ const Standard_Real aParam = aPOnC2.Parameter();
+ const Standard_Real aCFParam = theSplitDS.myCurve->FirstParameter();
+ const Standard_Real aCLParam = theSplitDS.myCurve->LastParameter();
+
+ if (aParam > aCFParam + Precision::PConfusion() &&
+ aParam < aCLParam - Precision::PConfusion() )
+ {
+ // Add only inner points.
+ theSplitDS.mySplits.Append(aParam);
+ }
+
+ const Standard_Real aDeltaCoeff = 0.01;
+ const Standard_Real aDelta = (theMaxParam - theMinParam +
+ aCLParam - aCFParam) * aDeltaCoeff;
+
+ if (aParam - aDelta > theMinParam + Precision::PConfusion())
+ {
+ FindSplitPoint(theSplitDS,
+ theMinParam, aParam - aDelta); // Curve parameters.
+ }
+
+ if (aParam + aDelta < theMaxParam - Precision::PConfusion())
+ {
+ FindSplitPoint(theSplitDS,
+ aParam + aDelta, theMaxParam); // Curve parameters.
+ }
+ }
+ } // for (Standard_Integer anIdx = 1; anIdx <= aNbExt; ++anIdx)
+ }
+}