Revolve/Sweep multiple sketches at once (#5779)
* revolve multiple sketches at once 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> * updates Signed-off-by: Jess Frazelle <github@jessfraz.com> * updates Signed-off-by: Jess Frazelle <github@jessfraz.com> * do the same for swweep Signed-off-by: Jess Frazelle <github@jessfraz.com> * updates Signed-off-by: Jess Frazelle <github@jessfraz.com> * do the same for swweep Signed-off-by: Jess Frazelle <github@jessfraz.com> --------- Signed-off-by: Jess Frazelle <github@jessfraz.com>
This commit is contained in:
@ -522,13 +522,6 @@ impl Args {
|
||||
FromArgs::from_args(self, 0)
|
||||
}
|
||||
|
||||
pub(crate) fn get_data_and_sketch<'a, T>(&'a self) -> Result<(T, Sketch), KclError>
|
||||
where
|
||||
T: serde::de::DeserializeOwned + FromArgs<'a>,
|
||||
{
|
||||
FromArgs::from_args(self, 0)
|
||||
}
|
||||
|
||||
pub(crate) fn get_data_and_sketch_set<'a, T>(&'a self) -> Result<(T, SketchSet), KclError>
|
||||
where
|
||||
T: serde::de::DeserializeOwned + FromArgs<'a>,
|
||||
|
@ -34,6 +34,9 @@ pub async fn extrude(exec_state: &mut ExecState, args: Args) -> Result<KclValue,
|
||||
/// create new 3-dimensional volume, or if extruded into an existing volume,
|
||||
/// cut into an existing solid.
|
||||
///
|
||||
/// You can provide more than one sketch to extrude, and they will all be
|
||||
/// extruded in the same direction.
|
||||
///
|
||||
/// ```no_run
|
||||
/// example = startSketchOn('XZ')
|
||||
/// |> startProfileAt([0, 0], %)
|
||||
@ -82,7 +85,7 @@ pub async fn extrude(exec_state: &mut ExecState, args: Args) -> Result<KclValue,
|
||||
keywords = true,
|
||||
unlabeled_first = true,
|
||||
args = {
|
||||
sketch_set = { docs = "Which sketches should be extruded"},
|
||||
sketch_set = { docs = "Which sketch or set of sketches should be extruded"},
|
||||
length = { docs = "How far to extrude the given sketches"},
|
||||
}
|
||||
}]
|
||||
|
@ -9,7 +9,7 @@ use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::{
|
||||
errors::{KclError, KclErrorDetails},
|
||||
execution::{ExecState, KclValue, Sketch, Solid},
|
||||
execution::{ExecState, KclValue, Sketch, SketchSet, SolidSet},
|
||||
std::{axis_or_reference::Axis2dOrEdgeReference, extrude::do_post_extrude, fillet::default_tolerance, Args},
|
||||
};
|
||||
|
||||
@ -28,12 +28,12 @@ pub struct RevolveData {
|
||||
pub tolerance: Option<f64>,
|
||||
}
|
||||
|
||||
/// Revolve a sketch around an axis.
|
||||
/// Revolve a sketch or set of sketches around an axis.
|
||||
pub async fn revolve(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
|
||||
let (data, sketch): (RevolveData, Sketch) = args.get_data_and_sketch()?;
|
||||
let (data, sketch_set): (RevolveData, SketchSet) = args.get_data_and_sketch_set()?;
|
||||
|
||||
let value = inner_revolve(data, sketch, exec_state, args).await?;
|
||||
Ok(KclValue::Solid { value })
|
||||
let value = inner_revolve(data, sketch_set, exec_state, args).await?;
|
||||
Ok(value.into())
|
||||
}
|
||||
|
||||
/// Rotate a sketch around some provided axis, creating a solid from its extent.
|
||||
@ -46,6 +46,9 @@ pub async fn revolve(exec_state: &mut ExecState, args: Args) -> Result<KclValue,
|
||||
///
|
||||
/// Revolve occurs around a local sketch axis rather than a global axis.
|
||||
///
|
||||
/// You can provide more than one sketch to revolve, and they will all be
|
||||
/// revolved around the same axis.
|
||||
///
|
||||
/// ```no_run
|
||||
/// part001 = startSketchOn('XY')
|
||||
/// |> startProfileAt([4, 12], %)
|
||||
@ -174,16 +177,39 @@ pub async fn revolve(exec_state: &mut ExecState, args: Args) -> Result<KclValue,
|
||||
/// }
|
||||
/// }, sketch001)
|
||||
/// ```
|
||||
///
|
||||
/// ```no_run
|
||||
/// // Revolve two sketches around the same axis.
|
||||
///
|
||||
/// sketch001 = startSketchOn('XY')
|
||||
/// profile001 = startProfileAt([4, 8], sketch001)
|
||||
/// |> xLine(length = 3)
|
||||
/// |> yLine(length = -3)
|
||||
/// |> xLine(length = -3)
|
||||
/// |> line(endAbsolute = [profileStartX(%), profileStartY(%)])
|
||||
/// |> close()
|
||||
///
|
||||
/// profile002 = startProfileAt([-5, 8], sketch001)
|
||||
/// |> xLine(length = 3)
|
||||
/// |> yLine(length = -3)
|
||||
/// |> xLine(length = -3)
|
||||
/// |> line(endAbsolute = [profileStartX(%), profileStartY(%)])
|
||||
/// |> close()
|
||||
///
|
||||
/// revolve({
|
||||
/// axis = "X",
|
||||
/// }, [profile001, profile002])
|
||||
/// ```
|
||||
#[stdlib {
|
||||
name = "revolve",
|
||||
feature_tree_operation = true,
|
||||
}]
|
||||
async fn inner_revolve(
|
||||
data: RevolveData,
|
||||
sketch: Sketch,
|
||||
sketch_set: SketchSet,
|
||||
exec_state: &mut ExecState,
|
||||
args: Args,
|
||||
) -> Result<Box<Solid>, KclError> {
|
||||
) -> Result<SolidSet, KclError> {
|
||||
if let Some(angle) = data.angle {
|
||||
// Return an error if the angle is zero.
|
||||
// We don't use validate() here because we want to return a specific error message that is
|
||||
@ -198,37 +224,44 @@ async fn inner_revolve(
|
||||
|
||||
let angle = Angle::from_degrees(data.angle.unwrap_or(360.0));
|
||||
|
||||
let id = exec_state.next_uuid();
|
||||
match data.axis {
|
||||
Axis2dOrEdgeReference::Axis(axis) => {
|
||||
let (axis, origin) = axis.axis_and_origin()?;
|
||||
args.batch_modeling_cmd(
|
||||
id,
|
||||
ModelingCmd::from(mcmd::Revolve {
|
||||
angle,
|
||||
target: sketch.id.into(),
|
||||
axis,
|
||||
origin,
|
||||
tolerance: LengthUnit(data.tolerance.unwrap_or(default_tolerance(&args.ctx.settings.units))),
|
||||
axis_is_2d: true,
|
||||
}),
|
||||
)
|
||||
.await?;
|
||||
}
|
||||
Axis2dOrEdgeReference::Edge(edge) => {
|
||||
let edge_id = edge.get_engine_id(exec_state, &args)?;
|
||||
args.batch_modeling_cmd(
|
||||
id,
|
||||
ModelingCmd::from(mcmd::RevolveAboutEdge {
|
||||
angle,
|
||||
target: sketch.id.into(),
|
||||
edge_id,
|
||||
tolerance: LengthUnit(data.tolerance.unwrap_or(default_tolerance(&args.ctx.settings.units))),
|
||||
}),
|
||||
)
|
||||
.await?;
|
||||
let sketches: Vec<Sketch> = sketch_set.into();
|
||||
let mut solids = Vec::new();
|
||||
for sketch in &sketches {
|
||||
let id = exec_state.next_uuid();
|
||||
|
||||
match &data.axis {
|
||||
Axis2dOrEdgeReference::Axis(axis) => {
|
||||
let (axis, origin) = axis.axis_and_origin()?;
|
||||
args.batch_modeling_cmd(
|
||||
id,
|
||||
ModelingCmd::from(mcmd::Revolve {
|
||||
angle,
|
||||
target: sketch.id.into(),
|
||||
axis,
|
||||
origin,
|
||||
tolerance: LengthUnit(data.tolerance.unwrap_or(default_tolerance(&args.ctx.settings.units))),
|
||||
axis_is_2d: true,
|
||||
}),
|
||||
)
|
||||
.await?;
|
||||
}
|
||||
Axis2dOrEdgeReference::Edge(edge) => {
|
||||
let edge_id = edge.get_engine_id(exec_state, &args)?;
|
||||
args.batch_modeling_cmd(
|
||||
id,
|
||||
ModelingCmd::from(mcmd::RevolveAboutEdge {
|
||||
angle,
|
||||
target: sketch.id.into(),
|
||||
edge_id,
|
||||
tolerance: LengthUnit(data.tolerance.unwrap_or(default_tolerance(&args.ctx.settings.units))),
|
||||
}),
|
||||
)
|
||||
.await?;
|
||||
}
|
||||
}
|
||||
|
||||
solids.push(do_post_extrude(sketch.clone(), id.into(), 0.0, exec_state, args.clone()).await?);
|
||||
}
|
||||
|
||||
do_post_extrude(sketch, id.into(), 0.0, exec_state, args).await
|
||||
Ok(solids.into())
|
||||
}
|
||||
|
@ -9,7 +9,7 @@ use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::{
|
||||
errors::KclError,
|
||||
execution::{ExecState, Helix, KclValue, Sketch, Solid},
|
||||
execution::{ExecState, Helix, KclValue, Sketch, SketchSet, SolidSet},
|
||||
std::{extrude::do_post_extrude, fillet::default_tolerance, Args},
|
||||
};
|
||||
|
||||
@ -30,7 +30,7 @@ pub async fn sweep(exec_state: &mut ExecState, args: Args) -> Result<KclValue, K
|
||||
let tolerance = args.get_kw_arg_opt("tolerance")?;
|
||||
|
||||
let value = inner_sweep(sketch, path, sectional, tolerance, exec_state, args).await?;
|
||||
Ok(KclValue::Solid { value })
|
||||
Ok(value.into())
|
||||
}
|
||||
|
||||
/// Extrude a sketch along a path.
|
||||
@ -41,6 +41,9 @@ pub async fn sweep(exec_state: &mut ExecState, args: Args) -> Result<KclValue, K
|
||||
/// creating more complex shapes that can't be created with a simple
|
||||
/// extrusion.
|
||||
///
|
||||
/// You can provide more than one sketch to sweep, and they will all be
|
||||
/// swept along the same path.
|
||||
///
|
||||
/// ```no_run
|
||||
/// // Create a pipe using a sweep.
|
||||
///
|
||||
@ -94,40 +97,79 @@ pub async fn sweep(exec_state: &mut ExecState, args: Args) -> Result<KclValue, K
|
||||
/// |> circle( center = [0, 0], radius = 1)
|
||||
/// |> sweep(path = helixPath)
|
||||
/// ```
|
||||
///
|
||||
/// ```
|
||||
/// // Sweep two sketches along the same path.
|
||||
///
|
||||
/// sketch001 = startSketchOn('XY')
|
||||
/// rectangleSketch = startProfileAt([-200, 23.86], sketch001)
|
||||
/// |> angledLine([0, 73.47], %, $rectangleSegmentA001)
|
||||
/// |> angledLine([
|
||||
/// segAng(rectangleSegmentA001) - 90,
|
||||
/// 50.61
|
||||
/// ], %)
|
||||
/// |> angledLine([
|
||||
/// segAng(rectangleSegmentA001),
|
||||
/// -segLen(rectangleSegmentA001)
|
||||
/// ], %)
|
||||
/// |> line(endAbsolute = [profileStartX(%), profileStartY(%)])
|
||||
/// |> close()
|
||||
///
|
||||
/// circleSketch = circle(sketch001, center = [200, -30.29], radius = 32.63)
|
||||
///
|
||||
/// sketch002 = startSketchOn('YZ')
|
||||
/// sweepPath = startProfileAt([0, 0], sketch002)
|
||||
/// |> yLine(length = 231.81)
|
||||
/// |> tangentialArc({
|
||||
/// radius = 80,
|
||||
/// offset = -90,
|
||||
/// }, %)
|
||||
/// |> xLine(length = 384.93)
|
||||
///
|
||||
/// sweep([rectangleSketch, circleSketch], path = sweepPath)
|
||||
/// ```
|
||||
#[stdlib {
|
||||
name = "sweep",
|
||||
feature_tree_operation = true,
|
||||
keywords = true,
|
||||
unlabeled_first = true,
|
||||
args = {
|
||||
sketch = { docs = "The sketch that should be swept in space" },
|
||||
sketch_set = { docs = "The sketch or set of sketches that should be swept in space" },
|
||||
path = { docs = "The path to sweep the sketch along" },
|
||||
sectional = { docs = "If true, the sweep will be broken up into sub-sweeps (extrusions, revolves, sweeps) based on the trajectory path components." },
|
||||
tolerance = { docs = "Tolerance for this operation" },
|
||||
}
|
||||
}]
|
||||
async fn inner_sweep(
|
||||
sketch: Sketch,
|
||||
sketch_set: SketchSet,
|
||||
path: SweepPath,
|
||||
sectional: Option<bool>,
|
||||
tolerance: Option<f64>,
|
||||
exec_state: &mut ExecState,
|
||||
args: Args,
|
||||
) -> Result<Box<Solid>, KclError> {
|
||||
let id = exec_state.next_uuid();
|
||||
args.batch_modeling_cmd(
|
||||
id,
|
||||
ModelingCmd::from(mcmd::Sweep {
|
||||
target: sketch.id.into(),
|
||||
trajectory: match path {
|
||||
SweepPath::Sketch(sketch) => sketch.id.into(),
|
||||
SweepPath::Helix(helix) => helix.value.into(),
|
||||
},
|
||||
sectional: sectional.unwrap_or(false),
|
||||
tolerance: LengthUnit(tolerance.unwrap_or(default_tolerance(&args.ctx.settings.units))),
|
||||
}),
|
||||
)
|
||||
.await?;
|
||||
) -> Result<SolidSet, KclError> {
|
||||
let trajectory = match path {
|
||||
SweepPath::Sketch(sketch) => sketch.id.into(),
|
||||
SweepPath::Helix(helix) => helix.value.into(),
|
||||
};
|
||||
|
||||
do_post_extrude(sketch, id.into(), 0.0, exec_state, args).await
|
||||
let sketches: Vec<Sketch> = sketch_set.into();
|
||||
let mut solids = Vec::new();
|
||||
for sketch in &sketches {
|
||||
let id = exec_state.next_uuid();
|
||||
args.batch_modeling_cmd(
|
||||
id,
|
||||
ModelingCmd::from(mcmd::Sweep {
|
||||
target: sketch.id.into(),
|
||||
trajectory,
|
||||
sectional: sectional.unwrap_or(false),
|
||||
tolerance: LengthUnit(tolerance.unwrap_or(default_tolerance(&args.ctx.settings.units))),
|
||||
}),
|
||||
)
|
||||
.await?;
|
||||
|
||||
solids.push(do_post_extrude(sketch.clone(), id.into(), 0.0, exec_state, args.clone()).await?);
|
||||
}
|
||||
|
||||
Ok(solids.into())
|
||||
}
|
||||
|
Reference in New Issue
Block a user