1
0
mirror of https://git.dev.opencascade.org/repos/occt.git synced 2025-04-10 18:51:21 +03:00
occt/src/BRepMesh/BRepMesh_DelaunayDeflectionControlMeshAlgo.hxx
mkrylova 4945e8be99 0031789: Coding Rules - remove redundant Standard_EXPORT from TKMesh
- Standard_EXPORT which were specified for inline methods were deleted.
- ALL occurrences of DEFINE_STANDARD_RTTI_INLINE were replaced by DEFINE_STANDARD_RTTIEXT in header files and IMPLEMENT_STANDARD_RTTIEXT in source files
- ALL occurrences of "inline" keyword were deleted where it didn't not cause a linkage errors
- Added source files for classes that were without them for IMPLEMENT_STANDARD_RTTIEXT
2020-10-02 16:12:49 +03:00

474 lines
15 KiB
C++

// Created on: 2016-07-07
// Copyright (c) 2016 OPEN CASCADE SAS
// Created by: Oleg AGASHIN
//
// This file is part of Open CASCADE Technology software library.
//
// This library is free software; you can redistribute it and/or modify it under
// the terms of the GNU Lesser General Public License version 2.1 as published
// by the Free Software Foundation, with special exception defined in the file
// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
// distribution for complete text of the license and disclaimer of any warranty.
//
// Alternatively, this file may be used under the terms of Open CASCADE
// commercial license or contractual agreement.
#ifndef _BRepMeshTools_DelaunayDeflectionControlMeshAlgo_HeaderFile
#define _BRepMeshTools_DelaunayDeflectionControlMeshAlgo_HeaderFile
#include <BRepMesh_DelaunayNodeInsertionMeshAlgo.hxx>
#include <BRepMesh_GeomTool.hxx>
#include <GeomLib.hxx>
//! Extends node insertion Delaunay meshing algo in order to control
//! deflection of generated trianges. Splits triangles failing the check.
template<class RangeSplitter, class BaseAlgo>
class BRepMesh_DelaunayDeflectionControlMeshAlgo : public BRepMesh_DelaunayNodeInsertionMeshAlgo<RangeSplitter, BaseAlgo>
{
private:
// Typedef for OCCT RTTI
typedef BRepMesh_DelaunayNodeInsertionMeshAlgo<RangeSplitter, BaseAlgo> DelaunayInsertionBaseClass;
public:
//! Constructor.
BRepMesh_DelaunayDeflectionControlMeshAlgo()
: myMaxSqDeflection(-1.),
myIsAllDegenerated(Standard_False),
myCircles(NULL)
{
}
//! Destructor.
virtual ~BRepMesh_DelaunayDeflectionControlMeshAlgo()
{
}
protected:
//! Performs processing of generated mesh. Generates surface nodes and inserts them into structure.
virtual void postProcessMesh (BRepMesh_Delaun& theMesher,
const Message_ProgressRange& theRange) Standard_OVERRIDE
{
Message_ProgressScope aPS(theRange, "Post process mesh", 2);
// Insert surface nodes.
DelaunayInsertionBaseClass::postProcessMesh (theMesher, aPS.Next());
if (!aPS.More())
{
return;
}
if (this->getParameters().ControlSurfaceDeflection &&
this->getStructure()->ElementsOfDomain().Extent() > 0)
{
optimizeMesh(theMesher, aPS.Next());
}
else
{
aPS.Next();
}
}
//! Checks deviation of a mesh from geometrical surface.
//! Inserts additional nodes in case of huge deviation.
virtual void optimizeMesh (BRepMesh_Delaun& theMesher,
const Message_ProgressRange& theRange)
{
Handle(NCollection_IncAllocator) aTmpAlloc =
new NCollection_IncAllocator(IMeshData::MEMORY_BLOCK_SIZE_HUGE);
myCouplesMap = new IMeshData::MapOfOrientedEdges(3 * this->getStructure()->ElementsOfDomain().Extent(), aTmpAlloc);
myControlNodes = new IMeshData::ListOfPnt2d(aTmpAlloc);
myCircles = &theMesher.Circles();
const Standard_Integer aIterationsNb = 11;
Standard_Boolean isInserted = Standard_True;
Message_ProgressScope aPS(theRange, "Iteration", aIterationsNb);
for (Standard_Integer aPass = 1; aPass <= aIterationsNb && isInserted && !myIsAllDegenerated; ++aPass)
{
if (!aPS.More())
{
return;
}
// Reset stop condition
myMaxSqDeflection = -1.;
myIsAllDegenerated = Standard_True;
myControlNodes->Clear();
if (this->getStructure()->ElementsOfDomain().Extent() < 1)
{
break;
}
// Iterate on current triangles
IMeshData::IteratorOfMapOfInteger aTriangleIt(this->getStructure()->ElementsOfDomain());
for (; aTriangleIt.More(); aTriangleIt.Next())
{
const BRepMesh_Triangle& aTriangle = this->getStructure()->GetElement(aTriangleIt.Key());
splitTriangleGeometry(aTriangle);
}
isInserted = this->insertNodes(myControlNodes, theMesher, aPS.Next());
}
myCouplesMap.Nullify();
myControlNodes.Nullify();
if (!(myMaxSqDeflection < 0.))
{
this->getDFace()->SetDeflection(Sqrt(myMaxSqDeflection));
}
}
private:
//! Contains geometrical data related to node of triangle.
struct TriangleNodeInfo
{
TriangleNodeInfo()
: isFrontierLink(Standard_False)
{
}
gp_XY Point2d;
gp_XYZ Point;
Standard_Boolean isFrontierLink;
};
//! Functor computing deflection of a point from surface.
class NormalDeviation
{
public:
NormalDeviation(
const gp_Pnt& theRefPnt,
const gp_Vec& theNormal)
: myRefPnt(theRefPnt),
myNormal(theNormal)
{
}
Standard_Real SquareDeviation(const gp_Pnt& thePoint) const
{
const Standard_Real aDeflection = Abs(myNormal.Dot(gp_Vec(myRefPnt, thePoint)));
return aDeflection * aDeflection;
}
private:
NormalDeviation (const NormalDeviation& theOther);
void operator= (const NormalDeviation& theOther);
private:
const gp_Pnt& myRefPnt;
const gp_Vec& myNormal;
};
//! Functor computing deflection of a point on triangle link from surface.
class LineDeviation
{
public:
LineDeviation(
const gp_Pnt& thePnt1,
const gp_Pnt& thePnt2)
: myPnt1(thePnt1),
myPnt2(thePnt2)
{
}
Standard_Real SquareDeviation(const gp_Pnt& thePoint) const
{
return BRepMesh_GeomTool::SquareDeflectionOfSegment(myPnt1, myPnt2, thePoint);
}
private:
LineDeviation (const LineDeviation& theOther);
void operator= (const LineDeviation& theOther);
private:
const gp_Pnt& myPnt1;
const gp_Pnt& myPnt2;
};
//! Returns nodes info of the given triangle.
void getTriangleInfo(
const BRepMesh_Triangle& theTriangle,
const Standard_Integer (&theNodesIndices)[3],
TriangleNodeInfo (&theInfo)[3]) const
{
const Standard_Integer(&e)[3] = theTriangle.myEdges;
for (Standard_Integer i = 0; i < 3; ++i)
{
const BRepMesh_Vertex& aVertex = this->getStructure()->GetNode(theNodesIndices[i]);
theInfo[i].Point2d = this->getRangeSplitter().Scale(aVertex.Coord(), Standard_False).XY();
theInfo[i].Point = this->getNodesMap()->Value(aVertex.Location3d()).XYZ();
theInfo[i].isFrontierLink = (this->getStructure()->GetLink(e[i]).Movability() == BRepMesh_Frontier);
}
}
// Check geometry of the given triangle. If triangle does not suit specified deflection, inserts new point.
void splitTriangleGeometry(const BRepMesh_Triangle& theTriangle)
{
if (theTriangle.Movability() != BRepMesh_Deleted)
{
Standard_Integer aNodexIndices[3];
this->getStructure()->ElementNodes(theTriangle, aNodexIndices);
TriangleNodeInfo aNodesInfo[3];
getTriangleInfo(theTriangle, aNodexIndices, aNodesInfo);
gp_Vec aNormal;
gp_Vec aLinkVec[3];
if (computeTriangleGeometry(aNodesInfo, aLinkVec, aNormal))
{
myIsAllDegenerated = Standard_False;
const gp_XY aCenter2d = (aNodesInfo[0].Point2d +
aNodesInfo[1].Point2d +
aNodesInfo[2].Point2d) / 3.;
usePoint(aCenter2d, NormalDeviation(aNodesInfo[0].Point, aNormal));
splitLinks(aNodesInfo, aNodexIndices);
}
}
}
//! Updates array of links vectors.
//! @return False on degenerative triangle.
Standard_Boolean computeTriangleGeometry(
const TriangleNodeInfo(&theNodesInfo)[3],
gp_Vec (&theLinks)[3],
gp_Vec &theNormal)
{
if (checkTriangleForDegenerativityAndGetLinks(theNodesInfo, theLinks))
{
if (checkTriangleArea2d(theNodesInfo))
{
if (computeNormal(theLinks[0], theLinks[1], theNormal))
{
return Standard_True;
}
}
}
return Standard_False;
}
//! Updates array of links vectors.
//! @return False on degenerative triangle.
Standard_Boolean checkTriangleForDegenerativityAndGetLinks(
const TriangleNodeInfo (&theNodesInfo)[3],
gp_Vec (&theLinks)[3])
{
const Standard_Real MinimalSqLength3d = 1.e-12;
for (Standard_Integer i = 0; i < 3; ++i)
{
theLinks[i] = theNodesInfo[(i + 1) % 3].Point - theNodesInfo[i].Point;
if (theLinks[i].SquareMagnitude() < MinimalSqLength3d)
{
return Standard_False;
}
}
return Standard_True;
}
//! Checks area of triangle in parametric space for degenerativity.
//! @return False on degenerative triangle.
Standard_Boolean checkTriangleArea2d(
const TriangleNodeInfo (&theNodesInfo)[3])
{
const gp_Vec2d aLink2d1(theNodesInfo[0].Point2d, theNodesInfo[1].Point2d);
const gp_Vec2d aLink2d2(theNodesInfo[1].Point2d, theNodesInfo[2].Point2d);
const Standard_Real MinimalArea2d = 1.e-9;
return (Abs(aLink2d1 ^ aLink2d2) > MinimalArea2d);
}
//! Computes normal using two link vectors.
//! @return True on success, False in case of normal of null magnitude.
Standard_Boolean computeNormal(const gp_Vec& theLink1,
const gp_Vec& theLink2,
gp_Vec& theNormal)
{
const gp_Vec aNormal(theLink1 ^ theLink2);
if (aNormal.SquareMagnitude() > gp::Resolution())
{
theNormal = aNormal.Normalized();
return Standard_True;
}
return Standard_False;
}
//! Computes deflection of midpoints of triangles links.
//! @return True if point fits specified deflection.
void splitLinks(
const TriangleNodeInfo (&theNodesInfo)[3],
const Standard_Integer (&theNodesIndices)[3])
{
// Check deflection at triangle links
for (Standard_Integer i = 0; i < 3; ++i)
{
if (theNodesInfo[i].isFrontierLink)
{
continue;
}
const Standard_Integer j = (i + 1) % 3;
// Check if this link was already processed
Standard_Integer aFirstVertex, aLastVertex;
if (theNodesIndices[i] < theNodesIndices[j])
{
aFirstVertex = theNodesIndices[i];
aLastVertex = theNodesIndices[j];
}
else
{
aFirstVertex = theNodesIndices[j];
aLastVertex = theNodesIndices[i];
}
if (myCouplesMap->Add(BRepMesh_OrientedEdge(aFirstVertex, aLastVertex)))
{
const gp_XY aMidPnt2d = (theNodesInfo[i].Point2d +
theNodesInfo[j].Point2d) / 2.;
if (!usePoint (aMidPnt2d, LineDeviation (theNodesInfo[i].Point,
theNodesInfo[j].Point)))
{
if (!checkLinkEndsForAngularDeviation(theNodesInfo[i],
theNodesInfo[j],
aMidPnt2d))
{
myControlNodes->Append(aMidPnt2d);
}
}
}
}
}
//! Checks the given point (located between the given nodes)
//! for specified angular deviation.
Standard_Boolean checkLinkEndsForAngularDeviation(const TriangleNodeInfo& theNodeInfo1,
const TriangleNodeInfo& theNodeInfo2,
const gp_XY& /*theMidPoint*/)
{
gp_Dir aNorm1, aNorm2;
const Handle(Geom_Surface)& aSurf =
this->getDFace()->GetSurface()->ChangeSurface().Surface().Surface();
if ((GeomLib::NormEstim(aSurf, theNodeInfo1.Point2d, Precision::Confusion(), aNorm1) == 0) &&
(GeomLib::NormEstim(aSurf, theNodeInfo2.Point2d, Precision::Confusion(), aNorm2) == 0))
{
Standard_Real anAngle = aNorm1.Angle(aNorm2);
if (anAngle > this->getParameters().AngleInterior)
return Standard_False;
}
#if 0
else if (GeomLib::NormEstim(aSurf, theMidPoint, Precision::Confusion(), aNorm1) != 0)
{
// It is better to consider the singular point as a node of triangulation.
// However, it leads to hangs up meshing some faces (including faces with
// degenerated edges). E.g. tests "mesh standard_incmesh Q6".
// So, this code fragment is better to implement in the future.
return Standard_False;
}
#endif
return Standard_True;
}
//! Computes deflection of the given point and caches it for
//! insertion in case if it overflows deflection.
//! @return True if point has been cached for insertion.
template<class DeflectionFunctor>
Standard_Boolean usePoint(
const gp_XY& thePnt2d,
const DeflectionFunctor& theDeflectionFunctor)
{
gp_Pnt aPnt;
this->getDFace()->GetSurface()->D0(thePnt2d.X(), thePnt2d.Y(), aPnt);
if (!checkDeflectionOfPointAndUpdateCache(thePnt2d, aPnt, theDeflectionFunctor.SquareDeviation(aPnt)))
{
myControlNodes->Append(thePnt2d);
return Standard_True;
}
return Standard_False;
}
//! Checks the given point for specified linear deflection.
//! Updates value of total mesh defleciton.
Standard_Boolean checkDeflectionOfPointAndUpdateCache(
const gp_XY& thePnt2d,
const gp_Pnt& thePnt3d,
const Standard_Real theSqDeflection)
{
if (theSqDeflection > myMaxSqDeflection)
{
myMaxSqDeflection = theSqDeflection;
}
const Standard_Real aSqDeflection =
this->getDFace()->GetDeflection() * this->getDFace()->GetDeflection();
if (theSqDeflection < aSqDeflection)
{
return Standard_True;
}
return rejectByMinSize(thePnt2d, thePnt3d);
}
//! Checks the given node for
Standard_Boolean rejectByMinSize(
const gp_XY& thePnt2d,
const gp_Pnt& thePnt3d)
{
const Standard_Real aSqMinSize =
this->getParameters().MinSize * this->getParameters().MinSize;
IMeshData::MapOfInteger aUsedNodes;
IMeshData::ListOfInteger& aCirclesList =
const_cast<BRepMesh_CircleTool&>(*myCircles).Select(
this->getRangeSplitter().Scale(thePnt2d, Standard_True).XY());
IMeshData::ListOfInteger::Iterator aCircleIt(aCirclesList);
for (; aCircleIt.More(); aCircleIt.Next())
{
const BRepMesh_Triangle& aTriangle = this->getStructure()->GetElement(aCircleIt.Value());
Standard_Integer aNodes[3];
this->getStructure()->ElementNodes(aTriangle, aNodes);
for (Standard_Integer i = 0; i < 3; ++i)
{
if (!aUsedNodes.Contains(aNodes[i]))
{
aUsedNodes.Add(aNodes[i]);
const BRepMesh_Vertex& aVertex = this->getStructure()->GetNode(aNodes[i]);
const gp_Pnt& aPoint = this->getNodesMap()->Value(aVertex.Location3d());
if (thePnt3d.SquareDistance(aPoint) < aSqMinSize)
{
return Standard_True;
}
}
}
}
return Standard_False;
}
private:
Standard_Real myMaxSqDeflection;
Standard_Boolean myIsAllDegenerated;
Handle(IMeshData::MapOfOrientedEdges) myCouplesMap;
Handle(IMeshData::ListOfPnt2d) myControlNodes;
const BRepMesh_CircleTool* myCircles;
};
#endif