Creating shell from complex shape

782 views
Skip to first unread message

Sean Leavey

unread,
Oct 19, 2021, 10:33:32 AM10/19/21
to cadq...@googlegroups.com
I'm trying to create a shell from a solid heart shape by removing the
face in the Z plane of the attached image (marked with the red X).

Selecting the face with .faces("+Z") or .faces("-Z") then .shell(0.1)
results in the error "Standard_NoSuchObject: NCollection_DataMap::Find":

def heart():
wire = cq.Workplane("XY") \
.lineTo(2, 2) \
.threePointArc((4, 1), (3.5, 0)) \
.mirrorX()

return wire \
.extrude(1.5) \
.edges(">Z") \
.fillet(1.2)

result = heart().faces("+Z").shell(0.1)

I can verify there is a +Z face by typing heart().faces("+Z").size() in
the console and getting 1 in return.

What's wrong with my code? Any advice would be much appreciated.
Screenshot_20211019_162702.png

Jeremy Wright

unread,
Oct 19, 2021, 11:46:19 AM10/19/21
to CadQuery
The following simplified code gives me the BRep_API: command not done error that says the CAD kernel had some sort of internal issue when applying the shell.

wire = (cq.Workplane("XY")

         .lineTo(2, 2)
         .threePointArc((4, 1), (3.5, 0))
         .mirrorX())

heart = wire.extrude(1.5)

heart = heart.faces(">Z").shell(0.1)

show_object(heart)

I'm guessing there's a community member who can figure out a work around, but this is an alternative you could explore, although your fillet was too large for your wall thickness so I had to decrease it.

wire = (cq.Workplane("XY")

         .lineTo(2, 2)
         .threePointArc((4, 1), (3.5, 0))
         .mirrorX())

wire2 = wire.offset2D(-0.1).translate((0, 0, 0.1))

heart = wire.extrude(1.5)

heart = heart.wires("<Z").toPending().offset2D(-0.1).cutBlind(1.4).edges(">Z").fillet(0.5)

show_object(heart)


You could also consider making the heart sketch parametric and using that instead of messing with toPending().offset2D().

Ami Fischman

unread,
Oct 19, 2021, 12:18:23 PM10/19/21
to CadQuery
Shelling using kind='intersection', and doing it before filleting, and increasing shell wall size to accomodate the fillet, makes it work (cadhub preview):
import cadquery as cq
def heart():
    wire = (cq.Workplane("XY")
        .lineTo(2, 2)
        .threePointArc((4, 1), (3.5, 0))
        .mirrorX()
    )
    return (
        wire
        .extrude(1.5)
        .faces("<Z").shell(0.3, kind='intersection')
        .edges(">Z").fillet(0.1)
    )
show_object(heart())

Jeremy Wright

unread,
Oct 19, 2021, 12:34:31 PM10/19/21
to CadQuery
I see some visual artifacts in the render that make me wonder if it's a valid shape though. Do you see those as well? The fillets have some extra edges and some of the features are transparent.

Ami Fischman

unread,
Oct 19, 2021, 12:40:42 PM10/19/21
to CadQuery
I also see visual artifacts but the generated STL looks good and PrusaSlicer seems to do the right thing.
Looks like a rendering bug.

Sean Leavey

unread,
Oct 19, 2021, 3:20:14 PM10/19/21
to CadQuery
Thanks both for your help! Both solutions give nice looking shapes but I was intentionally abusing the fillet feature to create that rounded effect on the rear.
I modified Ami's code to increase the fillet to 1 and it seems like it will work (haven't checked the STL though) but anything beyond that and I start to see weird artifacts (screenshot attached for a 1.3 fillet).
I like the idea of filleting *after* shelling though, that's not something I'd thought to try.

I also tried a different approach, creating a copy of the heart in the original code I posted, scaling it down, and cutting it out of the original heart. It doesn't produce uniformly thick walls as `shell` would do, but it's good enough for my application (a soap mould):

import cadquery as cq

def scale(workplane, x, y=None, z=None):
    """Scale workplane.
    
    From mbway: https://github.com/CadQuery/cadquery/issues/638
    """
    y = y if y is not None else x
    z = z if z is not None else x
    t = cq.Matrix([
        [x, 0, 0, 0],
        [0, y, 0, 0],
        [0, 0, z, 0],
        [0, 0, 0, 1]
    ])
    
    return workplane.newObject([
        o.transformGeometry(t) if isinstance(o, cq.Shape) else o
        for o in workplane.objects
    ])

def heart(scale=1):

    wire = cq.Workplane("XY") \
        .lineTo(scale*2, scale*2) \
        .threePointArc((scale*4, scale*1), (scale*3.5, 0)) \
        .mirrorX()
    
    return wire \
        .extrude(scale*1.5) \
        .edges(">Z") \
        .fillet(scale*1.2)

result = heart().cut(scale(heart(), 0.9).translate([0.2, 0, 0]))

Screenshots attached of the front and rear (latter showing the effect I'm using the fillet to achieve).
For the record I'm still interested to see if a shell can be made to work for the shape and fillet specified in the original post.

Thanks again for your help so far!
Screenshot_20211019_211649.png
Screenshot_20211019_211415.png
Screenshot_20211019_211431.png

Roger Maitland

unread,
Oct 19, 2021, 7:04:18 PM10/19/21
to Sean Leavey, CadQuery
I love this question 😉 - I think this version produces walls of constant thickness:
import cadquery as cq

outer = (
cq.Workplane("XY")
.lineTo(2, 2)
.threePointArc((4, 1), (3.5, 0))
.mirrorX()
.extrude(-1.5)
.edges("<Z")
.fillet(1.2)
)
inner = (
cq.Workplane("XY")
.lineTo(2, 2)
.threePointArc((4, 1), (3.5, 0))
.mirrorX()
.offset2D(-0.1, kind="intersection")
.extrude(-1.4)
.edges("<Z")
.fillet(1.1)
)

heart = outer - inner
show_object(heart, name="heart")



which generates:

heart.png

I find the "BRep_API: command not done" message frustrating as it doesn't really give any information about why.  I understand that this is a core issue and not specific to CadQuery but it definitely increases the slope of the learning curve.

Cheers,
Roger

--
cadquery home: https://github.com/CadQuery/cadquery
post issues at https://github.com/CadQuery/cadquery/issues
run it at home at : https://github.com/CadQuery/CQ-editor
---
You received this message because you are subscribed to the Google Groups "CadQuery" group.
To unsubscribe from this group and stop receiving emails from it, send an email to cadquery+u...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/cadquery/ebd69e9e-720b-4940-b2b2-6bde9c81dd47n%40googlegroups.com.

Sean Leavey

unread,
Oct 20, 2021, 2:30:04 PM10/20/21
to CadQuery
Wow, that's perfect! Thanks for that.
Reply all
Reply to author
Forward
0 new messages