]> OCCT Git - occt-copy.git/commitdiff
0028605: Improve the algorithm of calculation of valid intersection range of an edge
authormsv <msv@opencascade.com>
Fri, 24 Mar 2017 13:04:05 +0000 (16:04 +0300)
committeremv <emv@opencascade.com>
Fri, 7 Jul 2017 07:02:57 +0000 (10:02 +0300)
- New method BRepLib::FindValidRange() has been added. It computes the range of the edge not covered by boundary vertices.
- The algorithm of calculation of valid intersection range in the class IntTools_ShrunkRange has been corrected to use the new method.
- The method BOPTools_AlgoTools::MakeSplitEdge() has been improved to protect against errors in the case of reversed orientation of the input edge.
- Two new Draw commands have been added:
  validrange - it calls the new method BRepLib::FindValidRange().
  tolsphere  - it shows tolerances of vertices by drawing a sphere around each vertex of the shape.
- The test cases "offset shape_type_i_c YE1,YE2" became better. The scripts have been corrected to reflect the new state.

dox/user_guides/modeling_algos/modeling_algos.md
src/BOPTools/BOPTools_AlgoTools_2.cxx
src/BRepLib/BRepLib.hxx
src/BRepLib/BRepLib_1.cxx [new file with mode: 0644]
src/BRepLib/FILES
src/BRepTest/BRepTest_CheckCommands.cxx
src/IntTools/IntTools_ShrunkRange.cxx
tests/offset/shape_type_i_c/YE1
tests/offset/shape_type_i_c/YE2

index a71ec3369d56557f78f83f1a0f0753fe5191cb56..1c701ddb2f8b97fd02ef81b038b1d7779ecb51fa 100644 (file)
@@ -1162,8 +1162,9 @@ The following methods allow building PCurves of edges on faces:
 
 The following methods allow checking the validity of the shapes:
  * *BOPTools_AlgoTools::IsMicroEdge* detects the small edges;
- * *BOPTools_AlgoTools::ComputeTolerance* computs the correct tolerance for the edge on the face;
+ * *BOPTools_AlgoTools::ComputeTolerance* computes the correct tolerance of the edge on the face;
  * *BOPTools_AlgoTools::CorrectShapeTolerances* and *BOPTools_AlgoTools::CorrectTolerances* allows correcting the tolerances of the sub-shapes.
+ * *BRepLib::FindValidRange* finds a range of 3d curve of the edge not covered by tolerance spheres of vertices.
 
 @subsection occt_modalg_2_topo_tools_7 Taking a point inside the face
 
index 6aee96cc1c4e01ae775cfec1e30328a8ac388bb7..d78965c85e08eab9cdbd371e46dc1117fb148784 100644 (file)
@@ -146,7 +146,7 @@ void BOPTools_AlgoTools::MakeSplitEdge(const TopoDS_Edge&   aE,
   Standard_Real aTol;//f, l, 
   aTol=BRep_Tool::Tolerance(aE);
   //
-  TopoDS_Edge E=aE;
+  TopoDS_Edge E = TopoDS::Edge(aE.Oriented(TopAbs_FORWARD));
   E.EmptyCopy();
   //
   BRep_Builder BB;
@@ -159,6 +159,7 @@ void BOPTools_AlgoTools::MakeSplitEdge(const TopoDS_Edge&   aE,
   BB.Range(E, aP1, aP2);
   BB.UpdateEdge(E, aTol);
   aNewEdge=E;
+  aNewEdge.Orientation(aE.Orientation());
 }
 
 //=======================================================================
index 4e34987f232a6723c634b5b94f85b3a6ae1f2419..d29e7939e63cf0554ce2c7795f9d08fbb5584b29 100644 (file)
@@ -27,6 +27,8 @@
 #include <Standard_Integer.hxx>
 #include <TopTools_ListOfShape.hxx>
 #include <NCollection_List.hxx>
+
+class Adaptor3d_Curve;
 class Geom_Plane;
 class TopoDS_Edge;
 class TopoDS_Shape;
@@ -192,6 +194,23 @@ public:
   Standard_EXPORT static  void BoundingVertex(const NCollection_List<TopoDS_Shape>& theLV,
                                               gp_Pnt& theNewCenter, Standard_Real& theNewTol);
 
+  //! For an edge defined by 3d curve and tolerance and vertices defined by points,
+  //! parameters on curve and tolerances,
+  //! finds a range of curve between vertices not covered by vertices tolerances.
+  //! Returns false if there is no such range. Otherwise, sets theFirst and 
+  //! theLast as its bounds.
+  Standard_EXPORT static Standard_Boolean FindValidRange
+    (const Adaptor3d_Curve& theCurve, const Standard_Real theTolE,
+     const Standard_Real theParV1, const gp_Pnt& thePntV1, const Standard_Real theTolV1,
+     const Standard_Real theParV2, const gp_Pnt& thePntV2, const Standard_Real theTolV2,
+     Standard_Real& theFirst, Standard_Real& theLast);
+
+  //! Finds a range of 3d curve of the edge not covered by vertices tolerances.
+  //! Returns false if there is no such range. Otherwise, sets theFirst and 
+  //! theLast as its bounds.
+  Standard_EXPORT static Standard_Boolean FindValidRange
+    (const TopoDS_Edge& theEdge, Standard_Real& theFirst, Standard_Real& theLast);
+
 protected:
 
 
diff --git a/src/BRepLib/BRepLib_1.cxx b/src/BRepLib/BRepLib_1.cxx
new file mode 100644 (file)
index 0000000..736ee8e
--- /dev/null
@@ -0,0 +1,236 @@
+// Created on: 2017-03-24
+// Created by: Mikhail Sazonov
+// Copyright (c) 2017 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 <BRepLib.hxx>
+#include <BRep_Tool.hxx>
+#include <BRepAdaptor_Curve.hxx>
+#include <Geom_OffsetCurve.hxx>
+#include <Precision.hxx>
+#include <TopExp.hxx>
+#include <TopoDS_Vertex.hxx>
+
+//=======================================================================
+// function: findNearestValidPoint
+// purpose : Starting from the appointed end of the curve, find the nearest
+//           point on the curve that is an intersection with the sphere with
+//           center theVertPnt and radius theTol.
+//=======================================================================
+static Standard_Boolean findNearestValidPoint(
+  const Adaptor3d_Curve& theCurve,
+  const Standard_Real theFirst, const Standard_Real theLast,
+  const Standard_Boolean isFirst,
+  const gp_Pnt& theVertPnt,
+  const Standard_Real theTol,
+  const Standard_Real theEps,
+  Standard_Real& thePar)
+{
+  // 1. Check that the needed end is inside the sphere
+
+  Standard_Real aStartU = theFirst;
+  Standard_Real anEndU = theLast;
+  if (!isFirst)
+    std::swap(aStartU, anEndU);
+  gp_Pnt aP = theCurve.Value(aStartU);
+  const Standard_Real aSqTol = theTol * theTol;
+  if (aP.SquareDistance(theVertPnt) > aSqTol)
+    // the vertex does not cover the corresponding to this vertex end of the curve
+    return Standard_False;
+
+  // 2. Find a nearest point that is outside
+
+  // stepping along the curve by theTol till go out
+  //
+  // the general step is computed using general curve resolution
+  Standard_Real aStep = theCurve.Resolution(theTol) * 1.01;
+  // aD1Mag is a threshold to consider local derivative magnitude too small
+  // and to accelerate going out of sphere
+  // (inverse of resolution is the maximal derivative);
+  // this is actual for bezier and b-spline types only
+  Standard_Real aD1Mag = 0.;
+  GeomAbs_CurveType aType = theCurve.GetType();
+  if (aType == GeomAbs_OffsetCurve)
+  {
+    Handle(Geom_OffsetCurve) anOffsetCurve = theCurve.OffsetCurve();
+    Handle(Geom_Curve) aBaseCurve = anOffsetCurve->BasisCurve();
+    aType = GeomAdaptor_Curve(aBaseCurve).GetType();
+  }
+  if (aType == GeomAbs_BezierCurve || aType == GeomAbs_BSplineCurve)
+  {
+    aD1Mag = 1. / theCurve.Resolution(1.) * 0.01;
+    aD1Mag *= aD1Mag;
+  }
+  if (!isFirst)
+    aStep = -aStep;
+  Standard_Boolean isOut = Standard_False;
+  Standard_Real anUIn = aStartU;
+  Standard_Real anUOut = anUIn;
+  while (!isOut)
+  {
+    anUIn = anUOut;
+    anUOut += aStep;
+    if ((isFirst && anUOut > anEndU) || (!isFirst && anUOut < anEndU))
+    {
+      // step is too big and we go out of bounds,
+      // check if the opposite bound is outside
+      aP = theCurve.Value(anEndU);
+      isOut = (aP.SquareDistance(theVertPnt) > aSqTol);
+      if (!isOut)
+        // all range is inside sphere
+        return Standard_False;
+      anUOut = anEndU;
+      break;
+    }
+    if (aD1Mag > 0.)
+    {
+      Standard_Real aStepLocal = aStep;
+      for (;;)
+      {
+        // cycle to go out of local singularity
+        gp_Vec aD1;
+        theCurve.D1(anUOut, aP, aD1);
+        if (aD1.SquareMagnitude() < aD1Mag)
+        {
+          aStepLocal *= 2.;
+          anUOut += aStepLocal;
+          if ((isFirst && anUOut < anEndU) || (!isFirst && anUOut > anEndU))
+            // still in range
+            continue;
+          // went out of range, so check if the end point has out state
+          anUOut = anEndU;
+          aP = theCurve.Value(anUOut);
+          isOut = (aP.SquareDistance(theVertPnt) > aSqTol);
+          if (!isOut)
+            // all range is inside sphere
+            return Standard_False;
+        }
+        break;
+      }
+    }
+    else
+    {
+      aP = theCurve.Value(anUOut);
+    }
+    if (!isOut)
+      isOut = (aP.SquareDistance(theVertPnt) > aSqTol);
+  }
+
+  // 3. Precise solution with binary search
+
+  Standard_Real aDelta = Abs(anUOut - anUIn);
+  while (aDelta > theEps)
+  {
+    Standard_Real aMidU = (anUIn + anUOut) * 0.5;
+    aP = theCurve.Value(aMidU);
+    isOut = (aP.SquareDistance(theVertPnt) > aSqTol);
+    if (isOut)
+      anUOut = aMidU;
+    else
+      anUIn = aMidU;
+    aDelta = Abs(anUOut - anUIn);
+  }
+  thePar = (anUIn + anUOut) * 0.5;
+  return Standard_True;
+}
+
+//=======================================================================
+// function: FindValidRange
+// purpose : 
+//=======================================================================
+Standard_Boolean BRepLib::FindValidRange
+  (const Adaptor3d_Curve& theCurve, const Standard_Real theTolE,
+   const Standard_Real theParV1, const gp_Pnt& thePntV1, const Standard_Real theTolV1,
+   const Standard_Real theParV2, const gp_Pnt& thePntV2, const Standard_Real theTolV2,
+   Standard_Real& theFirst, Standard_Real& theLast)
+{
+  if (theParV2 - theParV1 < Precision::PConfusion())
+    return Standard_False;
+  
+  Standard_Real anEps = Max(theCurve.Resolution(theTolE) * 0.1, Precision::PConfusion());
+
+  if (Precision::IsInfinite(theParV1))
+    theFirst = theParV1;
+  else
+  {
+    if (!findNearestValidPoint(theCurve, theParV1, theParV2, Standard_True,
+                               thePntV1, theTolV1, anEps, theFirst))
+      return Standard_False;
+    if (theParV2 - theFirst < anEps)
+      return Standard_False;
+  }
+
+  if (Precision::IsInfinite(theParV2))
+    theLast = theParV2;
+  else
+  {
+    if (!findNearestValidPoint(theCurve, theParV1, theParV2, Standard_False,
+                               thePntV2, theTolV2, anEps, theLast))
+      return Standard_False;
+    if (theLast - theParV1 < anEps)
+      return Standard_False;
+  }
+
+  // check found parameters
+  if (theFirst > theLast)
+  {
+    // overlapping, not valid range
+    return Standard_False;
+  }
+
+  return Standard_True;
+}
+
+//=======================================================================
+// function: FindValidRange
+// purpose : 
+//=======================================================================
+Standard_Boolean BRepLib::FindValidRange
+  (const TopoDS_Edge& theEdge, Standard_Real& theFirst, Standard_Real& theLast)
+{
+  TopLoc_Location aLoc;
+  Standard_Real f, l;
+  if (BRep_Tool::Curve(theEdge, aLoc, f, l).IsNull())
+    return Standard_False;
+  BRepAdaptor_Curve anAC(theEdge);
+  Standard_Real aParV[2] = { anAC.FirstParameter(), anAC.LastParameter() };
+  if (aParV[1] - aParV[0] < Precision::PConfusion())
+    return Standard_False;
+
+  // get vertices
+  TopoDS_Vertex aV[2];
+  TopExp::Vertices(theEdge, aV[0], aV[1]);
+
+  Standard_Real aTolE = BRep_Tool::Tolerance(theEdge);
+  // to have correspondence with intersection precision
+  // the tolerances of vertices are increased on Precision::Confusion()
+  Standard_Real aTolV[2] = { Precision::Confusion(), Precision::Confusion() };
+  gp_Pnt aPntV[2];
+  for (Standard_Integer i = 0; i < 2; i++)
+  {
+    if (!aV[i].IsNull())
+    {
+      aTolV[i] += BRep_Tool::Tolerance(aV[i]);
+      aPntV[i] = BRep_Tool::Pnt(aV[i]);
+    }
+    else if (!Precision::IsInfinite(aParV[i]))
+    {
+      aTolV[i] += aTolE;
+      aPntV[i] = anAC.Value(aParV[i]);
+    }
+  }
+  return FindValidRange(anAC, aTolE, 
+                        aParV[0], aPntV[0], aTolV[0],
+                        aParV[1], aPntV[1], aTolV[1],
+                        theFirst, theLast);
+}
index a123c7d20c3ad21735c014ddf1b3f81341f5a90f..6d7d2f98c3867f71cc38f8d9ae5ca2254bd83f55 100755 (executable)
@@ -1,5 +1,6 @@
 BRepLib.cxx
 BRepLib.hxx
+BRepLib_1.cxx
 BRepLib_CheckCurveOnSurface.cxx
 BRepLib_CheckCurveOnSurface.hxx
 BRepLib_Command.cxx
index ff9e5fbedd2d26ec6c013b09aef01f496eaa3205..6aa3b93145a8d4f6f7110773918129379e101daa 100644 (file)
 #include <Precision.hxx>
 #include <LocalAnalysis.hxx>
 #include <LocalAnalysis_SurfaceContinuity.hxx>
+#include <Geom_SphericalSurface.hxx>
 #include <Geom_Surface.hxx>
 #include <Geom_Curve.hxx>
 #include <Geom2d_TrimmedCurve.hxx>
 #include <Geom2d_Curve.hxx>
 #include <DrawTrSurf.hxx>
 #include <GeomAbs_Shape.hxx>
+#include <TCollection_AsciiString.hxx>
 #include <TopoDS.hxx>
 #include <TopExp.hxx>
 #include <TopTools_IndexedDataMapOfShapeListOfShape.hxx>
@@ -57,6 +59,7 @@
 
 #include <TopOpeBRepTool_PurgeInternalEdges.hxx>
 //#include <TopOpeBRepTool_FuseEdges.hxx>
+#include <BRepLib.hxx>
 #include <BRepLib_FuseEdges.hxx>
 
 #include <TopTools_HSequenceOfShape.hxx>
@@ -1579,7 +1582,75 @@ static Standard_Integer listfuseedge(Draw_Interpretor& di,
   return 0;
 }
 
+//=======================================================================
+//function : tolsphere
+//purpose  : 
+//=======================================================================
+static Standard_Integer tolsphere(Draw_Interpretor& di, Standard_Integer n, const char** a)
+{
+  if (n != 2)
+  {
+    di << "use toolsphere shape\n";
+    return 1;
+  }
+
+  TopoDS_Shape aS = DBRep::Get(a[1]);
+  if (aS.IsNull())
+  {
+    di << "No such shape " << a[1] << "\n";
+    return 1;
+  }
+
+  TopTools_IndexedMapOfShape aMapV;
+  TopExp::MapShapes(aS, TopAbs_VERTEX, aMapV);
+  for (Standard_Integer i = 1; i <= aMapV.Extent(); i++)
+  {
+    const TopoDS_Vertex& aV = TopoDS::Vertex(aMapV.FindKey(i));
+    Standard_Real aRadius = BRep_Tool::Tolerance(aV);
+    gp_Pnt aCenter = BRep_Tool::Pnt(aV);
+    Handle(Geom_Surface) aSph = new Geom_SphericalSurface(gp_Ax2(aCenter,gp::DZ()), aRadius);
+    TCollection_AsciiString aName(a[1]);
+    aName = aName + "_v" + i;
+    DrawTrSurf::Set(aName.ToCString(), aSph);
+    di << aName << " ";
+  }
+  return 0;
+}
+
+//=======================================================================
+//function : validrange
+//purpose  : 
+//=======================================================================
+static Standard_Integer validrange(Draw_Interpretor& di,
+  Standard_Integer narg, const char** a)
+{
+  if (narg < 2)
+  {
+    di << "usage: validrange edge [(out) u1 u2]";
+    return 1;
+  }
+
+  TopoDS_Edge aE = TopoDS::Edge(DBRep::Get(a[1],TopAbs_EDGE, true));
+  if (aE.IsNull())
+    return 1;
 
+  Standard_Real u1, u2;
+  if (BRepLib::FindValidRange(aE, u1, u2))
+  {
+    if (narg > 3)
+    {
+      Draw::Set(a[2], u1);
+      Draw::Set(a[3], u2);
+    }
+    else
+    {
+      di << u1 << " " << u2;
+    }
+  }
+  else
+    di << "edge has no valid range";
+  return 0;
+}
 
 //=======================================================================
 //function : CheckCommands
@@ -1667,5 +1738,13 @@ theCommands.Add("listfuseedge",
                  "listfuseedge shape",
                  __FILE__,
                  listfuseedge,g);
+theCommands.Add("tolsphere", "toolsphere shape\n"
+                "\t\tshows vertex tolerances by drawing spheres",
+                __FILE__, tolsphere, g);
+theCommands.Add("validrange",
+                "validrange edge [(out) u1 u2]\n"
+                "\t\tcomputes valid range of the edge, and\n"
+                "\t\tprints first and last values or sets the variables u1 and u2",
+                __FILE__, validrange, g);
 }
 
index 6e8c479470442b59847ba876d15fe52a4d5f67c2..7ce4763c6525dede086168db4466ef2c8b2a7006 100644 (file)
@@ -14,6 +14,7 @@
 
 
 #include <Bnd_Box.hxx>
+#include <BRepLib.hxx>
 #include <BndLib_Add3dCurve.hxx>
 #include <BRep_Tool.hxx>
 #include <BRepAdaptor_Curve.hxx>
@@ -133,6 +134,8 @@ void IntTools_ShrunkRange::Perform()
     return;
   }
   //
+  gp_Pnt aP1 = BRep_Tool::Pnt(myV1);
+  gp_Pnt aP2 = BRep_Tool::Pnt(myV2);
   Standard_Real aTolE, aTolV1, aTolV2;
   aTolE = BRep_Tool::Tolerance(myEdge);
   aTolV1 = BRep_Tool::Tolerance(myV1);
@@ -150,42 +153,31 @@ void IntTools_ShrunkRange::Perform()
   // the tolerances of vertices are increased on Precision::Confusion()
   aTolV1 += aDTol;
   aTolV2 += aDTol;
-  //
-  BRepAdaptor_Curve aBAC(myEdge);
-  // parametric tolerance for the edge
-  // to be used in AbscissaPoint computations
-  Standard_Real aPTolE = aBAC.Resolution(aTolE);
-  // for the edges with big tolerance use 
-  // min parametric tolerance - 1% of its range
-  Standard_Real aPTolEMin = (myT2 - myT1) / 100.;
-  if (aPTolE > aPTolEMin) {
-    aPTolE = aPTolEMin;
-  }
-  //
+
   // compute the shrunk range - part of the edge not covered
   // by the tolerance spheres of its vertices
-  GCPnts_AbscissaPoint aPC1(aBAC, aTolV1, myT1, aPTolE);
-  // if Abscissa is unable to compute the parameter
-  // use the resolution of the curve
-  myTS1 = aPC1.IsDone() ? aPC1.Parameter() : (myT1 + aBAC.Resolution(aTolV1));
-  if (myT2 - myTS1 < aPDTol) {
-    // micro edge
-    return;
-  }
-  //
-  GCPnts_AbscissaPoint aPC2(aBAC, -aTolV2, myT2, aPTolE);
-  myTS2 = aPC2.IsDone() ? aPC2.Parameter() : (myT2 - aBAC.Resolution(aTolV2));
-  if (myTS2 - myT1 < aPDTol) {
-    // micro edge
+  BRepAdaptor_Curve aBAC(myEdge);
+  if (!BRepLib::FindValidRange(aBAC, aTolE, myT1, aP1, aTolV1,
+                               myT2, aP2, aTolV2, myTS1, myTS2)) {
+    // no valid range
     return;
   }
-  //
   if ((myTS2 - myTS1) < aPDTol) {
     // micro edge
     return;
   }
   //
   // compute the length of the edge on the shrunk range
+  //
+  // parametric tolerance for the edge
+  // to be used in AbscissaPoint computations
+  Standard_Real aPTolE = aBAC.Resolution(aTolE);
+  // for the edges with big tolerance use 
+  // min parametric tolerance - 1% of its range
+  Standard_Real aPTolEMin = (myT2 - myT1) / 100.;
+  if (aPTolE > aPTolEMin) {
+    aPTolE = aPTolEMin;
+  }
   Standard_Real anEdgeLength =
     GCPnts_AbscissaPoint::Length(aBAC, myTS1, myTS2, aPTolE);
   if (anEdgeLength < aDTol) {
index c2787498772ac72605689f73df9ed218419559be..a3938ba27d730f665c824cdb2995e269007fa526 100644 (file)
@@ -1,4 +1,4 @@
-puts "TODO CR27414 ALL: Error :  is WRONG because number of FACE entities in shape"
+puts "TODO OCC27414 ALL: WRONG because number of FACE .* is 15"
 
 restore [locate_data_file bug28442_simple3.brep] s
 
index fc02056f2383d3fe84ec847eed8208afb5133f77..6c212179f674b4a9274b822e93f4475ee293ead7 100644 (file)
@@ -1,4 +1,4 @@
-puts "TODO CR27414 ALL: Error :  is WRONG because number of FACE entities in shape"
+puts "TODO OCC27414 ALL: WRONG because number of FACE .* is 16"
 
 restore [locate_data_file bug28442_simple3.brep] s