refactor(ribbon): simplify draw tool registry

This commit is contained in:
Hakan Seven committed 2026-09-10 17:23:08 +03:00
1 parent 1b3efb84de
commit acba9f87bd
17 files changed
+269 -150

No files matched your search

+30 -3
View File
@@ -4,10 +4,10 @@
// Produces a Ray entity; repeats until Enter/Esc.
// XLINE — infinite construction line: same two-click pattern, yields XLine.
use crate::t;
use acadrust::entities::{Ray as RayEnt, XLine as XLineEnt};
use acadrust::types::Vector3;
use acadrust::EntityType;
use crate::t;
use crate::command::{CadCommand, CmdResult};
use crate::scene::model::wire_model::WireModel;
@@ -226,7 +226,34 @@ impl CadCommand for XLineCommand {
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn repeated_rays_and_xlines_keep_their_first_point() {
let base = DVec3::new(2.0, 3.0, 4.0);
let mut ray = RayCommand::new();
let mut xline = XLineCommand::new();
assert!(matches!(ray.on_point(base), CmdResult::NeedPoint));
assert!(matches!(xline.on_point(base), CmdResult::NeedPoint));
for through in [DVec3::new(3.0, 3.0, 4.0), DVec3::new(2.0, 5.0, 4.0)] {
let CmdResult::CommitEntity(EntityType::Ray(entity)) = ray.on_point(through) else {
panic!("ray was not committed");
};
assert_eq!(entity.base_point, Vector3::new(base.x, base.y, base.z));
let CmdResult::CommitEntity(EntityType::XLine(entity)) = xline.on_point(through) else {
panic!("construction line was not committed");
};
assert_eq!(entity.base_point, Vector3::new(base.x, base.y, base.z));
}
}
}
// ── Autocomplete registry ─────────────────────────────────
inventory::submit!(crate::command::CommandRegistration { names: &["RAY"] }); // RayCommand
inventory::submit!(crate::command::CommandRegistration { names: &["CONSTRUCTIONLINE", "XLINE"] }); // XLineCommand
inventory::submit!(crate::command::CommandRegistration { names: &["RAY"] }); // RayCommand
inventory::submit!(crate::command::CommandRegistration {
names: &["CONSTRUCTIONLINE", "XLINE"]
}); // XLineCommand
+59 -14
View File
@@ -3,9 +3,9 @@
// Command: SPLINE (SPL)
// Click to add fit points. Enter (≥2 pts) → commits EntityType::Spline.
use crate::t;
use acadrust::types::Vector3;
use acadrust::{EntityType, Spline};
use crate::t;
use crate::command::{CadCommand, CmdResult};
use crate::modules::{IconKind, ModuleEvent, ToolDef};
@@ -30,27 +30,35 @@ pub struct SplineCommand {
impl SplineCommand {
pub fn new() -> Self {
Self { pts: Vec::new(), control_vertices: false, choosing_method: false }
Self {
pts: Vec::new(),
control_vertices: false,
choosing_method: false,
}
}
pub fn control_vertices() -> Self {
Self { control_vertices: true, ..Self::new() }
Self {
control_vertices: true,
..Self::new()
}
}
fn build(&self, closed: bool) -> Option<EntityType> {
if self.pts.len() < 2 {
return None;
}
Some(EntityType::Spline(make_spline(&self.pts, closed, self.control_vertices)))
Some(EntityType::Spline(make_spline(
&self.pts,
closed,
self.control_vertices,
)))
}
}
/// Store the chosen construction method directly in the persistent spline.
fn make_spline(pts: &[DVec3], closed: bool, control_vertices: bool) -> Spline {
let mut points: Vec<Vector3> = pts
.iter()
.map(|p| Vector3::new(p.x, p.y, p.z))
.collect();
let mut points: Vec<Vector3> = pts.iter().map(|p| Vector3::new(p.x, p.y, p.z)).collect();
let mut spline = if control_vertices {
if closed && pts.first() != pts.last() {
points.push(points[0]);
@@ -61,9 +69,13 @@ fn make_spline(pts: &[DVec3], closed: bool, control_vertices: bool) -> Spline {
// Open uniform knot vector: degree + 1 equal knots at each endpoint.
let knots = (0..count + degree + 1)
.map(|index| {
if index <= degree { 0.0 }
else if index >= count { 1.0 }
else { (index - degree) as f64 / spans as f64 }
if index <= degree {
0.0
} else if index >= count {
1.0
} else {
(index - degree) as f64 / spans as f64
}
})
.collect();
Spline {
@@ -103,7 +115,11 @@ fn sample_curve(pts: &[DVec3], closed: bool, control_vertices: bool) -> Vec<[f32
impl CadCommand for SplineCommand {
fn name(&self) -> &'static str {
if self.control_vertices { "SPLINECV" } else { "SPLINE" }
if self.control_vertices {
"SPLINECV"
} else {
"SPLINE"
}
}
fn prompt(&self) -> String {
@@ -122,7 +138,10 @@ impl CadCommand for SplineCommand {
fn options(&self) -> Vec<crate::command::CmdOption> {
use crate::command::CmdOption;
if self.choosing_method {
return vec![CmdOption::new("Fit", "FIT"), CmdOption::new("Control vertices", "CV")];
return vec![
CmdOption::new("Fit", "FIT"),
CmdOption::new("Control vertices", "CV"),
];
}
if self.pts.is_empty() {
return vec![CmdOption::new(t!("Method").as_ref(), "M")];
@@ -213,6 +232,32 @@ impl CadCommand for SplineCommand {
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn control_vertices_make_a_clamped_finite_spline() {
let points = [
DVec3::new(0.0, 0.0, 0.0),
DVec3::new(1.0, 2.0, 0.0),
DVec3::new(2.0, 2.0, 0.0),
DVec3::new(3.0, 0.0, 0.0),
];
let spline = make_spline(&points, false, true);
assert_eq!(spline.degree, 3);
assert_eq!(spline.control_points.len(), 4);
assert_eq!(spline.knots, vec![0.0, 0.0, 0.0, 0.0, 1.0, 1.0, 1.0, 1.0]);
assert_eq!(spline.weights, vec![1.0; 4]);
assert!(sample_curve(&points, false, true)
.iter()
.flatten()
.all(|value| value.is_finite()));
}
}
// ── Autocomplete registry ─────────────────────────────────
inventory::submit!(crate::command::CommandRegistration { names: &["SPLINE", "SPLINECV"] }); // SplineCommand
inventory::submit!(crate::command::CommandRegistration {
names: &["SPLINE", "SPLINECV"]
}); // SplineCommand