Move transform functions to KCL (#7239)

Signed-off-by: Nick Cameron <nrc@ncameron.org>
This commit is contained in:
Nick Cameron
2025-05-29 07:15:04 +12:00
committed by GitHub
parent 21f4fcb041
commit 355a450c09
29 changed files with 840 additions and 33344 deletions

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -102,9 +102,9 @@ layout: manual
* [`union`](/docs/kcl-std/functions/std-solid-union)
* [**std::transform**](/docs/kcl-std/modules/std-transform)
* [`mirror2d`](/docs/kcl-std/functions/std-transform-mirror2d)
* [`rotate`](/docs/kcl-std/rotate)
* [`scale`](/docs/kcl-std/scale)
* [`translate`](/docs/kcl-std/translate)
* [`rotate`](/docs/kcl-std/functions/std-transform-rotate)
* [`scale`](/docs/kcl-std/functions/std-transform-scale)
* [`translate`](/docs/kcl-std/functions/std-transform-translate)
* [**std::units**](/docs/kcl-std/modules/std-units)
* [`units::toCentimeters`](/docs/kcl-std/functions/std-units-toCentimeters)
* [`units::toDegrees`](/docs/kcl-std/functions/std-units-toDegrees)

View File

@ -13,7 +13,7 @@ This module contains functions for transforming sketches and solids.
## Functions and constants
* [`mirror2d`](/docs/kcl-std/functions/std-transform-mirror2d)
* [`rotate`](/docs/kcl-std/rotate)
* [`scale`](/docs/kcl-std/scale)
* [`translate`](/docs/kcl-std/translate)
* [`rotate`](/docs/kcl-std/functions/std-transform-rotate)
* [`scale`](/docs/kcl-std/functions/std-transform-scale)
* [`translate`](/docs/kcl-std/functions/std-transform-translate)

File diff suppressed because it is too large Load Diff

View File

@ -161,6 +161,21 @@ pub const TEST_NAMES: &[&str] = &[
"std-transform-mirror2d-2",
"std-transform-mirror2d-3",
"std-transform-mirror2d-4",
"std-transform-translate-0",
"std-transform-translate-1",
"std-transform-translate-2",
"std-transform-translate-3",
"std-transform-translate-4",
"std-transform-rotate-0",
"std-transform-rotate-1",
"std-transform-rotate-2",
"std-transform-rotate-3",
"std-transform-rotate-4",
"std-transform-rotate-5",
"std-transform-rotate-6",
"std-transform-scale-0",
"std-transform-scale-1",
"std-transform-scale-2",
"std-units-toDegrees-0",
"std-units-toRadians-0",
];

View File

@ -744,12 +744,12 @@ impl ArgData {
} = &attr.inner
{
for p in props {
if p.key.name == "include_in_snippet" {
if p.key.name == "includeInSnippet" {
if let Some(b) = p.value.literal_bool() {
result.override_in_snippet = Some(b);
} else {
panic!(
"Invalid value for `include_in_snippet`, expected bool literal, found {:?}",
"Invalid value for `includeInSnippet`, expected bool literal, found {:?}",
p.value
);
}

View File

@ -1160,29 +1160,32 @@ mod tests {
#[test]
fn get_autocomplete_snippet_scale() {
let scale_fn: Box<dyn StdLibFn> = Box::new(crate::std::transform::Scale);
let snippet = scale_fn.to_autocomplete_snippet().unwrap();
assert_eq!(snippet, r#"scale(${0:%}, x = ${1:3.14}, y = ${2:3.14}, z = ${3:3.14})"#);
let data = kcl_doc::walk_prelude();
let DocData::Fn(data) = data.find_by_name("scale").unwrap() else {
panic!();
};
let snippet = data.to_autocomplete_snippet();
assert_eq!(snippet, r#"scale(x = ${0:10}, y = ${1:10}, z = ${2:10})"#);
}
#[test]
fn get_autocomplete_snippet_translate() {
let translate_fn: Box<dyn StdLibFn> = Box::new(crate::std::transform::Translate);
let snippet = translate_fn.to_autocomplete_snippet().unwrap();
assert_eq!(
snippet,
r#"translate(${0:%}, x = ${1:3.14}, y = ${2:3.14}, z = ${3:3.14})"#
);
let data = kcl_doc::walk_prelude();
let DocData::Fn(data) = data.find_by_name("translate").unwrap() else {
panic!();
};
let snippet = data.to_autocomplete_snippet();
assert_eq!(snippet, r#"translate(x = ${0:10}, y = ${1:10}, z = ${2:10})"#);
}
#[test]
fn get_autocomplete_snippet_rotate() {
let rotate_fn: Box<dyn StdLibFn> = Box::new(crate::std::transform::Rotate);
let snippet = rotate_fn.to_autocomplete_snippet().unwrap();
assert_eq!(
snippet,
r#"rotate(${0:%}, roll = ${1:3.14}, pitch = ${2:3.14}, yaw = ${3:3.14})"#
);
let data = kcl_doc::walk_prelude();
let DocData::Fn(data) = data.find_by_name("rotate").unwrap() else {
panic!();
};
let snippet = data.to_autocomplete_snippet();
assert_eq!(snippet, r#"rotate(roll = ${0:10}, pitch = ${1:10}, yaw = ${2:10})"#);
}
#[test]

View File

@ -84,10 +84,7 @@ lazy_static! {
Box::new(crate::std::sweep::Sweep),
Box::new(crate::std::loft::Loft),
Box::new(crate::std::assert::Assert),
Box::new(crate::std::assert::AssertIs),
Box::new(crate::std::transform::Scale),
Box::new(crate::std::transform::Translate),
Box::new(crate::std::transform::Rotate),
Box::new(crate::std::assert::AssertIs)
];
}
@ -228,6 +225,18 @@ pub(crate) fn std_fn(path: &str, fn_name: &str) -> (crate::std::StdFn, StdFnProp
|e, a| Box::pin(crate::std::mirror::mirror_2d(e, a)),
StdFnProps::default("std::transform::mirror2d"),
),
("transform", "translate") => (
|e, a| Box::pin(crate::std::transform::translate(e, a)),
StdFnProps::default("std::transform::translate"),
),
("transform", "rotate") => (
|e, a| Box::pin(crate::std::transform::rotate(e, a)),
StdFnProps::default("std::transform::rotate"),
),
("transform", "scale") => (
|e, a| Box::pin(crate::std::transform::scale(e, a)),
StdFnProps::default("std::transform::scale"),
),
("sketch", "revolve") => (
|e, a| Box::pin(crate::std::revolve::revolve(e, a)),
StdFnProps::default("std::sketch::revolve").include_in_feature_tree(),

View File

@ -1,7 +1,6 @@
//! Standard library transforms.
use anyhow::Result;
use kcl_derive_docs::stdlib;
use kcmc::{
each_cmd as mcmd,
length_unit::LengthUnit,
@ -57,106 +56,6 @@ pub async fn scale(exec_state: &mut ExecState, args: Args) -> Result<KclValue, K
Ok(objects.into())
}
/// Scale a solid or a sketch.
///
/// This is really useful for resizing parts. You can create a part and then scale it to the
/// correct size.
///
/// For sketches, you can use this to scale a sketch and then loft it with another sketch.
///
/// By default the transform is applied in local sketch axis, therefore the origin will not move.
///
/// If you want to apply the transform in global space, set `global` to `true`. The origin of the
/// model will move. If the model is not centered on origin and you scale globally it will
/// look like the model moves and gets bigger at the same time. Say you have a square
/// `(1,1) - (1,2) - (2,2) - (2,1)` and you scale by 2 globally it will become
/// `(2,2) - (2,4)`...etc so the origin has moved from `(1.5, 1.5)` to `(2,2)`.
///
/// ```no_run
/// // Scale a pipe.
///
/// // 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)
/// |> scale(
/// z = 2.5,
/// )
/// ```
///
/// ```no_run
/// // Scale an imported model.
///
/// import "tests/inputs/cube.sldprt" as cube
///
/// cube
/// |> scale(
/// y = 2.5,
/// )
/// ```
///
/// ```
/// // 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)
///
/// parts = sweep([rectangleSketch, circleSketch], path = sweepPath)
///
/// // Scale the sweep.
/// scale(parts, z = 0.5)
/// ```
#[stdlib {
name = "scale",
feature_tree_operation = false,
unlabeled_first = true,
args = {
objects = {docs = "The solid, sketch, or set of solids or sketches to scale."},
x = {docs = "The scale factor for the x axis. Default is 1 if not provided.", include_in_snippet = true},
y = {docs = "The scale factor for the y axis. Default is 1 if not provided.", include_in_snippet = true},
z = {docs = "The scale factor for the z axis. Default is 1 if not provided.", include_in_snippet = true},
global = {docs = "If true, the transform is applied in global space. The origin of the model will move. By default, the transform is applied in local sketch axis, therefore the origin will not move."}
},
tags = ["transform"]
}]
async fn inner_scale(
objects: SolidOrSketchOrImportedGeometry,
x: Option<f64>,
@ -230,163 +129,6 @@ pub async fn translate(exec_state: &mut ExecState, args: Args) -> Result<KclValu
Ok(objects.into())
}
/// Move a solid or a sketch.
///
/// This is really useful for assembling parts together. You can create a part
/// and then move it to the correct location.
///
/// Translate is really useful for sketches if you want to move a sketch
/// and then rotate it using the `rotate` function to create a loft.
///
/// ```no_run
/// // Move a pipe.
///
/// // 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)
/// |> translate(
/// x = 1.0,
/// y = 1.0,
/// z = 2.5,
/// )
/// ```
///
/// ```no_run
/// // Move an imported model.
///
/// import "tests/inputs/cube.sldprt" as cube
///
/// // Circle so you actually see the move.
/// startSketchOn(XY)
/// |> circle(
/// center = [-10, -10],
/// radius = 10,
/// )
/// |> extrude(
/// length = 10,
/// )
///
/// cube
/// |> translate(
/// x = 10.0,
/// y = 10.0,
/// z = 2.5,
/// )
/// ```
///
/// ```
/// // 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)
///
/// parts = sweep([rectangleSketch, circleSketch], path = sweepPath)
///
/// // Move the sweeps.
/// translate(parts, x = 1.0, y = 1.0, z = 2.5)
/// ```
///
/// ```no_run
/// // Move a sketch.
///
/// fn square(@length){
/// l = length / 2
/// p0 = [-l, -l]
/// p1 = [-l, l]
/// p2 = [l, l]
/// p3 = [l, -l]
///
/// return startSketchOn(XY)
/// |> startProfile(at = p0)
/// |> line(endAbsolute = p1)
/// |> line(endAbsolute = p2)
/// |> line(endAbsolute = p3)
/// |> close()
/// }
///
/// square(10)
/// |> translate(
/// x = 5,
/// y = 5,
/// )
/// |> extrude(
/// length = 10,
/// )
/// ```
///
/// ```no_run
/// // Translate and rotate a sketch to create a loft.
/// sketch001 = startSketchOn(XY)
///
/// fn square() {
/// return startProfile(sketch001, at = [-10, 10])
/// |> xLine(length = 20)
/// |> yLine(length = -20)
/// |> xLine(length = -20)
/// |> line(endAbsolute = [profileStartX(%), profileStartY(%)])
/// |> close()
/// }
///
/// profile001 = square()
///
/// profile002 = square()
/// |> translate(z = 20)
/// |> rotate(axis = [0, 0, 1.0], angle = 45)
///
/// loft([profile001, profile002])
/// ```
#[stdlib {
name = "translate",
feature_tree_operation = false,
unlabeled_first = true,
args = {
objects = {docs = "The solid, sketch, or set of solids or sketches to move."},
x = {docs = "The amount to move the solid or sketch along the x axis. Defaults to 0 if not provided.", include_in_snippet = true},
y = {docs = "The amount to move the solid or sketch along the y axis. Defaults to 0 if not provided.", include_in_snippet = true},
z = {docs = "The amount to move the solid or sketch along the z axis. Defaults to 0 if not provided.", include_in_snippet = true},
global = {docs = "If true, the transform is applied in global space. The origin of the model will move. By default, the transform is applied in local sketch axis, therefore the origin will not move."}
},
tags = ["transform"]
}]
async fn inner_translate(
objects: SolidOrSketchOrImportedGeometry,
x: Option<TyF64>,
@ -556,242 +298,6 @@ pub async fn rotate(exec_state: &mut ExecState, args: Args) -> Result<KclValue,
Ok(objects.into())
}
/// Rotate a solid or a sketch.
///
/// This is really useful for assembling parts together. You can create a part
/// and then rotate it to the correct orientation.
///
/// For sketches, you can use this to rotate a sketch and then loft it with another sketch.
///
/// ### Using Roll, Pitch, and Yaw
///
/// When rotating a part in 3D space, "roll," "pitch," and "yaw" refer to the
/// three rotational axes used to describe its orientation: roll is rotation
/// around the longitudinal axis (front-to-back), pitch is rotation around the
/// lateral axis (wing-to-wing), and yaw is rotation around the vertical axis
/// (up-down); essentially, it's like tilting the part on its side (roll),
/// tipping the nose up or down (pitch), and turning it left or right (yaw).
///
/// So, in the context of a 3D model:
///
/// - **Roll**: Imagine spinning a pencil on its tip - that's a roll movement.
///
/// - **Pitch**: Think of a seesaw motion, where the object tilts up or down along its side axis.
///
/// - **Yaw**: Like turning your head left or right, this is a rotation around the vertical axis
///
/// ### Using an Axis and Angle
///
/// When rotating a part around an axis, you specify the axis of rotation and the angle of
/// rotation.
///
/// ```no_run
/// // Rotate a pipe with roll, pitch, and yaw.
///
/// // 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)
/// |> rotate(
/// roll = 10,
/// pitch = 10,
/// yaw = 90,
/// )
/// ```
///
/// ```no_run
/// // Rotate a pipe with just roll.
///
/// // 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)
/// |> rotate(
/// roll = 10,
/// )
/// ```
///
/// ```no_run
/// // Rotate a pipe about a named axis with an angle.
///
/// // 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)
/// |> rotate(
/// axis = Z,
/// angle = 90,
/// )
/// ```
///
/// ```no_run
/// // Rotate an imported model.
///
/// import "tests/inputs/cube.sldprt" as cube
///
/// cube
/// |> rotate(
/// axis = [0, 0, 1.0],
/// angle = 9,
/// )
/// ```
///
/// ```no_run
/// // Rotate a pipe about a raw axis with an angle.
///
/// // 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)
/// |> rotate(
/// axis = [0, 0, 1.0],
/// angle = 90,
/// )
/// ```
///
/// ```
/// // 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)
///
/// parts = sweep([rectangleSketch, circleSketch], path = sweepPath)
///
/// // Rotate the sweeps.
/// rotate(parts, axis = [0, 0, 1.0], angle = 90)
/// ```
///
/// ```no_run
/// // Translate and rotate a sketch to create a loft.
/// sketch001 = startSketchOn(XY)
///
/// fn square() {
/// return startProfile(sketch001, at = [-10, 10])
/// |> xLine(length = 20)
/// |> yLine(length = -20)
/// |> xLine(length = -20)
/// |> line(endAbsolute = [profileStartX(%), profileStartY(%)])
/// |> close()
/// }
///
/// profile001 = square()
///
/// profile002 = square()
/// |> translate(x = 0, y = 0, z = 20)
/// |> rotate(axis = [0, 0, 1.0], angle = 45)
///
/// loft([profile001, profile002])
/// ```
#[stdlib {
name = "rotate",
feature_tree_operation = false,
unlabeled_first = true,
args = {
objects = {docs = "The solid, sketch, or set of solids or sketches to rotate."},
roll = {docs = "The roll angle in degrees. Must be between -360 and 360. Default is 0 if not given.", include_in_snippet = true},
pitch = {docs = "The pitch angle in degrees. Must be between -360 and 360. Default is 0 if not given.", include_in_snippet = true},
yaw = {docs = "The yaw angle in degrees. Must be between -360 and 360. Default is 0 if not given.", include_in_snippet = true},
axis = {docs = "The axis to rotate around. Must be used with `angle`.", include_in_snippet = false},
angle = {docs = "The angle to rotate in degrees. Must be used with `axis`. Must be between -360 and 360.", include_in_snippet = false},
global = {docs = "If true, the transform is applied in global space. The origin of the model will move. By default, the transform is applied in local sketch axis, therefore the origin will not move."}
},
tags = ["transform"]
}]
#[allow(clippy::too_many_arguments)]
async fn inner_rotate(
objects: SolidOrSketchOrImportedGeometry,

View File

@ -152,13 +152,13 @@ export fn helix(
/// Is the helix rotation counter clockwise? The default is `false`.
ccw?: bool,
/// Radius of the helix.
@(include_in_snippet = true)
@(includeInSnippet = true)
radius?: number(Length),
/// Axis to use for the helix.
@(include_in_snippet = true)
@(includeInSnippet = true)
axis?: Axis3d | Edge,
/// Length of the helix. This is not necessary if the helix is created around an edge. If not given the length of the edge is used.
@(include_in_snippet = true)
@(includeInSnippet = true)
length?: number(Length),
/// Cylinder to create the helix on.
cylinder?: Solid,

View File

@ -38,7 +38,7 @@ export fn circle(
/// The radius of the circle. Incompatible with `diameter`.
radius?: number(Length),
/// The diameter of the circle. Incompatible with `radius`.
@(include_in_snippet = true)
@(includeInSnippet = true)
diameter?: number(Length),
/// Create a new tag which refers to this circle.
tag?: tag,

View File

@ -3,6 +3,8 @@
@no_std
@settings(defaultLengthUnit = mm, kclVersion = 1.0)
import Axis3d from "std::types"
/// Mirror a sketch.
///
/// Mirror occurs around a local sketch axis rather than a global axis.
@ -90,3 +92,510 @@ export fn mirror2d(
/// The axis to reflect around.
axis: Axis2d | Edge,
): Sketch {}
/// Move a solid or a sketch.
///
/// This is really useful for assembling parts together. You can create a part
/// and then move it to the correct location.
///
/// Translate is really useful for sketches if you want to move a sketch
/// and then rotate it using the `rotate` function to create a loft.
///
/// ```kcl
/// // Move a pipe.
///
/// // 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)
/// |> translate(
/// x = 1.0,
/// y = 1.0,
/// z = 2.5,
/// )
/// ```
///
/// ```kcl
/// // Move an imported model.
///
/// import "tests/inputs/cube.sldprt" as cube
///
/// // Circle so you actually see the move.
/// startSketchOn(XY)
/// |> circle(
/// center = [-10, -10],
/// radius = 10,
/// )
/// |> extrude(
/// length = 10,
/// )
///
/// cube
/// |> translate(
/// x = 10.0,
/// y = 10.0,
/// z = 2.5,
/// )
/// ```
///
/// ```kcl
/// // 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)
///
/// parts = sweep([rectangleSketch, circleSketch], path = sweepPath)
///
/// // Move the sweeps.
/// translate(parts, x = 1.0, y = 1.0, z = 2.5)
/// ```
///
/// ```kcl
/// // Move a sketch.
///
/// fn square(@length){
/// l = length / 2
/// p0 = [-l, -l]
/// p1 = [-l, l]
/// p2 = [l, l]
/// p3 = [l, -l]
///
/// return startSketchOn(XY)
/// |> startProfile(at = p0)
/// |> line(endAbsolute = p1)
/// |> line(endAbsolute = p2)
/// |> line(endAbsolute = p3)
/// |> close()
/// }
///
/// square(10)
/// |> translate(
/// x = 5,
/// y = 5,
/// )
/// |> extrude(
/// length = 10,
/// )
/// ```
///
/// ```kcl
/// // Translate and rotate a sketch to create a loft.
/// sketch001 = startSketchOn(XY)
///
/// fn square() {
/// return startProfile(sketch001, at = [-10, 10])
/// |> xLine(length = 20)
/// |> yLine(length = -20)
/// |> xLine(length = -20)
/// |> line(endAbsolute = [profileStartX(%), profileStartY(%)])
/// |> close()
/// }
///
/// profile001 = square()
///
/// profile002 = square()
/// |> translate(z = 20)
/// |> rotate(axis = [0, 0, 1.0], angle = 45)
///
/// loft([profile001, profile002])
/// ```
@(impl = std_rust)
export fn translate(
/// The solid, sketch, or set of solids or sketches to move.
@objects: [Solid; 1+] | [Sketch; 1+] | ImportedGeometry,
/// The amount to move the solid or sketch along the x axis.
@(includeInSnippet = true)
x?: number(Length) = 0,
/// The amount to move the solid or sketch along the y axis.
@(includeInSnippet = true)
y?: number(Length) = 0,
/// The amount to move the solid or sketch along the z axis.
@(includeInSnippet = true)
z?: number(Length) = 0,
/// If true, the transform is applied in global space. The origin of the model will move. By default, the transform is applied in local sketch axis, therefore the origin will not move.
global?: bool = false,
): [Solid; 1+] | [Sketch; 1+] | ImportedGeometry {}
/// Rotate a solid or a sketch.
///
/// This is really useful for assembling parts together. You can create a part
/// and then rotate it to the correct orientation.
///
/// For sketches, you can use this to rotate a sketch and then loft it with another sketch.
///
/// ### Using Roll, Pitch, and Yaw
///
/// When rotating a part in 3D space, "roll," "pitch," and "yaw" refer to the
/// three rotational axes used to describe its orientation: roll is rotation
/// around the longitudinal axis (front-to-back), pitch is rotation around the
/// lateral axis (wing-to-wing), and yaw is rotation around the vertical axis
/// (up-down); essentially, it's like tilting the part on its side (roll),
/// tipping the nose up or down (pitch), and turning it left or right (yaw).
///
/// So, in the context of a 3D model:
///
/// - **Roll**: Imagine spinning a pencil on its tip - that's a roll movement.
///
/// - **Pitch**: Think of a seesaw motion, where the object tilts up or down along its side axis.
///
/// - **Yaw**: Like turning your head left or right, this is a rotation around the vertical axis
///
/// ### Using an Axis and Angle
///
/// When rotating a part around an axis, you specify the axis of rotation and the angle of
/// rotation.
///
/// ```kcl
/// // Rotate a pipe with roll, pitch, and yaw.
///
/// // 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)
/// |> rotate(
/// roll = 10,
/// pitch = 10,
/// yaw = 90,
/// )
/// ```
///
/// ```kcl
/// // Rotate a pipe with just roll.
///
/// // 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)
/// |> rotate(
/// roll = 10,
/// )
/// ```
///
/// ```kcl
/// // Rotate a pipe about a named axis with an angle.
///
/// // 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)
/// |> rotate(
/// axis = Z,
/// angle = 90,
/// )
/// ```
///
/// ```kcl
/// // Rotate an imported model.
///
/// import "tests/inputs/cube.sldprt" as cube
///
/// cube
/// |> rotate(
/// axis = [0, 0, 1.0],
/// angle = 9,
/// )
/// ```
///
/// ```kcl
/// // Rotate a pipe about a raw axis with an angle.
///
/// // 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)
/// |> rotate(
/// axis = [0, 0, 1.0],
/// angle = 90,
/// )
/// ```
///
/// ```kcl
/// // 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)
///
/// parts = sweep([rectangleSketch, circleSketch], path = sweepPath)
///
/// // Rotate the sweeps.
/// rotate(parts, axis = [0, 0, 1.0], angle = 90)
/// ```
///
/// ```kcl
/// // Translate and rotate a sketch to create a loft.
/// sketch001 = startSketchOn(XY)
///
/// fn square() {
/// return startProfile(sketch001, at = [-10, 10])
/// |> xLine(length = 20)
/// |> yLine(length = -20)
/// |> xLine(length = -20)
/// |> line(endAbsolute = [profileStartX(%), profileStartY(%)])
/// |> close()
/// }
///
/// profile001 = square()
///
/// profile002 = square()
/// |> translate(x = 0, y = 0, z = 20)
/// |> rotate(axis = [0, 0, 1.0], angle = 45)
///
/// loft([profile001, profile002])
/// ```
@(impl = std_rust)
export fn rotate(
/// The solid, sketch, or set of solids or sketches to rotate.
@objects: [Solid; 1+] | [Sketch; 1+] | ImportedGeometry,
/// The roll angle. Must be between -360deg and 360deg.
@(includeInSnippet = true)
roll?: number(Angle),
/// The pitch angle. Must be between -360deg and 360deg.
@(includeInSnippet = true)
pitch?: number(Angle),
/// The yaw angle. Must be between -360deg and 360deg.
@(includeInSnippet = true)
yaw?: number(Angle),
/// The axis to rotate around. Must be used with `angle`.
axis?: Axis3d | Point3d,
/// The angle to rotate. Must be used with `axis`. Must be between -360deg and 360deg.
angle?: number(Angle),
/// If true, the transform is applied in global space. The origin of the model will move. By default, the transform is applied in local sketch axis, therefore the origin will not move.
global?: bool = false,
): [Solid; 1+] | [Sketch; 1+] | ImportedGeometry {}
/// Scale a solid or a sketch.
///
/// This is really useful for resizing parts. You can create a part and then scale it to the
/// correct size.
///
/// For sketches, you can use this to scale a sketch and then loft it with another sketch.
///
/// By default the transform is applied in local sketch axis, therefore the origin will not move.
///
/// If you want to apply the transform in global space, set `global` to `true`. The origin of the
/// model will move. If the model is not centered on origin and you scale globally it will
/// look like the model moves and gets bigger at the same time. Say you have a square
/// `(1,1) - (1,2) - (2,2) - (2,1)` and you scale by 2 globally it will become
/// `(2,2) - (2,4)`...etc so the origin has moved from `(1.5, 1.5)` to `(2,2)`.
///
/// ```kcl
/// // Scale a pipe.
///
/// // 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)
/// |> scale(
/// z = 2.5,
/// )
/// ```
///
/// ```kcl
/// // Scale an imported model.
///
/// import "tests/inputs/cube.sldprt" as cube
///
/// cube
/// |> scale(
/// y = 2.5,
/// )
/// ```
///
/// ```kcl
/// // 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)
///
/// parts = sweep([rectangleSketch, circleSketch], path = sweepPath)
///
/// // Scale the sweep.
/// scale(parts, z = 0.5)
/// ```
@(impl = std_rust)
export fn scale(
/// The solid, sketch, or set of solids or sketches to scale.
@objects: [Solid; 1+] | [Sketch; 1+] | ImportedGeometry,
/// The scale factor for the x axis.
@(includeInSnippet = true)
x?: number(Count) = 1,
/// The scale factor for the y axis.
@(includeInSnippet = true)
y?: number(Count) = 1,
/// The scale factor for the z axis.
@(includeInSnippet = true)
z?: number(Count) = 1,
/// If true, the transform is applied in global space. The origin of the model will move. By default, the transform is applied in local sketch axis, therefore the origin will not move.
global?: bool = false,
): [Solid; 1+] | [Sketch; 1+] | ImportedGeometry {}

View File

Before

Width:  |  Height:  |  Size: 59 KiB

After

Width:  |  Height:  |  Size: 59 KiB

View File

Before

Width:  |  Height:  |  Size: 74 KiB

After

Width:  |  Height:  |  Size: 74 KiB

View File

Before

Width:  |  Height:  |  Size: 47 KiB

After

Width:  |  Height:  |  Size: 47 KiB

View File

Before

Width:  |  Height:  |  Size: 66 KiB

After

Width:  |  Height:  |  Size: 66 KiB

View File

Before

Width:  |  Height:  |  Size: 47 KiB

After

Width:  |  Height:  |  Size: 47 KiB

View File

Before

Width:  |  Height:  |  Size: 69 KiB

After

Width:  |  Height:  |  Size: 69 KiB

View File

Before

Width:  |  Height:  |  Size: 85 KiB

After

Width:  |  Height:  |  Size: 85 KiB

View File

Before

Width:  |  Height:  |  Size: 53 KiB

After

Width:  |  Height:  |  Size: 53 KiB

View File

Before

Width:  |  Height:  |  Size: 49 KiB

After

Width:  |  Height:  |  Size: 49 KiB

View File

Before

Width:  |  Height:  |  Size: 80 KiB

After

Width:  |  Height:  |  Size: 80 KiB