diff --git a/Cassiopee/CPlot/apps/tkCADFix.py b/Cassiopee/CPlot/apps/tkCADFix.py
index 9c03af784..6476332b6 100644
--- a/Cassiopee/CPlot/apps/tkCADFix.py
+++ b/Cassiopee/CPlot/apps/tkCADFix.py
@@ -6,6 +6,7 @@
import CPlot.PyTree as CPlot
import CPlot.Tk as CTK
import Converter.Internal as Internal
+import CPlot.iconics as iconics
# local widgets list
WIDGETS = {}; VARS = []
@@ -143,7 +144,7 @@ def removeFaces(event=None):
if CTK.CADHOOK is None: return
hook = CTK.CADHOOK
[hmax, hausd] = OCC.getCADcontainer(CTK.t)
- # Get selected edges
+ # Get selected faces
nzs = CPlot.getSelectedZones()
faces = []
for nz in nzs:
@@ -244,6 +245,91 @@ def fillHole(event=None):
CTK.display(CTK.t)
CTK.TXT.insert('START', 'Fill hole in CAD.\n')
+#==============================================================================
+def setTrimFace1():
+ if CTK.t == []: return
+ if CTK.__MAINTREE__ <= 0:
+ CTK.TXT.insert('START', 'Fail on a temporary tree.\n')
+ CTK.TXT.insert('START', 'Error: ', 'Error'); return
+ nzs = CPlot.getSelectedZones()
+ if nzs == []:
+ CTK.TXT.insert('START', 'Selection is empty.\n')
+ CTK.TXT.insert('START', 'Error: ', 'Error'); return
+ selected = ''
+ for nz in nzs:
+ nob = CTK.Nb[nz]+1
+ noz = CTK.Nz[nz]
+ b = CTK.t[2][nob]
+ if b[0] != 'FACES': continue
+ z = CTK.t[2][nob][2][noz]
+ CAD = Internal.getNodeFromName1(z, 'CAD')
+ if CAD is not None:
+ no = Internal.getNodeFromName1(CAD, 'no')
+ no = Internal.getValue(no)
+ selected += str(no)+' '
+ print(selected, flush=True)
+ VARS[5].set(selected)
+
+#==============================================================================
+def trimFaces(event=None):
+ import OCC.PyTree as OCC
+ if CTK.CADHOOK is None: return
+ hook = CTK.CADHOOK
+ [hmax, hausd] = OCC.getCADcontainer(CTK.t)
+ # Get selected faces
+ nzs = CPlot.getSelectedZones()
+ faces1 = []
+ for nz in nzs:
+ nob = CTK.Nb[nz]+1
+ noz = CTK.Nz[nz]
+ b = CTK.t[2][nob]
+ if b[0] != 'FACES': continue
+ z = CTK.t[2][nob][2][noz]
+ CAD = Internal.getNodeFromName1(z, 'CAD')
+ if CAD is not None:
+ no = Internal.getNodeFromName1(CAD, 'no')
+ no = Internal.getValue(no)
+ faces1.append(no)
+ if faces1 == []:
+ CTK.TXT.insert('START', 'No valid faces in selection.\n')
+ return
+
+ faces2 = []
+ st = VARS[5].get()
+ st = st.split(' ')
+ for s in st:
+ try:
+ val = int(s)
+ faces2.append(val)
+ except: pass
+ if faces2 == []:
+ CTK.TXT.insert('START', 'No valid faces in selection.\n')
+ return
+
+ CTK.setCursor(2, WIDGETS['frame'])
+ CTK.setCursor(2, WIDGETS['trimFacesButton'])
+
+ OCC.occ.trimFaces(hook, faces1, faces2)
+
+ # remesh CAD and redisplay
+ edges = Internal.getNodeFromName1(CTK.t, 'EDGES')
+ edges[2] = []
+ faces = Internal.getNodeFromName1(CTK.t, 'FACES')
+ faces[2] = []
+ OCC._meshAllEdges(hook, CTK.t, hmax=hmax, hausd=hausd) # loose manual remeshing...
+ OCC._meshAllFacesTri(hook, CTK.t, hmax=hmax, hausd=hausd)
+
+ CTK.setCursor(0, WIDGETS['frame'])
+ CTK.setCursor(0, WIDGETS['trimFacesButton'])
+ NL = OCC.getNbLonelyEdges(CTK.t)
+ VARS[4].set('Lonely edges: %d'%NL)
+
+ (CTK.Nb, CTK.Nz) = CPlot.updateCPlotNumbering(CTK.t)
+ CTK.TKTREE.updateApp()
+ CTK.display(CTK.t)
+
+ CTK.TXT.insert('START', 'Faces trimmed in CAD.\n')
+
#==============================================================================
# Create app widgets
#==============================================================================
@@ -285,13 +371,15 @@ def createApp(win):
V = TK.StringVar(win); V.set('0.1'); VARS.append(V)
# -4- Bilan des edges lonely
V = TK.StringVar(win); V.set('Lonely edges: %d'%NL); VARS.append(V)
+ # -5- List of face to trim (compound 1)
+ V = TK.StringVar(win); V.set(''); VARS.append(V)
# CAD file name
B = TTK.Entry(Frame, textvariable=VARS[0], background='White', width=15)
B.grid(row=0, column=0, sticky=TK.EW)
BB = CTK.infoBulle(parent=B, text='CAD file name.')
- # CAD fille format
+ # CAD file format
B = TTK.OptionMenu(Frame, VARS[1], 'fmt_step', 'fmt_iges')
B.grid(row=0, column=1, sticky=TK.EW)
@@ -333,16 +421,25 @@ def createApp(win):
# Remove faces
B = TTK.Button(Frame, text="Remove faces", command=removeFaces)
- B.grid(row=5, column=0, columnspan=2, sticky=TK.EW)
+ B.grid(row=5, column=0, columnspan=1, sticky=TK.EW)
BB = CTK.infoBulle(parent=B, text='Remove selected faces from CAD.')
WIDGETS['removeFacesButton'] = B
# Fill hole
B = TTK.Button(Frame, text="Fill hole", command=fillHole)
- B.grid(row=6, column=0, columnspan=2, sticky=TK.EW)
+ B.grid(row=5, column=1, columnspan=1, sticky=TK.EW)
BB = CTK.infoBulle(parent=B, text='Fill hole from CAD edges.')
WIDGETS['fillHoleButton'] = B
+ # Trim
+ B = TTK.Button(Frame, text="Trim faces", command=trimFaces)
+ B.grid(row=6, column=0, columnspan=1, sticky=TK.EW)
+ BB = CTK.infoBulle(parent=B, text='Trim faces.')
+ WIDGETS['trimFacesButton'] = B
+ B = TTK.Button(Frame, command=setTrimFace1,
+ image=iconics.PHOTO[8], padx=0, pady=0)
+ BB = CTK.infoBulle(parent=B, text='Set the faces for first compound.')
+ B.grid(row=6, column=1, columnspan=1, sticky=TK.EW)
#==============================================================================
# Called to display widgets
diff --git a/Cassiopee/OCC/OCC/Atomic/sewing.cpp b/Cassiopee/OCC/OCC/Atomic/sewing.cpp
index db8516499..d15e81ee8 100644
--- a/Cassiopee/OCC/OCC/Atomic/sewing.cpp
+++ b/Cassiopee/OCC/OCC/Atomic/sewing.cpp
@@ -16,7 +16,7 @@
You should have received a copy of the GNU General Public License
along with Cassiopee. If not, see .
*/
-// CAD split for parallel
+// CAD sewing
#include "occ.h"
#include "TopoDS.hxx"
diff --git a/Cassiopee/OCC/OCC/Atomic/trim.cpp b/Cassiopee/OCC/OCC/Atomic/trim.cpp
index 5558ce84c..74582c259 100644
--- a/Cassiopee/OCC/OCC/Atomic/trim.cpp
+++ b/Cassiopee/OCC/OCC/Atomic/trim.cpp
@@ -24,19 +24,21 @@
#include "BRepBuilderAPI_MakeWire.hxx"
#include "ShapeUpgrade_UnifySameDomain.hxx"
#include "BRepFeat_SplitShape.hxx"
+#include "BRep_Builder.hxx"
#include "TopExp.hxx"
#include "TopExp_Explorer.hxx"
#include "TopTools_IndexedMapOfShape.hxx"
#include "ShapeBuild_ReShape.hxx"
#include "TopoDS.hxx"
+#include "BRepAlgoAPI_Cut.hxx"
//=====================================================================
// Fix the full shape
//=====================================================================
PyObject* K_OCC::trimFaces(PyObject* self, PyObject* args)
{
- PyObject* hook; PyObject* listOfFaceNo; PyObject* listOfEdgeNo;
- if (!PYPARSETUPLE_(args, OOO_ , &hook, &listOfFaceNo, &listOfEdgeNo)) return NULL;
+ PyObject* hook; PyObject* listOfFaceNo1; PyObject* listOfFaceNo2;
+ if (!PYPARSETUPLE_(args, OOO_ , &hook, &listOfFaceNo1, &listOfFaceNo2)) return NULL;
void** packet = NULL;
#if (PY_MAJOR_VERSION == 2 && PY_MINOR_VERSION < 7) || (PY_MAJOR_VERSION == 3 && PY_MINOR_VERSION < 1)
@@ -46,33 +48,76 @@ PyObject* K_OCC::trimFaces(PyObject* self, PyObject* args)
#endif
TopTools_IndexedMapOfShape& surfaces = *(TopTools_IndexedMapOfShape*)packet[1];
- TopTools_IndexedMapOfShape& edges = *(TopTools_IndexedMapOfShape*)packet[2];
+ //TopTools_IndexedMapOfShape& edges = *(TopTools_IndexedMapOfShape*)packet[2];
- TopoDS_Shape* shp = (TopoDS_Shape*)packet[0];
- TopoDS_Shape* newshp = new TopoDS_Shape();
-
- // Build a wire
- BRepBuilderAPI_MakeWire wireBuilder;
- for (E_Int i = 0; i < PyList_Size(listOfEdgeNo); i++)
+ // Build remaining faces list
+ std::list pl;
+ E_Int nfaces = surfaces.Extent();
+ for (E_Int i = 1; i <= nfaces; i++) pl.push_back(i);
+
+ // Build compound from face1
+ BRep_Builder builder1;
+ TopoDS_Compound compound1;
+ builder1.MakeCompound(compound1);
+ for (E_Int i = 0; i < PyList_Size(listOfFaceNo1); i++)
{
- PyObject* edgeNoO = PyList_GetItem(listOfEdgeNo, i);
- E_Int edgeNo = PyLong_AsLong(edgeNoO);
- const TopoDS_Edge& E = TopoDS::Edge(edges(edgeNo));
- wireBuilder.Add(E);
+ PyObject* faceNoO = PyList_GetItem(listOfFaceNo1, i);
+ E_Int faceNo = PyLong_AsLong(faceNoO);
+ auto it = std::find(pl.begin(), pl.end(), faceNo);
+ if (it != pl.end()) pl.erase(it);
+ const TopoDS_Face& F = TopoDS::Face(surfaces(faceNo));
+ builder1.Add(compound1, F);
}
- TopoDS_Wire W = wireBuilder.Wire();
- BRepFeat_SplitShape splitter(*shp);
- // Add faces to splitter
- for (E_Int i = 0; i < PyList_Size(listOfFaceNo); i++)
+ // Build compound from face2
+ BRep_Builder builder2;
+ TopoDS_Compound compound2;
+ builder1.MakeCompound(compound2);
+ for (E_Int i = 0; i < PyList_Size(listOfFaceNo2); i++)
{
- PyObject* faceNoO = PyList_GetItem(listOfFaceNo, i);
+ PyObject* faceNoO = PyList_GetItem(listOfFaceNo2, i);
E_Int faceNo = PyLong_AsLong(faceNoO);
+ auto it = std::find(pl.begin(), pl.end(), faceNo);
+ if (it != pl.end()) pl.erase(it);
const TopoDS_Face& F = TopoDS::Face(surfaces(faceNo));
- splitter.Add(W, F);
+ builder2.Add(compound2, F);
+ }
+
+ // trim the compound
+ TopoDS_Shape trimmedCompound1 = BRepAlgoAPI_Cut(compound1, compound2);
+ TopoDS_Shape trimmedCompound2 = BRepAlgoAPI_Cut(compound2, compound1);
+
+ // rebuild
+ BRep_Builder builder3;
+ TopoDS_Compound compound3;
+ builder3.MakeCompound(compound3);
+
+ for (auto& i : pl)
+ {
+ TopoDS_Face F = TopoDS::Face(surfaces(i));
+ builder3.Add(compound3, F);
}
- splitter.Build();
- *newshp = splitter.Shape();
+
+ TopExp_Explorer expl1(trimmedCompound1, TopAbs_FACE);
+ while (expl1.More())
+ {
+ TopoDS_Shape shape = expl1.Current();
+ TopoDS_Face face = TopoDS::Face(shape);
+ builder3.Add(compound3, face);
+ expl1.Next();
+ }
+ TopExp_Explorer expl2(trimmedCompound2, TopAbs_FACE);
+ while (expl2.More())
+ {
+ TopoDS_Shape shape = expl2.Current();
+ TopoDS_Face face = TopoDS::Face(shape);
+ builder3.Add(compound3, face);
+ expl2.Next();
+ }
+
+ TopoDS_Shape* newshp = new TopoDS_Shape(compound3);
+ //TopoDS_Shape* newshp = new TopoDS_Shape(trimmedCompound2);
+
// Rebuild the hook
packet[0] = newshp;
@@ -95,3 +140,38 @@ PyObject* K_OCC::trimFaces(PyObject* self, PyObject* args)
Py_INCREF(Py_None);
return Py_None;
}
+
+//===
+/*
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+Handle(Geom_Surface) surface1 = ...; // Your first surface
+Handle(Geom_Surface) surface2 = ...; // Your second surface
+TopoDS_Face face1 = BRepBuilderAPI_MakeFace(surface1, Precision::Confusion());
+TopoDS_Face face2 = BRepBuilderAPI_MakeFace(surface2, Precision::Confusion());
+
+BRepAlgoAPI_Section section(face1, face2);
+section.ComputePCurveOn1(Standard_True);
+section.Approximation(Standard_True);
+section.Build();
+
+if (!section.IsDone()) {
+ std::cerr << "Error: Intersection computation failed." << std::endl;
+ return;
+}
+
+TopoDS_Shape intersection = section.Shape();
+TopoDS_Wire wire = BRepBuilderAPI_MakeWire(TopoDS::Edge(intersection));
+TopoDS_Face trimmedFace1 = BRepBuilderAPI_MakeFace(surface1, wire, Standard_True);
+TopoDS_Face trimmedFace2 = BRepBuilderAPI_MakeFace(surface2, wire, Standard_True);
+
+// on compounds ==
+TopoDS_Shape trimmedCompound = BRepAlgoAPI_Cut(compound1, compound2);
+*/
\ No newline at end of file
diff --git a/Cassiopee/OCC/OCC/PyTree.py b/Cassiopee/OCC/OCC/PyTree.py
index 620fc9a45..f87a46864 100644
--- a/Cassiopee/OCC/OCC/PyTree.py
+++ b/Cassiopee/OCC/OCC/PyTree.py
@@ -1235,6 +1235,11 @@ def _fillHole(hook, edges):
OCC.occ.fillHole(hook, edges)
return None
+# trim two set of surfaces
+def _trimFaces(hook, faces1, faces2):
+ OCC.occ.trimFaces(hook, faces1, faces2)
+ return None
+
# Return the number of edges in CAD hook
def getNbEdges(hook):
"""Return the number of edges in CAD hook."""