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

0027035: General fuse algorithm loses face

Porting the fix for issue #27035 to OCCT 6.8.0.

(cherry picked from commit f6f844dc652a256f1aa73c92fea2cf2756bea348)
(cherry picked from commit 6dd894d85532a447fd54f59c4504ddd76a99b658)

Addition correction in order to avoid compiler warnings/errors.
This commit is contained in:
nbv
2016-02-17 10:31:18 +03:00
parent 82b4c24940
commit b03b81ff37
7 changed files with 493 additions and 9 deletions

View File

@@ -59,6 +59,7 @@
#include <BOPTools_ListOfCoupleOfShape.hxx>
#include <BOPTools_MapOfSet.hxx>
#include <BOPTools_DataMapOfShapeSet.hxx>
#include <GeomLib.hxx>
static
@@ -284,6 +285,9 @@ void BOPAlgo_Builder::BuildSplitFaces()
}
//
const TopoDS_Face& aF=(*(TopoDS_Face*)(&aSI.Shape()));
Standard_Boolean isUClosed = Standard_False,
isVClosed = Standard_False,
isChecked = Standard_False;
//
bHasFaceInfo=myDS->HasFaceInfo(i);
if(!bHasFaceInfo) {
@@ -321,8 +325,6 @@ void BOPAlgo_Builder::BuildSplitFaces()
for (; aExp.More(); aExp.Next()) {
const TopoDS_Edge& aE=(*(TopoDS_Edge*)(&aExp.Current()));
anOriE=aE.Orientation();
bIsDegenerated=BRep_Tool::Degenerated(aE);
bIsClosed=BRep_Tool::IsClosed(aE, aF);
//
if (!myImages.IsBound(aE)) {
if (anOriE==TopAbs_INTERNAL) {
@@ -335,8 +337,32 @@ void BOPAlgo_Builder::BuildSplitFaces()
else {
aLE.Append(aE);
}
continue;
}
else {//else 1
if(!isChecked)
{
const Handle(Geom_Surface) aSurf = BRep_Tool::Surface(aF);
GeomLib::IsClosed(aSurf, BRep_Tool::Tolerance(aE),
isUClosed, isVClosed);
isChecked = Standard_True;
}
bIsClosed = Standard_False;
if((isUClosed || isVClosed) && BRep_Tool::IsClosed(aE, aF))
{
Standard_Boolean isUIso = Standard_False, isVIso = Standard_False;
BOPTools_AlgoTools2D::IsEdgeIsoline(aE, aF, isUIso, isVIso);
bIsClosed = ((isUClosed && isUIso) || (isVClosed && isVIso));
}
bIsDegenerated=BRep_Tool::Degenerated(aE);
const BOPCol_ListOfShape& aLIE=myImages.Find(aE);
aIt.Initialize(aLIE);
for (; aIt.More(); aIt.Next()) {
@@ -376,7 +402,6 @@ void BOPAlgo_Builder::BuildSplitFaces()
}
aLE.Append(aSp);
}// for (; aIt.More(); aIt.Next()) {
}// else 1
}// for (; aExp.More(); aExp.Next()) {
//
//

View File

@@ -197,4 +197,12 @@ is
--- Make empty P-Curve <aC> of relevant to <PC> type
---
IsEdgeIsoline(myclass;
theE: Edge from TopoDS;
theF: Face from TopoDS;
isTheUIso, isTheVIso: in out Boolean from Standard);
--- Purpose: Checks if CurveOnSurface of theE on theF matches with
-- isoline of theF surface. Sets corresponding values for
-- isTheUIso and isTheVIso variables.
end AlgoTools2D;

View File

@@ -833,3 +833,39 @@ Standard_Real MaxToleranceEdge (const TopoDS_Face& aF)
}
return aTolMax;
}
//=======================================================================
//function : IsEdgeIsoline
//purpose :
//=======================================================================
void BOPTools_AlgoTools2D::IsEdgeIsoline( const TopoDS_Edge& theE,
const TopoDS_Face& theF,
Standard_Boolean& isTheUIso,
Standard_Boolean& isTheVIso)
{
isTheUIso = isTheVIso = Standard_False;
gp_Vec2d aT;
gp_Pnt2d aP;
Standard_Real aFirst = 0.0, aLast = 0.0;
const Handle(Geom2d_Curve) aPC = BRep_Tool::CurveOnSurface(theE, theF, aFirst, aLast);
aPC->D1(0.5*(aFirst+aLast), aP, aT);
const Standard_Real aSqMagn = aT.SquareMagnitude();
if(aSqMagn <= gp::Resolution())
return;
//Normalyze aT
aT /= sqrt(aSqMagn);
//sin(da) ~ da, when da->0.
const Standard_Real aTol = Precision::Angular();
const gp_Vec2d aRefVDir(0.0, 1.0), aRefUDir(1.0, 0.0);
const Standard_Real aDPv = aT.CrossMagnitude(aRefVDir),
aDPu = aT.CrossMagnitude(aRefUDir);
isTheUIso = (aDPv <= aTol);
isTheVIso = (aDPu <= aTol);
}

View File

@@ -288,6 +288,35 @@ is
-- 2 for conical singular point
-- 3 if computation impossible (for ex. DU||DV - tangent isolines)
IsClosed(S: Surface from Geom ; Tol: Real from Standard;
isUClosed, isVClosed: in out Boolean from Standard);
--- Purpose: This method defines if opposite boundaries of surface
-- coincide with given tolerance
IsBSplUClosed(S: BSplineSurface from Geom; U1, U2, Tol: Real from Standard)
returns Boolean from Standard;
--- Purpose: Returns true if the poles of U1-isoline and the poles of
-- U2-isoline of surface are identical according to tolerance criterion.
-- For rational surfaces Weights(i)*Poles(i) are checked.
IsBSplVClosed(S: BSplineSurface from Geom; V1, V2, Tol: Real from Standard)
returns Boolean from Standard;
--- Purpose: Returns true if the poles of V1-isoline and the poles of
-- V2-isoline of surface are identical according to tolerance criterion.
-- For rational surfaces Weights(i)*Poles(i) are checked.
IsBzUClosed(S: BezierSurface from Geom; U1, U2, Tol: Real from Standard)
returns Boolean from Standard;
--- Purpose: Returns true if the poles of U1-isoline and the poles of
-- U2-isoline of surface are identical according to tolerance criterion.
IsBzVClosed(S: BezierSurface from Geom; V1, V2, Tol: Real from Standard)
returns Boolean from Standard;
--- Purpose: Returns true if the poles of V1-isoline and the poles of
-- V2-isoline of surface are identical according to tolerance criterion.
end GeomLib;

View File

@@ -138,6 +138,12 @@
#include <Standard_ConstructionError.hxx>
static Standard_Boolean CompareWeightPoles(const TColgp_Array1OfPnt& thePoles1,
const TColStd_Array1OfReal* const theW1,
const TColgp_Array1OfPnt& thePoles2,
const TColStd_Array1OfReal* const theW2,
const Standard_Real theTol);
//=======================================================================
//function : ComputeLambda
//purpose : Calcul le facteur lambda qui minimise la variation de vittesse
@@ -2439,4 +2445,358 @@ Standard_Integer GeomLib::NormEstim(const Handle(Geom_Surface)& S,
return 3;
}
//=======================================================================
//function : IsClosed
//purpose :
//=======================================================================
void GeomLib::IsClosed (const Handle(Geom_Surface)& S,
const Standard_Real Tol,
Standard_Boolean& isUClosed, Standard_Boolean& isVClosed)
{
isUClosed = Standard_False;
isVClosed = Standard_False;
//
GeomAdaptor_Surface aGAS(S);
GeomAbs_SurfaceType aSType = aGAS.GetType();
//
Standard_Real Tol2 = Tol * Tol;
switch (aSType)
{
case GeomAbs_Plane:
{
return;
}
case GeomAbs_Cylinder:
case GeomAbs_SurfaceOfExtrusion:
{
Standard_Real u1 = aGAS.FirstUParameter(), u2 = aGAS.LastUParameter();
Standard_Real v1 = aGAS.FirstVParameter();
if(Precision::IsInfinite(v1))
v1 = 0.;
gp_Pnt p1 = aGAS.Value(u1, v1);
gp_Pnt p2 = aGAS.Value(u2, v1);
isUClosed = p1.SquareDistance(p2) <= Tol2;
return;
}
case GeomAbs_Cone:
{
Standard_Real u1 = aGAS.FirstUParameter(), u2 = aGAS.LastUParameter();
Standard_Real v1 = aGAS.FirstVParameter(), v2 = aGAS.LastVParameter();
//find v with maximal distance from axis
if(!(Precision::IsInfinite(v1) || Precision::IsInfinite(v2)))
{
gp_Cone aCone = aGAS.Cone();
gp_Pnt anApex = aCone.Apex();
gp_Pnt P1 = aGAS.Value(u1, v1);
gp_Pnt P2 = aGAS.Value(u1, v2);
if(P2.SquareDistance(anApex) > P1.SquareDistance(anApex))
{
v1 = v2;
}
}
else
{
v1 = 0.;
}
gp_Pnt p1 = aGAS.Value(u1, v1);
gp_Pnt p2 = aGAS.Value(u2, v1);
isUClosed = p1.SquareDistance(p2) <= Tol2;
return;
}
case GeomAbs_Sphere:
{
Standard_Real u1 = aGAS.FirstUParameter(), u2 = aGAS.LastUParameter();
Standard_Real v1 = aGAS.FirstVParameter(), v2 = aGAS.LastVParameter();
//find v with maximal distance from axis
if(v1*v2 <= 0.)
{
v1 = 0.;
}
else
{
if(v1 < 0.)
{
v1 = v2;
}
}
gp_Pnt p1 = aGAS.Value(u1, v1);
gp_Pnt p2 = aGAS.Value(u2, v1);
isUClosed = p1.SquareDistance(p2) <= Tol2;
return;
}
case GeomAbs_Torus:
{
Standard_Real ures = aGAS.UResolution(Tol);
Standard_Real vres = aGAS.VResolution(Tol);
Standard_Real u1 = aGAS.FirstUParameter(), u2 = aGAS.LastUParameter();
Standard_Real v1 = aGAS.FirstVParameter(), v2 = aGAS.LastVParameter();
//
isUClosed = (u2 - u1) >= aGAS.UPeriod() - ures;
isVClosed = (v2 - v1) >= aGAS.VPeriod() - vres;
return;
}
case GeomAbs_BSplineSurface:
{
Standard_Real u1 = aGAS.FirstUParameter(), u2 = aGAS.LastUParameter();
Standard_Real v1 = aGAS.FirstVParameter(), v2 = aGAS.LastVParameter();
Handle(Geom_BSplineSurface) aBSpl = aGAS.BSpline();
isUClosed = GeomLib::IsBSplUClosed(aBSpl, u1, u2, Tol);
isVClosed = GeomLib::IsBSplVClosed(aBSpl, v1, v2, Tol);
return;
}
case GeomAbs_BezierSurface:
{
Standard_Real u1 = aGAS.FirstUParameter(), u2 = aGAS.LastUParameter();
Standard_Real v1 = aGAS.FirstVParameter(), v2 = aGAS.LastVParameter();
Handle(Geom_BezierSurface) aBz = aGAS.Bezier();
isUClosed = GeomLib::IsBzUClosed(aBz, u1, u2, Tol);
isVClosed = GeomLib::IsBzVClosed(aBz, v1, v2, Tol);
return;
}
case GeomAbs_SurfaceOfRevolution:
case GeomAbs_OffsetSurface:
case GeomAbs_OtherSurface:
{
Standard_Integer nbp = 23;
Standard_Real u1 = aGAS.FirstUParameter(), u2 = aGAS.LastUParameter();
Standard_Real v1 = aGAS.FirstVParameter(), v2 = aGAS.LastVParameter();
if(Precision::IsInfinite(v1))
{
v1 = Sign(1., v1);
}
if(Precision::IsInfinite(v2))
{
v2 = Sign(1., v2);
}
//
if(aSType == GeomAbs_OffsetSurface ||
aSType == GeomAbs_OtherSurface)
{
if(Precision::IsInfinite(u1))
{
u1 = Sign(1., u1);
}
if(Precision::IsInfinite(u2))
{
u2 = Sign(1., u2);
}
}
isUClosed = Standard_True;
Standard_Real dt = (v2 - v1) / (nbp - 1);
Standard_Real res = Max(aGAS.UResolution(Tol), Precision::PConfusion());
if(dt <= res)
{
nbp = RealToInt((v2 - v1) /(2.*res)) + 1;
nbp = Max(nbp, 2);
dt = (v2 - v1) / (nbp - 1);
}
Standard_Real t;
Standard_Integer i;
for(i = 0; i < nbp; ++i)
{
t = (i == nbp-1 ? v2 : v1 + i * dt);
gp_Pnt p1 = aGAS.Value(u1, t);
gp_Pnt p2 = aGAS.Value(u2, t);
if(p1.SquareDistance(p2) > Tol2)
{
isUClosed = Standard_False;
break;
}
}
//
nbp = 23;
isVClosed = Standard_True;
dt = (u2 - u1) / (nbp - 1);
res = Max(aGAS.VResolution(Tol), Precision::PConfusion());
if(dt <= res)
{
nbp = RealToInt((u2 - u1) /(2.*res)) + 1;
nbp = Max(nbp, 2);
dt = (u2 - u1) / (nbp - 1);
}
for(i = 0; i < nbp; ++i)
{
t = (i == nbp-1 ? u2 : u1 + i * dt);
gp_Pnt p1 = aGAS.Value(t, v1);
gp_Pnt p2 = aGAS.Value(t, v2);
if(p1.SquareDistance(p2) > Tol2)
{
isVClosed = Standard_False;
break;
}
}
return;
}
default:
{
return;
}
}
}
//=======================================================================
//function : IsBSplUClosed
//purpose :
//=======================================================================
Standard_Boolean GeomLib::IsBSplUClosed (const Handle(Geom_BSplineSurface)& S,
const Standard_Real U1,
const Standard_Real U2,
const Standard_Real Tol)
{
Handle(Geom_Curve) aCUF = S->UIso( U1 );
Handle(Geom_Curve) aCUL = S->UIso( U2 );
if(aCUF.IsNull() || aCUL.IsNull())
return Standard_False;
Standard_Real Tol2 = 2.*Tol;
Handle(Geom_BSplineCurve) aBsF = Handle(Geom_BSplineCurve)::DownCast(aCUF);
Handle(Geom_BSplineCurve) aBsL = Handle(Geom_BSplineCurve)::DownCast(aCUL);
TColgp_Array1OfPnt aPF(1, aBsF->NbPoles()), aPL(1, aBsL->NbPoles());
aBsF->Poles(aPF);
aBsL->Poles(aPL);
TColStd_Array1OfReal *aWF = 0, *aWL = 0;
if(aBsF->IsRational())
{
aWF = new TColStd_Array1OfReal(aPF.Lower(), aPF.Upper());
aBsF->Weights(*aWF);
}
if(aBsL->IsRational())
{
aWL = new TColStd_Array1OfReal(aPL.Lower(), aPL.Upper());
aBsL->Weights(*aWL);
}
const Standard_Boolean aRetVal = CompareWeightPoles(aPF, aWF, aPL, aWL, Tol2);
if(aWF)
delete aWF;
if(aWL)
delete aWL;
return aRetVal;
}
//=======================================================================
//function : IsBSplVClosed
//purpose :
//=======================================================================
Standard_Boolean GeomLib::IsBSplVClosed (const Handle(Geom_BSplineSurface)& S,
const Standard_Real V1,
const Standard_Real V2,
const Standard_Real Tol)
{
Handle(Geom_Curve) aCVF = S->VIso( V1 );
Handle(Geom_Curve) aCVL = S->VIso( V2 );
if(aCVF.IsNull() || aCVL.IsNull())
return Standard_False;
Standard_Real Tol2 = 2.*Tol;
Handle(Geom_BSplineCurve) aBsF = Handle(Geom_BSplineCurve)::DownCast(aCVF);
Handle(Geom_BSplineCurve) aBsL = Handle(Geom_BSplineCurve)::DownCast(aCVL);
TColgp_Array1OfPnt aPF(1, aBsF->NbPoles()), aPL(1, aBsL->NbPoles());
aBsF->Poles(aPF);
aBsL->Poles(aPL);
TColStd_Array1OfReal *aWF = 0, *aWL = 0;
if(aBsF->IsRational())
{
aWF = new TColStd_Array1OfReal(aPF.Lower(), aPF.Upper());
aBsF->Weights(*aWF);
}
if(aBsL->IsRational())
{
aWL = new TColStd_Array1OfReal(aPL.Lower(), aPL.Upper());
aBsL->Weights(*aWL);
}
const Standard_Boolean aRetVal = CompareWeightPoles(aPF, aWF, aPL, aWL, Tol2);
if(aWF)
delete aWF;
if(aWL)
delete aWL;
return aRetVal;
}
//=======================================================================
//function : IsBzUClosed
//purpose :
//=======================================================================
Standard_Boolean GeomLib::IsBzUClosed (const Handle(Geom_BezierSurface)& S,
const Standard_Real U1,
const Standard_Real U2,
const Standard_Real Tol)
{
Handle(Geom_Curve) aCUF = S->UIso( U1 );
Handle(Geom_Curve) aCUL = S->UIso( U2 );
if(aCUF.IsNull() || aCUL.IsNull())
return Standard_False;
Standard_Real Tol2 = 2.*Tol;
Handle(Geom_BezierCurve) aBzF = Handle(Geom_BezierCurve)::DownCast(aCUF);
Handle(Geom_BezierCurve) aBzL = Handle(Geom_BezierCurve)::DownCast(aCUL);
TColgp_Array1OfPnt aPF(1, aBzF->NbPoles()), aPL(1, aBzL->NbPoles());
aBzF->Poles(aPF);
aBzL->Poles(aPL);
//
return CompareWeightPoles(aPF, 0, aPL, 0, Tol2);
}
//=======================================================================
//function : IsBzVClosed
//purpose :
//=======================================================================
Standard_Boolean GeomLib::IsBzVClosed (const Handle(Geom_BezierSurface)& S,
const Standard_Real V1,
const Standard_Real V2,
const Standard_Real Tol)
{
Handle(Geom_Curve) aCVF = S->VIso( V1 );
Handle(Geom_Curve) aCVL = S->VIso( V2 );
if(aCVF.IsNull() || aCVL.IsNull())
return Standard_False;
Standard_Real Tol2 = 2.*Tol;
Handle(Geom_BezierCurve) aBzF = Handle(Geom_BezierCurve)::DownCast(aCVF);
Handle(Geom_BezierCurve) aBzL = Handle(Geom_BezierCurve)::DownCast(aCVL);
TColgp_Array1OfPnt aPF(1, aBzF->NbPoles()), aPL(1, aBzL->NbPoles());
aBzF->Poles(aPF);
aBzL->Poles(aPL);
//
return CompareWeightPoles(aPF, 0, aPL, 0, Tol2);
}
//=======================================================================
//function : CompareWeightPoles
//purpose : Checks if thePoles1(i)*theW1(i) is equal to thePoles2(i)*theW2(i)
// with tolerance theTol.
// It is necessary for not rational B-splines and Bezier curves
// to set theW1 and theW2 adresses to zero.
//=======================================================================
static Standard_Boolean CompareWeightPoles(const TColgp_Array1OfPnt& thePoles1,
const TColStd_Array1OfReal* const theW1,
const TColgp_Array1OfPnt& thePoles2,
const TColStd_Array1OfReal* const theW2,
const Standard_Real theTol)
{
if(thePoles1.Length() != thePoles2.Length())
{
return Standard_False;
}
//
Standard_Integer i = 1;
for( i = 1 ; i <= thePoles1.Length(); i++ )
{
const Standard_Real aW1 = (theW1 == 0) ? 1.0 : theW1->Value(i);
const Standard_Real aW2 = (theW2 == 0) ? 1.0 : theW2->Value(i);
gp_XYZ aPole1 = thePoles1.Value(i).XYZ() * aW1;
gp_XYZ aPole2 = thePoles2.Value(i).XYZ() * aW2;
if(!aPole1.IsEqual(aPole2, theTol))
return Standard_False;
}
//
return Standard_True;
}

View File

@@ -1,7 +1,6 @@
#puts "TODO OCC12345 ALL: Faulty shapes in variables faulty_1 to faulty_"
#puts "TODO OCC12345 ALL: Error : The square of result shape is"
puts "TODO OCC12345 ALL: Error : The command is not valid"
puts "TODO OCC12345 ALL: Error : Result shape is WRONG because it must contains"
puts "TODO OCC25917 ALL: Faulty shapes in variables faulty_1 to faulty_"
puts "TODO OCC25917 ALL: Error : The square of result shape"
puts "TODO OCC25917 ALL: Error : Result shape is WRONG"
puts "========================"
puts " OCC472 "
@@ -22,6 +21,6 @@ bfuse result b1 b2
set nb_v_good 5
set nb_e_edge 7
set square 0
set square 229.516
set 2dviewer 0

View File

@@ -0,0 +1,27 @@
puts "========"
puts "OCC27035"
puts "========"
puts ""
###########################################################################
# General fuse algorithm loses face
###########################################################################
restore [locate_data_file bug27035_cmpd.brep] a
explode a
bclearobjects
bcleartools
baddobjects a_1 a_2
bfillds
bbuild result
set nb_w_good 2
set nb_f_good 2
donly result
fit
set 2dviewer 1