Skip to content

Commit

Permalink
OCC: add fillet, removeFaces, fillHole
Browse files Browse the repository at this point in the history
  • Loading branch information
benoit128 committed Sep 18, 2024
1 parent 1b37113 commit 84de276
Show file tree
Hide file tree
Showing 9 changed files with 411 additions and 24 deletions.
134 changes: 132 additions & 2 deletions Cassiopee/CPlot/apps/tkCADFix.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,12 +62,119 @@ def sewCAD(event=None):
faces = Internal.getNodeFromName1(CTK.t, 'FACES')
faces[2] = []
CTK.setCursor(2, WIDGETS['frame'])
OCC._meshAllEdges(hook, CTK.t, hmax=hmax, hausd=hausd)
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.display(CTK.t)
CTK.TXT.insert('START', 'CAD sewed with %g.\n'%tol)

#==============================================================================
def filletCAD(event=None):
import OCC.PyTree as OCC
if CTK.CADHOOK is None: return
radius = CTK.varsFromWidget(VARS[3].get(), 1)[0]
hook = CTK.CADHOOK
[hmax, hausd] = OCC.getCADcontainer(CTK.t)
# Get selected edges
nzs = CPlot.getSelectedZones()
edges = []
for nz in nzs:
nob = CTK.Nb[nz]+1
noz = CTK.Nz[nz]
z = CTK.t[2][nob][2][noz]
print(z[0])
CAD = Internal.getNodeFromName1(z, 'CAD')
if CAD is not None:
no = Internal.getNodeFromName1(CAD, 'no')
no = Internal.getValue(no)
edges.append(no)
if edges == []:
CTK.TXT.insert('START', 'No valid edges in selection.\n')
return
OCC.occ.addFillet(hook, edges, radius)

# remesh CAD and redisplay
edges = Internal.getNodeFromName1(CTK.t, 'EDGES')
edges[2] = []
faces = Internal.getNodeFromName1(CTK.t, 'FACES')
faces[2] = []
CTK.setCursor(2, WIDGETS['frame'])
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.display(CTK.t)
CTK.TXT.insert('START', 'Fillet added.\n')

#==============================================================================
def removeFaces(event=None):
import OCC.PyTree as OCC
if CTK.CADHOOK is None: return
hook = CTK.CADHOOK
[hmax, hausd] = OCC.getCADcontainer(CTK.t)
# Get selected edges
nzs = CPlot.getSelectedZones()
faces = []
for nz in nzs:
nob = CTK.Nb[nz]+1
noz = CTK.Nz[nz]
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)
faces.append(no)
if faces == []:
CTK.TXT.insert('START', 'No valid faces in selection.\n')
return
OCC.occ.removeFaces(hook, faces)

# remesh CAD and redisplay
edges = Internal.getNodeFromName1(CTK.t, 'EDGES')
edges[2] = []
faces = Internal.getNodeFromName1(CTK.t, 'FACES')
faces[2] = []
CTK.setCursor(2, WIDGETS['frame'])
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.display(CTK.t)
CTK.TXT.insert('START', 'Faces removed from CAD.\n')

#==============================================================================
def fillHole(event=None):
import OCC.PyTree as OCC
if CTK.CADHOOK is None: return
hook = CTK.CADHOOK
[hmax, hausd] = OCC.getCADcontainer(CTK.t)
# Get selected edges
nzs = CPlot.getSelectedZones()
edges = []
for nz in nzs:
nob = CTK.Nb[nz]+1
noz = CTK.Nz[nz]
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)
edges.append(no)
if edges == []:
CTK.TXT.insert('START', 'No valid edges in selection.\n')
return
OCC.occ.fillHole(hook, edges)

# remesh CAD and redisplay
edges = Internal.getNodeFromName1(CTK.t, 'EDGES')
edges[2] = []
faces = Internal.getNodeFromName1(CTK.t, 'FACES')
faces[2] = []
CTK.setCursor(2, WIDGETS['frame'])
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.display(CTK.t)
CTK.TXT.insert('START', 'Fill hole in CAD.\n')

#==============================================================================
# Create app widgets
#==============================================================================
Expand Down Expand Up @@ -103,8 +210,10 @@ def createApp(win):
# -1- CAD file format -
V = TK.StringVar(win); V.set('fmt_step'); VARS.append(V)
V.set(fileFmt)
# -2- Sewing toplerance -
# -2- Sewing tolerance -
V = TK.StringVar(win); V.set('1.e-6'); VARS.append(V)
# -3- Fillet radius -
V = TK.StringVar(win); V.set('0.1'); VARS.append(V)

# Read/write CAD file
B = TTK.Button(Frame, text="Read", command=readCAD)
Expand Down Expand Up @@ -132,6 +241,27 @@ def createApp(win):
BB = CTK.infoBulle(parent=B, text='Sewing tolerance.')
B.bind('<Return>', sewCAD)

# Fillet
B = TTK.Button(Frame, text="Fillet", command=filletCAD)
B.grid(row=3, column=0, sticky=TK.EW)
BB = CTK.infoBulle(parent=B, text='Make a fillet from edges selection.')

B = TTK.Entry(Frame, textvariable=VARS[3], background='White', width=10)
B.grid(row=3, column=1, sticky=TK.EW)
BB = CTK.infoBulle(parent=B, text='Fillet radius.')
B.bind('<Return>', filletCAD)

# Remove faces
B = TTK.Button(Frame, text="Remove faces", command=removeFaces)
B.grid(row=4, column=0, columnspan=2, sticky=TK.EW)
BB = CTK.infoBulle(parent=B, text='Remove selected faces from CAD.')

# Fill hole
B = TTK.Button(Frame, text="Fill hole", command=fillHole)
B.grid(row=5, column=0, columnspan=2, sticky=TK.EW)
BB = CTK.infoBulle(parent=B, text='Fill hole from CAD edges.')


#==============================================================================
# Called to display widgets
#==============================================================================
Expand Down
83 changes: 83 additions & 0 deletions Cassiopee/OCC/OCC/Atomic/addFillet.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
/*
Copyright 2013-2024 Onera.
This file is part of Cassiopee.
Cassiopee is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Cassiopee is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Cassiopee. If not, see <http://www.gnu.org/licenses/>.
*/
// Add fillet from edges
#include "occ.h"

#include "TopoDS.hxx"
#include "BRep_Tool.hxx"
#include "TopExp.hxx"
#include "TopExp_Explorer.hxx"
#include "TopTools_IndexedMapOfShape.hxx"
#include "ShapeBuild_ReShape.hxx"
#include "BRep_Builder.hxx"
#include "BRepFilletAPI_MakeFillet.hxx"

//=====================================================================
// Remove some faces and rebuild compound
//=====================================================================
PyObject* K_OCC::addFillet(PyObject* self, PyObject* args)
{
PyObject* hook; PyObject* listEdges; E_Float radius;
if (!PYPARSETUPLE_(args, OO_ R_, &hook, &listEdges, &radius)) return NULL;

void** packet = NULL;
#if (PY_MAJOR_VERSION == 2 && PY_MINOR_VERSION < 7) || (PY_MAJOR_VERSION == 3 && PY_MINOR_VERSION < 1)
packet = (void**) PyCObject_AsVoidPtr(hook);
#else
packet = (void**) PyCapsule_GetPointer(hook, NULL);
#endif

// get top shape
TopoDS_Shape* shp = (TopoDS_Shape*)packet[0];
TopTools_IndexedMapOfShape& edges = *(TopTools_IndexedMapOfShape*)packet[2];
TopTools_IndexedMapOfShape& surfaces = *(TopTools_IndexedMapOfShape*)packet[1];

// get edges
BRepFilletAPI_MakeFillet mkFillet(*shp);
for (E_Int no = 0; no < PyList_Size(listEdges); no++)
{
PyObject* noEdgeO = PyList_GetItem(listEdges, no);
E_Int noEdge = PyInt_AsLong(noEdgeO);
const TopoDS_Edge& E = TopoDS::Edge(edges(noEdge));
mkFillet.Add(radius, E);
}
TopoDS_Shape shc = mkFillet.Shape();

// export
delete shp;
TopoDS_Shape* newshp = new TopoDS_Shape(shc);

// Export
packet[0] = newshp;
TopTools_IndexedMapOfShape* ptr = (TopTools_IndexedMapOfShape*)packet[1];
delete ptr;
TopTools_IndexedMapOfShape* sf = new TopTools_IndexedMapOfShape();
TopExp::MapShapes(*newshp, TopAbs_FACE, *sf);
packet[1] = sf;
TopTools_IndexedMapOfShape* ptr2 = (TopTools_IndexedMapOfShape*)packet[2];
delete ptr2;
TopTools_IndexedMapOfShape* se = new TopTools_IndexedMapOfShape();
TopExp::MapShapes(*newshp, TopAbs_EDGE, *se);
packet[2] = se;
printf("INFO: after removeFaces: Nb edges=%d\n", se->Extent());
printf("INFO: after removeFaces: Nb faces=%d\n", sf->Extent());

Py_INCREF(Py_None);
return Py_None;
}
100 changes: 100 additions & 0 deletions Cassiopee/OCC/OCC/Atomic/fillHole.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
/*
Copyright 2013-2024 Onera.
This file is part of Cassiopee.
Cassiopee is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Cassiopee is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Cassiopee. If not, see <http://www.gnu.org/licenses/>.
*/
// Fill hole from edges
#include "occ.h"

#include "TopoDS.hxx"
#include "BRep_Tool.hxx"
#include "TopExp.hxx"
#include "TopExp_Explorer.hxx"
#include "TopTools_IndexedMapOfShape.hxx"
#include "ShapeBuild_ReShape.hxx"
#include "BRep_Builder.hxx"
#include "BRepBuilderAPI_MakeWire.hxx"
#include "BRepBuilderAPI_MakeFace.hxx"

//=====================================================================
// Remove some faces and rebuild compound
//=====================================================================
PyObject* K_OCC::fillHole(PyObject* self, PyObject* args)
{
PyObject* hook; PyObject* listEdges;
if (!PYPARSETUPLE_(args, OO_, &hook, &listEdges)) return NULL;

void** packet = NULL;
#if (PY_MAJOR_VERSION == 2 && PY_MINOR_VERSION < 7) || (PY_MAJOR_VERSION == 3 && PY_MINOR_VERSION < 1)
packet = (void**) PyCObject_AsVoidPtr(hook);
#else
packet = (void**) PyCapsule_GetPointer(hook, NULL);
#endif

// get top shape
TopoDS_Shape* shp = (TopoDS_Shape*)packet[0];
TopTools_IndexedMapOfShape& edges = *(TopTools_IndexedMapOfShape*)packet[2];
TopTools_IndexedMapOfShape& surfaces = *(TopTools_IndexedMapOfShape*)packet[1];

// get edges and make a wire
BRepBuilderAPI_MakeWire wireMaker;
for (E_Int no = 0; no < PyList_Size(listEdges); no++)
{
PyObject* noEdgeO = PyList_GetItem(listEdges, no);
E_Int noEdge = PyInt_AsLong(noEdgeO);
const TopoDS_Edge& E = TopoDS::Edge(edges(noEdge));
wireMaker.Add(E);
}
TopoDS_Wire myWire = wireMaker.Wire();

// Build face on wire
BRepBuilderAPI_MakeFace faceMaker(myWire);
//faceMaker.Add(myWire);
TopoDS_Face F = faceMaker.Face();

// Add face to shape
//ShapeBuild_ReShape reshaper;
//reshaper.Add(F); // no add
//TopoDS_Shape shc = reshaper.Apply(*shp);

TopoDS_Compound shc;
BRep_Builder aBuilder;
aBuilder.MakeCompound(shc);
aBuilder.Add(shc, *shp);
aBuilder.Add(shc, F);

// export
delete shp;
TopoDS_Shape* newshp = new TopoDS_Shape(shc);

// Export
packet[0] = newshp;
TopTools_IndexedMapOfShape* ptr = (TopTools_IndexedMapOfShape*)packet[1];
delete ptr;
TopTools_IndexedMapOfShape* sf = new TopTools_IndexedMapOfShape();
TopExp::MapShapes(*newshp, TopAbs_FACE, *sf);
packet[1] = sf;
TopTools_IndexedMapOfShape* ptr2 = (TopTools_IndexedMapOfShape*)packet[2];
delete ptr2;
TopTools_IndexedMapOfShape* se = new TopTools_IndexedMapOfShape();
TopExp::MapShapes(*newshp, TopAbs_EDGE, *se);
packet[2] = se;
printf("INFO: after removeFaces: Nb edges=%d\n", se->Extent());
printf("INFO: after removeFaces: Nb faces=%d\n", sf->Extent());

Py_INCREF(Py_None);
return Py_None;
}
17 changes: 0 additions & 17 deletions Cassiopee/OCC/OCC/Atomic/freeHook.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,29 +24,12 @@
#include "TopoDS_Wire.hxx"
#include "BRepCheck_Wire.hxx"
#include "BRepTools_WireExplorer.hxx"
#include "ShapeAnalysis.hxx"
#include "BRepAdaptor_Curve.hxx"
#include "GCPnts_AbscissaPoint.hxx"
#include "GCPnts_UniformDeflection.hxx"
#include "GCPnts_UniformAbscissa.hxx"
#include "TopExp.hxx"
#include "TopExp_Explorer.hxx"
#include "TopTools_IndexedMapOfShape.hxx"
#include "Geom2d_Curve.hxx"
#include "BRepBuilderAPI_MakeFace.hxx"
#include "BRepGProp.hxx"
#include "ShapeUpgrade_FaceDivide.hxx"
#include "ShapeUpgrade_ShapeDivideArea.hxx"
#include "ShapeUpgrade_ShapeDivideClosed.hxx"
#include "ShapeUpgrade_ClosedFaceDivide.hxx"
#include "ShapeUpgrade_SplitSurfaceArea.hxx"
#include "TColGeom_SequenceOfSurface.hxx"
#include "ShapeExtend_CompositeSurface.hxx"
#include "ShapeBuild_ReShape.hxx"
#include "BRep_Builder.hxx"
#include "ShapeUpgrade_ShapeDivideClosedEdges.hxx"

#include "GProp_GProps.hxx"

//=====================================================================
// Split shape by max area
Expand Down
Loading

0 comments on commit 84de276

Please sign in to comment.