variable radius fillet

32 views
Skip to first unread message

D Del Vento

unread,
Jan 16, 2025, 9:53:22 PMJan 16
to CadQuery
I'm trying to model a piano black key, which looks like this


As you can see, it has a variable fillet. which AFAICT CQ does not support (despite Google search AI claiming the contrary and providing code that does not work ROTFL)

The best I can do with "traditional" CQ tools is

key_thickness = 10
key_len = 100
key_height = 24

keytop = Workplane("XY").box(key_len, key_thickness, key_height)

cut_front = Workplane("XY").box(key_len, 2 * key_thickness, 2 * key_height)
cut_front = cut_front.rotate((0, 0, 0), (0, 1, 0), 75)
cut_front = cut_front.translate((0.5 * key_len, 0, 0))
keytop = keytop.cut(cut_front)

cut_corner = Workplane("XY").box(key_height, key_height, key_height)
cut_corner = cut_corner.rotate((0, 0, 0), (0, 1, 0), 45)
cut_corner = cut_corner.rotate((0, 0, 0), (0, 0, 1), 45)
cut_corner = cut_corner.translate((1.3 * key_height, 0.5 * key_thickness, 0.8 * key_height))
keytop = keytop.cut(cut_corner)

cut_corner = Workplane("XY").box(key_height, key_height, key_height)
cut_corner = cut_corner.rotate((0, 0, 0), (0, 1, 0), 45)
cut_corner = cut_corner.rotate((0, 0, 0), (0, 0, 1), -45)
cut_corner = cut_corner.translate((1.3 * key_height, -0.5 * key_thickness, 0.8 * key_height))
keytop = keytop.cut(cut_corner)

keytop = keytop.fillet(2)

cut_bottom = Workplane("XY").box(2 * key_len, 2 * key_thickness, key_height)
cut_bottom = cut_bottom.translate((0, 0, - 0.9 * key_height))
keytop = keytop.cut(cut_bottom)

cut_back = Workplane("XY").box(key_len, 2 * key_thickness, 2 * key_height)
cut_back = cut_back.translate((- 0.9 * key_len, 0, 0))
keytop = keytop.cut(cut_back)

which is completely ugly and not at all similar to what I want/need. Jumping through many hoops, I think I can make design it doing something like the following

profile = Workplane("XY")
profile = profile.workplane(offset= -key_height)

fillet_r = 10
a = key_len / 2 - fillet_r
b = key_thickness / 2 - fillet_r

#profile = profile.radiusArc((a + fillet_r, -key_thickness), 10)
profile = profile.moveTo(+a + fillet_r, +b)
profile = profile.lineTo(+a + fillet_r, -b)
#profile = profile.lineTo(+a, -b + fillet_r)
profile = profile.radiusArc((+a, -b + fillet_r), -fillet_r)
profile = profile.lineTo(-a, -b + fillet_r)
#profile = profile.lineTo(-a - fillet_r, -b)
profile = profile.radiusArc((-a - fillet_r, -b), -fillet_r)
profile = profile.lineTo(-a - fillet_r, +b)
#profile = profile.lineTo(-a, b - fillet_r)
profile = profile.radiusArc((-a, b - fillet_r), -fillet_r)
profile = profile.lineTo(+a, b - fillet_r)
profile = profile.radiusArc((+a + fillet_r, +b), -fillet_r)
profile = profile.close()

old_fillet_r = fillet_r
fillet_r = key_thickness / 2 - 0.0001
a = key_len * 0.8 / 2 - fillet_r
b = key_thickness / 2 - fillet_r

profile = profile.workplane(offset= key_height)
profile = profile.moveTo(+a + fillet_r, +b)
profile = profile.lineTo(+a + fillet_r, -b)
#profile = profile.lineTo(+a, -b + fillet_r)
profile = profile.radiusArc((+a, -b + fillet_r), -fillet_r)
profile = profile.lineTo(-a, -b + fillet_r)
#profile = profile.lineTo(-a - fillet_r, -b)
profile = profile.radiusArc((-a - fillet_r, -b), -fillet_r)
profile = profile.lineTo(-a - fillet_r, +b)
#profile = profile.lineTo(-a, b - fillet_r)
profile = profile.radiusArc((-a, b - fillet_r), -fillet_r)
profile = profile.lineTo(+a, b - fillet_r)
profile = profile.radiusArc((+a + fillet_r, +b), -fillet_r)
profile = profile.close()

keytop = profile.loft(ruled= False, combine= False)

At the moment this is not correct, but I see that all the tools that are needed to make it work are there. I just need to do the math correctly (in dedicated functions) and with multiple levels (as I  learned in this chat from the lofted log spiral).

Is that the way to go, or is there an easier/simpler/more robust approach?

Adam Urbanczyk

unread,
Jan 17, 2025, 2:09:49 AMJan 17
to CadQuery
You could experiment with lofts, see for https://github.com/cubiq/OPK inspiration.

D Del Vento

unread,
Jan 17, 2025, 9:35:27 AMJan 17
to CadQuery
Thanks, that's exactly what I'm doing in my second example. 

The pain for doing it that way is somewhat justified in the case of the keycap, given the complexity of the shape. But for the black piano key it feels lots of work (to identify all the necessary middle points at the necessary resolution for not being too coarsely defined) for something that is simply straight lines with a variable radius fillet, hence my question.

Reply all
Reply to author
Forward
0 new messages