Skip to content

Commit

Permalink
3d tests, bore operation
Browse files Browse the repository at this point in the history
  • Loading branch information
Tom committed Jan 27, 2024
1 parent 0226877 commit ebcdfe3
Show file tree
Hide file tree
Showing 4 changed files with 194 additions and 13 deletions.
10 changes: 8 additions & 2 deletions detailer/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -914,6 +914,7 @@ impl<'a> Widget<'a> {
ui.set_min_width(60.0);
ui.selectable_value(&mut group.typ, GroupType::Hole, "Hole");
ui.selectable_value(&mut group.typ, GroupType::Extrude, "Extrude");
ui.selectable_value(&mut group.typ, GroupType::Bore, "Bore");
if ui.selectable_value(&mut group.typ, GroupType::Boundary, "Boundary").changed() {
boundary_group_set = Some(i);
};
Expand All @@ -929,10 +930,15 @@ impl<'a> Widget<'a> {
})
.body(|ui| {
match group.typ {
GroupType::Boundary | GroupType::Extrude => {
GroupType::Boundary | GroupType::Extrude | GroupType::Bore => {
ui.horizontal(|ui| {
let r = ui.available_size();
let text_rect = ui.add(egui::Label::new("Extrusion thickness").wrap(false)).rect;
let text_rect = ui.add(egui::Label::new(match group.typ {
GroupType::Boundary => "Part thickness",
GroupType::Extrude => "Extrusion thickness",
GroupType::Bore => "Bore depth",
_ => unreachable!(),
}).wrap(false)).rect;

if text_rect.width() < r.x / 2. {
ui.add_space(r.x / 2. - text_rect.width());
Expand Down
1 change: 1 addition & 0 deletions drawing/src/data/group.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ pub enum GroupType {
#[serde(alias = "Interior")]
Hole,
Extrude,
Bore,
}

#[derive(Clone, Debug, Default, PartialEq)]
Expand Down
6 changes: 6 additions & 0 deletions drawing/src/data/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ pub enum ExportErr {
#[derive(Clone, Copy, Debug, serde::Deserialize, serde::Serialize)]
pub enum CADOp {
Extrude(f64),
Bore(f64),
Hole,
}

Expand Down Expand Up @@ -1173,6 +1174,11 @@ impl Data {
ops.push((CADOp::Extrude(g.amt.unwrap_or(3.0)), p));
}
}
GroupType::Bore => {
for p in paths.into_iter() {
ops.push((CADOp::Bore(g.amt.unwrap_or(3.0)), p));
}
}
}
}

Expand Down
190 changes: 179 additions & 11 deletions drawing/src/l/three_d.rs
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,13 @@ pub fn extrude_from_paths(
let mut w = wire_from_path(path.clone(), &mut verts);

let (bottom_idx, top_idx) = *done_parents.get(&op_parent_idx[i]).unwrap();
let z_height = base[top_idx]
let bottom_offset_z = base[bottom_idx]
.absolute_boundaries()
.iter()
.map(|e| e.vertex_iter())
.flatten()
.fold(0.0, |acc: f64, v| acc.max(v.get_point().z));
let top_offset_z = base[top_idx]
.absolute_boundaries()
.iter()
.map(|e| e.vertex_iter())
Expand All @@ -133,11 +139,13 @@ pub fn extrude_from_paths(
match op {
CADOp::Hole => {
if path.area().signum() > 0.0 {
println!("inverting part: idx={}", i);
w.invert();
w.invert(); // negative geometry must have edges clockwise
}
let f: Face = builder::try_attach_plane(&vec![w]).unwrap();
let solid = builder::tsweep(&f, z_height * Vector3::unit_z());
let solid = builder::tsweep(
&f,
(top_offset_z - bottom_offset_z) * Vector3::unit_z(),
);
let mut b = solid.into_boundaries().pop().unwrap();

// Extract copies of the wires representing the boundaries of the hole.
Expand All @@ -152,12 +160,11 @@ pub fn extrude_from_paths(
}
CADOp::Extrude(amt) => {
if path.area().signum() < 0.0 {
println!("inverting part: idx={}", i);
w.invert();
w.invert(); // regular geometry must have edges counter-clockwise
}
let f: Face = builder::try_attach_plane(&vec![w]).unwrap();
let tf = builder::tsweep(&f, *amt * Vector3::unit_z());
let solid = builder::translated(&tf, z_height * Vector3::unit_z());
let solid = builder::translated(&tf, top_offset_z * Vector3::unit_z());
let b = solid.into_boundaries().pop().unwrap();

// Cut the base shape at the boundary so we can glue the extrusion
Expand All @@ -169,6 +176,26 @@ pub fn extrude_from_paths(

done_parents.insert(i as isize, (bottom_idx, base.len() - 1));
}
CADOp::Bore(amt) => {
if path.area().signum() > 0.0 {
w.invert(); // negative geometry must have edges clockwise
}
let f: Face = builder::try_attach_plane(&vec![w]).unwrap();
let tf = builder::tsweep(&f, *amt * Vector3::unit_z());
let solid =
builder::translated(&tf, (top_offset_z - *amt) * Vector3::unit_z());
let mut b = solid.into_boundaries().pop().unwrap();

let top_wire = &b.last().unwrap().boundaries()[0];
base[top_idx].add_boundary(top_wire.clone());

let next_face_idx = base.len(); // next face will be the bottom of the bore

// Add the faces of the bore except the top
b.pop();
base.extend(b.into_iter());
done_parents.insert(i as isize, (bottom_idx, next_face_idx));
}
}
done.insert(i);
}
Expand Down Expand Up @@ -226,6 +253,9 @@ pub fn solid_to_obj(s: Solid, tolerance: f64) -> Vec<u8> {
#[cfg(test)]
mod tests {
use super::*;
use truck_meshalgo::analyzers::WithPointCloud;
use truck_meshalgo::tessellation::MeshableShape;
use truck_meshalgo::tessellation::MeshedShape;

#[test]
fn op_parents_basic() {
Expand Down Expand Up @@ -367,7 +397,7 @@ mod tests {
}

#[test]
fn extrude_smoke_test() {
fn extrude_basic() {
use kurbo::Shape;

let rect = extrude_from_paths(
Expand All @@ -379,7 +409,7 @@ mod tests {
}
.into_path(0.1),
vec![],
3.0,
4.0,
);
for (i, (f, want)) in rect
.face_iter()
Expand All @@ -397,8 +427,58 @@ mod tests {
.join("\n")
);
}
let mesh = rect.triangulation(0.1).to_polygon();
assert_eq!(
true,
mesh.collide_with_neiborhood_of(
&[Point3 {
x: 1.5,
y: 1.5,
z: 1.5
}],
3.
)
);

let holey_rect = extrude_from_paths(
kurbo::Rect {
x0: 1.0,
y0: 1.0,
x1: 5.0,
y1: 5.0,
}
.into_path(0.1),
vec![(
CADOp::Hole,
kurbo::Rect {
x0: 2.0,
y0: 2.0,
x1: 4.0,
y1: 4.0,
}
.into_path(0.1),
)],
4.0,
);
let mesh = holey_rect.triangulation(0.1).to_polygon();
assert_eq!(
false,
mesh.collide_with_neiborhood_of(
&[Point3 {
x: 3.0,
y: 3.0,
z: 2.0,
}],
1.0
)
);
}

#[test]
fn extrude_hole() {
use kurbo::Shape;

extrude_from_paths(
let holey_rect = extrude_from_paths(
kurbo::Rect {
x0: 1.0,
y0: 1.0,
Expand All @@ -416,7 +496,95 @@ mod tests {
}
.into_path(0.1),
)],
3.0,
4.0,
);
let mesh = holey_rect.triangulation(0.1).to_polygon();
assert_eq!(
false,
mesh.collide_with_neiborhood_of(
&[Point3 {
x: 3.0,
y: 3.0,
z: 2.0,
}],
1.0
)
);
}

#[test]
fn extrude_extrusion() {
use kurbo::Shape;

let holey_rect = extrude_from_paths(
kurbo::Rect {
x0: 1.0,
y0: 1.0,
x1: 5.0,
y1: 5.0,
}
.into_path(0.1),
vec![(
CADOp::Extrude(4.5),
kurbo::Rect {
x0: 2.0,
y0: 2.0,
x1: 4.0,
y1: 4.0,
}
.into_path(0.1),
)],
4.0,
);
let mesh = holey_rect.triangulation(0.1).to_polygon();
assert_eq!(
true,
mesh.collide_with_neiborhood_of(
&[Point3 {
x: 3.0,
y: 3.0,
z: 8.0,
}],
1.0
)
);
}

#[test]
fn extrude_bore() {
use kurbo::Shape;

let holey_rect = extrude_from_paths(
kurbo::Rect {
x0: 1.0,
y0: 1.0,
x1: 5.0,
y1: 5.0,
}
.into_path(0.1),
vec![(
CADOp::Bore(5.0),
kurbo::Rect {
x0: 2.0,
y0: 2.0,
x1: 4.0,
y1: 4.0,
}
.into_path(0.1),
)],
10.0,
);
let mesh = holey_rect.triangulation(0.1).to_polygon();
assert_eq!(
false,
mesh.collide_with_neiborhood_of(
&[Point3 {
x: 3.0,
y: 3.0,
z: 10.0,
}],
1.0
)
);
}
}

0 comments on commit ebcdfe3

Please sign in to comment.