be90081174e34d0608bae22dd19f881b35ef29bd
[occt.git] / src / VrmlConverter / VrmlConverter_ShadedShape.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_Drawer.hxx>
15 #include <VrmlConverter_ShadedShape.hxx>
16 #include <Vrml_Normal.hxx>
17 #include <TopoDS_Shape.hxx>
18 #include <TopoDS_Face.hxx>
19 #include <TopoDS.hxx>
20 #include <TopAbs.hxx>
21 #include <Poly_Connect.hxx>
22 #include <TColgp_Array1OfDir.hxx>
23 #include <TColgp_HArray1OfVec.hxx>
24 #include <Poly_Triangle.hxx>
25 #include <Poly_Triangulation.hxx>
26 #include <BRepTools.hxx>
27 #include <BRep_Tool.hxx>
28 #include <gp_Pnt.hxx>
29 #include <gp_Vec.hxx>
30 #include <TopExp_Explorer.hxx>
31 #include <TopLoc_Location.hxx>
32 #include <TColgp_Array1OfPnt.hxx>
33 #include <Poly_Array1OfTriangle.hxx>
34 #include <Vrml_IndexedFaceSet.hxx>
35 #include <Vrml_Coordinate3.hxx>
36 #include <BRepBndLib.hxx>
37 #include <Bnd_Box.hxx>
38 #include <math.hxx>
39 #include <TColStd_HArray1OfInteger.hxx>
40 #include <Geom_Surface.hxx>
41 #include <CSLib_DerivativeStatus.hxx>
42 #include <CSLib_NormalStatus.hxx>
43 #include <CSLib.hxx>
44 #include <BRepAdaptor_Surface.hxx>
45 #include <TColgp_Array1OfPnt2d.hxx>
46 #include <Precision.hxx>
47 #include <Vrml_Material.hxx>
48 #include <VrmlConverter_ShadingAspect.hxx>
49 #include <Vrml_ShapeHints.hxx>
50 #include <Vrml_MaterialBindingAndNormalBinding.hxx>
51 #include <Vrml_NormalBinding.hxx>
52 #include <Vrml_Separator.hxx>
53 #include <Vrml_NormalBinding.hxx>
54 #include <BRepMesh_IncrementalMesh.hxx>
55
56 //=========================================================================
57 // function: Add
58 // purpose
59 //=========================================================================
60 void VrmlConverter_ShadedShape::Add( Standard_OStream& anOStream, 
61                                      const TopoDS_Shape& aShape,
62                                      const Handle(VrmlConverter_Drawer)& aDrawer )
63   {
64
65   // here the triangulation is computed on the whole shape
66   //  if it does not yet exist
67
68
69     Standard_Real theRequestedDeflection;
70     if(aDrawer->TypeOfDeflection() == Aspect_TOD_RELATIVE)   // TOD_RELATIVE, TOD_ABSOLUTE
71       {
72         Bnd_Box box;
73         BRepBndLib::AddClose(aShape, box);
74
75         Standard_Real  Xmin, Xmax, Ymin, Ymax, Zmin, Zmax, diagonal;
76         box.Get( Xmin, Ymin, Zmin, Xmax, Ymax, Zmax );
77         if (!(box.IsOpenXmin() || box.IsOpenXmax() ||
78               box.IsOpenYmin() || box.IsOpenYmax() ||
79               box.IsOpenZmin() || box.IsOpenZmax()))
80             {
81
82             diagonal = Sqrt ((Xmax - Xmin)*( Xmax - Xmin) + ( Ymax - Ymin)*( Ymax - Ymin) + ( Zmax - Zmin)*( Zmax - Zmin));
83             diagonal = Max(diagonal, Precision::Confusion());
84             theRequestedDeflection = aDrawer->DeviationCoefficient() * diagonal;      
85           }
86         else
87           {
88             diagonal =1000000.;
89             theRequestedDeflection = aDrawer->DeviationCoefficient() * diagonal;  
90           }
91 //      cout << "diagonal = "<< diagonal << endl;
92 //      cout << "theRequestedDeflection = "<< theRequestedDeflection << endl;
93
94       }
95     else 
96       {
97         theRequestedDeflection = aDrawer->MaximalChordialDeviation(); 
98       }
99
100     if (!BRepTools::Triangulation(aShape,theRequestedDeflection))
101     {
102       // computes and save the triangulation in the face.
103       BRepMesh_IncrementalMesh(aShape,theRequestedDeflection);
104     }
105   
106   
107   Handle(Poly_Triangulation) T;
108   TopLoc_Location theLocation;
109   Standard_Integer i, j, k, decal, nnv, EI;
110   
111   Standard_Integer t[3], n[3];
112   gp_Pnt p;
113   TopExp_Explorer ex;
114
115   // counting phasis. This phasis will count the valid triangle
116   // and the vertices to allocate the correct size for the arrays: 
117   
118   Standard_Integer nbTriangles = 0, nbVertices = 0;
119   
120   Standard_Integer nt, nnn, n1, n2, n3;
121     
122   // iterating on each face of the shape:
123   for (ex.Init(aShape, TopAbs_FACE); ex.More(); ex.Next()) {  
124     // getting the face:
125     const TopoDS_Face& F = TopoDS::Face(ex.Current());
126     // getting the triangulation of the face. The triangulation may not exist:
127     T = BRep_Tool::Triangulation(F, theLocation);
128       // number of triangles:
129     if (T.IsNull()) continue; //smh 
130       nnn = T->NbTriangles();            
131     
132     const TColgp_Array1OfPnt& Nodes = T->Nodes(); 
133     // getting a triangle. It is  a triplet of indices in the node table:       
134     const Poly_Array1OfTriangle& triangles = T->Triangles(); 
135     
136     // Taking the nodes of the triangle, taking into account the orientation
137     // of the triangle.
138     for (nt = 1; nt <= nnn; nt++) {
139       if (F.Orientation() == TopAbs_REVERSED) 
140         triangles(nt).Get(n1,n3,n2);
141       else 
142         triangles(nt).Get(n1,n2,n3);
143       
144       const gp_Pnt& P1 = Nodes(n1);
145       const gp_Pnt& P2 = Nodes(n2);
146       const gp_Pnt& P3 = Nodes(n3);
147       // controlling whether the triangle correct from a 3d point of 
148       // view: (the triangle may exist in the UV space but the
149       // in the 3d space a dimension is null for example)
150       gp_Vec V1(P1,P2);
151       if (V1.SquareMagnitude() > 1.e-10) {
152         gp_Vec V2(P2,P3);
153         if (V2.SquareMagnitude() > 1.e-10) {
154           gp_Vec V3(P3,P1);
155           if (V3.SquareMagnitude() > 1.e-10) {
156             V1.Normalize();
157             V2.Normalize();
158             V1.Cross(V2);
159             if (V1.SquareMagnitude() > 1.e-10) {
160               nbTriangles++;
161               }
162           }
163         }
164       }
165     }
166     nbVertices += T->NbNodes();
167   }      
168
169 //     cout << "nbTriangles = "<< nbTriangles << endl;
170 //     cout  << "nbVertices = "<< nbVertices << endl << endl;  
171
172 //----------------------------
173   // now we are going to iterate again to build graphic data from the triangle.   
174   if (nbVertices > 2 && nbTriangles > 0) {
175     // allocating the graphic arrays.
176
177      Handle(VrmlConverter_ShadingAspect) SA = new VrmlConverter_ShadingAspect;
178      SA = aDrawer->ShadingAspect();
179
180      Handle(TColgp_HArray1OfVec) HAV1 = new TColgp_HArray1OfVec(1, nbVertices);
181      Handle(TColgp_HArray1OfVec) HAV2 = new TColgp_HArray1OfVec(1, nbVertices);
182      
183      gp_Vec V, VV;
184
185      Handle(TColStd_HArray1OfInteger) HAI1 = new TColStd_HArray1OfInteger(1,4*nbTriangles);
186      Handle(TColStd_HArray1OfInteger) HAI3 = new TColStd_HArray1OfInteger(1,(nbVertices/3*4+nbVertices%3));
187      Handle(TColStd_HArray1OfInteger) HAI2 = new TColStd_HArray1OfInteger(1,1);
188      Handle(TColStd_HArray1OfInteger) HAI4 = new TColStd_HArray1OfInteger(1,1);
189
190         HAI2->SetValue (1,-1);
191         HAI4->SetValue (1,-1);
192
193 // !! Specialize HAI2 -  materialIndex  HAI4 - textureCoordinateIndex
194
195     EI = 1;
196     nnv = 1;
197
198     for (ex.Init(aShape, TopAbs_FACE); ex.More(); ex.Next()) {
199       const TopoDS_Face& F = TopoDS::Face(ex.Current());
200       T = BRep_Tool::Triangulation(F, theLocation);
201       if (!T.IsNull()) {
202         Poly_Connect pc(T);
203         
204         // 1 -  Building HAV1 -  array of all XYZ of nodes for Vrml_Coordinate3 from the triangles
205         //            and HAV2 - array of all normals of nodes for Vrml_Normal
206         
207         const TColgp_Array1OfPnt& Nodes = T->Nodes();
208         TColgp_Array1OfDir NORMAL(Nodes.Lower(), Nodes.Upper());
209
210           decal = nnv-1;
211         
212         for (j= Nodes.Lower(); j<= Nodes.Upper(); j++) {
213           p = Nodes(j).Transformed(theLocation.Transformation());
214
215           V.SetX(p.X()); V.SetY(p.Y()); V.SetZ(p.Z());
216           HAV1->SetValue(nnv,V);
217
218           if(SA->HasNormals())
219             {
220                 // to compute the normal.
221               ComputeNormal(F, pc, NORMAL);
222
223               VV.SetX(NORMAL(j).X());  VV.SetY(NORMAL(j).Y());  VV.SetZ(NORMAL(j).Z());
224               HAV2->SetValue(nnv,VV);
225             }
226           nnv++;
227         }
228         
229         // 2 -   Building HAI1 - array of indexes of all triangles and
230         //        HAI3 - array of indexes of all normales  for Vrml_IndexedFaceSet
231         nbTriangles = T->NbTriangles();
232         const Poly_Array1OfTriangle& triangles = T->Triangles();        
233         for (i = 1; i <= nbTriangles; i++) {
234           pc.Triangles(i,t[0],t[1],t[2]);
235           if (F.Orientation() == TopAbs_REVERSED) 
236             triangles(i).Get(n[0],n[2],n[1]);
237           else 
238             triangles(i).Get(n[0],n[1],n[2]);
239           const gp_Pnt& P1 = Nodes(n[0]);
240           const gp_Pnt& P2 = Nodes(n[1]);
241           const gp_Pnt& P3 = Nodes(n[2]);
242           gp_Vec V1(P1,P2);
243           if (V1.SquareMagnitude() > 1.e-10) {
244             gp_Vec V2(P2,P3);
245             if (V2.SquareMagnitude() > 1.e-10) {
246               gp_Vec V3(P3,P1);
247               if (V3.SquareMagnitude() > 1.e-10) {
248                 V1.Normalize();
249                 V2.Normalize();
250                 V1.Cross(V2);
251                 if (V1.SquareMagnitude() > 1.e-10) {
252                   for (j = 0; j < 3; j++) {
253                    
254                     HAI1->SetValue(EI, n[j]+decal-1);   // array of indexes of all triangles
255                     EI++;
256                   }
257
258                   HAI1->SetValue(EI, -1);                   
259                   EI++;           
260                 }
261               }
262             }
263           }
264         }
265       }
266     }
267   
268
269      if(SA->HasNormals())
270        {
271          j=1;
272          for (i=HAI3->Lower(); i <= HAI3->Upper(); i++)
273            {
274              k = i % 4;
275              if (k == 0)
276                {
277                  HAI3->SetValue(i, -1);
278                  j++;
279                }
280              else
281                {
282                  HAI3->SetValue(i, i-j);   
283                }
284            }
285        }
286
287 //-----------------------------
288 /*
289   cout  << " ******************** " << endl;  
290      cout  << " Array HAV1 - Coordinare3 " << endl;  
291
292      for ( i=HAV1->Lower(); i <= HAV1->Upper(); i++ )
293        {
294          cout << HAV1->Value(i).X() << " " << HAV1->Value(i).Y()<< " " << HAV1->Value(i).Z() << endl; 
295        }
296
297      if(SA->HasNormals())
298        {
299
300          cout  << " ******************** " << endl;         
301          cout  << " Array HAV2 - Normals " << endl;  
302
303          for ( i=HAV2->Lower(); i <= HAV2->Upper(); i++ )
304            {
305              cout << HAV2->Value(i).X() << " " << HAV2->Value(i).Y()<< " " << HAV2->Value(i).Z() << endl; 
306            }
307
308          cout  << " ******************** " << endl;  
309          cout  << " Array HAI3 - normalIndex " << endl;  
310
311          for ( i=HAI3->Lower(); i <= HAI3->Upper(); i++ )
312            {
313              cout << HAI3->Value(i) << endl;
314            }
315
316        }
317
318      cout  << " ******************** " << endl;         
319      cout  << " Array HAI1 - coordIndex " << endl;  
320        
321      for ( i=HAI1->Lower(); i <= HAI1->Upper(); i++ )
322        {
323          cout << HAI1->Value(i) << endl;
324        }
325    
326      cout  << " ******************** " << endl;       
327 */
328 //----------------------------
329
330 // creation of Vrml objects
331
332      Vrml_ShapeHints  SH; 
333      SH = SA->ShapeHints();
334
335      if(SA->HasNormals())
336        {
337 // Separator 1 {
338      Vrml_Separator SE1;
339      SE1.Print(anOStream);
340 // Material
341   if (SA->HasMaterial()){
342
343      Handle(Vrml_Material) M;
344      M = SA->FrontMaterial();
345
346      M->Print(anOStream);
347    }
348
349 // Coordinate3
350      Handle(Vrml_Coordinate3)  C3 = new Vrml_Coordinate3(HAV1);
351      C3->Print(anOStream);
352 // ShapeHints
353      SH.Print(anOStream);
354 // NormalBinding
355      Vrml_MaterialBindingAndNormalBinding MBNB1 = Vrml_PER_VERTEX_INDEXED;
356      Vrml_NormalBinding   NB(MBNB1);
357      NB.Print(anOStream);
358 // Separator 2 {
359      Vrml_Separator SE2;
360      SE2.Print(anOStream);
361 // Normal
362      Vrml_Normal  N(HAV2);
363      N.Print(anOStream);
364 // IndexedFaceSet
365      Vrml_IndexedFaceSet  IFS;
366      IFS.SetCoordIndex(HAI1);
367      IFS.SetNormalIndex(HAI3);
368      IFS.Print(anOStream);
369 // Separator 2 }     
370      SE2.Print(anOStream);
371 // Separator 1 }
372      SE1.Print(anOStream);
373         }
374      else 
375        { 
376 // Separator 1 {
377      Vrml_Separator SE1;
378      SE1.Print(anOStream);
379 // Material
380   if (SA->HasMaterial()){
381
382      Handle(Vrml_Material) M;
383      M = SA->FrontMaterial();
384
385      M->Print(anOStream);
386    }
387 // Coordinate3
388      Handle(Vrml_Coordinate3)  C3 = new Vrml_Coordinate3(HAV1);
389      C3->Print(anOStream);
390 // ShapeHints
391      SH.Print(anOStream);
392 // IndexedFaceSet
393      Vrml_IndexedFaceSet  IFS;
394      IFS.SetCoordIndex(HAI1);
395      IFS.Print(anOStream);
396 // Separator 1 }
397      SE1.Print(anOStream);
398        }
399   }
400 }
401
402
403 //--------- Notes -------------
404
405 // the necessary of calculation of Normals and Textures must be define in Drawer
406 // likes tolerance
407
408 //---------- End on notes ------------
409
410
411
412 //----------------------------
413 // Computing the normal
414 //-----------------------------
415
416 void VrmlConverter_ShadedShape::ComputeNormal(const TopoDS_Face& aFace, 
417                                               Poly_Connect& pc, 
418                                               TColgp_Array1OfDir& Nor)
419 {
420   const Handle(Poly_Triangulation)& T = pc.Triangulation();
421   BRepAdaptor_Surface S;
422   Standard_Boolean hasUV = T->HasUVNodes();
423   Standard_Integer i;
424   TopLoc_Location l;
425   Handle(Geom_Surface) GS = BRep_Tool::Surface(aFace, l);
426
427   if (hasUV && !GS.IsNull()) {
428     Standard_Boolean OK = Standard_True;
429     gp_Vec D1U,D1V;
430     gp_Vec D2U,D2V,D2UV;
431     gp_Pnt P;
432     Standard_Real U, V;
433     CSLib_DerivativeStatus Status;
434     CSLib_NormalStatus NStat;
435     S.Initialize(aFace);
436     const TColgp_Array1OfPnt2d& UVNodes = T->UVNodes();
437     for (i = UVNodes.Lower(); i <= UVNodes.Upper(); i++) {
438       U = UVNodes(i).X();
439       V = UVNodes(i).Y();
440       S.D1(U,V,P,D1U,D1V);
441       CSLib::Normal(D1U,D1V,Precision::Angular(),Status,Nor(i));
442       if (Status != CSLib_Done) {
443         S.D2(U,V,P,D1U,D1V,D2U,D2V,D2UV);
444         CSLib::Normal(D1U,D1V,D2U,D2V,D2UV,Precision::Angular(),OK,NStat,Nor(i));
445       }
446       if (aFace.Orientation() == TopAbs_REVERSED) (Nor(i)).Reverse();
447     }
448   }
449   else {
450     const TColgp_Array1OfPnt& Nodes = T->Nodes();
451     Standard_Integer n[3];
452     const Poly_Array1OfTriangle& triangles = T->Triangles();
453
454     for (i = Nodes.Lower(); i <= Nodes.Upper(); i++) {
455       gp_XYZ eqPlan(0, 0, 0);
456       for (pc.Initialize(i);  pc.More(); pc.Next()) {
457         triangles(pc.Value()).Get(n[0], n[1], n[2]);
458         gp_XYZ v1(Nodes(n[1]).Coord()-Nodes(n[0]).Coord());
459         gp_XYZ v2(Nodes(n[2]).Coord()-Nodes(n[1]).Coord());
460         eqPlan += (v1^v2).Normalized();
461       }
462       Nor(i) = gp_Dir(eqPlan);
463       if (aFace.Orientation() == TopAbs_REVERSED) (Nor(i)).Reverse();
464     }
465   }
466 }
467
468