forked from 1b-agent/opencadstudio-upstream
Complete 2D solid workflow
This commit is contained in:
1 parent
573ed3245e
commit
17dc0aff39
11 files changed
+257
-181
No files matched your search
@@ -1,11 +1,10 @@
|
||||
// 2D solid tool — interactive command.
|
||||
//
|
||||
// Command: SOLID (reachable as SO / SOLID2D — the bare SOLID verb currently
|
||||
// toggles the shaded display) — pick three or four corner points and commit a
|
||||
// filled triangle or quadrilateral. Four points may be picked either around
|
||||
// the perimeter (the natural order shown by the rubber band) or in the
|
||||
// traditional Z pattern. The command normalizes both forms to the DXF corner
|
||||
// order before committing. Enter after the third point commits a triangle.
|
||||
// Command: SOLID (reachable as SO / SOLID2D) — pick three or four corner points
|
||||
// and commit a filled triangle or quadrilateral. Four-point input is preserved
|
||||
// in the entity's documented Z order; after a quadrilateral, its opposite edge
|
||||
// starts the next connected shape. Enter after the third point commits a
|
||||
// triangle.
|
||||
|
||||
use acadrust::entities::Solid;
|
||||
use acadrust::types::Vector3;
|
||||
@@ -49,42 +48,12 @@ impl Solid2dCommand {
|
||||
Vector3::new(p.x, p.y, p.z)
|
||||
}
|
||||
|
||||
/// True when walking the four points in pick order produces a bow-tie.
|
||||
/// SOLID2D currently commits into the default world-XY OCS, so use that
|
||||
/// same plane when deciding whether the last two points need swapping.
|
||||
fn pick_order_crosses(points: &[DVec3]) -> bool {
|
||||
if points.len() != 4 {
|
||||
return false;
|
||||
}
|
||||
let orient = |a: DVec3, b: DVec3, c: DVec3| {
|
||||
(b.x - a.x) * (c.y - a.y) - (b.y - a.y) * (c.x - a.x)
|
||||
};
|
||||
let crosses = |a: DVec3, b: DVec3, c: DVec3, d: DVec3| {
|
||||
let ab_c = orient(a, b, c);
|
||||
let ab_d = orient(a, b, d);
|
||||
let cd_a = orient(c, d, a);
|
||||
let cd_b = orient(c, d, b);
|
||||
((ab_c > 0.0 && ab_d < 0.0) || (ab_c < 0.0 && ab_d > 0.0))
|
||||
&& ((cd_a > 0.0 && cd_b < 0.0) || (cd_a < 0.0 && cd_b > 0.0))
|
||||
};
|
||||
crosses(points[0], points[1], points[2], points[3])
|
||||
|| crosses(points[1], points[2], points[3], points[0])
|
||||
}
|
||||
|
||||
/// Convert either perimeter picks (1-2-3-4) or classic SOLID Z picks
|
||||
/// (1-2-4-3 around the perimeter) into the entity's DXF Z order.
|
||||
fn solid_from_four_points(points: &[DVec3]) -> Solid {
|
||||
let perimeter_order = !Self::pick_order_crosses(points);
|
||||
let (third, fourth) = if perimeter_order {
|
||||
(points[3], points[2])
|
||||
} else {
|
||||
(points[2], points[3])
|
||||
};
|
||||
Solid::new(
|
||||
Self::v3(points[0]),
|
||||
Self::v3(points[1]),
|
||||
Self::v3(third),
|
||||
Self::v3(fourth),
|
||||
Self::v3(points[2]),
|
||||
Self::v3(points[3]),
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -126,7 +95,10 @@ impl CadCommand for Solid2dCommand {
|
||||
.map(|point| self.plane.to_local(*point))
|
||||
.collect();
|
||||
let solid = Self::solid_from_four_points(&local);
|
||||
CmdResult::CommitAndExit(self.plane.place_entity(EntityType::Solid(solid)))
|
||||
let next_edge = [self.points[2], self.points[3]];
|
||||
self.points.clear();
|
||||
self.points.extend(next_edge);
|
||||
CmdResult::CommitEntity(self.plane.place_entity(EntityType::Solid(solid)))
|
||||
} else {
|
||||
CmdResult::NeedPoint
|
||||
}
|
||||
@@ -154,14 +126,22 @@ impl CadCommand for Solid2dCommand {
|
||||
if self.points.is_empty() {
|
||||
return None;
|
||||
}
|
||||
// Outline the corners picked so far plus the cursor, closed back to the
|
||||
// first point, as a rubber-band hint.
|
||||
// Outline the exact Z-ordered boundary that would be committed. Do not
|
||||
// reorder a crossing shape: point order is intentional geometry.
|
||||
let mut preview = self.points.clone();
|
||||
preview.push(pt);
|
||||
if preview.len() == 4 && Self::pick_order_crosses(&preview) {
|
||||
preview.swap(2, 3);
|
||||
}
|
||||
let mut pts: Vec<[f64; 3]> = preview.iter().map(|p| [p.x, p.y, p.z]).collect();
|
||||
let display_order: Vec<usize> = if preview.len() == 4 {
|
||||
vec![0, 1, 3, 2]
|
||||
} else {
|
||||
(0..preview.len()).collect()
|
||||
};
|
||||
let mut pts: Vec<[f64; 3]> = display_order
|
||||
.iter()
|
||||
.map(|index| {
|
||||
let point = preview[*index];
|
||||
[point.x, point.y, point.z]
|
||||
})
|
||||
.collect();
|
||||
pts.push([preview[0].x, preview[0].y, preview[0].z]);
|
||||
Some(WireModel::solid_f64(
|
||||
"rubber_band".to_string(),
|
||||
|
||||
Reference in new issue
Block a user