Files
cadcraft/crates/render/src/point.rs
T
Valentin KleinandClaude Opus 5.5 4c056c54bd Points draw with the point style (PDMODE/PDSIZE) (fixes #261) (#265)
POINT objects were always a one-pixel dot. They now draw the figure PDMODE
picks (nothing, plus, cross, tick, with an optional circle and/or square)
at the size PDSIZE gives: drawing units when positive, a percentage of the
view height when negative, 5 % when 0. The canvas passes its view height;
exports and plots use the plotted window or the extents.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-10 15:33:43 -04:00

59 lines
2.1 KiB
Rust

//! POINT display figures: point style (`PDMODE`) and size (`PDSIZE`).
use cadcraft_geom::{Circle, Vec2};
/// The figure a POINT draws.
#[derive(Debug, Default, PartialEq)]
pub struct Figure {
/// A one-pixel dot at the point.
pub dot: bool,
/// Line work (polylines).
pub lines: Vec<Vec<Vec2>>,
}
/// Figure size in drawing units: a positive `PDSIZE` is absolute, a negative one a percentage
/// of `view_height`, and 0 is 5 % of `view_height`.
pub fn size(pdsize: f64, view_height: f64) -> f64 {
if pdsize.is_finite() && pdsize > 0.0 {
return pdsize;
}
let percent = if pdsize.is_finite() && pdsize < 0.0 { -pdsize } else { 5.0 };
view_height * percent / 100.0
}
/// Whether `PDMODE` `mode` draws a figure with a size (anything but a dot or nothing).
pub fn sized(mode: i64) -> bool {
matches!(mode & 31, 2..=4) || mode & 96 != 0
}
/// The figure for `PDMODE` `mode`, `size` across, at `at`, turned by `angle` (radians). The low
/// bits pick dot (0), nothing (1), plus (2), cross (3) or a tick upwards (4); +32 adds a
/// circle and +64 a square. Without a usable size every visible figure falls back to a dot.
pub fn figure(mode: i64, size: f64, at: Vec2, angle: f64, tol: f64) -> Figure {
let base = mode & 31;
let mut f = Figure::default();
let r = size / 2.0;
if !(r.is_finite() && r > 0.0) {
f.dot = base != 1;
return f;
}
let angle = if angle.is_finite() { angle } else { 0.0 };
let p = |x: f64, y: f64| at + Vec2::new(x, y).rotate(angle);
match base {
1 => {}
2 => f.lines.extend([vec![p(-r, 0.0), p(r, 0.0)], vec![p(0.0, -r), p(0.0, r)]]),
3 => f.lines.extend([vec![p(-r, -r), p(r, r)], vec![p(-r, r), p(r, -r)]]),
4 => f.lines.push(vec![at, p(0.0, r)]),
_ => f.dot = true,
}
if mode & 32 != 0 {
let mut pts = Vec::new();
Circle { center: at, radius: r }.tessellate(tol.max(r * 1e-4), &mut pts);
f.lines.push(pts);
}
if mode & 64 != 0 {
f.lines.push(vec![p(-r, -r), p(r, -r), p(r, r), p(-r, r), p(-r, -r)]);
}
f
}