0030932: Modeling Algorithms - Invalid result on 2d curve on surface approximation
[occt.git] / src / Approx / Approx_CurveOnSurface.cxx
CommitLineData
b311480e 1// Created on: 1997-10-06
2// Created by: Roman BORISOV
3// Copyright (c) 1997-1999 Matra Datavision
973c2be1 4// Copyright (c) 1999-2014 OPEN CASCADE SAS
b311480e 5//
973c2be1 6// This file is part of Open CASCADE Technology software library.
b311480e 7//
d5f74e42 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
973c2be1 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.
b311480e 13//
973c2be1 14// Alternatively, this file may be used under the terms of Open CASCADE
15// commercial license or contractual agreement.
7fd59977 16
42cf5bc1 17
18#include <Adaptor2d_HCurve2d.hxx>
7fd59977 19#include <Adaptor3d_CurveOnSurface.hxx>
7fd59977 20#include <Adaptor3d_HCurve.hxx>
7fd59977 21#include <Adaptor3d_HCurveOnSurface.hxx>
42cf5bc1 22#include <Adaptor3d_HSurface.hxx>
23#include <AdvApprox_ApproxAFunction.hxx>
24#include <AdvApprox_DichoCutting.hxx>
25#include <AdvApprox_PrefAndRec.hxx>
26#include <Approx_CurveOnSurface.hxx>
27#include <Geom2d_BSplineCurve.hxx>
28#include <Geom2dAdaptor_HCurve.hxx>
29#include <Geom_BSplineCurve.hxx>
f04de133 30#include <Geom_TrimmedCurve.hxx>
42cf5bc1 31#include <GeomAdaptor_HCurve.hxx>
32#include <GeomAdaptor_HSurface.hxx>
f04de133 33#include <GeomConvert.hxx>
42cf5bc1 34#include <gp_Pnt.hxx>
35#include <gp_Vec.hxx>
36#include <Precision.hxx>
37#include <Standard_ConstructionError.hxx>
38#include <Standard_OutOfRange.hxx>
39#include <TColgp_Array1OfPnt.hxx>
7fd59977 40#include <TColgp_Array1OfPnt2d.hxx>
41#include <TColStd_Array1OfReal.hxx>
42cf5bc1 42#include <TColStd_HArray1OfReal.hxx>
7fd59977 43
44//=======================================================================
45//class : Approx_CurveOnSurface_Eval
46//purpose: evaluator class for approximation of both 2d and 3d curves
47//=======================================================================
7fd59977 48class Approx_CurveOnSurface_Eval : public AdvApprox_EvaluatorFunction
49{
50 public:
51 Approx_CurveOnSurface_Eval (const Handle(Adaptor3d_HCurve)& theFunc,
52 const Handle(Adaptor2d_HCurve2d)& theFunc2d,
53 Standard_Real First, Standard_Real Last)
54 : fonct(theFunc), fonct2d(theFunc2d)
55 { StartEndSav[0] = First; StartEndSav[1] = Last; }
56
57 virtual void Evaluate (Standard_Integer *Dimension,
58 Standard_Real StartEnd[2],
59 Standard_Real *Parameter,
60 Standard_Integer *DerivativeRequest,
61 Standard_Real *Result, // [Dimension]
62 Standard_Integer *ErrorCode);
63
64 private:
65 Handle(Adaptor3d_HCurve) fonct;
66 Handle(Adaptor2d_HCurve2d) fonct2d;
67 Standard_Real StartEndSav[2];
68};
69
70void Approx_CurveOnSurface_Eval::Evaluate (Standard_Integer *Dimension,
71 Standard_Real StartEnd[2],
72 Standard_Real *Param, // Parameter at which evaluation
73 Standard_Integer *Order, // Derivative Request
74 Standard_Real *Result,// [Dimension]
75 Standard_Integer *ErrorCode)
76{
77 *ErrorCode = 0;
78 Standard_Real par = *Param;
79
80// Dimension is incorrect
81 if (*Dimension != 5) {
82 *ErrorCode = 1;
83 }
84
85// Parameter is incorrect
86 if(StartEnd[0] != StartEndSav[0] || StartEnd[1]!= StartEndSav[1])
87 {
88 fonct = fonct->Trim(StartEnd[0],StartEnd[1],Precision::PConfusion());
89 fonct2d = fonct2d->Trim(StartEnd[0],StartEnd[1],
90 Precision::PConfusion());
91 StartEndSav[0]=StartEnd[0];
92 StartEndSav[1]=StartEnd[1];
93 }
94 gp_Pnt pnt;
95
96
97 gp_Pnt2d pnt2d;
98
99 switch (*Order) {
100 case 0:
101 {
102 fonct2d->D0(par, pnt2d);
103 fonct->D0(par, pnt);
104 Result[0] = pnt2d.X();
105 Result[1] = pnt2d.Y();
106 Result[2] = pnt.X();
107 Result[3] = pnt.Y();
108 Result[4] = pnt.Z();
109 break;
110 }
111 case 1:
112 {
113 gp_Vec v1;
114 gp_Vec2d v21;
115 fonct2d->D1(par, pnt2d, v21);
116 fonct->D1(par,pnt, v1);
117 Result[0] = v21.X();
118 Result[1] = v21.Y();
119 Result[2] = v1.X();
120 Result[3] = v1.Y();
121 Result[4] = v1.Z();
122 break;
123 }
124 case 2:
125 {
126 gp_Vec v1, v2;
127 gp_Vec2d v21, v22;
128 fonct2d->D2(par, pnt2d, v21, v22);
129 fonct->D2(par, pnt, v1, v2);
130 Result[0] = v22.X();
131 Result[1] = v22.Y();
132 Result[2] = v2.X();
133 Result[3] = v2.Y();
134 Result[4] = v2.Z();
135 break;
136 }
137 default:
138 Result[0] = Result[1] = Result[2] = Result[3] = Result[4] = 0.;
139 *ErrorCode = 3;
140 break;
141 }
142}
143
144//=======================================================================
145//class : Approx_CurveOnSurface_Eval3d
146//purpose: evaluator class for approximation of 3d curve
147//=======================================================================
148
149class Approx_CurveOnSurface_Eval3d : public AdvApprox_EvaluatorFunction
150{
151 public:
152 Approx_CurveOnSurface_Eval3d (const Handle(Adaptor3d_HCurve)& theFunc,
153 Standard_Real First, Standard_Real Last)
154 : fonct(theFunc) { StartEndSav[0] = First; StartEndSav[1] = Last; }
155
156 virtual void Evaluate (Standard_Integer *Dimension,
157 Standard_Real StartEnd[2],
158 Standard_Real *Parameter,
159 Standard_Integer *DerivativeRequest,
160 Standard_Real *Result, // [Dimension]
161 Standard_Integer *ErrorCode);
162
163 private:
164 Handle(Adaptor3d_HCurve) fonct;
165 Standard_Real StartEndSav[2];
166};
167
168void Approx_CurveOnSurface_Eval3d::Evaluate (Standard_Integer *Dimension,
169 Standard_Real StartEnd[2],
170 Standard_Real *Param, // Parameter at which evaluation
171 Standard_Integer *Order, // Derivative Request
172 Standard_Real *Result,// [Dimension]
173 Standard_Integer *ErrorCode)
174{
175 *ErrorCode = 0;
176 Standard_Real par = *Param;
177
178// Dimension is incorrect
179 if (*Dimension != 3) {
180 *ErrorCode = 1;
181 }
182
183// Parameter is incorrect
184 if(StartEnd[0] != StartEndSav[0] || StartEnd[1]!= StartEndSav[1])
185 {
186 fonct = fonct->Trim(StartEnd[0],StartEnd[1],Precision::PConfusion());
187 StartEndSav[0]=StartEnd[0];
188 StartEndSav[1]=StartEnd[1];
189 }
190
191 gp_Pnt pnt;
192
193 switch (*Order) {
194 case 0:
195 pnt = fonct->Value(par);
196 Result[0] = pnt.X();
197 Result[1] = pnt.Y();
198 Result[2] = pnt.Z();
199 break;
200 case 1:
201 {
202 gp_Vec v1;
203 fonct->D1(par, pnt, v1);
204 Result[0] = v1.X();
205 Result[1] = v1.Y();
206 Result[2] = v1.Z();
207 break;
208 }
209 case 2:
210 {
211 gp_Vec v1, v2;
212 fonct->D2(par, pnt, v1, v2);
213 Result[0] = v2.X();
214 Result[1] = v2.Y();
215 Result[2] = v2.Z();
216 break;
217 }
218 default:
219 Result[0] = Result[1] = Result[2] = 0.;
220 *ErrorCode = 3;
221 break;
222 }
223}
224
225//=======================================================================
226//class : Approx_CurveOnSurface_Eval2d
227//purpose: evaluator class for approximation of 2d curve
228//=======================================================================
229
230class Approx_CurveOnSurface_Eval2d : public AdvApprox_EvaluatorFunction
231{
232 public:
233 Approx_CurveOnSurface_Eval2d (const Handle(Adaptor2d_HCurve2d)& theFunc2d,
234 Standard_Real First, Standard_Real Last)
235 : fonct2d(theFunc2d) { StartEndSav[0] = First; StartEndSav[1] = Last; }
236
237 virtual void Evaluate (Standard_Integer *Dimension,
238 Standard_Real StartEnd[2],
239 Standard_Real *Parameter,
240 Standard_Integer *DerivativeRequest,
241 Standard_Real *Result, // [Dimension]
242 Standard_Integer *ErrorCode);
243
244 private:
245 Handle(Adaptor2d_HCurve2d) fonct2d;
246 Standard_Real StartEndSav[2];
247};
248
249void Approx_CurveOnSurface_Eval2d::Evaluate (Standard_Integer *Dimension,
250 Standard_Real StartEnd[2],
251 Standard_Real *Param, // Parameter at which evaluation
252 Standard_Integer *Order, // Derivative Request
253 Standard_Real *Result,// [Dimension]
254 Standard_Integer *ErrorCode)
255{
256 *ErrorCode = 0;
257 Standard_Real par = *Param;
258
259// Dimension is incorrect
260 if (*Dimension != 2) {
261 *ErrorCode = 1;
262 }
263
264// Parameter is incorrect
265 if(StartEnd[0] != StartEndSav[0] || StartEnd[1]!= StartEndSav[1])
266 {
267 fonct2d = fonct2d->Trim(StartEnd[0],StartEnd[1],Precision::PConfusion());
268 StartEndSav[0]=StartEnd[0];
269 StartEndSav[1]=StartEnd[1];
270 }
271
272 gp_Pnt2d pnt;
273
274 switch (*Order) {
275 case 0:
276 {
277 pnt = fonct2d->Value(par);
278 Result[0] = pnt.X();
279 Result[1] = pnt.Y();
280 break;
281 }
282 case 1:
283 {
284 gp_Vec2d v1;
285 fonct2d->D1(par, pnt, v1);
286 Result[0] = v1.X();
287 Result[1] = v1.Y();
288 break;
289 }
290 case 2:
291 {
292 gp_Vec2d v1, v2;
293 fonct2d->D2(par, pnt, v1, v2);
294 Result[0] = v2.X();
295 Result[1] = v2.Y();
296 break;
297 }
298 default:
299 Result[0] = Result[1] = 0.;
300 *ErrorCode = 3;
301 break;
302 }
303}
304
f04de133 305//=============================================================================
306//function : Approx_CurveOnSurface
307//purpose : Constructor
308//=============================================================================
7fd59977 309 Approx_CurveOnSurface::Approx_CurveOnSurface(const Handle(Adaptor2d_HCurve2d)& C2D,
310 const Handle(Adaptor3d_HSurface)& Surf,
311 const Standard_Real First,
312 const Standard_Real Last,
313 const Standard_Real Tol,
314 const GeomAbs_Shape S,
315 const Standard_Integer MaxDegree,
316 const Standard_Integer MaxSegments,
317 const Standard_Boolean only3d,
318 const Standard_Boolean only2d)
f04de133 319: myC2D(C2D),
320 mySurf(Surf),
321 myFirst(First),
322 myLast(Last),
323 myTol(Tol),
324 myIsDone(Standard_False),
325 myHasResult(Standard_False),
326 myError3d(0.0),
327 myError2dU(0.0),
328 myError2dV(0.0)
329 {
330 Perform(MaxSegments, MaxDegree, S, only3d, only2d);
331 }
332
333//=============================================================================
334//function : Approx_CurveOnSurface
335//purpose : Constructor
336//=============================================================================
337 Approx_CurveOnSurface::Approx_CurveOnSurface(const Handle(Adaptor2d_HCurve2d)& theC2D,
338 const Handle(Adaptor3d_HSurface)& theSurf,
339 const Standard_Real theFirst,
340 const Standard_Real theLast,
341 const Standard_Real theTol)
342: myC2D(theC2D),
343 mySurf(theSurf),
344 myFirst(theFirst),
345 myLast(theLast),
346 myTol(theTol),
347 myIsDone(Standard_False),
348 myHasResult(Standard_False),
349 myError3d(0.0),
350 myError2dU(0.0),
351 myError2dV(0.0)
352{
353}
354
355//=============================================================================
356//function : Perform
357//purpose :
358//=============================================================================
359void Approx_CurveOnSurface::Perform(const Standard_Integer theMaxSegments,
360 const Standard_Integer theMaxDegree,
361 const GeomAbs_Shape theContinuity,
362 const Standard_Boolean theOnly3d,
363 const Standard_Boolean theOnly2d)
7fd59977 364{
365 myIsDone = Standard_False;
f04de133 366 myHasResult = Standard_False;
367 myError2dU = 0.0;
368 myError2dV = 0.0;
369 myError3d = 0.0;
7fd59977 370
f04de133 371 if(theOnly3d && theOnly2d) throw Standard_ConstructionError();
372
373 Handle( Adaptor2d_HCurve2d ) TrimmedC2D = myC2D->Trim( myFirst, myLast, Precision::PConfusion() );
374
375 Standard_Boolean isU, isForward;
376 Standard_Real aParam;
377 if (theOnly3d && isIsoLine(TrimmedC2D, isU, aParam, isForward))
378 {
379 if (buildC3dOnIsoLine(TrimmedC2D, isU, aParam, isForward))
380 {
381 myIsDone = Standard_True;
382 myHasResult = Standard_True;
383 return;
384 }
385 }
7fd59977 386
f04de133 387 Adaptor3d_CurveOnSurface COnS( TrimmedC2D, mySurf );
7fd59977 388 Handle(Adaptor3d_HCurveOnSurface) HCOnS = new Adaptor3d_HCurveOnSurface();
389 HCOnS->Set(COnS);
390
391 Standard_Integer Num1DSS = 0, Num2DSS=0, Num3DSS=0;
392 Handle(TColStd_HArray1OfReal) OneDTol;
393 Handle(TColStd_HArray1OfReal) TwoDTolNul;
394 Handle(TColStd_HArray1OfReal) ThreeDTol;
395
396 // create evaluators and choose appropriate one
f04de133 397 Approx_CurveOnSurface_Eval3d Eval3dCvOnSurf (HCOnS, myFirst, myLast);
398 Approx_CurveOnSurface_Eval2d Eval2dCvOnSurf ( TrimmedC2D, myFirst, myLast);
399 Approx_CurveOnSurface_Eval EvalCvOnSurf (HCOnS, TrimmedC2D, myFirst, myLast);
7fd59977 400 AdvApprox_EvaluatorFunction* EvalPtr;
f04de133 401 if ( theOnly3d ) EvalPtr = &Eval3dCvOnSurf;
402 else if ( theOnly2d ) EvalPtr = &Eval2dCvOnSurf;
7fd59977 403 else EvalPtr = &EvalCvOnSurf;
404
405 // Initialization for 2d approximation
f04de133 406 if(!theOnly3d) {
7fd59977 407 Num1DSS = 2;
408 OneDTol = new TColStd_HArray1OfReal(1,Num1DSS);
409
410 Standard_Real TolU, TolV;
411
f04de133 412 TolU = mySurf->UResolution(myTol)/2;
413 TolV = mySurf->VResolution(myTol)/2;
7fd59977 414
415 OneDTol->SetValue(1,TolU);
416 OneDTol->SetValue(2,TolV);
417 }
418
f04de133 419 if(!theOnly2d) {
7fd59977 420 Num3DSS=1;
421 ThreeDTol = new TColStd_HArray1OfReal(1,Num3DSS);
f04de133 422 ThreeDTol->Init(myTol/2);
7fd59977 423 }
424
7fd59977 425
426 Standard_Integer NbInterv_C2 = HCOnS->NbIntervals(GeomAbs_C2);
427 TColStd_Array1OfReal CutPnts_C2(1, NbInterv_C2 + 1);
428 HCOnS->Intervals(CutPnts_C2, GeomAbs_C2);
429 Standard_Integer NbInterv_C3 = HCOnS->NbIntervals(GeomAbs_C3);
430 TColStd_Array1OfReal CutPnts_C3(1, NbInterv_C3 + 1);
431 HCOnS->Intervals(CutPnts_C3, GeomAbs_C3);
432
433 AdvApprox_PrefAndRec CutTool(CutPnts_C2,CutPnts_C3);
434 AdvApprox_ApproxAFunction aApprox (Num1DSS, Num2DSS, Num3DSS,
435 OneDTol, TwoDTolNul, ThreeDTol,
f04de133 436 myFirst, myLast, theContinuity,
437 theMaxDegree, theMaxSegments,
7fd59977 438 *EvalPtr, CutTool);
439
440 myIsDone = aApprox.IsDone();
441 myHasResult = aApprox.HasResult();
442
443 if (myHasResult) {
444 Handle(TColStd_HArray1OfReal) Knots = aApprox.Knots();
445 Handle(TColStd_HArray1OfInteger) Mults = aApprox.Multiplicities();
446 Standard_Integer Degree = aApprox.Degree();
447
f04de133 448 if(!theOnly2d)
7fd59977 449 {
450 TColgp_Array1OfPnt Poles(1,aApprox.NbPoles());
451 aApprox.Poles(1,Poles);
452 myCurve3d = new Geom_BSplineCurve(Poles, Knots->Array1(), Mults->Array1(), Degree);
453 myError3d = aApprox.MaxError(3, 1);
454 }
f04de133 455 if(!theOnly3d)
7fd59977 456 {
457 TColgp_Array1OfPnt2d Poles2d(1,aApprox.NbPoles());
458 TColStd_Array1OfReal Poles1dU(1,aApprox.NbPoles());
459 aApprox.Poles1d(1, Poles1dU);
460 TColStd_Array1OfReal Poles1dV(1,aApprox.NbPoles());
461 aApprox.Poles1d(2, Poles1dV);
462 for(Standard_Integer i = 1; i <= aApprox.NbPoles(); i++)
463 Poles2d.SetValue(i, gp_Pnt2d(Poles1dU.Value(i), Poles1dV.Value(i)));
464 myCurve2d = new Geom2d_BSplineCurve(Poles2d, Knots->Array1(), Mults->Array1(), Degree);
465
466 myError2dU = aApprox.MaxError(1, 1);
467 myError2dV = aApprox.MaxError(1, 2);
468 }
469 }
470
7fd59977 471}
472
473 Standard_Boolean Approx_CurveOnSurface::IsDone() const
474{
475 return myIsDone;
476}
477
478 Standard_Boolean Approx_CurveOnSurface::HasResult() const
479{
480 return myHasResult;
481}
482
483 Handle(Geom_BSplineCurve) Approx_CurveOnSurface::Curve3d() const
484{
485 return myCurve3d;
486}
487
488 Handle(Geom2d_BSplineCurve) Approx_CurveOnSurface::Curve2d() const
489{
490 return myCurve2d;
491}
492
493 Standard_Real Approx_CurveOnSurface::MaxError3d() const
494{
495 return myError3d;
496}
497
498 Standard_Real Approx_CurveOnSurface::MaxError2dU() const
499{
500 return myError2dU;
501}
502
503 Standard_Real Approx_CurveOnSurface::MaxError2dV() const
504{
505 return myError2dV;
506}
507
f04de133 508//=============================================================================
509//function : isIsoLine
510//purpose :
511//=============================================================================
512Standard_Boolean Approx_CurveOnSurface::isIsoLine(const Handle(Adaptor2d_HCurve2d) theC2D,
513 Standard_Boolean& theIsU,
514 Standard_Real& theParam,
515 Standard_Boolean& theIsForward) const
516{
517 // These variables are used to check line state (vertical or horizontal).
518 Standard_Boolean isAppropriateType = Standard_False;
519 gp_Pnt2d aLoc2d;
520 gp_Dir2d aDir2d;
521
522 // Test type.
523 const GeomAbs_CurveType aType = theC2D->GetType();
524 if (aType == GeomAbs_Line)
525 {
526 gp_Lin2d aLin2d = theC2D->Line();
527 aLoc2d = aLin2d.Location();
528 aDir2d = aLin2d.Direction();
529 isAppropriateType = Standard_True;
530 }
531 else if (aType == GeomAbs_BSplineCurve)
532 {
533 Handle(Geom2d_BSplineCurve) aBSpline2d = theC2D->BSpline();
534 if (aBSpline2d->Degree() != 1 || aBSpline2d->NbPoles() != 2)
535 return Standard_False; // Not a line or uneven parameterization.
536
537 aLoc2d = aBSpline2d->Pole(1);
538
539 // Vector should be non-degenerated.
540 gp_Vec2d aVec2d(aBSpline2d->Pole(1), aBSpline2d->Pole(2));
541 if (aVec2d.SquareMagnitude() < Precision::Confusion())
542 return Standard_False; // Degenerated spline.
543 aDir2d = aVec2d;
544
545 isAppropriateType = Standard_True;
546 }
547 else if (aType == GeomAbs_BezierCurve)
548 {
549 Handle(Geom2d_BezierCurve) aBezier2d = theC2D->Bezier();
550 if (aBezier2d->Degree() != 1 || aBezier2d->NbPoles() != 2)
551 return Standard_False; // Not a line or uneven parameterization.
552
553 aLoc2d = aBezier2d->Pole(1);
554
555 // Vector should be non-degenerated.
556 gp_Vec2d aVec2d(aBezier2d->Pole(1), aBezier2d->Pole(2));
557 if (aVec2d.SquareMagnitude() < Precision::Confusion())
558 return Standard_False; // Degenerated spline.
559 aDir2d = aVec2d;
560
561 isAppropriateType = Standard_True;
562 }
563
564 if (!isAppropriateType)
565 return Standard_False;
566
567 // Check line to be vertical or horizontal.
568 if (aDir2d.IsParallel(gp::DX2d(), Precision::Angular()))
569 {
570 // Horizontal line. V = const.
571 theIsU = Standard_False;
572 theParam = aLoc2d.Y();
573 theIsForward = aDir2d.Dot(gp::DX2d()) > 0.0;
574 return Standard_True;
575 }
576 else if (aDir2d.IsParallel(gp::DY2d(), Precision::Angular()))
577 {
578 // Vertical line. U = const.
579 theIsU = Standard_True;
580 theParam = aLoc2d.X();
581 theIsForward = aDir2d.Dot(gp::DY2d()) > 0.0;
582 return Standard_True;
583 }
584
585 return Standard_False;
586}
587
588#include <GeomLib.hxx>
589
590//=============================================================================
591//function : buildC3dOnIsoLine
592//purpose :
593//=============================================================================
594Standard_Boolean Approx_CurveOnSurface::buildC3dOnIsoLine(const Handle(Adaptor2d_HCurve2d) theC2D,
595 const Standard_Boolean theIsU,
596 const Standard_Real theParam,
597 const Standard_Boolean theIsForward)
598{
599 // Convert adapter to the appropriate type.
600 Handle(GeomAdaptor_HSurface) aGeomAdapter = Handle(GeomAdaptor_HSurface)::DownCast(mySurf);
601 if (aGeomAdapter.IsNull())
602 return Standard_False;
603
604 if (mySurf->GetType() == GeomAbs_Sphere)
605 return Standard_False;
606
607 // Extract isoline
608 Handle(Geom_Surface) aSurf = aGeomAdapter->ChangeSurface().Surface();
609 Handle(Geom_Curve) aC3d;
610
611 gp_Pnt2d aF2d = theC2D->Value(theC2D->FirstParameter());
612 gp_Pnt2d aL2d = theC2D->Value(theC2D->LastParameter());
613
614 if (theIsU)
615 {
616 aC3d = aSurf->UIso(theParam);
617 aC3d = new Geom_TrimmedCurve(aC3d, aF2d.Y(), aL2d.Y());
618 }
619 else
620 {
621 aC3d = aSurf->VIso(theParam);
622 aC3d = new Geom_TrimmedCurve(aC3d, aF2d.X(), aL2d.X());
623 }
624
625 // Convert arbitrary curve type to the b-spline.
626 myCurve3d = GeomConvert::CurveToBSplineCurve(aC3d, Convert_QuasiAngular);
627 if (!theIsForward)
628 myCurve3d->Reverse();
629
630 // Rebuild parameterization for the 3d curve to have the same parameterization with
631 // a two-dimensional curve.
632 TColStd_Array1OfReal aKnots = myCurve3d->Knots();
633 BSplCLib::Reparametrize(theC2D->FirstParameter(), theC2D->LastParameter(), aKnots);
634 myCurve3d->SetKnots(aKnots);
635
636 // Evaluate error.
637 myError3d = 0.0;
638
639 const Standard_Real aParF = myFirst;
640 const Standard_Real aParL = myLast;
641 const Standard_Integer aNbPnt = 23;
642 for(Standard_Integer anIdx = 0; anIdx <= aNbPnt; ++anIdx)
643 {
644 const Standard_Real aPar = aParF + ((aParL - aParF) * anIdx) / aNbPnt;
645
646 const gp_Pnt2d aPnt2d = theC2D->Value(aPar);
647
648 const gp_Pnt aPntC3D = myCurve3d->Value(aPar);
649 const gp_Pnt aPntC2D = mySurf->Value(aPnt2d.X(), aPnt2d.Y());
650
651 const Standard_Real aSqDeviation = aPntC3D.SquareDistance(aPntC2D);
652 myError3d = Max(aSqDeviation, myError3d);
653 }
654
655 myError3d = Sqrt(myError3d);
656
657 // Target tolerance is not obtained. This situation happens for isolines on the sphere.
658 // OCCT is unable to convert it keeping original parameterization, while the geometric
659 // form of the result is entirely identical. In that case, it is better to utilize
660 // a general-purpose approach.
661 if (myError3d > myTol)
662 return Standard_False;
663
664 return Standard_True;
665}