Unstitch and Reverse Normal (#856)
Unstitch takes a body's faces out as surface bodies; Reverse Normal turns a surface body's faces over. Both are saved in format 18. Closes #766.
This commit is contained in:
1 parent
b702f0efde
commit
753b0a2eab
16 files changed
+322
-19
No files matched your search
@@ -337,6 +337,7 @@ impl FeatureKind {
|
||||
| FeatureKind::MeshConvert { .. }
|
||||
| FeatureKind::BodyTransfer { .. } => {}
|
||||
FeatureKind::Patch { edges, .. } | FeatureKind::SurfaceExtend { edges, .. } => edges.iter_mut().for_each(pt),
|
||||
FeatureKind::Unstitch { faces, .. } | FeatureKind::ReverseNormal { faces, .. } => faces.iter_mut().for_each(pt),
|
||||
FeatureKind::SurfaceTrim { plane, tool, keep, .. } => {
|
||||
map_plane_ref(m, plane);
|
||||
if let Some(t) = tool {
|
||||
|
||||
@@ -321,6 +321,8 @@ impl FeatureKind {
|
||||
| K::SheetConvert { body, .. }
|
||||
| K::SurfaceExtend { body, .. }
|
||||
| K::SurfaceTrim { body, .. }
|
||||
| K::Unstitch { body, .. }
|
||||
| K::ReverseNormal { body, .. }
|
||||
| K::MeshConvert { body, .. } => mapped_name(body, bodies),
|
||||
_ => {}
|
||||
}
|
||||
|
||||
@@ -937,6 +937,19 @@ pub enum FeatureKind {
|
||||
curves: Vec<String>,
|
||||
extent: Extent,
|
||||
},
|
||||
/// A body taken apart: each face at `faces` (every face when empty) its own surface body,
|
||||
/// the faces left one surface body under the body's name. A solid comes apart into surfaces.
|
||||
Unstitch {
|
||||
body: String,
|
||||
#[serde(default, skip_serializing_if = "Vec::is_empty")]
|
||||
faces: Vec<Vec3>,
|
||||
},
|
||||
/// A surface body with the faces at `faces` (every face when empty) turned over.
|
||||
ReverseNormal {
|
||||
body: String,
|
||||
#[serde(default, skip_serializing_if = "Vec::is_empty")]
|
||||
faces: Vec<Vec3>,
|
||||
},
|
||||
/// A planar surface body extended outward by `distance` past the edges through `edges`.
|
||||
SurfaceExtend {
|
||||
body: String,
|
||||
@@ -1286,6 +1299,8 @@ impl FeatureKind {
|
||||
| K::Thicken { .. }
|
||||
| K::SurfaceExtend { .. }
|
||||
| K::SurfaceTrim { .. }
|
||||
| K::Unstitch { .. }
|
||||
| K::ReverseNormal { .. }
|
||||
| K::Move { .. }
|
||||
| K::Import { .. }
|
||||
| K::MeshImport { .. }
|
||||
@@ -1374,6 +1389,8 @@ impl FeatureKind {
|
||||
FeatureKind::Thicken { .. } => "ThickenFeature",
|
||||
FeatureKind::SurfaceTrim { .. } => "TrimFeature",
|
||||
FeatureKind::SurfaceExtend { .. } => "ExtendFeature",
|
||||
FeatureKind::Unstitch { .. } => "UnstitchFeature",
|
||||
FeatureKind::ReverseNormal { .. } => "ReverseNormalFeature",
|
||||
FeatureKind::Import { .. } => "BaseFeature",
|
||||
FeatureKind::MeshImport { .. } => "MeshFeature",
|
||||
FeatureKind::MeshConvert { .. } => "MeshConvertFeature",
|
||||
@@ -1441,6 +1458,8 @@ impl FeatureKind {
|
||||
FeatureKind::Thicken { .. } => "Thicken",
|
||||
FeatureKind::SurfaceTrim { .. } => "Trim",
|
||||
FeatureKind::SurfaceExtend { .. } => "Extend",
|
||||
FeatureKind::Unstitch { .. } => "Unstitch",
|
||||
FeatureKind::ReverseNormal { .. } => "ReverseNormal",
|
||||
FeatureKind::Import { .. } => "Import",
|
||||
FeatureKind::MeshImport { .. } => "Mesh",
|
||||
FeatureKind::MeshConvert { .. } => "ConvertMesh",
|
||||
@@ -1669,6 +1688,7 @@ impl FeatureKind {
|
||||
FeatureKind::Thicken { thickness, .. } => v.push(thickness),
|
||||
FeatureKind::SurfaceTrim { plane, .. } => plane_exprs(plane, &mut v),
|
||||
FeatureKind::SurfaceExtend { distance, .. } => v.push(distance),
|
||||
FeatureKind::Unstitch { .. } | FeatureKind::ReverseNormal { .. } => {}
|
||||
FeatureKind::Patch { .. } => {}
|
||||
FeatureKind::Import { .. } | FeatureKind::MeshImport { .. } | FeatureKind::BodyTransfer { .. } => {}
|
||||
}
|
||||
|
||||
@@ -3543,7 +3543,9 @@ fn eval_feature(doc: &Document, vals: &BTreeMap<String, Value>, f: &Feature, st:
|
||||
| FeatureKind::Thicken { .. }
|
||||
| FeatureKind::SurfaceTrim { .. }
|
||||
| FeatureKind::SurfaceExtend { .. }
|
||||
| FeatureKind::SurfaceExtrude { .. } => surface::eval(doc, vals, f, st),
|
||||
| FeatureKind::SurfaceExtrude { .. }
|
||||
| FeatureKind::Unstitch { .. }
|
||||
| FeatureKind::ReverseNormal { .. } => surface::eval(doc, vals, f, st),
|
||||
FeatureKind::Emboss { .. }
|
||||
| FeatureKind::Rib { .. }
|
||||
| FeatureKind::ReplaceFace { .. }
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
//! Evaluation of the surface features: Patch, Stitch, Thicken, Trim, Extend and Surface Extrude
|
||||
//! (kernel `surfaces`).
|
||||
//! Evaluation of the surface features: Patch, Stitch, Thicken, Trim, Extend, Surface Extrude,
|
||||
//! Unstitch and Reverse Normal (kernel `surfaces`).
|
||||
|
||||
use super::*;
|
||||
use solidcraft_geom::Seg2;
|
||||
@@ -113,6 +113,37 @@ pub(super) fn eval(doc: &Document, vals: &BTreeMap<String, Value>, f: &Feature,
|
||||
st.bodies.push(ModelBody::new(name, body, f.id));
|
||||
Ok(())
|
||||
}
|
||||
FeatureKind::Unstitch { body, faces } => {
|
||||
let i = st.bodies.iter().position(|b| &b.name == body).ok_or_else(|| DocError::Unknown(format!("body `{body}`")))?;
|
||||
let Some(mb) = st.bodies.get(i).cloned() else { return Err(DocError::Invalid("body".into())) };
|
||||
let (pieces, rest) = kernel::unstitch(&mb.body, faces)?;
|
||||
let source = mb.traced();
|
||||
// The faces left keep the body's name; each face taken out is a new surface body.
|
||||
match rest {
|
||||
Some(rest) => {
|
||||
if let Some(slot) = st.bodies.get_mut(i) {
|
||||
*slot = ModelBody::traced_new(mb.name.clone(), source.then(rest), mb.feature);
|
||||
}
|
||||
}
|
||||
None => {
|
||||
st.bodies.remove(i);
|
||||
}
|
||||
}
|
||||
for (k, piece) in pieces.into_iter().enumerate() {
|
||||
let name = new_name(st, f, k);
|
||||
st.bodies.push(ModelBody::traced_new(name, source.then(piece), f.id));
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
FeatureKind::ReverseNormal { body, faces } => {
|
||||
let i = st.bodies.iter().position(|b| &b.name == body).ok_or_else(|| DocError::Unknown(format!("body `{body}`")))?;
|
||||
let Some(mb) = st.bodies.get(i).cloned() else { return Err(DocError::Invalid("body".into())) };
|
||||
let turned = mb.traced().then(kernel::reverse_faces(&mb.body, faces)?);
|
||||
if let Some(slot) = st.bodies.get_mut(i) {
|
||||
*slot = ModelBody::traced_new(mb.name, turned, mb.feature);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
_ => Err(DocError::Invalid("not a surface feature".into())),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -104,13 +104,17 @@
|
||||
//! Construction Geometries); a sketch that shows its construction geometry saves as before.
|
||||
//! A `SurfaceExtrude` feature (Surface Extrude: `sketch`, optional `profiles`, `curves` and
|
||||
//! `extent`, walls only) is first saved in 17; 0.8.0 would refuse the unknown feature.
|
||||
//! - 18: surface features 0.9.0 doesn't know: `Unstitch` (a body's faces taken out as surface
|
||||
//! bodies) and `ReverseNormal` (a surface body's faces turned over), each a `body` and
|
||||
//! optional `faces` points. Version 17 designs need no transformation; the version stamp makes
|
||||
//! 0.9.0 (which reads up to 17) ask for an update instead of meeting a feature it can't read.
|
||||
|
||||
use serde_json::Value;
|
||||
|
||||
use crate::{DocError, Document, Result};
|
||||
|
||||
/// The format this build writes.
|
||||
pub const FORMAT: u32 = 17;
|
||||
pub const FORMAT: u32 = 18;
|
||||
|
||||
pub fn format_string(n: u32) -> String {
|
||||
format!("solidcraft/{n}")
|
||||
@@ -127,7 +131,7 @@ pub fn version_of(s: &str) -> Option<u32> {
|
||||
|
||||
/// JSON-level upgrades: entry `i` turns format `i + 1` into `i + 2`.
|
||||
type JsonStep = fn(&mut Value) -> Result<()>;
|
||||
const JSON_STEPS: [JsonStep; 16] = [
|
||||
const JSON_STEPS: [JsonStep; 17] = [
|
||||
|_| Ok(()),
|
||||
v2_to_v3,
|
||||
v3_to_v4,
|
||||
@@ -144,6 +148,7 @@ const JSON_STEPS: [JsonStep; 16] = [
|
||||
|_| Ok(()),
|
||||
|_| Ok(()),
|
||||
|_| Ok(()),
|
||||
|_| Ok(()),
|
||||
];
|
||||
|
||||
/// Stored face and edge names were worked out from geometry before format 14; they get the
|
||||
|
||||
@@ -277,6 +277,7 @@ impl FeatureKind {
|
||||
FeatureKind::Thicken { thickness, .. } => v.push(("Thickness", thickness, L)),
|
||||
FeatureKind::SurfaceTrim { plane, .. } => plane_inputs_mut(plane, &mut v),
|
||||
FeatureKind::SurfaceExtend { distance, .. } => v.push(("Distance", distance, L)),
|
||||
FeatureKind::Unstitch { .. } | FeatureKind::ReverseNormal { .. } => {}
|
||||
FeatureKind::Patch { .. } => {}
|
||||
FeatureKind::Combine { .. }
|
||||
| FeatureKind::SheetBase { .. }
|
||||
|
||||
Reference in new issue
Block a user