diff --git a/src/BRep/BRep_Tool.cxx b/src/BRep/BRep_Tool.cxx index 37c4f2213e..8fb6ef8638 100644 --- a/src/BRep/BRep_Tool.cxx +++ b/src/BRep/BRep_Tool.cxx @@ -206,6 +206,17 @@ Handle(Geom_Curve) BRep_Tool::Curve(const TopoDS_Edge& E, return C; } +//======================================================================= +//function : IsGeometric +//purpose : Returns True if has a surface. +//======================================================================= +Standard_Boolean BRep_Tool::IsGeometric (const TopoDS_Face& F) +{ + const BRep_TFace* TF = static_cast(F.TShape().get()); + const Handle(Geom_Surface)& S = TF->Surface(); + return !S.IsNull(); +} + //======================================================================= //function : IsGeometric //purpose : Returns True if is a 3d curve or a curve on diff --git a/src/BRep/BRep_Tool.hxx b/src/BRep/BRep_Tool.hxx index 6fdc110c06..e81eceab23 100644 --- a/src/BRep/BRep_Tool.hxx +++ b/src/BRep/BRep_Tool.hxx @@ -74,6 +74,9 @@ public: //! Returns the NaturalRestriction flag of the face. Standard_EXPORT static Standard_Boolean NaturalRestriction (const TopoDS_Face& F); + //! Returns True if has a surface, false otherwise. + Standard_EXPORT static Standard_Boolean IsGeometric (const TopoDS_Face& F); + //! Returns True if is a 3d curve or a curve on //! surface. Standard_EXPORT static Standard_Boolean IsGeometric (const TopoDS_Edge& E); diff --git a/src/BRepMesh/BRepMesh_Deflection.cxx b/src/BRepMesh/BRepMesh_Deflection.cxx index 776c7235bb..f6e37b2b48 100644 --- a/src/BRepMesh/BRepMesh_Deflection.cxx +++ b/src/BRepMesh/BRepMesh_Deflection.cxx @@ -164,3 +164,20 @@ void BRepMesh_Deflection::ComputeDeflection ( theDFace->SetDeflection (aFaceDeflection); } + +//======================================================================= +// Function: IsConsistent +// Purpose : +//======================================================================= +Standard_Boolean BRepMesh_Deflection::IsConsistent ( + const Standard_Real theCurrent, + const Standard_Real theRequired, + const Standard_Boolean theAllowDecrease, + const Standard_Real theRatio) +{ + // Check if the deflection of existing polygonal representation + // fits the required deflection. + Standard_Boolean isConsistent = theCurrent < (1. + theRatio) * theRequired + && (!theAllowDecrease || theCurrent > (1. - theRatio) * theRequired); + return isConsistent; +} diff --git a/src/BRepMesh/BRepMesh_Deflection.hxx b/src/BRepMesh/BRepMesh_Deflection.hxx index 35998a839b..d8c7caf472 100644 --- a/src/BRepMesh/BRepMesh_Deflection.hxx +++ b/src/BRepMesh/BRepMesh_Deflection.hxx @@ -58,6 +58,20 @@ public: const IMeshData::IFaceHandle& theDFace, const IMeshTools_Parameters& theParameters); + //! Checks if the deflection of current polygonal representation + //! is consistent with the required deflection. + //! @param theCurrent [in] Current deflection. + //! @param theRequired [in] Required deflection. + //! @param theAllowDecrease [in] Flag controlling the check. If decrease is allowed, + //! to be consistent the current and required deflections should be approximately the same. + //! If not allowed, the current deflection should be less than required. + //! @param theRatio [in] The ratio for comparison of the deflections (value from 0 to 1). + Standard_EXPORT static Standard_Boolean IsConsistent ( + const Standard_Real theCurrent, + const Standard_Real theRequired, + const Standard_Boolean theAllowDecrease, + const Standard_Real theRatio = 0.1); + DEFINE_STANDARD_RTTI_INLINE(BRepMesh_Deflection, Standard_Transient) }; diff --git a/src/BRepMesh/BRepMesh_EdgeDiscret.cxx b/src/BRepMesh/BRepMesh_EdgeDiscret.cxx index d9e575af43..4a305440d4 100644 --- a/src/BRepMesh/BRepMesh_EdgeDiscret.cxx +++ b/src/BRepMesh/BRepMesh_EdgeDiscret.cxx @@ -155,8 +155,10 @@ void BRepMesh_EdgeDiscret::process (const Standard_Integer theEdgeIndex) const const Handle (Poly_Polygon3D)& aPoly3D = BRep_Tool::Polygon3D (aDEdge->GetEdge (), aLoc); if (!aPoly3D.IsNull ()) { - if (aPoly3D->HasParameters () && - aPoly3D->Deflection () < 1.1 * aDEdge->GetDeflection ()) + if (aPoly3D->HasParameters() && + BRepMesh_Deflection::IsConsistent (aPoly3D->Deflection(), + aDEdge->GetDeflection(), + myParameters.AllowQualityDecrease)) { // Edge already has suitable 3d polygon. aDEdge->SetStatus(IMeshData_Reused); @@ -209,8 +211,10 @@ Standard_Real BRepMesh_EdgeDiscret::checkExistingPolygonAndUpdateStatus( if (!aPolygon.IsNull ()) { - Standard_Boolean isConsistent = aPolygon->HasParameters () && - aPolygon->Deflection () < 1.1 * theDEdge->GetDeflection (); + Standard_Boolean isConsistent = aPolygon->HasParameters() && + BRepMesh_Deflection::IsConsistent (aPolygon->Deflection(), + theDEdge->GetDeflection(), + myParameters.AllowQualityDecrease); if (!isConsistent) { diff --git a/src/BRepMesh/BRepMesh_ModelPreProcessor.cxx b/src/BRepMesh/BRepMesh_ModelPreProcessor.cxx index c9d02d486b..df9d9e48d9 100644 --- a/src/BRepMesh/BRepMesh_ModelPreProcessor.cxx +++ b/src/BRepMesh/BRepMesh_ModelPreProcessor.cxx @@ -14,6 +14,7 @@ // commercial license or contractual agreement. #include +#include #include #include #include @@ -30,8 +31,10 @@ namespace { public: //! Constructor - TriangulationConsistency(const Handle(IMeshData_Model)& theModel) + TriangulationConsistency(const Handle(IMeshData_Model)& theModel, + const Standard_Boolean theAllowQualityDecrease) : myModel (theModel) + , myAllowQualityDecrease (theAllowQualityDecrease) { } @@ -51,7 +54,9 @@ namespace if (!aTriangulation.IsNull()) { Standard_Boolean isTriangulationConsistent = - aTriangulation->Deflection() < 1.1 * aDFace->GetDeflection(); + BRepMesh_Deflection::IsConsistent (aTriangulation->Deflection(), + aDFace->GetDeflection(), + myAllowQualityDecrease); if (isTriangulationConsistent) { @@ -88,6 +93,7 @@ namespace private: Handle(IMeshData_Model) myModel; + Standard_Boolean myAllowQualityDecrease; //!< Flag used for consistency check }; //! Adds additional points to seam edges on specific surfaces. @@ -251,8 +257,10 @@ Standard_Boolean BRepMesh_ModelPreProcessor::performInternal( return Standard_False; } - OSD_Parallel::For(0, theModel->FacesNb(), SeamEdgeAmplifier(theModel, theParameters), !theParameters.InParallel); - OSD_Parallel::For(0, theModel->FacesNb(), TriangulationConsistency(theModel), !theParameters.InParallel); + const Standard_Integer aFacesNb = theModel->FacesNb(); + const Standard_Boolean isOneThread = !theParameters.InParallel; + OSD_Parallel::For(0, aFacesNb, SeamEdgeAmplifier (theModel, theParameters), isOneThread); + OSD_Parallel::For(0, aFacesNb, TriangulationConsistency (theModel, theParameters.AllowQualityDecrease), isOneThread); // Clean edges and faces from outdated polygons. Handle(NCollection_IncAllocator) aTmpAlloc(new NCollection_IncAllocator(IMeshData::MEMORY_BLOCK_SIZE_HUGE)); diff --git a/src/BRepTools/BRepTools.cxx b/src/BRepTools/BRepTools.cxx index 327fa12a60..cc38b3a2e5 100644 --- a/src/BRepTools/BRepTools.cxx +++ b/src/BRepTools/BRepTools.cxx @@ -760,19 +760,36 @@ Standard_Boolean BRepTools::Read(TopoDS_Shape& Sh, //purpose : //======================================================================= -void BRepTools::Clean(const TopoDS_Shape& theShape) +void BRepTools::Clean (const TopoDS_Shape& theShape) { + if (theShape.IsNull()) + return; + BRep_Builder aBuilder; Handle(Poly_Triangulation) aNullTriangulation; Handle(Poly_PolygonOnTriangulation) aNullPoly; - if (theShape.IsNull()) - return; + TopTools_MapOfShape aShapeMap; + const TopLoc_Location anEmptyLoc; TopExp_Explorer aFaceIt(theShape, TopAbs_FACE); for (; aFaceIt.More(); aFaceIt.Next()) { - const TopoDS_Face& aFace = TopoDS::Face(aFaceIt.Current()); + TopoDS_Shape aFaceNoLoc = aFaceIt.Value(); + aFaceNoLoc.Location (anEmptyLoc); + if (!aShapeMap.Add (aFaceNoLoc)) + { + // the face has already been processed + continue; + } + + const TopoDS_Face& aFace = TopoDS::Face (aFaceIt.Current()); + if (!BRep_Tool::IsGeometric (aFace)) + { + // Do not remove triangulation as there is no surface to recompute it. + continue; + } + TopLoc_Location aLoc; const Handle(Poly_Triangulation)& aTriangulation = @@ -782,6 +799,10 @@ void BRepTools::Clean(const TopoDS_Shape& theShape) continue; // Nullify edges + // Theoretically, the edges on the face (with surface) may have no geometry + // (no curve 3d or 2d or both). Such faces should be considered as invalid and + // are not supported by current implementation. So, both triangulation of the face + // and polygon on triangulation of the edges are removed unconditionally. TopExp_Explorer aEdgeIt(aFace, TopAbs_EDGE); for (; aEdgeIt.More(); aEdgeIt.Next()) { @@ -797,14 +818,27 @@ void BRepTools::Clean(const TopoDS_Shape& theShape) TopExp_Explorer aEdgeIt (theShape, TopAbs_EDGE); for (; aEdgeIt.More (); aEdgeIt.Next ()) { - const TopoDS_Edge& aEdge = TopoDS::Edge (aEdgeIt.Current ()); + TopoDS_Edge anEdgeNoLoc = TopoDS::Edge (aEdgeIt.Value()); + anEdgeNoLoc.Location (anEmptyLoc); + + if (!aShapeMap.Add (anEdgeNoLoc)) + { + // the edge has already been processed + continue; + } + + if (!BRep_Tool::IsGeometric (TopoDS::Edge (anEdgeNoLoc))) + { + // Do not remove polygon 3d as there is no curve to recompute it. + continue; + } TopLoc_Location aLoc; - Handle (Poly_Polygon3D) aPoly3d = BRep_Tool::Polygon3D (aEdge, aLoc); - if (aPoly3d.IsNull ()) + Handle (Poly_Polygon3D) aPoly3d = BRep_Tool::Polygon3D (anEdgeNoLoc, aLoc); + if (aPoly3d.IsNull()) continue; - aBuilder.UpdateEdge (aEdge, aNullPoly3d); + aBuilder.UpdateEdge (anEdgeNoLoc, aNullPoly3d); } } //======================================================================= diff --git a/src/BRepTools/BRepTools.hxx b/src/BRepTools/BRepTools.hxx index 5cfc5f7259..1e1b916ddb 100644 --- a/src/BRepTools/BRepTools.hxx +++ b/src/BRepTools/BRepTools.hxx @@ -150,9 +150,11 @@ public: //! edge on the face. Standard_EXPORT static void UpdateFaceUVPoints (const TopoDS_Face& theF); - //! Removes all the triangulations of the faces of - //! and removes all polygons on triangulations of the - //! edges. + //! Removes all cashed polygonal representation of the shape, + //! i.e. the triangulations of the faces of and polygons on + //! triangulations and polygons 3d of the edges. + //! In case polygonal representation is the only available representation + //! for the shape (shape does not have geometry) it is not removed. Standard_EXPORT static void Clean (const TopoDS_Shape& S); //! Removes geometry (curves and surfaces) from all edges and faces of the shape diff --git a/src/IMeshTools/IMeshTools_Parameters.hxx b/src/IMeshTools/IMeshTools_Parameters.hxx index c0526becdb..17c3591113 100644 --- a/src/IMeshTools/IMeshTools_Parameters.hxx +++ b/src/IMeshTools/IMeshTools_Parameters.hxx @@ -35,7 +35,8 @@ struct IMeshTools_Parameters { ControlSurfaceDeflection (Standard_True), CleanModel (Standard_True), AdjustMinSize (Standard_False), - ForceFaceDeflection (Standard_False) + ForceFaceDeflection (Standard_False), + AllowQualityDecrease (Standard_False) { } @@ -89,6 +90,10 @@ struct IMeshTools_Parameters { //! Enables/disables usage of shape tolerances for computing face deflection. //! Disabled by default. Standard_Boolean ForceFaceDeflection; + + //! Allows/forbids the decrease of the quality of the generated mesh + //! over the existing one. + Standard_Boolean AllowQualityDecrease; }; #endif diff --git a/src/IMeshTools/IMeshTools_ShapeExplorer.cxx b/src/IMeshTools/IMeshTools_ShapeExplorer.cxx index bc690a40df..a6214ee700 100644 --- a/src/IMeshTools/IMeshTools_ShapeExplorer.cxx +++ b/src/IMeshTools/IMeshTools_ShapeExplorer.cxx @@ -88,7 +88,6 @@ void IMeshTools_ShapeExplorer::Accept ( BRepLib::ReverseSortFaces (GetShape (), aFaceList); TopTools_MapOfShape aFaceMap; - TopLoc_Location aDummyLoc; const TopLoc_Location aEmptyLoc; TopTools_ListIteratorOfListOfShape aFaceIter (aFaceList); for (; aFaceIter.More (); aFaceIter.Next ()) @@ -101,8 +100,7 @@ void IMeshTools_ShapeExplorer::Accept ( } const TopoDS_Face& aFace = TopoDS::Face (aFaceIter.Value ()); - const Handle (Geom_Surface)& aSurf = BRep_Tool::Surface (aFace, aDummyLoc); - if (aSurf.IsNull()) + if (!BRep_Tool::IsGeometric (aFace)) { continue; } diff --git a/src/MeshTest/MeshTest.cxx b/src/MeshTest/MeshTest.cxx index 9882f52266..3624575271 100644 --- a/src/MeshTest/MeshTest.cxx +++ b/src/MeshTest/MeshTest.cxx @@ -89,7 +89,9 @@ options:\n\ surface (enabled by default)\n\ -parallel enables parallel execution (switched off by default)\n\ -adjust_min enables local adjustment of min size depending on edge size (switched off by default)\n\ - -force_face_def disables usage of shape tolerances for computing face deflection (switched off by default). \n"; + -force_face_def disables usage of shape tolerances for computing face deflection (switched off by default)\n\ + -decrease enforces the meshing of the shape even if current mesh satisfies the new criteria\ + (switched off by default).\n"; return 0; } @@ -126,6 +128,8 @@ options:\n\ aMeshParams.AdjustMinSize = Standard_True; else if (aOpt == "-force_face_def") aMeshParams.ForceFaceDeflection = Standard_True; + else if (aOpt == "-decrease") + aMeshParams.AllowQualityDecrease = Standard_True; else if (i < nbarg) { Standard_Real aVal = Draw::Atof(argv[i++]); diff --git a/tests/bugs/mesh/bug31461 b/tests/bugs/mesh/bug31461 new file mode 100644 index 0000000000..bd1c569c53 --- /dev/null +++ b/tests/bugs/mesh/bug31461 @@ -0,0 +1,17 @@ +puts "=======" +puts "0031461: Mesh - Add possibility to force the meshing of the shape" +puts "=======" +puts "" + +psphere s 10 + +incmesh s 0.01 +checktrinfo s -tri 10108 -nod 5106 + +incmesh s 0.1 -decrease +checktrinfo s -tri 978 -nod 507 + +tclean -geom s +incmesh s 0.01 +tclean s +checktrinfo s -tri 978 -nod 507