Coil (PrimitiveCoil: diameter, two of revolutions/height/pitch, circular or square section inside/on/outside, start angle, handedness) on a new kernel helical sweep; loft to a point (sketch point sections, pyramids); recipes: a sweep along a fitted 3D helix replays as a coil (oracle 49, compared within 0.5% since Fusion's path is a spline fit) and loft point sections (oracle 37)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01AS5Tn3xieewUSg3uxrMVdL
This commit is contained in:
1 parent
4455402eab
commit
9df954cd94
12 files changed
+490
-12
No files matched your search
@@ -11,6 +11,10 @@ use crate::params::{bad, bool_, expr, req_expr, str_, string_list, vec3};
|
||||
use crate::{Result, Session};
|
||||
|
||||
pub static COMMANDS: &[CommandSpec] = &[
|
||||
CommandSpec::new("PrimitiveCoil", "Coil", coil).at("SOLID", "CREATE").icon("coil").params(
|
||||
"diameter; two of revolutions (or turns), height, pitch; section_size; section?: circular|square; section_position?: inside|center|outside; \
|
||||
base?: [x,y,z]; axis?: X|Y|Z|[x,y,z] (default Z); start_angle?; clockwise?: bool; operation?, targets?, name?, body_name?",
|
||||
),
|
||||
CommandSpec::new("FusionRibCommand", "Rib", rib)
|
||||
.at("SOLID", "CREATE")
|
||||
.icon("rib")
|
||||
@@ -34,6 +38,70 @@ pub static COMMANDS: &[CommandSpec] = &[
|
||||
CommandSpec::new("SoftDeleteCommand", "Remove", remove).at("SOLID", "MODIFY").icon("delete").params("bodies: [names] (removed from here on in the timeline)"),
|
||||
];
|
||||
|
||||
fn coil(s: &mut Session, p: &Value) -> Result<Value> {
|
||||
let cmd = "PrimitiveCoil";
|
||||
let base = p.get("base").and_then(vec3).unwrap_or(Vec3::ZERO);
|
||||
let axis = match p.get("axis") {
|
||||
None => Vec3::Z,
|
||||
Some(Value::String(a)) => match a.to_ascii_uppercase().as_str() {
|
||||
"X" => Vec3::X,
|
||||
"Y" => Vec3::Y,
|
||||
"Z" => Vec3::Z,
|
||||
_ => return Err(bad(cmd, "`axis` must be X, Y, Z or [x, y, z]")),
|
||||
},
|
||||
Some(v) => vec3(v).and_then(|a| a.normalized()).ok_or_else(|| bad(cmd, "`axis` must be X, Y, Z or a non-zero [x, y, z]"))?,
|
||||
};
|
||||
let diameter = req_expr(cmd, p, "diameter")?;
|
||||
check_expr(s, &diameter, Kind::Length, cmd, "diameter")?;
|
||||
let turns = expr(p, "revolutions").or_else(|| expr(p, "turns"));
|
||||
let (height, pitch) = (expr(p, "height"), expr(p, "pitch"));
|
||||
let (turns, pitch) = match (turns, height, pitch) {
|
||||
(Some(n), _, Some(pt)) => (n, pt),
|
||||
(Some(n), Some(h), None) => (n.clone(), format!("({h}) / ({n})")),
|
||||
(None, Some(h), Some(pt)) => (format!("({h}) / ({pt})"), pt),
|
||||
_ => return Err(bad(cmd, "give two of `revolutions`, `height` and `pitch`")),
|
||||
};
|
||||
check_expr(s, &turns, Kind::Unitless, cmd, "revolutions")?;
|
||||
check_expr(s, &pitch, Kind::Length, cmd, "pitch")?;
|
||||
let section_size = req_expr(cmd, p, "section_size")?;
|
||||
check_expr(s, §ion_size, Kind::Length, cmd, "section_size")?;
|
||||
let section = match str_(p, "section").map(str::to_ascii_lowercase).as_deref() {
|
||||
None | Some("circular" | "circle") => solvecraft_doc::CoilSection::Circular,
|
||||
Some("square") => solvecraft_doc::CoilSection::Square,
|
||||
Some(o) => return Err(bad(cmd, format!("unknown section `{o}` (circular or square)"))),
|
||||
};
|
||||
let position = match str_(p, "section_position").map(str::to_ascii_lowercase).as_deref() {
|
||||
None | Some("center" | "on" | "on_center") => 0,
|
||||
Some("inside") => -1,
|
||||
Some("outside") => 1,
|
||||
Some(o) => return Err(bad(cmd, format!("unknown section position `{o}` (inside, center or outside)"))),
|
||||
};
|
||||
let start_angle = expr(p, "start_angle");
|
||||
if let Some(a) = &start_angle {
|
||||
check_expr(s, a, Kind::Angle, cmd, "start_angle")?;
|
||||
}
|
||||
let clockwise = bool_(p, "clockwise").unwrap_or(false);
|
||||
let operation = super::features::operation(p, cmd)?;
|
||||
add_feature(
|
||||
s,
|
||||
p,
|
||||
FeatureKind::Coil {
|
||||
base,
|
||||
axis,
|
||||
diameter,
|
||||
pitch,
|
||||
turns,
|
||||
section_size,
|
||||
section,
|
||||
position,
|
||||
start_angle,
|
||||
clockwise,
|
||||
operation,
|
||||
targets: string_list(p, "targets"),
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
fn curves_param(p: &Value, cmd: &str) -> Result<Vec<String>> {
|
||||
let c = string_list(p, "curves");
|
||||
if c.is_empty() || c.len() > 1000 {
|
||||
|
||||
Reference in new issue
Block a user