Files
modeling-app/rust/kcl-lib/std/math.kcl
Adam Chalmers 3156653287 Cross product
2025-07-01 15:45:38 -05:00

496 lines
13 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/// Functions for mathematical operations and some useful constants.
@no_std
@settings(defaultLengthUnit = mm, kclVersion = 1.0)
import Point2d from "std::types"
/// The value of `pi`, Archimedes constant (π).
///
/// `PI` is a number and is technically a ratio, so you might expect it to have type `number(_)`.
/// However, `PI` is nearly always used for converting between different units - usually degrees to or
/// from radians. Therefore, `PI` is treated a bit specially by KCL and always has unknown units. This
/// means that if you use `PI`, you will need to give KCL some extra information about the units of numbers.
/// Usually you should use type ascription on the result of calculations, e.g., `(2 * PI): number(rad)`.
/// It is better to use `units::toRadians` or `units::toDegrees` to convert between angles with
/// different units where possible.
///
/// ```
/// circumference = 70
///
/// exampleSketch = startSketchOn(XZ)
/// |> circle(center = [0, 0], radius = (circumference / (2 * PI)): number(mm))
///
/// example = extrude(exampleSketch, length = 5)
/// ```
export PI = 3.14159265358979323846264338327950288_?
/// The value of Eulers number `e`.
///
/// ```
/// exampleSketch = startSketchOn(XZ)
/// |> startProfile(at = [0, 0])
/// |> angledLine(
/// angle = 30deg,
/// length = 2 * E ^ 2,
/// )
/// |> yLine(endAbsolute = 0)
/// |> close()
///
/// example = extrude(exampleSketch, length = 10)
/// ```
export E = 2.71828182845904523536028747135266250_
/// The value of `tau`, the full circle constant (τ). Equal to 2π.
///
/// ```
/// exampleSketch = startSketchOn(XZ)
/// |> startProfile(at = [0, 0])
/// |> angledLine(
/// angle = 50deg,
/// length = 10 * TAU,
/// )
/// |> yLine(endAbsolute = 0)
/// |> close()
///
/// example = extrude(exampleSketch, length = 5)
/// ```
export TAU = 6.28318530717958647692528676655900577_
/// Compute the cosine of a number.
///
/// ```
/// exampleSketch = startSketchOn(XZ)
/// |> startProfile(at = [0, 0])
/// |> angledLine(
/// angle = 30deg,
/// length = 3 / cos(30deg),
/// )
/// |> yLine(endAbsolute = 0)
/// |> close()
///
/// example = extrude(exampleSketch, length = 5)
/// ```
@(impl = std_rust)
export fn cos(@num: number(Angle)): number {}
/// Compute the sine of a number.
///
/// ```
/// exampleSketch = startSketchOn(XZ)
/// |> startProfile(at = [0, 0])
/// |> angledLine(
/// angle = 50deg,
/// length = 15 / sin(135deg),
/// )
/// |> yLine(endAbsolute = 0)
/// |> close()
///
/// example = extrude(exampleSketch, length = 5)
/// ```
@(impl = std_rust)
export fn sin(@num: number(Angle)): number {}
/// Compute the tangent of a number.
///
/// ```
/// exampleSketch = startSketchOn(XZ)
/// |> startProfile(at = [0, 0])
/// |> angledLine(
/// angle = 50deg,
/// length = 50 * tan((1/2): number(rad)),
/// )
/// |> yLine(endAbsolute = 0)
/// |> close()
///
/// example = extrude(exampleSketch, length = 5)
/// ```
@(impl = std_rust)
export fn tan(@num: number(Angle)): number {}
/// Compute the arccosine of a number.
///
/// ```
/// sketch001 = startSketchOn(XZ)
/// |> startProfile(at = [0, 0])
/// |> angledLine(
/// angle = acos(0.5),
/// length = 10,
/// )
/// |> line(end = [5, 0])
/// |> line(endAbsolute = [12, 0])
/// |> close()
///
/// extrude001 = extrude(sketch001, length = 5)
/// ```
@(impl = std_rust)
export fn acos(@num: number(Count)): number(rad) {}
/// Compute the arcsine of a number.
///
/// ```
/// sketch001 = startSketchOn(XZ)
/// |> startProfile(at = [0, 0])
/// |> angledLine(
/// angle = asin(0.5),
/// length = 20,
/// )
/// |> yLine(endAbsolute = 0)
/// |> close()
///
/// extrude001 = extrude(sketch001, length = 5)
/// ```
@(impl = std_rust)
export fn asin(@num: number(Count)): number(rad) {}
/// Compute the arctangent of a number.
///
/// Consider using `atan2()` instead for the true inverse of tangent.
///
/// ```no_run
/// sketch001 = startSketchOn(XZ)
/// |> startProfile(at = [0, 0])
/// |> angledLine(
/// angle = atan(1.25),
/// length = 20,
/// )
/// |> yLine(endAbsolute = 0)
/// |> close()
///
/// extrude001 = extrude(sketch001, length = 5)
/// ```
@(impl = std_rust)
export fn atan(@num: number(Count)): number(rad) {}
/// Compute the four quadrant arctangent of Y and X.
///
/// ```
/// sketch001 = startSketchOn(XZ)
/// |> startProfile(at = [0, 0])
/// |> angledLine(
/// angle = atan2(y = 1.25, x = 2),
/// length = 20,
/// )
/// |> yLine(endAbsolute = 0)
/// |> close()
///
/// extrude001 = extrude(sketch001, length = 5)
/// ```
@(impl = std_rust)
export fn atan2(y: number(Length), x: number(Length)): number(rad) {}
/// Convert polar/sphere (azimuth, elevation, distance) coordinates to
/// cartesian (x/y/z grid) coordinates.
///
/// ```
/// exampleSketch = startSketchOn(XZ)
/// |> startProfile(at = [0, 0])
/// |> line(end = polar(angle = 30deg, length = 5), tag = $thing)
/// |> line(end = [0, 5])
/// |> line(end = [segEndX(thing), 0])
/// |> line(end = [-20, 10])
/// |> close()
///
/// example = extrude(exampleSketch, length = 5)
/// ```
export fn polar(angle: number(rad), length: number(Length)): Point2d {
x = length * cos(angle)
y = length * sin(angle)
return [x, y]
}
/// Compute the remainder after dividing `num` by `div`.
/// If `num` is negative, the result will be too.
///
/// ```
/// import rem from "std::math"
///
/// assert(rem( 7, divisor = 4), isEqualTo = 3, error = "remainder is 3")
/// assert(rem(-7, divisor = 4), isEqualTo = -3, error = "remainder is -3")
/// assert(rem( 7, divisor = -4), isEqualTo = 3, error = "remainder is 3")
/// assert(rem( 6, divisor = 2.5), isEqualTo = 1, error = "remainder is 1")
/// assert(rem( 6.5, divisor = 2.5), isEqualTo = 1.5, error = "remainder is 1.5")
/// assert(rem( 6.5, divisor = 2), isEqualTo = 0.5, error = "remainder is 0.5")
/// ```
@(impl = std_rust)
export fn rem(
/// The number which will be divided by `divisor`.
@num: number,
/// The number which will divide `num`.
divisor: number,
): number {}
/// Compute the square root of a number.
///
/// ```
/// exampleSketch = startSketchOn(XZ)
/// |> startProfile(at = [0, 0])
/// |> angledLine(
/// angle = 50deg,
/// length = sqrt(2500),
/// )
/// |> yLine(endAbsolute = 0)
/// |> close()
///
/// example = extrude(exampleSketch, length = 5)
/// ```
@(impl = std_rust)
export fn sqrt(@input: number): number {}
/// Compute the absolute value of a number.
///
/// ```
/// myAngle = -120deg
///
/// sketch001 = startSketchOn(XZ)
/// |> startProfile(at = [0, 0])
/// |> line(end = [8, 0])
/// |> angledLine(
/// angle = abs(myAngle),
/// length = 5,
/// )
/// |> line(end = [-5, 0])
/// |> angledLine(
/// angle = myAngle,
/// length = 5,
/// )
/// |> close()
///
/// baseExtrusion = extrude(sketch001, length = 5)
/// ```
@(impl = std_rust)
export fn abs(@input: number): number {}
/// Round a number to the nearest integer.
///
/// ```
/// sketch001 = startSketchOn(XZ)
/// |> startProfile(at = [0, 0])
/// |> line(endAbsolute = [12, 10])
/// |> line(end = [round(7.02986), 0])
/// |> yLine(endAbsolute = 0)
/// |> close()
///
/// extrude001 = extrude(sketch001, length = 5)
/// ```
@(impl = std_rust)
export fn round(@input: number): number {}
/// Compute the largest integer less than or equal to a number.
///
/// ```
/// sketch001 = startSketchOn(XZ)
/// |> startProfile(at = [0, 0])
/// |> line(endAbsolute = [12, 10])
/// |> line(end = [floor(7.02986), 0])
/// |> yLine(endAbsolute = 0)
/// |> close()
///
/// extrude001 = extrude(sketch001, length = 5)
/// ```
@(impl = std_rust)
export fn floor(@input: number): number {}
/// Compute the smallest integer greater than or equal to a number.
///
/// ```
/// sketch001 = startSketchOn(XZ)
/// |> startProfile(at = [0, 0])
/// |> line(endAbsolute = [12, 10])
/// |> line(end = [ceil(7.02986), 0])
/// |> yLine(endAbsolute = 0)
/// |> close()
///
/// extrude001 = extrude(sketch001, length = 5)
/// ```
@(impl = std_rust)
export fn ceil(@input: number): number {}
/// Compute the minimum of the given arguments.
///
/// ```
/// exampleSketch = startSketchOn(XZ)
/// |> startProfile(at = [0, 0])
/// |> angledLine(
/// angle = 70deg,
/// length = min([15, 31, 4, 13, 22])
/// )
/// |> line(end = [20, 0])
/// |> close()
///
/// example = extrude(exampleSketch, length = 5)
/// ```
@(impl = std_rust)
export fn min(
/// An array of numbers to compute the minimum of.
@input: [number; 1+],
): number {}
/// Compute the maximum of the given arguments.
///
/// ```
/// exampleSketch = startSketchOn(XZ)
/// |> startProfile(at = [0, 0])
/// |> angledLine(
/// angle = 70deg,
/// length = max([15, 31, 4, 13, 22])
/// )
/// |> line(end = [20, 0])
/// |> close()
///
/// example = extrude(exampleSketch, length = 5)
/// ```
@(impl = std_rust)
export fn max(
/// An array of numbers to compute the maximum of.
@input: [number; 1+],
): number {}
/// Compute the number to a power.
///
/// ```
/// exampleSketch = startSketchOn(XZ)
/// |> startProfile(at = [0, 0])
/// |> angledLine(
/// angle = 50deg,
/// length = pow(5, exp = 2),
/// )
/// |> yLine(endAbsolute = 0)
/// |> close()
///
/// example = extrude(exampleSketch, length = 5)
/// ```
@(impl = std_rust)
export fn pow(
/// The number to raise.
@input: number,
/// The power to raise to.
exp: number(Count),
): number {}
/// Compute the logarithm of the number with respect to an arbitrary base.
///
/// The result might not be correctly rounded owing to implementation
/// details; `log2` can produce more accurate results for base 2,
/// and `log10` can produce more accurate results for base 10.
///
/// ```
/// exampleSketch = startSketchOn(XZ)
/// |> startProfile(at = [0, 0])
/// |> line(end = [log(100, base = 5), 0])
/// |> line(end = [5, 8])
/// |> line(end = [-10, 0])
/// |> close()
///
/// example = extrude(exampleSketch, length = 5)
/// ```
@(impl = std_rust)
export fn log(
/// The number to compute the logarithm of.
@input: number,
/// The base of the logarithm.
base: number(Count),
): number {}
/// Compute the base 2 logarithm of the number.
///
/// ```
/// exampleSketch = startSketchOn(XZ)
/// |> startProfile(at = [0, 0])
/// |> line(end = [log2(100), 0])
/// |> line(end = [5, 8])
/// |> line(end = [-10, 0])
/// |> close()
///
/// example = extrude(exampleSketch, length = 5)
/// ```
@(impl = std_rust)
export fn log2(@input: number): number {}
/// Compute the base 10 logarithm of the number.
///
/// ```
/// exampleSketch = startSketchOn(XZ)
/// |> startProfile(at = [0, 0])
/// |> line(end = [log10(100), 0])
/// |> line(end = [5, 8])
/// |> line(end = [-10, 0])
/// |> close()
///
/// example = extrude(exampleSketch, length = 5)
/// ```
@(impl = std_rust)
export fn log10(@input: number): number {}
/// Compute the natural logarithm of the number.
///
/// ```
/// exampleSketch = startSketchOn(XZ)
/// |> startProfile(at = [0, 0])
/// |> line(end = [ln(100), 15])
/// |> line(end = [5, -6])
/// |> line(end = [-10, -10])
/// |> close()
///
/// example = extrude(exampleSketch, length = 5)
/// ```
@(impl = std_rust)
export fn ln(@input: number): number {}
/// Compute the length of the given leg.
///
/// ```kcl,no_run
/// legLen(hypotenuse = 5, leg = 3)
/// ```
@(impl = std_rust)
export fn legLen(
/// The length of the triangle's hypotenuse.
hypotenuse: number(Length),
/// The length of one of the triangle's legs (i.e. non-hypotenuse side).
leg: number(Length),
): number(Length) {}
/// Compute the angle of the given leg for x.
///
/// ```kcl,no_run
/// legAngX(hypotenuse = 5, leg = 3)
/// ```
@(impl = std_rust)
export fn legAngX(
/// The length of the triangle's hypotenuse.
hypotenuse: number(Length),
/// The length of one of the triangle's legs (i.e. non-hypotenuse side).
leg: number(Length),
): number(deg) {}
/// Compute the angle of the given leg for y.
///
/// ```kcl,no_run
/// legAngY(hypotenuse = 5, leg = 3)
/// ```
@(impl = std_rust)
export fn legAngY(
/// The length of the triangle's hypotenuse.
hypotenuse: number(Length),
/// The length of one of the triangle's legs (i.e. non-hypotenuse side).
leg: number(Length),
): number(deg) {}
/// Compute the cross product of two vectors.
///
/// ```kcl,no_run
/// p = XY
/// cross = crossProduct([planes::xAxis(p), planes::yAxis(p)])
/// ```
export fn crossProduct(
/// Returns the cross product of these two vectors.
@vectors: [Point3d; 2],
): Point3d {
a = vectors[0]
b = vectors[1]
x = a[1] * b[2] - (a[2] * b[1])
y = a[2] * b[0] - (a[0] * b[2])
z = a[0] * b[1] - (a[1] * b[0])
return [x,y,z]
}