// commercial license or contractual agreement.
+#include <algorithm>
+
#include <Adaptor2d_HCurve2d.hxx>
#include <Adaptor3d_HCurve.hxx>
#include <Adaptor3d_HSurface.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, SearchStep, WalkStep, t;
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;
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);
gp_Vec2d D;
if ((mySurface->IsUPeriodic() &&
- Abs(Usup - Uinf - mySurface->UPeriod()) < Precision::Confusion()) ||
+ Abs(aUppBorder.X() - aLowBorder.X() - mySurface->UPeriod()) < Precision::Confusion()) ||
(mySurface->IsVPeriodic() &&
- Abs(Vsup - Vinf - mySurface->VPeriod()) < Precision::Confusion()))
+ Abs(aUppBorder.Y() - aLowBorder.Y() - mySurface->VPeriod()) < Precision::Confusion()))
{
- if((Abs(U - Uinf) < mySurface->UResolution(Precision::PConfusion())) &&
+ if((Abs(U - aLowBorder.X()) < mySurface->UResolution(Precision::PConfusion())) &&
mySurface->IsUPeriodic())
{
d1(t, U, V, D, myCurve, mySurface);
- if (D.X() < 0 ) U = Usup;
+ if (D.X() < 0 ) U = aUppBorder.X();
}
- else if((Abs(U - Usup) < mySurface->UResolution(Precision::PConfusion())) &&
+ else if((Abs(U - aUppBorder.X()) < mySurface->UResolution(Precision::PConfusion())) &&
mySurface->IsUPeriodic())
{
d1(t, U, V, D, myCurve, mySurface);
- if (D.X() > 0) U = Uinf;
+ if (D.X() > 0) U = aLowBorder.X();
}
- if((Abs(V - Vinf) < mySurface->VResolution(Precision::PConfusion())) &&
+ if((Abs(V - aLowBorder.Y()) < mySurface->VResolution(Precision::PConfusion())) &&
mySurface->IsVPeriodic())
{
d1(t, U, V, D, myCurve, mySurface);
- if (D.Y() < 0) V = Vsup;
+ if (D.Y() < 0) V = aUppBorder.Y();
}
- else if((Abs(V - Vsup) <= mySurface->VResolution(Precision::PConfusion())) &&
+ else if((Abs(V - aUppBorder.Y()) <= mySurface->VResolution(Precision::PConfusion())) &&
mySurface->IsVPeriodic())
{
d1(t, U, V, D, myCurve, mySurface);
- if (D.Y() > 0) V = Vinf;
+ if (D.Y() > 0) V = aLowBorder.Y();
}
}
-
if (myMaxDist > 0)
{
// Here we are going to stop if the distance between projection and
}
if (!new_part) break;
-
//We have found a new continuous part
Handle(TColgp_HSequenceOfPnt) hSeq = new TColgp_HSequenceOfPnt();
mySequence->Append(hSeq);
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)
{
// Check for possible local traps.
UpdateTripleByTrapCriteria(Triple);
+ // Protection from case when the whole curve lies on a seam.
+ if (!isSplitsComputed)
+ {
+ 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;
+ }
+
+ if (isUPossible || isVPossible)
+ {
+ // When point is good conditioned.
+ BuildCurveSplits(myCurve, mySurface, myTolU, myTolV, aSplits);
+ isSplitsComputed = Standard_True;
+ }
+ }
+
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;
Step = WalkStep;
t += Step;
- if (t > (LastU-MinStep/2) )
+ if (t > (LastU-MinStep/2))
{
- Step =Step+LastU-t;
+ Step = Step + LastU - t;
t = LastU;
- }
+ }
+
+ // 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 post-proceeding.
Standard_Integer j;
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)
+ }
+}