Bidirectional extrude/revolve (#6154)

* extend extrude endpoint

* revolve and mocks

* add bounds check to revolve

* kcl examples of new args

* update to 110

* fix mock

* move example to prelude

* change to camelCase

* new prelude tests

* extend just file

* missed change

* change to XY

* redo sim tests

* review changes

* redo markdown
This commit is contained in:
Ben Crabbe
2025-04-10 15:46:10 +01:00
committed by GitHub
parent 4664427832
commit d125efcd60
109 changed files with 4595 additions and 571 deletions

View File

@ -10,6 +10,7 @@ use kcmc::{
ok_response::OkModelingCmdResponse,
output::ExtrusionFaceInfo,
shared::ExtrusionFaceCapType,
shared::Opposite,
websocket::{ModelingCmdReq, OkWebSocketResponseData},
ModelingCmd,
};
@ -30,10 +31,22 @@ use crate::{
pub async fn extrude(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
let sketches = args.get_unlabeled_kw_arg_typed("sketches", &RuntimeType::sketches(), exec_state)?;
let length = args.get_kw_arg("length")?;
let symmetric = args.get_kw_arg_opt("symmetric")?;
let bidirectional_length = args.get_kw_arg_opt("bidirectionalLength")?;
let tag_start = args.get_kw_arg_opt("tagStart")?;
let tag_end = args.get_kw_arg_opt("tagEnd")?;
let result = inner_extrude(sketches, length, tag_start, tag_end, exec_state, args).await?;
let result = inner_extrude(
sketches,
length,
symmetric,
bidirectional_length,
tag_start,
tag_end,
exec_state,
args,
)
.await?;
Ok(result.into())
}
@ -87,6 +100,50 @@ pub async fn extrude(exec_state: &mut ExecState, args: Args) -> Result<KclValue,
///
/// example = extrude(exampleSketch, length = 10)
/// ```
///
/// ```no_run
/// exampleSketch = startSketchOn('XZ')
/// |> startProfileAt([-10, 0], %)
/// |> arc({
/// angleStart = 120,
/// angleEnd = -60,
/// radius = 5,
/// }, %)
/// |> line(end = [10, 0])
/// |> line(end = [5, 0])
/// |> bezierCurve({
/// control1 = [-3, 0],
/// control2 = [2, 10],
/// to = [-5, 10],
/// }, %)
/// |> line(end = [-4, 10])
/// |> line(end = [-5, -2])
/// |> close()
///
/// example = extrude(exampleSketch, length = 20, symmetric = true)
/// ```
///
/// ```no_run
/// exampleSketch = startSketchOn('XZ')
/// |> startProfileAt([-10, 0], %)
/// |> arc({
/// angleStart = 120,
/// angleEnd = -60,
/// radius = 5,
/// }, %)
/// |> line(end = [10, 0])
/// |> line(end = [5, 0])
/// |> bezierCurve({
/// control1 = [-3, 0],
/// control2 = [2, 10],
/// to = [-5, 10],
/// }, %)
/// |> line(end = [-4, 10])
/// |> line(end = [-5, -2])
/// |> close()
///
/// example = extrude(exampleSketch, length = 10, bidirectionalLength = 50)
/// ```
#[stdlib {
name = "extrude",
feature_tree_operation = true,
@ -95,6 +152,9 @@ pub async fn extrude(exec_state: &mut ExecState, args: Args) -> Result<KclValue,
args = {
sketches = { docs = "Which sketch or sketches should be extruded"},
length = { docs = "How far to extrude the given sketches"},
symmetric = { docs = "If true, the extrusion will happen symmetrically around the sketch. Otherwise, the
extrusion will happen on only one side of the sketch." },
bidirectional_length = { docs = "If specified, will also extrude in the opposite direction to 'distance' to the specified distance. If 'symmetric' is true, this value is ignored."},
tag_start = { docs = "A named tag for the face at the start of the extrusion, i.e. the original sketch" },
tag_end = { docs = "A named tag for the face at the end of the extrusion, i.e. the new face created by extruding the original sketch" },
}
@ -103,6 +163,8 @@ pub async fn extrude(exec_state: &mut ExecState, args: Args) -> Result<KclValue,
async fn inner_extrude(
sketches: Vec<Sketch>,
length: f64,
symmetric: Option<bool>,
bidirectional_length: Option<f64>,
tag_start: Option<TagNode>,
tag_end: Option<TagNode>,
exec_state: &mut ExecState,
@ -110,6 +172,25 @@ async fn inner_extrude(
) -> Result<Vec<Solid>, KclError> {
// Extrude the element(s).
let mut solids = Vec::new();
if symmetric.unwrap_or(false) && bidirectional_length.is_some() {
return Err(KclError::Semantic(KclErrorDetails {
source_ranges: vec![args.source_range],
message: "You cannot give both `symmetric` and `bidirectional` params, you have to choose one or the other"
.to_owned(),
}));
}
let bidirection = bidirectional_length.map(LengthUnit);
let opposite = match (symmetric, bidirection) {
(Some(true), _) => Opposite::Symmetric,
(None, None) => Opposite::None,
(Some(false), None) => Opposite::None,
(None, Some(length)) => Opposite::Other(length),
(Some(false), Some(length)) => Opposite::Other(length),
};
for sketch in &sketches {
let id = exec_state.next_uuid();
args.batch_modeling_cmds(&sketch.build_sketch_mode_cmds(
@ -120,6 +201,7 @@ async fn inner_extrude(
target: sketch.id.into(),
distance: LengthUnit(length),
faces: Default::default(),
opposite: opposite.clone(),
}),
},
))