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.
.BOPAlgo_AlertShapeIsNotPeriodic
The shape is not periodic
+
+.BOPAlgo_AlertUnableToMakeClosedEdgeOnFace
+Unable to make closed edge on face.
//! The shape is not periodic
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
//
static
void MapFacesToBuildSolids(const TopoDS_Shape& theSol,
- TopTools_IndexedDataMapOfShapeListOfShape& theMFS,
- TopTools_IndexedMapOfShape& theMFI);
+ TopTools_IndexedDataMapOfShapeListOfShape& theMFS);
//=======================================================================
//function :
TopTools_IndexedMapOfShape aMUSols;
// Use map to chose the most outer faces to build result solids
aMFS.Clear();
- // Internal faces
- TopTools_IndexedMapOfShape aMFI;
//
TopoDS_Iterator aIt(myRC);
for (; aIt.More(); aIt.Next()) {
}
}
//
- MapFacesToBuildSolids(aSx, aMFS, aMFI);
+ MapFacesToBuildSolids(aSx, aMFS);
} // for (; aIt.More(); aIt.Next()) {
//
// Process possibly untouched solids.
}
//
if (aExp.More()) {
- MapFacesToBuildSolids(aSx, aMFS, aMFI);
+ MapFacesToBuildSolids(aSx, aMFS);
}
else {
BOPTools_Set aST;
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;
BOPTools_AlgoTools::MakeContainer(TopAbs_COMPOUND, aRC);
BOPAlgo_BuilderSolid aBS;
aBS.SetContext(myContext);
aBS.SetShapes(aSFS);
+ aBS.SetAvoidInternalShapes (Standard_True);
aBS.Perform();
if (aBS.HasErrors()) {
AddError (new BOPAlgo_AlertSolidBuilderFailed); // SolidBuilder failed
//=======================================================================
//function : MapFacesToBuildSolids
//purpose : Stores the faces of the given solid into outgoing maps:
-// <theMFS> - not internal faces with reference to solid;
-// <theMFI> - internal faces.
+// <theMFS> - not internal faces with reference to solid.
//=======================================================================
void MapFacesToBuildSolids(const TopoDS_Shape& theSol,
- TopTools_IndexedDataMapOfShapeListOfShape& theMFS,
- TopTools_IndexedMapOfShape& theMFI)
+ TopTools_IndexedDataMapOfShapeListOfShape& theMFS)
{
TopExp_Explorer aExp(theSol, TopAbs_FACE);
for (; aExp.More(); aExp.Next()) {
const TopoDS_Shape& aF = aExp.Current();
//
if (aF.Orientation() == TopAbs_INTERNAL) {
- theMFI.Add(aF);
continue;
}
//
"Unable to glue the shapes\n"
"\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";
#include <BOPAlgo_Builder.hxx>
+#include <BOPAlgo_Alerts.hxx>
#include <BOPAlgo_BuilderFace.hxx>
#include <BOPAlgo_PaveFiller.hxx>
#include <BOPAlgo_Tools.hxx>
if (bIsClosed) {
if (aMFence.Add(aSp)) {
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);
#include <Geom_RectangularTrimmedSurface.hxx>
#include <Geom_Surface.hxx>
#include <GeomAdaptor_Surface.hxx>
+#include <Geom2dAPI_ProjectPointOnCurve.hxx>
#include <gp_Cylinder.hxx>
#include <gp_Dir.hxx>
#include <gp_Dir2d.hxx>
//function : DoSplitSEAMOnFace
//purpose :
//=======================================================================
-void BOPTools_AlgoTools3D::DoSplitSEAMOnFace (const TopoDS_Edge& aSplit,
- const TopoDS_Face& aF)
+Standard_Boolean BOPTools_AlgoTools3D::DoSplitSEAMOnFace (const TopoDS_Edge& aSplit,
+ const TopoDS_Face& aF)
{
Standard_Boolean bIsUPeriodic, bIsVPeriodic, bIsLeft;
Standard_Real aTol, a, b, anUPeriod, anVPeriod, aT, anU, dU, anU1;
bIsVPeriodic=aSB->IsVPeriodic();
//
if (!(bIsUPeriodic || bIsVPeriodic)) {
- return;
+ return Standard_False;
}
anUPeriod = bIsUPeriodic ? aSB->UPeriod() : 0.;
anVPeriod = bIsVPeriodic ? aSB->VPeriod() : 0.;
//
if (aRTS.IsNull()) {
if (!bIsUClosed && !bIsVClosed) {
- return;
+ return Standard_False;
}
//
if (bIsUClosed) {
}
//
if (anU1==anU && anV1==anV) {
- return;
+ return Standard_False;
}
//
aScPr = (anU1==anU) ? aDir2D1*aDOX : aDir2D1*aDOY;
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
//purpose :
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);
- //! Make the edge <aSp> seam edge for the face <aF>
- Standard_EXPORT static void DoSplitSEAMOnFace (const TopoDS_Edge& aSp,
- const TopoDS_Face& aF);
+ //! Makes the split edge <theESplit> seam edge for the face <theFace> basing on the positions
+ //! of 2d curves of the original edge <theEOrigin>.
+ Standard_EXPORT static Standard_Boolean DoSplitSEAMOnFace (const TopoDS_Edge& theEOrigin,
+ const TopoDS_Edge& theESplit,
+ const TopoDS_Face& theFace);
//! Computes normal to the face <aF> for the point on the edge <aE>
//! at parameter <aT>.<br>
checkprops result -s 87449.7
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
--- /dev/null
+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