I apologize if the documentation for stuff like this is somewhere obvious, but I couldn’t find anything on filling in shapes made out of collections of curves. I am trying to convert over some of my old Tikz plots, and one of them was largely adapted from:
https://tex.stackexchange.com/questions/364646/how-do-you-create-a-keyhole-contour-not-centered-at-the-origin
How does one go about filling in a keyhole shaped contour? I know about cetz.angle.angle from one of the featured examples, but that would only get part of the contour.
Y.D.X
July 17, 2025, 3:47am
2
https://cetz-package.github.io/docs/api/draw-functions/shapes/compound-path/
https://cetz-package.github.io/docs/api/draw-functions/shapes/merge-path
These two functions might help?
A 60% implementation
#set page(height: auto, width: auto, margin: 2em)
#import "@preview/cetz:0.4.0"
#cetz.canvas({
import cetz.draw: *
compound-path(
group({
circle((0, 0), radius: 3, fill: blue)
circle((1, 1), radius: .5)
rotate(-45deg)
rect((-0.25, 1.8), (0.25, 3.1))
}),
fill: blue,
fill-rule: "even-odd",
)
})
Y.D.X
July 17, 2025, 4:36am
3
100% - ε implementation:
#set page(height: auto, width: auto, margin: 2em)
#import "@preview/cetz:0.4.0"
#cetz.canvas({
import cetz.draw: *
let R = 3 // outer.radius
let r = 0.5 // inner.radius
let c = 1 // distance(origin, inner.center)
let w = 1 / 4 // width of the hole
intersections(
"i",
{
hide(circle((0, 0), name: "outer", radius: R, fill: blue))
hide(circle((45deg, c), name: "inner", radius: r))
hide(group({
rotate(-45deg)
rect((-w / 2, c), (w / 2, R + r))
}))
},
)
// Debug:
// for-each-anchor("i", name => content("i." + name, name))
merge-path(
{
line("i.1", "i.3")
arc-through("i.3", (45deg, c - r), "i.2")
line("i.2", "i.0")
arc-through("i.0", (0, -R), "i.1")
},
fill: blue,
)
})
3 Likes
Ah, thank you, that looks wonderful.
I also didn’t realize much of the actual functionality of Cetz was explained in the API rather than the Docs.
1 Like