b311480e |
1 | // Created on: 1997-12-19 |
2 | // Created by: Roman BORISOV /Philippe MANGIN |
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 | |
7fd59977 |
17 | |
7fd59977 |
18 | #include <Adaptor3d_HCurve.hxx> |
7fd59977 |
19 | #include <Bnd_Box.hxx> |
42cf5bc1 |
20 | #include <BndLib_Add3dCurve.hxx> |
21 | #include <Geom_BezierCurve.hxx> |
22 | #include <Geom_BSplineCurve.hxx> |
23 | #include <Geom_Plane.hxx> |
24 | #include <GeomAbs_CurveType.hxx> |
25 | #include <GeomFill_CorrectedFrenet.hxx> |
26 | #include <GeomFill_Frenet.hxx> |
27 | #include <GeomFill_SnglrFunc.hxx> |
28 | #include <GeomFill_TrihedronLaw.hxx> |
7fd59977 |
29 | #include <GeomLib.hxx> |
42cf5bc1 |
30 | #include <gp_Trsf.hxx> |
31 | #include <gp_Vec.hxx> |
32 | #include <gp_Vec2d.hxx> |
7fd59977 |
33 | #include <Law_BSpFunc.hxx> |
34 | #include <Law_BSpline.hxx> |
42cf5bc1 |
35 | #include <Law_Composite.hxx> |
36 | #include <Law_Constant.hxx> |
37 | #include <Law_Function.hxx> |
38 | #include <Law_Interpolate.hxx> |
39 | #include <Precision.hxx> |
40 | #include <Standard_ConstructionError.hxx> |
41 | #include <Standard_OutOfRange.hxx> |
42 | #include <Standard_Type.hxx> |
7fd59977 |
43 | #include <TColgp_HArray1OfPnt.hxx> |
42cf5bc1 |
44 | #include <TColStd_HArray1OfReal.hxx> |
45 | #include <TColStd_SequenceOfReal.hxx> |
7fd59977 |
46 | |
42cf5bc1 |
47 | #include <stdio.h> |
92efcf78 |
48 | IMPLEMENT_STANDARD_RTTIEXT(GeomFill_CorrectedFrenet,GeomFill_TrihedronLaw) |
49 | |
42cf5bc1 |
50 | //Patch |
0797d9d3 |
51 | #ifdef OCCT_DEBUG |
7fd59977 |
52 | static Standard_Boolean Affich=0; |
53 | #endif |
54 | |
55 | #ifdef DRAW |
56 | static Standard_Integer CorrNumber = 0; |
57 | #include <Draw_Appli.hxx> |
58 | #include <DrawTrSurf.hxx> |
59 | #include <Draw_Segment2D.hxx> |
60 | //#include <Draw.hxx> |
61 | #include <TColgp_Array1OfPnt.hxx> |
62 | #include <TColStd_Array1OfReal.hxx> |
63 | #include <TColStd_HArray1OfInteger.hxx> |
64 | #endif |
65 | |
66 | #ifdef DRAW |
67 | static void draw(const Handle(Law_Function)& law) |
68 | { |
69 | Standard_Real Step, u, v, tmin; |
70 | Standard_Integer NbInt, i, j, jmax; |
71 | NbInt = law->NbIntervals(GeomAbs_C3); |
72 | TColStd_Array1OfReal Int(1, NbInt+1); |
73 | law->Intervals(Int, GeomAbs_C3); |
74 | gp_Pnt2d old; |
75 | Handle(Draw_Segment2D) tg2d; |
76 | |
77 | for(i = 1; i <= NbInt; i++){ |
78 | tmin = Int(i); |
79 | Step = (Int(i+1)-Int(i))/4; |
80 | if (i == NbInt) jmax = 4; |
81 | else jmax = 3; |
82 | for (j=1; j<=jmax; j++) { |
83 | u = tmin + (j-1)*Step; |
84 | v = law->Value(u); |
85 | gp_Pnt2d point2d(u,v); |
86 | if ((i>1)||(j>1)) { |
87 | tg2d = new Draw_Segment2D(old, point2d,Draw_kaki); |
88 | dout << tg2d; |
89 | } |
90 | old = point2d; |
91 | } |
92 | } |
93 | dout.Flush(); |
94 | } |
95 | #endif |
96 | |
a31abc03 |
97 | |
98 | static Standard_Real ComputeTorsion(const Standard_Real Param, |
99 | const Handle(Adaptor3d_HCurve)& aCurve) |
100 | { |
101 | Standard_Real Torsion; |
102 | |
103 | gp_Pnt aPoint; |
104 | gp_Vec DC1, DC2, DC3; |
105 | aCurve->D3(Param, aPoint, DC1, DC2, DC3); |
106 | gp_Vec DC1crossDC2 = DC1 ^ DC2; |
107 | Standard_Real Norm_DC1crossDC2 = DC1crossDC2.Magnitude(); |
108 | |
109 | Standard_Real DC1DC2DC3 = DC1crossDC2 * DC3 ; //mixed product |
110 | |
111 | Standard_Real Tol = gp::Resolution(); |
112 | Standard_Real SquareNorm_DC1crossDC2 = Norm_DC1crossDC2 * Norm_DC1crossDC2; |
113 | if (SquareNorm_DC1crossDC2 <= Tol) |
114 | Torsion = 0.; |
115 | else |
116 | Torsion = DC1DC2DC3 / SquareNorm_DC1crossDC2 ; |
117 | |
118 | return Torsion; |
119 | } |
120 | |
7fd59977 |
121 | //=============================================================== |
122 | // Function : smoothlaw |
123 | // Purpose : to smooth a law : Reduce the number of knots |
124 | //=============================================================== |
125 | static void smoothlaw(Handle(Law_BSpline)& Law, |
126 | const Handle(TColStd_HArray1OfReal)& Points, |
127 | const Handle(TColStd_HArray1OfReal)& Param, |
128 | const Standard_Real Tol) |
129 | { |
130 | Standard_Real tol, d; |
131 | Standard_Integer ii, Nbk; |
132 | Standard_Boolean B, Ok; |
133 | Handle(Law_BSpline) BS = Law->Copy(); |
134 | |
135 | Nbk = BS->NbKnots(); |
136 | tol = Tol/10; |
137 | Ok = Standard_False; |
138 | |
139 | for (ii=Nbk-1; ii>1; ii--) { // Une premiere passe tolerance serres |
140 | B = BS->RemoveKnot(ii, 0, tol); |
141 | if (B) Ok = Standard_True; |
142 | } |
143 | |
144 | if (Ok) { // controle |
145 | tol = 0.; |
146 | for (ii=1; ii<=Param->Length() && Ok; ii++) { |
147 | d = Abs(BS->Value(Param->Value(ii))-Points->Value(ii)); |
148 | if (d > tol) tol = d; |
149 | Ok = (tol <= Tol); |
150 | } |
151 | if (Ok) |
152 | tol = (Tol-tol)/2; |
153 | else { |
0797d9d3 |
154 | #ifdef OCCT_DEBUG |
04232180 |
155 | std::cout << "smooth law echec" << std::endl; |
7fd59977 |
156 | #endif |
157 | return; // Echec |
158 | } |
159 | } |
160 | else { |
161 | tol = Tol/2; |
162 | } |
163 | |
164 | |
165 | if (Ok) Law = BS; |
166 | |
167 | Ok = Standard_False; // Une deuxieme passe tolerance desserre |
168 | Nbk = BS->NbKnots(); |
169 | for (ii=Nbk-1; ii>1; ii--) { |
170 | B = BS->RemoveKnot(ii, 0, tol); |
171 | if (B) Ok = Standard_True; |
172 | } |
173 | |
174 | if (Ok) { // controle |
175 | tol = 0.; |
176 | for (ii=1; ii<=Param->Length() && Ok; ii++) { |
177 | d = Abs(BS->Value(Param->Value(ii))-Points->Value(ii)); |
178 | if (d > tol) tol = d; |
179 | Ok = (tol <= Tol); |
180 | } |
181 | if (!Ok) { |
0797d9d3 |
182 | #ifdef OCCT_DEBUG |
04232180 |
183 | std::cout << "smooth law echec" << std::endl; |
7fd59977 |
184 | #endif |
185 | } |
186 | } |
187 | if (Ok) Law = BS; |
188 | |
0797d9d3 |
189 | #ifdef OCCT_DEBUG |
7fd59977 |
190 | if (Affich) { |
04232180 |
191 | std::cout << "Knots Law : " << std::endl; |
7fd59977 |
192 | for (ii=1; ii<=BS->NbKnots(); ii++) { |
04232180 |
193 | std::cout << ii << " : " << BS->Knot(ii) << std::endl; |
7fd59977 |
194 | } |
195 | } |
196 | #endif |
197 | } |
198 | |
199 | //=============================================================== |
200 | // Function : FindPlane |
201 | // Purpose : |
202 | //=============================================================== |
464cd2fb |
203 | static Standard_Boolean FindPlane ( const Handle(Adaptor3d_HCurve)& theC, |
204 | Handle( Geom_Plane )& theP ) |
7fd59977 |
205 | { |
206 | Standard_Boolean found = Standard_True; |
207 | Handle(TColgp_HArray1OfPnt) TabP; |
208 | |
464cd2fb |
209 | switch (theC->GetType()) { |
7fd59977 |
210 | |
211 | case GeomAbs_Line: |
212 | { |
213 | found = Standard_False; |
214 | } |
215 | break; |
216 | |
217 | case GeomAbs_Circle: |
464cd2fb |
218 | theP = new Geom_Plane(gp_Ax3(theC->Circle().Position())); |
7fd59977 |
219 | break; |
220 | |
221 | case GeomAbs_Ellipse: |
464cd2fb |
222 | theP = new Geom_Plane(gp_Ax3(theC->Ellipse().Position())); |
7fd59977 |
223 | break; |
224 | |
225 | case GeomAbs_Hyperbola: |
464cd2fb |
226 | theP = new Geom_Plane(gp_Ax3(theC->Hyperbola().Position())); |
7fd59977 |
227 | break; |
228 | |
229 | case GeomAbs_Parabola: |
464cd2fb |
230 | theP = new Geom_Plane(gp_Ax3(theC->Parabola().Position())); |
7fd59977 |
231 | break; |
232 | |
233 | case GeomAbs_BezierCurve: |
234 | { |
464cd2fb |
235 | Handle(Geom_BezierCurve) GC = theC->Bezier(); |
7fd59977 |
236 | Standard_Integer nbp = GC->NbPoles(); |
237 | if ( nbp < 2) |
238 | found = Standard_False; |
239 | else if ( nbp == 2) { |
240 | found = Standard_False; |
241 | } |
242 | else { |
243 | TabP = new (TColgp_HArray1OfPnt) (1, nbp); |
244 | GC->Poles(TabP->ChangeArray1()); |
245 | } |
246 | } |
247 | break; |
248 | |
249 | case GeomAbs_BSplineCurve: |
250 | { |
464cd2fb |
251 | Handle(Geom_BSplineCurve) GC = theC->BSpline(); |
7fd59977 |
252 | Standard_Integer nbp = GC->NbPoles(); |
253 | if ( nbp < 2) |
254 | found = Standard_False; |
255 | else if ( nbp == 2) { |
256 | found = Standard_False; |
257 | } |
258 | else { |
259 | TabP = new (TColgp_HArray1OfPnt) (1, nbp); |
260 | GC->Poles(TabP->ChangeArray1()); |
261 | } |
262 | } |
263 | break; |
264 | |
265 | default: |
266 | { // On utilise un echantillonage |
464cd2fb |
267 | Standard_Integer nbp = 15 + theC->NbIntervals(GeomAbs_C3); |
7fd59977 |
268 | Standard_Real f, l, t, inv; |
269 | Standard_Integer ii; |
464cd2fb |
270 | f = theC->FirstParameter(); |
271 | l = theC->LastParameter(); |
7fd59977 |
272 | inv = 1./(nbp-1); |
7e425ba7 |
273 | TabP = new (TColgp_HArray1OfPnt) (1, nbp); |
7fd59977 |
274 | for (ii=1; ii<=nbp; ii++) { |
275 | t = ( f*(nbp-ii) + l*(ii-1)); |
276 | t *= inv; |
464cd2fb |
277 | TabP->SetValue(ii, theC->Value(t)); |
7fd59977 |
278 | } |
279 | } |
280 | } |
281 | |
282 | if (! TabP.IsNull()) { // Recherche d'un plan moyen et controle |
283 | Standard_Boolean issingular; |
284 | gp_Ax2 inertia; |
285 | GeomLib::AxeOfInertia(TabP->Array1(), inertia, issingular); |
286 | if (issingular) { |
287 | found = Standard_False; |
288 | } |
289 | else { |
464cd2fb |
290 | theP = new Geom_Plane(inertia); |
7fd59977 |
291 | } |
292 | if (found) |
293 | { |
294 | //control = Controle(TabP->Array1(), P, myTolerance); |
295 | // Standard_Boolean isOnPlane; |
296 | Standard_Real a,b,c,d, dist; |
297 | Standard_Integer ii; |
464cd2fb |
298 | theP->Coefficients(a,b,c,d); |
7fd59977 |
299 | for (ii=1; ii<=TabP->Length() && found; ii++) { |
300 | const gp_XYZ& xyz = TabP->Value(ii).XYZ(); |
301 | dist = a*xyz.X() + b*xyz.Y() + c*xyz.Z() + d; |
302 | found = (Abs(dist) <= Precision::Confusion()); |
303 | } |
304 | return found; |
305 | } |
306 | } |
307 | |
308 | return found; |
309 | } |
310 | |
311 | //=============================================================== |
a31abc03 |
312 | // Function : Constructor |
7fd59977 |
313 | // Purpose : |
314 | //=============================================================== |
315 | GeomFill_CorrectedFrenet::GeomFill_CorrectedFrenet() |
316 | : isFrenet(Standard_False) |
317 | { |
318 | frenet = new GeomFill_Frenet(); |
a31abc03 |
319 | myForEvaluation = Standard_False; |
320 | } |
321 | |
322 | //=============================================================== |
323 | // Function : Constructor |
324 | // Purpose : |
325 | //=============================================================== |
326 | GeomFill_CorrectedFrenet::GeomFill_CorrectedFrenet(const Standard_Boolean ForEvaluation) |
327 | : isFrenet(Standard_False) |
328 | { |
329 | frenet = new GeomFill_Frenet(); |
330 | myForEvaluation = ForEvaluation; |
7fd59977 |
331 | } |
332 | |
333 | Handle(GeomFill_TrihedronLaw) GeomFill_CorrectedFrenet::Copy() const |
334 | { |
335 | Handle(GeomFill_CorrectedFrenet) copy = new (GeomFill_CorrectedFrenet)(); |
336 | if (!myCurve.IsNull()) copy->SetCurve(myCurve); |
337 | return copy; |
338 | } |
339 | |
340 | void GeomFill_CorrectedFrenet::SetCurve(const Handle(Adaptor3d_HCurve)& C) |
341 | { |
342 | |
343 | GeomFill_TrihedronLaw::SetCurve(C); |
344 | if (! C.IsNull()) { |
345 | frenet->SetCurve(C); |
346 | |
347 | GeomAbs_CurveType type; |
348 | type = C->GetType(); |
349 | switch (type) { |
350 | case GeomAbs_Circle: |
351 | case GeomAbs_Ellipse: |
352 | case GeomAbs_Hyperbola: |
353 | case GeomAbs_Parabola: |
354 | case GeomAbs_Line: |
355 | { |
356 | // No probleme isFrenet |
357 | isFrenet = Standard_True; |
a31abc03 |
358 | break; |
7fd59977 |
359 | } |
360 | default : |
361 | { |
362 | // We have to search singulaties |
363 | isFrenet = Standard_True; |
364 | Init(); |
365 | } |
366 | } |
367 | } |
368 | } |
369 | |
370 | |
371 | //=============================================================== |
372 | // Function : Init |
373 | // Purpose : Compute angle's law |
374 | //=============================================================== |
375 | void GeomFill_CorrectedFrenet::Init() |
376 | { |
377 | EvolAroundT = new Law_Composite(); |
378 | Standard_Integer NbI = frenet->NbIntervals(GeomAbs_C0), i; |
379 | TColStd_Array1OfReal T(1, NbI + 1); |
380 | frenet->Intervals(T, GeomAbs_C0); |
381 | Handle(Law_Function) Func; |
382 | //OCC78 |
383 | TColStd_SequenceOfReal SeqPoles, SeqAngle; |
384 | TColgp_SequenceOfVec SeqTangent, SeqNormal; |
385 | |
386 | gp_Vec Tangent, Normal, BN; |
387 | frenet->D0(myTrimmed->FirstParameter(), Tangent, Normal, BN); |
388 | Standard_Integer NbStep; |
389 | // Standard_Real StartAng = 0, AvStep, Step, t; |
390 | Standard_Real StartAng = 0, AvStep, Step; |
391 | |
392 | #if DRAW |
393 | Standard_Real t; |
394 | |
395 | if (Affich) { // Display the curve C'^C''(t) |
396 | GeomFill_SnglrFunc CS(myCurve); |
397 | NbStep = 99; |
398 | AvStep = (myTrimmed->LastParameter() - |
399 | myTrimmed->FirstParameter())/NbStep; |
400 | TColgp_Array1OfPnt TabP(1, NbStep+1); |
401 | |
402 | TColStd_Array1OfReal TI(1, NbStep+1); |
403 | TColStd_Array1OfInteger M(1,NbStep+1); |
404 | M.Init(1); |
405 | M(1) = M(NbStep+1) = 2; |
406 | for (i=1; i<=NbStep+1; i++) { |
407 | t = (myTrimmed->FirstParameter()+ (i-1)*AvStep); |
408 | CS.D0(t, TabP(i)); |
409 | TI(i) = t; |
410 | } |
411 | char tname[100]; |
412 | Standard_CString name = tname ; |
413 | sprintf(name,"Binorm_%d", ++CorrNumber); |
414 | Handle(Geom_BSplineCurve) BS = new |
415 | (Geom_BSplineCurve) (TabP, TI, M, 1); |
416 | // DrawTrSurf::Set(&name[0], BS); |
417 | DrawTrSurf::Set(name, BS); |
418 | } |
419 | #endif |
420 | |
421 | |
422 | NbStep = 10; |
423 | AvStep = (myTrimmed->LastParameter() - myTrimmed->FirstParameter())/NbStep; |
424 | for(i = 1; i <= NbI; i++) { |
425 | NbStep = Max(Standard_Integer((T(i+1) - T(i))/AvStep), 3); |
426 | Step = (T(i+1) - T(i))/NbStep; |
a31abc03 |
427 | if(!InitInterval(T(i), T(i+1), Step, StartAng, Tangent, Normal, AT, AN, Func, |
428 | SeqPoles, SeqAngle, SeqTangent, SeqNormal)) |
429 | { |
430 | if(isFrenet) |
431 | isFrenet = Standard_False; |
432 | } |
7fd59977 |
433 | Handle(Law_Composite)::DownCast(EvolAroundT)->ChangeLaws().Append(Func); |
434 | } |
435 | if(myTrimmed->IsPeriodic()) |
436 | Handle(Law_Composite)::DownCast(EvolAroundT)->SetPeriodic(); |
437 | |
438 | TLaw = EvolAroundT; |
439 | //OCC78 |
440 | Standard_Integer iEnd = SeqPoles.Length(); |
441 | HArrPoles = new TColStd_HArray1OfReal(1, iEnd); |
442 | HArrAngle = new TColStd_HArray1OfReal(1, iEnd); |
443 | HArrTangent = new TColgp_HArray1OfVec(1, iEnd); |
444 | HArrNormal = new TColgp_HArray1OfVec(1, iEnd); |
445 | for(i = 1; i <= iEnd; i++){ |
446 | HArrPoles->ChangeValue(i) = SeqPoles(i); |
447 | HArrAngle->ChangeValue(i) = SeqAngle(i); |
448 | HArrTangent->ChangeValue(i) = SeqTangent(i); |
449 | HArrNormal->ChangeValue(i) = SeqNormal(i); |
450 | }; |
a31abc03 |
451 | |
7fd59977 |
452 | #if DRAW |
453 | if (Affich) { |
454 | draw(EvolAroundT); |
455 | } |
456 | #endif |
457 | } |
458 | |
459 | //=============================================================== |
460 | // Function : InitInterval |
461 | // Purpose : Compute the angle law on a span |
462 | //=============================================================== |
463 | Standard_Boolean GeomFill_CorrectedFrenet:: |
464 | InitInterval(const Standard_Real First, const Standard_Real Last, |
465 | const Standard_Real Step, |
466 | Standard_Real& startAng, gp_Vec& prevTangent, |
467 | gp_Vec& prevNormal, gp_Vec& aT, gp_Vec& aN, |
468 | Handle(Law_Function)& FuncInt, |
469 | TColStd_SequenceOfReal& SeqPoles, |
470 | TColStd_SequenceOfReal& SeqAngle, |
471 | TColgp_SequenceOfVec& SeqTangent, |
472 | TColgp_SequenceOfVec& SeqNormal) const |
473 | { |
474 | Bnd_Box Boite; |
475 | gp_Vec Tangent, Normal, BN, cross; |
476 | TColStd_SequenceOfReal parameters; |
477 | TColStd_SequenceOfReal EvolAT; |
96a95605 |
478 | Standard_Real Param = First, L, norm; |
7fd59977 |
479 | Standard_Boolean isZero = Standard_True, isConst = Standard_True; |
a31abc03 |
480 | const Standard_Real minnorm = 1.e-16; |
7fd59977 |
481 | Standard_Integer i; |
482 | gp_Pnt PonC; |
483 | gp_Vec D1; |
484 | |
485 | frenet->SetInterval(First, Last); //To have the rigth evaluation at bounds |
486 | GeomFill_SnglrFunc CS(myCurve); |
487 | BndLib_Add3dCurve::Add(CS, First, Last, 1.e-2, Boite); |
7fd59977 |
488 | |
489 | aT = gp_Vec(0, 0, 0); |
490 | aN = gp_Vec(0, 0, 0); |
491 | |
1d47d8d0 |
492 | Standard_Real angleAT = 0., currParam, currStep = Step; |
7fd59977 |
493 | |
494 | Handle( Geom_Plane ) aPlane; |
a31abc03 |
495 | Standard_Boolean isPlanar = Standard_False; |
496 | if (!myForEvaluation) |
497 | isPlanar = FindPlane( myCurve, aPlane ); |
7fd59977 |
498 | |
499 | i = 1; |
500 | currParam = Param; |
501 | Standard_Real DLast = Last - Precision::PConfusion(); |
502 | |
503 | while (Param < Last) { |
504 | if (currParam > DLast) { |
505 | currStep = DLast - Param; |
506 | currParam = Last; |
507 | } |
508 | if (isPlanar) |
509 | currParam = Last; |
510 | |
511 | frenet->D0(currParam, Tangent, Normal, BN); |
c6541a0c |
512 | if (prevTangent.Angle(Tangent) < M_PI/3 || i == 1) { |
7fd59977 |
513 | parameters.Append(currParam); |
514 | //OCC78 |
515 | SeqPoles.Append(Param); |
516 | SeqAngle.Append(i > 1? EvolAT(i-1) : startAng); |
517 | SeqTangent.Append(prevTangent); |
518 | SeqNormal.Append(prevNormal); |
519 | angleAT = CalcAngleAT(Tangent,Normal,prevTangent,prevNormal); |
520 | |
521 | if(isConst && i > 1) |
522 | if(Abs(angleAT) > Precision::PConfusion()) |
523 | isConst = Standard_False; |
524 | |
525 | angleAT += (i > 1) ? EvolAT(i-1) : startAng; |
526 | EvolAT.Append(angleAT); |
527 | prevNormal = Normal; |
528 | |
529 | if(isZero) |
530 | if(Abs(angleAT) > Precision::PConfusion()) |
531 | isZero = Standard_False; |
532 | |
533 | aT += Tangent; |
534 | cross = Tangent.Crossed(Normal); |
535 | aN.SetLinearForm(Sin(angleAT), cross, |
536 | 1 - Cos(angleAT), Tangent.Crossed(cross), |
537 | Normal+aN); |
538 | prevTangent = Tangent; |
539 | Param = currParam; |
540 | i++; |
541 | |
542 | //Evaluate the Next step |
543 | CS.D1(Param, PonC, D1); |
a31abc03 |
544 | |
545 | L = PonC.XYZ().Modulus()/2; |
7fd59977 |
546 | norm = D1.Magnitude(); |
a31abc03 |
547 | if (norm <= gp::Resolution()) |
548 | { |
549 | //norm = 2.*gp::Resolution(); |
550 | norm = minnorm; |
7fd59977 |
551 | } |
552 | currStep = L / norm; |
a31abc03 |
553 | if (currStep <= gp::Resolution()) //L = 0 => curvature = 0, linear segment |
554 | currStep = Step; |
555 | if (currStep < Precision::Confusion()) //too small step |
556 | currStep = Precision::Confusion(); |
557 | if (currStep > Step) //too big step |
558 | currStep = Step;//default value |
7fd59977 |
559 | } |
560 | else |
561 | currStep /= 2; // Step too long ! |
562 | |
563 | currParam = Param + currStep; |
564 | } |
565 | |
566 | if (! isPlanar) |
567 | { |
568 | aT /= parameters.Length() - 1; |
569 | aN /= parameters.Length() - 1; |
570 | } |
571 | startAng = angleAT; |
572 | |
573 | // Interpolation |
574 | if (isConst || isPlanar) { |
575 | FuncInt = new Law_Constant(); |
576 | Handle(Law_Constant)::DownCast(FuncInt)->Set( angleAT, First, Last ); |
577 | } |
578 | |
579 | else { |
580 | Standard_Integer Length = parameters.Length(); |
581 | Handle(TColStd_HArray1OfReal) pararr = |
582 | new TColStd_HArray1OfReal(1, Length); |
583 | Handle(TColStd_HArray1OfReal) angleATarr = |
584 | new TColStd_HArray1OfReal(1, Length); |
585 | |
586 | |
587 | for (i = 1; i <= Length; i++) { |
588 | pararr->ChangeValue(i) = parameters(i); |
589 | angleATarr->ChangeValue(i) = EvolAT(i); |
590 | } |
591 | |
0797d9d3 |
592 | #ifdef OCCT_DEBUG |
7fd59977 |
593 | if (Affich) { |
04232180 |
594 | std::cout<<"NormalEvolution"<<std::endl; |
7fd59977 |
595 | for (i = 1; i <= Length; i++) { |
04232180 |
596 | std::cout<<"("<<pararr->Value(i)<<", "<<angleATarr->Value(i)<<")" << std::endl; |
7fd59977 |
597 | } |
04232180 |
598 | std::cout<<std::endl; |
7fd59977 |
599 | } |
600 | #endif |
601 | |
602 | Law_Interpolate lawAT(angleATarr, pararr, |
603 | Standard_False, Precision::PConfusion()); |
604 | lawAT.Perform(); |
605 | Handle(Law_BSpline) BS = lawAT.Curve(); |
606 | smoothlaw(BS, angleATarr, pararr, 0.1); |
607 | |
608 | FuncInt = new Law_BSpFunc(BS, First, Last); |
609 | } |
610 | return isZero; |
611 | } |
612 | //=============================================================== |
613 | // Function : CalcAngleAT (OCC78) |
614 | // Purpose : Calculate angle of rotation of trihedron normal and its derivatives relative |
615 | // at any position on his curve |
616 | //=============================================================== |
617 | Standard_Real GeomFill_CorrectedFrenet::CalcAngleAT(const gp_Vec& Tangent, const gp_Vec& Normal, |
618 | const gp_Vec& prevTangent, const gp_Vec& prevNormal) const |
619 | { |
620 | Standard_Real angle; |
621 | gp_Vec Normal_rot, cross; |
622 | angle = Tangent.Angle(prevTangent); |
623 | if (Abs(angle) > Precision::Angular()) { |
624 | cross = Tangent.Crossed(prevTangent).Normalized(); |
625 | Normal_rot = Normal + sin(angle)*cross.Crossed(Normal) + |
626 | (1 - cos(angle))*cross.Crossed(cross.Crossed(Normal)); |
627 | } |
628 | else |
629 | Normal_rot = Normal; |
630 | Standard_Real angleAT = Normal_rot.Angle(prevNormal); |
c6541a0c |
631 | if(angleAT > Precision::Angular() && M_PI - angleAT > Precision::Angular()) |
7fd59977 |
632 | if (Normal_rot.Crossed(prevNormal).IsOpposite(prevTangent, Precision::Angular())) |
633 | angleAT = -angleAT; |
634 | return angleAT; |
a3f6f591 |
635 | } |
7fd59977 |
636 | //=============================================================== |
637 | // Function : ... (OCC78) |
638 | // Purpose : This family of functions produce conversion of angle utility |
639 | //=============================================================== |
7fd59977 |
640 | static Standard_Real corr2PI_PI(Standard_Real Ang){ |
c6541a0c |
641 | return Ang = (Ang < M_PI? Ang: Ang-2*M_PI); |
a3f6f591 |
642 | } |
7fd59977 |
643 | static Standard_Real diffAng(Standard_Real A, Standard_Real Ao){ |
c6541a0c |
644 | Standard_Real dA = (A-Ao) - Floor((A-Ao)/2.0/M_PI)*2.0*M_PI; |
7fd59977 |
645 | return dA = dA >= 0? corr2PI_PI(dA): -corr2PI_PI(-dA); |
a3f6f591 |
646 | } |
7fd59977 |
647 | //=============================================================== |
648 | // Function : CalcAngleAT (OCC78) |
649 | // Purpose : Calculate angle of rotation of trihedron normal and its derivatives relative |
650 | // at any position on his curve |
651 | //=============================================================== |
652 | Standard_Real GeomFill_CorrectedFrenet::GetAngleAT(const Standard_Real Param) const{ |
653 | // Search index of low margin from poles of TLaw by bisection method |
654 | Standard_Integer iB = 1, iE = HArrPoles->Length(), iC = (iE+iB)/2; |
655 | if(Param == HArrPoles->Value(iB)) return TLaw->Value(Param); |
656 | if(Param > HArrPoles->Value(iE)) iC = iE; |
657 | if(iC < iE){ |
658 | while(!(HArrPoles->Value(iC) <= Param && Param <= HArrPoles->Value(iC+1))){ |
659 | if(HArrPoles->Value(iC) < Param) iB = iC; else iE = iC; |
660 | iC = (iE+iB)/2; |
661 | }; |
662 | if(HArrPoles->Value(iC) == Param || Param == HArrPoles->Value(iC+1)) return TLaw->Value(Param); |
663 | }; |
7fd59977 |
664 | // Calculate differenciation between apporoximated and local values of AngleAT |
665 | Standard_Real AngP = TLaw->Value(Param), AngPo = HArrAngle->Value(iC), dAng = AngP - AngPo; |
666 | gp_Vec Tangent, Normal, BN; |
667 | frenet->D0(Param, Tangent, Normal, BN); |
668 | Standard_Real DAng = CalcAngleAT(Tangent, Normal, HArrTangent->Value(iC), HArrNormal->Value(iC)); |
669 | Standard_Real DA = diffAng(DAng,dAng); |
670 | // The correction (there is core of OCC78 bug) |
c6541a0c |
671 | if(Abs(DA) > M_PI/2.0){ |
7fd59977 |
672 | AngP = AngPo + DAng; |
673 | }; |
674 | return AngP; |
a3f6f591 |
675 | } |
7fd59977 |
676 | //=============================================================== |
677 | // Function : D0 |
678 | // Purpose : |
679 | //=============================================================== |
680 | Standard_Boolean GeomFill_CorrectedFrenet::D0(const Standard_Real Param, |
681 | gp_Vec& Tangent, |
682 | gp_Vec& Normal, |
683 | gp_Vec& BiNormal) |
684 | { |
685 | frenet->D0(Param, Tangent, Normal, BiNormal); |
686 | if (isFrenet) return Standard_True; |
687 | |
688 | Standard_Real angleAT; |
689 | //angleAT = TLaw->Value(Param); |
690 | angleAT = GetAngleAT(Param); //OCC78 |
691 | |
692 | // rotation around Tangent |
693 | gp_Vec cross; |
694 | cross = Tangent.Crossed(Normal); |
695 | Normal.SetLinearForm(Sin(angleAT), cross, |
696 | (1 - Cos(angleAT)), Tangent.Crossed(cross), |
697 | Normal); |
698 | BiNormal = Tangent.Crossed(Normal); |
699 | |
700 | return Standard_True; |
701 | } |
702 | |
703 | //=============================================================== |
704 | // Function : D1 |
705 | // Purpose : |
706 | //=============================================================== |
707 | |
708 | Standard_Boolean GeomFill_CorrectedFrenet::D1(const Standard_Real Param, |
709 | gp_Vec& Tangent, |
710 | gp_Vec& DTangent, |
711 | gp_Vec& Normal, |
712 | gp_Vec& DNormal, |
713 | gp_Vec& BiNormal, |
714 | gp_Vec& DBiNormal) |
715 | { |
716 | frenet->D1(Param, Tangent, DTangent, Normal, DNormal, BiNormal, DBiNormal); |
717 | if (isFrenet) return Standard_True; |
718 | |
719 | Standard_Real angleAT, d_angleAT; |
720 | Standard_Real sina, cosa; |
721 | |
722 | TLaw->D1(Param, angleAT, d_angleAT); |
723 | angleAT = GetAngleAT(Param); //OCC78 |
724 | |
725 | gp_Vec cross, dcross, tcross, dtcross, aux; |
726 | sina = Sin(angleAT); |
727 | cosa = Cos(angleAT); |
728 | |
729 | cross = Tangent.Crossed(Normal); |
730 | dcross.SetLinearForm(1, DTangent.Crossed(Normal), |
731 | Tangent.Crossed(DNormal)); |
732 | |
733 | tcross = Tangent.Crossed(cross); |
734 | dtcross.SetLinearForm(1, DTangent.Crossed(cross), |
735 | Tangent.Crossed(dcross)); |
736 | |
737 | aux.SetLinearForm(sina, dcross, |
738 | cosa*d_angleAT, cross); |
739 | aux.SetLinearForm(1 - cosa, dtcross, |
740 | sina*d_angleAT, tcross, |
741 | aux); |
742 | DNormal+=aux; |
743 | |
744 | Normal.SetLinearForm( sina, cross, |
745 | (1 - cosa), tcross, |
746 | Normal); |
747 | |
748 | BiNormal = Tangent.Crossed(Normal); |
749 | |
750 | DBiNormal.SetLinearForm(1, DTangent.Crossed(Normal), |
751 | Tangent.Crossed(DNormal)); |
752 | |
753 | // for test |
754 | /* gp_Vec FDN, Tf, Nf, BNf; |
755 | Standard_Real h; |
756 | h = 1.0e-8; |
757 | if (Param + h > myTrimmed->LastParameter()) h = -h; |
758 | D0(Param + h, Tf, Nf, BNf); |
759 | FDN = (Nf - Normal)/h; |
04232180 |
760 | std::cout<<"Param = "<<Param<<std::endl; |
761 | std::cout<<"DN = ("<<DNormal.X()<<", "<<DNormal.Y()<<", "<<DNormal.Z()<<")"<<std::endl; |
762 | std::cout<<"FDN = ("<<FDN.X()<<", "<<FDN.Y()<<", "<<FDN.Z()<<")"<<std::endl; |
7fd59977 |
763 | */ |
764 | |
765 | return Standard_True; |
766 | } |
767 | |
768 | //=============================================================== |
769 | // Function : D2 |
770 | // Purpose : |
771 | //=============================================================== |
772 | Standard_Boolean GeomFill_CorrectedFrenet::D2(const Standard_Real Param, |
773 | gp_Vec& Tangent, |
774 | gp_Vec& DTangent, |
775 | gp_Vec& D2Tangent, |
776 | gp_Vec& Normal, |
777 | gp_Vec& DNormal, |
778 | gp_Vec& D2Normal, |
779 | gp_Vec& BiNormal, |
780 | gp_Vec& DBiNormal, |
781 | gp_Vec& D2BiNormal) |
782 | { |
783 | frenet->D2(Param, Tangent, DTangent, D2Tangent, |
784 | Normal, DNormal, D2Normal, |
785 | BiNormal, DBiNormal, D2BiNormal); |
786 | if (isFrenet) return Standard_True; |
787 | |
788 | Standard_Real angleAT, d_angleAT, d2_angleAT; |
789 | Standard_Real sina, cosa; |
790 | TLaw->D2(Param, angleAT, d_angleAT, d2_angleAT); |
791 | angleAT = GetAngleAT(Param); //OCC78 |
792 | |
793 | gp_Vec cross, dcross, d2cross, tcross, dtcross, d2tcross, aux; |
794 | sina = Sin(angleAT); |
795 | cosa = Cos(angleAT); |
796 | cross = Tangent.Crossed(Normal); |
797 | dcross.SetLinearForm(1, DTangent.Crossed(Normal), |
798 | Tangent.Crossed(DNormal)); |
799 | d2cross.SetLinearForm(1, D2Tangent.Crossed(Normal), |
800 | 2, DTangent.Crossed(DNormal), |
801 | Tangent.Crossed(D2Normal)); |
802 | |
803 | |
804 | tcross = Tangent.Crossed(cross); |
805 | dtcross.SetLinearForm(1, DTangent.Crossed(cross), |
806 | Tangent.Crossed(dcross)); |
807 | d2tcross.SetLinearForm(1, D2Tangent.Crossed(cross), |
808 | 2, DTangent.Crossed(dcross), |
809 | Tangent.Crossed(d2cross)); |
810 | |
811 | |
812 | aux.SetLinearForm(sina, d2cross, |
813 | 2*cosa*d_angleAT, dcross, |
814 | cosa*d2_angleAT - sina*d_angleAT*d_angleAT, cross); |
815 | |
816 | aux.SetLinearForm(1 - cosa, d2tcross, |
817 | 2*sina*d_angleAT, dtcross, |
818 | cosa*d_angleAT*d_angleAT + sina*d2_angleAT, tcross, |
819 | aux); |
820 | D2Normal += aux; |
821 | |
822 | /* D2Normal += sina*(D2Tangent.Crossed(Normal) + 2*DTangent.Crossed(DNormal) + Tangent.Crossed(D2Normal)) + |
823 | 2*cosa*d_angleAT*(DTangent.Crossed(Normal) + Tangent.Crossed(DNormal)) + |
824 | (cosa*d2_angleAT - sina*d_angleAT*d_angleAT)*Tangent.Crossed(Normal) + |
825 | 2*sina*d_angleAT*(DTangent.Crossed(Tangent.Crossed(Normal)) + Tangent.Crossed(DTangent.Crossed(Normal)) + Tangent.Crossed(Tangent.Crossed(DNormal))) + |
826 | (1 - cosa)*(D2Tangent.Crossed(Tangent.Crossed(Normal)) + Tangent.Crossed(D2Tangent.Crossed(Normal)) + Tangent.Crossed(Tangent.Crossed(D2Normal)) + 2*DTangent.Crossed(DTangent.Crossed(Normal)) + 2*DTangent.Crossed(Tangent.Crossed(DNormal)) + 2*Tangent.Crossed(DTangent.Crossed(DNormal))) |
827 | + |
828 | (cosa*d_angleAT*d_angleAT + sina*d2_angleAT)*Tangent.Crossed(Tangent.Crossed(Normal));*/ |
829 | |
830 | |
831 | aux.SetLinearForm(sina, dcross, |
832 | cosa*d_angleAT, cross); |
833 | aux.SetLinearForm(1 - cosa, dtcross, |
834 | sina*d_angleAT, tcross, |
835 | aux); |
836 | DNormal+=aux; |
837 | |
838 | |
839 | Normal.SetLinearForm( sina, cross, |
840 | (1 - cosa), tcross, |
841 | Normal); |
842 | |
843 | BiNormal = Tangent.Crossed(Normal); |
844 | |
845 | DBiNormal.SetLinearForm(1, DTangent.Crossed(Normal), |
846 | Tangent.Crossed(DNormal)); |
847 | |
848 | D2BiNormal.SetLinearForm(1, D2Tangent.Crossed(Normal), |
849 | 2, DTangent.Crossed(DNormal), |
850 | Tangent.Crossed(D2Normal)); |
851 | |
852 | // for test |
853 | /* gp_Vec FD2N, FD2T, FD2BN, Tf, DTf, Nf, DNf, BNf, DBNf; |
854 | Standard_Real h; |
855 | h = 1.0e-8; |
856 | if (Param + h > myTrimmed->LastParameter()) h = -h; |
857 | D1(Param + h, Tf, DTf, Nf, DNf, BNf, DBNf); |
858 | FD2N = (DNf - DNormal)/h; |
859 | FD2T = (DTf - DTangent)/h; |
860 | FD2BN = (DBNf - DBiNormal)/h; |
04232180 |
861 | std::cout<<"Param = "<<Param<<std::endl; |
862 | std::cout<<"D2N = ("<<D2Normal.X()<<", "<<D2Normal.Y()<<", "<<D2Normal.Z()<<")"<<std::endl; |
863 | std::cout<<"FD2N = ("<<FD2N.X()<<", "<<FD2N.Y()<<", "<<FD2N.Z()<<")"<<std::endl<<std::endl; |
864 | std::cout<<"D2T = ("<<D2Tangent.X()<<", "<<D2Tangent.Y()<<", "<<D2Tangent.Z()<<")"<<std::endl; |
865 | std::cout<<"FD2T = ("<<FD2T.X()<<", "<<FD2T.Y()<<", "<<FD2T.Z()<<")"<<std::endl<<std::endl; |
866 | std::cout<<"D2BN = ("<<D2BiNormal.X()<<", "<<D2BiNormal.Y()<<", "<<D2BiNormal.Z()<<")"<<std::endl; |
867 | std::cout<<"FD2BN = ("<<FD2BN.X()<<", "<<FD2BN.Y()<<", "<<FD2BN.Z()<<")"<<std::endl<<std::endl; |
7fd59977 |
868 | */ |
869 | // |
870 | return Standard_True; |
871 | } |
872 | |
873 | //=============================================================== |
874 | // Function : NbIntervals |
875 | // Purpose : |
876 | //=============================================================== |
877 | Standard_Integer GeomFill_CorrectedFrenet::NbIntervals(const GeomAbs_Shape S) const |
878 | { |
879 | Standard_Integer NbFrenet, NbLaw; |
880 | NbFrenet = frenet->NbIntervals(S); |
881 | if (isFrenet) return NbFrenet; |
882 | |
883 | NbLaw = EvolAroundT->NbIntervals(S); |
884 | if (NbFrenet == 1) |
885 | return NbLaw; |
886 | |
887 | TColStd_Array1OfReal FrenetInt(1, NbFrenet + 1); |
888 | TColStd_Array1OfReal LawInt(1, NbLaw + 1); |
889 | TColStd_SequenceOfReal Fusion; |
890 | |
891 | frenet->Intervals(FrenetInt, S); |
892 | EvolAroundT->Intervals(LawInt, S); |
893 | GeomLib::FuseIntervals(FrenetInt, LawInt, Fusion); |
894 | |
895 | return Fusion.Length()-1; |
896 | } |
897 | |
898 | //=============================================================== |
899 | // Function : Intervals |
900 | // Purpose : |
901 | //=============================================================== |
902 | void GeomFill_CorrectedFrenet::Intervals(TColStd_Array1OfReal& T, |
903 | const GeomAbs_Shape S) const |
904 | { |
905 | Standard_Integer NbFrenet, NbLaw; |
906 | if (isFrenet) { |
907 | frenet->Intervals(T, S); |
908 | return; |
909 | } |
910 | |
911 | NbFrenet = frenet->NbIntervals(S); |
912 | if(NbFrenet==1) { |
913 | EvolAroundT->Intervals(T, S); |
914 | } |
915 | |
916 | NbLaw = EvolAroundT->NbIntervals(S); |
917 | |
918 | TColStd_Array1OfReal FrenetInt(1, NbFrenet + 1); |
919 | TColStd_Array1OfReal LawInt(1, NbLaw + 1); |
920 | TColStd_SequenceOfReal Fusion; |
921 | |
922 | frenet->Intervals(FrenetInt, S); |
923 | EvolAroundT->Intervals(LawInt, S); |
924 | GeomLib::FuseIntervals(FrenetInt, LawInt, Fusion); |
925 | |
926 | for(Standard_Integer i = 1; i <= Fusion.Length(); i++) |
927 | T.ChangeValue(i) = Fusion.Value(i); |
928 | } |
929 | |
930 | //=============================================================== |
931 | // Function : SetInterval |
932 | // Purpose : |
933 | //=============================================================== |
934 | void GeomFill_CorrectedFrenet::SetInterval(const Standard_Real First, |
935 | const Standard_Real Last) |
936 | { |
937 | GeomFill_TrihedronLaw::SetInterval(First, Last); |
938 | frenet->SetInterval(First, Last); |
939 | if (!isFrenet) TLaw = EvolAroundT->Trim(First, Last, |
940 | Precision::PConfusion()/2); |
941 | } |
942 | |
943 | //=============================================================== |
a31abc03 |
944 | // Function : EvaluateBestMode |
945 | // Purpose : |
946 | //=============================================================== |
947 | GeomFill_Trihedron GeomFill_CorrectedFrenet::EvaluateBestMode() |
948 | { |
949 | if (EvolAroundT.IsNull()) |
950 | return GeomFill_IsFrenet; //Frenet |
951 | |
952 | const Standard_Real MaxAngle = 3.*M_PI/4.; |
953 | const Standard_Real MaxTorsion = 100.; |
954 | |
955 | Standard_Real Step, u, v, tmin, tmax; |
956 | Standard_Integer NbInt, i, j, k = 1; |
957 | NbInt = EvolAroundT->NbIntervals(GeomAbs_CN); |
958 | TColStd_Array1OfReal Int(1, NbInt+1); |
959 | EvolAroundT->Intervals(Int, GeomAbs_CN); |
960 | gp_Pnt2d old; |
961 | gp_Vec2d aVec, PrevVec; |
962 | |
963 | Standard_Integer NbSamples = 10; |
964 | for(i = 1; i <= NbInt; i++){ |
965 | tmin = Int(i); |
966 | tmax = Int(i+1); |
967 | Standard_Real Torsion = ComputeTorsion(tmin, myTrimmed); |
968 | if (Abs(Torsion) > MaxTorsion) |
969 | return GeomFill_IsDiscreteTrihedron; //DiscreteTrihedron |
970 | |
971 | Handle(Law_Function) trimmedlaw = EvolAroundT->Trim(tmin, tmax, Precision::PConfusion()/2); |
972 | Step = (Int(i+1)-Int(i))/NbSamples; |
973 | for (j = 0; j <= NbSamples; j++) { |
974 | u = tmin + j*Step; |
975 | v = trimmedlaw->Value(u); |
976 | gp_Pnt2d point2d(u,v); |
977 | if (j != 0) |
978 | { |
979 | aVec.SetXY(point2d.XY() - old.XY()); |
980 | if (k > 2) |
981 | { |
982 | Standard_Real theAngle = PrevVec.Angle(aVec); |
983 | if (Abs(theAngle) > MaxAngle) |
984 | return GeomFill_IsDiscreteTrihedron; //DiscreteTrihedron |
985 | } |
986 | PrevVec = aVec; |
987 | } |
988 | old = point2d; |
989 | k++; |
990 | } |
991 | } |
992 | |
993 | return GeomFill_IsCorrectedFrenet; //CorrectedFrenet |
994 | } |
995 | |
996 | //=============================================================== |
7fd59977 |
997 | // Function : GetAverageLaw |
998 | // Purpose : |
999 | //=============================================================== |
1000 | void GeomFill_CorrectedFrenet::GetAverageLaw(gp_Vec& ATangent, |
1001 | gp_Vec& ANormal, |
1002 | gp_Vec& ABiNormal) |
1003 | { |
1004 | if (isFrenet) frenet->GetAverageLaw(ATangent, ANormal, ABiNormal); |
1005 | else { |
1006 | ATangent = AT; |
1007 | ANormal = AN; |
1008 | ABiNormal = ATangent; |
1009 | ABiNormal.Cross(ANormal); |
1010 | } |
1011 | } |
1012 | |
1013 | //=============================================================== |
1014 | // Function : IsConstant |
1015 | // Purpose : |
1016 | //=============================================================== |
1017 | Standard_Boolean GeomFill_CorrectedFrenet::IsConstant() const |
1018 | { |
1019 | return (myCurve->GetType() == GeomAbs_Line); |
1020 | } |
1021 | |
1022 | //=============================================================== |
1023 | // Function : IsOnlyBy3dCurve |
1024 | // Purpose : |
1025 | //=============================================================== |
1026 | Standard_Boolean GeomFill_CorrectedFrenet::IsOnlyBy3dCurve() const |
1027 | { |
1028 | return Standard_True; |
1029 | } |