0028966: Coding Rules - remove Adaptor2d_HCurve2d, Adaptor3d_HCurve and Adaptor3d_HSu...
[occt.git] / src / BRepMesh / BRepMesh_DelaunayDeflectionControlMeshAlgo.hxx
CommitLineData
7bd071ed 1// Created on: 2016-07-07
2// Copyright (c) 2016 OPEN CASCADE SAS
3// Created by: Oleg AGASHIN
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#ifndef _BRepMeshTools_DelaunayDeflectionControlMeshAlgo_HeaderFile
17#define _BRepMeshTools_DelaunayDeflectionControlMeshAlgo_HeaderFile
18
19#include <BRepMesh_DelaunayNodeInsertionMeshAlgo.hxx>
20#include <BRepMesh_GeomTool.hxx>
46478ffe 21#include <GeomLib.hxx>
7bd071ed 22
23//! Extends node insertion Delaunay meshing algo in order to control
24//! deflection of generated trianges. Splits triangles failing the check.
4c04741d 25template<class RangeSplitter, class BaseAlgo>
26class BRepMesh_DelaunayDeflectionControlMeshAlgo : public BRepMesh_DelaunayNodeInsertionMeshAlgo<RangeSplitter, BaseAlgo>
7bd071ed 27{
28private:
29 // Typedef for OCCT RTTI
4c04741d 30 typedef BRepMesh_DelaunayNodeInsertionMeshAlgo<RangeSplitter, BaseAlgo> DelaunayInsertionBaseClass;
7bd071ed 31
32public:
33
34 //! Constructor.
35 BRepMesh_DelaunayDeflectionControlMeshAlgo()
36 : myMaxSqDeflection(-1.),
d533dafb 37 myIsAllDegenerated(Standard_False),
38 myCircles(NULL)
7bd071ed 39 {
40 }
41
42 //! Destructor.
43 virtual ~BRepMesh_DelaunayDeflectionControlMeshAlgo()
44 {
45 }
46
47protected:
48
f2006a6f 49 //! Performs processing of generated mesh. Generates surface nodes and inserts them into structure.
ce97cd97 50 virtual void postProcessMesh (BRepMesh_Delaun& theMesher,
51 const Message_ProgressRange& theRange) Standard_OVERRIDE
7bd071ed 52 {
ce97cd97 53 Message_ProgressScope aPS(theRange, "Post process mesh", 2);
7bd071ed 54 // Insert surface nodes.
ce97cd97 55 DelaunayInsertionBaseClass::postProcessMesh (theMesher, aPS.Next());
56 if (!aPS.More())
57 {
58 return;
59 }
7bd071ed 60
61 if (this->getParameters().ControlSurfaceDeflection &&
62 this->getStructure()->ElementsOfDomain().Extent() > 0)
63 {
ce97cd97 64 optimizeMesh(theMesher, aPS.Next());
65 }
66 else
67 {
68 aPS.Next();
7bd071ed 69 }
70 }
71
72 //! Checks deviation of a mesh from geometrical surface.
73 //! Inserts additional nodes in case of huge deviation.
ce97cd97 74 virtual void optimizeMesh (BRepMesh_Delaun& theMesher,
75 const Message_ProgressRange& theRange)
7bd071ed 76 {
77 Handle(NCollection_IncAllocator) aTmpAlloc =
78 new NCollection_IncAllocator(IMeshData::MEMORY_BLOCK_SIZE_HUGE);
79
80 myCouplesMap = new IMeshData::MapOfOrientedEdges(3 * this->getStructure()->ElementsOfDomain().Extent(), aTmpAlloc);
81 myControlNodes = new IMeshData::ListOfPnt2d(aTmpAlloc);
82 myCircles = &theMesher.Circles();
83
84 const Standard_Integer aIterationsNb = 11;
85 Standard_Boolean isInserted = Standard_True;
ce97cd97 86 Message_ProgressScope aPS(theRange, "Iteration", aIterationsNb);
7bd071ed 87 for (Standard_Integer aPass = 1; aPass <= aIterationsNb && isInserted && !myIsAllDegenerated; ++aPass)
88 {
ce97cd97 89 if (!aPS.More())
90 {
91 return;
92 }
7bd071ed 93 // Reset stop condition
94 myMaxSqDeflection = -1.;
95 myIsAllDegenerated = Standard_True;
96 myControlNodes->Clear();
97
98 if (this->getStructure()->ElementsOfDomain().Extent() < 1)
99 {
100 break;
101 }
7bd071ed 102 // Iterate on current triangles
103 IMeshData::IteratorOfMapOfInteger aTriangleIt(this->getStructure()->ElementsOfDomain());
104 for (; aTriangleIt.More(); aTriangleIt.Next())
105 {
106 const BRepMesh_Triangle& aTriangle = this->getStructure()->GetElement(aTriangleIt.Key());
107 splitTriangleGeometry(aTriangle);
108 }
109
ce97cd97 110 isInserted = this->insertNodes(myControlNodes, theMesher, aPS.Next());
7bd071ed 111 }
112
113 myCouplesMap.Nullify();
114 myControlNodes.Nullify();
115
116 if (!(myMaxSqDeflection < 0.))
117 {
118 this->getDFace()->SetDeflection(Sqrt(myMaxSqDeflection));
119 }
120 }
121
122private:
123 //! Contains geometrical data related to node of triangle.
124 struct TriangleNodeInfo
125 {
d533dafb 126 TriangleNodeInfo()
127 : isFrontierLink(Standard_False)
128 {
129 }
130
7bd071ed 131 gp_XY Point2d;
132 gp_XYZ Point;
133 Standard_Boolean isFrontierLink;
134 };
135
136 //! Functor computing deflection of a point from surface.
137 class NormalDeviation
138 {
139 public:
140 NormalDeviation(
141 const gp_Pnt& theRefPnt,
142 const gp_Vec& theNormal)
143 : myRefPnt(theRefPnt),
144 myNormal(theNormal)
145 {
146 }
147
148 Standard_Real SquareDeviation(const gp_Pnt& thePoint) const
149 {
150 const Standard_Real aDeflection = Abs(myNormal.Dot(gp_Vec(myRefPnt, thePoint)));
151 return aDeflection * aDeflection;
152 }
153
154 private:
155
156 NormalDeviation (const NormalDeviation& theOther);
157
158 void operator= (const NormalDeviation& theOther);
159
160 private:
161
162 const gp_Pnt& myRefPnt;
163 const gp_Vec& myNormal;
164 };
165
166 //! Functor computing deflection of a point on triangle link from surface.
167 class LineDeviation
168 {
169 public:
170
171 LineDeviation(
172 const gp_Pnt& thePnt1,
173 const gp_Pnt& thePnt2)
174 : myPnt1(thePnt1),
175 myPnt2(thePnt2)
176 {
177 }
178
179 Standard_Real SquareDeviation(const gp_Pnt& thePoint) const
180 {
181 return BRepMesh_GeomTool::SquareDeflectionOfSegment(myPnt1, myPnt2, thePoint);
182 }
183
184 private:
185
186 LineDeviation (const LineDeviation& theOther);
187
188 void operator= (const LineDeviation& theOther);
189
190 private:
191 const gp_Pnt& myPnt1;
192 const gp_Pnt& myPnt2;
193 };
194
195 //! Returns nodes info of the given triangle.
4945e8be 196 void getTriangleInfo(
7bd071ed 197 const BRepMesh_Triangle& theTriangle,
198 const Standard_Integer (&theNodesIndices)[3],
199 TriangleNodeInfo (&theInfo)[3]) const
200 {
201 const Standard_Integer(&e)[3] = theTriangle.myEdges;
202 for (Standard_Integer i = 0; i < 3; ++i)
203 {
204 const BRepMesh_Vertex& aVertex = this->getStructure()->GetNode(theNodesIndices[i]);
205 theInfo[i].Point2d = this->getRangeSplitter().Scale(aVertex.Coord(), Standard_False).XY();
206 theInfo[i].Point = this->getNodesMap()->Value(aVertex.Location3d()).XYZ();
207 theInfo[i].isFrontierLink = (this->getStructure()->GetLink(e[i]).Movability() == BRepMesh_Frontier);
208 }
209 }
210
211 // Check geometry of the given triangle. If triangle does not suit specified deflection, inserts new point.
212 void splitTriangleGeometry(const BRepMesh_Triangle& theTriangle)
213 {
214 if (theTriangle.Movability() != BRepMesh_Deleted)
215 {
216 Standard_Integer aNodexIndices[3];
217 this->getStructure()->ElementNodes(theTriangle, aNodexIndices);
218
219 TriangleNodeInfo aNodesInfo[3];
220 getTriangleInfo(theTriangle, aNodexIndices, aNodesInfo);
221
222 gp_Vec aNormal;
223 gp_Vec aLinkVec[3];
224 if (computeTriangleGeometry(aNodesInfo, aLinkVec, aNormal))
225 {
226 myIsAllDegenerated = Standard_False;
227
228 const gp_XY aCenter2d = (aNodesInfo[0].Point2d +
229 aNodesInfo[1].Point2d +
230 aNodesInfo[2].Point2d) / 3.;
231
232 usePoint(aCenter2d, NormalDeviation(aNodesInfo[0].Point, aNormal));
233 splitLinks(aNodesInfo, aNodexIndices);
234 }
235 }
236 }
237
238 //! Updates array of links vectors.
239 //! @return False on degenerative triangle.
4945e8be 240 Standard_Boolean computeTriangleGeometry(
7bd071ed 241 const TriangleNodeInfo(&theNodesInfo)[3],
242 gp_Vec (&theLinks)[3],
243 gp_Vec &theNormal)
244 {
245 if (checkTriangleForDegenerativityAndGetLinks(theNodesInfo, theLinks))
246 {
247 if (checkTriangleArea2d(theNodesInfo))
248 {
249 if (computeNormal(theLinks[0], theLinks[1], theNormal))
250 {
251 return Standard_True;
252 }
253 }
254 }
255
256 return Standard_False;
257 }
258
259 //! Updates array of links vectors.
260 //! @return False on degenerative triangle.
4945e8be 261 Standard_Boolean checkTriangleForDegenerativityAndGetLinks(
7bd071ed 262 const TriangleNodeInfo (&theNodesInfo)[3],
263 gp_Vec (&theLinks)[3])
264 {
265 const Standard_Real MinimalSqLength3d = 1.e-12;
266 for (Standard_Integer i = 0; i < 3; ++i)
267 {
268 theLinks[i] = theNodesInfo[(i + 1) % 3].Point - theNodesInfo[i].Point;
269 if (theLinks[i].SquareMagnitude() < MinimalSqLength3d)
270 {
271 return Standard_False;
272 }
273 }
274
275 return Standard_True;
276 }
277
278 //! Checks area of triangle in parametric space for degenerativity.
279 //! @return False on degenerative triangle.
4945e8be 280 Standard_Boolean checkTriangleArea2d(
7bd071ed 281 const TriangleNodeInfo (&theNodesInfo)[3])
282 {
283 const gp_Vec2d aLink2d1(theNodesInfo[0].Point2d, theNodesInfo[1].Point2d);
284 const gp_Vec2d aLink2d2(theNodesInfo[1].Point2d, theNodesInfo[2].Point2d);
285
286 const Standard_Real MinimalArea2d = 1.e-9;
287 return (Abs(aLink2d1 ^ aLink2d2) > MinimalArea2d);
288 }
289
290 //! Computes normal using two link vectors.
291 //! @return True on success, False in case of normal of null magnitude.
4945e8be 292 Standard_Boolean computeNormal(const gp_Vec& theLink1,
293 const gp_Vec& theLink2,
294 gp_Vec& theNormal)
7bd071ed 295 {
296 const gp_Vec aNormal(theLink1 ^ theLink2);
297 if (aNormal.SquareMagnitude() > gp::Resolution())
298 {
299 theNormal = aNormal.Normalized();
300 return Standard_True;
301 }
302
303 return Standard_False;
304 }
305
306 //! Computes deflection of midpoints of triangles links.
307 //! @return True if point fits specified deflection.
4945e8be 308 void splitLinks(
7bd071ed 309 const TriangleNodeInfo (&theNodesInfo)[3],
310 const Standard_Integer (&theNodesIndices)[3])
311 {
312 // Check deflection at triangle links
313 for (Standard_Integer i = 0; i < 3; ++i)
314 {
315 if (theNodesInfo[i].isFrontierLink)
316 {
317 continue;
318 }
319
320 const Standard_Integer j = (i + 1) % 3;
321 // Check if this link was already processed
322 Standard_Integer aFirstVertex, aLastVertex;
323 if (theNodesIndices[i] < theNodesIndices[j])
324 {
325 aFirstVertex = theNodesIndices[i];
326 aLastVertex = theNodesIndices[j];
327 }
328 else
329 {
330 aFirstVertex = theNodesIndices[j];
331 aLastVertex = theNodesIndices[i];
332 }
333
334 if (myCouplesMap->Add(BRepMesh_OrientedEdge(aFirstVertex, aLastVertex)))
335 {
336 const gp_XY aMidPnt2d = (theNodesInfo[i].Point2d +
337 theNodesInfo[j].Point2d) / 2.;
338
46478ffe 339 if (!usePoint (aMidPnt2d, LineDeviation (theNodesInfo[i].Point,
340 theNodesInfo[j].Point)))
341 {
342 if (!checkLinkEndsForAngularDeviation(theNodesInfo[i],
343 theNodesInfo[j],
344 aMidPnt2d))
345 {
346 myControlNodes->Append(aMidPnt2d);
347 }
348 }
7bd071ed 349 }
350 }
351 }
352
46478ffe 353 //! Checks the given point (located between the given nodes)
354 //! for specified angular deviation.
355 Standard_Boolean checkLinkEndsForAngularDeviation(const TriangleNodeInfo& theNodeInfo1,
356 const TriangleNodeInfo& theNodeInfo2,
357 const gp_XY& /*theMidPoint*/)
358 {
359 gp_Dir aNorm1, aNorm2;
c22b52d6 360 const Handle(Geom_Surface)& aSurf = this->getDFace()->GetSurface()->Surface().Surface();
46478ffe 361
362 if ((GeomLib::NormEstim(aSurf, theNodeInfo1.Point2d, Precision::Confusion(), aNorm1) == 0) &&
363 (GeomLib::NormEstim(aSurf, theNodeInfo2.Point2d, Precision::Confusion(), aNorm2) == 0))
364 {
365 Standard_Real anAngle = aNorm1.Angle(aNorm2);
366 if (anAngle > this->getParameters().AngleInterior)
367 return Standard_False;
368 }
369#if 0
370 else if (GeomLib::NormEstim(aSurf, theMidPoint, Precision::Confusion(), aNorm1) != 0)
371 {
372 // It is better to consider the singular point as a node of triangulation.
373 // However, it leads to hangs up meshing some faces (including faces with
374 // degenerated edges). E.g. tests "mesh standard_incmesh Q6".
375 // So, this code fragment is better to implement in the future.
376 return Standard_False;
377 }
378#endif
379
380 return Standard_True;
381 }
382
7bd071ed 383 //! Computes deflection of the given point and caches it for
384 //! insertion in case if it overflows deflection.
385 //! @return True if point has been cached for insertion.
386 template<class DeflectionFunctor>
4945e8be 387 Standard_Boolean usePoint(
7bd071ed 388 const gp_XY& thePnt2d,
389 const DeflectionFunctor& theDeflectionFunctor)
390 {
391 gp_Pnt aPnt;
392 this->getDFace()->GetSurface()->D0(thePnt2d.X(), thePnt2d.Y(), aPnt);
393 if (!checkDeflectionOfPointAndUpdateCache(thePnt2d, aPnt, theDeflectionFunctor.SquareDeviation(aPnt)))
394 {
395 myControlNodes->Append(thePnt2d);
46478ffe 396 return Standard_True;
7bd071ed 397 }
46478ffe 398
399 return Standard_False;
7bd071ed 400 }
401
402 //! Checks the given point for specified linear deflection.
403 //! Updates value of total mesh defleciton.
404 Standard_Boolean checkDeflectionOfPointAndUpdateCache(
405 const gp_XY& thePnt2d,
406 const gp_Pnt& thePnt3d,
407 const Standard_Real theSqDeflection)
408 {
409 if (theSqDeflection > myMaxSqDeflection)
410 {
411 myMaxSqDeflection = theSqDeflection;
412 }
413
414 const Standard_Real aSqDeflection =
415 this->getDFace()->GetDeflection() * this->getDFace()->GetDeflection();
416 if (theSqDeflection < aSqDeflection)
417 {
418 return Standard_True;
419 }
420
421 return rejectByMinSize(thePnt2d, thePnt3d);
422 }
423
424 //! Checks the given node for
425 Standard_Boolean rejectByMinSize(
426 const gp_XY& thePnt2d,
427 const gp_Pnt& thePnt3d)
428 {
429 const Standard_Real aSqMinSize =
430 this->getParameters().MinSize * this->getParameters().MinSize;
431
432 IMeshData::MapOfInteger aUsedNodes;
433 IMeshData::ListOfInteger& aCirclesList =
434 const_cast<BRepMesh_CircleTool&>(*myCircles).Select(
435 this->getRangeSplitter().Scale(thePnt2d, Standard_True).XY());
436
437 IMeshData::ListOfInteger::Iterator aCircleIt(aCirclesList);
438 for (; aCircleIt.More(); aCircleIt.Next())
439 {
440 const BRepMesh_Triangle& aTriangle = this->getStructure()->GetElement(aCircleIt.Value());
441
442 Standard_Integer aNodes[3];
443 this->getStructure()->ElementNodes(aTriangle, aNodes);
444
445 for (Standard_Integer i = 0; i < 3; ++i)
446 {
447 if (!aUsedNodes.Contains(aNodes[i]))
448 {
449 aUsedNodes.Add(aNodes[i]);
450 const BRepMesh_Vertex& aVertex = this->getStructure()->GetNode(aNodes[i]);
451 const gp_Pnt& aPoint = this->getNodesMap()->Value(aVertex.Location3d());
452
453 if (thePnt3d.SquareDistance(aPoint) < aSqMinSize)
454 {
455 return Standard_True;
456 }
457 }
458 }
459 }
460
461 return Standard_False;
462 }
463
464private:
465 Standard_Real myMaxSqDeflection;
466 Standard_Boolean myIsAllDegenerated;
467 Handle(IMeshData::MapOfOrientedEdges) myCouplesMap;
468 Handle(IMeshData::ListOfPnt2d) myControlNodes;
469 const BRepMesh_CircleTool* myCircles;
470};
471
472#endif