1 // Created on: 2016-07-07
2 // Copyright (c) 2016 OPEN CASCADE SAS
3 // Created by: Oleg AGASHIN
5 // This file is part of Open CASCADE Technology software library.
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.
13 // Alternatively, this file may be used under the terms of Open CASCADE
14 // commercial license or contractual agreement.
16 #ifndef _BRepMeshTools_DelaunayDeflectionControlMeshAlgo_HeaderFile
17 #define _BRepMeshTools_DelaunayDeflectionControlMeshAlgo_HeaderFile
19 #include <BRepMesh_DelaunayNodeInsertionMeshAlgo.hxx>
20 #include <BRepMesh_GeomTool.hxx>
21 #include <GeomLib.hxx>
23 //! Extends node insertion Delaunay meshing algo in order to control
24 //! deflection of generated trianges. Splits triangles failing the check.
25 template<class RangeSplitter, class BaseAlgo>
26 class BRepMesh_DelaunayDeflectionControlMeshAlgo : public BRepMesh_DelaunayNodeInsertionMeshAlgo<RangeSplitter, BaseAlgo>
29 // Typedef for OCCT RTTI
30 typedef BRepMesh_DelaunayNodeInsertionMeshAlgo<RangeSplitter, BaseAlgo> DelaunayInsertionBaseClass;
35 BRepMesh_DelaunayDeflectionControlMeshAlgo()
36 : myMaxSqDeflection(-1.),
37 myIsAllDegenerated(Standard_False)
42 virtual ~BRepMesh_DelaunayDeflectionControlMeshAlgo()
48 //! Perfroms processing of generated mesh. Generates surface nodes and inserts them into structure.
49 virtual void postProcessMesh(BRepMesh_Delaun& theMesher) Standard_OVERRIDE
51 // Insert surface nodes.
52 DelaunayInsertionBaseClass::postProcessMesh(theMesher);
54 if (this->getParameters().ControlSurfaceDeflection &&
55 this->getStructure()->ElementsOfDomain().Extent() > 0)
57 optimizeMesh(theMesher);
61 //! Checks deviation of a mesh from geometrical surface.
62 //! Inserts additional nodes in case of huge deviation.
63 virtual void optimizeMesh(BRepMesh_Delaun& theMesher)
65 Handle(NCollection_IncAllocator) aTmpAlloc =
66 new NCollection_IncAllocator(IMeshData::MEMORY_BLOCK_SIZE_HUGE);
68 myCouplesMap = new IMeshData::MapOfOrientedEdges(3 * this->getStructure()->ElementsOfDomain().Extent(), aTmpAlloc);
69 myControlNodes = new IMeshData::ListOfPnt2d(aTmpAlloc);
70 myCircles = &theMesher.Circles();
72 const Standard_Integer aIterationsNb = 11;
73 Standard_Boolean isInserted = Standard_True;
74 for (Standard_Integer aPass = 1; aPass <= aIterationsNb && isInserted && !myIsAllDegenerated; ++aPass)
76 // Reset stop condition
77 myMaxSqDeflection = -1.;
78 myIsAllDegenerated = Standard_True;
79 myControlNodes->Clear();
81 if (this->getStructure()->ElementsOfDomain().Extent() < 1)
86 // Iterate on current triangles
87 IMeshData::IteratorOfMapOfInteger aTriangleIt(this->getStructure()->ElementsOfDomain());
88 for (; aTriangleIt.More(); aTriangleIt.Next())
90 const BRepMesh_Triangle& aTriangle = this->getStructure()->GetElement(aTriangleIt.Key());
91 splitTriangleGeometry(aTriangle);
94 isInserted = this->insertNodes(myControlNodes, theMesher);
97 myCouplesMap.Nullify();
98 myControlNodes.Nullify();
100 if (!(myMaxSqDeflection < 0.))
102 this->getDFace()->SetDeflection(Sqrt(myMaxSqDeflection));
107 //! Contains geometrical data related to node of triangle.
108 struct TriangleNodeInfo
112 Standard_Boolean isFrontierLink;
115 //! Functor computing deflection of a point from surface.
116 class NormalDeviation
120 const gp_Pnt& theRefPnt,
121 const gp_Vec& theNormal)
122 : myRefPnt(theRefPnt),
127 Standard_Real SquareDeviation(const gp_Pnt& thePoint) const
129 const Standard_Real aDeflection = Abs(myNormal.Dot(gp_Vec(myRefPnt, thePoint)));
130 return aDeflection * aDeflection;
135 NormalDeviation (const NormalDeviation& theOther);
137 void operator= (const NormalDeviation& theOther);
141 const gp_Pnt& myRefPnt;
142 const gp_Vec& myNormal;
145 //! Functor computing deflection of a point on triangle link from surface.
151 const gp_Pnt& thePnt1,
152 const gp_Pnt& thePnt2)
158 Standard_Real SquareDeviation(const gp_Pnt& thePoint) const
160 return BRepMesh_GeomTool::SquareDeflectionOfSegment(myPnt1, myPnt2, thePoint);
165 LineDeviation (const LineDeviation& theOther);
167 void operator= (const LineDeviation& theOther);
170 const gp_Pnt& myPnt1;
171 const gp_Pnt& myPnt2;
174 //! Returns nodes info of the given triangle.
175 inline void getTriangleInfo(
176 const BRepMesh_Triangle& theTriangle,
177 const Standard_Integer (&theNodesIndices)[3],
178 TriangleNodeInfo (&theInfo)[3]) const
180 const Standard_Integer(&e)[3] = theTriangle.myEdges;
181 for (Standard_Integer i = 0; i < 3; ++i)
183 const BRepMesh_Vertex& aVertex = this->getStructure()->GetNode(theNodesIndices[i]);
184 theInfo[i].Point2d = this->getRangeSplitter().Scale(aVertex.Coord(), Standard_False).XY();
185 theInfo[i].Point = this->getNodesMap()->Value(aVertex.Location3d()).XYZ();
186 theInfo[i].isFrontierLink = (this->getStructure()->GetLink(e[i]).Movability() == BRepMesh_Frontier);
190 // Check geometry of the given triangle. If triangle does not suit specified deflection, inserts new point.
191 void splitTriangleGeometry(const BRepMesh_Triangle& theTriangle)
193 if (theTriangle.Movability() != BRepMesh_Deleted)
195 Standard_Integer aNodexIndices[3];
196 this->getStructure()->ElementNodes(theTriangle, aNodexIndices);
198 TriangleNodeInfo aNodesInfo[3];
199 getTriangleInfo(theTriangle, aNodexIndices, aNodesInfo);
203 if (computeTriangleGeometry(aNodesInfo, aLinkVec, aNormal))
205 myIsAllDegenerated = Standard_False;
207 const gp_XY aCenter2d = (aNodesInfo[0].Point2d +
208 aNodesInfo[1].Point2d +
209 aNodesInfo[2].Point2d) / 3.;
211 usePoint(aCenter2d, NormalDeviation(aNodesInfo[0].Point, aNormal));
212 splitLinks(aNodesInfo, aNodexIndices);
217 //! Updates array of links vectors.
218 //! @return False on degenerative triangle.
219 inline Standard_Boolean computeTriangleGeometry(
220 const TriangleNodeInfo(&theNodesInfo)[3],
221 gp_Vec (&theLinks)[3],
224 if (checkTriangleForDegenerativityAndGetLinks(theNodesInfo, theLinks))
226 if (checkTriangleArea2d(theNodesInfo))
228 if (computeNormal(theLinks[0], theLinks[1], theNormal))
230 return Standard_True;
235 return Standard_False;
238 //! Updates array of links vectors.
239 //! @return False on degenerative triangle.
240 inline Standard_Boolean checkTriangleForDegenerativityAndGetLinks(
241 const TriangleNodeInfo (&theNodesInfo)[3],
242 gp_Vec (&theLinks)[3])
244 const Standard_Real MinimalSqLength3d = 1.e-12;
245 for (Standard_Integer i = 0; i < 3; ++i)
247 theLinks[i] = theNodesInfo[(i + 1) % 3].Point - theNodesInfo[i].Point;
248 if (theLinks[i].SquareMagnitude() < MinimalSqLength3d)
250 return Standard_False;
254 return Standard_True;
257 //! Checks area of triangle in parametric space for degenerativity.
258 //! @return False on degenerative triangle.
259 inline Standard_Boolean checkTriangleArea2d(
260 const TriangleNodeInfo (&theNodesInfo)[3])
262 const gp_Vec2d aLink2d1(theNodesInfo[0].Point2d, theNodesInfo[1].Point2d);
263 const gp_Vec2d aLink2d2(theNodesInfo[1].Point2d, theNodesInfo[2].Point2d);
265 const Standard_Real MinimalArea2d = 1.e-9;
266 return (Abs(aLink2d1 ^ aLink2d2) > MinimalArea2d);
269 //! Computes normal using two link vectors.
270 //! @return True on success, False in case of normal of null magnitude.
271 inline Standard_Boolean computeNormal(const gp_Vec& theLink1,
272 const gp_Vec& theLink2,
275 const gp_Vec aNormal(theLink1 ^ theLink2);
276 if (aNormal.SquareMagnitude() > gp::Resolution())
278 theNormal = aNormal.Normalized();
279 return Standard_True;
282 return Standard_False;
285 //! Computes deflection of midpoints of triangles links.
286 //! @return True if point fits specified deflection.
287 inline void splitLinks(
288 const TriangleNodeInfo (&theNodesInfo)[3],
289 const Standard_Integer (&theNodesIndices)[3])
291 // Check deflection at triangle links
292 for (Standard_Integer i = 0; i < 3; ++i)
294 if (theNodesInfo[i].isFrontierLink)
299 const Standard_Integer j = (i + 1) % 3;
300 // Check if this link was already processed
301 Standard_Integer aFirstVertex, aLastVertex;
302 if (theNodesIndices[i] < theNodesIndices[j])
304 aFirstVertex = theNodesIndices[i];
305 aLastVertex = theNodesIndices[j];
309 aFirstVertex = theNodesIndices[j];
310 aLastVertex = theNodesIndices[i];
313 if (myCouplesMap->Add(BRepMesh_OrientedEdge(aFirstVertex, aLastVertex)))
315 const gp_XY aMidPnt2d = (theNodesInfo[i].Point2d +
316 theNodesInfo[j].Point2d) / 2.;
318 if (!usePoint (aMidPnt2d, LineDeviation (theNodesInfo[i].Point,
319 theNodesInfo[j].Point)))
321 if (!checkLinkEndsForAngularDeviation(theNodesInfo[i],
325 myControlNodes->Append(aMidPnt2d);
332 //! Checks the given point (located between the given nodes)
333 //! for specified angular deviation.
334 Standard_Boolean checkLinkEndsForAngularDeviation(const TriangleNodeInfo& theNodeInfo1,
335 const TriangleNodeInfo& theNodeInfo2,
336 const gp_XY& /*theMidPoint*/)
338 gp_Dir aNorm1, aNorm2;
339 const Handle(Geom_Surface)& aSurf =
340 this->getDFace()->GetSurface()->ChangeSurface().Surface().Surface();
342 if ((GeomLib::NormEstim(aSurf, theNodeInfo1.Point2d, Precision::Confusion(), aNorm1) == 0) &&
343 (GeomLib::NormEstim(aSurf, theNodeInfo2.Point2d, Precision::Confusion(), aNorm2) == 0))
345 Standard_Real anAngle = aNorm1.Angle(aNorm2);
346 if (anAngle > this->getParameters().AngleInterior)
347 return Standard_False;
350 else if (GeomLib::NormEstim(aSurf, theMidPoint, Precision::Confusion(), aNorm1) != 0)
352 // It is better to consider the singular point as a node of triangulation.
353 // However, it leads to hangs up meshing some faces (including faces with
354 // degenerated edges). E.g. tests "mesh standard_incmesh Q6".
355 // So, this code fragment is better to implement in the future.
356 return Standard_False;
360 return Standard_True;
363 //! Computes deflection of the given point and caches it for
364 //! insertion in case if it overflows deflection.
365 //! @return True if point has been cached for insertion.
366 template<class DeflectionFunctor>
367 inline Standard_Boolean usePoint(
368 const gp_XY& thePnt2d,
369 const DeflectionFunctor& theDeflectionFunctor)
372 this->getDFace()->GetSurface()->D0(thePnt2d.X(), thePnt2d.Y(), aPnt);
373 if (!checkDeflectionOfPointAndUpdateCache(thePnt2d, aPnt, theDeflectionFunctor.SquareDeviation(aPnt)))
375 myControlNodes->Append(thePnt2d);
376 return Standard_True;
379 return Standard_False;
382 //! Checks the given point for specified linear deflection.
383 //! Updates value of total mesh defleciton.
384 Standard_Boolean checkDeflectionOfPointAndUpdateCache(
385 const gp_XY& thePnt2d,
386 const gp_Pnt& thePnt3d,
387 const Standard_Real theSqDeflection)
389 if (theSqDeflection > myMaxSqDeflection)
391 myMaxSqDeflection = theSqDeflection;
394 const Standard_Real aSqDeflection =
395 this->getDFace()->GetDeflection() * this->getDFace()->GetDeflection();
396 if (theSqDeflection < aSqDeflection)
398 return Standard_True;
401 return rejectByMinSize(thePnt2d, thePnt3d);
404 //! Checks the given node for
405 Standard_Boolean rejectByMinSize(
406 const gp_XY& thePnt2d,
407 const gp_Pnt& thePnt3d)
409 const Standard_Real aSqMinSize =
410 this->getParameters().MinSize * this->getParameters().MinSize;
412 IMeshData::MapOfInteger aUsedNodes;
413 IMeshData::ListOfInteger& aCirclesList =
414 const_cast<BRepMesh_CircleTool&>(*myCircles).Select(
415 this->getRangeSplitter().Scale(thePnt2d, Standard_True).XY());
417 IMeshData::ListOfInteger::Iterator aCircleIt(aCirclesList);
418 for (; aCircleIt.More(); aCircleIt.Next())
420 const BRepMesh_Triangle& aTriangle = this->getStructure()->GetElement(aCircleIt.Value());
422 Standard_Integer aNodes[3];
423 this->getStructure()->ElementNodes(aTriangle, aNodes);
425 for (Standard_Integer i = 0; i < 3; ++i)
427 if (!aUsedNodes.Contains(aNodes[i]))
429 aUsedNodes.Add(aNodes[i]);
430 const BRepMesh_Vertex& aVertex = this->getStructure()->GetNode(aNodes[i]);
431 const gp_Pnt& aPoint = this->getNodesMap()->Value(aVertex.Location3d());
433 if (thePnt3d.SquareDistance(aPoint) < aSqMinSize)
435 return Standard_True;
441 return Standard_False;
445 Standard_Real myMaxSqDeflection;
446 Standard_Boolean myIsAllDegenerated;
447 Handle(IMeshData::MapOfOrientedEdges) myCouplesMap;
448 Handle(IMeshData::ListOfPnt2d) myControlNodes;
449 const BRepMesh_CircleTool* myCircles;