1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033 |
- // Boost.Geometry
- // This file is manually converted from PROJ4
- // Copyright (c) 2023 Adam Wulkiewicz, Lodz, Poland.
- // This file was modified by Oracle on 2017, 2018.
- // Modifications copyright (c) 2017-2018, Oracle and/or its affiliates.
- // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
- // Use, modification and distribution is subject to the Boost Software License,
- // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
- // http://www.boost.org/LICENSE_1_0.txt)
- // This file is converted from PROJ4, http://trac.osgeo.org/proj
- // PROJ4 is originally written by Gerald Evenden (then of the USGS)
- // PROJ4 is maintained by Frank Warmerdam
- // This file was converted to Geometry Library by Adam Wulkiewicz
- // Original copyright notice:
- // Copyright (c) 2000, Frank Warmerdam
- // 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.
- #ifndef BOOST_GEOMETRY_SRS_PROJECTIONS_IMPL_PJ_TRANSFORM_HPP
- #define BOOST_GEOMETRY_SRS_PROJECTIONS_IMPL_PJ_TRANSFORM_HPP
- #include <boost/geometry/core/access.hpp>
- #include <boost/geometry/core/coordinate_dimension.hpp>
- #include <boost/geometry/core/radian_access.hpp>
- #include <boost/geometry/srs/projections/impl/geocent.hpp>
- #include <boost/geometry/srs/projections/impl/pj_apply_gridshift.hpp>
- #include <boost/geometry/srs/projections/impl/projects.hpp>
- #include <boost/geometry/srs/projections/invalid_point.hpp>
- #include <boost/geometry/util/condition.hpp>
- #include <boost/geometry/util/range.hpp>
- #include <cstring>
- #include <cmath>
- namespace boost { namespace geometry { namespace projections
- {
- namespace detail
- {
- // -----------------------------------------------------------
- // Boost.Geometry helpers begin
- // -----------------------------------------------------------
- template
- <
- typename Point,
- bool HasCoord2 = (dimension<Point>::value > 2)
- >
- struct z_access
- {
- typedef typename coordinate_type<Point>::type type;
- static inline type get(Point const& point)
- {
- return geometry::get<2>(point);
- }
- static inline void set(Point & point, type const& h)
- {
- return geometry::set<2>(point, h);
- }
- };
- template <typename Point>
- struct z_access<Point, false>
- {
- typedef typename coordinate_type<Point>::type type;
- static inline type get(Point const& )
- {
- return type(0);
- }
- static inline void set(Point & , type const& )
- {}
- };
- template <typename XYorXYZ>
- inline typename z_access<XYorXYZ>::type
- get_z(XYorXYZ const& xy_or_xyz)
- {
- return z_access<XYorXYZ>::get(xy_or_xyz);
- }
- template <typename XYorXYZ>
- inline void set_z(XYorXYZ & xy_or_xyz,
- typename z_access<XYorXYZ>::type const& z)
- {
- return z_access<XYorXYZ>::set(xy_or_xyz, z);
- }
- template
- <
- typename Range,
- bool AddZ = (dimension<typename boost::range_value<Range>::type>::value < 3)
- >
- struct range_wrapper
- {
- typedef Range range_type;
- typedef typename boost::range_value<Range>::type point_type;
- typedef typename coordinate_type<point_type>::type coord_t;
- range_wrapper(Range & range)
- : m_range(range)
- {}
- range_type & get_range() { return m_range; }
- coord_t get_z(std::size_t i) { return detail::get_z(range::at(m_range, i)); }
- void set_z(std::size_t i, coord_t const& v) { return detail::set_z(range::at(m_range, i), v); }
- private:
- Range & m_range;
- };
- template <typename Range>
- struct range_wrapper<Range, true>
- {
- typedef Range range_type;
- typedef typename boost::range_value<Range>::type point_type;
- typedef typename coordinate_type<point_type>::type coord_t;
- range_wrapper(Range & range)
- : m_range(range)
- , m_zs(boost::size(range), coord_t(0))
- {}
- range_type & get_range() { return m_range; }
- coord_t get_z(std::size_t i) { return m_zs[i]; }
- void set_z(std::size_t i, coord_t const& v) { m_zs[i] = v; }
- private:
- Range & m_range;
- std::vector<coord_t> m_zs;
- };
- // -----------------------------------------------------------
- // Boost.Geometry helpers end
- // -----------------------------------------------------------
- template <typename Par>
- inline typename Par::type Dx_BF(Par const& defn) { return defn.datum_params[0]; }
- template <typename Par>
- inline typename Par::type Dy_BF(Par const& defn) { return defn.datum_params[1]; }
- template <typename Par>
- inline typename Par::type Dz_BF(Par const& defn) { return defn.datum_params[2]; }
- template <typename Par>
- inline typename Par::type Rx_BF(Par const& defn) { return defn.datum_params[3]; }
- template <typename Par>
- inline typename Par::type Ry_BF(Par const& defn) { return defn.datum_params[4]; }
- template <typename Par>
- inline typename Par::type Rz_BF(Par const& defn) { return defn.datum_params[5]; }
- template <typename Par>
- inline typename Par::type M_BF(Par const& defn) { return defn.datum_params[6]; }
- /*
- ** This table is intended to indicate for any given error code in
- ** the range 0 to -56, whether that error will occur for all locations (ie.
- ** it is a problem with the coordinate system as a whole) in which case the
- ** value would be 0, or if the problem is with the point being transformed
- ** in which case the value is 1.
- **
- ** At some point we might want to move this array in with the error message
- ** list or something, but while experimenting with it this should be fine.
- **
- **
- ** NOTE (2017-10-01): Non-transient errors really should have resulted in a
- ** PJ==0 during initialization, and hence should be handled at the level
- ** before calling pj_transform. The only obvious example of the contrary
- ** appears to be the PJD_ERR_GRID_AREA case, which may also be taken to
- ** mean "no grids available"
- **
- **
- */
- static const int transient_error[60] = {
- /* 0 1 2 3 4 5 6 7 8 9 */
- /* 0 to 9 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- /* 10 to 19 */ 0, 0, 0, 0, 1, 1, 0, 1, 1, 1,
- /* 20 to 29 */ 1, 0, 0, 0, 0, 0, 0, 1, 0, 0,
- /* 30 to 39 */ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- /* 40 to 49 */ 0, 0, 0, 0, 0, 0, 0, 0, 1, 0,
- /* 50 to 59 */ 1, 0, 1, 0, 1, 1, 1, 1, 0, 0 };
- template <typename T, typename Range>
- inline int pj_geocentric_to_geodetic( T const& a, T const& es,
- Range & range );
- template <typename T, typename Range>
- inline int pj_geodetic_to_geocentric( T const& a, T const& es,
- Range & range );
- /************************************************************************/
- /* pj_transform() */
- /* */
- /* Currently this function doesn't recognise if two projections */
- /* are identical (to short circuit reprojection) because it is */
- /* difficult to compare PJ structures (since there are some */
- /* projection specific components). */
- /************************************************************************/
- template <
- typename SrcPrj,
- typename DstPrj2,
- typename Par,
- typename Range,
- typename Grids
- >
- inline bool pj_transform(SrcPrj const& srcprj, Par const& srcdefn,
- DstPrj2 const& dstprj, Par const& dstdefn,
- Range & range,
- Grids const& srcgrids,
- Grids const& dstgrids)
- {
- typedef typename boost::range_value<Range>::type point_type;
- typedef typename coordinate_type<point_type>::type coord_t;
- static const std::size_t dimension = geometry::dimension<point_type>::value;
- std::size_t point_count = boost::size(range);
- bool result = true;
- /* -------------------------------------------------------------------- */
- /* Transform unusual input coordinate axis orientation to */
- /* standard form if needed. */
- /* -------------------------------------------------------------------- */
- // Ignored
- /* -------------------------------------------------------------------- */
- /* Transform Z to meters if it isn't already. */
- /* -------------------------------------------------------------------- */
- if( srcdefn.vto_meter != 1.0 && BOOST_GEOMETRY_CONDITION(dimension > 2) )
- {
- for( std::size_t i = 0; i < point_count; i++ )
- {
- point_type & point = geometry::range::at(range, i);
- set_z(point, get_z(point) * srcdefn.vto_meter);
- }
- }
- /* -------------------------------------------------------------------- */
- /* Transform geocentric source coordinates to lat/long. */
- /* -------------------------------------------------------------------- */
- if( BOOST_GEOMETRY_CONDITION(srcdefn.is_geocent) )
- {
- // Point should be cartesian 3D (ECEF)
- if ( BOOST_GEOMETRY_CONDITION(dimension < 3) )
- BOOST_THROW_EXCEPTION( projection_exception(error_geocentric) );
- //return PJD_ERR_GEOCENTRIC;
- if( srcdefn.to_meter != 1.0 )
- {
- for(std::size_t i = 0; i < point_count; i++ )
- {
- point_type & point = range::at(range, i);
- if( ! is_invalid_point(point) )
- {
- set<0>(point, get<0>(point) * srcdefn.to_meter);
- set<1>(point, get<1>(point) * srcdefn.to_meter);
- }
- }
- }
- range_wrapper<Range, false> rng(range);
- int err = pj_geocentric_to_geodetic( srcdefn.a_orig, srcdefn.es_orig,
- rng );
- if( err != 0 )
- BOOST_THROW_EXCEPTION( projection_exception(err) );
- //return err;
- // NOTE: here 3D cartesian ECEF is converted into 3D geodetic LLH
- }
- /* -------------------------------------------------------------------- */
- /* Transform source points to lat/long, if they aren't */
- /* already. */
- /* -------------------------------------------------------------------- */
- else if( !srcdefn.is_latlong )
- {
- // Point should be cartesian 2D or 3D (map projection)
- /* Check first if projection is invertible. */
- /*if( (srcdefn->inv3d == NULL) && (srcdefn->inv == NULL))
- {
- pj_ctx_set_errno( pj_get_ctx(srcdefn), -17 );
- pj_log( pj_get_ctx(srcdefn), PJ_LOG_ERROR,
- "pj_transform(): source projection not invertible" );
- return -17;
- }*/
- /* If invertible - First try inv3d if defined */
- //if (srcdefn->inv3d != NULL)
- //{
- // /* Three dimensions must be defined */
- // if ( z == NULL)
- // {
- // pj_ctx_set_errno( pj_get_ctx(srcdefn), PJD_ERR_GEOCENTRIC);
- // return PJD_ERR_GEOCENTRIC;
- // }
- // for (i=0; i < point_count; i++)
- // {
- // XYZ projected_loc;
- // XYZ geodetic_loc;
- // projected_loc.u = x[point_offset*i];
- // projected_loc.v = y[point_offset*i];
- // projected_loc.w = z[point_offset*i];
- // if (projected_loc.u == HUGE_VAL)
- // continue;
- // geodetic_loc = pj_inv3d(projected_loc, srcdefn);
- // if( srcdefn->ctx->last_errno != 0 )
- // {
- // if( (srcdefn->ctx->last_errno != 33 /*EDOM*/
- // && srcdefn->ctx->last_errno != 34 /*ERANGE*/ )
- // && (srcdefn->ctx->last_errno > 0
- // || srcdefn->ctx->last_errno < -44 || point_count == 1
- // || transient_error[-srcdefn->ctx->last_errno] == 0 ) )
- // return srcdefn->ctx->last_errno;
- // else
- // {
- // geodetic_loc.u = HUGE_VAL;
- // geodetic_loc.v = HUGE_VAL;
- // geodetic_loc.w = HUGE_VAL;
- // }
- // }
- // x[point_offset*i] = geodetic_loc.u;
- // y[point_offset*i] = geodetic_loc.v;
- // z[point_offset*i] = geodetic_loc.w;
- // }
- //}
- //else
- {
- /* Fallback to the original PROJ.4 API 2d inversion - inv */
- for( std::size_t i = 0; i < point_count; i++ )
- {
- point_type & point = range::at(range, i);
- if( is_invalid_point(point) )
- continue;
- try
- {
- pj_inv(srcprj, srcdefn, point, point);
- }
- catch(projection_exception const& e)
- {
- if( (e.code() != 33 /*EDOM*/
- && e.code() != 34 /*ERANGE*/ )
- && (e.code() > 0
- || e.code() < -44 /*|| point_count == 1*/
- || transient_error[-e.code()] == 0) ) {
- BOOST_RETHROW
- } else {
- set_invalid_point(point);
- result = false;
- if (point_count == 1)
- return result;
- }
- }
- }
- }
- }
- /* -------------------------------------------------------------------- */
- /* But if they are already lat long, adjust for the prime */
- /* meridian if there is one in effect. */
- /* -------------------------------------------------------------------- */
- if( srcdefn.from_greenwich != 0.0 )
- {
- for( std::size_t i = 0; i < point_count; i++ )
- {
- point_type & point = range::at(range, i);
- if( ! is_invalid_point(point) )
- set<0>(point, get<0>(point) + srcdefn.from_greenwich);
- }
- }
- /* -------------------------------------------------------------------- */
- /* Do we need to translate from geoid to ellipsoidal vertical */
- /* datum? */
- /* -------------------------------------------------------------------- */
- /*if( srcdefn->has_geoid_vgrids && z != NULL )
- {
- if( pj_apply_vgridshift( srcdefn, "sgeoidgrids",
- &(srcdefn->vgridlist_geoid),
- &(srcdefn->vgridlist_geoid_count),
- 0, point_count, point_offset, x, y, z ) != 0 )
- return pj_ctx_get_errno(srcdefn->ctx);
- }*/
- /* -------------------------------------------------------------------- */
- /* Convert datums if needed, and possible. */
- /* -------------------------------------------------------------------- */
- if ( ! pj_datum_transform( srcdefn, dstdefn, range, srcgrids, dstgrids ) )
- {
- result = false;
- }
- /* -------------------------------------------------------------------- */
- /* Do we need to translate from ellipsoidal to geoid vertical */
- /* datum? */
- /* -------------------------------------------------------------------- */
- /*if( dstdefn->has_geoid_vgrids && z != NULL )
- {
- if( pj_apply_vgridshift( dstdefn, "sgeoidgrids",
- &(dstdefn->vgridlist_geoid),
- &(dstdefn->vgridlist_geoid_count),
- 1, point_count, point_offset, x, y, z ) != 0 )
- return dstdefn->ctx->last_errno;
- }*/
- /* -------------------------------------------------------------------- */
- /* But if they are staying lat long, adjust for the prime */
- /* meridian if there is one in effect. */
- /* -------------------------------------------------------------------- */
- if( dstdefn.from_greenwich != 0.0 )
- {
- for( std::size_t i = 0; i < point_count; i++ )
- {
- point_type & point = range::at(range, i);
- if( ! is_invalid_point(point) )
- set<0>(point, get<0>(point) - dstdefn.from_greenwich);
- }
- }
- /* -------------------------------------------------------------------- */
- /* Transform destination latlong to geocentric if required. */
- /* -------------------------------------------------------------------- */
- if( BOOST_GEOMETRY_CONDITION(dstdefn.is_geocent) )
- {
- // Point should be cartesian 3D (ECEF)
- if ( BOOST_GEOMETRY_CONDITION(dimension < 3) )
- BOOST_THROW_EXCEPTION( projection_exception(error_geocentric) );
- //return PJD_ERR_GEOCENTRIC;
- // NOTE: In the original code the return value of the following
- // function is not checked
- range_wrapper<Range, false> rng(range);
- int err = pj_geodetic_to_geocentric( dstdefn.a_orig, dstdefn.es_orig,
- rng );
- if( err == -14 )
- result = false;
- else
- BOOST_THROW_EXCEPTION( projection_exception(err) );
- if( dstdefn.fr_meter != 1.0 )
- {
- for( std::size_t i = 0; i < point_count; i++ )
- {
- point_type & point = range::at(range, i);
- if( ! is_invalid_point(point) )
- {
- set<0>(point, get<0>(point) * dstdefn.fr_meter);
- set<1>(point, get<1>(point) * dstdefn.fr_meter);
- }
- }
- }
- }
- /* -------------------------------------------------------------------- */
- /* Transform destination points to projection coordinates, if */
- /* desired. */
- /* -------------------------------------------------------------------- */
- else if( !dstdefn.is_latlong )
- {
- //if( dstdefn->fwd3d != NULL)
- //{
- // for( i = 0; i < point_count; i++ )
- // {
- // XYZ projected_loc;
- // LPZ geodetic_loc;
- // geodetic_loc.u = x[point_offset*i];
- // geodetic_loc.v = y[point_offset*i];
- // geodetic_loc.w = z[point_offset*i];
- // if (geodetic_loc.u == HUGE_VAL)
- // continue;
- // projected_loc = pj_fwd3d( geodetic_loc, dstdefn);
- // if( dstdefn->ctx->last_errno != 0 )
- // {
- // if( (dstdefn->ctx->last_errno != 33 /*EDOM*/
- // && dstdefn->ctx->last_errno != 34 /*ERANGE*/ )
- // && (dstdefn->ctx->last_errno > 0
- // || dstdefn->ctx->last_errno < -44 || point_count == 1
- // || transient_error[-dstdefn->ctx->last_errno] == 0 ) )
- // return dstdefn->ctx->last_errno;
- // else
- // {
- // projected_loc.u = HUGE_VAL;
- // projected_loc.v = HUGE_VAL;
- // projected_loc.w = HUGE_VAL;
- // }
- // }
- // x[point_offset*i] = projected_loc.u;
- // y[point_offset*i] = projected_loc.v;
- // z[point_offset*i] = projected_loc.w;
- // }
- //}
- //else
- {
- for(std::size_t i = 0; i < point_count; i++ )
- {
- point_type & point = range::at(range, i);
- if( is_invalid_point(point) )
- continue;
- try {
- pj_fwd(dstprj, dstdefn, point, point);
- } catch (projection_exception const& e) {
- if( (e.code() != 33 /*EDOM*/
- && e.code() != 34 /*ERANGE*/ )
- && (e.code() > 0
- || e.code() < -44 /*|| point_count == 1*/
- || transient_error[-e.code()] == 0) ) {
- BOOST_RETHROW
- } else {
- set_invalid_point(point);
- result = false;
- if (point_count == 1)
- return result;
- }
- }
- }
- }
- }
- /* -------------------------------------------------------------------- */
- /* If a wrapping center other than 0 is provided, rewrap around */
- /* the suggested center (for latlong coordinate systems only). */
- /* -------------------------------------------------------------------- */
- else if( dstdefn.is_latlong && dstdefn.is_long_wrap_set )
- {
- for( std::size_t i = 0; i < point_count; i++ )
- {
- point_type & point = range::at(range, i);
- coord_t x = get_as_radian<0>(point);
- if( is_invalid_point(point) )
- continue;
- // TODO - units-dependant constants could be used instead
- while( x < dstdefn.long_wrap_center - math::pi<coord_t>() )
- x += math::two_pi<coord_t>();
- while( x > dstdefn.long_wrap_center + math::pi<coord_t>() )
- x -= math::two_pi<coord_t>();
- set_from_radian<0>(point, x);
- }
- }
- /* -------------------------------------------------------------------- */
- /* Transform Z from meters if needed. */
- /* -------------------------------------------------------------------- */
- if( dstdefn.vto_meter != 1.0 && BOOST_GEOMETRY_CONDITION(dimension > 2) )
- {
- for( std::size_t i = 0; i < point_count; i++ )
- {
- point_type & point = geometry::range::at(range, i);
- set_z(point, get_z(point) * dstdefn.vfr_meter);
- }
- }
- /* -------------------------------------------------------------------- */
- /* Transform normalized axes into unusual output coordinate axis */
- /* orientation if needed. */
- /* -------------------------------------------------------------------- */
- // Ignored
- return result;
- }
- /************************************************************************/
- /* pj_geodetic_to_geocentric() */
- /************************************************************************/
- template <typename T, typename Range, bool AddZ>
- inline int pj_geodetic_to_geocentric( T const& a, T const& es,
- range_wrapper<Range, AddZ> & range_wrapper )
- {
- //typedef typename boost::range_iterator<Range>::type iterator;
- typedef typename boost::range_value<Range>::type point_type;
- //typedef typename coordinate_type<point_type>::type coord_t;
- Range & rng = range_wrapper.get_range();
- std::size_t point_count = boost::size(rng);
- int ret_errno = 0;
- T const b = (es == 0.0) ? a : a * sqrt(1-es);
- GeocentricInfo<T> gi;
- if( pj_Set_Geocentric_Parameters( gi, a, b ) != 0 )
- {
- return error_geocentric;
- }
- for( std::size_t i = 0 ; i < point_count ; ++i )
- {
- point_type & point = range::at(rng, i);
- if( is_invalid_point(point) )
- continue;
- T X = 0, Y = 0, Z = 0;
- if( pj_Convert_Geodetic_To_Geocentric( gi,
- get_as_radian<0>(point),
- get_as_radian<1>(point),
- range_wrapper.get_z(i), // Height
- X, Y, Z ) != 0 )
- {
- ret_errno = error_lat_or_lon_exceed_limit;
- set_invalid_point(point);
- /* but keep processing points! */
- }
- else
- {
- set<0>(point, X);
- set<1>(point, Y);
- range_wrapper.set_z(i, Z);
- }
- }
- return ret_errno;
- }
- /************************************************************************/
- /* pj_geodetic_to_geocentric() */
- /************************************************************************/
- template <typename T, typename Range, bool AddZ>
- inline int pj_geocentric_to_geodetic( T const& a, T const& es,
- range_wrapper<Range, AddZ> & range_wrapper )
- {
- //typedef typename boost::range_iterator<Range>::type iterator;
- typedef typename boost::range_value<Range>::type point_type;
- //typedef typename coordinate_type<point_type>::type coord_t;
- Range & rng = range_wrapper.get_range();
- std::size_t point_count = boost::size(rng);
- T const b = (es == 0.0) ? a : a * sqrt(1-es);
- GeocentricInfo<T> gi;
- if( pj_Set_Geocentric_Parameters( gi, a, b ) != 0 )
- {
- return error_geocentric;
- }
- for( std::size_t i = 0 ; i < point_count ; ++i )
- {
- point_type & point = range::at(rng, i);
- if( is_invalid_point(point) )
- continue;
- T Longitude = 0, Latitude = 0, Height = 0;
- pj_Convert_Geocentric_To_Geodetic( gi,
- get<0>(point),
- get<1>(point),
- range_wrapper.get_z(i), // z
- Longitude, Latitude, Height );
- set_from_radian<0>(point, Longitude);
- set_from_radian<1>(point, Latitude);
- range_wrapper.set_z(i, Height); // Height
- }
- return 0;
- }
- /************************************************************************/
- /* pj_compare_datums() */
- /* */
- /* Returns TRUE if the two datums are identical, otherwise */
- /* FALSE. */
- /************************************************************************/
- template <typename Par>
- inline bool pj_compare_datums( Par & srcdefn, Par & dstdefn )
- {
- if( srcdefn.datum_type != dstdefn.datum_type )
- {
- return false;
- }
- else if( srcdefn.a_orig != dstdefn.a_orig
- || math::abs(srcdefn.es_orig - dstdefn.es_orig) > 0.000000000050 )
- {
- /* the tolerance for es is to ensure that GRS80 and WGS84 are
- considered identical */
- return false;
- }
- else if( srcdefn.datum_type == datum_3param )
- {
- return (srcdefn.datum_params[0] == dstdefn.datum_params[0]
- && srcdefn.datum_params[1] == dstdefn.datum_params[1]
- && srcdefn.datum_params[2] == dstdefn.datum_params[2]);
- }
- else if( srcdefn.datum_type == datum_7param )
- {
- return (srcdefn.datum_params[0] == dstdefn.datum_params[0]
- && srcdefn.datum_params[1] == dstdefn.datum_params[1]
- && srcdefn.datum_params[2] == dstdefn.datum_params[2]
- && srcdefn.datum_params[3] == dstdefn.datum_params[3]
- && srcdefn.datum_params[4] == dstdefn.datum_params[4]
- && srcdefn.datum_params[5] == dstdefn.datum_params[5]
- && srcdefn.datum_params[6] == dstdefn.datum_params[6]);
- }
- else if( srcdefn.datum_type == datum_gridshift )
- {
- return srcdefn.nadgrids == dstdefn.nadgrids;
- }
- else
- return true;
- }
- /************************************************************************/
- /* pj_geocentic_to_wgs84() */
- /************************************************************************/
- template <typename Par, typename Range, bool AddZ>
- inline int pj_geocentric_to_wgs84( Par const& defn,
- range_wrapper<Range, AddZ> & range_wrapper )
- {
- typedef typename boost::range_value<Range>::type point_type;
- typedef typename coordinate_type<point_type>::type coord_t;
- Range & rng = range_wrapper.get_range();
- std::size_t point_count = boost::size(rng);
- if( defn.datum_type == datum_3param )
- {
- for(std::size_t i = 0; i < point_count; i++ )
- {
- point_type & point = range::at(rng, i);
- if( is_invalid_point(point) )
- continue;
- set<0>(point, get<0>(point) + Dx_BF(defn));
- set<1>(point, get<1>(point) + Dy_BF(defn));
- range_wrapper.set_z(i, range_wrapper.get_z(i) + Dz_BF(defn));
- }
- }
- else if( defn.datum_type == datum_7param )
- {
- for(std::size_t i = 0; i < point_count; i++ )
- {
- point_type & point = range::at(rng, i);
- if( is_invalid_point(point) )
- continue;
- coord_t x = get<0>(point);
- coord_t y = get<1>(point);
- coord_t z = range_wrapper.get_z(i);
- coord_t x_out, y_out, z_out;
- x_out = M_BF(defn)*( x - Rz_BF(defn)*y + Ry_BF(defn)*z) + Dx_BF(defn);
- y_out = M_BF(defn)*( Rz_BF(defn)*x + y - Rx_BF(defn)*z) + Dy_BF(defn);
- z_out = M_BF(defn)*(-Ry_BF(defn)*x + Rx_BF(defn)*y + z) + Dz_BF(defn);
- set<0>(point, x_out);
- set<1>(point, y_out);
- range_wrapper.set_z(i, z_out);
- }
- }
- return 0;
- }
- /************************************************************************/
- /* pj_geocentic_from_wgs84() */
- /************************************************************************/
- template <typename Par, typename Range, bool AddZ>
- inline int pj_geocentric_from_wgs84( Par const& defn,
- range_wrapper<Range, AddZ> & range_wrapper )
- {
- typedef typename boost::range_value<Range>::type point_type;
- typedef typename coordinate_type<point_type>::type coord_t;
- Range & rng = range_wrapper.get_range();
- std::size_t point_count = boost::size(rng);
- if( defn.datum_type == datum_3param )
- {
- for(std::size_t i = 0; i < point_count; i++ )
- {
- point_type & point = range::at(rng, i);
- if( is_invalid_point(point) )
- continue;
- set<0>(point, get<0>(point) - Dx_BF(defn));
- set<1>(point, get<1>(point) - Dy_BF(defn));
- range_wrapper.set_z(i, range_wrapper.get_z(i) - Dz_BF(defn));
- }
- }
- else if( defn.datum_type == datum_7param )
- {
- for(std::size_t i = 0; i < point_count; i++ )
- {
- point_type & point = range::at(rng, i);
- if( is_invalid_point(point) )
- continue;
- coord_t x = get<0>(point);
- coord_t y = get<1>(point);
- coord_t z = range_wrapper.get_z(i);
- coord_t x_tmp = (x - Dx_BF(defn)) / M_BF(defn);
- coord_t y_tmp = (y - Dy_BF(defn)) / M_BF(defn);
- coord_t z_tmp = (z - Dz_BF(defn)) / M_BF(defn);
- x = x_tmp + Rz_BF(defn)*y_tmp - Ry_BF(defn)*z_tmp;
- y = -Rz_BF(defn)*x_tmp + y_tmp + Rx_BF(defn)*z_tmp;
- z = Ry_BF(defn)*x_tmp - Rx_BF(defn)*y_tmp + z_tmp;
- set<0>(point, x);
- set<1>(point, y);
- range_wrapper.set_z(i, z);
- }
- }
- return 0;
- }
- inline bool pj_datum_check_error(int err)
- {
- return err != 0 && (err > 0 || transient_error[-err] == 0);
- }
- /************************************************************************/
- /* pj_datum_transform() */
- /* */
- /* The input should be long/lat/z coordinates in radians in the */
- /* source datum, and the output should be long/lat/z */
- /* coordinates in radians in the destination datum. */
- /************************************************************************/
- template <typename Par, typename Range, typename Grids>
- inline bool pj_datum_transform(Par const& srcdefn,
- Par const& dstdefn,
- Range & range,
- Grids const& srcgrids,
- Grids const& dstgrids)
- {
- typedef typename Par::type calc_t;
- // This has to be consistent with default spheroid and pj_ellps
- // TODO: Define in one place
- static const calc_t wgs84_a = 6378137.0;
- static const calc_t wgs84_b = 6356752.3142451793;
- static const calc_t wgs84_es = 1. - (wgs84_b * wgs84_b) / (wgs84_a * wgs84_a);
- bool result = true;
- calc_t src_a, src_es, dst_a, dst_es;
- /* -------------------------------------------------------------------- */
- /* We cannot do any meaningful datum transformation if either */
- /* the source or destination are of an unknown datum type */
- /* (ie. only a +ellps declaration, no +datum). This is new */
- /* behavior for PROJ 4.6.0. */
- /* -------------------------------------------------------------------- */
- if( srcdefn.datum_type == datum_unknown
- || dstdefn.datum_type == datum_unknown )
- return result;
- /* -------------------------------------------------------------------- */
- /* Short cut if the datums are identical. */
- /* -------------------------------------------------------------------- */
- if( pj_compare_datums( srcdefn, dstdefn ) )
- return result;
- src_a = srcdefn.a_orig;
- src_es = srcdefn.es_orig;
- dst_a = dstdefn.a_orig;
- dst_es = dstdefn.es_orig;
- /* -------------------------------------------------------------------- */
- /* Create a temporary Z array if one is not provided. */
- /* -------------------------------------------------------------------- */
- range_wrapper<Range> z_range(range);
- /* -------------------------------------------------------------------- */
- /* If this datum requires grid shifts, then apply it to geodetic */
- /* coordinates. */
- /* -------------------------------------------------------------------- */
- if( srcdefn.datum_type == datum_gridshift )
- {
- try {
- pj_apply_gridshift_2<false>( srcdefn, range, srcgrids );
- } catch (projection_exception const& e) {
- if (pj_datum_check_error(e.code())) {
- BOOST_RETHROW
- }
- }
- src_a = wgs84_a;
- src_es = wgs84_es;
- }
- if( dstdefn.datum_type == datum_gridshift )
- {
- dst_a = wgs84_a;
- dst_es = wgs84_es;
- }
- /* ==================================================================== */
- /* Do we need to go through geocentric coordinates? */
- /* ==================================================================== */
- if( src_es != dst_es || src_a != dst_a
- || srcdefn.datum_type == datum_3param
- || srcdefn.datum_type == datum_7param
- || dstdefn.datum_type == datum_3param
- || dstdefn.datum_type == datum_7param)
- {
- /* -------------------------------------------------------------------- */
- /* Convert to geocentric coordinates. */
- /* -------------------------------------------------------------------- */
- int err = pj_geodetic_to_geocentric( src_a, src_es, z_range );
- if (pj_datum_check_error(err))
- BOOST_THROW_EXCEPTION( projection_exception(err) );
- else if (err != 0)
- result = false;
- /* -------------------------------------------------------------------- */
- /* Convert between datums. */
- /* -------------------------------------------------------------------- */
- if( srcdefn.datum_type == datum_3param
- || srcdefn.datum_type == datum_7param )
- {
- try {
- pj_geocentric_to_wgs84( srcdefn, z_range );
- } catch (projection_exception const& e) {
- if (pj_datum_check_error(e.code())) {
- BOOST_RETHROW
- }
- }
- }
- if( dstdefn.datum_type == datum_3param
- || dstdefn.datum_type == datum_7param )
- {
- try {
- pj_geocentric_from_wgs84( dstdefn, z_range );
- } catch (projection_exception const& e) {
- if (pj_datum_check_error(e.code())) {
- BOOST_RETHROW
- }
- }
- }
- /* -------------------------------------------------------------------- */
- /* Convert back to geodetic coordinates. */
- /* -------------------------------------------------------------------- */
- err = pj_geocentric_to_geodetic( dst_a, dst_es, z_range );
- if (pj_datum_check_error(err))
- BOOST_THROW_EXCEPTION( projection_exception(err) );
- else if (err != 0)
- result = false;
- }
- /* -------------------------------------------------------------------- */
- /* Apply grid shift to destination if required. */
- /* -------------------------------------------------------------------- */
- if( dstdefn.datum_type == datum_gridshift )
- {
- try {
- pj_apply_gridshift_2<true>( dstdefn, range, dstgrids );
- } catch (projection_exception const& e) {
- if (pj_datum_check_error(e.code()))
- BOOST_RETHROW
- }
- }
- return result;
- }
- } // namespace detail
- }}} // namespace boost::geometry::projections
- #endif // BOOST_GEOMETRY_SRS_PROJECTIONS_IMPL_PJ_TRANSFORM_HPP
|