SVG markers (<marker>, placed via
marker-start/marker-mid/marker-end or the marker
shorthand) are positioned at a shape’s vertices —
moveto/lineto/curveto/arc endpoints, not curve control points — and
oriented along the tangent direction(s) of whatever segment(s) meet there.
This group is the vertex-and-tangent extraction and orientation-angle math
behind that placement, reusing the same get-datum-based technique
dc-path->polylines uses (racket/draw represents every
built shape using only two segment shapes, so no separate arc-tangent math
is needed even for native .arc/.ellipse geometry).
One vertex of a flattened path: its position
(x ,y), and the
tangent angle (in radians,
dc<%>’s own clockwise-in-y-down
convention) of the segment arriving at it (
in-angle) and the
segment leaving it (
out-angle) —
either is
#f if this
vertex is an endpoint of an open subpath with no segment on that side. A
closed subpath that doesn’t already loop back to its own starting point gets
an implicit closing vertex added (matching SVG’s own treatment of
Z/
z as generating its own vertex), consistent with how
dc-path->polylines closes a polyline’s loop explicitly too.
A zigzag path with each of its vertices marked:

Extracts every vertex of
p (across all of its subpaths), in order,
as described above. This is what
svg/svg calls internally to decide
where to place
marker-start/
marker-mid/
marker-end instances
along a
<path>,
<line>,
<polyline>, or
<polygon>.
Example:
Averages two angles
a1/
a2 (radians), correctly across the
wraparound at ±180°, where a naive
(/ (+ a1 a2) 2) would fail
(averaging 179° and −179° should give ~180°, not 0°). Implemented by summing
the two angles’ unit vectors and taking the resulting direction; if they
point exactly opposite each other (an ambiguous bisector), returns
perpendicular to
a1 as a reasonable, consistent convention rather
than an arbitrary one. This is what
marker-angle-degrees uses to
compute
orient="auto"’s bisector at a vertex where both an incoming and
an outgoing tangent exist.
Examples:
Two tangent directions (blue: incoming, green: outgoing) and their bisector
(red) at a vertex:

Computes the angle (in degrees) to rotate a marker instance placed at vertex
v, given its
orient (as
parse-marker-orient
returns it) and whether this is the path’s
marker-start vertex
specifically (
is-start?). A numeric
orient is returned
as-is;
'auto gives the bisector of
v’s
in-angle/
out-angle (via
average-angle), or
whichever one of the two exists at an open path’s endpoint;
'auto-start-reverse is the same, plus 180° when
is-start?
is true —
so a single arrowhead marker used as both
marker-start and
marker-end points consistently "into" the line at both ends rather than
the same nominal direction at both.
Parses a <marker>’s orient attribute: "auto" and
"auto-start-reverse" give the matching symbol; a numeric angle (in
degrees, with or without a trailing deg unit specifier being ignored
since only the leading number is read) gives that number; anything else
(including an absent value) gives 0.
Examples:
Arrowhead markers placed at each vertex of a curve, oriented via
marker-angle-degrees with orient= 'auto — each arrow
points along the curve’s own tangent direction at that point:
