Pasted features now act on the bodies pasted with them instead of the originals (#613).
This commit is contained in:
1 parent
319d360c85
commit
aa24d9f071
2 files changed
+88
-56
No files matched your search
+65
-56
@@ -243,69 +243,19 @@ fn remap_link(
|
||||
}
|
||||
}
|
||||
|
||||
impl crate::Feature {
|
||||
/// Clone identities through typed reference fields. Sketch-local entity IDs stay local.
|
||||
pub fn remap_clone(
|
||||
&mut self,
|
||||
ids: &BTreeMap<u64, u64>,
|
||||
names: &BTreeMap<String, String>,
|
||||
bodies: &BTreeMap<String, String>,
|
||||
parameters: &BTreeMap<String, String>,
|
||||
) -> crate::Result<()> {
|
||||
impl FeatureKind {
|
||||
/// Point the body names a feature acts on (targets, tools, the body it rounds…) at the
|
||||
/// copies in `bodies`; names not in the map stay as they are.
|
||||
pub fn remap_bodies(&mut self, bodies: &BTreeMap<String, String>) {
|
||||
use FeatureKind as K;
|
||||
match &self.kind {
|
||||
K::Sketch { plane, sketch } => {
|
||||
checked_plane(plane, 0)?;
|
||||
for link in &sketch.links {
|
||||
checked_link(&link.source, 0)?;
|
||||
}
|
||||
}
|
||||
K::ConstructionPlane { plane }
|
||||
| K::Split { plane, .. }
|
||||
| K::SplitFace { plane, .. }
|
||||
| K::Mirror { plane, .. }
|
||||
| K::SurfaceTrim { plane, .. } => checked_plane(plane, 0)?,
|
||||
K::Draft { neutral, .. } => checked_plane(neutral, 0)?,
|
||||
K::ReplaceFace { target, .. } => checked_plane(target, 0)?,
|
||||
K::ConstructionAxis { def } => {
|
||||
for r in def.refs() {
|
||||
checked_geo(r, 0)?;
|
||||
}
|
||||
}
|
||||
K::ConstructionPoint { def } => {
|
||||
for r in def.refs() {
|
||||
checked_geo(r, 0)?;
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
self.kind.remap_refs(ids, names);
|
||||
for n in &mut self.body_names {
|
||||
mapped_name(n, bodies);
|
||||
}
|
||||
for n in &mut self.participants {
|
||||
mapped_name(n, bodies);
|
||||
}
|
||||
for n in &mut self.param_names {
|
||||
mapped_name(n, parameters);
|
||||
}
|
||||
for n in self.face_names.iter_mut().chain(&mut self.edge_names) {
|
||||
*n = remap_topology(n, ids, bodies);
|
||||
}
|
||||
for (_, e, _) in self.kind.inputs_mut() {
|
||||
*e = clone_expression(e, parameters);
|
||||
}
|
||||
for e in self.kind.point_expr_mut().into_iter().flatten() {
|
||||
*e = clone_expression(e, parameters);
|
||||
}
|
||||
match &mut self.kind {
|
||||
match self {
|
||||
K::Emboss { face: Some(face), .. } => mapped_name(&mut face.body, bodies),
|
||||
K::Split { tool: Some(tool), .. } | K::SplitFace { tool: Some(tool), .. } | K::SurfaceTrim { tool: Some(tool), .. } => {
|
||||
mapped_name(&mut tool.body, bodies)
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
match &mut self.kind {
|
||||
match self {
|
||||
K::Extrude { targets, .. }
|
||||
| K::Revolve { targets, .. }
|
||||
| K::Loft { targets, .. }
|
||||
@@ -373,6 +323,65 @@ impl crate::Feature {
|
||||
| K::MeshConvert { body, .. } => mapped_name(body, bodies),
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl crate::Feature {
|
||||
/// Clone identities through typed reference fields. Sketch-local entity IDs stay local.
|
||||
pub fn remap_clone(
|
||||
&mut self,
|
||||
ids: &BTreeMap<u64, u64>,
|
||||
names: &BTreeMap<String, String>,
|
||||
bodies: &BTreeMap<String, String>,
|
||||
parameters: &BTreeMap<String, String>,
|
||||
) -> crate::Result<()> {
|
||||
use FeatureKind as K;
|
||||
match &self.kind {
|
||||
K::Sketch { plane, sketch } => {
|
||||
checked_plane(plane, 0)?;
|
||||
for link in &sketch.links {
|
||||
checked_link(&link.source, 0)?;
|
||||
}
|
||||
}
|
||||
K::ConstructionPlane { plane }
|
||||
| K::Split { plane, .. }
|
||||
| K::SplitFace { plane, .. }
|
||||
| K::Mirror { plane, .. }
|
||||
| K::SurfaceTrim { plane, .. } => checked_plane(plane, 0)?,
|
||||
K::Draft { neutral, .. } => checked_plane(neutral, 0)?,
|
||||
K::ReplaceFace { target, .. } => checked_plane(target, 0)?,
|
||||
K::ConstructionAxis { def } => {
|
||||
for r in def.refs() {
|
||||
checked_geo(r, 0)?;
|
||||
}
|
||||
}
|
||||
K::ConstructionPoint { def } => {
|
||||
for r in def.refs() {
|
||||
checked_geo(r, 0)?;
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
self.kind.remap_refs(ids, names);
|
||||
for n in &mut self.body_names {
|
||||
mapped_name(n, bodies);
|
||||
}
|
||||
for n in &mut self.participants {
|
||||
mapped_name(n, bodies);
|
||||
}
|
||||
for n in &mut self.param_names {
|
||||
mapped_name(n, parameters);
|
||||
}
|
||||
for n in self.face_names.iter_mut().chain(&mut self.edge_names) {
|
||||
*n = remap_topology(n, ids, bodies);
|
||||
}
|
||||
for (_, e, _) in self.kind.inputs_mut() {
|
||||
*e = clone_expression(e, parameters);
|
||||
}
|
||||
for e in self.kind.point_expr_mut().into_iter().flatten() {
|
||||
*e = clone_expression(e, parameters);
|
||||
}
|
||||
self.kind.remap_bodies(bodies);
|
||||
match &mut self.kind {
|
||||
K::Sketch { plane, sketch } => {
|
||||
remap_plane(plane, ids, names, bodies, 0)?;
|
||||
|
||||
@@ -72,6 +72,8 @@ fn paste(s: &mut Session, p: &Value) -> Result<Value> {
|
||||
for f in feats {
|
||||
let mut kind = f.kind.clone();
|
||||
kind.remap_refs(&sketches, &names);
|
||||
// A body made by an earlier copy is the one this copy acts on (#613).
|
||||
kind.remap_bodies(&bodies);
|
||||
if let FeatureKind::Sketch { plane, .. } = &mut kind
|
||||
&& let Some(anchor) = super::sketch::face::anchor_mut(plane)
|
||||
{
|
||||
@@ -208,4 +210,25 @@ mod tests {
|
||||
let mut t = Session::default();
|
||||
assert!(t.execute("timeline.paste", &json!({})).is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn pasted_fillet_rounds_the_copied_body_it_names() {
|
||||
let mut s = Session::default();
|
||||
run(&mut s, "sketch.create", json!({"plane": "XY", "name": "S"}));
|
||||
run(&mut s, "sketch.rectangle.two_point", json!({"p0": [0, 0], "p1": [40, 20]}));
|
||||
run(&mut s, "sketch.finish", json!({}));
|
||||
run(&mut s, "solid.extrude", json!({"sketch": "S", "distance": 10, "operation": "new", "body_name": "Block", "name": "Block"}));
|
||||
run(&mut s, "solid.fillet", json!({"body": "Block", "radius": 2, "edges": [[20, 0, 10], [20, 20, 10]], "name": "Round"}));
|
||||
let one = volume(&mut s);
|
||||
assert!(one < 8000.0 - 1.0, "the fillet removes material: {one}");
|
||||
run(&mut s, "timeline.copy", json!({"features": ["S", "Block", "Round"]}));
|
||||
let r = run(&mut s, "timeline.paste", json!({"translate": [0, 40, 0]}));
|
||||
assert_eq!(r["errors"].as_array().map(Vec::len), Some(0), "{r}");
|
||||
let round = r["pasted"][2]["name"].as_str().unwrap_or_default().to_string();
|
||||
let def = run(&mut s, "timeline.inspect", json!({"feature": round}));
|
||||
assert_eq!(def["definition"]["body"], "Block (copy)", "{def}");
|
||||
let m = run(&mut s, "inspect.measure", json!({}));
|
||||
assert_eq!(m["body_count"], 2, "{m}");
|
||||
assert!((volume(&mut s) - 2.0 * one).abs() < 1e-6, "both blocks are rounded: {m}");
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user