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