|
|
|
@ -4,35 +4,28 @@ use anyhow::Result;
|
|
|
|
|
use kcl_derive_docs::stdlib;
|
|
|
|
|
use kcmc::{each_cmd as mcmd, length_unit::LengthUnit, shared::Angle, ModelingCmd};
|
|
|
|
|
use kittycad_modeling_cmds::{self as kcmc};
|
|
|
|
|
use schemars::JsonSchema;
|
|
|
|
|
use serde::{Deserialize, Serialize};
|
|
|
|
|
|
|
|
|
|
use crate::{
|
|
|
|
|
errors::{KclError, KclErrorDetails},
|
|
|
|
|
execution::{ExecState, KclValue, Sketch, Solid},
|
|
|
|
|
execution::{
|
|
|
|
|
kcl_value::{ArrayLen, RuntimeType},
|
|
|
|
|
ExecState, KclValue, PrimitiveType, Sketch, Solid,
|
|
|
|
|
},
|
|
|
|
|
std::{axis_or_reference::Axis2dOrEdgeReference, extrude::do_post_extrude, fillet::default_tolerance, Args},
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/// Data for revolution surfaces.
|
|
|
|
|
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema)]
|
|
|
|
|
#[ts(export)]
|
|
|
|
|
pub struct RevolveData {
|
|
|
|
|
/// Angle to revolve (in degrees). Default is 360.
|
|
|
|
|
#[serde(default)]
|
|
|
|
|
#[schemars(range(min = -360.0, max = 360.0))]
|
|
|
|
|
pub angle: Option<f64>,
|
|
|
|
|
/// Axis of revolution.
|
|
|
|
|
pub axis: Axis2dOrEdgeReference,
|
|
|
|
|
/// Tolerance for the revolve operation.
|
|
|
|
|
#[serde(default)]
|
|
|
|
|
pub tolerance: Option<f64>,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Revolve a sketch or set of sketches around an axis.
|
|
|
|
|
pub async fn revolve(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
|
|
|
|
|
let (data, sketches): (RevolveData, _) = args.get_data_and_sketches(exec_state)?;
|
|
|
|
|
let sketches = args.get_unlabeled_kw_arg_typed(
|
|
|
|
|
"sketches",
|
|
|
|
|
&RuntimeType::Array(PrimitiveType::Sketch, ArrayLen::NonEmpty),
|
|
|
|
|
exec_state,
|
|
|
|
|
)?;
|
|
|
|
|
let axis: Axis2dOrEdgeReference = args.get_kw_arg("axis")?;
|
|
|
|
|
let angle = args.get_kw_arg_opt("angle")?;
|
|
|
|
|
let tolerance = args.get_kw_arg_opt("tolerance")?;
|
|
|
|
|
|
|
|
|
|
let value = inner_revolve(data, sketches, exec_state, args).await?;
|
|
|
|
|
let value = inner_revolve(sketches, axis, angle, tolerance, exec_state, args).await?;
|
|
|
|
|
Ok(value.into())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@ -60,17 +53,17 @@ pub async fn revolve(exec_state: &mut ExecState, args: Args) -> Result<KclValue,
|
|
|
|
|
/// |> line(end = [0, -5.5])
|
|
|
|
|
/// |> line(end = [-2, 0])
|
|
|
|
|
/// |> close()
|
|
|
|
|
/// |> revolve({axis = 'y'}, %) // default angle is 360
|
|
|
|
|
/// |> revolve(axis = 'y') // default angle is 360
|
|
|
|
|
/// ```
|
|
|
|
|
///
|
|
|
|
|
/// ```no_run
|
|
|
|
|
/// // A donut shape.
|
|
|
|
|
/// sketch001 = startSketchOn('XY')
|
|
|
|
|
/// |> circle( center = [15, 0], radius = 5 )
|
|
|
|
|
/// |> revolve({
|
|
|
|
|
/// |> revolve(
|
|
|
|
|
/// angle = 360,
|
|
|
|
|
/// axis = 'y'
|
|
|
|
|
/// }, %)
|
|
|
|
|
/// )
|
|
|
|
|
/// ```
|
|
|
|
|
///
|
|
|
|
|
/// ```no_run
|
|
|
|
@ -84,7 +77,7 @@ pub async fn revolve(exec_state: &mut ExecState, args: Args) -> Result<KclValue,
|
|
|
|
|
/// |> line(end = [0, -5.5])
|
|
|
|
|
/// |> line(end = [-2, 0])
|
|
|
|
|
/// |> close()
|
|
|
|
|
/// |> revolve({axis = 'y', angle = 180}, %)
|
|
|
|
|
/// |> revolve(axis = 'y', angle = 180)
|
|
|
|
|
/// ```
|
|
|
|
|
///
|
|
|
|
|
/// ```no_run
|
|
|
|
@ -98,7 +91,8 @@ pub async fn revolve(exec_state: &mut ExecState, args: Args) -> Result<KclValue,
|
|
|
|
|
/// |> line(end = [0, -5.5])
|
|
|
|
|
/// |> line(end = [-2, 0])
|
|
|
|
|
/// |> close()
|
|
|
|
|
/// |> revolve({axis = 'y', angle = 180}, %)
|
|
|
|
|
/// |> revolve(axis = 'y', angle = 180)
|
|
|
|
|
///
|
|
|
|
|
/// part002 = startSketchOn(part001, 'end')
|
|
|
|
|
/// |> startProfileAt([4.5, -5], %)
|
|
|
|
|
/// |> line(end = [0, 5])
|
|
|
|
@ -119,10 +113,10 @@ pub async fn revolve(exec_state: &mut ExecState, args: Args) -> Result<KclValue,
|
|
|
|
|
///
|
|
|
|
|
/// sketch001 = startSketchOn(box, "END")
|
|
|
|
|
/// |> circle( center = [10,10], radius = 4 )
|
|
|
|
|
/// |> revolve({
|
|
|
|
|
/// |> revolve(
|
|
|
|
|
/// angle = -90,
|
|
|
|
|
/// axis = 'y'
|
|
|
|
|
/// }, %)
|
|
|
|
|
/// )
|
|
|
|
|
/// ```
|
|
|
|
|
///
|
|
|
|
|
/// ```no_run
|
|
|
|
@ -136,10 +130,10 @@ pub async fn revolve(exec_state: &mut ExecState, args: Args) -> Result<KclValue,
|
|
|
|
|
///
|
|
|
|
|
/// sketch001 = startSketchOn(box, "END")
|
|
|
|
|
/// |> circle( center = [10,10], radius = 4 )
|
|
|
|
|
/// |> revolve({
|
|
|
|
|
/// |> revolve(
|
|
|
|
|
/// angle = 90,
|
|
|
|
|
/// axis = getOppositeEdge(revolveAxis)
|
|
|
|
|
/// }, %)
|
|
|
|
|
/// )
|
|
|
|
|
/// ```
|
|
|
|
|
///
|
|
|
|
|
/// ```no_run
|
|
|
|
@ -153,11 +147,11 @@ pub async fn revolve(exec_state: &mut ExecState, args: Args) -> Result<KclValue,
|
|
|
|
|
///
|
|
|
|
|
/// sketch001 = startSketchOn(box, "END")
|
|
|
|
|
/// |> circle( center = [10,10], radius = 4 )
|
|
|
|
|
/// |> revolve({
|
|
|
|
|
/// |> revolve(
|
|
|
|
|
/// angle = 90,
|
|
|
|
|
/// axis = getOppositeEdge(revolveAxis),
|
|
|
|
|
/// tolerance: 0.0001
|
|
|
|
|
/// }, %)
|
|
|
|
|
/// tolerance = 0.0001
|
|
|
|
|
/// )
|
|
|
|
|
/// ```
|
|
|
|
|
///
|
|
|
|
|
/// ```no_run
|
|
|
|
@ -168,14 +162,15 @@ pub async fn revolve(exec_state: &mut ExecState, args: Args) -> Result<KclValue,
|
|
|
|
|
/// |> line(endAbsolute = [profileStartX(%), profileStartY(%)])
|
|
|
|
|
/// |> close()
|
|
|
|
|
///
|
|
|
|
|
/// part001 = revolve({
|
|
|
|
|
/// part001 = revolve(
|
|
|
|
|
/// sketch001,
|
|
|
|
|
/// axis = {
|
|
|
|
|
/// custom: {
|
|
|
|
|
/// axis = [0.0, 1.0],
|
|
|
|
|
/// origin: [0.0, 0.0]
|
|
|
|
|
/// }
|
|
|
|
|
/// }
|
|
|
|
|
/// }, sketch001)
|
|
|
|
|
/// )
|
|
|
|
|
/// ```
|
|
|
|
|
///
|
|
|
|
|
/// ```no_run
|
|
|
|
@ -196,9 +191,10 @@ pub async fn revolve(exec_state: &mut ExecState, args: Args) -> Result<KclValue,
|
|
|
|
|
/// |> line(endAbsolute = [profileStartX(%), profileStartY(%)])
|
|
|
|
|
/// |> close()
|
|
|
|
|
///
|
|
|
|
|
/// revolve({
|
|
|
|
|
/// revolve(
|
|
|
|
|
/// [profile001, profile002],
|
|
|
|
|
/// axis = "X",
|
|
|
|
|
/// }, [profile001, profile002])
|
|
|
|
|
/// )
|
|
|
|
|
/// ```
|
|
|
|
|
///
|
|
|
|
|
/// ```no_run
|
|
|
|
@ -213,7 +209,7 @@ pub async fn revolve(exec_state: &mut ExecState, args: Args) -> Result<KclValue,
|
|
|
|
|
///
|
|
|
|
|
/// sketch001 = startSketchOn('XY')
|
|
|
|
|
/// |> circle(center = [-10, 10], radius = 4)
|
|
|
|
|
/// |> revolve({ angle: 90, axis: revolveAxis }, %)
|
|
|
|
|
/// |> revolve(angle = 90, axis = revolveAxis)
|
|
|
|
|
/// ```
|
|
|
|
|
///
|
|
|
|
|
/// ```no_run
|
|
|
|
@ -226,19 +222,29 @@ pub async fn revolve(exec_state: &mut ExecState, args: Args) -> Result<KclValue,
|
|
|
|
|
///
|
|
|
|
|
/// sketch001 = startSketchOn('XY')
|
|
|
|
|
/// |> circle(center = [-10, 10], radius = 4)
|
|
|
|
|
/// |> revolve({ angle: 90, axis: revolveAxis }, %)
|
|
|
|
|
/// |> revolve(angle = 90, axis = revolveAxis)
|
|
|
|
|
/// ```
|
|
|
|
|
#[stdlib {
|
|
|
|
|
name = "revolve",
|
|
|
|
|
feature_tree_operation = true,
|
|
|
|
|
keywords = true,
|
|
|
|
|
unlabeled_first = true,
|
|
|
|
|
args = {
|
|
|
|
|
sketches = { docs = "The sketch or set of sketches that should be revolved" },
|
|
|
|
|
axis = { docs = "Axis of revolution." },
|
|
|
|
|
angle = { docs = "Angle to revolve (in degrees). Default is 360." },
|
|
|
|
|
tolerance = { docs = "Tolerance for the revolve operation." },
|
|
|
|
|
}
|
|
|
|
|
}]
|
|
|
|
|
async fn inner_revolve(
|
|
|
|
|
data: RevolveData,
|
|
|
|
|
sketches: Vec<Sketch>,
|
|
|
|
|
axis: Axis2dOrEdgeReference,
|
|
|
|
|
angle: Option<f64>,
|
|
|
|
|
tolerance: Option<f64>,
|
|
|
|
|
exec_state: &mut ExecState,
|
|
|
|
|
args: Args,
|
|
|
|
|
) -> Result<Vec<Solid>, KclError> {
|
|
|
|
|
if let Some(angle) = data.angle {
|
|
|
|
|
if let Some(angle) = angle {
|
|
|
|
|
// Return an error if the angle is zero.
|
|
|
|
|
// We don't use validate() here because we want to return a specific error message that is
|
|
|
|
|
// nice and we use the other data in the docs, so we still need use the derive above for the json schema.
|
|
|
|
@ -250,13 +256,13 @@ async fn inner_revolve(
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
let angle = Angle::from_degrees(data.angle.unwrap_or(360.0));
|
|
|
|
|
let angle = Angle::from_degrees(angle.unwrap_or(360.0));
|
|
|
|
|
|
|
|
|
|
let mut solids = Vec::new();
|
|
|
|
|
for sketch in &sketches {
|
|
|
|
|
let id = exec_state.next_uuid();
|
|
|
|
|
|
|
|
|
|
match &data.axis {
|
|
|
|
|
match &axis {
|
|
|
|
|
Axis2dOrEdgeReference::Axis(axis) => {
|
|
|
|
|
let (axis, origin) = axis.axis_and_origin()?;
|
|
|
|
|
args.batch_modeling_cmd(
|
|
|
|
@ -266,7 +272,7 @@ async fn inner_revolve(
|
|
|
|
|
target: sketch.id.into(),
|
|
|
|
|
axis,
|
|
|
|
|
origin,
|
|
|
|
|
tolerance: LengthUnit(data.tolerance.unwrap_or(default_tolerance(&args.ctx.settings.units))),
|
|
|
|
|
tolerance: LengthUnit(tolerance.unwrap_or(default_tolerance(&args.ctx.settings.units))),
|
|
|
|
|
axis_is_2d: true,
|
|
|
|
|
}),
|
|
|
|
|
)
|
|
|
|
@ -280,7 +286,7 @@ async fn inner_revolve(
|
|
|
|
|
angle,
|
|
|
|
|
target: sketch.id.into(),
|
|
|
|
|
edge_id,
|
|
|
|
|
tolerance: LengthUnit(data.tolerance.unwrap_or(default_tolerance(&args.ctx.settings.units))),
|
|
|
|
|
tolerance: LengthUnit(tolerance.unwrap_or(default_tolerance(&args.ctx.settings.units))),
|
|
|
|
|
}),
|
|
|
|
|
)
|
|
|
|
|
.await?;
|
|
|
|
|