use super::super::ir::{Bbox, PlacedNode};
use super::geometry::bearing_dir;
use crate::resolve::{AttrMap, ResolvedInst, ResolvedValue};
const OVERHANG: f64 = 4.0;
pub(crate) fn is_chrome(attrs: &AttrMap) -> bool {
attrs.get("chrome").is_some()
}
pub(in crate::layout) fn placeholder(inst: &ResolvedInst) -> PlacedNode {
PlacedNode {
id: inst.id.clone(),
kind: inst.kind,
type_chain: inst.type_chain.clone(),
applied_styles: inst.applied_styles.clone(),
label: None,
attrs: inst.attrs.clone(),
own_style: inst.own_style.clone(),
markers: inst.markers.clone(),
cx: 0.0,
cy: 0.0,
bbox: Bbox::empty(),
rotation: 0.0,
children: Vec::new(),
gutters: Vec::new(),
links: Vec::new(),
sketch: None,
origin: (0.0, 0.0),
span: inst.span,
}
}
pub(in crate::layout) fn fill(children: &mut [PlacedNode], geometry: Bbox, scale: f64) {
for c in children.iter_mut() {
if let Some(ResolvedValue::Tuple(items)) = c.attrs.get("chrome")
&& let [
ResolvedValue::Ident(k),
ResolvedValue::Ident(sense),
ResolvedValue::Number(pitch),
] = items.as_slice()
&& k == "thread-arc"
{
thread_arc(c, geometry, sense == "internal", *pitch, scale);
continue;
}
let bearing = match c.attrs.get("chrome") {
Some(ResolvedValue::Ident(k)) if k == "x-axis" => 90.0,
Some(ResolvedValue::Ident(k)) if k == "y-axis" => 0.0,
Some(ResolvedValue::Number(b)) => *b,
_ => continue,
};
let d = bearing_dir(bearing);
let corners = [
(geometry.min_x, geometry.min_y),
(geometry.max_x, geometry.min_y),
(geometry.min_x, geometry.max_y),
(geometry.max_x, geometry.max_y),
];
let (mut lo, mut hi) = (f64::INFINITY, f64::NEG_INFINITY);
for (x, y) in corners {
let t = x * d.0 + y * d.1;
lo = lo.min(t);
hi = hi.max(t);
}
let (lo, hi) = (lo - OVERHANG, hi + OVERHANG);
let (a, b) = ((d.0 * lo, d.1 * lo), (d.0 * hi, d.1 * hi));
let point = |p: (f64, f64)| {
ResolvedValue::Tuple(vec![ResolvedValue::Number(p.0), ResolvedValue::Number(p.1)])
};
c.attrs
.insert("points", ResolvedValue::List(vec![point(a), point(b)]));
let half = c.attrs.number("stroke-width").unwrap_or(0.0) / 2.0;
c.bbox = Bbox {
min_x: a.0.min(b.0),
min_y: a.1.min(b.1),
max_x: a.0.max(b.0),
max_y: a.1.max(b.1),
}
.inflate(half);
}
}
fn thread_arc(c: &mut PlacedNode, geometry: Bbox, internal: bool, pitch: f64, scale: f64) {
let r_drawn = geometry.w() / 2.0;
let r = if internal {
r_drawn + 0.54125 * pitch * scale
} else {
r_drawn - super::threads::THREAD_DEPTH * pitch * scale
};
if r <= 0.0 {
return;
}
let n = super::geometry::n;
c.attrs.insert(
"path",
crate::resolve::ResolvedValue::String(format!(
"M {} 0 A {} {} 0 1 1 0 {}",
n(r),
n(r),
n(r),
n(-r)
)),
);
c.kind = crate::resolve::NodeKind::Path;
let half = c.attrs.number("stroke-width").unwrap_or(0.0) / 2.0;
c.bbox = Bbox::centered(2.0 * r, 2.0 * r).inflate(half);
}