1 // Created on: 1995-06-06
2 // Created by: Xavier BENVENISTE
3 // Copyright (c) 1995-1999 Matra Datavision
4 // Copyright (c) 1999-2014 OPEN CASCADE SAS
6 // This file is part of Open CASCADE Technology software library.
8 // This library is free software; you can redistribute it and/or modify it under
9 // the terms of the GNU Lesser General Public License version 2.1 as published
10 // by the Free Software Foundation, with special exception defined in the file
11 // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
12 // distribution for complete text of the license and disclaimer of any warranty.
14 // Alternatively, this file may be used under the terms of Open CASCADE
15 // commercial license or contractual agreement.
17 #include <Approx_SameParameter.hxx>
19 #include <Adaptor2d_Curve2d.hxx>
20 #include <Adaptor3d_CurveOnSurface.hxx>
21 #include <Adaptor3d_Curve.hxx>
22 #include <Adaptor3d_Surface.hxx>
23 #include <Extrema_ExtPC.hxx>
24 #include <Extrema_LocateExtPC.hxx>
25 #include <Geom2d_BSplineCurve.hxx>
26 #include <Geom2d_Curve.hxx>
27 #include <Geom2dAdaptor_Curve.hxx>
28 #include <GeomAdaptor_Curve.hxx>
29 #include <GeomAdaptor_Surface.hxx>
30 #include <GeomLib_MakeCurvefromApprox.hxx>
31 #include <Precision.hxx>
32 #include <TColStd_Array1OfReal.hxx>
33 #include <Geom2dAdaptor.hxx>
35 //=======================================================================
36 //class : Approx_SameParameter_Evaluator
37 //purpose : Used in same parameterization curve approximation.
38 //=======================================================================
39 class Approx_SameParameter_Evaluator : public AdvApprox_EvaluatorFunction
42 Approx_SameParameter_Evaluator (const TColStd_Array1OfReal& theFlatKnots,
43 const TColStd_Array1OfReal& thePoles,
44 const Handle(Adaptor2d_Curve2d)& theHCurve2d)
45 : FlatKnots(theFlatKnots),
47 HCurve2d(theHCurve2d) {}
49 virtual void Evaluate (Standard_Integer *Dimension,
50 Standard_Real StartEnd[2],
51 Standard_Real *Parameter,
52 Standard_Integer *DerivativeRequest,
53 Standard_Real *Result, // [Dimension]
54 Standard_Integer *ErrorCode);
57 const TColStd_Array1OfReal& FlatKnots;
58 const TColStd_Array1OfReal& Poles;
59 Handle(Adaptor2d_Curve2d) HCurve2d;
62 //=======================================================================
65 //=======================================================================
66 void Approx_SameParameter_Evaluator::Evaluate (Standard_Integer *,/*Dimension*/
67 Standard_Real /*StartEnd*/[2],
68 Standard_Real *Parameter,
69 Standard_Integer *DerivativeRequest,
70 Standard_Real *Result,
71 Standard_Integer *ReturnCode)
73 const Standard_Integer aDegree = 3;
74 Standard_Integer extrap_mode[2] = {aDegree, aDegree};
75 Standard_Real eval_result[2];
76 Standard_Real *PolesArray = (Standard_Real *) &Poles(Poles.Lower()) ;
78 // Evaluate the 1D B-Spline that represents the change in parameterization.
79 BSplCLib::Eval(*Parameter,
91 if (*DerivativeRequest == 0)
93 HCurve2d->D0(eval_result[0], aPoint);
94 aPoint.Coord(Result[0],Result[1]);
96 else if (*DerivativeRequest == 1)
98 HCurve2d->D1(eval_result[0], aPoint, aVector);
99 aVector.Multiply(eval_result[1]);
100 aVector.Coord(Result[0],Result[1]);
106 //=======================================================================
107 //function : ProjectPointOnCurve
109 //=======================================================================
110 static void ProjectPointOnCurve(const Standard_Real InitValue,
111 const gp_Pnt& APoint,
112 const Standard_Real Tolerance,
113 const Standard_Integer NumIteration,
114 const Adaptor3d_Curve& Curve,
115 Standard_Boolean& Status,
116 Standard_Real& Result)
118 Standard_Integer num_iter = 0, not_done = 1;
121 gp_Vec vector, d1, d2;
122 Standard_Real func, func_derivative,
124 Status = Standard_False;
128 Curve.D2(param, a_point, d1, d2);
129 vector = gp_Vec(a_point,APoint);
131 func = vector.Dot(d1);
132 if ( Abs(func) < Tolerance * d1.Magnitude())
135 Status = Standard_True;
139 func_derivative = vector.Dot(d2) - d1.Dot(d1);
141 // Avoid division by zero.
142 const Standard_Real Toler = 1.0e-12;
143 if( Abs(func_derivative) > Toler )
144 param -= func / func_derivative;
146 param = Max(param,Curve.FirstParameter());
147 param = Min(param,Curve.LastParameter());
149 } while (not_done && num_iter <= NumIteration);
154 //=======================================================================
155 //function : ComputeTolReached
157 //=======================================================================
158 static Standard_Real ComputeTolReached(const Handle(Adaptor3d_Curve)& c3d,
159 const Adaptor3d_CurveOnSurface& cons,
160 const Standard_Integer nbp)
162 Standard_Real d2 = 0.0; // Square max discrete deviation.
163 const Standard_Real first = c3d->FirstParameter();
164 const Standard_Real last = c3d->LastParameter();
165 for(Standard_Integer i = 0; i <= nbp; i++)
167 Standard_Real t = IntToReal(i) / IntToReal(nbp);
168 Standard_Real u = first * (1.0 - t) + last * t;
172 Pc3d = c3d->Value(u);
173 Pcons = cons.Value(u);
175 catch (Standard_Failure const&)
177 d2 = Precision::Infinite();
180 if (Precision::IsInfinite(Pcons.X()) ||
181 Precision::IsInfinite(Pcons.Y()) ||
182 Precision::IsInfinite(Pcons.Z()))
184 d2=Precision::Infinite();
187 d2 = Max(d2, Pc3d.SquareDistance(Pcons));
190 const Standard_Real aMult = 1. + 0.05; //
191 Standard_Real aDeviation = aMult * sqrt(d2);
192 aDeviation = Max(aDeviation, Precision::Confusion()); // Tolerance in modeling space.
196 //=======================================================================
198 //purpose : Check current interpolation for validity.
199 //=======================================================================
200 static Standard_Boolean Check(const TColStd_Array1OfReal& FlatKnots,
201 const TColStd_Array1OfReal& Poles,
202 const Standard_Integer nbp,
203 const Standard_Real *pc3d,
204 const Handle(Adaptor3d_Curve)& c3d,
205 const Adaptor3d_CurveOnSurface& cons,
207 const Standard_Real oldtol)
209 const Standard_Integer aDegree = 3;
210 Standard_Integer extrap_mode[2] = {aDegree, aDegree};
212 // Correction of the interval of valid values. This condition has no sensible
213 // grounds. But it is better then the old one (which is commented out) because
214 // it fixes the bug OCC5898. To develop more or less sensible criterion it is
215 // necessary to deeply investigate this problem which is not possible in frames
217 Standard_Real aParamFirst = 3.0 * pc3d[0] - 2.0 * pc3d[nbp - 1];
218 Standard_Real aParamLast = 3.0 * pc3d[nbp - 1] - 2.0 * pc3d[0];
220 Standard_Real FirstPar = cons.FirstParameter();
221 Standard_Real LastPar = cons.LastParameter();
222 if (aParamFirst < FirstPar)
223 aParamFirst = FirstPar;
224 if (aParamLast > LastPar)
225 aParamLast = LastPar;
227 Standard_Real d2 = 0.0; // Maximum square deviation on the samples.
228 const Standard_Real d = tol;
229 const Standard_Integer nn = 2 * nbp;
230 const Standard_Real unsurnn = 1.0 / nn;
231 Standard_Real tprev = aParamFirst;
232 for(Standard_Integer i = 0; i <= nn; i++)
234 // Compute corresponding parameter on 2d curve.
235 // It should be inside of 3d curve parameter space.
236 Standard_Real t = unsurnn*i;
237 Standard_Real tc3d = pc3d[0]*(1.0 - t) + pc3d[nbp - 1] * t; // weight function.
238 gp_Pnt Pc3d = c3d->Value(tc3d);
240 BSplCLib::Eval(tc3d, Standard_False, 0, extrap_mode[0],
241 aDegree, FlatKnots, 1, (Standard_Real&)Poles(1), tcons);
246 tol = Precision::Infinite();
247 return Standard_False;
250 gp_Pnt Pcons = cons.Value(tcons);
251 Standard_Real temp = Pc3d.SquareDistance(Pcons);
252 if(temp > d2) d2 = temp;
256 // Check poles parameters to be ordered.
257 for(Standard_Integer i = Poles.Lower() + 1; i <= Poles.Upper(); ++i)
259 const Standard_Real aPreviousParam = Poles(i - 1);
260 const Standard_Real aCurrentParam = Poles(i);
262 if (aPreviousParam > aCurrentParam)
263 return Standard_False;
266 return (tol <= d || tol > 0.8 * oldtol);
269 //=======================================================================
270 //function : Approx_SameParameter
272 //=======================================================================
273 Approx_SameParameter::Approx_SameParameter(const Handle(Geom_Curve)& C3D,
274 const Handle(Geom2d_Curve)& C2D,
275 const Handle(Geom_Surface)& S,
276 const Standard_Real Tol)
277 : myDeltaMin(Precision::PConfusion()),
278 mySameParameter(Standard_True),
279 myDone(Standard_False)
281 myHCurve2d = new Geom2dAdaptor_Curve(C2D);
282 myC3d = new GeomAdaptor_Curve(C3D);
283 mySurf = new GeomAdaptor_Surface(S);
287 //=======================================================================
288 //function : Approx_SameParameter
290 //=======================================================================
291 Approx_SameParameter::Approx_SameParameter(const Handle(Adaptor3d_Curve)& C3D,
292 const Handle(Geom2d_Curve)& C2D,
293 const Handle(Adaptor3d_Surface)& S,
294 const Standard_Real Tol)
295 : myDeltaMin(Precision::PConfusion()),
296 mySameParameter(Standard_True),
297 myDone(Standard_False)
301 myHCurve2d = new Geom2dAdaptor_Curve(C2D);
305 //=======================================================================
306 //function : Approx_SameParameter
308 //=======================================================================
309 Approx_SameParameter::Approx_SameParameter(const Handle(Adaptor3d_Curve)& C3D,
310 const Handle(Adaptor2d_Curve2d)& C2D,
311 const Handle(Adaptor3d_Surface)& S,
312 const Standard_Real Tol)
313 : myDeltaMin(Precision::PConfusion()),
314 mySameParameter(Standard_True),
315 myDone(Standard_False)
323 //=======================================================================
326 //=======================================================================
327 void Approx_SameParameter::Build(const Standard_Real Tolerance)
330 // 1) Build initial distribution. Increase number of samples in case of C0 continuity.
331 // 2.1) Check same parameter state on samples.
332 // 2.2) Compute parameters in 2d space if not same parameter.
333 // 3) Loop over poles number and try to interpolate 2d curve.
334 // 4) If loop is failed build 2d curve forcibly or use original pcurve.
335 Standard_Real qpcons[myMaxArraySize], qnewpcons[myMaxArraySize],
336 qpc3d[myMaxArraySize], qnewpc3d[myMaxArraySize];
338 // Create and fill data structure.
339 Approx_SameParameter_Data aData;
340 aData.myCOnS = Adaptor3d_CurveOnSurface(myHCurve2d,mySurf);
341 aData.myC2dPF = aData.myCOnS.FirstParameter();
342 aData.myC2dPL = aData.myCOnS.LastParameter();
343 aData.myC3dPF = myC3d->FirstParameter();
344 aData.myC3dPL = myC3d->LastParameter();
345 aData.myNbPnt = 0; // No points initially.
346 aData.myPC2d = qpcons;
347 aData.myPC3d = qpc3d;
348 aData.myNewPC2d = qnewpcons;
349 aData.myNewPC3d = qnewpc3d;
350 aData.myTol = Tolerance;
352 // Build initial distribution.
353 if (!BuildInitialDistribution(aData))
355 mySameParameter = Standard_False;
356 myDone = Standard_False;
360 // Check same parameter state on distribution.
361 Standard_Real aMaxSqDeviation = 0.0;
362 const Standard_Real aPercentOfBadProj = 0.3;
363 Standard_Integer aNbPnt = aData.myNbPnt - RealToInt(aPercentOfBadProj * aData.myNbPnt);
364 mySameParameter = CheckSameParameter(aData, aMaxSqDeviation);
367 myTolReached = ComputeTolReached(myC3d, aData.myCOnS, 2 * myNbSamples);
368 myDone = Standard_True;
373 // Control number of sample points after checking sameparameter
374 // If number of points is less then initial one, it means that there are
375 // problems with projection
376 if(aData.myNbPnt < aNbPnt )
378 myTolReached = ComputeTolReached(myC3d,aData.myCOnS, 2 * myNbSamples);
379 myCurve2d = Geom2dAdaptor::MakeCurve (*myHCurve2d);
380 myDone = Standard_False;
385 // Control tangents at the extremities to know if the
386 // reparametring is possible and calculate the tangents
387 // at the extremities of the function of change of variable.
388 Standard_Real tangent[2] = { 0.0, 0.0 };
389 if(!ComputeTangents(aData.myCOnS, tangent[0], tangent[1]))
391 // Cannot compute tangents.
392 mySameParameter = Standard_False;
393 myDone = Standard_False;
394 myTolReached = ComputeTolReached(myC3d, aData.myCOnS, 2 * myNbSamples);
398 // There is at least one point where same parameter is broken.
399 // Try to build B-spline approximation curve using interpolation with degree 3.
400 // The loop is organized over number of poles.
401 GeomAbs_Shape aContinuity = myHCurve2d->Continuity();
402 if(aContinuity > GeomAbs_C1) aContinuity = GeomAbs_C1;
404 Standard_Real besttol2 = aData.myTol * aData.myTol,
405 tolsov = Precision::Infinite();
406 Standard_Boolean interpolok = Standard_False,
407 hasCountChanged = Standard_False;
410 // Interpolation data.
411 Standard_Integer num_knots = aData.myNbPnt + 7;
412 Standard_Integer num_poles = aData.myNbPnt + 3;
413 TColStd_Array1OfReal Poles(1, num_poles);
414 TColStd_Array1OfReal FlatKnots(1 ,num_knots);
416 if (!Interpolate(aData, tangent[0], tangent[1], Poles, FlatKnots))
418 // Interpolation fails.
419 mySameParameter = Standard_False;
420 myDone = Standard_False;
421 myTolReached = ComputeTolReached(myC3d, aData.myCOnS, 2 * myNbSamples);
425 Standard_Real algtol = sqrt(besttol2);
426 interpolok = Check (FlatKnots, Poles, aData.myNbPnt+1, aData.myPC3d,
427 myC3d, aData.myCOnS, algtol, tolsov);
430 // Try to build 2d curve and check it for validity.
433 Standard_Real besttol = sqrt(besttol2);
435 Handle(TColStd_HArray1OfReal) tol1d,tol2d,tol3d;
436 tol1d = new TColStd_HArray1OfReal(1,2);
437 tol1d->SetValue(1, mySurf->UResolution(besttol));
438 tol1d->SetValue(2, mySurf->VResolution(besttol));
440 Approx_SameParameter_Evaluator ev (FlatKnots, Poles, myHCurve2d);
441 Standard_Integer aMaxDeg = 11, aMaxSeg = 1000;
442 AdvApprox_ApproxAFunction anApproximator(2,0,0,tol1d,tol2d,tol3d,aData.myC3dPF,aData.myC3dPL,
443 aContinuity,aMaxDeg,aMaxSeg,ev);
445 if (anApproximator.IsDone() || anApproximator.HasResult())
447 Adaptor3d_CurveOnSurface ACS = aData.myCOnS;
448 GeomLib_MakeCurvefromApprox aCurveBuilder(anApproximator);
449 Handle(Geom2d_BSplineCurve) aC2d = aCurveBuilder.Curve2dFromTwo1d(1,2);
450 Handle(Adaptor2d_Curve2d) aHCurve2d = new Geom2dAdaptor_Curve(aC2d);
451 aData.myCOnS.Load(aHCurve2d);
452 myTolReached = ComputeTolReached(myC3d,aData.myCOnS, 2 * myNbSamples);
454 const Standard_Real aMult = 250.0; // To be tolerant with discrete tolerance.
455 if (myTolReached < aMult * besttol )
458 myHCurve2d = aHCurve2d;
459 myDone = Standard_True;
462 else if(aData.myNbPnt < myMaxArraySize - 1)
464 interpolok = Standard_False;
475 hasCountChanged = IncreaseNbPoles(Poles, FlatKnots, aData, besttol2);
477 } while(!interpolok && hasCountChanged);
481 // Loop is finished unsuccessfully. Fix tolerance by maximal deviation,
482 // using data from the last loop iteration or initial data. Use data set with minimal deflection.
484 // Original 2d curve.
485 aData.myCOnS.Load(myHCurve2d);
486 myTolReached = ComputeTolReached(myC3d,aData.myCOnS, 2 * myNbSamples);
487 myCurve2d = Geom2dAdaptor::MakeCurve (*myHCurve2d);
489 // Approximation curve.
490 Standard_Integer num_knots = aData.myNbPnt + 7;
491 Standard_Integer num_poles = aData.myNbPnt + 3;
492 TColStd_Array1OfReal Poles(1, num_poles);
493 TColStd_Array1OfReal FlatKnots(1 ,num_knots);
495 Interpolate(aData, tangent[0], tangent[1],
498 Standard_Real besttol = sqrt(besttol2);
499 Handle(TColStd_HArray1OfReal) tol1d,tol2d,tol3d;
500 tol1d = new TColStd_HArray1OfReal(1,2) ;
501 tol1d->SetValue(1, mySurf->UResolution(besttol));
502 tol1d->SetValue(2, mySurf->VResolution(besttol));
504 Approx_SameParameter_Evaluator ev(FlatKnots, Poles, myHCurve2d);
505 AdvApprox_ApproxAFunction anApproximator(2,0,0,tol1d,tol2d,tol3d,aData.myC3dPF,aData.myC3dPL,
506 aContinuity,11,40,ev);
508 if (!anApproximator.IsDone() &&
509 !anApproximator.HasResult() )
511 myDone = Standard_False;
515 GeomLib_MakeCurvefromApprox aCurveBuilder(anApproximator);
516 Handle(Geom2d_BSplineCurve) aC2d = aCurveBuilder.Curve2dFromTwo1d(1,2);
517 Handle(Adaptor2d_Curve2d) aHCurve2d = new Geom2dAdaptor_Curve(aC2d);
518 aData.myCOnS.Load(aHCurve2d);
520 Standard_Real anApproxTol = ComputeTolReached(myC3d,aData.myCOnS,2 * myNbSamples);
521 if (anApproxTol < myTolReached)
523 myTolReached = anApproxTol;
525 myHCurve2d = aHCurve2d;
527 myDone = Standard_True;
530 myCurveOnSurface = Handle(Adaptor3d_CurveOnSurface)::DownCast(aData.myCOnS.ShallowCopy());
533 //=======================================================================
534 //function : BuildInitialDistribution
535 //purpose : Sub-method in Build.
536 //=======================================================================
537 Standard_Boolean Approx_SameParameter::BuildInitialDistribution(Approx_SameParameter_Data &theData) const
539 // Take a multiple of the sample pof CheckShape,
540 // at least the control points will be correct.
541 // Take parameters with constant step on the curve on surface
543 const Standard_Real deltacons = (theData.myC2dPL - theData.myC2dPF) / myNbSamples;
544 const Standard_Real deltac3d = (theData.myC3dPL - theData.myC3dPF) / myNbSamples;
545 Standard_Real wcons = theData.myC2dPF;
546 Standard_Real wc3d = theData.myC3dPF;
547 for (Standard_Integer ii = 0 ; ii < myNbSamples; ii++)
549 theData.myPC2d[ii] = wcons;
550 theData.myPC3d[ii] = wc3d;
554 theData.myNbPnt = myNbSamples;
555 theData.myPC2d[theData.myNbPnt] = theData.myC2dPL;
556 theData.myPC3d[theData.myNbPnt] = theData.myC3dPL;
558 // Change number of points in case of C0 continuity.
559 GeomAbs_Shape Continuity = myHCurve2d->Continuity();
560 if(Continuity < GeomAbs_C1)
562 if (!IncreaseInitialNbSamples(theData))
564 // Number of samples is too big.
565 return Standard_False;
569 return Standard_True;
572 //=======================================================================
573 //function : IncreaseInitialNbSamples
574 //purpose : Get number of C1 intervals and build new distribution on them.
575 // Sub-method in BuildInitialDistribution.
576 //=======================================================================
577 Standard_Boolean Approx_SameParameter::IncreaseInitialNbSamples(Approx_SameParameter_Data &theData) const
579 Standard_Integer NbInt = myHCurve2d->NbIntervals(GeomAbs_C1) + 1;
580 TColStd_Array1OfReal aC1Intervals (1, NbInt);
581 myHCurve2d->Intervals(aC1Intervals, GeomAbs_C1);
583 Standard_Integer inter = 1;
584 while(inter <= NbInt && aC1Intervals(inter) <= theData.myC3dPF + myDeltaMin) inter++;
585 while(NbInt > 0 && aC1Intervals(NbInt) >= theData.myC3dPL - myDeltaMin) NbInt--;
587 // Compute new parameters.
588 TColStd_SequenceOfReal aNewPar;
589 aNewPar.Append(theData.myC3dPF);
590 Standard_Integer ii = 1;
591 while(inter <= NbInt || (ii < myNbSamples && inter <= aC1Intervals.Length()) )
593 if(aC1Intervals(inter) < theData.myPC2d[ii])
595 aNewPar.Append(aC1Intervals(inter));
596 if((theData.myPC2d[ii] - aC1Intervals(inter)) <= myDeltaMin)
608 if((aC1Intervals(inter) - theData.myPC2d[ii]) > myDeltaMin)
610 aNewPar.Append(theData.myPC2d[ii]);
615 // Simple protection if theNewNbPoints > allocated elements in array but one
616 // myMaxArraySize - 1 index may be filled after projection.
617 theData.myNbPnt = aNewPar.Length();
618 if (theData.myNbPnt > myMaxArraySize - 1)
620 return Standard_False;
623 for(ii = 1; ii < theData.myNbPnt; ii++)
625 // Copy only internal points.
626 theData.myPC2d[ii] = theData.myPC3d[ii] = aNewPar.Value(ii + 1);
628 theData.myPC3d[theData.myNbPnt] = theData.myC3dPL;
629 theData.myPC2d[theData.myNbPnt] = theData.myC2dPL;
631 return Standard_True;
634 //=======================================================================
635 //function : CheckSameParameter
636 //purpose : Sub-method in Build.
637 //=======================================================================
638 Standard_Boolean Approx_SameParameter::CheckSameParameter(Approx_SameParameter_Data &theData,
639 Standard_Real &theSqDist) const
641 const Standard_Real Tol2 = theData.myTol * theData.myTol;
642 Standard_Boolean isSameParam = Standard_True;
644 // Compute initial distance on boundary points.
646 theData.myCOnS.D0(theData.myC2dPF, Pcons);
647 myC3d->D0(theData.myC3dPF, Pc3d);
648 Standard_Real dist2 = Pcons.SquareDistance(Pc3d);
649 Standard_Real dmax2 = dist2;
651 theData.myCOnS.D0(theData.myC2dPL, Pcons);
652 myC3d->D0(theData.myC3dPL, Pc3d);
653 dist2 = Pcons.SquareDistance(Pc3d);
654 dmax2 = Max(dmax2, dist2);
656 Extrema_LocateExtPC Projector;
657 Projector.Initialize (*myC3d, theData.myC3dPF, theData.myC3dPL, theData.myTol);
659 Standard_Integer count = 1;
660 Standard_Real previousp = theData.myC3dPF, initp=0, curp;
661 Standard_Real bornesup = theData.myC3dPL - myDeltaMin;
662 Standard_Boolean isProjOk = Standard_False;
663 for (Standard_Integer ii = 1; ii < theData.myNbPnt; ii++)
665 theData.myCOnS.D0(theData.myPC2d[ii],Pcons);
666 myC3d->D0(theData.myPC3d[ii],Pc3d);
667 dist2 = Pcons.SquareDistance(Pc3d);
669 // Same parameter point.
670 Standard_Boolean isUseParam = (dist2 <= Tol2 && // Good distance.
671 (theData.myPC3d[ii] > theData.myPC3d[count-1] + myDeltaMin)); // Point is separated from previous.
676 initp = previousp = theData.myPC3d[count] = theData.myPC3d[ii];
677 theData.myPC2d[count] = theData.myPC2d[ii];
682 // Local search: local extrema and iterative projection algorithm.
684 initp = theData.myPC3d[ii];
685 isProjOk = isSameParam = Standard_False;
686 Projector.Perform(Pcons, initp);
687 if (Projector.IsDone())
689 // Local extrema is found.
690 curp = Projector.Point().Parameter();
691 isProjOk = Standard_True;
695 ProjectPointOnCurve(initp,Pcons,theData.myTol,30, *myC3d,isProjOk,curp);
697 isProjOk = isProjOk && // Good projection.
698 curp > previousp + myDeltaMin && // Point is separated from previous.
699 curp < bornesup; // Inside of parameter space.
702 initp = previousp = theData.myPC3d[count] = curp;
703 theData.myPC2d[count] = theData.myPC2d[ii];
708 // Whole parameter space search using general extrema.
709 Extrema_ExtPC PR(Pcons, *myC3d, theData.myC3dPF, theData.myC3dPL, theData.myTol);
710 if (!PR.IsDone() || PR.NbExt() == 0) // Lazy evaluation is used.
713 const Standard_Integer aNbExt = PR.NbExt();
714 Standard_Integer anIndMin = 0;
715 Standard_Real aCurDistMin = RealLast();
716 for(Standard_Integer i = 1; i <= aNbExt; i++)
718 const gp_Pnt &aP = PR.Point(i).Value();
719 Standard_Real aDist2 = aP.SquareDistance(Pcons);
720 if(aDist2 < aCurDistMin)
722 aCurDistMin = aDist2;
728 curp = PR.Point(anIndMin).Parameter();
729 if( curp > previousp + myDeltaMin && curp < bornesup)
731 initp = previousp = theData.myPC3d[count] = curp;
732 theData.myPC2d[count] = theData.myPC2d[ii];
734 isProjOk = Standard_True;
738 theData.myNbPnt = count;
739 theData.myPC2d[theData.myNbPnt] = theData.myC2dPL;
740 theData.myPC3d[theData.myNbPnt] = theData.myC3dPL;
746 //=======================================================================
747 //function : ComputeTangents
748 //purpose : Sub-method in Build.
749 //=======================================================================
750 Standard_Boolean Approx_SameParameter::ComputeTangents(const Adaptor3d_CurveOnSurface & theCOnS,
751 Standard_Real &theFirstTangent,
752 Standard_Real &theLastTangent) const
754 const Standard_Real aSmallMagnitude = 1.0e-12;
755 // Check tangency on curve border.
756 gp_Pnt aPnt, aPntCOnS;
757 gp_Vec aVec, aVecConS;
760 const Standard_Real aParamFirst = myC3d->FirstParameter();
761 theCOnS.D1(aParamFirst, aPntCOnS, aVecConS);
762 myC3d->D1(aParamFirst, aPnt, aVec);
763 Standard_Real aMagnitude = aVecConS.Magnitude();
764 if (aMagnitude > aSmallMagnitude)
765 theFirstTangent = aVec.Magnitude() / aMagnitude;
767 return Standard_False;
770 const Standard_Real aParamLast = myC3d->LastParameter();
771 theCOnS.D1(aParamLast,aPntCOnS,aVecConS);
772 myC3d->D1(aParamLast, aPnt, aVec);
774 aMagnitude = aVecConS.Magnitude();
775 if (aMagnitude > aSmallMagnitude)
776 theLastTangent = aVec.Magnitude() / aMagnitude;
778 return Standard_False;
780 return Standard_True;
783 //=======================================================================
784 //function : Interpolate
785 //purpose : Sub-method in Build.
786 //=======================================================================
787 Standard_Boolean Approx_SameParameter::Interpolate(const Approx_SameParameter_Data & theData,
788 const Standard_Real aTangFirst,
789 const Standard_Real aTangLast,
790 TColStd_Array1OfReal & thePoles,
791 TColStd_Array1OfReal & theFlatKnots) const
793 Standard_Integer num_poles = theData.myNbPnt + 3;
794 TColStd_Array1OfInteger ContactOrder(1,num_poles);
795 TColStd_Array1OfReal aParameters(1, num_poles);
797 // Fill tables taking attention to end values.
798 ContactOrder.Init(0);
799 ContactOrder(2) = ContactOrder(num_poles - 1) = 1;
801 theFlatKnots(1) = theFlatKnots(2) = theFlatKnots(3) = theFlatKnots(4) = theData.myC3dPF;
802 theFlatKnots(num_poles + 1) = theFlatKnots(num_poles + 2) =
803 theFlatKnots(num_poles + 3) = theFlatKnots(num_poles + 4) = theData.myC3dPL;
805 thePoles(1) = theData.myC2dPF; thePoles(num_poles) = theData.myC2dPL;
806 thePoles(2) = aTangFirst; thePoles(num_poles - 1) = aTangLast;
808 aParameters(1) = aParameters(2) = theData.myC3dPF;
809 aParameters(num_poles - 1) = aParameters(num_poles) = theData.myC3dPL;
811 for (Standard_Integer ii = 3; ii <= num_poles - 2; ii++)
813 thePoles(ii) = theData.myPC2d[ii - 2];
814 aParameters(ii) = theFlatKnots(ii+2) = theData.myPC3d[ii - 2];
816 Standard_Integer inversion_problem;
817 BSplCLib::Interpolate(3,theFlatKnots,aParameters,ContactOrder,
818 1,thePoles(1),inversion_problem);
819 if(inversion_problem)
821 return Standard_False;
824 return Standard_True;
827 //=======================================================================
828 //function : IncreaseNbPoles
829 //purpose : Sub-method in Build.
830 //=======================================================================
831 Standard_Boolean Approx_SameParameter::IncreaseNbPoles(const TColStd_Array1OfReal & thePoles,
832 const TColStd_Array1OfReal & theFlatKnots,
833 Approx_SameParameter_Data & theData,
834 Standard_Real &theBestSqTol) const
836 Extrema_LocateExtPC Projector;
837 Projector.Initialize (*myC3d, myC3d->FirstParameter(), myC3d->LastParameter(), theData.myTol);
838 Standard_Real curp = 0.0;
839 Standard_Boolean projok = Standard_False;
841 // Project middle point to fix parameterization and check projection existence.
842 const Standard_Integer aDegree = 3;
843 const Standard_Integer DerivativeRequest = 0;
844 Standard_Integer extrap_mode[2] = {aDegree, aDegree};
845 Standard_Real eval_result;
846 Standard_Real *PolesArray = (Standard_Real *) &thePoles(thePoles.Lower());
847 Standard_Integer newcount = 0;
848 for (Standard_Integer ii = 0; ii < theData.myNbPnt; ii++)
850 theData.myNewPC2d[newcount] = theData.myPC2d[ii];
851 theData.myNewPC3d[newcount] = theData.myPC3d[ii];
854 if(theData.myNbPnt - ii + newcount == myMaxArraySize) continue;
856 BSplCLib::Eval(0.5*(theData.myPC3d[ii]+theData.myPC3d[ii+1]), Standard_False, DerivativeRequest,
857 extrap_mode[0], 3, theFlatKnots, 1, PolesArray[0], eval_result);
859 if(eval_result < theData.myPC2d[ii] || eval_result > theData.myPC2d[ii+1])
861 Standard_Real ucons = 0.5*(theData.myPC2d[ii]+theData.myPC2d[ii+1]);
862 Standard_Real uc3d = 0.5*(theData.myPC3d[ii]+theData.myPC3d[ii+1]);
865 theData.myCOnS.D0(ucons,Pcons);
866 Projector.Perform(Pcons, uc3d);
867 if (Projector.IsDone())
869 curp = Projector.Point().Parameter();
870 Standard_Real dist_2 = Projector.SquareDistance();
871 if(dist_2 > theBestSqTol) theBestSqTol = dist_2;
876 ProjectPointOnCurve(uc3d,Pcons,theData.myTol,30, *myC3d,projok,curp);
880 if(curp > theData.myPC3d[ii] + myDeltaMin && curp < theData.myPC3d[ii+1] - myDeltaMin)
882 theData.myNewPC3d[newcount] = curp;
883 theData.myNewPC2d[newcount] = ucons;
888 } // for (ii = 0; ii < count; ii++)
889 theData.myNewPC3d[newcount] = theData.myPC3d[theData.myNbPnt];
890 theData.myNewPC2d[newcount] = theData.myPC2d[theData.myNbPnt];
892 if((theData.myNbPnt != newcount) && newcount < myMaxArraySize - 1)
894 // Distribution is changed.
895 theData.Swap(newcount);
896 return Standard_True;
899 // Increase number of samples in two times.
901 for(Standard_Integer n = 0; n < theData.myNbPnt; n++)
903 theData.myNewPC3d[newcount] = theData.myPC3d[n];
904 theData.myNewPC2d[newcount] = theData.myPC2d[n];
907 if(theData.myNbPnt - n + newcount == myMaxArraySize) continue;
909 Standard_Real ucons = 0.5*(theData.myPC2d[n]+theData.myPC2d[n+1]);
910 Standard_Real uc3d = 0.5*(theData.myPC3d[n]+theData.myPC3d[n+1]);
913 theData.myCOnS.D0(ucons,Pcons);
914 Projector.Perform(Pcons, uc3d);
915 if (Projector.IsDone())
917 curp = Projector.Point().Parameter();
918 Standard_Real dist_2 = Projector.SquareDistance();
919 if(dist_2 > theBestSqTol) theBestSqTol = dist_2;
924 ProjectPointOnCurve(uc3d,Pcons,theData.myTol,30, *myC3d,projok,curp);
928 if(curp > theData.myPC3d[n] + myDeltaMin && curp < theData.myPC3d[n+1] - myDeltaMin)
930 theData.myNewPC3d[newcount] = curp;
931 theData.myNewPC2d[newcount] = ucons;
936 theData.myNewPC3d[newcount] = theData.myPC3d[theData.myNbPnt];
937 theData.myNewPC2d[newcount] = theData.myPC2d[theData.myNbPnt];
939 if(theData.myNbPnt != newcount)
941 // Distribution is changed.
942 theData.Swap(newcount);
943 return Standard_True;
946 return Standard_False;