Fillets (#1401)
* add fillet Signed-off-by: Jess Frazelle <github@jessfraz.com> * updates Signed-off-by: Jess Frazelle <github@jessfraz.com> * update tests Signed-off-by: Jess Frazelle <github@jessfraz.com> * fixes Signed-off-by: Jess Frazelle <github@jessfraz.com> * get end cap info Signed-off-by: Jess Frazelle <github@jessfraz.com> * tryu Signed-off-by: Jess Frazelle <github@jessfraz.com> * next-adjacent Signed-off-by: Jess Frazelle <github@jessfraz.com> * fix js tests Signed-off-by: Jess Frazelle <github@jessfraz.com> * works Signed-off-by: Jess Frazelle <github@jessfraz.com> * updates Signed-off-by: Jess Frazelle <github@jessfraz.com> * u[pdates Signed-off-by: Jess Frazelle <github@jessfraz.com> * updates Signed-off-by: Jess Frazelle <github@jessfraz.com> * updates Signed-off-by: Jess Frazelle <github@jessfraz.com> * move back to functions 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:
7573
docs/kcl/std.json
7573
docs/kcl/std.json
File diff suppressed because it is too large
Load Diff
1137
docs/kcl/std.md
1137
docs/kcl/std.md
File diff suppressed because it is too large
Load Diff
@ -80,6 +80,7 @@ const mySketch001 = startSketchOn('XY')
|
|||||||
rotation: [0, 0, 0, 1],
|
rotation: [0, 0, 0, 1],
|
||||||
endCapId: null,
|
endCapId: null,
|
||||||
startCapId: null,
|
startCapId: null,
|
||||||
|
sketchGroupValues: expect.any(Array),
|
||||||
xAxis: { x: 1, y: 0, z: 0 },
|
xAxis: { x: 1, y: 0, z: 0 },
|
||||||
yAxis: { x: 0, y: 1, z: 0 },
|
yAxis: { x: 0, y: 1, z: 0 },
|
||||||
zAxis: { x: 0, y: 0, z: 1 },
|
zAxis: { x: 0, y: 0, z: 1 },
|
||||||
@ -122,6 +123,7 @@ const sk2 = startSketchOn('XY')
|
|||||||
rotation: [0, 0, 0, 1],
|
rotation: [0, 0, 0, 1],
|
||||||
endCapId: null,
|
endCapId: null,
|
||||||
startCapId: null,
|
startCapId: null,
|
||||||
|
sketchGroupValues: expect.any(Array),
|
||||||
xAxis: { x: 1, y: 0, z: 0 },
|
xAxis: { x: 1, y: 0, z: 0 },
|
||||||
yAxis: { x: 0, y: 1, z: 0 },
|
yAxis: { x: 0, y: 1, z: 0 },
|
||||||
zAxis: { x: 0, y: 0, z: 1 },
|
zAxis: { x: 0, y: 0, z: 1 },
|
||||||
@ -137,6 +139,7 @@ const sk2 = startSketchOn('XY')
|
|||||||
|
|
||||||
endCapId: null,
|
endCapId: null,
|
||||||
startCapId: null,
|
startCapId: null,
|
||||||
|
sketchGroupValues: expect.any(Array),
|
||||||
xAxis: { x: 1, y: 0, z: 0 },
|
xAxis: { x: 1, y: 0, z: 0 },
|
||||||
yAxis: { x: 0, y: 1, z: 0 },
|
yAxis: { x: 0, y: 1, z: 0 },
|
||||||
zAxis: { x: 0, y: 0, z: 1 },
|
zAxis: { x: 0, y: 0, z: 1 },
|
||||||
|
4
src/wasm-lib/Cargo.lock
generated
4
src/wasm-lib/Cargo.lock
generated
@ -1952,9 +1952,9 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "kittycad"
|
name = "kittycad"
|
||||||
version = "0.2.58"
|
version = "0.2.59"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "049c3881ffbe77bf1c3a968372a246ce906eceb79f61cd0bc5fa229bec3504cb"
|
checksum = "4080db4364c103601db486e4a8aa889ea56c011991e4c454373d8050a165d3da"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
"anyhow",
|
||||||
"async-trait",
|
"async-trait",
|
||||||
|
@ -58,7 +58,7 @@ members = [
|
|||||||
]
|
]
|
||||||
|
|
||||||
[workspace.dependencies]
|
[workspace.dependencies]
|
||||||
kittycad = { version = "0.2.58", default-features = false, features = ["js", "requests"] }
|
kittycad = { version = "0.2.59", default-features = false, features = ["js", "requests"] }
|
||||||
kittycad-execution-plan = { git = "https://github.com/KittyCAD/modeling-api", branch = "main" }
|
kittycad-execution-plan = { git = "https://github.com/KittyCAD/modeling-api", branch = "main" }
|
||||||
kittycad-execution-plan-macros = { git = "https://github.com/KittyCAD/modeling-api", branch = "main" }
|
kittycad-execution-plan-macros = { git = "https://github.com/KittyCAD/modeling-api", branch = "main" }
|
||||||
kittycad-execution-plan-traits = { git = "https://github.com/KittyCAD/modeling-api", branch = "main" }
|
kittycad-execution-plan-traits = { git = "https://github.com/KittyCAD/modeling-api", branch = "main" }
|
||||||
|
@ -558,6 +558,8 @@ pub struct ExtrudeGroup {
|
|||||||
pub id: uuid::Uuid,
|
pub id: uuid::Uuid,
|
||||||
/// The extrude surfaces.
|
/// The extrude surfaces.
|
||||||
pub value: Vec<ExtrudeSurface>,
|
pub value: Vec<ExtrudeSurface>,
|
||||||
|
/// The sketch group paths.
|
||||||
|
pub sketch_group_values: Vec<Path>,
|
||||||
/// The height of the extrude group.
|
/// The height of the extrude group.
|
||||||
pub height: f64,
|
pub height: f64,
|
||||||
/// The position of the extrude group.
|
/// The position of the extrude group.
|
||||||
|
@ -159,6 +159,7 @@ async fn inner_extrude(length: f64, sketch_group: Box<SketchGroup>, args: Args)
|
|||||||
// sketch group.
|
// sketch group.
|
||||||
id: sketch_group.id,
|
id: sketch_group.id,
|
||||||
value: new_value,
|
value: new_value,
|
||||||
|
sketch_group_values: sketch_group.value.clone(),
|
||||||
height: length,
|
height: length,
|
||||||
position: sketch_group.position,
|
position: sketch_group.position,
|
||||||
rotation: sketch_group.rotation,
|
rotation: sketch_group.rotation,
|
||||||
|
308
src/wasm-lib/kcl/src/std/fillet.rs
Normal file
308
src/wasm-lib/kcl/src/std/fillet.rs
Normal file
@ -0,0 +1,308 @@
|
|||||||
|
//! Standard library fillets.
|
||||||
|
|
||||||
|
use anyhow::Result;
|
||||||
|
use derive_docs::stdlib;
|
||||||
|
use kittycad::types::ModelingCmd;
|
||||||
|
use schemars::JsonSchema;
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
use uuid::Uuid;
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
errors::{KclError, KclErrorDetails},
|
||||||
|
executor::{ExtrudeGroup, ExtrudeSurface, MemoryItem, UserVal},
|
||||||
|
std::Args,
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Data for fillets.
|
||||||
|
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema)]
|
||||||
|
#[ts(export)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
|
pub struct FilletData {
|
||||||
|
/// The radius of the fillet.
|
||||||
|
pub radius: f64,
|
||||||
|
/// The tags of the paths you want to fillet.
|
||||||
|
pub tags: Vec<StringOrUuid>,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A string or a uuid.
|
||||||
|
#[derive(Debug, Clone, Deserialize, Serialize, PartialEq, ts_rs::TS, JsonSchema, Ord, PartialOrd, Eq, Hash)]
|
||||||
|
#[ts(export)]
|
||||||
|
#[serde(untagged)]
|
||||||
|
pub enum StringOrUuid {
|
||||||
|
/// A uuid.
|
||||||
|
Uuid(Uuid),
|
||||||
|
/// A string.
|
||||||
|
String(String),
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Create fillets on tagged paths.
|
||||||
|
pub async fn fillet(args: Args) -> Result<MemoryItem, KclError> {
|
||||||
|
let (data, extrude_group): (FilletData, Box<ExtrudeGroup>) = args.get_data_and_extrude_group()?;
|
||||||
|
|
||||||
|
let extrude_group = inner_fillet(data, extrude_group, args).await?;
|
||||||
|
Ok(MemoryItem::ExtrudeGroup(extrude_group))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Create fillets on tagged paths.
|
||||||
|
#[stdlib {
|
||||||
|
name = "fillet",
|
||||||
|
}]
|
||||||
|
async fn inner_fillet(
|
||||||
|
data: FilletData,
|
||||||
|
extrude_group: Box<ExtrudeGroup>,
|
||||||
|
args: Args,
|
||||||
|
) -> Result<Box<ExtrudeGroup>, KclError> {
|
||||||
|
// Check if tags contains any duplicate values.
|
||||||
|
let mut tags = data.tags.clone();
|
||||||
|
tags.sort();
|
||||||
|
tags.dedup();
|
||||||
|
if tags.len() != data.tags.len() {
|
||||||
|
return Err(KclError::Type(KclErrorDetails {
|
||||||
|
message: "Duplicate tags are not allowed.".to_string(),
|
||||||
|
source_ranges: vec![args.source_range],
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
for tag in data.tags {
|
||||||
|
let edge_id = match tag {
|
||||||
|
StringOrUuid::Uuid(uuid) => uuid,
|
||||||
|
StringOrUuid::String(tag) => {
|
||||||
|
extrude_group
|
||||||
|
.sketch_group_values
|
||||||
|
.iter()
|
||||||
|
.find(|p| p.get_name() == tag)
|
||||||
|
.ok_or_else(|| {
|
||||||
|
KclError::Type(KclErrorDetails {
|
||||||
|
message: format!("No edge found with tag: `{}`", tag),
|
||||||
|
source_ranges: vec![args.source_range],
|
||||||
|
})
|
||||||
|
})?
|
||||||
|
.get_base()
|
||||||
|
.geo_meta
|
||||||
|
.id
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
args.send_modeling_cmd(
|
||||||
|
uuid::Uuid::new_v4(),
|
||||||
|
ModelingCmd::Solid3DFilletEdge {
|
||||||
|
edge_id,
|
||||||
|
object_id: extrude_group.id,
|
||||||
|
radius: data.radius,
|
||||||
|
tolerance: 0.0000001, // We can let the user set this in the future.
|
||||||
|
},
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(extrude_group)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get the opposite edge to the edge given.
|
||||||
|
pub async fn get_opposite_edge(args: Args) -> Result<MemoryItem, KclError> {
|
||||||
|
let (tag, extrude_group): (String, Box<ExtrudeGroup>) = args.get_data_and_extrude_group()?;
|
||||||
|
|
||||||
|
let edge = inner_get_opposite_edge(tag, extrude_group, args.clone()).await?;
|
||||||
|
Ok(MemoryItem::UserVal(UserVal {
|
||||||
|
value: serde_json::to_value(edge).map_err(|e| {
|
||||||
|
KclError::Type(KclErrorDetails {
|
||||||
|
message: format!("Failed to convert Uuid to json: {}", e),
|
||||||
|
source_ranges: vec![args.source_range],
|
||||||
|
})
|
||||||
|
})?,
|
||||||
|
meta: vec![args.source_range.into()],
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get the opposite edge to the edge given.
|
||||||
|
#[stdlib {
|
||||||
|
name = "getOppositeEdge",
|
||||||
|
}]
|
||||||
|
async fn inner_get_opposite_edge(tag: String, extrude_group: Box<ExtrudeGroup>, args: Args) -> Result<Uuid, KclError> {
|
||||||
|
let tagged_path = extrude_group
|
||||||
|
.sketch_group_values
|
||||||
|
.iter()
|
||||||
|
.find(|p| p.get_name() == tag)
|
||||||
|
.ok_or_else(|| {
|
||||||
|
KclError::Type(KclErrorDetails {
|
||||||
|
message: format!("No edge found with tag: `{}`", tag),
|
||||||
|
source_ranges: vec![args.source_range],
|
||||||
|
})
|
||||||
|
})?
|
||||||
|
.get_base();
|
||||||
|
|
||||||
|
let face_id = get_adjacent_face_to_tag(&extrude_group, &tag, &args)?;
|
||||||
|
|
||||||
|
let resp = args
|
||||||
|
.send_modeling_cmd(
|
||||||
|
uuid::Uuid::new_v4(),
|
||||||
|
ModelingCmd::Solid3DGetOppositeEdge {
|
||||||
|
edge_id: tagged_path.geo_meta.id,
|
||||||
|
object_id: extrude_group.id,
|
||||||
|
face_id,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
let kittycad::types::OkWebSocketResponseData::Modeling {
|
||||||
|
modeling_response: kittycad::types::OkModelingCmdResponse::Solid3DGetOppositeEdge { data: opposite_edge },
|
||||||
|
} = &resp
|
||||||
|
else {
|
||||||
|
return Err(KclError::Engine(KclErrorDetails {
|
||||||
|
message: format!("Solid3DGetOppositeEdge response was not as expected: {:?}", resp),
|
||||||
|
source_ranges: vec![args.source_range],
|
||||||
|
}));
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(opposite_edge.edge)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get the next adjacent edge to the edge given.
|
||||||
|
pub async fn get_next_adjacent_edge(args: Args) -> Result<MemoryItem, KclError> {
|
||||||
|
let (tag, extrude_group): (String, Box<ExtrudeGroup>) = args.get_data_and_extrude_group()?;
|
||||||
|
|
||||||
|
let edge = inner_get_next_adjacent_edge(tag, extrude_group, args.clone()).await?;
|
||||||
|
Ok(MemoryItem::UserVal(UserVal {
|
||||||
|
value: serde_json::to_value(edge).map_err(|e| {
|
||||||
|
KclError::Type(KclErrorDetails {
|
||||||
|
message: format!("Failed to convert Uuid to json: {}", e),
|
||||||
|
source_ranges: vec![args.source_range],
|
||||||
|
})
|
||||||
|
})?,
|
||||||
|
meta: vec![args.source_range.into()],
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get the next adjacent edge to the edge given.
|
||||||
|
#[stdlib {
|
||||||
|
name = "getNextAdjacentEdge",
|
||||||
|
}]
|
||||||
|
async fn inner_get_next_adjacent_edge(
|
||||||
|
tag: String,
|
||||||
|
extrude_group: Box<ExtrudeGroup>,
|
||||||
|
args: Args,
|
||||||
|
) -> Result<Uuid, KclError> {
|
||||||
|
let tagged_path = extrude_group
|
||||||
|
.sketch_group_values
|
||||||
|
.iter()
|
||||||
|
.find(|p| p.get_name() == tag)
|
||||||
|
.ok_or_else(|| {
|
||||||
|
KclError::Type(KclErrorDetails {
|
||||||
|
message: format!("No edge found with tag: `{}`", tag),
|
||||||
|
source_ranges: vec![args.source_range],
|
||||||
|
})
|
||||||
|
})?
|
||||||
|
.get_base();
|
||||||
|
|
||||||
|
let face_id = get_adjacent_face_to_tag(&extrude_group, &tag, &args)?;
|
||||||
|
|
||||||
|
let resp = args
|
||||||
|
.send_modeling_cmd(
|
||||||
|
uuid::Uuid::new_v4(),
|
||||||
|
ModelingCmd::Solid3DGetNextAdjacentEdge {
|
||||||
|
edge_id: tagged_path.geo_meta.id,
|
||||||
|
object_id: extrude_group.id,
|
||||||
|
face_id,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
let kittycad::types::OkWebSocketResponseData::Modeling {
|
||||||
|
modeling_response: kittycad::types::OkModelingCmdResponse::Solid3DGetNextAdjacentEdge { data: ajacent_edge },
|
||||||
|
} = &resp
|
||||||
|
else {
|
||||||
|
return Err(KclError::Engine(KclErrorDetails {
|
||||||
|
message: format!("Solid3DGetNextAdjacentEdge response was not as expected: {:?}", resp),
|
||||||
|
source_ranges: vec![args.source_range],
|
||||||
|
}));
|
||||||
|
};
|
||||||
|
|
||||||
|
ajacent_edge.edge.ok_or_else(|| {
|
||||||
|
KclError::Type(KclErrorDetails {
|
||||||
|
message: format!("No edge found next adjacent to tag: `{}`", tag),
|
||||||
|
source_ranges: vec![args.source_range],
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get the previous adjacent edge to the edge given.
|
||||||
|
pub async fn get_previous_adjacent_edge(args: Args) -> Result<MemoryItem, KclError> {
|
||||||
|
let (tag, extrude_group): (String, Box<ExtrudeGroup>) = args.get_data_and_extrude_group()?;
|
||||||
|
|
||||||
|
let edge = inner_get_previous_adjacent_edge(tag, extrude_group, args.clone()).await?;
|
||||||
|
Ok(MemoryItem::UserVal(UserVal {
|
||||||
|
value: serde_json::to_value(edge).map_err(|e| {
|
||||||
|
KclError::Type(KclErrorDetails {
|
||||||
|
message: format!("Failed to convert Uuid to json: {}", e),
|
||||||
|
source_ranges: vec![args.source_range],
|
||||||
|
})
|
||||||
|
})?,
|
||||||
|
meta: vec![args.source_range.into()],
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get the previous adjacent edge to the edge given.
|
||||||
|
#[stdlib {
|
||||||
|
name = "getPreviousAdjacentEdge",
|
||||||
|
}]
|
||||||
|
async fn inner_get_previous_adjacent_edge(
|
||||||
|
tag: String,
|
||||||
|
extrude_group: Box<ExtrudeGroup>,
|
||||||
|
args: Args,
|
||||||
|
) -> Result<Uuid, KclError> {
|
||||||
|
let tagged_path = extrude_group
|
||||||
|
.sketch_group_values
|
||||||
|
.iter()
|
||||||
|
.find(|p| p.get_name() == tag)
|
||||||
|
.ok_or_else(|| {
|
||||||
|
KclError::Type(KclErrorDetails {
|
||||||
|
message: format!("No edge found with tag: `{}`", tag),
|
||||||
|
source_ranges: vec![args.source_range],
|
||||||
|
})
|
||||||
|
})?
|
||||||
|
.get_base();
|
||||||
|
|
||||||
|
let face_id = get_adjacent_face_to_tag(&extrude_group, &tag, &args)?;
|
||||||
|
|
||||||
|
let resp = args
|
||||||
|
.send_modeling_cmd(
|
||||||
|
uuid::Uuid::new_v4(),
|
||||||
|
ModelingCmd::Solid3DGetPrevAdjacentEdge {
|
||||||
|
edge_id: tagged_path.geo_meta.id,
|
||||||
|
object_id: extrude_group.id,
|
||||||
|
face_id,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
.await?;
|
||||||
|
let kittycad::types::OkWebSocketResponseData::Modeling {
|
||||||
|
modeling_response: kittycad::types::OkModelingCmdResponse::Solid3DGetPrevAdjacentEdge { data: ajacent_edge },
|
||||||
|
} = &resp
|
||||||
|
else {
|
||||||
|
return Err(KclError::Engine(KclErrorDetails {
|
||||||
|
message: format!("Solid3DGetPrevAdjacentEdge response was not as expected: {:?}", resp),
|
||||||
|
source_ranges: vec![args.source_range],
|
||||||
|
}));
|
||||||
|
};
|
||||||
|
|
||||||
|
ajacent_edge.edge.ok_or_else(|| {
|
||||||
|
KclError::Type(KclErrorDetails {
|
||||||
|
message: format!("No edge found previous adjacent to tag: `{}`", tag),
|
||||||
|
source_ranges: vec![args.source_range],
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_adjacent_face_to_tag(extrude_group: &ExtrudeGroup, tag: &str, args: &Args) -> Result<uuid::Uuid, KclError> {
|
||||||
|
extrude_group
|
||||||
|
.value
|
||||||
|
.iter()
|
||||||
|
.find_map(|extrude_surface| match extrude_surface {
|
||||||
|
ExtrudeSurface::ExtrudePlane(extrude_plane) if extrude_plane.name == tag => Some(Ok(extrude_plane.face_id)),
|
||||||
|
ExtrudeSurface::ExtrudeArc(extrude_arc) if extrude_arc.name == tag => Some(Ok(extrude_arc.face_id)),
|
||||||
|
ExtrudeSurface::ExtrudePlane(_) | ExtrudeSurface::ExtrudeArc(_) => None,
|
||||||
|
})
|
||||||
|
.ok_or_else(|| {
|
||||||
|
KclError::Type(KclErrorDetails {
|
||||||
|
message: format!("Expected a face with the tag `{}`", tag),
|
||||||
|
source_ranges: vec![args.source_range],
|
||||||
|
})
|
||||||
|
})?
|
||||||
|
}
|
@ -1,6 +1,7 @@
|
|||||||
//! Functions implemented for language execution.
|
//! Functions implemented for language execution.
|
||||||
|
|
||||||
pub mod extrude;
|
pub mod extrude;
|
||||||
|
pub mod fillet;
|
||||||
pub mod import;
|
pub mod import;
|
||||||
pub mod kcl_stdlib;
|
pub mod kcl_stdlib;
|
||||||
pub mod math;
|
pub mod math;
|
||||||
@ -73,6 +74,10 @@ lazy_static! {
|
|||||||
Box::new(crate::std::sketch::Hole),
|
Box::new(crate::std::sketch::Hole),
|
||||||
Box::new(crate::std::patterns::PatternLinear),
|
Box::new(crate::std::patterns::PatternLinear),
|
||||||
Box::new(crate::std::patterns::PatternCircular),
|
Box::new(crate::std::patterns::PatternCircular),
|
||||||
|
Box::new(crate::std::fillet::Fillet),
|
||||||
|
Box::new(crate::std::fillet::GetOppositeEdge),
|
||||||
|
Box::new(crate::std::fillet::GetNextAdjacentEdge),
|
||||||
|
Box::new(crate::std::fillet::GetPreviousAdjacentEdge),
|
||||||
Box::new(crate::std::import::Import),
|
Box::new(crate::std::import::Import),
|
||||||
Box::new(crate::std::math::Cos),
|
Box::new(crate::std::math::Cos),
|
||||||
Box::new(crate::std::math::Sin),
|
Box::new(crate::std::math::Sin),
|
||||||
@ -573,6 +578,50 @@ impl Args {
|
|||||||
Ok((data, sketch_surface))
|
Ok((data, sketch_surface))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn get_data_and_extrude_group<T: serde::de::DeserializeOwned>(&self) -> Result<(T, Box<ExtrudeGroup>), KclError> {
|
||||||
|
let first_value = self
|
||||||
|
.args
|
||||||
|
.first()
|
||||||
|
.ok_or_else(|| {
|
||||||
|
KclError::Type(KclErrorDetails {
|
||||||
|
message: format!("Expected a struct as the first argument, found `{:?}`", self.args),
|
||||||
|
source_ranges: vec![self.source_range],
|
||||||
|
})
|
||||||
|
})?
|
||||||
|
.get_json_value()?;
|
||||||
|
|
||||||
|
let data: T = serde_json::from_value(first_value).map_err(|e| {
|
||||||
|
KclError::Type(KclErrorDetails {
|
||||||
|
message: format!("Failed to deserialize struct from JSON: {}", e),
|
||||||
|
source_ranges: vec![self.source_range],
|
||||||
|
})
|
||||||
|
})?;
|
||||||
|
|
||||||
|
let second_value = self.args.get(1).ok_or_else(|| {
|
||||||
|
KclError::Type(KclErrorDetails {
|
||||||
|
message: format!(
|
||||||
|
"Expected an ExtrudeGroup as the second argument, found `{:?}`",
|
||||||
|
self.args
|
||||||
|
),
|
||||||
|
source_ranges: vec![self.source_range],
|
||||||
|
})
|
||||||
|
})?;
|
||||||
|
|
||||||
|
let extrude_group = if let MemoryItem::ExtrudeGroup(eg) = second_value {
|
||||||
|
eg.clone()
|
||||||
|
} else {
|
||||||
|
return Err(KclError::Type(KclErrorDetails {
|
||||||
|
message: format!(
|
||||||
|
"Expected an ExtrudeGroup as the second argument, found `{:?}`",
|
||||||
|
self.args
|
||||||
|
),
|
||||||
|
source_ranges: vec![self.source_range],
|
||||||
|
}));
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok((data, extrude_group))
|
||||||
|
}
|
||||||
|
|
||||||
fn get_segment_name_to_number_sketch_group(&self) -> Result<(String, f64, Box<SketchGroup>), KclError> {
|
fn get_segment_name_to_number_sketch_group(&self) -> Result<(String, f64, Box<SketchGroup>), KclError> {
|
||||||
// Iterate over our args, the first argument should be a UserVal with a string value.
|
// Iterate over our args, the first argument should be a UserVal with a string value.
|
||||||
// The second argument should be a number.
|
// The second argument should be a number.
|
||||||
|
@ -203,6 +203,107 @@ const part002 = startSketchOn(part001, "END")
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[tokio::test(flavor = "multi_thread")]
|
||||||
|
async fn serial_test_fillet_duplicate_tags() {
|
||||||
|
let code = r#"const part001 = startSketchOn('XY')
|
||||||
|
|> startProfileAt([0,0], %)
|
||||||
|
|> line({to: [0, 10], tag: "thing"}, %)
|
||||||
|
|> line([10, 0], %)
|
||||||
|
|> line({to: [0, -10], tag: "thing2"}, %)
|
||||||
|
|> close(%)
|
||||||
|
|> extrude(10, %)
|
||||||
|
|> fillet({radius: 0.5, tags: ["thing", "thing"]}, %)
|
||||||
|
"#;
|
||||||
|
|
||||||
|
let result = execute_and_snapshot(code, kittycad::types::UnitLength::Mm).await;
|
||||||
|
assert!(result.is_err());
|
||||||
|
assert_eq!(
|
||||||
|
result.err().unwrap().to_string(),
|
||||||
|
r#"type: KclErrorDetails { source_ranges: [SourceRange([227, 277])], message: "Duplicate tags are not allowed." }"#,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test(flavor = "multi_thread")]
|
||||||
|
async fn serial_test_basic_fillet_cube_start() {
|
||||||
|
let code = r#"const part001 = startSketchOn('XY')
|
||||||
|
|> startProfileAt([0,0], %)
|
||||||
|
|> line({to: [0, 10], tag: "thing"}, %)
|
||||||
|
|> line([10, 0], %)
|
||||||
|
|> line({to: [0, -10], tag: "thing2"}, %)
|
||||||
|
|> close(%)
|
||||||
|
|> extrude(10, %)
|
||||||
|
|> fillet({radius: 2, tags: ["thing", "thing2"]}, %)
|
||||||
|
"#;
|
||||||
|
|
||||||
|
let result = execute_and_snapshot(code, kittycad::types::UnitLength::Mm)
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
twenty_twenty::assert_image("tests/executor/outputs/basic_fillet_cube_start.png", &result, 0.999);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test(flavor = "multi_thread")]
|
||||||
|
async fn serial_test_basic_fillet_cube_end() {
|
||||||
|
let code = r#"const part001 = startSketchOn('XY')
|
||||||
|
|> startProfileAt([0,0], %)
|
||||||
|
|> line({to: [0, 10], tag: "thing"}, %)
|
||||||
|
|> line([10, 0], %)
|
||||||
|
|> line({to: [0, -10], tag: "thing2"}, %)
|
||||||
|
|> close(%)
|
||||||
|
|> extrude(10, %)
|
||||||
|
|> fillet({radius: 2, tags: ["thing", getOppositeEdge("thing", %)]}, %)
|
||||||
|
|
||||||
|
"#;
|
||||||
|
|
||||||
|
let result = execute_and_snapshot(code, kittycad::types::UnitLength::Mm)
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
twenty_twenty::assert_image("tests/executor/outputs/basic_fillet_cube_end.png", &result, 0.999);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test(flavor = "multi_thread")]
|
||||||
|
async fn serial_test_basic_fillet_cube_next_adjacent() {
|
||||||
|
let code = r#"const part001 = startSketchOn('XY')
|
||||||
|
|> startProfileAt([0,0], %)
|
||||||
|
|> line({to: [0, 10], tag: "thing"}, %)
|
||||||
|
|> line({to: [10, 0], tag: "thing1"}, %)
|
||||||
|
|> line({to: [0, -10], tag: "thing2"}, %)
|
||||||
|
|> close(%)
|
||||||
|
|> extrude(10, %)
|
||||||
|
|> fillet({radius: 2, tags: [getNextAdjacentEdge("thing", %)]}, %)
|
||||||
|
"#;
|
||||||
|
|
||||||
|
let result = execute_and_snapshot(code, kittycad::types::UnitLength::Mm)
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
twenty_twenty::assert_image(
|
||||||
|
"tests/executor/outputs/basic_fillet_cube_next_adjacent.png",
|
||||||
|
&result,
|
||||||
|
0.999,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test(flavor = "multi_thread")]
|
||||||
|
async fn serial_test_basic_fillet_cube_previous_adjacent() {
|
||||||
|
let code = r#"const part001 = startSketchOn('XY')
|
||||||
|
|> startProfileAt([0,0], %)
|
||||||
|
|> line({to: [0, 10], tag: "thing"}, %)
|
||||||
|
|> line({to: [10, 0], tag: "thing1"}, %)
|
||||||
|
|> line({to: [0, -10], tag: "thing2"}, %)
|
||||||
|
|> close(%)
|
||||||
|
|> extrude(10, %)
|
||||||
|
|> fillet({radius: 2, tags: [getPreviousAdjacentEdge("thing2", %)]}, %)
|
||||||
|
"#;
|
||||||
|
|
||||||
|
let result = execute_and_snapshot(code, kittycad::types::UnitLength::Mm)
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
twenty_twenty::assert_image(
|
||||||
|
"tests/executor/outputs/basic_fillet_cube_previous_adjacent.png",
|
||||||
|
&result,
|
||||||
|
0.999,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
#[tokio::test(flavor = "multi_thread")]
|
#[tokio::test(flavor = "multi_thread")]
|
||||||
async fn serial_test_execute_with_function_sketch() {
|
async fn serial_test_execute_with_function_sketch() {
|
||||||
let code = r#"fn box = (h, l, w) => {
|
let code = r#"fn box = (h, l, w) => {
|
||||||
|
BIN
src/wasm-lib/tests/executor/outputs/basic_fillet_cube_end.png
Normal file
BIN
src/wasm-lib/tests/executor/outputs/basic_fillet_cube_end.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 98 KiB |
Binary file not shown.
After Width: | Height: | Size: 98 KiB |
Binary file not shown.
After Width: | Height: | Size: 98 KiB |
BIN
src/wasm-lib/tests/executor/outputs/basic_fillet_cube_start.png
Normal file
BIN
src/wasm-lib/tests/executor/outputs/basic_fillet_cube_start.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 98 KiB |
Reference in New Issue
Block a user