Strange behavior when shell and chamfer combined

58 views
Skip to first unread message

Wojciech

unread,
Jul 19, 2024, 11:21:35 PM7/19/24
to CadQuery
Hi !

This is my first post there. I've played with cadquery a bit, as I'm doing some simple modeling in FreeCAD and OpenSCAD. The first is buggy and unstable for me. The second is fine for 80% of the models I need, but gets messy when doing complex things. I've been very happy with cadquery so far, but I've found some peculiar behaviors. I'm not sure if those are bugs or me not understanding the inner workings of this tool. So... I'll start with the first issue.

I've been trying to make a box with shell and chamfer. When combined they behave "wierd" when selecting faces. let me explain on some examples:

    x1 = cq.Workplane('XY').box(15, 15, 15)
    x1 = x1.edges("|Z").chamfer(1)
    x1 = x1.faces(">X").sphere(1)
    x1.val().exportStl("./test1.stl")

    x2 = cq.Workplane('XY').box(15, 15, 15)
    x2 = x2.faces(">Z").shell(3, kind='intersection')
    x2 = x2.faces(">X").sphere(1)
    x2.val().exportStl("./test2.stl")

I'm using chamfer and shell separately. As you can see the sphere is placed on the X most face as expected. So far so good. Now lets combine the two.

    x3 = cq.Workplane('XY').box(15, 15, 15)
    x3 = x3.faces(">Z").shell(3, kind='intersection')
    x3 = x3.edges("|Z").chamfer(1)
    x3.val().exportStl("./test3.stl")

    x4 = cq.Workplane('XY').box(15, 15, 15)
    x4 = x4.edges("|Z").chamfer(1)
    x4 = x4.faces(">Z").shell(3, kind='intersection')
    x4.val().exportStl("./test4.stl")

There are two ways of doing so: shell-then-chamfer (x3) or chamfer-then-shell (x4). The shapes produced are similar but a bit different in geometry. No surprises here. But lets now add a sphere on these shapes, creating x5 and x6 respectively.

    x5 = cq.Workplane('XY').box(15, 15, 15)
    x5 = x5.faces(">Z").shell(3, kind='intersection')
    x5 = x5.edges("|Z").chamfer(1)
    x5 = x5.faces(">X").sphere(1)
    x5.val().exportStl("./test5.stl")

    x6 = cq.Workplane('XY').box(15, 15, 15)
    x6 = x6.edges("|Z").chamfer(1)
    x6 = x6.faces(">Z").shell(3, kind='intersection')
    x6 = x6.faces(">X").sphere(1)
    x6.val().exportStl("./test6.stl")

For me, x6 looks as expected, but x5 produces... just the sphere. The box is gone. I don't know if this is some quirk of cadquery or a bug, but it this left me very confused. The x5 STL is also over twice as large as x1, x2, x6 (x4 and x5 have just straight lines so they're tiny).

I'd love to hear form you.

Thank you,
Wojciech
test1.stl
test5.stl
test3.stl
test4.stl
test6.stl
test2.stl

Wojciech

unread,
Jul 20, 2024, 10:10:35 PM7/20/24
to CadQuery
Another thing I've noticed and documented with an example below. If I select a face, set a workplane(), draw a rectangle and extrude, the two cases (x3 and x4) behave differently. The x4 case extrudes normally (outward from the face) as shown in x8. The x3 case on the other hand "extrudes" inwards creating a cut (as if the solid is in some way... a negative volume?) which can be seen in example x7.

x7 = cq.Workplane('XY').box(15, 15, 15)
x7 = x7.faces(">Z").shell(3, kind='intersection')
x7 = x7.edges("|Z").chamfer(1)
x7 = x7.faces(">X").workplane().rect(5, 5).extrude(1)
x7.val().exportStl(os.path.join(current_directory, "./test7.stl"))

x8 = cq.Workplane('XY').box(15, 15, 15)
x8 = x8.edges("|Z").chamfer(1)
x8 = x8.faces(">Z").shell(3, kind='intersection')
x8 = x8.faces(">X").workplane().rect(5, 5).extrude(1)
x8.val().exportStl(os.path.join(current_directory, "./test8.stl"))
test7.stl
test8.stl

Edi

unread,
Jul 22, 2024, 4:41:30 AM7/22/24
to CadQuery
I concur on the "strange behavior " of the X7 example. When you call .extrude it is expected an extrusion not a slot.

P.s. I feel that inline screenshots would be more helpful in fomenting this discussion than attaching .stl files

Adam Urbanczyk

unread,
Jul 23, 2024, 2:03:46 AM7/23/24
to CadQuery
Regarding x5 for some reason the kernel fails on the chamfer step:

x5 = (

    cq.Workplane('XY').box(15, 15, 15)
    .faces(">Z")
    .shell(3, kind='intersection')
    .invoke(lambda x: show_object(x.val().moved(x=-40), name='shell'))
    .edges("|Z")
    .chamfer(1)
    .invoke(lambda x: show_object(x.val().moved(x=40), name='chamfer'))
    .faces(">X")
    .sphere(1)
)

show_object(x5)


You could apply the following workaround.

x5 = (

    cq.Workplane('XY').box(15, 15, 15)
    .faces(">Z")
    .shell(3, kind='intersection')
    .edges("|Z")
    .chamfer(1)
    .map(lambda x: x.fix())
    .faces(">X")
    .sphere(1)
)

show_object(x5)

In the end this seems to be an OCCT issue.
Reply all
Reply to author
Forward
0 new messages