0031458: Visualization - refine classes across Prs3d and StdPrs packages
[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
184   int aNbFaces;
185   IVtk_MeshType aType;
186   myEdgesTypes.Clear();
187
188   TopExp_Explorer anEdgeIter (GetShapeObj()->GetShape(), TopAbs_EDGE);
189   for (; anEdgeIter.More(); anEdgeIter.Next())
190   {
191     const TopoDS_Edge& anOcctEdge = TopoDS::Edge (anEdgeIter.Current());
192     aNbFaces = anEdgesMap.FindFromKey (anOcctEdge).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 = MT_SharedEdge;
204     }
205     addEdge (anOcctEdge, GetShapeObj()->GetSubShapeId (anOcctEdge), aType);
206     myEdgesTypes.Bind (anOcctEdge, aType);
207   }
208 }
209
210 //================================================================
211 // Function : addWireFrameFaces
212 // Purpose  : 
213 //================================================================
214 void IVtkOCC_ShapeMesher::addWireFrameFaces()
215 {
216   // Check the deflection value once for all faces
217   if (GetDeflection() < Precision::Confusion())
218   {
219     return;
220   }
221
222   TopExp_Explorer aFaceIter (GetShapeObj()->GetShape(), TopAbs_FACE);
223   for (; aFaceIter.More(); aFaceIter.Next())
224   {
225     const TopoDS_Face& anOcctFace = TopoDS::Face (aFaceIter.Current());
226     try
227     {
228       OCC_CATCH_SIGNALS
229       addWFFace (anOcctFace, 
230                  GetShapeObj()->GetSubShapeId (anOcctFace));
231     }
232     catch (Standard_Failure)
233     { }
234   }
235 }
236
237 //================================================================
238 // Function : addShadedFaces
239 // Purpose  : 
240 //================================================================
241 void IVtkOCC_ShapeMesher::addShadedFaces()
242 {
243   TopExp_Explorer aFaceIter (GetShapeObj()->GetShape(), TopAbs_FACE);
244   for (; aFaceIter.More(); aFaceIter.Next())
245   {
246     const TopoDS_Face& anOcctFace = TopoDS::Face (aFaceIter.Current());
247     addShadedFace (anOcctFace,
248                    GetShapeObj()->GetSubShapeId (anOcctFace));
249   }
250 }
251
252 //================================================================
253 // Function : addVertex
254 // Purpose  : 
255 //================================================================
256 void IVtkOCC_ShapeMesher::addVertex (const TopoDS_Vertex& theVertex,
257                                      const IVtk_IdType    theShapeId,
258                                      const IVtk_MeshType  theMeshType)
259 {
260   if (theVertex.IsNull())
261   {
262     return;
263   }
264
265   gp_Pnt aPnt3d = BRep_Tool::Pnt (theVertex);
266
267   IVtk_PointId anId = 
268     myShapeData->InsertCoordinate (aPnt3d.X(), aPnt3d.Y(), aPnt3d.Z());
269   myShapeData->InsertVertex (theShapeId, anId, theMeshType);
270
271 }
272
273 //================================================================
274 // Function : processPolyline
275 // Purpose  : 
276 //================================================================
277 void IVtkOCC_ShapeMesher::processPolyline (Standard_Integer          theNbNodes,
278                                       const TColgp_Array1OfPnt&      thePoints,
279                                       const TColStd_Array1OfInteger& thePointIds,
280                                       const IVtk_IdType              theOcctId,
281                                       bool                           theNoTransform,
282                                       gp_Trsf                        theTransformation,
283                                       const IVtk_MeshType            theMeshType)
284 {
285   if (theNbNodes < 2)
286   {
287     return;
288   }
289
290   IVtk_PointIdList aPolyPointIds;
291
292   IVtk_PointId anId;
293   for (Standard_Integer aJ = 0; aJ < theNbNodes; aJ++)
294   {
295     Standard_Integer aPntId = thePointIds (aJ + 1);
296     gp_Pnt point = thePoints (aPntId);
297
298     if (!theNoTransform)
299     {
300       // Apply the transformation to points
301       point.Transform (theTransformation);
302     }
303
304     anId = myShapeData->InsertCoordinate (point.X(), point.Y(), point.Z());
305     aPolyPointIds.Append (anId);
306   }
307
308   myShapeData->InsertLine (theOcctId, &aPolyPointIds, theMeshType);
309 }
310
311 //================================================================
312 // Function : addEdge
313 // Purpose  : 
314 //================================================================
315 void IVtkOCC_ShapeMesher::addEdge (const TopoDS_Edge&  theEdge,
316                                    const IVtk_IdType   theShapeId,
317                                    const IVtk_MeshType theMeshType)
318 {
319   if (theEdge.IsNull() || BRep_Tool::Degenerated (theEdge))
320   {
321     return;
322   }
323
324   // Two discrete representations of an OCCT edge are possible:
325   // 1. Polygon on trinagulation - holds Ids of points
326   // contained in Poly_Triangulation object
327   Handle(Poly_PolygonOnTriangulation) aPolyOnTriangulation;
328   Handle(Poly_Triangulation) aTriangulation;
329   TopLoc_Location aLocation;
330   BRep_Tool::PolygonOnTriangulation (theEdge,
331                                      aPolyOnTriangulation,
332                                      aTriangulation,
333                                      aLocation,
334                                      1);
335
336   // 2. 3D polygon - holds 3D points
337   Handle(Poly_Polygon3D) aPoly3d;
338   if (aPolyOnTriangulation.IsNull())
339   {
340     aPoly3d = BRep_Tool::Polygon3D (theEdge, aLocation);
341   }
342
343   if (aPoly3d.IsNull() && aPolyOnTriangulation.IsNull())
344   {
345     return;
346   }
347
348   // Handle a non-identity transofmation applied to the edge
349   gp_Trsf anEdgeTransf;
350   bool noTransform = true;
351   if (!aLocation.IsIdentity())
352   {
353     noTransform = false;
354     anEdgeTransf = aLocation.Transformation();
355   }
356
357   if (!aPoly3d.IsNull())
358   {
359     Standard_Integer aNbNodes = aPoly3d->NbNodes();
360     const TColgp_Array1OfPnt& aPoints = aPoly3d->Nodes();
361     TColStd_Array1OfInteger aPointIds (1, aNbNodes);
362
363     for (Standard_Integer anI = 1; anI <= aNbNodes; anI++)
364     {
365       aPointIds.SetValue (anI, anI);
366     }
367
368     processPolyline (aNbNodes,
369                      aPoints,
370                      aPointIds,
371                      theShapeId,
372                      noTransform,
373                      anEdgeTransf,
374                      theMeshType);
375   }
376   else
377   {
378     Standard_Integer aNbNodes = aPolyOnTriangulation->NbNodes();
379     const TColStd_Array1OfInteger& aPointIds = aPolyOnTriangulation->Nodes();
380     const TColgp_Array1OfPnt& aPoints = aTriangulation->Nodes();
381
382     processPolyline (aNbNodes,
383                      aPoints,
384                      aPointIds,
385                      theShapeId,
386                      noTransform,
387                      anEdgeTransf,
388                      theMeshType);
389   }
390 }
391
392 //================================================================
393 // Function : addWFFace
394 // Purpose  : 
395 //================================================================
396 void IVtkOCC_ShapeMesher::addWFFace (const TopoDS_Face& theFace,
397                                      const IVtk_IdType  theShapeId)
398 {
399   if (theFace.IsNull())
400   {
401     return;
402   }
403
404   TopoDS_Face aFaceToMesh = theFace;
405   aFaceToMesh.Orientation (TopAbs_FORWARD);
406
407   // The code that builds wireframe representation for a TopoDS_Face
408   // has been adapted from some OCCT 6.5.1 methods:
409   // - Prs3d_WFShape::Add()
410   // - StdPrs_WFDeflectionRestrictedFace::Add()
411   // - StdPrs_DeflectionCurve::Add()
412
413   // Add face's edges here but with the face ID
414   for (TopExp_Explorer anEdgeIter (aFaceToMesh, TopAbs_EDGE); anEdgeIter.More(); anEdgeIter.Next())
415   {
416     const TopoDS_Edge& anOcctEdge = TopoDS::Edge (anEdgeIter.Current());
417     addEdge (anOcctEdge, theShapeId, myEdgesTypes (anOcctEdge));
418   }
419
420   TopLoc_Location aLoc;
421   const Handle(Geom_Surface)& aGeomSurf = BRep_Tool::Surface (aFaceToMesh, aLoc);
422   if (aGeomSurf.IsNull())
423   {
424     return;
425   }
426
427   const Standard_Real aDeflection = GetDeflection();
428   Handle(Prs3d_Drawer) aDrawer = new Prs3d_Drawer();
429   aDrawer->SetUIsoAspect (new Prs3d_IsoAspect (Quantity_NOC_WHITE, Aspect_TOL_SOLID, 1.0f, myNbIsos[0]));
430   aDrawer->SetVIsoAspect (new Prs3d_IsoAspect (Quantity_NOC_WHITE, Aspect_TOL_SOLID, 1.0f, myNbIsos[1]));
431   aDrawer->SetDeviationAngle (myDevAngle);
432   aDrawer->SetDeviationCoefficient (myDevCoeff);
433   aDrawer->SetMaximalChordialDeviation (aDeflection);
434
435   Prs3d_NListOfSequenceOfPnt aPolylines;
436   StdPrs_Isolines::Add (theFace, aDrawer, aDeflection, aPolylines, aPolylines);
437   for (Prs3d_NListOfSequenceOfPnt::Iterator aPolyIter (aPolylines); aPolyIter.More(); aPolyIter.Next())
438   {
439     const Handle(TColgp_HSequenceOfPnt)& aPoints = aPolyIter.Value();
440     const Standard_Integer theNbNodes = aPoints->Length();
441     if (theNbNodes < 2)
442     {
443       continue;
444     }
445
446     IVtk_PointIdList aPolyPointIds;
447     for (TColgp_HSequenceOfPnt::Iterator aNodeIter (*aPoints); aNodeIter.More(); aNodeIter.Next())
448     {
449       const gp_Pnt& aPnt = aNodeIter.Value();
450       const IVtk_PointId anId = myShapeData->InsertCoordinate (aPnt.X(), aPnt.Y(), aPnt.Z());
451       aPolyPointIds.Append (anId);
452     }
453
454     myShapeData->InsertLine (theShapeId, &aPolyPointIds, MT_IsoLine);
455   }
456 }
457
458 //================================================================
459 // Function : addShadedFace
460 // Purpose  : 
461 //================================================================
462 void IVtkOCC_ShapeMesher::addShadedFace (const TopoDS_Face& theFace,
463                                          const IVtk_IdType  theShapeId)
464 {
465   if (theFace.IsNull())
466   {
467     return;
468   }
469
470   // Build triangulation of the face.
471   TopLoc_Location aLoc;
472   Handle(Poly_Triangulation) anOcctTriangulation = BRep_Tool::Triangulation (theFace, aLoc);
473   if (anOcctTriangulation.IsNull())
474   {
475     return;
476   }
477
478   gp_Trsf aPntTransform;
479   Standard_Boolean noTransform = Standard_True;
480   if (!aLoc.IsIdentity())
481   {
482     noTransform = Standard_False;
483     aPntTransform = aLoc.Transformation();
484   }
485
486   // Get triangulation points.
487   const TColgp_Array1OfPnt& aPoints = anOcctTriangulation->Nodes();
488   Standard_Integer aNbPoints = anOcctTriangulation->NbNodes();
489
490   // Keep inserted points id's of triangulation in an array.
491   NCollection_Array1<IVtk_PointId> aPointIds (1, aNbPoints);
492   IVtk_PointId anId;
493
494   Standard_Integer anI;
495   for (anI = 1; anI <= aNbPoints; anI++)
496   {
497     gp_Pnt aPoint = aPoints (anI);
498
499     if (!noTransform)
500     {
501       aPoint.Transform (aPntTransform);
502     }
503
504     // Add a point into output shape data and keep its id in the array.
505     anId = myShapeData->InsertCoordinate (aPoint.X(), aPoint.Y(), aPoint.Z());
506     aPointIds.SetValue (anI, anId);
507   }
508
509   // Create triangles on the created triangulation points.
510   const Poly_Array1OfTriangle& aTriangles = anOcctTriangulation->Triangles();
511   Standard_Integer aNbTriangles = anOcctTriangulation->NbTriangles();
512   Standard_Integer aN1, aN2, aN3;
513   for (anI = 1; anI <= aNbTriangles; anI++)
514   {
515     aTriangles(anI).Get (aN1, aN2, aN3); // get indexes of triangle's points
516     // Insert new triangle on these points into output shape data.
517     myShapeData->InsertTriangle (
518       theShapeId, aPointIds(aN1), aPointIds(aN2), aPointIds(aN3), MT_ShadedFace);
519   }
520 }