0030680: VIS - IVtkOCC_ShapeMesher displays Isoline wrong
[occt.git] / src / IVtkOCC / IVtkOCC_ShapeMesher.cxx
CommitLineData
913a4c4a 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
913a4c4a 16#include <Adaptor3d_IsoCurve.hxx>
17#include <Bnd_Box.hxx>
18#include <BRep_Tool.hxx>
913a4c4a 19#include <BRepBndLib.hxx>
20#include <BRepMesh_DiscretFactory.hxx>
21#include <BRepMesh_DiscretRoot.hxx>
913a4c4a 22#include <BRepTools.hxx>
23#include <Hatch_Hatcher.hxx>
24#include <GCPnts_QuasiUniformDeflection.hxx>
25#include <GCPnts_TangentialDeflection.hxx>
c04c30b3 26#include <Geom_BezierSurface.hxx>
27#include <Geom_BSplineSurface.hxx>
913a4c4a 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>
98eb4489 40#include <Prs3d_IsoAspect.hxx>
913a4c4a 41#include <Standard_ErrorHandler.hxx>
98eb4489 42#include <StdPrs_Isolines.hxx>
913a4c4a 43#include <TColgp_SequenceOfPnt2d.hxx>
44#include <TColStd_Array1OfReal.hxx>
45#include <TopExp.hxx>
46#include <TopExp_Explorer.hxx>
47
92efcf78 48IMPLEMENT_STANDARD_RTTIEXT(IVtkOCC_ShapeMesher,IVtk_IShapeMesher)
49
913a4c4a 50// Handle implementation
ec357c5c 51
913a4c4a 52
53//================================================================
54// Function : internalBuild
55// Purpose :
56//================================================================
57void 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//================================================================
81const 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//================================================================
90Standard_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//================================================================
107void IVtkOCC_ShapeMesher::meshShape()
108{
a2f76b15 109 const TopoDS_Shape& anOcctShape = GetShapeObj()->GetShape();
913a4c4a 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//================================================================
146void 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 }
a2f76b15 166 const TopoDS_Vertex& aVertex = TopoDS::Vertex (aVertexMap.FindKey (anIt));
913a4c4a 167 addVertex (aVertex, GetShapeObj()->GetSubShapeId (aVertex), aType);
168 }
169}
170
171//================================================================
172// Function : addEdges
173// Purpose :
174//================================================================
175void 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 {
a2f76b15 190 const TopoDS_Edge& anOcctEdge = TopoDS::Edge (anEdgeIter.Current());
913a4c4a 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//================================================================
213void 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 {
a2f76b15 224 const TopoDS_Face& anOcctFace = TopoDS::Face (aFaceIter.Current());
913a4c4a 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//================================================================
240void IVtkOCC_ShapeMesher::addShadedFaces()
241{
242 TopExp_Explorer aFaceIter (GetShapeObj()->GetShape(), TopAbs_FACE);
243 for (; aFaceIter.More(); aFaceIter.Next())
244 {
a2f76b15 245 const TopoDS_Face& anOcctFace = TopoDS::Face (aFaceIter.Current());
913a4c4a 246 addShadedFace (anOcctFace,
247 GetShapeObj()->GetSubShapeId (anOcctFace));
248 }
249}
250
251//================================================================
252// Function : addVertex
253// Purpose :
254//================================================================
255void 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//================================================================
276void 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
a2f76b15 289 IVtk_PointIdList aPolyPointIds;
913a4c4a 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());
a2f76b15 304 aPolyPointIds.Append (anId);
913a4c4a 305 }
306
a2f76b15 307 myShapeData->InsertLine (theOcctId, &aPolyPointIds, theMeshType);
913a4c4a 308}
309
310//================================================================
311// Function : addEdge
312// Purpose :
313//================================================================
314void 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
913a4c4a 391//================================================================
392// Function : addWFFace
393// Purpose :
394//================================================================
395void 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
98eb4489 413 for (TopExp_Explorer anEdgeIter (aFaceToMesh, TopAbs_EDGE); anEdgeIter.More(); anEdgeIter.Next())
913a4c4a 414 {
a2f76b15 415 const TopoDS_Edge& anOcctEdge = TopoDS::Edge (anEdgeIter.Current());
913a4c4a 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
98eb4489 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);
913a4c4a 433
98eb4489 434 Prs3d_NListOfSequenceOfPnt aPolylines;
435 StdPrs_Isolines::Add (theFace, aDrawer, aDeflection, aPolylines, aPolylines);
436 for (Prs3d_NListOfSequenceOfPnt::Iterator aPolyIter (aPolylines); aPolyIter.More(); aPolyIter.Next())
913a4c4a 437 {
98eb4489 438 const Handle(TColgp_HSequenceOfPnt)& aPoints = aPolyIter.Value();
439 const Standard_Integer theNbNodes = aPoints->Length();
440 if (theNbNodes < 2)
913a4c4a 441 {
98eb4489 442 continue;
913a4c4a 443 }
913a4c4a 444
98eb4489 445 IVtk_PointIdList aPolyPointIds;
446 for (TColgp_HSequenceOfPnt::Iterator aNodeIter (*aPoints); aNodeIter.More(); aNodeIter.Next())
913a4c4a 447 {
98eb4489 448 const gp_Pnt& aPnt = aNodeIter.Value();
449 const IVtk_PointId anId = myShapeData->InsertCoordinate (aPnt.X(), aPnt.Y(), aPnt.Z());
450 aPolyPointIds.Append (anId);
913a4c4a 451 }
98eb4489 452
453 myShapeData->InsertLine (theShapeId, &aPolyPointIds, MT_IsoLine);
913a4c4a 454 }
455}
456
457//================================================================
458// Function : addShadedFace
459// Purpose :
460//================================================================
461void 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}