cadcraft/crates/render/tests/plot_styles.rs

118 lines
5.4 KiB
Rust

//! Plot style tables applied to the display list (issue #410): colour-dependent tables map an
//! object's colour to its printed colour, screening, linetype and lineweight; layouts show them
//! when "Display plot styles" is on.
use std::sync::Arc;
use cadcraft_color::{Color, Rgb};
use cadcraft_doc::{Common, Drawing, EntityKind, Line, Lineweight, PlotStyle, PlotStyleKind, PlotStyleTable, Space};
use cadcraft_geom::Vec3;
use cadcraft_render::{DisplayList, Options, build, build_plot};
const BLACK: Rgb = Rgb(0, 0, 0);
fn line(y: f64) -> EntityKind {
EntityKind::Line(Line { a: Vec3::new(0.0, y, 0.0), b: Vec3::new(10.0, y, 0.0) })
}
/// Lines in red (1), green (3), colour 7 (ByLayer on layer 0) and a true orange, in `space`.
fn drawing(space: &Space) -> Drawing {
let mut d = Drawing::new_metric();
let c = |color| Common { color, ..Default::default() };
d.add(space, c(Color::Index(1)), line(0.0)).unwrap();
d.add(space, c(Color::Index(3)), line(1.0)).unwrap();
d.add(space, Common::default(), line(2.0)).unwrap();
d.add(space, c(Color::True(Rgb(255, 128, 0))), line(3.0)).unwrap();
d
}
fn with_table(t: PlotStyleTable) -> Options {
Options { plot_style_table: Some(Arc::new(t)), lineweights: true, ..Default::default() }
}
fn colours(l: &DisplayList) -> Vec<Rgb> {
l.prims.iter().map(|p| p.display_rgb(Rgb(255, 255, 255))).collect()
}
#[test]
fn monochrome_prints_every_colour_black() {
let d = drawing(&Space::Model);
let l = build_plot(&d, &Space::Model, &with_table(PlotStyleTable::builtin("monochrome.ctb").unwrap()));
assert_eq!(l.prims.len(), 4);
assert!(l.prims.iter().all(|p| p.color == BLACK && !p.aci7), "{:?}", l.prims);
// Without a table the colours are the objects'.
let plain = build_plot(&d, &Space::Model, &Options::default());
assert_eq!(colours(&plain), [Rgb(255, 0, 0), Rgb(0, 255, 0), BLACK, Rgb(255, 128, 0)]);
}
#[test]
fn grayscale_and_default_tables() {
let d = drawing(&Space::Model);
let l = build_plot(&d, &Space::Model, &with_table(PlotStyleTable::builtin("grayscale.ctb").unwrap()));
for c in colours(&l) {
assert!(c.0 == c.1 && c.1 == c.2, "grey: {c:?}");
}
let c = colours(&l);
assert!(c[1].0 > c[0].0, "green is lighter than red");
assert_eq!(c[2], BLACK, "colour 7 prints black");
let keep = build_plot(&d, &Space::Model, &with_table(PlotStyleTable::builtin("default.ctb").unwrap()));
assert_eq!(colours(&keep), colours(&build_plot(&d, &Space::Model, &Options::default())));
}
#[test]
fn screening_lineweight_and_linetype_overrides() {
let mut d = Drawing::new_metric();
d.header.set_f64("LTSCALE", 0.05);
d.add(&Space::Model, Common { color: Color::Index(1), lineweight: Lineweight::Mm100(13), ..Default::default() }, line(0.0)).unwrap();
d.add(&Space::Model, Common { color: Color::Index(5), ..Default::default() }, line(1.0)).unwrap();
let table = PlotStyleTable::color_dependent("pens.ctb", "", |i| {
(i == 1).then(|| PlotStyle {
color: Some(BLACK),
screening: 50,
lineweight: Some(70),
linetype: Some("DASHED".into()),
..PlotStyle::default()
})
});
let l = build_plot(&d, &Space::Model, &with_table(table.clone()));
let red: Vec<_> = l.prims.iter().filter(|p| p.color == Rgb(128, 128, 128)).collect();
assert!(red.len() > 1, "dashed into several pieces: {}", red.len());
assert!(red.iter().all(|p| p.lw == 0.7), "pen lineweight replaces 0.13 mm");
let blue: Vec<_> = l.prims.iter().filter(|p| p.color == Rgb(0, 0, 255)).collect();
assert_eq!(blue.len(), 1, "colour 5 keeps its own style");
assert_eq!(blue[0].lw, 0.25, "object lineweight (LWDEFAULT)");
// With lineweights off nothing gets a width.
let thin = build_plot(&d, &Space::Model, &Options { lineweights: false, ..with_table(table) });
assert!(thin.prims.iter().all(|p| p.lw == 0.0));
}
#[test]
fn layout_display_plot_styles_flag() {
let space = Space::Paper("Layout1".into());
let mut d = drawing(&space);
d.layouts[0].page.plot_style_table = "monochrome.ctb".into();
let red = |l: &DisplayList| l.prims.iter().any(|p| p.color == Rgb(255, 0, 0));
assert!(red(&build(&d, &space, &Options::default())), "flag off: object colours on screen");
d.layouts[0].page.show_plot_styles = true;
assert!(!red(&build(&d, &space, &Options::default())), "flag on: monochrome on screen");
// Plotting takes its table from the options (the plotter passes the page's).
assert!(red(&build_plot(&d, &space, &Options::default())));
// Model space and unknown tables draw object colours.
d.layouts[0].page.plot_style_table = "unknown.ctb".into();
assert!(red(&build(&d, &space, &Options::default())));
}
#[test]
fn hostile_tables_do_not_panic() {
let d = drawing(&Space::Model);
for styles in [Vec::new(), vec![PlotStyle { screening: 255, lineweight: Some(u16::MAX), linetype: Some("NOPE".into()), ..PlotStyle::default() }]]
{
let t = PlotStyleTable { name: "x.ctb".into(), styles, ..PlotStyleTable::default() };
let l = build_plot(&d, &Space::Model, &with_table(t));
assert_eq!(l.prims.len(), 4);
assert!(l.prims.iter().all(|p| p.lw <= 2.11));
}
let named = PlotStyleTable { kind: PlotStyleKind::Named, styles: vec![PlotStyle::object("Normal")], ..PlotStyleTable::default() };
assert_eq!(build_plot(&d, &Space::Model, &with_table(named)).prims.len(), 4);
}