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_FastDiscret.cxx

990 lines
33 KiB
C++

// Created on: 1996-02-27
// Created by: Ekaterina SMIRNOVA
// Copyright (c) 1996-1999 Matra Datavision
// Copyright (c) 1999-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_FastDiscret.hxx>
#include <BRepMesh_WireChecker.hxx>
#include <BRepMesh_FastDiscretFace.hxx>
#include <BRepMesh_FaceAttribute.hxx>
#include <BRepMesh_DataStructureOfDelaun.hxx>
#include <BRepMesh_GeomTool.hxx>
#include <BRepMesh_PairOfPolygon.hxx>
#include <BRepMesh_Classifier.hxx>
#include <BRepMesh_EdgeParameterProvider.hxx>
#include <BRepMesh_IEdgeTool.hxx>
#include <BRepMesh_EdgeTessellator.hxx>
#include <BRepMesh_EdgeTessellationExtractor.hxx>
#include <BRepAdaptor_Curve.hxx>
#include <BRepAdaptor_Surface.hxx>
#include <BRepAdaptor_HSurface.hxx>
#include <Bnd_Box.hxx>
#include <BRepTools.hxx>
#include <BRepBndLib.hxx>
#include <BndLib_Add3dCurve.hxx>
#include <Poly_Triangulation.hxx>
#include <Poly_PolygonOnTriangulation.hxx>
#include <Precision.hxx>
#include <Geom2d_Curve.hxx>
#include <Geom2dAdaptor_HCurve.hxx>
#include <Geom_Surface.hxx>
#include <Geom_Plane.hxx>
#include <GeomAbs_SurfaceType.hxx>
#include <Extrema_LocateExtPC.hxx>
#include <TColStd_Array1OfInteger.hxx>
#include <TColStd_Array1OfCharacter.hxx>
#include <TColStd_HArray1OfReal.hxx>
#include <TColgp_Array1OfPnt2d.hxx>
#include <TColGeom2d_SequenceOfCurve.hxx>
#include <TopTools_SequenceOfShape.hxx>
#include <TopTools_ListIteratorOfListOfShape.hxx>
#include <TopAbs.hxx>
#include <TopoDS.hxx>
#include <TopoDS_Vertex.hxx>
#include <TopExp.hxx>
#include <TopExp_Explorer.hxx>
#include <OSD_Parallel.hxx>
#include <Standard_ErrorHandler.hxx>
#include <Standard_Failure.hxx>
#include <NCollection_IncAllocator.hxx>
#include <Message_ProgressSentry.hxx>
#include <BRep_ListIteratorOfListOfPointRepresentation.hxx>
#include <BRep_PointRepresentation.hxx>
#include <vector>
IMPLEMENT_STANDARD_RTTIEXT(BRepMesh_FastDiscret,Standard_Transient)
#define UVDEFLECTION 1.e-05
//=======================================================================
//function : BRepMesh_FastDiscret
//purpose :
//=======================================================================
BRepMesh_FastDiscret::BRepMesh_FastDiscret( const Bnd_Box& theBox,
const BRepMesh_FastDiscret::Parameters& theParams)
:
myMapdefle(1000, new NCollection_IncAllocator()),
myBoundaryVertices(new BRepMesh::DMapOfVertexInteger),
myBoundaryPoints(new BRepMesh::DMapOfIntegerPnt),
myParameters(theParams),
myDtotale(0.)
{
if ( myParameters.Relative )
BRepMesh_ShapeTool::BoxMaxDimension(theBox, myDtotale);
}
//=======================================================================
//function : InitSharedFaces
//purpose :
//=======================================================================
void BRepMesh_FastDiscret::InitSharedFaces(const TopoDS_Shape& theShape)
{
TopExp::MapShapesAndAncestors(theShape, TopAbs_EDGE, TopAbs_FACE, mySharedFaces);
}
//=======================================================================
//function : Perform(shape)
//purpose :
//=======================================================================
void BRepMesh_FastDiscret::Perform(const TopoDS_Shape& theShape)
{
InitSharedFaces(theShape);
std::vector<TopoDS_Face> aFaces;
TopExp_Explorer anExplorer(theShape, TopAbs_FACE);
for (; anExplorer.More(); anExplorer.Next())
{
const TopoDS_Face& aFace = TopoDS::Face(anExplorer.Current());
Add(aFace);
aFaces.push_back(aFace);
}
OSD_Parallel::ForEach(aFaces.begin(), aFaces.end(), *this, !myParameters.InParallel);
}
//=======================================================================
//function : Process
//purpose :
//=======================================================================
void BRepMesh_FastDiscret::Process(const TopoDS_Face& theFace) const
{
Process (theFace, NULL);
}
//=======================================================================
//function : Process
//purpose :
//=======================================================================
void BRepMesh_FastDiscret::Process (const TopoDS_Face& theFace,
Message_ProgressSentry* theProgrEntry) const
{
Handle(BRepMesh_FaceAttribute) anAttribute;
if (GetFaceAttribute(theFace, anAttribute)
&& (theProgrEntry == NULL || theProgrEntry->More()))
{
try
{
OCC_CATCH_SIGNALS
BRepMesh_FastDiscretFace aTool(myParameters.Angle, myParameters.MinSize,
myParameters.InternalVerticesMode, myParameters.ControlSurfaceDeflection);
aTool.Perform (anAttribute, theProgrEntry);
}
catch (Standard_Failure)
{
anAttribute->SetStatus(BRepMesh_Failure);
}
}
}
//=======================================================================
//function : resetDataStructure
//purpose :
//=======================================================================
void BRepMesh_FastDiscret::resetDataStructure()
{
Handle(NCollection_IncAllocator) aAllocator;
if (myAttribute->ChangeStructure().IsNull())
aAllocator = new NCollection_IncAllocator(BRepMesh::MEMORY_BLOCK_SIZE_HUGE);
else
aAllocator = myAttribute->ChangeStructure()->Allocator();
myAttribute->Clear();
aAllocator->Reset(Standard_False);
Handle(BRepMesh_DataStructureOfDelaun) aStructure =
new BRepMesh_DataStructureOfDelaun(aAllocator);
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;
aStructure->Data()->SetCellSize ( uCellSize, vCellSize);
aStructure->Data()->SetTolerance( aTolU , aTolV );
myAttribute->ChangeStructure() = aStructure;
}
//=======================================================================
//function : Add(face)
//purpose :
//=======================================================================
Standard_Integer BRepMesh_FastDiscret::Add(const TopoDS_Face& theFace)
{
myAttribute.Nullify();
GetFaceAttribute(theFace, myAttribute, Standard_True);
try
{
OCC_CATCH_SIGNALS
// Initialize face attributes
if (!myAttribute->IsInitialized ())
myAttribute->SetFace (theFace, myParameters.AdaptiveMin);
BRepMesh::HIMapOfInteger& aVertexEdgeMap = myAttribute->ChangeVertexEdgeMap();
BRepMesh::HDMapOfShapePairOfPolygon& aInternalEdges = myAttribute->ChangeInternalEdges();
resetDataStructure();
Standard_Real defedge = myParameters.Deflection;
Standard_Integer nbEdge = 0;
Standard_Real savangle = myParameters.Angle;
Standard_Real cdef;
Standard_Real maxdef = 2.* BRepMesh_ShapeTool::MaxFaceTolerance(theFace);
Standard_Real defface = 0.;
if (!myParameters.Relative)
{
defedge = Max(UVDEFLECTION, defedge);
defface = Max(myParameters.Deflection, maxdef);
}
const TopoDS_Face& aFace = myAttribute->Face();
for (TopoDS_Iterator aWireIt(aFace); aWireIt.More(); aWireIt.Next())
{
for (TopoDS_Iterator aEdgeIt(aWireIt.Value()); aEdgeIt.More(); aEdgeIt.Next(), ++nbEdge)
{
const TopoDS_Edge& aEdge = TopoDS::Edge(aEdgeIt.Value());
if (aEdge.IsNull())
continue;
if (myParameters.Relative)
{
if (!myMapdefle.IsBound(aEdge))
{
if (myEdges.IsBound(aEdge))
{
const BRepMesh_PairOfPolygon& aPair = myEdges.Find(aEdge);
const Handle(Poly_PolygonOnTriangulation)& aPolygon = aPair.First();
defedge = aPolygon->Deflection();
}
else
{
defedge = BRepMesh_ShapeTool::RelativeEdgeDeflection(
aEdge, myParameters.Deflection, myDtotale, cdef);
myParameters.Angle = savangle * cdef;
}
}
else
{
defedge = myMapdefle(aEdge);
}
defface += defedge;
defface = Max(maxdef, defface);
if (!myMapdefle.IsBound(aEdge))
{
defedge = Max(UVDEFLECTION, defedge);
myMapdefle.Bind(aEdge, defedge);
}
}
else
{
if (!myMapdefle.IsBound(aEdge))
{
myMapdefle.Bind(aEdge, defedge);
}
}
Standard_Real aFirstParam, aLastParam;
Handle(Geom2d_Curve) aCurve2d =
BRep_Tool::CurveOnSurface(aEdge, aFace, aFirstParam, aLastParam);
if (aCurve2d.IsNull())
continue;
Handle(Geom2dAdaptor_HCurve) aPCurve =
new Geom2dAdaptor_HCurve(aCurve2d, aFirstParam, aLastParam);
add(aEdge, aPCurve, defedge);
myParameters.Angle = savangle;
}
}
if ( nbEdge == 0 || aVertexEdgeMap->Extent() < 3 )
{
myAttribute->ChangeStructure().Nullify();
myAttribute->SetStatus(BRepMesh_Failure);
return myAttribute->GetStatus();
}
if ( myParameters.Relative )
{
defface = defface / nbEdge;
}
else
{
defface = myParameters.Deflection;
}
defface = Max(maxdef, defface);
TopLoc_Location aLoc;
Handle(Poly_Triangulation) aTriangulation = BRep_Tool::Triangulation(aFace, aLoc);
const Handle(BRepAdaptor_HSurface)& gFace = myAttribute->Surface();
if ( aTriangulation.IsNull() )
{
Standard_Real xCur, yCur;
Standard_Real maxX, minX, maxY, minY;
minX = minY = 1.e100;
maxX = maxY =-1.e100;
Standard_Integer ipn = 0;
Standard_Integer i1 = 1;
for ( i1 = 1; i1 <= aVertexEdgeMap->Extent(); ++i1 )
{
const BRepMesh_Vertex& aVertex =
myAttribute->ChangeStructure()->GetNode(aVertexEdgeMap->FindKey(i1));
++ipn;
xCur = aVertex.Coord().X();
yCur = aVertex.Coord().Y();
minX = Min(xCur, minX);
maxX = Max(xCur, maxX);
minY = Min(yCur, minY);
maxY = Max(yCur, maxY);
}
Standard_Real myumin = minX;
Standard_Real myumax = maxX;
Standard_Real myvmin = minY;
Standard_Real myvmax = maxY;
const Standard_Real umin = gFace->FirstUParameter();
const Standard_Real umax = gFace->LastUParameter();
const Standard_Real vmin = gFace->FirstVParameter();
const Standard_Real vmax = gFace->LastVParameter();
if (myumin < umin || myumax > umax)
{
if (gFace->IsUPeriodic())
{
if ((myumax - myumin) > (umax - umin))
myumax = myumin + (umax - umin);
}
else
{
if (umin > myumin)
myumin = umin;
if (umax < myumax)
myumax = umax;
}
}
if (myvmin < vmin || myvmax > vmax)
{
if (gFace->IsVPeriodic())
{
if ((myvmax - myvmin) > (vmax - vmin))
myvmax = myvmin + (vmax - vmin);
}
else
{
if ( vmin > myvmin )
myvmin = vmin;
if (vmax < myvmax)
myvmax = vmax;
}
}
GeomAbs_SurfaceType aSurfType = gFace->GetType();
// Fast verification of the validity of calculated limits.
// If wrong, sure a problem of pcurve.
if (aSurfType == GeomAbs_BezierSurface &&
(myumin < -0.5 || myumax > 1.5 || myvmin < -0.5 || myvmax > 1.5) )
{
myAttribute->ChangeStructure().Nullify();
myAttribute->SetStatus(BRepMesh_Failure);
return myAttribute->GetStatus();
}
//define parameters for correct parametrics
Standard_Real deltaX = 1.0;
Standard_Real deltaY = 1.0;
{
Standard_Real aTolU, aTolV;
myAttribute->ChangeStructure()->Data()->GetTolerance(aTolU, aTolV);
const Standard_Real aTol = Sqrt(aTolU * aTolU + aTolV * aTolV);
BRepMesh::HClassifier& aClassifier = myAttribute->ChangeClassifier();
BRepMesh_WireChecker aDFaceChecker(aFace, aTol, aInternalEdges,
aVertexEdgeMap, myAttribute->ChangeStructure(),
myumin, myumax, myvmin, myvmax, myParameters.InParallel );
aDFaceChecker.ReCompute(aClassifier);
BRepMesh_Status aCheckStatus = aDFaceChecker.Status();
if (aCheckStatus == BRepMesh_SelfIntersectingWire)
{
Standard_Integer nbmaill = 0;
Standard_Real eps = Precision::Confusion();
while (nbmaill < 5 && aCheckStatus != BRepMesh_ReMesh)
{
++nbmaill;
resetDataStructure();
for (TopoDS_Iterator aWireIt(aFace); aWireIt.More(); aWireIt.Next())
{
for (TopoDS_Iterator aEdgeIt(aWireIt.Value()); aEdgeIt.More(); aEdgeIt.Next(), ++nbEdge)
{
const TopoDS_Edge& anEdge = TopoDS::Edge(aEdgeIt.Value());
if (anEdge.IsNull())
continue;
if (myEdges.IsBound(anEdge))
myEdges.UnBind(anEdge);
defedge = Max(myMapdefle(anEdge) / 3.0, eps);
myMapdefle.Bind(anEdge, defedge);
Standard_Real aFirstParam, aLastParam;
Handle(Geom2d_Curve) aCurve2d =
BRep_Tool::CurveOnSurface(anEdge, aFace, aFirstParam, aLastParam);
if (aCurve2d.IsNull())
continue;
Handle(Geom2dAdaptor_HCurve) aPCurve =
new Geom2dAdaptor_HCurve(aCurve2d, aFirstParam, aLastParam);
add(anEdge, aPCurve, defedge);
}
}
aDFaceChecker.ReCompute(aClassifier);
if (aDFaceChecker.Status() == BRepMesh_NoError)
aCheckStatus = BRepMesh_ReMesh;
}
}
myAttribute->SetStatus(aCheckStatus);
if (!myAttribute->IsValid())
{
myAttribute->ChangeStructure().Nullify();
return myAttribute->GetStatus();
}
}
// try to find the real length:
// 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;
Standard_Real du = 0.05 * ( myumax - myumin );
Standard_Real dv = 0.05 * ( myvmax - myvmin );
Standard_Real dfuave = 0.5 * ( myumin + myumax );
Standard_Real dfvave = 0.5 * ( myvmin + myvmax );
Standard_Real dfucur, dfvcur;
// U loop
gFace->D0(myumin, myvmin, P11);
gFace->D0(myumin, dfvave, P21);
gFace->D0(myumin, myvmax, P31);
for (i1=1, dfucur=myumin+du; i1 <= 20; i1++, dfucur+=du)
{
gFace->D0(dfucur, myvmin, P12);
gFace->D0(dfucur, dfvave, P22);
gFace->D0(dfucur, myvmax, P32);
longu += ( P11.Distance(P12) + P21.Distance(P22) + P31.Distance(P32) );
P11 = P12;
P21 = P22;
P31 = P32;
}
// V loop
gFace->D0(myumin, myvmin, P11);
gFace->D0(dfuave, myvmin, P21);
gFace->D0(myumax, myvmin, P31);
for (i1=1, dfvcur=myvmin+dv; i1 <= 20; i1++, dfvcur+=dv)
{
gFace->D0(myumin, dfvcur, P12);
gFace->D0(dfuave, dfvcur, P22);
gFace->D0(myumax, dfvcur, P32);
longv += ( P11.Distance(P12) + P21.Distance(P22) + P31.Distance(P32) );
P11 = P12;
P21 = P22;
P31 = P32;
}
longu /= 3.;
longv /= 3.;
// akm (bug OCC16) ^^^^^
if (longu <= 1.e-16 || longv <= 1.e-16)
{
//yes, it is seen!!
myAttribute->ChangeStructure().Nullify();
myAttribute->SetStatus(BRepMesh_Failure);
return myAttribute->GetStatus();
}
if (aSurfType == GeomAbs_Torus)
{
gp_Torus Tor = gFace->Torus();
Standard_Real r = Tor.MinorRadius(), R = Tor.MajorRadius();
Standard_Real Du, Dv;//, pasu, pasv;
Dv = Max(1.0e0 - (defface/r),0.0e0) ;
Standard_Real oldDv = 2.0 * ACos (Dv);
oldDv = Min(oldDv, myParameters.Angle);
Dv = 0.9*oldDv; //TWOTHIRD * oldDv;
Dv = oldDv;
Standard_Integer nbV = Max((Standard_Integer)((myvmax-myvmin)/Dv), 2);
Dv = (myvmax-myvmin)/(nbV+1);
Standard_Real ru = R + r;
if ( ru > 1.e-16 )
{
Du = Max(1.0e0 - (defface/ru),0.0e0);
Du = (2.0 * ACos (Du));
Du = Min(Du, myParameters.Angle);
Standard_Real aa = sqrt(Du*Du + oldDv*oldDv);
if (aa < gp::Resolution())
{
myAttribute->ChangeStructure().Nullify();
return myAttribute->GetStatus();
}
Du = Du * Min(oldDv, Du) / aa;
}
else
{
Du = Dv;
}
Standard_Integer nbU = Max((Standard_Integer)((myumax-myumin)/Du), 2);
nbU = Max(nbU, (Standard_Integer)(nbV*(myumax-myumin)*R/((myvmax-myvmin)*r)/5.));
Du = (myumax-myumin)/(nbU+1);
//-- DeltaX and DeltaY are chosen so that to avoid "jumping"
//-- of points on the grid
deltaX = Du;
deltaY = Dv;
}
else if (aSurfType == GeomAbs_Cylinder)
{
gp_Cylinder Cyl = gFace->Cylinder();
Standard_Real R = Cyl.Radius();
// Calculate parameters for iteration in U direction
Standard_Real Du = 1.0 - (defface/R);
if (Du < 0.0)
Du = 0.0;
Du = 2.0 * ACos (Du);
if (Du > myParameters.Angle)
Du = myParameters.Angle;
deltaX = Du / longv;
deltaY = 1.;
}
else
{
deltaX = (myumax-myumin)/longu;
deltaY = (myvmax-myvmin)/longv;
}
// Restore face attribute
myAttribute->SetDefFace(defface);
myAttribute->SetUMax(myumax);
myAttribute->SetVMax(myvmax);
myAttribute->SetUMin(myumin);
myAttribute->SetVMin(myvmin);
myAttribute->SetDeltaX(deltaX);
myAttribute->SetDeltaY(deltaY);
}
myAttribute->ChangeMeshNodes() =
myAttribute->ChangeStructure()->Data()->Vertices();
}
catch(Standard_Failure)
{
myAttribute->SetStatus(BRepMesh_Failure);
}
myAttribute->ChangeStructure().Nullify();
return myAttribute->GetStatus();
}
//=======================================================================
//function : getEdgeAttributes
//purpose :
//=======================================================================
Standard_Boolean BRepMesh_FastDiscret::getEdgeAttributes(
const TopoDS_Edge& theEdge,
const Handle(Geom2dAdaptor_HCurve)& thePCurve,
const Standard_Real theDefEdge,
BRepMesh_FastDiscret::EdgeAttributes& theAttributes) const
{
EdgeAttributes& aEAttr = theAttributes;
// Get vertices
TopExp::Vertices(theEdge, aEAttr.FirstVertex, aEAttr.LastVertex);
if (aEAttr.FirstVertex.IsNull() || aEAttr.LastVertex.IsNull())
return Standard_False;
// Get range on 2d curve
const TopoDS_Face& aFace = myAttribute->Face();
BRep_Tool::Range(theEdge, aFace, aEAttr.FirstParam, aEAttr.LastParam);
// Get end points on 2d curve
BRep_Tool::UVPoints(theEdge, aFace, aEAttr.FirstUV, aEAttr.LastUV);
aEAttr.IsSameUV =
aEAttr.FirstUV.IsEqual(aEAttr.LastUV, Precision::PConfusion());
if (aEAttr.IsSameUV)
{
// 1. is it really sameUV without being degenerated
gp_Pnt2d uvF, uvL;
thePCurve->D0(thePCurve->FirstParameter(), uvF);
thePCurve->D0(thePCurve->LastParameter(), uvL);
if (!aEAttr.FirstUV.IsEqual(uvF, Precision::PConfusion()))
aEAttr.FirstUV = uvF;
if (!aEAttr.LastUV.IsEqual(uvL, Precision::PConfusion()))
aEAttr.LastUV = uvL;
aEAttr.IsSameUV =
aEAttr.FirstUV.IsEqual(aEAttr.LastUV, Precision::PConfusion());
}
//Control tolerance of vertices
const Handle(BRepAdaptor_HSurface)& gFace = myAttribute->Surface();
gp_Pnt pFirst = gFace->Value(aEAttr.FirstUV.X(), aEAttr.FirstUV.Y());
gp_Pnt pLast = gFace->Value(aEAttr.LastUV.X(), aEAttr.LastUV.Y());
Standard_Real aSqDist = pFirst.SquareDistance(BRep_Tool::Pnt(aEAttr.FirstVertex));
aSqDist = Max(aSqDist, pLast.SquareDistance(BRep_Tool::Pnt(aEAttr.LastVertex)));
aEAttr.Deflection = Max(theDefEdge, BRep_Tool::Tolerance(theEdge));
aEAttr.Deflection = Max(aEAttr.Deflection, sqrt(aSqDist));
return Standard_True;
}
//=======================================================================
//function : registerEdgeVertices
//purpose :
//=======================================================================
void BRepMesh_FastDiscret::registerEdgeVertices(
BRepMesh_FastDiscret::EdgeAttributes& theAttributes,
Standard_Integer& ipf,
Standard_Integer& ivf,
Standard_Integer& isvf,
Standard_Integer& ipl,
Standard_Integer& ivl,
Standard_Integer& isvl)
{
EdgeAttributes& aEAttr = theAttributes;
if (aEAttr.FirstVExtractor.IsNull())
{
// Use edge geometry to produce tesselation.
aEAttr.FirstVExtractor =
new TopoDSVExplorer(aEAttr.FirstVertex, aEAttr.IsSameUV, aEAttr.LastVertex);
}
if (aEAttr.LastVExtractor.IsNull())
{
// Use edge geometry to produce tesselation.
aEAttr.LastVExtractor =
new TopoDSVExplorer(aEAttr.LastVertex, aEAttr.IsSameUV, aEAttr.FirstVertex);
}
// Process first vertex
ipf = myAttribute->GetVertexIndex(aEAttr.FirstVExtractor, Standard_True);
Standard_Real aMinDist = 2. * BRep_Tool::Tolerance(aEAttr.FirstVertex);
gp_XY aTmpUV1 = BRepMesh_ShapeTool::FindUV(ipf, aEAttr.FirstUV, aMinDist, myAttribute);
myAttribute->AddNode(ipf, aTmpUV1, BRepMesh_Frontier, ivf, isvf);
// Process last vertex
ipl = aEAttr.LastVertex.IsSame(aEAttr.FirstVertex) ? ipf :
myAttribute->GetVertexIndex(aEAttr.LastVExtractor, Standard_True);
aMinDist = 2. * BRep_Tool::Tolerance(aEAttr.LastVertex);
gp_XY aTmpUV2 = BRepMesh_ShapeTool::FindUV(ipl, aEAttr.LastUV, aMinDist, myAttribute);
myAttribute->AddNode(ipl, aTmpUV2, BRepMesh_Frontier, ivl, isvl);
// Update edge deflection
const Handle(BRepAdaptor_HSurface)& gFace = myAttribute->Surface();
gp_Pnt aPntE1 = gFace->Value(aEAttr.FirstUV.X(), aEAttr.FirstUV.Y());
gp_Pnt aPntFound1 = gFace->Value(aTmpUV1.X(), aTmpUV1.Y());
Standard_Real aSqDist = aPntE1.SquareDistance(aPntFound1);
gp_Pnt aPntE2 = gFace->Value(aEAttr.LastUV.X(), aEAttr.LastUV.Y());
gp_Pnt aPntFound2 = gFace->Value(aTmpUV2.X(), aTmpUV2.Y());
aSqDist = Max(aSqDist, aPntE2.SquareDistance(aPntFound2));
aEAttr.Deflection = Max(aEAttr.Deflection, sqrt(aSqDist));
}
//=======================================================================
//function : add
//purpose :
//=======================================================================
void BRepMesh_FastDiscret::add(
const TopoDS_Edge& theEdge,
const Handle(Geom2dAdaptor_HCurve)& thePCurve,
const Standard_Real theDefEdge)
{
const TopAbs_Orientation orEdge = theEdge.Orientation();
if (orEdge == TopAbs_EXTERNAL)
return;
EdgeAttributes aEAttr;
if (!getEdgeAttributes(theEdge, thePCurve, theDefEdge, aEAttr))
return;
if (!myEdges.IsBound(theEdge))
{
update(theEdge, thePCurve, theDefEdge, aEAttr);
return;
}
Standard_Integer ipf, ivf, isvf, ipl, ivl, isvl;
registerEdgeVertices(aEAttr, ipf, ivf, isvf, ipl, ivl, isvl);
// If this Edge has been already checked and it is not degenerated,
// the points of the polygon calculated at the first check are retrieved :
// retrieve the polygone:
const BRepMesh_PairOfPolygon& aPair = myEdges.Find(theEdge);
const Handle(Poly_PolygonOnTriangulation)& aPolygon = aPair.First();
const TColStd_Array1OfInteger& aNodes = aPolygon->Nodes();
Handle(TColStd_HArray1OfReal) aParams = aPolygon->Parameters();
// creation anew:
const Standard_Integer aNodesNb = aNodes.Length();
TColStd_Array1OfInteger aNewNodes (1, aNodesNb);
TColStd_Array1OfReal aNewParams(1, aNodesNb);
aNewNodes (1) = isvf;
aNewParams(1) = aEAttr.FirstParam;
aNewNodes (aNodesNb) = isvl;
aNewParams(aNodesNb) = aEAttr.LastParam;
const TopoDS_Face& aFace = myAttribute->Face();
if (!BRepMesh_ShapeTool::IsDegenerated(theEdge, aFace))
{
BRepMesh_EdgeParameterProvider aProvider(theEdge, aFace, aParams);
for (Standard_Integer i = 2; i < aNodesNb; ++i)
{
const Standard_Integer aPointId = aNodes(i);
const gp_Pnt& aPnt = myBoundaryPoints->Find(aPointId);
const Standard_Real aParam = aProvider.Parameter(i, aPnt);
gp_Pnt2d aUV = thePCurve->Value(aParam);
Standard_Integer iv2, isv;
myAttribute->AddNode(aPointId, aUV.Coord(), BRepMesh_OnCurve, iv2, isv);
aNewNodes (i) = isv;
aNewParams(i) = aParam;
}
}
Handle(Poly_PolygonOnTriangulation) P1 =
new Poly_PolygonOnTriangulation(aNewNodes, aNewParams);
storePolygon(theEdge, P1, aEAttr.Deflection);
}
//=======================================================================
//function : update(edge)
//purpose :
//=======================================================================
void BRepMesh_FastDiscret::update(
const TopoDS_Edge& theEdge,
const Handle(Geom2dAdaptor_HCurve)& theC2d,
const Standard_Real theDefEdge,
BRepMesh_FastDiscret::EdgeAttributes& theAttributes)
{
EdgeAttributes& aEAttr = theAttributes;
const TopoDS_Face& aFace = myAttribute->Face();
Handle(BRepMesh_IEdgeTool) aEdgeTool;
// Try to find existing tessellation.
for (Standard_Integer i = 1; aEdgeTool.IsNull(); ++i)
{
TopLoc_Location aLoc;
Handle(Poly_Triangulation) aTriangulation;
Handle(Poly_PolygonOnTriangulation) aPolygon;
BRep_Tool::PolygonOnTriangulation(theEdge, aPolygon, aTriangulation, aLoc, i);
if (aPolygon.IsNull())
break;
if (aTriangulation.IsNull() || !aPolygon->HasParameters())
continue;
if (aPolygon->Deflection() > 1.1 * theDefEdge)
continue;
const TColgp_Array1OfPnt& aNodes = aTriangulation->Nodes();
const TColStd_Array1OfInteger& aIndices = aPolygon->Nodes();
Handle(TColStd_HArray1OfReal) aParams = aPolygon->Parameters();
aEAttr.FirstVExtractor = new PolyVExplorer(aEAttr.FirstVertex,
aEAttr.IsSameUV, aEAttr.LastVertex, aIndices(1), aNodes, aLoc);
aEAttr.LastVExtractor = new PolyVExplorer(aEAttr.LastVertex,
aEAttr.IsSameUV, aEAttr.FirstVertex, aIndices(aIndices.Length()), aNodes, aLoc);
aEdgeTool = new BRepMesh_EdgeTessellationExtractor(theEdge, theC2d,
aFace, aTriangulation, aPolygon, aLoc);
}
if (aEdgeTool.IsNull())
{
aEdgeTool = new BRepMesh_EdgeTessellator(theEdge, myAttribute,
mySharedFaces, theDefEdge, myParameters.Angle, myParameters.MinSize);
}
Standard_Integer ipf, ivf, isvf, ipl, ivl, isvl;
registerEdgeVertices(aEAttr, ipf, ivf, isvf, ipl, ivl, isvl);
Handle(Poly_PolygonOnTriangulation) P1, P2;
if (BRepMesh_ShapeTool::IsDegenerated(theEdge, aFace))
{
// two nodes
Standard_Integer aNewNodesArr[] = {isvf, isvl};
Standard_Integer aNewNodInStructArr[] = {ipf, ipl};
Standard_Real aNewParamsArr[] = {aEAttr.FirstParam, aEAttr.LastParam};
TColStd_Array1OfInteger aNewNodes (aNewNodesArr[0], 1, 2);
TColStd_Array1OfInteger aNewNodInStruct(aNewNodInStructArr[0], 1, 2);
TColStd_Array1OfReal aNewParams (aNewParamsArr[0], 1, 2);
P1 = new Poly_PolygonOnTriangulation(aNewNodes, aNewParams);
P2 = new Poly_PolygonOnTriangulation(aNewNodInStruct, aNewParams);
}
else
{
const Standard_Integer aNodesNb = aEdgeTool->NbPoints();
// Allocate the memory for arrays aNewNodesVec, aNewNodesInStructVec, aNewParamsVec
// only once using the buffer aBuf.
TColStd_Array1OfCharacter aBuf(1, aNodesNb * (2*sizeof(Standard_Integer) + sizeof(Standard_Real)));
TColStd_Array1OfInteger aNewNodesVec(*reinterpret_cast<const Standard_Integer*>
(&aBuf(1)), 1, aNodesNb);
TColStd_Array1OfInteger aNewNodesInStructVec(*reinterpret_cast<const Standard_Integer*>
(&aBuf(1 + aNodesNb*sizeof(Standard_Integer))), 1, aNodesNb);
TColStd_Array1OfReal aNewParamsVec(*reinterpret_cast<const Standard_Real*>
(&aBuf(1 + aNodesNb*2*sizeof(Standard_Integer))), 1, aNodesNb);
Standard_Integer aNodesCount = 1;
aNewNodesInStructVec(aNodesCount) = ipf;
aNewNodesVec (aNodesCount) = isvf;
aNewParamsVec (aNodesCount) = aEAttr.FirstParam;
++aNodesCount;
Standard_Integer aPrevNodeId = ivf;
Standard_Integer aLastPointId = myAttribute->LastPointId();
for (Standard_Integer i = 2; i < aNodesNb; ++i)
{
gp_Pnt aPnt;
gp_Pnt2d aUV;
Standard_Real aParam;
if (!aEdgeTool->Value(i, aParam, aPnt, aUV))
continue;
// Imitate index of 3d point in order to not to add points to map without necessity.
Standard_Integer iv2, isv;
myAttribute->AddNode(aLastPointId + 1, aUV.Coord(), BRepMesh_Frontier, iv2, isv);
if (aPrevNodeId == iv2)
continue;
// Ok, now we can add point to the map.
myBoundaryPoints->Bind (++aLastPointId, aPnt);
aNewNodesInStructVec(aNodesCount) = aLastPointId;
aNewNodesVec (aNodesCount) = isv;
aNewParamsVec (aNodesCount) = aParam;
++aNodesCount;
aPrevNodeId = iv2;
}
aNewNodesInStructVec(aNodesCount) = ipl;
aNewNodesVec (aNodesCount) = isvl;
aNewParamsVec (aNodesCount) = aEAttr.LastParam;
TColStd_Array1OfInteger aNewNodes (aNewNodesVec.First (), 1, aNodesCount);
TColStd_Array1OfInteger aNewNodInStruct(aNewNodesInStructVec.First(), 1, aNodesCount);
TColStd_Array1OfReal aNewParams (aNewParamsVec.First(), 1, aNodesCount);
P1 = new Poly_PolygonOnTriangulation(aNewNodes, aNewParams);
P2 = new Poly_PolygonOnTriangulation(aNewNodInStruct, aNewParams);
}
storePolygon(theEdge, P1, aEAttr.Deflection);
storePolygonSharedData(theEdge, P2, aEAttr.Deflection);
}
//=======================================================================
//function : storeInternalPolygon
//purpose :
//=======================================================================
void BRepMesh_FastDiscret::storePolygon(
const TopoDS_Edge& theEdge,
Handle(Poly_PolygonOnTriangulation)& thePolygon,
const Standard_Real theDeflection)
{
thePolygon->Deflection(theDeflection);
BRepMesh::HDMapOfShapePairOfPolygon& aInternalEdges = myAttribute->ChangeInternalEdges();
if (aInternalEdges->IsBound(theEdge))
{
BRepMesh_PairOfPolygon& aPair = aInternalEdges->ChangeFind(theEdge);
if (theEdge.Orientation() == TopAbs_REVERSED)
aPair.Append(thePolygon);
else
aPair.Prepend(thePolygon);
return;
}
BRepMesh_PairOfPolygon aPair;
aPair.Append(thePolygon);
aInternalEdges->Bind(theEdge, aPair);
}
//=======================================================================
//function : storePolygonSharedData
//purpose :
//=======================================================================
void BRepMesh_FastDiscret::storePolygonSharedData(
const TopoDS_Edge& theEdge,
Handle(Poly_PolygonOnTriangulation)& thePolygon,
const Standard_Real theDeflection)
{
thePolygon->Deflection(theDeflection);
BRepMesh_PairOfPolygon aPair;
aPair.Append(thePolygon);
myEdges.Bind(theEdge, aPair);
}
//=======================================================================
//function : GetFaceAttribute
//purpose :
//=======================================================================
Standard_Boolean BRepMesh_FastDiscret::GetFaceAttribute(
const TopoDS_Face& theFace,
Handle(BRepMesh_FaceAttribute)& theAttribute,
const Standard_Boolean isForceCreate) const
{
if (myAttributes.IsBound(theFace))
{
theAttribute = myAttributes(theFace);
return Standard_True;
}
else if (isForceCreate)
{
theAttribute = new BRepMesh_FaceAttribute(myBoundaryVertices, myBoundaryPoints);
myAttributes.Bind(theFace, theAttribute);
}
return Standard_False;
}
//=======================================================================
//function : RemoveFaceAttribute
//purpose :
//=======================================================================
void BRepMesh_FastDiscret::RemoveFaceAttribute(const TopoDS_Face& theFace)
{
if (myAttributes.IsBound(theFace))
myAttributes.UnBind(theFace);
}