Untrim: holes removed and a face restored to its natural bounds (#1150)
Adds surface.untrim (#761); the SurfaceUntrim feature is first saved in format 21.
This commit is contained in:
1 parent
734f69ad72
commit
16c49c3e86
25 files changed
+961
-18
No files matched your search
@@ -1019,6 +1019,19 @@ pub enum FeatureKind {
|
||||
#[serde(default, skip_serializing_if = "Vec::is_empty")]
|
||||
faces: Vec<Vec3>,
|
||||
},
|
||||
/// The face at `face` restored towards its surface: the inner loops at the `holes` points
|
||||
/// taken away (every one when `None`; none when empty), and with `outer` its outer boundary
|
||||
/// back at the surface's natural bounds (an analytic surface's: the face's own span). A new
|
||||
/// surface body; with `in_place`, a surface body's face is untrimmed where it is.
|
||||
SurfaceUntrim {
|
||||
face: FaceAt,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
holes: Option<Vec<Vec3>>,
|
||||
#[serde(default, skip_serializing_if = "std::ops::Not::not")]
|
||||
outer: bool,
|
||||
#[serde(default, skip_serializing_if = "std::ops::Not::not")]
|
||||
in_place: bool,
|
||||
},
|
||||
/// A surface body turned about an axis from open curve chains and the boundaries of
|
||||
/// profiles: walls only, no caps (a solid where a full turn closes them).
|
||||
SurfaceRevolve {
|
||||
@@ -1444,6 +1457,7 @@ impl FeatureKind {
|
||||
FeatureKind::SurfaceExtend { .. } => "ExtendFeature",
|
||||
FeatureKind::Unstitch { .. } => "UnstitchFeature",
|
||||
FeatureKind::ReverseNormal { .. } => "ReverseNormalFeature",
|
||||
FeatureKind::SurfaceUntrim { .. } => "UntrimFeature",
|
||||
FeatureKind::Import { .. } => "BaseFeature",
|
||||
FeatureKind::MeshImport { .. } => "MeshFeature",
|
||||
FeatureKind::MeshConvert { .. } => "MeshConvertFeature",
|
||||
@@ -1518,6 +1532,7 @@ impl FeatureKind {
|
||||
FeatureKind::SurfaceExtend { .. } => "Extend",
|
||||
FeatureKind::Unstitch { .. } => "Unstitch",
|
||||
FeatureKind::ReverseNormal { .. } => "ReverseNormal",
|
||||
FeatureKind::SurfaceUntrim { .. } => "Untrim",
|
||||
FeatureKind::Import { .. } => "Import",
|
||||
FeatureKind::MeshImport { .. } => "Mesh",
|
||||
FeatureKind::MeshConvert { .. } => "ConvertMesh",
|
||||
|
||||
@@ -3925,7 +3925,8 @@ fn eval_feature(doc: &Document, vals: &BTreeMap<String, Value>, f: &Feature, st:
|
||||
| FeatureKind::SurfaceRevolve { .. }
|
||||
| FeatureKind::SurfaceSweep { .. }
|
||||
| FeatureKind::SurfaceLoft { .. }
|
||||
| FeatureKind::SurfaceOffset { .. } => surface::eval(doc, vals, f, st),
|
||||
| FeatureKind::SurfaceOffset { .. }
|
||||
| FeatureKind::SurfaceUntrim { .. } => surface::eval(doc, vals, f, st),
|
||||
FeatureKind::Emboss { .. }
|
||||
| FeatureKind::Rib { .. }
|
||||
| FeatureKind::ReplaceFace { .. }
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
//! Evaluation of the surface features: Patch, Stitch, Thicken, Trim, Extend, Surface Extrude,
|
||||
//! Revolve, Sweep and Loft, Offset, Unstitch and Reverse Normal (kernel `surfaces`,
|
||||
//! `surface_offset`).
|
||||
//! Revolve, Sweep and Loft, Offset, Untrim, Unstitch and Reverse Normal (kernel `surfaces`,
|
||||
//! `surface_offset`, `surface_untrim`).
|
||||
|
||||
use super::*;
|
||||
use solidcraft_geom::Seg2;
|
||||
@@ -234,6 +234,28 @@ pub(super) fn eval(doc: &Document, vals: &BTreeMap<String, Value>, f: &Feature,
|
||||
st.bodies.push(ModelBody::traced_new(name, made, f.id));
|
||||
Ok(())
|
||||
}
|
||||
FeatureKind::SurfaceUntrim { face, holes, outer, in_place } => {
|
||||
let i = st.bodies.iter().position(|b| b.name == face.body).ok_or_else(|| DocError::Unknown(format!("body `{}`", face.body)))?;
|
||||
let Some(mb) = st.bodies.get(i).cloned() else { return Err(DocError::Invalid("body".into())) };
|
||||
let fi = crate::appearance::face_index_at(&mb, face.point)
|
||||
.ok_or_else(|| DocError::Invalid(format!("Untrim: no face of {} at {:?}", mb.name, face.point)))?;
|
||||
let which = match holes {
|
||||
None => kernel::UntrimHoles::All,
|
||||
Some(points) => kernel::UntrimHoles::At(points),
|
||||
};
|
||||
// A surface body's face is untrimmed where it is when asked; a solid's is copied out.
|
||||
let replace = *in_place && mb.body.is_surface();
|
||||
let made = mb.traced().then(kernel::untrim(&mb.body, fi, which, *outer, replace)?);
|
||||
if replace {
|
||||
if let Some(slot) = st.bodies.get_mut(i) {
|
||||
*slot = ModelBody::traced_new(mb.name, made, mb.feature);
|
||||
}
|
||||
} else {
|
||||
let name = new_name(st, f, 0);
|
||||
st.bodies.push(ModelBody::traced_new(name, made, f.id));
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
_ => Err(DocError::Invalid("not a surface feature".into())),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -157,6 +157,15 @@ macro_rules! geometry_walk {
|
||||
f(Pos(p));
|
||||
}
|
||||
}
|
||||
// The face is picked (and named); the holes are picked by points on their edges.
|
||||
FeatureKind::SurfaceUntrim { face, holes, .. } => {
|
||||
f(Pick(& $($m)? face.point));
|
||||
if let Some(points) = holes {
|
||||
for p in points {
|
||||
f(Pos(p));
|
||||
}
|
||||
}
|
||||
}
|
||||
FeatureKind::BoundaryFill { cells, .. } => {
|
||||
for p in cells {
|
||||
f(Pos(p));
|
||||
|
||||
@@ -174,6 +174,7 @@ macro_rules! feature_walk {
|
||||
f(B(b));
|
||||
}
|
||||
}
|
||||
FeatureKind::SurfaceUntrim { face, .. } => f(B(& $($m)? face.body)),
|
||||
FeatureKind::SheetConvert { body, .. }
|
||||
| FeatureKind::SurfaceExtend { body, .. }
|
||||
| FeatureKind::Unstitch { body, .. }
|
||||
|
||||
@@ -151,6 +151,7 @@ pub(super) fn fixtures() -> Vec<(&'static str, Value)> {
|
||||
("surface_offset", json!({"type": "surface_offset", "faces": [o], "distance": "soff.distance", "tolerance": "soff.tolerance"})),
|
||||
("unstitch", json!({"type": "unstitch", "body": "B"})),
|
||||
("reverse_normal", json!({"type": "reverse_normal", "body": "B"})),
|
||||
("surface_untrim", json!({"type": "surface_untrim", "face": {"body": "B", "point": o}, "holes": [o], "outer": true})),
|
||||
("surface_extend", json!({"type": "surface_extend", "body": "B", "edges": [o], "distance": "extend.distance"})),
|
||||
("surface_trim", json!({"type": "surface_trim", "body": "B", "plane": plane("trim"), "keep": o})),
|
||||
("move", json!({"type": "move", "bodies": ["B"], "translate": ["move.x", "move.y", "move.z"], "angle": "move.angle"})),
|
||||
|
||||
@@ -325,6 +325,7 @@ surface_offset
|
||||
expressions: soff.distance, soff.tolerance
|
||||
unstitch
|
||||
reverse_normal
|
||||
surface_untrim
|
||||
surface_extend
|
||||
inputs:
|
||||
Distance = extend.distance (Length)
|
||||
|
||||
@@ -150,6 +150,9 @@ unstitch
|
||||
moves: faces[0][0], faces[0][1], faces[0][2]
|
||||
reverse_normal
|
||||
moves: faces[0][0], faces[0][1], faces[0][2]
|
||||
surface_untrim
|
||||
moves: face.point[0], face.point[1], face.point[2], holes[0][0], holes[0][1], holes[0][2]
|
||||
face points: [0, 0, 0]
|
||||
surface_extend
|
||||
moves: edges[0][0], edges[0][1], edges[0][2]
|
||||
surface_trim
|
||||
|
||||
@@ -168,6 +168,8 @@ unstitch
|
||||
remap_bodies: body
|
||||
reverse_normal
|
||||
remap_bodies: body
|
||||
surface_untrim
|
||||
remap_bodies: face.body
|
||||
surface_extend
|
||||
remap_bodies: body
|
||||
surface_trim
|
||||
|
||||
@@ -167,6 +167,9 @@
|
||||
//! Under the same version, looks can explicitly select opaque PBR parameters (`pbr`: metal
|
||||
//! fraction, roughness, dielectric IOR). Absent fields keep the scalar shading a look always
|
||||
//! had; 0.11.0 asks for an update instead of silently dropping the response.
|
||||
//! A `SurfaceUntrim` feature (Untrim: a `face` as `body` and `point`, optional `holes`
|
||||
//! points, `outer` and `in_place`) is also first saved in 21; 0.11.0 asks for an update
|
||||
//! instead of meeting a feature it can't read.
|
||||
|
||||
use serde_json::Value;
|
||||
|
||||
|
||||
@@ -354,7 +354,7 @@ macro_rules! feature_walk {
|
||||
FeatureKind::Thicken { thickness, .. } => f("Thickness", thickness, L, I),
|
||||
FeatureKind::SurfaceTrim { plane, .. } => $plane(plane, f),
|
||||
FeatureKind::SurfaceExtend { distance, .. } => f("Distance", distance, L, I),
|
||||
FeatureKind::Unstitch { .. } | FeatureKind::ReverseNormal { .. } => {}
|
||||
FeatureKind::Unstitch { .. } | FeatureKind::ReverseNormal { .. } | FeatureKind::SurfaceUntrim { .. } => {}
|
||||
FeatureKind::SurfaceOffset { distance, tolerance, .. } => {
|
||||
f("Distance", distance, L, I);
|
||||
if let Some(t) = tolerance {
|
||||
|
||||
Reference in new issue
Block a user