EVOLUTION-MANAGER
Edit File: fwd.cpp
/****************************************************************************** * Project: PROJ.4 * Purpose: Forward operation invocation * Author: Thomas Knudsen, thokn@sdfe.dk, 2018-01-02 * Based on material from Gerald Evenden (original pj_fwd) * and Piyush Agram (original pj_fwd3d) * ****************************************************************************** * Copyright (c) 2000, Frank Warmerdam * Copyright (c) 2018, Thomas Knudsen / SDFE * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included * in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. *****************************************************************************/ #include <errno.h> #include <math.h> #include "proj_internal.h" #include "proj_math.h" #define INPUT_UNITS P->left #define OUTPUT_UNITS P->right static PJ_COORD fwd_prepare (PJ *P, PJ_COORD coo) { if (HUGE_VAL==coo.v[0] || HUGE_VAL==coo.v[1] || HUGE_VAL==coo.v[2]) return proj_coord_error (); /* The helmert datum shift will choke unless it gets a sensible 4D coordinate */ if (HUGE_VAL==coo.v[2] && P->helmert) coo.v[2] = 0.0; if (HUGE_VAL==coo.v[3] && P->helmert) coo.v[3] = 0.0; /* Check validity of angular input coordinates */ if (INPUT_UNITS==PJ_IO_UNITS_RADIANS) { double t; /* check for latitude or longitude over-range */ t = (coo.lp.phi < 0 ? -coo.lp.phi : coo.lp.phi) - M_HALFPI; if (t > PJ_EPS_LAT || coo.lp.lam > 10 || coo.lp.lam < -10) { proj_errno_set (P, PJD_ERR_LAT_OR_LON_EXCEED_LIMIT); return proj_coord_error (); } /* Clamp latitude to -90..90 degree range */ if (coo.lp.phi > M_HALFPI) coo.lp.phi = M_HALFPI; if (coo.lp.phi < -M_HALFPI) coo.lp.phi = -M_HALFPI; /* If input latitude is geocentrical, convert to geographical */ if (P->geoc) coo = pj_geocentric_latitude (P, PJ_INV, coo); /* Ensure longitude is in the -pi:pi range */ if (0==P->over) coo.lp.lam = adjlon(coo.lp.lam); if (P->hgridshift) coo = proj_trans (P->hgridshift, PJ_INV, coo); else if (P->helmert || (P->cart_wgs84 != nullptr && P->cart != nullptr)) { coo = proj_trans (P->cart_wgs84, PJ_FWD, coo); /* Go cartesian in WGS84 frame */ if( P->helmert ) coo = proj_trans (P->helmert, PJ_INV, coo); /* Step into local frame */ coo = proj_trans (P->cart, PJ_INV, coo); /* Go back to angular using local ellps */ } if (coo.lp.lam==HUGE_VAL) return coo; if (P->vgridshift) coo = proj_trans (P->vgridshift, PJ_FWD, coo); /* Go orthometric from geometric */ /* Distance from central meridian, taking system zero meridian into account */ coo.lp.lam = (coo.lp.lam - P->from_greenwich) - P->lam0; /* Ensure longitude is in the -pi:pi range */ if (0==P->over) coo.lp.lam = adjlon(coo.lp.lam); return coo; } /* We do not support gridshifts on cartesian input */ if (INPUT_UNITS==PJ_IO_UNITS_CARTESIAN && P->helmert) return proj_trans (P->helmert, PJ_INV, coo); return coo; } static PJ_COORD fwd_finalize (PJ *P, PJ_COORD coo) { switch (OUTPUT_UNITS) { /* Handle false eastings/northings and non-metric linear units */ case PJ_IO_UNITS_CARTESIAN: if (P->is_geocent) { coo = proj_trans (P->cart, PJ_FWD, coo); } coo.xyz.x *= P->fr_meter; coo.xyz.y *= P->fr_meter; coo.xyz.z *= P->fr_meter; break; /* Classic proj.4 functions return plane coordinates in units of the semimajor axis */ case PJ_IO_UNITS_CLASSIC: coo.xy.x *= P->a; coo.xy.y *= P->a; /* Falls through */ /* (<-- GCC warning silencer) */ /* to continue processing in common with PJ_IO_UNITS_PROJECTED */ case PJ_IO_UNITS_PROJECTED: coo.xyz.x = P->fr_meter * (coo.xyz.x + P->x0); coo.xyz.y = P->fr_meter * (coo.xyz.y + P->y0); coo.xyz.z = P->vfr_meter * (coo.xyz.z + P->z0); break; case PJ_IO_UNITS_WHATEVER: break; case PJ_IO_UNITS_RADIANS: coo.lpz.z = P->vfr_meter * (coo.lpz.z + P->z0); if( P->is_long_wrap_set ) { if( coo.lpz.lam != HUGE_VAL ) { coo.lpz.lam = P->long_wrap_center + adjlon(coo.lpz.lam - P->long_wrap_center); } } break; } if (P->axisswap) coo = proj_trans (P->axisswap, PJ_FWD, coo); return coo; } static PJ_COORD error_or_coord(PJ *P, PJ_COORD coord, int last_errno) { if (proj_errno(P)) return proj_coord_error(); proj_errno_restore(P, last_errno); return coord; } PJ_XY pj_fwd(PJ_LP lp, PJ *P) { int last_errno; PJ_COORD coo = {{0,0,0,0}}; coo.lp = lp; last_errno = proj_errno_reset(P); if (!P->skip_fwd_prepare) coo = fwd_prepare (P, coo); if (HUGE_VAL==coo.v[0] || HUGE_VAL==coo.v[1]) return proj_coord_error ().xy; /* Do the transformation, using the lowest dimensional transformer available */ if (P->fwd) coo.xy = P->fwd(coo.lp, P); else if (P->fwd3d) coo.xyz = P->fwd3d (coo.lpz, P); else if (P->fwd4d) coo = P->fwd4d (coo, P); else { proj_errno_set (P, EINVAL); return proj_coord_error ().xy; } if (HUGE_VAL==coo.v[0]) return proj_coord_error ().xy; if (!P->skip_fwd_finalize) coo = fwd_finalize (P, coo); return error_or_coord(P, coo, last_errno).xy; } PJ_XYZ pj_fwd3d(PJ_LPZ lpz, PJ *P) { int last_errno; PJ_COORD coo = {{0,0,0,0}}; coo.lpz = lpz; last_errno = proj_errno_reset(P); if (!P->skip_fwd_prepare) coo = fwd_prepare (P, coo); if (HUGE_VAL==coo.v[0]) return proj_coord_error ().xyz; /* Do the transformation, using the lowest dimensional transformer feasible */ if (P->fwd3d) coo.xyz = P->fwd3d(coo.lpz, P); else if (P->fwd4d) coo = P->fwd4d (coo, P); else if (P->fwd) coo.xy = P->fwd (coo.lp, P); else { proj_errno_set (P, EINVAL); return proj_coord_error ().xyz; } if (HUGE_VAL==coo.v[0]) return proj_coord_error ().xyz; if (!P->skip_fwd_finalize) coo = fwd_finalize (P, coo); return error_or_coord(P, coo, last_errno).xyz; } PJ_COORD pj_fwd4d (PJ_COORD coo, PJ *P) { int last_errno = proj_errno_reset(P); if (!P->skip_fwd_prepare) coo = fwd_prepare (P, coo); if (HUGE_VAL==coo.v[0]) return proj_coord_error (); /* Call the highest dimensional converter available */ if (P->fwd4d) coo = P->fwd4d (coo, P); else if (P->fwd3d) coo.xyz = P->fwd3d (coo.lpz, P); else if (P->fwd) coo.xy = P->fwd (coo.lp, P); else { proj_errno_set (P, EINVAL); return proj_coord_error (); } if (HUGE_VAL==coo.v[0]) return proj_coord_error (); if (!P->skip_fwd_finalize) coo = fwd_finalize (P, coo); return error_or_coord(P, coo, last_errno); }