0028417: Using PRECOMPILED HEADER to speed up compilation time
[occt.git] / src / VrmlData / VrmlData_ShapeConvert.cxx
1 // Created on: 2007-08-04
2 // Created by: Alexander GRIGORIEV
3 // Copyright (c) 2007-2014 OPEN CASCADE SAS
4 //
5 // This file is part of Open CASCADE Technology software library.
6 //
7 // This library is free software; you can redistribute it and/or modify it under
8 // the terms of the GNU Lesser General Public License version 2.1 as published
9 // by the Free Software Foundation, with special exception defined in the file
10 // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
11 // distribution for complete text of the license and disclaimer of any warranty.
12 //
13 // Alternatively, this file may be used under the terms of Open CASCADE
14 // commercial license or contractual agreement.
15
16 #include <VrmlData_ShapeConvert.hxx>
17 #include <VrmlData_Scene.hxx>
18 #include <VrmlData_Group.hxx>
19 #include <VrmlData_Coordinate.hxx>
20 #include <VrmlData_IndexedFaceSet.hxx>
21 #include <VrmlData_IndexedLineSet.hxx>
22 #include <VrmlData_ShapeNode.hxx>
23 #include <BRepMesh_IncrementalMesh.hxx>
24 #include <BRep_Builder.hxx>
25 #include <BRep_Tool.hxx>
26 #include <Geom_Surface.hxx>
27 #include <NCollection_DataMap.hxx>
28 #include <Poly_Triangulation.hxx>
29 #include <Poly_Connect.hxx>
30 #include <Poly_PolygonOnTriangulation.hxx>
31 #include <Poly_Polygon3D.hxx>
32 #include <Precision.hxx>
33 #include <TColgp_Array1OfPnt2d.hxx>
34 #include <TopExp_Explorer.hxx>
35 #include <TopoDS.hxx>
36 #include <TopoDS_Edge.hxx>
37 #include <TopoDS_Face.hxx>
38 #include <TopoDS_Shape.hxx>
39 #include <TopoDS_Wire.hxx>
40 #include <GCPnts_TangentialDeflection.hxx>
41 #include <BRepAdaptor_Curve.hxx>
42 #include <TColStd_Array1OfReal.hxx>
43 #include <TColStd_HArray1OfReal.hxx>
44 #include <TShort_Array1OfShortReal.hxx>
45 #include <GeomLib.hxx>
46 #include <TShort_HArray1OfShortReal.hxx>
47 #include <VrmlData_Appearance.hxx>
48
49 //=======================================================================
50 //function : AddShape
51 //purpose  : 
52 //=======================================================================
53
54 void VrmlData_ShapeConvert::AddShape (const TopoDS_Shape& theShape,
55                                       const char *        theName)
56 {
57   ShapeData aData;/* = { - compilation problem on SUN 
58     TCollection_AsciiString(),
59     theShape,
60     NULL
61   };*/
62   aData.Shape = theShape;
63   aData.Node = NULL;
64
65   if (theName) {
66     char buf[2048], * optr = &buf[0];
67     char * eptr = &buf[sizeof(buf)-1];
68     for (const char * ptr = theName;; ptr++) {
69       char sym = *ptr;
70       if (sym == '\0' || sym == '\n' || sym == '\r') {
71         * optr = '\0';
72         break;
73       }
74       if (sym == '\"' || sym == '\\')
75         * optr = '/';
76       else if (sym == '.')
77         * optr = '_';
78       else
79         * optr = sym;
80       if (++optr >= eptr) {
81         *optr = '\0';
82         break;
83       }
84     }
85     aData.Name = buf;
86   }
87   myShapes.Append (aData);
88 }
89
90 //=======================================================================
91 //function : Convert
92 //purpose  : 
93 //=======================================================================
94
95 void VrmlData_ShapeConvert::Convert (const Standard_Boolean theExtractFaces,
96                                      const Standard_Boolean theExtractEdges,
97                                      const Standard_Real    theDeflection,
98                                      const Standard_Real    theDeflAngle)
99 {
100   const Standard_Real aDeflection =
101     theDeflection < 0.0001 ? 0.0001 : theDeflection;
102
103   Standard_Boolean Extract[2] = {theExtractFaces, theExtractEdges};
104   TopAbs_ShapeEnum ShapeType[2] = {TopAbs_FACE, TopAbs_EDGE};
105   Standard_Integer i;
106
107   const Handle(NCollection_IncAllocator) anAlloc = new NCollection_IncAllocator;
108
109   // Relocation map for converted shapes. We should distinguish both TShape
110   // and Orientation in this map.
111   NCollection_DataMap <TopoDS_Shape,Handle(VrmlData_Geometry)>
112     aRelMap (100, anAlloc);
113
114
115   NCollection_List<ShapeData>::Iterator anIter (myShapes);
116   for (; anIter.More(); anIter.Next()) {
117
118     ShapeData& aData = anIter.ChangeValue();
119     Handle(VrmlData_Group) aGroup =
120       new VrmlData_Group (myScene, aData.Name.ToCString());
121     myScene.AddNode (aGroup);
122
123     for(i = 0; i < 2; ++i) {
124
125       if(!Extract[i]) continue;
126
127       TopExp_Explorer anExp (aData.Shape, ShapeType[i]);
128       for (; anExp.More(); anExp.Next()) {
129         const TopoDS_Shape& aShape = anExp.Current();
130         TopLoc_Location aLoc;
131         Handle(VrmlData_Geometry) aTShapeNode;
132         const Standard_Boolean isReverse=(aShape.Orientation()==TopAbs_REVERSED); 
133
134         TopoDS_Shape aTestedShape;
135         aTestedShape.TShape (aShape.TShape());
136         aTestedShape.Orientation (isReverse ? TopAbs_REVERSED : TopAbs_FORWARD);
137         switch (ShapeType[i]) {
138         case TopAbs_FACE:
139           {
140             const TopoDS_Face& aFace = TopoDS::Face (aShape);
141             if (aFace.IsNull() == Standard_False) {
142               Handle(Poly_Triangulation) aTri =
143                 BRep_Tool::Triangulation (aFace, aLoc);
144       
145               if (aRelMap.IsBound (aTestedShape)) {
146                 aTShapeNode = aRelMap(aTestedShape);
147                 break;
148               }
149
150               if (aTri.IsNull() == Standard_False) {
151                 TopoDS_Shape aTestedShapeRev = aTestedShape;
152                 aTestedShapeRev.Orientation (isReverse ?
153                                              TopAbs_FORWARD : TopAbs_REVERSED);
154                 Handle(VrmlData_IndexedFaceSet) aFaceSetToReuse;
155                 if (aRelMap.IsBound (aTestedShapeRev))
156                   aFaceSetToReuse = Handle(VrmlData_IndexedFaceSet)::DownCast
157                     (aRelMap(aTestedShapeRev));
158
159                 Handle(VrmlData_Coordinate) aCoordToReuse;
160                 if (aFaceSetToReuse.IsNull() == Standard_False)
161                   aCoordToReuse = aFaceSetToReuse->Coordinates();
162
163                 aTShapeNode = triToIndexedFaceSet (aTri, aFace, aCoordToReuse);
164                 myScene.AddNode (aTShapeNode, Standard_False);
165                 // Bind the converted face
166                 aRelMap.Bind (aTestedShape, aTShapeNode);
167               }
168             }
169           }
170           break;
171         case TopAbs_WIRE:
172           {
173             const TopoDS_Wire& aWire = TopoDS::Wire (aShape);
174             if (aWire.IsNull() == Standard_False) {
175             }
176           }
177           break;
178        case TopAbs_EDGE:
179          {
180            const TopoDS_Edge& aEdge = TopoDS::Edge (aShape);
181             if (aEdge.IsNull() == Standard_False) {
182               if (aRelMap.IsBound (aTestedShape)) {
183                 aTShapeNode = aRelMap(aTestedShape);
184                 break;
185               }
186               // Check the presence of reversly oriented Edge. It can also be used
187               // because we do not distinguish the orientation for edges.
188               aTestedShape.Orientation (isReverse ?
189                                         TopAbs_FORWARD : TopAbs_REVERSED);
190               if (aRelMap.IsBound (aTestedShape)) {
191                 aTShapeNode = aRelMap(aTestedShape);
192                 break;
193               }
194
195               //try to find PolygonOnTriangulation
196               Handle(Poly_PolygonOnTriangulation) aPT;
197               Handle(Poly_Triangulation) aT;
198               TopLoc_Location aL;
199               BRep_Tool::PolygonOnTriangulation(aEdge, aPT, aT, aL);
200
201               // If PolygonOnTriangulation was found -> get the Polygon3D
202               Handle(Poly_Polygon3D) aPol;
203               if(!aPT.IsNull() && !aT.IsNull() && aPT->HasParameters()) {
204                 BRepAdaptor_Curve aCurve(aEdge);
205                 Handle(TColStd_HArray1OfReal) aPrs = aPT->Parameters();
206                 Standard_Integer nbNodes = aPT->NbNodes();
207                 TColgp_Array1OfPnt arrNodes(1, nbNodes);
208                 TColStd_Array1OfReal arrUVNodes(1, nbNodes);
209
210                 for(Standard_Integer j = 1; j <= nbNodes; j++) {
211                   arrUVNodes(j) = aPrs->Value(aPrs->Lower() + j - 1);
212                   arrNodes(j) = aCurve.Value(arrUVNodes(j));
213                 }
214                 aPol = new Poly_Polygon3D(arrNodes, arrUVNodes);
215                 aPol->Deflection (aPT->Deflection());
216               }
217               else {
218                 aPol = BRep_Tool::Polygon3D(aEdge, aL);
219
220                 // If polygon was not found -> generate it
221                 if (aPol.IsNull()) {
222                   BRepAdaptor_Curve aCurve(aEdge);
223                   const Standard_Real aFirst = aCurve.FirstParameter();
224                   const Standard_Real aLast  = aCurve.LastParameter();
225                 
226                   GCPnts_TangentialDeflection TD (aCurve, aFirst, aLast,
227                                                   theDeflAngle, aDeflection, 2);
228                   const Standard_Integer nbNodes = TD.NbPoints();
229                 
230                   TColgp_Array1OfPnt arrNodes(1, nbNodes);
231                   TColStd_Array1OfReal arrUVNodes(1, nbNodes);
232                   for (Standard_Integer j = 1; j <= nbNodes; j++) {
233                     arrNodes(j) = TD.Value(j);
234                     arrUVNodes(j) = TD.Parameter(j);
235                   }
236                   aPol = new Poly_Polygon3D(arrNodes, arrUVNodes);
237                   aPol->Deflection (aDeflection);
238                 }
239               }
240
241               if (aPol.IsNull())
242                 continue;
243
244               aTShapeNode = polToIndexedLineSet (aPol);
245               myScene.AddNode (aTShapeNode, Standard_False);
246               // Bind the converted face
247               aRelMap.Bind (aTestedShape, aTShapeNode);
248             }
249           }
250           break;
251         default:
252           break;
253         }
254         
255         if (aTShapeNode.IsNull() == Standard_False) {
256           const Handle(VrmlData_ShapeNode) aShapeNode =
257             new VrmlData_ShapeNode (myScene, 0L);
258           aShapeNode->SetAppearance (ShapeType[i] == TopAbs_FACE ?
259                                      defaultMaterialFace():defaultMaterialEdge());
260           myScene.AddNode (aShapeNode, Standard_False);
261           aShapeNode->SetGeometry (aTShapeNode);
262           if (aLoc.IsIdentity())
263             // Store the shape node directly into the main Group.
264             aGroup->AddNode (aShapeNode);
265           else {
266             // Create a Transform grouping node
267             Handle(VrmlData_Group) aTrans = new VrmlData_Group (myScene, 0L,
268                                                                 Standard_True);
269             gp_Trsf aTrsf (aLoc);
270             if (fabs(myScale - 1.) > Precision::Confusion()) {
271               const gp_XYZ aTransl = aTrsf.TranslationPart() * myScale;
272               aTrsf.SetTranslationPart (aTransl);
273             }
274             aTrans->SetTransform (aTrsf);
275             myScene.AddNode (aTrans, Standard_False);
276             aGroup->AddNode (aTrans);
277             
278             // Store the shape node under the transform.
279             aTrans->AddNode (aShapeNode);
280           }
281         }
282       }
283     }
284   }
285   myShapes.Clear();
286 }
287
288 //=======================================================================
289 //function : triToIndexedFaceSet
290 //purpose  : 
291 //=======================================================================
292
293 Handle(VrmlData_Geometry) VrmlData_ShapeConvert::triToIndexedFaceSet
294                                   (const Handle(Poly_Triangulation)&  theTri,
295                                    const TopoDS_Face&                theFace,
296                                    const Handle(VrmlData_Coordinate)& theCoord)
297 {
298   Standard_Integer i;
299   const Standard_Integer nNodes         (theTri->NbNodes());
300   const Standard_Integer nTriangles     (theTri->NbTriangles());
301   const TColgp_Array1OfPnt&    arrPolyNodes = theTri->Nodes();
302   const Poly_Array1OfTriangle& arrTriangles = theTri->Triangles();
303
304   const Handle(VrmlData_IndexedFaceSet) aFaceSet =
305     new VrmlData_IndexedFaceSet (myScene,
306                                  0L,                    // no name
307                                  Standard_True,         // IsCCW
308                                  Standard_False,        // IsSolid
309                                  Standard_False);       // IsConvex
310   const Handle(NCollection_IncAllocator)& anAlloc = myScene.Allocator();
311   const Standard_Boolean isReverse = (theFace.Orientation() == TopAbs_REVERSED);
312
313   // Create the array of triangles
314   const Standard_Integer ** arrPolygons = static_cast<const Standard_Integer **>
315     (anAlloc->Allocate (nTriangles * sizeof(const Standard_Integer *)));
316   aFaceSet->SetPolygons (nTriangles, arrPolygons);
317
318   // Store the triangles
319   for (i = 0; i < nTriangles; i++) {
320     Standard_Integer * aPolygon = static_cast<Standard_Integer *>
321       (anAlloc->Allocate (4*sizeof(Standard_Integer)));
322     aPolygon[0] = 3;
323     arrTriangles(i+1).Get (aPolygon[1],aPolygon[2],aPolygon[3]);
324     aPolygon[1]--;
325     if (isReverse) {
326       const Standard_Integer aTmp = aPolygon[2]-1;
327       aPolygon[2] = aPolygon[3]-1;
328       aPolygon[3] = aTmp;
329     } else {
330       aPolygon[2]--;
331       aPolygon[3]--;
332     }
333     arrPolygons[i] = aPolygon;
334   }
335
336   // Create the Coordinates node
337   if (theCoord.IsNull() == Standard_False)
338     aFaceSet->SetCoordinates (theCoord);
339   else {
340     gp_XYZ * arrNodes = static_cast <gp_XYZ *>
341       (anAlloc->Allocate (nNodes * sizeof(gp_XYZ)));
342     for  (i = 0; i < nNodes; i++)
343       arrNodes[i] = arrPolyNodes(i+1).XYZ() * myScale;
344
345     const Handle(VrmlData_Coordinate) aCoordNode =
346       new VrmlData_Coordinate (myScene, 0L, nNodes, arrNodes);
347     myScene.AddNode (aCoordNode, Standard_False);
348     aFaceSet->SetCoordinates (aCoordNode);
349   }
350
351   // Create the Normals node if theTri has normals
352   if(theTri->HasNormals()) {
353     gp_XYZ * arrVec = static_cast <gp_XYZ *>
354       (anAlloc->Allocate (nNodes * sizeof(gp_XYZ)));
355     const TShort_Array1OfShortReal& Norm = theTri->Normals();
356     Standard_Integer j;
357     for  (i = 0, j = 1; i < nNodes; i++, j += 3) {
358       
359       gp_XYZ aNormal(Norm(j), Norm(j+1), Norm(j+2));
360       arrVec[i] = aNormal;
361
362     }
363     const Handle(VrmlData_Normal) aNormalNode =
364       new VrmlData_Normal (myScene, 0L, nNodes, arrVec);
365     myScene.AddNode (aNormalNode, Standard_False);
366     aFaceSet->SetNormals (aNormalNode);
367     return Handle(VrmlData_Geometry) (aFaceSet);
368   }
369
370   Poly_Connect PC(theTri);
371   // Create the Normals node (if UV- values are available)
372   TopLoc_Location aLoc;
373   const Standard_Real aConf2 = Precision::SquareConfusion();
374   const Handle(Geom_Surface) aSurface = BRep_Tool::Surface (theFace, aLoc);
375   if (theTri->HasUVNodes() && aSurface.IsNull() == Standard_False) {
376     if (aSurface->IsCNu(1) && aSurface->IsCNv(1))
377     {
378       Standard_Integer nbNormVal  = nNodes * 3; 
379       Handle(TShort_HArray1OfShortReal) Normals = 
380         new TShort_HArray1OfShortReal(1, nbNormVal);
381
382       const TColgp_Array1OfPnt2d& arrUV = theTri->UVNodes();
383       gp_XYZ * arrVec = static_cast <gp_XYZ *>
384         (anAlloc->Allocate (nNodes * sizeof(gp_XYZ)));
385
386       // Compute the normal vectors
387       Standard_Real Tol = Sqrt(aConf2);
388       for  (i = 0; i < nNodes; i++) {
389         const gp_Pnt2d& aUV = arrUV(i+1);
390         
391         gp_Dir aNormal;
392         
393         if (GeomLib::NormEstim(aSurface, aUV, Tol, aNormal) > 1) {
394           //Try to estimate as middle normal of adjacent triangles
395           Standard_Integer n[3];
396
397           gp_XYZ eqPlan(0., 0., 0.);
398           for (PC.Initialize(i+1);  PC.More(); PC.Next()) {
399             arrTriangles(PC.Value()).Get(n[0], n[1], n[2]);
400             gp_XYZ v1(arrPolyNodes(n[1]).Coord()-arrPolyNodes(n[0]).Coord());
401             gp_XYZ v2(arrPolyNodes(n[2]).Coord()-arrPolyNodes(n[1]).Coord());
402             gp_XYZ vv = v1^v2;
403
404             Standard_Real mod = vv.Modulus();
405             if (mod < Tol)
406               continue;
407
408             eqPlan += vv/mod;
409           }
410
411           if (eqPlan.SquareModulus() > gp::Resolution())
412             aNormal = gp_Dir(eqPlan);
413         }
414         if (isReverse)
415           aNormal.Reverse();
416
417         if (aNormal.X()*aNormal.X() < aConf2)
418           aNormal.SetX(0.);
419         if (aNormal.Y()*aNormal.Y() < aConf2)
420           aNormal.SetY(0.);
421         if (aNormal.Z()*aNormal.Z() < aConf2)
422           aNormal.SetZ(0.);
423         arrVec[i] = aNormal.XYZ();
424
425         Standard_Integer j = i * 3;
426         Normals->SetValue(j + 1, (Standard_ShortReal)aNormal.X());
427         Normals->SetValue(j + 2, (Standard_ShortReal)aNormal.Y());
428         Normals->SetValue(j + 3, (Standard_ShortReal)aNormal.Z());
429
430       }
431
432       theTri->SetNormals(Normals);  
433   
434       const Handle(VrmlData_Normal) aNormalNode =
435         new VrmlData_Normal (myScene, 0L, nNodes, arrVec);
436       myScene.AddNode (aNormalNode, Standard_False);
437       aFaceSet->SetNormals (aNormalNode);
438     }
439   }
440
441   return Handle(VrmlData_Geometry) (aFaceSet);
442 }
443
444 //=======================================================================
445 //function : polToIndexedLineSet
446 //purpose  : single polygon3D => IndexedLineSet
447 //=======================================================================
448
449 Handle(VrmlData_Geometry) VrmlData_ShapeConvert::polToIndexedLineSet
450                                         (const Handle(Poly_Polygon3D)& thePol)
451 {
452   Standard_Integer i;
453   const Standard_Integer    nNodes (thePol->NbNodes());
454   const TColgp_Array1OfPnt& arrPolyNodes = thePol->Nodes();
455   const Handle(NCollection_IncAllocator)& anAlloc = myScene.Allocator();
456
457   const Handle(VrmlData_IndexedLineSet) aLineSet =
458     new VrmlData_IndexedLineSet (myScene, 0L);
459
460   // Create the array of polygons (1 member)
461   const Standard_Integer ** arrPolygons = static_cast<const Standard_Integer **>
462     (anAlloc->Allocate (sizeof(const Standard_Integer *)));
463   aLineSet->SetPolygons (1, arrPolygons);
464
465   // Store the polygon
466   Standard_Integer * aPolygon = static_cast<Standard_Integer *>
467     (anAlloc->Allocate ((nNodes+1)*sizeof(Standard_Integer)));
468   aPolygon[0] = nNodes;
469   for (i = 1; i <= nNodes; i++)
470     aPolygon[i] = i-1;
471   arrPolygons[0] = aPolygon;
472
473   // Create the Coordinates node
474   gp_XYZ * arrNodes = static_cast <gp_XYZ *>
475     (anAlloc->Allocate (nNodes * sizeof(gp_XYZ)));
476   for  (i = 0; i < nNodes; i++)
477     arrNodes[i] = arrPolyNodes(i+1).XYZ() * myScale;
478
479   const Handle(VrmlData_Coordinate) aCoordNode =
480     new VrmlData_Coordinate (myScene, 0L, nNodes, arrNodes);
481   myScene.AddNode (aCoordNode, Standard_False);
482   aLineSet->SetCoordinates (aCoordNode);
483
484   return Handle(VrmlData_Geometry) (aLineSet);
485 }
486
487 //=======================================================================
488 //function : defaultMaterialFace
489 //purpose  : 
490 //=======================================================================
491
492 Handle(VrmlData_Appearance) VrmlData_ShapeConvert::defaultMaterialFace () const
493 {
494   static char aNodeName[] = "__defaultMaterialFace";
495   Handle(VrmlData_Appearance) anAppearance =
496     Handle(VrmlData_Appearance)::DownCast(myScene.FindNode(aNodeName));
497   if (anAppearance.IsNull()) {
498     const Handle(VrmlData_Material) aMaterial =
499       new VrmlData_Material (myScene, 0L, 1.0, 0.022, 0.);
500     aMaterial->SetDiffuseColor (Quantity_Color(0.780392, 0.568627, 0.113725,
501                                                Quantity_TOC_RGB));
502     aMaterial->SetEmissiveColor(Quantity_Color(0.329412, 0.223529, 0.027451,
503                                                Quantity_TOC_RGB));
504     aMaterial->SetSpecularColor(Quantity_Color(0.992157, 0.941176, 0.807843,
505                                                Quantity_TOC_RGB));
506     myScene.AddNode (aMaterial, Standard_False);
507     anAppearance = new VrmlData_Appearance (myScene, aNodeName);
508     anAppearance->SetMaterial (aMaterial);
509     myScene.AddNode (anAppearance, Standard_False);
510   }
511   return anAppearance;
512 }
513
514 //=======================================================================
515 //function : defaultMaterialEdge
516 //purpose  : 
517 //=======================================================================
518
519 Handle(VrmlData_Appearance) VrmlData_ShapeConvert::defaultMaterialEdge () const
520 {
521   static char aNodeName[] = "__defaultMaterialEdge";
522   Handle(VrmlData_Appearance) anAppearance =
523     Handle(VrmlData_Appearance)::DownCast(myScene.FindNode(aNodeName));
524   if (anAppearance.IsNull()) { 
525     const Handle(VrmlData_Material) aMaterial =
526       new VrmlData_Material (myScene, 0L, 0.2, 0.2, 0.2);
527     aMaterial->SetDiffuseColor (Quantity_Color(0.2, 0.7, 0.2,
528                                                Quantity_TOC_RGB));
529     aMaterial->SetEmissiveColor(Quantity_Color(0.2, 0.7, 0.2,
530                                                Quantity_TOC_RGB));
531     aMaterial->SetSpecularColor(Quantity_Color(0.2, 0.7, 0.2,
532                                                Quantity_TOC_RGB));
533     myScene.AddNode (aMaterial, Standard_False);
534     anAppearance = new VrmlData_Appearance (myScene, aNodeName);
535     anAppearance->SetMaterial (aMaterial);
536     myScene.AddNode (anAppearance, Standard_False);
537   }
538   return anAppearance;
539 }