Remove trig functions from prelude and change their unit handling (BREAKING) (#6565)

Remove trig functions from prelude and change their unit handling

Signed-off-by: Nick Cameron <nrc@ncameron.org>
This commit is contained in:
Nick Cameron
2025-04-30 12:40:11 +12:00
committed by GitHub
parent fa51b4bbbc
commit 844f229b5a
94 changed files with 5880 additions and 13152 deletions

View File

@ -116,6 +116,17 @@ impl TyF64 {
angle.adjust_to(self.n, UnitAngle::Degrees).0
}
pub fn to_radians(&self) -> f64 {
let angle = match self.ty {
NumericType::Default { angle, .. } => angle,
NumericType::Known(UnitType::Angle(angle)) => angle,
_ => unreachable!(),
};
assert_ne!(angle, UnitAngle::Unknown);
angle.adjust_to(self.n, UnitAngle::Radians).0
}
pub fn count(n: f64) -> Self {
Self {
n,

View File

@ -140,19 +140,19 @@ pub async fn reduce(exec_state: &mut ExecState, args: Args) -> Result<KclValue,
/// // Declare a function that sketches a decagon.
/// fn decagon(radius) {
/// // Each side of the decagon is turned this many radians from the previous angle.
/// stepAngle = (1/10) * TAU
/// stepAngle = ((1/10) * TAU): number(rad)
///
/// // Start the decagon sketch at this point.
/// startOfDecagonSketch = startSketchOn('XY')
/// |> startProfile(at = [(cos(0)*radius), (sin(0) * radius)])
/// startOfDecagonSketch = startSketchOn(XY)
/// |> startProfile(at = [(math::cos(0)*radius), (math::sin(0) * radius)])
///
/// // Use a `reduce` to draw the remaining decagon sides.
/// // For each number in the array 1..10, run the given function,
/// // which takes a partially-sketched decagon and adds one more edge to it.
/// fullDecagon = reduce([1..10], initial = startOfDecagonSketch, f = fn(i, partialDecagon) {
/// // Draw one edge of the decagon.
/// x = cos(stepAngle * i) * radius
/// y = sin(stepAngle * i) * radius
/// x = math::cos(stepAngle * i) * radius
/// y = math::sin(stepAngle * i) * radius
/// return line(partialDecagon, end = [x, y])
/// })
///
@ -163,15 +163,15 @@ pub async fn reduce(exec_state: &mut ExecState, args: Args) -> Result<KclValue,
/// /*
/// The `decagon` above is basically like this pseudo-code:
/// fn decagon(radius):
/// stepAngle = (1/10) * TAU
/// plane = startSketchOn('XY')
/// startOfDecagonSketch = startProfile(plane, at = [(cos(0)*radius), (sin(0) * radius)])
/// stepAngle = ((1/10) * TAU): number(rad)
/// plane = startSketchOn(XY)
/// startOfDecagonSketch = startProfile(plane, at = [(math::cos(0)*radius), (math::sin(0) * radius)])
///
/// // Here's the reduce part.
/// partialDecagon = startOfDecagonSketch
/// for i in [1..10]:
/// x = cos(stepAngle * i) * radius
/// y = sin(stepAngle * i) * radius
/// x = math::cos(stepAngle * i) * radius
/// y = math::sin(stepAngle * i) * radius
/// partialDecagon = line(partialDecagon, end = [x, y])
/// fullDecagon = partialDecagon // it's now full
/// return fullDecagon

View File

@ -6,7 +6,7 @@ use kcl_derive_docs::stdlib;
use crate::{
errors::KclError,
execution::{
types::{ArrayLen, NumericType, RuntimeType, UnitAngle, UnitType},
types::{ArrayLen, NumericType, RuntimeType},
ExecState, KclValue,
},
std::args::{Args, TyF64},
@ -21,7 +21,7 @@ pub async fn rem(exec_state: &mut ExecState, args: Args) -> Result<KclValue, Kcl
let (n, d, ty) = NumericType::combine_div(n, d);
if ty == NumericType::Unknown {
exec_state.warn(CompilationError::err(
exec_state.err(CompilationError::err(
args.source_range,
"Calling `rem` on numbers which have unknown or incompatible units.\n\nYou may need to add information about the type of the argument, for example:\n using a numeric suffix: `42{ty}`\n or using type ascription: `foo(): number({ty})`"
));
@ -59,61 +59,21 @@ fn inner_rem(num: f64, divisor: f64) -> f64 {
/// Compute the cosine of a number (in radians).
pub async fn cos(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
let num: TyF64 = args.get_unlabeled_kw_arg_typed("input", &RuntimeType::angle(), exec_state)?;
let num = match num.ty {
NumericType::Default {
angle: UnitAngle::Degrees,
..
} => {
exec_state.warn(CompilationError::err(
args.source_range,
"`cos` requires its input in radians, but the input is assumed to be in degrees. You can use a numeric suffix (e.g., `0rad`) or type ascription (e.g., `(1/2): number(rad)`) to show the number is in radians, or `units::toRadians` to convert from degrees to radians",
));
num.n
}
NumericType::Known(UnitType::Angle(UnitAngle::Degrees)) => num.n.to_radians(),
_ => num.n,
};
let num = num.to_radians();
Ok(args.make_user_val_from_f64_with_type(TyF64::count(num.cos())))
}
/// Compute the sine of a number (in radians).
pub async fn sin(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
let num: TyF64 = args.get_unlabeled_kw_arg_typed("input", &RuntimeType::angle(), exec_state)?;
let num = match num.ty {
NumericType::Default {
angle: UnitAngle::Degrees,
..
} => {
exec_state.warn(CompilationError::err(
args.source_range,
"`sin` requires its input in radians, but the input is assumed to be in degrees. You can use a numeric suffix (e.g., `0rad`) or type ascription (e.g., `(1/2): number(rad)`) to show the number is in radians, or `units::toRadians` to convert from degrees to radians",
));
num.n
}
NumericType::Known(UnitType::Angle(UnitAngle::Degrees)) => num.n.to_radians(),
_ => num.n,
};
let num = num.to_radians();
Ok(args.make_user_val_from_f64_with_type(TyF64::count(num.sin())))
}
/// Compute the tangent of a number (in radians).
pub async fn tan(exec_state: &mut ExecState, args: Args) -> Result<KclValue, KclError> {
let num: TyF64 = args.get_unlabeled_kw_arg_typed("input", &RuntimeType::angle(), exec_state)?;
let num = match num.ty {
NumericType::Default {
angle: UnitAngle::Degrees,
..
} => {
exec_state.warn(CompilationError::err(
args.source_range,
"`tan` requires its input in radians, but the input is assumed to be in degrees. You can use a numeric suffix (e.g., `0rad`) or type ascription (e.g., `(1/2): number(rad)`) to show the number is in radians, or `units::toRadians` to convert from degrees to radians",
));
num.n
}
NumericType::Known(UnitType::Angle(UnitAngle::Degrees)) => num.n.to_radians(),
_ => num.n,
};
let num = num.to_radians();
Ok(args.make_user_val_from_f64_with_type(TyF64::count(num.tan())))
}

View File

@ -202,7 +202,7 @@ pub async fn pattern_transform_2d(exec_state: &mut ExecState, args: Args) -> Res
/// // Defines how to modify each layer of the vase.
/// // Each replica is shifted up the Z axis, and has a smoothly-varying radius
/// fn transform(replicaId) {
/// scale = r * abs(1 - (t * replicaId)) * (5 + cos((replicaId / 8): number(rad)))
/// scale = r * abs(1 - (t * replicaId)) * (5 + math::cos((replicaId / 8): number(rad)))
/// return {
/// translate = [0, 0, replicaId * 10],
/// scale = [scale, scale, 0],