Merge branch 'main' into achalmers/restore-prompt-to-edit-tests
This commit is contained in:
		
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							@ -17,7 +17,7 @@ lastSegX(sketch: Sketch) -> number
 | 
			
		||||
 | 
			
		||||
| Name | Type | Description | Required |
 | 
			
		||||
|----------|------|-------------|----------|
 | 
			
		||||
| `sketch` | [`Sketch`](/docs/kcl/types/Sketch) | A sketch is a collection of paths. | Yes |
 | 
			
		||||
| `sketch` | [`Sketch`](/docs/kcl/types/Sketch) | The sketch whose line segment is being queried | Yes |
 | 
			
		||||
 | 
			
		||||
### Returns
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -17,7 +17,7 @@ lastSegY(sketch: Sketch) -> number
 | 
			
		||||
 | 
			
		||||
| Name | Type | Description | Required |
 | 
			
		||||
|----------|------|-------------|----------|
 | 
			
		||||
| `sketch` | [`Sketch`](/docs/kcl/types/Sketch) | A sketch is a collection of paths. | Yes |
 | 
			
		||||
| `sketch` | [`Sketch`](/docs/kcl/types/Sketch) | The sketch whose line segment is being queried | Yes |
 | 
			
		||||
 | 
			
		||||
### Returns
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							@ -17,7 +17,7 @@ segAng(tag: TagIdentifier) -> number
 | 
			
		||||
 | 
			
		||||
| Name | Type | Description | Required |
 | 
			
		||||
|----------|------|-------------|----------|
 | 
			
		||||
| `tag` | [`TagIdentifier`](/docs/kcl/types#tag-identifier) |  | Yes |
 | 
			
		||||
| `tag` | [`TagIdentifier`](/docs/kcl/types#tag-identifier) | The line segment being queried by its tag | Yes |
 | 
			
		||||
 | 
			
		||||
### Returns
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -17,7 +17,7 @@ segEnd(tag: TagIdentifier) -> [number]
 | 
			
		||||
 | 
			
		||||
| Name | Type | Description | Required |
 | 
			
		||||
|----------|------|-------------|----------|
 | 
			
		||||
| `tag` | [`TagIdentifier`](/docs/kcl/types#tag-identifier) |  | Yes |
 | 
			
		||||
| `tag` | [`TagIdentifier`](/docs/kcl/types#tag-identifier) | The line segment being queried by its tag | Yes |
 | 
			
		||||
 | 
			
		||||
### Returns
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -17,7 +17,7 @@ segEndX(tag: TagIdentifier) -> number
 | 
			
		||||
 | 
			
		||||
| Name | Type | Description | Required |
 | 
			
		||||
|----------|------|-------------|----------|
 | 
			
		||||
| `tag` | [`TagIdentifier`](/docs/kcl/types#tag-identifier) |  | Yes |
 | 
			
		||||
| `tag` | [`TagIdentifier`](/docs/kcl/types#tag-identifier) | The line segment being queried by its tag | Yes |
 | 
			
		||||
 | 
			
		||||
### Returns
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -17,7 +17,7 @@ segEndY(tag: TagIdentifier) -> number
 | 
			
		||||
 | 
			
		||||
| Name | Type | Description | Required |
 | 
			
		||||
|----------|------|-------------|----------|
 | 
			
		||||
| `tag` | [`TagIdentifier`](/docs/kcl/types#tag-identifier) |  | Yes |
 | 
			
		||||
| `tag` | [`TagIdentifier`](/docs/kcl/types#tag-identifier) | The line segment being queried by its tag | Yes |
 | 
			
		||||
 | 
			
		||||
### Returns
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -17,7 +17,7 @@ segLen(tag: TagIdentifier) -> number
 | 
			
		||||
 | 
			
		||||
| Name | Type | Description | Required |
 | 
			
		||||
|----------|------|-------------|----------|
 | 
			
		||||
| `tag` | [`TagIdentifier`](/docs/kcl/types#tag-identifier) |  | Yes |
 | 
			
		||||
| `tag` | [`TagIdentifier`](/docs/kcl/types#tag-identifier) | The line segment being queried by its tag | Yes |
 | 
			
		||||
 | 
			
		||||
### Returns
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -17,7 +17,7 @@ segStart(tag: TagIdentifier) -> [number]
 | 
			
		||||
 | 
			
		||||
| Name | Type | Description | Required |
 | 
			
		||||
|----------|------|-------------|----------|
 | 
			
		||||
| `tag` | [`TagIdentifier`](/docs/kcl/types#tag-identifier) |  | Yes |
 | 
			
		||||
| `tag` | [`TagIdentifier`](/docs/kcl/types#tag-identifier) | The line segment being queried by its tag | Yes |
 | 
			
		||||
 | 
			
		||||
### Returns
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -17,7 +17,7 @@ segStartX(tag: TagIdentifier) -> number
 | 
			
		||||
 | 
			
		||||
| Name | Type | Description | Required |
 | 
			
		||||
|----------|------|-------------|----------|
 | 
			
		||||
| `tag` | [`TagIdentifier`](/docs/kcl/types#tag-identifier) |  | Yes |
 | 
			
		||||
| `tag` | [`TagIdentifier`](/docs/kcl/types#tag-identifier) | The line segment being queried by its tag | Yes |
 | 
			
		||||
 | 
			
		||||
### Returns
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -17,7 +17,7 @@ segStartY(tag: TagIdentifier) -> number
 | 
			
		||||
 | 
			
		||||
| Name | Type | Description | Required |
 | 
			
		||||
|----------|------|-------------|----------|
 | 
			
		||||
| `tag` | [`TagIdentifier`](/docs/kcl/types#tag-identifier) |  | Yes |
 | 
			
		||||
| `tag` | [`TagIdentifier`](/docs/kcl/types#tag-identifier) | The line segment being queried by its tag | Yes |
 | 
			
		||||
 | 
			
		||||
### Returns
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										6023
									
								
								docs/kcl/std.json
									
									
									
									
									
								
							
							
						
						
									
										6023
									
								
								docs/kcl/std.json
									
									
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							@ -17,7 +17,7 @@ tangentToEnd(tag: TagIdentifier) -> number
 | 
			
		||||
 | 
			
		||||
| Name | Type | Description | Required |
 | 
			
		||||
|----------|------|-------------|----------|
 | 
			
		||||
| `tag` | [`TagIdentifier`](/docs/kcl/types#tag-identifier) |  | Yes |
 | 
			
		||||
| `tag` | [`TagIdentifier`](/docs/kcl/types#tag-identifier) | The line segment being queried by its tag | Yes |
 | 
			
		||||
 | 
			
		||||
### Returns
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -85,7 +85,7 @@
 | 
			
		||||
    "fmt": "prettier --write ./src *.ts *.json *.js ./e2e ./packages",
 | 
			
		||||
    "fmt-check": "prettier --check ./src *.ts *.json *.js ./e2e ./packages",
 | 
			
		||||
    "fetch:wasm": "./get-latest-wasm-bundle.sh",
 | 
			
		||||
    "fetch:samples": "echo \"Fetching latest KCL samples...\" && curl -o public/kcl-samples-manifest-fallback.json https://raw.githubusercontent.com/KittyCAD/kcl-samples/achalmers/kw-pattern/manifest.json",
 | 
			
		||||
    "fetch:samples": "echo \"Fetching latest KCL samples...\" && curl -o public/kcl-samples-manifest-fallback.json https://raw.githubusercontent.com/KittyCAD/kcl-samples/achalmers/kw-pattern-transform2/manifest.json",
 | 
			
		||||
    "isomorphic-copy-wasm": "(copy src/wasm-lib/pkg/wasm_lib_bg.wasm public || cp src/wasm-lib/pkg/wasm_lib_bg.wasm public)",
 | 
			
		||||
    "build:wasm-dev": "yarn wasm-prep && (cd src/wasm-lib && wasm-pack build --dev --target web --out-dir pkg && cargo test -p kcl-lib export_bindings) && yarn isomorphic-copy-wasm && yarn fmt",
 | 
			
		||||
    "build:wasm": "yarn wasm-prep && cd src/wasm-lib && wasm-pack build --release --target web --out-dir pkg && cargo test -p kcl-lib export_bindings && cd ../.. && yarn isomorphic-copy-wasm && yarn fmt",
 | 
			
		||||
 | 
			
		||||
@ -32,7 +32,7 @@ child_process.spawnSync('git', [
 | 
			
		||||
  'clone',
 | 
			
		||||
  '--single-branch',
 | 
			
		||||
  '--branch',
 | 
			
		||||
  'achalmers/kw-pattern',
 | 
			
		||||
  'achalmers/kw-pattern-transform2',
 | 
			
		||||
  URL_GIT_KCL_SAMPLES,
 | 
			
		||||
  DIR_KCL_SAMPLES,
 | 
			
		||||
])
 | 
			
		||||
 | 
			
		||||
@ -1235,7 +1235,7 @@ fn layer = () => {
 | 
			
		||||
const x = 5
 | 
			
		||||
 | 
			
		||||
// The 10 layers are replicas of each other, with a transform applied to each.
 | 
			
		||||
let shape = layer() |> patternTransform(10, transform, %)
 | 
			
		||||
let shape = layer() |> patternTransform(instances = 10, transform = transform)
 | 
			
		||||
"#;
 | 
			
		||||
 | 
			
		||||
        let result = parse_execute(ast).await;
 | 
			
		||||
 | 
			
		||||
@ -358,10 +358,6 @@ impl Args {
 | 
			
		||||
        Ok(numbers)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub(crate) fn get_pattern_transform_args(&self) -> Result<(u32, FnAsArg<'_>, SolidSet, Option<bool>), KclError> {
 | 
			
		||||
        FromArgs::from_args(self, 0)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub(crate) fn get_hypotenuse_leg(&self) -> Result<(f64, f64), KclError> {
 | 
			
		||||
        let numbers = self.get_number_array()?;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -27,9 +27,9 @@ pub async fn int(_exec_state: &mut ExecState, args: Args) -> Result<KclValue, Kc
 | 
			
		||||
/// startSketchOn('XZ')
 | 
			
		||||
///   |> circle({ center = [0, 0], radius = 2 }, %)
 | 
			
		||||
///   |> extrude(length = 5)
 | 
			
		||||
///   |> patternTransform(n, fn(id) {
 | 
			
		||||
///   |> patternTransform(instances = n, transform = fn(id) {
 | 
			
		||||
///   return { translate = [4 * id, 0, 0] }
 | 
			
		||||
/// }, %)
 | 
			
		||||
/// })
 | 
			
		||||
/// ```
 | 
			
		||||
#[stdlib {
 | 
			
		||||
    name = "int",
 | 
			
		||||
 | 
			
		||||
@ -16,7 +16,7 @@ use schemars::JsonSchema;
 | 
			
		||||
use serde::{Deserialize, Serialize};
 | 
			
		||||
use uuid::Uuid;
 | 
			
		||||
 | 
			
		||||
use super::args::Arg;
 | 
			
		||||
use super::{args::Arg, FnAsArg};
 | 
			
		||||
use crate::{
 | 
			
		||||
    errors::{KclError, KclErrorDetails},
 | 
			
		||||
    execution::{
 | 
			
		||||
@ -47,10 +47,14 @@ pub struct LinearPattern3dData {
 | 
			
		||||
 | 
			
		||||
/// Repeat some 3D solid, changing each repetition slightly.
 | 
			
		||||
pub async fn pattern_transform(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
 | 
			
		||||
    let (num_repetitions, transform, extr, use_original) = args.get_pattern_transform_args()?;
 | 
			
		||||
    let solid_set = args.get_unlabeled_kw_arg("solidSet")?;
 | 
			
		||||
    let instances: u32 = args.get_kw_arg("instances")?;
 | 
			
		||||
    let transform: FnAsArg<'_> = args.get_kw_arg("transform")?;
 | 
			
		||||
    let use_original: Option<bool> = args.get_kw_arg_opt("useOriginal")?;
 | 
			
		||||
 | 
			
		||||
    let solids = inner_pattern_transform(
 | 
			
		||||
        num_repetitions,
 | 
			
		||||
        solid_set,
 | 
			
		||||
        instances,
 | 
			
		||||
        FunctionParam {
 | 
			
		||||
            inner: transform.func,
 | 
			
		||||
            fn_expr: transform.expr,
 | 
			
		||||
@ -58,7 +62,6 @@ pub async fn pattern_transform(exec_state: &mut ExecState, args: Args) -> Result
 | 
			
		||||
            ctx: args.ctx.clone(),
 | 
			
		||||
            memory: transform.memory,
 | 
			
		||||
        },
 | 
			
		||||
        extr,
 | 
			
		||||
        use_original,
 | 
			
		||||
        exec_state,
 | 
			
		||||
        &args,
 | 
			
		||||
@ -69,11 +72,14 @@ pub async fn pattern_transform(exec_state: &mut ExecState, args: Args) -> Result
 | 
			
		||||
 | 
			
		||||
/// Repeat some 2D sketch, changing each repetition slightly.
 | 
			
		||||
pub async fn pattern_transform_2d(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
 | 
			
		||||
    let (num_repetitions, transform, sketch, use_original): (u32, super::FnAsArg<'_>, SketchSet, Option<bool>) =
 | 
			
		||||
        super::args::FromArgs::from_args(&args, 0)?;
 | 
			
		||||
    let sketch_set = args.get_unlabeled_kw_arg("sketchSet")?;
 | 
			
		||||
    let instances: u32 = args.get_kw_arg("instances")?;
 | 
			
		||||
    let transform: FnAsArg<'_> = args.get_kw_arg("transform")?;
 | 
			
		||||
    let use_original: Option<bool> = args.get_kw_arg_opt("useOriginal")?;
 | 
			
		||||
 | 
			
		||||
    let sketches = inner_pattern_transform_2d(
 | 
			
		||||
        num_repetitions,
 | 
			
		||||
        sketch_set,
 | 
			
		||||
        instances,
 | 
			
		||||
        FunctionParam {
 | 
			
		||||
            inner: transform.func,
 | 
			
		||||
            fn_expr: transform.expr,
 | 
			
		||||
@ -81,7 +87,6 @@ pub async fn pattern_transform_2d(exec_state: &mut ExecState, args: Args) -> Res
 | 
			
		||||
            ctx: args.ctx.clone(),
 | 
			
		||||
            memory: transform.memory,
 | 
			
		||||
        },
 | 
			
		||||
        sketch,
 | 
			
		||||
        use_original,
 | 
			
		||||
        exec_state,
 | 
			
		||||
        &args,
 | 
			
		||||
@ -96,7 +101,7 @@ pub async fn pattern_transform_2d(exec_state: &mut ExecState, args: Args) -> Res
 | 
			
		||||
/// Transformation function could alter rotation, scale, visibility, position, etc.
 | 
			
		||||
///
 | 
			
		||||
/// The `patternTransform` call itself takes a number for how many total instances of
 | 
			
		||||
/// the shape should be. For example, if you use a circle with `patternTransform(4, transform)`
 | 
			
		||||
/// the shape should be. For example, if you use a circle with `patternTransform(instances = 4, transform = f)`
 | 
			
		||||
/// then there will be 4 circles: the original, and 3 created by replicating the original and
 | 
			
		||||
/// calling the transform function on each.
 | 
			
		||||
///
 | 
			
		||||
@ -140,7 +145,7 @@ pub async fn pattern_transform_2d(exec_state: &mut ExecState, args: Args) -> Res
 | 
			
		||||
/// sketch001 = startSketchOn('XZ')
 | 
			
		||||
///   |> circle({ center = [0, 0], radius = 2 }, %)
 | 
			
		||||
///   |> extrude(length = 5)
 | 
			
		||||
///   |> patternTransform(4, transform, %)
 | 
			
		||||
///   |> patternTransform(instances = 4, transform = transform)
 | 
			
		||||
/// ```
 | 
			
		||||
/// ```no_run
 | 
			
		||||
/// // Each instance will be shifted along the X axis,
 | 
			
		||||
@ -153,7 +158,7 @@ pub async fn pattern_transform_2d(exec_state: &mut ExecState, args: Args) -> Res
 | 
			
		||||
/// sketch001 = startSketchOn('XZ')
 | 
			
		||||
///   |> circle({ center = [0, 0], radius = 2 }, %)
 | 
			
		||||
///   |> extrude(length = 5)
 | 
			
		||||
///   |> patternTransform(4, transform, %)
 | 
			
		||||
///   |> patternTransform(instances = 4, transform = transform)
 | 
			
		||||
/// ```
 | 
			
		||||
/// ```no_run
 | 
			
		||||
/// fn cube(length, center) {
 | 
			
		||||
@ -192,7 +197,7 @@ pub async fn pattern_transform_2d(exec_state: &mut ExecState, args: Args) -> Res
 | 
			
		||||
///
 | 
			
		||||
/// myCubes =
 | 
			
		||||
///   cube(width, [100,0])
 | 
			
		||||
///   |> patternTransform(25, transform, %)
 | 
			
		||||
///   |> patternTransform(instances = 25, transform = transform)
 | 
			
		||||
/// ```
 | 
			
		||||
///
 | 
			
		||||
/// ```no_run
 | 
			
		||||
@ -228,7 +233,7 @@ pub async fn pattern_transform_2d(exec_state: &mut ExecState, args: Args) -> Res
 | 
			
		||||
/// }
 | 
			
		||||
/// myCubes =
 | 
			
		||||
///   cube(width, [100,100])
 | 
			
		||||
///   |> patternTransform(4, transform, %)
 | 
			
		||||
///   |> patternTransform(instances = 4, transform = transform)
 | 
			
		||||
/// ```
 | 
			
		||||
/// ```no_run
 | 
			
		||||
/// // Parameters
 | 
			
		||||
@ -252,7 +257,7 @@ pub async fn pattern_transform_2d(exec_state: &mut ExecState, args: Args) -> Res
 | 
			
		||||
/// }
 | 
			
		||||
/// // The vase is 100 layers tall.
 | 
			
		||||
/// // The 100 layers are replica of each other, with a slight transformation applied to each.
 | 
			
		||||
/// vase = layer() |> patternTransform(100, transform, %)
 | 
			
		||||
/// vase = layer() |> patternTransform(instances = 100, transform = transform)
 | 
			
		||||
/// ```
 | 
			
		||||
/// ```
 | 
			
		||||
/// fn transform(i) {
 | 
			
		||||
@ -271,33 +276,48 @@ pub async fn pattern_transform_2d(exec_state: &mut ExecState, args: Args) -> Res
 | 
			
		||||
///        inscribed: false
 | 
			
		||||
///      }, %)
 | 
			
		||||
///   |> extrude(length = 4)
 | 
			
		||||
///   |> patternTransform(3, transform, %)
 | 
			
		||||
///   |> patternTransform(instances = 3, transform = transform)
 | 
			
		||||
/// ```
 | 
			
		||||
#[stdlib {
 | 
			
		||||
    name = "patternTransform",
 | 
			
		||||
    feature_tree_operation = true,
 | 
			
		||||
    keywords = true,
 | 
			
		||||
    unlabeled_first = true,
 | 
			
		||||
    args = {
 | 
			
		||||
        solid_set = { docs = "The solid(s) 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." },
 | 
			
		||||
        transform = { docs = "How each replica should be transformed. The transform function takes a single parameter: an integer representing which number replication the transform is for. E.g. the first replica to be transformed will be passed the argument `1`. This simplifies your math: the transform function can rely on id `0` being the original instance passed into the `patternTransform`. See the examples." },
 | 
			
		||||
        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_transform<'a>(
 | 
			
		||||
    total_instances: u32,
 | 
			
		||||
    transform_function: FunctionParam<'a>,
 | 
			
		||||
    solid_set: SolidSet,
 | 
			
		||||
    instances: u32,
 | 
			
		||||
    transform: FunctionParam<'a>,
 | 
			
		||||
    use_original: Option<bool>,
 | 
			
		||||
    exec_state: &mut ExecState,
 | 
			
		||||
    args: &'a Args,
 | 
			
		||||
) -> Result<Vec<Box<Solid>>, KclError> {
 | 
			
		||||
    // Build the vec of transforms, one for each repetition.
 | 
			
		||||
    let mut transform = Vec::with_capacity(usize::try_from(total_instances).unwrap());
 | 
			
		||||
    if total_instances < 1 {
 | 
			
		||||
    let mut transform_vec = Vec::with_capacity(usize::try_from(instances).unwrap());
 | 
			
		||||
    if instances < 1 {
 | 
			
		||||
        return Err(KclError::Semantic(KclErrorDetails {
 | 
			
		||||
            source_ranges: vec![args.source_range],
 | 
			
		||||
            message: MUST_HAVE_ONE_INSTANCE.to_owned(),
 | 
			
		||||
        }));
 | 
			
		||||
    }
 | 
			
		||||
    for i in 1..total_instances {
 | 
			
		||||
        let t = make_transform::<Box<Solid>>(i, &transform_function, args.source_range, exec_state).await?;
 | 
			
		||||
        transform.push(t);
 | 
			
		||||
    for i in 1..instances {
 | 
			
		||||
        let t = make_transform::<Box<Solid>>(i, &transform, args.source_range, exec_state).await?;
 | 
			
		||||
        transform_vec.push(t);
 | 
			
		||||
    }
 | 
			
		||||
    execute_pattern_transform(transform, solid_set, use_original.unwrap_or_default(), exec_state, args).await
 | 
			
		||||
    execute_pattern_transform(
 | 
			
		||||
        transform_vec,
 | 
			
		||||
        solid_set,
 | 
			
		||||
        use_original.unwrap_or_default(),
 | 
			
		||||
        exec_state,
 | 
			
		||||
        args,
 | 
			
		||||
    )
 | 
			
		||||
    .await
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Just like patternTransform, but works on 2D sketches not 3D solids.
 | 
			
		||||
@ -310,32 +330,47 @@ async fn inner_pattern_transform<'a>(
 | 
			
		||||
/// // Sketch 4 circles.
 | 
			
		||||
/// sketch001 = startSketchOn('XZ')
 | 
			
		||||
///   |> circle({ center: [0, 0], radius: 2 }, %)
 | 
			
		||||
///   |> patternTransform2d(4, transform, %)
 | 
			
		||||
///   |> patternTransform2d(instances = 4, transform = transform)
 | 
			
		||||
/// ```
 | 
			
		||||
#[stdlib {
 | 
			
		||||
    name = "patternTransform2d",
 | 
			
		||||
    keywords = true,
 | 
			
		||||
    unlabeled_first = true,
 | 
			
		||||
    args = {
 | 
			
		||||
        sketch_set = { 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." },
 | 
			
		||||
        transform = { docs = "How each replica should be transformed. The transform function takes a single parameter: an integer representing which number replication the transform is for. E.g. the first replica to be transformed will be passed the argument `1`. This simplifies your math: the transform function can rely on id `0` being the original instance passed into the `patternTransform`. See the examples." },
 | 
			
		||||
        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_transform_2d<'a>(
 | 
			
		||||
    total_instances: u32,
 | 
			
		||||
    transform_function: FunctionParam<'a>,
 | 
			
		||||
    solid_set: SketchSet,
 | 
			
		||||
    sketch_set: SketchSet,
 | 
			
		||||
    instances: u32,
 | 
			
		||||
    transform: FunctionParam<'a>,
 | 
			
		||||
    use_original: Option<bool>,
 | 
			
		||||
    exec_state: &mut ExecState,
 | 
			
		||||
    args: &'a Args,
 | 
			
		||||
) -> Result<Vec<Box<Sketch>>, KclError> {
 | 
			
		||||
    // Build the vec of transforms, one for each repetition.
 | 
			
		||||
    let mut transform = Vec::with_capacity(usize::try_from(total_instances).unwrap());
 | 
			
		||||
    if total_instances < 1 {
 | 
			
		||||
    let mut transform_vec = Vec::with_capacity(usize::try_from(instances).unwrap());
 | 
			
		||||
    if instances < 1 {
 | 
			
		||||
        return Err(KclError::Semantic(KclErrorDetails {
 | 
			
		||||
            source_ranges: vec![args.source_range],
 | 
			
		||||
            message: MUST_HAVE_ONE_INSTANCE.to_owned(),
 | 
			
		||||
        }));
 | 
			
		||||
    }
 | 
			
		||||
    for i in 1..total_instances {
 | 
			
		||||
        let t = make_transform::<Box<Sketch>>(i, &transform_function, args.source_range, exec_state).await?;
 | 
			
		||||
        transform.push(t);
 | 
			
		||||
    for i in 1..instances {
 | 
			
		||||
        let t = make_transform::<Box<Sketch>>(i, &transform, args.source_range, exec_state).await?;
 | 
			
		||||
        transform_vec.push(t);
 | 
			
		||||
    }
 | 
			
		||||
    execute_pattern_transform(transform, solid_set, use_original.unwrap_or_default(), exec_state, args).await
 | 
			
		||||
    execute_pattern_transform(
 | 
			
		||||
        transform_vec,
 | 
			
		||||
        sketch_set,
 | 
			
		||||
        use_original.unwrap_or_default(),
 | 
			
		||||
        exec_state,
 | 
			
		||||
        args,
 | 
			
		||||
    )
 | 
			
		||||
    .await
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
async fn execute_pattern_transform<T: GeometryTrait>(
 | 
			
		||||
@ -406,7 +441,7 @@ async fn send_pattern_transform<T: GeometryTrait>(
 | 
			
		||||
 | 
			
		||||
async fn make_transform<T: GeometryTrait>(
 | 
			
		||||
    i: u32,
 | 
			
		||||
    transform_function: &FunctionParam<'_>,
 | 
			
		||||
    transform: &FunctionParam<'_>,
 | 
			
		||||
    source_range: SourceRange,
 | 
			
		||||
    exec_state: &mut ExecState,
 | 
			
		||||
) -> Result<Vec<Transform>, KclError> {
 | 
			
		||||
@ -416,7 +451,7 @@ async fn make_transform<T: GeometryTrait>(
 | 
			
		||||
        meta: vec![source_range.into()],
 | 
			
		||||
    };
 | 
			
		||||
    let transform_fn_args = vec![Arg::synthetic(repetition_num)];
 | 
			
		||||
    let transform_fn_return = transform_function.call(exec_state, transform_fn_args).await?;
 | 
			
		||||
    let transform_fn_return = transform.call(exec_state, transform_fn_args).await?;
 | 
			
		||||
 | 
			
		||||
    // Unpack the returned transform object.
 | 
			
		||||
    let source_ranges = vec![source_range];
 | 
			
		||||
 | 
			
		||||
@ -12,7 +12,7 @@ use crate::{
 | 
			
		||||
 | 
			
		||||
/// Returns the point at the end of the given segment.
 | 
			
		||||
pub async fn segment_end(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
 | 
			
		||||
    let tag: TagIdentifier = args.get_data()?;
 | 
			
		||||
    let tag: TagIdentifier = args.get_unlabeled_kw_arg("tag")?;
 | 
			
		||||
    let result = inner_segment_end(&tag, exec_state, args.clone())?;
 | 
			
		||||
 | 
			
		||||
    args.make_user_val_from_point(result)
 | 
			
		||||
@ -45,6 +45,11 @@ pub async fn segment_end(exec_state: &mut ExecState, args: Args) -> Result<KclVa
 | 
			
		||||
/// ```
 | 
			
		||||
#[stdlib {
 | 
			
		||||
    name = "segEnd",
 | 
			
		||||
    keywords = true,
 | 
			
		||||
    unlabeled_first = true,
 | 
			
		||||
    args = {
 | 
			
		||||
        tag = { docs = "The line segment being queried by its tag"},
 | 
			
		||||
    }
 | 
			
		||||
}]
 | 
			
		||||
fn inner_segment_end(tag: &TagIdentifier, exec_state: &mut ExecState, args: Args) -> Result<[f64; 2], KclError> {
 | 
			
		||||
    let line = args.get_tag_engine_info(exec_state, tag)?;
 | 
			
		||||
@ -60,7 +65,7 @@ fn inner_segment_end(tag: &TagIdentifier, exec_state: &mut ExecState, args: Args
 | 
			
		||||
 | 
			
		||||
/// Returns the segment end of x.
 | 
			
		||||
pub async fn segment_end_x(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
 | 
			
		||||
    let tag: TagIdentifier = args.get_data()?;
 | 
			
		||||
    let tag: TagIdentifier = args.get_unlabeled_kw_arg("tag")?;
 | 
			
		||||
    let result = inner_segment_end_x(&tag, exec_state, args.clone())?;
 | 
			
		||||
 | 
			
		||||
    Ok(args.make_user_val_from_f64(result))
 | 
			
		||||
@ -81,6 +86,11 @@ pub async fn segment_end_x(exec_state: &mut ExecState, args: Args) -> Result<Kcl
 | 
			
		||||
/// ```
 | 
			
		||||
#[stdlib {
 | 
			
		||||
    name = "segEndX",
 | 
			
		||||
    keywords = true,
 | 
			
		||||
    unlabeled_first = true,
 | 
			
		||||
    args = {
 | 
			
		||||
        tag = { docs = "The line segment being queried by its tag"},
 | 
			
		||||
    }
 | 
			
		||||
}]
 | 
			
		||||
fn inner_segment_end_x(tag: &TagIdentifier, exec_state: &mut ExecState, args: Args) -> Result<f64, KclError> {
 | 
			
		||||
    let line = args.get_tag_engine_info(exec_state, tag)?;
 | 
			
		||||
@ -96,7 +106,7 @@ fn inner_segment_end_x(tag: &TagIdentifier, exec_state: &mut ExecState, args: Ar
 | 
			
		||||
 | 
			
		||||
/// Returns the segment end of y.
 | 
			
		||||
pub async fn segment_end_y(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
 | 
			
		||||
    let tag: TagIdentifier = args.get_data()?;
 | 
			
		||||
    let tag: TagIdentifier = args.get_unlabeled_kw_arg("tag")?;
 | 
			
		||||
    let result = inner_segment_end_y(&tag, exec_state, args.clone())?;
 | 
			
		||||
 | 
			
		||||
    Ok(args.make_user_val_from_f64(result))
 | 
			
		||||
@ -118,6 +128,11 @@ pub async fn segment_end_y(exec_state: &mut ExecState, args: Args) -> Result<Kcl
 | 
			
		||||
/// ```
 | 
			
		||||
#[stdlib {
 | 
			
		||||
    name = "segEndY",
 | 
			
		||||
    keywords = true,
 | 
			
		||||
    unlabeled_first = true,
 | 
			
		||||
    args = {
 | 
			
		||||
        tag = { docs = "The line segment being queried by its tag"},
 | 
			
		||||
    }
 | 
			
		||||
}]
 | 
			
		||||
fn inner_segment_end_y(tag: &TagIdentifier, exec_state: &mut ExecState, args: Args) -> Result<f64, KclError> {
 | 
			
		||||
    let line = args.get_tag_engine_info(exec_state, tag)?;
 | 
			
		||||
@ -133,7 +148,7 @@ fn inner_segment_end_y(tag: &TagIdentifier, exec_state: &mut ExecState, args: Ar
 | 
			
		||||
 | 
			
		||||
/// Returns the point at the start of the given segment.
 | 
			
		||||
pub async fn segment_start(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
 | 
			
		||||
    let tag: TagIdentifier = args.get_data()?;
 | 
			
		||||
    let tag: TagIdentifier = args.get_unlabeled_kw_arg("tag")?;
 | 
			
		||||
    let result = inner_segment_start(&tag, exec_state, args.clone())?;
 | 
			
		||||
 | 
			
		||||
    args.make_user_val_from_point(result)
 | 
			
		||||
@ -166,6 +181,11 @@ pub async fn segment_start(exec_state: &mut ExecState, args: Args) -> Result<Kcl
 | 
			
		||||
/// ```
 | 
			
		||||
#[stdlib {
 | 
			
		||||
    name = "segStart",
 | 
			
		||||
    keywords = true,
 | 
			
		||||
    unlabeled_first = true,
 | 
			
		||||
    args = {
 | 
			
		||||
        tag = { docs = "The line segment being queried by its tag"},
 | 
			
		||||
    }
 | 
			
		||||
}]
 | 
			
		||||
fn inner_segment_start(tag: &TagIdentifier, exec_state: &mut ExecState, args: Args) -> Result<[f64; 2], KclError> {
 | 
			
		||||
    let line = args.get_tag_engine_info(exec_state, tag)?;
 | 
			
		||||
@ -181,7 +201,7 @@ fn inner_segment_start(tag: &TagIdentifier, exec_state: &mut ExecState, args: Ar
 | 
			
		||||
 | 
			
		||||
/// Returns the segment start of x.
 | 
			
		||||
pub async fn segment_start_x(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
 | 
			
		||||
    let tag: TagIdentifier = args.get_data()?;
 | 
			
		||||
    let tag: TagIdentifier = args.get_unlabeled_kw_arg("tag")?;
 | 
			
		||||
    let result = inner_segment_start_x(&tag, exec_state, args.clone())?;
 | 
			
		||||
 | 
			
		||||
    Ok(args.make_user_val_from_f64(result))
 | 
			
		||||
@ -202,6 +222,11 @@ pub async fn segment_start_x(exec_state: &mut ExecState, args: Args) -> Result<K
 | 
			
		||||
/// ```
 | 
			
		||||
#[stdlib {
 | 
			
		||||
    name = "segStartX",
 | 
			
		||||
    keywords = true,
 | 
			
		||||
    unlabeled_first = true,
 | 
			
		||||
    args = {
 | 
			
		||||
        tag = { docs = "The line segment being queried by its tag"},
 | 
			
		||||
    }
 | 
			
		||||
}]
 | 
			
		||||
fn inner_segment_start_x(tag: &TagIdentifier, exec_state: &mut ExecState, args: Args) -> Result<f64, KclError> {
 | 
			
		||||
    let line = args.get_tag_engine_info(exec_state, tag)?;
 | 
			
		||||
@ -217,7 +242,7 @@ fn inner_segment_start_x(tag: &TagIdentifier, exec_state: &mut ExecState, args:
 | 
			
		||||
 | 
			
		||||
/// Returns the segment start of y.
 | 
			
		||||
pub async fn segment_start_y(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
 | 
			
		||||
    let tag: TagIdentifier = args.get_data()?;
 | 
			
		||||
    let tag: TagIdentifier = args.get_unlabeled_kw_arg("tag")?;
 | 
			
		||||
    let result = inner_segment_start_y(&tag, exec_state, args.clone())?;
 | 
			
		||||
 | 
			
		||||
    Ok(args.make_user_val_from_f64(result))
 | 
			
		||||
@ -239,6 +264,11 @@ pub async fn segment_start_y(exec_state: &mut ExecState, args: Args) -> Result<K
 | 
			
		||||
/// ```
 | 
			
		||||
#[stdlib {
 | 
			
		||||
    name = "segStartY",
 | 
			
		||||
    keywords = true,
 | 
			
		||||
    unlabeled_first = true,
 | 
			
		||||
    args = {
 | 
			
		||||
        tag = { docs = "The line segment being queried by its tag"},
 | 
			
		||||
    }
 | 
			
		||||
}]
 | 
			
		||||
fn inner_segment_start_y(tag: &TagIdentifier, exec_state: &mut ExecState, args: Args) -> Result<f64, KclError> {
 | 
			
		||||
    let line = args.get_tag_engine_info(exec_state, tag)?;
 | 
			
		||||
@ -253,7 +283,7 @@ fn inner_segment_start_y(tag: &TagIdentifier, exec_state: &mut ExecState, args:
 | 
			
		||||
}
 | 
			
		||||
/// Returns the last segment of x.
 | 
			
		||||
pub async fn last_segment_x(_exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
 | 
			
		||||
    let sketch = args.get_sketch()?;
 | 
			
		||||
    let sketch = args.get_unlabeled_kw_arg("sketch")?;
 | 
			
		||||
    let result = inner_last_segment_x(sketch, args.clone())?;
 | 
			
		||||
 | 
			
		||||
    Ok(args.make_user_val_from_f64(result))
 | 
			
		||||
@ -275,6 +305,11 @@ pub async fn last_segment_x(_exec_state: &mut ExecState, args: Args) -> Result<K
 | 
			
		||||
/// ```
 | 
			
		||||
#[stdlib {
 | 
			
		||||
    name = "lastSegX",
 | 
			
		||||
    keywords = true,
 | 
			
		||||
    unlabeled_first = true,
 | 
			
		||||
    args = {
 | 
			
		||||
        sketch = { docs = "The sketch whose line segment is being queried"},
 | 
			
		||||
    }
 | 
			
		||||
}]
 | 
			
		||||
fn inner_last_segment_x(sketch: Sketch, args: Args) -> Result<f64, KclError> {
 | 
			
		||||
    let last_line = sketch
 | 
			
		||||
@ -293,7 +328,7 @@ fn inner_last_segment_x(sketch: Sketch, args: Args) -> Result<f64, KclError> {
 | 
			
		||||
 | 
			
		||||
/// Returns the last segment of y.
 | 
			
		||||
pub async fn last_segment_y(_exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
 | 
			
		||||
    let sketch = args.get_sketch()?;
 | 
			
		||||
    let sketch = args.get_unlabeled_kw_arg("sketch")?;
 | 
			
		||||
    let result = inner_last_segment_y(sketch, args.clone())?;
 | 
			
		||||
 | 
			
		||||
    Ok(args.make_user_val_from_f64(result))
 | 
			
		||||
@ -315,6 +350,11 @@ pub async fn last_segment_y(_exec_state: &mut ExecState, args: Args) -> Result<K
 | 
			
		||||
/// ```
 | 
			
		||||
#[stdlib {
 | 
			
		||||
    name = "lastSegY",
 | 
			
		||||
    keywords = true,
 | 
			
		||||
    unlabeled_first = true,
 | 
			
		||||
    args = {
 | 
			
		||||
        sketch = { docs = "The sketch whose line segment is being queried"},
 | 
			
		||||
    }
 | 
			
		||||
}]
 | 
			
		||||
fn inner_last_segment_y(sketch: Sketch, args: Args) -> Result<f64, KclError> {
 | 
			
		||||
    let last_line = sketch
 | 
			
		||||
@ -333,7 +373,7 @@ fn inner_last_segment_y(sketch: Sketch, args: Args) -> Result<f64, KclError> {
 | 
			
		||||
 | 
			
		||||
/// Returns the length of the segment.
 | 
			
		||||
pub async fn segment_length(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
 | 
			
		||||
    let tag: TagIdentifier = args.get_data()?;
 | 
			
		||||
    let tag: TagIdentifier = args.get_unlabeled_kw_arg("tag")?;
 | 
			
		||||
    let result = inner_segment_length(&tag, exec_state, args.clone())?;
 | 
			
		||||
    Ok(args.make_user_val_from_f64(result))
 | 
			
		||||
}
 | 
			
		||||
@ -361,6 +401,11 @@ pub async fn segment_length(exec_state: &mut ExecState, args: Args) -> Result<Kc
 | 
			
		||||
/// ```
 | 
			
		||||
#[stdlib {
 | 
			
		||||
    name = "segLen",
 | 
			
		||||
    keywords = true,
 | 
			
		||||
    unlabeled_first = true,
 | 
			
		||||
    args = {
 | 
			
		||||
        tag = { docs = "The line segment being queried by its tag"},
 | 
			
		||||
    }
 | 
			
		||||
}]
 | 
			
		||||
fn inner_segment_length(tag: &TagIdentifier, exec_state: &mut ExecState, args: Args) -> Result<f64, KclError> {
 | 
			
		||||
    let line = args.get_tag_engine_info(exec_state, tag)?;
 | 
			
		||||
@ -378,7 +423,7 @@ fn inner_segment_length(tag: &TagIdentifier, exec_state: &mut ExecState, args: A
 | 
			
		||||
 | 
			
		||||
/// Returns the angle of the segment.
 | 
			
		||||
pub async fn segment_angle(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
 | 
			
		||||
    let tag: TagIdentifier = args.get_data()?;
 | 
			
		||||
    let tag: TagIdentifier = args.get_unlabeled_kw_arg("tag")?;
 | 
			
		||||
 | 
			
		||||
    let result = inner_segment_angle(&tag, exec_state, args.clone())?;
 | 
			
		||||
    Ok(args.make_user_val_from_f64(result))
 | 
			
		||||
@ -401,6 +446,11 @@ pub async fn segment_angle(exec_state: &mut ExecState, args: Args) -> Result<Kcl
 | 
			
		||||
/// ```
 | 
			
		||||
#[stdlib {
 | 
			
		||||
    name = "segAng",
 | 
			
		||||
    keywords = true,
 | 
			
		||||
    unlabeled_first = true,
 | 
			
		||||
    args = {
 | 
			
		||||
        tag = { docs = "The line segment being queried by its tag"},
 | 
			
		||||
    }
 | 
			
		||||
}]
 | 
			
		||||
fn inner_segment_angle(tag: &TagIdentifier, exec_state: &mut ExecState, args: Args) -> Result<f64, KclError> {
 | 
			
		||||
    let line = args.get_tag_engine_info(exec_state, tag)?;
 | 
			
		||||
@ -418,7 +468,7 @@ fn inner_segment_angle(tag: &TagIdentifier, exec_state: &mut ExecState, args: Ar
 | 
			
		||||
 | 
			
		||||
/// Returns the angle coming out of the end of the segment in degrees.
 | 
			
		||||
pub async fn tangent_to_end(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
 | 
			
		||||
    let tag: TagIdentifier = args.get_data()?;
 | 
			
		||||
    let tag: TagIdentifier = args.get_unlabeled_kw_arg("tag")?;
 | 
			
		||||
 | 
			
		||||
    let result = inner_tangent_to_end(&tag, exec_state, args.clone()).await?;
 | 
			
		||||
    Ok(args.make_user_val_from_f64(result))
 | 
			
		||||
@ -496,6 +546,11 @@ pub async fn tangent_to_end(exec_state: &mut ExecState, args: Args) -> Result<Kc
 | 
			
		||||
/// ```
 | 
			
		||||
#[stdlib {
 | 
			
		||||
    name = "tangentToEnd",
 | 
			
		||||
    keywords = true,
 | 
			
		||||
    unlabeled_first = true,
 | 
			
		||||
    args = {
 | 
			
		||||
        tag = { docs = "The line segment being queried by its tag"},
 | 
			
		||||
    }
 | 
			
		||||
}]
 | 
			
		||||
async fn inner_tangent_to_end(tag: &TagIdentifier, exec_state: &mut ExecState, args: Args) -> Result<f64, KclError> {
 | 
			
		||||
    let line = args.get_tag_engine_info(exec_state, tag)?;
 | 
			
		||||
 | 
			
		||||
@ -12,5 +12,5 @@ startSketchAt([0, 0])
 | 
			
		||||
       inscribed: false
 | 
			
		||||
     }, %)
 | 
			
		||||
  |> extrude(length = 4)
 | 
			
		||||
  |> patternTransform(3, transform, %)
 | 
			
		||||
  |> patternTransform(instances = 3, transform = transform)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -23,4 +23,4 @@ fn layer = () => {
 | 
			
		||||
}
 | 
			
		||||
// The vase is 100 layers tall.
 | 
			
		||||
// The 100 layers are replica of each other, with a slight transformation applied to each.
 | 
			
		||||
let vase = layer() |> patternTransform(100, transform, %)
 | 
			
		||||
let vase = layer() |> patternTransform(instances = 100, transform = transform)
 | 
			
		||||
 | 
			
		||||
@ -77,5 +77,5 @@ const peg = startSketchOn(s, 'end')
 | 
			
		||||
       distance = pitch
 | 
			
		||||
     )
 | 
			
		||||
  |> extrude(bumpHeight, %)
 | 
			
		||||
  // |> patternTransform(int(totalBumps-1), tr, %)
 | 
			
		||||
  // |> patternTransform(instances = int(totalBumps-1), transform = tr)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
		Reference in New Issue
	
	Block a user