Project faces split by hidden seams as a whole (#352)
Projecting a cylinder's wall or the face of a round along a circular edge failed with "face projection has an open or invalid boundary": these surfaces are stored in halves joined by hidden seams, and the projection dropped the seams but kept only the picked half. It now projects the whole patch, the face as drawn, through the same surface_patch the viewport uses to highlight it.
This commit is contained in:
1 parent
2ebceb6918
commit
511d105dcb
2 files changed
+33
No files matched your search
@@ -9,7 +9,13 @@ use crate::{DocError, Result};
|
||||
|
||||
type Key = (i64, i64, i64);
|
||||
|
||||
/// Boundary of the picked face as drawn: a closed surface cut into pieces (a cylinder or a
|
||||
/// round's torus in halves) projects as the whole patch, since its seams are hidden.
|
||||
pub(super) fn face_edges(mesh: &Mesh, face: u32, plane: &Plane) -> Result<Vec<usize>> {
|
||||
let patch = mesh.surface_patch(face as usize);
|
||||
if patch.len() > 1 {
|
||||
return family_edges(mesh, &patch.into_iter().collect(), plane);
|
||||
}
|
||||
let edges = mesh.face_edges(face).into_iter().filter(|e| !mesh.seams.get(*e).copied().unwrap_or(false)).collect();
|
||||
boundary_edges(mesh, edges, plane)
|
||||
}
|
||||
|
||||
@@ -499,3 +499,30 @@ fn project_and_include_from_other_bodies() {
|
||||
assert!(row["error"].is_null(), "{row}");
|
||||
assert!(row["warning"].as_str().is_some_and(|w| w.contains("lost")), "{row}");
|
||||
}
|
||||
|
||||
/// A cylinder's wall and the torus of a rounded rim are drawn as one face but stored in halves
|
||||
/// joined by hidden seams; projecting one projects the whole face, not an open half.
|
||||
#[test]
|
||||
fn faces_split_by_hidden_seams_project_whole() {
|
||||
let mut s = Session::default();
|
||||
run(&mut s, "sketch.create", json!({"plane":"XY"}));
|
||||
run(&mut s, "sketch.circle.center", json!({"center":[0,0],"radius":20}));
|
||||
run(&mut s, "sketch.finish", json!({}));
|
||||
run(&mut s, "solid.extrude", json!({"distance":10}));
|
||||
run(&mut s, "sketch.create", json!({"plane":"XZ"}));
|
||||
run(&mut s, "sketch.project", json!({"refs":[{"face":[20,0,5]}]}));
|
||||
let wall = run(&mut s, "sketch.inspect", json!({}));
|
||||
let heights: Vec<f64> =
|
||||
wall["curves"].as_array().unwrap().iter().flat_map(|c| [c["start_at"][1].as_f64().unwrap(), c["end_at"][1].as_f64().unwrap()]).collect();
|
||||
assert!(heights.iter().any(|y| y.abs() < 1e-6) && heights.iter().any(|y| (y.abs() - 10.).abs() < 1e-6), "{wall}");
|
||||
run(&mut s, "sketch.finish", json!({}));
|
||||
run(&mut s, "solid.fillet", json!({"edges":[[20,0,10]],"radius":3}));
|
||||
run(&mut s, "sketch.create", json!({"plane":"XY"}));
|
||||
let t = 0.5f64.sqrt() * 3.;
|
||||
run(&mut s, "sketch.project", json!({"refs":[{"face":[17. + t, 0, 7. + t]}]}));
|
||||
let round = run(&mut s, "sketch.inspect", json!({}));
|
||||
let mut radii: Vec<f64> = round["curves"].as_array().unwrap().iter().map(|c| c["radius"].as_f64().unwrap()).collect();
|
||||
radii.sort_by(f64::total_cmp);
|
||||
assert_eq!(radii.len(), 4, "{round}");
|
||||
assert!(radii[..2].iter().all(|r| (r - 17.).abs() < 1e-6) && radii[2..].iter().all(|r| (r - 20.).abs() < 1e-6), "{round}");
|
||||
}
|
||||
Reference in new issue
Block a user