Thanks @DuBearte.
This commit is contained in:
1 parent
dc6eca6830
commit
6f270f6259
12 files changed
+145
-11
No files matched your search
@@ -751,6 +751,12 @@ pub enum FeatureKind {
|
||||
plane: PlaneRef,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
tool: Option<FaceAt>,
|
||||
/// A straight line of this sketch as the tool (#1552): the plane through it along the
|
||||
/// sketch's normal, which follows the sketch.
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
sketch: Option<SketchId>,
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
line: Option<String>,
|
||||
},
|
||||
/// A construction axis (Fusion's CONSTRUCT axes).
|
||||
ConstructionAxis {
|
||||
|
||||
+22
-1
@@ -4400,10 +4400,17 @@ fn eval_feature(doc: &Document, vals: &BTreeMap<String, Value>, f: &Feature, st:
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
FeatureKind::Split { body, plane, tool } => {
|
||||
FeatureKind::Split { body, plane, tool, sketch, line } => {
|
||||
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::Unknown(format!("body `{body}`"))) };
|
||||
let parts = match tool {
|
||||
// A sketch line: the plane through it along the sketch's normal.
|
||||
_ if sketch.is_some() || line.is_some() => {
|
||||
let (Some(sketch), Some(line)) = (sketch, line) else {
|
||||
return Err(DocError::Invalid("a sketch line tool needs both its sketch and its line".into()));
|
||||
};
|
||||
kernel::split_by_plane(&mb.body, &sketch_line_plane(st, sketch.0, line)?)?
|
||||
}
|
||||
// A face of a body (its surface extended).
|
||||
Some(t) => {
|
||||
let tb = st.body(&t.body).ok_or_else(|| DocError::Unknown(format!("body `{}`", t.body)))?;
|
||||
@@ -5267,3 +5274,17 @@ mod body_name_tests {
|
||||
assert!(began.elapsed() < std::time::Duration::from_secs(5), "{:?}", began.elapsed());
|
||||
}
|
||||
}
|
||||
|
||||
/// The plane a straight sketch line sweeps along its sketch's normal: through the line, its x
|
||||
/// along the line and its y along the normal (a Split Body tool, #1552).
|
||||
pub fn sketch_line_plane(st: &ModelState, sketch: u64, line: &str) -> Result<Plane> {
|
||||
let ss = st.sketch(sketch).ok_or_else(|| DocError::Unknown(format!("sketch {sketch}")))?;
|
||||
let ci = ss.sketch.curve_index(line).ok_or_else(|| DocError::Unknown(format!("curve `{line}`")))?;
|
||||
let (a, b) = match ss.sketch.segs(ci).as_slice() {
|
||||
[solidcraft_geom::Seg2::Line { a, b }] => (*a, *b),
|
||||
_ => return Err(DocError::Invalid(format!("`{line}` is not a straight line: split by a sketch line"))),
|
||||
};
|
||||
let (wa, wb) = (ss.plane.to_world(a), ss.plane.to_world(b));
|
||||
let x = (wb - wa).normalized().ok_or_else(|| DocError::Invalid(format!("`{line}` has no length")))?;
|
||||
Ok(Plane { origin: wa, x, y: ss.plane.normal() })
|
||||
}
|
||||
@@ -84,6 +84,7 @@ pub(super) fn fixtures() -> Vec<(&'static str, Value)> {
|
||||
("draft", json!({"type": "draft", "faces": [o], "angle": "draft.angle", "neutral": plane("draft_neutral"), "pull": [0, 0, 1]})),
|
||||
("construction_plane", json!({"type": "construction_plane", "plane": plane("cplane")})),
|
||||
("split", json!({"type": "split", "body": "B", "plane": plane("split")})),
|
||||
("split_line", json!({"type": "split", "body": "B", "plane": plane("split_line")})),
|
||||
(
|
||||
"construction_axis",
|
||||
json!({"type": "construction_axis", "def": {"type": "two_planes", "a": geo_plane("axis_a"), "b": geo_plane("axis_b")}}),
|
||||
@@ -203,6 +204,7 @@ pub(super) fn with_refs(name: &str, mut v: Value) -> Value {
|
||||
"hole_simple" | "hole_drilled" | "hole_counterbore" | "hole_countersink" => json!({"points": {"sketch": 3, "ids": ["p"]}}),
|
||||
"loft" => json!({"sections": [{"sketch": 4, "profiles": {"type": "all"}}, {"sketch": 5, "profiles": {"type": "all"}}], "targets": ["B"]}),
|
||||
"split" | "surface_trim" => json!({"tool": tool}),
|
||||
"split_line" => json!({"sketch": 6, "line": "l1"}),
|
||||
"surface_loft" => json!({"sections": [{"sketch": 4}, {"sketch": 5}]}),
|
||||
"split_face" => json!({"body": "B", "tool": tool, "sketch": 6}),
|
||||
"emboss" => json!({"face": {"body": "B", "at": o}, "targets": ["B"]}),
|
||||
|
||||
@@ -161,6 +161,11 @@ split
|
||||
Angle = split.angle (Angle)
|
||||
Offset = split.offset (Length)
|
||||
expressions: split.angle, split.offset
|
||||
split_line
|
||||
inputs:
|
||||
Angle = split_line.angle (Angle)
|
||||
Offset = split_line.offset (Length)
|
||||
expressions: split_line.angle, split_line.offset
|
||||
construction_axis
|
||||
inputs:
|
||||
Angle = axis_a.angle (Angle)
|
||||
|
||||
@@ -76,6 +76,8 @@ construction_plane
|
||||
moves: plane.axis_dir[0], plane.axis_dir[1], plane.axis_origin[0], plane.axis_origin[1], plane.axis_origin[2]
|
||||
split
|
||||
moves: plane.axis_dir[0], plane.axis_dir[1], plane.axis_origin[0], plane.axis_origin[1], plane.axis_origin[2], tool.point[0], tool.point[1], tool.point[2]
|
||||
split_line
|
||||
moves: plane.axis_dir[0], plane.axis_dir[1], plane.axis_origin[0], plane.axis_origin[1], plane.axis_origin[2]
|
||||
construction_axis
|
||||
moves: def.a.plane.axis_dir[0], def.a.plane.axis_dir[1], def.a.plane.axis_origin[0], def.a.plane.axis_origin[1], def.a.plane.axis_origin[2], def.b.plane.axis_dir[0], def.b.plane.axis_dir[1], def.b.plane.axis_origin[0], def.b.plane.axis_origin[1], def.b.plane.axis_origin[2]
|
||||
construction_point_planes
|
||||
|
||||
@@ -81,6 +81,10 @@ construction_plane
|
||||
split
|
||||
remap_refs: plane.base.base.name
|
||||
remap_bodies: body, tool.body
|
||||
split_line
|
||||
sketches: [6]
|
||||
remap_refs: plane.base.base.name, sketch
|
||||
remap_bodies: body
|
||||
construction_axis
|
||||
construction_point_planes
|
||||
construction_point_along
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
//! A Split Body feature can take a straight sketch line as its tool (`sketch`, the sketch's
|
||||
//! feature id, and `line`, the line's id), splitting by the plane through the line along the
|
||||
//! sketch's normal (#1552). Older designs need no transformation: a split without them uses its
|
||||
//! plane or face as before; 0.13.x asks for an update instead of splitting by the stored plane.
|
||||
@@ -59,8 +59,8 @@ pub use document::*;
|
||||
pub use eval::{
|
||||
EdgeRef, FeatureResult, Model, ModelBody, ModelState, PlacedBodies, RevolveExtent, SolvedSketch, ThreadInfo, curve_pick_error, edge_names_for,
|
||||
edge_refs, face_point_names, face_point_state, hole_direction_at, import_body_names, object_height, parse_metric_thread, pattern_matrices,
|
||||
revolve_extent, revolve_extent_with_convention, select_profiles, sketch_hole_direction, state_in_frame, state_in_frame_at, through_all_distance,
|
||||
world_state, world_state_reusing,
|
||||
revolve_extent, revolve_extent_with_convention, select_profiles, sketch_hole_direction, sketch_line_plane, state_in_frame, state_in_frame_at,
|
||||
through_all_distance, world_state, world_state_reusing,
|
||||
};
|
||||
pub use expr::Expr;
|
||||
pub use names::{BodyName, FeatureName, SketchId};
|
||||
|
||||
Reference in new issue
Block a user