1use super::DisplayWithUnit;
2
3#[must_use]
33#[derive(Debug, Clone, Copy, PartialEq, PartialOrd, Default)]
34pub struct Angle(pub(crate) f64);
35
36#[derive(Debug, Clone, Copy, PartialEq, Eq)]
38pub enum AngleUnit {
39 Radian,
41 Degree,
43 ArcMinute,
45 ArcSecond,
47 MilliArcSecond,
49 Revolution,
51 MilliRadian,
53 Grad,
55 HourAngle,
57}
58
59impl AngleUnit {
60 const fn symbol(self) -> &'static str {
61 match self {
62 Self::Radian => "rad",
63 Self::Degree => "deg",
64 Self::ArcMinute => "arcmin",
65 Self::ArcSecond => "arcsec",
66 Self::MilliArcSecond => "mas",
67 Self::Revolution => "rev",
68 Self::MilliRadian => "mrad",
69 Self::Grad => "grad",
70 Self::HourAngle => "hour_angle",
71 }
72 }
73
74 const fn radians_per_unit(self) -> f64 {
75 match self {
76 Self::Radian => 1.0,
77 Self::Degree => core::f64::consts::PI / 180.0,
78 Self::ArcMinute => core::f64::consts::PI / 10_800.0,
79 Self::ArcSecond => core::f64::consts::PI / 648_000.0,
80 Self::MilliArcSecond => core::f64::consts::PI / 648_000_000.0,
81 Self::Revolution => core::f64::consts::TAU,
82 Self::MilliRadian => 1e-3,
83 Self::Grad => core::f64::consts::PI / 200.0,
84 Self::HourAngle => core::f64::consts::PI / 12.0,
85 }
86 }
87}
88
89impl Angle {
90 pub const fn from_rad(val: f64) -> Self {
92 Self(val)
93 }
94
95 pub const fn from_deg(val: f64) -> Self {
97 Self(val * (core::f64::consts::PI / 180.0))
98 }
99
100 pub const fn from_rev(val: f64) -> Self {
102 Self(val * core::f64::consts::TAU)
103 }
104
105 pub const fn from_arcmin(val: f64) -> Self {
107 Self(val * (core::f64::consts::PI / 10_800.0))
108 }
109
110 pub const fn from_arcsec(val: f64) -> Self {
112 Self(val * (core::f64::consts::PI / 648_000.0))
113 }
114
115 pub const fn from_mas(val: f64) -> Self {
117 Self(val * (core::f64::consts::PI / 648_000_000.0))
118 }
119
120 pub const fn from_mrad(val: f64) -> Self {
122 Self(val * 1e-3)
123 }
124
125 pub const fn from_grad(val: f64) -> Self {
127 Self(val * (core::f64::consts::PI / 200.0))
128 }
129
130 pub const fn from_hour_angle(val: f64) -> Self {
132 Self(val * (core::f64::consts::PI / 12.0))
133 }
134
135 pub const fn in_rad(self) -> f64 {
137 self.0
138 }
139
140 pub const fn in_deg(self) -> f64 {
142 self.0 / (core::f64::consts::PI / 180.0)
143 }
144
145 pub const fn in_rev(self) -> f64 {
147 self.0 / core::f64::consts::TAU
148 }
149
150 pub const fn in_arcmin(self) -> f64 {
152 self.0 / (core::f64::consts::PI / 10_800.0)
153 }
154
155 pub const fn in_arcsec(self) -> f64 {
157 self.0 / (core::f64::consts::PI / 648_000.0)
158 }
159
160 pub const fn in_mas(self) -> f64 {
162 self.0 / (core::f64::consts::PI / 648_000_000.0)
163 }
164
165 pub const fn in_mrad(self) -> f64 {
167 self.0 / 1e-3
168 }
169
170 pub const fn in_grad(self) -> f64 {
172 self.0 / (core::f64::consts::PI / 200.0)
173 }
174
175 pub const fn in_hour_angle(self) -> f64 {
177 self.0 / (core::f64::consts::PI / 12.0)
178 }
179
180 pub fn in_unit(self, unit: AngleUnit) -> f64 {
182 self.0 / unit.radians_per_unit()
183 }
184
185 pub fn display_as(self, unit: AngleUnit) -> DisplayWithUnit {
187 DisplayWithUnit {
188 value: self.in_unit(unit),
189 symbol: unit.symbol(),
190 }
191 }
192
193 pub fn normalize(self) -> Self {
195 let tau = core::f64::consts::TAU;
196 let mut v = self.0 % tau;
197 if v < 0.0 {
198 v += tau;
199 }
200 Self(v)
201 }
202
203 pub fn abs(self) -> Self {
205 Self(self.0.abs())
206 }
207
208 #[cfg(feature = "std")]
210 pub fn sin(self) -> f64 {
211 self.0.sin()
212 }
213
214 #[cfg(feature = "std")]
216 pub fn cos(self) -> f64 {
217 self.0.cos()
218 }
219
220 #[cfg(feature = "std")]
222 pub fn tan(self) -> f64 {
223 self.0.tan()
224 }
225
226 #[cfg(feature = "std")]
228 pub fn asin(val: f64) -> Self {
229 Self(val.asin())
230 }
231
232 #[cfg(feature = "std")]
234 pub fn acos(val: f64) -> Self {
235 Self(val.acos())
236 }
237
238 #[cfg(feature = "std")]
240 pub fn atan2(y: f64, x: f64) -> Self {
241 Self(y.atan2(x))
242 }
243}
244
245impl_quantity_display!(Angle, "rad");
246
247impl_common_ops!(Angle);
248
249#[must_use]
271#[derive(Debug, Clone, Copy, PartialEq, PartialOrd, Default)]
272pub struct AngularVelocity(pub(crate) f64);
273
274#[derive(Debug, Clone, Copy, PartialEq, Eq)]
276pub enum AngularVelocityUnit {
277 RadPerS,
279 DegPerS,
281 Rpm,
283 RevPerS,
285}
286
287impl AngularVelocityUnit {
288 const fn symbol(self) -> &'static str {
289 match self {
290 Self::RadPerS => "rad/s",
291 Self::DegPerS => "deg/s",
292 Self::Rpm => "rpm",
293 Self::RevPerS => "rev/s",
294 }
295 }
296
297 const fn radps_per_unit(self) -> f64 {
298 match self {
299 Self::RadPerS => 1.0,
300 Self::DegPerS => core::f64::consts::PI / 180.0,
301 Self::Rpm => core::f64::consts::TAU / 60.0,
302 Self::RevPerS => core::f64::consts::TAU,
303 }
304 }
305}
306
307impl AngularVelocity {
308 pub const fn from_radps(val: f64) -> Self {
310 Self(val)
311 }
312
313 pub const fn from_degps(val: f64) -> Self {
315 Self(val * (core::f64::consts::PI / 180.0))
316 }
317
318 pub const fn from_rpm(val: f64) -> Self {
320 Self(val * (core::f64::consts::TAU / 60.0))
321 }
322
323 pub const fn from_revps(val: f64) -> Self {
325 Self(val * core::f64::consts::TAU)
326 }
327
328 pub const fn in_radps(self) -> f64 {
330 self.0
331 }
332
333 pub const fn in_degps(self) -> f64 {
335 self.0 / (core::f64::consts::PI / 180.0)
336 }
337
338 pub const fn in_rpm(self) -> f64 {
340 self.0 / (core::f64::consts::TAU / 60.0)
341 }
342
343 pub const fn in_revps(self) -> f64 {
345 self.0 / core::f64::consts::TAU
346 }
347
348 pub fn in_unit(self, unit: AngularVelocityUnit) -> f64 {
350 self.0 / unit.radps_per_unit()
351 }
352
353 pub fn display_as(self, unit: AngularVelocityUnit) -> DisplayWithUnit {
355 DisplayWithUnit {
356 value: self.in_unit(unit),
357 symbol: unit.symbol(),
358 }
359 }
360
361 pub fn abs(self) -> Self {
363 Self(self.0.abs())
364 }
365}
366
367impl_quantity_display!(AngularVelocity, "rad/s");
368
369impl_common_ops!(AngularVelocity);
370
371#[must_use]
392#[derive(Debug, Clone, Copy, PartialEq, PartialOrd, Default)]
393pub struct AngularAcceleration(pub(crate) f64);
394
395#[derive(Debug, Clone, Copy, PartialEq, Eq)]
397pub enum AngularAccelerationUnit {
398 RadPerS2,
400 DegPerS2,
402 RevPerS2,
404}
405
406impl AngularAccelerationUnit {
407 const fn symbol(self) -> &'static str {
408 match self {
409 Self::RadPerS2 => "rad/s^2",
410 Self::DegPerS2 => "deg/s^2",
411 Self::RevPerS2 => "rev/s^2",
412 }
413 }
414
415 const fn radps2_per_unit(self) -> f64 {
416 match self {
417 Self::RadPerS2 => 1.0,
418 Self::DegPerS2 => core::f64::consts::PI / 180.0,
419 Self::RevPerS2 => core::f64::consts::TAU,
420 }
421 }
422}
423
424impl AngularAcceleration {
425 pub const fn from_radps2(val: f64) -> Self {
427 Self(val)
428 }
429
430 pub const fn from_degps2(val: f64) -> Self {
432 Self(val * (core::f64::consts::PI / 180.0))
433 }
434
435 pub const fn from_revps2(val: f64) -> Self {
437 Self(val * core::f64::consts::TAU)
438 }
439
440 pub const fn in_radps2(self) -> f64 {
442 self.0
443 }
444
445 pub const fn in_degps2(self) -> f64 {
447 self.0 / (core::f64::consts::PI / 180.0)
448 }
449
450 pub const fn in_revps2(self) -> f64 {
452 self.0 / core::f64::consts::TAU
453 }
454
455 pub fn in_unit(self, unit: AngularAccelerationUnit) -> f64 {
457 self.0 / unit.radps2_per_unit()
458 }
459
460 pub fn display_as(self, unit: AngularAccelerationUnit) -> DisplayWithUnit {
462 DisplayWithUnit {
463 value: self.in_unit(unit),
464 symbol: unit.symbol(),
465 }
466 }
467
468 pub fn abs(self) -> Self {
470 Self(self.0.abs())
471 }
472}
473
474impl_quantity_display!(AngularAcceleration, "rad/s²");
475
476impl_common_ops!(AngularAcceleration);
477
478#[must_use]
500#[derive(Debug, Clone, Copy, PartialEq, PartialOrd, Default)]
501pub struct Torque(pub(crate) f64);
502
503#[derive(Debug, Clone, Copy, PartialEq, Eq)]
505pub enum TorqueUnit {
506 NewtonMeter,
508 KiloNewtonMeter,
510 PoundForceFoot,
512}
513
514impl TorqueUnit {
515 const fn symbol(self) -> &'static str {
516 match self {
517 Self::NewtonMeter => "N*m",
518 Self::KiloNewtonMeter => "kN*m",
519 Self::PoundForceFoot => "lbf*ft",
520 }
521 }
522}
523
524impl Torque {
525 pub const fn from_nm(val: f64) -> Self {
527 Self(val)
528 }
529
530 pub const fn from_knm(val: f64) -> Self {
532 Self(val * 1_000.0)
533 }
534
535 pub const fn from_lbf_ft(val: f64) -> Self {
537 Self(val * 1.355_817_948_331_4)
538 }
539
540 pub const fn in_nm(self) -> f64 {
542 self.0
543 }
544
545 pub const fn in_knm(self) -> f64 {
547 self.0 / 1_000.0
548 }
549
550 pub const fn in_lbf_ft(self) -> f64 {
552 self.0 / 1.355_817_948_331_4
553 }
554
555 pub const fn display_as(self, unit: TorqueUnit) -> DisplayWithUnit {
557 match unit {
558 TorqueUnit::NewtonMeter => DisplayWithUnit {
559 value: self.0,
560 symbol: unit.symbol(),
561 },
562 TorqueUnit::KiloNewtonMeter => DisplayWithUnit {
563 value: self.in_knm(),
564 symbol: unit.symbol(),
565 },
566 TorqueUnit::PoundForceFoot => DisplayWithUnit {
567 value: self.in_lbf_ft(),
568 symbol: unit.symbol(),
569 },
570 }
571 }
572
573 pub fn abs(self) -> Self {
575 Self(self.0.abs())
576 }
577}
578
579impl_quantity_display!(Torque, "N·m");
580
581impl_common_ops!(Torque);
582
583#[must_use]
597#[derive(Debug, Clone, Copy, PartialEq, PartialOrd, Default)]
598pub struct AngularMomentum(pub(crate) f64);
599
600#[derive(Debug, Clone, Copy, PartialEq, Eq)]
602pub enum AngularMomentumUnit {
603 NewtonMeterSecond,
605}
606
607impl AngularMomentumUnit {
608 const fn symbol(self) -> &'static str {
609 match self {
610 Self::NewtonMeterSecond => "N*m*s",
611 }
612 }
613}
614
615impl AngularMomentum {
616 pub const fn from_n_m_s(val: f64) -> Self {
618 Self(val)
619 }
620
621 pub const fn in_n_m_s(self) -> f64 {
623 self.0
624 }
625
626 pub const fn display_as(self, unit: AngularMomentumUnit) -> DisplayWithUnit {
628 match unit {
629 AngularMomentumUnit::NewtonMeterSecond => DisplayWithUnit {
630 value: self.0,
631 symbol: unit.symbol(),
632 },
633 }
634 }
635
636 pub fn abs(self) -> Self {
638 Self(self.0.abs())
639 }
640}
641
642impl_quantity_display!(AngularMomentum, "N·m·s");
643
644impl_common_ops!(AngularMomentum);
645
646#[must_use]
667#[derive(Debug, Clone, Copy, PartialEq, PartialOrd, Default)]
668pub struct MomentOfInertia(pub(crate) f64);
669
670#[derive(Debug, Clone, Copy, PartialEq, Eq)]
672pub enum MomentOfInertiaUnit {
673 KgM2,
675 GramCentimeter2,
677 SlugFoot2,
679}
680
681impl MomentOfInertiaUnit {
682 const fn symbol(self) -> &'static str {
683 match self {
684 Self::KgM2 => "kg*m^2",
685 Self::GramCentimeter2 => "g*cm^2",
686 Self::SlugFoot2 => "slug*ft^2",
687 }
688 }
689}
690
691impl MomentOfInertia {
692 pub const fn from_kgm2(val: f64) -> Self {
694 Self(val)
695 }
696
697 pub const fn from_gcm2(val: f64) -> Self {
699 Self(val * 1e-7)
700 }
701
702 pub const fn from_slug_ft2(val: f64) -> Self {
704 Self(val * 1.355_817_948_331_4)
705 }
706
707 pub const fn in_kgm2(self) -> f64 {
709 self.0
710 }
711
712 pub const fn in_gcm2(self) -> f64 {
714 self.0 / 1e-7
715 }
716
717 pub const fn in_slug_ft2(self) -> f64 {
719 self.0 / 1.355_817_948_331_4
720 }
721
722 pub const fn display_as(self, unit: MomentOfInertiaUnit) -> DisplayWithUnit {
724 match unit {
725 MomentOfInertiaUnit::KgM2 => DisplayWithUnit {
726 value: self.0,
727 symbol: unit.symbol(),
728 },
729 MomentOfInertiaUnit::GramCentimeter2 => DisplayWithUnit {
730 value: self.in_gcm2(),
731 symbol: unit.symbol(),
732 },
733 MomentOfInertiaUnit::SlugFoot2 => DisplayWithUnit {
734 value: self.in_slug_ft2(),
735 symbol: unit.symbol(),
736 },
737 }
738 }
739
740 pub fn abs(self) -> Self {
742 Self(self.0.abs())
743 }
744}
745
746impl_quantity_display!(MomentOfInertia, "kg·m²");
747
748impl_common_ops!(MomentOfInertia);
749
750#[must_use]
766#[derive(Debug, Clone, Copy, PartialEq, PartialOrd, Default)]
767pub struct SolidAngle(pub(crate) f64);
768
769#[derive(Debug, Clone, Copy, PartialEq, Eq)]
771pub enum SolidAngleUnit {
772 Steradian,
774 SquareDegree,
776 Spat,
778}
779
780impl SolidAngleUnit {
781 const fn symbol(self) -> &'static str {
782 match self {
783 Self::Steradian => "sr",
784 Self::SquareDegree => "deg^2",
785 Self::Spat => "spat",
786 }
787 }
788
789 const fn sr_per_unit(self) -> f64 {
790 match self {
791 Self::Steradian => 1.0,
792 Self::SquareDegree => (core::f64::consts::PI / 180.0) * (core::f64::consts::PI / 180.0),
794 Self::Spat => 4.0 * core::f64::consts::PI,
795 }
796 }
797}
798
799impl SolidAngle {
800 pub const fn from_sr(val: f64) -> Self {
802 Self(val)
803 }
804
805 pub const fn from_deg2(val: f64) -> Self {
807 Self(val * (core::f64::consts::PI / 180.0) * (core::f64::consts::PI / 180.0))
808 }
809
810 pub const fn from_spat(val: f64) -> Self {
812 Self(val * 4.0 * core::f64::consts::PI)
813 }
814
815 pub const fn in_sr(self) -> f64 {
817 self.0
818 }
819
820 pub const fn in_deg2(self) -> f64 {
822 self.0 / ((core::f64::consts::PI / 180.0) * (core::f64::consts::PI / 180.0))
823 }
824
825 pub const fn in_spat(self) -> f64 {
827 self.0 / (4.0 * core::f64::consts::PI)
828 }
829
830 pub fn in_unit(self, unit: SolidAngleUnit) -> f64 {
832 self.0 / unit.sr_per_unit()
833 }
834
835 pub fn display_as(self, unit: SolidAngleUnit) -> DisplayWithUnit {
837 DisplayWithUnit {
838 value: self.in_unit(unit),
839 symbol: unit.symbol(),
840 }
841 }
842
843 pub fn abs(self) -> Self {
845 Self(self.0.abs())
846 }
847}
848
849impl_quantity_display!(SolidAngle, "sr");
850
851impl_common_ops!(SolidAngle);