Skip to content

Commit ef087cc

Browse files
committed
xy/set_xy for CoordinateSet. Tests via tmerc/merc
1 parent 94e6fea commit ef087cc

File tree

4 files changed

+120
-40
lines changed

4 files changed

+120
-40
lines changed

src/coordinate/mod.rs

+21
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,27 @@ pub trait CoordinateSet: CoordinateMetadata {
164164
self.len() == 0
165165
}
166166

167+
/// Replace the two first elements of the `index`th `CoordinateTuple` with `x` and `y`.
168+
/// If the dimension in less than 2, fill the coordinate with `f64::NAN`.
169+
/// For efficiency, consider implemented a specific implementation, when implementing
170+
/// the CoordinateSet trait for a concrete data type: The provided version is not
171+
/// very efficient.
172+
fn set_xy(&mut self, index: usize, x: f64, y: f64) {
173+
let mut coord = self.get_coord(index);
174+
coord.set_nth_unchecked(0, x);
175+
coord.set_nth_unchecked(1, y);
176+
self.set_coord(index, &coord);
177+
}
178+
179+
/// Replace the two first elements of the `index`th `CoordinateTuple` with `x` and `y`.
180+
/// If the dimension in less than 2, fill the coordinate with `f64::NAN`.
181+
/// For efficiency, consider implemented a specific implementation, when implementing
182+
/// the CoordinateSet trait for a concrete data type: The provided version is not
183+
/// very efficient.
184+
fn xy(&self, index: usize) -> (f64, f64) {
185+
self.get_coord(index).xy()
186+
}
187+
167188
/// Set all coordinate tuples in the set to NaN
168189
fn stomp(&mut self) {
169190
let nanny = Coor4D::nan();

src/coordinate/set.rs

+60
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,12 @@ impl CoordinateSet for &mut [Coor4D] {
1515
fn set_coord(&mut self, index: usize, value: &Coor4D) {
1616
self[index] = *value;
1717
}
18+
fn xy(&self, index: usize) -> (f64, f64) {
19+
self[index].xy()
20+
}
21+
fn set_xy(&mut self, index: usize, x: f64, y: f64) {
22+
self[index].set_xy(x, y);
23+
}
1824
}
1925

2026
impl<const N: usize> CoordinateSet for [Coor4D; N] {
@@ -30,6 +36,12 @@ impl<const N: usize> CoordinateSet for [Coor4D; N] {
3036
fn set_coord(&mut self, index: usize, value: &Coor4D) {
3137
self[index] = *value;
3238
}
39+
fn xy(&self, index: usize) -> (f64, f64) {
40+
self[index].xy()
41+
}
42+
fn set_xy(&mut self, index: usize, x: f64, y: f64) {
43+
self[index].set_xy(x, y);
44+
}
3345
}
3446

3547
impl CoordinateSet for Vec<Coor4D> {
@@ -45,6 +57,12 @@ impl CoordinateSet for Vec<Coor4D> {
4557
fn set_coord(&mut self, index: usize, value: &Coor4D) {
4658
self[index] = *value;
4759
}
60+
fn xy(&self, index: usize) -> (f64, f64) {
61+
self[index].xy()
62+
}
63+
fn set_xy(&mut self, index: usize, x: f64, y: f64) {
64+
self[index].set_xy(x, y);
65+
}
4866
}
4967

5068
// ----- CoordinateSet implementations for some Coor3D containers ------------
@@ -62,6 +80,12 @@ impl<const N: usize> CoordinateSet for [Coor3D; N] {
6280
fn set_coord(&mut self, index: usize, value: &Coor4D) {
6381
self[index] = Coor3D([value[0], value[1], value[2]]);
6482
}
83+
fn xy(&self, index: usize) -> (f64, f64) {
84+
self[index].xy()
85+
}
86+
fn set_xy(&mut self, index: usize, x: f64, y: f64) {
87+
self[index].set_xy(x, y);
88+
}
6589
}
6690

6791
impl CoordinateSet for &mut [Coor3D] {
@@ -77,6 +101,12 @@ impl CoordinateSet for &mut [Coor3D] {
77101
fn set_coord(&mut self, index: usize, value: &Coor4D) {
78102
self[index] = Coor3D([value[0], value[1], value[2]]);
79103
}
104+
fn xy(&self, index: usize) -> (f64, f64) {
105+
self[index].xy()
106+
}
107+
fn set_xy(&mut self, index: usize, x: f64, y: f64) {
108+
self[index].set_xy(x, y);
109+
}
80110
}
81111

82112
impl CoordinateSet for Vec<Coor3D> {
@@ -92,6 +122,12 @@ impl CoordinateSet for Vec<Coor3D> {
92122
fn set_coord(&mut self, index: usize, value: &Coor4D) {
93123
self[index] = Coor3D([value[0], value[1], value[2]]);
94124
}
125+
fn xy(&self, index: usize) -> (f64, f64) {
126+
self[index].xy()
127+
}
128+
fn set_xy(&mut self, index: usize, x: f64, y: f64) {
129+
self[index].set_xy(x, y);
130+
}
95131
}
96132

97133
// ----- CoordinateSet implementations for some Coor2D containers ------------
@@ -127,6 +163,12 @@ impl<const N: usize> CoordinateSet for [Coor2D; N] {
127163
fn set_coord(&mut self, index: usize, value: &Coor4D) {
128164
self[index] = Coor2D([value[0], value[1]]);
129165
}
166+
fn xy(&self, index: usize) -> (f64, f64) {
167+
self[index].xy()
168+
}
169+
fn set_xy(&mut self, index: usize, x: f64, y: f64) {
170+
self[index].set_xy(x, y);
171+
}
130172
}
131173

132174
impl CoordinateSet for &mut [Coor2D] {
@@ -142,6 +184,12 @@ impl CoordinateSet for &mut [Coor2D] {
142184
fn set_coord(&mut self, index: usize, value: &Coor4D) {
143185
self[index] = Coor2D([value[0], value[1]]);
144186
}
187+
fn xy(&self, index: usize) -> (f64, f64) {
188+
self[index].xy()
189+
}
190+
fn set_xy(&mut self, index: usize, x: f64, y: f64) {
191+
self[index].set_xy(x, y);
192+
}
145193
}
146194

147195
impl CoordinateSet for Vec<Coor2D> {
@@ -157,6 +205,12 @@ impl CoordinateSet for Vec<Coor2D> {
157205
fn set_coord(&mut self, index: usize, value: &Coor4D) {
158206
self[index] = Coor2D([value[0], value[1]]);
159207
}
208+
fn xy(&self, index: usize) -> (f64, f64) {
209+
self[index].xy()
210+
}
211+
fn set_xy(&mut self, index: usize, x: f64, y: f64) {
212+
self[index].set_xy(x, y);
213+
}
160214
}
161215

162216
/// User defined values for third and fourth coordinate dimension.
@@ -218,6 +272,12 @@ impl CoordinateSet for &mut [Coor32] {
218272
fn set_coord(&mut self, index: usize, value: &Coor4D) {
219273
self[index] = Coor32::raw(value[0], value[1]);
220274
}
275+
fn xy(&self, index: usize) -> (f64, f64) {
276+
self[index].xy()
277+
}
278+
fn set_xy(&mut self, index: usize, x: f64, y: f64) {
279+
self[index].set_xy(x, y);
280+
}
221281
}
222282

223283
// ----- Implementations: Coordinate Metadata ---------------------------------

src/inner_op/merc.rs

+12-14
Original file line numberDiff line numberDiff line change
@@ -15,15 +15,13 @@ fn fwd(op: &Op, _ctx: &dyn Context, operands: &mut dyn CoordinateSet) -> usize {
1515
let mut successes = 0_usize;
1616
let length = operands.len();
1717
for i in 0..length {
18-
let mut coord = operands.get_coord(i);
19-
// Easting
20-
coord[0] = (coord[0] - lon_0) * k_0 * a - x_0;
18+
let (lon, lat) = operands.xy(i);
2119

22-
// Northing
23-
let lat = coord[1] + lat_0;
24-
coord[1] = a * k_0 * ellps.latitude_geographic_to_isometric(lat) - y_0;
20+
let easting = (lon - lon_0) * k_0 * a - x_0;
21+
let isometric = ellps.latitude_geographic_to_isometric(lat + lat_0);
22+
let northing = a * k_0 * isometric - y_0;
2523

26-
operands.set_coord(i, &coord);
24+
operands.set_xy(i, easting, northing);
2725
successes += 1;
2826
}
2927

@@ -44,17 +42,17 @@ fn inv(op: &Op, _ctx: &dyn Context, operands: &mut dyn CoordinateSet) -> usize {
4442
let mut successes = 0_usize;
4543
let length = operands.len();
4644
for i in 0..length {
47-
let mut coord = operands.get_coord(i);
45+
let (mut x, mut y) = operands.xy(i);
4846

4947
// Easting -> Longitude
50-
let x = coord[0] + x_0;
51-
coord[0] = x / (a * k_0) - lon_0;
48+
x += x_0;
49+
let lon = x / (a * k_0) - lon_0;
5250

5351
// Northing -> Latitude
54-
let y = coord[1] + y_0;
52+
y += y_0;
5553
let psi = y / (a * k_0);
56-
coord[1] = ellps.latitude_isometric_to_geographic(psi) - lat_0;
57-
operands.set_coord(i, &coord);
54+
let lat = ellps.latitude_isometric_to_geographic(psi) - lat_0;
55+
operands.set_xy(i, lon, lat);
5856
successes += 1;
5957
}
6058

@@ -160,9 +158,9 @@ mod tests {
160158
let definition = "merc lat_ts=56";
161159
let op = ctx.op(definition)?;
162160

163-
// Validation value from PROJ: echo 12 55 0 0 | cct -d18 +proj=merc +lat_ts=56
164161
let geo = [Coor4D::geo(55., 12., 0., 0.)];
165162

163+
// Validation value from PROJ: echo 12 55 0 0 | cct -d18 +proj=merc +lat_ts=56
166164
let projected = [Coor4D::raw(
167165
748_713.257_925_886_8,
168166
4_106_573.862_841_270_4,

src/inner_op/tmerc.rs

+27-26
Original file line numberDiff line numberDiff line change
@@ -29,14 +29,15 @@ fn fwd(op: &Op, _ctx: &dyn Context, operands: &mut dyn CoordinateSet) -> usize {
2929
let range = 0..operands.len();
3030
let mut successes = 0_usize;
3131
for i in range {
32-
let mut coord = operands.get_coord(i);
32+
//let mut coord = operands.get_coord(i);
33+
let (lon, lat) = operands.xy(i);
3334

3435
// --- 1. Geographical -> Conformal latitude, rotated longitude
3536

3637
// The conformal latitude
37-
let lat = ellps.latitude_geographic_to_conformal(coord[1], conformal);
38+
let lat = ellps.latitude_geographic_to_conformal(lat, conformal);
3839
// The longitude as reckoned from the central meridian
39-
let lon = coord[0] - lon_0;
40+
let lon = lon - lon_0;
4041

4142
// --- 2. Conformal LAT, LNG -> complex spherical LAT
4243

@@ -48,7 +49,7 @@ fn fwd(op: &Op, _ctx: &dyn Context, operands: &mut dyn CoordinateSet) -> usize {
4849
// --- 3. Complex spherical N, E -> ellipsoidal normalized N, E
4950

5051
// Some numerical optimizations from PROJ modifications by Even Rouault,
51-
let inv_denom_tan_lon = 1. / sin_lat.hypot(cos_lat_lon);
52+
let inv_denom_tan_lon = sin_lat.hypot(cos_lat_lon).recip();
5253
let tan_lon = sin_lon * cos_lat * inv_denom_tan_lon;
5354
// Inverse Gudermannian, using the precomputed tan(lon)
5455
let mut lon = tan_lon.asinh();
@@ -74,17 +75,18 @@ fn fwd(op: &Op, _ctx: &dyn Context, operands: &mut dyn CoordinateSet) -> usize {
7475

7576
// Don't wanna play if we're too far from the center meridian
7677
if lon.abs() > 2.623395162778 {
77-
coord[0] = f64::NAN;
78-
coord[1] = f64::NAN;
78+
operands.set_xy(i, f64::NAN, f64::NAN);
7979
continue;
8080
}
8181

8282
// --- 4. ellipsoidal normalized N, E -> metric N, E
8383

84-
coord[0] = qs * lon + x_0; // Easting
85-
coord[1] = qs * lat + zb; // Northing
84+
let easting = qs * lon + x_0; // Easting
85+
let northing = qs * lat + zb; // Northing
86+
87+
// Done!
88+
operands.set_xy(i, easting, northing);
8689
successes += 1;
87-
operands.set_coord(i, &coord);
8890
}
8991

9092
successes
@@ -118,17 +120,16 @@ fn inv(op: &Op, _ctx: &dyn Context, operands: &mut dyn CoordinateSet) -> usize {
118120
let range = 0..operands.len();
119121
let mut successes = 0_usize;
120122
for i in range {
121-
let mut coord = operands.get_coord(i);
123+
let (x, y) = operands.xy(i);
122124

123125
// --- 1. Normalize N, E
124126

125-
let mut lon = (coord[0] - x_0) / qs;
126-
let mut lat = (coord[1] - zb) / qs;
127+
let mut lon = (x - x_0) / qs;
128+
let mut lat = (y - zb) / qs;
127129

128130
// Don't wanna play if we're too far from the center meridian
129131
if lon.abs() > 2.623395162778 {
130-
coord[0] = f64::NAN;
131-
coord[1] = f64::NAN;
132+
operands.set_xy(i, f64::NAN, f64::NAN);
132133
continue;
133134
}
134135

@@ -151,10 +152,10 @@ fn inv(op: &Op, _ctx: &dyn Context, operands: &mut dyn CoordinateSet) -> usize {
151152

152153
let lon = angular::normalize_symmetric(lon + lon_0);
153154
let lat = ellps.latitude_conformal_to_geographic(lat, conformal);
154-
(coord[0], coord[1]) = (lon, lat);
155155

156+
// Done!
157+
operands.set_xy(i, lon, lat);
156158
successes += 1;
157-
operands.set_coord(i, &coord);
158159
}
159160

160161
successes
@@ -374,8 +375,8 @@ mod tests {
374375
let geo = [
375376
Coor2D::geo( 55., 12.),
376377
Coor2D::geo(-55., 12.),
377-
Coor2D::geo( 55., -6.),
378-
Coor2D::geo(-55., -6.)
378+
Coor2D::geo( 55., -6.),
379+
Coor2D::geo(-55., -6.)
379380
];
380381

381382
#[rustfmt::skip]
@@ -407,18 +408,18 @@ mod tests {
407408

408409
#[rustfmt::skip]
409410
let geo = [
410-
Coor4D::geo( 55., 12., 0., 0.),
411-
Coor4D::geo(-55., 12., 0., 0.),
412-
Coor4D::geo( 55., -6., 0., 0.),
413-
Coor4D::geo(-55., -6., 0., 0.)
411+
Coor2D::geo( 55., 12.),
412+
Coor2D::geo(-55., 12.),
413+
Coor2D::geo( 55., -6.,),
414+
Coor2D::geo(-55., -6.,)
414415
];
415416

416417
#[rustfmt::skip]
417418
let projected = [
418-
Coor4D::raw( 691_875.632_139_661, 1e7+6_098_907.825_005_012, 0., 0.),
419-
Coor4D::raw( 691_875.632_139_661, 1e7-6_098_907.825_005_012, 0., 0.),
420-
Coor4D::raw(-455_673.814_189_040, 1e7+6_198_246.671_090_279, 0., 0.),
421-
Coor4D::raw(-455_673.814_189_040, 1e7-6_198_246.671_090_279, 0., 0.)
419+
Coor2D::raw( 691_875.632_139_661, 1e7+6_098_907.825_005_012),
420+
Coor2D::raw( 691_875.632_139_661, 1e7-6_098_907.825_005_012),
421+
Coor2D::raw(-455_673.814_189_040, 1e7+6_198_246.671_090_279),
422+
Coor2D::raw(-455_673.814_189_040, 1e7-6_198_246.671_090_279)
422423
];
423424

424425
let mut operands = geo;

0 commit comments

Comments
 (0)