Enhance helixes (#4973)

* updates

Signed-off-by: Jess Frazelle <github@jessfraz.com>

* updates

Signed-off-by: Jess Frazelle <github@jessfraz.com>

* updates

Signed-off-by: Jess Frazelle <github@jessfraz.com>

* allow a helix to go into a sweep

Signed-off-by: Jess Frazelle <github@jessfraz.com>

* fix clippy

Signed-off-by: Jess Frazelle <github@jessfraz.com>

* updates

Signed-off-by: Jess Frazelle <github@jessfraz.com>

* udpates

Signed-off-by: Jess Frazelle <github@jessfraz.com>

* updates

Signed-off-by: Jess Frazelle <github@jessfraz.com>

* snapshots

Signed-off-by: Jess Frazelle <github@jessfraz.com>

* docs

Signed-off-by: Jess Frazelle <github@jessfraz.com>

* docs

Signed-off-by: Jess Frazelle <github@jessfraz.com>

* fix

Signed-off-by: Jess Frazelle <github@jessfraz.com>

* updates

Signed-off-by: Jess Frazelle <github@jessfraz.com>

* updates

Signed-off-by: Jess Frazelle <github@jessfraz.com>

* updates

Signed-off-by: Jess Frazelle <github@jessfraz.com>

* A snapshot a day keeps the bugs away! 📷🐛 (OS: namespace-profile-ubuntu-8-cores)

* updates

Signed-off-by: Jess Frazelle <github@jessfraz.com>

* updates

Signed-off-by: Jess Frazelle <github@jessfraz.com>

* docs

Signed-off-by: Jess Frazelle <github@jessfraz.com>

* updates

Signed-off-by: Jess Frazelle <github@jessfraz.com>

* A snapshot a day keeps the bugs away! 📷🐛 (OS: namespace-profile-ubuntu-8-cores)

* em,pty

* A snapshot a day keeps the bugs away! 📷🐛 (OS: namespace-profile-ubuntu-8-cores)

* updates

Signed-off-by: Jess Frazelle <github@jessfraz.com>

* updates

Signed-off-by: Jess Frazelle <github@jessfraz.com>

---------

Signed-off-by: Jess Frazelle <github@jessfraz.com>
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
This commit is contained in:
Jess Frazelle
2025-01-07 19:10:53 -08:00
committed by GitHub
parent a9ceaf2678
commit 5ebd5c8dbb
58 changed files with 4057 additions and 1312 deletions

View File

@ -24,3 +24,5 @@ once fixed in engine will just start working here with no language changes.
chamfer cases work currently. chamfer cases work currently.
- **Appearance**: Changing the appearance on a loft does not work. - **Appearance**: Changing the appearance on a loft does not work.
- **Helix**: Currently sweeping a helix does not work.

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -48,6 +48,7 @@ layout: manual
* [`getOppositeEdge`](kcl/getOppositeEdge) * [`getOppositeEdge`](kcl/getOppositeEdge)
* [`getPreviousAdjacentEdge`](kcl/getPreviousAdjacentEdge) * [`getPreviousAdjacentEdge`](kcl/getPreviousAdjacentEdge)
* [`helix`](kcl/helix) * [`helix`](kcl/helix)
* [`helixRevolutions`](kcl/helixRevolutions)
* [`hole`](kcl/hole) * [`hole`](kcl/hole)
* [`hollow`](kcl/hollow) * [`hollow`](kcl/hollow)
* [`import`](kcl/import) * [`import`](kcl/import)

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

View File

@ -1,19 +1,19 @@
--- ---
title: "AxisOrEdgeReference" title: "Axis2dOrEdgeReference"
excerpt: "Axis or tagged edge." excerpt: "A 2D axis or tagged edge."
layout: manual layout: manual
--- ---
Axis or tagged edge. A 2D axis or tagged edge.
**This schema accepts any of the following:** **This schema accepts any of the following:**
Axis and origin. 2D axis and origin.
[`AxisAndOrigin`](/docs/kcl/types/AxisAndOrigin) [`AxisAndOrigin2d`](/docs/kcl/types/AxisAndOrigin2d)

View File

@ -0,0 +1,42 @@
---
title: "Axis3dOrEdgeReference"
excerpt: "A 3D axis or tagged edge."
layout: manual
---
A 3D axis or tagged edge.
**This schema accepts any of the following:**
3D axis and origin.
[`AxisAndOrigin3d`](/docs/kcl/types/AxisAndOrigin3d)
----
Tagged edge.
[`EdgeReference`](/docs/kcl/types/EdgeReference)
----

View File

@ -1,10 +1,10 @@
--- ---
title: "AxisAndOrigin" title: "AxisAndOrigin2d"
excerpt: "Axis and origin." excerpt: "A 2D axis and origin."
layout: manual layout: manual
--- ---
Axis and origin. A 2D axis and origin.

View File

@ -0,0 +1,105 @@
---
title: "AxisAndOrigin3d"
excerpt: "A 3D axis and origin."
layout: manual
---
A 3D axis and origin.
**This schema accepts exactly one of the following:**
X-axis.
**enum:** `X`
----
Y-axis.
**enum:** `Y`
----
Z-axis.
**enum:** `Z`
----
Flip the X-axis.
**enum:** `-X`
----
Flip the Y-axis.
**enum:** `-Y`
----
Flip the Z-axis.
**enum:** `-Z`
----
**Type:** `object`
## Properties
| Property | Type | Description | Required |
|----------|------|-------------|----------|
| `custom` |`object`| | No |
----

25
docs/kcl/types/Helix.md Normal file
View File

@ -0,0 +1,25 @@
---
title: "Helix"
excerpt: "A helix."
layout: manual
---
A helix.
**Type:** `object`
## Properties
| Property | Type | Description | Required |
|----------|------|-------------|----------|
| `value` |`string`| The id of the helix. | No |
| `revolutions` |`number`| Number of revolutions. | No |
| `angleStart` |`number`| Start angle (in degrees). | No |
| `ccw` |`boolean`| Is the helix rotation counter clockwise? | No |
| `__meta` |`[` [`Metadata`](/docs/kcl/types/Metadata) `]`| | No |

View File

@ -1,10 +1,10 @@
--- ---
title: "HelixData" title: "HelixData"
excerpt: "Data for helices." excerpt: "Data for a helix."
layout: manual layout: manual
--- ---
Data for helices. Data for a helix.
**Type:** `object` **Type:** `object`
@ -19,6 +19,8 @@ Data for helices.
| `revolutions` |`number`| Number of revolutions. | No | | `revolutions` |`number`| Number of revolutions. | No |
| `angleStart` |`number`| Start angle (in degrees). | No | | `angleStart` |`number`| Start angle (in degrees). | No |
| `ccw` |`boolean`| Is the helix rotation counter clockwise? The default is `false`. | No | | `ccw` |`boolean`| Is the helix rotation counter clockwise? The default is `false`. | No |
| `length` |`number`| Length of the helix. If this argument is not provided, the height of the solid is used. | No | | `length` |`number`| Length of the helix. | No |
| `radius` |`number`| Radius of the helix. | No |
| `axis` |[`Axis3dOrEdgeReference`](/docs/kcl/types/Axis3dOrEdgeReference)| Axis to use as mirror. | No |

View File

@ -0,0 +1,24 @@
---
title: "HelixRevolutionsData"
excerpt: "Data for helix revolutions."
layout: manual
---
Data for helix revolutions.
**Type:** `object`
## Properties
| Property | Type | Description | Required |
|----------|------|-------------|----------|
| `revolutions` |`number`| Number of revolutions. | No |
| `angleStart` |`number`| Start angle (in degrees). | No |
| `ccw` |`boolean`| Is the helix rotation counter clockwise? The default is `false`. | No |
| `length` |`number`| Length of the helix. If this argument is not provided, the height of the solid is used. | No |

View File

@ -0,0 +1,25 @@
---
title: "HelixValue"
excerpt: "A helix."
layout: manual
---
A helix.
**Type:** `object`
## Properties
| Property | Type | Description | Required |
|----------|------|-------------|----------|
| `value` |`string`| The id of the helix. | No |
| `revolutions` |`number`| Number of revolutions. | No |
| `angleStart` |`number`| Start angle (in degrees). | No |
| `ccw` |`boolean`| Is the helix rotation counter clockwise? | No |
| `__meta` |`[` [`Metadata`](/docs/kcl/types/Metadata) `]`| | No |

View File

@ -285,6 +285,27 @@ An solid is a collection of extrude surfaces.
| `value` |`[` [`Solid`](/docs/kcl/types/Solid) `]`| | No | | `value` |`[` [`Solid`](/docs/kcl/types/Solid) `]`| | No |
----
A helix.
**Type:** `object`
## Properties
| Property | Type | Description | Required |
|----------|------|-------------|----------|
| `type` |enum: [`Helix`](/docs/kcl/types/Helix)| | No |
| `value` |`string`| The id of the helix. | No |
| `revolutions` |`number`| Number of revolutions. | No |
| `angleStart` |`number`| Start angle (in degrees). | No |
| `ccw` |`boolean`| Is the helix rotation counter clockwise? | No |
| `__meta` |`[` [`Metadata`](/docs/kcl/types/Metadata) `]`| | No |
---- ----
Data for an imported geometry. Data for an imported geometry.

View File

@ -16,6 +16,6 @@ Data for a mirror.
| Property | Type | Description | Required | | Property | Type | Description | Required |
|----------|------|-------------|----------| |----------|------|-------------|----------|
| `axis` |[`AxisOrEdgeReference`](/docs/kcl/types/AxisOrEdgeReference)| Axis to use as mirror. | No | | `axis` |[`Axis2dOrEdgeReference`](/docs/kcl/types/Axis2dOrEdgeReference)| Axis to use as mirror. | No |

View File

@ -17,7 +17,7 @@ Data for revolution surfaces.
| Property | Type | Description | Required | | Property | Type | Description | Required |
|----------|------|-------------|----------| |----------|------|-------------|----------|
| `angle` |`number` (**maximum:** 360.0) (**minimum:** -360.0)| Angle to revolve (in degrees). Default is 360. | No | | `angle` |`number` (**maximum:** 360.0) (**minimum:** -360.0)| Angle to revolve (in degrees). Default is 360. | No |
| `axis` |[`AxisOrEdgeReference`](/docs/kcl/types/AxisOrEdgeReference)| Axis of revolution. | No | | `axis` |[`Axis2dOrEdgeReference`](/docs/kcl/types/Axis2dOrEdgeReference)| Axis of revolution. | No |
| `tolerance` |`number`| Tolerance for the revolve operation. | No | | `tolerance` |`number`| Tolerance for the revolve operation. | No |

View File

@ -16,7 +16,7 @@ Data for a sweep.
| Property | Type | Description | Required | | Property | Type | Description | Required |
|----------|------|-------------|----------| |----------|------|-------------|----------|
| `path` |[`Sketch`](/docs/kcl/types/Sketch)| The path to sweep along. | No | | `path` |[`SweepPath`](/docs/kcl/types/SweepPath)| The path to sweep along. | No |
| `sectional` |`boolean`| If true, the sweep will be broken up into sub-sweeps (extrusions, revolves, sweeps) based on the trajectory path components. | No | | `sectional` |`boolean`| If true, the sweep will be broken up into sub-sweeps (extrusions, revolves, sweeps) based on the trajectory path components. | No |
| `tolerance` |`number`| Tolerance for the sweep operation. | No | | `tolerance` |`number`| Tolerance for the sweep operation. | No |

View File

@ -0,0 +1,42 @@
---
title: "SweepPath"
excerpt: "A path to sweep along."
layout: manual
---
A path to sweep along.
**This schema accepts any of the following:**
A path to sweep along.
[`Sketch`](/docs/kcl/types/Sketch)
----
A path to sweep along.
[`Helix`](/docs/kcl/types/Helix)
----

View File

@ -39,8 +39,8 @@ test.describe('Sketch tests', () => {
${startProfileAt1} ${startProfileAt1}
|> arc({ |> arc({
radius = screwRadius, radius = screwRadius,
angle_start = 0, angleStart = 0,
angle_end = 360 angleEnd = 360
}, %) }, %)
part001 = startSketchOn('XY') part001 = startSketchOn('XY')
@ -60,8 +60,8 @@ test.describe('Sketch tests', () => {
|> yLine(wireOffset, %) |> yLine(wireOffset, %)
|> arc({ |> arc({
radius = wireRadius, radius = wireRadius,
angle_start = 0, angleStart = 0,
angle_end = 180 angleEnd = 180
}, %) }, %)
|> yLine(-wireOffset, %) |> yLine(-wireOffset, %)
|> xLine(-width / 4, %) |> xLine(-width / 4, %)

View File

@ -389,25 +389,25 @@ test.describe('Testing selections', () => {
await expect(u.codeLocator).toContainText(`sketch005 = startSketchOn({ await expect(u.codeLocator).toContainText(`sketch005 = startSketchOn({
plane = { plane = {
origin = { x = 0, y = -50, z = 0 }, origin = { x = 0, y = -50, z = 0 },
x_axis = { x = 1, y = 0, z = 0 }, xAxis = { x = 1, y = 0, z = 0 },
y_axis = { x = 0, y = 0, z = 1 }, yAxis = { x = 0, y = 0, z = 1 },
z_axis = { x = 0, y = -1, z = 0 } zAxis = { x = 0, y = -1, z = 0 }
} }
})`) })`)
await expect(u.codeLocator).toContainText(`sketch003 = startSketchOn({ await expect(u.codeLocator).toContainText(`sketch003 = startSketchOn({
plane = { plane = {
origin = { x = 116.53, y = 0, z = 163.25 }, origin = { x = 116.53, y = 0, z = 163.25 },
x_axis = { x = -0.81, y = 0, z = 0.58 }, xAxis = { x = -0.81, y = 0, z = 0.58 },
y_axis = { x = 0, y = -1, z = 0 }, yAxis = { x = 0, y = -1, z = 0 },
z_axis = { x = 0.58, y = 0, z = 0.81 } zAxis = { x = 0.58, y = 0, z = 0.81 }
} }
})`) })`)
await expect(u.codeLocator).toContainText(`sketch002 = startSketchOn({ await expect(u.codeLocator).toContainText(`sketch002 = startSketchOn({
plane = { plane = {
origin = { x = -91.74, y = 0, z = 80.89 }, origin = { x = -91.74, y = 0, z = 80.89 },
x_axis = { x = -0.66, y = 0, z = -0.75 }, xAxis = { x = -0.66, y = 0, z = -0.75 },
y_axis = { x = 0, y = -1, z = 0 }, yAxis = { x = 0, y = -1, z = 0 },
z_axis = { x = -0.75, y = 0, z = 0.66 } zAxis = { x = -0.75, y = 0, z = 0.66 }
} }
})`) })`)

View File

@ -806,9 +806,9 @@ sketch001 = startSketchOn('XZ')
sketch002 = startSketchOn({ sketch002 = startSketchOn({
plane = { plane = {
origin = { x = 1, y = 2, z = 3 }, origin = { x = 1, y = 2, z = 3 },
x_axis = { x = 4, y = 5, z = 6 }, xAxis = { x = 4, y = 5, z = 6 },
y_axis = { x = 7, y = 8, z = 9 }, yAxis = { x = 7, y = 8, z = 9 },
z_axis = { x = 10, y = 11, z = 12 } zAxis = { x = 10, y = 11, z = 12 }
} }
}) })
|> startProfileAt([-12.55, 2.89], %) |> startProfileAt([-12.55, 2.89], %)
@ -862,9 +862,9 @@ sketch001 = startSketchOn('XZ')
sketch002 = startSketchOn({ sketch002 = startSketchOn({
plane = { plane = {
origin = { x = 1, y = 2, z = 3 }, origin = { x = 1, y = 2, z = 3 },
x_axis = { x = 4, y = 5, z = 6 }, xAxis = { x = 4, y = 5, z = 6 },
y_axis = { x = 7, y = 8, z = 9 }, yAxis = { x = 7, y = 8, z = 9 },
z_axis = { x = 10, y = 11, z = 12 } zAxis = { x = 10, y = 11, z = 12 }
} }
}) })
|> startProfileAt([-12.55, 2.89], %) |> startProfileAt([-12.55, 2.89], %)

View File

@ -1278,17 +1278,17 @@ export async function deleteFromSelection(
y: roundLiteral(faceDetails.origin.y), y: roundLiteral(faceDetails.origin.y),
z: roundLiteral(faceDetails.origin.z), z: roundLiteral(faceDetails.origin.z),
}), }),
x_axis: createObjectExpression({ xAxis: createObjectExpression({
x: roundLiteral(faceDetails.x_axis.x), x: roundLiteral(faceDetails.x_axis.x),
y: roundLiteral(faceDetails.x_axis.y), y: roundLiteral(faceDetails.x_axis.y),
z: roundLiteral(faceDetails.x_axis.z), z: roundLiteral(faceDetails.x_axis.z),
}), }),
y_axis: createObjectExpression({ yAxis: createObjectExpression({
x: roundLiteral(faceDetails.y_axis.x), x: roundLiteral(faceDetails.y_axis.x),
y: roundLiteral(faceDetails.y_axis.y), y: roundLiteral(faceDetails.y_axis.y),
z: roundLiteral(faceDetails.y_axis.z), z: roundLiteral(faceDetails.y_axis.z),
}), }),
z_axis: createObjectExpression({ zAxis: createObjectExpression({
x: roundLiteral(faceDetails.z_axis.x), x: roundLiteral(faceDetails.z_axis.x),
y: roundLiteral(faceDetails.z_axis.y), y: roundLiteral(faceDetails.z_axis.y),
z: roundLiteral(faceDetails.z_axis.z), z: roundLiteral(faceDetails.z_axis.z),

View File

@ -1819,9 +1819,9 @@ dependencies = [
[[package]] [[package]]
name = "kittycad-modeling-cmds" name = "kittycad-modeling-cmds"
version = "0.2.79" version = "0.2.86"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "10a9cab4476455be70ea57643c31444068b056d091bd348cab6044c0d8ad7fcc" checksum = "65e34a8eeb4fff5167666d1f2bc36c95d08ab3a0f736a02c8d33a8cde21cfd8d"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"chrono", "chrono",

View File

@ -76,7 +76,7 @@ members = [
[workspace.dependencies] [workspace.dependencies]
http = "1" http = "1"
kittycad = { version = "0.3.28", default-features = false, features = ["js", "requests"] } kittycad = { version = "0.3.28", default-features = false, features = ["js", "requests"] }
kittycad-modeling-cmds = { version = "0.2.79", features = ["websocket"] } kittycad-modeling-cmds = { version = "0.2.86", features = ["websocket"] }
[workspace.lints.clippy] [workspace.lints.clippy]
assertions_on_result_states = "warn" assertions_on_result_states = "warn"

View File

@ -535,7 +535,11 @@ fn generate_type(
|| name == "CircularPattern3dData" || name == "CircularPattern3dData"
|| name == "LinearPattern2dData" || name == "LinearPattern2dData"
|| name == "LinearPattern3dData" || name == "LinearPattern3dData"
|| name == "Mirror2dData") || name == "Mirror2dData"
|| name == "Axis2dOrEdgeReference"
|| name == "Axis3dOrEdgeReference"
|| name == "AxisAndOrigin2d"
|| name == "AxisAndOrigin3d")
{ {
return Err(anyhow::anyhow!("Type name is not pascal cased: {}", name)); return Err(anyhow::anyhow!("Type name is not pascal cased: {}", name));
} }

View File

@ -7,7 +7,9 @@ use serde::{Deserialize, Serialize};
use crate::{ use crate::{
errors::KclErrorDetails, errors::KclErrorDetails,
exec::{ProgramMemory, Sketch}, exec::{ProgramMemory, Sketch},
execution::{Face, ImportedGeometry, MemoryFunction, Metadata, Plane, SketchSet, Solid, SolidSet, TagIdentifier}, execution::{
Face, Helix, ImportedGeometry, MemoryFunction, Metadata, Plane, SketchSet, Solid, SolidSet, TagIdentifier,
},
parsing::{ parsing::{
ast::types::{FunctionExpression, KclNone, LiteralValue, TagDeclarator, TagNode}, ast::types::{FunctionExpression, KclNone, LiteralValue, TagDeclarator, TagNode},
token::NumericSuffix, token::NumericSuffix,
@ -72,6 +74,7 @@ pub enum KclValue {
Solids { Solids {
value: Vec<Box<Solid>>, value: Vec<Box<Solid>>,
}, },
Helix(Box<Helix>),
ImportedGeometry(ImportedGeometry), ImportedGeometry(ImportedGeometry),
#[ts(skip)] #[ts(skip)]
Function { Function {
@ -141,6 +144,7 @@ impl From<KclValue> for Vec<SourceRange> {
KclValue::Solids { value } => value.iter().flat_map(|eg| to_vec_sr(&eg.meta)).collect(), KclValue::Solids { value } => value.iter().flat_map(|eg| to_vec_sr(&eg.meta)).collect(),
KclValue::Sketch { value } => to_vec_sr(&value.meta), KclValue::Sketch { value } => to_vec_sr(&value.meta),
KclValue::Sketches { value } => value.iter().flat_map(|eg| to_vec_sr(&eg.meta)).collect(), KclValue::Sketches { value } => value.iter().flat_map(|eg| to_vec_sr(&eg.meta)).collect(),
KclValue::Helix(e) => to_vec_sr(&e.meta),
KclValue::ImportedGeometry(i) => to_vec_sr(&i.meta), KclValue::ImportedGeometry(i) => to_vec_sr(&i.meta),
KclValue::Function { meta, .. } => to_vec_sr(&meta), KclValue::Function { meta, .. } => to_vec_sr(&meta),
KclValue::Plane(p) => to_vec_sr(&p.meta), KclValue::Plane(p) => to_vec_sr(&p.meta),
@ -171,6 +175,7 @@ impl From<&KclValue> for Vec<SourceRange> {
KclValue::Solids { value } => value.iter().flat_map(|eg| to_vec_sr(&eg.meta)).collect(), KclValue::Solids { value } => value.iter().flat_map(|eg| to_vec_sr(&eg.meta)).collect(),
KclValue::Sketch { value } => to_vec_sr(&value.meta), KclValue::Sketch { value } => to_vec_sr(&value.meta),
KclValue::Sketches { value } => value.iter().flat_map(|eg| to_vec_sr(&eg.meta)).collect(), KclValue::Sketches { value } => value.iter().flat_map(|eg| to_vec_sr(&eg.meta)).collect(),
KclValue::Helix(x) => to_vec_sr(&x.meta),
KclValue::ImportedGeometry(i) => to_vec_sr(&i.meta), KclValue::ImportedGeometry(i) => to_vec_sr(&i.meta),
KclValue::Function { meta, .. } => to_vec_sr(meta), KclValue::Function { meta, .. } => to_vec_sr(meta),
KclValue::Plane(p) => to_vec_sr(&p.meta), KclValue::Plane(p) => to_vec_sr(&p.meta),
@ -206,6 +211,7 @@ impl KclValue {
KclValue::Sketches { value } => value.iter().flat_map(|sketch| &sketch.meta).copied().collect(), KclValue::Sketches { value } => value.iter().flat_map(|sketch| &sketch.meta).copied().collect(),
KclValue::Solid(x) => x.meta.clone(), KclValue::Solid(x) => x.meta.clone(),
KclValue::Solids { value } => value.iter().flat_map(|sketch| &sketch.meta).copied().collect(), KclValue::Solids { value } => value.iter().flat_map(|sketch| &sketch.meta).copied().collect(),
KclValue::Helix(x) => x.meta.clone(),
KclValue::ImportedGeometry(x) => x.meta.clone(), KclValue::ImportedGeometry(x) => x.meta.clone(),
KclValue::Function { meta, .. } => meta.clone(), KclValue::Function { meta, .. } => meta.clone(),
KclValue::Module { meta, .. } => meta.clone(), KclValue::Module { meta, .. } => meta.clone(),
@ -264,6 +270,7 @@ impl KclValue {
KclValue::Solids { .. } => "Solids", KclValue::Solids { .. } => "Solids",
KclValue::Sketch { .. } => "Sketch", KclValue::Sketch { .. } => "Sketch",
KclValue::Sketches { .. } => "Sketches", KclValue::Sketches { .. } => "Sketches",
KclValue::Helix(_) => "Helix",
KclValue::ImportedGeometry(_) => "ImportedGeometry", KclValue::ImportedGeometry(_) => "ImportedGeometry",
KclValue::Function { .. } => "Function", KclValue::Function { .. } => "Function",
KclValue::Plane(_) => "Plane", KclValue::Plane(_) => "Plane",

View File

@ -702,6 +702,23 @@ pub struct ImportedGeometry {
pub meta: Vec<Metadata>, pub meta: Vec<Metadata>,
} }
/// A helix.
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema)]
#[ts(export)]
#[serde(rename_all = "camelCase")]
pub struct Helix {
/// The id of the helix.
pub value: uuid::Uuid,
/// Number of revolutions.
pub revolutions: f64,
/// Start angle (in degrees).
pub angle_start: f64,
/// Is the helix rotation counter clockwise?
pub ccw: bool,
#[serde(rename = "__meta")]
pub meta: Vec<Metadata>,
}
/// A plane. /// A plane.
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema)] #[derive(Debug, Clone, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema)]
#[ts(export)] #[ts(export)]

View File

@ -8,12 +8,12 @@ use super::shapes::PolygonType;
use crate::{ use crate::{
errors::{KclError, KclErrorDetails}, errors::{KclError, KclErrorDetails},
execution::{ execution::{
ExecState, ExecutorContext, ExtrudeSurface, KclObjectFields, KclValue, Metadata, Sketch, SketchSet, ExecState, ExecutorContext, ExtrudeSurface, Helix, KclObjectFields, KclValue, Metadata, Sketch, SketchSet,
SketchSurface, Solid, SolidSet, TagIdentifier, SketchSurface, Solid, SolidSet, TagIdentifier,
}, },
parsing::ast::types::TagNode, parsing::ast::types::TagNode,
source_range::SourceRange, source_range::SourceRange,
std::{shapes::SketchOrSurface, sketch::FaceTag, FnAsArg}, std::{shapes::SketchOrSurface, sketch::FaceTag, sweep::SweepPath, FnAsArg},
ModuleId, ModuleId,
}; };
@ -634,7 +634,7 @@ where
message: format!( message: format!(
"Argument at index {i} was supposed to be type {} but found {}", "Argument at index {i} was supposed to be type {} but found {}",
type_name::<T>(), type_name::<T>(),
arg.value.human_friendly_type() arg.value.human_friendly_type(),
), ),
source_ranges: arg.source_ranges(), source_ranges: arg.source_ranges(),
})); }));
@ -1105,13 +1105,34 @@ impl<'a> FromKclValue<'a> for super::appearance::AppearanceData {
} }
impl<'a> FromKclValue<'a> for super::helix::HelixData { impl<'a> FromKclValue<'a> for super::helix::HelixData {
fn from_kcl_val(arg: &'a KclValue) -> Option<Self> {
let obj = arg.as_object()?;
let_field_of!(obj, revolutions);
let_field_of!(obj, length);
let_field_of!(obj, ccw?);
let_field_of!(obj, radius);
let_field_of!(obj, axis);
let ccw = ccw.unwrap_or_default();
let angle_start = obj.get("angleStart")?.as_f64()?;
Some(Self {
revolutions,
angle_start,
ccw,
length,
radius,
axis,
})
}
}
impl<'a> FromKclValue<'a> for super::helix::HelixRevolutionsData {
fn from_kcl_val(arg: &'a KclValue) -> Option<Self> { fn from_kcl_val(arg: &'a KclValue) -> Option<Self> {
let obj = arg.as_object()?; let obj = arg.as_object()?;
let_field_of!(obj, revolutions); let_field_of!(obj, revolutions);
let_field_of!(obj, length?); let_field_of!(obj, length?);
let_field_of!(obj, ccw?); let_field_of!(obj, ccw?);
let ccw = ccw.unwrap_or_default(); let ccw = ccw.unwrap_or_default();
let angle_start = obj.get("angleStart").or_else(|| obj.get("angle_start"))?.as_f64()?; let angle_start = obj.get("angleStart")?.as_f64()?;
Some(Self { Some(Self {
revolutions, revolutions,
angle_start, angle_start,
@ -1159,8 +1180,8 @@ impl<'a> FromKclValue<'a> for super::sketch::ArcData {
let obj = arg.as_object()?; let obj = arg.as_object()?;
let_field_of!(obj, radius); let_field_of!(obj, radius);
let case1 = || { let case1 = || {
let angle_start = obj.get("angleStart").or_else(|| obj.get("angle_start"))?.as_f64()?; let angle_start = obj.get("angleStart")?.as_f64()?;
let angle_end = obj.get("angleEnd").or_else(|| obj.get("angle_end"))?.as_f64()?; let angle_end = obj.get("angleEnd")?.as_f64()?;
Some(Self::AnglesAndRadius { Some(Self::AnglesAndRadius {
angle_start, angle_start,
angle_end, angle_end,
@ -1256,21 +1277,9 @@ impl<'a> FromKclValue<'a> for super::sketch::PlaneData {
let obj = arg.as_object()?; let obj = arg.as_object()?;
let_field_of!(obj, plane, &KclObjectFields); let_field_of!(obj, plane, &KclObjectFields);
let origin = plane.get("origin").and_then(FromKclValue::from_kcl_val).map(Box::new)?; let origin = plane.get("origin").and_then(FromKclValue::from_kcl_val).map(Box::new)?;
let x_axis = plane let x_axis = plane.get("xAxis").and_then(FromKclValue::from_kcl_val).map(Box::new)?;
.get("xAxis") let y_axis = plane.get("yAxis").and_then(FromKclValue::from_kcl_val).map(Box::new)?;
.or_else(|| plane.get("x_axis")) let z_axis = plane.get("zAxis").and_then(FromKclValue::from_kcl_val).map(Box::new)?;
.and_then(FromKclValue::from_kcl_val)
.map(Box::new)?;
let y_axis = plane
.get("yAxis")
.or_else(|| plane.get("y_axis"))
.and_then(FromKclValue::from_kcl_val)
.map(Box::new)?;
let z_axis = plane
.get("zAxis")
.or_else(|| plane.get("z_axis"))
.and_then(FromKclValue::from_kcl_val)
.map(Box::new)?;
Some(Self::Plane { Some(Self::Plane {
origin, origin,
x_axis, x_axis,
@ -1442,7 +1451,7 @@ impl<'a> FromKclValue<'a> for super::sketch::SketchData {
} }
} }
impl<'a> FromKclValue<'a> for super::revolve::AxisAndOrigin { impl<'a> FromKclValue<'a> for super::axis_or_reference::AxisAndOrigin2d {
fn from_kcl_val(arg: &'a KclValue) -> Option<Self> { fn from_kcl_val(arg: &'a KclValue) -> Option<Self> {
// Case 1: predefined planes. // Case 1: predefined planes.
if let Some(s) = arg.as_str() { if let Some(s) = arg.as_str() {
@ -1463,6 +1472,29 @@ impl<'a> FromKclValue<'a> for super::revolve::AxisAndOrigin {
} }
} }
impl<'a> FromKclValue<'a> for super::axis_or_reference::AxisAndOrigin3d {
fn from_kcl_val(arg: &'a KclValue) -> Option<Self> {
// Case 1: predefined planes.
if let Some(s) = arg.as_str() {
return match s {
"X" | "x" => Some(Self::X),
"Y" | "y" => Some(Self::Y),
"Z" | "z" => Some(Self::Z),
"-X" | "-x" => Some(Self::NegX),
"-Y" | "-y" => Some(Self::NegY),
"-Z" | "-z" => Some(Self::NegZ),
_ => None,
};
}
// Case 2: custom planes.
let obj = arg.as_object()?;
let_field_of!(obj, custom, &KclObjectFields);
let_field_of!(custom, origin);
let_field_of!(custom, axis);
Some(Self::Custom { axis, origin })
}
}
impl<'a> FromKclValue<'a> for super::fillet::EdgeReference { impl<'a> FromKclValue<'a> for super::fillet::EdgeReference {
fn from_kcl_val(arg: &'a KclValue) -> Option<Self> { fn from_kcl_val(arg: &'a KclValue) -> Option<Self> {
let id = arg.as_uuid().map(Self::Uuid); let id = arg.as_uuid().map(Self::Uuid);
@ -1471,9 +1503,17 @@ impl<'a> FromKclValue<'a> for super::fillet::EdgeReference {
} }
} }
impl<'a> FromKclValue<'a> for super::revolve::AxisOrEdgeReference { impl<'a> FromKclValue<'a> for super::axis_or_reference::Axis2dOrEdgeReference {
fn from_kcl_val(arg: &'a KclValue) -> Option<Self> { fn from_kcl_val(arg: &'a KclValue) -> Option<Self> {
let case1 = super::revolve::AxisAndOrigin::from_kcl_val; let case1 = super::axis_or_reference::AxisAndOrigin2d::from_kcl_val;
let case2 = super::fillet::EdgeReference::from_kcl_val;
case1(arg).map(Self::Axis).or_else(|| case2(arg).map(Self::Edge))
}
}
impl<'a> FromKclValue<'a> for super::axis_or_reference::Axis3dOrEdgeReference {
fn from_kcl_val(arg: &'a KclValue) -> Option<Self> {
let case1 = super::axis_or_reference::AxisAndOrigin3d::from_kcl_val;
let case2 = super::fillet::EdgeReference::from_kcl_val; let case2 = super::fillet::EdgeReference::from_kcl_val;
case1(arg).map(Self::Axis).or_else(|| case2(arg).map(Self::Edge)) case1(arg).map(Self::Axis).or_else(|| case2(arg).map(Self::Edge))
} }
@ -1584,6 +1624,24 @@ impl<'a> FromKclValue<'a> for Sketch {
Some(value.as_ref().to_owned()) Some(value.as_ref().to_owned())
} }
} }
impl<'a> FromKclValue<'a> for Helix {
fn from_kcl_val(arg: &'a KclValue) -> Option<Self> {
let KclValue::Helix(value) = arg else {
return None;
};
Some(value.as_ref().to_owned())
}
}
impl<'a> FromKclValue<'a> for SweepPath {
fn from_kcl_val(arg: &'a KclValue) -> Option<Self> {
let case1 = Sketch::from_kcl_val;
let case2 = Helix::from_kcl_val;
case1(arg)
.map(Self::Sketch)
.or_else(|| case2(arg).map(|arg0: Helix| Self::Helix(Box::new(arg0))))
}
}
impl<'a> FromKclValue<'a> for String { impl<'a> FromKclValue<'a> for String {
fn from_kcl_val(arg: &'a KclValue) -> Option<Self> { fn from_kcl_val(arg: &'a KclValue) -> Option<Self> {
let KclValue::String { value, meta: _ } = arg else { let KclValue::String { value, meta: _ } = arg else {

View File

@ -0,0 +1,233 @@
//! Types for referencing an axis or edge.
use anyhow::Result;
use kcmc::length_unit::LengthUnit;
use kittycad_modeling_cmds::{self as kcmc};
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
use crate::{errors::KclError, std::fillet::EdgeReference};
/// A 2D axis or tagged edge.
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema)]
#[ts(export)]
#[serde(untagged)]
pub enum Axis2dOrEdgeReference {
/// 2D axis and origin.
Axis(AxisAndOrigin2d),
/// Tagged edge.
Edge(EdgeReference),
}
/// A 2D axis and origin.
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema)]
#[ts(export)]
#[serde(rename_all = "camelCase")]
pub enum AxisAndOrigin2d {
/// X-axis.
#[serde(rename = "X", alias = "x")]
X,
/// Y-axis.
#[serde(rename = "Y", alias = "y")]
Y,
/// Flip the X-axis.
#[serde(rename = "-X", alias = "-x")]
NegX,
/// Flip the Y-axis.
#[serde(rename = "-Y", alias = "-y")]
NegY,
Custom {
/// The axis.
axis: [f64; 2],
/// The origin.
origin: [f64; 2],
},
}
impl AxisAndOrigin2d {
/// Get the axis and origin.
pub fn axis_and_origin(&self) -> Result<(kcmc::shared::Point3d<f64>, kcmc::shared::Point3d<LengthUnit>), KclError> {
let (axis, origin) = match self {
AxisAndOrigin2d::X => ([1.0, 0.0, 0.0], [0.0, 0.0, 0.0]),
AxisAndOrigin2d::Y => ([0.0, 1.0, 0.0], [0.0, 0.0, 0.0]),
AxisAndOrigin2d::NegX => ([-1.0, 0.0, 0.0], [0.0, 0.0, 0.0]),
AxisAndOrigin2d::NegY => ([0.0, -1.0, 0.0], [0.0, 0.0, 0.0]),
AxisAndOrigin2d::Custom { axis, origin } => ([axis[0], axis[1], 0.0], [origin[0], origin[1], 0.0]),
};
Ok((
kcmc::shared::Point3d {
x: axis[0],
y: axis[1],
z: axis[2],
},
kcmc::shared::Point3d {
x: LengthUnit(origin[0]),
y: LengthUnit(origin[1]),
z: LengthUnit(origin[2]),
},
))
}
}
/// A 3D axis or tagged edge.
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema)]
#[ts(export)]
#[serde(untagged)]
pub enum Axis3dOrEdgeReference {
/// 3D axis and origin.
Axis(AxisAndOrigin3d),
/// Tagged edge.
Edge(EdgeReference),
}
/// A 3D axis and origin.
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema)]
#[ts(export)]
#[serde(rename_all = "camelCase")]
pub enum AxisAndOrigin3d {
/// X-axis.
#[serde(rename = "X", alias = "x")]
X,
/// Y-axis.
#[serde(rename = "Y", alias = "y")]
Y,
/// Z-axis.
#[serde(rename = "Z", alias = "z")]
Z,
/// Flip the X-axis.
#[serde(rename = "-X", alias = "-x")]
NegX,
/// Flip the Y-axis.
#[serde(rename = "-Y", alias = "-y")]
NegY,
/// Flip the Z-axis.
#[serde(rename = "-Z", alias = "-z")]
NegZ,
Custom {
/// The axis.
axis: [f64; 3],
/// The origin.
origin: [f64; 3],
},
}
impl AxisAndOrigin3d {
/// Get the axis and origin.
pub fn axis_and_origin(&self) -> Result<(kcmc::shared::Point3d<f64>, kcmc::shared::Point3d<LengthUnit>), KclError> {
let (axis, origin) = match self {
AxisAndOrigin3d::X => ([1.0, 0.0, 0.0], [0.0, 0.0, 0.0]),
AxisAndOrigin3d::Y => ([0.0, 1.0, 0.0], [0.0, 0.0, 0.0]),
AxisAndOrigin3d::Z => ([0.0, 0.0, 1.0], [0.0, 0.0, 0.0]),
AxisAndOrigin3d::NegX => ([-1.0, 0.0, 0.0], [0.0, 0.0, 0.0]),
AxisAndOrigin3d::NegY => ([0.0, -1.0, 0.0], [0.0, 0.0, 0.0]),
AxisAndOrigin3d::NegZ => ([0.0, 0.0, -1.0], [0.0, 0.0, 0.0]),
AxisAndOrigin3d::Custom { axis, origin } => {
([axis[0], axis[1], axis[2]], [origin[0], origin[1], origin[2]])
}
};
Ok((
kcmc::shared::Point3d {
x: axis[0],
y: axis[1],
z: axis[2],
},
kcmc::shared::Point3d {
x: LengthUnit(origin[0]),
y: LengthUnit(origin[1]),
z: LengthUnit(origin[2]),
},
))
}
}
#[cfg(test)]
mod tests {
use pretty_assertions::assert_eq;
use crate::std::axis_or_reference::{
Axis2dOrEdgeReference, Axis3dOrEdgeReference, AxisAndOrigin2d, AxisAndOrigin3d,
};
#[test]
fn test_deserialize_revolve_axis_2d() {
let data = Axis2dOrEdgeReference::Axis(AxisAndOrigin2d::X);
let mut str_json = serde_json::to_string(&data).unwrap();
assert_eq!(str_json, "\"X\"");
str_json = "\"Y\"".to_string();
let data: Axis2dOrEdgeReference = serde_json::from_str(&str_json).unwrap();
assert_eq!(data, Axis2dOrEdgeReference::Axis(AxisAndOrigin2d::Y));
str_json = "\"-Y\"".to_string();
let data: Axis2dOrEdgeReference = serde_json::from_str(&str_json).unwrap();
assert_eq!(data, Axis2dOrEdgeReference::Axis(AxisAndOrigin2d::NegY));
str_json = "\"-x\"".to_string();
let data: Axis2dOrEdgeReference = serde_json::from_str(&str_json).unwrap();
assert_eq!(data, Axis2dOrEdgeReference::Axis(AxisAndOrigin2d::NegX));
let data = Axis2dOrEdgeReference::Axis(AxisAndOrigin2d::Custom {
axis: [0.0, -1.0],
origin: [1.0, 0.0],
});
str_json = serde_json::to_string(&data).unwrap();
assert_eq!(str_json, r#"{"custom":{"axis":[0.0,-1.0],"origin":[1.0,0.0]}}"#);
str_json = r#"{"custom": {"axis": [0,-1], "origin": [1,2.0]}}"#.to_string();
let data: Axis2dOrEdgeReference = serde_json::from_str(&str_json).unwrap();
assert_eq!(
data,
Axis2dOrEdgeReference::Axis(AxisAndOrigin2d::Custom {
axis: [0.0, -1.0],
origin: [1.0, 2.0]
})
);
}
#[test]
fn test_deserialize_revolve_axis_3d() {
let data = Axis3dOrEdgeReference::Axis(AxisAndOrigin3d::X);
let mut str_json = serde_json::to_string(&data).unwrap();
assert_eq!(str_json, "\"X\"");
str_json = "\"Y\"".to_string();
let data: Axis3dOrEdgeReference = serde_json::from_str(&str_json).unwrap();
assert_eq!(data, Axis3dOrEdgeReference::Axis(AxisAndOrigin3d::Y));
str_json = "\"Z\"".to_string();
let data: Axis3dOrEdgeReference = serde_json::from_str(&str_json).unwrap();
assert_eq!(data, Axis3dOrEdgeReference::Axis(AxisAndOrigin3d::Z));
str_json = "\"-Y\"".to_string();
let data: Axis3dOrEdgeReference = serde_json::from_str(&str_json).unwrap();
assert_eq!(data, Axis3dOrEdgeReference::Axis(AxisAndOrigin3d::NegY));
str_json = "\"-x\"".to_string();
let data: Axis3dOrEdgeReference = serde_json::from_str(&str_json).unwrap();
assert_eq!(data, Axis3dOrEdgeReference::Axis(AxisAndOrigin3d::NegX));
str_json = "\"-z\"".to_string();
let data: Axis3dOrEdgeReference = serde_json::from_str(&str_json).unwrap();
assert_eq!(data, Axis3dOrEdgeReference::Axis(AxisAndOrigin3d::NegZ));
let data = Axis3dOrEdgeReference::Axis(AxisAndOrigin3d::Custom {
axis: [0.0, -1.0, 0.0],
origin: [1.0, 0.0, 0.0],
});
str_json = serde_json::to_string(&data).unwrap();
assert_eq!(str_json, r#"{"custom":{"axis":[0.0,-1.0,0.0],"origin":[1.0,0.0,0.0]}}"#);
str_json = r#"{"custom": {"axis": [0,-1,0], "origin": [1,2.0,0]}}"#.to_string();
let data: Axis3dOrEdgeReference = serde_json::from_str(&str_json).unwrap();
assert_eq!(
data,
Axis3dOrEdgeReference::Axis(AxisAndOrigin3d::Custom {
axis: [0.0, -1.0, 0.0],
origin: [1.0, 2.0, 0.0]
})
);
}
}

View File

@ -9,14 +9,145 @@ use serde::{Deserialize, Serialize};
use crate::{ use crate::{
errors::KclError, errors::KclError,
execution::{ExecState, KclValue, Solid}, execution::{ExecState, Helix as HelixValue, KclValue, Solid},
std::Args, std::{axis_or_reference::Axis3dOrEdgeReference, Args},
}; };
/// Data for helices. /// Data for a helix.
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema)] #[derive(Debug, Clone, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema)]
#[ts(export)] #[ts(export)]
pub struct HelixData { pub struct HelixData {
/// Number of revolutions.
pub revolutions: f64,
/// Start angle (in degrees).
#[serde(rename = "angleStart")]
pub angle_start: f64,
/// Is the helix rotation counter clockwise?
/// The default is `false`.
#[serde(default)]
pub ccw: bool,
/// Length of the helix.
pub length: f64,
/// Radius of the helix.
pub radius: f64,
/// Axis to use as mirror.
pub axis: Axis3dOrEdgeReference,
}
/// Create a helix.
pub async fn helix(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
let data: HelixData = args.get_data()?;
let helix = inner_helix(data, exec_state, args).await?;
Ok(KclValue::Helix(helix))
}
/// Create a helix.
///
/// ```no_run
/// // Create a helix around the Z axis.
/// helixPath = helix({
/// angleStart = 0,
/// ccw = true,
/// revolutions = 16,
/// length = 10,
/// radius = 5,
/// axis = 'Z',
/// })
///
///
/// // Create a spring by sweeping around the helix path.
/// springSketch = startSketchOn('YZ')
/// |> circle({ center = [0, 0], radius = 1 }, %)
/// //|> sweep({ path = helixPath }, %)
/// ```
///
/// ```no_run
/// // Create a helix around an edge.
/// /*helper001 = startSketchOn('XZ')
/// |> startProfileAt([0, 0], %)
/// |> line([0, 10], %, $edge001)
///
/// helixPath = helix({
/// angleStart = 0,
/// ccw = true,
/// revolutions = 16,
/// length = 10,
/// radius = 5,
/// axis = edge001,
/// })
///
/// // Create a spring by sweeping around the helix path.
/// springSketch = startSketchOn('XY')
/// |> circle({ center = [0, 0], radius = 1 }, %)
/// |> sweep({ path = helixPath }, %)*/
/// ```
#[stdlib {
name = "helix",
feature_tree_operation = true,
}]
async fn inner_helix(data: HelixData, exec_state: &mut ExecState, args: Args) -> Result<Box<HelixValue>, KclError> {
let id = exec_state.next_uuid();
let helix_result = Box::new(HelixValue {
value: id,
revolutions: data.revolutions,
angle_start: data.angle_start,
ccw: data.ccw,
meta: vec![args.source_range.into()],
});
if args.ctx.is_mock() {
return Ok(helix_result);
}
match data.axis {
Axis3dOrEdgeReference::Axis(axis) => {
let (axis, origin) = axis.axis_and_origin()?;
args.batch_modeling_cmd(
exec_state.next_uuid(),
ModelingCmd::from(mcmd::EntityMakeHelixFromParams {
radius: data.radius,
is_clockwise: !data.ccw,
length: LengthUnit(data.length),
revolutions: data.revolutions,
start_angle: Angle::from_degrees(data.angle_start),
axis,
center: origin,
}),
)
.await?;
}
Axis3dOrEdgeReference::Edge(_edge) => {
/*let edge_id = edge.get_engine_id(exec_state, &args)?;
args.batch_modeling_cmd(
exec_state.next_uuid(),
ModelingCmd::from(mcmd::EntityMakeHelixFromEdge {
radius: data.radius,
is_clockwise: !data.ccw,
length: LengthUnit(data.length),
revolutions: data.revolutions,
start_angle: Angle::from_degrees(data.angle_start),
edge_id,
}),
)
.await?;*/
return Err(KclError::Unimplemented(crate::errors::KclErrorDetails {
message: "Helix around edge is not yet implemented".to_string(),
source_ranges: vec![args.source_range],
}));
}
};
Ok(helix_result)
}
/// Data for helix revolutions.
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema)]
#[ts(export)]
pub struct HelixRevolutionsData {
/// Number of revolutions. /// Number of revolutions.
pub revolutions: f64, pub revolutions: f64,
/// Start angle (in degrees). /// Start angle (in degrees).
@ -32,10 +163,10 @@ pub struct HelixData {
} }
/// Create a helix on a cylinder. /// Create a helix on a cylinder.
pub async fn helix(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> { pub async fn helix_revolutions(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
let (data, solid): (HelixData, Box<Solid>) = args.get_data_and_solid()?; let (data, solid): (HelixRevolutionsData, Box<Solid>) = args.get_data_and_solid()?;
let solid = inner_helix(data, solid, exec_state, args).await?; let solid = inner_helix_revolutions(data, solid, exec_state, args).await?;
Ok(KclValue::Solid(solid)) Ok(KclValue::Solid(solid))
} }
@ -45,18 +176,18 @@ pub async fn helix(exec_state: &mut ExecState, args: Args) -> Result<KclValue, K
/// part001 = startSketchOn('XY') /// part001 = startSketchOn('XY')
/// |> circle({ center: [5, 5], radius: 10 }, %) /// |> circle({ center: [5, 5], radius: 10 }, %)
/// |> extrude(10, %) /// |> extrude(10, %)
/// |> helix({ /// |> helixRevolutions({
/// angleStart = 0, /// angleStart = 0,
/// ccw = true, /// ccw = true,
/// revolutions = 16, /// revolutions = 16,
/// }, %) /// }, %)
/// ``` /// ```
#[stdlib { #[stdlib {
name = "helix", name = "helixRevolutions",
feature_tree_operation = true, feature_tree_operation = true,
}] }]
async fn inner_helix( async fn inner_helix_revolutions(
data: HelixData, data: HelixRevolutionsData,
solid: Box<Solid>, solid: Box<Solid>,
exec_state: &mut ExecState, exec_state: &mut ExecState,
args: Args, args: Args,

View File

@ -10,7 +10,7 @@ use serde::{Deserialize, Serialize};
use crate::{ use crate::{
errors::KclError, errors::KclError,
execution::{ExecState, KclValue, Sketch, SketchSet}, execution::{ExecState, KclValue, Sketch, SketchSet},
std::{revolve::AxisOrEdgeReference, Args}, std::{axis_or_reference::Axis2dOrEdgeReference, Args},
}; };
/// Data for a mirror. /// Data for a mirror.
@ -19,7 +19,7 @@ use crate::{
#[serde(rename_all = "camelCase")] #[serde(rename_all = "camelCase")]
pub struct Mirror2dData { pub struct Mirror2dData {
/// Axis to use as mirror. /// Axis to use as mirror.
pub axis: AxisOrEdgeReference, pub axis: Axis2dOrEdgeReference,
} }
/// Mirror a sketch. /// Mirror a sketch.
@ -117,7 +117,7 @@ async fn inner_mirror_2d(
} }
match data.axis { match data.axis {
AxisOrEdgeReference::Axis(axis) => { Axis2dOrEdgeReference::Axis(axis) => {
let (axis, origin) = axis.axis_and_origin()?; let (axis, origin) = axis.axis_and_origin()?;
args.batch_modeling_cmd( args.batch_modeling_cmd(
@ -130,7 +130,7 @@ async fn inner_mirror_2d(
) )
.await?; .await?;
} }
AxisOrEdgeReference::Edge(edge) => { Axis2dOrEdgeReference::Edge(edge) => {
let edge_id = edge.get_engine_id(exec_state, &args)?; let edge_id = edge.get_engine_id(exec_state, &args)?;
args.batch_modeling_cmd( args.batch_modeling_cmd(

View File

@ -4,6 +4,7 @@ pub mod appearance;
pub mod args; pub mod args;
pub mod array; pub mod array;
pub mod assert; pub mod assert;
pub mod axis_or_reference;
pub mod chamfer; pub mod chamfer;
pub mod convert; pub mod convert;
pub mod extrude; pub mod extrude;
@ -114,6 +115,7 @@ lazy_static! {
Box::new(crate::std::fillet::GetNextAdjacentEdge), Box::new(crate::std::fillet::GetNextAdjacentEdge),
Box::new(crate::std::fillet::GetPreviousAdjacentEdge), Box::new(crate::std::fillet::GetPreviousAdjacentEdge),
Box::new(crate::std::helix::Helix), Box::new(crate::std::helix::Helix),
Box::new(crate::std::helix::HelixRevolutions),
Box::new(crate::std::shell::Shell), Box::new(crate::std::shell::Shell),
Box::new(crate::std::shell::Hollow), Box::new(crate::std::shell::Hollow),
Box::new(crate::std::revolve::Revolve), Box::new(crate::std::revolve::Revolve),

View File

@ -10,11 +10,7 @@ use serde::{Deserialize, Serialize};
use crate::{ use crate::{
errors::{KclError, KclErrorDetails}, errors::{KclError, KclErrorDetails},
execution::{ExecState, KclValue, Sketch, Solid}, execution::{ExecState, KclValue, Sketch, Solid},
std::{ std::{axis_or_reference::Axis2dOrEdgeReference, extrude::do_post_extrude, fillet::default_tolerance, Args},
extrude::do_post_extrude,
fillet::{default_tolerance, EdgeReference},
Args,
},
}; };
/// Data for revolution surfaces. /// Data for revolution surfaces.
@ -26,74 +22,12 @@ pub struct RevolveData {
#[schemars(range(min = -360.0, max = 360.0))] #[schemars(range(min = -360.0, max = 360.0))]
pub angle: Option<f64>, pub angle: Option<f64>,
/// Axis of revolution. /// Axis of revolution.
pub axis: AxisOrEdgeReference, pub axis: Axis2dOrEdgeReference,
/// Tolerance for the revolve operation. /// Tolerance for the revolve operation.
#[serde(default)] #[serde(default)]
pub tolerance: Option<f64>, pub tolerance: Option<f64>,
} }
/// Axis or tagged edge.
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema)]
#[ts(export)]
#[serde(untagged)]
pub enum AxisOrEdgeReference {
/// Axis and origin.
Axis(AxisAndOrigin),
/// Tagged edge.
Edge(EdgeReference),
}
/// Axis and origin.
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema)]
#[ts(export)]
#[serde(rename_all = "camelCase")]
pub enum AxisAndOrigin {
/// X-axis.
#[serde(rename = "X", alias = "x")]
X,
/// Y-axis.
#[serde(rename = "Y", alias = "y")]
Y,
/// Flip the X-axis.
#[serde(rename = "-X", alias = "-x")]
NegX,
/// Flip the Y-axis.
#[serde(rename = "-Y", alias = "-y")]
NegY,
Custom {
/// The axis.
axis: [f64; 2],
/// The origin.
origin: [f64; 2],
},
}
impl AxisAndOrigin {
/// Get the axis and origin.
pub fn axis_and_origin(&self) -> Result<(kcmc::shared::Point3d<f64>, kcmc::shared::Point3d<LengthUnit>), KclError> {
let (axis, origin) = match self {
AxisAndOrigin::X => ([1.0, 0.0, 0.0], [0.0, 0.0, 0.0]),
AxisAndOrigin::Y => ([0.0, 1.0, 0.0], [0.0, 0.0, 0.0]),
AxisAndOrigin::NegX => ([-1.0, 0.0, 0.0], [0.0, 0.0, 0.0]),
AxisAndOrigin::NegY => ([0.0, -1.0, 0.0], [0.0, 0.0, 0.0]),
AxisAndOrigin::Custom { axis, origin } => ([axis[0], axis[1], 0.0], [origin[0], origin[1], 0.0]),
};
Ok((
kcmc::shared::Point3d {
x: axis[0],
y: axis[1],
z: axis[2],
},
kcmc::shared::Point3d {
x: LengthUnit(origin[0]),
y: LengthUnit(origin[1]),
z: LengthUnit(origin[2]),
},
))
}
}
/// Revolve a sketch around an axis. /// Revolve a sketch around an axis.
pub async fn revolve(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> { pub async fn revolve(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
let (data, sketch): (RevolveData, Sketch) = args.get_data_and_sketch()?; let (data, sketch): (RevolveData, Sketch) = args.get_data_and_sketch()?;
@ -266,7 +200,7 @@ async fn inner_revolve(
let id = exec_state.next_uuid(); let id = exec_state.next_uuid();
match data.axis { match data.axis {
AxisOrEdgeReference::Axis(axis) => { Axis2dOrEdgeReference::Axis(axis) => {
let (axis, origin) = axis.axis_and_origin()?; let (axis, origin) = axis.axis_and_origin()?;
args.batch_modeling_cmd( args.batch_modeling_cmd(
id, id,
@ -281,7 +215,7 @@ async fn inner_revolve(
) )
.await?; .await?;
} }
AxisOrEdgeReference::Edge(edge) => { Axis2dOrEdgeReference::Edge(edge) => {
let edge_id = edge.get_engine_id(exec_state, &args)?; let edge_id = edge.get_engine_id(exec_state, &args)?;
args.batch_modeling_cmd( args.batch_modeling_cmd(
id, id,
@ -298,47 +232,3 @@ async fn inner_revolve(
do_post_extrude(sketch, 0.0, exec_state, args).await do_post_extrude(sketch, 0.0, exec_state, args).await
} }
#[cfg(test)]
mod tests {
use pretty_assertions::assert_eq;
use crate::std::revolve::{AxisAndOrigin, AxisOrEdgeReference};
#[test]
fn test_deserialize_revolve_axis() {
let data = AxisOrEdgeReference::Axis(AxisAndOrigin::X);
let mut str_json = serde_json::to_string(&data).unwrap();
assert_eq!(str_json, "\"X\"");
str_json = "\"Y\"".to_string();
let data: AxisOrEdgeReference = serde_json::from_str(&str_json).unwrap();
assert_eq!(data, AxisOrEdgeReference::Axis(AxisAndOrigin::Y));
str_json = "\"-Y\"".to_string();
let data: AxisOrEdgeReference = serde_json::from_str(&str_json).unwrap();
assert_eq!(data, AxisOrEdgeReference::Axis(AxisAndOrigin::NegY));
str_json = "\"-x\"".to_string();
let data: AxisOrEdgeReference = serde_json::from_str(&str_json).unwrap();
assert_eq!(data, AxisOrEdgeReference::Axis(AxisAndOrigin::NegX));
let data = AxisOrEdgeReference::Axis(AxisAndOrigin::Custom {
axis: [0.0, -1.0],
origin: [1.0, 0.0],
});
str_json = serde_json::to_string(&data).unwrap();
assert_eq!(str_json, r#"{"custom":{"axis":[0.0,-1.0],"origin":[1.0,0.0]}}"#);
str_json = r#"{"custom": {"axis": [0,-1], "origin": [1,2.0]}}"#.to_string();
let data: AxisOrEdgeReference = serde_json::from_str(&str_json).unwrap();
assert_eq!(
data,
AxisOrEdgeReference::Axis(AxisAndOrigin::Custom {
axis: [0.0, -1.0],
origin: [1.0, 2.0]
})
);
}
}

View File

@ -9,16 +9,25 @@ use serde::{Deserialize, Serialize};
use crate::{ use crate::{
errors::KclError, errors::KclError,
execution::{ExecState, KclValue, Sketch, Solid}, execution::{ExecState, Helix, KclValue, Sketch, Solid},
std::{extrude::do_post_extrude, fillet::default_tolerance, Args}, std::{extrude::do_post_extrude, fillet::default_tolerance, Args},
}; };
/// A path to sweep along.
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema)]
#[ts(export)]
#[serde(untagged)]
pub enum SweepPath {
Sketch(Sketch),
Helix(Box<Helix>),
}
/// Data for a sweep. /// Data for a sweep.
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema)] #[derive(Debug, Clone, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema)]
#[ts(export)] #[ts(export)]
pub struct SweepData { pub struct SweepData {
/// The path to sweep along. /// The path to sweep along.
pub path: Sketch, pub path: SweepPath,
/// If true, the sweep will be broken up into sub-sweeps (extrusions, revolves, sweeps) based on the trajectory path components. /// If true, the sweep will be broken up into sub-sweeps (extrusions, revolves, sweeps) based on the trajectory path components.
pub sectional: Option<bool>, pub sectional: Option<bool>,
/// Tolerance for the sweep operation. /// Tolerance for the sweep operation.
@ -77,6 +86,26 @@ pub async fn sweep(exec_state: &mut ExecState, args: Args) -> Result<KclValue, K
/// path: sweepPath, /// 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 = 16,
/// length = 10,
/// radius = 5,
/// axis = 'Z',
/// })
///
///
/// // Create a spring by sweeping around the helix path.
/// springSketch = startSketchOn('YZ')
/// |> circle({ center = [0, 0], radius = 1 }, %)
/// //|> sweep({ path = helixPath }, %)
/// ```
#[stdlib { #[stdlib {
name = "sweep", name = "sweep",
feature_tree_operation = true, feature_tree_operation = true,
@ -92,7 +121,10 @@ async fn inner_sweep(
id, id,
ModelingCmd::from(mcmd::Sweep { ModelingCmd::from(mcmd::Sweep {
target: sketch.id.into(), target: sketch.id.into(),
trajectory: data.path.id.into(), trajectory: match data.path {
SweepPath::Sketch(sketch) => sketch.id.into(),
SweepPath::Helix(helix) => helix.value.into(),
},
sectional: data.sectional.unwrap_or(false), sectional: data.sectional.unwrap_or(false),
tolerance: LengthUnit(data.tolerance.unwrap_or(default_tolerance(&args.ctx.settings.units))), tolerance: LengthUnit(data.tolerance.unwrap_or(default_tolerance(&args.ctx.settings.units))),
}), }),

View File

@ -1,13 +1,14 @@
--- ---
source: kcl/src/simulation_tests.rs source: kcl/src/simulation_tests.rs
description: Result of parsing helix_ccw.kcl description: Result of parsing helix_ccw.kcl
snapshot_kind: text
--- ---
{ {
"Ok": { "Ok": {
"body": [ "body": [
{ {
"declaration": { "declaration": {
"end": 188, "end": 199,
"id": { "id": {
"end": 7, "end": 7,
"name": "part001", "name": "part001",
@ -151,90 +152,90 @@ description: Result of parsing helix_ccw.kcl
{ {
"arguments": [ "arguments": [
{ {
"end": 184, "end": 195,
"properties": [ "properties": [
{ {
"end": 135, "end": 146,
"key": { "key": {
"end": 130, "end": 141,
"name": "revolutions", "name": "revolutions",
"start": 119, "start": 130,
"type": "Identifier" "type": "Identifier"
}, },
"start": 119, "start": 130,
"type": "ObjectProperty", "type": "ObjectProperty",
"value": { "value": {
"end": 135, "end": 146,
"raw": "16", "raw": "16",
"start": 133, "start": 144,
"type": "Literal", "type": "Literal",
"type": "Literal", "type": "Literal",
"value": 16.0 "value": 16.0
} }
}, },
{ {
"end": 158, "end": 169,
"key": { "key": {
"end": 154, "end": 165,
"name": "angleStart", "name": "angleStart",
"start": 144, "start": 155,
"type": "Identifier" "type": "Identifier"
}, },
"start": 144, "start": 155,
"type": "ObjectProperty", "type": "ObjectProperty",
"value": { "value": {
"end": 158, "end": 169,
"raw": "0", "raw": "0",
"start": 157, "start": 168,
"type": "Literal", "type": "Literal",
"type": "Literal", "type": "Literal",
"value": 0.0 "value": 0.0
} }
}, },
{ {
"end": 177, "end": 188,
"key": { "key": {
"end": 170, "end": 181,
"name": "ccw", "name": "ccw",
"start": 167, "start": 178,
"type": "Identifier" "type": "Identifier"
}, },
"start": 167, "start": 178,
"type": "ObjectProperty", "type": "ObjectProperty",
"value": { "value": {
"end": 177, "end": 188,
"raw": "true", "raw": "true",
"start": 173, "start": 184,
"type": "Literal", "type": "Literal",
"type": "Literal", "type": "Literal",
"value": true "value": true
} }
} }
], ],
"start": 110, "start": 121,
"type": "ObjectExpression", "type": "ObjectExpression",
"type": "ObjectExpression" "type": "ObjectExpression"
}, },
{ {
"end": 187, "end": 198,
"start": 186, "start": 197,
"type": "PipeSubstitution", "type": "PipeSubstitution",
"type": "PipeSubstitution" "type": "PipeSubstitution"
} }
], ],
"callee": { "callee": {
"end": 109, "end": 120,
"name": "helix", "name": "helixRevolutions",
"start": 104, "start": 104,
"type": "Identifier" "type": "Identifier"
}, },
"end": 188, "end": 199,
"start": 104, "start": 104,
"type": "CallExpression", "type": "CallExpression",
"type": "CallExpression" "type": "CallExpression"
} }
], ],
"end": 188, "end": 199,
"start": 10, "start": 10,
"type": "PipeExpression", "type": "PipeExpression",
"type": "PipeExpression" "type": "PipeExpression"
@ -242,14 +243,14 @@ description: Result of parsing helix_ccw.kcl
"start": 0, "start": 0,
"type": "VariableDeclarator" "type": "VariableDeclarator"
}, },
"end": 188, "end": 199,
"kind": "const", "kind": "const",
"start": 0, "start": 0,
"type": "VariableDeclaration", "type": "VariableDeclaration",
"type": "VariableDeclaration" "type": "VariableDeclaration"
} }
], ],
"end": 189, "end": 200,
"start": 0 "start": 0
} }
} }

View File

@ -1,7 +1,7 @@
part001 = startSketchOn('XY') part001 = startSketchOn('XY')
|> circle({ center = [5, 5], radius = 10 }, %) |> circle({ center = [5, 5], radius = 10 }, %)
|> extrude(10, %) |> extrude(10, %)
|> helix({ |> helixRevolutions({
revolutions = 16, revolutions = 16,
angleStart = 0, angleStart = 0,
ccw = true ccw = true

View File

@ -53,23 +53,23 @@ snapshot_kind: text
"labeledArgs": { "labeledArgs": {
"data": { "data": {
"sourceRange": [ "sourceRange": [
110, 121,
184, 195,
0 0
] ]
}, },
"solid": { "solid": {
"sourceRange": [ "sourceRange": [
186, 197,
187, 198,
0 0
] ]
} }
}, },
"name": "helix", "name": "helixRevolutions",
"sourceRange": [ "sourceRange": [
104, 104,
188, 199,
0 0
], ],
"type": "StdLibCall", "type": "StdLibCall",

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 132 KiB

After

Width:  |  Height:  |  Size: 182 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 132 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 182 KiB

File diff suppressed because it is too large Load Diff

View File

@ -2,8 +2,8 @@ triangleHeight = 200
plumbusLen = 100 plumbusLen = 100
radius = 80 radius = 80
circ = { circ = {
angle_start = 0, angleStart = 0,
angle_end = 360, angleEnd = 360,
radius = radius radius = radius
} }

View File

@ -8,16 +8,16 @@ snapshot_kind: text
"labeledArgs": { "labeledArgs": {
"data": { "data": {
"sourceRange": [ "sourceRange": [
154, 152,
158, 156,
0 0
] ]
} }
}, },
"name": "startSketchOn", "name": "startSketchOn",
"sourceRange": [ "sourceRange": [
140, 138,
159, 157,
0 0
], ],
"type": "StdLibCall", "type": "StdLibCall",
@ -27,23 +27,23 @@ snapshot_kind: text
"labeledArgs": { "labeledArgs": {
"length": { "length": {
"sourceRange": [ "sourceRange": [
389, 387,
401,
0
]
},
"sketch_set": {
"sourceRange": [
403, 403,
0 404,
]
},
"sketch_set": {
"sourceRange": [
405,
406,
0 0
] ]
} }
}, },
"name": "extrude", "name": "extrude",
"sourceRange": [ "sourceRange": [
381, 379,
407, 405,
0 0
], ],
"type": "StdLibCall", "type": "StdLibCall",
@ -53,15 +53,15 @@ snapshot_kind: text
"type": "UserDefinedFunctionCall", "type": "UserDefinedFunctionCall",
"name": "circl", "name": "circl",
"functionSourceRange": [ "functionSourceRange": [
417, 415,
567, 565,
0 0
], ],
"unlabeledArg": null, "unlabeledArg": null,
"labeledArgs": {}, "labeledArgs": {},
"sourceRange": [ "sourceRange": [
574, 572,
588, 586,
0 0
] ]
}, },
@ -69,23 +69,23 @@ snapshot_kind: text
"labeledArgs": { "labeledArgs": {
"data": { "data": {
"sourceRange": [ "sourceRange": [
452, 450,
453, 451,
0 0
] ]
}, },
"tag": { "tag": {
"sourceRange": [ "sourceRange": [
455, 453,
459, 457,
0 0
] ]
} }
}, },
"name": "startSketchOn", "name": "startSketchOn",
"sourceRange": [ "sourceRange": [
438, 436,
460, 458,
0 0
], ],
"type": "StdLibCall", "type": "StdLibCall",
@ -98,23 +98,23 @@ snapshot_kind: text
"labeledArgs": { "labeledArgs": {
"length": { "length": {
"sourceRange": [ "sourceRange": [
616, 614,
624,
0
]
},
"sketch_set": {
"sourceRange": [
626, 626,
0 627,
]
},
"sketch_set": {
"sourceRange": [
628,
629,
0 0
] ]
} }
}, },
"name": "extrude", "name": "extrude",
"sourceRange": [ "sourceRange": [
608, 606,
630, 628,
0 0
], ],
"type": "StdLibCall", "type": "StdLibCall",
@ -124,23 +124,23 @@ snapshot_kind: text
"labeledArgs": { "labeledArgs": {
"data": { "data": {
"sourceRange": [ "sourceRange": [
643, 641,
763, 761,
0 0
] ]
}, },
"solid": { "solid": {
"sourceRange": [ "sourceRange": [
765, 763,
766, 764,
0 0
] ]
} }
}, },
"name": "fillet", "name": "fillet",
"sourceRange": [ "sourceRange": [
636, 634,
767, 765,
0 0
], ],
"type": "StdLibCall", "type": "StdLibCall",
@ -150,15 +150,15 @@ snapshot_kind: text
"type": "UserDefinedFunctionCall", "type": "UserDefinedFunctionCall",
"name": "circl", "name": "circl",
"functionSourceRange": [ "functionSourceRange": [
417, 415,
567, 565,
0 0
], ],
"unlabeledArg": null, "unlabeledArg": null,
"labeledArgs": {}, "labeledArgs": {},
"sourceRange": [ "sourceRange": [
773, 771,
786, 784,
0 0
] ]
}, },
@ -166,23 +166,23 @@ snapshot_kind: text
"labeledArgs": { "labeledArgs": {
"data": { "data": {
"sourceRange": [ "sourceRange": [
452, 450,
453, 451,
0 0
] ]
}, },
"tag": { "tag": {
"sourceRange": [ "sourceRange": [
455, 453,
459, 457,
0 0
] ]
} }
}, },
"name": "startSketchOn", "name": "startSketchOn",
"sourceRange": [ "sourceRange": [
438, 436,
460, 458,
0 0
], ],
"type": "StdLibCall", "type": "StdLibCall",
@ -195,23 +195,23 @@ snapshot_kind: text
"labeledArgs": { "labeledArgs": {
"length": { "length": {
"sourceRange": [ "sourceRange": [
814, 812,
824, 822,
0 0
] ]
}, },
"sketch_set": { "sketch_set": {
"sourceRange": [ "sourceRange": [
826, 824,
827, 825,
0 0
] ]
} }
}, },
"name": "extrude", "name": "extrude",
"sourceRange": [ "sourceRange": [
806, 804,
828, 826,
0 0
], ],
"type": "StdLibCall", "type": "StdLibCall",
@ -221,23 +221,23 @@ snapshot_kind: text
"labeledArgs": { "labeledArgs": {
"data": { "data": {
"sourceRange": [ "sourceRange": [
841, 839,
961, 959,
0 0
] ]
}, },
"solid": { "solid": {
"sourceRange": [ "sourceRange": [
963, 961,
964, 962,
0 0
] ]
} }
}, },
"name": "fillet", "name": "fillet",
"sourceRange": [ "sourceRange": [
834, 832,
965, 963,
0 0
], ],
"type": "StdLibCall", "type": "StdLibCall",

View File

@ -4,6 +4,6 @@ const height = 3
const body = startSketchOn('XY') const body = startSketchOn('XY')
|> startProfileAt([center[0]+radius, center[1]], %) |> startProfileAt([center[0]+radius, center[1]], %)
|> arc({angle_end: 360, angle_start: 0, radius: radius}, %) |> arc({angleEnd: 360, angleStart: 0, radius: radius}, %)
|> close(%) |> close(%)
|> extrude(height, %) |> extrude(height, %)

View File

@ -12,9 +12,9 @@ const extrude000 = extrude(1.0, sketch000)
const plane005 = { const plane005 = {
plane: { plane: {
origin: [0.0, 0.0, 1.0], origin: [0.0, 0.0, 1.0],
x_axis: [0.707107, 0.707107, 0.0], xAxis: [0.707107, 0.707107, 0.0],
y_axis: [-0.0, 0.0, 1.0], yAxis: [-0.0, 0.0, 1.0],
z_axis: [0.707107, -0.707107, 0.0] zAxis: [0.707107, -0.707107, 0.0]
} }
} }

View File

@ -28,9 +28,9 @@ fn rectShape = (pos, w, l) => {
const bracketPlane = { const bracketPlane = {
plane: { plane: {
origin: { x: 0, y: length / 2 + thk, z: 0 }, origin: { x: 0, y: length / 2 + thk, z: 0 },
x_axis: { x: 1, y: 0, z: 0 }, xAxis: { x: 1, y: 0, z: 0 },
y_axis: { x: 0, y: 0, z: 1 }, yAxis: { x: 0, y: 0, z: 1 },
z_axis: { x: 0, y: -1, z: 0 } zAxis: { x: 0, y: -1, z: 0 }
} }
} }

View File

@ -28,9 +28,9 @@ fn rectShape = (pos, w, l) => {
const bracketPlane = { const bracketPlane = {
plane: { plane: {
origin: { x: 0, y: length / 2 + thk, z: 0 }, origin: { x: 0, y: length / 2 + thk, z: 0 },
x_axis: { x: 1, y: 0, z: 0 }, xAxis: { x: 1, y: 0, z: 0 },
y_axis: { x: 0, y: 0, z: 1 }, yAxis: { x: 0, y: 0, z: 1 },
z_axis: { x: 0, y: -1, z: 0 } zAxis: { x: 0, y: -1, z: 0 }
} }
} }
@ -67,9 +67,9 @@ const bracketBody = bs
const tabPlane = { const tabPlane = {
plane: { plane: {
origin: { x: 0, y: 0, z: depth + thk }, origin: { x: 0, y: 0, z: depth + thk },
x_axis: { x: 1, y: 0, z: 0 }, xAxis: { x: 1, y: 0, z: 0 },
y_axis: { x: 0, y: 1, z: 0 }, yAxis: { x: 0, y: 1, z: 0 },
z_axis: { x: 0, y: 0, z: 1 } zAxis: { x: 0, y: 0, z: 1 }
} }
} }
@ -133,9 +133,9 @@ const tabsL = startSketchOn(tabPlane)
const retPlane = { const retPlane = {
plane: { plane: {
origin: { x: -width / 2 + 20, y: 0, z: 0 }, origin: { x: -width / 2 + 20, y: 0, z: 0 },
x_axis: { x: 0, y: 1, z: 0 }, xAxis: { x: 0, y: 1, z: 0 },
y_axis: { x: 0, y: 0, z: 1 }, yAxis: { x: 0, y: 0, z: 1 },
z_axis: { x: 1, y: 0, z: 0 } zAxis: { x: 1, y: 0, z: 0 }
} }
} }

View File

@ -1,4 +1,4 @@
const part001 = startSketchOn('XY') const part001 = startSketchOn('XY')
|> circle({ center: [5, 5], radius: 10 }, %) |> circle({ center: [5, 5], radius: 10 }, %)
|> extrude(10, %) |> extrude(10, %)
|> helix({revolutions: 16, angle_start: 0}, %) |> helixRevolutions({revolutions = 16, angleStart = 0}, %)

View File

@ -1,4 +1,4 @@
const part001 = startSketchOn('XY') const part001 = startSketchOn('XY')
|> circle({ center: [5, 5], radius: 10 }, %) |> circle({ center: [5, 5], radius: 10 }, %)
|> extrude(-10, %) |> extrude(-10, %)
|> helix({revolutions: 16, angle_start: 0}, %) |> helixRevolutions({revolutions = 16, angleStart = 0}, %)

View File

@ -1,4 +1,4 @@
const part001 = startSketchOn('XY') const part001 = startSketchOn('XY')
|> circle({ center: [5, 5], radius: 10 }, %) |> circle({ center: [5, 5], radius: 10 }, %)
|> extrude(10, %) |> extrude(10, %)
|> helix({revolutions: 16, angle_start: 0, length: 3}, %) |> helixRevolutions({revolutions = 16, angleStart = 0, length = 3}, %)

View File

@ -2,13 +2,13 @@
const plane94894440791888 = { const plane94894440791888 = {
plane: { plane: {
origin: [0.005000000000000001, 0.01, -0.005], origin: [0.005000000000000001, 0.01, -0.005],
x_axis: [ xAxis: [
0.9285064634886234, 0.9285064634886234,
0.37131623619207604, 0.37131623619207604,
0.0 0.0
], ],
y_axis: [-0.0, 0.0, 1.0], yAxis: [-0.0, 0.0, 1.0],
z_axis: [ zAxis: [
0.37131623619207604, 0.37131623619207604,
-0.9285064634886234, -0.9285064634886234,
0.0 0.0

View File

@ -2,13 +2,13 @@
const plane94894440791888 = { const plane94894440791888 = {
plane: { plane: {
origin: [0.005000000000000001, 0.01, -0.005], origin: [0.005000000000000001, 0.01, -0.005],
x_axis: [ xAxis: [
0.9285064634886234, 0.9285064634886234,
0.37131623619207604, 0.37131623619207604,
0.0 0.0
], ],
y_axis: [-0.0, 0.0, 1.0], yAxis: [-0.0, 0.0, 1.0],
z_axis: [ zAxis: [
0.37131623619207604, 0.37131623619207604,
-0.9285064634886234, -0.9285064634886234,
0.0 0.0

View File

@ -13,8 +13,8 @@ const sketch001 = startSketchOn('XZ')
|> startProfileAt([0, depth - templateGap], %) |> startProfileAt([0, depth - templateGap], %)
|> xLine(length001, %, $seg01) |> xLine(length001, %, $seg01)
|> arc({ |> arc({
angle_end: 0, angleEnd: 0,
angle_start: 90, angleStart: 90,
radius: radius - templateGap radius: radius - templateGap
}, %) }, %)
|> yLineTo(-templateGap * 2 - (templateDiameter / 2), %, $seg05) |> yLineTo(-templateGap * 2 - (templateDiameter / 2), %, $seg05)
@ -26,8 +26,8 @@ const sketch001 = startSketchOn('XZ')
|> xLine(segLen(seg04, %), %) |> xLine(segLen(seg04, %), %)
|> yLine(segLen(seg05, %), %) |> yLine(segLen(seg05, %), %)
|> arc({ |> arc({
angle_end: 90, angleEnd: 90,
angle_start: 180, angleStart: 180,
radius: radius - templateGap radius: radius - templateGap
}, %) }, %)
|> lineTo([profileStartX(%), profileStartY(%)], %) |> lineTo([profileStartX(%), profileStartY(%)], %)

View File

@ -285,7 +285,7 @@ async fn optional_params() {
fn other_circle = (pos, radius, tag?) => { fn other_circle = (pos, radius, tag?) => {
sg = startSketchOn('XY') sg = startSketchOn('XY')
|> startProfileAt(pos, %) |> startProfileAt(pos, %)
|> arc({angle_end: 360, angle_start: 0, radius: radius}, %) |> arc({angleEnd: 360, angleStart: 0, radius: radius}, %)
|> close(%) |> close(%)
|> extrude(2, %) |> extrude(2, %)
@ -1160,8 +1160,8 @@ async fn kcl_test_plumbus_fillets() {
sg = startSketchOn(ext, face) sg = startSketchOn(ext, face)
|> startProfileAt([pos[0] + radius, pos[1]], %) |> startProfileAt([pos[0] + radius, pos[1]], %)
|> arc({ |> arc({
angle_end: 360, angleEnd: 360,
angle_start: 0, angleStart: 0,
radius: radius radius: radius
}, %, $arc1) }, %, $arc1)
|> close(%) |> close(%)
@ -1235,9 +1235,9 @@ async fn kcl_test_member_expression_in_params() {
y: originStart[1], y: originStart[1],
z: originStart[2], z: originStart[2],
}, },
x_axis: { x: 0, y: 0, z: -1 }, xAxis: { x: 0, y: 0, z: -1 },
y_axis: { x: 1, y: 0, z: 0 }, yAxis: { x: 1, y: 0, z: 0 },
z_axis: { x: 0, y: 1, z: 0 } zAxis: { x: 0, y: 1, z: 0 }
} }
}) })
|> circle({ center: [0, 0], radius: capDia / 2 }, %) |> circle({ center: [0, 0], radius: capDia / 2 }, %)
@ -1732,8 +1732,8 @@ async fn kcl_test_arc_error_same_start_end() {
let code = r#"startSketchOn('XY') let code = r#"startSketchOn('XY')
|> startProfileAt([10, 0], %) |> startProfileAt([10, 0], %)
|> arc({ |> arc({
angle_start: 180, angleStart: 180,
angle_end: 180, angleEnd: 180,
radius: 1.5 radius: 1.5
}, %) }, %)
|> close(%) |> close(%)
@ -1749,7 +1749,7 @@ async fn kcl_test_arc_error_same_start_end() {
assert!(result.is_err()); assert!(result.is_err());
assert_eq!( assert_eq!(
result.err().unwrap().to_string(), result.err().unwrap().to_string(),
r#"type: KclErrorDetails { source_ranges: [SourceRange([57, 140, 0])], message: "Arc start and end angles must be different" }"# r#"type: KclErrorDetails { source_ranges: [SourceRange([57, 138, 0])], message: "Arc start and end angles must be different" }"#
); );
} }