1 // Created on: 1993-03-30
2 // Created by: Laurent BUCHARD
3 // Copyright (c) 1993-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 <AppParCurves_Constraint.hxx>
18 #include <GeomAbs_SurfaceType.hxx>
19 #include <IntSurf_Quadric.hxx>
20 #include <gp_Trsf.hxx>
21 #include <gp_Trsf2d.hxx>
22 #include <IntSurf_PntOn2S.hxx>
23 #include <Precision.hxx>
24 #include <ApproxInt_KnotTools.hxx>
26 // If quantity of points is less than aMinNbPointsForApprox
27 // then interpolation is used.
28 const Standard_Integer aMinNbPointsForApprox = 5;
30 // This constant should be removed in the future.
31 const Standard_Real RatioTol = 1.5 ;
33 //=======================================================================
34 //function : ComputeTrsf3d
36 //=======================================================================
37 static void ComputeTrsf3d(const Handle(TheWLine)& theline,
42 const Standard_Integer aNbPnts = theline->NbPnts();
43 Standard_Real aXmin = RealLast(), aYmin = RealLast(), aZmin = RealLast();
44 for(Standard_Integer i=1;i<=aNbPnts;i++)
46 const gp_Pnt& P = theline->Point(i).Value();
47 aXmin = Min(P.X(), aXmin);
48 aYmin = Min(P.Y(), aYmin);
49 aZmin = Min(P.Z(), aZmin);
57 //=======================================================================
58 //function : ComputeTrsf2d
60 //=======================================================================
61 static void ComputeTrsf2d(const Handle(TheWLine)& theline,
62 const Standard_Boolean onFirst,
66 const Standard_Integer aNbPnts = theline->NbPnts();
67 Standard_Real aUmin = RealLast(), aVmin = RealLast();
69 // pointer to a member-function
70 void (IntSurf_PntOn2S::* pfunc)(Standard_Real&,Standard_Real&) const;
73 pfunc = &IntSurf_PntOn2S::ParametersOnS1;
75 pfunc = &IntSurf_PntOn2S::ParametersOnS2;
77 for(Standard_Integer i=1; i<=aNbPnts; i++)
79 const IntSurf_PntOn2S& POn2S = theline->Point(i);
82 aUmin = Min(U, aUmin);
83 aVmin = Min(V, aVmin);
90 //=======================================================================
91 //function : Parameters
93 //=======================================================================
94 static void Parameters(const ApproxInt_TheMultiLine& Line,
95 const Standard_Integer firstP,
96 const Standard_Integer lastP,
97 const Approx_ParametrizationType Par,
98 math_Vector& TheParameters)
100 Standard_Integer i, j, nbP2d, nbP3d;
105 if (Par == Approx_ChordLength || Par == Approx_Centripetal) {
106 nbP3d = ApproxInt_TheMultiLineTool::NbP3d(Line);
107 nbP2d = ApproxInt_TheMultiLineTool::NbP2d(Line);
108 Standard_Integer mynbP3d=nbP3d, mynbP2d=nbP2d;
109 if (nbP3d == 0) mynbP3d = 1;
110 if (nbP2d == 0) mynbP2d = 1;
112 TheParameters(firstP) = 0.0;
114 TColgp_Array1OfPnt tabP(1, mynbP3d);
115 TColgp_Array1OfPnt tabPP(1, mynbP3d);
116 TColgp_Array1OfPnt2d tabP2d(1, mynbP2d);
117 TColgp_Array1OfPnt2d tabPP2d(1, mynbP2d);
119 for (i = firstP+1; i <= lastP; i++) {
120 if (nbP3d != 0 && nbP2d != 0) ApproxInt_TheMultiLineTool::Value(Line, i-1, tabP, tabP2d);
121 else if (nbP2d != 0) ApproxInt_TheMultiLineTool::Value(Line, i-1, tabP2d);
122 else if (nbP3d != 0) ApproxInt_TheMultiLineTool::Value(Line, i-1, tabP);
124 if (nbP3d != 0 && nbP2d != 0) ApproxInt_TheMultiLineTool::Value(Line, i, tabPP, tabPP2d);
125 else if (nbP2d != 0) ApproxInt_TheMultiLineTool::Value(Line, i, tabPP2d);
126 else if (nbP3d != 0) ApproxInt_TheMultiLineTool::Value(Line, i, tabPP);
128 for (j = 1; j <= nbP3d; j++) {
131 dist += P2.Distance(P1);
133 for (j = 1; j <= nbP2d; j++) {
136 dist += P22d.Distance(P12d);
138 if(Par == Approx_ChordLength)
139 TheParameters(i) = TheParameters(i-1) + dist;
140 else {// Par == Approx_Centripetal
141 TheParameters(i) = TheParameters(i-1) + Sqrt(dist);
144 for (i = firstP; i <= lastP; i++) TheParameters(i) /= TheParameters(lastP);
147 for (i = firstP; i <= lastP; i++) {
148 TheParameters(i) = (Standard_Real(i)-firstP)/
149 (Standard_Real(lastP)-Standard_Real(firstP));
154 //=======================================================================
155 //function : Default constructor
157 //=======================================================================
158 ApproxInt_Approx::ApproxInt_Approx():
159 myComputeLine(4, 8, 0.001, 0.001, 5),
160 myComputeLineBezier(4, 8, 0.001, 0.001, 5),
161 myWithTangency(Standard_True),
170 myComputeLine.SetContinuity(2);
171 //myComputeLineBezier.SetContinuity(2);
174 //=======================================================================
176 //purpose : Build without surfaces information.
177 //=======================================================================
178 void ApproxInt_Approx::Perform(const Handle(TheWLine)& theline,
179 const Standard_Boolean ApproxXYZ,
180 const Standard_Boolean ApproxU1V1,
181 const Standard_Boolean ApproxU2V2,
182 const Standard_Integer indicemin,
183 const Standard_Integer indicemax)
186 prepareDS(ApproxXYZ, ApproxU1V1, ApproxU2V2, indicemin, indicemax);
188 const Standard_Integer nbpntbez = myData.indicemax - myData.indicemin;
189 if(nbpntbez < aMinNbPointsForApprox)
190 myData.myBezierApprox = Standard_False;
192 myData.myBezierApprox = Standard_True;
194 // Fill data structure.
198 buildKnots(theline, NULL);
199 if (myKnots.Length() == 2 &&
200 indicemax - indicemin > 2 * myData.myNbPntMax)
202 // At least 3 knots for BrepApprox.
203 myKnots.ChangeLast() = (indicemax - indicemin) / 2;
204 myKnots.Append(indicemax);
207 myComputeLine.Init (myDegMin, myDegMax, myTol3d, myTol2d, myNbIterMax, Standard_True, myData.parametrization);
208 myComputeLineBezier.Init(myDegMin, myDegMax, myTol3d, myTol2d, myNbIterMax, Standard_True, myData.parametrization);
210 buildCurve(theline, NULL);
213 //=======================================================================
215 //purpose : Definition of next steps according to surface types
216 // (i.e. coordination algorithm).
217 //=======================================================================
218 void ApproxInt_Approx::Perform(const ThePSurface& Surf1,
219 const ThePSurface& Surf2,
220 const Handle(TheWLine)& theline,
221 const Standard_Boolean ApproxXYZ,
222 const Standard_Boolean ApproxU1V1,
223 const Standard_Boolean ApproxU2V2,
224 const Standard_Integer indicemin,
225 const Standard_Integer indicemax)
228 myTolReached3d = myTolReached2d = 0.;
230 const GeomAbs_SurfaceType typeS1 = ThePSurfaceTool::GetType(Surf1);
231 const GeomAbs_SurfaceType typeS2 = ThePSurfaceTool::GetType(Surf2);
233 const Standard_Boolean isQuadric = ((typeS1 == GeomAbs_Plane) ||
234 (typeS1 == GeomAbs_Cylinder) ||
235 (typeS1 == GeomAbs_Sphere) ||
236 (typeS1 == GeomAbs_Cone) ||
237 (typeS2 == GeomAbs_Plane) ||
238 (typeS2 == GeomAbs_Cylinder) ||
239 (typeS2 == GeomAbs_Sphere) ||
240 (typeS2 == GeomAbs_Cone));
244 IntSurf_Quadric Quad;
245 Standard_Boolean SecondIsImplicit=Standard_False;
249 Quad.SetValue(ThePSurfaceTool::Plane(Surf1));
252 case GeomAbs_Cylinder:
253 Quad.SetValue(ThePSurfaceTool::Cylinder(Surf1));
257 Quad.SetValue(ThePSurfaceTool::Sphere(Surf1));
261 Quad.SetValue(ThePSurfaceTool::Cone(Surf1));
266 SecondIsImplicit = Standard_True;
270 Quad.SetValue(ThePSurfaceTool::Plane(Surf2));
273 case GeomAbs_Cylinder:
274 Quad.SetValue(ThePSurfaceTool::Cylinder(Surf2));
278 Quad.SetValue(ThePSurfaceTool::Sphere(Surf2));
282 Quad.SetValue(ThePSurfaceTool::Cone(Surf2));
293 Perform(Quad, (SecondIsImplicit? Surf1: Surf2), theline,
294 ApproxXYZ, ApproxU1V1, ApproxU2V2,
295 indicemin, indicemax, !SecondIsImplicit);
300 // Here, isQuadric == FALSE.
303 prepareDS(ApproxXYZ, ApproxU1V1, ApproxU2V2, indicemin, indicemax);
305 // Non-analytical case: Param-Param perform.
306 ApproxInt_ThePrmPrmSvSurfaces myPrmPrmSvSurfaces(Surf1,Surf2);
308 Standard_Integer nbpntbez = indicemax-indicemin;
310 if(nbpntbez < aMinNbPointsForApprox)
312 myData.myBezierApprox = Standard_False;
316 myData.myBezierApprox = Standard_True;
319 // Fill data structure.
322 const Standard_Boolean cut = myData.myBezierApprox;
323 const Standard_Address ptrsvsurf = &myPrmPrmSvSurfaces;
326 buildKnots(theline, ptrsvsurf);
328 myComputeLine.Init ( myDegMin, myDegMax, myTol3d, myTol2d,
329 myNbIterMax, cut, myData.parametrization);
330 myComputeLineBezier.Init( myDegMin, myDegMax, myTol3d, myTol2d,
331 myNbIterMax, cut, myData.parametrization);
333 buildCurve(theline, ptrsvsurf);
336 //=======================================================================
338 //purpose : Analytic-Param perform.
339 //=======================================================================
340 void ApproxInt_Approx::Perform(const TheISurface& ISurf,
341 const ThePSurface& PSurf,
342 const Handle(TheWLine)& theline,
343 const Standard_Boolean ApproxXYZ,
344 const Standard_Boolean ApproxU1V1,
345 const Standard_Boolean ApproxU2V2,
346 const Standard_Integer indicemin,
347 const Standard_Integer indicemax,
348 const Standard_Boolean isTheQuadFirst)
351 prepareDS(ApproxXYZ, ApproxU1V1, ApproxU2V2, indicemin, indicemax);
353 // Non-analytical case: Analytic-Param perform.
354 ApproxInt_TheImpPrmSvSurfaces myImpPrmSvSurfaces =
355 isTheQuadFirst? ApproxInt_TheImpPrmSvSurfaces(ISurf, PSurf):
356 ApproxInt_TheImpPrmSvSurfaces(PSurf, ISurf);
358 const Standard_Integer nbpntbez = indicemax-indicemin;
359 if(nbpntbez < aMinNbPointsForApprox)
361 myData.myBezierApprox = Standard_False;
365 myData.myBezierApprox = Standard_True;
368 const Standard_Boolean cut = myData.myBezierApprox;
369 const Standard_Address ptrsvsurf = &myImpPrmSvSurfaces;
371 // Fill data structure.
375 buildKnots(theline, ptrsvsurf);
377 myComputeLine.Init ( myDegMin, myDegMax, myTol3d, myTol2d,
378 myNbIterMax, cut, myData.parametrization);
379 myComputeLineBezier.Init( myDegMin, myDegMax, myTol3d, myTol2d,
380 myNbIterMax, cut, myData.parametrization);
382 buildCurve(theline, ptrsvsurf);
385 //=======================================================================
386 //function : SetParameters
388 //=======================================================================
389 void ApproxInt_Approx::SetParameters( const Standard_Real Tol3d,
390 const Standard_Real Tol2d,
391 const Standard_Integer DegMin,
392 const Standard_Integer DegMax,
393 const Standard_Integer NbIterMax,
394 const Standard_Integer NbPntMax,
395 const Standard_Boolean ApproxWithTangency,
396 const Approx_ParametrizationType Parametrization)
398 myData.myNbPntMax = NbPntMax;
399 myWithTangency = ApproxWithTangency;
400 myTol3d = Tol3d/RatioTol;
401 myTol2d = Tol2d/RatioTol;
404 myNbIterMax = NbIterMax;
406 myComputeLine.Init ( myDegMin, myDegMax, myTol3d, myTol2d,
407 myNbIterMax, Standard_True, Parametrization);
408 myComputeLineBezier.Init( myDegMin, myDegMax, myTol3d, myTol2d,
409 myNbIterMax, Standard_True, Parametrization);
411 if(!ApproxWithTangency)
413 myComputeLine.SetConstraints(AppParCurves_PassPoint,AppParCurves_PassPoint);
414 myComputeLineBezier.SetConstraints(AppParCurves_PassPoint,AppParCurves_PassPoint);
417 myData.myBezierApprox = Standard_True;
420 //=======================================================================
421 //function : NbMultiCurves
423 //=======================================================================
424 Standard_Integer ApproxInt_Approx::NbMultiCurves() const
429 //=======================================================================
430 //function : UpdateTolReached
432 //=======================================================================
433 void ApproxInt_Approx::UpdateTolReached()
435 if (myData.myBezierApprox)
437 const Standard_Integer NbCurves = myComputeLineBezier.NbMultiCurves() ;
438 for (Standard_Integer ICur = 1 ; ICur <= NbCurves ; ICur++)
440 Standard_Real Tol3D, Tol2D ;
441 myComputeLineBezier.Error (ICur, Tol3D, Tol2D) ;
442 myTolReached3d = Max(myTolReached3d, Tol3D);
443 myTolReached2d = Max(myTolReached2d, Tol2D);
448 myComputeLine.Error (myTolReached3d, myTolReached2d);
452 //=======================================================================
453 //function : TolReached3d
455 //=======================================================================
456 Standard_Real ApproxInt_Approx::TolReached3d() const
458 return myTolReached3d * RatioTol;
461 //=======================================================================
462 //function : TolReached2d
464 //=======================================================================
465 Standard_Real ApproxInt_Approx::TolReached2d() const
467 return myTolReached2d * RatioTol;
470 //=======================================================================
473 //=======================================================================
474 Standard_Boolean ApproxInt_Approx::IsDone() const
476 if(myData.myBezierApprox)
478 return(myComputeLineBezier.NbMultiCurves() > 0);
482 return(myComputeLine.IsToleranceReached());
486 //=======================================================================
489 //=======================================================================
490 const AppParCurves_MultiBSpCurve& ApproxInt_Approx::Value(const Standard_Integer ) const
492 if(myData.myBezierApprox)
494 return(myBezToBSpl.Value());
498 return(myComputeLine.Value());
502 //=======================================================================
503 //function : fillData
504 //purpose : Fill ApproxInt data structure.
505 //=======================================================================
506 void ApproxInt_Approx::fillData(const Handle(TheWLine)& theline)
509 ComputeTrsf3d(theline, myData.Xo, myData.Yo, myData.Zo);
511 myData.Xo = myData.Yo = myData.Zo = 0.0;
513 if(myData.ApproxU1V1)
514 ComputeTrsf2d(theline, Standard_True, myData.U1o, myData.V1o);
516 myData.U1o = myData.V1o = 0.0;
518 if(myData.ApproxU2V2)
519 ComputeTrsf2d(theline, Standard_False, myData.U2o, myData.V2o);
521 myData.U2o = myData.V2o = 0.0;
524 //=======================================================================
525 //function : prepareDS
527 //=======================================================================
528 void ApproxInt_Approx::prepareDS(const Standard_Boolean theApproxXYZ,
529 const Standard_Boolean theApproxU1V1,
530 const Standard_Boolean theApproxU2V2,
531 const Standard_Integer theIndicemin,
532 const Standard_Integer theIndicemax)
534 myTolReached3d = myTolReached2d = 0.0;
535 myData.ApproxU1V1 = theApproxU1V1;
536 myData.ApproxU2V2 = theApproxU2V2;
537 myData.ApproxXYZ = theApproxXYZ;
538 myData.indicemin = theIndicemin;
539 myData.indicemax = theIndicemax;
540 myData.parametrization = myComputeLineBezier.Parametrization();
543 //=======================================================================
544 //function : buildKnots
546 //=======================================================================
547 void ApproxInt_Approx::buildKnots(const Handle(TheWLine)& theline,
548 const Standard_Address thePtrSVSurf)
551 if(!myData.myBezierApprox)
553 myKnots.Append(myData.indicemin);
554 myKnots.Append(myData.indicemax);
558 const ApproxInt_TheMultiLine aTestLine( theline, thePtrSVSurf,
559 ((myData.ApproxXYZ)? 1 : 0),
560 ((myData.ApproxU1V1)? 1: 0) +
561 ((myData.ApproxU2V2)? 1: 0),
562 myData.Xo, myData.Yo, myData.Zo,
563 myData.U1o, myData.V1o, myData.U2o, myData.V2o,
565 myData.indicemin, myData.indicemax);
567 const Standard_Integer nbp3d = aTestLine.NbP3d(),
568 nbp2d = aTestLine.NbP2d();
569 TColgp_Array1OfPnt aTabPnt3d(1, Max(1, nbp3d));
570 TColgp_Array1OfPnt2d aTabPnt2d(1, Max(1, nbp2d));
571 TColgp_Array1OfPnt aPntXYZ(myData.indicemin, myData.indicemax);
572 TColgp_Array1OfPnt2d aPntU1V1(myData.indicemin, myData.indicemax);
573 TColgp_Array1OfPnt2d aPntU2V2(myData.indicemin, myData.indicemax);
575 for(Standard_Integer i = myData.indicemin; i <= myData.indicemax; ++i)
577 if (nbp3d != 0 && nbp2d != 0) aTestLine.Value(i, aTabPnt3d, aTabPnt2d);
578 else if (nbp2d != 0) aTestLine.Value(i, aTabPnt2d);
579 else if (nbp3d != 0) aTestLine.Value(i, aTabPnt3d);
583 aPntXYZ(i) = aTabPnt3d(1);
587 aPntU1V1(i) = aTabPnt2d(1);
588 aPntU2V2(i) = aTabPnt2d(2);
592 if(myData.ApproxU1V1)
594 aPntU1V1(i) = aTabPnt2d(1);
598 aPntU2V2(i) = aTabPnt2d(1);
603 Standard_Integer aMinNbPnts = myData.myNbPntMax;
605 // Expected parametrization.
606 math_Vector aPars(myData.indicemin, myData.indicemax);
607 Parameters(aTestLine, myData.indicemin, myData.indicemax, myData.parametrization, aPars);
609 ApproxInt_KnotTools::BuildKnots(aPntXYZ, aPntU1V1, aPntU2V2, aPars,
610 myData.ApproxXYZ, myData.ApproxU1V1, myData.ApproxU2V2, aMinNbPnts, myKnots);
613 //=======================================================================
614 //function : buildCurve
616 //=======================================================================
617 void ApproxInt_Approx::buildCurve(const Handle(TheWLine)& theline,
618 const Standard_Address thePtrSVSurf)
620 if(myData.myBezierApprox)
625 Standard_Integer kind = myKnots.Lower();
626 Standard_Integer imin = 0, imax = 0;
627 Standard_Boolean OtherInter = Standard_False;
630 // Base cycle: iterate over knots.
631 imin = myKnots(kind);
632 imax = myKnots(kind+1);
633 ApproxInt_TheMultiLine myMultiLine(theline, thePtrSVSurf,
634 ((myData.ApproxXYZ)? 1 : 0),
635 ((myData.ApproxU1V1)? 1: 0) + ((myData.ApproxU2V2)? 1: 0),
636 myData.Xo, myData.Yo, myData.Zo, myData.U1o, myData.V1o,
637 myData.U2o, myData.V2o, myData.ApproxU1V1, imin, imax);
639 if(myData.myBezierApprox)
641 myComputeLineBezier.Perform(myMultiLine);
642 if (myComputeLineBezier.NbMultiCurves() == 0)
647 myComputeLine.Perform(myMultiLine);
652 Standard_Integer indice3d = 1, indice2d1 = 2, indice2d2 = 3;
653 if(!myData.ApproxXYZ) { indice2d1--; indice2d2--; }
654 if(!myData.ApproxU1V1) { indice2d2--; }
657 if(myData.myBezierApprox)
659 for(Standard_Integer nbmc = myComputeLineBezier.NbMultiCurves() ; nbmc>=1; nbmc--)
661 myComputeLineBezier.ChangeValue(nbmc).Transform(indice3d, -myData.Xo, 1.0, -myData.Yo, 1.0, -myData.Zo, 1.0);
666 myComputeLine.ChangeValue().Transform(indice3d, -myData.Xo, 1.0, -myData.Yo, 1.0, -myData.Zo, 1.0);
669 if(myData.ApproxU1V1)
671 if(myData.myBezierApprox) {
672 for(Standard_Integer nbmc = myComputeLineBezier.NbMultiCurves() ; nbmc>=1; nbmc--)
674 myComputeLineBezier.ChangeValue(nbmc).Transform2d(indice2d1, -myData.U1o, 1.0, -myData.V1o, 1.0);
679 myComputeLine.ChangeValue().Transform2d(indice2d1, -myData.U1o, 1.0, -myData.V1o, 1.0);
682 if(myData.ApproxU2V2)
684 if(myData.myBezierApprox)
686 for(Standard_Integer nbmc = myComputeLineBezier.NbMultiCurves() ; nbmc>=1; nbmc--)
688 myComputeLineBezier.ChangeValue(nbmc).Transform2d(indice2d2, -myData.U2o, 1.0, -myData.V2o, 1.0);
693 myComputeLine.ChangeValue().Transform2d(indice2d2, -myData.U2o, 1.0, -myData.V2o, 1.0);
697 OtherInter = Standard_False;
698 if(myData.myBezierApprox)
700 for(Standard_Integer nbmc = 1;
701 nbmc <= myComputeLineBezier.NbMultiCurves();
704 myBezToBSpl.Append(myComputeLineBezier.Value(nbmc));
707 if(kind < myKnots.Upper())
709 OtherInter = Standard_True;
715 if(myData.myBezierApprox)
717 myBezToBSpl.Perform();