| ... | ... | @@ -37,6 +37,12 @@ pub const sqrt2 = 1.414213562373095048801688724209698079; |
| 37 | 37 | /// 1/sqrt(2) |
| 38 | 38 | pub const sqrt1_2 = 0.707106781186547524400844362104849039; |
| 39 | 39 | |
| 40 | /// pi/180.0 |
| 41 | pub const rad_per_deg = 0.0174532925199432957692369076848861271344287188854172545609719144; |
| 42 | |
| 43 | /// 180.0/pi |
| 44 | pub const deg_per_rad = 57.295779513082320876798154814105170332405472466564321549160243861; |
| 45 | |
| 40 | 46 | pub const floatExponentBits = @import("math/float.zig").floatExponentBits; |
| 41 | 47 | pub const floatMantissaBits = @import("math/float.zig").floatMantissaBits; |
| 42 | 48 | pub const floatFractionalBits = @import("math/float.zig").floatFractionalBits; |
| ... | ... | @@ -293,32 +299,68 @@ pub inline fn tan(value: anytype) @TypeOf(value) { |
| 293 | 299 | return @tan(value); |
| 294 | 300 | } |
| 295 | 301 | |
| 296 | | /// Converts an angle in radians to degrees. T must be a float type. |
| 297 | | pub fn radiansToDegrees(comptime T: type, angle_in_radians: T) T { |
| 298 | | if (@typeInfo(T) != .Float and @typeInfo(T) != .ComptimeFloat) |
| 299 | | @compileError("T must be a float type"); |
| 300 | | return angle_in_radians * 180.0 / pi; |
| 302 | /// Converts an angle in radians to degrees. T must be a float or comptime number or a vector of floats. |
| 303 | pub fn radiansToDegrees(ang: anytype) if (@TypeOf(ang) == comptime_int) comptime_float else @TypeOf(ang) { |
| 304 | const T = @TypeOf(ang); |
| 305 | switch (@typeInfo(T)) { |
| 306 | .Float, .ComptimeFloat, .ComptimeInt => return ang * deg_per_rad, |
| 307 | .Vector => |V| if (@typeInfo(V.child) == .Float) return ang * @as(T, @splat(deg_per_rad)), |
| 308 | else => {}, |
| 309 | } |
| 310 | @compileError("Input must be float or a comptime number, or a vector of floats."); |
| 301 | 311 | } |
| 302 | 312 | |
| 303 | 313 | test "radiansToDegrees" { |
| 304 | | try std.testing.expectApproxEqAbs(@as(f32, 0), radiansToDegrees(f32, 0), 1e-6); |
| 305 | | try std.testing.expectApproxEqAbs(@as(f32, 90), radiansToDegrees(f32, pi / 2.0), 1e-6); |
| 306 | | try std.testing.expectApproxEqAbs(@as(f32, -45), radiansToDegrees(f32, -pi / 4.0), 1e-6); |
| 307 | | try std.testing.expectApproxEqAbs(@as(f32, 180), radiansToDegrees(f32, pi), 1e-6); |
| 308 | | try std.testing.expectApproxEqAbs(@as(f32, 360), radiansToDegrees(f32, 2.0 * pi), 1e-6); |
| 309 | | } |
| 310 | | |
| 311 | | /// Converts an angle in degrees to radians. T must be a float type. |
| 312 | | pub fn degreesToRadians(comptime T: type, angle_in_degrees: T) T { |
| 313 | | if (@typeInfo(T) != .Float and @typeInfo(T) != .ComptimeFloat) |
| 314 | | @compileError("T must be a float type"); |
| 315 | | return angle_in_degrees * pi / 180.0; |
| 314 | const zero: f32 = 0; |
| 315 | const half_pi: f32 = pi / 2.0; |
| 316 | const neg_quart_pi: f32 = -pi / 4.0; |
| 317 | const one_pi: f32 = pi; |
| 318 | const two_pi: f32 = 2.0 * pi; |
| 319 | try std.testing.expectApproxEqAbs(@as(f32, 0), radiansToDegrees(zero), 1e-6); |
| 320 | try std.testing.expectApproxEqAbs(@as(f32, 90), radiansToDegrees(half_pi), 1e-6); |
| 321 | try std.testing.expectApproxEqAbs(@as(f32, -45), radiansToDegrees(neg_quart_pi), 1e-6); |
| 322 | try std.testing.expectApproxEqAbs(@as(f32, 180), radiansToDegrees(one_pi), 1e-6); |
| 323 | try std.testing.expectApproxEqAbs(@as(f32, 360), radiansToDegrees(two_pi), 1e-6); |
| 324 | |
| 325 | const result = radiansToDegrees(@Vector(4, f32){ |
| 326 | half_pi, |
| 327 | neg_quart_pi, |
| 328 | one_pi, |
| 329 | two_pi, |
| 330 | }); |
| 331 | try std.testing.expectApproxEqAbs(@as(f32, 90), result[0], 1e-6); |
| 332 | try std.testing.expectApproxEqAbs(@as(f32, -45), result[1], 1e-6); |
| 333 | try std.testing.expectApproxEqAbs(@as(f32, 180), result[2], 1e-6); |
| 334 | try std.testing.expectApproxEqAbs(@as(f32, 360), result[3], 1e-6); |
| 335 | } |
| 336 | |
| 337 | /// Converts an angle in degrees to radians. T must be a float or comptime number or a vector of floats. |
| 338 | pub fn degreesToRadians(ang: anytype) if (@TypeOf(ang) == comptime_int) comptime_float else @TypeOf(ang) { |
| 339 | const T = @TypeOf(ang); |
| 340 | switch (@typeInfo(T)) { |
| 341 | .Float, .ComptimeFloat, .ComptimeInt => return ang * rad_per_deg, |
| 342 | .Vector => |V| if (@typeInfo(V.child) == .Float) return ang * @as(T, @splat(rad_per_deg)), |
| 343 | else => {}, |
| 344 | } |
| 345 | @compileError("Input must be float or a comptime number, or a vector of floats."); |
| 316 | 346 | } |
| 317 | 347 | |
| 318 | 348 | test "degreesToRadians" { |
| 319 | | try std.testing.expectApproxEqAbs(@as(f32, pi / 2.0), degreesToRadians(f32, 90), 1e-6); |
| 320 | | try std.testing.expectApproxEqAbs(@as(f32, -3 * pi / 2.0), degreesToRadians(f32, -270), 1e-6); |
| 321 | | try std.testing.expectApproxEqAbs(@as(f32, 2 * pi), degreesToRadians(f32, 360), 1e-6); |
| 349 | const ninety: f32 = 90; |
| 350 | const neg_two_seventy: f32 = -270; |
| 351 | const three_sixty: f32 = 360; |
| 352 | try std.testing.expectApproxEqAbs(@as(f32, pi / 2.0), degreesToRadians(ninety), 1e-6); |
| 353 | try std.testing.expectApproxEqAbs(@as(f32, -3 * pi / 2.0), degreesToRadians(neg_two_seventy), 1e-6); |
| 354 | try std.testing.expectApproxEqAbs(@as(f32, 2 * pi), degreesToRadians(three_sixty), 1e-6); |
| 355 | |
| 356 | const result = degreesToRadians(@Vector(3, f32){ |
| 357 | ninety, |
| 358 | neg_two_seventy, |
| 359 | three_sixty, |
| 360 | }); |
| 361 | try std.testing.expectApproxEqAbs(@as(f32, pi / 2.0), result[0], 1e-6); |
| 362 | try std.testing.expectApproxEqAbs(@as(f32, -3 * pi / 2.0), result[1], 1e-6); |
| 363 | try std.testing.expectApproxEqAbs(@as(f32, 2 * pi), result[2], 1e-6); |
| 322 | 364 | } |
| 323 | 365 | |
| 324 | 366 | /// Base-e exponential function on a floating point number. |