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