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:
5571
docs/kcl/std.json
5571
docs/kcl/std.json
File diff suppressed because it is too large
Load Diff
130
docs/kcl/std.md
130
docs/kcl/std.md
@ -46,8 +46,10 @@
|
||||
* [`log2`](#log2)
|
||||
* [`max`](#max)
|
||||
* [`min`](#min)
|
||||
* [`patternCircular`](#patternCircular)
|
||||
* [`patternLinear`](#patternLinear)
|
||||
* [`patternCircular2d`](#patternCircular2d)
|
||||
* [`patternCircular3d`](#patternCircular3d)
|
||||
* [`patternLinear2d`](#patternLinear2d)
|
||||
* [`patternLinear3d`](#patternLinear3d)
|
||||
* [`pi`](#pi)
|
||||
* [`pow`](#pow)
|
||||
* [`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
|
||||
|
||||
* `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.
|
||||
arcDegrees: number,
|
||||
// The axis around which to make the pattern. This is a 2D vector.
|
||||
axis: [number, number],
|
||||
// The center about which to make th pattern. This is a 3D vector.
|
||||
center: [number, number, number],
|
||||
// The center about which to make th pattern. This is a 2D vector.
|
||||
center: [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,
|
||||
}
|
||||
```
|
||||
* `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.
|
||||
@ -7276,7 +7276,6 @@ patternCircular(data: CircularPatternData, geometry: Geometry) -> Geometries
|
||||
// The to point.
|
||||
to: [number, number],
|
||||
},
|
||||
type: "SketchGroup",
|
||||
// The paths in the sketch group.
|
||||
value: [{
|
||||
// The from point.
|
||||
@ -7360,7 +7359,44 @@ patternCircular(data: CircularPatternData, geometry: Geometry) -> Geometries
|
||||
y: 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
|
||||
endCapId: uuid,
|
||||
@ -7439,7 +7475,6 @@ patternCircular(data: CircularPatternData, geometry: Geometry) -> Geometries
|
||||
}],
|
||||
// The id of the extrusion start cap
|
||||
startCapId: uuid,
|
||||
type: "ExtrudeGroup",
|
||||
// The extrude surfaces.
|
||||
value: [{
|
||||
// The face id for the extrude plane.
|
||||
@ -7494,31 +7529,23 @@ patternCircular(data: CircularPatternData, geometry: Geometry) -> Geometries
|
||||
|
||||
#### Returns
|
||||
|
||||
* `Geometries` - A set of geometry.
|
||||
```
|
||||
{
|
||||
type: "SketchGroups",
|
||||
} |
|
||||
{
|
||||
type: "ExtrudeGroups",
|
||||
}
|
||||
```
|
||||
* `[ExtrudeGroup]`
|
||||
|
||||
|
||||
|
||||
### 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
|
||||
|
||||
* `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.
|
||||
@ -7529,7 +7556,7 @@ patternLinear(data: LinearPatternData, geometry: Geometry) -> Geometries
|
||||
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.
|
||||
@ -7608,7 +7635,6 @@ patternLinear(data: LinearPatternData, geometry: Geometry) -> Geometries
|
||||
// The to point.
|
||||
to: [number, number],
|
||||
},
|
||||
type: "SketchGroup",
|
||||
// The paths in the sketch group.
|
||||
value: [{
|
||||
// The from point.
|
||||
@ -7692,7 +7718,40 @@ patternLinear(data: LinearPatternData, geometry: Geometry) -> Geometries
|
||||
y: 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
|
||||
endCapId: uuid,
|
||||
@ -7771,7 +7830,6 @@ patternLinear(data: LinearPatternData, geometry: Geometry) -> Geometries
|
||||
}],
|
||||
// The id of the extrusion start cap
|
||||
startCapId: uuid,
|
||||
type: "ExtrudeGroup",
|
||||
// The extrude surfaces.
|
||||
value: [{
|
||||
// The face id for the extrude plane.
|
||||
@ -7826,15 +7884,7 @@ patternLinear(data: LinearPatternData, geometry: Geometry) -> Geometries
|
||||
|
||||
#### Returns
|
||||
|
||||
* `Geometries` - A set of geometry.
|
||||
```
|
||||
{
|
||||
type: "SketchGroups",
|
||||
} |
|
||||
{
|
||||
type: "ExtrudeGroups",
|
||||
}
|
||||
```
|
||||
* `[ExtrudeGroup]`
|
||||
|
||||
|
||||
|
||||
|
20
src/wasm-lib/Cargo.lock
generated
20
src/wasm-lib/Cargo.lock
generated
@ -947,7 +947,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "derive-docs"
|
||||
version = "0.1.9"
|
||||
version = "0.1.10"
|
||||
dependencies = [
|
||||
"convert_case",
|
||||
"expectorate",
|
||||
@ -962,22 +962,6 @@ dependencies = [
|
||||
"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]]
|
||||
name = "diesel_derives"
|
||||
version = "2.1.2"
|
||||
@ -1918,7 +1902,7 @@ dependencies = [
|
||||
"criterion",
|
||||
"dashmap",
|
||||
"databake",
|
||||
"derive-docs 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"derive-docs",
|
||||
"expectorate",
|
||||
"futures",
|
||||
"gltf-json",
|
||||
|
@ -1,7 +1,7 @@
|
||||
[package]
|
||||
name = "derive-docs"
|
||||
description = "A tool for generating documentation from Rust derive macros"
|
||||
version = "0.1.9"
|
||||
version = "0.1.10"
|
||||
edition = "2021"
|
||||
license = "MIT"
|
||||
repository = "https://github.com/KittyCAD/modeling-app"
|
||||
|
@ -223,31 +223,59 @@ fn do_stdlib_inner(
|
||||
}
|
||||
}
|
||||
|
||||
let ret_ty = ast.sig.output.clone();
|
||||
let ret_ty_string = ret_ty
|
||||
.into_token_stream()
|
||||
.to_string()
|
||||
.replace("-> ", "")
|
||||
.replace("Result < ", "")
|
||||
.replace(", KclError >", "");
|
||||
let return_type = if !ret_ty_string.is_empty() {
|
||||
let ret_ty_string = if ret_ty_string.starts_with("Box <") {
|
||||
ret_ty_string
|
||||
.trim_start_matches("Box <")
|
||||
.trim_end_matches(' ')
|
||||
.trim_end_matches('>')
|
||||
.trim()
|
||||
.to_string()
|
||||
let return_type_inner = match &ast.sig.output {
|
||||
syn::ReturnType::Default => quote! { () },
|
||||
syn::ReturnType::Type(_, ty) => {
|
||||
// Get the inside of the result.
|
||||
match &**ty {
|
||||
syn::Type::Path(syn::TypePath { path, .. }) => {
|
||||
let path = &path.segments;
|
||||
if path.len() == 1 {
|
||||
let seg = &path[0];
|
||||
if seg.ident == "Result" {
|
||||
if let syn::PathArguments::AngleBracketed(syn::AngleBracketedGenericArguments {
|
||||
args,
|
||||
..
|
||||
}) = &seg.arguments
|
||||
{
|
||||
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 {
|
||||
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);
|
||||
quote! {
|
||||
Some(#docs_crate::StdLibFnArg {
|
||||
name: "".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,
|
||||
})
|
||||
}
|
||||
@ -547,6 +575,93 @@ fn parse_array_type(type_name: &str) -> Option<(&str, usize)> {
|
||||
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)]
|
||||
mod tests {
|
||||
|
||||
@ -672,7 +787,7 @@ mod tests {
|
||||
fn inner_show(
|
||||
/// The args to do shit to.
|
||||
args: Option<f64>
|
||||
) -> Box<f64> {
|
||||
) -> Result<Box<f64>> {
|
||||
args
|
||||
}
|
||||
},
|
||||
@ -693,7 +808,7 @@ mod tests {
|
||||
fn inner_show(
|
||||
/// The args to do shit to.
|
||||
args: [f64; 2]
|
||||
) -> Box<f64> {
|
||||
) -> Result<Box<f64>> {
|
||||
args
|
||||
}
|
||||
},
|
||||
@ -714,7 +829,7 @@ mod tests {
|
||||
fn inner_import(
|
||||
/// The args to do shit to.
|
||||
args: Option<kittycad::types::InputFormat>
|
||||
) -> Box<f64> {
|
||||
) -> Result<Box<f64>> {
|
||||
args
|
||||
}
|
||||
},
|
||||
@ -727,4 +842,52 @@ mod tests {
|
||||
&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(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -55,7 +55,7 @@ impl crate::docs::StdLibFn for Show {
|
||||
Some(crate::docs::StdLibFnArg {
|
||||
name: "".to_string(),
|
||||
type_: "number".to_string(),
|
||||
schema: f64::json_schema(&mut generator),
|
||||
schema: <f64>::json_schema(&mut generator),
|
||||
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
|
||||
}
|
||||
|
@ -55,7 +55,7 @@ impl crate::docs::StdLibFn for Show {
|
||||
Some(crate::docs::StdLibFnArg {
|
||||
name: "".to_string(),
|
||||
type_: "number".to_string(),
|
||||
schema: f64::json_schema(&mut generator),
|
||||
schema: <f64>::json_schema(&mut generator),
|
||||
required: true,
|
||||
})
|
||||
}
|
||||
|
@ -63,7 +63,7 @@ impl crate::docs::StdLibFn for LineTo {
|
||||
Some(crate::docs::StdLibFnArg {
|
||||
name: "".to_string(),
|
||||
type_: "SketchGroup".to_string(),
|
||||
schema: SketchGroup::json_schema(&mut generator),
|
||||
schema: <SketchGroup>::json_schema(&mut generator),
|
||||
required: true,
|
||||
})
|
||||
}
|
||||
|
@ -55,7 +55,7 @@ impl crate::docs::StdLibFn for Min {
|
||||
Some(crate::docs::StdLibFnArg {
|
||||
name: "".to_string(),
|
||||
type_: "number".to_string(),
|
||||
schema: f64::json_schema(&mut generator),
|
||||
schema: <f64>::json_schema(&mut generator),
|
||||
required: true,
|
||||
})
|
||||
}
|
||||
|
@ -55,7 +55,7 @@ impl crate::docs::StdLibFn for Show {
|
||||
Some(crate::docs::StdLibFnArg {
|
||||
name: "".to_string(),
|
||||
type_: "number".to_string(),
|
||||
schema: f64::json_schema(&mut generator),
|
||||
schema: <f64>::json_schema(&mut generator),
|
||||
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
|
||||
}
|
||||
|
@ -55,7 +55,7 @@ impl crate::docs::StdLibFn for Import {
|
||||
Some(crate::docs::StdLibFnArg {
|
||||
name: "".to_string(),
|
||||
type_: "number".to_string(),
|
||||
schema: f64::json_schema(&mut generator),
|
||||
schema: <f64>::json_schema(&mut generator),
|
||||
required: true,
|
||||
})
|
||||
}
|
||||
@ -79,6 +79,6 @@ impl crate::docs::StdLibFn for Import {
|
||||
|
||||
fn inner_import(
|
||||
#[doc = r" The args to do shit to."] args: Option<kittycad::types::InputFormat>,
|
||||
) -> Box<f64> {
|
||||
) -> Result<Box<f64>> {
|
||||
args
|
||||
}
|
||||
|
@ -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
|
||||
}
|
84
src/wasm-lib/derive-docs/tests/return_vec_sketch_group.gen
Normal file
84
src/wasm-lib/derive-docs/tests/return_vec_sketch_group.gen
Normal 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
|
||||
}
|
@ -52,7 +52,12 @@ impl crate::docs::StdLibFn for Show {
|
||||
let mut settings = schemars::gen::SchemaSettings::openapi3();
|
||||
settings.inline_subschemas = true;
|
||||
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 {
|
||||
|
@ -17,8 +17,8 @@ async-trait = "0.1.77"
|
||||
clap = { version = "4.5.2", features = ["cargo", "derive", "env", "unicode"], optional = true }
|
||||
dashmap = "5.5.3"
|
||||
databake = { version = "0.1.7", features = ["derive"] }
|
||||
derive-docs = { version = "0.1.9" }
|
||||
#derive-docs = { path = "../derive-docs" }
|
||||
#derive-docs = { version = "0.1.10" }
|
||||
derive-docs = { path = "../derive-docs" }
|
||||
futures = { version = "0.3.30" }
|
||||
gltf-json = "1.4.0"
|
||||
kittycad = { workspace = true }
|
||||
|
@ -310,7 +310,7 @@ pub fn get_type_string_from_schema(schema: &schemars::schema::Schema) -> Result<
|
||||
if let Some(format) = &o.format {
|
||||
if format == "uuid" {
|
||||
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));
|
||||
} else {
|
||||
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 format == "uuid" {
|
||||
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());
|
||||
} else {
|
||||
anyhow::bail!("unknown format: {}", format);
|
||||
|
@ -27,8 +27,7 @@ use crate::{
|
||||
engine::EngineManager,
|
||||
errors::{KclError, KclErrorDetails},
|
||||
executor::{
|
||||
ExecutorContext, ExtrudeGroup, Geometry, MemoryItem, Metadata, SketchGroup, SketchGroupSet, SketchSurface,
|
||||
SourceRange,
|
||||
ExecutorContext, ExtrudeGroup, MemoryItem, Metadata, SketchGroup, SketchGroupSet, SketchSurface, SourceRange,
|
||||
},
|
||||
std::{kcl_stdlib::KclStdLibFn, sketch::SketchOnFaceTag},
|
||||
};
|
||||
@ -72,8 +71,10 @@ lazy_static! {
|
||||
Box::new(crate::std::sketch::TangentialArcTo),
|
||||
Box::new(crate::std::sketch::BezierCurve),
|
||||
Box::new(crate::std::sketch::Hole),
|
||||
Box::new(crate::std::patterns::PatternLinear),
|
||||
Box::new(crate::std::patterns::PatternCircular),
|
||||
Box::new(crate::std::patterns::PatternLinear2D),
|
||||
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::GetOppositeEdge),
|
||||
Box::new(crate::std::fillet::GetNextAdjacentEdge),
|
||||
@ -522,49 +523,6 @@ impl Args {
|
||||
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> {
|
||||
let first_value = self
|
||||
.args
|
||||
|
@ -8,47 +8,71 @@ use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::{
|
||||
errors::{KclError, KclErrorDetails},
|
||||
executor::{Geometries, Geometry, MemoryItem},
|
||||
executor::{ExtrudeGroup, Geometries, Geometry, MemoryItem, SketchGroup},
|
||||
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)]
|
||||
#[ts(export)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct LinearPatternData {
|
||||
pub struct LinearPattern2dData {
|
||||
/// 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: usize,
|
||||
pub repetitions: u32,
|
||||
/// The distance between each repetition. This can also be referred to as spacing.
|
||||
pub distance: f64,
|
||||
/// The axis of the pattern. This is a 2D vector.
|
||||
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)]
|
||||
#[ts(export)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct CircularPatternData {
|
||||
pub struct LinearPattern3dData {
|
||||
/// 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: usize,
|
||||
/// The axis around which to make the pattern. This is a 2D vector.
|
||||
pub axis: [f64; 2],
|
||||
/// 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 repetitions: u32,
|
||||
/// The distance between each repetition. This can also be referred to as spacing.
|
||||
pub distance: f64,
|
||||
/// The axis of the pattern.
|
||||
pub axis: [f64; 3],
|
||||
}
|
||||
|
||||
/// A linear pattern.
|
||||
pub async fn pattern_linear(args: Args) -> Result<MemoryItem, KclError> {
|
||||
let (data, geometry): (LinearPatternData, Geometry) = args.get_data_and_geometry()?;
|
||||
pub enum LinearPattern {
|
||||
ThreeD(LinearPattern3dData),
|
||||
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] {
|
||||
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?;
|
||||
match new_geometries {
|
||||
Geometries::SketchGroups(sketch_groups) => Ok(MemoryItem::SketchGroups { value: sketch_groups }),
|
||||
Geometries::ExtrudeGroups(extrude_groups) => Ok(MemoryItem::ExtrudeGroups { value: extrude_groups }),
|
||||
}
|
||||
let sketch_groups = inner_pattern_linear_2d(data, sketch_group, args).await?;
|
||||
Ok(MemoryItem::SketchGroups { value: sketch_groups })
|
||||
}
|
||||
|
||||
/// A circular pattern.
|
||||
pub async fn pattern_circular(args: Args) -> Result<MemoryItem, KclError> {
|
||||
let (data, geometry): (CircularPatternData, Geometry) = args.get_data_and_geometry()?;
|
||||
/// A linear pattern on a 2D sketch.
|
||||
#[stdlib {
|
||||
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 {
|
||||
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(),
|
||||
source_ranges: vec![args.source_range],
|
||||
}));
|
||||
}
|
||||
|
||||
let new_geometries = inner_pattern_circular(data, geometry, args).await?;
|
||||
match new_geometries {
|
||||
Geometries::SketchGroups(sketch_groups) => Ok(MemoryItem::SketchGroups { value: sketch_groups }),
|
||||
Geometries::ExtrudeGroups(extrude_groups) => Ok(MemoryItem::ExtrudeGroups { value: extrude_groups }),
|
||||
}
|
||||
let extrude_groups = inner_pattern_linear_3d(data, extrude_group, args).await?;
|
||||
Ok(MemoryItem::ExtrudeGroups { value: extrude_groups })
|
||||
}
|
||||
|
||||
/// A linear pattern.
|
||||
/// A linear pattern on a 3D model.
|
||||
#[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 resp = args
|
||||
@ -98,13 +164,13 @@ async fn inner_pattern_linear(data: LinearPatternData, geometry: Geometry, args:
|
||||
id,
|
||||
ModelingCmd::EntityLinearPattern {
|
||||
axis: kittycad::types::Point3D {
|
||||
x: data.axis[0],
|
||||
y: data.axis[1],
|
||||
z: 0.0,
|
||||
x: data.axis()[0],
|
||||
y: data.axis()[1],
|
||||
z: data.axis()[2],
|
||||
},
|
||||
entity_id: geometry.id(),
|
||||
num_repetitions: data.repetitions as u32,
|
||||
spacing: data.distance,
|
||||
num_repetitions: data.repetitions(),
|
||||
spacing: data.distance(),
|
||||
},
|
||||
)
|
||||
.await?;
|
||||
@ -143,15 +209,153 @@ async fn inner_pattern_linear(data: LinearPatternData, geometry: Geometry, args:
|
||||
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 {
|
||||
name = "patternCircular",
|
||||
name = "patternCircular2d",
|
||||
}]
|
||||
async fn inner_pattern_circular(
|
||||
data: CircularPatternData,
|
||||
geometry: Geometry,
|
||||
async fn inner_pattern_circular_2d(
|
||||
data: CircularPattern2dData,
|
||||
sketch_group: Box<SketchGroup>,
|
||||
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 resp = args
|
||||
@ -159,15 +363,15 @@ async fn inner_pattern_circular(
|
||||
id,
|
||||
ModelingCmd::EntityCircularPattern {
|
||||
axis: kittycad::types::Point3D {
|
||||
x: data.axis[0],
|
||||
y: data.axis[1],
|
||||
z: 0.0,
|
||||
x: data.axis()[0],
|
||||
y: data.axis()[1],
|
||||
z: data.axis()[2],
|
||||
},
|
||||
entity_id: geometry.id(),
|
||||
center: data.center.into(),
|
||||
num_repetitions: data.repetitions as u32,
|
||||
arc_degrees: data.arc_degrees,
|
||||
rotate_duplicates: data.rotate_duplicates,
|
||||
center: data.center().into(),
|
||||
num_repetitions: data.repetitions(),
|
||||
arc_degrees: data.arc_degrees(),
|
||||
rotate_duplicates: data.rotate_duplicates(),
|
||||
},
|
||||
)
|
||||
.await?;
|
||||
|
@ -815,7 +815,7 @@ async fn serial_test_top_level_expression() {
|
||||
async fn serial_test_patterns_linear_basic() {
|
||||
let code = r#"const part = startSketchOn('XY')
|
||||
|> 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)
|
||||
@ -833,7 +833,7 @@ async fn serial_test_patterns_linear_basic_3d() {
|
||||
|> line([0, -1], %)
|
||||
|> close(%)
|
||||
|> 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)
|
||||
@ -846,7 +846,7 @@ async fn serial_test_patterns_linear_basic_3d() {
|
||||
async fn serial_test_patterns_linear_basic_negative_distance() {
|
||||
let code = r#"const part = startSketchOn('XY')
|
||||
|> 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)
|
||||
@ -863,7 +863,7 @@ async fn serial_test_patterns_linear_basic_negative_distance() {
|
||||
async fn serial_test_patterns_linear_basic_negative_axis() {
|
||||
let code = r#"const part = startSketchOn('XY')
|
||||
|> 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)
|
||||
@ -880,7 +880,7 @@ async fn serial_test_patterns_linear_basic_negative_axis() {
|
||||
async fn serial_test_patterns_linear_basic_holes() {
|
||||
let code = r#"const circles = startSketchOn('XY')
|
||||
|> circle([5, 5], 1, %)
|
||||
|> patternLinear({axis: [1,1], repetitions: 12, distance: 3}, %)
|
||||
|> patternLinear2d({axis: [1,1], repetitions: 12, distance: 3}, %)
|
||||
|
||||
const rectangle = startSketchOn('XY')
|
||||
|> startProfileAt([0, 0], %)
|
||||
@ -902,7 +902,7 @@ const rectangle = startSketchOn('XY')
|
||||
async fn serial_test_patterns_circular_basic_2d() {
|
||||
let code = r#"const part = startSketchOn('XY')
|
||||
|> 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)
|
||||
@ -920,7 +920,7 @@ async fn serial_test_patterns_circular_basic_3d() {
|
||||
|> line([0, -1], %)
|
||||
|> close(%)
|
||||
|> 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)
|
||||
@ -938,7 +938,7 @@ async fn serial_test_patterns_circular_3d_tilted_axis() {
|
||||
|> line([0, -1], %)
|
||||
|> close(%)
|
||||
|> 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)
|
||||
|
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 |
Reference in New Issue
Block a user