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

0027448: BOPTools_AlgoTools::IsMicroEdge does not correspond to shape validity criteria

1. IntTools_ShrunkRange::Perform
The algorithm of building shrunk range on the edge has been redesigned to make this range as big as possible.
By new definition it has to have the length not less than Precision::Confusion().
Although, the possibility of splitting of the edge has been taken into account. If it is impossible to put
vertex on edge in such a way that the tolerance spheres of the edge's vertices do not intersect the tolerance
sphere of the putting vertex the edge cannot be split. This possibility is saved in the new field
IntTools_ShrunkRange::myIsSplittable. It can be checked by the corresponding method IntTools_ShrunkRange::IsSplittable().
It returns TRUE if the shrunk range is computed successfully and it has the length more than the value of sum of two tolerance
values of the edge (for putting vertex, as its tolerance should not be less than the tolerance value of edge) and
two Precision::Confusion() values (to make two new edges valid by Shape validity criteria).

IntTools_ShrunkRange::myErrorStatus and IntTools_ShrunkRange::ErrorStatus() have been replaced by
the IntTools_ShrunkRange::myIsDone and IntTools_ShrunkRange::IsDone(). IntTools_ShrunkRange::IsDone() returns TRUE
if the shrunk range has been computed and it has length more than Precision::Confusion().

All computations of the parameters are performed using the GCPnts_AbscissaPoint, but if AbscissaPoint is unable to
compute the parameters the Resolution of the curve is used.

2. Boolean Operations algorithm now partially works with the edges that cannot be split or does not have the ShrunkData
at all (previously such edges have been considered as micro and just ignored). If by the result of some intersection such
edges should be split, i.e. the intersection vertex should be created, the algorithm just ignores them and no vertex is created.
But if such edges coincide with other shapes (other edges or faces) the algorithm uses them for creation of common blocks.
The information of the possibility for the edges to be split is saved in its PaveBlocks, in the new BOPDS_PaveBlock::myIsSplittable field.
It can be retrieved by the BOPDS_PaveBlock::IsSplittable() or BOPDS_PaveBlock::ShrunkData(), but these methods
make sense only after filling of the shrunk data for the pave block.

BOPTools_AlgoTools::IsMicroEdge() has an additional parameter that defines whether it is necessary to take into account
the possibility for the edge to be split or not. By default it is set to TRUE, i.e. by default the edge will be considered as micro
even if the shrunk range is computed, but it is too short for the edge to be split.

3. BOPAlgo_PaveFiller::PerformEF
To avoid creation of too close intersection vertices the intersection ranges of the edges participating in Edge/Face
intersections are reduced taking into account the common ranges computed during Edge/Edge intersections.
Thus, the Edge/Face intersection vertex is not created if it gets into a common range of the Edge/Edge intersection
between that edge and one of the face's edges. The tolerance value of Edge/Edge intersection vertex is increased
to reach the Edge/Face intersection.

4. Unification of the vertices of the section edges considered as micro edges.
If by the result of some Face/Face intersection the section edge is considered as micro edge,
the vertices of this edge will be united and the edge itself will be removed.

5. Test cases for the issues.

6. Adjusting test cases for issue CR27448.
This commit is contained in:
emv
2016-05-04 16:42:55 +03:00
committed by bugmaster
parent 1aee6c8210
commit 01b5b3df55
24 changed files with 527 additions and 491 deletions

View File

@@ -17,17 +17,9 @@
#include <BndLib_Add3dCurve.hxx>
#include <BRep_Tool.hxx>
#include <BRepAdaptor_Curve.hxx>
#include <BRepBuilderAPI_MakeVertex.hxx>
#include <ElCLib.hxx>
#include <Geom_Curve.hxx>
#include <gp.hxx>
#include <gp_Circ.hxx>
#include <gp_Lin.hxx>
#include <IntTools_Context.hxx>
#include <GCPnts_AbscissaPoint.hxx>
#include <IntTools_ShrunkRange.hxx>
#include <Precision.hxx>
#include <TopoDS_Edge.hxx>
#include <TopoDS_Vertex.hxx>
//=======================================================================
//function :
@@ -39,7 +31,8 @@
myT2=myT1;
myTS1=myT1;
myTS2=myT1;
myErrorStatus=1;
myIsDone=Standard_False;
myIsSplittable=Standard_False;
}
//=======================================================================
//function : ~
@@ -63,7 +56,8 @@ void IntTools_ShrunkRange::SetData(const TopoDS_Edge& aE,
myV2=aV2;
myT1=aT1;
myT2=aT2;
myErrorStatus=1;
myIsDone=Standard_False;
myIsSplittable=Standard_False;
}
//=======================================================================
//function : SetContext
@@ -107,15 +101,6 @@ const Bnd_Box& IntTools_ShrunkRange::BndBox() const
{
return myBndBox;
}
//=======================================================================
//function : ErrorStatus
//purpose :
//=======================================================================
Standard_Integer IntTools_ShrunkRange::ErrorStatus() const
{
return myErrorStatus;
}
//=======================================================================
//function : SetShrunkRange
//purpose :
@@ -127,7 +112,7 @@ void IntTools_ShrunkRange::SetShrunkRange(const Standard_Real aT1,
myTS2=aT2;
//
BRepAdaptor_Curve aBAC(myEdge);
BndLib_Add3dCurve::Add (aBAC, aT1, aT2, 0., myBndBox);
BndLib_Add3dCurve::Add(aBAC, aT1, aT2, 0., myBndBox);
}
//=======================================================================
@@ -136,24 +121,23 @@ void IntTools_ShrunkRange::SetShrunkRange(const Standard_Real aT1,
//=======================================================================
void IntTools_ShrunkRange::Perform()
{
Standard_Real aCF, aCL, aTolE, aTolV1;
Standard_Real aTolV2, t1, t11, t1C, t2, t12, t2C, dummy;
Standard_Real aCoeff1, aCoeff2, aTol1, aTol2, dt1, dt2, aR, anEps;
Standard_Integer pri;
Standard_Boolean bInf1, bInf2, bAppr;
GeomAbs_CurveType aCurveType;
Handle(Geom_Curve) aC;
myIsDone = Standard_False;
myIsSplittable = Standard_False;
//
myErrorStatus=0;
myTS1=-99;
myTS2=myTS1;
anEps = 1.e-8;
// default tolerance - Precision::Confusion()
Standard_Real aDTol = Precision::Confusion();
// default parametric tolerance - Precision::PConfusion()
Standard_Real aPDTol = Precision::PConfusion();
//
if (myT2 - myT1 < aPDTol) {
return;
}
//
Standard_Real aTolE, aTolV1, aTolV2;
aTolE = BRep_Tool::Tolerance(myEdge);
aTolV1 = BRep_Tool::Tolerance(myV1);
aTolV2 = BRep_Tool::Tolerance(myV2);
//
aTolE =BRep_Tool::Tolerance(myEdge);
aTolV1=BRep_Tool::Tolerance(myV1);
aTolV2=BRep_Tool::Tolerance(myV2);
//for edges with the tolerance value
//more than the tolerance value of vertices
if (aTolV1 < aTolE) {
aTolV1 = aTolE;
}
@@ -162,331 +146,65 @@ void IntTools_ShrunkRange::Perform()
aTolV2 = aTolE;
}
//
t1=myT1;
t2=myT2;
// to have correspondence with intersection precision
// the tolerances of vertices are increased on Precision::Confusion()
aTolV1 += aDTol;
aTolV2 += aDTol;
//
BRepAdaptor_Curve aBAC(myEdge);
aCurveType=aBAC.GetType();
// 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;
}
//
aC=BRep_Tool::Curve(myEdge, aCF, aCL);
BRep_Tool::Range(myEdge, aCF, aCL);
//
if (t1 < aCF || t2 > aCL) {
myErrorStatus=2;
// 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;
}
//
bAppr = !(fabs(t2 - t1) > 100);
if (fabs(t2 - t1) < anEps) {
myErrorStatus=7;
GCPnts_AbscissaPoint aPC2(aBAC, -aTolV2, myT2, aPTolE);
myTS2 = aPC2.IsDone() ? aPC2.Parameter() : (myT2 - aBAC.Resolution(aTolV2));
if (myTS2 - myT1 < aPDTol) {
// micro edge
return;
}
//
if (t1 > t2) {
myErrorStatus=3;
if ((myTS2 - myTS1) < aPDTol) {
// micro edge
return;
}
//
aTol1 = Max(aTolV1, aTolE);
aTol2 = Max(aTolV2, aTolE);
//
aCoeff1 = (aTolE>0.05) ? 1. : 2.;
aCoeff2 = aCoeff1;
if (aCoeff1 == 2.) {
aCoeff1=(aTol1>0.05) ? 1.5 : 2.;
aCoeff2=(aTol2>0.05) ? 1.5 : 2.;
}
// xf
if (aCurveType==GeomAbs_Line && (aCoeff1 != 1 || aCoeff2 != 1)) {
Standard_Real aTV1, aTV2, aEps;
gp_Pnt aPV1, aPV2, aPC1, aPC2;
gp_Lin aL;
//
aEps=Precision::Confusion();
aEps=aEps*aEps;//1.e-14;
aL=aBAC.Line();
//
aPV1=BRep_Tool::Pnt(myV1);
aTV1=ElCLib::Parameter(aL, aPV1);
//
aPV2=BRep_Tool::Pnt(myV2);
aTV2=ElCLib::Parameter(aL, aPV2);
//
if (fabs(aTV1-aCF)<aEps) {
aCoeff1=1.;
aTol1 += Precision::Confusion();
}
if (fabs(aTV2-aCL)<aEps) {
aCoeff2=1.;
aTol2 += Precision::Confusion();
}
}
//
dt1=aCoeff1*aTol1;
dt2=aCoeff2*aTol2;
// xt
//
if (aCurveType==GeomAbs_Line) {
Standard_Real dt1x, dt2x;
dt1x = aBAC.Resolution(dt1);
t11=t1+dt1x;
dt2x = aBAC.Resolution(dt2);
t12=t2-dt2x;
if (t11>t2 || t12<t1) {
t1C=t1;
t2C=t2;
myTS1=t1C;
myTS2=t2C;
//
// BndBox
Standard_Real ddx=aTolE;//1.e-12;
BndLib_Add3dCurve::Add (aBAC, t1C, t2C, ddx, myBndBox);
myErrorStatus=6;//0
return;
}
}
//
if (aCurveType==GeomAbs_Circle) {
gp_Circ aCrc=aBAC.Circle();
aR=aCrc.Radius();
t1C=t1+dt1/aR;
t2C=t2-dt2/aR;
}
else {
//
// Vertex1 => t1C
gp_Pnt aP1,aP11;
aC->D0 (t1, aP1);
//
bInf1=Precision::IsNegativeInfinite(t1);
if (bInf1) {
t1C=t1;
}
//
else {
Standard_Real d1 = aCoeff1*aTol1;
// dt1 = aBAC.Resolution(d1);
//
gp_Vec aD1vec1;
gp_Pnt aPoint;
aBAC.D1(t1, aPoint, aD1vec1);
Standard_Real ad1length1 = aD1vec1.Magnitude();
Standard_Boolean bTryOtherPoints = Standard_False;
dt1 = (t2 - t1) * 0.5;
if(ad1length1 > 1.e-12) {
dt1 = d1 / ad1length1;
if(dt1 > (t2 - t1)) {
// bad parametrization, big tolerance or too small range
bTryOtherPoints = Standard_True;
}
}
else {
bTryOtherPoints = Standard_True;
}
if(bTryOtherPoints) {
Standard_Integer nbsamples = 5;
Standard_Integer ii = 0;
Standard_Real adelta = (t2 - t1) / (nbsamples + 1);
Standard_Boolean bFound = Standard_False;
for(ii = 1; ii <= nbsamples; ii++) {
Standard_Real aparameter = t1 + (adelta * ii);
gp_Pnt aPoint2;
aBAC.D1(aparameter, aPoint2, aD1vec1);
if(aPoint.Distance(aPoint2) < d1)
dt1 = adelta * ii;
ad1length1 = aD1vec1.Magnitude();
if(ad1length1 > 1.e-12) {
dt1 = d1 / ad1length1;
if(dt1 < (t2 - t1)) {
bFound = Standard_True;
break;
}
}
}
if(!bFound) {
if(dt1 > (t2 - t1)) {
dt1 = aBAC.Resolution(d1);
if (dt1 > (t2 - t1)) {
myErrorStatus = 7;
return;
}
}
}
}
//
if (!bAppr) {
dt1 *= 10;
}
t11=t1+dt1;
aC->D0 (t11, aP11);
gp_Vec aV11(aP1, aP11);
// avoid exception if aP1 == aP11
if (aV11.SquareMagnitude() < gp::Resolution())
t1C = t1;
else {
gp_Dir aD11(aV11);
gp_Pnt aP1L;
//
aP1L.SetCoord (aP1.X()+d1*aD11.X(),
aP1.Y()+d1*aD11.Y(),
aP1.Z()+d1*aD11.Z());
BRepBuilderAPI_MakeVertex aMV1(aP1L);
const TopoDS_Vertex& aV1L=aMV1.Vertex();
//
pri = myCtx->ComputeVE(aV1L, myEdge, t1C, dummy);
//
if (pri==-3) {
myErrorStatus=4;
return;
}
}
}
//
// Vertex2 => t2C
gp_Pnt aP2, aP12;
aC->D0 (t2, aP2);
//
bInf2=Precision::IsPositiveInfinite(t2);
if (bInf2) {
t2C=t2;
}
//
else {
Standard_Real d2 = aCoeff2*aTol2;
// dt2 = aBAC.Resolution(d2);
//
gp_Vec aD1vec2;
gp_Pnt aPoint;
aBAC.D1(t2, aPoint, aD1vec2);
Standard_Real ad1length2 = aD1vec2.Magnitude();
Standard_Boolean bTryOtherPoints = Standard_False;
dt2 = (t2 - t1) * 0.5;
if(ad1length2 > 1.e-12) {
dt2 = d2 / ad1length2;
if(dt2 > (t2 - t1)) {
bTryOtherPoints = Standard_True;
}
}
else {
bTryOtherPoints = Standard_True;
}
if(bTryOtherPoints) {
Standard_Integer nbsamples = 5;
Standard_Integer ii = 0;
Standard_Real adelta = (t2 - t1) / (nbsamples + 1);
Standard_Boolean bFound = Standard_False;
for(ii = 1; ii <= nbsamples; ii++) {
Standard_Real aparameter = t2 - (adelta * ii);
gp_Pnt aPoint2;
aBAC.D1(aparameter, aPoint2, aD1vec2);
if(aPoint.Distance(aPoint2) < d2)
dt2 = adelta * ii;
ad1length2 = aD1vec2.Magnitude();
if(ad1length2 > 1.e-12) {
dt2 = d2 / ad1length2;
if(dt2 < (t2 - t1)) {
bFound = Standard_True;
break;
}
}
}
if(!bFound) {
if(dt2 > (t2 - t1)) {
dt2 = aBAC.Resolution(d2);
if(dt2 > (t2 - t1)) {
myErrorStatus = 7;
return;
}
}
}
}
//
if (!bAppr) {
dt2 *= 10;
}
t12=t2-dt2;
aC->D0 (t12, aP12);
gp_Vec aV12(aP2, aP12);
// avoid exception if aP1 == aP11
if (aV12.SquareMagnitude() < gp::Resolution())
t2C = t2;
else {
gp_Dir aD12(aV12);
gp_Pnt aP2L;
//
aP2L.SetCoord (aP2.X()+d2*aD12.X(),
aP2.Y()+d2*aD12.Y(),
aP2.Z()+d2*aD12.Z());
BRepBuilderAPI_MakeVertex aMV2(aP2L);
const TopoDS_Vertex& aV2L=aMV2.Vertex();
//
pri = myCtx->ComputeVE(aV2L, myEdge, t2C, dummy);
//
if (pri==-3) {
myErrorStatus=5;
return;
}
}
}
} // else {
//
if (t1C>t2){
t1C=0.5*(t2+t1);
t2C=t1C+0.1*(t2-t1C);
}
if (t1C>t2C) {
t2C=t1C+0.1*(t2-t1C);
}
//
if (t2C-t1C < anEps) {
myErrorStatus = 7;
// compute the length of the edge on the shrunk range
Standard_Real anEdgeLength =
GCPnts_AbscissaPoint::Length(aBAC, myTS1, myTS2, aPTolE);
if (anEdgeLength < aDTol) {
// micro edge
return;
}
//
myTS1=t1C;
myTS2=t2C;
myIsDone = Standard_True;
//
// BndBox
Standard_Real ddx = aTolE + Precision::Confusion();
BndLib_Add3dCurve::Add (aBAC, t1C, t2C, ddx, myBndBox);
// check the shrunk range to have the length not less than
// 2*aTolE+2*Precision::Confusion()
// for the edge to have possibility to be split at least once:
// 2*TolE - minimal diameter of tolerance sphere of splitting vertex
// 2*Precision::Confusion() - minimal length of the new edges
if (anEdgeLength > (2 * aTolE + 2 * aDTol)) {
myIsSplittable = Standard_True;
}
//
// build bounding box for the edge on the shrunk range
BndLib_Add3dCurve::Add(aBAC, myTS1, myTS2,
aTolE + aDTol, myBndBox);
}
/////////////////////////////////////////////////////////////////////////
//
// myErrorStatus :
//
// 1- Nothing has been done
// 2- The source range is out of the edge's range
// 3- t1 < t2 for source range
// 4- Can not project V1L to the Edge;
// 5- Can not project V2L to the Edge;
// 6- for obtained shrunk range [t11, t12] -> t11>t2 || t12<t1;
// 7- too small range.

View File

@@ -60,27 +60,22 @@ Standard_EXPORT virtual ~IntTools_ShrunkRange();
Standard_EXPORT void Perform();
//! Returns TRUE in case the shrunk range is computed
Standard_Boolean IsDone() const
{
return myIsDone;
}
//! Returns code of computing shrunk range
//! completion
//! 0 - means successful completion
//! 1 - nothing has been done
//! 2 - initial range is out of edge's range
//! 3 - first boundary of initial range is more than
//! last boundary
//! 4 - projection of first vertex failed
//! 5 - projection of second vertex failed
//! 6 - shrunk range can not be computed
//! shrunk range is setted to initial range
Standard_EXPORT Standard_Integer ErrorStatus() const;
//! Returns FALSE in case the shrunk range is
//! too short and the edge cannot be split,
//! otherwise returns TRUE
Standard_Boolean IsSplittable() const
{
return myIsSplittable;
}
protected:
TopoDS_Edge myEdge;
TopoDS_Vertex myV1;
TopoDS_Vertex myV2;
@@ -90,21 +85,11 @@ protected:
Standard_Real myTS2;
Bnd_Box myBndBox;
Handle(IntTools_Context) myCtx;
Standard_Integer myErrorStatus;
Standard_Boolean myIsDone;
Standard_Boolean myIsSplittable;
private:
};
#endif // _IntTools_ShrunkRange_HeaderFile