forked from 1b-agent/opencadstudio-upstream
fix(offset): allow OFFSET of XLINE (and Ellipse/Spline) objects (#296)
OFFSET rejected XLINE targets: on_entity_pick only accepted Line/Circle/Arc/LwPolyline, compute_offset had no XLine arm, and entity_wire_pts returned no points for it (so hover/preview/through-distance failed too). Add offset_xline (parallel infinite line: same direction, base point shifted perpendicular toward the pick side), a compute_offset arm, and an entity_wire_pts case (a long segment standing in for the infinite line during hit-test and preview; the committed XLine renders true). Also widen the pick filter to every type compute_offset supports — this additionally reaches Ellipse and Spline, whose offset functions already existed but weren't selectable. Co-Authored-By: Claude Opus 4.8 <[email protected]>
This commit is contained in:
1 parent
e015fbe328
commit
07eb9dcb9a
1 file changed
+47
-2
@@ -15,7 +15,7 @@ use crate::modules::draw::modify::spline_ops::{spline_pts_wire, spline_sample_xy
|
||||
use acadrust::entities::LwVertex;
|
||||
use acadrust::entities::{
|
||||
Arc as ArcEnt, Circle as CircleEnt, Ellipse as EllipseEnt, Line as LineEnt, LwPolyline,
|
||||
Spline as SplineEnt,
|
||||
Spline as SplineEnt, XLine as XLineEnt,
|
||||
};
|
||||
use acadrust::{EntityType, Handle};
|
||||
use glam::{DVec3, Vec3};
|
||||
@@ -86,6 +86,33 @@ fn offset_line(l: &LineEnt, dist: f64, side_pt: Vec3) -> Option<EntityType> {
|
||||
Some(EntityType::Line(new_l))
|
||||
}
|
||||
|
||||
// ── XLine (infinite construction line) offset ────────────────────────────────
|
||||
// A parallel infinite line: same direction, base point shifted perpendicular by
|
||||
// `dist` toward the side the cursor is on. (#296)
|
||||
|
||||
fn offset_xline(x: &XLineEnt, dist: f64, side_pt: Vec3) -> Option<EntityType> {
|
||||
let dx = x.direction.x;
|
||||
let dy = x.direction.y;
|
||||
let len = (dx * dx + dy * dy).sqrt();
|
||||
if len < 1e-12 {
|
||||
return None;
|
||||
}
|
||||
|
||||
let nx = -dy / len; // left-perpendicular
|
||||
let ny = dx / len;
|
||||
|
||||
let vx = side_pt.x as f64 - x.base_point.x;
|
||||
let vy = side_pt.y as f64 - x.base_point.y;
|
||||
let cross = dx * vy - dy * vx;
|
||||
let sign = if cross >= 0.0 { 1.0 } else { -1.0 };
|
||||
|
||||
let mut new_x = x.clone();
|
||||
new_x.common.handle = Handle::NULL;
|
||||
new_x.base_point.x += sign * nx * dist;
|
||||
new_x.base_point.y += sign * ny * dist;
|
||||
Some(EntityType::XLine(new_x))
|
||||
}
|
||||
|
||||
// ── Circle offset ──────────────────────────────────────────────────────────
|
||||
|
||||
fn offset_circle(c: &CircleEnt, dist: f64, side_pt: Vec3) -> Option<EntityType> {
|
||||
@@ -424,6 +451,7 @@ fn compute_offset(entity: &EntityType, dist: f64, side_pt: Vec3) -> Option<Entit
|
||||
EntityType::LwPolyline(p) => offset_lwpolyline(p, dist, side_pt),
|
||||
EntityType::Ellipse(e) => offset_ellipse(e, dist, side_pt),
|
||||
EntityType::Spline(s) => offset_spline(s, dist, side_pt),
|
||||
EntityType::XLine(x) => offset_xline(x, dist, side_pt),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
@@ -540,6 +568,18 @@ fn entity_wire_pts(e: &EntityType) -> Vec<[f32; 3]> {
|
||||
.collect()
|
||||
}
|
||||
EntityType::Spline(s) => spline_pts_wire(s),
|
||||
EntityType::XLine(x) => {
|
||||
// Infinite in both directions — represent it as a very long segment
|
||||
// for hit-testing and the offset preview. Long enough to read as
|
||||
// infinite at any working zoom; the committed XLine renders true.
|
||||
const HL: f64 = 1.0e6;
|
||||
let (bx, by, bz) = (x.base_point.x, x.base_point.y, x.base_point.z);
|
||||
let (dx, dy, dz) = (x.direction.x, x.direction.y, x.direction.z);
|
||||
vec![
|
||||
[(bx - dx * HL) as f32, (by - dy * HL) as f32, (bz - dz * HL) as f32],
|
||||
[(bx + dx * HL) as f32, (by + dy * HL) as f32, (bz + dz * HL) as f32],
|
||||
]
|
||||
}
|
||||
_ => vec![],
|
||||
}
|
||||
}
|
||||
@@ -690,11 +730,16 @@ impl CadCommand for OffsetCommand {
|
||||
.find(|e| e.common().handle == handle)
|
||||
.cloned();
|
||||
|
||||
// Accept every type compute_offset can offset — including XLine (#296),
|
||||
// and Ellipse/Spline whose offset functions existed but weren't reachable.
|
||||
match entity {
|
||||
Some(e @ EntityType::Line(_))
|
||||
| Some(e @ EntityType::Circle(_))
|
||||
| Some(e @ EntityType::Arc(_))
|
||||
| Some(e @ EntityType::LwPolyline(_)) => {
|
||||
| Some(e @ EntityType::LwPolyline(_))
|
||||
| Some(e @ EntityType::Ellipse(_))
|
||||
| Some(e @ EntityType::Spline(_))
|
||||
| Some(e @ EntityType::XLine(_)) => {
|
||||
self.step = Step::PickSide {
|
||||
handle,
|
||||
entity: e,
|
||||
|
||||
Reference in new issue
Block a user