kasane_logic/geometry/point/ecef/mod.rs
1pub mod impls;
2
3use crate::{RangeId, SingleId, error::Error, geometry::point::coordinate::Coordinate};
4
5/// 地心直交座標系(ECEF: Earth-Centered, Earth-Fixed)における座標を表す。
6///
7/// 原点は地球の重心にあり、
8/// * X 軸は赤道面上で本初子午線方向
9/// * Y 軸は赤道面上で東経 90 度方向
10/// * Z 軸は北極方向
11///
12/// 単位はすべてメートル。
13#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
14#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
15#[derive(Clone, Copy, PartialEq, PartialOrd)]
16pub struct Ecef {
17 x: f64,
18 y: f64,
19 z: f64,
20}
21
22impl Ecef {
23 /// 指定された XYZ 成分から [`Ecef`] を生成する。
24 ///
25 /// # Examples
26 /// ```no_run
27 /// # use kasane_logic::Ecef;
28 ///
29 /// let ecef = Ecef::new(10.0, 20.0, 30.0);
30 ///
31 /// assert_eq!(ecef.x(), 10.0);
32 /// assert_eq!(ecef.y(), 20.0);
33 /// assert_eq!(ecef.z(), 30.0);
34 /// ```
35 pub fn new(x: f64, y: f64, z: f64) -> Ecef {
36 Ecef { x, y, z }
37 }
38 /// X 成分を返す。
39 ///
40 /// # Examples
41 /// ```
42 /// # use kasane_logic::Ecef;
43 ///
44 /// let ecef = Ecef::new(1.0, 0.0, 0.0);
45 /// assert_eq!(ecef.x(), 1.0);
46 /// ```
47 pub fn x(&self) -> f64 {
48 self.x
49 }
50
51 /// Y 成分を返す。
52 ///
53 /// # Examples
54 /// ```
55 /// # use kasane_logic::Ecef;
56 ///
57 /// let ecef = Ecef::new(0.0, 2.0, 0.0);
58 /// assert_eq!(ecef.y(), 2.0);
59 /// ```
60 pub fn y(&self) -> f64 {
61 self.y
62 }
63
64 /// Z 成分を返す。
65 ///
66 /// # Examples
67 /// ```
68 /// # use kasane_logic::Ecef;
69 ///
70 /// let ecef = Ecef::new(0.0, 0.0, 3.0);
71 /// assert_eq!(ecef.z(), 3.0);
72 /// ```
73 pub fn z(&self) -> f64 {
74 self.z
75 }
76
77 /// X 成分を設定する。
78 ///
79 /// # Examples
80 /// ```
81 /// # use kasane_logic::Ecef;
82 ///
83 /// let mut ecef = Ecef::new(0.0, 0.0, 0.0);
84 /// ecef.set_x(5.0);
85 ///
86 /// assert_eq!(ecef.x(), 5.0);
87 /// ```
88 pub fn set_x(&mut self, x: f64) {
89 self.x = x;
90 }
91
92 /// Y 成分を設定する。
93 ///
94 /// # Examples
95 /// ```
96 /// # use kasane_logic::Ecef;
97 ///
98 /// let mut ecef = Ecef::new(0.0, 0.0, 0.0);
99 /// ecef.set_y(6.0);
100 ///
101 /// assert_eq!(ecef.y(), 6.0);
102 /// ```
103 pub fn set_y(&mut self, y: f64) {
104 self.y = y;
105 }
106
107 /// Z 成分を設定する。
108 ///
109 /// # Examples
110 /// ```
111 /// # use kasane_logic::Ecef;
112 ///
113 /// let mut ecef = Ecef::new(0.0, 0.0, 0.0);
114 /// ecef.set_z(7.0);
115 ///
116 /// assert_eq!(ecef.z(), 7.0);
117 /// ```
118 pub fn set_z(&mut self, z: f64) {
119 self.z = z;
120 }
121
122 /// この ECEF 座標を、指定されたズームレベルの [`SingleId`] に変換する。
123 pub fn single_id(&self, z: u8) -> Result<SingleId, Error> {
124 let coordinate: Coordinate = (*self).try_into()?;
125 coordinate.single_id(z)
126 }
127
128 /// この ECEF 座標を、指定されたズームレベルの [`RangeId`] に変換する。
129 pub fn range_id(&self, z: u8) -> Result<RangeId, Error> {
130 let coordinate: Coordinate = (*self).try_into()?;
131 Ok(RangeId::from(coordinate.single_id(z)?))
132 }
133
134 /// 他の [`Ecef`] 座標との距離をメートル単位で返す。
135 ///
136 /// # Examples
137 /// ```
138 /// # use kasane_logic::Ecef;
139 ///
140 /// let a = Ecef::new(0.0, 0.0, 0.0);
141 /// let b = Ecef::new(3.0, 4.0, 0.0);
142 ///
143 /// assert_eq!(a.distance(&b), 5.0);
144 /// ```
145 pub fn distance(&self, other: &Ecef) -> f64 {
146 ((self.x() - other.x()).powi(2)
147 + (self.y() - other.y()).powi(2)
148 + (self.z() - other.z()).powi(2))
149 .sqrt()
150 }
151
152 ///他の[Ecef]型との外積を取る。
153 pub fn cross(&self, other: &Ecef) -> Ecef {
154 Ecef {
155 x: self.y * other.z - self.z * other.y,
156 y: self.z * other.x - self.x * other.z,
157 z: self.x * other.y - self.y * other.x,
158 }
159 }
160
161 // 原点からの距離の2乗を取得する。
162 pub fn norm_squared(&self) -> f64 {
163 self.x * self.x + self.y * self.y + self.z * self.z
164 }
165
166 /// Ecefが同じ位置にあるかを判定します
167 /// 2点間の直線距離が epsilon 以内にあるかを判定します
168 pub fn eq_epsilon(&self, other: &Ecef, epsilon: f64) -> bool {
169 let distance_squared = self.distance(other);
170 distance_squared < epsilon * epsilon
171 }
172
173 /// 内積(ドット積)を計算する。
174 pub fn dot(&self, other: &Ecef) -> f64 {
175 self.x * other.x + self.y * other.y + self.z * other.z
176 }
177
178 /// 指定された軸インデックス (0=x, 1=y, 2=z) の成分を返す。
179 /// 投影計算などで軸を動的に扱いたい場合に有用。
180 pub fn get_component(&self, index: usize) -> f64 {
181 match index {
182 0 => self.x,
183 1 => self.y,
184 _ => self.z,
185 }
186 }
187
188 /// 指定された2つの軸(u, v)に基づいて 2D 平面に投影した座標を返す。
189 pub fn project_2d(&self, u_axis: usize, v_axis: usize) -> (f64, f64) {
190 (self.get_component(u_axis), self.get_component(v_axis))
191 }
192}