// 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 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include //#define DEBUG_MESH "mesh.tcl" #ifdef DEBUG_MESH #include #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 (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 { //--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(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 aNorMap(1, anAlloc); BRepMesh::MapOfIntegerInteger aStatMap(1, anAlloc); NCollection_Map 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 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(); }