1 // Boost.Geometry (aka GGL, Generic Geometry Library)
2 // This file is manually converted from PROJ4
4 // Copyright (c) 2008-2012 Barend Gehrels, Amsterdam, the Netherlands.
6 // This file was modified by Oracle on 2017, 2018, 2019.
7 // Modifications copyright (c) 2017-2019, Oracle and/or its affiliates.
8 // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
10 // Use, modification and distribution is subject to the Boost Software License,
11 // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
12 // http://www.boost.org/LICENSE_1_0.txt)
14 // This file is converted from PROJ4, http://trac.osgeo.org/proj
15 // PROJ4 is originally written by Gerald Evenden (then of the USGS)
16 // PROJ4 is maintained by Frank Warmerdam
17 // PROJ4 is converted to Geometry Library by Barend Gehrels (Geodan, Amsterdam)
19 // Original copyright notice:
21 // Permission is hereby granted, free of charge, to any person obtaining a
22 // copy of this software and associated documentation files (the "Software"),
23 // to deal in the Software without restriction, including without limitation
24 // the rights to use, copy, modify, merge, publish, distribute, sublicense,
25 // and/or sell copies of the Software, and to permit persons to whom the
26 // Software is furnished to do so, subject to the following conditions:
28 // The above copyright notice and this permission notice shall be included
29 // in all copies or substantial portions of the Software.
31 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
32 // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
33 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
34 // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
35 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
36 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
37 // DEALINGS IN THE SOFTWARE.
39 #ifndef BOOST_GEOMETRY_PROJECTIONS_IMPL_PJ_DATUM_SET_HPP
40 #define BOOST_GEOMETRY_PROJECTIONS_IMPL_PJ_DATUM_SET_HPP
46 #include <boost/algorithm/string.hpp>
48 #include <boost/geometry/srs/projections/dpar.hpp>
49 #include <boost/geometry/srs/projections/exception.hpp>
50 #include <boost/geometry/srs/projections/impl/projects.hpp>
51 #include <boost/geometry/srs/projections/impl/pj_datums.hpp>
52 #include <boost/geometry/srs/projections/impl/pj_param.hpp>
53 #include <boost/geometry/srs/projections/proj4.hpp>
54 #include <boost/geometry/srs/projections/spar.hpp>
57 namespace boost { namespace geometry { namespace projections {
62 /* SEC_TO_RAD = Pi/180/3600 */
64 inline T sec_to_rad() { return 4.84813681109535993589914102357e-6; }
66 /************************************************************************/
67 /* pj_datum_find_datum() */
68 /************************************************************************/
71 inline const pj_datums_type<T>* pj_datum_find_datum(srs::detail::proj4_parameters const& params)
73 std::string name = pj_get_param_s(params, "datum");
76 /* find the datum definition */
77 const pj_datums_type<T>* pj_datums = pj_get_datums<T>().first;
78 const int n = pj_get_datums<T>().second;
80 for (int i = 0; i < n && index == -1; i++)
82 if(pj_datums[i].id == name)
90 return pj_datums + index;
94 BOOST_THROW_EXCEPTION( projection_exception(error_unknown_ellp_param) );
101 template <typename T>
102 inline const pj_datums_type<T>* pj_datum_find_datum(srs::dpar::parameters<T> const& params)
104 typename srs::dpar::parameters<T>::const_iterator
105 it = pj_param_find(params, srs::dpar::datum);
107 if (it != params.end())
109 const pj_datums_type<T>* pj_datums = pj_get_datums<T>().first;
110 const int n = pj_get_datums<T>().second;
111 int i = it->template get_value<int>();
114 return pj_datums + i;
118 BOOST_THROW_EXCEPTION( projection_exception(error_unknown_ellp_param) );
128 typename Param = typename srs::spar::detail::tuples_find_if
131 srs::spar::detail::is_param_tr<srs::spar::detail::datum_traits>::pred
133 bool IsFound = srs::spar::detail::tuples_is_found<Param>::value
135 struct pj_datum_find_datum_static
137 template <typename T>
138 static const pj_datums_type<T>* apply(Params const& )
140 const pj_datums_type<T>* pj_datums = pj_get_datums<T>().first;
141 const int n = pj_get_datums<T>().second;
142 const int i = srs::spar::detail::datum_traits<Param>::id;
145 return pj_datums + i;
149 // TODO: Implemnt as MPL_ASSERT instead
150 BOOST_THROW_EXCEPTION( projection_exception(error_unknown_ellp_param) );
154 template <typename Params, typename Param>
155 struct pj_datum_find_datum_static<Params, Param, false>
157 template <typename T>
158 static const pj_datums_type<T>* apply(Params const& )
164 template <typename T, BOOST_GEOMETRY_PROJECTIONS_DETAIL_TYPENAME_PX>
165 inline const pj_datums_type<T>* pj_datum_find_datum(srs::spar::parameters<BOOST_GEOMETRY_PROJECTIONS_DETAIL_PX> const& params)
167 return pj_datum_find_datum_static
169 srs::spar::parameters<BOOST_GEOMETRY_PROJECTIONS_DETAIL_PX>
170 >::template apply<T>(params);
173 /************************************************************************/
174 /* pj_datum_find_nadgrids() */
175 /************************************************************************/
177 inline bool pj_datum_find_nadgrids(srs::detail::proj4_parameters const& params,
178 srs::detail::nadgrids & out)
180 std::string snadgrids = pj_get_param_s(params, "nadgrids");
181 if (! snadgrids.empty())
183 for (std::string::size_type i = 0 ; i < snadgrids.size() ; )
185 std::string::size_type end = snadgrids.find(',', i);
186 std::string name = snadgrids.substr(i, end - i);
189 if (end != std::string::npos)
197 return ! out.empty();
200 template <typename T>
201 inline bool pj_datum_find_nadgrids(srs::dpar::parameters<T> const& params,
202 srs::detail::nadgrids & out)
204 typename srs::dpar::parameters<T>::const_iterator
205 it = pj_param_find(params, srs::dpar::nadgrids);
206 if (it != params.end())
208 out = it->template get_value<srs::detail::nadgrids>();
211 return ! out.empty();
217 int I = srs::spar::detail::tuples_find_index_if
220 srs::spar::detail::is_param<srs::spar::nadgrids>::pred
222 int N = boost::tuples::length<Params>::value
224 struct pj_datum_find_nadgrids_static
226 static void apply(Params const& params, srs::detail::nadgrids & out)
228 out = boost::tuples::get<I>(params);
231 template <typename Params, int N>
232 struct pj_datum_find_nadgrids_static<Params, N, N>
234 static void apply(Params const& , srs::detail::nadgrids & )
238 template <BOOST_GEOMETRY_PROJECTIONS_DETAIL_TYPENAME_PX>
239 inline bool pj_datum_find_nadgrids(srs::spar::parameters<BOOST_GEOMETRY_PROJECTIONS_DETAIL_PX> const& params,
240 srs::detail::nadgrids & out)
242 pj_datum_find_nadgrids_static
244 srs::spar::parameters<BOOST_GEOMETRY_PROJECTIONS_DETAIL_PX>
245 >::apply(params, out);
247 return ! out.empty();
250 /************************************************************************/
251 /* pj_datum_find_towgs84() */
252 /************************************************************************/
254 template <typename T>
255 inline bool pj_datum_find_towgs84(srs::detail::proj4_parameters const& params,
256 srs::detail::towgs84<T> & out)
258 std::string towgs84 = pj_get_param_s(params, "towgs84");
259 if(! towgs84.empty())
261 std::vector<std::string> parm;
262 boost::split(parm, towgs84, boost::is_any_of(" ,"));
264 std::size_t n = (std::min<std::size_t>)(parm.size(), 7);
265 std::size_t z = n <= 3 ? 3 : 7;
267 /* parse out the pvalues */
268 for (std::size_t i = 0 ; i < n; ++i)
270 out.push_back(geometry::str_cast<T>(parm[i]));
272 for (std::size_t i = out.size() ; i < z; ++i)
278 return ! out.empty();
281 template <typename T>
282 inline bool pj_datum_find_towgs84(srs::dpar::parameters<T> const& params,
283 srs::detail::towgs84<T> & out)
285 typename srs::dpar::parameters<T>::const_iterator
286 it = pj_param_find(params, srs::dpar::towgs84);
288 if (it != params.end())
290 srs::detail::towgs84<T> const&
291 towgs84 = it->template get_value<srs::detail::towgs84<T> >();
293 std::size_t n = (std::min<std::size_t>)(towgs84.size(), 7u);
294 std::size_t z = n <= 3 ? 3 : 7;
296 for (std::size_t i = 0 ; i < n; ++i)
298 out.push_back(towgs84[i]);
300 for (std::size_t i = out.size() ; i < z; ++i)
306 return ! out.empty();
312 int I = srs::spar::detail::tuples_find_index_if
315 srs::spar::detail::is_param_t<srs::spar::towgs84>::pred
317 int N = boost::tuples::length<Params>::value
319 struct pj_datum_find_towgs84_static
321 template <typename T>
322 static void apply(Params const& params, srs::detail::towgs84<T> & out)
324 typename boost::tuples::element<I, Params>::type const&
325 towgs84 = boost::tuples::get<I>(params);
327 std::size_t n = (std::min<std::size_t>)(towgs84.size(), 7u);
328 std::size_t z = n <= 3 ? 3 : 7;
330 for (std::size_t i = 0 ; i < n; ++i)
332 out.push_back(towgs84[i]);
334 for (std::size_t i = out.size() ; i < z; ++i)
340 template <typename Params, int N>
341 struct pj_datum_find_towgs84_static<Params, N, N>
343 template <typename T>
344 static void apply(Params const& , srs::detail::towgs84<T> & )
348 template <typename T, BOOST_GEOMETRY_PROJECTIONS_DETAIL_TYPENAME_PX>
349 inline bool pj_datum_find_towgs84(srs::spar::parameters<BOOST_GEOMETRY_PROJECTIONS_DETAIL_PX> const& params,
350 srs::detail::towgs84<T> & out)
352 pj_datum_find_towgs84_static
354 srs::spar::parameters<BOOST_GEOMETRY_PROJECTIONS_DETAIL_PX>
355 >::apply(params, out);
357 return ! out.empty();
360 /************************************************************************/
361 /* pj_datum_prepare_towgs84() */
362 /************************************************************************/
364 template <typename T>
365 inline bool pj_datum_prepare_towgs84(srs::detail::towgs84<T> & towgs84)
367 if( towgs84.size() == 7
368 && (towgs84[3] != 0.0
371 || towgs84[6] != 0.0) )
373 static const T sec_to_rad = detail::sec_to_rad<T>();
375 /* transform from arc seconds to radians */
376 towgs84[3] *= sec_to_rad;
377 towgs84[4] *= sec_to_rad;
378 towgs84[5] *= sec_to_rad;
379 /* transform from parts per million to scaling factor */
380 towgs84[6] = (towgs84[6]/1000000.0) + 1;
389 /************************************************************************/
390 /* pj_datum_init() */
391 /************************************************************************/
393 // This function works differently than the original pj_datum_set().
394 // It doesn't push parameters defined in datum into params list.
395 // Instead it tries to use nadgrids and towgs84 and only then
396 // falls back to nadgrid or towgs84 defiend in datum parameter.
397 template <typename Params, typename T>
398 inline void pj_datum_init(Params const& params, parameters<T> & projdef)
400 projdef.datum_type = datum_unknown;
402 // Check for nadgrids parameter.
403 if(pj_datum_find_nadgrids(params, projdef.nadgrids))
405 // NOTE: It's different than in the original proj4.
406 // Nadgrids names are stored in projection definition.
408 projdef.datum_type = datum_gridshift;
410 // Check for towgs84 parameter.
411 else if(pj_datum_find_towgs84(params, projdef.datum_params))
413 if (pj_datum_prepare_towgs84(projdef.datum_params))
415 projdef.datum_type = datum_7param;
419 projdef.datum_type = datum_3param;
422 /* Note that pj_init() will later switch datum_type to
423 PJD_WGS84 if shifts are all zero, and ellipsoid is WGS84 or GRS80 */
425 // Check for datum parameter.
428 const pj_datums_type<T>* datum = pj_datum_find_datum<T>(params);
431 if (! datum->nadgrids.empty())
433 projdef.nadgrids = datum->nadgrids;
434 projdef.datum_type = datum_gridshift;
436 else if ( ! datum->towgs84.empty() )
438 projdef.datum_params = datum->towgs84;
439 if (pj_datum_prepare_towgs84(projdef.datum_params))
441 projdef.datum_type = datum_7param;
445 projdef.datum_type = datum_3param;
452 } // namespace detail
453 }}} // namespace boost::geometry::projections
455 #endif // BOOST_GEOMETRY_PROJECTIONS_IMPL_PJ_DATUM_SET_HPP