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