kcl_lib/std/
sweep.rs

1//! Standard library sweep.
2
3use anyhow::Result;
4use kcmc::{ModelingCmd, each_cmd as mcmd, length_unit::LengthUnit};
5use kittycad_modeling_cmds::{self as kcmc, shared::RelativeTo};
6use serde::Serialize;
7
8use super::{DEFAULT_TOLERANCE_MM, args::TyF64};
9use crate::{
10    errors::KclError,
11    execution::{
12        ExecState, Helix, KclValue, ModelingCmdMeta, Sketch, Solid,
13        types::{NumericType, RuntimeType},
14    },
15    parsing::ast::types::TagNode,
16    std::{Args, extrude::do_post_extrude},
17};
18
19/// A path to sweep along.
20#[derive(Debug, Clone, Serialize, PartialEq, ts_rs::TS)]
21#[ts(export)]
22#[serde(untagged)]
23#[allow(clippy::large_enum_variant)]
24pub enum SweepPath {
25    Sketch(Sketch),
26    Helix(Box<Helix>),
27}
28
29/// Extrude a sketch along a path.
30pub async fn sweep(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
31    let sketches = args.get_unlabeled_kw_arg("sketches", &RuntimeType::sketches(), exec_state)?;
32    let path: SweepPath = args.get_kw_arg(
33        "path",
34        &RuntimeType::Union(vec![RuntimeType::sketch(), RuntimeType::helix()]),
35        exec_state,
36    )?;
37    let sectional = args.get_kw_arg_opt("sectional", &RuntimeType::bool(), exec_state)?;
38    let tolerance: Option<TyF64> = args.get_kw_arg_opt("tolerance", &RuntimeType::length(), exec_state)?;
39    let relative_to: Option<String> = args.get_kw_arg_opt("relativeTo", &RuntimeType::string(), exec_state)?;
40    let tag_start = args.get_kw_arg_opt("tagStart", &RuntimeType::tag_decl(), exec_state)?;
41    let tag_end = args.get_kw_arg_opt("tagEnd", &RuntimeType::tag_decl(), exec_state)?;
42
43    let value = inner_sweep(
44        sketches,
45        path,
46        sectional,
47        tolerance,
48        relative_to,
49        tag_start,
50        tag_end,
51        exec_state,
52        args,
53    )
54    .await?;
55    Ok(value.into())
56}
57
58#[allow(clippy::too_many_arguments)]
59async fn inner_sweep(
60    sketches: Vec<Sketch>,
61    path: SweepPath,
62    sectional: Option<bool>,
63    tolerance: Option<TyF64>,
64    relative_to: Option<String>,
65    tag_start: Option<TagNode>,
66    tag_end: Option<TagNode>,
67    exec_state: &mut ExecState,
68    args: Args,
69) -> Result<Vec<Solid>, KclError> {
70    let trajectory = match path {
71        SweepPath::Sketch(sketch) => sketch.id.into(),
72        SweepPath::Helix(helix) => helix.value.into(),
73    };
74    let relative_to = match relative_to.as_deref() {
75        Some("sketchPlane") => RelativeTo::SketchPlane,
76        Some("trajectoryCurve") | None => RelativeTo::TrajectoryCurve,
77        Some(_) => {
78            return Err(KclError::new_syntax(crate::errors::KclErrorDetails::new(
79                "If you provide relativeTo, it must either be 'sketchPlane' or 'trajectoryCurve'".to_owned(),
80                vec![args.source_range],
81            )));
82        }
83    };
84
85    let mut solids = Vec::new();
86    for sketch in &sketches {
87        let id = exec_state.next_uuid();
88        exec_state
89            .batch_modeling_cmd(
90                ModelingCmdMeta::from_args_id(&args, id),
91                ModelingCmd::from(mcmd::Sweep {
92                    target: sketch.id.into(),
93                    trajectory,
94                    sectional: sectional.unwrap_or(false),
95                    tolerance: LengthUnit(tolerance.as_ref().map(|t| t.to_mm()).unwrap_or(DEFAULT_TOLERANCE_MM)),
96                    relative_to,
97                }),
98            )
99            .await?;
100
101        solids.push(
102            do_post_extrude(
103                sketch,
104                id.into(),
105                TyF64::new(0.0, NumericType::mm()),
106                sectional.unwrap_or(false),
107                &super::extrude::NamedCapTags {
108                    start: tag_start.as_ref(),
109                    end: tag_end.as_ref(),
110                },
111                kittycad_modeling_cmds::shared::ExtrudeMethod::Merge,
112                exec_state,
113                &args,
114                None,
115            )
116            .await?,
117        );
118    }
119
120    // Hide the artifact from the sketch or helix.
121    exec_state
122        .batch_modeling_cmd(
123            (&args).into(),
124            ModelingCmd::from(mcmd::ObjectVisible {
125                object_id: trajectory.into(),
126                hidden: true,
127            }),
128        )
129        .await?;
130
131    Ok(solids)
132}