CadQuery / cadquery

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

Unexpected ValueError: Null TopoDS_Shape object during cut operation #1503

Closed GaN-T closed 10 months ago

GaN-T commented 10 months ago

I have a list of lists that contain the vertices of polygons imported from a cell in a GDS file. (please just copy paste them to a new variable from the attached file if you are trying to reproduce my error). polygons.txt

In my program, this list of lists is called "polygons". I am trying to do a through all cut using all these shapes into a box object but am getting "ValueError: Null TopoDS_Shape object" only when i center the box to the polygon. What is the best way of doing this without the error?

Here is what I tried:


cellCen = (0.5841240000000001, 0.8565)   # center coordinates of the imported polygon cell
(box_w, box_l, box_h) = (1.968248, 2.513, 0.038)  # box dimensions
slab = cq.Workplane("front").box(box_w, box_l, box_h)
pols = [slab.faces(">Z").workplane().polyline(polygons[i]).close().extrude(-(box_h + 0.0001), combine = False) for i in range(len(polygons))]
p0 = pols[0]
for i in range(len(pols)):
    # p0 becomes the group of solids I want to cut out of the slab
    p0 = p0.union(pols[i], glue = True)   

slab.cut(p0)

This cut operation works correctly, but only when I add the 0.0001 additional cut depth in the extrude operation. If I leave the extrude depth equal to -box_h, it doesn't cut all the way through the box. This is the first issue.

The second problem that raises the ValueError is when I first try to center the box to the cell before the cut, see below. I also get the same error when I try to do a shallower cut (not all the way through the box), with or without centering the box:

slab = cq.Workplane("front").box(box_w, box_l, box_h).translate((cellCen[0]/2 , cellCen[1]/2 , 0))   # translate the box to center it on the polygon cells in x and y directions.
pols = [slab.faces(">Z").workplane().polyline(polygons[i]).close().extrude(-(box_h + 0.0001), combine = False) for i in range(len(polygons))]
p0 = pols[0]
for i in range(len(pols)):
    # p0 becomes the group of solids I want to cut out of the slab
    p0 = p0.union(pols[i], glue = True)   

slab.cut(p0)

When I try to visualize the objects I am trying to cut in an assembly it looks correct, however I am unable to perform the cut, which was possible before I centered the slab to the polygon cells. Why is this happening and how can i avoid it to get the output I want?

assy = cq.Assembly()

assy = addToAssembly(assy, slab, "sub", color = cq.Color("Gold"))
assy = addToAssembly(assy, (p0), "trench", color = cq.Color("black"))

display(assy)

P.S. Images are not being uploaded inline, please see the attached zip for screenshots of my output. Images.zip

GaN-T commented 10 months ago

After looking around, I saw a reply to a post on the FreeCAD forum by chrisb.

"The boolean operations frequently fail if coplanar faces are involved. If you want to cut something make the object you want to cut off slightly bigger if possible. If you want to make a fusion let them overlap."

This tipped me off to offset the construction workplane for the polygons object by a tiny bit before doing the cut and I dont get the Null TopoDS_Shape error anymore 👯

offset = 0.001
(box_w, box_l, box_h) = (1.968248, 2.513, 0.038)
slab = cq.Workplane("front").box(box_w, box_l, box_h).translate((cellCen[0]/2 , cellCen[1]/2 , 0))   # translate the box to center it on the polygon cells in x and y directions.
pols = [slab.faces(">Z").workplane(offset = offset).polyline(polygons[i]).close().extrude(-(box_h + 0.0001 + offset), combine = False) for i in range(len(polygons))]
p0 = pols[0]
for i in range(len(pols)):
    p0 = p0.union(pols[i], glue = True)   

slab.cut(p0)
GaN-T commented 10 months ago

While this solution works, it still doesn't explain why the cut operation worked in the first instance (without the centering or the offset that I added later)