Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Initialize zt before calling proj_trans #104

Merged
merged 2 commits into from
Feb 10, 2022
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 31 additions & 11 deletions src/proj.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use proj_sys::{
proj_create, proj_create_crs_to_crs, proj_destroy, proj_errno_string, proj_get_area_of_use,
proj_grid_cache_set_enable, proj_info, proj_normalize_for_visualization, proj_pj_info,
proj_trans, proj_trans_array, PJconsts, PJ_AREA, PJ_CONTEXT, PJ_COORD, PJ_DIRECTION_PJ_FWD,
PJ_DIRECTION_PJ_INV, PJ_INFO, PJ_LP, PJ_XY,
PJ_DIRECTION_PJ_INV, PJ_INFO, PJ_LPZT, PJ_XYZT,
};
use std::{
ffi,
Expand Down Expand Up @@ -673,11 +673,17 @@ impl Proj {
// This signals that we wish to project geodetic coordinates.
// For conversion (i.e. between projected coordinates) you should use
// PJ_XY {x: , y: }
let coords = PJ_LP { lam: c_x, phi: c_y };
// We also initialize z and t in case libproj tries to read them.
let coords = PJ_LPZT {
lam: c_x,
phi: c_y,
z: 0.0,
t: f64::INFINITY,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Curious, why did you choose infinity here?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's what libproj does in proj_transform_generic (or another function with a similar name).

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PROJ dates back to before-or-about-the-same-time as IEEE-754 arithmetic, and hence before the NaN concept was common. So all the way from Jerry Evenden's earliest PROJ work around 1980, HUGE_VAL has been used as the exceptional value in PROJ. Often HUGE_VAL is defined as infinity for C stdlibs running on a IEEE-754 platform, so it makes much sense here.

There was a recent PROJ discussion (which I cannot find atm), focusing on the reasonable idea of changing from HUGE_VAL to NaN. That would, however, be a breaking change. In Rust Geodesy I try to use NaN, when None or Err is not a better option.

};
unsafe {
proj_errno_reset(self.c_proj);
// PJ_DIRECTION_* determines a forward or inverse projection
let trans = proj_trans(self.c_proj, inv, PJ_COORD { lp: coords });
let trans = proj_trans(self.c_proj, inv, PJ_COORD { lpzt: coords });
// output of coordinates uses the PJ_XY struct
new_x = trans.xy.x;
new_y = trans.xy.y;
Expand Down Expand Up @@ -738,10 +744,19 @@ impl Proj {
let new_x;
let new_y;
let err;
let coords = PJ_XY { x: c_x, y: c_y };

// This doesn't seem strictly correct, but if we set PJ_XY or PJ_LP here, the
// other two values remain uninitialized and we can't be sure that libproj
// doesn't try to read them. proj_trans_generic does the same thing.
let xyzt = PJ_XYZT {
x: c_x,
y: c_y,
z: 0.0,
t: f64::INFINITY,
};
unsafe {
proj_errno_reset(self.c_proj);
let trans = proj_trans(self.c_proj, PJ_DIRECTION_PJ_FWD, PJ_COORD { xy: coords });
let trans = proj_trans(self.c_proj, PJ_DIRECTION_PJ_FWD, PJ_COORD { xyzt });
new_x = trans.xy.x;
new_y = trans.xy.y;
err = proj_errno(self.c_proj);
Expand Down Expand Up @@ -860,7 +875,12 @@ impl Proj {
let c_x: c_double = point.x().to_f64().ok_or(ProjError::FloatConversion)?;
let c_y: c_double = point.y().to_f64().ok_or(ProjError::FloatConversion)?;
Ok(PJ_COORD {
xy: PJ_XY { x: c_x, y: c_y },
xyzt: PJ_XYZT {
x: c_x,
y: c_y,
z: 0.0,
t: f64::INFINITY,
},
})
})
.collect::<Result<Vec<_>, ProjError>>()?;
Expand Down Expand Up @@ -1152,11 +1172,11 @@ mod test {
fn test_conversion() {
// Generated by PROJ by specifying "from" and "to" EPSG codes and calling def()
let projstring = "
proj=pipeline step proj=unitconvert xy_in=us-ft
xy_out=m step inv proj=lcc lat_0=32.1666666666667
lon_0=-116.25 lat_1=33.8833333333333 lat_2=32.7833333333333
x_0=2000000.0001016 y_0=500000.0001016 ellps=GRS80 step proj=lcc lat_0=32.1666666666667
lon_0=-116.25 lat_1=33.8833333333333 lat_2=32.7833333333333 x_0=2000000 y_0=500000
proj=pipeline step proj=unitconvert xy_in=us-ft
xy_out=m step inv proj=lcc lat_0=32.1666666666667
lon_0=-116.25 lat_1=33.8833333333333 lat_2=32.7833333333333
x_0=2000000.0001016 y_0=500000.0001016 ellps=GRS80 step proj=lcc lat_0=32.1666666666667
lon_0=-116.25 lat_1=33.8833333333333 lat_2=32.7833333333333 x_0=2000000 y_0=500000
ellps=GRS80
";
let nad83_m = Proj::new(projstring).unwrap();
Expand Down