Stub csg functions for front end (#5899)
* initial placeholder csg functions Signed-off-by: Jess Frazelle <github@jessfraz.com> * updates Signed-off-by: Jess Frazelle <github@jessfraz.com> * generate docs Signed-off-by: Jess Frazelle <github@jessfraz.com> * generate docs Signed-off-by: Jess Frazelle <github@jessfraz.com> --------- Signed-off-by: Jess Frazelle <github@jessfraz.com>
This commit is contained in:
210
rust/kcl-lib/src/std/csg.rs
Normal file
210
rust/kcl-lib/src/std/csg.rs
Normal file
@ -0,0 +1,210 @@
|
||||
//! Constructive Solid Geometry (CSG) operations.
|
||||
|
||||
use anyhow::Result;
|
||||
use kcl_derive_docs::stdlib;
|
||||
|
||||
use crate::{
|
||||
errors::{KclError, KclErrorDetails},
|
||||
execution::{
|
||||
kcl_value::{ArrayLen, RuntimeType},
|
||||
ExecState, KclValue, PrimitiveType, Solid,
|
||||
},
|
||||
std::Args,
|
||||
};
|
||||
|
||||
/// 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(
|
||||
"objects",
|
||||
&RuntimeType::Union(vec![RuntimeType::Array(PrimitiveType::Solid, ArrayLen::NonEmpty)]),
|
||||
exec_state,
|
||||
)?;
|
||||
|
||||
if solids.len() < 2 {
|
||||
return Err(KclError::UndefinedValue(KclErrorDetails {
|
||||
message: "At least two solids are required for a union operation.".to_string(),
|
||||
source_ranges: vec![args.source_range],
|
||||
}));
|
||||
}
|
||||
|
||||
let solids = inner_union(solids, exec_state, args).await?;
|
||||
Ok(solids.into())
|
||||
}
|
||||
|
||||
/// Union two or more solids into a single solid.
|
||||
///
|
||||
/// ```no_run
|
||||
/// fn cube(center) {
|
||||
/// 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])
|
||||
/// |> close()
|
||||
/// |> extrude(length = 10)
|
||||
/// }
|
||||
///
|
||||
/// part001 = cube([0, 0])
|
||||
/// part002 = cube([20, 10])
|
||||
///
|
||||
/// unionedPart = union([part001, part002])
|
||||
/// ```
|
||||
#[stdlib {
|
||||
name = "union",
|
||||
feature_tree_operation = false,
|
||||
keywords = true,
|
||||
unlabeled_first = true,
|
||||
deprecated = true,
|
||||
args = {
|
||||
solids = {docs = "The solids to union."},
|
||||
}
|
||||
}]
|
||||
async fn inner_union(solids: Vec<Solid>, exec_state: &mut ExecState, args: Args) -> Result<Vec<Solid>, KclError> {
|
||||
// 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.
|
||||
|
||||
// For now just return the first solid.
|
||||
// Til we have a proper implementation.
|
||||
Ok(vec![solids[0].clone()])
|
||||
}
|
||||
|
||||
/// 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(
|
||||
"objects",
|
||||
&RuntimeType::Union(vec![RuntimeType::Array(PrimitiveType::Solid, ArrayLen::NonEmpty)]),
|
||||
exec_state,
|
||||
)?;
|
||||
|
||||
if solids.len() < 2 {
|
||||
return Err(KclError::UndefinedValue(KclErrorDetails {
|
||||
message: "At least two solids are required for an intersect operation.".to_string(),
|
||||
source_ranges: vec![args.source_range],
|
||||
}));
|
||||
}
|
||||
|
||||
let solids = inner_intersect(solids, exec_state, args).await?;
|
||||
Ok(solids.into())
|
||||
}
|
||||
|
||||
/// Intersect returns the shared volume between multiple solids, preserving only
|
||||
/// overlapping regions.
|
||||
///
|
||||
/// Intersect computes the geometric intersection of multiple solid bodies,
|
||||
/// returning a new solid representing the volume that is common to all input
|
||||
/// solids. This operation is useful for determining shared material regions,
|
||||
/// verifying fit, and analyzing overlapping geometries in assemblies.
|
||||
///
|
||||
/// ```no_run
|
||||
/// fn cube(center) {
|
||||
/// 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])
|
||||
/// |> close()
|
||||
/// |> extrude(length = 10)
|
||||
/// }
|
||||
///
|
||||
/// part001 = cube([0, 0])
|
||||
/// part002 = cube([8, 8])
|
||||
///
|
||||
/// intersectedPart = intersect([part001, part002])
|
||||
/// ```
|
||||
#[stdlib {
|
||||
name = "intersect",
|
||||
feature_tree_operation = false,
|
||||
keywords = true,
|
||||
unlabeled_first = true,
|
||||
deprecated = true,
|
||||
args = {
|
||||
solids = {docs = "The solids to intersect."},
|
||||
}
|
||||
}]
|
||||
async fn inner_intersect(solids: Vec<Solid>, exec_state: &mut ExecState, args: Args) -> Result<Vec<Solid>, KclError> {
|
||||
// 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.
|
||||
|
||||
// For now just return the first solid.
|
||||
// Til we have a proper implementation.
|
||||
Ok(vec![solids[0].clone()])
|
||||
}
|
||||
|
||||
/// Subtract removes tool solids from base solids, leaving the remaining material.
|
||||
pub async fn subtract(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
|
||||
let solids: Vec<Solid> = args.get_unlabeled_kw_arg_typed(
|
||||
"objects",
|
||||
&RuntimeType::Union(vec![RuntimeType::Array(PrimitiveType::Solid, ArrayLen::NonEmpty)]),
|
||||
exec_state,
|
||||
)?;
|
||||
let tools: Vec<Solid> = args.get_kw_arg_typed(
|
||||
"tools",
|
||||
&RuntimeType::Union(vec![RuntimeType::Array(PrimitiveType::Solid, ArrayLen::NonEmpty)]),
|
||||
exec_state,
|
||||
)?;
|
||||
|
||||
let solids = inner_subtract(solids, tools, exec_state, args).await?;
|
||||
Ok(solids.into())
|
||||
}
|
||||
|
||||
/// Subtract removes tool solids from base solids, leaving the remaining material.
|
||||
///
|
||||
/// Performs a boolean subtraction operation, removing the volume of one or more
|
||||
/// tool solids from one or more base solids. The result is a new solid
|
||||
/// representing the material that remains after all tool solids have been cut
|
||||
/// away. This function is essential for machining simulations, cavity creation,
|
||||
/// and complex multi-body part modeling.
|
||||
///
|
||||
/// ```no_run
|
||||
/// fn cube(center) {
|
||||
/// 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])
|
||||
/// |> close()
|
||||
/// |> extrude(length = 10)
|
||||
/// }
|
||||
///
|
||||
/// part001 = cube([0, 0])
|
||||
/// part002 = startSketchOn('XY')
|
||||
/// |> circle(center = [0, 0], radius = 2)
|
||||
/// |> extrude(length = 10)
|
||||
///
|
||||
/// subtractedPart = subtract([part001], tools=[part002])
|
||||
/// ```
|
||||
#[stdlib {
|
||||
name = "subtract",
|
||||
feature_tree_operation = false,
|
||||
keywords = true,
|
||||
unlabeled_first = true,
|
||||
deprecated = true,
|
||||
args = {
|
||||
solids = {docs = "The solids to intersect."},
|
||||
tools = {docs = "The solids to subtract."},
|
||||
}
|
||||
}]
|
||||
async fn inner_subtract(
|
||||
solids: Vec<Solid>,
|
||||
tools: Vec<Solid>,
|
||||
exec_state: &mut ExecState,
|
||||
args: Args,
|
||||
) -> Result<Vec<Solid>, KclError> {
|
||||
// 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.
|
||||
|
||||
// For now just return the first solid.
|
||||
// Til we have a proper implementation.
|
||||
Ok(vec![solids[0].clone()])
|
||||
}
|
Reference in New Issue
Block a user