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