Shell two at once from the same sketch on face (#3908)

* shell two at once from the same obhject

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

* docs

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

---------

Signed-off-by: Jess Frazelle <github@jessfraz.com>
This commit is contained in:
Jess Frazelle
2024-09-17 18:49:08 -07:00
committed by GitHub
parent 00fa40bbc9
commit 4a74c60150
6 changed files with 7974 additions and 3665 deletions

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

View File

@ -8,7 +8,7 @@ use serde::{Deserialize, Serialize};
use crate::{ use crate::{
errors::{KclError, KclErrorDetails}, errors::{KclError, KclErrorDetails},
executor::{ExecState, ExtrudeGroup, KclValue}, executor::{ExecState, ExtrudeGroup, ExtrudeGroupSet, KclValue},
std::{sketch::FaceTag, Args}, std::{sketch::FaceTag, Args},
}; };
@ -25,10 +25,10 @@ pub struct ShellData {
/// Create a shell. /// Create a shell.
pub async fn shell(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> { pub async fn shell(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
let (data, extrude_group): (ShellData, Box<ExtrudeGroup>) = args.get_data_and_extrude_group()?; let (data, extrude_group_set): (ShellData, ExtrudeGroupSet) = args.get_data_and_extrude_group_set()?;
let extrude_group = inner_shell(data, extrude_group, exec_state, args).await?; let result = inner_shell(data, extrude_group_set, exec_state, args).await?;
Ok(KclValue::ExtrudeGroup(extrude_group)) Ok(result.into())
} }
/// Remove volume from a 3-dimensional shape such that a wall of the /// Remove volume from a 3-dimensional shape such that a wall of the
@ -148,15 +148,40 @@ pub async fn shell(exec_state: &mut ExecState, args: Args) -> Result<KclValue, K
/// // We put "thing1" in the shell function to shell the end face of the object. /// // We put "thing1" in the shell function to shell the end face of the object.
/// shell({ faces: ['end'], thickness: 5 }, thing1) /// shell({ faces: ['end'], thickness: 5 }, thing1)
/// ``` /// ```
///
/// ```no_run
/// // Shell sketched on face objects on the end face, include all sketches to shell
/// // the entire object.
///
/// let size = 100
/// const case = startSketchOn('XY')
/// |> startProfileAt([-size, -size], %)
/// |> line([2 * size, 0], %)
/// |> line([0, 2 * size], %)
/// |> tangentialArcTo([-size, size], %)
/// |> close(%)
/// |> extrude(65, %)
///
/// const thing1 = startSketchOn(case, 'end')
/// |> circle([-size / 2, -size / 2], 25, %)
/// |> extrude(50, %)
///
/// const thing2 = startSketchOn(case, 'end')
/// |> circle([size / 2, -size / 2], 25, %)
/// |> extrude(50, %)
///
/// // We put "thing1" and "thing2" in the shell function to shell the end face of the object.
/// shell({ faces: ['end'], thickness: 5 }, [thing1, thing2])
/// ```
#[stdlib { #[stdlib {
name = "shell", name = "shell",
}] }]
async fn inner_shell( async fn inner_shell(
data: ShellData, data: ShellData,
extrude_group: Box<ExtrudeGroup>, extrude_group_set: ExtrudeGroupSet,
exec_state: &mut ExecState, exec_state: &mut ExecState,
args: Args, args: Args,
) -> Result<Box<ExtrudeGroup>, KclError> { ) -> Result<ExtrudeGroupSet, KclError> {
if data.faces.is_empty() { if data.faces.is_empty() {
return Err(KclError::Type(KclErrorDetails { return Err(KclError::Type(KclErrorDetails {
message: "Expected at least one face".to_string(), message: "Expected at least one face".to_string(),
@ -164,11 +189,26 @@ async fn inner_shell(
})); }));
} }
let mut face_ids = Vec::new(); let extrude_groups: Vec<Box<ExtrudeGroup>> = extrude_group_set.clone().into();
for tag in data.faces { if extrude_groups.is_empty() {
let extrude_plane_id = tag.get_face_id(&extrude_group, exec_state, &args, false).await?; return Err(KclError::Type(KclErrorDetails {
message: "Expected at least one extrude group".to_string(),
source_ranges: vec![args.source_range],
}));
}
face_ids.push(extrude_plane_id); let mut face_ids = Vec::new();
for extrude_group in &extrude_groups {
// Flush the batch for our fillets/chamfers if there are any.
// If we do not do these for sketch on face, things will fail with face does not exist.
args.flush_batch_for_extrude_group_set(exec_state, extrude_group.clone().into())
.await?;
for tag in &data.faces {
let extrude_plane_id = tag.get_face_id(extrude_group, exec_state, &args, false).await?;
face_ids.push(extrude_plane_id);
}
} }
if face_ids.is_empty() { if face_ids.is_empty() {
@ -178,23 +218,28 @@ async fn inner_shell(
})); }));
} }
// Flush the batch for our fillets/chamfers if there are any. // Make sure all the extrude groups have the same id, as we are going to shell them all at
// If we do not do these for sketch on face, things will fail with face does not exist. // once.
args.flush_batch_for_extrude_group_set(exec_state, extrude_group.clone().into()) if !extrude_groups.iter().all(|eg| eg.id == extrude_groups[0].id) {
.await?; return Err(KclError::Type(KclErrorDetails {
message: "All extrude groups stem from the same root object, like multiple sketch on face extrusions, etc."
.to_string(),
source_ranges: vec![args.source_range],
}));
}
args.batch_modeling_cmd( args.batch_modeling_cmd(
uuid::Uuid::new_v4(), uuid::Uuid::new_v4(),
ModelingCmd::Solid3DShellFace { ModelingCmd::Solid3DShellFace {
hollow: false, hollow: false,
face_ids, face_ids,
object_id: extrude_group.id, object_id: extrude_groups[0].id,
shell_thickness: data.thickness, shell_thickness: data.thickness,
}, },
) )
.await?; .await?;
Ok(extrude_group) Ok(extrude_group_set)
} }
/// Make the inside of a 3D object hollow. /// Make the inside of a 3D object hollow.
@ -211,6 +256,7 @@ pub async fn hollow(exec_state: &mut ExecState, args: Args) -> Result<KclValue,
/// provided thickness remains around the exterior of the shape. /// provided thickness remains around the exterior of the shape.
/// ///
/// ```no_run /// ```no_run
/// // Hollow a basic sketch.
/// const firstSketch = startSketchOn('XY') /// const firstSketch = startSketchOn('XY')
/// |> startProfileAt([-12, 12], %) /// |> startProfileAt([-12, 12], %)
/// |> line([24, 0], %) /// |> line([24, 0], %)
@ -222,6 +268,7 @@ pub async fn hollow(exec_state: &mut ExecState, args: Args) -> Result<KclValue,
/// ``` /// ```
/// ///
/// ```no_run /// ```no_run
/// // Hollow a basic sketch.
/// const firstSketch = startSketchOn('-XZ') /// const firstSketch = startSketchOn('-XZ')
/// |> startProfileAt([-12, 12], %) /// |> startProfileAt([-12, 12], %)
/// |> line([24, 0], %) /// |> line([24, 0], %)
@ -231,6 +278,28 @@ pub async fn hollow(exec_state: &mut ExecState, args: Args) -> Result<KclValue,
/// |> extrude(6, %) /// |> extrude(6, %)
/// |> hollow (0.5, %) /// |> hollow (0.5, %)
/// ``` /// ```
///
/// ```no_run
/// // Hollow a sketch on face object.
/// let size = 100
/// const case = startSketchOn('-XZ')
/// |> startProfileAt([-size, -size], %)
/// |> line([2 * size, 0], %)
/// |> line([0, 2 * size], %)
/// |> tangentialArcTo([-size, size], %)
/// |> close(%)
/// |> extrude(65, %)
///
/// const thing1 = startSketchOn(case, 'end')
/// |> circle([-size / 2, -size / 2], 25, %)
/// |> extrude(50, %)
///
/// const thing2 = startSketchOn(case, 'end')
/// |> circle([size / 2, -size / 2], 25, %)
/// |> extrude(50, %)
///
/// hollow(0.5, case)
/// ```
#[stdlib { #[stdlib {
name = "hollow", name = "hollow",
}] }]

Binary file not shown.

After

Width:  |  Height:  |  Size: 69 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 55 KiB