mirror of
https://github.com/bherbruck/solidcraft.git
synced 2026-11-03 10:35:58 +00:00
doc: a hole in sheet metal is a cut-out or a bore by its drill's direction
sheet_hole_cut chose by failure: a hole's drills were tried all at once and, if that was refused, one by one; each drill was tried as a flat cut-out and, if that was refused (or machined nothing), as a bore. Now the drill's geometry decides, one path each: - SheetBody::drilled_panels: the panels a straight drill meets and how square it is to each (|panel normal · axis|); a drill into a bend is refused, as before. add_bore uses it. - sheet_drill: square across every panel it meets is Drill::Across (sheet_primitive_cut, a cut-out or pocket of the flat pattern), along every one into a rim is Drill::Along (sheet_bore_cut, a bore), meeting no sheet is None, and anything else (square to one panel and along another, or at an angle) is refused with the angle message. - The all-at-once pass (sheet_drill_cuts) passes its errors on; its None (the drills not all square along one axis) still puts the model back and drills them one by one. - sheet_bore_cut passes add_bore's refusal on instead of answering None. (not built: base in progress) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017itGh5fpMEousnZ91cYcVt
This commit is contained in:
+9
-16
@@ -3991,15 +3991,15 @@ fn sheet_hole_cut(
|
||||
// Many plain drills along one axis (a hole on each of a pattern's points): all in one pass.
|
||||
let prisms: Option<Vec<more::PrimitivePrism>> = tools.iter().map(|(_, prism)| *prism).collect();
|
||||
if let Some(prisms) = prisms {
|
||||
match more::sheet_drill_cuts(f, st, &prisms, &mut parted) {
|
||||
Ok(Some(done)) => {
|
||||
match more::sheet_drill_cuts(f, st, &prisms, &mut parted)? {
|
||||
Some(done) => {
|
||||
if let Some(note) = parted {
|
||||
append_warning(warning, note);
|
||||
}
|
||||
return Ok(done);
|
||||
}
|
||||
// Not all of them that way, or refused at once: one by one, from the model as it was.
|
||||
Ok(None) | Err(_) => {
|
||||
// Not all of them that way: one by one, from the model as it was.
|
||||
None => {
|
||||
(st.sheets, st.bodies) = saved.clone();
|
||||
parted = None;
|
||||
}
|
||||
@@ -4007,22 +4007,15 @@ fn sheet_hole_cut(
|
||||
}
|
||||
for (tool, prism) in tools {
|
||||
let tool = &tool.body;
|
||||
// Square across the panels it meets, a flat cut-out; along them into a rim, a bore.
|
||||
let done = match prism {
|
||||
Some(prism) => match more::sheet_primitive_cut(f, st, tool, *prism, Operation::Cut, true, &mut parted) {
|
||||
Ok(done) => done,
|
||||
// Drilled along a panel (into a rim) the hole is no flat cut-out: a bore of
|
||||
// that panel, when it stays inside it.
|
||||
Err(e) => match more::sheet_bore_cut(f, st, *prism)? {
|
||||
Some(done) => done,
|
||||
None => return Err(e),
|
||||
},
|
||||
Some(prism) => match more::sheet_drill(f, st, *prism)? {
|
||||
Some(more::Drill::Across) => more::sheet_primitive_cut(f, st, tool, *prism, Operation::Cut, true, &mut parted)?,
|
||||
Some(more::Drill::Along) => more::sheet_bore_cut(f, st, *prism)?.unwrap_or_default(),
|
||||
None => Vec::new(),
|
||||
},
|
||||
None => Vec::new(),
|
||||
};
|
||||
let done = match (done.is_empty(), prism) {
|
||||
(true, Some(prism)) => more::sheet_bore_cut(f, st, *prism)?.unwrap_or_default(),
|
||||
_ => done,
|
||||
};
|
||||
if done.is_empty() {
|
||||
let mut meets = false;
|
||||
for sheet in &st.sheets {
|
||||
|
||||
@@ -1065,11 +1065,39 @@ pub(super) fn sheet_primitive_cut(
|
||||
sheet_prism_cut(f, st, &plane, std::slice::from_ref(®ion), operation, &tools, &[], None, false, &[], warning)
|
||||
}
|
||||
|
||||
/// How a hole's straight drill machines the sheets it meets, from the panels it passes through.
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||
pub(super) enum Drill {
|
||||
/// Square across every panel it meets: a cut-out or pocket of the flat pattern
|
||||
/// ([`sheet_primitive_cut`]).
|
||||
Across,
|
||||
/// Along every panel it meets, into a rim: a bore of each ([`sheet_bore_cut`]).
|
||||
Along,
|
||||
}
|
||||
|
||||
/// Which [`Drill`] a hole's straight drill is for the sheets `f` machines; None when it meets
|
||||
/// none of them. A box is a prism across its sheet. A drill square to some panels it meets and
|
||||
/// along others, or at an angle to one, has no exact place in the flat pattern and is refused.
|
||||
pub(super) fn sheet_drill(f: &Feature, st: &ModelState, prism: PrimitivePrism) -> Result<Option<Drill>> {
|
||||
let PrimitivePrism::Cylinder { base, axis, radius, height } = prism else { return Ok(Some(Drill::Across)) };
|
||||
let mut squares = Vec::new();
|
||||
for sh in st.sheets.iter().filter(|sh| sheet_eligible(f, st, &[], sh)) {
|
||||
squares.extend(sh.drilled_panels(base, axis, radius, height)?.into_iter().map(|(_, square)| square));
|
||||
}
|
||||
if squares.is_empty() {
|
||||
Ok(None)
|
||||
} else if squares.iter().all(|s| *s >= 1.0 - 1e-6) {
|
||||
Ok(Some(Drill::Across))
|
||||
} else if squares.iter().all(|s| *s <= 1e-6) {
|
||||
Ok(Some(Drill::Along))
|
||||
} else {
|
||||
Err(DocError::Invalid("this hole crosses a sheet panel at an angle; drill it square to the panel, or along it into a rim".into()))
|
||||
}
|
||||
}
|
||||
|
||||
/// A hole's straight drill along a panel of a sheet (into its rim), kept as a bore of each
|
||||
/// panel it meets (see [`crate::sheet::SheetBore`]), so the sheet still unfolds. Returns the
|
||||
/// sheet bodies it machined; None, with the model as it was, when the drill is not a plain
|
||||
/// cylinder or a sheet it meets can't keep it that way (it runs into a bend, or crosses a
|
||||
/// panel at an angle).
|
||||
/// sheet bodies it machined; None when the drill is not a plain cylinder or meets no sheet.
|
||||
pub(super) fn sheet_bore_cut(f: &Feature, st: &mut ModelState, prism: PrimitivePrism) -> Result<Option<Vec<String>>> {
|
||||
let PrimitivePrism::Cylinder { base, axis, radius, height } = prism else { return Ok(None) };
|
||||
let mut plans = Vec::new();
|
||||
@@ -1081,8 +1109,6 @@ pub(super) fn sheet_bore_cut(f: &Feature, st: &mut ModelState, prism: PrimitiveP
|
||||
match sh.add_bore(base, axis, radius, height) {
|
||||
Ok(true) => {}
|
||||
Ok(false) => continue,
|
||||
// Refused here, the hole keeps the message of the machining it was first tried as.
|
||||
Err(DocError::Invalid(_)) => return Ok(None),
|
||||
Err(e) => return Err(e),
|
||||
}
|
||||
let body = sh.solid()?;
|
||||
@@ -1112,8 +1138,8 @@ const MAX_DRILLS_AT_ONCE: usize = 1000;
|
||||
/// of them, rather than one per drill, each on a sheet machined by the ones before.
|
||||
/// The drills are the cut-outs and pockets [`sheet_primitive_cut`] makes of them one at a time.
|
||||
/// None when they can't all be taken this way (they are not all cylinders along one axis that
|
||||
/// every sheet they may machine takes square, or a sheet keeps one some other way): the caller
|
||||
/// then puts the model back and drills them one by one.
|
||||
/// every sheet they may machine takes square, or a depth of them meets no sheet): the caller then
|
||||
/// puts the model back and drills them one by one.
|
||||
pub(super) fn sheet_drill_cuts(
|
||||
f: &Feature,
|
||||
st: &mut ModelState,
|
||||
|
||||
+23
-9
@@ -1691,18 +1691,14 @@ impl SheetBody {
|
||||
Ok(body)
|
||||
}
|
||||
|
||||
/// Record a round bore drilled along the sheet (a hole into a rim): the world cylinder from
|
||||
/// `base` along `axis`, one record per panel whose material it meets. Ok(false) when it
|
||||
/// meets no material; an error when it meets a bend, or crosses a panel other than along
|
||||
/// its plane (that machining has no exact place in the flat pattern).
|
||||
pub(crate) fn add_bore(&mut self, base: Vec3, axis: Vec3, radius: f64, height: f64) -> Result<bool> {
|
||||
/// The panels a straight drill (the world cylinder from `base` along `axis`) meets, each with
|
||||
/// how square the drill is to it: |panel normal · axis|, 1 across the panel and 0 along it.
|
||||
/// A drill that meets a bend is refused (a bend's material has no flat place for a hole).
|
||||
pub(crate) fn drilled_panels(&self, base: Vec3, axis: Vec3, radius: f64, height: f64) -> Result<Vec<(Option<usize>, f64)>> {
|
||||
let axis = axis.normalized().ok_or_else(|| DocError::Invalid("bore axis".into()))?;
|
||||
if ![base.x, base.y, base.z, radius, height].iter().all(|v| v.is_finite()) || !(radius > 0.0) || height == 0.0 {
|
||||
return Err(DocError::Invalid("invalid sheet bore".into()));
|
||||
}
|
||||
if self.bores.len() >= MAX_BORES {
|
||||
return Err(flat_budget_error());
|
||||
}
|
||||
let mut work = FlatWork::new();
|
||||
let drill = kernel::cylinder(base, axis, radius, height)?;
|
||||
let mut found = Vec::new();
|
||||
@@ -1726,11 +1722,29 @@ impl SheetBody {
|
||||
));
|
||||
};
|
||||
let w = self.world(if self.flat { None } else { pi });
|
||||
if apply_vector(&w, Vec3::Z).dot(axis).abs() > 1e-6 {
|
||||
found.push((pi, apply_vector(&w, Vec3::Z).dot(axis).abs()));
|
||||
}
|
||||
Ok(found)
|
||||
}
|
||||
|
||||
/// Record a round bore drilled along the sheet (a hole into a rim): the world cylinder from
|
||||
/// `base` along `axis`, one record per panel whose material it meets. Ok(false) when it
|
||||
/// meets no material; an error when it meets a bend, or crosses a panel other than along
|
||||
/// its plane (that machining has no exact place in the flat pattern).
|
||||
pub(crate) fn add_bore(&mut self, base: Vec3, axis: Vec3, radius: f64, height: f64) -> Result<bool> {
|
||||
if self.bores.len() >= MAX_BORES {
|
||||
return Err(flat_budget_error());
|
||||
}
|
||||
let panels = self.drilled_panels(base, axis, radius, height)?;
|
||||
let axis = axis.normalized().ok_or_else(|| DocError::Invalid("bore axis".into()))?;
|
||||
let mut found = Vec::new();
|
||||
for (pi, square) in panels {
|
||||
if square > 1e-6 {
|
||||
return Err(DocError::Invalid(
|
||||
"this hole crosses a sheet panel at an angle; drill it square to the panel, or along it into a rim".into(),
|
||||
));
|
||||
}
|
||||
let w = self.world(if self.flat { None } else { pi });
|
||||
let inv = mat_inverse(&w).ok_or_else(|| DocError::Invalid("invalid sheet panel frame".into()))?;
|
||||
let bore = SheetBore { panel: pi, base: apply_point(&inv, base), axis: apply_vector(&inv, axis), radius, height };
|
||||
if !found.contains(&bore) {
|
||||
|
||||
Reference in New Issue
Block a user