- 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.
compound b1 b2 b3 c
~~~~~
-@subsubsection occt_draw_7_1_5 checkshape
-Syntax:
-~~~~~
-checkshape [-top] shape [result] [-short]
-~~~~~
-
-Where:
-* *top* -- optional parameter, which allows checking only topological validity of a shape.
-* *shape* -- the only required parameter which represents the name of the shape to check.
-* *result* -- optional parameter which is the prefix of the output shape names.
-* *short* -- a short description of the check.
-
-**checkshape** examines the selected object for topological and geometric coherence. The object should be a three dimensional shape.
-
-**Example:**
-~~~~~
-# checkshape returns a comment valid or invalid
-box b1 0 0 0 1 1 1
-checkshape b1
-# returns the comment
-this shape seems to be valid
-~~~~~
-
-**Note** that this test is performed using the tolerance set in the algorithm.
-
-@subsubsection occt_draw_7_1_6 compare
+@subsubsection occt_draw_7_1_5 compare
Syntax:
~~~~~
# shapes are not same
~~~~~
-@subsubsection occt_draw_7_1_7 issubshape
+@subsubsection occt_draw_7_1_6 issubshape
Syntax:
~~~~~
@subsection occt_draw_7_9 Analysis of topology and geometry
-Analysis of shapes includes commands to compute length, area, volumes and inertial properties.
+Analysis of shapes includes commands to compute length, area, volumes and inertial properties, as well as to compute some aspects impacting shape validity.
* Use **lprops**, **sprops**, **vprops** to compute integral properties.
* Use **bounding** to display the bounding box of a shape.
* Use **distmini** to calculate the minimum distance between two shapes.
* Use **xdistef**, **xdistcs**, **xdistcc**, **xdistc2dc2dss**, **xdistcc2ds** to check the distance between two objects on even grid.
+ * Use **checkshape** to check validity of the shape.
+ * Use **tolsphere** to see the tolerance spheres of all vertices in the shape.
+ * Use **validrange** to check range of an edge not covered by vertices.
@subsubsection occt_draw_7_9_1 lprops, sprops, vprops
xdistc2dc2dss c2d1_1 c2d2_1 s1 s2 0 1 1000
~~~~~
+@subsubsection occt_draw_7_9_5 checkshape
+
+Syntax:
+~~~~~
+checkshape [-top] shape [result] [-short]
+~~~~~
+
+Where:
+* *top* -- optional parameter, which allows checking only topological validity of a shape.
+* *shape* -- the only required parameter which represents the name of the shape to check.
+* *result* -- optional parameter which is the prefix of the output shape names.
+* *short* -- a short description of the check.
+
+**checkshape** examines the selected object for topological and geometric coherence. The object should be a three dimensional shape.
+
+**Example:**
+~~~~~
+# checkshape returns a comment valid or invalid
+box b1 0 0 0 1 1 1
+checkshape b1
+# returns the comment
+this shape seems to be valid
+~~~~~
+
+@subsubsection occt_draw_7_9_6 tolsphere
+
+Syntax:
+~~~~~
+tolsphere shape
+~~~~~
+
+Where:
+* *shape* -- the name of the shape to process.
+
+**tolsphere** shows vertex tolerances by drawing spheres around each vertex in the shape. Each sphere is assigned a name of the shape with suffix "_vXXX", where XXX is the number of the vertex in the shape.
+
+**Example:**
+~~~~~
+# tolsphere returns all names of created spheres.
+box b1 0 0 0 1 1 1
+settolerance b1 0.05
+tolsphere b1
+# creates spheres and returns the names
+b1_v1 b1_v2 b1_v3 b1_v4 b1_v5 b1_v6 b1_v7 b1_v8
+~~~~~
+
+@subsubsection occt_draw_7_9_7 validrange
+
+Syntax:
+~~~~~
+validrange edge [(out) u1 u2]
+~~~~~
+
+Where:
+* *edge* -- the name of the edge to analyze.
+* *u1*, *u2* -- optional names of variables to put the range into.
+
+**validrange** computes valid range of the edge. If *u1* and *u2* are not given it returns first and last parameters. Otherwise, it sets the variables u1 and u2.
+
+**Example:**
+~~~~~
+circle c 0 0 0 10
+mkedge e c
+mkedge e c 0 pi
+validrange e
+# returns the range
+1.9884375000000002e-008 3.1415926337054181
+validrange e u1 u2
+dval u1
+1.9884375000000002e-008
+dval u2
+3.1415926337054181
+~~~~~
+
@subsection occt_draw_7_10 Surface creation
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
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;
BB.Range(E, aP1, aP2);
BB.UpdateEdge(E, aTol);
aNewEdge=E;
+ aNewEdge.Orientation(aE.Orientation());
}
//=======================================================================
#include <Standard_Integer.hxx>
#include <TopTools_ListOfShape.hxx>
#include <NCollection_List.hxx>
+
+class Adaptor3d_Curve;
class Geom_Plane;
class TopoDS_Edge;
class TopoDS_Shape;
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:
--- /dev/null
+// 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);
+}
BRepLib.cxx
BRepLib.hxx
+BRepLib_1.cxx
BRepLib_CheckCurveOnSurface.cxx
BRepLib_CheckCurveOnSurface.hxx
BRepLib_Command.cxx
#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>
#include <TopOpeBRepTool_PurgeInternalEdges.hxx>
//#include <TopOpeBRepTool_FuseEdges.hxx>
+#include <BRepLib.hxx>
#include <BRepLib_FuseEdges.hxx>
#include <TopTools_HSequenceOfShape.hxx>
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
"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);
}
#include <Bnd_Box.hxx>
+#include <BRepLib.hxx>
#include <BndLib_Add3dCurve.hxx>
#include <BRep_Tool.hxx>
#include <BRepAdaptor_Curve.hxx>
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);
// 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) {
-puts "TODO OCC27414 ALL: Error: The command cannot be built"
-puts "TODO OCC27414 ALL: Tcl Exception"
-puts "TODO OCC27414 ALL: TEST INCOMPLETE"
-
+puts "TODO OCC27414 ALL: WRONG because number of FACE .* is 15"
restore [locate_data_file bug28442_simple3.brep] s
-puts "TODO OCC27414 ALL: Error: The command cannot be built"
-puts "TODO OCC27414 ALL: Tcl Exception"
-puts "TODO OCC27414 ALL: TEST INCOMPLETE"
-
+puts "TODO OCC27414 ALL: WRONG because number of FACE .* is 16"
restore [locate_data_file bug28442_simple3.brep] s
}
offsetperform result
-checkprops result -v 0 -s 0
+checkprops result -v 1410.52 -s 845.819
unifysamedom result_unif result
-checknbshapes result_unif -face 13 -shell 1
+checknbshapes result_unif -face 14 -shell 1
checkview -display result_unif -2d -path ${imagedir}/${test_image}.png