aboutsummaryrefslogtreecommitdiff
path: root/src/transformations/deformation.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/transformations/deformation.cpp')
-rw-r--r--src/transformations/deformation.cpp193
1 files changed, 149 insertions, 44 deletions
diff --git a/src/transformations/deformation.cpp b/src/transformations/deformation.cpp
index f1311a54..8aee50c9 100644
--- a/src/transformations/deformation.cpp
+++ b/src/transformations/deformation.cpp
@@ -56,20 +56,90 @@ grid-values in units of mm/year in ENU-space.
#include "proj.h"
#include "proj_internal.h"
#include <math.h>
+#include "grids.hpp"
+
+#include <algorithm>
PROJ_HEAD(deformation, "Kinematic grid shift");
#define TOL 1e-8
#define MAX_ITERATIONS 10
+using namespace NS_PROJ;
+
namespace { // anonymous namespace
-struct pj_opaque {
- double dt;
- double t_epoch;
- PJ *cart;
+struct deformationData {
+ double dt = 0;
+ double t_epoch = 0;
+ PJ *cart = nullptr;
+ ListOfGenericGrids grids{};
+ ListOfHGrids hgrids{};
+ ListOfVGrids vgrids{};
};
} // anonymous namespace
+// ---------------------------------------------------------------------------
+
+static bool get_grid_values(PJ* P,
+ deformationData* Q,
+ const PJ_LP& lp,
+ double& vx,
+ double& vy,
+ double& vz)
+{
+ GenericShiftGridSet* gridset = nullptr;
+ auto grid = pj_find_generic_grid(Q->grids, lp, gridset);
+ if( !grid ) {
+ return false;
+ }
+ if( grid->isNullGrid() ) {
+ vx = 0;
+ vy = 0;
+ vz = 0;
+ return true;
+ }
+ const auto samplesPerPixel = grid->samplesPerPixel();
+ if( samplesPerPixel < 3 ) {
+ proj_log_error(P, "deformation: grid has not enough samples");
+ return false;
+ }
+ int sampleE = 0;
+ int sampleN = 1;
+ int sampleU = 2;
+ for( int i = 0; i < samplesPerPixel; i++ )
+ {
+ const auto desc = grid->description(i);
+ if( desc == "east_velocity") {
+ sampleE = i;
+ } else if( desc == "north_velocity") {
+ sampleN = i;
+ } else if( desc == "up_velocity") {
+ sampleU = i;
+ }
+ }
+ const auto unit = grid->unit(sampleE);
+ if( !unit.empty() && unit != "millimetres per year" ) {
+ proj_log_error(P, "deformation: Only unit=millimetres per year currently handled");
+ return false;
+ }
+
+ bool must_retry = false;
+ if( !pj_bilinear_interpolation_three_samples(grid, lp,
+ sampleE, sampleN, sampleU,
+ vx, vy, vz,
+ must_retry) )
+ {
+ if( must_retry )
+ return get_grid_values( P, Q, lp, vx, vy, vz);
+ return false;
+ }
+ // divide by 1000 to get m/year
+ vx /= 1000;
+ vy /= 1000;
+ vz /= 1000;
+ return true;
+}
+
/********************************************************************************/
static PJ_XYZ get_grid_shift(PJ* P, const PJ_XYZ& cartesian) {
/********************************************************************************
@@ -85,22 +155,39 @@ static PJ_XYZ get_grid_shift(PJ* P, const PJ_XYZ& cartesian) {
PJ_COORD geodetic, shift, temp;
double sp, cp, sl, cl;
int previous_errno = proj_errno_reset(P);
+ auto Q = static_cast<deformationData*>(P->opaque);
/* cartesian to geodetic */
- geodetic.lpz = pj_inv3d(cartesian, static_cast<struct pj_opaque*>(P->opaque)->cart);
+ geodetic.lpz = pj_inv3d(cartesian, Q->cart);
/* look up correction values in grids */
- shift.lp = proj_hgrid_value(P, geodetic.lp);
- shift.enu.u = proj_vgrid_value(P, geodetic.lp, 1.0);
-
- if (proj_errno(P) == PJD_ERR_GRID_AREA)
- proj_log_debug(P, "deformation: coordinate (%.3f, %.3f) outside deformation model",
- proj_todeg(geodetic.lpz.lam), proj_todeg(geodetic.lpz.phi));
-
- /* grid values are stored as mm/yr, we need m/yr */
- shift.xyz.x /= 1000;
- shift.xyz.y /= 1000;
- shift.xyz.z /= 1000;
+ if( !Q->grids.empty() )
+ {
+ double vx = 0;
+ double vy = 0;
+ double vz = 0;
+ if( !get_grid_values(P, Q, geodetic.lp, vx, vy, vz) )
+ {
+ return proj_coord_error().xyz;
+ }
+ shift.xyz.x = vx;
+ shift.xyz.y = vy;
+ shift.xyz.z = vz;
+ }
+ else
+ {
+ shift.lp = pj_hgrid_value(P, Q->hgrids, geodetic.lp);
+ shift.enu.u = pj_vgrid_value(P, Q->vgrids, geodetic.lp, 1.0);
+
+ if (proj_errno(P) == PJD_ERR_GRID_AREA)
+ proj_log_debug(P, "deformation: coordinate (%.3f, %.3f) outside deformation model",
+ proj_todeg(geodetic.lpz.lam), proj_todeg(geodetic.lpz.phi));
+
+ /* grid values are stored as mm/yr, we need m/yr */
+ shift.xyz.x /= 1000;
+ shift.xyz.y /= 1000;
+ shift.xyz.z /= 1000;
+ }
/* pre-calc cosines and sines */
sp = sin(geodetic.lpz.phi);
@@ -130,6 +217,9 @@ static PJ_XYZ reverse_shift(PJ *P, PJ_XYZ input, double dt) {
int i = MAX_ITERATIONS;
delta = get_grid_shift(P, input);
+ if (delta.x == HUGE_VAL) {
+ return delta;
+ }
/* Store the origial z shift for later application */
z0 = delta.z;
@@ -163,7 +253,7 @@ static PJ_XYZ reverse_shift(PJ *P, PJ_XYZ input, double dt) {
}
static PJ_XYZ forward_3d(PJ_LPZ lpz, PJ *P) {
- struct pj_opaque *Q = (struct pj_opaque *) P->opaque;
+ struct deformationData *Q = (struct deformationData *) P->opaque;
PJ_COORD out, in;
PJ_XYZ shift;
in.lpz = lpz;
@@ -176,6 +266,9 @@ static PJ_XYZ forward_3d(PJ_LPZ lpz, PJ *P) {
}
shift = get_grid_shift(P, in.xyz);
+ if (shift.x == HUGE_VAL) {
+ return shift;
+ }
out.xyz.x += Q->dt * shift.x;
out.xyz.y += Q->dt * shift.y;
@@ -186,7 +279,7 @@ static PJ_XYZ forward_3d(PJ_LPZ lpz, PJ *P) {
static PJ_COORD forward_4d(PJ_COORD in, PJ *P) {
- struct pj_opaque *Q = (struct pj_opaque *) P->opaque;
+ struct deformationData *Q = (struct deformationData *) P->opaque;
double dt;
PJ_XYZ shift;
PJ_COORD out = in;
@@ -209,7 +302,7 @@ static PJ_COORD forward_4d(PJ_COORD in, PJ *P) {
static PJ_LPZ reverse_3d(PJ_XYZ in, PJ *P) {
- struct pj_opaque *Q = (struct pj_opaque *) P->opaque;
+ struct deformationData *Q = (struct deformationData *) P->opaque;
PJ_COORD out;
out.xyz = in;
@@ -225,7 +318,7 @@ static PJ_LPZ reverse_3d(PJ_XYZ in, PJ *P) {
}
static PJ_COORD reverse_4d(PJ_COORD in, PJ *P) {
- struct pj_opaque *Q = (struct pj_opaque *) P->opaque;
+ struct deformationData *Q = (struct deformationData *) P->opaque;
PJ_COORD out = in;
double dt;
@@ -244,23 +337,23 @@ static PJ *destructor(PJ *P, int errlev) {
if (nullptr==P)
return nullptr;
- if (nullptr==P->opaque)
- return pj_default_destructor (P, errlev);
-
- if (static_cast<struct pj_opaque*>(P->opaque)->cart)
- static_cast<struct pj_opaque*>(P->opaque)->cart->destructor (static_cast<struct pj_opaque*>(P->opaque)->cart, errlev);
+ auto Q = static_cast<struct deformationData*>(P->opaque);
+ if( Q )
+ {
+ if (Q->cart)
+ Q->cart->destructor (Q->cart, errlev);
+ delete Q;
+ }
+ P->opaque = nullptr;
return pj_default_destructor(P, errlev);
}
PJ *TRANSFORMATION(deformation,1) {
- int has_xy_grids = 0;
- int has_z_grids = 0;
- struct pj_opaque *Q = static_cast<struct pj_opaque*>(pj_calloc (1, sizeof (struct pj_opaque)));
- if (nullptr==Q)
- return destructor(P, ENOMEM);
+ auto Q = new deformationData;
P->opaque = (void *) Q;
+ P->destructor = destructor;
// Pass a dummy ellipsoid definition that will be overridden just afterwards
Q->cart = proj_create(P->ctx, "+proj=cart +a=1");
@@ -270,25 +363,38 @@ PJ *TRANSFORMATION(deformation,1) {
/* inherit ellipsoid definition from P to Q->cart */
pj_inherit_ellipsoid_def (P, Q->cart);
- has_xy_grids = pj_param(P->ctx, P->params, "txy_grids").i;
- has_z_grids = pj_param(P->ctx, P->params, "tz_grids").i;
+ int has_xy_grids = pj_param(P->ctx, P->params, "txy_grids").i;
+ int has_z_grids = pj_param(P->ctx, P->params, "tz_grids").i;
+ int has_grids = pj_param(P->ctx, P->params, "tgrids").i;
/* Build gridlists. Both horizontal and vertical grids are mandatory. */
- if (!has_xy_grids || !has_z_grids) {
- proj_log_error(P, "deformation: Both +xy_grids and +z_grids should be specified.");
+ if ( !has_grids && (!has_xy_grids || !has_z_grids)) {
+ proj_log_error(P, "deformation: Either +grids or (+xy_grids and +z_grids) should be specified.");
return destructor(P, PJD_ERR_NO_ARGS );
}
- proj_hgrid_init(P, "xy_grids");
- if (proj_errno(P)) {
- proj_log_error(P, "deformation: could not find requested xy_grid(s).");
- return destructor(P, PJD_ERR_FAILED_TO_LOAD_GRID);
+ if( has_grids )
+ {
+ Q->grids = pj_generic_grid_init(P, "grids");
+ /* Was gridlist compiled properly? */
+ if ( proj_errno(P) ) {
+ proj_log_error(P, "deformation: could not find required grid(s).");
+ return destructor(P, PJD_ERR_FAILED_TO_LOAD_GRID);
+ }
}
-
- proj_vgrid_init(P, "z_grids");
- if (proj_errno(P)) {
- proj_log_error(P, "deformation: could not find requested z_grid(s).");
- return destructor(P, PJD_ERR_FAILED_TO_LOAD_GRID);
+ else
+ {
+ Q->hgrids = pj_hgrid_init(P, "xy_grids");
+ if (proj_errno(P)) {
+ proj_log_error(P, "deformation: could not find requested xy_grid(s).");
+ return destructor(P, PJD_ERR_FAILED_TO_LOAD_GRID);
+ }
+
+ Q->vgrids = pj_vgrid_init(P, "z_grids");
+ if (proj_errno(P)) {
+ proj_log_error(P, "deformation: could not find requested z_grid(s).");
+ return destructor(P, PJD_ERR_FAILED_TO_LOAD_GRID);
+ }
}
Q->dt = HUGE_VAL;
@@ -325,7 +431,6 @@ PJ *TRANSFORMATION(deformation,1) {
P->left = PJ_IO_UNITS_CARTESIAN;
P->right = PJ_IO_UNITS_CARTESIAN;
- P->destructor = destructor;
return P;
}