A venture into variadic templates for strategies and transforms.

This commit is contained in:
Blake Thompson 2015-04-16 23:37:20 -05:00
parent a19da799e0
commit 75ccfdf934
5 changed files with 195 additions and 0 deletions

View file

@ -0,0 +1,69 @@
/*****************************************************************************
*
* This file is part of Mapnik (c++ mapping toolkit)
*
* Copyright (C) 2015 Artem Pavlenko
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
*****************************************************************************/
#ifndef MAPNIK_GEOMETRY_STRATEGY_HPP
#define MAPNIK_GEOMETRY_STRATEGY_HPP
namespace mapnik {
namespace geometry {
template <typename Strategy, typename... Strategies>
struct strategy_group
{
strategy_group(Strategy const& op, Strategies const& ... ops)
: ops_(op, ops ...) {}
template <typename P1, typename P2>
inline bool apply(P1 const& p1, P2 & p2) const
{
bool status = true;
p2 = execute_first<0, P1, P2, Strategy, ...Strategies>(p1, status);
return status;
}
template <int c, typename P1, typename P2, typename T, typename ...Args>
inline P2 execute_first(P1 const& p, bool & status)
{
return execute_next<c+1,P1,P2,...Args>(std::get<c>(ops_).template execute<P1,P2>(p, status), status);
}
template <int c, typename P2, typename T, typename ...Args>
inline P2 execute_next(P2 const& p, bool & status)
{
return execute_next<c+1, P2, ...Args>(std::get<c>(ops_).template execute<P2,P2>(p, status), status);
}
template <int c, typename P2, typename T>
inline P2 execute_next(P2 const& p, bool & status)
{
return std::get<c>(ops_).template execute<P2,P2>(p, status);
}
private:
std::tuple<Strategy const&, Strategies const& ...> ops_;
};
} // end geometry ns
} // end mapnik ns
#endif //MAPNIK_GEOMETRY_STRATEGY_HPP

View file

@ -70,6 +70,7 @@ struct geometry_transform
}
Transformer const& transformer_;
};
} // ns detail
template <typename T0, typename T1, typename T2>

View file

@ -27,6 +27,9 @@
#include <mapnik/config.hpp>
#include <mapnik/util/noncopyable.hpp>
// boost
#include <boost/geometry.hpp>
namespace mapnik {
namespace geometry {
@ -68,6 +71,36 @@ private:
bool wgs84_to_merc_;
bool merc_to_wgs84_;
};
struct proj_strategy
{
proj_strategy(proj_transform const& prj_trans)
: prj_trans_(prj_trans) {}
template <typename P1, typename P2>
inline bool apply(P1 const& p1, P2 & p2) const
{
using p2_type = typename boost::geometry::coordinate_type<P2>::type;
double x = boost::geometry::get<0>(p1);
double y = boost::geometry::get<1>(p1);
double z = 0.0;
if (!prj_trans_.forward(x, y, z)) return false;
boost::geometry::set<0>(p2, boost::numeric_cast<p2_type>(x));
boost::geometry::set<1>(p2, boost::numeric_cast<p2_type>(y));
return true;
}
template <typename P1, typename P2>
inline P2 execute(P1 const& p1, bool & status) const
{
P2 p2;
status = apply(p1, p2);
return p2;
}
proj_transform const& prj_trans_;
};
}
#endif // MAPNIK_PROJ_TRANSFORM_HPP

View file

@ -178,6 +178,39 @@ public:
return extent_;
}
};
template <typename CalculationType>
struct view_strategy
{
using calc_type = CalculationType;
view_strategy(view_transform const& tr)
: tr_(tr) {}
template <typename P1, typename P2>
inline bool apply(P1 const& p1, P2 & p2) const
{
using coordinate_type = typename boost::geometry::coordinate_type<P2>::type;
calc_type x = boost::geometry::get<0>(p1);
calc_type y = boost::geometry::get<1>(p1);
calc_type z = 0.0;
tr_.forward(&x,&y);
boost::geometry::set<0>(p2, boost::numeric_cast<coordinate_type>(x));
boost::geometry::set<1>(p2, boost::numeric_cast<coordinate_type>(y));
return true;
}
template <typename P1, typename P2>
inline P2 execute(P1 const& p1, bool & status) const
{
P2 p2;
status = apply(p1, p2);
return p2;
}
view_transform const& tr_;
};
}
#endif // MAPNIK_VIEW_TRANSFORM_HPP

View file

@ -0,0 +1,59 @@
#include "catch.hpp"
#include "geometry_equal.hpp"
#include <mapnik/geometry.hpp>
#include <mapnik/projection.hpp>
#include <mapnik/proj_transform.hpp>
#include <mapnik/view_transform.hpp>
#include <mapnik/geometry_transform.hpp>
#include <mapnik/geometry_strategy.hpp>
TEST_CASE("geometry strategy tests") {
SECTION("proj and view strategy") {
using namespace mapnik::geometry;
mapnik::box2d<double> e(-20037508.342789,-20037508.342789,20037508.342789,20037508.342789);
mapnik::view_transform vt(256, 256, e);
mapnik::view_strategy<double> vs(vt);
mapnik::projection source("+init=epsg:4326");
mapnik::projection dest("+init=epsg:3857");
mapnik::proj_transform proj_trans(source, dest);
mapnik::proj_strategy ps(proj_trans);
{
// Test first that proj strategy works properly
point<double> p1(-97.553098,35.523105);
point<double> r1(-1.08596e+07, 4.2352e+06);
geometry<double> p2 = transform<double>(p1, ps);
REQUIRE(p2.is<point<double> >());
point<double> p3 = mapnik::util::get<point<double> >(p2);
assert_g_equal(r1, p3);
}
{
// Test next that view_strategy works
point<double> p1(-1.08596e+07, 4.2352e+06);
point<double> r1(58.6287 , 100.945);
geometry<double> p2 = transform<double>(p1, vs);
REQUIRE(p2.is<point<double> >());
point<double> p3 = mapnik::util::get<point<double> >(p2);
//std::cout << p3.x << " , " << p3.y << std::endl;
assert_g_equal(r1, p3);
}
{
// Test that both work streamed together
using sg_type = strategy_group<mapnik::proj_strategy, mapnik::view_strategy<double> >;
sg_type sg(ps, vs);
point<double> p1(-97.553098,35.523105);
point<double> r1(58.6287 , 100.945);
geometry<double> p2 = transform<double>(p1, sg);
REQUIRE(p2.is<point<double> >());
point<double> p3 = mapnik::util::get<point<double> >(p2);
std::cout << p3.x << " , " << p3.y << std::endl;
assert_g_equal(r1, p3);
}
}
}