kcl_lib/std/
sweep.rs

1//! Standard library sweep.
2
3use anyhow::Result;
4use kcl_derive_docs::stdlib;
5use kcmc::{each_cmd as mcmd, length_unit::LengthUnit, ModelingCmd};
6use kittycad_modeling_cmds::{self as kcmc};
7use schemars::JsonSchema;
8use serde::{Deserialize, Serialize};
9
10use crate::{
11    errors::KclError,
12    execution::{ExecState, Helix, KclValue, Sketch, Solid},
13    std::{extrude::do_post_extrude, fillet::default_tolerance, Args},
14};
15
16/// A path to sweep along.
17#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema)]
18#[ts(export)]
19#[serde(untagged)]
20pub enum SweepPath {
21    Sketch(Sketch),
22    Helix(Box<Helix>),
23}
24
25/// Extrude a sketch along a path.
26pub async fn sweep(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
27    let sketch = args.get_unlabeled_kw_arg("sketch")?;
28    let path: SweepPath = args.get_kw_arg("path")?;
29    let sectional = args.get_kw_arg_opt("sectional")?;
30    let tolerance = args.get_kw_arg_opt("tolerance")?;
31
32    let value = inner_sweep(sketch, path, sectional, tolerance, exec_state, args).await?;
33    Ok(KclValue::Solid { value })
34}
35
36/// Extrude a sketch along a path.
37///
38/// This, like extrude, is able to create a 3-dimensional solid from a
39/// 2-dimensional sketch. However, unlike extrude, this creates a solid
40/// by using the extent of the sketch as its path. This is useful for
41/// creating more complex shapes that can't be created with a simple
42/// extrusion.
43///
44/// ```no_run
45/// // Create a pipe using a sweep.
46///
47/// // Create a path for the sweep.
48/// sweepPath = startSketchOn('XZ')
49///     |> startProfileAt([0.05, 0.05], %)
50///     |> line(end = [0, 7])
51///     |> tangentialArc({
52///         offset: 90,
53///         radius: 5
54///     }, %)
55///     |> line(end = [-3, 0])
56///     |> tangentialArc({
57///         offset: -90,
58///         radius: 5
59///     }, %)
60///     |> line(end = [0, 7])
61///
62/// // Create a hole for the pipe.
63/// pipeHole = startSketchOn('XY')
64///     |> circle(
65///         center = [0, 0],
66///         radius = 1.5,
67///     )
68///
69/// sweepSketch = startSketchOn('XY')
70///     |> circle(
71///         center = [0, 0],
72///         radius = 2,
73///         )              
74///     |> hole(pipeHole, %)
75///     |> sweep(path = sweepPath)   
76/// ```
77///
78/// ```no_run
79/// // Create a spring by sweeping around a helix path.
80///
81/// // Create a helix around the Z axis.
82/// helixPath = helix(
83///     angleStart = 0,
84///     ccw = true,
85///     revolutions = 4,
86///     length = 10,
87///     radius = 5,
88///     axis = 'Z',
89///  )
90///
91///
92/// // Create a spring by sweeping around the helix path.
93/// springSketch = startSketchOn('YZ')
94///     |> circle( center = [0, 0], radius = 1)
95///     |> sweep(path = helixPath)
96/// ```
97#[stdlib {
98    name = "sweep",
99    feature_tree_operation = true,
100    keywords = true,
101    unlabeled_first = true,
102    args = {
103        sketch = { docs = "The sketch that should be swept in space" },
104        path = { docs = "The path to sweep the sketch along" },
105        sectional = { docs = "If true, the sweep will be broken up into sub-sweeps (extrusions, revolves, sweeps) based on the trajectory path components." },
106        tolerance = { docs = "Tolerance for this operation" },
107    }
108}]
109async fn inner_sweep(
110    sketch: Sketch,
111    path: SweepPath,
112    sectional: Option<bool>,
113    tolerance: Option<f64>,
114    exec_state: &mut ExecState,
115    args: Args,
116) -> Result<Box<Solid>, KclError> {
117    let id = exec_state.next_uuid();
118    args.batch_modeling_cmd(
119        id,
120        ModelingCmd::from(mcmd::Sweep {
121            target: sketch.id.into(),
122            trajectory: match path {
123                SweepPath::Sketch(sketch) => sketch.id.into(),
124                SweepPath::Helix(helix) => helix.value.into(),
125            },
126            sectional: sectional.unwrap_or(false),
127            tolerance: LengthUnit(tolerance.unwrap_or(default_tolerance(&args.ctx.settings.units))),
128        }),
129    )
130    .await?;
131
132    do_post_extrude(sketch, id.into(), 0.0, exec_state, args).await
133}