Skip to content

Commit

Permalink
OCC: add trimFaces
Browse files Browse the repository at this point in the history
  • Loading branch information
benoit128 committed Nov 4, 2024
1 parent 506755f commit d9a5ccb
Show file tree
Hide file tree
Showing 4 changed files with 208 additions and 26 deletions.
105 changes: 101 additions & 4 deletions Cassiopee/CPlot/apps/tkCADFix.py
Original file line number Diff line number Diff line change
Expand Up @@ -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 = []
Expand Down Expand Up @@ -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:
Expand Down Expand Up @@ -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
#==============================================================================
Expand Down Expand Up @@ -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)

Expand Down Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion Cassiopee/OCC/OCC/Atomic/sewing.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
You should have received a copy of the GNU General Public License
along with Cassiopee. If not, see <http://www.gnu.org/licenses/>.
*/
// CAD split for parallel
// CAD sewing
#include "occ.h"

#include "TopoDS.hxx"
Expand Down
122 changes: 101 additions & 21 deletions Cassiopee/OCC/OCC/Atomic/trim.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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<E_Int> 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;
Expand All @@ -95,3 +140,38 @@ PyObject* K_OCC::trimFaces(PyObject* self, PyObject* args)
Py_INCREF(Py_None);
return Py_None;
}

//===
/*
#include <BRepAlgoAPI_Section.hxx>
#include <BRepBuilderAPI_MakeFace.hxx>
#include <TopoDS_Shape.hxx>
#include <TopoDS_Face.hxx>
#include <TopoDS_Edge.hxx>
#include <TopoDS_Wire.hxx>
#include <Geom_Surface.hxx>
#include <GeomAPI_ProjectPointOnSurf.hxx>
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);
*/
5 changes: 5 additions & 0 deletions Cassiopee/OCC/OCC/PyTree.py
Original file line number Diff line number Diff line change
Expand Up @@ -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."""
Expand Down

0 comments on commit d9a5ccb

Please sign in to comment.