Move more functions to KCL decls (#7266)
* Move some sketch functions to KCL Signed-off-by: Nick Cameron <nrc@ncameron.org> * Move asserts to KCL Signed-off-by: Nick Cameron <nrc@ncameron.org> * sweep, loft -> KCL Signed-off-by: Nick Cameron <nrc@ncameron.org> * Move pattern transforms to KCL Signed-off-by: Nick Cameron <nrc@ncameron.org> --------- Signed-off-by: Nick Cameron <nrc@ncameron.org>
This commit is contained in:
@ -644,13 +644,13 @@ impl FnData {
|
||||
format!("{}({})", self.preferred_name, args.join(", "))
|
||||
}
|
||||
|
||||
fn to_signature_help(&self) -> SignatureHelp {
|
||||
pub(crate) fn to_signature_help(&self) -> SignatureHelp {
|
||||
// TODO Fill this in based on the current position of the cursor.
|
||||
let active_parameter = None;
|
||||
|
||||
SignatureHelp {
|
||||
signatures: vec![SignatureInformation {
|
||||
label: self.preferred_name.clone(),
|
||||
label: self.preferred_name.clone() + &self.fn_signature(),
|
||||
documentation: self.short_docs().map(|s| {
|
||||
Documentation::MarkupContent(MarkupContent {
|
||||
kind: MarkupKind::Markdown,
|
||||
@ -824,6 +824,7 @@ impl ArgData {
|
||||
),
|
||||
)),
|
||||
Some("Axis2d | Edge") | Some("Axis3d | Edge") => Some((index, format!(r#"{label}${{{index}:X}}"#))),
|
||||
Some("Sketch") | Some("Sketch | Helix") => Some((index, format!(r#"{label}${{{index}:sketch000}}"#))),
|
||||
Some("Edge") => Some((index, format!(r#"{label}${{{index}:tag_or_edge_fn}}"#))),
|
||||
Some("[Edge; 1+]") => Some((index, format!(r#"{label}[${{{index}:tag_or_edge_fn}}]"#))),
|
||||
Some("Plane") => Some((index, format!(r#"{label}${{{}:XY}}"#, index))),
|
||||
@ -1280,7 +1281,10 @@ mod test {
|
||||
continue;
|
||||
};
|
||||
|
||||
for i in 0..f.examples.len() {
|
||||
for (i, (_, props)) in f.examples.iter().enumerate() {
|
||||
if props.norun {
|
||||
continue;
|
||||
}
|
||||
let name = format!("{}-{i}", f.qual_name.replace("::", "-"));
|
||||
assert!(TEST_NAMES.contains(&&*name), "Missing test for example \"{name}\", maybe need to update kcl-derive-docs/src/example_tests.rs?")
|
||||
}
|
||||
|
@ -976,9 +976,12 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn get_autocomplete_snippet_extrude() {
|
||||
let extrude_fn: Box<dyn StdLibFn> = Box::new(crate::std::extrude::Extrude);
|
||||
let snippet = extrude_fn.to_autocomplete_snippet().unwrap();
|
||||
assert_eq!(snippet, r#"extrude(${0:%}, length = ${1:3.14})"#);
|
||||
let data = kcl_doc::walk_prelude();
|
||||
let DocData::Fn(data) = data.find_by_name("extrude").unwrap() else {
|
||||
panic!();
|
||||
};
|
||||
let snippet = data.to_autocomplete_snippet();
|
||||
assert_eq!(snippet, r#"extrude(length = ${0:10})"#);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -1064,11 +1067,14 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn get_autocomplete_snippet_pattern_linear_2d() {
|
||||
let pattern_fn: Box<dyn StdLibFn> = Box::new(crate::std::patterns::PatternLinear2D);
|
||||
let snippet = pattern_fn.to_autocomplete_snippet().unwrap();
|
||||
let data = kcl_doc::walk_prelude();
|
||||
let DocData::Fn(data) = data.find_by_name("patternLinear2d").unwrap() else {
|
||||
panic!();
|
||||
};
|
||||
let snippet = data.to_autocomplete_snippet();
|
||||
assert_eq!(
|
||||
snippet,
|
||||
r#"patternLinear2d(${0:%}, instances = ${1:10}, distance = ${2:3.14}, axis = [${3:1}, ${4:0}])"#
|
||||
r#"patternLinear2d(instances = ${0:10}, distance = ${1:10}, axis = [${2:1}, ${3:0}])"#
|
||||
);
|
||||
}
|
||||
|
||||
@ -1084,16 +1090,22 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn get_autocomplete_snippet_loft() {
|
||||
let loft_fn: Box<dyn StdLibFn> = Box::new(crate::std::loft::Loft);
|
||||
let snippet = loft_fn.to_autocomplete_snippet().unwrap();
|
||||
let data = kcl_doc::walk_prelude();
|
||||
let DocData::Fn(data) = data.find_by_name("loft").unwrap() else {
|
||||
panic!();
|
||||
};
|
||||
let snippet = data.to_autocomplete_snippet();
|
||||
assert_eq!(snippet, r#"loft([${0:sketch000}, ${1:sketch001}])"#);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn get_autocomplete_snippet_sweep() {
|
||||
let sweep_fn: Box<dyn StdLibFn> = Box::new(crate::std::sweep::Sweep);
|
||||
let snippet = sweep_fn.to_autocomplete_snippet().unwrap();
|
||||
assert_eq!(snippet, r#"sweep(${0:%}, path = ${1:sketch000})"#);
|
||||
let data = kcl_doc::walk_prelude();
|
||||
let DocData::Fn(data) = data.find_by_name("sweep").unwrap() else {
|
||||
panic!();
|
||||
};
|
||||
let snippet = data.to_autocomplete_snippet();
|
||||
assert_eq!(snippet, r#"sweep(path = ${0:sketch000})"#);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -1225,18 +1237,21 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn get_extrude_signature_help() {
|
||||
let extrude_fn: Box<dyn StdLibFn> = Box::new(crate::std::extrude::Extrude);
|
||||
let sh = extrude_fn.to_signature_help();
|
||||
let data = kcl_doc::walk_prelude();
|
||||
let DocData::Fn(data) = data.find_by_name("extrude").unwrap() else {
|
||||
panic!();
|
||||
};
|
||||
let sh = data.to_signature_help();
|
||||
assert_eq!(
|
||||
sh.signatures[0].label,
|
||||
r#"extrude(
|
||||
@sketches: [Sketch],
|
||||
length: number,
|
||||
@sketches: [Sketch; 1+],
|
||||
length: number(Length),
|
||||
symmetric?: bool,
|
||||
bidirectionalLength?: number,
|
||||
tagStart?: TagNode,
|
||||
tagEnd?: TagNode,
|
||||
): [Solid]"#
|
||||
bidirectionalLength?: number(Length),
|
||||
tagStart?: tag,
|
||||
tagEnd?: tag,
|
||||
): [Solid; 1+]"#
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -1202,17 +1202,7 @@ a1 = startSketchOn(offsetPlane(XY, offset = 10))
|
||||
"Expected one signature, got {:?}",
|
||||
signature_help.signatures
|
||||
);
|
||||
assert_eq!(
|
||||
signature_help.signatures[0].label,
|
||||
r#"extrude(
|
||||
@sketches: [Sketch],
|
||||
length: number,
|
||||
symmetric?: bool,
|
||||
bidirectionalLength?: number,
|
||||
tagStart?: TagNode,
|
||||
tagEnd?: TagNode,
|
||||
): [Solid]"#
|
||||
);
|
||||
assert!(signature_help.signatures[0].label.starts_with("extrude"));
|
||||
} else {
|
||||
panic!("Expected signature help");
|
||||
}
|
||||
@ -1300,17 +1290,7 @@ a1 = startSketchOn(offsetPlane(XY, offset = 10))
|
||||
"Expected one signature, got {:?}",
|
||||
signature_help.signatures
|
||||
);
|
||||
assert_eq!(
|
||||
signature_help.signatures[0].label,
|
||||
r#"extrude(
|
||||
@sketches: [Sketch],
|
||||
length: number,
|
||||
symmetric?: bool,
|
||||
bidirectionalLength?: number,
|
||||
tagStart?: TagNode,
|
||||
tagEnd?: TagNode,
|
||||
): [Solid]"#
|
||||
);
|
||||
assert!(signature_help.signatures[0].label.starts_with("extrude"));
|
||||
} else {
|
||||
panic!("Expected signature help");
|
||||
}
|
||||
@ -1393,17 +1373,7 @@ a1 = startSketchOn(offsetPlane(XY, offset = 10))
|
||||
"Expected one signature, got {:?}",
|
||||
signature_help.signatures
|
||||
);
|
||||
assert_eq!(
|
||||
signature_help.signatures[0].label,
|
||||
r#"extrude(
|
||||
@sketches: [Sketch],
|
||||
length: number,
|
||||
symmetric?: bool,
|
||||
bidirectionalLength?: number,
|
||||
tagStart?: TagNode,
|
||||
tagEnd?: TagNode,
|
||||
): [Solid]"#
|
||||
);
|
||||
assert!(signature_help.signatures[0].label.starts_with("extrude"));
|
||||
} else {
|
||||
panic!("Expected signature help");
|
||||
}
|
||||
@ -1491,17 +1461,7 @@ a1 = startSketchOn(offsetPlane(XY, offset = 10))
|
||||
"Expected one signature, got {:?}",
|
||||
signature_help.signatures
|
||||
);
|
||||
assert_eq!(
|
||||
signature_help.signatures[0].label,
|
||||
r#"extrude(
|
||||
@sketches: [Sketch],
|
||||
length: number,
|
||||
symmetric?: bool,
|
||||
bidirectionalLength?: number,
|
||||
tagStart?: TagNode,
|
||||
tagEnd?: TagNode,
|
||||
): [Solid]"#
|
||||
);
|
||||
assert!(signature_help.signatures[0].label.starts_with("extrude"));
|
||||
} else {
|
||||
panic!("Expected signature help");
|
||||
}
|
||||
|
@ -1,7 +1,6 @@
|
||||
//! Standard library assert functions.
|
||||
|
||||
use anyhow::Result;
|
||||
use kcl_derive_docs::stdlib;
|
||||
|
||||
use super::args::TyF64;
|
||||
use crate::{
|
||||
@ -42,19 +41,6 @@ pub async fn assert(exec_state: &mut ExecState, args: Args) -> Result<KclValue,
|
||||
Ok(KclValue::none())
|
||||
}
|
||||
|
||||
/// Asserts that a value is the boolean value true.
|
||||
/// ```no_run
|
||||
/// kclIsFun = true
|
||||
/// assertIs(kclIsFun)
|
||||
/// ```
|
||||
#[stdlib{
|
||||
name = "assertIs",
|
||||
unlabeled_first = true,
|
||||
args = {
|
||||
actual = { docs = "Value to check. If this is the boolean value true, assert passes. Otherwise it fails." },
|
||||
error = { docs = "If the value was false, the program will terminate with this error message" },
|
||||
}
|
||||
}]
|
||||
async fn inner_assert_is(actual: bool, error: Option<String>, args: &Args) -> Result<(), KclError> {
|
||||
let error_msg = match &error {
|
||||
Some(x) => x,
|
||||
@ -63,29 +49,6 @@ async fn inner_assert_is(actual: bool, error: Option<String>, args: &Args) -> Re
|
||||
_assert(actual, error_msg, args).await
|
||||
}
|
||||
|
||||
/// Check a value meets some expected conditions at runtime. Program terminates with an error if conditions aren't met.
|
||||
/// If you provide multiple conditions, they will all be checked and all must be met.
|
||||
///
|
||||
/// ```no_run
|
||||
/// n = 10
|
||||
/// assert(n, isEqualTo = 10)
|
||||
/// assert(n, isGreaterThanOrEqual = 0, isLessThan = 100, error = "number should be between 0 and 100")
|
||||
/// assert(1.0000000000012, isEqualTo = 1, tolerance = 0.0001, error = "number should be almost exactly 1")
|
||||
/// ```
|
||||
#[stdlib {
|
||||
name = "assert",
|
||||
unlabeled_first = true,
|
||||
args = {
|
||||
actual = { docs = "Value to check. It will be compared with one of the comparison arguments." },
|
||||
is_greater_than = { docs = "Comparison argument. If given, checks the `actual` value is greater than this." },
|
||||
is_less_than = { docs = "Comparison argument. If given, checks the `actual` value is less than this." },
|
||||
is_greater_than_or_equal = { docs = "Comparison argument. If given, checks the `actual` value is greater than or equal to this." },
|
||||
is_less_than_or_equal = { docs = "Comparison argument. If given, checks the `actual` value is less than or equal to this." },
|
||||
is_equal_to = { docs = "Comparison argument. If given, checks the `actual` value is less than or equal to this.", include_in_snippet = true },
|
||||
tolerance = { docs = "If `isEqualTo` is used, this is the tolerance to allow for the comparison. This tolerance is used because KCL's number system has some floating-point imprecision when used with very large decimal places." },
|
||||
error = { docs = "If the value was false, the program will terminate with this error message" },
|
||||
}
|
||||
}]
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
async fn inner_assert(
|
||||
actual: TyF64,
|
||||
|
@ -3,7 +3,6 @@
|
||||
use std::collections::HashMap;
|
||||
|
||||
use anyhow::Result;
|
||||
use kcl_derive_docs::stdlib;
|
||||
use kcmc::{
|
||||
each_cmd as mcmd,
|
||||
length_unit::LengthUnit,
|
||||
@ -52,113 +51,6 @@ pub async fn extrude(exec_state: &mut ExecState, args: Args) -> Result<KclValue,
|
||||
Ok(result.into())
|
||||
}
|
||||
|
||||
/// Extend a 2-dimensional sketch through a third dimension in order to
|
||||
/// create new 3-dimensional volume, or if extruded into an existing volume,
|
||||
/// cut into an existing solid.
|
||||
///
|
||||
/// You can provide more than one sketch to extrude, and they will all be
|
||||
/// extruded in the same direction.
|
||||
///
|
||||
/// ```no_run
|
||||
/// example = startSketchOn(XZ)
|
||||
/// |> startProfile(at = [0, 0])
|
||||
/// |> line(end = [10, 0])
|
||||
/// |> arc(
|
||||
/// angleStart = 120,
|
||||
/// angleEnd = 0,
|
||||
/// radius = 5,
|
||||
/// )
|
||||
/// |> line(end = [5, 0])
|
||||
/// |> line(end = [0, 10])
|
||||
/// |> bezierCurve(
|
||||
/// control1 = [-10, 0],
|
||||
/// control2 = [2, 10],
|
||||
/// end = [-5, 10],
|
||||
/// )
|
||||
/// |> line(end = [-5, -2])
|
||||
/// |> close()
|
||||
/// |> extrude(length = 10)
|
||||
/// ```
|
||||
///
|
||||
/// ```no_run
|
||||
/// exampleSketch = startSketchOn(XZ)
|
||||
/// |> startProfile(at = [-10, 0])
|
||||
/// |> arc(
|
||||
/// angleStart = 120,
|
||||
/// angleEnd = -60,
|
||||
/// radius = 5,
|
||||
/// )
|
||||
/// |> line(end = [10, 0])
|
||||
/// |> line(end = [5, 0])
|
||||
/// |> bezierCurve(
|
||||
/// control1 = [-3, 0],
|
||||
/// control2 = [2, 10],
|
||||
/// end = [-5, 10],
|
||||
/// )
|
||||
/// |> line(end = [-4, 10])
|
||||
/// |> line(end = [-5, -2])
|
||||
/// |> close()
|
||||
///
|
||||
/// example = extrude(exampleSketch, length = 10)
|
||||
/// ```
|
||||
///
|
||||
/// ```no_run
|
||||
/// exampleSketch = startSketchOn(XZ)
|
||||
/// |> startProfile(at = [-10, 0])
|
||||
/// |> arc(
|
||||
/// angleStart = 120,
|
||||
/// angleEnd = -60,
|
||||
/// radius = 5,
|
||||
/// )
|
||||
/// |> line(end = [10, 0])
|
||||
/// |> line(end = [5, 0])
|
||||
/// |> bezierCurve(
|
||||
/// control1 = [-3, 0],
|
||||
/// control2 = [2, 10],
|
||||
/// end = [-5, 10],
|
||||
/// )
|
||||
/// |> line(end = [-4, 10])
|
||||
/// |> line(end = [-5, -2])
|
||||
/// |> close()
|
||||
///
|
||||
/// example = extrude(exampleSketch, length = 20, symmetric = true)
|
||||
/// ```
|
||||
///
|
||||
/// ```no_run
|
||||
/// exampleSketch = startSketchOn(XZ)
|
||||
/// |> startProfile(at = [-10, 0])
|
||||
/// |> arc(
|
||||
/// angleStart = 120,
|
||||
/// angleEnd = -60,
|
||||
/// radius = 5,
|
||||
/// )
|
||||
/// |> line(end = [10, 0])
|
||||
/// |> line(end = [5, 0])
|
||||
/// |> bezierCurve(
|
||||
/// control1 = [-3, 0],
|
||||
/// control2 = [2, 10],
|
||||
/// end = [-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,
|
||||
unlabeled_first = true,
|
||||
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" },
|
||||
},
|
||||
tags = ["sketch"]
|
||||
}]
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
async fn inner_extrude(
|
||||
sketches: Vec<Sketch>,
|
||||
|
@ -3,7 +3,6 @@
|
||||
use std::num::NonZeroU32;
|
||||
|
||||
use anyhow::Result;
|
||||
use kcl_derive_docs::stdlib;
|
||||
use kcmc::{each_cmd as mcmd, length_unit::LengthUnit, ModelingCmd};
|
||||
use kittycad_modeling_cmds as kcmc;
|
||||
|
||||
@ -55,87 +54,6 @@ pub async fn loft(exec_state: &mut ExecState, args: Args) -> Result<KclValue, Kc
|
||||
Ok(KclValue::Solid { value })
|
||||
}
|
||||
|
||||
/// Create a 3D surface or solid by interpolating between two or more sketches.
|
||||
///
|
||||
/// The sketches need to closed and on the same plane.
|
||||
///
|
||||
/// ```no_run
|
||||
/// // Loft a square and a triangle.
|
||||
/// squareSketch = startSketchOn(XY)
|
||||
/// |> startProfile(at = [-100, 200])
|
||||
/// |> line(end = [200, 0])
|
||||
/// |> line(end = [0, -200])
|
||||
/// |> line(end = [-200, 0])
|
||||
/// |> line(endAbsolute = [profileStartX(%), profileStartY(%)])
|
||||
/// |> close()
|
||||
///
|
||||
/// triangleSketch = startSketchOn(offsetPlane(XY, offset = 75))
|
||||
/// |> startProfile(at = [0, 125])
|
||||
/// |> line(end = [-15, -30])
|
||||
/// |> line(end = [30, 0])
|
||||
/// |> line(endAbsolute = [profileStartX(%), profileStartY(%)])
|
||||
/// |> close()
|
||||
///
|
||||
/// loft([triangleSketch, squareSketch])
|
||||
/// ```
|
||||
///
|
||||
/// ```no_run
|
||||
/// // Loft a square, a circle, and another circle.
|
||||
/// squareSketch = startSketchOn(XY)
|
||||
/// |> startProfile(at = [-100, 200])
|
||||
/// |> line(end = [200, 0])
|
||||
/// |> line(end = [0, -200])
|
||||
/// |> line(end = [-200, 0])
|
||||
/// |> line(endAbsolute = [profileStartX(%), profileStartY(%)])
|
||||
/// |> close()
|
||||
///
|
||||
/// circleSketch0 = startSketchOn(offsetPlane(XY, offset = 75))
|
||||
/// |> circle( center = [0, 100], radius = 50 )
|
||||
///
|
||||
/// circleSketch1 = startSketchOn(offsetPlane(XY, offset = 150))
|
||||
/// |> circle( center = [0, 100], radius = 20 )
|
||||
///
|
||||
/// loft([squareSketch, circleSketch0, circleSketch1])
|
||||
/// ```
|
||||
///
|
||||
/// ```no_run
|
||||
/// // Loft a square, a circle, and another circle with options.
|
||||
/// squareSketch = startSketchOn(XY)
|
||||
/// |> startProfile(at = [-100, 200])
|
||||
/// |> line(end = [200, 0])
|
||||
/// |> line(end = [0, -200])
|
||||
/// |> line(end = [-200, 0])
|
||||
/// |> line(endAbsolute = [profileStartX(%), profileStartY(%)])
|
||||
/// |> close()
|
||||
///
|
||||
/// circleSketch0 = startSketchOn(offsetPlane(XY, offset = 75))
|
||||
/// |> circle( center = [0, 100], radius = 50 )
|
||||
///
|
||||
/// circleSketch1 = startSketchOn(offsetPlane(XY, offset = 150))
|
||||
/// |> circle( center = [0, 100], radius = 20 )
|
||||
///
|
||||
/// loft([squareSketch, circleSketch0, circleSketch1],
|
||||
/// baseCurveIndex = 0,
|
||||
/// bezApproximateRational = false,
|
||||
/// tolerance = 0.000001,
|
||||
/// vDegree = 2,
|
||||
/// )
|
||||
/// ```
|
||||
#[stdlib {
|
||||
name = "loft",
|
||||
feature_tree_operation = true,
|
||||
unlabeled_first = true,
|
||||
args = {
|
||||
sketches = {docs = "Which sketches to loft. Must include at least 2 sketches."},
|
||||
v_degree = {docs = "Degree of the interpolation. Must be greater than zero. For example, use 2 for quadratic, or 3 for cubic interpolation in the V direction. This defaults to 2, if not specified."},
|
||||
bez_approximate_rational = {docs = "Attempt to approximate rational curves (such as arcs) using a bezier. This will remove banding around interpolations between arcs and non-arcs. It may produce errors in other scenarios Over time, this field won't be necessary."},
|
||||
base_curve_index = {docs = "This can be set to override the automatically determined topological base curve, which is usually the first section encountered."},
|
||||
tolerance = {docs = "Tolerance for the loft operation."},
|
||||
tag_start = { docs = "A named tag for the face at the start of the loft, i.e. the original sketch" },
|
||||
tag_end = { docs = "A named tag for the face at the end of the loft, i.e. the last sketch" },
|
||||
},
|
||||
tags = ["sketch"]
|
||||
}]
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
async fn inner_loft(
|
||||
sketches: Vec<Sketch>,
|
||||
|
@ -45,7 +45,6 @@ pub type StdFn = fn(
|
||||
|
||||
lazy_static! {
|
||||
static ref CORE_FNS: Vec<Box<dyn StdLibFn>> = vec![
|
||||
Box::new(crate::std::extrude::Extrude),
|
||||
Box::new(crate::std::segment::SegEnd),
|
||||
Box::new(crate::std::segment::SegEndX),
|
||||
Box::new(crate::std::segment::SegEndY),
|
||||
@ -57,8 +56,6 @@ lazy_static! {
|
||||
Box::new(crate::std::segment::SegLen),
|
||||
Box::new(crate::std::segment::SegAng),
|
||||
Box::new(crate::std::segment::TangentToEnd),
|
||||
Box::new(crate::std::shapes::CircleThreePoint),
|
||||
Box::new(crate::std::shapes::Polygon),
|
||||
Box::new(crate::std::sketch::InvoluteCircular),
|
||||
Box::new(crate::std::sketch::Line),
|
||||
Box::new(crate::std::sketch::XLine),
|
||||
@ -75,12 +72,6 @@ lazy_static! {
|
||||
Box::new(crate::std::sketch::TangentialArc),
|
||||
Box::new(crate::std::sketch::BezierCurve),
|
||||
Box::new(crate::std::sketch::Subtract2D),
|
||||
Box::new(crate::std::patterns::PatternLinear2D),
|
||||
Box::new(crate::std::patterns::PatternCircular2D),
|
||||
Box::new(crate::std::sweep::Sweep),
|
||||
Box::new(crate::std::loft::Loft),
|
||||
Box::new(crate::std::assert::Assert),
|
||||
Box::new(crate::std::assert::AssertIs)
|
||||
];
|
||||
}
|
||||
|
||||
@ -233,6 +224,14 @@ pub(crate) fn std_fn(path: &str, fn_name: &str) -> (crate::std::StdFn, StdFnProp
|
||||
|e, a| Box::pin(crate::std::planes::offset_plane(e, a)),
|
||||
StdFnProps::default("std::offsetPlane").include_in_feature_tree(),
|
||||
),
|
||||
("prelude", "assert") => (
|
||||
|e, a| Box::pin(crate::std::assert::assert(e, a)),
|
||||
StdFnProps::default("std::assert"),
|
||||
),
|
||||
("prelude", "assertIs") => (
|
||||
|e, a| Box::pin(crate::std::assert::assert_is(e, a)),
|
||||
StdFnProps::default("std::assertIs"),
|
||||
),
|
||||
("solid", "fillet") => (
|
||||
|e, a| Box::pin(crate::std::fillet::fillet(e, a)),
|
||||
StdFnProps::default("std::solid::fillet").include_in_feature_tree(),
|
||||
@ -301,6 +300,10 @@ pub(crate) fn std_fn(path: &str, fn_name: &str) -> (crate::std::StdFn, StdFnProp
|
||||
|e, a| Box::pin(crate::std::shapes::circle(e, a)),
|
||||
StdFnProps::default("std::sketch::circle"),
|
||||
),
|
||||
("sketch", "extrude") => (
|
||||
|e, a| Box::pin(crate::std::extrude::extrude(e, a)),
|
||||
StdFnProps::default("std::sketch::extrude").include_in_feature_tree(),
|
||||
),
|
||||
("sketch", "patternTransform2d") => (
|
||||
|e, a| Box::pin(crate::std::patterns::pattern_transform_2d(e, a)),
|
||||
StdFnProps::default("std::sketch::patternTransform2d"),
|
||||
@ -309,6 +312,22 @@ pub(crate) fn std_fn(path: &str, fn_name: &str) -> (crate::std::StdFn, StdFnProp
|
||||
|e, a| Box::pin(crate::std::revolve::revolve(e, a)),
|
||||
StdFnProps::default("std::sketch::revolve").include_in_feature_tree(),
|
||||
),
|
||||
("sketch", "sweep") => (
|
||||
|e, a| Box::pin(crate::std::sweep::sweep(e, a)),
|
||||
StdFnProps::default("std::sketch::sweep").include_in_feature_tree(),
|
||||
),
|
||||
("sketch", "loft") => (
|
||||
|e, a| Box::pin(crate::std::loft::loft(e, a)),
|
||||
StdFnProps::default("std::sketch::loft").include_in_feature_tree(),
|
||||
),
|
||||
("sketch", "polygon") => (
|
||||
|e, a| Box::pin(crate::std::shapes::polygon(e, a)),
|
||||
StdFnProps::default("std::sketch::polygon"),
|
||||
),
|
||||
("sketch", "circleThreePoint") => (
|
||||
|e, a| Box::pin(crate::std::shapes::circle_three_point(e, a)),
|
||||
StdFnProps::default("std::sketch::circleThreePoint"),
|
||||
),
|
||||
("sketch", "getCommonEdge") => (
|
||||
|e, a| Box::pin(crate::std::edge::get_common_edge(e, a)),
|
||||
StdFnProps::default("std::sketch::getCommonEdge"),
|
||||
@ -325,6 +344,14 @@ pub(crate) fn std_fn(path: &str, fn_name: &str) -> (crate::std::StdFn, StdFnProp
|
||||
|e, a| Box::pin(crate::std::edge::get_previous_adjacent_edge(e, a)),
|
||||
StdFnProps::default("std::sketch::getPreviousAdjacentEdge"),
|
||||
),
|
||||
("sketch", "patternLinear2d") => (
|
||||
|e, a| Box::pin(crate::std::patterns::pattern_linear_2d(e, a)),
|
||||
StdFnProps::default("std::sketch::patternLinear2d"),
|
||||
),
|
||||
("sketch", "patternCircular2d") => (
|
||||
|e, a| Box::pin(crate::std::patterns::pattern_circular_2d(e, a)),
|
||||
StdFnProps::default("std::sketch::patternCircular2d"),
|
||||
),
|
||||
("appearance", "hexString") => (
|
||||
|e, a| Box::pin(crate::std::appearance::hex_string(e, a)),
|
||||
StdFnProps::default("std::appearance::hexString"),
|
||||
|
@ -3,7 +3,6 @@
|
||||
use std::cmp::Ordering;
|
||||
|
||||
use anyhow::Result;
|
||||
use kcl_derive_docs::stdlib;
|
||||
use kcmc::{
|
||||
each_cmd as mcmd, length_unit::LengthUnit, ok_response::OkModelingCmdResponse, shared::Transform,
|
||||
websocket::OkWebSocketResponseData, ModelingCmd,
|
||||
@ -546,47 +545,6 @@ pub async fn pattern_linear_2d(exec_state: &mut ExecState, args: Args) -> Result
|
||||
Ok(sketches.into())
|
||||
}
|
||||
|
||||
/// Repeat a 2-dimensional sketch along some dimension, with a dynamic amount
|
||||
/// of distance between each repetition, some specified number of times.
|
||||
///
|
||||
/// ```no_run
|
||||
/// /// Pattern using a named axis.
|
||||
///
|
||||
/// exampleSketch = startSketchOn(XZ)
|
||||
/// |> circle(center = [0, 0], radius = 1)
|
||||
/// |> patternLinear2d(
|
||||
/// axis = X,
|
||||
/// instances = 7,
|
||||
/// distance = 4
|
||||
/// )
|
||||
///
|
||||
/// example = extrude(exampleSketch, length = 1)
|
||||
/// ```
|
||||
///
|
||||
/// ```no_run
|
||||
/// /// Pattern using a raw axis.
|
||||
///
|
||||
/// exampleSketch = startSketchOn(XZ)
|
||||
/// |> circle(center = [0, 0], radius = 1)
|
||||
/// |> patternLinear2d(
|
||||
/// axis = [1, 0],
|
||||
/// instances = 7,
|
||||
/// distance = 4
|
||||
/// )
|
||||
///
|
||||
/// example = extrude(exampleSketch, length = 1)
|
||||
/// ```
|
||||
#[stdlib {
|
||||
name = "patternLinear2d",
|
||||
unlabeled_first = true,
|
||||
args = {
|
||||
sketches = { docs = "The sketch(es) to duplicate" },
|
||||
instances = { docs = "The number of total instances. Must be greater than or equal to 1. This includes the original entity. For example, if instances is 2, there will be two copies -- the original, and one new copy. If instances is 1, this has no effect." },
|
||||
distance = { docs = "Distance between each repetition. Also known as 'spacing'."},
|
||||
axis = { docs = "The axis of the pattern. A 2D vector.", snippet_value_array = ["1", "0"] },
|
||||
use_original = { docs = "If the target was sketched on an extrusion, setting this will use the original sketch as the target, not the entire joined solid. Defaults to false." },
|
||||
}
|
||||
}]
|
||||
async fn inner_pattern_linear_2d(
|
||||
sketches: Vec<Sketch>,
|
||||
instances: u32,
|
||||
@ -810,40 +768,6 @@ pub async fn pattern_circular_2d(exec_state: &mut ExecState, args: Args) -> Resu
|
||||
Ok(sketches.into())
|
||||
}
|
||||
|
||||
/// Repeat a 2-dimensional sketch some number of times along a partial or
|
||||
/// complete circle some specified number of times. Each object may
|
||||
/// additionally be rotated along the circle, ensuring orientation of the
|
||||
/// solid with respect to the center of the circle is maintained.
|
||||
///
|
||||
/// ```no_run
|
||||
/// exampleSketch = startSketchOn(XZ)
|
||||
/// |> startProfile(at = [.5, 25])
|
||||
/// |> line(end = [0, 5])
|
||||
/// |> line(end = [-1, 0])
|
||||
/// |> line(end = [0, -5])
|
||||
/// |> close()
|
||||
/// |> patternCircular2d(
|
||||
/// center = [0, 0],
|
||||
/// instances = 13,
|
||||
/// arcDegrees = 360,
|
||||
/// rotateDuplicates = true
|
||||
/// )
|
||||
///
|
||||
/// example = extrude(exampleSketch, length = 1)
|
||||
/// ```
|
||||
#[stdlib {
|
||||
name = "patternCircular2d",
|
||||
unlabeled_first = true,
|
||||
args = {
|
||||
sketch_set = { docs = "Which sketch(es) to pattern" },
|
||||
instances = { docs = "The number of total instances. Must be greater than or equal to 1. This includes the original entity. For example, if instances is 2, there will be two copies -- the original, and one new copy. If instances is 1, this has no effect."},
|
||||
center = { docs = "The center about which to make the pattern. This is a 2D vector.", snippet_value_array = ["0", "0"]},
|
||||
arc_degrees = { docs = "The arc angle (in degrees) to place the repetitions. Must be greater than 0. Defaults to 360."},
|
||||
rotate_duplicates= { docs = "Whether or not to rotate the duplicates as they are copied. Defaults to true."},
|
||||
use_original= { docs = "If the target was sketched on an extrusion, setting this will use the original sketch as the target, not the entire joined solid. Defaults to false."},
|
||||
},
|
||||
tags = ["sketch"]
|
||||
}]
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
async fn inner_pattern_circular_2d(
|
||||
sketch_set: Vec<Sketch>,
|
||||
|
@ -1,7 +1,6 @@
|
||||
//! Standard library shapes.
|
||||
|
||||
use anyhow::Result;
|
||||
use kcl_derive_docs::stdlib;
|
||||
use kcmc::{
|
||||
each_cmd as mcmd,
|
||||
length_unit::LengthUnit,
|
||||
@ -143,26 +142,6 @@ pub async fn circle_three_point(exec_state: &mut ExecState, args: Args) -> Resul
|
||||
})
|
||||
}
|
||||
|
||||
/// Construct a circle derived from 3 points.
|
||||
///
|
||||
/// ```no_run
|
||||
/// exampleSketch = startSketchOn(XY)
|
||||
/// |> circleThreePoint(p1 = [10,10], p2 = [20,8], p3 = [15,5])
|
||||
/// |> extrude(length = 5)
|
||||
/// ```
|
||||
#[stdlib {
|
||||
name = "circleThreePoint",
|
||||
unlabeled_first = true,
|
||||
args = {
|
||||
sketch_surface_or_group = {docs = "Plane or surface to sketch on."},
|
||||
p1 = {docs = "1st point to derive the circle."},
|
||||
p2 = {docs = "2nd point to derive the circle."},
|
||||
p3 = {docs = "3rd point to derive the circle."},
|
||||
tag = {docs = "Identifier for the circle to reference elsewhere."},
|
||||
},
|
||||
tags = ["sketch"]
|
||||
}]
|
||||
|
||||
// Similar to inner_circle, but needs to retain 3-point information in the
|
||||
// path so it can be used for other features, otherwise it's lost.
|
||||
async fn inner_circle_three_point(
|
||||
@ -281,44 +260,6 @@ pub async fn polygon(exec_state: &mut ExecState, args: Args) -> Result<KclValue,
|
||||
})
|
||||
}
|
||||
|
||||
/// Create a regular polygon with the specified number of sides that is either inscribed or circumscribed around a circle of the specified radius.
|
||||
///
|
||||
/// ```no_run
|
||||
/// // Create a regular hexagon inscribed in a circle of radius 10
|
||||
/// hex = startSketchOn(XY)
|
||||
/// |> polygon(
|
||||
/// radius = 10,
|
||||
/// numSides = 6,
|
||||
/// center = [0, 0],
|
||||
/// inscribed = true,
|
||||
/// )
|
||||
///
|
||||
/// example = extrude(hex, length = 5)
|
||||
/// ```
|
||||
///
|
||||
/// ```no_run
|
||||
/// // Create a square circumscribed around a circle of radius 5
|
||||
/// square = startSketchOn(XY)
|
||||
/// |> polygon(
|
||||
/// radius = 5.0,
|
||||
/// numSides = 4,
|
||||
/// center = [10, 10],
|
||||
/// inscribed = false,
|
||||
/// )
|
||||
/// example = extrude(square, length = 5)
|
||||
/// ```
|
||||
#[stdlib {
|
||||
name = "polygon",
|
||||
unlabeled_first = true,
|
||||
args = {
|
||||
sketch_surface_or_group = { docs = "Plane or surface to sketch on" },
|
||||
radius = { docs = "The radius of the polygon", include_in_snippet = true },
|
||||
num_sides = { docs = "The number of sides in the polygon", include_in_snippet = true },
|
||||
center = { docs = "The center point of the polygon", snippet_value_array = ["0", "0"] },
|
||||
inscribed = { docs = "Whether the polygon is inscribed (true, the default) or circumscribed (false) about a circle with the specified radius" },
|
||||
},
|
||||
tags = ["sketch"]
|
||||
}]
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
async fn inner_polygon(
|
||||
sketch_surface_or_group: SketchOrSurface,
|
||||
|
@ -1,7 +1,6 @@
|
||||
//! Standard library sweep.
|
||||
|
||||
use anyhow::Result;
|
||||
use kcl_derive_docs::stdlib;
|
||||
use kcmc::{each_cmd as mcmd, length_unit::LengthUnit, ModelingCmd};
|
||||
use kittycad_modeling_cmds::{self as kcmc, shared::RelativeTo};
|
||||
use schemars::JsonSchema;
|
||||
@ -56,122 +55,6 @@ pub async fn sweep(exec_state: &mut ExecState, args: Args) -> Result<KclValue, K
|
||||
Ok(value.into())
|
||||
}
|
||||
|
||||
/// Extrude a sketch along a path.
|
||||
///
|
||||
/// This, like extrude, is able to create a 3-dimensional solid from a
|
||||
/// 2-dimensional sketch. However, unlike extrude, this creates a solid
|
||||
/// by using the extent of the sketch as its path. This is useful for
|
||||
/// creating more complex shapes that can't be created with a simple
|
||||
/// extrusion.
|
||||
///
|
||||
/// You can provide more than one sketch to sweep, and they will all be
|
||||
/// swept along the same path.
|
||||
///
|
||||
/// ```no_run
|
||||
/// // Create a pipe using a sweep.
|
||||
///
|
||||
/// // Create a path for the sweep.
|
||||
/// sweepPath = startSketchOn(XZ)
|
||||
/// |> startProfile(at = [0.05, 0.05])
|
||||
/// |> line(end = [0, 7])
|
||||
/// |> tangentialArc(angle = 90, radius = 5)
|
||||
/// |> line(end = [-3, 0])
|
||||
/// |> tangentialArc(angle = -90, radius = 5)
|
||||
/// |> line(end = [0, 7])
|
||||
///
|
||||
/// // Create a hole for the pipe.
|
||||
/// pipeHole = startSketchOn(XY)
|
||||
/// |> circle(
|
||||
/// center = [0, 0],
|
||||
/// radius = 1.5,
|
||||
/// )
|
||||
///
|
||||
/// sweepSketch = startSketchOn(XY)
|
||||
/// |> circle(
|
||||
/// center = [0, 0],
|
||||
/// radius = 2,
|
||||
/// )
|
||||
/// |> subtract2d(tool = pipeHole)
|
||||
/// |> sweep(path = sweepPath)
|
||||
/// ```
|
||||
///
|
||||
/// ```no_run
|
||||
/// // Create a spring by sweeping around a helix path.
|
||||
///
|
||||
/// // Create a helix around the Z axis.
|
||||
/// helixPath = helix(
|
||||
/// angleStart = 0,
|
||||
/// ccw = true,
|
||||
/// revolutions = 4,
|
||||
/// length = 10,
|
||||
/// radius = 5,
|
||||
/// axis = Z,
|
||||
/// )
|
||||
///
|
||||
///
|
||||
/// // Create a spring by sweeping around the helix path.
|
||||
/// springSketch = startSketchOn(XZ)
|
||||
/// |> circle( center = [5, 0], radius = 1)
|
||||
/// |> sweep(path = helixPath)
|
||||
/// ```
|
||||
///
|
||||
/// ```no_run
|
||||
/// // Sweep two sketches along the same path.
|
||||
///
|
||||
/// sketch001 = startSketchOn(XY)
|
||||
/// rectangleSketch = startProfile(sketch001, at = [-200, 23.86])
|
||||
/// |> angledLine(angle = 0, length = 73.47, tag = $rectangleSegmentA001)
|
||||
/// |> angledLine(
|
||||
/// angle = segAng(rectangleSegmentA001) - 90,
|
||||
/// length = 50.61,
|
||||
/// )
|
||||
/// |> angledLine(
|
||||
/// angle = segAng(rectangleSegmentA001),
|
||||
/// length = -segLen(rectangleSegmentA001),
|
||||
/// )
|
||||
/// |> line(endAbsolute = [profileStartX(%), profileStartY(%)])
|
||||
/// |> close()
|
||||
///
|
||||
/// circleSketch = circle(sketch001, center = [200, -30.29], radius = 32.63)
|
||||
///
|
||||
/// sketch002 = startSketchOn(YZ)
|
||||
/// sweepPath = startProfile(sketch002, at = [0, 0])
|
||||
/// |> yLine(length = 231.81)
|
||||
/// |> tangentialArc(radius = 80, angle = -90)
|
||||
/// |> xLine(length = 384.93)
|
||||
///
|
||||
/// sweep([rectangleSketch, circleSketch], path = sweepPath)
|
||||
/// ```
|
||||
/// ```
|
||||
/// // Sectionally sweep one sketch along the path
|
||||
///
|
||||
/// sketch001 = startSketchOn(XY)
|
||||
/// circleSketch = circle(sketch001, center = [200, -30.29], radius = 32.63)
|
||||
///
|
||||
/// sketch002 = startSketchOn(YZ)
|
||||
/// sweepPath = startProfile(sketch002, at = [0, 0])
|
||||
/// |> yLine(length = 231.81)
|
||||
/// |> tangentialArc(radius = 80, angle = -90)
|
||||
/// |> xLine(length = 384.93)
|
||||
///
|
||||
/// sweep(circleSketch, path = sweepPath, sectional = true)
|
||||
/// ```
|
||||
|
||||
#[stdlib {
|
||||
name = "sweep",
|
||||
feature_tree_operation = true,
|
||||
unlabeled_first = true,
|
||||
args = {
|
||||
sketches = { docs = "The sketch or set of sketches that should be swept in space" },
|
||||
path = { docs = "The path to sweep the sketch along" },
|
||||
sectional = { docs = "If true, the sweep will be broken up into sub-sweeps (extrusions, revolves, sweeps) based on the trajectory path components." },
|
||||
tolerance = { docs = "Tolerance for this operation" },
|
||||
relative_to = { docs = "What is the sweep relative to? Can be either 'sketchPlane' or 'trajectoryCurve'. Defaults to trajectoryCurve."},
|
||||
tag_start = { docs = "A named tag for the face at the start of the sweep, i.e. the original sketch" },
|
||||
tag_end = { docs = "A named tag for the face at the end of the sweep" },
|
||||
},
|
||||
tags = ["sketch"]
|
||||
}]
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
async fn inner_sweep(
|
||||
sketches: Vec<Sketch>,
|
||||
|
Reference in New Issue
Block a user