pythonocc-core icon indicating copy to clipboard operation
pythonocc-core copied to clipboard

Iterating over TopTools_ListOfShape

Open Equidamoid opened this issue 5 years ago • 2 comments

I want to automatically fillet the new edges produced by fusing 2 shapes. Something like this: https://upload.wikimedia.org/wikipedia/commons/f/fd/Fillet.jpg

BRepFilletAPI_MakeFillet wants the edges returned TopTools_ListOfShape BRepAlgoAPI_Fuse::SectionEdges() to be added one by one. And I don't see any way to non-destructively iterate over TopTools_ListOfShape. If I try to copy it and iterate using First(); RemoveFirst() I get a segfault.

Here is what I have now, it only fillets 2 edges. How do I get the rest?

from OCC.Core.BRepFilletAPI import BRepFilletAPI_MakeFillet
from OCC.Core import gp
import OCC.Core.BRepPrimAPI as occprim
import OCC.Core.BRepAlgoAPI as occalgo
from OCC.Display.SimpleGui import init_display
from OCC.Display.backend import load_backend
load_backend()

cyl = occprim.BRepPrimAPI_MakeCylinder(10, 10).Shape()

cpos = gp.gp_Pnt(9, 0, -2)

cube = occprim.BRepPrimAPI_MakeBox(cpos, 6, 6, 6).Shape()
display, start_display, add_menu, add_function_to_menu = init_display()

fus = occalgo.BRepAlgoAPI_Fuse(cyl, cube)

se = fus.SectionEdges()
new_edges = []
fil = BRepFilletAPI_MakeFillet(fus.Shape())

print("%d edges" % (se.Size()))

# Here ideally it should be like "for edge in se: fil.Add(0.1, edge)"

fil.Add(0.1, se.First())
fil.Add(0.1, se.Last())

fil.Build()
assert fil.IsDone()
ret = fil.Shape()
display.DisplayShape(ret, update=True)
start_display()

As an additional note, if you replace cube position to cpos = gp.gp_Pnt(9, 0, -2) it crashes. Not sure if it's related.

Equidamoid avatar Jul 13 '20 18:07 Equidamoid

Hacking something that works is as easy as this:

diff --git a/src/SWIG_files/wrapper/TopTools.i b/src/SWIG_files/wrapper/TopTools.i
index b9535fbd..3a7e6913 100644
--- a/src/SWIG_files/wrapper/TopTools.i
+++ b/src/SWIG_files/wrapper/TopTools.i
@@ -210,6 +210,17 @@ from OCC.Core.Exception import *
         return self.Size()
     }
 };
+
+%inline %{
+    const TopoDS_Shape& TopTools_ListOfShape_get(const NCollection_List<TopoDS_Shape>& ttlos, int idx){
+        auto it = ttlos.begin();
+        while (idx){
+          ++ it;
+          -- idx;
+        }
+        return *it;
+    }
+%}
 %template(TopTools_MapOfOrientedShape) NCollection_Map<TopoDS_Shape,TopTools_OrientedShapeMapHasher>;
 %template(TopTools_MapOfShape) NCollection_Map<TopoDS_Shape,TopTools_ShapeMapHasher>;
 %template(TopTools_SequenceOfShape) NCollection_Sequence<TopoDS_Shape>;

Iteration is then possible with something like

for i in range(se.Size()):
    fil.Add(0.5, toptools.TopTools_ListOfShape_get(se, i))
fil.Build()

I don't dare to try making a proper iterator support with swig though.

Equidamoid avatar Jul 13 '20 19:07 Equidamoid

Interesting feedback, thank you for your report. I guess the best way would be to wrap the ___iter__ or __next__ python methods to allow constructs such as:

for shp in a_TopTools_ListOfShape:
   do_something()

tpaviot avatar Jul 14 '20 08:07 tpaviot