1
0
mirror of https://git.dev.opencascade.org/repos/occt.git synced 2025-08-14 13:30:48 +03:00

0028605: Improve the algorithm of calculation of valid intersection range of an edge

- 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.
This commit is contained in:
msv
2017-03-24 16:04:05 +03:00
committed by bugmaster
parent 501d0d386a
commit c0a1a35fac
10 changed files with 441 additions and 66 deletions

View 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());
}
//=======================================================================

View 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;
@@ -234,6 +236,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:

236
src/BRepLib/BRepLib_1.cxx Normal file
View File

@@ -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);
}

View File

@@ -1,5 +1,6 @@
BRepLib.cxx
BRepLib.hxx
BRepLib_1.cxx
BRepLib_CheckCurveOnSurface.cxx
BRepLib_CheckCurveOnSurface.hxx
BRepLib_Command.cxx

View File

@@ -39,12 +39,14 @@
#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);
}

View 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,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) {