Patterns and mirrors of holes drill each copy afresh (its spot moved by the instance transform and found on the surface there), so a blind hole's depth counts from the face at the copy instead of from the bottom of the original hole (QA s30: three blind holes now remove three holes)
Co-Authored-By: Claude Opus 5.5 <[email protected]> Claude-Session: https://claude.ai/code/session_01AS5Tn3xieewUSg3uxrMVdL
This commit is contained in:
1 parent
83a10c813a
commit
b36b332619
2 files changed
+58
-4
No files matched your search
+32
-4
@@ -1134,6 +1134,20 @@ fn hole_spots(st: &ModelState, f: &Feature) -> Result<(Vec<Vec3>, Vec3)> {
|
||||
Ok((spots.into_iter().map(|p| hole_on_surface(st, p, dir)).collect(), dir))
|
||||
}
|
||||
|
||||
/// A hole's spots as given (not yet moved onto the surface) and its direction.
|
||||
fn hole_spots_raw(st: &ModelState, f: &Feature) -> Result<(Vec<Vec3>, Vec3)> {
|
||||
let FeatureKind::Hole { position, direction, points, .. } = &f.kind else { return Err(DocError::Invalid("not a hole".into())) };
|
||||
match points {
|
||||
Some(sp) => {
|
||||
let ss = st.sketch(sp.sketch).ok_or_else(|| DocError::Unknown(format!("sketch {}", sp.sketch)))?;
|
||||
let v: Vec<Vec3> =
|
||||
sp.ids.iter().filter_map(|id| ss.sketch.points.iter().find(|p| &p.id == id)).map(|p| ss.plane.to_world(p.pos)).take(10_000).collect();
|
||||
Ok((v, -ss.plane.normal()))
|
||||
}
|
||||
None => Ok((vec![*position], direction.normalized().ok_or_else(|| DocError::Invalid("hole direction".into()))?)),
|
||||
}
|
||||
}
|
||||
|
||||
/// The cutting tools of one hole at `position`, drilling along `dir`.
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
fn hole_tools(
|
||||
@@ -1766,12 +1780,26 @@ fn replay(doc: &Document, vals: &BTreeMap<String, Value>, f: &Feature, st: &mut
|
||||
}
|
||||
continue;
|
||||
}
|
||||
let tools = feature_tools(vals, src, st)?;
|
||||
let (op, targets) = feature_op(src);
|
||||
let mut copies = Vec::new();
|
||||
for m in mats {
|
||||
for t in &tools {
|
||||
copies.push(kernel::transform_matrix(t, *m)?);
|
||||
if let FeatureKind::Hole { diameter, depth, hole, .. } = &src.kind {
|
||||
// A hole is drilled again at each copy of its spot (found on the surface there), so
|
||||
// a blind hole's depth counts from the face at the copy, not from the bottom of the
|
||||
// original hole under the original spot.
|
||||
let (spots, dir) = hole_spots_raw(st, src)?;
|
||||
for m in mats {
|
||||
let d = crate::apply_vector(m, dir).normalized().ok_or_else(|| DocError::Invalid("hole direction".into()))?;
|
||||
for p in &spots {
|
||||
let at = hole_on_surface(st, crate::apply_point(m, *p), d);
|
||||
copies.extend(hole_tools(vals, st, &at, d, diameter, depth, hole)?);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
let tools = feature_tools(vals, src, st)?;
|
||||
for m in mats {
|
||||
for t in &tools {
|
||||
copies.push(kernel::transform_matrix(t, *m)?);
|
||||
}
|
||||
}
|
||||
}
|
||||
// New bodies from a pattern join their source when they touch it (as one feature would).
|
||||
|
||||
@@ -114,3 +114,29 @@ fn path_pattern_orientation_follows_the_path() {
|
||||
assert!((width_of_copy("identical") - 2.0).abs() < 1e-6);
|
||||
assert!((width_of_copy("path") - 4.0).abs() < 1e-6);
|
||||
}
|
||||
|
||||
/// Patterns of a blind hole drill every copy to the full depth from the face at the copy
|
||||
/// (QA s30): n copies remove n times one hole.
|
||||
#[test]
|
||||
fn patterns_of_a_blind_hole_drill_every_copy() {
|
||||
let one = {
|
||||
let mut s = Session::default();
|
||||
run(&mut s, "PrimitiveBox", json!({"length": 50, "width": 25, "height": 15}));
|
||||
let v0 = volume(&mut s);
|
||||
run(&mut s, "FusionHoleCommand", json!({"position": [10, 12, 15], "diameter": "5 mm", "depth": "10 mm"}));
|
||||
v0 - volume(&mut s)
|
||||
};
|
||||
let patterned = |p: (&str, Value)| {
|
||||
let mut s = Session::default();
|
||||
run(&mut s, "PrimitiveBox", json!({"length": 50, "width": 25, "height": 15}));
|
||||
let v0 = volume(&mut s);
|
||||
run(&mut s, "FusionHoleCommand", json!({"position": [10, 12, 15], "diameter": "5 mm", "depth": "10 mm"}));
|
||||
run(&mut s, p.0, p.1);
|
||||
v0 - volume(&mut s)
|
||||
};
|
||||
let r = patterned(("PatternRectangular", json!({"features": ["Hole1"], "dir1": [1, 0, 0], "count1": 3, "spacing1": "15 mm"})));
|
||||
assert!((r - 3.0 * one).abs() < 1e-3 * one, "{r} vs 3 × {one}");
|
||||
let c =
|
||||
patterned(("PatternCircular", json!({"features": ["Hole1"], "axis": {"origin": [25, 12, 0], "dir": [0, 0, 1]}, "count": 2, "angle": 360})));
|
||||
assert!((c - 2.0 * one).abs() < 1e-3 * one, "{c} vs 2 × {one}");
|
||||
}
|
||||
Reference in new issue
Block a user