0025279: OCCT fails to read VRML file created by OCCT
[occt.git] / src / VrmlConverter / VrmlConverter_DeflectionCurve.cxx
1 // Copyright (c) 1999-2014 OPEN CASCADE SAS
2 //
3 // This file is part of Open CASCADE Technology software library.
4 //
5 // This library is free software; you can redistribute it and/or modify it under
6 // the terms of the GNU Lesser General Public License version 2.1 as published
7 // by the Free Software Foundation, with special exception defined in the file
8 // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
9 // distribution for complete text of the license and disclaimer of any warranty.
10 //
11 // Alternatively, this file may be used under the terms of Open CASCADE
12 // commercial license or contractual agreement.
13
14 #include <VrmlConverter_DeflectionCurve.ixx>
15 #include <gp_Pnt.hxx>
16 #include <gp_Circ.hxx>
17 #include <gp_Dir.hxx>
18 #include <gp_Vec.hxx>
19 #include <Bnd_Box.hxx>
20 #include <Precision.hxx>
21 #include <TColgp_HArray1OfVec.hxx>
22 #include <TColStd_HArray1OfInteger.hxx>
23 #include <Vrml_Material.hxx>
24 #include <VrmlConverter_LineAspect.hxx>
25 #include <Vrml_Separator.hxx>
26 #include <Vrml_Coordinate3.hxx>
27 #include <Vrml_IndexedLineSet.hxx>
28 #include <Precision.hxx>
29 #include <GCPnts_QuasiUniformDeflection.hxx>
30 #include <BndLib_Add3dCurve.hxx>
31
32 //==================================================================
33 // function: FindLimits
34 // purpose:
35 //==================================================================
36 static void FindLimits(const Adaptor3d_Curve& aCurve,
37                        const Standard_Real  aLimit,
38                        Standard_Real&       First,
39                        Standard_Real&       Last)
40 {
41   First = aCurve.FirstParameter();
42   Last  = aCurve.LastParameter();
43   Standard_Boolean firstInf = Precision::IsNegativeInfinite(First);
44   Standard_Boolean lastInf  = Precision::IsPositiveInfinite(Last);
45
46   if (firstInf || lastInf) {
47     gp_Pnt P1,P2;
48     Standard_Real delta = 1;
49     if (firstInf && lastInf) {
50       do {
51         delta *= 2;
52         First = - delta;
53         Last  =   delta;
54         aCurve.D0(First,P1);
55         aCurve.D0(Last,P2);
56       } while (P1.Distance(P2) < aLimit);
57     }
58     else if (firstInf) {
59       aCurve.D0(Last,P2);
60       do {
61         delta *= 2;
62         First = Last - delta;
63         aCurve.D0(First,P1);
64       } while (P1.Distance(P2) < aLimit);
65     }
66     else if (lastInf) {
67       aCurve.D0(First,P1);
68       do {
69         delta *= 2;
70         Last = First + delta;
71         aCurve.D0(Last,P2);
72       } while (P1.Distance(P2) < aLimit);
73     }
74   }    
75 }
76
77
78 //==================================================================
79 // function: PrintPoints
80 // purpose:
81 //==================================================================
82 static void PrintPoints (Handle(TColgp_HArray1OfVec)& aHAV1,
83                          Handle(TColStd_HArray1OfInteger)& aHAI1,
84                          const Handle(VrmlConverter_Drawer)& aDrawer,
85                          Standard_OStream&             anOStream)
86 {
87 // creation of Vrml objects
88     Handle(VrmlConverter_LineAspect) LA = new VrmlConverter_LineAspect;
89     LA = aDrawer->LineAspect();
90
91 // Separator 1 {
92     Vrml_Separator SE1;
93     SE1.Print(anOStream);
94 // Material
95     if (LA->HasMaterial()){
96
97       Handle(Vrml_Material) M;
98       M = LA->Material();
99     
100       M->Print(anOStream);
101     }
102 // Coordinate3
103     Handle(Vrml_Coordinate3)  C3 = new Vrml_Coordinate3(aHAV1);
104     C3->Print(anOStream);
105 // IndexedLineSet
106     Vrml_IndexedLineSet  ILS;
107     ILS.SetCoordIndex(aHAI1);
108     ILS.Print(anOStream);
109 // Separator 1 }
110     SE1.Print(anOStream);
111 }
112
113 //==================================================================
114 // function: DrawCurve
115 // purpose:
116 //==================================================================
117 static void DrawCurve (Adaptor3d_Curve&          aCurve,
118                        const Standard_Real           TheDeflection,
119                        const Standard_Real           U1,
120                        const Standard_Real           U2,
121                        const Handle(VrmlConverter_Drawer)& aDrawer, // for passsing of LineAspect
122                        Standard_OStream&             anOStream) 
123 {
124   Standard_Integer i;
125   Standard_Boolean key = Standard_False;
126   Handle(TColgp_HArray1OfVec) HAV1;
127   Handle(TColStd_HArray1OfInteger) HAI1;
128
129   switch (aCurve.GetType()) {
130   case GeomAbs_Line:
131     {
132      gp_Vec V;
133      key = Standard_True;
134      HAV1 = new TColgp_HArray1OfVec(1, 2);
135      HAI1 = new TColStd_HArray1OfInteger(1,3);
136
137 // array of coordinates of line 
138      gp_Pnt p = aCurve.Value(U1);
139      V.SetX(p.X()); V.SetY(p.Y()); V.SetZ(p.Z());
140      HAV1->SetValue(1,V);
141
142      p = aCurve.Value(U2);
143      V.SetX(p.X()); V.SetY(p.Y()); V.SetZ(p.Z());
144      HAV1->SetValue(2,V);
145
146 // array of indexes of line
147      HAI1->SetValue(1,0);       
148      HAI1->SetValue(2,1);
149      HAI1->SetValue(3,-1);
150
151     }
152     break;
153   case GeomAbs_Circle:
154     {
155       Standard_Real Radius = aCurve.Circle().Radius();
156      if (!Precision::IsInfinite(Radius)) {
157        Standard_Real DU = Sqrt(8.0 * TheDeflection / Radius);
158        Standard_Integer N = Standard_Integer(Abs( U2 - U1) / DU);
159
160        if ( N > 0) {
161
162          gp_Vec V;
163          key = Standard_True;
164          HAV1 = new TColgp_HArray1OfVec(1, N+1);
165          HAI1 = new TColStd_HArray1OfInteger(1,N+2);
166
167          DU = (U2-U1) / N;
168          Standard_Real U;
169          gp_Pnt p;
170
171          for (Standard_Integer Index = 1; Index <= N+1; Index++) {
172            U = U1 + (Index - 1) * DU;
173            p = aCurve.Value(U);
174
175            V.SetX(p.X()); V.SetY(p.Y()); V.SetZ(p.Z());
176            HAV1->SetValue(Index,V);
177            HAI1->SetValue(Index,Index-1);       
178
179          }
180 /*
181          if( HAV1->Value(1).IsEqual( HAV1->Value(N+1),Precision::Confusion(), Precision::Angular() ) )
182            {
183              HAI1->SetValue(N+1, 0);
184            }
185 */       
186          HAI1->SetValue(HAI1->Upper(),-1);
187        }
188      }
189     }
190     break;
191     
192   default:
193     {
194        GCPnts_QuasiUniformDeflection Algo(aCurve,TheDeflection,U1,U2);
195        if(Algo.IsDone()){
196
197          Standard_Integer NumberOfPoints = Algo.NbPoints();
198          if (NumberOfPoints > 0) {
199           
200           gp_Vec V;
201           key = Standard_True;
202           HAV1 = new TColgp_HArray1OfVec(1, NumberOfPoints);
203           HAI1 = new TColStd_HArray1OfInteger(1,NumberOfPoints+1);
204           gp_Pnt p;
205           
206           for (i=1;i<=NumberOfPoints;i++) { 
207             p = Algo.Value(i);
208             V.SetX(p.X()); V.SetY(p.Y()); V.SetZ(p.Z());
209             HAV1->SetValue(i,V);
210           }
211
212           for (i=HAI1->Lower(); i < HAI1->Upper(); i++)
213             {
214               HAI1->SetValue(i,i-1);    
215             }
216           HAI1->SetValue(HAI1->Upper(),-1);
217           
218         }
219       }
220       //else
221       //cannot draw with respect to a maximal chordial deviation
222     }
223   }
224
225 //cout  << " Array HAI1 - coordIndex " << endl;  
226 //     
227 //for ( i=HAI1->Lower(); i <= HAI1->Upper(); i++ )
228 //  {
229 //    cout << HAI1->Value(i) << endl;
230 //  } 
231
232
233   if (key) {
234     PrintPoints(HAV1, HAI1, aDrawer, anOStream);
235   }
236 }
237
238 //==================================================================
239 // function: GetDeflection
240 // purpose:
241 //==================================================================
242 static Standard_Real GetDeflection(const Adaptor3d_Curve&        aCurve,
243                                    const Standard_Real         U1, 
244                                    const Standard_Real         U2, 
245                                    const Handle(VrmlConverter_Drawer)& aDrawer) {
246
247   Standard_Real theRequestedDeflection;
248   if(aDrawer->TypeOfDeflection() == Aspect_TOD_RELATIVE)   // TOD_RELATIVE, TOD_ABSOLUTE
249     {
250       Bnd_Box box;
251       BndLib_Add3dCurve::Add(aCurve, U1, U2, Precision::Confusion(), box);
252
253       Standard_Real  Xmin, Xmax, Ymin, Ymax, Zmin, Zmax, diagonal;
254       box.Get( Xmin, Ymin, Zmin, Xmax, Ymax, Zmax );
255       if (!(box.IsOpenXmin() || box.IsOpenXmax() ||
256             box.IsOpenYmin() || box.IsOpenYmax() ||
257             box.IsOpenZmin() || box.IsOpenZmax()))
258         {
259           diagonal = Sqrt ((Xmax - Xmin)*( Xmax - Xmin) + ( Ymax - Ymin)*( Ymax - Ymin) + ( Zmax - Zmin)*( Zmax - Zmin));
260           diagonal = Max(diagonal, Precision::Confusion());
261           theRequestedDeflection = aDrawer->DeviationCoefficient() * diagonal;      
262         }  
263       else
264         {
265           diagonal =1000000.;
266           theRequestedDeflection = aDrawer->DeviationCoefficient() * diagonal;  
267         }
268 //      cout << "diagonal = " << diagonal << endl;
269 //      cout << "theRequestedDeflection = " << theRequestedDeflection << endl;
270     }
271   else 
272     {
273       theRequestedDeflection = aDrawer->MaximalChordialDeviation(); 
274     }
275   return theRequestedDeflection;
276 }
277 //==================================================================
278 // function: Add
279 // purpose: 1
280 //==================================================================
281 void VrmlConverter_DeflectionCurve::Add(Standard_OStream&                   anOStream, 
282                                          Adaptor3d_Curve&                aCurve, 
283                                         const Handle(VrmlConverter_Drawer)& aDrawer)
284 {
285
286   Standard_Real V1, V2;
287   Standard_Real aLimit = aDrawer->MaximalParameterValue();
288   FindLimits(aCurve, aLimit, V1, V2);
289  
290   Standard_Real theRequestedDeflection = GetDeflection(aCurve, V1, V2, aDrawer);
291
292   DrawCurve(aCurve,
293             theRequestedDeflection,
294             V1 , V2, aDrawer, anOStream);
295 }
296
297 //==================================================================
298 // function: Add 
299 // purpose: 2
300 //==================================================================
301 void VrmlConverter_DeflectionCurve::Add(Standard_OStream&                   anOStream,
302                                         Adaptor3d_Curve&                aCurve, 
303                                         const Standard_Real                 U1, 
304                                         const Standard_Real                 U2, 
305                                         const Handle(VrmlConverter_Drawer)& aDrawer)
306 {
307   Standard_Real V1 = U1;
308   Standard_Real V2 = U2;  
309
310   if (Precision::IsNegativeInfinite(V1)) V1 = -aDrawer->MaximalParameterValue();
311   if (Precision::IsPositiveInfinite(V2)) V2 = aDrawer->MaximalParameterValue();
312
313   Standard_Real theRequestedDeflection = GetDeflection(aCurve, V1, V2, aDrawer);
314   DrawCurve(aCurve,
315             theRequestedDeflection,
316             V1 , V2, aDrawer, anOStream);
317
318 }
319 //==================================================================
320 // function: Add
321 // purpose: 3
322 //==================================================================
323
324 void VrmlConverter_DeflectionCurve::Add(Standard_OStream&    anOStream, 
325                                         Adaptor3d_Curve& aCurve, 
326                                         const Standard_Real  aDeflection, 
327                                         const Standard_Real  aLimit)
328 {
329   Standard_Real V1, V2;
330   FindLimits(aCurve, aLimit, V1, V2);
331
332   Handle(VrmlConverter_Drawer) aDrawer = new VrmlConverter_Drawer;
333   Handle(VrmlConverter_LineAspect) la = new  VrmlConverter_LineAspect;
334   aDrawer->SetLineAspect(la);
335
336   DrawCurve(aCurve,
337             aDeflection,
338             V1 , V2, aDrawer, anOStream);
339 }
340 //==================================================================
341 // function: Add
342 // purpose: 4
343 //==================================================================
344
345 void VrmlConverter_DeflectionCurve::Add(Standard_OStream&                   anOStream, 
346                                         Adaptor3d_Curve&                aCurve, 
347                                         const Standard_Real                 aDeflection, 
348                                         const Handle(VrmlConverter_Drawer)& aDrawer)
349 {
350   Standard_Real aLimit = aDrawer->MaximalParameterValue();
351   Standard_Real V1, V2;
352   FindLimits(aCurve, aLimit, V1, V2);
353
354   DrawCurve(aCurve,
355             aDeflection,
356             V1 , V2, aDrawer, anOStream);
357 }
358 //==================================================================
359 // function: Add
360 // purpose: 5
361 //==================================================================
362
363 void VrmlConverter_DeflectionCurve::Add(Standard_OStream&    anOStream, 
364                                         Adaptor3d_Curve& aCurve, 
365                                         const Standard_Real  U1, 
366                                         const Standard_Real  U2, 
367                                         const Standard_Real  aDeflection)
368 {
369   Handle(VrmlConverter_Drawer) aDrawer = new VrmlConverter_Drawer;
370   Handle(VrmlConverter_LineAspect) la = new VrmlConverter_LineAspect;
371   aDrawer->SetLineAspect(la);
372
373   DrawCurve(aCurve,
374             aDeflection,
375             U1 , U2, aDrawer, anOStream);
376 }
377
378 //==================================================================
379 // function: Add
380 // purpose: 6
381 //==================================================================
382
383 void VrmlConverter_DeflectionCurve::Add(Standard_OStream& anOStream,
384                                         const Adaptor3d_Curve& aCurve,
385                                         const Handle(TColStd_HArray1OfReal)& aParams,
386                                         const Standard_Integer aNbNodes,
387                                         const Handle(VrmlConverter_Drawer)& aDrawer)
388 {
389   Handle(TColgp_HArray1OfVec) aHAV1 = new TColgp_HArray1OfVec(1, aNbNodes);
390   Handle(TColStd_HArray1OfInteger) aHAI1 = new TColStd_HArray1OfInteger(1, aNbNodes + 1);
391
392   Standard_Integer i;
393   gp_Pnt aPoint;
394   gp_Vec aVec;
395   for (i = 1; i<=aNbNodes; i++)
396   {
397     Standard_Real aParam = aParams->Value(aParams->Lower() + i - 1);
398     aPoint = aCurve.Value(aParam);
399     aVec.SetX(aPoint.X());
400     aVec.SetY(aPoint.Y());
401     aVec.SetZ(aPoint.Z());
402     aHAV1->SetValue(i, aVec);
403   }
404
405   for (i = aHAI1->Lower(); i < aHAI1->Upper(); i++)
406   {
407     aHAI1->SetValue(i,i-1);
408   }
409   aHAI1->SetValue(aHAI1->Upper(),-1);
410
411   PrintPoints(aHAV1, aHAI1, aDrawer, anOStream);
412 }