From: oan Date: Fri, 2 Nov 2018 13:50:47 +0000 (+0300) Subject: 0028379: BRepMesh produces mangled mesh for a cone X-Git-Tag: V7_4_0_beta~312 X-Git-Url: http://git.dev.opencascade.org/gitweb/?p=occt.git;a=commitdiff_plain;h=dc57476a0e478cd473400be81495083f2233ce12 0028379: BRepMesh produces mangled mesh for a cone Split seam edge of a cone according to the specified parameters. Seam edge functor is called before check of triangulation consistency in order to keep face status consistent. The cause is that split seam edge can set Outdated flag when Reused is set by another functor without reset which can lead to refusement of such face by triangulation procedure. Fix compilation error on VS2008 --- diff --git a/src/BRepMesh/BRepMesh_ConeRangeSplitter.cxx b/src/BRepMesh/BRepMesh_ConeRangeSplitter.cxx index 8900fa870b..da28dd093c 100644 --- a/src/BRepMesh/BRepMesh_ConeRangeSplitter.cxx +++ b/src/BRepMesh/BRepMesh_ConeRangeSplitter.cxx @@ -17,11 +17,12 @@ #include //======================================================================= -// Function: GenerateSurfaceNodes +// Function: GetSplitSteps // Purpose : //======================================================================= -Handle(IMeshData::ListOfPnt2d) BRepMesh_ConeRangeSplitter::GenerateSurfaceNodes( - const IMeshTools_Parameters& theParameters) const +std::pair BRepMesh_ConeRangeSplitter::GetSplitSteps( + const IMeshTools_Parameters& theParameters, + std::pair& theStepsNb) const { const std::pair& aRangeU = GetRangeU(); const std::pair& aRangeV = GetRangeV(); @@ -43,15 +44,33 @@ Handle(IMeshData::ListOfPnt2d) BRepMesh_ConeRangeSplitter::GenerateSurfaceNodes( Du = aDiffU / (nbU + 1); Dv = aDiffV / (nbV + 1); + theStepsNb.first = nbU; + theStepsNb.second = nbV; + return std::make_pair (Du, Dv); +} + +//======================================================================= +// Function: GenerateSurfaceNodes +// Purpose : +//======================================================================= +Handle(IMeshData::ListOfPnt2d) BRepMesh_ConeRangeSplitter::GenerateSurfaceNodes( + const IMeshTools_Parameters& theParameters) const +{ + const std::pair& aRangeU = GetRangeU(); + const std::pair& aRangeV = GetRangeV(); + + std::pair aStepsNb; + std::pair aSteps = GetSplitSteps (theParameters, aStepsNb); + const Handle(NCollection_IncAllocator) aTmpAlloc = new NCollection_IncAllocator(IMeshData::MEMORY_BLOCK_SIZE_HUGE); Handle(IMeshData::ListOfPnt2d) aNodes = new IMeshData::ListOfPnt2d(aTmpAlloc); - const Standard_Real aPasMaxV = aRangeV.second - Dv*0.5; - const Standard_Real aPasMaxU = aRangeU.second - Du*0.5; - for (Standard_Real aPasV = aRangeV.first + Dv; aPasV < aPasMaxV; aPasV += Dv) + const Standard_Real aPasMaxV = aRangeV.second - aSteps.second*0.5; + const Standard_Real aPasMaxU = aRangeU.second - aSteps.first *0.5; + for (Standard_Real aPasV = aRangeV.first + aSteps.second; aPasV < aPasMaxV; aPasV += aSteps.second) { - for (Standard_Real aPasU = aRangeU.first + Du; aPasU < aPasMaxU; aPasU += Du) + for (Standard_Real aPasU = aRangeU.first + aSteps.first; aPasU < aPasMaxU; aPasU += aSteps.first) { aNodes->Append(gp_Pnt2d(aPasU, aPasV)); } diff --git a/src/BRepMesh/BRepMesh_ConeRangeSplitter.hxx b/src/BRepMesh/BRepMesh_ConeRangeSplitter.hxx index 779c1cadad..e9abf42fec 100644 --- a/src/BRepMesh/BRepMesh_ConeRangeSplitter.hxx +++ b/src/BRepMesh/BRepMesh_ConeRangeSplitter.hxx @@ -35,6 +35,13 @@ public: { } + //! Returns split intervals along U and V direction. + //! @param theParameters meshing parameters. + //! @param[out] theStepsNb number of steps along corresponding direction. + std::pair GetSplitSteps( + const IMeshTools_Parameters& theParameters, + std::pair& theStepsNb) const; + //! Returns list of nodes generated using surface data and specified parameters. Standard_EXPORT virtual Handle(IMeshData::ListOfPnt2d) GenerateSurfaceNodes( const IMeshTools_Parameters& theParameters) const Standard_OVERRIDE; diff --git a/src/BRepMesh/BRepMesh_ModelPreProcessor.cxx b/src/BRepMesh/BRepMesh_ModelPreProcessor.cxx index a583a9997e..7ec3d4040c 100644 --- a/src/BRepMesh/BRepMesh_ModelPreProcessor.cxx +++ b/src/BRepMesh/BRepMesh_ModelPreProcessor.cxx @@ -21,6 +21,7 @@ #include #include #include +#include namespace { @@ -88,6 +89,137 @@ namespace Handle(IMeshData_Model) myModel; }; + + //! Adds additional points to seam edges on specific surfaces. + class SeamEdgeAmplifier + { + public: + //! Constructor + SeamEdgeAmplifier(const Handle(IMeshData_Model)& theModel, + const IMeshTools_Parameters& theParameters) + : myModel (theModel) + , myParameters (theParameters) + { + } + + //! Main functor. + void operator()(const Standard_Integer theFaceIndex) const + { + const IMeshData::IFaceHandle& aDFace = myModel->GetFace(theFaceIndex); + if (aDFace->GetSurface()->GetType() != GeomAbs_Cone) + { + return; + } + + const IMeshData::IWireHandle& aDWire = aDFace->GetWire (0); + for (Standard_Integer aEdgeIdx = 0; aEdgeIdx < aDWire->EdgesNb() - 1; ++aEdgeIdx) + { + const IMeshData::IEdgePtr& aDEdge = aDWire->GetEdge (aEdgeIdx); + + if (aDEdge->GetPCurve(aDFace.get(), TopAbs_FORWARD) != aDEdge->GetPCurve(aDFace.get(), TopAbs_REVERSED)) + { + if (aDEdge->GetCurve()->ParametersNb() == 2) + { + if (splitEdge (aDEdge, Abs (getConeStep (aDFace)))) + { + TopLoc_Location aLoc; + const Handle (Poly_Triangulation)& aTriangulation = + BRep_Tool::Triangulation (aDFace->GetFace (), aLoc); + + if (!aTriangulation.IsNull ()) + { + aDFace->SetStatus (IMeshData_Outdated); + } + } + } + return; + } + } + } + + private: + + //! Returns step for splitting seam edge of a cone. + Standard_Real getConeStep(const IMeshData::IFaceHandle& theDFace) const + { + BRepMesh_ConeRangeSplitter aSplitter; + aSplitter.Reset (theDFace, myParameters); + + const IMeshData::IWireHandle& aDWire = theDFace->GetWire (0); + for (Standard_Integer aEdgeIt = 0; aEdgeIt < aDWire->EdgesNb(); ++aEdgeIt) + { + const IMeshData::IEdgeHandle aDEdge = aDWire->GetEdge(aEdgeIt); + const IMeshData::IPCurveHandle& aPCurve = aDEdge->GetPCurve( + theDFace.get(), aDWire->GetEdgeOrientation(aEdgeIt)); + + for (Standard_Integer aPointIt = 0; aPointIt < aPCurve->ParametersNb(); ++aPointIt) + { + const gp_Pnt2d& aPnt2d = aPCurve->GetPoint(aPointIt); + aSplitter.AddPoint(aPnt2d); + } + } + + std::pair aStepsNb; + std::pair aSteps = aSplitter.GetSplitSteps (myParameters, aStepsNb); + return aSteps.second; + } + + //! Splits 3D and all pcurves accoring using the specified step. + Standard_Boolean splitEdge(const IMeshData::IEdgePtr& theDEdge, + const Standard_Real theDU) const + { + if (!splitCurve (theDEdge->GetCurve (), theDU)) + { + return Standard_False; + } + + for (Standard_Integer aPCurveIdx = 0; aPCurveIdx < theDEdge->PCurvesNb(); ++aPCurveIdx) + { + splitCurve (theDEdge->GetPCurve (aPCurveIdx), theDU); + } + + return Standard_True; + } + + //! Splits the given curve using the specified step. + template + Standard_Boolean splitCurve(Curve& theCurve, const Standard_Real theDU) const + { + Standard_Boolean isUpdated = Standard_False; + PointType aDir = theCurve->GetPoint(theCurve->ParametersNb() - 1).Coord() - theCurve->GetPoint(0).Coord(); + const Standard_Real aModulus = aDir.Modulus(); + if (aModulus < gp::Resolution()) + { + return isUpdated; + } + aDir /= aModulus; + + const Standard_Real aLastParam = theCurve->GetParameter(theCurve->ParametersNb() - 1); + const Standard_Boolean isReversed = theCurve->GetParameter(0) > aLastParam; + for (Standard_Integer aPointIdx = 1; ; ++aPointIdx) + { + const Standard_Real aCurrParam = theCurve->GetParameter(0) + aPointIdx * theDU * (isReversed ? -1.0 : 1.0); + if (( isReversed && (aCurrParam < aLastParam)) || + (!isReversed && !(aCurrParam < aLastParam))) + { + break; + } + + theCurve->InsertPoint(theCurve->ParametersNb() - 1, + theCurve->GetPoint(0).Translated (aDir * aPointIdx * theDU), + aCurrParam); + + isUpdated = Standard_True; + } + + return isUpdated; + } + + private: + + Handle(IMeshData_Model) myModel; + IMeshTools_Parameters myParameters; + }; } //======================================================================= @@ -119,7 +251,8 @@ Standard_Boolean BRepMesh_ModelPreProcessor::Perform( return Standard_False; } - OSD_Parallel::For(0, theModel->FacesNb(), TriangulationConsistency(theModel), !theParameters.InParallel); + OSD_Parallel::For(0, theModel->FacesNb(), SeamEdgeAmplifier(theModel, theParameters), !theParameters.InParallel); + OSD_Parallel::For(0, theModel->FacesNb(), TriangulationConsistency(theModel), !theParameters.InParallel); // Clean edges and faces from outdated polygons. Handle(NCollection_IncAllocator) aTmpAlloc(new NCollection_IncAllocator(IMeshData::MEMORY_BLOCK_SIZE_HUGE)); diff --git a/tests/bugs/mesh/bug25042 b/tests/bugs/mesh/bug25042 index 6fa2292bbd..b44908d565 100644 --- a/tests/bugs/mesh/bug25042 +++ b/tests/bugs/mesh/bug25042 @@ -1,6 +1,3 @@ -puts "TODO 0025042 All: Error: Number of triangles = 931 is not equal to expected 957" -puts "TODO 0025042 All: Error: Number of nodes = 532 is not equal to expected 558" - puts "==========" puts "0025042: Cone Meshing: Missing two connecting edges." puts "=========="