0028379: BRepMesh produces mangled mesh for a cone
authoroan <oan@opencascade.com>
Fri, 2 Nov 2018 13:50:47 +0000 (16:50 +0300)
committerapn <apn@opencascade.com>
Tue, 13 Nov 2018 12:45:19 +0000 (15:45 +0300)
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

src/BRepMesh/BRepMesh_ConeRangeSplitter.cxx
src/BRepMesh/BRepMesh_ConeRangeSplitter.hxx
src/BRepMesh/BRepMesh_ModelPreProcessor.cxx
tests/bugs/mesh/bug25042

index 8900fa8..da28dd0 100644 (file)
 #include <GCPnts_TangentialDeflection.hxx>
 
 //=======================================================================
-// Function: GenerateSurfaceNodes
+// Function: GetSplitSteps
 // Purpose : 
 //=======================================================================
-Handle(IMeshData::ListOfPnt2d) BRepMesh_ConeRangeSplitter::GenerateSurfaceNodes(
-  const IMeshTools_Parameters& theParameters) const
+std::pair<Standard_Real, Standard_Real> BRepMesh_ConeRangeSplitter::GetSplitSteps(
+  const IMeshTools_Parameters&                   theParameters,    
+  std::pair<Standard_Integer, Standard_Integer>& theStepsNb) const
 {
   const std::pair<Standard_Real, Standard_Real>& aRangeU = GetRangeU();
   const std::pair<Standard_Real, Standard_Real>& 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<Standard_Real, Standard_Real>& aRangeU = GetRangeU();
+  const std::pair<Standard_Real, Standard_Real>& aRangeV = GetRangeV();
+
+  std::pair<Standard_Integer, Standard_Integer> aStepsNb;
+  std::pair<Standard_Real, Standard_Real> 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));
     }
index 779c1ca..e9abf42 100644 (file)
@@ -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<Standard_Real, Standard_Real> GetSplitSteps(
+    const IMeshTools_Parameters&                   theParameters,    
+    std::pair<Standard_Integer, Standard_Integer>& 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;
index a583a99..7ec3d40 100644 (file)
@@ -21,6 +21,7 @@
 #include <IMeshData_Wire.hxx>
 #include <IMeshData_PCurve.hxx>
 #include <OSD_Parallel.hxx>
+#include <BRepMesh_ConeRangeSplitter.hxx>
 
 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<Standard_Integer, Standard_Integer> aStepsNb;
+      std::pair<Standard_Real, Standard_Real> 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<gp_XYZ> (theDEdge->GetCurve (), theDU))
+      {
+        return Standard_False;
+      }
+
+      for (Standard_Integer aPCurveIdx = 0; aPCurveIdx < theDEdge->PCurvesNb(); ++aPCurveIdx)
+      {
+        splitCurve<gp_XY> (theDEdge->GetPCurve (aPCurveIdx), theDU);
+      }
+
+      return Standard_True;
+    }
+
+    //! Splits the given curve using the specified step.
+    template<class PointType, class Curve>
+    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));
index 6fa2292..b44908d 100644 (file)
@@ -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 "=========="