Patterns fixes (2d) (#2197)

* updates

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

* patterns fixes

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

* fix docs

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

* better autocomplete

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

* fix

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

---------

Signed-off-by: Jess Frazelle <github@jessfraz.com>
This commit is contained in:
Jess Frazelle
2024-04-23 10:31:20 -07:00
committed by GitHub
parent 2d8d29b345
commit c620f7269c
12 changed files with 5286 additions and 2358 deletions

View File

@ -9,7 +9,7 @@ Extrudes by a given amount.
```js
extrude(length: number, sketch_group: SketchGroup) -> ExtrudeGroup
extrude(length: number, sketch_group_set: SketchGroupSet) -> ExtrudeGroupSet
```
### Examples
@ -29,7 +29,7 @@ startSketchOn('XY')
### Arguments
* `length`: `number` (REQUIRED)
* `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.
@ -110,6 +110,7 @@ startSketchOn('XY')
// The to point.
to: [number, number],
},
type: "sketchGroup",
// The paths in the sketch group.
value: [{
// The from point.
@ -193,12 +194,15 @@ startSketchOn('XY')
y: number,
z: number,
},
} |
{
type: "sketchGroups",
}
```
### Returns
`ExtrudeGroup` - An extrude group is a collection of extrude surfaces.
`ExtrudeGroupSet` - A extrude group or a group of extrude groups.
```js
{
// The id of the extrusion end cap
@ -278,6 +282,7 @@ startSketchOn('XY')
}],
// The id of the extrusion start cap
startCapId: uuid,
type: "extrudeGroup",
// The extrude surfaces.
value: [{
// The face id for the extrude plane.
@ -327,6 +332,9 @@ startSketchOn('XY')
y: number,
z: number,
},
} |
{
type: "extrudeGroups",
}
```

View File

@ -9,7 +9,7 @@ A linear pattern on a 2D sketch.
```js
patternLinear2d(data: LinearPattern2dData, sketch_group: SketchGroup) -> [SketchGroup]
patternLinear2d(data: LinearPattern2dData, sketch_group_set: SketchGroupSet) -> [SketchGroup]
```
### Examples
@ -39,7 +39,7 @@ const part = startSketchOn('XY')
repetitions: number,
}
```
* `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.
@ -120,6 +120,7 @@ const part = startSketchOn('XY')
// The to point.
to: [number, number],
},
type: "sketchGroup",
// The paths in the sketch group.
value: [{
// The from point.
@ -203,6 +204,9 @@ const part = startSketchOn('XY')
y: number,
z: number,
},
} |
{
type: "sketchGroups",
}
```

File diff suppressed because it is too large Load Diff

View File

@ -6,10 +6,10 @@
serial-integration = { max-threads = 4 }
[profile.default]
slow-timeout = { period = "10s", terminate-after = 1 }
slow-timeout = { period = "30s", terminate-after = 1 }
[profile.ci]
slow-timeout = { period = "30s", terminate-after = 5 }
slow-timeout = { period = "50s", terminate-after = 5 }
[[profile.default.overrides]]
filter = "test(serial_test_)"

View File

@ -62,7 +62,11 @@ impl StdLibFnArg {
}
pub fn get_autocomplete_snippet(&self, index: usize) -> Result<Option<(usize, String)>> {
if self.type_ == "SketchGroup" || self.type_ == "ExtrudeGroup" || self.type_ == "SketchSurface" {
if self.type_ == "SketchGroup"
|| self.type_ == "ExtrudeGroup"
|| self.type_ == "SketchSurface"
|| self.type_ == "SketchGroupSet"
{
return Ok(Some((index, format!("${{{}:{}}}", index, "%"))));
}
get_autocomplete_snippet_from_schema(&self.schema.clone(), index)

View File

@ -191,6 +191,15 @@ pub enum SketchGroupSet {
SketchGroups(Vec<Box<SketchGroup>>),
}
/// A extrude group or a group of extrude groups.
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema)]
#[ts(export)]
#[serde(tag = "type", rename_all = "camelCase")]
pub enum ExtrudeGroupSet {
ExtrudeGroup(Box<ExtrudeGroup>),
ExtrudeGroups(Vec<Box<ExtrudeGroup>>),
}
/// Data for an imported geometry.
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema)]
#[ts(export)]

View File

@ -7,17 +7,23 @@ use uuid::Uuid;
use crate::{
errors::{KclError, KclErrorDetails},
executor::{ExtrudeGroup, ExtrudeSurface, ExtrudeTransform, GeoMeta, MemoryItem, Path, SketchGroup, SketchSurface},
executor::{
ExtrudeGroup, ExtrudeGroupSet, ExtrudeSurface, ExtrudeTransform, GeoMeta, MemoryItem, Path, SketchGroup,
SketchGroupSet, SketchSurface,
},
std::Args,
};
/// Extrudes by a given amount.
pub async fn extrude(args: Args) -> Result<MemoryItem, KclError> {
let (length, sketch_group) = args.get_number_sketch_group()?;
let (length, sketch_group_set) = args.get_number_sketch_group_set()?;
let result = inner_extrude(length, sketch_group, args).await?;
let result = inner_extrude(length, sketch_group_set, args).await?;
Ok(MemoryItem::ExtrudeGroup(result))
match result {
ExtrudeGroupSet::ExtrudeGroup(extrude_group) => Ok(MemoryItem::ExtrudeGroup(extrude_group)),
ExtrudeGroupSet::ExtrudeGroups(extrude_groups) => Ok(MemoryItem::ExtrudeGroups { value: extrude_groups }),
}
}
/// Extrudes by a given amount.
@ -34,10 +40,16 @@ pub async fn extrude(args: Args) -> Result<MemoryItem, KclError> {
#[stdlib {
name = "extrude"
}]
async fn inner_extrude(length: f64, sketch_group: Box<SketchGroup>, args: Args) -> Result<Box<ExtrudeGroup>, KclError> {
async fn inner_extrude(length: f64, sketch_group_set: SketchGroupSet, args: Args) -> Result<ExtrudeGroupSet, KclError> {
let id = uuid::Uuid::new_v4();
// Extrude the element.
// Extrude the element(s).
let sketch_groups = match sketch_group_set {
SketchGroupSet::SketchGroup(sketch_group) => vec![sketch_group],
SketchGroupSet::SketchGroups(sketch_groups) => sketch_groups,
};
let mut extrude_groups = Vec::new();
for sketch_group in sketch_groups.iter() {
args.send_modeling_cmd(
id,
kittycad::types::ModelingCmd::Extrude {
@ -47,8 +59,14 @@ async fn inner_extrude(length: f64, sketch_group: Box<SketchGroup>, args: Args)
},
)
.await?;
extrude_groups.push(do_post_extrude(sketch_group.clone(), length, id, args.clone()).await?);
}
do_post_extrude(sketch_group, length, id, args).await
if extrude_groups.len() == 1 {
Ok(ExtrudeGroupSet::ExtrudeGroup(extrude_groups.pop().unwrap()))
} else {
Ok(ExtrudeGroupSet::ExtrudeGroups(extrude_groups))
}
}
pub(crate) async fn do_post_extrude(

View File

@ -628,6 +628,49 @@ impl Args {
Ok((data, sketch_group))
}
fn get_data_and_sketch_group_set<T: serde::de::DeserializeOwned>(&self) -> Result<(T, SketchGroupSet), 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 a SketchGroup as the second argument, found `{:?}`", self.args),
source_ranges: vec![self.source_range],
})
})?;
let sketch_set = if let MemoryItem::SketchGroup(sg) = second_value {
SketchGroupSet::SketchGroup(sg.clone())
} else if let MemoryItem::SketchGroups { value } = second_value {
SketchGroupSet::SketchGroups(value.clone())
} else {
return Err(KclError::Type(KclErrorDetails {
message: format!(
"Expected a SketchGroup or Vector of SketchGroups as the second argument, found `{:?}`",
self.args
),
source_ranges: vec![self.source_range],
}));
};
Ok((data, sketch_set))
}
fn get_data_and_sketch_group_and_tag<T: serde::de::DeserializeOwned>(
&self,
) -> Result<(T, Box<SketchGroup>, Option<String>), KclError> {
@ -823,7 +866,7 @@ impl Args {
Ok((segment_name, to_number, sketch_group))
}
fn get_number_sketch_group(&self) -> Result<(f64, Box<SketchGroup>), KclError> {
fn get_number_sketch_group_set(&self) -> Result<(f64, SketchGroupSet), KclError> {
// Iterate over our args, the first argument should be a number.
// The second argument should be a SketchGroup.
let first_value = self
@ -846,16 +889,21 @@ impl Args {
})
})?;
let sketch_group = if let MemoryItem::SketchGroup(sg) = second_value {
sg.clone()
let sketch_set = if let MemoryItem::SketchGroup(sg) = second_value {
SketchGroupSet::SketchGroup(sg.clone())
} else if let MemoryItem::SketchGroups { value } = second_value {
SketchGroupSet::SketchGroups(value.clone())
} else {
return Err(KclError::Type(KclErrorDetails {
message: format!("Expected a SketchGroup as the second argument, found `{:?}`", self.args),
message: format!(
"Expected a SketchGroup or Vector of SketchGroups as the second argument, found `{:?}`",
self.args
),
source_ranges: vec![self.source_range],
}));
};
Ok((number, sketch_group))
Ok((number, sketch_set))
}
fn get_path_name_extrude_group(&self) -> Result<(String, Box<ExtrudeGroup>), KclError> {

View File

@ -8,7 +8,7 @@ use serde::{Deserialize, Serialize};
use crate::{
errors::{KclError, KclErrorDetails},
executor::{ExtrudeGroup, Geometries, Geometry, MemoryItem, SketchGroup},
executor::{ExtrudeGroup, Geometries, Geometry, MemoryItem, SketchGroup, SketchGroupSet},
std::Args,
};
@ -72,7 +72,7 @@ impl LinearPattern {
/// A linear pattern on a 2D sketch.
pub async fn pattern_linear_2d(args: Args) -> Result<MemoryItem, KclError> {
let (data, sketch_group): (LinearPattern2dData, Box<SketchGroup>) = args.get_data_and_sketch_group()?;
let (data, sketch_group_set): (LinearPattern2dData, SketchGroupSet) = args.get_data_and_sketch_group_set()?;
if data.axis == [0.0, 0.0] {
return Err(KclError::Semantic(KclErrorDetails {
@ -83,7 +83,7 @@ pub async fn pattern_linear_2d(args: Args) -> Result<MemoryItem, KclError> {
}));
}
let sketch_groups = inner_pattern_linear_2d(data, sketch_group, args).await?;
let sketch_groups = inner_pattern_linear_2d(data, sketch_group_set, args).await?;
Ok(MemoryItem::SketchGroups { value: sketch_groups })
}
@ -99,23 +99,33 @@ pub async fn pattern_linear_2d(args: Args) -> Result<MemoryItem, KclError> {
}]
async fn inner_pattern_linear_2d(
data: LinearPattern2dData,
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,
};
let mut sketch_groups = Vec::new();
for sketch_group in starting_sketch_groups.iter() {
let geometries = pattern_linear(
LinearPattern::TwoD(data),
Geometry::SketchGroup(sketch_group),
LinearPattern::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)
}

View File

@ -0,0 +1,56 @@
// Lego Brick
const lbumps = 10 // number of bumps long
const wbumps = 6 // number of bumps wide
const pitch = 8.0
const clearance = 0.1
const bumpDiam = 4.8
const bumpHeight = 1.8
const height = 3.2
const t = (pitch - (2 * clearance) - bumpDiam) / 2.0
const postDiam = pitch - t // works out to 6.5
const total_length = lbumps * pitch - (2.0 * clearance)
const total_width = wbumps * pitch - (2.0 * clearance)
const lSegments = total_length / (lbumps + 1)
const wSegments = total_width / (wbumps + 1)
// make the base
const s = startSketchOn('XY')
|> startProfileAt([-total_width / 2, -total_length / 2], %)
|> line([total_width, 0], %)
|> line([0, total_length], %)
|> line([-total_width, 0], %)
|> close(%)
|> extrude(height, %)
const shellExtrude = startSketchOn(s, "start")
|> startProfileAt([
-(total_width / 2 - t),
-(total_length / 2 - t)
], %)
|> line([total_width - (2 * t), 0], %)
|> line([0, total_length - (2 * t)], %)
|> line([-(total_width - (2 * t)), 0], %)
|> close(%)
|> extrude(-(height - t), %)
const peg = startSketchOn(s, "end")
|> circle([
-(total_width / 2 - wSegments),
-(total_length / 2 - lSegments)
], bumpDiam / 2, %)
|> patternLinear2d({
axis: [1, 0],
repetitions: 5,
distance: 7
}, %)
|> patternLinear2d({
axis: [0, 1],
repetitions: 9,
distance: 7
}, %)
|> extrude(bumpHeight, %)

View File

@ -115,6 +115,15 @@ async fn serial_test_riddle_small() {
twenty_twenty::assert_image("tests/executor/outputs/riddle_small.png", &result, 0.999);
}
#[tokio::test(flavor = "multi_thread")]
async fn serial_test_lego() {
let code = include_str!("inputs/lego.kcl");
let result = execute_and_snapshot(code, kittycad::types::UnitLength::Mm)
.await
.unwrap();
twenty_twenty::assert_image("tests/executor/outputs/lego.png", &result, 0.999);
}
#[tokio::test(flavor = "multi_thread")]
async fn serial_test_pentagon_fillet_desugar() {
let code = include_str!("inputs/pentagon_fillet_desugar.kcl");

Binary file not shown.

After

Width:  |  Height:  |  Size: 199 KiB