geop_core_math/primitives/
datum.rs1use serde::{Deserialize, Serialize};
5
6use super::CoordinateSystem;
7use crate::{
8 geop_error::{GeopError, GeopResult},
9 scalars::Scalar,
10};
11
12#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
14#[serde(rename_all = "snake_case")]
15pub enum DatumKind {
16 Point,
18 Axis,
20 Plane,
23 Frame,
27}
28
29#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
31#[serde(rename_all = "snake_case")]
32pub enum FrameAxis {
33 X,
34 Y,
35 Z,
36}
37
38impl FrameAxis {
39 pub const ALL: [FrameAxis; 3] = [FrameAxis::X, FrameAxis::Y, FrameAxis::Z];
40
41 pub fn letter(self) -> &'static str {
43 match self {
44 FrameAxis::X => "x",
45 FrameAxis::Y => "y",
46 FrameAxis::Z => "z",
47 }
48 }
49
50 pub fn of<S: Scalar>(self, frame: &CoordinateSystem<S>) -> crate::vector::Vector3<S> {
52 match self {
53 FrameAxis::X => *frame.u(),
54 FrameAxis::Y => *frame.v(),
55 FrameAxis::Z => *frame.w(),
56 }
57 }
58}
59
60#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
63#[serde(rename_all = "snake_case")]
64pub enum DatumComponent {
65 Axis(FrameAxis),
67 Plane(FrameAxis),
69}
70
71impl std::fmt::Display for DatumComponent {
72 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
73 match self {
74 DatumComponent::Axis(axis) => write!(f, "{} axis", axis.letter()),
75 DatumComponent::Plane(normal) => {
76 let [a, b] = match normal {
77 FrameAxis::X => [FrameAxis::Y, FrameAxis::Z],
78 FrameAxis::Y => [FrameAxis::Z, FrameAxis::X],
79 FrameAxis::Z => [FrameAxis::X, FrameAxis::Y],
80 };
81 write!(f, "{}{} plane", a.letter(), b.letter())
82 }
83 }
84 }
85}
86
87#[derive(Clone, Debug)]
92pub struct Datum<S: Scalar> {
93 pub kind: DatumKind,
94 pub frame: CoordinateSystem<S>,
95}
96
97impl<S: Scalar> Datum<S> {
98 pub fn component(&self, component: DatumComponent) -> GeopResult<Datum<S>> {
105 if self.kind != DatumKind::Frame {
106 return Err(GeopError::new(format!(
107 "Datum::component: a {:?} datum has no {component}, only a frame has",
108 self.kind
109 )));
110 }
111 let f = &self.frame;
112 let along = |axis: FrameAxis| {
113 let (u, v, w) = (*f.u(), *f.v(), *f.w());
114 let (u, v, w) = match axis {
115 FrameAxis::X => (v, w, u),
116 FrameAxis::Y => (u, w.neg(), v),
117 FrameAxis::Z => (u, v, w),
118 };
119 CoordinateSystem::try_new(*f.origin(), u, v, w)
120 };
121 Ok(match component {
122 DatumComponent::Axis(axis) => Datum {
123 kind: DatumKind::Axis,
124 frame: along(axis)?,
125 },
126 DatumComponent::Plane(normal) => Datum {
127 kind: DatumKind::Plane,
128 frame: along(normal)?,
129 },
130 })
131 }
132}