Patterning a pattern should always work (#2680)
* patterning a pattern should alwayus work Signed-off-by: Jess Frazelle <github@jessfraz.com> * add images; Signed-off-by: Jess Frazelle <github@jessfraz.com> * std lib Signed-off-by: Jess Frazelle <github@jessfraz.com> * bu,mp Signed-off-by: Jess Frazelle <github@jessfraz.com> * fix tests Signed-off-by: Jess Frazelle <github@jessfraz.com> * update lock Signed-off-by: Jess Frazelle <github@jessfraz.com> * bump Signed-off-by: Jess Frazelle <github@jessfraz.com> * fixes Signed-off-by: Jess Frazelle <github@jessfraz.com> * fixes Signed-off-by: Jess Frazelle <github@jessfraz.com> --------- Signed-off-by: Jess Frazelle <github@jessfraz.com>
This commit is contained in:
@ -9,7 +9,7 @@ A circular pattern on a 2D sketch.
|
||||
|
||||
|
||||
```js
|
||||
patternCircular2d(data: CircularPattern2dData, sketch_group: SketchGroup) -> [SketchGroup]
|
||||
patternCircular2d(data: CircularPattern2dData, sketch_group_set: SketchGroupSet) -> [SketchGroup]
|
||||
```
|
||||
|
||||
### Examples
|
||||
@ -48,7 +48,7 @@ const example = extrude(1, exampleSketch)
|
||||
rotateDuplicates: string,
|
||||
}
|
||||
```
|
||||
* `sketch_group`: `SketchGroup` - A sketch group is a collection of paths. (REQUIRED)
|
||||
* `sketch_group_set`: `SketchGroupSet` - A sketch group or a group of sketch groups. (REQUIRED)
|
||||
```js
|
||||
{
|
||||
// The plane id or face id of the sketch group.
|
||||
@ -129,6 +129,7 @@ const example = extrude(1, exampleSketch)
|
||||
// The to point.
|
||||
to: [number, number],
|
||||
},
|
||||
type: "sketchGroup",
|
||||
// The paths in the sketch group.
|
||||
value: [{
|
||||
// The from point.
|
||||
@ -212,6 +213,9 @@ const example = extrude(1, exampleSketch)
|
||||
y: number,
|
||||
z: number,
|
||||
},
|
||||
} |
|
||||
{
|
||||
type: "sketchGroups",
|
||||
}
|
||||
```
|
||||
|
||||
|
@ -9,7 +9,7 @@ A circular pattern on a 3D model.
|
||||
|
||||
|
||||
```js
|
||||
patternCircular3d(data: CircularPattern3dData, extrude_group: ExtrudeGroup) -> [ExtrudeGroup]
|
||||
patternCircular3d(data: CircularPattern3dData, extrude_group_set: ExtrudeGroupSet) -> [ExtrudeGroup]
|
||||
```
|
||||
|
||||
### Examples
|
||||
@ -47,7 +47,7 @@ const example = extrude(-5, exampleSketch)
|
||||
rotateDuplicates: string,
|
||||
}
|
||||
```
|
||||
* `extrude_group`: `ExtrudeGroup` - An extrude group is a collection of extrude surfaces. (REQUIRED)
|
||||
* `extrude_group_set`: `ExtrudeGroupSet` - A extrude group or a group of extrude groups. (REQUIRED)
|
||||
```js
|
||||
{
|
||||
// The id of the extrusion end cap
|
||||
@ -127,6 +127,7 @@ const example = extrude(-5, exampleSketch)
|
||||
}],
|
||||
// The id of the extrusion start cap
|
||||
startCapId: uuid,
|
||||
type: "extrudeGroup",
|
||||
// The extrude surfaces.
|
||||
value: [{
|
||||
// The face id for the extrude plane.
|
||||
@ -176,6 +177,9 @@ const example = extrude(-5, exampleSketch)
|
||||
y: number,
|
||||
z: number,
|
||||
},
|
||||
} |
|
||||
{
|
||||
type: "extrudeGroups",
|
||||
}
|
||||
```
|
||||
|
||||
|
@ -9,7 +9,7 @@ A linear pattern on a 3D model.
|
||||
|
||||
|
||||
```js
|
||||
patternLinear3d(data: LinearPattern3dData, extrude_group: ExtrudeGroup) -> [ExtrudeGroup]
|
||||
patternLinear3d(data: LinearPattern3dData, extrude_group_set: ExtrudeGroupSet) -> [ExtrudeGroup]
|
||||
```
|
||||
|
||||
### Examples
|
||||
@ -45,7 +45,7 @@ const example = extrude(1, exampleSketch)
|
||||
repetitions: number,
|
||||
}
|
||||
```
|
||||
* `extrude_group`: `ExtrudeGroup` - An extrude group is a collection of extrude surfaces. (REQUIRED)
|
||||
* `extrude_group_set`: `ExtrudeGroupSet` - A extrude group or a group of extrude groups. (REQUIRED)
|
||||
```js
|
||||
{
|
||||
// The id of the extrusion end cap
|
||||
@ -125,6 +125,7 @@ const example = extrude(1, exampleSketch)
|
||||
}],
|
||||
// The id of the extrusion start cap
|
||||
startCapId: uuid,
|
||||
type: "extrudeGroup",
|
||||
// The extrude surfaces.
|
||||
value: [{
|
||||
// The face id for the extrude plane.
|
||||
@ -174,6 +175,9 @@ const example = extrude(1, exampleSketch)
|
||||
y: number,
|
||||
z: number,
|
||||
},
|
||||
} |
|
||||
{
|
||||
type: "extrudeGroups",
|
||||
}
|
||||
```
|
||||
|
||||
|
2563
docs/kcl/std.json
2563
docs/kcl/std.json
File diff suppressed because it is too large
Load Diff
1639
src-tauri/Cargo.lock
generated
1639
src-tauri/Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
@ -20,7 +20,7 @@ kittycad = "0.3.5"
|
||||
log = "0.4.21"
|
||||
oauth2 = "4.4.2"
|
||||
serde_json = "1.0"
|
||||
tauri = { version = "2.0.0-beta.15", features = [ "devtools", "unstable"] }
|
||||
tauri = { version = "2.0.0-beta.22", features = [ "devtools", "unstable"] }
|
||||
tauri-plugin-cli = { version = "2.0.0-beta.3" }
|
||||
tauri-plugin-deep-link = { version = "2.0.0-beta.3" }
|
||||
tauri-plugin-dialog = { version = "2.0.0-beta.6" }
|
||||
|
@ -63,11 +63,12 @@
|
||||
"subcommands": {}
|
||||
},
|
||||
"deep-link": {
|
||||
"domains": [
|
||||
{
|
||||
"host": "app.zoo.dev"
|
||||
}
|
||||
"mobile": [],
|
||||
"desktop": {
|
||||
"schemes": [
|
||||
"app.zoo.dev"
|
||||
]
|
||||
}
|
||||
},
|
||||
"shell": {
|
||||
"open": true
|
||||
|
2
src/wasm-lib/Cargo.lock
generated
2
src/wasm-lib/Cargo.lock
generated
@ -1369,7 +1369,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "kcl-lib"
|
||||
version = "0.1.59"
|
||||
version = "0.1.60"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"approx",
|
||||
|
@ -1,7 +1,7 @@
|
||||
[package]
|
||||
name = "kcl-lib"
|
||||
description = "KittyCAD Language implementation and tools"
|
||||
version = "0.1.59"
|
||||
version = "0.1.60"
|
||||
edition = "2021"
|
||||
license = "MIT"
|
||||
repository = "https://github.com/KittyCAD/modeling-app"
|
||||
|
@ -63,9 +63,10 @@ impl StdLibFnArg {
|
||||
|
||||
pub fn get_autocomplete_snippet(&self, index: usize) -> Result<Option<(usize, String)>> {
|
||||
if self.type_ == "SketchGroup"
|
||||
|| self.type_ == "ExtrudeGroup"
|
||||
|| self.type_ == "SketchSurface"
|
||||
|| self.type_ == "SketchGroupSet"
|
||||
|| self.type_ == "ExtrudeGroup"
|
||||
|| self.type_ == "ExtrudeGroupSet"
|
||||
|| self.type_ == "SketchSurface"
|
||||
{
|
||||
return Ok(Some((index, format!("${{{}:{}}}", index, "%"))));
|
||||
}
|
||||
|
@ -31,7 +31,8 @@ use crate::{
|
||||
docs::StdLibFn,
|
||||
errors::{KclError, KclErrorDetails},
|
||||
executor::{
|
||||
ExecutorContext, ExtrudeGroup, MemoryItem, Metadata, SketchGroup, SketchGroupSet, SketchSurface, SourceRange,
|
||||
ExecutorContext, ExtrudeGroup, ExtrudeGroupSet, MemoryItem, Metadata, SketchGroup, SketchGroupSet,
|
||||
SketchSurface, SourceRange,
|
||||
},
|
||||
std::{kcl_stdlib::KclStdLibFn, sketch::SketchOnFaceTag},
|
||||
};
|
||||
@ -773,6 +774,52 @@ impl Args {
|
||||
Ok((data, sketch_surface, tag))
|
||||
}
|
||||
|
||||
fn get_data_and_extrude_group_set<T: serde::de::DeserializeOwned>(&self) -> Result<(T, ExtrudeGroupSet), KclError> {
|
||||
let first_value = self
|
||||
.args
|
||||
.first()
|
||||
.ok_or_else(|| {
|
||||
KclError::Type(KclErrorDetails {
|
||||
message: format!("Expected a struct as the first argument, found `{:?}`", self.args),
|
||||
source_ranges: vec![self.source_range],
|
||||
})
|
||||
})?
|
||||
.get_json_value()?;
|
||||
|
||||
let data: T = serde_json::from_value(first_value).map_err(|e| {
|
||||
KclError::Type(KclErrorDetails {
|
||||
message: format!("Failed to deserialize struct from JSON: {}", e),
|
||||
source_ranges: vec![self.source_range],
|
||||
})
|
||||
})?;
|
||||
|
||||
let second_value = self.args.get(1).ok_or_else(|| {
|
||||
KclError::Type(KclErrorDetails {
|
||||
message: format!(
|
||||
"Expected an ExtrudeGroup as the second argument, found `{:?}`",
|
||||
self.args
|
||||
),
|
||||
source_ranges: vec![self.source_range],
|
||||
})
|
||||
})?;
|
||||
|
||||
let extrude_set = if let MemoryItem::ExtrudeGroup(eg) = second_value {
|
||||
ExtrudeGroupSet::ExtrudeGroup(eg.clone())
|
||||
} else if let MemoryItem::ExtrudeGroups { value } = second_value {
|
||||
ExtrudeGroupSet::ExtrudeGroups(value.clone())
|
||||
} else {
|
||||
return Err(KclError::Type(KclErrorDetails {
|
||||
message: format!(
|
||||
"Expected a ExtrudeGroup or Vector of ExtrudeGroups as the second argument, found `{:?}`",
|
||||
self.args
|
||||
),
|
||||
source_ranges: vec![self.source_range],
|
||||
}));
|
||||
};
|
||||
|
||||
Ok((data, extrude_set))
|
||||
}
|
||||
|
||||
fn get_data_and_extrude_group<T: serde::de::DeserializeOwned>(&self) -> Result<(T, Box<ExtrudeGroup>), KclError> {
|
||||
let first_value = self
|
||||
.args
|
||||
|
@ -8,7 +8,7 @@ use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::{
|
||||
errors::{KclError, KclErrorDetails},
|
||||
executor::{ExtrudeGroup, Geometries, Geometry, MemoryItem, SketchGroup, SketchGroupSet},
|
||||
executor::{ExtrudeGroup, ExtrudeGroupSet, Geometries, Geometry, MemoryItem, SketchGroup, SketchGroupSet},
|
||||
std::{types::Uint, Args},
|
||||
};
|
||||
|
||||
@ -141,7 +141,7 @@ async fn inner_pattern_linear_2d(
|
||||
|
||||
/// A linear pattern on a 3D model.
|
||||
pub async fn pattern_linear_3d(args: Args) -> Result<MemoryItem, KclError> {
|
||||
let (data, extrude_group): (LinearPattern3dData, Box<ExtrudeGroup>) = args.get_data_and_extrude_group()?;
|
||||
let (data, extrude_group_set): (LinearPattern3dData, ExtrudeGroupSet) = args.get_data_and_extrude_group_set()?;
|
||||
|
||||
if data.axis == [0.0, 0.0, 0.0] {
|
||||
return Err(KclError::Semantic(KclErrorDetails {
|
||||
@ -152,7 +152,7 @@ pub async fn pattern_linear_3d(args: Args) -> Result<MemoryItem, KclError> {
|
||||
}));
|
||||
}
|
||||
|
||||
let extrude_groups = inner_pattern_linear_3d(data, extrude_group, args).await?;
|
||||
let extrude_groups = inner_pattern_linear_3d(data, extrude_group_set, args).await?;
|
||||
Ok(MemoryItem::ExtrudeGroups { value: extrude_groups })
|
||||
}
|
||||
|
||||
@ -178,27 +178,37 @@ pub async fn pattern_linear_3d(args: Args) -> Result<MemoryItem, KclError> {
|
||||
}]
|
||||
async fn inner_pattern_linear_3d(
|
||||
data: LinearPattern3dData,
|
||||
extrude_group: Box<ExtrudeGroup>,
|
||||
extrude_group_set: ExtrudeGroupSet,
|
||||
args: Args,
|
||||
) -> Result<Vec<Box<ExtrudeGroup>>, KclError> {
|
||||
let starting_extrude_groups = match extrude_group_set {
|
||||
ExtrudeGroupSet::ExtrudeGroup(extrude_group) => vec![extrude_group],
|
||||
ExtrudeGroupSet::ExtrudeGroups(extrude_groups) => extrude_groups,
|
||||
};
|
||||
|
||||
if args.ctx.is_mock {
|
||||
return Ok(vec![extrude_group.clone()]);
|
||||
return Ok(starting_extrude_groups);
|
||||
}
|
||||
|
||||
let mut extrude_groups = Vec::new();
|
||||
for extrude_group in starting_extrude_groups.iter() {
|
||||
let geometries = pattern_linear(
|
||||
LinearPattern::ThreeD(data),
|
||||
Geometry::ExtrudeGroup(extrude_group),
|
||||
LinearPattern::ThreeD(data.clone()),
|
||||
Geometry::ExtrudeGroup(extrude_group.clone()),
|
||||
args.clone(),
|
||||
)
|
||||
.await?;
|
||||
|
||||
let Geometries::ExtrudeGroups(extrude_groups) = geometries else {
|
||||
let Geometries::ExtrudeGroups(new_extrude_groups) = geometries else {
|
||||
return Err(KclError::Semantic(KclErrorDetails {
|
||||
message: "Expected a vec of extrude groups".to_string(),
|
||||
source_ranges: vec![args.source_range],
|
||||
}));
|
||||
};
|
||||
|
||||
extrude_groups.extend(new_extrude_groups);
|
||||
}
|
||||
|
||||
Ok(extrude_groups)
|
||||
}
|
||||
|
||||
@ -335,9 +345,9 @@ impl CircularPattern {
|
||||
|
||||
/// A circular pattern on a 2D sketch.
|
||||
pub async fn pattern_circular_2d(args: Args) -> Result<MemoryItem, KclError> {
|
||||
let (data, sketch_group): (CircularPattern2dData, Box<SketchGroup>) = args.get_data_and_sketch_group()?;
|
||||
let (data, sketch_group_set): (CircularPattern2dData, SketchGroupSet) = args.get_data_and_sketch_group_set()?;
|
||||
|
||||
let sketch_groups = inner_pattern_circular_2d(data, sketch_group, args).await?;
|
||||
let sketch_groups = inner_pattern_circular_2d(data, sketch_group_set, args).await?;
|
||||
Ok(MemoryItem::SketchGroups { value: sketch_groups })
|
||||
}
|
||||
|
||||
@ -364,35 +374,45 @@ pub async fn pattern_circular_2d(args: Args) -> Result<MemoryItem, KclError> {
|
||||
}]
|
||||
async fn inner_pattern_circular_2d(
|
||||
data: CircularPattern2dData,
|
||||
sketch_group: Box<SketchGroup>,
|
||||
sketch_group_set: SketchGroupSet,
|
||||
args: Args,
|
||||
) -> Result<Vec<Box<SketchGroup>>, KclError> {
|
||||
let starting_sketch_groups = match sketch_group_set {
|
||||
SketchGroupSet::SketchGroup(sketch_group) => vec![sketch_group],
|
||||
SketchGroupSet::SketchGroups(sketch_groups) => sketch_groups,
|
||||
};
|
||||
|
||||
if args.ctx.is_mock {
|
||||
return Ok(vec![sketch_group]);
|
||||
return Ok(starting_sketch_groups);
|
||||
}
|
||||
|
||||
let mut sketch_groups = Vec::new();
|
||||
for sketch_group in starting_sketch_groups.iter() {
|
||||
let geometries = pattern_circular(
|
||||
CircularPattern::TwoD(data),
|
||||
Geometry::SketchGroup(sketch_group),
|
||||
CircularPattern::TwoD(data.clone()),
|
||||
Geometry::SketchGroup(sketch_group.clone()),
|
||||
args.clone(),
|
||||
)
|
||||
.await?;
|
||||
|
||||
let Geometries::SketchGroups(sketch_groups) = geometries else {
|
||||
let Geometries::SketchGroups(new_sketch_groups) = geometries else {
|
||||
return Err(KclError::Semantic(KclErrorDetails {
|
||||
message: "Expected a vec of sketch groups".to_string(),
|
||||
source_ranges: vec![args.source_range],
|
||||
}));
|
||||
};
|
||||
|
||||
sketch_groups.extend(new_sketch_groups);
|
||||
}
|
||||
|
||||
Ok(sketch_groups)
|
||||
}
|
||||
|
||||
/// A circular pattern on a 3D model.
|
||||
pub async fn pattern_circular_3d(args: Args) -> Result<MemoryItem, KclError> {
|
||||
let (data, extrude_group): (CircularPattern3dData, Box<ExtrudeGroup>) = args.get_data_and_extrude_group()?;
|
||||
let (data, extrude_group_set): (CircularPattern3dData, ExtrudeGroupSet) = args.get_data_and_extrude_group_set()?;
|
||||
|
||||
let extrude_groups = inner_pattern_circular_3d(data, extrude_group, args).await?;
|
||||
let extrude_groups = inner_pattern_circular_3d(data, extrude_group_set, args).await?;
|
||||
Ok(MemoryItem::ExtrudeGroups { value: extrude_groups })
|
||||
}
|
||||
|
||||
@ -416,27 +436,37 @@ pub async fn pattern_circular_3d(args: Args) -> Result<MemoryItem, KclError> {
|
||||
}]
|
||||
async fn inner_pattern_circular_3d(
|
||||
data: CircularPattern3dData,
|
||||
extrude_group: Box<ExtrudeGroup>,
|
||||
extrude_group_set: ExtrudeGroupSet,
|
||||
args: Args,
|
||||
) -> Result<Vec<Box<ExtrudeGroup>>, KclError> {
|
||||
let starting_extrude_groups = match extrude_group_set {
|
||||
ExtrudeGroupSet::ExtrudeGroup(extrude_group) => vec![extrude_group],
|
||||
ExtrudeGroupSet::ExtrudeGroups(extrude_groups) => extrude_groups,
|
||||
};
|
||||
|
||||
if args.ctx.is_mock {
|
||||
return Ok(vec![extrude_group]);
|
||||
return Ok(starting_extrude_groups);
|
||||
}
|
||||
|
||||
let mut extrude_groups = Vec::new();
|
||||
for extrude_group in starting_extrude_groups.iter() {
|
||||
let geometries = pattern_circular(
|
||||
CircularPattern::ThreeD(data),
|
||||
Geometry::ExtrudeGroup(extrude_group),
|
||||
CircularPattern::ThreeD(data.clone()),
|
||||
Geometry::ExtrudeGroup(extrude_group.clone()),
|
||||
args.clone(),
|
||||
)
|
||||
.await?;
|
||||
|
||||
let Geometries::ExtrudeGroups(extrude_groups) = geometries else {
|
||||
let Geometries::ExtrudeGroups(new_extrude_groups) = geometries else {
|
||||
return Err(KclError::Semantic(KclErrorDetails {
|
||||
message: "Expected a vec of extrude groups".to_string(),
|
||||
source_ranges: vec![args.source_range],
|
||||
}));
|
||||
};
|
||||
|
||||
extrude_groups.extend(new_extrude_groups);
|
||||
}
|
||||
|
||||
Ok(extrude_groups)
|
||||
}
|
||||
|
||||
|
@ -1959,3 +1959,53 @@ async fn serial_test_neg_xz_plane() {
|
||||
let result = execute_and_snapshot(code, UnitLength::Mm).await.unwrap();
|
||||
twenty_twenty::assert_image("tests/executor/outputs/neg_xz_plane.png", &result, 1.0);
|
||||
}
|
||||
|
||||
#[tokio::test(flavor = "multi_thread")]
|
||||
async fn serial_test_linear_pattern3d_a_pattern() {
|
||||
let code = r#"const exampleSketch = startSketchOn('XZ')
|
||||
|> startProfileAt([0, 0], %)
|
||||
|> line([0, 2], %)
|
||||
|> line([3, 1], %)
|
||||
|> line([0, -4], %)
|
||||
|> close(%)
|
||||
|> extrude(1, %)
|
||||
|
||||
const pattn1 = patternLinear3d({
|
||||
axis: [1, 0, 0],
|
||||
repetitions: 6,
|
||||
distance: 6
|
||||
}, exampleSketch)
|
||||
|
||||
const pattn2 = patternLinear3d({
|
||||
axis: [0, 0, 1],
|
||||
distance: 1,
|
||||
repetitions: 6
|
||||
}, pattn1)
|
||||
"#;
|
||||
|
||||
let result = execute_and_snapshot(code, UnitLength::Mm).await.unwrap();
|
||||
twenty_twenty::assert_image("tests/executor/outputs/linear_pattern3d_a_pattern.png", &result, 1.0);
|
||||
}
|
||||
|
||||
#[tokio::test(flavor = "multi_thread")]
|
||||
async fn serial_test_circular_pattern3d_a_pattern() {
|
||||
let code = r#"const exampleSketch = startSketchOn('XZ')
|
||||
|> startProfileAt([0, 0], %)
|
||||
|> line([0, 2], %)
|
||||
|> line([3, 1], %)
|
||||
|> line([0, -4], %)
|
||||
|> close(%)
|
||||
|> extrude(1, %)
|
||||
|
||||
const pattn1 = patternLinear3d({
|
||||
axis: [1, 0, 0],
|
||||
repetitions: 6,
|
||||
distance: 6
|
||||
}, exampleSketch)
|
||||
|
||||
const pattn2 = patternCircular3d({axis: [0,0, 1], center: [-20, -20, -20], repetitions: 40, arcDegrees: 360, rotateDuplicates: false}, pattn1)
|
||||
"#;
|
||||
|
||||
let result = execute_and_snapshot(code, UnitLength::Mm).await.unwrap();
|
||||
twenty_twenty::assert_image("tests/executor/outputs/circular_pattern3d_a_pattern.png", &result, 1.0);
|
||||
}
|
||||
|
Binary file not shown.
After Width: | Height: | Size: 209 KiB |
Binary file not shown.
After Width: | Height: | Size: 176 KiB |
Reference in New Issue
Block a user