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