2024-12-11 12:59:02 -08:00
|
|
|
//! Standard library sweep.
|
|
|
|
|
|
|
|
use anyhow::Result;
|
|
|
|
use kcmc::{each_cmd as mcmd, length_unit::LengthUnit, ModelingCmd};
|
2025-05-14 13:54:10 -05:00
|
|
|
use kittycad_modeling_cmds::{self as kcmc, shared::RelativeTo};
|
2024-12-11 12:59:02 -08:00
|
|
|
use schemars::JsonSchema;
|
2025-04-07 19:02:41 +12:00
|
|
|
use serde::Serialize;
|
2024-12-11 12:59:02 -08:00
|
|
|
|
2025-04-14 05:58:19 -04:00
|
|
|
use super::{args::TyF64, DEFAULT_TOLERANCE};
|
2024-12-11 12:59:02 -08:00
|
|
|
use crate::{
|
|
|
|
errors::KclError,
|
2025-04-23 10:58:35 +12:00
|
|
|
execution::{
|
|
|
|
types::{NumericType, RuntimeType},
|
|
|
|
ExecState, Helix, KclValue, Sketch, Solid,
|
|
|
|
},
|
2025-03-19 12:18:19 -07:00
|
|
|
parsing::ast::types::TagNode,
|
2025-03-31 15:28:15 -04:00
|
|
|
std::{extrude::do_post_extrude, Args},
|
2024-12-11 12:59:02 -08:00
|
|
|
};
|
|
|
|
|
2025-01-07 19:10:53 -08:00
|
|
|
/// A path to sweep along.
|
2025-04-07 19:02:41 +12:00
|
|
|
#[derive(Debug, Clone, Serialize, PartialEq, ts_rs::TS, JsonSchema)]
|
2025-01-07 19:10:53 -08:00
|
|
|
#[ts(export)]
|
|
|
|
#[serde(untagged)]
|
2025-06-03 16:32:24 -05:00
|
|
|
#[allow(clippy::large_enum_variant)]
|
2025-01-07 19:10:53 -08:00
|
|
|
pub enum SweepPath {
|
|
|
|
Sketch(Sketch),
|
|
|
|
Helix(Box<Helix>),
|
|
|
|
}
|
|
|
|
|
2024-12-11 12:59:02 -08:00
|
|
|
/// Extrude a sketch along a path.
|
|
|
|
pub async fn sweep(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
|
2025-06-06 10:45:58 +12:00
|
|
|
let sketches = args.get_unlabeled_kw_arg("sketches", &RuntimeType::sketches(), exec_state)?;
|
|
|
|
let path: SweepPath = args.get_kw_arg(
|
2025-04-23 10:58:35 +12:00
|
|
|
"path",
|
|
|
|
&RuntimeType::Union(vec![RuntimeType::sketch(), RuntimeType::helix()]),
|
|
|
|
exec_state,
|
|
|
|
)?;
|
2025-06-06 10:45:58 +12:00
|
|
|
let sectional = args.get_kw_arg_opt("sectional", &RuntimeType::bool(), exec_state)?;
|
|
|
|
let tolerance: Option<TyF64> = args.get_kw_arg_opt("tolerance", &RuntimeType::length(), exec_state)?;
|
|
|
|
let relative_to: Option<String> = args.get_kw_arg_opt("relativeTo", &RuntimeType::string(), exec_state)?;
|
|
|
|
let tag_start = args.get_kw_arg_opt("tagStart", &RuntimeType::tag_decl(), exec_state)?;
|
|
|
|
let tag_end = args.get_kw_arg_opt("tagEnd", &RuntimeType::tag_decl(), exec_state)?;
|
2024-12-11 12:59:02 -08:00
|
|
|
|
2025-03-19 12:18:19 -07:00
|
|
|
let value = inner_sweep(
|
2025-05-14 13:54:10 -05:00
|
|
|
sketches,
|
|
|
|
path,
|
|
|
|
sectional,
|
|
|
|
tolerance,
|
|
|
|
relative_to,
|
|
|
|
tag_start,
|
|
|
|
tag_end,
|
|
|
|
exec_state,
|
|
|
|
args,
|
2025-03-19 12:18:19 -07:00
|
|
|
)
|
|
|
|
.await?;
|
2025-03-13 09:38:22 -07:00
|
|
|
Ok(value.into())
|
2024-12-11 12:59:02 -08:00
|
|
|
}
|
|
|
|
|
2025-03-19 12:18:19 -07:00
|
|
|
#[allow(clippy::too_many_arguments)]
|
2024-12-11 12:59:02 -08:00
|
|
|
async fn inner_sweep(
|
2025-03-17 17:57:26 +13:00
|
|
|
sketches: Vec<Sketch>,
|
2025-02-07 12:35:04 -06:00
|
|
|
path: SweepPath,
|
|
|
|
sectional: Option<bool>,
|
2025-04-23 10:58:35 +12:00
|
|
|
tolerance: Option<TyF64>,
|
2025-05-14 13:54:10 -05:00
|
|
|
relative_to: Option<String>,
|
2025-03-19 12:18:19 -07:00
|
|
|
tag_start: Option<TagNode>,
|
|
|
|
tag_end: Option<TagNode>,
|
2024-12-11 12:59:02 -08:00
|
|
|
exec_state: &mut ExecState,
|
|
|
|
args: Args,
|
2025-03-17 17:57:26 +13:00
|
|
|
) -> Result<Vec<Solid>, KclError> {
|
2025-03-13 09:38:22 -07:00
|
|
|
let trajectory = match path {
|
|
|
|
SweepPath::Sketch(sketch) => sketch.id.into(),
|
|
|
|
SweepPath::Helix(helix) => helix.value.into(),
|
|
|
|
};
|
2025-05-14 13:54:10 -05:00
|
|
|
let relative_to = match relative_to.as_deref() {
|
|
|
|
Some("sketchPlane") => RelativeTo::SketchPlane,
|
2025-05-15 04:50:55 -07:00
|
|
|
Some("trajectoryCurve") | None => RelativeTo::TrajectoryCurve,
|
2025-05-14 13:54:10 -05:00
|
|
|
Some(_) => {
|
2025-06-02 13:30:57 -05:00
|
|
|
return Err(KclError::new_syntax(crate::errors::KclErrorDetails::new(
|
2025-05-19 14:13:10 -04:00
|
|
|
"If you provide relativeTo, it must either be 'sketchPlane' or 'trajectoryCurve'".to_owned(),
|
|
|
|
vec![args.source_range],
|
|
|
|
)))
|
2025-05-14 13:54:10 -05:00
|
|
|
}
|
|
|
|
};
|
2025-03-13 09:38:22 -07:00
|
|
|
|
|
|
|
let mut solids = Vec::new();
|
|
|
|
for sketch in &sketches {
|
|
|
|
let id = exec_state.next_uuid();
|
|
|
|
args.batch_modeling_cmd(
|
|
|
|
id,
|
|
|
|
ModelingCmd::from(mcmd::Sweep {
|
|
|
|
target: sketch.id.into(),
|
|
|
|
trajectory,
|
|
|
|
sectional: sectional.unwrap_or(false),
|
2025-04-23 10:58:35 +12:00
|
|
|
tolerance: LengthUnit(tolerance.as_ref().map(|t| t.to_mm()).unwrap_or(DEFAULT_TOLERANCE)),
|
2025-05-14 13:54:10 -05:00
|
|
|
relative_to,
|
2025-03-13 09:38:22 -07:00
|
|
|
}),
|
|
|
|
)
|
|
|
|
.await?;
|
|
|
|
|
2025-03-19 12:18:19 -07:00
|
|
|
solids.push(
|
|
|
|
do_post_extrude(
|
|
|
|
sketch,
|
|
|
|
id.into(),
|
2025-04-23 10:58:35 +12:00
|
|
|
TyF64::new(0.0, NumericType::mm()),
|
2025-03-20 20:42:41 -04:00
|
|
|
sectional.unwrap_or(false),
|
2025-03-19 12:18:19 -07:00
|
|
|
&super::extrude::NamedCapTags {
|
|
|
|
start: tag_start.as_ref(),
|
|
|
|
end: tag_end.as_ref(),
|
|
|
|
},
|
|
|
|
exec_state,
|
|
|
|
&args,
|
2025-05-16 23:02:30 +01:00
|
|
|
None,
|
2025-03-19 12:18:19 -07:00
|
|
|
)
|
|
|
|
.await?,
|
|
|
|
);
|
2025-03-13 09:38:22 -07:00
|
|
|
}
|
2024-12-11 12:59:02 -08:00
|
|
|
|
2025-04-11 12:53:53 -07:00
|
|
|
// Hide the artifact from the sketch or helix.
|
|
|
|
args.batch_modeling_cmd(
|
|
|
|
exec_state.next_uuid(),
|
|
|
|
ModelingCmd::from(mcmd::ObjectVisible {
|
|
|
|
object_id: trajectory.into(),
|
|
|
|
hidden: true,
|
|
|
|
}),
|
|
|
|
)
|
|
|
|
.await?;
|
|
|
|
|
2025-03-17 17:57:26 +13:00
|
|
|
Ok(solids)
|
2024-12-11 12:59:02 -08:00
|
|
|
}
|