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