Edit Feature dialogs for rectangular/circular patterns, loft, sweep and move (directions along other vectors are kept)
Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_01AS5Tn3xieewUSg3uxrMVdL
This commit is contained in:
1 parent
0271919d52
commit
7518c4f4b5
1 file changed
+109
-4
@@ -9,7 +9,7 @@ use serde_json::{Value, json};
|
||||
use solvecraft_engine::Sel;
|
||||
use solvecraft_engine::Session;
|
||||
use solvecraft_engine::doc::expr::Kind as ValueKind;
|
||||
use solvecraft_engine::doc::{AxisRef, Direction, FeatureKind, HoleKind, Operation, PlaneRef, ProfileSel};
|
||||
use solvecraft_engine::doc::{AxisRef, Direction, FeatureKind, HoleKind, Operation, PatternKind, PlaneRef, ProfileSel};
|
||||
use solvecraft_engine::geom::Vec3;
|
||||
|
||||
use crate::SolveApp;
|
||||
@@ -1059,8 +1059,12 @@ fn dialog_commands(app: &SolveApp, d: &Dialog) -> Result<Vec<(String, Value)>, S
|
||||
}
|
||||
Kind::PatternRect { count, spacing, count2, spacing2 } => {
|
||||
need(0, "objects")?;
|
||||
need(1, "a direction (an axis or a sketch line)")?;
|
||||
let (_, d1) = sels(d, 1).first().and_then(|x| axis_of(app, x)).ok_or("the direction must be an axis or a sketch line")?;
|
||||
let kept = d.extra.get("dir1").and_then(|v| serde_json::from_value::<[f64; 3]>(v.clone()).ok()).map(|a| Vec3::new(a[0], a[1], a[2]));
|
||||
let d1 = match (sels(d, 1).first(), kept) {
|
||||
(Some(x), _) => axis_of(app, x).ok_or("the direction must be an axis or a sketch line")?.1,
|
||||
(None, Some(k)) => k,
|
||||
(None, None) => return Err("select a direction (an axis or a sketch line) first".into()),
|
||||
};
|
||||
let mut p = json!({"features": source_features(s, &body_names(0)), "dir1": pt(d1), "count1": count, "spacing1": spacing});
|
||||
if let Some((_, d2)) = sels(d, 2).first().and_then(|x| axis_of(app, x)) {
|
||||
p["dir2"] = pt(d2);
|
||||
@@ -1071,8 +1075,8 @@ fn dialog_commands(app: &SolveApp, d: &Dialog) -> Result<Vec<(String, Value)>, S
|
||||
}
|
||||
Kind::PatternCirc { count, angle } => {
|
||||
need(0, "objects")?;
|
||||
need(1, "an axis")?;
|
||||
let axis = match sels(d, 1).first() {
|
||||
None if d.extra.contains_key("axis") => d.extra.get("axis").cloned().unwrap_or(Value::Null),
|
||||
Some(Sel::Axis { name }) => json!(name),
|
||||
Some(x) => {
|
||||
let (o, dir) = axis_of(app, x).ok_or("the axis must be an origin axis or a sketch line")?;
|
||||
@@ -1296,6 +1300,11 @@ fn op_index(o: &Operation) -> usize {
|
||||
}
|
||||
}
|
||||
|
||||
/// The origin axis a unit direction runs along (either way), if any.
|
||||
fn world_axis(d: Vec3) -> Option<String> {
|
||||
[("X", Vec3::X), ("Y", Vec3::Y), ("Z", Vec3::Z)].into_iter().find(|(_, a)| d.cross(*a).len() < 1e-9 && d.dot(*a) > 0.0).map(|(n, _)| n.to_string())
|
||||
}
|
||||
|
||||
fn pt3(v: Vec3) -> Value {
|
||||
json!([v.x, v.y, v.z])
|
||||
}
|
||||
@@ -1476,6 +1485,102 @@ pub fn for_feature(app: &SolveApp, id: u64, marker: Option<usize>) -> Option<Dia
|
||||
}
|
||||
d
|
||||
}
|
||||
FeatureKind::Pattern { features, pattern } => {
|
||||
let ids: Vec<u64> = features.iter().filter_map(|n| s.doc.find_feature(n).map(|f| f.id)).collect();
|
||||
let bodies: Vec<Sel> = st.bodies.iter().filter(|b| ids.contains(&b.feature)).map(|b| Sel::Body { name: b.name.clone() }).collect();
|
||||
let mut d = match pattern {
|
||||
PatternKind::Rectangular { dir1, count1, spacing1, dir2, count2, spacing2 } => {
|
||||
let mut d = start("PatternRectangular")?;
|
||||
d.kind = Kind::PatternRect {
|
||||
count: count1.clone(),
|
||||
spacing: spacing1.clone(),
|
||||
count2: count2.clone().unwrap_or_else(|| "1".into()),
|
||||
spacing2: spacing2.clone().unwrap_or_else(|| "20 mm".into()),
|
||||
};
|
||||
// Directions along the origin axes show as those axes; others are kept as is.
|
||||
for (i, (key, dir)) in [("dir1", Some(*dir1)), ("dir2", *dir2)].into_iter().enumerate() {
|
||||
let Some(dir) = dir else { continue };
|
||||
match world_axis(dir) {
|
||||
Some(name) => {
|
||||
if let Some(inp) = d.inputs.get_mut(i + 1) {
|
||||
inp.items = vec![Sel::Axis { name }];
|
||||
}
|
||||
}
|
||||
None => {
|
||||
d.extra.insert(key.into(), pt3(dir));
|
||||
}
|
||||
}
|
||||
}
|
||||
d
|
||||
}
|
||||
PatternKind::Circular { origin, axis, count, angle } => {
|
||||
let mut d = start("PatternCircular")?;
|
||||
d.kind = Kind::PatternCirc { count: count.clone(), angle: angle.clone() };
|
||||
match world_axis(*axis).filter(|_| origin.len() < 1e-9) {
|
||||
Some(name) => {
|
||||
if let Some(inp) = d.inputs.get_mut(1) {
|
||||
inp.items = vec![Sel::Axis { name }];
|
||||
}
|
||||
}
|
||||
None => {
|
||||
d.extra.insert("axis".into(), json!({"origin": pt3(*origin), "dir": pt3(*axis)}));
|
||||
}
|
||||
}
|
||||
d
|
||||
}
|
||||
};
|
||||
if let Some(inp) = d.inputs.first_mut() {
|
||||
inp.items = bodies;
|
||||
}
|
||||
d
|
||||
}
|
||||
FeatureKind::Loft { sections, operation, targets } => {
|
||||
let mut d = start("SolidLoft")?;
|
||||
d.kind = Kind::Loft { operation: op_index(operation) };
|
||||
if let Some(inp) = d.inputs.first_mut() {
|
||||
inp.items = sections
|
||||
.iter()
|
||||
.flat_map(|sec| {
|
||||
let idx = st.sketch(sec.sketch).map(|ss| profile_indices(ss, &sec.profiles)).unwrap_or_default();
|
||||
idx.into_iter().map(move |index| Sel::Profile { sketch: sec.sketch, index })
|
||||
})
|
||||
.collect();
|
||||
}
|
||||
if !targets.is_empty() {
|
||||
d.extra.insert("targets".into(), json!(targets));
|
||||
}
|
||||
d
|
||||
}
|
||||
FeatureKind::Sweep { sketch, profiles, path, operation, targets, .. } => {
|
||||
let mut d = start("Sweep")?;
|
||||
d.kind = Kind::Sweep { operation: op_index(operation) };
|
||||
let items = st.sketch(*sketch).map(|ss| profile_indices(ss, profiles)).unwrap_or_default();
|
||||
if let Some(inp) = d.inputs.get_mut(0) {
|
||||
inp.items = items.into_iter().map(|index| Sel::Profile { sketch: *sketch, index }).collect();
|
||||
}
|
||||
if let Some(inp) = d.inputs.get_mut(1) {
|
||||
inp.items = path.iter().map(|id| Sel::SketchCurve { id: id.clone() }).collect();
|
||||
}
|
||||
if !targets.is_empty() {
|
||||
d.extra.insert("targets".into(), json!(targets));
|
||||
}
|
||||
d
|
||||
}
|
||||
FeatureKind::Move { bodies, translate, rotate_axis, angle } => {
|
||||
let mut d = start("FusionMoveCommand")?;
|
||||
let [x, y, z] = translate.clone();
|
||||
d.kind = Kind::Move { x, y, z };
|
||||
if let Some(inp) = d.inputs.first_mut() {
|
||||
inp.items = bodies.iter().map(|n| Sel::Body { name: n.clone() }).collect();
|
||||
}
|
||||
if let Some(a) = rotate_axis {
|
||||
d.extra.insert("axis".into(), pt3(*a));
|
||||
}
|
||||
if let Some(a) = angle {
|
||||
d.extra.insert("angle".into(), json!(a));
|
||||
}
|
||||
d
|
||||
}
|
||||
_ => return None,
|
||||
};
|
||||
d.editing = Some((id, marker));
|
||||
|
||||
Reference in new issue
Block a user