CadQuery / cadquery

A python parametric CAD scripting framework based on OCCT
https://cadquery.readthedocs.io
Other
3.03k stars 284 forks source link

Applying shell operator to extruded dxf shape leads to 'BRep_API: command not done' error #515

Open Jakob-em opened 3 years ago

Jakob-em commented 3 years ago

While trying to create 3d models from dxf files where the top and bottom of the shapes are removed, I ran into a problem. According to the documentation the shell operator does what I want, but when I apply it to an imported shape I get the following error:

~/miniconda3/lib/python3.8/site-packages/cadquery/cq.py in shell(self, thickness, kind)
   1089         faces = [f for f in self.objects if isinstance(f, Face)]
   1090 
-> 1091         s = solidRef.shell(faces, thickness, kind=kind)
   1092         return self.newObject([s])
   1093 

~/miniconda3/lib/python3.8/site-packages/cadquery/occ_impl/shapes.py in shell(self, faceList, thickness, tolerance, kind)
   1860 
   1861             shell_builder.Build()
-> 1862             rv = shell_builder.Shape()
   1863 
   1864         else:  # if no faces provided a watertight solid will be constructed

StdFail_NotDone: BRep_API: command not done

This is the code I am using to generate the model:

result = cq.importers.importDXF('test.dxf').wires().toPending().extrude(10).faces('|Z').shell(1)

And this is a zip file containing an example dxf file: test.zip

I should mention that it works fine with very simple shapes like rectangles, but as soon as the shape is a little bit more complex I run into the error.

Is there something I am doing wrong or is this a bug?

jmwright commented 3 years ago

If you change the selector to "<Z" or ">Z" does it work? If so, it would probably be better to use offset2d to create an insert copy of the wire(s), and then extrude that. That should give you a tube-like object, which if sounds like is what you want.

https://cadquery.readthedocs.io/en/latest/classreference.html?highlight=offset#cadquery.Workplane.offset2D

https://cadquery.readthedocs.io/en/latest/classreference.html?highlight=offset#cadquery.Wire.offset2D

Jakob-em commented 3 years ago

Thanks for the pointer with the offset2d, this should do what i want. But when I try to apply it to the imported wires I get the following error:

result = cq.importers.importDXF('test.dxf').wires().toPending().offset2D(1)
~/miniconda3/lib/python3.8/site-packages/cadquery/cq.py in offset2D(self, d, kind)
   3651 
   3652         ws = self._consolidateWires()
-> 3653         rv = list(chain.from_iterable(w.offset2D(d, kind) for w in ws))
   3654 
   3655         self.ctx.pendingEdges = []

~/miniconda3/lib/python3.8/site-packages/cadquery/cq.py in <genexpr>(.0)
   3651 
   3652         ws = self._consolidateWires()
-> 3653         rv = list(chain.from_iterable(w.offset2D(d, kind) for w in ws))
   3654 
   3655         self.ctx.pendingEdges = []

~/miniconda3/lib/python3.8/site-packages/cadquery/occ_impl/shapes.py in offset2D(self, d, kind)
   1544         offset.Perform(d)
   1545 
-> 1546         obj = downcast(offset.Shape())
   1547 
   1548         if isinstance(obj, TopoDS_Compound):

~/miniconda3/lib/python3.8/site-packages/cadquery/occ_impl/shapes.py in downcast(obj)
    305     """
    306 
--> 307     f_downcast: Any = downcast_LUT[shapetype(obj)]
    308     rv = f_downcast(obj)
    309 

~/miniconda3/lib/python3.8/site-packages/cadquery/occ_impl/shapes.py in shapetype(obj)
    295 
    296     if obj.IsNull():
--> 297         raise ValueError("Null TopoDS_Shape object")
    298 
    299     return obj.ShapeType()

ValueError: Null TopoDS_Shape object
adam-urbanczyk commented 3 years ago

Anything special about this DXF content? I see it has 4 edges, out of which 3 are B-splines. Does this work with a single B-spline edge?

Jakob-em commented 3 years ago

I tried it again with a lot of different shapes and now it seems to work. It seems like there was something wrong with the dxf. (Maybe i messed something up in inkscape). But now I run into a different problem which kinda looks like the original one:

After extruding the imported and offsetted dxf shape I want to apply a chamfer. This works fine with shapes that don't have any B-splines, but as soon as there is a single B-Spline in the imported shape I get the following error:

~\anaconda3\envs\cq-ocp\lib\site-packages\cadquery\cq.py in chamfer(self, length, length2)
   1156             raise ValueError("Chamfer requires that edges be selected")
   1157 
-> 1158         s = solid.chamfer(length, length2, edgeList)
   1159 
   1160         return self.newObject([s])

~\anaconda3\envs\cq-ocp\lib\site-packages\cadquery\occ_impl\shapes.py in chamfer(self, length, length2, edgeList)
   1828                 d1, d2, e, TopoDS.Face_s(face)
   1829             )  # NB: edge_face_map return a generic TopoDS_Shape
-> 1830         return self.__class__(chamfer_builder.Shape())
   1831 
   1832     def shell(

StdFail_NotDone: BRep_API: command not done

It is especially strange that it works when the offset is removed. I am using the following code:

result = cq.importers.importDXF('test.dxf').wires().toPending().offset2D(2).extrude(10).faces('>Z').chamfer(1)

in combination with this shape (a simple circle exported from inkscape as dxf) test.zip

Do you have any idea why this won't work?

adam-urbanczyk commented 3 years ago

I'm not sure why the above code does not work. The following does work (it uses a different way of constructing the offset):

result = (
    cq.importers.importDXF('/home/adam/cq/CQ-editor/test.dxf')
    .wires().toPending()
    .offset2D(2,kind='intersection')
    .extrude(10)
    .faces('>Z')
    .chamfer(1)
    )

image