use crate::patching::definition::Model;
fn view_box_mm(size_m: [f32; 2]) -> [f32; 2] {
size_m.map(|metres| (metres * 1000.0).round().max(1.0))
}
impl Model {
pub fn circle(name: impl Into<String>, diameter_m: f32) -> Self {
Self {
name: name.into(),
size_m: [diameter_m; 2],
svg: r##"<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 10 10"><circle cx="5" cy="5" r="4.5" fill="#ffffff"/></svg>"##
.to_string(),
}
}
pub fn rounded_rect(name: impl Into<String>, size_m: [f32; 2]) -> Self {
let [width, height] = view_box_mm(size_m);
let radius = 0.2 * width.min(height);
Self {
name: name.into(),
size_m,
svg: format!(
r##"<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 {width} {height}"><rect width="{width}" height="{height}" rx="{radius}" fill="#ffffff"/></svg>"##
),
}
}
pub fn frame(name: impl Into<String>, size_m: [f32; 2]) -> Self {
let [width, height] = view_box_mm(size_m);
let stroke = (0.04 * width.min(height)).clamp(1.0, 16.0);
let inset = stroke / 2.0;
let radius = 0.1 * width.min(height);
let inner_width = width - stroke;
let inner_height = height - stroke;
Self {
name: name.into(),
size_m,
svg: format!(
r##"<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 {width} {height}"><rect x="{inset}" y="{inset}" width="{inner_width}" height="{inner_height}" rx="{radius}" fill="none" stroke="#ffffff" stroke-width="{stroke}"/></svg>"##
),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn a_rounded_rect_spans_its_size_in_millimetres() {
let model = Model::rounded_rect("chip", [0.014, 0.09]);
assert!(model.svg.contains(r#"viewBox="0 0 14 90""#));
}
#[test]
fn a_zero_sized_frame_still_has_a_view_box() {
let model = Model::frame("body", [0.0, 0.0]);
assert!(model.svg.contains(r#"viewBox="0 0 1 1""#));
}
}