0031642: Visualization - crash in Graphic3d_Structure::SetVisual() on redisplaying...
[occt.git] / src / GCPnts / GCPnts_QuasiUniformDeflection.pxx
1 // Copyright (c) 1995-1999 Matra Datavision
2 // Copyright (c) 1999-2014 OPEN CASCADE SAS
3 //
4 // This file is part of Open CASCADE Technology software library.
5 //
6 // This library is free software; you can redistribute it and/or modify it under
7 // the terms of the GNU Lesser General Public License version 2.1 as published
8 // by the Free Software Foundation, with special exception defined in the file
9 // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
10 // distribution for complete text of the license and disclaimer of any warranty.
11 //
12 // Alternatively, this file may be used under the terms of Open CASCADE
13 // commercial license or contractual agreement.
14
15 #include <StdFail_NotDone.hxx>
16 #include <Standard_DomainError.hxx>
17 #include <Standard_OutOfRange.hxx>
18 #include <Standard_ConstructionError.hxx>
19 #include <Standard_NotImplemented.hxx>
20 #include <GCPnts_DeflectionType.hxx>
21 #include <TColStd_Array1OfReal.hxx>
22 #include <TColStd_SequenceOfReal.hxx>
23 #include <BSplCLib.hxx>
24 #include <gp_Circ.hxx>
25 #include <gp_Circ2d.hxx>
26 #include <Precision.hxx>
27
28
29 static void QuasiFleche(const TheCurve&,
30                         const Standard_Real,
31                         const Standard_Real,
32                         const gp_Pnt&,
33                         const gp_Vec&,
34                         const Standard_Real,
35                         const gp_Pnt&,
36                         const gp_Vec&,
37                         const Standard_Integer,
38                         const Standard_Real,
39                         TColStd_SequenceOfReal&,
40                         TColgp_SequenceOfPnt&,
41                         Standard_Integer&);
42
43 static void QuasiFleche(const TheCurve&,
44                         const Standard_Real,
45                         const Standard_Real,
46                         const gp_Pnt&,
47                         const Standard_Real,
48                         const gp_Pnt&,
49                         const Standard_Integer,
50                         TColStd_SequenceOfReal&,
51                         TColgp_SequenceOfPnt&,
52                         Standard_Integer&);
53
54
55 //=======================================================================
56 //function : PerformLinear
57 //purpose  :
58 //=======================================================================
59 static Standard_Boolean PerformLinear (const TheCurve& C,
60                                        TColStd_SequenceOfReal& Parameters,
61                                        TColgp_SequenceOfPnt& Points,
62                                        const Standard_Real U1,
63                                        const Standard_Real U2)
64 {
65   gp_Pnt aPoint;
66   Parameters.Append (U1);
67   aPoint = Value (C, U1);
68   Points.Append (aPoint);
69
70   Parameters.Append (U2);
71   aPoint = Value (C, U2);
72   Points.Append (aPoint);
73   return Standard_True;
74 }
75
76
77 //=======================================================================
78 //function : PerformCircular
79 //purpose  :
80 //=======================================================================
81 static Standard_Boolean PerformCircular (const TheCurve& C,
82                                          TColStd_SequenceOfReal& Parameters,
83                                          TColgp_SequenceOfPnt& Points,
84                                          const Standard_Real Deflection,
85                                          const Standard_Real U1,
86                                          const Standard_Real U2)
87
88 {
89   gp_Pnt aPoint;
90   Standard_Real Angle = Max (1.0e0 - (Deflection / C.Circle().Radius()), 0.0e0);
91   Angle = 2.0e0 * ACos (Angle);
92   Standard_Integer NbPoints = (Standard_Integer )((U2 - U1) / Angle);
93   NbPoints += 2;
94   Angle = (U2 - U1) / (Standard_Real) (NbPoints - 1);
95   Standard_Real U = U1;
96   for (Standard_Integer i = 1; i <= NbPoints; ++i)
97   {
98     Parameters.Append (U);
99     aPoint = Value (C,U);
100     Points.Append (aPoint);
101     U += Angle;
102   }
103   return Standard_True;
104 }
105
106
107 //=======================================================================
108 //function : GetDefType
109 //purpose  :
110 //=======================================================================
111 static GCPnts_DeflectionType GetDefType (const TheCurve& C)
112 {
113   if (C.NbIntervals(GeomAbs_C1) > 1)
114     return GCPnts_DefComposite;
115   // pour forcer les decoupages aux cassures. G1 devrait marcher,
116   // mais donne des exceptions...
117
118   switch (C.GetType())
119   {
120     case GeomAbs_Line:   return GCPnts_Linear;
121     case GeomAbs_Circle: return GCPnts_Circular;
122     case GeomAbs_BSplineCurve:
123     {
124       Handle_TheBSplineCurve BS = C.BSpline();
125       return (BS->NbPoles() == 2) ? GCPnts_Linear : GCPnts_Curved;
126     }
127     case GeomAbs_BezierCurve:
128     {
129       Handle_TheBezierCurve BZ = C.Bezier();
130       return (BZ->NbPoles() == 2) ? GCPnts_Linear : GCPnts_Curved;
131     }
132     default: return GCPnts_Curved;
133   }
134 }
135
136
137 //=======================================================================
138 //function : PerformCurve
139 //purpose  :
140 //=======================================================================
141 static Standard_Boolean PerformCurve (TColStd_SequenceOfReal& Parameters,
142                                       TColgp_SequenceOfPnt& Points,
143                                       const TheCurve& C,
144                                       const Standard_Real Deflection,
145                                       const Standard_Real U1,
146                                       const Standard_Real U2,
147                                       const Standard_Real EPSILON,
148                                       const GeomAbs_Shape Continuity)
149 {
150   Standard_Integer Nbmin = 2;
151   Standard_Integer aNbCallQF = 0;
152
153   gp_Pnt Pdeb;
154   if (Continuity <= GeomAbs_G1)
155   {
156
157     Pdeb = Value (C, U1);
158     Parameters.Append (U1);
159     Points.Append (Pdeb);
160
161     gp_Pnt Pfin (Value (C, U2));
162     QuasiFleche (C, Deflection * Deflection,
163                 U1, Pdeb,
164                 U2, Pfin,
165                 Nbmin,
166                 Parameters, Points, aNbCallQF);
167   }
168   else
169   {
170     gp_Pnt Pfin;
171     gp_Vec Ddeb, Dfin;
172     D1 (C, U1, Pdeb, Ddeb);
173     Parameters.Append (U1);
174     Points.Append (Pdeb);
175
176     Standard_Real aDecreasedU2 = U2 - Epsilon(U2) * 10.;
177     D1 (C, aDecreasedU2, Pfin, Dfin);
178     QuasiFleche (C, Deflection * Deflection,
179                  U1, Pdeb,
180                  Ddeb,
181                  U2, Pfin,
182                  Dfin,
183                  Nbmin,
184                  EPSILON * EPSILON,
185                  Parameters, Points, aNbCallQF);
186   }
187 //  cout << "Nb de pts: " << Points.Length()<< endl;
188   return Standard_True;
189 }
190
191
192 //=======================================================================
193 //function : PerformComposite
194 //purpose  :
195 //=======================================================================
196 static Standard_Boolean PerformComposite (TColStd_SequenceOfReal& Parameters,
197                                           TColgp_SequenceOfPnt& Points,
198                                           const TheCurve& C,
199                                           const Standard_Real Deflection,
200                                           const Standard_Real U1,
201                                           const Standard_Real U2,
202                                           const Standard_Real EPSILON,
203                                           const GeomAbs_Shape Continuity)
204 {
205 //
206 //  coherence avec Intervals
207 //
208   Standard_Integer NbIntervals = C.NbIntervals (GeomAbs_C2);
209   Standard_Integer PIndex;
210   TColStd_Array1OfReal TI (1, NbIntervals + 1);
211   C.Intervals (TI, GeomAbs_C2);
212   BSplCLib::Hunt (TI, U1, PIndex);
213
214   // iterate by continuous segments
215   Standard_Real Ua = U1;
216   for (Standard_Integer Index = PIndex;;)
217   {
218     Standard_Real Ub = Index + 1 <= TI.Upper()
219                      ? Min (U2, TI (Index + 1))
220                      : U2;
221     if (!PerformCurve (Parameters, Points, C, Deflection,
222                                    Ua, Ub, EPSILON, Continuity))
223       return Standard_False;
224
225     ++Index;
226     if (Index > NbIntervals || U2 < TI (Index))
227       return Standard_True;
228
229     // remove last point to avoid duplication
230     Parameters.Remove (Parameters.Length());
231     Points.Remove (Points.Length());
232
233     Ua = Ub;
234   }
235 }
236
237
238 //=======================================================================
239 //function : GCPnts_QuasiUniformDeflection
240 //purpose  :
241 //=======================================================================
242 GCPnts_QuasiUniformDeflection::GCPnts_QuasiUniformDeflection
243                                (const TheCurve& C,
244                                 const Standard_Real Deflection,
245                                 const Standard_Real U1,
246                                 const Standard_Real U2,
247                                 const GeomAbs_Shape Continuity)
248 {
249   Initialize (C, Deflection, U1, U2, Continuity);
250 }
251
252
253 //=======================================================================
254 //function : GCPnts_QuasiUniformDeflection
255 //purpose  :
256 //=======================================================================
257 GCPnts_QuasiUniformDeflection::GCPnts_QuasiUniformDeflection
258                                (const TheCurve& C,
259                                 const Standard_Real Deflection,
260                                 const GeomAbs_Shape Continuity)
261 {
262   Initialize (C, Deflection, Continuity);
263 }
264
265
266 //=======================================================================
267 //function : Initialize
268 //purpose  :
269 //=======================================================================
270 void GCPnts_QuasiUniformDeflection::Initialize (const TheCurve& C,
271                                                 const Standard_Real Deflection,
272                                                 const GeomAbs_Shape Continuity)
273 {
274   Initialize (C, Deflection, C.FirstParameter(),
275               C.LastParameter(), Continuity);
276 }
277
278
279 //=======================================================================
280 //function : Initialize
281 //purpose  :
282 //=======================================================================
283
284 void GCPnts_QuasiUniformDeflection::Initialize
285                      (const TheCurve& C,
286                                       const Standard_Real Deflection,
287                                       const Standard_Real theU1,
288                                       const Standard_Real theU2,
289                                       const GeomAbs_Shape Continuity)
290 {
291   myCont = (Continuity > GeomAbs_G1) ? GeomAbs_C1 : GeomAbs_C0;
292   Standard_Real EPSILON = C.Resolution (Precision::Confusion());
293   EPSILON = Min (EPSILON, 1.e50);
294   myDeflection = Deflection;
295   myDone = Standard_False;
296   myParams.Clear();
297   myPoints.Clear();
298   GCPnts_DeflectionType Type = GetDefType (C);
299
300   Standard_Real U1 = Min (theU1, theU2);
301   Standard_Real U2 = Max (theU1, theU2);
302
303   if (Type == GCPnts_Curved || Type == GCPnts_DefComposite)
304   {
305     if (C.GetType() == GeomAbs_BSplineCurve || C.GetType() == GeomAbs_BezierCurve)
306     {
307       Standard_Real maxpar = Max (Abs (C.FirstParameter()), Abs (C.LastParameter()));
308       if (EPSILON < Epsilon (maxpar)) return;
309     }
310   }
311
312   switch (Type)
313   {
314     case GCPnts_Linear:
315       myDone = PerformLinear (C, myParams, myPoints, U1, U2);
316       break;
317     case GCPnts_Circular:
318       myDone = PerformCircular (C, myParams, myPoints, Deflection, U1, U2);
319       break;
320     case GCPnts_Curved:
321       myDone = PerformCurve (myParams, myPoints, C, Deflection,
322                              U1, U2, EPSILON, myCont);
323       break;
324     case GCPnts_DefComposite:
325       myDone = PerformComposite (myParams, myPoints, C, Deflection,
326                                  U1, U2, EPSILON, myCont);
327       break;
328   }
329 }
330
331
332 //=======================================================================
333 //function : QuasiFleche
334 //purpose  :
335 //=======================================================================
336 void QuasiFleche (const TheCurve& C,
337                   const Standard_Real Deflection2,
338                   const Standard_Real Udeb,
339                   const gp_Pnt& Pdeb,
340                   const gp_Vec& Vdeb,
341                   const Standard_Real Ufin,
342                   const gp_Pnt& Pfin,
343                   const gp_Vec& Vfin,
344                   const Standard_Integer Nbmin,
345                   const Standard_Real Eps,
346                   TColStd_SequenceOfReal& Parameters,
347                   TColgp_SequenceOfPnt& Points,
348                   Standard_Integer& theNbCalls)
349 {
350   theNbCalls++;
351   if (theNbCalls >= MyMaxQuasiFleshe)
352   {
353     return;
354   }
355   Standard_Integer Ptslength = Points.Length();
356   if (theNbCalls > 100 && Ptslength < 2)
357   {
358     return;
359   }
360   Standard_Real Udelta = Ufin - Udeb;
361   gp_Pnt Pdelta;
362   gp_Vec Vdelta;
363   if (Nbmin > 2)
364   {
365     Udelta /= (Nbmin - 1);
366     D1 (C, Udeb + Udelta, Pdelta, Vdelta);
367   }
368   else
369   {
370     Pdelta = Pfin;
371     Vdelta = Vfin;
372   }
373
374   Standard_Real Norme = gp_Vec (Pdeb, Pdelta).SquareMagnitude();
375   Standard_Real theFleche = 0;
376   Standard_Boolean flecheok = Standard_False;
377   if (Norme > Eps)
378   {
379     // Evaluation de la fleche par interpolation . Voir IntWalk_IWalking_5.gxx
380     Standard_Real N1 = Vdeb.SquareMagnitude();
381     Standard_Real N2 = Vdelta.SquareMagnitude();
382     if (N1 > Eps && N2 > Eps)
383     {
384       Standard_Real Normediff = (Vdeb.Normalized().XYZ() - Vdelta.Normalized().XYZ()).SquareModulus();
385       if (Normediff > Eps)
386       {
387         theFleche = Normediff * Norme / 64.;
388         flecheok = Standard_True;
389       }
390     }
391   }
392   if (!flecheok)
393   {
394     gp_Pnt Pmid ((Pdeb.XYZ() + Pdelta.XYZ()) * 0.5);
395     gp_Pnt Pverif (Value(C, Udeb + Udelta * 0.5));
396     theFleche = Pmid.SquareDistance (Pverif);
397   }
398
399   if (theFleche < Deflection2)
400   {
401     Parameters.Append (Udeb + Udelta);
402     Points.Append (Pdelta);
403   }
404   else
405   {
406     QuasiFleche (C, Deflection2, Udeb, Pdeb,
407                  Vdeb,
408                  Udeb + Udelta, Pdelta,
409                  Vdelta,
410                  3,
411                  Eps,
412                  Parameters, Points, theNbCalls);
413   }
414
415   if (Nbmin > 2)
416   {
417     QuasiFleche (C, Deflection2, Udeb + Udelta, Pdelta,
418                  Vdelta,
419                  Ufin, Pfin,
420                  Vfin,
421                  Nbmin - (Points.Length() - Ptslength),
422                  Eps,
423                  Parameters, Points, theNbCalls);
424   }
425   theNbCalls--;
426 }
427
428
429 //=======================================================================
430 //function : QuasiFleche
431 //purpose  :
432 //=======================================================================
433 void QuasiFleche (const TheCurve& C,
434                   const Standard_Real Deflection2,
435                   const Standard_Real Udeb,
436                   const gp_Pnt& Pdeb,
437                   const Standard_Real Ufin,
438                   const gp_Pnt& Pfin,
439                   const Standard_Integer Nbmin,
440                   TColStd_SequenceOfReal& Parameters,
441                   TColgp_SequenceOfPnt& Points,
442                   Standard_Integer& theNbCalls)
443 {
444   theNbCalls++;
445   if (theNbCalls >= MyMaxQuasiFleshe)
446   {
447     return;
448   }
449   Standard_Integer Ptslength = Points.Length();
450   if (theNbCalls > 100 && Ptslength < 2)
451   {
452     return;
453   }
454   Standard_Real Udelta = Ufin - Udeb;
455   gp_Pnt Pdelta;
456   if (Nbmin > 2)
457   {
458     Udelta /= (Nbmin-1);
459     Pdelta = Value (C, Udeb + Udelta);
460   }
461   else
462   {
463     Pdelta = Pfin;
464   }
465
466   gp_Pnt Pmid ((Pdeb.XYZ() + Pdelta.XYZ()) * 0.5);
467   gp_Pnt Pverif (Value (C, Udeb + Udelta * 0.5));
468   Standard_Real theFleche = Pmid.SquareDistance (Pverif);
469
470   if (theFleche < Deflection2)
471   {
472     Parameters.Append(Udeb + Udelta);
473     Points.Append (Pdelta);
474   }
475   else
476   {
477     QuasiFleche (C, Deflection2, Udeb, Pdeb,
478                  Udeb + Udelta * 0.5, Pverif,
479                  2,
480                  Parameters, Points, theNbCalls);
481
482     QuasiFleche (C, Deflection2, Udeb + Udelta * 0.5, Pverif,
483                  Udeb + Udelta, Pdelta,
484                  2,
485                  Parameters, Points, theNbCalls);
486   }
487
488   if (Nbmin > 2)
489   {
490     QuasiFleche (C, Deflection2, Udeb + Udelta, Pdelta,
491                  Ufin, Pfin,
492                  Nbmin - (Points.Length() - Ptslength),
493                  Parameters, Points, theNbCalls);
494   }
495   theNbCalls--;
496 }