diff --git a/docs/kcl-std/types/std-types-Plane.md b/docs/kcl-std/types/std-types-Plane.md index b3f1d0b2c..45199173f 100644 --- a/docs/kcl-std/types/std-types-Plane.md +++ b/docs/kcl-std/types/std-types-Plane.md @@ -26,6 +26,8 @@ myXY = { ``` Any object with appropriate `origin`, `xAxis`, and `yAxis` fields can be used as a plane. +The plane's Z axis (i.e. which way is "up") will be the cross product X x Y. In other words, +KCL planes follow the right-hand rule. diff --git a/rust/kcl-lib/src/engine/mod.rs b/rust/kcl-lib/src/engine/mod.rs index 152b72cb9..d2dff8184 100644 --- a/rust/kcl-lib/src/engine/mod.rs +++ b/rust/kcl-lib/src/engine/mod.rs @@ -49,38 +49,61 @@ lazy_static::lazy_static! { pub static ref GRID_SCALE_TEXT_OBJECT_ID: uuid::Uuid = uuid::Uuid::parse_str("10782f33-f588-4668-8bcd-040502d26590").unwrap(); pub static ref DEFAULT_PLANE_INFO: IndexMap = IndexMap::from([ - (PlaneName::Xy,PlaneInfo{ - origin: Point3d::new(0.0, 0.0, 0.0, UnitLen::Mm), - x_axis: Point3d::new(1.0, 0.0, 0.0, UnitLen::Unknown), - y_axis: Point3d::new(0.0, 1.0, 0.0, UnitLen::Unknown), - }), - (PlaneName::NegXy, - PlaneInfo{ - origin: Point3d::new(0.0, 0.0, 0.0, UnitLen::Mm), - x_axis: Point3d::new(-1.0, 0.0, 0.0, UnitLen::Unknown), - y_axis: Point3d::new(0.0, 1.0, 0.0, UnitLen::Unknown), - }), - (PlaneName::Xz, PlaneInfo{ - origin: Point3d::new(0.0, 0.0, 0.0, UnitLen::Mm), - x_axis: Point3d::new(1.0, 0.0, 0.0, UnitLen::Unknown), - y_axis: Point3d::new(0.0, 0.0, 1.0, UnitLen::Unknown), - }), - (PlaneName::NegXz, PlaneInfo{ - origin: Point3d::new(0.0, 0.0, 0.0, UnitLen::Mm), - x_axis: Point3d::new(-1.0, 0.0, 0.0, UnitLen::Unknown), - y_axis: Point3d::new(0.0, 0.0, 1.0, UnitLen::Unknown), - }), - (PlaneName::Yz, PlaneInfo{ - origin: Point3d::new(0.0, 0.0, 0.0, UnitLen::Mm), - x_axis: Point3d::new(0.0, 1.0, 0.0, UnitLen::Unknown), - y_axis: Point3d::new(0.0, 0.0, 1.0, UnitLen::Unknown), - }), - (PlaneName::NegYz, PlaneInfo{ - origin: Point3d::new(0.0, 0.0, 0.0, UnitLen::Mm), - x_axis: Point3d::new(0.0, -1.0, 0.0, UnitLen::Unknown), - y_axis: Point3d::new(0.0, 0.0, 1.0, UnitLen::Unknown), - }), - ]); + ( + PlaneName::Xy, + PlaneInfo { + origin: Point3d::new(0.0, 0.0, 0.0, UnitLen::Mm), + x_axis: Point3d::new(1.0, 0.0, 0.0, UnitLen::Unknown), + y_axis: Point3d::new(0.0, 1.0, 0.0, UnitLen::Unknown), + z_axis: Point3d::new(0.0, 0.0, 1.0, UnitLen::Unknown), + }, + ), + ( + PlaneName::NegXy, + PlaneInfo { + origin: Point3d::new( 0.0, 0.0, 0.0, UnitLen::Mm), + x_axis: Point3d::new(-1.0, 0.0, 0.0, UnitLen::Unknown), + y_axis: Point3d::new( 0.0, 1.0, 0.0, UnitLen::Unknown), + z_axis: Point3d::new( 0.0, 0.0, -1.0, UnitLen::Unknown), + }, + ), + ( + PlaneName::Xz, + PlaneInfo { + origin: Point3d::new(0.0, 0.0, 0.0, UnitLen::Mm), + x_axis: Point3d::new(1.0, 0.0, 0.0, UnitLen::Unknown), + y_axis: Point3d::new(0.0, 0.0, 1.0, UnitLen::Unknown), + z_axis: Point3d::new(1.0, 0.0, 0.0, UnitLen::Unknown), + }, + ), + ( + PlaneName::NegXz, + PlaneInfo { + origin: Point3d::new( 0.0, 0.0, 0.0, UnitLen::Mm), + x_axis: Point3d::new(-1.0, 0.0, 0.0, UnitLen::Unknown), + y_axis: Point3d::new( 0.0, 0.0, 1.0, UnitLen::Unknown), + z_axis: Point3d::new(-1.0, 0.0, 0.0, UnitLen::Unknown), + }, + ), + ( + PlaneName::Yz, + PlaneInfo { + origin: Point3d::new(0.0, 0.0, 0.0, UnitLen::Mm), + x_axis: Point3d::new(0.0, 1.0, 0.0, UnitLen::Unknown), + y_axis: Point3d::new(0.0, 0.0, 1.0, UnitLen::Unknown), + z_axis: Point3d::new(0.0, 1.0, 0.0, UnitLen::Unknown), + }, + ), + ( + PlaneName::NegYz, + PlaneInfo { + origin: Point3d::new(0.0, 0.0, 0.0, UnitLen::Mm), + x_axis: Point3d::new(0.0, -1.0, 0.0, UnitLen::Unknown), + y_axis: Point3d::new(0.0, 0.0, 1.0, UnitLen::Unknown), + z_axis: Point3d::new(0.0, -1.0, 0.0, UnitLen::Unknown), + }, + ), + ]); } #[derive(Default, Debug)] diff --git a/rust/kcl-lib/src/execution/geometry.rs b/rust/kcl-lib/src/execution/geometry.rs index f4fcc996c..b1e150128 100644 --- a/rust/kcl-lib/src/execution/geometry.rs +++ b/rust/kcl-lib/src/execution/geometry.rs @@ -299,6 +299,8 @@ pub struct PlaneInfo { pub x_axis: Point3d, /// What should the plane's Y axis be? pub y_axis: Point3d, + /// What should the plane's Z axis be? + pub z_axis: Point3d, } impl PlaneInfo { @@ -327,6 +329,7 @@ impl PlaneInfo { z: 0.0, units: _, }, + z_axis: _, } => return PlaneData::XY, Self { origin: @@ -350,6 +353,7 @@ impl PlaneInfo { z: 0.0, units: _, }, + z_axis: _, } => return PlaneData::NegXY, Self { origin: @@ -373,6 +377,7 @@ impl PlaneInfo { z: 1.0, units: _, }, + z_axis: _, } => return PlaneData::XZ, Self { origin: @@ -396,6 +401,7 @@ impl PlaneInfo { z: 1.0, units: _, }, + z_axis: _, } => return PlaneData::NegXZ, Self { origin: @@ -419,6 +425,7 @@ impl PlaneInfo { z: 1.0, units: _, }, + z_axis: _, } => return PlaneData::YZ, Self { origin: @@ -442,6 +449,7 @@ impl PlaneInfo { z: 1.0, units: _, }, + z_axis: _, } => return PlaneData::NegYZ, _ => {} } @@ -451,6 +459,7 @@ impl PlaneInfo { origin: self.origin, x_axis: self.x_axis, y_axis: self.y_axis, + z_axis: self.z_axis, }) } } diff --git a/rust/kcl-lib/src/execution/types.rs b/rust/kcl-lib/src/execution/types.rs index 6ea937ab5..14142ece8 100644 --- a/rust/kcl-lib/src/execution/types.rs +++ b/rust/kcl-lib/src/execution/types.rs @@ -1182,6 +1182,7 @@ impl KclValue { .get("yAxis") .and_then(Point3d::from_kcl_val) .ok_or(CoercionError::from(self))?; + let z_axis = x_axis.axes_cross_product(&y_axis); if value.get("zAxis").is_some() { exec_state.warn(CompilationError::err( @@ -1198,6 +1199,7 @@ impl KclValue { origin, x_axis: x_axis.normalize(), y_axis: y_axis.normalize(), + z_axis: z_axis.normalize(), }, value: super::PlaneType::Uninit, meta: meta.clone(), diff --git a/rust/kcl-lib/src/lint/checks/offset_plane.rs b/rust/kcl-lib/src/lint/checks/offset_plane.rs index ac4b257a0..6136f7a98 100644 --- a/rust/kcl-lib/src/lint/checks/offset_plane.rs +++ b/rust/kcl-lib/src/lint/checks/offset_plane.rs @@ -212,6 +212,7 @@ pub fn common( origin, x_axis: x_vec, y_axis: y_vec, + z_axis: x_vec.axes_cross_product(&y_vec), }; // Return early if we have a default plane. diff --git a/rust/kcl-lib/src/std/args.rs b/rust/kcl-lib/src/std/args.rs index 087a6220c..4e06e0893 100644 --- a/rust/kcl-lib/src/std/args.rs +++ b/rust/kcl-lib/src/std/args.rs @@ -674,6 +674,7 @@ impl<'a> FromKclValue<'a> for super::sketch::PlaneData { origin: value.info.origin, x_axis: value.info.x_axis, y_axis: value.info.y_axis, + z_axis: value.info.z_axis, })); } // Case 1: predefined plane @@ -692,9 +693,15 @@ impl<'a> FromKclValue<'a> for super::sketch::PlaneData { let obj = arg.as_object()?; let_field_of!(obj, plane, &KclObjectFields); let origin = plane.get("origin").and_then(FromKclValue::from_kcl_val)?; - let x_axis = plane.get("xAxis").and_then(FromKclValue::from_kcl_val)?; + let x_axis: crate::execution::Point3d = plane.get("xAxis").and_then(FromKclValue::from_kcl_val)?; let y_axis = plane.get("yAxis").and_then(FromKclValue::from_kcl_val)?; - Some(Self::Plane(PlaneInfo { origin, x_axis, y_axis })) + let z_axis = x_axis.axes_cross_product(&y_axis); + Some(Self::Plane(PlaneInfo { + origin, + x_axis, + y_axis, + z_axis, + })) } } diff --git a/rust/kcl-lib/src/std/planes.rs b/rust/kcl-lib/src/std/planes.rs index 25fe4cce3..9ff57c696 100644 --- a/rust/kcl-lib/src/std/planes.rs +++ b/rust/kcl-lib/src/std/planes.rs @@ -51,6 +51,7 @@ async fn inner_plane_of( origin: Default::default(), x_axis: Default::default(), y_axis: Default::default(), + z_axis: Default::default(), }, meta: vec![Metadata { source_range: args.source_range, @@ -81,6 +82,7 @@ async fn inner_plane_of( ))); let Some(x_axis) = planar.x_axis else { return not_planar }; let Some(y_axis) = planar.y_axis else { return not_planar }; + let Some(z_axis) = planar.z_axis else { return not_planar }; let Some(origin) = planar.origin else { return not_planar }; // Engine always returns measurements in mm. @@ -97,6 +99,12 @@ async fn inner_plane_of( z: y_axis.z, units: engine_units, }; + let z_axis = crate::execution::Point3d { + x: z_axis.x, + y: z_axis.y, + z: z_axis.z, + units: engine_units, + }; let origin = crate::execution::Point3d { x: origin.x.0, y: origin.y.0, @@ -111,7 +119,12 @@ async fn inner_plane_of( id: plane_id, // Engine doesn't know about the ID we created, so set this to Uninit. value: PlaneType::Uninit, - info: crate::execution::PlaneInfo { origin, x_axis, y_axis }, + info: crate::execution::PlaneInfo { + origin, + x_axis, + y_axis, + z_axis, + }, meta: vec![Metadata { source_range: args.source_range, }], diff --git a/rust/kcl-lib/std/types.kcl b/rust/kcl-lib/std/types.kcl index 91e29918a..6d9429c17 100644 --- a/rust/kcl-lib/std/types.kcl +++ b/rust/kcl-lib/std/types.kcl @@ -210,6 +210,8 @@ export type fn /// ``` /// /// Any object with appropriate `origin`, `xAxis`, and `yAxis` fields can be used as a plane. +/// The plane's Z axis (i.e. which way is "up") will be the cross product X x Y. In other words, +/// KCL planes follow the right-hand rule. @(impl = std_rust) export type Plane