Patterns 2d 3d (#1701)

* refactor

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

* pattern2d and 3d

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

* fix derive docs more

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

* fixes

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-03-12 12:54:45 -07:00
committed by GitHub
parent 82fb227868
commit 73b7d3cc9d
21 changed files with 7576 additions and 7029 deletions

File diff suppressed because it is too large Load Diff

View File

@ -46,8 +46,10 @@
* [`log2`](#log2) * [`log2`](#log2)
* [`max`](#max) * [`max`](#max)
* [`min`](#min) * [`min`](#min)
* [`patternCircular`](#patternCircular) * [`patternCircular2d`](#patternCircular2d)
* [`patternLinear`](#patternLinear) * [`patternCircular3d`](#patternCircular3d)
* [`patternLinear2d`](#patternLinear2d)
* [`patternLinear3d`](#patternLinear3d)
* [`pi`](#pi) * [`pi`](#pi)
* [`pow`](#pow) * [`pow`](#pow)
* [`segAng`](#segAng) * [`segAng`](#segAng)
@ -7170,34 +7172,32 @@ min(args: [number]) -> number
### patternCircular ### patternCircular2d
A Circular pattern. A circular pattern on a 2D sketch.
``` ```
patternCircular(data: CircularPatternData, geometry: Geometry) -> Geometries patternCircular2d(data: CircularPattern2dData, sketch_group: SketchGroup) -> [SketchGroup]
``` ```
#### Arguments #### Arguments
* `data`: `CircularPatternData` - Data for a circular pattern. (REQUIRED) * `data`: `CircularPattern2dData` - Data for a circular pattern on a 2D sketch. (REQUIRED)
``` ```
{ {
// The arc angle (in degrees) to place the repetitions. Must be greater than 0. // The arc angle (in degrees) to place the repetitions. Must be greater than 0.
arcDegrees: number, arcDegrees: number,
// The axis around which to make the pattern. This is a 2D vector. // The center about which to make th pattern. This is a 2D vector.
axis: [number, number], center: [number, number],
// The center about which to make th pattern. This is a 3D vector.
center: [number, number, number],
// The number of repetitions. Must be greater than 0. This excludes the original entity. For example, if `repetitions` is 1, the original entity will be copied once. // The number of repetitions. Must be greater than 0. This excludes the original entity. For example, if `repetitions` is 1, the original entity will be copied once.
repetitions: number, repetitions: number,
// Whether or not to rotate the duplicates as they are copied. // Whether or not to rotate the duplicates as they are copied.
rotateDuplicates: string, rotateDuplicates: string,
} }
``` ```
* `geometry`: `Geometry` - A geometry. (REQUIRED) * `sketch_group`: `SketchGroup` - A sketch group is a collection of paths. (REQUIRED)
``` ```
{ {
// The plane id or face id of the sketch group. // The plane id or face id of the sketch group.
@ -7276,7 +7276,6 @@ patternCircular(data: CircularPatternData, geometry: Geometry) -> Geometries
// The to point. // The to point.
to: [number, number], to: [number, number],
}, },
type: "SketchGroup",
// The paths in the sketch group. // The paths in the sketch group.
value: [{ value: [{
// The from point. // The from point.
@ -7360,7 +7359,44 @@ patternCircular(data: CircularPatternData, geometry: Geometry) -> Geometries
y: number, y: number,
z: number, z: number,
}, },
} | }
```
#### Returns
* `[SketchGroup]`
### patternCircular3d
A circular pattern on a 3D model.
```
patternCircular3d(data: CircularPattern3dData, extrude_group: ExtrudeGroup) -> [ExtrudeGroup]
```
#### Arguments
* `data`: `CircularPattern3dData` - Data for a circular pattern on a 3D model. (REQUIRED)
```
{
// The arc angle (in degrees) to place the repetitions. Must be greater than 0.
arcDegrees: number,
// The axis around which to make the pattern. This is a 3D vector.
axis: [number, number, number],
// The center about which to make th pattern. This is a 3D vector.
center: [number, number, number],
// The number of repetitions. Must be greater than 0. This excludes the original entity. For example, if `repetitions` is 1, the original entity will be copied once.
repetitions: number,
// Whether or not to rotate the duplicates as they are copied.
rotateDuplicates: string,
}
```
* `extrude_group`: `ExtrudeGroup` - An extrude group is a collection of extrude surfaces. (REQUIRED)
```
{ {
// The id of the extrusion end cap // The id of the extrusion end cap
endCapId: uuid, endCapId: uuid,
@ -7439,7 +7475,6 @@ patternCircular(data: CircularPatternData, geometry: Geometry) -> Geometries
}], }],
// The id of the extrusion start cap // The id of the extrusion start cap
startCapId: uuid, startCapId: uuid,
type: "ExtrudeGroup",
// The extrude surfaces. // The extrude surfaces.
value: [{ value: [{
// The face id for the extrude plane. // The face id for the extrude plane.
@ -7494,31 +7529,23 @@ patternCircular(data: CircularPatternData, geometry: Geometry) -> Geometries
#### Returns #### Returns
* `Geometries` - A set of geometry. * `[ExtrudeGroup]`
```
{
type: "SketchGroups",
} |
{
type: "ExtrudeGroups",
}
```
### patternLinear ### patternLinear2d
A linear pattern. A linear pattern on a 2D sketch.
``` ```
patternLinear(data: LinearPatternData, geometry: Geometry) -> Geometries patternLinear2d(data: LinearPattern2dData, sketch_group: SketchGroup) -> [SketchGroup]
``` ```
#### Arguments #### Arguments
* `data`: `LinearPatternData` - Data for a linear pattern. (REQUIRED) * `data`: `LinearPattern2dData` - Data for a linear pattern on a 2D sketch. (REQUIRED)
``` ```
{ {
// The axis of the pattern. This is a 2D vector. // The axis of the pattern. This is a 2D vector.
@ -7529,7 +7556,7 @@ patternLinear(data: LinearPatternData, geometry: Geometry) -> Geometries
repetitions: number, repetitions: number,
} }
``` ```
* `geometry`: `Geometry` - A geometry. (REQUIRED) * `sketch_group`: `SketchGroup` - A sketch group is a collection of paths. (REQUIRED)
``` ```
{ {
// The plane id or face id of the sketch group. // The plane id or face id of the sketch group.
@ -7608,7 +7635,6 @@ patternLinear(data: LinearPatternData, geometry: Geometry) -> Geometries
// The to point. // The to point.
to: [number, number], to: [number, number],
}, },
type: "SketchGroup",
// The paths in the sketch group. // The paths in the sketch group.
value: [{ value: [{
// The from point. // The from point.
@ -7692,7 +7718,40 @@ patternLinear(data: LinearPatternData, geometry: Geometry) -> Geometries
y: number, y: number,
z: number, z: number,
}, },
} | }
```
#### Returns
* `[SketchGroup]`
### patternLinear3d
A linear pattern on a 3D model.
```
patternLinear3d(data: LinearPattern3dData, extrude_group: ExtrudeGroup) -> [ExtrudeGroup]
```
#### Arguments
* `data`: `LinearPattern3dData` - Data for a linear pattern on a 3D model. (REQUIRED)
```
{
// The axis of the pattern.
axis: [number, number, number],
// The distance between each repetition. This can also be referred to as spacing.
distance: number,
// The number of repetitions. Must be greater than 0. This excludes the original entity. For example, if `repetitions` is 1, the original entity will be copied once.
repetitions: number,
}
```
* `extrude_group`: `ExtrudeGroup` - An extrude group is a collection of extrude surfaces. (REQUIRED)
```
{ {
// The id of the extrusion end cap // The id of the extrusion end cap
endCapId: uuid, endCapId: uuid,
@ -7771,7 +7830,6 @@ patternLinear(data: LinearPatternData, geometry: Geometry) -> Geometries
}], }],
// The id of the extrusion start cap // The id of the extrusion start cap
startCapId: uuid, startCapId: uuid,
type: "ExtrudeGroup",
// The extrude surfaces. // The extrude surfaces.
value: [{ value: [{
// The face id for the extrude plane. // The face id for the extrude plane.
@ -7826,15 +7884,7 @@ patternLinear(data: LinearPatternData, geometry: Geometry) -> Geometries
#### Returns #### Returns
* `Geometries` - A set of geometry. * `[ExtrudeGroup]`
```
{
type: "SketchGroups",
} |
{
type: "ExtrudeGroups",
}
```

View File

@ -947,7 +947,7 @@ dependencies = [
[[package]] [[package]]
name = "derive-docs" name = "derive-docs"
version = "0.1.9" version = "0.1.10"
dependencies = [ dependencies = [
"convert_case", "convert_case",
"expectorate", "expectorate",
@ -962,22 +962,6 @@ dependencies = [
"syn 2.0.52", "syn 2.0.52",
] ]
[[package]]
name = "derive-docs"
version = "0.1.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b81bc4c6288273218d0bb4f2ee7cda229264f2e8381e53aae250c840946171f9"
dependencies = [
"convert_case",
"once_cell",
"proc-macro2",
"quote",
"regex",
"serde",
"serde_tokenstream",
"syn 2.0.52",
]
[[package]] [[package]]
name = "diesel_derives" name = "diesel_derives"
version = "2.1.2" version = "2.1.2"
@ -1918,7 +1902,7 @@ dependencies = [
"criterion", "criterion",
"dashmap", "dashmap",
"databake", "databake",
"derive-docs 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", "derive-docs",
"expectorate", "expectorate",
"futures", "futures",
"gltf-json", "gltf-json",

View File

@ -1,7 +1,7 @@
[package] [package]
name = "derive-docs" name = "derive-docs"
description = "A tool for generating documentation from Rust derive macros" description = "A tool for generating documentation from Rust derive macros"
version = "0.1.9" version = "0.1.10"
edition = "2021" edition = "2021"
license = "MIT" license = "MIT"
repository = "https://github.com/KittyCAD/modeling-app" repository = "https://github.com/KittyCAD/modeling-app"

View File

@ -223,31 +223,59 @@ fn do_stdlib_inner(
} }
} }
let ret_ty = ast.sig.output.clone(); let return_type_inner = match &ast.sig.output {
let ret_ty_string = ret_ty syn::ReturnType::Default => quote! { () },
.into_token_stream() syn::ReturnType::Type(_, ty) => {
.to_string() // Get the inside of the result.
.replace("-> ", "") match &**ty {
.replace("Result < ", "") syn::Type::Path(syn::TypePath { path, .. }) => {
.replace(", KclError >", ""); let path = &path.segments;
let return_type = if !ret_ty_string.is_empty() { if path.len() == 1 {
let ret_ty_string = if ret_ty_string.starts_with("Box <") { let seg = &path[0];
ret_ty_string if seg.ident == "Result" {
.trim_start_matches("Box <") if let syn::PathArguments::AngleBracketed(syn::AngleBracketedGenericArguments {
.trim_end_matches(' ') args,
.trim_end_matches('>') ..
.trim() }) = &seg.arguments
.to_string() {
if args.len() == 2 || args.len() == 1 {
let mut args = args.iter();
let ok = args.next().unwrap();
if let syn::GenericArgument::Type(ty) = ok {
let ty = unbox(unbox_vec(ty.clone()));
quote! { #ty }
} else { } else {
ret_ty_string.trim().to_string() quote! { () }
}
} else {
quote! { () }
}
} else {
quote! { () }
}
} else {
let ty = unbox(unbox_vec(*ty.clone()));
quote! { #ty }
}
} else {
quote! { () }
}
}
_ => {
quote! { () }
}
}
}
}; };
let ret_ty_ident = format_ident!("{}", ret_ty_string);
let ret_ty_string = return_type_inner.to_string().replace(' ', "");
let return_type = if !ret_ty_string.is_empty() || ret_ty_string != "()" {
let ret_ty_string = rust_type_to_openapi_type(&ret_ty_string); let ret_ty_string = rust_type_to_openapi_type(&ret_ty_string);
quote! { quote! {
Some(#docs_crate::StdLibFnArg { Some(#docs_crate::StdLibFnArg {
name: "".to_string(), name: "".to_string(),
type_: #ret_ty_string.to_string(), type_: #ret_ty_string.to_string(),
schema: #ret_ty_ident::json_schema(&mut generator), schema: <#return_type_inner>::json_schema(&mut generator),
required: true, required: true,
}) })
} }
@ -547,6 +575,93 @@ fn parse_array_type(type_name: &str) -> Option<(&str, usize)> {
Some((inner_type.as_str(), length)) Some((inner_type.as_str(), length))
} }
// Unbox a syn::Type that is boxed to the inner object.
fn unbox(t: syn::Type) -> syn::Type {
match t {
syn::Type::Path(syn::TypePath { ref path, .. }) => {
let path = &path.segments;
if path.len() == 1 {
let seg = &path[0];
if seg.ident == "Box" {
if let syn::PathArguments::AngleBracketed(syn::AngleBracketedGenericArguments { args, .. }) =
&seg.arguments
{
if args.len() == 1 {
let mut args = args.iter();
let ok = args.next().unwrap();
if let syn::GenericArgument::Type(ty) = ok {
return ty.clone();
}
}
}
}
}
}
_ => {
return t;
}
}
t
}
// For a Vec<Box<T>> return Vec<T>.
// For a Vec<T> return Vec<T>.
// For a Box<T> return T.
fn unbox_vec(t: syn::Type) -> syn::Type {
match t {
syn::Type::Path(syn::TypePath { ref path, .. }) => {
let path = &path.segments;
if path.len() == 1 {
let seg = &path[0];
if seg.ident == "Vec" {
if let syn::PathArguments::AngleBracketed(syn::AngleBracketedGenericArguments { args, .. }) =
&seg.arguments
{
if args.len() == 1 {
let mut args = args.iter();
let ok = args.next().unwrap();
if let syn::GenericArgument::Type(ty) = ok {
let unboxed = unbox(ty.clone());
// Wrap it back in a vec.
let wrapped = syn::Type::Path(syn::TypePath {
qself: None,
path: syn::Path {
leading_colon: None,
segments: {
let mut segments = syn::punctuated::Punctuated::new();
segments.push_value(syn::PathSegment {
ident: syn::Ident::new("Vec", proc_macro2::Span::call_site()),
arguments: syn::PathArguments::AngleBracketed(
syn::AngleBracketedGenericArguments {
colon2_token: None,
lt_token: syn::token::Lt::default(),
args: {
let mut args = syn::punctuated::Punctuated::new();
args.push_value(syn::GenericArgument::Type(unboxed));
args
},
gt_token: syn::token::Gt::default(),
},
),
});
segments
},
},
});
return wrapped;
}
}
}
}
}
}
_ => {
return t;
}
}
t
}
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
@ -672,7 +787,7 @@ mod tests {
fn inner_show( fn inner_show(
/// The args to do shit to. /// The args to do shit to.
args: Option<f64> args: Option<f64>
) -> Box<f64> { ) -> Result<Box<f64>> {
args args
} }
}, },
@ -693,7 +808,7 @@ mod tests {
fn inner_show( fn inner_show(
/// The args to do shit to. /// The args to do shit to.
args: [f64; 2] args: [f64; 2]
) -> Box<f64> { ) -> Result<Box<f64>> {
args args
} }
}, },
@ -714,7 +829,7 @@ mod tests {
fn inner_import( fn inner_import(
/// The args to do shit to. /// The args to do shit to.
args: Option<kittycad::types::InputFormat> args: Option<kittycad::types::InputFormat>
) -> Box<f64> { ) -> Result<Box<f64>> {
args args
} }
}, },
@ -727,4 +842,52 @@ mod tests {
&openapitor::types::get_text_fmt(&item).unwrap(), &openapitor::types::get_text_fmt(&item).unwrap(),
); );
} }
#[test]
fn test_stdlib_return_vec_sketch_group() {
let (item, errors) = do_stdlib(
quote! {
name = "import",
},
quote! {
fn inner_import(
/// The args to do shit to.
args: Option<kittycad::types::InputFormat>
) -> Result<Vec<SketchGroup>> {
args
}
},
)
.unwrap();
assert!(errors.is_empty());
expectorate::assert_contents(
"tests/return_vec_sketch_group.gen",
&openapitor::types::get_text_fmt(&item).unwrap(),
);
}
#[test]
fn test_stdlib_return_vec_box_sketch_group() {
let (item, errors) = do_stdlib(
quote! {
name = "import",
},
quote! {
fn inner_import(
/// The args to do shit to.
args: Option<kittycad::types::InputFormat>
) -> Result<Vec<Box<SketchGroup>>> {
args
}
},
)
.unwrap();
assert!(errors.is_empty());
expectorate::assert_contents(
"tests/return_vec_box_sketch_group.gen",
&openapitor::types::get_text_fmt(&item).unwrap(),
);
}
} }

View File

@ -55,7 +55,7 @@ impl crate::docs::StdLibFn for Show {
Some(crate::docs::StdLibFnArg { Some(crate::docs::StdLibFnArg {
name: "".to_string(), name: "".to_string(),
type_: "number".to_string(), type_: "number".to_string(),
schema: f64::json_schema(&mut generator), schema: <f64>::json_schema(&mut generator),
required: true, required: true,
}) })
} }
@ -77,6 +77,6 @@ impl crate::docs::StdLibFn for Show {
} }
} }
fn inner_show(#[doc = r" The args to do shit to."] args: [f64; 2]) -> Box<f64> { fn inner_show(#[doc = r" The args to do shit to."] args: [f64; 2]) -> Result<Box<f64>> {
args args
} }

View File

@ -55,7 +55,7 @@ impl crate::docs::StdLibFn for Show {
Some(crate::docs::StdLibFnArg { Some(crate::docs::StdLibFnArg {
name: "".to_string(), name: "".to_string(),
type_: "number".to_string(), type_: "number".to_string(),
schema: f64::json_schema(&mut generator), schema: <f64>::json_schema(&mut generator),
required: true, required: true,
}) })
} }

View File

@ -63,7 +63,7 @@ impl crate::docs::StdLibFn for LineTo {
Some(crate::docs::StdLibFnArg { Some(crate::docs::StdLibFnArg {
name: "".to_string(), name: "".to_string(),
type_: "SketchGroup".to_string(), type_: "SketchGroup".to_string(),
schema: SketchGroup::json_schema(&mut generator), schema: <SketchGroup>::json_schema(&mut generator),
required: true, required: true,
}) })
} }

View File

@ -55,7 +55,7 @@ impl crate::docs::StdLibFn for Min {
Some(crate::docs::StdLibFnArg { Some(crate::docs::StdLibFnArg {
name: "".to_string(), name: "".to_string(),
type_: "number".to_string(), type_: "number".to_string(),
schema: f64::json_schema(&mut generator), schema: <f64>::json_schema(&mut generator),
required: true, required: true,
}) })
} }

View File

@ -55,7 +55,7 @@ impl crate::docs::StdLibFn for Show {
Some(crate::docs::StdLibFnArg { Some(crate::docs::StdLibFnArg {
name: "".to_string(), name: "".to_string(),
type_: "number".to_string(), type_: "number".to_string(),
schema: f64::json_schema(&mut generator), schema: <f64>::json_schema(&mut generator),
required: true, required: true,
}) })
} }
@ -77,6 +77,6 @@ impl crate::docs::StdLibFn for Show {
} }
} }
fn inner_show(#[doc = r" The args to do shit to."] args: Option<f64>) -> Box<f64> { fn inner_show(#[doc = r" The args to do shit to."] args: Option<f64>) -> Result<Box<f64>> {
args args
} }

View File

@ -55,7 +55,7 @@ impl crate::docs::StdLibFn for Import {
Some(crate::docs::StdLibFnArg { Some(crate::docs::StdLibFnArg {
name: "".to_string(), name: "".to_string(),
type_: "number".to_string(), type_: "number".to_string(),
schema: f64::json_schema(&mut generator), schema: <f64>::json_schema(&mut generator),
required: true, required: true,
}) })
} }
@ -79,6 +79,6 @@ impl crate::docs::StdLibFn for Import {
fn inner_import( fn inner_import(
#[doc = r" The args to do shit to."] args: Option<kittycad::types::InputFormat>, #[doc = r" The args to do shit to."] args: Option<kittycad::types::InputFormat>,
) -> Box<f64> { ) -> Result<Box<f64>> {
args args
} }

View File

@ -0,0 +1,84 @@
#[allow(non_camel_case_types, missing_docs)]
#[doc = "Std lib function: import"]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, schemars :: JsonSchema, ts_rs :: TS)]
#[ts(export)]
pub(crate) struct Import {}
#[allow(non_upper_case_globals, missing_docs)]
#[doc = "Std lib function: import"]
pub(crate) const Import: Import = Import {};
fn boxed_import(
args: crate::std::Args,
) -> std::pin::Pin<
Box<
dyn std::future::Future<
Output = anyhow::Result<crate::executor::MemoryItem, crate::errors::KclError>,
>,
>,
> {
Box::pin(import(args))
}
impl crate::docs::StdLibFn for Import {
fn name(&self) -> String {
"import".to_string()
}
fn summary(&self) -> String {
"".to_string()
}
fn description(&self) -> String {
"".to_string()
}
fn tags(&self) -> Vec<String> {
vec![]
}
fn args(&self) -> Vec<crate::docs::StdLibFnArg> {
let mut settings = schemars::gen::SchemaSettings::openapi3();
settings.inline_subschemas = true;
let mut generator = schemars::gen::SchemaGenerator::new(settings);
vec![crate::docs::StdLibFnArg {
name: "args".to_string(),
type_: "kittycad::types::InputFormat".to_string(),
schema: <Option<kittycad::types::InputFormat>>::json_schema(&mut generator),
required: false,
}]
}
fn return_value(&self) -> Option<crate::docs::StdLibFnArg> {
let mut settings = schemars::gen::SchemaSettings::openapi3();
settings.inline_subschemas = true;
let mut generator = schemars::gen::SchemaGenerator::new(settings);
Some(crate::docs::StdLibFnArg {
name: "".to_string(),
type_: "[SketchGroup]".to_string(),
schema: <Vec<SketchGroup>>::json_schema(&mut generator),
required: true,
})
}
fn unpublished(&self) -> bool {
false
}
fn deprecated(&self) -> bool {
false
}
fn std_lib_fn(&self) -> crate::std::StdFn {
boxed_import
}
fn clone_box(&self) -> Box<dyn crate::docs::StdLibFn> {
Box::new(self.clone())
}
}
fn inner_import(
#[doc = r" The args to do shit to."] args: Option<kittycad::types::InputFormat>,
) -> Result<Vec<Box<SketchGroup>>> {
args
}

View File

@ -0,0 +1,84 @@
#[allow(non_camel_case_types, missing_docs)]
#[doc = "Std lib function: import"]
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, schemars :: JsonSchema, ts_rs :: TS)]
#[ts(export)]
pub(crate) struct Import {}
#[allow(non_upper_case_globals, missing_docs)]
#[doc = "Std lib function: import"]
pub(crate) const Import: Import = Import {};
fn boxed_import(
args: crate::std::Args,
) -> std::pin::Pin<
Box<
dyn std::future::Future<
Output = anyhow::Result<crate::executor::MemoryItem, crate::errors::KclError>,
>,
>,
> {
Box::pin(import(args))
}
impl crate::docs::StdLibFn for Import {
fn name(&self) -> String {
"import".to_string()
}
fn summary(&self) -> String {
"".to_string()
}
fn description(&self) -> String {
"".to_string()
}
fn tags(&self) -> Vec<String> {
vec![]
}
fn args(&self) -> Vec<crate::docs::StdLibFnArg> {
let mut settings = schemars::gen::SchemaSettings::openapi3();
settings.inline_subschemas = true;
let mut generator = schemars::gen::SchemaGenerator::new(settings);
vec![crate::docs::StdLibFnArg {
name: "args".to_string(),
type_: "kittycad::types::InputFormat".to_string(),
schema: <Option<kittycad::types::InputFormat>>::json_schema(&mut generator),
required: false,
}]
}
fn return_value(&self) -> Option<crate::docs::StdLibFnArg> {
let mut settings = schemars::gen::SchemaSettings::openapi3();
settings.inline_subschemas = true;
let mut generator = schemars::gen::SchemaGenerator::new(settings);
Some(crate::docs::StdLibFnArg {
name: "".to_string(),
type_: "[SketchGroup]".to_string(),
schema: <Vec<SketchGroup>>::json_schema(&mut generator),
required: true,
})
}
fn unpublished(&self) -> bool {
false
}
fn deprecated(&self) -> bool {
false
}
fn std_lib_fn(&self) -> crate::std::StdFn {
boxed_import
}
fn clone_box(&self) -> Box<dyn crate::docs::StdLibFn> {
Box::new(self.clone())
}
}
fn inner_import(
#[doc = r" The args to do shit to."] args: Option<kittycad::types::InputFormat>,
) -> Result<Vec<SketchGroup>> {
args
}

View File

@ -52,7 +52,12 @@ impl crate::docs::StdLibFn for Show {
let mut settings = schemars::gen::SchemaSettings::openapi3(); let mut settings = schemars::gen::SchemaSettings::openapi3();
settings.inline_subschemas = true; settings.inline_subschemas = true;
let mut generator = schemars::gen::SchemaGenerator::new(settings); let mut generator = schemars::gen::SchemaGenerator::new(settings);
None Some(crate::docs::StdLibFnArg {
name: "".to_string(),
type_: "()".to_string(),
schema: <()>::json_schema(&mut generator),
required: true,
})
} }
fn unpublished(&self) -> bool { fn unpublished(&self) -> bool {

View File

@ -17,8 +17,8 @@ async-trait = "0.1.77"
clap = { version = "4.5.2", features = ["cargo", "derive", "env", "unicode"], optional = true } clap = { version = "4.5.2", features = ["cargo", "derive", "env", "unicode"], optional = true }
dashmap = "5.5.3" dashmap = "5.5.3"
databake = { version = "0.1.7", features = ["derive"] } databake = { version = "0.1.7", features = ["derive"] }
derive-docs = { version = "0.1.9" } #derive-docs = { version = "0.1.10" }
#derive-docs = { path = "../derive-docs" } derive-docs = { path = "../derive-docs" }
futures = { version = "0.3.30" } futures = { version = "0.3.30" }
gltf-json = "1.4.0" gltf-json = "1.4.0"
kittycad = { workspace = true } kittycad = { workspace = true }

View File

@ -310,7 +310,7 @@ pub fn get_type_string_from_schema(schema: &schemars::schema::Schema) -> Result<
if let Some(format) = &o.format { if let Some(format) = &o.format {
if format == "uuid" { if format == "uuid" {
return Ok((Primitive::Uuid.to_string(), false)); return Ok((Primitive::Uuid.to_string(), false));
} else if format == "double" || format == "uint" || format == "int64" { } else if format == "double" || format == "uint" || format == "int64" || format == "uint32" {
return Ok((Primitive::Number.to_string(), false)); return Ok((Primitive::Number.to_string(), false));
} else { } else {
anyhow::bail!("unknown format: {}", format); anyhow::bail!("unknown format: {}", format);
@ -428,7 +428,7 @@ pub fn get_autocomplete_string_from_schema(schema: &schemars::schema::Schema) ->
if let Some(format) = &o.format { if let Some(format) = &o.format {
if format == "uuid" { if format == "uuid" {
return Ok(Primitive::Uuid.to_string()); return Ok(Primitive::Uuid.to_string());
} else if format == "double" || format == "uint" || format == "int64" { } else if format == "double" || format == "uint" || format == "int64" || format == "uint32" {
return Ok(Primitive::Number.to_string()); return Ok(Primitive::Number.to_string());
} else { } else {
anyhow::bail!("unknown format: {}", format); anyhow::bail!("unknown format: {}", format);

View File

@ -27,8 +27,7 @@ use crate::{
engine::EngineManager, engine::EngineManager,
errors::{KclError, KclErrorDetails}, errors::{KclError, KclErrorDetails},
executor::{ executor::{
ExecutorContext, ExtrudeGroup, Geometry, MemoryItem, Metadata, SketchGroup, SketchGroupSet, SketchSurface, ExecutorContext, ExtrudeGroup, MemoryItem, Metadata, SketchGroup, SketchGroupSet, SketchSurface, SourceRange,
SourceRange,
}, },
std::{kcl_stdlib::KclStdLibFn, sketch::SketchOnFaceTag}, std::{kcl_stdlib::KclStdLibFn, sketch::SketchOnFaceTag},
}; };
@ -72,8 +71,10 @@ lazy_static! {
Box::new(crate::std::sketch::TangentialArcTo), Box::new(crate::std::sketch::TangentialArcTo),
Box::new(crate::std::sketch::BezierCurve), Box::new(crate::std::sketch::BezierCurve),
Box::new(crate::std::sketch::Hole), Box::new(crate::std::sketch::Hole),
Box::new(crate::std::patterns::PatternLinear), Box::new(crate::std::patterns::PatternLinear2D),
Box::new(crate::std::patterns::PatternCircular), Box::new(crate::std::patterns::PatternLinear3D),
Box::new(crate::std::patterns::PatternCircular2D),
Box::new(crate::std::patterns::PatternCircular3D),
Box::new(crate::std::fillet::Fillet), Box::new(crate::std::fillet::Fillet),
Box::new(crate::std::fillet::GetOppositeEdge), Box::new(crate::std::fillet::GetOppositeEdge),
Box::new(crate::std::fillet::GetNextAdjacentEdge), Box::new(crate::std::fillet::GetNextAdjacentEdge),
@ -522,49 +523,6 @@ impl Args {
Ok((data, sketch_group)) Ok((data, sketch_group))
} }
fn get_data_and_geometry<T: serde::de::DeserializeOwned>(&self) -> Result<(T, Geometry), 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 geometry = if let MemoryItem::SketchGroup(sg) = second_value {
Geometry::SketchGroup(sg.clone())
} else if let MemoryItem::ExtrudeGroup(eg) = second_value {
Geometry::ExtrudeGroup(eg.clone())
} else {
return Err(KclError::Type(KclErrorDetails {
message: format!(
"Expected a SketchGroup or ExtrudeGroup as the second argument, found `{:?}`",
self.args
),
source_ranges: vec![self.source_range],
}));
};
Ok((data, geometry))
}
fn get_data_and_sketch_surface<T: serde::de::DeserializeOwned>(&self) -> Result<(T, SketchSurface), KclError> { fn get_data_and_sketch_surface<T: serde::de::DeserializeOwned>(&self) -> Result<(T, SketchSurface), KclError> {
let first_value = self let first_value = self
.args .args

View File

@ -8,47 +8,71 @@ use serde::{Deserialize, Serialize};
use crate::{ use crate::{
errors::{KclError, KclErrorDetails}, errors::{KclError, KclErrorDetails},
executor::{Geometries, Geometry, MemoryItem}, executor::{ExtrudeGroup, Geometries, Geometry, MemoryItem, SketchGroup},
std::Args, std::Args,
}; };
/// Data for a linear pattern. /// Data for a linear pattern on a 2D sketch.
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema)] #[derive(Debug, Clone, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema)]
#[ts(export)] #[ts(export)]
#[serde(rename_all = "camelCase")] #[serde(rename_all = "camelCase")]
pub struct LinearPatternData { pub struct LinearPattern2dData {
/// The number of repetitions. Must be greater than 0. /// The number of repetitions. Must be greater than 0.
/// This excludes the original entity. For example, if `repetitions` is 1, /// This excludes the original entity. For example, if `repetitions` is 1,
/// the original entity will be copied once. /// the original entity will be copied once.
pub repetitions: usize, pub repetitions: u32,
/// The distance between each repetition. This can also be referred to as spacing. /// The distance between each repetition. This can also be referred to as spacing.
pub distance: f64, pub distance: f64,
/// The axis of the pattern. This is a 2D vector. /// The axis of the pattern. This is a 2D vector.
pub axis: [f64; 2], pub axis: [f64; 2],
} }
/// Data for a circular pattern. /// Data for a linear pattern on a 3D model.
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema)] #[derive(Debug, Clone, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema)]
#[ts(export)] #[ts(export)]
#[serde(rename_all = "camelCase")] #[serde(rename_all = "camelCase")]
pub struct CircularPatternData { pub struct LinearPattern3dData {
/// The number of repetitions. Must be greater than 0. /// The number of repetitions. Must be greater than 0.
/// This excludes the original entity. For example, if `repetitions` is 1, /// This excludes the original entity. For example, if `repetitions` is 1,
/// the original entity will be copied once. /// the original entity will be copied once.
pub repetitions: usize, pub repetitions: u32,
/// The axis around which to make the pattern. This is a 2D vector. /// The distance between each repetition. This can also be referred to as spacing.
pub axis: [f64; 2], pub distance: f64,
/// The center about which to make th pattern. This is a 3D vector. /// The axis of the pattern.
pub center: [f64; 3], pub axis: [f64; 3],
/// The arc angle (in degrees) to place the repetitions. Must be greater than 0.
pub arc_degrees: f64,
/// Whether or not to rotate the duplicates as they are copied.
pub rotate_duplicates: bool,
} }
/// A linear pattern. pub enum LinearPattern {
pub async fn pattern_linear(args: Args) -> Result<MemoryItem, KclError> { ThreeD(LinearPattern3dData),
let (data, geometry): (LinearPatternData, Geometry) = args.get_data_and_geometry()?; TwoD(LinearPattern2dData),
}
impl LinearPattern {
pub fn axis(&self) -> [f64; 3] {
match self {
LinearPattern::TwoD(lp) => [lp.axis[0], lp.axis[1], 0.0],
LinearPattern::ThreeD(lp) => lp.axis,
}
}
pub fn repetitions(&self) -> u32 {
match self {
LinearPattern::TwoD(lp) => lp.repetitions,
LinearPattern::ThreeD(lp) => lp.repetitions,
}
}
pub fn distance(&self) -> f64 {
match self {
LinearPattern::TwoD(lp) => lp.distance,
LinearPattern::ThreeD(lp) => lp.distance,
}
}
}
/// 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()?;
if data.axis == [0.0, 0.0] { if data.axis == [0.0, 0.0] {
return Err(KclError::Semantic(KclErrorDetails { return Err(KclError::Semantic(KclErrorDetails {
@ -59,38 +83,80 @@ pub async fn pattern_linear(args: Args) -> Result<MemoryItem, KclError> {
})); }));
} }
let new_geometries = inner_pattern_linear(data, geometry, args).await?; let sketch_groups = inner_pattern_linear_2d(data, sketch_group, args).await?;
match new_geometries { Ok(MemoryItem::SketchGroups { value: sketch_groups })
Geometries::SketchGroups(sketch_groups) => Ok(MemoryItem::SketchGroups { value: sketch_groups }),
Geometries::ExtrudeGroups(extrude_groups) => Ok(MemoryItem::ExtrudeGroups { value: extrude_groups }),
}
} }
/// A circular pattern. /// A linear pattern on a 2D sketch.
pub async fn pattern_circular(args: Args) -> Result<MemoryItem, KclError> { #[stdlib {
let (data, geometry): (CircularPatternData, Geometry) = args.get_data_and_geometry()?; name = "patternLinear2d",
}]
async fn inner_pattern_linear_2d(
data: LinearPattern2dData,
sketch_group: Box<SketchGroup>,
args: Args,
) -> Result<Vec<Box<SketchGroup>>, KclError> {
let geometries = pattern_linear(
LinearPattern::TwoD(data),
Geometry::SketchGroup(sketch_group),
args.clone(),
)
.await?;
if data.axis == [0.0, 0.0] { let Geometries::SketchGroups(sketch_groups) = geometries else {
return Err(KclError::Semantic(KclErrorDetails {
message: "Expected a vec of sketch groups".to_string(),
source_ranges: vec![args.source_range],
}));
};
Ok(sketch_groups)
}
/// 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()?;
if data.axis == [0.0, 0.0, 0.0] {
return Err(KclError::Semantic(KclErrorDetails { return Err(KclError::Semantic(KclErrorDetails {
message: message:
"The axis of the circular pattern cannot be the zero vector. Otherwise they will just duplicate in place." "The axis of the linear pattern cannot be the zero vector. Otherwise they will just duplicate in place."
.to_string(), .to_string(),
source_ranges: vec![args.source_range], source_ranges: vec![args.source_range],
})); }));
} }
let new_geometries = inner_pattern_circular(data, geometry, args).await?; let extrude_groups = inner_pattern_linear_3d(data, extrude_group, args).await?;
match new_geometries { Ok(MemoryItem::ExtrudeGroups { value: extrude_groups })
Geometries::SketchGroups(sketch_groups) => Ok(MemoryItem::SketchGroups { value: sketch_groups }),
Geometries::ExtrudeGroups(extrude_groups) => Ok(MemoryItem::ExtrudeGroups { value: extrude_groups }),
}
} }
/// A linear pattern. /// A linear pattern on a 3D model.
#[stdlib { #[stdlib {
name = "patternLinear", name = "patternLinear3d",
}] }]
async fn inner_pattern_linear(data: LinearPatternData, geometry: Geometry, args: Args) -> Result<Geometries, KclError> { async fn inner_pattern_linear_3d(
data: LinearPattern3dData,
extrude_group: Box<ExtrudeGroup>,
args: Args,
) -> Result<Vec<Box<ExtrudeGroup>>, KclError> {
let geometries = pattern_linear(
LinearPattern::ThreeD(data),
Geometry::ExtrudeGroup(extrude_group),
args.clone(),
)
.await?;
let Geometries::ExtrudeGroups(extrude_groups) = geometries else {
return Err(KclError::Semantic(KclErrorDetails {
message: "Expected a vec of extrude groups".to_string(),
source_ranges: vec![args.source_range],
}));
};
Ok(extrude_groups)
}
async fn pattern_linear(data: LinearPattern, geometry: Geometry, args: Args) -> Result<Geometries, KclError> {
let id = uuid::Uuid::new_v4(); let id = uuid::Uuid::new_v4();
let resp = args let resp = args
@ -98,13 +164,13 @@ async fn inner_pattern_linear(data: LinearPatternData, geometry: Geometry, args:
id, id,
ModelingCmd::EntityLinearPattern { ModelingCmd::EntityLinearPattern {
axis: kittycad::types::Point3D { axis: kittycad::types::Point3D {
x: data.axis[0], x: data.axis()[0],
y: data.axis[1], y: data.axis()[1],
z: 0.0, z: data.axis()[2],
}, },
entity_id: geometry.id(), entity_id: geometry.id(),
num_repetitions: data.repetitions as u32, num_repetitions: data.repetitions(),
spacing: data.distance, spacing: data.distance(),
}, },
) )
.await?; .await?;
@ -143,15 +209,153 @@ async fn inner_pattern_linear(data: LinearPatternData, geometry: Geometry, args:
Ok(geometries) Ok(geometries)
} }
/// A Circular pattern. /// Data for a circular pattern on a 2D sketch.
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema)]
#[ts(export)]
#[serde(rename_all = "camelCase")]
pub struct CircularPattern2dData {
/// The number of repetitions. Must be greater than 0.
/// This excludes the original entity. For example, if `repetitions` is 1,
/// the original entity will be copied once.
pub repetitions: u32,
/// The center about which to make th pattern. This is a 2D vector.
pub center: [f64; 2],
/// The arc angle (in degrees) to place the repetitions. Must be greater than 0.
pub arc_degrees: f64,
/// Whether or not to rotate the duplicates as they are copied.
pub rotate_duplicates: bool,
}
/// Data for a circular pattern on a 3D model.
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema)]
#[ts(export)]
#[serde(rename_all = "camelCase")]
pub struct CircularPattern3dData {
/// The number of repetitions. Must be greater than 0.
/// This excludes the original entity. For example, if `repetitions` is 1,
/// the original entity will be copied once.
pub repetitions: u32,
/// The axis around which to make the pattern. This is a 3D vector.
pub axis: [f64; 3],
/// The center about which to make th pattern. This is a 3D vector.
pub center: [f64; 3],
/// The arc angle (in degrees) to place the repetitions. Must be greater than 0.
pub arc_degrees: f64,
/// Whether or not to rotate the duplicates as they are copied.
pub rotate_duplicates: bool,
}
pub enum CircularPattern {
ThreeD(CircularPattern3dData),
TwoD(CircularPattern2dData),
}
impl CircularPattern {
pub fn axis(&self) -> [f64; 3] {
match self {
CircularPattern::TwoD(_lp) => [0.0, 0.0, 0.0],
CircularPattern::ThreeD(lp) => lp.axis,
}
}
pub fn center(&self) -> [f64; 3] {
match self {
CircularPattern::TwoD(lp) => [lp.center[0], lp.center[1], 0.0],
CircularPattern::ThreeD(lp) => lp.center,
}
}
pub fn repetitions(&self) -> u32 {
match self {
CircularPattern::TwoD(lp) => lp.repetitions,
CircularPattern::ThreeD(lp) => lp.repetitions,
}
}
pub fn arc_degrees(&self) -> f64 {
match self {
CircularPattern::TwoD(lp) => lp.arc_degrees,
CircularPattern::ThreeD(lp) => lp.arc_degrees,
}
}
pub fn rotate_duplicates(&self) -> bool {
match self {
CircularPattern::TwoD(lp) => lp.rotate_duplicates,
CircularPattern::ThreeD(lp) => lp.rotate_duplicates,
}
}
}
/// 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 sketch_groups = inner_pattern_circular_2d(data, sketch_group, args).await?;
Ok(MemoryItem::SketchGroups { value: sketch_groups })
}
/// A circular pattern on a 2D sketch.
#[stdlib { #[stdlib {
name = "patternCircular", name = "patternCircular2d",
}] }]
async fn inner_pattern_circular( async fn inner_pattern_circular_2d(
data: CircularPatternData, data: CircularPattern2dData,
geometry: Geometry, sketch_group: Box<SketchGroup>,
args: Args, args: Args,
) -> Result<Geometries, KclError> { ) -> Result<Vec<Box<SketchGroup>>, KclError> {
let geometries = pattern_circular(
CircularPattern::TwoD(data),
Geometry::SketchGroup(sketch_group),
args.clone(),
)
.await?;
let Geometries::SketchGroups(sketch_groups) = geometries else {
return Err(KclError::Semantic(KclErrorDetails {
message: "Expected a vec of sketch groups".to_string(),
source_ranges: vec![args.source_range],
}));
};
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 extrude_groups = inner_pattern_circular_3d(data, extrude_group, args).await?;
Ok(MemoryItem::ExtrudeGroups { value: extrude_groups })
}
/// A circular pattern on a 3D model.
#[stdlib {
name = "patternCircular3d",
}]
async fn inner_pattern_circular_3d(
data: CircularPattern3dData,
extrude_group: Box<ExtrudeGroup>,
args: Args,
) -> Result<Vec<Box<ExtrudeGroup>>, KclError> {
let geometries = pattern_circular(
CircularPattern::ThreeD(data),
Geometry::ExtrudeGroup(extrude_group),
args.clone(),
)
.await?;
let Geometries::ExtrudeGroups(extrude_groups) = geometries else {
return Err(KclError::Semantic(KclErrorDetails {
message: "Expected a vec of extrude groups".to_string(),
source_ranges: vec![args.source_range],
}));
};
Ok(extrude_groups)
}
async fn pattern_circular(data: CircularPattern, geometry: Geometry, args: Args) -> Result<Geometries, KclError> {
let id = uuid::Uuid::new_v4(); let id = uuid::Uuid::new_v4();
let resp = args let resp = args
@ -159,15 +363,15 @@ async fn inner_pattern_circular(
id, id,
ModelingCmd::EntityCircularPattern { ModelingCmd::EntityCircularPattern {
axis: kittycad::types::Point3D { axis: kittycad::types::Point3D {
x: data.axis[0], x: data.axis()[0],
y: data.axis[1], y: data.axis()[1],
z: 0.0, z: data.axis()[2],
}, },
entity_id: geometry.id(), entity_id: geometry.id(),
center: data.center.into(), center: data.center().into(),
num_repetitions: data.repetitions as u32, num_repetitions: data.repetitions(),
arc_degrees: data.arc_degrees, arc_degrees: data.arc_degrees(),
rotate_duplicates: data.rotate_duplicates, rotate_duplicates: data.rotate_duplicates(),
}, },
) )
.await?; .await?;

View File

@ -815,7 +815,7 @@ async fn serial_test_top_level_expression() {
async fn serial_test_patterns_linear_basic() { async fn serial_test_patterns_linear_basic() {
let code = r#"const part = startSketchOn('XY') let code = r#"const part = startSketchOn('XY')
|> circle([0,0], 2, %) |> circle([0,0], 2, %)
|> patternLinear({axis: [0,1], repetitions: 12, distance: 2}, %) |> patternLinear2d({axis: [0,1], repetitions: 12, distance: 2}, %)
"#; "#;
let result = execute_and_snapshot(code, kittycad::types::UnitLength::Mm) let result = execute_and_snapshot(code, kittycad::types::UnitLength::Mm)
@ -833,7 +833,7 @@ async fn serial_test_patterns_linear_basic_3d() {
|> line([0, -1], %) |> line([0, -1], %)
|> close(%) |> close(%)
|> extrude(1, %) |> extrude(1, %)
|> patternLinear({axis: [1, 0], repetitions: 3, distance: 6}, %) |> patternLinear3d({axis: [1, 0, 1], repetitions: 3, distance: 6}, %)
"#; "#;
let result = execute_and_snapshot(code, kittycad::types::UnitLength::Mm) let result = execute_and_snapshot(code, kittycad::types::UnitLength::Mm)
@ -846,7 +846,7 @@ async fn serial_test_patterns_linear_basic_3d() {
async fn serial_test_patterns_linear_basic_negative_distance() { async fn serial_test_patterns_linear_basic_negative_distance() {
let code = r#"const part = startSketchOn('XY') let code = r#"const part = startSketchOn('XY')
|> circle([0,0], 2, %) |> circle([0,0], 2, %)
|> patternLinear({axis: [0,1], repetitions: 12, distance: -2}, %) |> patternLinear2d({axis: [0,1], repetitions: 12, distance: -2}, %)
"#; "#;
let result = execute_and_snapshot(code, kittycad::types::UnitLength::Mm) let result = execute_and_snapshot(code, kittycad::types::UnitLength::Mm)
@ -863,7 +863,7 @@ async fn serial_test_patterns_linear_basic_negative_distance() {
async fn serial_test_patterns_linear_basic_negative_axis() { async fn serial_test_patterns_linear_basic_negative_axis() {
let code = r#"const part = startSketchOn('XY') let code = r#"const part = startSketchOn('XY')
|> circle([0,0], 2, %) |> circle([0,0], 2, %)
|> patternLinear({axis: [0,-1], repetitions: 12, distance: 2}, %) |> patternLinear2d({axis: [0,-1], repetitions: 12, distance: 2}, %)
"#; "#;
let result = execute_and_snapshot(code, kittycad::types::UnitLength::Mm) let result = execute_and_snapshot(code, kittycad::types::UnitLength::Mm)
@ -880,7 +880,7 @@ async fn serial_test_patterns_linear_basic_negative_axis() {
async fn serial_test_patterns_linear_basic_holes() { async fn serial_test_patterns_linear_basic_holes() {
let code = r#"const circles = startSketchOn('XY') let code = r#"const circles = startSketchOn('XY')
|> circle([5, 5], 1, %) |> circle([5, 5], 1, %)
|> patternLinear({axis: [1,1], repetitions: 12, distance: 3}, %) |> patternLinear2d({axis: [1,1], repetitions: 12, distance: 3}, %)
const rectangle = startSketchOn('XY') const rectangle = startSketchOn('XY')
|> startProfileAt([0, 0], %) |> startProfileAt([0, 0], %)
@ -902,7 +902,7 @@ const rectangle = startSketchOn('XY')
async fn serial_test_patterns_circular_basic_2d() { async fn serial_test_patterns_circular_basic_2d() {
let code = r#"const part = startSketchOn('XY') let code = r#"const part = startSketchOn('XY')
|> circle([0,0], 2, %) |> circle([0,0], 2, %)
|> patternCircular({axis: [0,1], center: [20, 20, 20], repetitions: 12, arcDegrees: 210, rotateDuplicates: true}, %) |> patternCircular2d({center: [20, 20], repetitions: 12, arcDegrees: 210, rotateDuplicates: true}, %)
"#; "#;
let result = execute_and_snapshot(code, kittycad::types::UnitLength::Mm) let result = execute_and_snapshot(code, kittycad::types::UnitLength::Mm)
@ -920,7 +920,7 @@ async fn serial_test_patterns_circular_basic_3d() {
|> line([0, -1], %) |> line([0, -1], %)
|> close(%) |> close(%)
|> extrude(1, %) |> extrude(1, %)
|> patternCircular({axis: [0,1], center: [-20, -20, -20], repetitions: 40, arcDegrees: 360, rotateDuplicates: false}, %) |> patternCircular3d({axis: [0,0, 1], center: [-20, -20, -20], repetitions: 40, arcDegrees: 360, rotateDuplicates: false}, %)
"#; "#;
let result = execute_and_snapshot(code, kittycad::types::UnitLength::Mm) let result = execute_and_snapshot(code, kittycad::types::UnitLength::Mm)
@ -938,7 +938,7 @@ async fn serial_test_patterns_circular_3d_tilted_axis() {
|> line([0, -1], %) |> line([0, -1], %)
|> close(%) |> close(%)
|> extrude(1, %) |> extrude(1, %)
|> patternCircular({axis: [1,1], center: [10, 0, 10], repetitions: 10, arcDegrees: 360, rotateDuplicates: true}, %) |> patternCircular3d({axis: [1,1,0], center: [10, 0, 10], repetitions: 10, arcDegrees: 360, rotateDuplicates: true}, %)
"#; "#;
let result = execute_and_snapshot(code, kittycad::types::UnitLength::Mm) let result = execute_and_snapshot(code, kittycad::types::UnitLength::Mm)

Binary file not shown.

Before

Width:  |  Height:  |  Size: 102 KiB

After

Width:  |  Height:  |  Size: 106 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 93 KiB

After

Width:  |  Height:  |  Size: 93 KiB