KCL: Better docs for patternTransform and int (#4002)

This commit is contained in:
Adam Chalmers
2024-09-26 16:39:19 -05:00
committed by GitHub
parent 71c5451e3a
commit 20777a60aa
9 changed files with 99 additions and 32 deletions

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -137746,7 +137746,7 @@
"unpublished": false, "unpublished": false,
"deprecated": false, "deprecated": false,
"examples": [ "examples": [
"const sketch001 = startSketchOn('XZ')\n |> circle({ center: [0, 0], radius: 2 }, %)\nconst extrude001 = extrude(5, sketch001)\n\nlet n = int(ceil(5 / 2))\nassertEqual(n, 3, 0.0001, \"5/2 = 2.5, rounded up makes 3\")\nconst pattern01 = patternTransform(n, (id) => {\n return { translate: [4 * id, 0, 0] }\n}, extrude001)" "let n = int(ceil(5 / 2))\nassertEqual(n, 3, 0.0001, \"5/2 = 2.5, rounded up makes 3\")\n// Draw n cylinders.\nstartSketchOn('XZ')\n |> circle({ center: [0, 0], radius: 2 }, %)\n |> extrude(5, %)\n |> patternTransform(n, (id) => {\n return { translate: [4 * id, 0, 0] }\n}, %)"
] ]
}, },
{ {
@ -203739,12 +203739,12 @@
}, },
{ {
"name": "patternTransform", "name": "patternTransform",
"summary": "Repeat a 3-dimensional solid by successively applying a transformation (such", "summary": "Repeat a 3-dimensional solid, changing it each time.",
"description": "as rotation, scale, translation, visibility) on each repetition.\nThe transformation 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`.", "description": "Replicates the 3D solid, applying a transformation function to each replica. Transformation function could alter rotation, scale, visibility, position, etc.\nThe `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)` then there will be 4 circles: the original, and 3 created by replicating the original and calling the transform function on each.\nThe 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.",
"tags": [], "tags": [],
"args": [ "args": [
{ {
"name": "num_repetitions", "name": "total_instances",
"type": "u32", "type": "u32",
"schema": { "schema": {
"type": "integer", "type": "integer",
@ -210861,6 +210861,8 @@
"unpublished": false, "unpublished": false,
"deprecated": false, "deprecated": false,
"examples": [ "examples": [
"// Each instance will be shifted along the X axis.\nfn transform = (id) => {\n return { translate: [4 * id, 0, 0] }\n}\n\n// Sketch 4 cylinders.\nconst sketch001 = startSketchOn('XZ')\n |> circle({ center: [0, 0], radius: 2 }, %)\n |> extrude(5, %)\n |> patternTransform(4, transform, %)",
"// Each instance will be shifted along the X axis,\n// with a gap between the original (at x = 0) and the first replica\n// (at x = 8). This is because `id` starts at 1.\nfn transform = (id) => {\n return { translate: [4 * (1 + id), 0, 0] }\n}\n\nconst sketch001 = startSketchOn('XZ')\n |> circle({ center: [0, 0], radius: 2 }, %)\n |> extrude(5, %)\n |> patternTransform(4, transform, %)",
"fn cube = (length, center) => {\n let l = length / 2\n let x = center[0]\n let y = center[1]\n let p0 = [-l + x, -l + y]\n let p1 = [-l + x, l + y]\n let p2 = [l + x, l + y]\n let p3 = [l + x, -l + y]\n\n return startSketchAt(p0)\n |> lineTo(p1, %)\n |> lineTo(p2, %)\n |> lineTo(p3, %)\n |> lineTo(p0, %)\n |> close(%)\n |> extrude(length, %)\n}\n\nlet width = 20\nfn transform = (i) => {\n return {\n // Move down each time.\n translate: [0, 0, -i * width],\n // Make the cube longer, wider and flatter each time.\n scale: [pow(1.1, i), pow(1.1, i), pow(0.9, i)],\n // Turn by 15 degrees each time.\n rotation: { angle: 15 * i, origin: \"local\" }\n}\n}\n\nlet myCubes = cube(width, [100, 0])\n |> patternTransform(25, transform, %)", "fn cube = (length, center) => {\n let l = length / 2\n let x = center[0]\n let y = center[1]\n let p0 = [-l + x, -l + y]\n let p1 = [-l + x, l + y]\n let p2 = [l + x, l + y]\n let p3 = [l + x, -l + y]\n\n return startSketchAt(p0)\n |> lineTo(p1, %)\n |> lineTo(p2, %)\n |> lineTo(p3, %)\n |> lineTo(p0, %)\n |> close(%)\n |> extrude(length, %)\n}\n\nlet width = 20\nfn transform = (i) => {\n return {\n // Move down each time.\n translate: [0, 0, -i * width],\n // Make the cube longer, wider and flatter each time.\n scale: [pow(1.1, i), pow(1.1, i), pow(0.9, i)],\n // Turn by 15 degrees each time.\n rotation: { angle: 15 * i, origin: \"local\" }\n}\n}\n\nlet myCubes = cube(width, [100, 0])\n |> patternTransform(25, transform, %)",
"// Parameters\nconst r = 50 // base radius\nconst h = 10 // layer height\nconst t = 0.005 // taper factor [0-1)\n// Defines how to modify each layer of the vase.\n// Each replica is shifted up the Z axis, and has a smoothly-varying radius\nfn transform = (replicaId) => {\n let scale = r * abs(1 - (t * replicaId)) * (5 + cos(replicaId / 8))\n return {\n translate: [0, 0, replicaId * 10],\n scale: [scale, scale, 0]\n}\n}\n// Each layer is just a pretty thin cylinder.\nfn layer = () => {\n return startSketchOn(\"XY\")\n // or some other plane idk\n |> circle({ center: [0, 0], radius: 1 }, %, $tag1)\n |> extrude(h, %)\n}\n// The vase is 100 layers tall.\n// The 100 layers are replica of each other, with a slight transformation applied to each.\nlet vase = layer()\n |> patternTransform(100, transform, %)" "// Parameters\nconst r = 50 // base radius\nconst h = 10 // layer height\nconst t = 0.005 // taper factor [0-1)\n// Defines how to modify each layer of the vase.\n// Each replica is shifted up the Z axis, and has a smoothly-varying radius\nfn transform = (replicaId) => {\n let scale = r * abs(1 - (t * replicaId)) * (5 + cos(replicaId / 8))\n return {\n translate: [0, 0, replicaId * 10],\n scale: [scale, scale, 0]\n}\n}\n// Each layer is just a pretty thin cylinder.\nfn layer = () => {\n return startSketchOn(\"XY\")\n // or some other plane idk\n |> circle({ center: [0, 0], radius: 1 }, %, $tag1)\n |> extrude(h, %)\n}\n// The vase is 100 layers tall.\n// The 100 layers are replica of each other, with a slight transformation applied to each.\nlet vase = layer()\n |> patternTransform(100, transform, %)"
] ]

View File

@ -49,15 +49,15 @@ pub async fn int(_exec_state: &mut ExecState, args: Args) -> Result<KclValue, Kc
/// a runtime error. /// a runtime error.
/// ///
/// ```no_run /// ```no_run
/// const sketch001 = startSketchOn('XZ')
/// |> circle({ center: [0, 0], radius: 2 }, %)
/// const extrude001 = extrude(5, sketch001)
///
/// let n = int(ceil(5/2)) /// let n = int(ceil(5/2))
/// assertEqual(n, 3, 0.0001, "5/2 = 2.5, rounded up makes 3") /// assertEqual(n, 3, 0.0001, "5/2 = 2.5, rounded up makes 3")
/// const pattern01 = patternTransform(n, (id) => { /// // Draw n cylinders.
/// startSketchOn('XZ')
/// |> circle({ center: [0, 0], radius: 2 }, %)
/// |> extrude(5, %)
/// |> patternTransform(n, (id) => {
/// return { translate: [4 * id, 0, 0] } /// return { translate: [4 * id, 0, 0] }
/// }, extrude001) /// }, %)
/// ``` /// ```
#[stdlib { #[stdlib {
name = "int", name = "int",

View File

@ -105,12 +105,45 @@ pub async fn pattern_transform(exec_state: &mut ExecState, args: Args) -> Result
Ok(KclValue::ExtrudeGroups { value: extrude_groups }) Ok(KclValue::ExtrudeGroups { value: extrude_groups })
} }
/// Repeat a 3-dimensional solid by successively applying a transformation (such /// Repeat a 3-dimensional solid, changing it each time.
/// as rotation, scale, translation, visibility) on each repetition.
/// ///
/// The transformation takes a single parameter: an integer representing which /// Replicates the 3D solid, applying a transformation function to each replica.
/// 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)`
/// then there will be 4 circles: the original, and 3 created by replicating the original and
/// calling the transform function on each.
///
/// 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 /// number replication the transform is for. E.g. the first replica to be transformed
/// will be passed the argument `1`. /// 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.
/// ```no_run
/// // Each instance will be shifted along the X axis.
/// fn transform = (id) => {
/// return { translate: [4 * id, 0, 0] }
/// }
///
/// // Sketch 4 cylinders.
/// const sketch001 = startSketchOn('XZ')
/// |> circle({ center: [0, 0], radius: 2 }, %)
/// |> extrude(5, %)
/// |> patternTransform(4, transform, %)
/// ```
/// ```no_run
/// // Each instance will be shifted along the X axis,
/// // with a gap between the original (at x = 0) and the first replica
/// // (at x = 8). This is because `id` starts at 1.
/// fn transform = (id) => {
/// return { translate: [4 * (1+id), 0, 0] }
/// }
///
/// const sketch001 = startSketchOn('XZ')
/// |> circle({ center: [0, 0], radius: 2 }, %)
/// |> extrude(5, %)
/// |> patternTransform(4, transform, %)
/// ```
/// ```no_run /// ```no_run
/// fn cube = (length, center) => { /// fn cube = (length, center) => {
/// let l = length/2 /// let l = length/2
@ -178,15 +211,15 @@ pub async fn pattern_transform(exec_state: &mut ExecState, args: Args) -> Result
name = "patternTransform", name = "patternTransform",
}] }]
async fn inner_pattern_transform<'a>( async fn inner_pattern_transform<'a>(
num_repetitions: u32, total_instances: u32,
transform_function: FunctionParam<'a>, transform_function: FunctionParam<'a>,
extrude_group_set: ExtrudeGroupSet, extrude_group_set: ExtrudeGroupSet,
exec_state: &mut ExecState, exec_state: &mut ExecState,
args: &'a Args, args: &'a Args,
) -> Result<Vec<Box<ExtrudeGroup>>, KclError> { ) -> Result<Vec<Box<ExtrudeGroup>>, KclError> {
// Build the vec of transforms, one for each repetition. // Build the vec of transforms, one for each repetition.
let mut transform = Vec::with_capacity(usize::try_from(num_repetitions).unwrap()); let mut transform = Vec::with_capacity(usize::try_from(total_instances).unwrap());
for i in 1..num_repetitions { for i in 1..total_instances {
let t = make_transform(i, &transform_function, args.source_range, exec_state).await?; let t = make_transform(i, &transform_function, args.source_range, exec_state).await?;
transform.push(t); transform.push(t);
} }

Binary file not shown.

Before

Width:  |  Height:  |  Size: 83 KiB

After

Width:  |  Height:  |  Size: 87 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 227 KiB

After

Width:  |  Height:  |  Size: 76 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 83 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 227 KiB