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 |
48 | class 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 | |
70 | void 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 | |
149 | class 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 | |
168 | void 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 | |
230 | class 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 | |
249 | void 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 | //============================================================================= |
359 | void 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 | //============================================================================= |
512 | Standard_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 | //============================================================================= |
594 | Standard_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 | } |