use super::Ink;
pub(super) const SPAN: i64 = 1000;
pub(super) enum Shape {
Disc { cx: i64, cy: i64, r: i64, ink: Ink },
Ring {
cx: i64,
cy: i64,
r: i64,
half: i64,
ink: Ink,
},
Bar {
ax: i64,
ay: i64,
bx: i64,
by: i64,
half: i64,
ink: Ink,
},
}
impl Shape {
pub(super) fn ink(&self) -> Ink {
match self {
Self::Disc { ink, .. } | Self::Ring { ink, .. } | Self::Bar { ink, .. } => *ink,
}
}
pub(super) fn holds(&self, x: i64, y: i64, den: i64) -> bool {
match self {
Self::Disc { cx, cy, r, .. } => square(x - cx * den, y - cy * den) <= (r * den).pow(2),
Self::Ring {
cx, cy, r, half, ..
} => {
let from = square(x - cx * den, y - cy * den);
from <= ((r + half) * den).pow(2) && from >= ((r - half) * den).pow(2)
}
Self::Bar {
ax,
ay,
bx,
by,
half,
..
} => {
let (ax, ay) = (x - ax * den, y - ay * den);
let (bx, by) = (x - bx * den, y - by * den);
let (ux, uy) = (ax - bx, ay - by);
let along = ax * ux + ay * uy;
let span = square(ux, uy);
let reach = (half * den).pow(2);
if along <= 0 {
square(ax, ay) <= reach
} else if along >= span {
square(bx, by) <= reach
} else {
i128::from(square(ax, ay) - reach) * i128::from(span)
<= i128::from(along).pow(2)
}
}
}
}
pub(super) fn element(&self) -> String {
match self {
Self::Disc { cx, cy, r, ink } => format!(
" <circle cx=\"{cx}\" cy=\"{cy}\" r=\"{r}\" fill=\"{}\"/>",
ink.hex()
),
Self::Ring {
cx,
cy,
r,
half,
ink,
} => format!(
" <circle cx=\"{cx}\" cy=\"{cy}\" r=\"{r}\" fill=\"none\" \
stroke=\"{}\" stroke-width=\"{}\"/>",
ink.hex(),
half * 2
),
Self::Bar {
ax,
ay,
bx,
by,
half,
ink,
} => format!(
" <line x1=\"{ax}\" y1=\"{ay}\" x2=\"{bx}\" y2=\"{by}\" \
stroke=\"{}\" stroke-width=\"{}\" stroke-linecap=\"round\"/>",
ink.hex(),
half * 2
),
}
}
}
fn square(x: i64, y: i64) -> i64 {
x.pow(2) + y.pow(2)
}