Allow same syntax for patterns as mirror revolve (#7054)

* allow named axis for patterns

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

* docs

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

* images

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

* Fix typo

Co-authored-by: Jonathan Tran <jonnytran@gmail.com>

---------

Signed-off-by: Jess Frazelle <github@jessfraz.com>
Co-authored-by: Adam Chalmers <adam.chalmers@zoo.dev>
Co-authored-by: Jonathan Tran <jonnytran@gmail.com>
This commit is contained in:
Jess Frazelle
2025-05-18 19:25:35 -07:00
committed by GitHub
parent bd01059a92
commit 658497da1d
12 changed files with 177 additions and 16 deletions

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -156307,7 +156307,11 @@
"deprecated": false,
"examples": [
[
"exampleSketch = startSketchOn(XZ)\n |> circle(center = [0, 0], radius = 1)\n |> patternLinear2d(axis = [1, 0], instances = 7, distance = 4)\n\nexample = extrude(exampleSketch, length = 1)",
"// / Pattern using a named axis.\n\n\nexampleSketch = startSketchOn(XZ)\n |> circle(center = [0, 0], radius = 1)\n |> patternLinear2d(axis = X, instances = 7, distance = 4)\n\nexample = extrude(exampleSketch, length = 1)",
false
],
[
"// / Pattern using a raw axis.\n\n\nexampleSketch = startSketchOn(XZ)\n |> circle(center = [0, 0], radius = 1)\n |> patternLinear2d(axis = [1, 0], instances = 7, distance = 4)\n\nexample = extrude(exampleSketch, length = 1)",
false
]
]
@ -165963,7 +165967,11 @@
"deprecated": false,
"examples": [
[
"exampleSketch = startSketchOn(XZ)\n |> startProfile(at = [0, 0])\n |> line(end = [0, 2])\n |> line(end = [3, 1])\n |> line(end = [0, -4])\n |> close()\n\nexample = extrude(exampleSketch, length = 1)\n |> patternLinear3d(axis = [1, 0, 1], instances = 7, distance = 6)",
"// / Pattern using a named axis.\n\n\nexampleSketch = startSketchOn(XZ)\n |> startProfile(at = [0, 0])\n |> line(end = [0, 2])\n |> line(end = [3, 1])\n |> line(end = [0, -4])\n |> close()\n\nexample = extrude(exampleSketch, length = 1)\n |> patternLinear3d(axis = X, instances = 7, distance = 6)",
false
],
[
"// / Pattern using a raw axis.\n\n\nexampleSketch = startSketchOn(XZ)\n |> startProfile(at = [0, 0])\n |> line(end = [0, 2])\n |> line(end = [3, 1])\n |> line(end = [0, -4])\n |> close()\n\nexample = extrude(exampleSketch, length = 1)\n |> patternLinear3d(axis = [1, 0, 1], instances = 7, distance = 6)",
false
],
[

View File

@ -1283,6 +1283,32 @@ impl<'a> FromKclValue<'a> for super::axis_or_reference::Axis3dOrEdgeReference {
}
}
impl<'a> FromKclValue<'a> for super::axis_or_reference::Axis2dOrPoint2d {
fn from_kcl_val(arg: &'a KclValue) -> Option<Self> {
let case1 = |arg: &KclValue| {
let obj = arg.as_object()?;
let_field_of!(obj, direction);
let_field_of!(obj, origin);
Some(Self::Axis { direction, origin })
};
let case2 = <[TyF64; 2]>::from_kcl_val;
case1(arg).or_else(|| case2(arg).map(Self::Point))
}
}
impl<'a> FromKclValue<'a> for super::axis_or_reference::Axis3dOrPoint3d {
fn from_kcl_val(arg: &'a KclValue) -> Option<Self> {
let case1 = |arg: &KclValue| {
let obj = arg.as_object()?;
let_field_of!(obj, direction);
let_field_of!(obj, origin);
Some(Self::Axis { direction, origin })
};
let case2 = <[TyF64; 3]>::from_kcl_val;
case1(arg).or_else(|| case2(arg).map(Self::Point))
}
}
impl<'a> FromKclValue<'a> for i64 {
fn from_kcl_val(arg: &'a KclValue) -> Option<Self> {
match arg {

View File

@ -21,3 +21,41 @@ pub enum Axis3dOrEdgeReference {
/// Tagged edge.
Edge(EdgeReference),
}
/// A 2D axis or a raw point2d.
#[derive(Debug, Clone, PartialEq)]
pub enum Axis2dOrPoint2d {
/// 2D axis and origin.
Axis { direction: [TyF64; 2], origin: [TyF64; 2] },
/// Raw point2d.
Point([TyF64; 2]),
}
impl Axis2dOrPoint2d {
/// Convert to a 2D axis.
pub fn to_point2d(&self) -> [TyF64; 2] {
match self {
Axis2dOrPoint2d::Axis { direction, origin: _ } => direction.clone(),
Axis2dOrPoint2d::Point(point) => point.clone(),
}
}
}
/// A 3D axis or a raw point3d.
#[derive(Debug, Clone, PartialEq)]
pub enum Axis3dOrPoint3d {
/// 3D axis and origin.
Axis { direction: [TyF64; 3], origin: [TyF64; 3] },
/// Raw point3d.
Point([TyF64; 3]),
}
impl Axis3dOrPoint3d {
/// Convert to a 3D axis.
pub fn to_point3d(&self) -> [TyF64; 3] {
match self {
Axis3dOrPoint3d::Axis { direction, origin: _ } => direction.clone(),
Axis3dOrPoint3d::Point(point) => point.clone(),
}
}
}

View File

@ -17,7 +17,6 @@ use crate::{
};
/// Mirror a sketch.
///
pub async fn mirror_2d(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
let sketches = args.get_unlabeled_kw_arg_typed("sketches", &RuntimeType::sketches(), exec_state)?;
let axis = args.get_kw_arg_typed(
@ -34,7 +33,6 @@ pub async fn mirror_2d(exec_state: &mut ExecState, args: Args) -> Result<KclValu
}
/// Mirror a sketch.
///
async fn inner_mirror_2d(
sketches: Vec<Sketch>,
axis: Axis2dOrEdgeReference,

View File

@ -15,21 +15,24 @@ use kittycad_modeling_cmds::{
use serde::Serialize;
use uuid::Uuid;
use super::{
args::{Arg, KwArgs},
utils::{point_3d_to_mm, point_to_mm},
};
use crate::{
errors::{KclError, KclErrorDetails},
execution::{
kcl_value::FunctionSource,
types::{NumericType, RuntimeType},
types::{NumericType, PrimitiveType, RuntimeType},
ExecState, Geometries, Geometry, KclObjectFields, KclValue, Sketch, Solid,
},
std::{args::TyF64, Args},
std::{
args::{Arg, KwArgs, TyF64},
axis_or_reference::Axis2dOrPoint2d,
utils::{point_3d_to_mm, point_to_mm},
Args,
},
ExecutorContext, SourceRange,
};
use super::axis_or_reference::Axis3dOrPoint3d;
const MUST_HAVE_ONE_INSTANCE: &str = "There must be at least 1 instance of your geometry";
/// Repeat some 3D solid, changing each repetition slightly.
@ -742,9 +745,17 @@ pub async fn pattern_linear_2d(exec_state: &mut ExecState, args: Args) -> Result
let sketches = args.get_unlabeled_kw_arg_typed("sketches", &RuntimeType::sketches(), exec_state)?;
let instances: u32 = args.get_kw_arg("instances")?;
let distance: TyF64 = args.get_kw_arg_typed("distance", &RuntimeType::length(), exec_state)?;
let axis: [TyF64; 2] = args.get_kw_arg_typed("axis", &RuntimeType::point2d(), exec_state)?;
let axis: Axis2dOrPoint2d = args.get_kw_arg_typed(
"axis",
&RuntimeType::Union(vec![
RuntimeType::Primitive(PrimitiveType::Axis2d),
RuntimeType::point2d(),
]),
exec_state,
)?;
let use_original: Option<bool> = args.get_kw_arg_opt("useOriginal")?;
let axis = axis.to_point2d();
if axis[0].n == 0.0 && axis[1].n == 0.0 {
return Err(KclError::Semantic(KclErrorDetails {
message:
@ -762,6 +773,22 @@ pub async fn pattern_linear_2d(exec_state: &mut ExecState, args: Args) -> Result
/// of distance between each repetition, some specified number of times.
///
/// ```no_run
/// /// Pattern using a named axis.
///
/// exampleSketch = startSketchOn(XZ)
/// |> circle(center = [0, 0], radius = 1)
/// |> patternLinear2d(
/// axis = X,
/// instances = 7,
/// distance = 4
/// )
///
/// example = extrude(exampleSketch, length = 1)
/// ```
///
/// ```no_run
/// /// Pattern using a raw axis.
///
/// exampleSketch = startSketchOn(XZ)
/// |> circle(center = [0, 0], radius = 1)
/// |> patternLinear2d(
@ -821,9 +848,17 @@ pub async fn pattern_linear_3d(exec_state: &mut ExecState, args: Args) -> Result
let solids = args.get_unlabeled_kw_arg_typed("solids", &RuntimeType::solids(), exec_state)?;
let instances: u32 = args.get_kw_arg("instances")?;
let distance: TyF64 = args.get_kw_arg_typed("distance", &RuntimeType::length(), exec_state)?;
let axis: [TyF64; 3] = args.get_kw_arg_typed("axis", &RuntimeType::point3d(), exec_state)?;
let axis: Axis3dOrPoint3d = args.get_kw_arg_typed(
"axis",
&RuntimeType::Union(vec![
RuntimeType::Primitive(PrimitiveType::Axis3d),
RuntimeType::point3d(),
]),
exec_state,
)?;
let use_original: Option<bool> = args.get_kw_arg_opt("useOriginal")?;
let axis = axis.to_point3d();
if axis[0].n == 0.0 && axis[1].n == 0.0 && axis[2].n == 0.0 {
return Err(KclError::Semantic(KclErrorDetails {
message:
@ -841,6 +876,26 @@ pub async fn pattern_linear_3d(exec_state: &mut ExecState, args: Args) -> Result
/// of distance between each repetition, some specified number of times.
///
/// ```no_run
/// /// Pattern using a named axis.
///
/// exampleSketch = startSketchOn(XZ)
/// |> startProfile(at = [0, 0])
/// |> line(end = [0, 2])
/// |> line(end = [3, 1])
/// |> line(end = [0, -4])
/// |> close()
///
/// example = extrude(exampleSketch, length = 1)
/// |> patternLinear3d(
/// axis = X,
/// instances = 7,
/// distance = 6
/// )
/// ```
///
/// ```no_run
/// /// Pattern using a raw axis.
///
/// exampleSketch = startSketchOn(XZ)
/// |> startProfile(at = [0, 0])
/// |> line(end = [0, 2])

Binary file not shown.

After

Width:  |  Height:  |  Size: 47 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 43 KiB

After

Width:  |  Height:  |  Size: 46 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 64 KiB

After

Width:  |  Height:  |  Size: 43 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 52 KiB

After

Width:  |  Height:  |  Size: 64 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 52 KiB