Marks at specific angles of circle
janosh opened this issue · comments
admittedly, this diagram is a bit of a mess right now:
i'm trying to create marks at 6 points along a circle to achieve this output. i changed from circle
to arc
since circle
doesn't seem to support arc
at all. but even with arc
, i only managed to place marks at start
and end
. i was looking through this PR but didn't spot an example of intermediate marks but might have missed it
#import "@preview/cetz:0.3.2": canvas, draw
#import "@preview/modpattern:0.1.0": modpattern
#set page(width: auto, height: auto, margin: 8pt)
#let hatched = modpattern(
(.1cm, .1cm),
std.line(start: (0%, 100%), end: (100%, 0%), stroke: 0.5pt),
background: white,
)
#canvas({
import draw: line, content, circle, arc, group, translate, mark, rotate
// Define styles and constants
let radius = 1.25 // \lrad in original
let small-rad = 0.1 * radius // \srad in original
let med-rad = 0.15 * radius // \mrad in original
let arrow-style = (
mark: (end: "stealth", fill: black, scale: .5),
stroke: (paint: black, thickness: 0.75pt),
)
// Helper functions
let cross(pos, label: none, rel-label: (0, 5pt)) = {
content(pos, text(size: 16pt)[$times.circle$], stroke: none, fill: white, frame: "circle", padding: -2.5pt)
if label != none {
content((rel: rel-label, to: pos), $#label$)
}
}
let dressed-vertex(pos, label: none, rel-label: none) = {
circle(pos, radius: small-rad, fill: hatched, stroke: black)
if label != none {
content(
if rel-label != none { (rel: rel-label, to: pos) } else { pos },
label,
)
}
}
let momentum-label(pos, num) = {
content(pos, $p_#num$, size: 8pt)
}
// Draw first diagram
group({
// Main loop with momentum labels
arc(
(-radius, 0),
start: 0deg,
stop: 360deg,
radius: radius,
stroke: 1pt,
name: "loop",
mark: ("mid": "stealth", fill: black, scale: .5),
anchor: "arc-center",
)
// Add momentum arrows around loop
for (ii, pos) in ((6, "0.0625"), (1, "0.1875"), (2, "0.3125"), (3, "0.4375"), (4, "0.625"), (5, "0.875")) {
let percent = str(calc.round(float(pos) * 100, digits: 2)) + "%"
let angle = float(pos) * 360
let label-angle = (angle - 3) * 1deg
let label-pos = (
0.7 * radius * calc.cos(label-angle),
0.7 * radius * calc.sin(label-angle),
)
momentum-label(label-pos, ii)
mark(
"loop." + percent, // Start from the loop edge
(0, 0),
symbol: "stealth",
name: "p" + str(ii),
)
}
// Add dressed vertices and cross
cross((0, radius), label: $partial_k R_(k,i j) (p_1,p_2)$, rel-label: (0, 0.5))
dressed-vertex(
(radius * calc.cos(135deg), radius * calc.sin(135deg)),
label: $G_(k,j k)(p_2,p_3)$,
rel-label: (-1.2, 0.2),
)
dressed-vertex(
(radius * calc.cos(45deg), radius * calc.sin(45deg)),
label: $G_(k,n i)(p_6,p_1)$,
rel-label: (1.2, 0.2),
)
dressed-vertex(
(0, -radius),
label: $G_(k,l m) (p_4,p_5)$,
rel-label: (0, -0.6),
)
// External lines and labels
let ext-len = 2 * radius
line((-ext-len, 0), (-radius, 0), stroke: 1pt)
line((radius, 0), (ext-len, 0), stroke: 1pt)
content((-1.4 * radius, -0.3), $phi_a$)
content((1.4 * radius, -0.3), $phi_b$)
// External momentum arrows
line((-1.9 * radius, 0.15), (-1.25 * radius, 0.15), ..arrow-style, name: "q1-line")
content("q1-line", $q_1$, anchor: "south", padding: (0, 0, 2pt))
line((1.25 * radius, 0.15), (1.9 * radius, 0.15), ..arrow-style, name: "q2-line")
content("q2-line", $q_2$, anchor: "south", padding: (0, 0, 2pt))
// Vertex labels with connecting lines
let label-style = (stroke: gray + 0.4pt)
content((-2.2 * radius, -1.2 * radius), $Gamma_(k,a k l)^(3)(q_1,p_3,-p_4)$)
line((-1.6 * radius, -1 * radius), (-radius, 0), ..label-style)
dressed-vertex((-radius, 0))
content((2.3 * radius, -1.2 * radius), $Gamma_(k,b m n)^(3)(-q_2,p_5,-p_6)$)
line((1.6 * radius, -1 * radius), (radius, 0), ..label-style)
dressed-vertex((radius, 0))
})
})
You can place marks at a percentage of the path:
#import "@preview/cetz:0.3.2": canvas, draw
#set page(width: auto, height: auto, margin: 8pt)
#canvas({
import draw: *
set-style(arc: (mark: (width: .2, length: .075)))
arc((0, 0), name: "c", start: 0deg, stop: 360deg, anchor: "origin", mode: "PIE",
mark: (
end: (
(pos: 25% - 25%/2, symbol: "barbed"),
(pos: 25% + 25%/2, symbol: "barbed"),
(pos: 50% + 25%/4, symbol: "barbed"),
(pos: 75% - 25%/4, symbol: "barbed"),
(pos: 75% + 25%/4, symbol: "barbed"),
(pos: 75% + 25%/4*3, symbol: "barbed"),
),
// Do not shorten the arc
shorten-to: none,
))
})
(I discovered some bugs with arc anchors for 0-360 arcs.)
I guess the better alternative is to place marks on-top of a circle and use angle anchors:
#import "@preview/cetz:0.3.2": canvas, draw
#set page(width: auto, height: auto, margin: 8pt)
#canvas({
import draw: *
circle((0, 0), name: "c")
for angle in (22.5deg, 90deg - 22.5deg, 90deg + 22.5deg, 180deg - 22.5deg, 225deg, 315deg) {
mark(symbol: "barbed", width: .25, length: .1,
(name: "c", anchor: angle),
(name: "c", anchor: angle + .1deg))
}
})
excellent, thank you very much! i cleaned up the code a little. final result looks great as usual.
i keep discovering new features in CeTZ. impressive how close it has already come to feature parity with TikZ. definitely surpassed it in developer experience for my use cases :)