diff options
Diffstat (limited to 'boost/geometry/srs/projections/impl/pj_init.hpp')
-rw-r--r-- | boost/geometry/srs/projections/impl/pj_init.hpp | 494 |
1 files changed, 313 insertions, 181 deletions
diff --git a/boost/geometry/srs/projections/impl/pj_init.hpp b/boost/geometry/srs/projections/impl/pj_init.hpp index 1d2db1af24..28b2b5850d 100644 --- a/boost/geometry/srs/projections/impl/pj_init.hpp +++ b/boost/geometry/srs/projections/impl/pj_init.hpp @@ -44,12 +44,15 @@ #include <vector> #include <boost/algorithm/string.hpp> +#include <boost/mpl/find.hpp> +#include <boost/mpl/if.hpp> #include <boost/range.hpp> #include <boost/type_traits/is_same.hpp> #include <boost/geometry/util/math.hpp> #include <boost/geometry/util/condition.hpp> +#include <boost/geometry/srs/projections/dpar.hpp> #include <boost/geometry/srs/projections/impl/dms_parser.hpp> #include <boost/geometry/srs/projections/impl/pj_datum_set.hpp> #include <boost/geometry/srs/projections/impl/pj_datums.hpp> @@ -58,6 +61,7 @@ #include <boost/geometry/srs/projections/impl/pj_units.hpp> #include <boost/geometry/srs/projections/impl/projects.hpp> #include <boost/geometry/srs/projections/proj4.hpp> +#include <boost/geometry/srs/projections/spar.hpp> namespace boost { namespace geometry { namespace projections @@ -67,70 +71,62 @@ namespace boost { namespace geometry { namespace projections namespace detail { -template <typename BGParams, typename T> -inline void pj_push_defaults(BGParams const& /*bg_params*/, parameters<T>& pin) +/************************************************************************/ +/* pj_init_proj() */ +/************************************************************************/ + +template <typename T> +inline void pj_init_proj(srs::detail::proj4_parameters const& params, + parameters<T> & par) { - pin.params.push_back(pj_mkparam<T>("ellps", "WGS84")); + par.id = pj_get_param_s(params, "proj"); +} - if (pin.name == "aea") - { - pin.params.push_back(pj_mkparam<T>("lat_1", "29.5")); - pin.params.push_back(pj_mkparam<T>("lat_2", "45.5 ")); - } - else if (pin.name == "lcc") - { - pin.params.push_back(pj_mkparam<T>("lat_1", "33")); - pin.params.push_back(pj_mkparam<T>("lat_2", "45")); - } - else if (pin.name == "lagrng") +template <typename T> +inline void pj_init_proj(srs::dpar::parameters<T> const& params, + parameters<T> & par) +{ + typename srs::dpar::parameters<T>::const_iterator it = pj_param_find(params, srs::dpar::proj); + if (it != params.end()) { - pin.params.push_back(pj_mkparam<T>("W", "2")); + par.id = static_cast<srs::dpar::value_proj>(it->template get_value<int>()); } } -template <BOOST_GEOMETRY_PROJECTIONS_DETAIL_TYPENAME_PX, typename T> -inline void pj_push_defaults(srs::static_proj4<BOOST_GEOMETRY_PROJECTIONS_DETAIL_PX> const& /*bg_params*/, - parameters<T>& pin) +template <typename T, BOOST_GEOMETRY_PROJECTIONS_DETAIL_TYPENAME_PX> +inline void pj_init_proj(srs::spar::parameters<BOOST_GEOMETRY_PROJECTIONS_DETAIL_PX> const& , + parameters<T> & par) { - typedef srs::static_proj4<BOOST_GEOMETRY_PROJECTIONS_DETAIL_PX> static_parameters_type; - typedef typename srs::par4::detail::pick_proj_tag + typedef srs::spar::parameters<BOOST_GEOMETRY_PROJECTIONS_DETAIL_PX> params_type; + typedef typename srs::spar::detail::tuples_find_if < - static_parameters_type - >::type proj_tag; + params_type, + srs::spar::detail::is_param_tr<srs::spar::detail::proj_traits>::pred + >::type proj_type; - // statically defaulting to WGS84 - //pin.params.push_back(pj_mkparam("ellps", "WGS84")); + static const bool is_found = srs::spar::detail::tuples_is_found<proj_type>::value; - if (BOOST_GEOMETRY_CONDITION((boost::is_same<proj_tag, srs::par4::aea>::value))) - { - pin.params.push_back(pj_mkparam<T>("lat_1", "29.5")); - pin.params.push_back(pj_mkparam<T>("lat_2", "45.5 ")); - } - else if (BOOST_GEOMETRY_CONDITION((boost::is_same<proj_tag, srs::par4::lcc>::value))) - { - pin.params.push_back(pj_mkparam<T>("lat_1", "33")); - pin.params.push_back(pj_mkparam<T>("lat_2", "45")); - } - else if (BOOST_GEOMETRY_CONDITION((boost::is_same<proj_tag, srs::par4::lagrng>::value))) - { - pin.params.push_back(pj_mkparam<T>("W", "2")); - } + BOOST_MPL_ASSERT_MSG((is_found), PROJECTION_NOT_NAMED, (params_type)); + + par.id = srs::spar::detail::proj_traits<proj_type>::id; } -template <typename T> -inline void pj_init_units(std::vector<pvalue<T> > const& params, - std::string const& sunits, - std::string const& sto_meter, +/************************************************************************/ +/* pj_init_units() */ +/************************************************************************/ + +template <typename T, bool Vertical> +inline void pj_init_units(srs::detail::proj4_parameters const& params, T & to_meter, T & fr_meter, T const& default_to_meter, T const& default_fr_meter) { std::string s; - std::string units = pj_get_param_s(params, sunits); + std::string units = pj_get_param_s(params, Vertical ? "vunits" : "units"); if (! units.empty()) { - const int n = sizeof(pj_units) / sizeof(pj_units[0]); + static const int n = sizeof(pj_units) / sizeof(pj_units[0]); int index = -1; for (int i = 0; i < n && index == -1; i++) { @@ -148,9 +144,10 @@ inline void pj_init_units(std::vector<pvalue<T> > const& params, if (s.empty()) { - s = pj_get_param_s(params, sto_meter); + s = pj_get_param_s(params, Vertical ? "vto_meter" : "to_meter"); } + // TODO: numerator and denominator could be taken from pj_units if (! s.empty()) { std::size_t const pos = s.find('/'); @@ -181,63 +178,283 @@ inline void pj_init_units(std::vector<pvalue<T> > const& params, } } +template <typename T, bool Vertical> +inline void pj_init_units(srs::dpar::parameters<T> const& params, + T & to_meter, + T & fr_meter, + T const& default_to_meter, + T const& default_fr_meter) +{ + typename srs::dpar::parameters<T>::const_iterator + it = pj_param_find(params, Vertical ? srs::dpar::vunits : srs::dpar::units); + if (it != params.end()) + { + static const int n = sizeof(pj_units) / sizeof(pj_units[0]); + const int i = it->template get_value<int>(); + if (i >= 0 && i < n) + { + T const numerator = pj_units[i].numerator; + T const denominator = pj_units[i].denominator; + if (numerator == 0.0 || denominator == 0.0) + { + BOOST_THROW_EXCEPTION( projection_exception(error_unit_factor_less_than_0) ); + } + to_meter = numerator / denominator; + fr_meter = 1. / to_meter; + } + else + { + BOOST_THROW_EXCEPTION( projection_exception(error_unknow_unit_id) ); + } + } + else + { + it = pj_param_find(params, Vertical ? srs::dpar::vto_meter : srs::dpar::to_meter); + if (it != params.end()) + { + to_meter = it->template get_value<T>(); + fr_meter = 1. / to_meter; + } + else + { + to_meter = default_to_meter; + fr_meter = default_fr_meter; + } + } +} + +template +< + typename Params, + bool Vertical, + int UnitsI = srs::spar::detail::tuples_find_index_if + < + Params, + boost::mpl::if_c + < + Vertical, + srs::spar::detail::is_param_t<srs::spar::vunits>, + srs::spar::detail::is_param_tr<srs::spar::detail::units_traits> + >::type::template pred + >::value, + int ToMeterI = srs::spar::detail::tuples_find_index_if + < + Params, + boost::mpl::if_c + < + Vertical, + srs::spar::detail::is_param_t<srs::spar::vto_meter>, + srs::spar::detail::is_param_t<srs::spar::to_meter> + >::type::template pred + >::value, + int N = boost::tuples::length<Params>::value +> +struct pj_init_units_static + : pj_init_units_static<Params, Vertical, UnitsI, N, N> +{}; + +template <typename Params, bool Vertical, int UnitsI, int N> +struct pj_init_units_static<Params, Vertical, UnitsI, N, N> +{ + static const int n = sizeof(pj_units) / sizeof(pj_units[0]); + static const int i = srs::spar::detail::units_traits + < + typename boost::tuples::element<UnitsI, Params>::type + >::id; + static const bool is_valid = i >= 0 && i < n; + + BOOST_MPL_ASSERT_MSG((is_valid), UNKNOWN_UNIT_ID, (Params)); + + template <typename T> + static void apply(Params const& , + T & to_meter, T & fr_meter, + T const& , T const& ) + { + T const numerator = pj_units[i].numerator; + T const denominator = pj_units[i].denominator; + if (numerator == 0.0 || denominator == 0.0) + { + BOOST_THROW_EXCEPTION( projection_exception(error_unit_factor_less_than_0) ); + } + to_meter = numerator / denominator; + fr_meter = 1. / to_meter; + } +}; + +template <typename Params, bool Vertical, int ToMeterI, int N> +struct pj_init_units_static<Params, Vertical, N, ToMeterI, N> +{ + template <typename T> + static void apply(Params const& params, + T & to_meter, T & fr_meter, + T const& , T const& ) + { + to_meter = boost::tuples::get<ToMeterI>(params).value; + fr_meter = 1. / to_meter; + } +}; + +template <typename Params, bool Vertical, int N> +struct pj_init_units_static<Params, Vertical, N, N, N> +{ + template <typename T> + static void apply(Params const& , + T & to_meter, T & fr_meter, + T const& default_to_meter, T const& default_fr_meter) + { + to_meter = default_to_meter; + fr_meter = default_fr_meter; + } +}; + +template <typename T, bool Vertical, BOOST_GEOMETRY_PROJECTIONS_DETAIL_TYPENAME_PX> +inline void pj_init_units(srs::spar::parameters<BOOST_GEOMETRY_PROJECTIONS_DETAIL_PX> const& params, + T & to_meter, + T & fr_meter, + T const& default_to_meter, + T const& default_fr_meter) +{ + pj_init_units_static + < + srs::spar::parameters<BOOST_GEOMETRY_PROJECTIONS_DETAIL_PX>, + Vertical + >::apply(params, to_meter, fr_meter, default_to_meter, default_fr_meter); +} + +/************************************************************************/ +/* pj_init_pm() */ +/************************************************************************/ + +template <typename T> +inline void pj_init_pm(srs::detail::proj4_parameters const& params, T& val) +{ + std::string pm = pj_get_param_s(params, "pm"); + if (! pm.empty()) + { + int n = sizeof(pj_prime_meridians) / sizeof(pj_prime_meridians[0]); + for (int i = 0; i < n ; i++) + { + if(pj_prime_meridians[i].id == pm) + { + val = pj_prime_meridians[i].deg * math::d2r<T>(); + return; + } + } + + // TODO: Is this try-catch needed? + // In other cases the bad_str_cast exception is simply thrown + BOOST_TRY + { + val = dms_parser<T, true>::apply(pm).angle(); + return; + } + BOOST_CATCH(geometry::bad_str_cast const&) + { + BOOST_THROW_EXCEPTION( projection_exception(error_unknown_prime_meridian) ); + } + BOOST_CATCH_END + } + + val = 0.0; +} + +template <typename T> +inline void pj_init_pm(srs::dpar::parameters<T> const& params, T& val) +{ + typename srs::dpar::parameters<T>::const_iterator it = pj_param_find(params, srs::dpar::pm); + if (it != params.end()) + { + if (it->template is_value_set<int>()) + { + int n = sizeof(pj_prime_meridians) / sizeof(pj_prime_meridians[0]); + int i = it->template get_value<int>(); + if (i >= 0 && i < n) + { + val = pj_prime_meridians[i].deg * math::d2r<T>(); + return; + } + else + { + BOOST_THROW_EXCEPTION( projection_exception(error_unknown_prime_meridian) ); + } + } + else if (it->template is_value_set<T>()) + { + val = it->template get_value<T>() * math::d2r<T>(); + return; + } + } + + val = 0.0; +} + +template +< + typename Params, + int I = srs::spar::detail::tuples_find_index_if + < + Params, + srs::spar::detail::is_param_tr<srs::spar::detail::pm_traits>::pred + >::value, + int N = boost::tuples::length<Params>::value +> +struct pj_init_pm_static +{ + template <typename T> + static void apply(Params const& params, T & val) + { + typedef typename boost::tuples::element<I, Params>::type param_type; + + val = srs::spar::detail::pm_traits<param_type>::value(boost::tuples::get<I>(params)); + } +}; +template <typename Params, int N> +struct pj_init_pm_static<Params, N, N> +{ + template <typename T> + static void apply(Params const& , T & val) + { + val = 0; + } +}; + +template <typename T, BOOST_GEOMETRY_PROJECTIONS_DETAIL_TYPENAME_PX> +inline void pj_init_pm(srs::spar::parameters<BOOST_GEOMETRY_PROJECTIONS_DETAIL_PX> const& params, T& val) +{ + pj_init_pm_static + < + srs::spar::parameters<BOOST_GEOMETRY_PROJECTIONS_DETAIL_PX> + >::apply(params, val); +} + /************************************************************************/ /* pj_init() */ /* */ /* Main entry point for initialing a PJ projections */ -/* definition. Note that the projection specific function is */ -/* called to do the initial allocation so it can be created */ -/* large enough to hold projection specific parameters. */ +/* definition. */ /************************************************************************/ -template <typename T, typename BGParams, typename R> -inline parameters<T> pj_init(BGParams const& bg_params, R const& arguments, bool use_defaults = true) +template <typename T, typename Params> +inline parameters<T> pj_init(Params const& params) { parameters<T> pin; - for (std::vector<std::string>::const_iterator it = boost::begin(arguments); - it != boost::end(arguments); it++) - { - pin.params.push_back(pj_mkparam<T>(*it)); - } - - // maybe TODO: handle "init" parameter - /* check if +init present */ - //std::string sinit; - //if (pj_param_s(pin.params, "init", sinit)) - //{ - // //if (!(curr = get_init(&arguments, curr, sinit))) - //} // find projection -> implemented in projection factory - pin.name = pj_get_param_s(pin.params, "proj"); + pj_init_proj(params, pin); // exception thrown in projection<> // TODO: consider throwing here both projection_unknown_id_exception and // projection_not_named_exception in order to throw before other exceptions //if (pin.name.empty()) //{ BOOST_THROW_EXCEPTION( projection_not_named_exception() ); } - // set defaults, unless inhibited - // GL-Addition, if use_defaults is false then defaults are ignored - if (use_defaults && ! pj_get_param_b(pin.params, "no_defs")) - { - // proj4 gets defaults from "proj_def.dat", file of 94/02/23 with a few defaults. - // Here manually - pj_push_defaults(bg_params, pin); - //curr = get_defaults(&arguments, curr, name); - } - - /* allocate projection structure */ - // done by BGParams constructor: - // pin.is_latlong = 0; - // pin.is_geocent = 0; - // pin.long_wrap_center = 0.0; - // pin.long_wrap_center = 0.0; - pin.is_long_wrap_set = false; - + // NOTE: proj4 gets defaults from "proj_def.dat". + // In Boost.Geometry this is emulated by manually setting them in + // pj_ell_init and projections aea, lcc and lagrng + /* set datum parameters */ - pj_datum_set(bg_params, pin.params, pin); + pj_datum_init(params, pin); /* set ellipsoid/sphere parameters */ - pj_ell_set(bg_params, pin.params, pin.a, pin.es); + pj_ell_init(params, pin.a, pin.es); pin.a_orig = pin.a; pin.es_orig = pin.es; @@ -262,28 +479,28 @@ inline parameters<T> pj_init(BGParams const& bg_params, R const& arguments, bool } /* set pin.geoc coordinate system */ - pin.geoc = (pin.es && pj_get_param_b(pin.params, "geoc")); + pin.geoc = (pin.es && pj_get_param_b<srs::spar::geoc>(params, "geoc", srs::dpar::geoc)); /* over-ranging flag */ - pin.over = pj_get_param_b(pin.params, "over"); + pin.over = pj_get_param_b<srs::spar::over>(params, "over", srs::dpar::over); /* longitude center for wrapping */ - pin.is_long_wrap_set = pj_param_r(pin.params, "lon_wrap", pin.long_wrap_center); + pin.is_long_wrap_set = pj_param_r<srs::spar::lon_wrap>(params, "lon_wrap", srs::dpar::lon_wrap, pin.long_wrap_center); /* central meridian */ - pin.lam0 = pj_get_param_r(pin.params, "lon_0"); + pin.lam0 = pj_get_param_r<T, srs::spar::lon_0>(params, "lon_0", srs::dpar::lon_0); /* central latitude */ - pin.phi0 = pj_get_param_r(pin.params, "lat_0"); + pin.phi0 = pj_get_param_r<T, srs::spar::lat_0>(params, "lat_0", srs::dpar::lat_0); /* false easting and northing */ - pin.x0 = pj_get_param_f(pin.params, "x_0"); - pin.y0 = pj_get_param_f(pin.params, "y_0"); + pin.x0 = pj_get_param_f<T, srs::spar::x_0>(params, "x_0", srs::dpar::x_0); + pin.y0 = pj_get_param_f<T, srs::spar::y_0>(params, "y_0", srs::dpar::y_0); /* general scaling factor */ - if (pj_param_f(pin.params, "k_0", pin.k0)) { + if (pj_param_f<srs::spar::k_0>(params, "k_0", srs::dpar::k_0, pin.k0)) { /* empty */ - } else if (pj_param_f(pin.params, "k", pin.k0)) { + } else if (pj_param_f<srs::spar::k>(params, "k", srs::dpar::k, pin.k0)) { /* empty */ } else pin.k0 = 1.; @@ -292,100 +509,15 @@ inline parameters<T> pj_init(BGParams const& bg_params, R const& arguments, bool } /* set units */ - pj_init_units(pin.params, "units", "to_meter", - pin.to_meter, pin.fr_meter, 1., 1.); - pj_init_units(pin.params, "vunits", "vto_meter", - pin.vto_meter, pin.vfr_meter, pin.to_meter, pin.fr_meter); + pj_init_units<T, false>(params, pin.to_meter, pin.fr_meter, 1., 1.); + pj_init_units<T, true>(params, pin.vto_meter, pin.vfr_meter, pin.to_meter, pin.fr_meter); /* prime meridian */ - std::string pm = pj_get_param_s(pin.params, "pm"); - if (! pm.empty()) - { - std::string value; - - int n = sizeof(pj_prime_meridians) / sizeof(pj_prime_meridians[0]); - for (int i = 0; i < n ; i++) - { - if(pj_prime_meridians[i].id == pm) - { - value = pj_prime_meridians[i].defn; - break; - } - } - - dms_parser<T, true> parser; - - // TODO: Is this try-catch needed? - // In other cases the bad_str_cast exception is simply thrown - BOOST_TRY - { - if (value.empty()) { - pin.from_greenwich = parser.apply(pm).angle(); - } else { - pin.from_greenwich = parser.apply(value).angle(); - } - } - BOOST_CATCH(geometry::bad_str_cast const&) - { - BOOST_THROW_EXCEPTION( projection_exception(error_unknown_prime_meridian) ); - } - BOOST_CATCH_END - } - else - { - pin.from_greenwich = 0.0; - } + pj_init_pm(params, pin.from_greenwich); return pin; } -/************************************************************************/ -/* pj_init_plus() */ -/* */ -/* Same as pj_init() except it takes one argument string with */ -/* individual arguments preceeded by '+', such as "+proj=utm */ -/* +zone=11 +ellps=WGS84". */ -/************************************************************************/ -template <typename T, typename BGParams> -inline parameters<T> pj_init_plus(BGParams const& bg_params, std::string const& definition, bool use_defaults = true) -{ - const char* sep = " +"; - - /* split into arguments based on '+' and trim white space */ - - // boost::split splits on one character, here it should be on " +", so implementation below - // todo: put in different routine or sort out - std::vector<std::string> arguments; - std::string def = boost::trim_copy(definition); - boost::trim_left_if(def, boost::is_any_of(sep)); - - std::string::size_type loc = def.find(sep); - while (loc != std::string::npos) - { - std::string par = def.substr(0, loc); - boost::trim(par); - if (! par.empty()) - { - arguments.push_back(par); - } - - def.erase(0, loc); - boost::trim_left_if(def, boost::is_any_of(sep)); - loc = def.find(sep); - } - - if (! def.empty()) - { - arguments.push_back(def); - } - - /*boost::split(arguments, definition, boost::is_any_of("+")); - for (std::vector<std::string>::iterator it = arguments.begin(); it != arguments.end(); it++) - { - boost::trim(*it); - }*/ - return pj_init<T>(bg_params, arguments, use_defaults); -} } // namespace detail }}} // namespace boost::geometry::projections |