0031668: Visualization - WebGL sample doesn't work on Emscripten 1.39
[occt.git] / src / IVtkOCC / IVtkOCC_ShapeMesher.cxx
1 // Created on: 2011-10-14 
2 // Created by: Roman KOZLOV
3 // Copyright (c) 2011-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 <Adaptor3d_IsoCurve.hxx>
17 #include <Bnd_Box.hxx>
18 #include <BRep_Tool.hxx>
19 #include <BRepBndLib.hxx>
20 #include <BRepMesh_DiscretFactory.hxx>
21 #include <BRepMesh_DiscretRoot.hxx>
22 #include <BRepTools.hxx>
23 #include <Hatch_Hatcher.hxx>
24 #include <GCPnts_QuasiUniformDeflection.hxx>
25 #include <GCPnts_TangentialDeflection.hxx>
26 #include <Geom_BezierSurface.hxx>
27 #include <Geom_BSplineSurface.hxx>
28 #include <Geom2dAdaptor_Curve.hxx>
29 #include <GeomAdaptor_Curve.hxx>
30 #include <gp_Dir2d.hxx>
31 #include <gp_Pnt2d.hxx>
32 #include <IVtkOCC_ShapeMesher.hxx>
33 #include <NCollection_Array1.hxx>
34 #include <Poly_Polygon3D.hxx>
35 #include <Poly_PolygonOnTriangulation.hxx>
36 #include <Poly_Triangulation.hxx>
37 #include <Precision.hxx>
38 #include <Prs3d.hxx>
39 #include <Prs3d_Drawer.hxx>
40 #include <Prs3d_IsoAspect.hxx>
41 #include <Standard_ErrorHandler.hxx>
42 #include <StdPrs_Isolines.hxx>
43 #include <StdPrs_ToolTriangulatedShape.hxx>
44 #include <TColgp_SequenceOfPnt2d.hxx>
45 #include <TColStd_Array1OfReal.hxx>
46 #include <TopExp.hxx>
47 #include <TopExp_Explorer.hxx>
48
49 IMPLEMENT_STANDARD_RTTIEXT(IVtkOCC_ShapeMesher,IVtk_IShapeMesher)
50
51 // Handle implementation
52
53
54 //================================================================
55 // Function : internalBuild
56 // Purpose  : 
57 //================================================================
58 void IVtkOCC_ShapeMesher::internalBuild()
59 {
60   // TODO: do we need any protection here so as not to triangualte
61   // the shape twice??? This can be done e.g. by checking if
62   // triangulation exists for TopoDS_Shape..
63   meshShape();
64
65   // Free vertices and free edges should always be shown.
66   // Shared edges are needed in WF representation only.
67   // TODO: how to filter free edges at visualization level????
68   addFreeVertices();
69   addEdges();
70
71   // Build wireframe points and cells (lines for isolines)
72   addWireFrameFaces();
73
74   // Build shaded representation (based on Poly_Triangulation)
75   addShadedFaces();
76 }
77
78 //================================================================
79 // Function : GetShapeObj
80 // Purpose  : 
81 //================================================================
82 const IVtkOCC_Shape::Handle IVtkOCC_ShapeMesher::GetShapeObj() const
83 {
84   return (IVtkOCC_Shape::Handle::DownCast(myShapeObj));
85 }
86
87 //================================================================
88 // Function : GetDeflection
89 // Purpose  : Returns absolute deflection used by this algorithm.
90 //================================================================
91 Standard_Real IVtkOCC_ShapeMesher::GetDeflection() const
92 {
93   if (myDeflection < Precision::Confusion()) // if not yet initialized
94   {
95     Handle(Prs3d_Drawer) aDefDrawer = new Prs3d_Drawer();
96     aDefDrawer->SetTypeOfDeflection (Aspect_TOD_RELATIVE);
97     aDefDrawer->SetDeviationCoefficient (GetDeviationCoeff());
98     myDeflection = StdPrs_ToolTriangulatedShape::GetDeflection (GetShapeObj()->GetShape(), aDefDrawer);
99   }
100
101   return myDeflection;
102 }
103
104 //================================================================
105 // Function : meshShape
106 // Purpose  : 
107 //================================================================
108 void IVtkOCC_ShapeMesher::meshShape()
109 {
110   const TopoDS_Shape& anOcctShape = GetShapeObj()->GetShape();
111   if (anOcctShape.IsNull())
112   {
113     return;
114   }
115
116   //Clean triangulation before compute incremental mesh
117   BRepTools::Clean (anOcctShape);
118
119   //Compute triangulation
120   Standard_Real aDeflection = GetDeflection();
121   if (aDeflection < Precision::Confusion())
122   {
123     return;
124   }
125
126   try
127   {
128     OCC_CATCH_SIGNALS
129
130     Handle(BRepMesh_DiscretRoot) anAlgo;
131     anAlgo = BRepMesh_DiscretFactory::Get().Discret (anOcctShape,
132                                                      aDeflection,
133                                                      GetDeviationAngle());
134     if (!anAlgo.IsNull())
135     {
136       anAlgo->Perform();
137     }
138   }
139   catch (Standard_Failure)
140   { }
141 }
142
143 //================================================================
144 // Function : addFreeVertices
145 // Purpose  : 
146 //================================================================
147 void IVtkOCC_ShapeMesher::addFreeVertices()
148 {
149   TopTools_IndexedDataMapOfShapeListOfShape aVertexMap;
150   TopExp::MapShapesAndAncestors (GetShapeObj()->GetShape(),
151                                  TopAbs_VERTEX,
152                                  TopAbs_EDGE,
153                                  aVertexMap);
154
155   Standard_Integer aVertNum = aVertexMap.Extent();
156   IVtk_MeshType aType;
157   for (Standard_Integer anIt = 1; anIt <= aVertNum; anIt++)
158   {
159     if (aVertexMap.FindFromIndex(anIt).IsEmpty())
160     {
161       aType = MT_FreeVertex;
162     }
163     else
164     {
165       aType = MT_SharedVertex;
166     }
167     const TopoDS_Vertex& aVertex = TopoDS::Vertex (aVertexMap.FindKey (anIt));
168     addVertex (aVertex, GetShapeObj()->GetSubShapeId (aVertex), aType);
169   }
170 }
171
172 //================================================================
173 // Function : addEdges
174 // Purpose  : 
175 //================================================================
176 void IVtkOCC_ShapeMesher::addEdges()
177 {
178   TopTools_IndexedDataMapOfShapeListOfShape anEdgesMap;
179   TopExp::MapShapesAndAncestors (GetShapeObj()->GetShape(), 
180                                  TopAbs_EDGE, 
181                                  TopAbs_FACE,
182                                  anEdgesMap);
183   int aNbFaces;
184   IVtk_MeshType aType;
185   myEdgesTypes.Clear();
186
187   TopTools_IndexedDataMapOfShapeListOfShape::Iterator aEdgeIt(anEdgesMap);
188   for (; aEdgeIt.More(); aEdgeIt.Next())
189   {
190     const TopoDS_Edge& anOcctEdge = TopoDS::Edge (aEdgeIt.Key());
191     const TopTools_ListOfShape& aFaceList = aEdgeIt.Value();
192     aNbFaces = aFaceList.Extent();
193     if (aNbFaces == 0)
194     {
195       aType = MT_FreeEdge;
196     }
197     else if (aNbFaces == 1)
198     {
199       aType = MT_BoundaryEdge;
200     }
201     else
202     {
203       aType = (aNbFaces >= 2) && (BRep_Tool::MaxContinuity(anOcctEdge) > GeomAbs_G2) ?
204         MT_SeamEdge : MT_SharedEdge;
205     }
206     addEdge (anOcctEdge, GetShapeObj()->GetSubShapeId (anOcctEdge), aType);
207     myEdgesTypes.Bind (anOcctEdge, aType);
208   }
209 }
210
211 //================================================================
212 // Function : addWireFrameFaces
213 // Purpose  : 
214 //================================================================
215 void IVtkOCC_ShapeMesher::addWireFrameFaces()
216 {
217   // Check the deflection value once for all faces
218   if (GetDeflection() < Precision::Confusion())
219   {
220     return;
221   }
222
223   TopExp_Explorer aFaceIter (GetShapeObj()->GetShape(), TopAbs_FACE);
224   for (; aFaceIter.More(); aFaceIter.Next())
225   {
226     const TopoDS_Face& anOcctFace = TopoDS::Face (aFaceIter.Current());
227     try
228     {
229       OCC_CATCH_SIGNALS
230       addWFFace (anOcctFace, 
231                  GetShapeObj()->GetSubShapeId (anOcctFace));
232     }
233     catch (Standard_Failure)
234     { }
235   }
236 }
237
238 //================================================================
239 // Function : addShadedFaces
240 // Purpose  : 
241 //================================================================
242 void IVtkOCC_ShapeMesher::addShadedFaces()
243 {
244   TopExp_Explorer aFaceIter (GetShapeObj()->GetShape(), TopAbs_FACE);
245   for (; aFaceIter.More(); aFaceIter.Next())
246   {
247     const TopoDS_Face& anOcctFace = TopoDS::Face (aFaceIter.Current());
248     addShadedFace (anOcctFace,
249                    GetShapeObj()->GetSubShapeId (anOcctFace));
250   }
251 }
252
253 //================================================================
254 // Function : addVertex
255 // Purpose  : 
256 //================================================================
257 void IVtkOCC_ShapeMesher::addVertex (const TopoDS_Vertex& theVertex,
258                                      const IVtk_IdType    theShapeId,
259                                      const IVtk_MeshType  theMeshType)
260 {
261   if (theVertex.IsNull())
262   {
263     return;
264   }
265
266   gp_Pnt aPnt3d = BRep_Tool::Pnt (theVertex);
267
268   IVtk_PointId anId = 
269     myShapeData->InsertCoordinate (aPnt3d.X(), aPnt3d.Y(), aPnt3d.Z());
270   myShapeData->InsertVertex (theShapeId, anId, theMeshType);
271
272 }
273
274 //================================================================
275 // Function : processPolyline
276 // Purpose  : 
277 //================================================================
278 void IVtkOCC_ShapeMesher::processPolyline (Standard_Integer          theNbNodes,
279                                       const TColgp_Array1OfPnt&      thePoints,
280                                       const TColStd_Array1OfInteger& thePointIds,
281                                       const IVtk_IdType              theOcctId,
282                                       bool                           theNoTransform,
283                                       gp_Trsf                        theTransformation,
284                                       const IVtk_MeshType            theMeshType)
285 {
286   if (theNbNodes < 2)
287   {
288     return;
289   }
290
291   IVtk_PointIdList aPolyPointIds;
292
293   IVtk_PointId anId;
294   for (Standard_Integer aJ = 0; aJ < theNbNodes; aJ++)
295   {
296     Standard_Integer aPntId = thePointIds (aJ + 1);
297     gp_Pnt point = thePoints (aPntId);
298
299     if (!theNoTransform)
300     {
301       // Apply the transformation to points
302       point.Transform (theTransformation);
303     }
304
305     anId = myShapeData->InsertCoordinate (point.X(), point.Y(), point.Z());
306     aPolyPointIds.Append (anId);
307   }
308
309   myShapeData->InsertLine (theOcctId, &aPolyPointIds, theMeshType);
310 }
311
312 //================================================================
313 // Function : addEdge
314 // Purpose  : 
315 //================================================================
316 void IVtkOCC_ShapeMesher::addEdge (const TopoDS_Edge&  theEdge,
317                                    const IVtk_IdType   theShapeId,
318                                    const IVtk_MeshType theMeshType)
319 {
320   if (theEdge.IsNull() || BRep_Tool::Degenerated (theEdge))
321   {
322     return;
323   }
324
325   // Two discrete representations of an OCCT edge are possible:
326   // 1. Polygon on trinagulation - holds Ids of points
327   // contained in Poly_Triangulation object
328   Handle(Poly_PolygonOnTriangulation) aPolyOnTriangulation;
329   Handle(Poly_Triangulation) aTriangulation;
330   TopLoc_Location aLocation;
331   BRep_Tool::PolygonOnTriangulation (theEdge,
332                                      aPolyOnTriangulation,
333                                      aTriangulation,
334                                      aLocation,
335                                      1);
336
337   // 2. 3D polygon - holds 3D points
338   Handle(Poly_Polygon3D) aPoly3d;
339   if (aPolyOnTriangulation.IsNull())
340   {
341     aPoly3d = BRep_Tool::Polygon3D (theEdge, aLocation);
342   }
343
344   if (aPoly3d.IsNull() && aPolyOnTriangulation.IsNull())
345   {
346     return;
347   }
348
349   // Handle a non-identity transofmation applied to the edge
350   gp_Trsf anEdgeTransf;
351   bool noTransform = true;
352   if (!aLocation.IsIdentity())
353   {
354     noTransform = false;
355     anEdgeTransf = aLocation.Transformation();
356   }
357
358   if (!aPoly3d.IsNull())
359   {
360     Standard_Integer aNbNodes = aPoly3d->NbNodes();
361     const TColgp_Array1OfPnt& aPoints = aPoly3d->Nodes();
362     TColStd_Array1OfInteger aPointIds (1, aNbNodes);
363
364     for (Standard_Integer anI = 1; anI <= aNbNodes; anI++)
365     {
366       aPointIds.SetValue (anI, anI);
367     }
368
369     processPolyline (aNbNodes,
370                      aPoints,
371                      aPointIds,
372                      theShapeId,
373                      noTransform,
374                      anEdgeTransf,
375                      theMeshType);
376   }
377   else
378   {
379     Standard_Integer aNbNodes = aPolyOnTriangulation->NbNodes();
380     const TColStd_Array1OfInteger& aPointIds = aPolyOnTriangulation->Nodes();
381     const TColgp_Array1OfPnt& aPoints = aTriangulation->Nodes();
382
383     processPolyline (aNbNodes,
384                      aPoints,
385                      aPointIds,
386                      theShapeId,
387                      noTransform,
388                      anEdgeTransf,
389                      theMeshType);
390   }
391 }
392
393 //================================================================
394 // Function : addWFFace
395 // Purpose  : 
396 //================================================================
397 void IVtkOCC_ShapeMesher::addWFFace (const TopoDS_Face& theFace,
398                                      const IVtk_IdType  theShapeId)
399 {
400   if (theFace.IsNull())
401   {
402     return;
403   }
404
405   TopoDS_Face aFaceToMesh = theFace;
406   aFaceToMesh.Orientation (TopAbs_FORWARD);
407
408   // The code that builds wireframe representation for a TopoDS_Face
409   // has been adapted from some OCCT 6.5.1 methods:
410   // - Prs3d_WFShape::Add()
411   // - StdPrs_WFDeflectionRestrictedFace::Add()
412   // - StdPrs_DeflectionCurve::Add()
413
414   // Add face's edges here but with the face ID
415   for (TopExp_Explorer anEdgeIter (aFaceToMesh, TopAbs_EDGE); anEdgeIter.More(); anEdgeIter.Next())
416   {
417     const TopoDS_Edge& anOcctEdge = TopoDS::Edge (anEdgeIter.Current());
418     addEdge (anOcctEdge, theShapeId, myEdgesTypes (anOcctEdge));
419   }
420
421   TopLoc_Location aLoc;
422   const Handle(Geom_Surface)& aGeomSurf = BRep_Tool::Surface (aFaceToMesh, aLoc);
423   if (aGeomSurf.IsNull())
424   {
425     return;
426   }
427
428   const Standard_Real aDeflection = GetDeflection();
429   Handle(Prs3d_Drawer) aDrawer = new Prs3d_Drawer();
430   aDrawer->SetUIsoAspect (new Prs3d_IsoAspect (Quantity_NOC_WHITE, Aspect_TOL_SOLID, 1.0f, myNbIsos[0]));
431   aDrawer->SetVIsoAspect (new Prs3d_IsoAspect (Quantity_NOC_WHITE, Aspect_TOL_SOLID, 1.0f, myNbIsos[1]));
432   aDrawer->SetDeviationAngle (myDevAngle);
433   aDrawer->SetDeviationCoefficient (myDevCoeff);
434   aDrawer->SetMaximalChordialDeviation (aDeflection);
435
436   Prs3d_NListOfSequenceOfPnt aPolylines;
437   StdPrs_Isolines::Add (theFace, aDrawer, aDeflection, aPolylines, aPolylines);
438   for (Prs3d_NListOfSequenceOfPnt::Iterator aPolyIter (aPolylines); aPolyIter.More(); aPolyIter.Next())
439   {
440     const Handle(TColgp_HSequenceOfPnt)& aPoints = aPolyIter.Value();
441     const Standard_Integer theNbNodes = aPoints->Length();
442     if (theNbNodes < 2)
443     {
444       continue;
445     }
446
447     IVtk_PointIdList aPolyPointIds;
448     for (TColgp_HSequenceOfPnt::Iterator aNodeIter (*aPoints); aNodeIter.More(); aNodeIter.Next())
449     {
450       const gp_Pnt& aPnt = aNodeIter.Value();
451       const IVtk_PointId anId = myShapeData->InsertCoordinate (aPnt.X(), aPnt.Y(), aPnt.Z());
452       aPolyPointIds.Append (anId);
453     }
454
455     myShapeData->InsertLine (theShapeId, &aPolyPointIds, MT_IsoLine);
456   }
457 }
458
459 //================================================================
460 // Function : addShadedFace
461 // Purpose  : 
462 //================================================================
463 void IVtkOCC_ShapeMesher::addShadedFace (const TopoDS_Face& theFace,
464                                          const IVtk_IdType  theShapeId)
465 {
466   if (theFace.IsNull())
467   {
468     return;
469   }
470
471   // Build triangulation of the face.
472   TopLoc_Location aLoc;
473   Handle(Poly_Triangulation) anOcctTriangulation = BRep_Tool::Triangulation (theFace, aLoc);
474   if (anOcctTriangulation.IsNull())
475   {
476     return;
477   }
478
479   gp_Trsf aPntTransform;
480   Standard_Boolean noTransform = Standard_True;
481   if (!aLoc.IsIdentity())
482   {
483     noTransform = Standard_False;
484     aPntTransform = aLoc.Transformation();
485   }
486
487   // Get triangulation points.
488   const TColgp_Array1OfPnt& aPoints = anOcctTriangulation->Nodes();
489   Standard_Integer aNbPoints = anOcctTriangulation->NbNodes();
490
491   // Keep inserted points id's of triangulation in an array.
492   NCollection_Array1<IVtk_PointId> aPointIds (1, aNbPoints);
493   IVtk_PointId anId;
494
495   Standard_Integer anI;
496   for (anI = 1; anI <= aNbPoints; anI++)
497   {
498     gp_Pnt aPoint = aPoints (anI);
499
500     if (!noTransform)
501     {
502       aPoint.Transform (aPntTransform);
503     }
504
505     // Add a point into output shape data and keep its id in the array.
506     anId = myShapeData->InsertCoordinate (aPoint.X(), aPoint.Y(), aPoint.Z());
507     aPointIds.SetValue (anI, anId);
508   }
509
510   // Create triangles on the created triangulation points.
511   const Poly_Array1OfTriangle& aTriangles = anOcctTriangulation->Triangles();
512   Standard_Integer aNbTriangles = anOcctTriangulation->NbTriangles();
513   Standard_Integer aN1, aN2, aN3;
514   for (anI = 1; anI <= aNbTriangles; anI++)
515   {
516     aTriangles(anI).Get (aN1, aN2, aN3); // get indexes of triangle's points
517     // Insert new triangle on these points into output shape data.
518     myShapeData->InsertTriangle (
519       theShapeId, aPointIds(aN1), aPointIds(aN2), aPointIds(aN3), MT_ShadedFace);
520   }
521 }