mirror of
https://git.dev.opencascade.org/repos/occt.git
synced 2025-04-10 18:51:21 +03:00
0030559: BOP Fuse: result is inconsistent
Implement alternative approach for making the edge seam (closed) on the face. This approach is useful for non-periodic surfaces (e.g. tore-like surface of revolution is periodic in U direction only). Avoid internal faces in the affected solids of the result of BOP Fuse.
This commit is contained in:
parent
b3bf8485a2
commit
d476fc37f8
@ -124,3 +124,6 @@ Unable to glue the shapes
|
|||||||
|
|
||||||
.BOPAlgo_AlertShapeIsNotPeriodic
|
.BOPAlgo_AlertShapeIsNotPeriodic
|
||||||
The shape is not periodic
|
The shape is not periodic
|
||||||
|
|
||||||
|
.BOPAlgo_AlertUnableToMakeClosedEdgeOnFace
|
||||||
|
Unable to make closed edge on face.
|
||||||
|
@ -138,4 +138,7 @@ DEFINE_ALERT_WITH_SHAPE(BOPAlgo_AlertUnableToGlue)
|
|||||||
//! The shape is not periodic
|
//! The shape is not periodic
|
||||||
DEFINE_ALERT_WITH_SHAPE(BOPAlgo_AlertShapeIsNotPeriodic)
|
DEFINE_ALERT_WITH_SHAPE(BOPAlgo_AlertShapeIsNotPeriodic)
|
||||||
|
|
||||||
|
//! Unable to make closed edge on face (to make a seam)
|
||||||
|
DEFINE_ALERT_WITH_SHAPE(BOPAlgo_AlertUnableToMakeClosedEdgeOnFace)
|
||||||
|
|
||||||
#endif // _BOPAlgo_Alerts_HeaderFile
|
#endif // _BOPAlgo_Alerts_HeaderFile
|
||||||
|
@ -60,8 +60,7 @@ static
|
|||||||
//
|
//
|
||||||
static
|
static
|
||||||
void MapFacesToBuildSolids(const TopoDS_Shape& theSol,
|
void MapFacesToBuildSolids(const TopoDS_Shape& theSol,
|
||||||
TopTools_IndexedDataMapOfShapeListOfShape& theMFS,
|
TopTools_IndexedDataMapOfShapeListOfShape& theMFS);
|
||||||
TopTools_IndexedMapOfShape& theMFI);
|
|
||||||
|
|
||||||
//=======================================================================
|
//=======================================================================
|
||||||
//function :
|
//function :
|
||||||
@ -1002,8 +1001,6 @@ void BOPAlgo_BOP::BuildSolid()
|
|||||||
TopTools_IndexedMapOfShape aMUSols;
|
TopTools_IndexedMapOfShape aMUSols;
|
||||||
// Use map to chose the most outer faces to build result solids
|
// Use map to chose the most outer faces to build result solids
|
||||||
aMFS.Clear();
|
aMFS.Clear();
|
||||||
// Internal faces
|
|
||||||
TopTools_IndexedMapOfShape aMFI;
|
|
||||||
//
|
//
|
||||||
TopoDS_Iterator aIt(myRC);
|
TopoDS_Iterator aIt(myRC);
|
||||||
for (; aIt.More(); aIt.Next()) {
|
for (; aIt.More(); aIt.Next()) {
|
||||||
@ -1015,7 +1012,7 @@ void BOPAlgo_BOP::BuildSolid()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
//
|
//
|
||||||
MapFacesToBuildSolids(aSx, aMFS, aMFI);
|
MapFacesToBuildSolids(aSx, aMFS);
|
||||||
} // for (; aIt.More(); aIt.Next()) {
|
} // for (; aIt.More(); aIt.Next()) {
|
||||||
//
|
//
|
||||||
// Process possibly untouched solids.
|
// Process possibly untouched solids.
|
||||||
@ -1035,7 +1032,7 @@ void BOPAlgo_BOP::BuildSolid()
|
|||||||
}
|
}
|
||||||
//
|
//
|
||||||
if (aExp.More()) {
|
if (aExp.More()) {
|
||||||
MapFacesToBuildSolids(aSx, aMFS, aMFI);
|
MapFacesToBuildSolids(aSx, aMFS);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
BOPTools_Set aST;
|
BOPTools_Set aST;
|
||||||
@ -1058,13 +1055,6 @@ void BOPAlgo_BOP::BuildSolid()
|
|||||||
aSFS.Append(aFx);
|
aSFS.Append(aFx);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Internal faces
|
|
||||||
aNb = aMFI.Extent();
|
|
||||||
for (i = 1; i <= aNb; ++i) {
|
|
||||||
TopoDS_Shape aFx = aMFI.FindKey(i);
|
|
||||||
aSFS.Append(aFx.Oriented(TopAbs_FORWARD));
|
|
||||||
aSFS.Append(aFx.Oriented(TopAbs_REVERSED));
|
|
||||||
}
|
|
||||||
//
|
//
|
||||||
TopoDS_Shape aRC;
|
TopoDS_Shape aRC;
|
||||||
BOPTools_AlgoTools::MakeContainer(TopAbs_COMPOUND, aRC);
|
BOPTools_AlgoTools::MakeContainer(TopAbs_COMPOUND, aRC);
|
||||||
@ -1073,6 +1063,7 @@ void BOPAlgo_BOP::BuildSolid()
|
|||||||
BOPAlgo_BuilderSolid aBS;
|
BOPAlgo_BuilderSolid aBS;
|
||||||
aBS.SetContext(myContext);
|
aBS.SetContext(myContext);
|
||||||
aBS.SetShapes(aSFS);
|
aBS.SetShapes(aSFS);
|
||||||
|
aBS.SetAvoidInternalShapes (Standard_True);
|
||||||
aBS.Perform();
|
aBS.Perform();
|
||||||
if (aBS.HasErrors()) {
|
if (aBS.HasErrors()) {
|
||||||
AddError (new BOPAlgo_AlertSolidBuilderFailed); // SolidBuilder failed
|
AddError (new BOPAlgo_AlertSolidBuilderFailed); // SolidBuilder failed
|
||||||
@ -1518,19 +1509,16 @@ Standard_Integer NbCommonItemsInMap(const TopTools_MapOfShape& theM1,
|
|||||||
//=======================================================================
|
//=======================================================================
|
||||||
//function : MapFacesToBuildSolids
|
//function : MapFacesToBuildSolids
|
||||||
//purpose : Stores the faces of the given solid into outgoing maps:
|
//purpose : Stores the faces of the given solid into outgoing maps:
|
||||||
// <theMFS> - not internal faces with reference to solid;
|
// <theMFS> - not internal faces with reference to solid.
|
||||||
// <theMFI> - internal faces.
|
|
||||||
//=======================================================================
|
//=======================================================================
|
||||||
void MapFacesToBuildSolids(const TopoDS_Shape& theSol,
|
void MapFacesToBuildSolids(const TopoDS_Shape& theSol,
|
||||||
TopTools_IndexedDataMapOfShapeListOfShape& theMFS,
|
TopTools_IndexedDataMapOfShapeListOfShape& theMFS)
|
||||||
TopTools_IndexedMapOfShape& theMFI)
|
|
||||||
{
|
{
|
||||||
TopExp_Explorer aExp(theSol, TopAbs_FACE);
|
TopExp_Explorer aExp(theSol, TopAbs_FACE);
|
||||||
for (; aExp.More(); aExp.Next()) {
|
for (; aExp.More(); aExp.Next()) {
|
||||||
const TopoDS_Shape& aF = aExp.Current();
|
const TopoDS_Shape& aF = aExp.Current();
|
||||||
//
|
//
|
||||||
if (aF.Orientation() == TopAbs_INTERNAL) {
|
if (aF.Orientation() == TopAbs_INTERNAL) {
|
||||||
theMFI.Add(aF);
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
//
|
//
|
||||||
|
@ -126,4 +126,7 @@ static const char BOPAlgo_BOPAlgo_msg[] =
|
|||||||
"Unable to glue the shapes\n"
|
"Unable to glue the shapes\n"
|
||||||
"\n"
|
"\n"
|
||||||
".BOPAlgo_AlertShapeIsNotPeriodic\n"
|
".BOPAlgo_AlertShapeIsNotPeriodic\n"
|
||||||
"The shape is not periodic\n";
|
"The shape is not periodic\n"
|
||||||
|
"\n"
|
||||||
|
".BOPAlgo_AlertUnableToMakeClosedEdgeOnFace\n"
|
||||||
|
"Unable to make closed edge on face.\n";
|
||||||
|
@ -17,6 +17,7 @@
|
|||||||
|
|
||||||
|
|
||||||
#include <BOPAlgo_Builder.hxx>
|
#include <BOPAlgo_Builder.hxx>
|
||||||
|
#include <BOPAlgo_Alerts.hxx>
|
||||||
#include <BOPAlgo_BuilderFace.hxx>
|
#include <BOPAlgo_BuilderFace.hxx>
|
||||||
#include <BOPAlgo_PaveFiller.hxx>
|
#include <BOPAlgo_PaveFiller.hxx>
|
||||||
#include <BOPAlgo_Tools.hxx>
|
#include <BOPAlgo_Tools.hxx>
|
||||||
@ -383,7 +384,18 @@ void BOPAlgo_Builder::BuildSplitFaces()
|
|||||||
if (bIsClosed) {
|
if (bIsClosed) {
|
||||||
if (aMFence.Add(aSp)) {
|
if (aMFence.Add(aSp)) {
|
||||||
if (!BRep_Tool::IsClosed(aSp, aF)){
|
if (!BRep_Tool::IsClosed(aSp, aF)){
|
||||||
BOPTools_AlgoTools3D::DoSplitSEAMOnFace(aSp, aF);
|
if (!BOPTools_AlgoTools3D::DoSplitSEAMOnFace(aSp, aF))
|
||||||
|
{
|
||||||
|
// try different approach
|
||||||
|
if (!BOPTools_AlgoTools3D::DoSplitSEAMOnFace(aE, aSp, aF))
|
||||||
|
{
|
||||||
|
TopoDS_Compound aWS;
|
||||||
|
BRep_Builder().MakeCompound (aWS);
|
||||||
|
BRep_Builder().Add (aWS, aF);
|
||||||
|
BRep_Builder().Add (aWS, aSp);
|
||||||
|
AddWarning (new BOPAlgo_AlertUnableToMakeClosedEdgeOnFace (aWS));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
//
|
//
|
||||||
aSp.Orientation(TopAbs_FORWARD);
|
aSp.Orientation(TopAbs_FORWARD);
|
||||||
|
@ -39,6 +39,7 @@
|
|||||||
#include <Geom_RectangularTrimmedSurface.hxx>
|
#include <Geom_RectangularTrimmedSurface.hxx>
|
||||||
#include <Geom_Surface.hxx>
|
#include <Geom_Surface.hxx>
|
||||||
#include <GeomAdaptor_Surface.hxx>
|
#include <GeomAdaptor_Surface.hxx>
|
||||||
|
#include <Geom2dAPI_ProjectPointOnCurve.hxx>
|
||||||
#include <gp_Cylinder.hxx>
|
#include <gp_Cylinder.hxx>
|
||||||
#include <gp_Dir.hxx>
|
#include <gp_Dir.hxx>
|
||||||
#include <gp_Dir2d.hxx>
|
#include <gp_Dir2d.hxx>
|
||||||
@ -72,7 +73,7 @@ static
|
|||||||
//function : DoSplitSEAMOnFace
|
//function : DoSplitSEAMOnFace
|
||||||
//purpose :
|
//purpose :
|
||||||
//=======================================================================
|
//=======================================================================
|
||||||
void BOPTools_AlgoTools3D::DoSplitSEAMOnFace (const TopoDS_Edge& aSplit,
|
Standard_Boolean BOPTools_AlgoTools3D::DoSplitSEAMOnFace (const TopoDS_Edge& aSplit,
|
||||||
const TopoDS_Face& aF)
|
const TopoDS_Face& aF)
|
||||||
{
|
{
|
||||||
Standard_Boolean bIsUPeriodic, bIsVPeriodic, bIsLeft;
|
Standard_Boolean bIsUPeriodic, bIsVPeriodic, bIsLeft;
|
||||||
@ -131,7 +132,7 @@ void BOPTools_AlgoTools3D::DoSplitSEAMOnFace (const TopoDS_Edge& aSplit,
|
|||||||
bIsVPeriodic=aSB->IsVPeriodic();
|
bIsVPeriodic=aSB->IsVPeriodic();
|
||||||
//
|
//
|
||||||
if (!(bIsUPeriodic || bIsVPeriodic)) {
|
if (!(bIsUPeriodic || bIsVPeriodic)) {
|
||||||
return;
|
return Standard_False;
|
||||||
}
|
}
|
||||||
anUPeriod = bIsUPeriodic ? aSB->UPeriod() : 0.;
|
anUPeriod = bIsUPeriodic ? aSB->UPeriod() : 0.;
|
||||||
anVPeriod = bIsVPeriodic ? aSB->VPeriod() : 0.;
|
anVPeriod = bIsVPeriodic ? aSB->VPeriod() : 0.;
|
||||||
@ -139,7 +140,7 @@ void BOPTools_AlgoTools3D::DoSplitSEAMOnFace (const TopoDS_Edge& aSplit,
|
|||||||
//
|
//
|
||||||
if (aRTS.IsNull()) {
|
if (aRTS.IsNull()) {
|
||||||
if (!bIsUClosed && !bIsVClosed) {
|
if (!bIsUClosed && !bIsVClosed) {
|
||||||
return;
|
return Standard_False;
|
||||||
}
|
}
|
||||||
//
|
//
|
||||||
if (bIsUClosed) {
|
if (bIsUClosed) {
|
||||||
@ -191,7 +192,7 @@ void BOPTools_AlgoTools3D::DoSplitSEAMOnFace (const TopoDS_Edge& aSplit,
|
|||||||
}
|
}
|
||||||
//
|
//
|
||||||
if (anU1==anU && anV1==anV) {
|
if (anU1==anU && anV1==anV) {
|
||||||
return;
|
return Standard_False;
|
||||||
}
|
}
|
||||||
//
|
//
|
||||||
aScPr = (anU1==anU) ? aDir2D1*aDOX : aDir2D1*aDOY;
|
aScPr = (anU1==anU) ? aDir2D1*aDOX : aDir2D1*aDOY;
|
||||||
@ -222,7 +223,96 @@ void BOPTools_AlgoTools3D::DoSplitSEAMOnFace (const TopoDS_Edge& aSplit,
|
|||||||
BB.UpdateEdge(aSp, aC2, aC1, aF, aTol);
|
BB.UpdateEdge(aSp, aC2, aC1, aF, aTol);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return Standard_True;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//=======================================================================
|
||||||
|
//function : DoSplitSEAMOnFace
|
||||||
|
//purpose :
|
||||||
|
//=======================================================================
|
||||||
|
Standard_Boolean BOPTools_AlgoTools3D::DoSplitSEAMOnFace (const TopoDS_Edge& theEOrigin,
|
||||||
|
const TopoDS_Edge& theESplit,
|
||||||
|
const TopoDS_Face& theFace)
|
||||||
|
{
|
||||||
|
if (!BRep_Tool::IsClosed (theEOrigin, theFace))
|
||||||
|
return Standard_False;
|
||||||
|
|
||||||
|
if (BRep_Tool::IsClosed (theESplit, theFace))
|
||||||
|
return Standard_True;
|
||||||
|
|
||||||
|
TopoDS_Edge aESplit = theESplit;
|
||||||
|
aESplit.Orientation (TopAbs_FORWARD);
|
||||||
|
|
||||||
|
TopoDS_Face aFace = theFace;
|
||||||
|
aFace.Orientation (TopAbs_FORWARD);
|
||||||
|
|
||||||
|
Standard_Real aTS1, aTS2;
|
||||||
|
Handle(Geom2d_Curve) aC2DSplit = BRep_Tool::CurveOnSurface (aESplit, aFace, aTS1, aTS2);
|
||||||
|
if (aC2DSplit.IsNull())
|
||||||
|
return Standard_False;
|
||||||
|
|
||||||
|
Standard_Real aT1, aT2;
|
||||||
|
Handle(Geom2d_Curve) aC2D1 = BRep_Tool::CurveOnSurface (
|
||||||
|
TopoDS::Edge (theEOrigin.Oriented (TopAbs_FORWARD)), aFace, aT1, aT2);
|
||||||
|
Handle(Geom2d_Curve) aC2D2 = BRep_Tool::CurveOnSurface (
|
||||||
|
TopoDS::Edge (theEOrigin.Oriented (TopAbs_REVERSED)), aFace, aT1, aT2);
|
||||||
|
|
||||||
|
Standard_Real aT = BOPTools_AlgoTools2D::IntermediatePoint (aTS1, aTS2);
|
||||||
|
gp_Pnt2d aPMid;
|
||||||
|
gp_Vec2d aVTgt;
|
||||||
|
aC2DSplit->D1 (aT, aPMid, aVTgt);
|
||||||
|
|
||||||
|
// project on original 2d curves
|
||||||
|
Geom2dAPI_ProjectPointOnCurve aProjPC1, aProjPC2;
|
||||||
|
aProjPC1.Init (aPMid, aC2D1, aT1, aT2);
|
||||||
|
aProjPC2.Init (aPMid, aC2D2, aT1, aT2);
|
||||||
|
|
||||||
|
if (!aProjPC1.NbPoints() && !aProjPC2.NbPoints())
|
||||||
|
return Standard_False;
|
||||||
|
|
||||||
|
Standard_Real aDist1 = aProjPC1.NbPoints() ? aProjPC1.LowerDistance() : RealLast();
|
||||||
|
Standard_Real aDist2 = aProjPC2.NbPoints() ? aProjPC2.LowerDistance() : RealLast();
|
||||||
|
|
||||||
|
if (aDist1 > Precision::PConfusion() && aDist2 > Precision::PConfusion())
|
||||||
|
return Standard_False;
|
||||||
|
|
||||||
|
// choose the closest and take corresponding point from the opposite
|
||||||
|
gp_Pnt2d aNewPnt = aDist1 < aDist2 ? aC2D2->Value (aProjPC1.LowerDistanceParameter()) :
|
||||||
|
aC2D1->Value (aProjPC2.LowerDistanceParameter());
|
||||||
|
|
||||||
|
Handle (Geom2d_Curve) aTmpC1 = Handle (Geom2d_Curve)::DownCast (aC2DSplit->Copy());
|
||||||
|
Handle (Geom2d_Curve) aTmpC2 = Handle (Geom2d_Curve)::DownCast (aC2DSplit->Copy());
|
||||||
|
|
||||||
|
Handle (Geom2d_TrimmedCurve) aC1 = new Geom2d_TrimmedCurve (aTmpC1, aTS1, aTS2);
|
||||||
|
Handle (Geom2d_TrimmedCurve) aC2 = new Geom2d_TrimmedCurve (aTmpC2, aTS1, aTS2);
|
||||||
|
|
||||||
|
gp_Vec2d aTrVec (aPMid, aNewPnt);
|
||||||
|
aC2->Translate (aTrVec);
|
||||||
|
|
||||||
|
gp_Pnt2d aPProj;
|
||||||
|
gp_Vec2d aVTgtOrigin;
|
||||||
|
if (aDist1 < aDist2)
|
||||||
|
{
|
||||||
|
aC2D1->D1 (aProjPC1.LowerDistanceParameter(), aPProj, aVTgtOrigin);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
aC2D2->D1 (aProjPC2.LowerDistanceParameter(), aPProj, aVTgtOrigin);
|
||||||
|
}
|
||||||
|
|
||||||
|
Standard_Real aDot = aVTgt.Dot (aVTgtOrigin);
|
||||||
|
|
||||||
|
if ((aDist1 < aDist2) == (aDot > 0))
|
||||||
|
{
|
||||||
|
BRep_Builder().UpdateEdge (aESplit, aC1, aC2, aFace, BRep_Tool::Tolerance (aESplit));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
BRep_Builder().UpdateEdge (aESplit, aC2, aC1, aFace, BRep_Tool::Tolerance (aESplit));
|
||||||
|
}
|
||||||
|
return Standard_True;
|
||||||
|
}
|
||||||
|
|
||||||
//=======================================================================
|
//=======================================================================
|
||||||
//function : GetNormalToFaceOnEdge
|
//function : GetNormalToFaceOnEdge
|
||||||
//purpose :
|
//purpose :
|
||||||
|
@ -43,11 +43,15 @@ public:
|
|||||||
|
|
||||||
DEFINE_STANDARD_ALLOC
|
DEFINE_STANDARD_ALLOC
|
||||||
|
|
||||||
|
//! Makes the edge <theESplit> seam edge for the face <theFace> basing on the surface properties (U and V periods)
|
||||||
|
Standard_EXPORT static Standard_Boolean DoSplitSEAMOnFace (const TopoDS_Edge& theESplit,
|
||||||
|
const TopoDS_Face& theFace);
|
||||||
|
|
||||||
|
//! Makes the split edge <theESplit> seam edge for the face <theFace> basing on the positions
|
||||||
//! Make the edge <aSp> seam edge for the face <aF>
|
//! of 2d curves of the original edge <theEOrigin>.
|
||||||
Standard_EXPORT static void DoSplitSEAMOnFace (const TopoDS_Edge& aSp,
|
Standard_EXPORT static Standard_Boolean DoSplitSEAMOnFace (const TopoDS_Edge& theEOrigin,
|
||||||
const TopoDS_Face& aF);
|
const TopoDS_Edge& theESplit,
|
||||||
|
const TopoDS_Face& theFace);
|
||||||
|
|
||||||
//! Computes normal to the face <aF> for the point on the edge <aE>
|
//! Computes normal to the face <aF> for the point on the edge <aE>
|
||||||
//! at parameter <aT>.<br>
|
//! at parameter <aT>.<br>
|
||||||
|
@ -24,6 +24,6 @@ puts "Finish boolean operation ..."
|
|||||||
checkprops result -s 87449.7
|
checkprops result -s 87449.7
|
||||||
checkshape result
|
checkshape result
|
||||||
|
|
||||||
checknbshapes result -vertex 17 -edge 25 -wire 14 -face 10 -shell 2 -solid 1 -compsolid 0 -compound 1 -shape 70
|
checknbshapes result -vertex 17 -edge 24 -wire 13 -face 9 -shell 1 -solid 1
|
||||||
|
|
||||||
checkview -display result -2d -path ${imagedir}/${test_image}.png
|
checkview -display result -2d -path ${imagedir}/${test_image}.png
|
||||||
|
25
tests/bugs/modalg_7/bug30559
Normal file
25
tests/bugs/modalg_7/bug30559
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
puts "TODO CR29596 ALL: Warning: Intersection of pair of shapes has failed"
|
||||||
|
|
||||||
|
puts "============================================================================================="
|
||||||
|
puts "0030559: BOP Fuse: result is inconsistent"
|
||||||
|
puts "============================================================================================="
|
||||||
|
puts ""
|
||||||
|
|
||||||
|
restore [locate_data_file bug30559_VALVE_1_of_BRANCH_6028_B3.brep] a
|
||||||
|
set exp [explode a So]
|
||||||
|
bclearobjects
|
||||||
|
bcleartools
|
||||||
|
baddobjects a_1
|
||||||
|
eval baddtools [lrange $exp 1 end]
|
||||||
|
bfillds
|
||||||
|
bbop result 1
|
||||||
|
|
||||||
|
checkshape result
|
||||||
|
checknbshapes result -wire 26 -face 20 -shell 1 -solid 1
|
||||||
|
checkprops result -s 456495 -v 1.2165e+07
|
||||||
|
|
||||||
|
if {![regexp "This shape seems to be OK" [bopcheck result]]} {
|
||||||
|
puts "Error: result is self-interfered shape"
|
||||||
|
}
|
||||||
|
|
||||||
|
checkview -display result -2d -path ${imagedir}/${test_image}.png
|
Loading…
x
Reference in New Issue
Block a user