gistools/proj/convert/
axis_swap.rs1use crate::proj::{
2 AxisDirection, CoordinateStep, IoUnits, Proj, ProjectCoordinates, ProjectionTransform, Step,
3 TransformCoordinates,
4};
5use alloc::{rc::Rc, vec::Vec};
6use core::cell::RefCell;
7
8#[derive(Debug, Clone, Copy, PartialEq)]
10pub struct AxisSwap {
11 pub axis: [i64; 4],
13 pub sign: [i32; 4],
15}
16impl Default for AxisSwap {
17 fn default() -> Self {
18 Self {
19 axis: [0, 1, 2, 3], sign: [1; 4],
21 }
22 }
23}
24impl AxisSwap {
25 pub fn is_empty(&self) -> bool {
27 self.axis == [0, 1, 2, 3] && self.sign == [1; 4]
28 }
29}
30impl From<Vec<AxisDirection>> for AxisSwap {
31 fn from(directions: Vec<AxisDirection>) -> Self {
32 if directions.len() > 4 {
33 panic!("Too many axes specified");
34 }
35
36 let mut axis = [0, 1, 2, 3]; let mut sign = [1; 4];
38
39 for (i, dir) in directions.iter().enumerate() {
40 match dir {
41 AxisDirection::West => {
42 axis[i] = 0;
43 sign[i] = -1;
44 }
45 AxisDirection::East => {
46 axis[i] = 0;
47 sign[i] = 1;
48 }
49 AxisDirection::South => {
50 axis[i] = 1;
51 sign[i] = -1;
52 }
53 AxisDirection::North => {
54 axis[i] = 1;
55 sign[i] = 1;
56 }
57 AxisDirection::Down => {
58 axis[i] = 2;
59 sign[i] = -1;
60 }
61 AxisDirection::Up => {
62 axis[i] = 2;
63 sign[i] = 1;
64 }
65 _ => {} }
67 }
68
69 for a in 0..directions.len() {
71 for b in (a + 1)..directions.len() {
72 if axis[a] == axis[b] {
73 panic!("Duplicate axis mapping");
74 }
75 }
76 }
77
78 Self { axis, sign }
79 }
80}
81
82#[derive(Debug, Clone, PartialEq)]
84pub struct AxisSwapConverter {
85 proj: Rc<RefCell<Proj>>,
86 pub swap: AxisSwap,
88}
89impl ProjectCoordinates for AxisSwapConverter {
90 fn code(&self) -> i64 {
91 -1
92 }
93
94 fn name(&self) -> &'static str {
95 "axis swap"
96 }
97
98 fn names() -> &'static [&'static str] {
99 &["axis swap", "axis"]
100 }
101}
102impl From<AxisSwapConverter> for ProjectionTransform {
103 fn from(asc: AxisSwapConverter) -> ProjectionTransform {
104 ProjectionTransform {
105 proj: asc.proj.clone(),
106 method: Step::AxisSwap(asc.into()),
107 ..Default::default()
108 }
109 }
110}
111impl CoordinateStep for AxisSwapConverter {
112 fn new(proj: Rc<RefCell<Proj>>) -> Self {
113 {
114 let proj = &mut proj.borrow_mut();
115 proj.left = IoUnits::RADIANS;
116 proj.right = IoUnits::RADIANS;
117 proj.is_ll = true;
118 }
119 AxisSwapConverter { proj, swap: AxisSwap::default() }
120 }
121 fn forward<P: TransformCoordinates>(&self, coords: &mut P) {
123 if self.swap.is_empty() {
124 return;
125 }
126
127 let mut out = [0.0; 4];
128 for (i, out) in out.iter_mut().enumerate() {
129 let src_idx = self.swap.axis[i] as usize;
130 let sign = self.swap.sign[i] as f64;
131 *out = coords.get(src_idx) * sign;
132 }
133
134 for (i, out) in out.iter_mut().enumerate() {
135 coords.set(i, *out);
136 }
137 }
138 fn inverse<P: TransformCoordinates>(&self, coords: &mut P) {
140 if self.swap.is_empty() {
141 return;
142 }
143
144 let mut out = [0.0; 4];
145 for i in 0..4 {
146 let dst_idx = self.swap.axis[i] as usize;
147 let sign = self.swap.sign[i] as f64;
148 out[dst_idx] = coords.get(i) * sign;
149 }
150
151 for (i, out) in out.iter_mut().enumerate() {
152 coords.set(i, *out);
153 }
154 }
155}