Warn on inferred angle units

Signed-off-by: Nick Cameron <nrc@ncameron.org>
This commit is contained in:
Nick Cameron
2025-06-17 09:03:13 +12:00
parent 8395869b2e
commit bfaec5c04e
8 changed files with 126 additions and 43 deletions

View File

@ -37,12 +37,14 @@ pub(crate) const WARNINGS: &str = "warnings";
pub(crate) const WARN_ALLOW: &str = "allow"; pub(crate) const WARN_ALLOW: &str = "allow";
pub(crate) const WARN_DENY: &str = "deny"; pub(crate) const WARN_DENY: &str = "deny";
pub(crate) const WARN_UNKNOWN_UNITS: &str = "unknownUnits"; pub(crate) const WARN_UNKNOWN_UNITS: &str = "unknownUnits";
pub(crate) const WARN_ANGLE_UNITS: &str = "angleUnits";
pub(crate) const WARN_UNKNOWN_ATTR: &str = "unknownAttribute"; pub(crate) const WARN_UNKNOWN_ATTR: &str = "unknownAttribute";
pub(crate) const WARN_MOD_RETURN_VALUE: &str = "moduleReturnValue"; pub(crate) const WARN_MOD_RETURN_VALUE: &str = "moduleReturnValue";
pub(crate) const WARN_DEPRECATED: &str = "deprecated"; pub(crate) const WARN_DEPRECATED: &str = "deprecated";
pub(crate) const WARN_IGNORED_Z_AXIS: &str = "ignoredZAxis"; pub(crate) const WARN_IGNORED_Z_AXIS: &str = "ignoredZAxis";
pub(super) const WARN_VALUES: [&str; 5] = [ pub(super) const WARN_VALUES: [&str; 6] = [
WARN_UNKNOWN_UNITS, WARN_UNKNOWN_UNITS,
WARN_ANGLE_UNITS,
WARN_UNKNOWN_ATTR, WARN_UNKNOWN_ATTR,
WARN_MOD_RETURN_VALUE, WARN_MOD_RETURN_VALUE,
WARN_DEPRECATED, WARN_DEPRECATED,

View File

@ -49,9 +49,20 @@ impl ExecutorContext {
for annotation in annotations { for annotation in annotations {
if annotation.name() == Some(annotations::SETTINGS) { if annotation.name() == Some(annotations::SETTINGS) {
if matches!(body_type, BodyType::Root) { if matches!(body_type, BodyType::Root) {
if exec_state.mod_local.settings.update_from_annotation(annotation)? { let (updated_len, updated_angle) =
exec_state.mod_local.settings.update_from_annotation(annotation)?;
if updated_len {
exec_state.mod_local.explicit_length_units = true; exec_state.mod_local.explicit_length_units = true;
} }
if updated_angle {
exec_state.warn(
CompilationError::err(
annotation.as_source_range(),
"Prefer to use explicit units for angles",
),
annotations::WARN_ANGLE_UNITS,
);
}
} else { } else {
exec_state.err(CompilationError::err( exec_state.err(CompilationError::err(
annotation.as_source_range(), annotation.as_source_range(),
@ -1204,12 +1215,12 @@ impl Node<BinaryExpression> {
let value = match self.operator { let value = match self.operator {
BinaryOperator::Add => { BinaryOperator::Add => {
let (l, r, ty) = NumericType::combine_eq_coerce(left, right); let (l, r, ty) = NumericType::combine_eq_coerce(left, right, None);
self.warn_on_unknown(&ty, "Adding", exec_state); self.warn_on_unknown(&ty, "Adding", exec_state);
KclValue::Number { value: l + r, meta, ty } KclValue::Number { value: l + r, meta, ty }
} }
BinaryOperator::Sub => { BinaryOperator::Sub => {
let (l, r, ty) = NumericType::combine_eq_coerce(left, right); let (l, r, ty) = NumericType::combine_eq_coerce(left, right, None);
self.warn_on_unknown(&ty, "Subtracting", exec_state); self.warn_on_unknown(&ty, "Subtracting", exec_state);
KclValue::Number { value: l - r, meta, ty } KclValue::Number { value: l - r, meta, ty }
} }
@ -1234,32 +1245,32 @@ impl Node<BinaryExpression> {
ty: exec_state.current_default_units(), ty: exec_state.current_default_units(),
}, },
BinaryOperator::Neq => { BinaryOperator::Neq => {
let (l, r, ty) = NumericType::combine_eq(left, right); let (l, r, ty) = NumericType::combine_eq(left, right, exec_state, self.as_source_range());
self.warn_on_unknown(&ty, "Comparing", exec_state); self.warn_on_unknown(&ty, "Comparing", exec_state);
KclValue::Bool { value: l != r, meta } KclValue::Bool { value: l != r, meta }
} }
BinaryOperator::Gt => { BinaryOperator::Gt => {
let (l, r, ty) = NumericType::combine_eq(left, right); let (l, r, ty) = NumericType::combine_eq(left, right, exec_state, self.as_source_range());
self.warn_on_unknown(&ty, "Comparing", exec_state); self.warn_on_unknown(&ty, "Comparing", exec_state);
KclValue::Bool { value: l > r, meta } KclValue::Bool { value: l > r, meta }
} }
BinaryOperator::Gte => { BinaryOperator::Gte => {
let (l, r, ty) = NumericType::combine_eq(left, right); let (l, r, ty) = NumericType::combine_eq(left, right, exec_state, self.as_source_range());
self.warn_on_unknown(&ty, "Comparing", exec_state); self.warn_on_unknown(&ty, "Comparing", exec_state);
KclValue::Bool { value: l >= r, meta } KclValue::Bool { value: l >= r, meta }
} }
BinaryOperator::Lt => { BinaryOperator::Lt => {
let (l, r, ty) = NumericType::combine_eq(left, right); let (l, r, ty) = NumericType::combine_eq(left, right, exec_state, self.as_source_range());
self.warn_on_unknown(&ty, "Comparing", exec_state); self.warn_on_unknown(&ty, "Comparing", exec_state);
KclValue::Bool { value: l < r, meta } KclValue::Bool { value: l < r, meta }
} }
BinaryOperator::Lte => { BinaryOperator::Lte => {
let (l, r, ty) = NumericType::combine_eq(left, right); let (l, r, ty) = NumericType::combine_eq(left, right, exec_state, self.as_source_range());
self.warn_on_unknown(&ty, "Comparing", exec_state); self.warn_on_unknown(&ty, "Comparing", exec_state);
KclValue::Bool { value: l <= r, meta } KclValue::Bool { value: l <= r, meta }
} }
BinaryOperator::Eq => { BinaryOperator::Eq => {
let (l, r, ty) = NumericType::combine_eq(left, right); let (l, r, ty) = NumericType::combine_eq(left, right, exec_state, self.as_source_range());
self.warn_on_unknown(&ty, "Comparing", exec_state); self.warn_on_unknown(&ty, "Comparing", exec_state);
KclValue::Bool { value: l == r, meta } KclValue::Bool { value: l == r, meta }
} }

View File

@ -542,10 +542,11 @@ impl MetaSettings {
pub(crate) fn update_from_annotation( pub(crate) fn update_from_annotation(
&mut self, &mut self,
annotation: &crate::parsing::ast::types::Node<Annotation>, annotation: &crate::parsing::ast::types::Node<Annotation>,
) -> Result<bool, KclError> { ) -> Result<(bool, bool), KclError> {
let properties = annotations::expect_properties(annotations::SETTINGS, annotation)?; let properties = annotations::expect_properties(annotations::SETTINGS, annotation)?;
let mut updated_len = false; let mut updated_len = false;
let mut updated_angle = false;
for p in properties { for p in properties {
match &*p.inner.key.name { match &*p.inner.key.name {
annotations::SETTINGS_UNIT_LENGTH => { annotations::SETTINGS_UNIT_LENGTH => {
@ -558,6 +559,7 @@ impl MetaSettings {
let value = annotations::expect_ident(&p.inner.value)?; let value = annotations::expect_ident(&p.inner.value)?;
let value = types::UnitAngle::from_str(value, annotation.as_source_range())?; let value = types::UnitAngle::from_str(value, annotation.as_source_range())?;
self.default_angle_units = value; self.default_angle_units = value;
updated_angle = true;
} }
annotations::SETTINGS_VERSION => { annotations::SETTINGS_VERSION => {
let value = annotations::expect_number(&p.inner.value)?; let value = annotations::expect_number(&p.inner.value)?;
@ -576,6 +578,6 @@ impl MetaSettings {
} }
} }
Ok(updated_len) Ok((updated_len, updated_angle))
} }
} }

View File

@ -506,7 +506,12 @@ impl NumericType {
/// ///
/// This combinator function is suitable for comparisons where uncertainty should /// This combinator function is suitable for comparisons where uncertainty should
/// be handled by the user. /// be handled by the user.
pub fn combine_eq(a: TyF64, b: TyF64) -> (f64, f64, NumericType) { pub fn combine_eq(
a: TyF64,
b: TyF64,
exec_state: &mut ExecState,
source_range: SourceRange,
) -> (f64, f64, NumericType) {
use NumericType::*; use NumericType::*;
match (a.ty, b.ty) { match (a.ty, b.ty) {
(at, bt) if at == bt => (a.n, b.n, at), (at, bt) if at == bt => (a.n, b.n, at),
@ -521,8 +526,24 @@ impl NumericType {
} }
(t @ Known(UnitType::Length(l1)), Default { len: l2, .. }) if l1 == l2 => (a.n, b.n, t), (t @ Known(UnitType::Length(l1)), Default { len: l2, .. }) if l1 == l2 => (a.n, b.n, t),
(Default { len: l1, .. }, t @ Known(UnitType::Length(l2))) if l1 == l2 => (a.n, b.n, t), (Default { len: l1, .. }, t @ Known(UnitType::Length(l2))) if l1 == l2 => (a.n, b.n, t),
(t @ Known(UnitType::Angle(a1)), Default { angle: a2, .. }) if a1 == a2 => (a.n, b.n, t), (t @ Known(UnitType::Angle(a1)), Default { angle: a2, .. }) if a1 == a2 => {
(Default { angle: a1, .. }, t @ Known(UnitType::Angle(a2))) if a1 == a2 => (a.n, b.n, t), if b.n != 0.0 {
exec_state.warn(
CompilationError::err(source_range, "Prefer to use explicit units for angles"),
annotations::WARN_ANGLE_UNITS,
);
}
(a.n, b.n, t)
}
(Default { angle: a1, .. }, t @ Known(UnitType::Angle(a2))) if a1 == a2 => {
if a.n != 0.0 {
exec_state.warn(
CompilationError::err(source_range, "Prefer to use explicit units for angles"),
annotations::WARN_ANGLE_UNITS,
);
}
(a.n, b.n, t)
}
_ => (a.n, b.n, Unknown), _ => (a.n, b.n, Unknown),
} }
@ -535,7 +556,11 @@ impl NumericType {
/// coerced together, for example two arguments to the same function or two numbers in an array being used as a point. /// coerced together, for example two arguments to the same function or two numbers in an array being used as a point.
/// ///
/// Prefer to use `combine_eq` if possible since using that prioritises correctness over ergonomics. /// Prefer to use `combine_eq` if possible since using that prioritises correctness over ergonomics.
pub fn combine_eq_coerce(a: TyF64, b: TyF64) -> (f64, f64, NumericType) { pub fn combine_eq_coerce(
a: TyF64,
b: TyF64,
for_errs: Option<(&mut ExecState, SourceRange)>,
) -> (f64, f64, NumericType) {
use NumericType::*; use NumericType::*;
match (a.ty, b.ty) { match (a.ty, b.ty) {
(at, bt) if at == bt => (a.n, b.n, at), (at, bt) if at == bt => (a.n, b.n, at),
@ -553,8 +578,28 @@ impl NumericType {
(t @ Known(UnitType::Length(l1)), Default { len: l2, .. }) => (a.n, l2.adjust_to(b.n, l1).0, t), (t @ Known(UnitType::Length(l1)), Default { len: l2, .. }) => (a.n, l2.adjust_to(b.n, l1).0, t),
(Default { len: l1, .. }, t @ Known(UnitType::Length(l2))) => (l1.adjust_to(a.n, l2).0, b.n, t), (Default { len: l1, .. }, t @ Known(UnitType::Length(l2))) => (l1.adjust_to(a.n, l2).0, b.n, t),
(t @ Known(UnitType::Angle(a1)), Default { angle: a2, .. }) => (a.n, a2.adjust_to(b.n, a1).0, t), (t @ Known(UnitType::Angle(a1)), Default { angle: a2, .. }) => {
(Default { angle: a1, .. }, t @ Known(UnitType::Angle(a2))) => (a1.adjust_to(a.n, a2).0, b.n, t), if let Some((exec_state, source_range)) = for_errs {
if b.n != 0.0 {
exec_state.warn(
CompilationError::err(source_range, "Prefer to use explicit units for angles"),
annotations::WARN_ANGLE_UNITS,
);
}
}
(a.n, a2.adjust_to(b.n, a1).0, t)
}
(Default { angle: a1, .. }, t @ Known(UnitType::Angle(a2))) => {
if let Some((exec_state, source_range)) = for_errs {
if a.n != 0.0 {
exec_state.warn(
CompilationError::err(source_range, "Prefer to use explicit units for angles"),
annotations::WARN_ANGLE_UNITS,
);
}
}
(a1.adjust_to(a.n, a2).0, b.n, t)
}
(Known(_), Known(_)) | (Default { .. }, Default { .. }) | (_, Unknown) | (Unknown, _) => { (Known(_), Known(_)) | (Default { .. }, Default { .. }) | (_, Unknown) | (Unknown, _) => {
(a.n, b.n, Unknown) (a.n, b.n, Unknown)
@ -2350,14 +2395,18 @@ b = 180 / PI * a + 360
#[tokio::test(flavor = "multi_thread")] #[tokio::test(flavor = "multi_thread")]
async fn cos_coercions() { async fn cos_coercions() {
let program = r#" let program = r#"
a = cos(units::toRadians(30)) a = cos(units::toRadians(30deg))
b = 3 / a b = 3 / a
c = cos(30deg) c = cos(30deg)
d = cos(30) d = cos(1rad)
"#; "#;
let result = parse_execute(program).await.unwrap(); let result = parse_execute(program).await.unwrap();
assert!(result.exec_state.errors().is_empty()); assert!(
result.exec_state.errors().is_empty(),
"{:?}",
result.exec_state.errors()
);
assert_value_and_type("a", &result, 1.0, NumericType::default()); assert_value_and_type("a", &result, 1.0, NumericType::default());
assert_value_and_type("b", &result, 3.0, NumericType::default()); assert_value_and_type("b", &result, 3.0, NumericType::default());

View File

@ -9,6 +9,7 @@ pub use crate::execution::fn_call::Args;
use crate::{ use crate::{
errors::{KclError, KclErrorDetails}, errors::{KclError, KclErrorDetails},
execution::{ execution::{
annotations,
kcl_value::FunctionSource, kcl_value::FunctionSource,
types::{NumericType, PrimitiveType, RuntimeType, UnitAngle, UnitLen, UnitType}, types::{NumericType, PrimitiveType, RuntimeType, UnitAngle, UnitLen, UnitType},
ExecState, ExtrudeSurface, Helix, KclObjectFields, KclValue, Metadata, PlaneInfo, Sketch, SketchSurface, Solid, ExecState, ExtrudeSurface, Helix, KclObjectFields, KclValue, Metadata, PlaneInfo, Sketch, SketchSurface, Solid,
@ -21,7 +22,7 @@ use crate::{
sketch::FaceTag, sketch::FaceTag,
sweep::SweepPath, sweep::SweepPath,
}, },
ModuleId, CompilationError, ModuleId,
}; };
const ERROR_STRING_SKETCH_TO_SOLID_HELPER: &str = const ERROR_STRING_SKETCH_TO_SOLID_HELPER: &str =
@ -56,9 +57,17 @@ impl TyF64 {
len.adjust_to(self.n, units).0 len.adjust_to(self.n, units).0
} }
pub fn to_degrees(&self) -> f64 { pub fn to_degrees(&self, exec_state: &mut ExecState, source_range: SourceRange) -> f64 {
let angle = match self.ty { let angle = match self.ty {
NumericType::Default { angle, .. } => angle, NumericType::Default { angle, .. } => {
if self.n != 0.0 {
exec_state.warn(
CompilationError::err(source_range, "Prefer to use explicit units for angles"),
annotations::WARN_ANGLE_UNITS,
);
}
angle
}
NumericType::Known(UnitType::Angle(angle)) => angle, NumericType::Known(UnitType::Angle(angle)) => angle,
_ => unreachable!(), _ => unreachable!(),
}; };
@ -68,9 +77,17 @@ impl TyF64 {
angle.adjust_to(self.n, UnitAngle::Degrees).0 angle.adjust_to(self.n, UnitAngle::Degrees).0
} }
pub fn to_radians(&self) -> f64 { pub fn to_radians(&self, exec_state: &mut ExecState, source_range: SourceRange) -> f64 {
let angle = match self.ty { let angle = match self.ty {
NumericType::Default { angle, .. } => angle, NumericType::Default { angle, .. } => {
if self.n != 0.0 {
exec_state.warn(
CompilationError::err(source_range, "Prefer to use explicit units for angles"),
annotations::WARN_ANGLE_UNITS,
);
}
angle
}
NumericType::Known(UnitType::Angle(angle)) => angle, NumericType::Known(UnitType::Angle(angle)) => angle,
_ => unreachable!(), _ => unreachable!(),
}; };

View File

@ -34,21 +34,21 @@ pub async fn rem(exec_state: &mut ExecState, args: Args) -> Result<KclValue, Kcl
/// Compute the cosine of a number (in radians). /// Compute the cosine of a number (in radians).
pub async fn cos(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> { pub async fn cos(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
let num: TyF64 = args.get_unlabeled_kw_arg("input", &RuntimeType::angle(), exec_state)?; let num: TyF64 = args.get_unlabeled_kw_arg("input", &RuntimeType::angle(), exec_state)?;
let num = num.to_radians(); let num = num.to_radians(exec_state, args.source_range);
Ok(args.make_user_val_from_f64_with_type(TyF64::new(libm::cos(num), exec_state.current_default_units()))) Ok(args.make_user_val_from_f64_with_type(TyF64::new(libm::cos(num), exec_state.current_default_units())))
} }
/// Compute the sine of a number (in radians). /// Compute the sine of a number (in radians).
pub async fn sin(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> { pub async fn sin(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
let num: TyF64 = args.get_unlabeled_kw_arg("input", &RuntimeType::angle(), exec_state)?; let num: TyF64 = args.get_unlabeled_kw_arg("input", &RuntimeType::angle(), exec_state)?;
let num = num.to_radians(); let num = num.to_radians(exec_state, args.source_range);
Ok(args.make_user_val_from_f64_with_type(TyF64::new(libm::sin(num), exec_state.current_default_units()))) Ok(args.make_user_val_from_f64_with_type(TyF64::new(libm::sin(num), exec_state.current_default_units())))
} }
/// Compute the tangent of a number (in radians). /// Compute the tangent of a number (in radians).
pub async fn tan(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> { pub async fn tan(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
let num: TyF64 = args.get_unlabeled_kw_arg("input", &RuntimeType::angle(), exec_state)?; let num: TyF64 = args.get_unlabeled_kw_arg("input", &RuntimeType::angle(), exec_state)?;
let num = num.to_radians(); let num = num.to_radians(exec_state, args.source_range);
Ok(args.make_user_val_from_f64_with_type(TyF64::new(libm::tan(num), exec_state.current_default_units()))) Ok(args.make_user_val_from_f64_with_type(TyF64::new(libm::tan(num), exec_state.current_default_units())))
} }
@ -190,7 +190,7 @@ pub async fn atan(exec_state: &mut ExecState, args: Args) -> Result<KclValue, Kc
pub async fn atan2(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> { pub async fn atan2(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
let y = args.get_kw_arg("y", &RuntimeType::length(), exec_state)?; let y = args.get_kw_arg("y", &RuntimeType::length(), exec_state)?;
let x = args.get_kw_arg("x", &RuntimeType::length(), exec_state)?; let x = args.get_kw_arg("x", &RuntimeType::length(), exec_state)?;
let (y, x, _) = NumericType::combine_eq_coerce(y, x); let (y, x, _) = NumericType::combine_eq_coerce(y, x, Some((exec_state, args.source_range)));
let result = libm::atan2(y, x); let result = libm::atan2(y, x);
Ok(args.make_user_val_from_f64_with_type(TyF64::new(result, NumericType::radians()))) Ok(args.make_user_val_from_f64_with_type(TyF64::new(result, NumericType::radians())))
@ -237,7 +237,7 @@ pub async fn ln(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclE
pub async fn leg_length(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> { pub async fn leg_length(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
let hypotenuse: TyF64 = args.get_kw_arg("hypotenuse", &RuntimeType::length(), exec_state)?; let hypotenuse: TyF64 = args.get_kw_arg("hypotenuse", &RuntimeType::length(), exec_state)?;
let leg: TyF64 = args.get_kw_arg("leg", &RuntimeType::length(), exec_state)?; let leg: TyF64 = args.get_kw_arg("leg", &RuntimeType::length(), exec_state)?;
let (hypotenuse, leg, ty) = NumericType::combine_eq_coerce(hypotenuse, leg); let (hypotenuse, leg, ty) = NumericType::combine_eq_coerce(hypotenuse, leg, Some((exec_state, args.source_range)));
let result = (hypotenuse.powi(2) - f64::min(hypotenuse.abs(), leg.abs()).powi(2)).sqrt(); let result = (hypotenuse.powi(2) - f64::min(hypotenuse.abs(), leg.abs()).powi(2)).sqrt();
Ok(KclValue::from_number_with_type(result, ty, vec![args.into()])) Ok(KclValue::from_number_with_type(result, ty, vec![args.into()]))
} }
@ -246,7 +246,7 @@ pub async fn leg_length(exec_state: &mut ExecState, args: Args) -> Result<KclVal
pub async fn leg_angle_x(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> { pub async fn leg_angle_x(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
let hypotenuse: TyF64 = args.get_kw_arg("hypotenuse", &RuntimeType::length(), exec_state)?; let hypotenuse: TyF64 = args.get_kw_arg("hypotenuse", &RuntimeType::length(), exec_state)?;
let leg: TyF64 = args.get_kw_arg("leg", &RuntimeType::length(), exec_state)?; let leg: TyF64 = args.get_kw_arg("leg", &RuntimeType::length(), exec_state)?;
let (hypotenuse, leg, _ty) = NumericType::combine_eq_coerce(hypotenuse, leg); let (hypotenuse, leg, _ty) = NumericType::combine_eq_coerce(hypotenuse, leg, Some((exec_state, args.source_range)));
let result = libm::acos(leg.min(hypotenuse) / hypotenuse).to_degrees(); let result = libm::acos(leg.min(hypotenuse) / hypotenuse).to_degrees();
Ok(KclValue::from_number_with_type( Ok(KclValue::from_number_with_type(
result, result,
@ -259,7 +259,7 @@ pub async fn leg_angle_x(exec_state: &mut ExecState, args: Args) -> Result<KclVa
pub async fn leg_angle_y(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> { pub async fn leg_angle_y(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
let hypotenuse: TyF64 = args.get_kw_arg("hypotenuse", &RuntimeType::length(), exec_state)?; let hypotenuse: TyF64 = args.get_kw_arg("hypotenuse", &RuntimeType::length(), exec_state)?;
let leg: TyF64 = args.get_kw_arg("leg", &RuntimeType::length(), exec_state)?; let leg: TyF64 = args.get_kw_arg("leg", &RuntimeType::length(), exec_state)?;
let (hypotenuse, leg, _ty) = NumericType::combine_eq_coerce(hypotenuse, leg); let (hypotenuse, leg, _ty) = NumericType::combine_eq_coerce(hypotenuse, leg, Some((exec_state, args.source_range)));
let result = libm::asin(leg.min(hypotenuse) / hypotenuse).to_degrees(); let result = libm::asin(leg.min(hypotenuse) / hypotenuse).to_degrees();
Ok(KclValue::from_number_with_type( Ok(KclValue::from_number_with_type(
result, result,

View File

@ -132,6 +132,8 @@ async fn inner_involute_circular(
args: Args, args: Args,
) -> Result<Sketch, KclError> { ) -> Result<Sketch, KclError> {
let id = exec_state.next_uuid(); let id = exec_state.next_uuid();
let angle_deg = angle.to_degrees(exec_state, args.source_range);
let angle_rad = angle.to_radians(exec_state, args.source_range);
exec_state exec_state
.batch_modeling_cmd( .batch_modeling_cmd(
@ -141,7 +143,7 @@ async fn inner_involute_circular(
segment: PathSegment::CircularInvolute { segment: PathSegment::CircularInvolute {
start_radius: LengthUnit(start_radius.to_mm()), start_radius: LengthUnit(start_radius.to_mm()),
end_radius: LengthUnit(end_radius.to_mm()), end_radius: LengthUnit(end_radius.to_mm()),
angle: Angle::from_degrees(angle.to_degrees()), angle: Angle::from_degrees(angle_deg),
reverse: reverse.unwrap_or_default(), reverse: reverse.unwrap_or_default(),
}, },
}), }),
@ -157,11 +159,11 @@ async fn inner_involute_circular(
let theta = f64::sqrt(end_radius * end_radius - start_radius * start_radius) / start_radius; let theta = f64::sqrt(end_radius * end_radius - start_radius * start_radius) / start_radius;
let (x, y) = involute_curve(start_radius, theta); let (x, y) = involute_curve(start_radius, theta);
end.x = x * libm::cos(angle.to_radians()) - y * libm::sin(angle.to_radians()); end.x = x * libm::cos(angle_rad) - y * libm::sin(angle_rad);
end.y = x * libm::sin(angle.to_radians()) + y * libm::cos(angle.to_radians()); end.y = x * libm::sin(angle_rad) + y * libm::cos(angle_rad);
end.x -= start_radius * libm::cos(angle.to_radians()); end.x -= start_radius * libm::cos(angle_rad);
end.y -= start_radius * libm::sin(angle.to_radians()); end.y -= start_radius * libm::sin(angle_rad);
if reverse.unwrap_or_default() { if reverse.unwrap_or_default() {
end.x = -end.x; end.x = -end.x;
@ -718,7 +720,7 @@ pub async fn inner_angled_line_that_intersects(
point_to_len_unit(path.get_to(), from.units), point_to_len_unit(path.get_to(), from.units),
], ],
offset.map(|t| t.to_length_units(from.units)).unwrap_or_default(), offset.map(|t| t.to_length_units(from.units)).unwrap_or_default(),
angle.to_degrees(), angle.to_degrees(exec_state, args.source_range),
from.ignore_units(), from.ignore_units(),
); );
let to = [ let to = [
@ -1256,8 +1258,8 @@ pub async fn relative_arc(
radius: TyF64, radius: TyF64,
tag: Option<TagNode>, tag: Option<TagNode>,
) -> Result<Sketch, KclError> { ) -> Result<Sketch, KclError> {
let a_start = Angle::from_degrees(angle_start.to_degrees()); let a_start = Angle::from_degrees(angle_start.to_degrees(exec_state, args.source_range));
let a_end = Angle::from_degrees(angle_end.to_degrees()); let a_end = Angle::from_degrees(angle_end.to_degrees(exec_state, args.source_range));
let radius = radius.to_length_units(from.units); let radius = radius.to_length_units(from.units);
let (center, end) = arc_center_and_end(from.ignore_units(), a_start, a_end, radius); let (center, end) = arc_center_and_end(from.ignore_units(), a_start, a_end, radius);
if a_start == a_end { if a_start == a_end {
@ -1409,7 +1411,7 @@ async fn inner_tangential_arc_radius_angle(
let (center, to, ccw) = match data { let (center, to, ccw) = match data {
TangentialArcData::RadiusAndOffset { radius, offset } => { TangentialArcData::RadiusAndOffset { radius, offset } => {
// KCL stdlib types use degrees. // KCL stdlib types use degrees.
let offset = Angle::from_degrees(offset.to_degrees()); let offset = Angle::from_degrees(offset.to_degrees(exec_state, args.source_range));
// Calculate the end point from the angle and radius. // Calculate the end point from the angle and radius.
// atan2 outputs radians. // atan2 outputs radians.

View File

@ -6,7 +6,7 @@ use super::args::TyF64;
use crate::execution::types::{NumericType, UnitLen}; use crate::execution::types::{NumericType, UnitLen};
pub(crate) fn untype_point(p: [TyF64; 2]) -> ([f64; 2], NumericType) { pub(crate) fn untype_point(p: [TyF64; 2]) -> ([f64; 2], NumericType) {
let (x, y, ty) = NumericType::combine_eq_coerce(p[0].clone(), p[1].clone()); let (x, y, ty) = NumericType::combine_eq_coerce(p[0].clone(), p[1].clone(), None);
([x, y], ty) ([x, y], ty)
} }