Bump modeling api & pull thru csg endpoints (#6245)
* csg-upts Signed-off-by: Jess Frazelle <github@jessfraz.com> * base Signed-off-by: Jess Frazelle <github@jessfraz.com> * do the id shit Signed-off-by: Jess Frazelle <github@jessfraz.com> * tried to run Signed-off-by: Jess Frazelle <github@jessfraz.com> * csg-upts Signed-off-by: Jess Frazelle <github@jessfraz.com> * use bens samples Signed-off-by: Jess Frazelle <github@jessfraz.com> * use bens samples Signed-off-by: Jess Frazelle <github@jessfraz.com> * gen std Signed-off-by: Jess Frazelle <github@jessfraz.com> * gen std 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> * fix; Signed-off-by: Jess Frazelle <github@jessfraz.com> --------- Signed-off-by: Jess Frazelle <github@jessfraz.com>
This commit is contained in:
@ -2,6 +2,13 @@
|
||||
|
||||
use anyhow::Result;
|
||||
use kcl_derive_docs::stdlib;
|
||||
use kcmc::{each_cmd as mcmd, length_unit::LengthUnit, ModelingCmd};
|
||||
use kittycad_modeling_cmds::{
|
||||
self as kcmc,
|
||||
ok_response::OkModelingCmdResponse,
|
||||
output::{BooleanIntersection, BooleanSubtract, BooleanUnion},
|
||||
websocket::OkWebSocketResponseData,
|
||||
};
|
||||
|
||||
use crate::{
|
||||
errors::{KclError, KclErrorDetails},
|
||||
@ -9,10 +16,13 @@ use crate::{
|
||||
std::Args,
|
||||
};
|
||||
|
||||
use super::DEFAULT_TOLERANCE;
|
||||
|
||||
/// Union two or more solids into a single solid.
|
||||
pub async fn union(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
|
||||
let solids: Vec<Solid> =
|
||||
args.get_unlabeled_kw_arg_typed("solids", &RuntimeType::Union(vec![RuntimeType::solids()]), exec_state)?;
|
||||
let tolerance = args.get_kw_arg_opt("tolerance")?;
|
||||
|
||||
if solids.len() < 2 {
|
||||
return Err(KclError::UndefinedValue(KclErrorDetails {
|
||||
@ -21,7 +31,7 @@ pub async fn union(exec_state: &mut ExecState, args: Args) -> Result<KclValue, K
|
||||
}));
|
||||
}
|
||||
|
||||
let solids = inner_union(solids, exec_state, args).await?;
|
||||
let solids = inner_union(solids, tolerance, exec_state, args).await?;
|
||||
Ok(solids.into())
|
||||
}
|
||||
|
||||
@ -30,18 +40,19 @@ pub async fn union(exec_state: &mut ExecState, args: Args) -> Result<KclValue, K
|
||||
/// ```no_run
|
||||
/// // Union two cubes using the stdlib functions.
|
||||
///
|
||||
/// fn cube(center) {
|
||||
/// fn cube(center, size) {
|
||||
/// return startSketchOn('XY')
|
||||
/// |> startProfileAt([center[0] - 10, center[1] - 10], %)
|
||||
/// |> line(endAbsolute = [center[0] + 10, center[1] - 10])
|
||||
/// |> line(endAbsolute = [center[0] + 10, center[1] + 10])
|
||||
/// |> line(endAbsolute = [center[0] - 10, center[1] + 10])
|
||||
/// |> startProfileAt([center[0] - size, center[1] - size], %)
|
||||
/// |> line(endAbsolute = [center[0] + size, center[1] - size])
|
||||
/// |> line(endAbsolute = [center[0] + size, center[1] + size])
|
||||
/// |> line(endAbsolute = [center[0] - size, center[1] + size])
|
||||
/// |> close()
|
||||
/// |> extrude(length = 10)
|
||||
/// }
|
||||
///
|
||||
/// part001 = cube([0, 0])
|
||||
/// part002 = cube([20, 10])
|
||||
/// part001 = cube([0, 0], 10)
|
||||
/// part002 = cube([7, 3], 5)
|
||||
/// |> translate(z = 1)
|
||||
///
|
||||
/// unionedPart = union([part001, part002])
|
||||
/// ```
|
||||
@ -51,18 +62,19 @@ pub async fn union(exec_state: &mut ExecState, args: Args) -> Result<KclValue, K
|
||||
/// // NOTE: This will not work when using codemods through the UI.
|
||||
/// // Codemods will generate the stdlib function call instead.
|
||||
///
|
||||
/// fn cube(center) {
|
||||
/// fn cube(center, size) {
|
||||
/// return startSketchOn('XY')
|
||||
/// |> startProfileAt([center[0] - 10, center[1] - 10], %)
|
||||
/// |> line(endAbsolute = [center[0] + 10, center[1] - 10])
|
||||
/// |> line(endAbsolute = [center[0] + 10, center[1] + 10])
|
||||
/// |> line(endAbsolute = [center[0] - 10, center[1] + 10])
|
||||
/// |> startProfileAt([center[0] - size, center[1] - size], %)
|
||||
/// |> line(endAbsolute = [center[0] + size, center[1] - size])
|
||||
/// |> line(endAbsolute = [center[0] + size, center[1] + size])
|
||||
/// |> line(endAbsolute = [center[0] - size, center[1] + size])
|
||||
/// |> close()
|
||||
/// |> extrude(length = 10)
|
||||
/// }
|
||||
///
|
||||
/// part001 = cube([0, 0])
|
||||
/// part002 = cube([20, 10])
|
||||
/// part001 = cube([0, 0], 10)
|
||||
/// part002 = cube([7, 3], 5)
|
||||
/// |> translate(z = 1)
|
||||
///
|
||||
/// // This is the equivalent of: union([part001, part002])
|
||||
/// unionedPart = part001 + part002
|
||||
@ -73,18 +85,19 @@ pub async fn union(exec_state: &mut ExecState, args: Args) -> Result<KclValue, K
|
||||
/// // NOTE: This will not work when using codemods through the UI.
|
||||
/// // Codemods will generate the stdlib function call instead.
|
||||
///
|
||||
/// fn cube(center) {
|
||||
/// fn cube(center, size) {
|
||||
/// return startSketchOn('XY')
|
||||
/// |> startProfileAt([center[0] - 10, center[1] - 10], %)
|
||||
/// |> line(endAbsolute = [center[0] + 10, center[1] - 10])
|
||||
/// |> line(endAbsolute = [center[0] + 10, center[1] + 10])
|
||||
/// |> line(endAbsolute = [center[0] - 10, center[1] + 10])
|
||||
/// |> startProfileAt([center[0] - size, center[1] - size], %)
|
||||
/// |> line(endAbsolute = [center[0] + size, center[1] - size])
|
||||
/// |> line(endAbsolute = [center[0] + size, center[1] + size])
|
||||
/// |> line(endAbsolute = [center[0] - size, center[1] + size])
|
||||
/// |> close()
|
||||
/// |> extrude(length = 10)
|
||||
/// }
|
||||
///
|
||||
/// part001 = cube([0, 0])
|
||||
/// part002 = cube([20, 10])
|
||||
/// part001 = cube([0, 0], 10)
|
||||
/// part002 = cube([7, 3], 5)
|
||||
/// |> translate(z = 1)
|
||||
///
|
||||
/// // This is the equivalent of: union([part001, part002])
|
||||
/// // Programmers will understand `|` as a union operation, but mechanical engineers
|
||||
@ -96,31 +109,64 @@ pub async fn union(exec_state: &mut ExecState, args: Args) -> Result<KclValue, K
|
||||
feature_tree_operation = true,
|
||||
keywords = true,
|
||||
unlabeled_first = true,
|
||||
deprecated = true,
|
||||
args = {
|
||||
solids = {docs = "The solids to union."},
|
||||
tolerance = {docs = "The tolerance to use for the union operation."},
|
||||
}
|
||||
}]
|
||||
pub(crate) async fn inner_union(
|
||||
solids: Vec<Solid>,
|
||||
tolerance: Option<f64>,
|
||||
exec_state: &mut ExecState,
|
||||
args: Args,
|
||||
) -> Result<Vec<Solid>, KclError> {
|
||||
let solid_out_id = exec_state.next_uuid();
|
||||
|
||||
let mut solid = solids[0].clone();
|
||||
solid.id = solid_out_id;
|
||||
let mut new_solids = vec![solid.clone()];
|
||||
|
||||
if args.ctx.no_engine_commands().await {
|
||||
return Ok(new_solids);
|
||||
}
|
||||
|
||||
// Flush the fillets for the solids.
|
||||
args.flush_batch_for_solids(exec_state, &solids).await?;
|
||||
|
||||
// TODO: call the engine union operation.
|
||||
// TODO: figure out all the shit after for the faces etc.
|
||||
let result = args
|
||||
.send_modeling_cmd(
|
||||
solid_out_id,
|
||||
ModelingCmd::from(mcmd::BooleanUnion {
|
||||
solid_ids: solids.iter().map(|s| s.id).collect(),
|
||||
tolerance: LengthUnit(tolerance.unwrap_or(DEFAULT_TOLERANCE)),
|
||||
}),
|
||||
)
|
||||
.await?;
|
||||
|
||||
// For now just return the first solid.
|
||||
// Til we have a proper implementation.
|
||||
Ok(vec![solids[0].clone()])
|
||||
let OkWebSocketResponseData::Modeling {
|
||||
modeling_response: OkModelingCmdResponse::BooleanUnion(BooleanUnion { extra_solid_ids }),
|
||||
} = result
|
||||
else {
|
||||
return Err(KclError::Internal(KclErrorDetails {
|
||||
message: "Failed to get the result of the union operation.".to_string(),
|
||||
source_ranges: vec![args.source_range],
|
||||
}));
|
||||
};
|
||||
|
||||
// If we have more solids, set those as well.
|
||||
if !extra_solid_ids.is_empty() {
|
||||
solid.id = extra_solid_ids[0];
|
||||
new_solids.push(solid.clone());
|
||||
}
|
||||
|
||||
Ok(new_solids)
|
||||
}
|
||||
|
||||
/// Intersect returns the shared volume between multiple solids, preserving only
|
||||
/// overlapping regions.
|
||||
pub async fn intersect(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
|
||||
let solids: Vec<Solid> = args.get_unlabeled_kw_arg_typed("solids", &RuntimeType::solids(), exec_state)?;
|
||||
let tolerance = args.get_kw_arg_opt("tolerance")?;
|
||||
|
||||
if solids.len() < 2 {
|
||||
return Err(KclError::UndefinedValue(KclErrorDetails {
|
||||
@ -129,7 +175,7 @@ pub async fn intersect(exec_state: &mut ExecState, args: Args) -> Result<KclValu
|
||||
}));
|
||||
}
|
||||
|
||||
let solids = inner_intersect(solids, exec_state, args).await?;
|
||||
let solids = inner_intersect(solids, tolerance, exec_state, args).await?;
|
||||
Ok(solids.into())
|
||||
}
|
||||
|
||||
@ -144,18 +190,19 @@ pub async fn intersect(exec_state: &mut ExecState, args: Args) -> Result<KclValu
|
||||
/// ```no_run
|
||||
/// // Intersect two cubes using the stdlib functions.
|
||||
///
|
||||
/// fn cube(center) {
|
||||
/// fn cube(center, size) {
|
||||
/// return startSketchOn('XY')
|
||||
/// |> startProfileAt([center[0] - 10, center[1] - 10], %)
|
||||
/// |> line(endAbsolute = [center[0] + 10, center[1] - 10])
|
||||
/// |> line(endAbsolute = [center[0] + 10, center[1] + 10])
|
||||
/// |> line(endAbsolute = [center[0] - 10, center[1] + 10])
|
||||
/// |> startProfileAt([center[0] - size, center[1] - size], %)
|
||||
/// |> line(endAbsolute = [center[0] + size, center[1] - size])
|
||||
/// |> line(endAbsolute = [center[0] + size, center[1] + size])
|
||||
/// |> line(endAbsolute = [center[0] - size, center[1] + size])
|
||||
/// |> close()
|
||||
/// |> extrude(length = 10)
|
||||
/// }
|
||||
///
|
||||
/// part001 = cube([0, 0])
|
||||
/// part002 = cube([8, 8])
|
||||
/// part001 = cube([0, 0], 10)
|
||||
/// part002 = cube([7, 3], 5)
|
||||
/// |> translate(z = 1)
|
||||
///
|
||||
/// intersectedPart = intersect([part001, part002])
|
||||
/// ```
|
||||
@ -165,18 +212,19 @@ pub async fn intersect(exec_state: &mut ExecState, args: Args) -> Result<KclValu
|
||||
/// // NOTE: This will not work when using codemods through the UI.
|
||||
/// // Codemods will generate the stdlib function call instead.
|
||||
///
|
||||
/// fn cube(center) {
|
||||
/// fn cube(center, size) {
|
||||
/// return startSketchOn('XY')
|
||||
/// |> startProfileAt([center[0] - 10, center[1] - 10], %)
|
||||
/// |> line(endAbsolute = [center[0] + 10, center[1] - 10])
|
||||
/// |> line(endAbsolute = [center[0] + 10, center[1] + 10])
|
||||
/// |> line(endAbsolute = [center[0] - 10, center[1] + 10])
|
||||
/// |> startProfileAt([center[0] - size, center[1] - size], %)
|
||||
/// |> line(endAbsolute = [center[0] + size, center[1] - size])
|
||||
/// |> line(endAbsolute = [center[0] + size, center[1] + size])
|
||||
/// |> line(endAbsolute = [center[0] - size, center[1] + size])
|
||||
/// |> close()
|
||||
/// |> extrude(length = 10)
|
||||
/// }
|
||||
///
|
||||
/// part001 = cube([0, 0])
|
||||
/// part002 = cube([8, 8])
|
||||
/// part001 = cube([0, 0], 10)
|
||||
/// part002 = cube([7, 3], 5)
|
||||
/// |> translate(z = 1)
|
||||
///
|
||||
/// // This is the equivalent of: intersect([part001, part002])
|
||||
/// intersectedPart = part001 & part002
|
||||
@ -186,25 +234,57 @@ pub async fn intersect(exec_state: &mut ExecState, args: Args) -> Result<KclValu
|
||||
feature_tree_operation = true,
|
||||
keywords = true,
|
||||
unlabeled_first = true,
|
||||
deprecated = true,
|
||||
args = {
|
||||
solids = {docs = "The solids to intersect."},
|
||||
tolerance = {docs = "The tolerance to use for the intersection operation."},
|
||||
}
|
||||
}]
|
||||
pub(crate) async fn inner_intersect(
|
||||
solids: Vec<Solid>,
|
||||
tolerance: Option<f64>,
|
||||
exec_state: &mut ExecState,
|
||||
args: Args,
|
||||
) -> Result<Vec<Solid>, KclError> {
|
||||
let solid_out_id = exec_state.next_uuid();
|
||||
|
||||
let mut solid = solids[0].clone();
|
||||
solid.id = solid_out_id;
|
||||
let mut new_solids = vec![solid.clone()];
|
||||
|
||||
if args.ctx.no_engine_commands().await {
|
||||
return Ok(new_solids);
|
||||
}
|
||||
|
||||
// Flush the fillets for the solids.
|
||||
args.flush_batch_for_solids(exec_state, &solids).await?;
|
||||
|
||||
// TODO: call the engine union operation.
|
||||
// TODO: figure out all the shit after for the faces etc.
|
||||
let result = args
|
||||
.send_modeling_cmd(
|
||||
solid_out_id,
|
||||
ModelingCmd::from(mcmd::BooleanIntersection {
|
||||
solid_ids: solids.iter().map(|s| s.id).collect(),
|
||||
tolerance: LengthUnit(tolerance.unwrap_or(DEFAULT_TOLERANCE)),
|
||||
}),
|
||||
)
|
||||
.await?;
|
||||
|
||||
// For now just return the first solid.
|
||||
// Til we have a proper implementation.
|
||||
Ok(vec![solids[0].clone()])
|
||||
let OkWebSocketResponseData::Modeling {
|
||||
modeling_response: OkModelingCmdResponse::BooleanIntersection(BooleanIntersection { extra_solid_ids }),
|
||||
} = result
|
||||
else {
|
||||
return Err(KclError::Internal(KclErrorDetails {
|
||||
message: "Failed to get the result of the intersection operation.".to_string(),
|
||||
source_ranges: vec![args.source_range],
|
||||
}));
|
||||
};
|
||||
|
||||
// If we have more solids, set those as well.
|
||||
if !extra_solid_ids.is_empty() {
|
||||
solid.id = extra_solid_ids[0];
|
||||
new_solids.push(solid.clone());
|
||||
}
|
||||
|
||||
Ok(new_solids)
|
||||
}
|
||||
|
||||
/// Subtract removes tool solids from base solids, leaving the remaining material.
|
||||
@ -212,7 +292,23 @@ pub async fn subtract(exec_state: &mut ExecState, args: Args) -> Result<KclValue
|
||||
let solids: Vec<Solid> = args.get_unlabeled_kw_arg_typed("solids", &RuntimeType::solids(), exec_state)?;
|
||||
let tools: Vec<Solid> = args.get_kw_arg_typed("tools", &RuntimeType::solids(), exec_state)?;
|
||||
|
||||
let solids = inner_subtract(solids, tools, exec_state, args).await?;
|
||||
if solids.len() > 1 {
|
||||
return Err(KclError::UndefinedValue(KclErrorDetails {
|
||||
message: "Only one solid is allowed for a subtract operation, currently.".to_string(),
|
||||
source_ranges: vec![args.source_range],
|
||||
}));
|
||||
}
|
||||
|
||||
if tools.len() > 1 {
|
||||
return Err(KclError::UndefinedValue(KclErrorDetails {
|
||||
message: "Only one tool is allowed for a subtract operation, currently.".to_string(),
|
||||
source_ranges: vec![args.source_range],
|
||||
}));
|
||||
}
|
||||
|
||||
let tolerance = args.get_kw_arg_opt("tolerance")?;
|
||||
|
||||
let solids = inner_subtract(solids, tools, tolerance, exec_state, args).await?;
|
||||
Ok(solids.into())
|
||||
}
|
||||
|
||||
@ -227,20 +323,19 @@ pub async fn subtract(exec_state: &mut ExecState, args: Args) -> Result<KclValue
|
||||
/// ```no_run
|
||||
/// // Subtract a cylinder from a cube using the stdlib functions.
|
||||
///
|
||||
/// fn cube(center) {
|
||||
/// fn cube(center, size) {
|
||||
/// return startSketchOn('XY')
|
||||
/// |> startProfileAt([center[0] - 10, center[1] - 10], %)
|
||||
/// |> line(endAbsolute = [center[0] + 10, center[1] - 10])
|
||||
/// |> line(endAbsolute = [center[0] + 10, center[1] + 10])
|
||||
/// |> line(endAbsolute = [center[0] - 10, center[1] + 10])
|
||||
/// |> startProfileAt([center[0] - size, center[1] - size], %)
|
||||
/// |> line(endAbsolute = [center[0] + size, center[1] - size])
|
||||
/// |> line(endAbsolute = [center[0] + size, center[1] + size])
|
||||
/// |> line(endAbsolute = [center[0] - size, center[1] + size])
|
||||
/// |> close()
|
||||
/// |> extrude(length = 10)
|
||||
/// }
|
||||
///
|
||||
/// part001 = cube([0, 0])
|
||||
/// part002 = startSketchOn('XY')
|
||||
/// |> circle(center = [0, 0], radius = 2)
|
||||
/// |> extrude(length = 10)
|
||||
/// part001 = cube([0, 0], 10)
|
||||
/// part002 = cube([7, 3], 5)
|
||||
/// |> translate(z = 1)
|
||||
///
|
||||
/// subtractedPart = subtract([part001], tools=[part002])
|
||||
/// ```
|
||||
@ -250,20 +345,19 @@ pub async fn subtract(exec_state: &mut ExecState, args: Args) -> Result<KclValue
|
||||
/// // NOTE: This will not work when using codemods through the UI.
|
||||
/// // Codemods will generate the stdlib function call instead.
|
||||
///
|
||||
/// fn cube(center) {
|
||||
/// fn cube(center, size) {
|
||||
/// return startSketchOn('XY')
|
||||
/// |> startProfileAt([center[0] - 10, center[1] - 10], %)
|
||||
/// |> line(endAbsolute = [center[0] + 10, center[1] - 10])
|
||||
/// |> line(endAbsolute = [center[0] + 10, center[1] + 10])
|
||||
/// |> line(endAbsolute = [center[0] - 10, center[1] + 10])
|
||||
/// |> startProfileAt([center[0] - size, center[1] - size], %)
|
||||
/// |> line(endAbsolute = [center[0] + size, center[1] - size])
|
||||
/// |> line(endAbsolute = [center[0] + size, center[1] + size])
|
||||
/// |> line(endAbsolute = [center[0] - size, center[1] + size])
|
||||
/// |> close()
|
||||
/// |> extrude(length = 10)
|
||||
/// }
|
||||
///
|
||||
/// part001 = cube([0, 0])
|
||||
/// part002 = startSketchOn('XY')
|
||||
/// |> circle(center = [0, 0], radius = 2)
|
||||
/// |> extrude(length = 10)
|
||||
/// part001 = cube([0, 0], 10)
|
||||
/// part002 = cube([7, 3], 5)
|
||||
/// |> translate(z = 1)
|
||||
///
|
||||
/// // This is the equivalent of: subtract([part001], tools=[part002])
|
||||
/// subtractedPart = part001 - part002
|
||||
@ -273,26 +367,59 @@ pub async fn subtract(exec_state: &mut ExecState, args: Args) -> Result<KclValue
|
||||
feature_tree_operation = true,
|
||||
keywords = true,
|
||||
unlabeled_first = true,
|
||||
deprecated = true,
|
||||
args = {
|
||||
solids = {docs = "The solids to use as the base to subtract from."},
|
||||
tools = {docs = "The solids to subtract."},
|
||||
tolerance = {docs = "The tolerance to use for the subtraction operation."},
|
||||
}
|
||||
}]
|
||||
pub(crate) async fn inner_subtract(
|
||||
solids: Vec<Solid>,
|
||||
tools: Vec<Solid>,
|
||||
tolerance: Option<f64>,
|
||||
exec_state: &mut ExecState,
|
||||
args: Args,
|
||||
) -> Result<Vec<Solid>, KclError> {
|
||||
let solid_out_id = exec_state.next_uuid();
|
||||
|
||||
let mut solid = solids[0].clone();
|
||||
solid.id = solid_out_id;
|
||||
let mut new_solids = vec![solid.clone()];
|
||||
|
||||
if args.ctx.no_engine_commands().await {
|
||||
return Ok(new_solids);
|
||||
}
|
||||
|
||||
// Flush the fillets for the solids and the tools.
|
||||
let combined_solids = solids.iter().chain(tools.iter()).cloned().collect::<Vec<Solid>>();
|
||||
args.flush_batch_for_solids(exec_state, &combined_solids).await?;
|
||||
|
||||
// TODO: call the engine union operation.
|
||||
// TODO: figure out all the shit after for the faces etc.
|
||||
let result = args
|
||||
.send_modeling_cmd(
|
||||
solid_out_id,
|
||||
ModelingCmd::from(mcmd::BooleanSubtract {
|
||||
target_ids: solids.iter().map(|s| s.id).collect(),
|
||||
tool_ids: tools.iter().map(|s| s.id).collect(),
|
||||
tolerance: LengthUnit(tolerance.unwrap_or(DEFAULT_TOLERANCE)),
|
||||
}),
|
||||
)
|
||||
.await?;
|
||||
|
||||
// For now just return the first solid.
|
||||
// Til we have a proper implementation.
|
||||
Ok(vec![solids[0].clone()])
|
||||
let OkWebSocketResponseData::Modeling {
|
||||
modeling_response: OkModelingCmdResponse::BooleanSubtract(BooleanSubtract { extra_solid_ids }),
|
||||
} = result
|
||||
else {
|
||||
return Err(KclError::Internal(KclErrorDetails {
|
||||
message: "Failed to get the result of the subtract operation.".to_string(),
|
||||
source_ranges: vec![args.source_range],
|
||||
}));
|
||||
};
|
||||
|
||||
// If we have more solids, set those as well.
|
||||
if !extra_solid_ids.is_empty() {
|
||||
solid.id = extra_solid_ids[0];
|
||||
new_solids.push(solid.clone());
|
||||
}
|
||||
|
||||
Ok(new_solids)
|
||||
}
|
||||
|
Reference in New Issue
Block a user