diff --git a/dox/user_guides/draw_test_harness/draw_test_harness.md b/dox/user_guides/draw_test_harness/draw_test_harness.md index bebb59e3f6..5a6f0eaa00 100644 --- a/dox/user_guides/draw_test_harness/draw_test_harness.md +++ b/dox/user_guides/draw_test_harness/draw_test_harness.md @@ -5942,33 +5942,8 @@ box b3 6 0 0 1 1 1 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: ~~~~~ @@ -5994,7 +5969,7 @@ compare b1 b2 # shapes are not same ~~~~~ -@subsubsection occt_draw_7_1_7 issubshape +@subsubsection occt_draw_7_1_6 issubshape Syntax: ~~~~~ @@ -7273,12 +7248,15 @@ buildevol @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 @@ -7411,6 +7389,80 @@ xdistcc2ds c_1 c2d2_1 s2 0 1 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 diff --git a/dox/user_guides/modeling_algos/modeling_algos.md b/dox/user_guides/modeling_algos/modeling_algos.md index b952681ea4..7211f9d877 100644 --- a/dox/user_guides/modeling_algos/modeling_algos.md +++ b/dox/user_guides/modeling_algos/modeling_algos.md @@ -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 diff --git a/src/BOPTools/BOPTools_AlgoTools_2.cxx b/src/BOPTools/BOPTools_AlgoTools_2.cxx index 6aee96cc1c..d78965c85e 100644 --- a/src/BOPTools/BOPTools_AlgoTools_2.cxx +++ b/src/BOPTools/BOPTools_AlgoTools_2.cxx @@ -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()); } //======================================================================= diff --git a/src/BRepLib/BRepLib.hxx b/src/BRepLib/BRepLib.hxx index 4d4b89c242..d19127a3aa 100644 --- a/src/BRepLib/BRepLib.hxx +++ b/src/BRepLib/BRepLib.hxx @@ -27,6 +27,8 @@ #include #include #include + +class Adaptor3d_Curve; class Geom_Plane; class TopoDS_Edge; class TopoDS_Shape; @@ -234,6 +236,23 @@ public: Standard_EXPORT static void BoundingVertex(const NCollection_List& 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 index 0000000000..736ee8ea9c --- /dev/null +++ b/src/BRepLib/BRepLib_1.cxx @@ -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 +#include +#include +#include +#include +#include +#include + +//======================================================================= +// 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); +} diff --git a/src/BRepLib/FILES b/src/BRepLib/FILES index a123c7d20c..6d7d2f98c3 100755 --- a/src/BRepLib/FILES +++ b/src/BRepLib/FILES @@ -1,5 +1,6 @@ BRepLib.cxx BRepLib.hxx +BRepLib_1.cxx BRepLib_CheckCurveOnSurface.cxx BRepLib_CheckCurveOnSurface.hxx BRepLib_Command.cxx diff --git a/src/BRepTest/BRepTest_CheckCommands.cxx b/src/BRepTest/BRepTest_CheckCommands.cxx index 60f6510c82..e35547afbb 100644 --- a/src/BRepTest/BRepTest_CheckCommands.cxx +++ b/src/BRepTest/BRepTest_CheckCommands.cxx @@ -39,12 +39,14 @@ #include #include #include +#include #include #include #include #include #include #include +#include #include #include #include @@ -57,6 +59,7 @@ #include //#include +#include #include #include @@ -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); } diff --git a/src/IntTools/IntTools_ShrunkRange.cxx b/src/IntTools/IntTools_ShrunkRange.cxx index 6e8c479470..7ce4763c65 100644 --- a/src/IntTools/IntTools_ShrunkRange.cxx +++ b/src/IntTools/IntTools_ShrunkRange.cxx @@ -14,6 +14,7 @@ #include +#include #include #include #include @@ -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,8 +153,22 @@ void IntTools_ShrunkRange::Perform() // the tolerances of vertices are increased on Precision::Confusion() aTolV1 += aDTol; aTolV2 += aDTol; - // + + // compute the shrunk range - part of the edge not covered + // by the tolerance spheres of its vertices 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); @@ -161,31 +178,6 @@ void IntTools_ShrunkRange::Perform() 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 - return; - } - // - if ((myTS2 - myTS1) < aPDTol) { - // micro edge - return; - } - // - // compute the length of the edge on the shrunk range Standard_Real anEdgeLength = GCPnts_AbscissaPoint::Length(aBAC, myTS1, myTS2, aPTolE); if (anEdgeLength < aDTol) { diff --git a/tests/offset/shape_type_i_c/YE1 b/tests/offset/shape_type_i_c/YE1 index ff32f12c65..a3938ba27d 100644 --- a/tests/offset/shape_type_i_c/YE1 +++ b/tests/offset/shape_type_i_c/YE1 @@ -1,7 +1,4 @@ -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 diff --git a/tests/offset/shape_type_i_c/YE2 b/tests/offset/shape_type_i_c/YE2 index 60bc252cae..3c32bd9b62 100644 --- a/tests/offset/shape_type_i_c/YE2 +++ b/tests/offset/shape_type_i_c/YE2 @@ -1,7 +1,4 @@ -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 @@ -25,9 +22,9 @@ foreach f [explode s f] { } 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