Merge pull request #1191 from ramox81/codex/fix-ray-invalid-input

This commit is contained in:
Hakan Seven committed 2026-09-11 12:36:18 +03:00
commit 7f6f56aa44
1 file changed
+93
+93
View File
@@ -50,6 +50,9 @@ impl CadCommand for RayCommand {
}
fn on_point(&mut self, pt: DVec3) -> CmdResult {
if !pt.is_finite() {
return CmdResult::NeedPoint;
}
if let Some(base) = self.base {
let dir = pt - base;
let len = dir.length();
@@ -408,6 +411,13 @@ impl CadCommand for XLineCommand {
mod tests {
use super::*;
fn direction(entity: EntityType) -> DVec3 {
let EntityType::XLine(entity) = entity else {
panic!("expected a construction line");
};
DVec3::new(entity.direction.x, entity.direction.y, entity.direction.z)
}
#[test]
fn repeated_rays_and_xlines_keep_their_first_point() {
let base = DVec3::new(2.0, 3.0, 4.0);
@@ -428,6 +438,89 @@ mod tests {
assert_eq!(entity.base_point, Vector3::new(base.x, base.y, base.z));
}
}
#[test]
fn ray_rejects_nonfinite_points_without_losing_its_base() {
let mut ray = RayCommand::new();
assert!(matches!(ray.on_point(DVec3::splat(f64::NAN)), CmdResult::NeedPoint));
let base = DVec3::new(1.0, 2.0, 3.0);
assert!(matches!(ray.on_point(base), CmdResult::NeedPoint));
assert!(matches!(ray.on_point(DVec3::splat(f64::INFINITY)), CmdResult::NeedPoint));
let CmdResult::CommitEntity(EntityType::Ray(entity)) = ray.on_point(base + DVec3::X)
else {
panic!("valid direction must commit a ray");
};
assert_eq!(entity.base_point, Vector3::new(base.x, base.y, base.z));
assert_eq!(entity.direction, Vector3::new(1.0, 0.0, 0.0));
}
#[test]
fn xline_horizontal_and_two_point_angle_use_the_working_plane() {
let plane = WorkingPlane::new(DVec3::ZERO, DVec3::Y, DVec3::Z);
let mut horizontal = XLineCommand::new();
horizontal.set_working_plane(plane);
assert!(matches!(horizontal.on_text_input("H"), Some(CmdResult::NeedPoint)));
let CmdResult::CommitEntity(entity) = horizontal.on_point(DVec3::new(3.0, 4.0, 5.0))
else {
panic!("horizontal mode must commit immediately");
};
assert!(direction(entity).abs_diff_eq(plane.x, 1.0e-12));
let mut angle = XLineCommand::new();
angle.set_working_plane(plane);
assert!(matches!(angle.on_text_input("A"), Some(CmdResult::NeedPoint)));
assert!(matches!(angle.on_point(DVec3::ZERO), CmdResult::NeedPoint));
assert!(matches!(angle.on_point(plane.y * 2.0), CmdResult::NeedPoint));
let CmdResult::CommitEntity(entity) = angle.on_point(DVec3::new(7.0, 8.0, 9.0))
else {
panic!("acquired angle must accept a through point");
};
assert!(direction(entity).abs_diff_eq(plane.y, 1.0e-12));
}
#[test]
fn xline_bisector_reuses_its_vertex_and_first_ray() {
let mut command = XLineCommand::new();
assert!(matches!(command.on_text_input("B"), Some(CmdResult::NeedPoint)));
assert!(matches!(command.on_point(DVec3::ZERO), CmdResult::NeedPoint));
assert!(matches!(command.on_point(DVec3::X), CmdResult::NeedPoint));
for end in [DVec3::Y, -DVec3::Y] {
let CmdResult::CommitEntity(entity) = command.on_point(end) else {
panic!("valid bisector must commit");
};
let expected = (DVec3::X + end).normalize();
assert!(direction(entity).abs_diff_eq(expected, 1.0e-12));
}
}
#[test]
fn xline_offset_distance_returns_to_source_selection() {
let mut command = XLineCommand::new();
assert!(matches!(command.on_text_input("O"), Some(CmdResult::NeedPoint)));
assert!(matches!(command.on_point(DVec3::ZERO), CmdResult::NeedPoint));
assert!(matches!(command.on_point(DVec3::Y * 2.0), CmdResult::NeedPoint));
assert!(command.needs_entity_pick());
let line = acadrust::entities::Line::from_points(
Vector3::new(0.0, 0.0, 0.0),
Vector3::new(1.0, 0.0, 0.0),
);
command.inject_picked_entity(EntityType::Line(line));
assert!(matches!(
command.on_entity_pick(acadrust::Handle::new(1), DVec3::ZERO),
CmdResult::NeedPoint
));
let CmdResult::CommitEntity(EntityType::XLine(entity)) =
command.on_point(DVec3::Y)
else {
panic!("offset side must commit a construction line");
};
assert_eq!(entity.base_point, Vector3::new(0.0, 2.0, 0.0));
assert_eq!(entity.direction, Vector3::new(1.0, 0.0, 0.0));
assert!(command.needs_entity_pick());
}
}
// ── Autocomplete registry ─────────────────────────────────