1
0
mirror of https://git.dev.opencascade.org/repos/occt.git synced 2025-04-05 18:16:23 +03:00
occt/src/BRepMesh/BRepMesh_FastDiscretFace.cxx
drazmyslovich 3e782664b8 0029715: Mesh - Estimate the grid size of the acceleration structure by the complexity of the face
The circles acceleration structure sizes are estimated using the required deflection and the complexity of the face.
2018-05-25 21:54:56 +03:00

1693 lines
56 KiB
C++

// Created by: Ekaterina SMIRNOVA
// Copyright (c) 2008-2014 OPEN CASCADE SAS
//
// 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.
#include <BRepMesh_FastDiscretFace.hxx>
#include <BRepMesh_PairOfPolygon.hxx>
#include <BRepMesh_ShapeTool.hxx>
#include <Poly_PolygonOnTriangulation.hxx>
#include <Poly_Triangulation.hxx>
#include <BRepAdaptor_Surface.hxx>
#include <BRepAdaptor_HSurface.hxx>
#include <BRepAdaptor_Curve.hxx>
#include <Adaptor3d_IsoCurve.hxx>
#include <Adaptor3d_HCurve.hxx>
#include <BRep_ListIteratorOfListOfPointRepresentation.hxx>
#include <BRep_PointRepresentation.hxx>
#include <BRep_TVertex.hxx>
#include <BRep_Tool.hxx>
#include <GeomLib.hxx>
#include <Geom_Surface.hxx>
#include <Geom_BSplineSurface.hxx>
#include <Geom_BezierSurface.hxx>
#include <GCPnts_TangentialDeflection.hxx>
#include <GCPnts_AbscissaPoint.hxx>
#include <Standard_ErrorHandler.hxx>
#include <Standard_Failure.hxx>
#include <TColStd_Array1OfReal.hxx>
#include <TColStd_ListOfInteger.hxx>
#include <TColStd_SequenceOfReal.hxx>
#include <TColStd_Array1OfInteger.hxx>
#include <TColStd_HArray1OfReal.hxx>
#include <TColgp_Array1OfPnt2d.hxx>
#include <TopTools_DataMapOfShapeReal.hxx>
#include <TopExp_Explorer.hxx>
#include <TopoDS.hxx>
#include <TopoDS_Vertex.hxx>
#include <TopExp.hxx>
#include <NCollection_Map.hxx>
#include <Bnd_Box2d.hxx>
#include <algorithm>
//#define DEBUG_MESH "mesh.tcl"
#ifdef DEBUG_MESH
#include <fstream>
#endif
IMPLEMENT_STANDARD_RTTIEXT(BRepMesh_FastDiscretFace,Standard_Transient)
static Standard_Real FUN_CalcAverageDUV(TColStd_Array1OfReal& P, const Standard_Integer PLen)
{
Standard_Integer i, j, n = 0;
Standard_Real p, result = 0.;
for(i = 1; i <= PLen; i++)
{
// Sort
for(j = i + 1; j <= PLen; j++)
{
if(P(i) > P(j))
{
p = P(i);
P(i) = P(j);
P(j) = p;
}
}
// Accumulate
if (i != 1)
{
p = Abs(P(i) - P(i-1));
if(p > 1.e-7)
{
result += p;
n++;
}
}
}
return (n? (result / (Standard_Real) n) : -1.);
}
namespace
{
Standard_Real deflectionOfSegment (
const gp_Pnt& theFirstPoint,
const gp_Pnt& theLastPoint,
const gp_Pnt& theMidPoint)
{
// 23.03.2010 skl for OCC21645 - change precision for comparison
if (theFirstPoint.SquareDistance (theLastPoint) > Precision::SquareConfusion ())
{
gp_Lin aLin (theFirstPoint, gp_Dir (gp_Vec (theFirstPoint, theLastPoint)));
return aLin.Distance (theMidPoint);
}
return theFirstPoint.Distance (theMidPoint);
}
Standard_Boolean IsCompexSurface (const GeomAbs_SurfaceType theType)
{
return (
theType != GeomAbs_Sphere &&
theType != GeomAbs_Cylinder &&
theType != GeomAbs_Cone &&
theType != GeomAbs_Torus);
}
//! Auxiliary class used to extract geometrical parameters of fixed TopoDS_Vertex.
class FixedVExplorer
{
public:
DEFINE_STANDARD_ALLOC
FixedVExplorer(const TopoDS_Vertex& theVertex)
: myVertex(theVertex)
{
}
const TopoDS_Vertex& Vertex() const
{
return myVertex;
}
Standard_Boolean IsSameUV() const
{
return Standard_False;
}
TopoDS_Vertex SameVertex() const
{
return TopoDS_Vertex();
}
gp_Pnt Point() const
{
return BRep_Tool::Pnt(myVertex);
}
private:
void operator =(const FixedVExplorer& /*theOther*/)
{
}
private:
const TopoDS_Vertex& myVertex;
};
void ComputeErrFactors (const Standard_Real theDeflection,
const Handle(Adaptor3d_HSurface)& theFace,
Standard_Real& theErrFactorU,
Standard_Real& theErrFactorV)
{
theErrFactorU = theDeflection * 10.;
theErrFactorV = theDeflection * 10.;
switch (theFace->GetType ())
{
case GeomAbs_Cylinder:
case GeomAbs_Cone:
case GeomAbs_Sphere:
case GeomAbs_Torus:
break;
case GeomAbs_SurfaceOfExtrusion:
case GeomAbs_SurfaceOfRevolution:
{
Handle (Adaptor3d_HCurve) aCurve = theFace->BasisCurve ();
if (aCurve->GetType () == GeomAbs_BSplineCurve && aCurve->Degree () > 2)
{
theErrFactorV /= (aCurve->Degree () * aCurve->NbKnots ());
}
break;
}
case GeomAbs_BezierSurface:
{
if (theFace->UDegree () > 2)
{
theErrFactorU /= (theFace->UDegree ());
}
if (theFace->VDegree () > 2)
{
theErrFactorV /= (theFace->VDegree ());
}
break;
}
case GeomAbs_BSplineSurface:
{
if (theFace->UDegree () > 2)
{
theErrFactorU /= (theFace->UDegree () * theFace->NbUKnots ());
}
if (theFace->VDegree () > 2)
{
theErrFactorV /= (theFace->VDegree () * theFace->NbVKnots ());
}
break;
}
case GeomAbs_Plane:
default:
theErrFactorU = theErrFactorV = 1.;
}
}
void AdjustCellsCounts (const Handle(Adaptor3d_HSurface)& theFace,
const Standard_Integer theNbVertices,
Standard_Integer& theCellsCountU,
Standard_Integer& theCellsCountV)
{
const GeomAbs_SurfaceType aType = theFace->GetType ();
if (aType == GeomAbs_OtherSurface)
{
// fallback to the default behavior
theCellsCountU = theCellsCountV = -1;
return;
}
Standard_Real aSqNbVert = theNbVertices;
if (aType == GeomAbs_Plane)
{
theCellsCountU = theCellsCountV = (Standard_Integer)Ceiling (Pow (2, Log10 (aSqNbVert)));
}
else if (aType == GeomAbs_Cylinder || aType == GeomAbs_Cone)
{
theCellsCountV = (Standard_Integer)Ceiling (Pow (2, Log10 (aSqNbVert)));
}
else if (aType == GeomAbs_SurfaceOfExtrusion || aType == GeomAbs_SurfaceOfRevolution)
{
Handle (Adaptor3d_HCurve) aCurve = theFace->BasisCurve ();
if (aCurve->GetType () == GeomAbs_Line ||
(aCurve->GetType () == GeomAbs_BSplineCurve && aCurve->Degree () < 2))
{
// planar, cylindrical, conical cases
if (aType == GeomAbs_SurfaceOfExtrusion)
theCellsCountU = (Standard_Integer)Ceiling (Pow (2, Log10 (aSqNbVert)));
else
theCellsCountV = (Standard_Integer)Ceiling (Pow (2, Log10 (aSqNbVert)));
}
if (aType == GeomAbs_SurfaceOfExtrusion)
{
// V is always a line
theCellsCountV = (Standard_Integer)Ceiling (Pow (2, Log10 (aSqNbVert)));
}
}
else if (aType == GeomAbs_BezierSurface || aType == GeomAbs_BSplineSurface)
{
if (theFace->UDegree () < 2)
{
theCellsCountU = (Standard_Integer)Ceiling (Pow (2, Log10 (aSqNbVert)));
}
if (theFace->VDegree () < 2)
{
theCellsCountV = (Standard_Integer)Ceiling (Pow (2, Log10 (aSqNbVert)));
}
}
theCellsCountU = Max (theCellsCountU, 2);
theCellsCountV = Max (theCellsCountV, 2);
}
}
//=======================================================================
//function : BRepMesh_FastDiscretFace
//purpose :
//=======================================================================
BRepMesh_FastDiscretFace::BRepMesh_FastDiscretFace(
const Standard_Real theAngle,
const Standard_Real theMinSize,
const Standard_Boolean isInternalVerticesMode,
const Standard_Boolean isControlSurfaceDeflection)
: myAngle(theAngle),
myInternalVerticesMode(isInternalVerticesMode),
myMinSize(theMinSize),
myIsControlSurfaceDeflection(isControlSurfaceDeflection)
{
}
//=======================================================================
//function : Perform
//purpose :
//=======================================================================
void BRepMesh_FastDiscretFace::Perform(const Handle(BRepMesh_FaceAttribute)& theAttribute)
{
add(theAttribute);
commitSurfaceTriangulation();
}
//=======================================================================
//function : initDataStructure
//purpose :
//=======================================================================
void BRepMesh_FastDiscretFace::initDataStructure()
{
const Standard_Real aTolU = myAttribute->ToleranceU();
const Standard_Real aTolV = myAttribute->ToleranceV();
const Standard_Real uCellSize = 14.0 * aTolU;
const Standard_Real vCellSize = 14.0 * aTolV;
const Standard_Real deltaX = myAttribute->GetDeltaX();
const Standard_Real deltaY = myAttribute->GetDeltaY();
Handle(NCollection_IncAllocator) aAllocator =
new NCollection_IncAllocator(BRepMesh::MEMORY_BLOCK_SIZE_HUGE);
myStructure = new BRepMesh_DataStructureOfDelaun(aAllocator);
myStructure->Data()->SetCellSize ( uCellSize / deltaX, vCellSize / deltaY);
myStructure->Data()->SetTolerance( aTolU / deltaX, aTolV / deltaY);
myAttribute->ChangeStructure() = myStructure;
myAttribute->ChangeSurfacePoints() = new BRepMesh::DMapOfIntegerPnt(1, aAllocator);
myAttribute->ChangeSurfaceVertices()= new BRepMesh::DMapOfVertexInteger(1, aAllocator);
// Check the necessity to fill the map of parameters
const Handle(BRepAdaptor_HSurface)& gFace = myAttribute->Surface();
GeomAbs_SurfaceType thetype = gFace->GetType();
const Standard_Boolean isBSpline = (thetype == GeomAbs_BezierSurface ||
thetype == GeomAbs_BSplineSurface);
const Standard_Boolean useUVParam = (thetype == GeomAbs_Torus || IsCompexSurface (thetype));
Handle(NCollection_BaseAllocator) aBaseAlloc = aAllocator;
myUParam.Clear (aBaseAlloc);
myVParam.Clear (aBaseAlloc);
// essai de determination de la longueur vraie:
// akm (bug OCC16) : We must calculate these measures in non-singular
// parts of face. Let`s try to compute average value of three
// (umin, (umin+umax)/2, umax), and respectively for v.
// vvvvv
//Standard_Real longu = 0.0, longv = 0.0; //, last , first;
//gp_Pnt P11, P12, P21, P22, P31, P32;
BRepMesh::HVectorOfVertex& aBoundaryNodes = myAttribute->ChangeMeshNodes();
BRepMesh::VectorOfVertex::Iterator aNodesIt(*aBoundaryNodes);
for (; aNodesIt.More(); aNodesIt.Next())
{
BRepMesh_Vertex& aNode = aNodesIt.ChangeValue();
gp_XY aPnt2d = aNode.Coord();
if (useUVParam)
{
myUParam.Add(aPnt2d.X());
myVParam.Add(aPnt2d.Y());
}
aNode.ChangeCoord() = myAttribute->Scale(aPnt2d, Standard_True);
myStructure->AddNode(aNode, Standard_True);
}
aBoundaryNodes.Nullify();
if (isBSpline)
{
const Standard_Real aRange[2][2] = {
{myAttribute->GetUMin(), myAttribute->GetUMax()},
{myAttribute->GetVMin(), myAttribute->GetVMax()}
};
const GeomAbs_Shape aContinuity = GeomAbs_CN;
for (Standard_Integer i = 0; i < 2; ++i)
{
const Standard_Boolean isU = (i == 0);
const Standard_Integer aIntervalsNb = isU ?
gFace->NbUIntervals(aContinuity) :
gFace->NbVIntervals(aContinuity);
BRepMesh::IMapOfReal& aParams = isU ? myUParam : myVParam;
if (aIntervalsNb < aParams.Size())
continue;
TColStd_Array1OfReal aIntervals(1, aIntervalsNb + 1);
if (isU)
gFace->UIntervals(aIntervals, aContinuity);
else
gFace->VIntervals(aIntervals, aContinuity);
for (Standard_Integer j = 1; j <= aIntervals.Upper(); ++j)
{
const Standard_Real aParam = aIntervals(j);
if (aParam > aRange[i][0] && aParam < aRange[i][1])
aParams.Add(aParam);
}
}
}
////////////////////////////////////////////////////////////
//add internal vertices after self-intersection check
if ( myInternalVerticesMode )
{
TopExp_Explorer anExplorer(myAttribute->Face(), TopAbs_VERTEX, TopAbs_EDGE);
for ( ; anExplorer.More(); anExplorer.Next() )
add(TopoDS::Vertex(anExplorer.Current()));
}
const BRepMesh::HDMapOfShapePairOfPolygon& aEdges = myAttribute->ChangeInternalEdges();
TopExp_Explorer aWireIt(myAttribute->Face(), TopAbs_WIRE);
for (; aWireIt.More(); aWireIt.Next())
{
TopExp_Explorer aEdgeIt(aWireIt.Current(), TopAbs_EDGE);
for (; aEdgeIt.More(); aEdgeIt.Next())
{
const TopoDS_Edge& aEdge = TopoDS::Edge(aEdgeIt.Current());
BRepMesh_PairOfPolygon aPair;
if (!aEdges->Find(aEdge, aPair))
continue;
TopAbs_Orientation aOri = aEdge.Orientation();
const Handle(Poly_PolygonOnTriangulation)& aPolygon =
aOri == TopAbs_REVERSED ? aPair.Last() : aPair.First();
const TColStd_Array1OfInteger& aIndices = aPolygon->Nodes();
const Standard_Integer aNodesNb = aPolygon->NbNodes();
Standard_Integer aPrevId = aIndices(1);
for (Standard_Integer i = 2; i <= aNodesNb; ++i)
{
const Standard_Integer aCurId = aIndices(i);
addLinkToMesh(aPrevId, aCurId, aOri);
aPrevId = aCurId;
}
}
}
}
//=======================================================================
//function : addLinkToMesh
//purpose :
//=======================================================================
void BRepMesh_FastDiscretFace::addLinkToMesh(
const Standard_Integer theFirstNodeId,
const Standard_Integer theLastNodeId,
const TopAbs_Orientation theOrientation)
{
if (theOrientation == TopAbs_FORWARD)
myStructure->AddLink(BRepMesh_Edge(theFirstNodeId, theLastNodeId, BRepMesh_Frontier));
else if (theOrientation == TopAbs_REVERSED)
myStructure->AddLink(BRepMesh_Edge(theLastNodeId, theFirstNodeId, BRepMesh_Frontier));
else if (theOrientation == TopAbs_INTERNAL)
myStructure->AddLink(BRepMesh_Edge(theFirstNodeId, theLastNodeId, BRepMesh_Fixed));
}
//=======================================================================
//function : Add
//purpose :
//=======================================================================
void BRepMesh_FastDiscretFace::add(const Handle(BRepMesh_FaceAttribute)& theAttribute)
{
if (!theAttribute->IsValid() || theAttribute->ChangeMeshNodes()->IsEmpty())
return;
myAttribute = theAttribute;
initDataStructure();
BRepMesh::HIMapOfInteger& aVertexEdgeMap = myAttribute->ChangeVertexEdgeMap();
Standard_Integer nbVertices = aVertexEdgeMap->Extent();
BRepMesh::Array1OfInteger tabvert_corr(1, nbVertices);
for ( Standard_Integer i = 1; i <= nbVertices; ++i )
tabvert_corr(i) = i;
Handle (Adaptor3d_HSurface) aSurface (myAttribute->Surface ());
GeomAbs_SurfaceType aType = aSurface->GetType ();
while (aType == GeomAbs_OffsetSurface)
{
aSurface = aSurface->BasisSurface ();
aType = aSurface->GetType ();
}
// For better meshing performance we try to estimate the acceleration circles grid structure sizes:
// For each parametric direction (U, V) we estimate firstly an approximate distance between the future points -
// this estimation takes into account the required face deflection and the complexity of the face.
// Particularly, the complexity of the faces based on BSpline curves and surfaces requires much more points.
// At the same time, for planar faces and linear parts of the arbitrary surfaces usually no intermediate points
// are necessary.
// The general idea for each parametric direction:
// cells_count = 2 ^ log10 ( estimated_points_count )
// For linear parametric direction we fall back to the initial vertex count:
// cells_count = 2 ^ log10 ( initial_vertex_count )
Standard_Real anErrFactorU, anErrFactorV;
ComputeErrFactors(myAttribute->GetDefFace (), aSurface, anErrFactorU, anErrFactorV);
Standard_Integer aCellsCountU, aCellsCountV;
if (aType == GeomAbs_Torus)
{
aCellsCountU = (Standard_Integer)Ceiling(Pow(2, Log10(
(myAttribute->GetUMax() - myAttribute->GetUMin()) / myAttribute->GetDeltaX())));
aCellsCountV = (Standard_Integer)Ceiling(Pow(2, Log10(
(myAttribute->GetVMax() - myAttribute->GetVMin()) / myAttribute->GetDeltaY())));
}
else if (aType == GeomAbs_Cylinder)
{
aCellsCountU = (Standard_Integer)Ceiling(Pow(2, Log10(
(myAttribute->GetUMax() - myAttribute->GetUMin()) / myAttribute->GetDeltaX() /
(myAttribute->GetVMax() - myAttribute->GetVMin()))));
aCellsCountV = (Standard_Integer)Ceiling(Pow(2, Log10(
(myAttribute->GetVMax() - myAttribute->GetVMin()) / anErrFactorV)));
}
else
{
aCellsCountU = (Standard_Integer)Ceiling(Pow(2, Log10(
(myAttribute->GetUMax() - myAttribute->GetUMin()) / myAttribute->GetDeltaX() / anErrFactorU)));
aCellsCountV = (Standard_Integer)Ceiling(Pow(2, Log10(
(myAttribute->GetVMax() - myAttribute->GetVMin()) / myAttribute->GetDeltaY() / anErrFactorV)));
}
AdjustCellsCounts(aSurface, nbVertices, aCellsCountU, aCellsCountV);
BRepMesh_Delaun trigu(myStructure, tabvert_corr, aCellsCountU, aCellsCountV);
//removed all free edges from triangulation
const Standard_Integer nbLinks = myStructure->NbLinks();
for( Standard_Integer i = 1; i <= nbLinks; i++ )
{
if( myStructure->ElementsConnectedTo(i).Extent() < 1 )
{
BRepMesh_Edge& anEdge = (BRepMesh_Edge&)trigu.GetEdge(i);
if ( anEdge.Movability() == BRepMesh_Deleted )
continue;
anEdge.SetMovability(BRepMesh_Free);
myStructure->RemoveLink(i);
}
}
Standard_Boolean rajout =
(aType == GeomAbs_Sphere || aType == GeomAbs_Torus);
// Check the necessity to fill the map of parameters
const Standard_Boolean useUVParam = (aType == GeomAbs_Torus ||
aType == GeomAbs_BezierSurface ||
aType == GeomAbs_BSplineSurface);
const Standard_Real umax = myAttribute->GetUMax();
const Standard_Real umin = myAttribute->GetUMin();
const Standard_Real vmax = myAttribute->GetVMax();
const Standard_Real vmin = myAttribute->GetVMin();
Standard_Boolean isaline =
((umax - umin) < Precision::PConfusion() ||
(vmax - vmin) < Precision::PConfusion());
Standard_Real aDef = -1;
if ( !isaline && myStructure->ElementsOfDomain().Extent() > 0 )
{
if (!rajout)
{
// compute maximal deflection
aDef = control(trigu, Standard_True);
rajout = (aDef > myAttribute->GetDefFace() || aDef < 0.);
}
if (aType != GeomAbs_Plane)
{
if (!rajout && useUVParam)
{
rajout = (myVParam.Extent() > 2 &&
(aSurface->IsUClosed() || aSurface->IsVClosed()));
}
if (rajout)
{
insertInternalVertices(trigu);
//control internal points
if (myIsControlSurfaceDeflection)
aDef = control(trigu, Standard_False);
}
}
}
//modify myStructure back
BRepMesh::HVectorOfVertex& aMeshNodes = myStructure->Data()->ChangeVertices();
for ( Standard_Integer i = 1; i <= myStructure->NbNodes(); ++i )
{
BRepMesh_Vertex& aNode = aMeshNodes->ChangeValue(i - 1);
aNode.ChangeCoord() = myAttribute->Scale(aNode.Coord(), Standard_False);
const BRepMesh::ListOfInteger& alist = myStructure->LinksConnectedTo(i);
// Register internal nodes used in triangulation
if (!alist.IsEmpty() && aVertexEdgeMap->FindIndex(i) == 0)
aVertexEdgeMap->Add(i);
}
if (!(aDef < 0.))
myAttribute->SetDefFace(aDef);
}
//=======================================================================
//function : addVerticesToMesh
//purpose :
//=======================================================================
Standard_Boolean BRepMesh_FastDiscretFace::addVerticesToMesh(
const BRepMesh::ListOfVertex& theVertices,
BRepMesh_Delaun& theMeshBuilder)
{
if (theVertices.IsEmpty())
return Standard_False;
BRepMesh::Array1OfVertexOfDelaun aArrayOfNewVertices(1, theVertices.Extent());
BRepMesh::ListOfVertex::Iterator aVertexIt(theVertices);
for (Standard_Integer aVertexId = 0; aVertexIt.More(); aVertexIt.Next())
aArrayOfNewVertices(++aVertexId) = aVertexIt.Value();
theMeshBuilder.AddVertices(aArrayOfNewVertices);
return Standard_True;
}
//=======================================================================
//function : filterParameters
//purpose :
//=======================================================================
static void filterParameters(const BRepMesh::IMapOfReal& theParams,
const Standard_Real theMinDist,
const Standard_Real theFilterDist,
BRepMesh::SequenceOfReal& theResult)
{
// Sort sequence of parameters
const Standard_Integer anInitLen = theParams.Extent();
TColStd_Array1OfReal aParamArray(1, anInitLen);
Standard_Integer j;
for (j = 1; j <= anInitLen; j++)
aParamArray(j) = theParams(j);
std::sort (aParamArray.begin(), aParamArray.end());
// mandatory pre-filtering using the first (minimal) filter value
Standard_Integer aParamLength = 1;
for (j = 2; j <= anInitLen; j++)
{
if ((aParamArray(j)-aParamArray(aParamLength)) > theMinDist)
{
if (++aParamLength < j)
aParamArray(aParamLength) = aParamArray(j);
}
}
//perform filtering on series
Standard_Real aLastAdded, aLastCandidate;
Standard_Boolean isCandidateDefined = Standard_False;
aLastAdded = aParamArray(1);
aLastCandidate = aLastAdded;
theResult.Append(aLastAdded);
for(j=2; j < aParamLength; j++)
{
Standard_Real aVal = aParamArray(j);
if(aVal-aLastAdded > theFilterDist)
{
//adds the parameter
if(isCandidateDefined) {
aLastAdded = aLastCandidate;
isCandidateDefined = Standard_False;
j--;
}
else
{
aLastAdded = aVal;
}
theResult.Append(aLastAdded);
continue;
}
aLastCandidate = aVal;
isCandidateDefined = Standard_True;
}
theResult.Append(aParamArray(aParamLength));
}
//=======================================================================
//function : insertInternalVertices
//purpose :
//=======================================================================
void BRepMesh_FastDiscretFace::insertInternalVertices(BRepMesh_Delaun& theMeshBuilder)
{
Handle(NCollection_IncAllocator) anAlloc = new NCollection_IncAllocator;
BRepMesh::ListOfVertex aNewVertices(anAlloc);
const Handle(BRepAdaptor_HSurface)& gFace = myAttribute->Surface();
switch (gFace->GetType())
{
case GeomAbs_Sphere:
insertInternalVerticesSphere(aNewVertices);
break;
case GeomAbs_Cylinder:
insertInternalVerticesCylinder(aNewVertices);
break;
case GeomAbs_Cone:
insertInternalVerticesCone(aNewVertices);
break;
case GeomAbs_Torus:
insertInternalVerticesTorus(aNewVertices);
break;
default:
insertInternalVerticesOther(aNewVertices);
break;
}
addVerticesToMesh(aNewVertices, theMeshBuilder);
}
//=======================================================================
//function : insertInternalVerticesSphere
//purpose :
//=======================================================================
void BRepMesh_FastDiscretFace::insertInternalVerticesSphere(
BRepMesh::ListOfVertex& theNewVertices)
{
Standard_Real aRange[] = {
myAttribute->GetVMin(), myAttribute->GetVMax(),
myAttribute->GetUMin(), myAttribute->GetUMax()
};
gp_Sphere aSphere = myAttribute->Surface()->Sphere();
// Calculate parameters for iteration in V direction
Standard_Real aStep = 0.7 * GCPnts_TangentialDeflection::ArcAngularStep(
aSphere.Radius(), myAttribute->GetDefFace(), myAngle, myMinSize);
Standard_Real aDd[2] = {aStep, aStep};
Standard_Real aPasMax[2] = {0., 0.};
for (Standard_Integer i = 0; i < 2; ++i)
{
const Standard_Real aMax = aRange[2 * i + 1];
const Standard_Real aDiff = aMax - aRange[2 * i + 0];
aDd[i] = aDiff / ((Standard_Integer)(aDiff / aDd[i]) + 1);
aPasMax[i] = aMax - Precision::PConfusion();
}
const Standard_Real aHalfDu = aDd[1] * 0.5;
Standard_Boolean Shift = Standard_False;
Standard_Real aPasV = aRange[0] + aDd[0];
for (; aPasV < aPasMax[0]; aPasV += aDd[0])
{
Shift = !Shift;
const Standard_Real d = (Shift) ? aHalfDu : 0.;
Standard_Real aPasU = aRange[2] + d;
for (; aPasU < aPasMax[1]; aPasU += aDd[1])
{
tryToInsertAnalyticVertex(gp_Pnt2d(aPasU, aPasV), aSphere, theNewVertices);
}
}
}
//=======================================================================
//function : insertInternalVerticesCylinder
//purpose :
//=======================================================================
void BRepMesh_FastDiscretFace::insertInternalVerticesCylinder(
BRepMesh::ListOfVertex& theNewVertices)
{
const Standard_Real umax = myAttribute->GetUMax();
const Standard_Real umin = myAttribute->GetUMin();
const Standard_Real vmax = myAttribute->GetVMax();
const Standard_Real vmin = myAttribute->GetVMin();
gp_Cylinder aCylinder = myAttribute->Surface()->Cylinder();
const Standard_Real aRadius = aCylinder.Radius();
Standard_Integer nbU = 0;
Standard_Integer nbV = 0;
const Standard_Real su = umax - umin;
const Standard_Real sv = vmax - vmin;
const Standard_Real aArcLen = su * aRadius;
if (aArcLen > myAttribute->GetDefFace ())
{
// Calculate parameters for iteration in U direction
const Standard_Real Du = GCPnts_TangentialDeflection::ArcAngularStep (
aRadius, myAttribute->GetDefFace (), myAngle, myMinSize);
nbU = (Standard_Integer)(su / Du);
// Calculate parameters for iteration in V direction
const Standard_Real aDv = nbU*sv / aArcLen;
// Protection against overflow during casting to int in case
// of long cylinder with small radius.
nbV = aDv > static_cast<Standard_Real> (IntegerLast ()) ?
0 : (Standard_Integer)(aDv);
nbV = Min (nbV, 100 * nbU);
}
const Standard_Real Du = su / (nbU + 1);
const Standard_Real Dv = sv / (nbV + 1);
Standard_Real pasu, pasv, pasvmax = vmax - Dv*0.5, pasumax = umax - Du*0.5;
for (pasv = vmin + Dv; pasv < pasvmax; pasv += Dv)
{
for (pasu = umin + Du; pasu < pasumax; pasu += Du)
{
tryToInsertAnalyticVertex(gp_Pnt2d(pasu, pasv), aCylinder, theNewVertices);
}
}
}
//=======================================================================
//function : insertInternalVerticesCone
//purpose :
//=======================================================================
void BRepMesh_FastDiscretFace::insertInternalVerticesCone(
BRepMesh::ListOfVertex& theNewVertices)
{
const Standard_Real umax = myAttribute->GetUMax();
const Standard_Real umin = myAttribute->GetUMin();
const Standard_Real vmax = myAttribute->GetVMax();
const Standard_Real vmin = myAttribute->GetVMin();
gp_Cone aCone = myAttribute->Surface()->Cone();
Standard_Real RefR = aCone.RefRadius();
Standard_Real SAng = aCone.SemiAngle();
Standard_Real aRadius = Max(Abs(RefR + vmin*Sin(SAng)), Abs(RefR + vmax*Sin(SAng)));
Standard_Real Du = GCPnts_TangentialDeflection::ArcAngularStep(
aRadius, myAttribute->GetDefFace(), myAngle, myMinSize);
Standard_Real Dv, pasu, pasv;
Standard_Integer nbU = (Standard_Integer)((umax - umin) / Du);
Standard_Integer nbV = (Standard_Integer)(nbU*(vmax - vmin) / ((umax - umin)*aRadius));
Du = (umax - umin) / (nbU + 1);
Dv = (vmax - vmin) / (nbV + 1);
Standard_Real pasvmax = vmax - Dv*0.5, pasumax = umax - Du*0.5;
for (pasv = vmin + Dv; pasv < pasvmax; pasv += Dv)
{
for (pasu = umin + Du; pasu < pasumax; pasu += Du)
{
tryToInsertAnalyticVertex(gp_Pnt2d(pasu, pasv), aCone, theNewVertices);
}
}
}
//=======================================================================
//function : insertInternalVerticesTorus
//purpose :
//=======================================================================
void BRepMesh_FastDiscretFace::insertInternalVerticesTorus(
BRepMesh::ListOfVertex& theNewVertices)
{
const Standard_Real umax = myAttribute->GetUMax();
const Standard_Real umin = myAttribute->GetUMin();
const Standard_Real vmax = myAttribute->GetVMax();
const Standard_Real vmin = myAttribute->GetVMin();
const Standard_Real deltaX = myAttribute->GetDeltaX();
const Standard_Real deltaY = myAttribute->GetDeltaY();
const Standard_Real aDefFace = myAttribute->GetDefFace();
gp_Torus T = myAttribute->Surface()->Torus();
Standard_Boolean insert;
Standard_Integer i, j, ParamULength, ParamVLength;
Standard_Real pp, pasu, pasv;
Standard_Real r = T.MinorRadius(), R = T.MajorRadius();
BRepMesh::SequenceOfReal ParamU, ParamV;
Standard_Real oldDv = GCPnts_TangentialDeflection::ArcAngularStep(
r, aDefFace, myAngle, myMinSize);
Standard_Real Dv = 0.9*oldDv; //TWOTHIRD * oldDv;
Dv = oldDv;
Standard_Real Du;
Standard_Integer nbV = Max((Standard_Integer)((vmax - vmin) / Dv), 2);
Dv = (vmax - vmin) / (nbV + 1);
Standard_Real ru = R + r;
if (ru > 1.e-16)
{
Du = GCPnts_TangentialDeflection::ArcAngularStep(
ru, aDefFace, myAngle, myMinSize);
Standard_Real aa = sqrt(Du*Du + oldDv*oldDv);
if (aa < gp::Resolution())
return;
Du *= Min(oldDv, Du) / aa;
}
else Du = Dv;
Standard_Integer nbU = Max((Standard_Integer)((umax - umin) / Du), 2);
nbU = Max(nbU, (int)(nbV*(umax - umin)*R / ((vmax - vmin)*r) / 5.));
Du = (umax - umin) / (nbU + 1);
if (R < r)
{
// As the points of edges are returned.
// in this case, the points are not representative.
//-- Choose DeltaX and DeltaY so that to avoid skipping points on the grid
for (i = 0; i <= nbU; i++) ParamU.Append(umin + i* Du);
}//R<r
else //U if R > r
{
//--ofv: U
// Number of mapped U parameters
const Standard_Integer LenU = myUParam.Extent();
// Fill array of U parameters
TColStd_Array1OfReal Up(1, LenU);
for (j = 1; j <= LenU; j++) Up(j) = myUParam(j);
// Calculate DU, leave array of parameters
Standard_Real aDU = FUN_CalcAverageDUV(Up, LenU);
aDU = Max(aDU, Abs(umax - umin) / (Standard_Real)nbU / 2.);
Standard_Real dUstd = Abs(umax - umin) / (Standard_Real)LenU;
if (aDU > dUstd) dUstd = aDU;
// Add U parameters
for (j = 1; j <= LenU; j++)
{
pp = Up(j);
insert = Standard_True;
ParamULength = ParamU.Length();
for (i = 1; i <= ParamULength && insert; i++)
{
insert = (Abs(ParamU.Value(i) - pp) > (0.5*dUstd));
}
if (insert) ParamU.Append(pp);
}
}
//--ofv: V
// Number of mapped V parameters
const Standard_Integer LenV = myVParam.Extent();
// Fill array of V parameters
TColStd_Array1OfReal Vp(1, LenV);
for (j = 1; j <= LenV; j++) Vp(j) = myVParam(j);
// Calculate DV, sort array of parameters
Standard_Real aDV = FUN_CalcAverageDUV(Vp, LenV);
aDV = Max(aDV, Abs(vmax - vmin) / (Standard_Real)nbV / 2.);
Standard_Real dVstd = Abs(vmax - vmin) / (Standard_Real)LenV;
if (aDV > dVstd) dVstd = aDV;
// Add V parameters
for (j = 1; j <= LenV; j++)
{
pp = Vp(j);
insert = Standard_True;
ParamVLength = ParamV.Length();
for (i = 1; i <= ParamVLength && insert; i++)
{
insert = (Abs(ParamV.Value(i) - pp) > (dVstd*2. / 3.));
}
if (insert) ParamV.Append(pp);
}
Standard_Integer Lu = ParamU.Length(), Lv = ParamV.Length();
Standard_Real uminnew = umin + deltaY*0.1;
Standard_Real vminnew = vmin + deltaX*0.1;
Standard_Real umaxnew = umax - deltaY*0.1;
Standard_Real vmaxnew = vmax - deltaX*0.1;
for (i = 1; i <= Lu; i++)
{
pasu = ParamU.Value(i);
if (pasu >= uminnew && pasu < umaxnew)
{
for (j = 1; j <= Lv; j++)
{
pasv = ParamV.Value(j);
if (pasv >= vminnew && pasv < vmaxnew)
{
tryToInsertAnalyticVertex(gp_Pnt2d(pasu, pasv), T, theNewVertices);
}
}
}
}
}
//=======================================================================
//function : insertInternalVerticesOther
//purpose :
//=======================================================================
void BRepMesh_FastDiscretFace::insertInternalVerticesOther(
BRepMesh::ListOfVertex& theNewVertices)
{
const Standard_Real aRange[2][2] = {
{ myAttribute->GetUMax(), myAttribute->GetUMin() },
{ myAttribute->GetVMax(), myAttribute->GetVMin() }
};
const Standard_Real aDelta[2] = {
myAttribute->GetDeltaX(),
myAttribute->GetDeltaY()
};
const Standard_Real aDefFace = myAttribute->GetDefFace();
const Handle(BRepAdaptor_HSurface)& gFace = myAttribute->Surface();
Handle(NCollection_IncAllocator) anAlloc = new NCollection_IncAllocator;
BRepMesh::SequenceOfReal aParams[2] = { BRepMesh::SequenceOfReal(anAlloc),
BRepMesh::SequenceOfReal(anAlloc) };
for (Standard_Integer i = 0; i < 2; ++i)
{
Standard_Boolean isU = (i == 0);
Standard_Real aRes = isU ?
gFace->UResolution(aDefFace) :
gFace->VResolution(aDefFace);
// Sort and filter sequence of parameters
Standard_Real aMinDiff = Precision::PConfusion();
if (aDelta[i] < 1.)
aMinDiff /= aDelta[i];
aMinDiff = Max(myMinSize, aMinDiff);
Standard_Real aRangeDiff = aRange[i][0] - aRange[i][1];
Standard_Real aDiffMaxLim = 0.1 * aRangeDiff;
Standard_Real aDiffMinLim = Max(0.005 * aRangeDiff, 2. * aRes);
Standard_Real aDiff = Max(myMinSize, Min(aDiffMaxLim, aDiffMinLim));
filterParameters(isU ? myUParam : myVParam, aMinDiff, aDiff, aParams[i]);
}
// check intermediate isolines
Handle (Geom_Surface) aSurface = gFace->ChangeSurface ().Surface ().Surface ();
BRepMesh::MapOfReal aParamsToRemove[2] = { BRepMesh::MapOfReal(1, anAlloc),
BRepMesh::MapOfReal(1, anAlloc) };
BRepMesh::MapOfReal aParamsForbiddenToRemove[2] = { BRepMesh::MapOfReal(1, anAlloc),
BRepMesh::MapOfReal(1, anAlloc) };
// insert additional points where it is needed to conform criteria.
// precision for normals calculation
const Standard_Real aNormPrec = Precision::Confusion();
for (Standard_Integer k = 0; k < 2; ++k)
{
const Standard_Integer aOtherIndex = (k + 1) % 2;
BRepMesh::SequenceOfReal& aParams1 = aParams[k];
BRepMesh::SequenceOfReal& aParams2 = aParams[aOtherIndex];
const Standard_Boolean isU = (k == 0);
for (Standard_Integer i = 2; i < aParams1.Length(); ++i)
{
const Standard_Real aParam1 = aParams1(i);
GeomAdaptor_Curve aIso(isU ?
aSurface->UIso(aParam1) : aSurface->VIso(aParam1));
Standard_Real aPrevParam2 = aParams2(1);
gp_Pnt aPrevPnt2;
gp_Vec aPrevVec2;
aIso.D1(aPrevParam2, aPrevPnt2, aPrevVec2);
for (Standard_Integer j = 2; j <= aParams2.Length();)
{
Standard_Real aParam2 = aParams2(j);
gp_Pnt aPnt2;
gp_Vec aVec2;
aIso.D1(aParam2, aPnt2, aVec2);
Standard_Real aMidParam = 0.5 * (aPrevParam2 + aParam2);
gp_Pnt aMidPnt = aIso.Value(aMidParam);
Standard_Real aDist = deflectionOfSegment(aPrevPnt2, aPnt2, aMidPnt);
if (aDist > aDefFace && aDist > myMinSize)
{
// insertion
aParams2.InsertBefore(j, aMidParam);
continue;
}
//put regular grig for normals
gp_Pnt2d aStPnt1, aStPnt2;
if (isU)
{
aStPnt1 = gp_Pnt2d(aParam1, aPrevParam2);
aStPnt2 = gp_Pnt2d(aParam1, aMidParam);
}
else
{
aStPnt1 = gp_Pnt2d(aPrevParam2, aParam1);
aStPnt2 = gp_Pnt2d(aMidParam, aParam1);
}
gp_Dir N1(0, 0, 1), N2(0, 0, 1);
Standard_Integer aSt1 = GeomLib::NormEstim(aSurface, aStPnt1, aNormPrec, N1);
Standard_Integer aSt2 = GeomLib::NormEstim(aSurface, aStPnt2, aNormPrec, N2);
const Standard_Real aAngle = N2.Angle(N1);
if (aSt1 < 1 && aSt2 < 1 && aAngle > myAngle)
{
const Standard_Real aLen = GCPnts_AbscissaPoint::Length(
aIso, aPrevParam2, aMidParam, aDefFace);
if (aLen > myMinSize)
{
// insertion
aParams2.InsertBefore(j, aMidParam);
continue;
}
}
aPrevParam2 = aParam2;
aPrevPnt2 = aPnt2;
aPrevVec2 = aVec2;
++j;
}
}
}
#ifdef DEBUG_InsertInternal
// output numbers of parameters along U and V
cout << "aParams: " << aParams[0].Length() << " " << aParams[1].Length() << endl;
#endif
// try to reduce number of points evaluating of isolines sampling
for (Standard_Integer k = 0; k < 2; ++k)
{
const Standard_Integer aOtherIndex = (k + 1) % 2;
BRepMesh::SequenceOfReal& aParams1 = aParams[k];
BRepMesh::SequenceOfReal& aParams2 = aParams[aOtherIndex];
const Standard_Boolean isU = (k == 0);
BRepMesh::MapOfReal& aToRemove2 = aParamsToRemove[aOtherIndex];
BRepMesh::MapOfReal& aForbiddenToRemove1 = aParamsForbiddenToRemove[k];
BRepMesh::MapOfReal& aForbiddenToRemove2 = aParamsForbiddenToRemove[aOtherIndex];
for (Standard_Integer i = 2; i < aParams1.Length(); ++i)
{
const Standard_Real aParam1 = aParams1(i);
GeomAdaptor_Curve aIso(isU ?
aSurface->UIso (aParam1) : aSurface->VIso (aParam1));
#ifdef DEBUG_InsertInternal
// write polyline containing initial parameters to the file
{
ofstream ff(DEBUG_InsertInternal, std::ios_base::app);
ff << "polyline " << (k == 0 ? "u" : "v") << i << " ";
for (Standard_Integer j = 1; j <= aParams2.Length(); j++)
{
gp_Pnt aP;
aIso.D0(aParams2(j), aP);
ff << aP.X() << " " << aP.Y() << " " << aP.Z() << " ";
}
ff << endl;
}
#endif
Standard_Real aPrevParam2 = aParams2(1);
gp_Pnt aPrevPnt2;
gp_Vec aPrevVec2;
aIso.D1 (aPrevParam2, aPrevPnt2, aPrevVec2);
for (Standard_Integer j = 2; j <= aParams2.Length();)
{
Standard_Real aParam2 = aParams2(j);
gp_Pnt aPnt2;
gp_Vec aVec2;
aIso.D1 (aParam2, aPnt2, aVec2);
// Here we should leave at least 3 parameters as far as
// we must have at least one parameter related to surface
// internals in order to prevent movement of triangle body
// outside the surface in case of highly curved ones, e.g.
// BSpline springs.
if (aParams2.Length() > 3 && j < aParams2.Length())
{
// Remove too dense points
const Standard_Real aNextParam = aParams2(j + 1);
gp_Pnt aNextPnt;
gp_Vec aNextVec;
aIso.D1(aNextParam, aNextPnt, aNextVec);
// Lets check current parameter.
// If it fits deflection, we can remove it.
Standard_Real aDist = deflectionOfSegment(aPrevPnt2, aNextPnt, aPnt2);
if (aDist < aDefFace)
{
// Lets check parameters for angular deflection.
if (aPrevVec2.SquareMagnitude() > gp::Resolution() &&
aNextVec.SquareMagnitude() > gp::Resolution() &&
aPrevVec2.Angle(aNextVec) < myAngle)
{
// For current Iso line we can remove this parameter.
#ifdef DEBUG_InsertInternal
// write point of removed parameter
{
ofstream ff(DEBUG_InsertInternal, std::ios_base::app);
ff << "point " << (k == 0 ? "u" : "v") << i << "r_" << j << " "
<< aPnt2.X() << " " << aPnt2.Y() << " " << aPnt2.Z() << endl;
}
#endif
aToRemove2.Add(aParam2);
aPrevParam2 = aNextParam;
aPrevPnt2 = aNextPnt;
aPrevVec2 = aNextVec;
j += 2;
continue;
}
else {
// We have found a place on the surface refusing
// removement of this parameter.
#ifdef DEBUG_InsertInternal
// write point of forbidden to remove parameter
{
ofstream ff(DEBUG_InsertInternal, std::ios_base::app);
ff << "vertex " << (k == 0 ? "u" : "v") << i << "f_" << j << " "
<< aPnt2.X() << " " << aPnt2.Y() << " " << aPnt2.Z() << endl;
}
#endif
aForbiddenToRemove1.Add(aParam1);
aForbiddenToRemove2.Add(aParam2);
}
}
}
aPrevParam2 = aParam2;
aPrevPnt2 = aPnt2;
aPrevVec2 = aVec2;
++j;
}
}
}
// remove filtered out parameters
for (Standard_Integer k = 0; k < 2; ++k)
{
BRepMesh::SequenceOfReal& aParamsk = aParams[k];
for (Standard_Integer i = 1; i <= aParamsk.Length();)
{
const Standard_Real aParam = aParamsk.Value(i);
if (aParamsToRemove[k].Contains(aParam) &&
!aParamsForbiddenToRemove[k].Contains(aParam))
{
aParamsk.Remove(i);
}
else
i++;
}
}
#ifdef DEBUG_InsertInternal
// write polylines containing remaining parameters
{
ofstream ff(DEBUG_InsertInternal, std::ios_base::app);
for (Standard_Integer k = 0; k < 2; ++k)
{
for (Standard_Integer i = 1; i <= aParams[k].Length(); i++)
{
ff << "polyline " << (k == 0 ? "uo" : "vo") << i << " ";
for (Standard_Integer j = 1; j <= aParams[1 - k].Length(); j++)
{
gp_Pnt aP;
if (k == 0)
gFace->D0(aParams[k](i), aParams[1 - k](j), aP);
else
gFace->D0(aParams[1 - k](j), aParams[k](i), aP);
ff << aP.X() << " " << aP.Y() << " " << aP.Z() << " ";
}
ff << endl;
}
}
}
#endif
// insert nodes of the regular grid
const BRepMesh::HClassifier& aClassifier = myAttribute->ChangeClassifier();
for (Standard_Integer i = 1; i <= aParams[0].Length(); ++i)
{
const Standard_Real aParam1 = aParams[0].Value (i);
for (Standard_Integer j = 1; j <= aParams[1].Length(); ++j)
{
const Standard_Real aParam2 = aParams[1].Value (j);
gp_Pnt2d aPnt2d(aParam1, aParam2);
// Classify intersection point
if (aClassifier->Perform(aPnt2d) == TopAbs_IN)
{
gp_Pnt aPnt;
gFace->D0(aPnt2d.X(), aPnt2d.Y(), aPnt);
insertVertex(aPnt, aPnt2d.Coord(), theNewVertices);
}
}
}
}
//=======================================================================
//function : checkDeflectionAndInsert
//purpose :
//=======================================================================
Standard_Boolean BRepMesh_FastDiscretFace::checkDeflectionAndInsert(
const gp_Pnt& thePnt3d,
const gp_XY& theUV,
const Standard_Boolean isDeflectionCheckOnly,
const Standard_Real theTriangleDeflection,
const Standard_Real theFaceDeflection,
const BRepMesh_CircleTool& theCircleTool,
BRepMesh::ListOfVertex& theVertices,
Standard_Real& theMaxTriangleDeflection,
const Handle(NCollection_IncAllocator)& theTempAlloc)
{
if (theTriangleDeflection > theMaxTriangleDeflection)
theMaxTriangleDeflection = theTriangleDeflection;
if (theTriangleDeflection < theFaceDeflection)
return Standard_True;
if (myMinSize > Precision::Confusion())
{
// Iterator in the list of indexes of circles containing the node
BRepMesh::ListOfInteger& aCirclesList =
const_cast<BRepMesh_CircleTool&>(theCircleTool).Select(
myAttribute->Scale(theUV, Standard_True));
BRepMesh::MapOfInteger aUsedNodes(10, theTempAlloc);
BRepMesh::ListOfInteger::Iterator aCircleIt(aCirclesList);
for (; aCircleIt.More(); aCircleIt.Next())
{
const BRepMesh_Triangle& aTriangle =
myStructure->GetElement(aCircleIt.Value());
Standard_Integer aNodes[3];
myStructure->ElementNodes(aTriangle, aNodes);
for (Standard_Integer i = 0; i < 3; ++i)
{
const Standard_Integer aNodeId = aNodes[i];
if (aUsedNodes.Contains(aNodeId))
continue;
aUsedNodes.Add(aNodeId);
const BRepMesh_Vertex& aNode = myStructure->GetNode(aNodeId);
const gp_Pnt& aPoint = myAttribute->GetPoint(aNode);
if (thePnt3d.SquareDistance(aPoint) < myMinSize * myMinSize)
return Standard_True;
}
}
}
if (isDeflectionCheckOnly)
return Standard_False;
insertVertex(thePnt3d, theUV, theVertices);
return Standard_True;
}
//=======================================================================
//function : control
//purpose :
//=======================================================================
Standard_Real BRepMesh_FastDiscretFace::control(
BRepMesh_Delaun& theTrigu,
const Standard_Boolean theIsFirst)
{
Standard_Integer aTrianglesNb = myStructure->ElementsOfDomain().Extent();
if (aTrianglesNb < 1)
return -1.0;
//IMPORTANT: Constants used in calculations
const Standard_Real MinimalArea2d = 1.e-9;
const Standard_Real MinimalSqLength3d = 1.e-12;
const Standard_Real aSqDefFace = myAttribute->GetDefFace() * myAttribute->GetDefFace();
const Handle(BRepAdaptor_HSurface)& gFace = myAttribute->Surface();
Handle(Geom_Surface) aBSpline;
const GeomAbs_SurfaceType aSurfType = gFace->GetType ();
if (IsCompexSurface (aSurfType) && aSurfType != GeomAbs_SurfaceOfExtrusion)
aBSpline = gFace->ChangeSurface ().Surface().Surface();
Handle(NCollection_IncAllocator) anAlloc =
new NCollection_IncAllocator(BRepMesh::MEMORY_BLOCK_SIZE_HUGE);
NCollection_DataMap<Standard_Integer, gp_Dir> aNorMap(1, anAlloc);
BRepMesh::MapOfIntegerInteger aStatMap(1, anAlloc);
NCollection_Map<BRepMesh_Edge> aCouples(3 * aTrianglesNb, anAlloc);
const BRepMesh_CircleTool& aCircles = theTrigu.Circles();
// Perform refinement passes
// Define the number of iterations
Standard_Integer aIterationsNb = 11;
const Standard_Integer aPassesNb = (theIsFirst ? 1 : aIterationsNb);
// Initialize stop condition
Standard_Real aMaxSqDef = -1.;
Standard_Integer aPass = 1, aInsertedNb = 1;
Standard_Boolean isAllDegenerated = Standard_False;
Handle(NCollection_IncAllocator) aTempAlloc =
new NCollection_IncAllocator(BRepMesh::MEMORY_BLOCK_SIZE_HUGE);
for (; aPass <= aPassesNb && aInsertedNb && !isAllDegenerated; ++aPass)
{
aTempAlloc->Reset(Standard_False);
BRepMesh::ListOfVertex aNewVertices(aTempAlloc);
// Reset stop condition
aInsertedNb = 0;
aMaxSqDef = -1.;
isAllDegenerated = Standard_True;
aTrianglesNb = myStructure->ElementsOfDomain().Extent();
if (aTrianglesNb < 1)
break;
// Iterate on current triangles
const BRepMesh::MapOfInteger& aTriangles = myStructure->ElementsOfDomain();
BRepMesh::MapOfInteger::Iterator aTriangleIt(aTriangles);
for (; aTriangleIt.More(); aTriangleIt.Next())
{
const Standard_Integer aTriangleId = aTriangleIt.Key();
const BRepMesh_Triangle& aCurrentTriangle = myStructure->GetElement(aTriangleId);
if (aCurrentTriangle.Movability() == BRepMesh_Deleted)
continue;
Standard_Integer v[3];
myStructure->ElementNodes(aCurrentTriangle, v);
Standard_Integer e[3];
Standard_Boolean o[3];
aCurrentTriangle.Edges(e, o);
gp_XY xy[3];
gp_XYZ p[3];
Standard_Boolean m[3];
for (Standard_Integer i = 0; i < 3; ++i)
{
m[i] = (myStructure->GetLink(e[i]).Movability() == BRepMesh_Frontier);
const BRepMesh_Vertex& aVertex = myStructure->GetNode(v[i]);
xy[i] = myAttribute->Scale(aVertex.Coord(), Standard_False);
p [i] = myAttribute->GetPoint(aVertex).Coord();
}
gp_XYZ aLinkVec[3];
Standard_Boolean isDegeneratedTri = Standard_False;
for (Standard_Integer i = 0; i < 3 && !isDegeneratedTri; ++i)
{
aLinkVec[i] = p[(i + 1) % 3] - p[i];
isDegeneratedTri = (aLinkVec[i].SquareModulus() < MinimalSqLength3d);
}
if (isDegeneratedTri)
continue;
isAllDegenerated = Standard_False;
// Check triangle area in 2d
if (Abs((xy[1]-xy[0])^(xy[2]-xy[1])) < MinimalArea2d)
continue;
// Check triangle normal
gp_Pnt pDef;
Standard_Real aSqDef = -1.;
Standard_Boolean isSkipped = Standard_False;
gp_XYZ normal(aLinkVec[0] ^ aLinkVec[1]);
if (normal.SquareModulus () < gp::Resolution())
continue;
normal.Normalize();
// Check deflection at triangle centroid
gp_XY aCenter2d = (xy[0] + xy[1] + xy[2]) / 3.0;
gFace->D0(aCenter2d.X(), aCenter2d.Y(), pDef);
aSqDef = Abs(normal * (pDef.XYZ() - p[0]));
aSqDef *= aSqDef;
isSkipped = !checkDeflectionAndInsert(pDef, aCenter2d, theIsFirst,
aSqDef, aSqDefFace, aCircles, aNewVertices, aMaxSqDef, aTempAlloc);
if (isSkipped)
break;
// Check deflection at triangle links
for (Standard_Integer i = 0; i < 3 && !isSkipped; ++i)
{
if (m[i]) // is a boundary
continue;
// Check if this link was already processed
if (aCouples.Add(myStructure->GetLink(e[i])))
{
// Check deflection on edge 1
Standard_Integer j = (i + 1) % 3;
gp_XY mi2d = (xy[i] + xy[j]) * 0.5;
gFace->D0(mi2d.X(), mi2d.Y(), pDef);
gp_Lin aLin(p[i], gp_Vec(p[i], p[j]));
aSqDef = aLin.SquareDistance(pDef);
isSkipped = !checkDeflectionAndInsert(pDef, mi2d, theIsFirst,
aSqDef, aSqDefFace, aCircles, aNewVertices, aMaxSqDef, aTempAlloc);
}
}
if (isSkipped)
break;
//check normal on bsplines
if (theIsFirst && !aBSpline.IsNull())
{
gp_Dir N[3] = { gp::DZ(), gp::DZ(), gp::DZ() };
Standard_Integer aSt[3];
for (Standard_Integer i = 0; i < 3; ++i)
{
if (aNorMap.IsBound(v[i]))
{
aSt[i] = aStatMap.Find(v[i]);
N[i] = aNorMap.Find(v[i]);
}
else
{
aSt[i] = GeomLib::NormEstim(aBSpline, gp_Pnt2d(xy[i]), Precision::Confusion(), N[i]);
aStatMap.Bind(v[i], aSt[i]);
aNorMap.Bind(v[i], N[i]);
}
}
Standard_Real aAngle[3];
for (Standard_Integer i = 0; i < 3; ++i)
aAngle[i] = N[(i + 1) % 3].Angle(N[i]);
if (aSt[0] < 1 && aSt[1] < 1 && aSt[2] < 1)
{
if (aAngle[0] > myAngle || aAngle[1] > myAngle || aAngle[2] > myAngle)
{
aMaxSqDef = -1.;
break;
}
}
}
}
if (theIsFirst)
continue;
#ifdef DEBUG_MESH
// append to the file triangles in the form of polyline commands;
// so the file can be sourced in draw to analyze triangles on each pass of the algorithm.
// write triangles
ofstream ftt(DEBUG_MESH, std::ios_base::app);
Standard_Integer nbElem = myStructure->NbElements();
for (Standard_Integer i = 1; i <= nbElem; i++)
{
const BRepMesh_Triangle& aTri = myStructure->GetElement(i);
if (aTri.Movability() == BRepMesh_Deleted)
continue;
Standard_Integer n[3];
myStructure->ElementNodes(aTri, n);
const BRepMesh_Vertex& aV1 = myStructure->GetNode(n[0]);
const BRepMesh_Vertex& aV2 = myStructure->GetNode(n[1]);
const BRepMesh_Vertex& aV3 = myStructure->GetNode(n[2]);
const gp_Pnt& aP1 = myAttribute->GetPoint(aV1);
const gp_Pnt& aP2 = myAttribute->GetPoint(aV2);
const gp_Pnt& aP3 = myAttribute->GetPoint(aV3);
ftt << "polyline t" << aPass << "_" << i << " "
<< aP1.X() << " " << aP1.Y() << " " << aP1.Z() << " "
<< aP2.X() << " " << aP2.Y() << " " << aP2.Z() << " "
<< aP3.X() << " " << aP3.Y() << " " << aP3.Z() << " "
<< aP1.X() << " " << aP1.Y() << " " << aP1.Z() << endl;
}
// write points to insert on the current pass
BRepMesh::ListOfVertex::Iterator it(aNewVertices);
for (Standard_Integer i=1; it.More(); it.Next(), i++)
{
const BRepMesh_Vertex& aVertex = it.Value();
const gp_Pnt& aP = myAttribute->GetPoint(aVertex);
ftt << "vertex vt" << aPass << "_" << i << " "
<< aP.X() << " " << aP.Y() << " " << aP.Z() << endl;
}
#endif
if (addVerticesToMesh(aNewVertices, theTrigu))
++aInsertedNb;
}
return (aMaxSqDef < 0) ? aMaxSqDef : Sqrt(aMaxSqDef);
}
//=======================================================================
//function : add
//purpose :
//=======================================================================
void BRepMesh_FastDiscretFace::add(const TopoDS_Vertex& theVertex)
{
if (theVertex.Orientation() != TopAbs_INTERNAL)
return;
try
{
OCC_CATCH_SIGNALS
gp_Pnt2d aPnt2d = BRep_Tool::Parameters(theVertex, myAttribute->Face());
// check UV values for internal vertices
if (myAttribute->ChangeClassifier()->Perform(aPnt2d) != TopAbs_IN)
return;
NCollection_Handle<FixedVExplorer> aFixedVExplorer = new FixedVExplorer(theVertex);
Standard_Integer aIndex = myAttribute->GetVertexIndex(aFixedVExplorer);
gp_XY anUV = BRepMesh_ShapeTool::FindUV(aIndex, aPnt2d,
BRep_Tool::Tolerance(theVertex), myAttribute);
Standard_Integer aTmpId1, aTmpId2;
anUV = myAttribute->Scale(anUV, Standard_True);
myAttribute->AddNode(aIndex, anUV, BRepMesh_Fixed, aTmpId1, aTmpId2);
}
catch (Standard_Failure)
{
}
}
//=======================================================================
//function : insertVertex
//purpose :
//=======================================================================
void BRepMesh_FastDiscretFace::insertVertex(
const gp_Pnt& thePnt3d,
const gp_XY& theUV,
BRepMesh::ListOfVertex& theVertices)
{
Standard_Integer aNbLocat = myAttribute->LastPointId();
myAttribute->ChangeSurfacePoints()->Bind(++aNbLocat, thePnt3d);
gp_XY aPnt2d = myAttribute->Scale(theUV, Standard_True);
BRepMesh_Vertex aVertex(aPnt2d, aNbLocat, BRepMesh_Free);
theVertices.Append(aVertex);
}
//=======================================================================
//function : commitSurfaceTriangulation
//purpose :
//=======================================================================
void BRepMesh_FastDiscretFace::commitSurfaceTriangulation()
{
if (myAttribute.IsNull() || !myAttribute->IsValid())
return;
const TopoDS_Face& aFace = myAttribute->Face();
BRepMesh_ShapeTool::NullifyFace(aFace);
Handle(BRepMesh_DataStructureOfDelaun)& aStructure = myAttribute->ChangeStructure();
const BRepMesh::MapOfInteger& aTriangles = aStructure->ElementsOfDomain();
if (aTriangles.IsEmpty())
{
myAttribute->SetStatus(BRepMesh_Failure);
return;
}
BRepMesh::HIMapOfInteger& aVetrexEdgeMap = myAttribute->ChangeVertexEdgeMap();
// Store triangles
Standard_Integer aVerticesNb = aVetrexEdgeMap->Extent();
Standard_Integer aTrianglesNb = aTriangles.Extent();
Handle(Poly_Triangulation) aNewTriangulation =
new Poly_Triangulation(aVerticesNb, aTrianglesNb, Standard_True);
Poly_Array1OfTriangle& aPolyTrianges = aNewTriangulation->ChangeTriangles();
Standard_Integer aTriangeId = 1;
BRepMesh::MapOfInteger::Iterator aTriIt(aTriangles);
for (; aTriIt.More(); aTriIt.Next())
{
const BRepMesh_Triangle& aCurElem = aStructure->GetElement(aTriIt.Key());
Standard_Integer aNode[3];
aStructure->ElementNodes(aCurElem, aNode);
Standard_Integer aNodeId[3];
for (Standard_Integer i = 0; i < 3; ++i)
aNodeId[i] = aVetrexEdgeMap->FindIndex(aNode[i]);
aPolyTrianges(aTriangeId++).Set(aNodeId[0], aNodeId[1], aNodeId[2]);
}
// Store mesh nodes
TColgp_Array1OfPnt& aNodes = aNewTriangulation->ChangeNodes();
TColgp_Array1OfPnt2d& aNodes2d = aNewTriangulation->ChangeUVNodes();
for (Standard_Integer i = 1; i <= aVerticesNb; ++i)
{
Standard_Integer aVertexId = aVetrexEdgeMap->FindKey(i);
const BRepMesh_Vertex& aVertex = aStructure->GetNode(aVertexId);
const gp_Pnt& aPoint = myAttribute->GetPoint(aVertex);
aNodes(i) = aPoint;
aNodes2d(i) = aVertex.Coord();
}
aNewTriangulation->Deflection(myAttribute->GetDefFace());
BRepMesh_ShapeTool::AddInFace(aFace, aNewTriangulation);
// Delete unused data
myUParam.Clear(0L);
myVParam.Clear(0L);
myAttribute->ChangeStructure().Nullify();
myAttribute->ChangeSurfacePoints().Nullify();
myAttribute->ChangeSurfaceVertices().Nullify();
myAttribute->ChangeClassifier().Nullify();
myAttribute->ChangeLocation2D().Nullify();
myAttribute->ChangeVertexEdgeMap().Nullify();
}