Updated reprojection code

This commit is contained in:
Blake Thompson 2015-04-07 11:55:37 -05:00
parent 54d8746aa8
commit 0fec41a87e
5 changed files with 733 additions and 160 deletions

View file

@ -74,6 +74,9 @@ test-python:
test-cpp: test-cpp:
./tests/cpp_tests/run ./tests/cpp_tests/run
test-cxx:
./tests/cxx/run
check: test-local check: test-local
bench: bench:

View file

@ -27,16 +27,36 @@
#include <mapnik/proj_transform.hpp> #include <mapnik/proj_transform.hpp>
#include <mapnik/geometry.hpp> #include <mapnik/geometry.hpp>
// std
#include <string>
namespace mapnik { namespace mapnik {
MAPNIK_DECL geometry::geometry reproject(geometry::geometry const& geom, proj_transform const& proj_trans, unsigned int & n_err, bool reverse = false); namespace geometry {
MAPNIK_DECL geometry::geometry reproject(geometry::geometry const& geom, projection const& source, projection const& dest, unsigned int & n_err); // There is a difference between reprojecting a const vs reprojecting a non const in behavior. If you reproject a
// const a new geometry (or perhaps empty geometry) will be returned no matter how many geometries fail to reproject.
// This is done this way so that large geometry collections that only have a few failing points or polygon parts could
// still be return with out the few failing projections.
MAPNIK_DECL geometry::geometry reproject(geometry::geometry const& geom, std::string const& source, std::string const& dest, unsigned int & n_err); MAPNIK_DECL geometry reproject_copy(geometry const& geom, proj_transform const& proj_trans, unsigned int & n_err, bool reverse = false);
template <typename T>
MAPNIK_DECL T reproject_copy(T const& geom, proj_transform const& proj_trans, unsigned int & n_err, bool reverse = false);
template <typename T>
MAPNIK_DECL T reproject_copy(T const& geom, projection const& source, projection const& dest, unsigned int & n_err);
// No error count is required for a non const reprojection and this will reproject in place.
// because the reprojection is done on the same memory it is important to check if it succeeded,
// otherwise you could be dealing with a corrupt geometry.
template <typename T>
MAPNIK_DECL bool reproject(T & geom, proj_transform const& proj_trans, bool reverse = false);
template <typename T>
MAPNIK_DECL bool reproject(T & geom, projection const& source, projection const& dest);
} // end geometry ns
} // end mapnik ns } // end mapnik ns

View file

@ -274,6 +274,12 @@ struct unwrapper<recursive_wrapper<T>>
{ {
return obj.get(); return obj.get();
} }
auto operator() (recursive_wrapper<T> & obj) const
-> typename recursive_wrapper<T>::type &
{
return obj.get();
}
}; };
template <typename T> template <typename T>

View file

@ -22,223 +22,283 @@
// mapnik // mapnik
#include <mapnik/geometry_reprojection.hpp> #include <mapnik/geometry_reprojection.hpp>
#include <mapnik/geometry.hpp>
namespace mapnik { namespace mapnik {
namespace geometry {
namespace detail { namespace detail {
struct geom_reproj_visitor {
geom_reproj_visitor(proj_transform const & proj_trans, unsigned int & n_err, bool reverse)
: proj_trans_(proj_trans), n_err_(n_err), reverse_(reverse) {}
geometry::geometry operator() (geometry::geometry_empty const&)
{
return geometry::geometry(geometry::geometry_empty());
}
bool trans_point(geometry::point & new_p) geometry_empty reproject_internal(geometry_empty const&, proj_transform const&, unsigned int &, bool)
{
return geometry_empty();
}
point reproject_internal(point const & p, proj_transform const& proj_trans, unsigned int & n_err, bool reverse)
{
point new_p(p);
if (!reverse)
{ {
if (!reverse_) if (!proj_trans.forward(new_p))
{ {
if (!proj_trans_.forward(new_p)) n_err++;
{ }
n_err_++; }
return false; else
} {
if (!proj_trans.backward(new_p))
{
n_err++;
}
}
return std::move(new_p);
}
line_string reproject_internal(line_string const & ls, proj_transform const& proj_trans, unsigned int & n_err, bool reverse)
{
line_string new_ls(ls);
unsigned int err = 0;
if (!reverse)
{
err = proj_trans.forward(new_ls);
}
else
{
err = proj_trans.backward(new_ls);
}
if (err > 0)
{
n_err += err;
}
return std::move(new_ls);
}
polygon reproject_internal(polygon const & poly, proj_transform const& proj_trans, unsigned int & n_err, bool reverse)
{
polygon new_poly;
linear_ring new_ext(poly.exterior_ring);
int err = 0;
if (!reverse)
{
err = proj_trans.forward(new_ext);
}
else
{
err = proj_trans.backward(new_ext);
}
// If the exterior ring doesn't transform don't bother with the holes.
if (err > 0)
{
n_err += err;
return std::move(new_poly);
}
new_poly.set_exterior_ring(std::move(new_ext));
new_poly.interior_rings.reserve(poly.interior_rings.size());
for (auto const& lr : poly.interior_rings)
{
linear_ring new_lr(lr);
if (!reverse)
{
err = proj_trans.forward(new_lr);
} }
else else
{ {
if (!proj_trans_.backward(new_p)) err = proj_trans.backward(new_lr);
{
n_err_++;
return false;
}
}
return true;
}
geometry::geometry operator() (geometry::point const & p)
{
geometry::point new_p(p);
if (!trans_point(new_p))
{
return geometry::geometry(geometry::geometry_empty());
}
return geometry::geometry(std::move(new_p));
}
bool trans_ls(geometry::line_string & new_ls)
{
unsigned int err = 0;
if (!reverse_)
{
err = proj_trans_.forward(new_ls);
}
else
{
err = proj_trans_.backward(new_ls);
} }
if (err > 0) if (err > 0)
{ {
n_err_ += err; n_err += err;
return false; // If there is an error in interior ring drop
// it from polygon.
continue;
} }
return true; new_poly.add_hole(std::move(new_lr));
} }
return std::move(new_poly);
}
geometry::geometry operator() (geometry::line_string const & ls) multi_point reproject_internal(multi_point const & mp, proj_transform const& proj_trans, unsigned int & n_err, bool reverse)
{
if (proj_trans.is_known())
{ {
geometry::line_string new_ls(ls); // If the projection is known we do them all at once because it is faster
if (!trans_ls(new_ls)) // since we know that no point will fail reprojection
multi_point new_mp(mp);
if (!reverse)
{ {
return geometry::geometry(geometry::geometry_empty()); proj_trans.forward(new_mp);
}
return geometry::geometry(std::move(new_ls));
}
bool trans_poly(geometry::polygon & new_poly, geometry::polygon const & poly)
{
geometry::linear_ring new_ext(poly.exterior_ring);
int err = 0;
if (!reverse_)
{
err = proj_trans_.forward(new_ext);
} }
else else
{ {
err = proj_trans_.backward(new_ext); proj_trans.backward(new_mp);
} }
// If the exterior ring doesn't transform don't bother with the holes. return std::move(new_mp);
if (err > 0) }
multi_point new_mp;
new_mp.reserve(mp.size());
for (auto const& p : mp)
{
point new_p(p);
if (!reverse)
{ {
n_err_ += err; if (!proj_trans.forward(new_p))
return false;
}
new_poly.set_exterior_ring(std::move(new_ext));
new_poly.interior_rings.reserve(poly.interior_rings.size());
for (auto const& lr : poly.interior_rings)
{
geometry::linear_ring new_lr(lr);
if (!reverse_)
{ {
err = proj_trans_.forward(new_lr); n_err++;
} }
else else
{ {
err = proj_trans_.backward(new_lr); new_mp.emplace_back(std::move(new_p));
} }
if (err > 0)
{
n_err_ += err;
// If there is an error in interior ring drop
// it from polygon.
continue;
}
new_poly.add_hole(std::move(new_lr));
} }
return true; else
{
if (!proj_trans.backward(new_p))
{
n_err++;
}
else
{
new_mp.emplace_back(std::move(new_p));
}
}
}
return std::move(new_mp);
}
multi_line_string reproject_internal(multi_line_string const & mls, proj_transform const& proj_trans, unsigned int & n_err, bool reverse)
{
multi_line_string new_mls;
new_mls.reserve(mls.size());
for (auto const& ls : mls)
{
line_string new_ls = reproject_internal(ls, proj_trans, n_err, reverse);
if (!new_ls.empty())
{
new_mls.emplace_back(std::move(new_ls));
}
}
return std::move(new_mls);
}
multi_polygon reproject_internal(multi_polygon const & mpoly, proj_transform const& proj_trans, unsigned int & n_err, bool reverse)
{
multi_polygon new_mpoly;
new_mpoly.reserve(mpoly.size());
for (auto const& poly : mpoly)
{
polygon new_poly = reproject_internal(poly, proj_trans, n_err, reverse);
if (!new_poly.exterior_ring.empty())
{
new_mpoly.emplace_back(std::move(new_poly));
}
}
return std::move(new_mpoly);
}
geometry_collection reproject_internal(geometry_collection const & c, proj_transform const& proj_trans, unsigned int & n_err, bool reverse)
{
geometry_collection new_c;
new_c.reserve(c.size());
for (auto const& g : c)
{
geometry new_g(std::move(reproject_copy(g, proj_trans, n_err, reverse)));
if (!new_g.is<geometry_empty>())
{
new_c.emplace_back(std::move(new_g));
}
}
return std::move(new_c);
}
struct geom_reproj_copy_visitor {
geom_reproj_copy_visitor(proj_transform const & proj_trans,
unsigned int & n_err,
bool reverse)
: proj_trans_(proj_trans),
n_err_(n_err),
reverse_(reverse) {}
geometry operator() (geometry_empty const&)
{
return std::move(geometry_empty());
} }
geometry::geometry operator() (geometry::polygon const & poly) geometry operator() (point const& p)
{ {
geometry::polygon new_poly; int intial_err = n_err_;
if (!trans_poly(new_poly, poly)) point new_p = reproject_internal(p, proj_trans_, n_err_, reverse_);
if (n_err_ > intial_err)
{ {
return std::move(geometry::geometry_empty()); return std::move(geometry_empty());
}
return std::move(new_p);
}
geometry operator() (line_string const& ls)
{
int intial_err = n_err_;
line_string new_ls = reproject_internal(ls, proj_trans_, n_err_, reverse_);
if (n_err_ > intial_err)
{
return std::move(geometry_empty());
}
return std::move(new_ls);
}
geometry operator() (polygon const& poly)
{
polygon new_poly = reproject_internal(poly, proj_trans_, n_err_, reverse_);
if (new_poly.exterior_ring.empty())
{
return std::move(geometry_empty());
} }
return std::move(new_poly); return std::move(new_poly);
} }
geometry::geometry operator() (geometry::multi_point const & mp) geometry operator() (multi_point const& mp)
{ {
if (proj_trans_.is_known()) multi_point new_mp = reproject_internal(mp, proj_trans_, n_err_, reverse_);
{
geometry::multi_point new_mp(mp);
if (!trans_ls(new_mp))
{
// should be impossible to reach this currently
/* LCOV_EXCL_START */
return std::move(geometry::geometry_empty());
/* LCOV_EXCL_END */
}
return std::move(new_mp);
}
geometry::multi_point new_mp;
new_mp.reserve(mp.size());
for (auto const& p : mp)
{
geometry::point new_p(p);
if (trans_point(new_p))
{
new_mp.emplace_back(new_p);
}
}
if (new_mp.empty()) if (new_mp.empty())
{ {
return std::move(geometry::geometry_empty()); return std::move(geometry_empty());
} }
return std::move(new_mp); return std::move(new_mp);
} }
geometry::geometry operator() (geometry::multi_line_string const & mls) geometry operator() (multi_line_string const& mls)
{ {
geometry::multi_line_string new_mls; multi_line_string new_mls = reproject_internal(mls, proj_trans_, n_err_, reverse_);
new_mls.reserve(mls.size());
for (auto const& ls : mls)
{
geometry::line_string new_ls(ls);
if (trans_ls(new_ls))
{
new_mls.emplace_back(new_ls);
}
}
if (new_mls.empty()) if (new_mls.empty())
{ {
return std::move(geometry::geometry_empty()); return std::move(geometry_empty());
} }
return std::move(new_mls); return std::move(new_mls);
} }
geometry::geometry operator() (geometry::multi_polygon const & mpoly) geometry operator() (multi_polygon const& mpoly)
{ {
geometry::multi_polygon new_mpoly; multi_polygon new_mpoly = reproject_internal(mpoly, proj_trans_, n_err_, reverse_);
new_mpoly.reserve(mpoly.size());
for (auto const& poly : mpoly)
{
geometry::polygon new_poly;
if (trans_poly(new_poly, poly))
{
new_mpoly.emplace_back(new_poly);
}
}
if (new_mpoly.empty()) if (new_mpoly.empty())
{ {
return std::move(geometry::geometry_empty()); return std::move(geometry_empty());
} }
return std::move(new_mpoly); return std::move(new_mpoly);
} }
geometry::geometry operator() (geometry::geometry_collection const & c) geometry operator() (geometry_collection const& c)
{ {
geometry::geometry_collection new_c; geometry_collection new_c = reproject_internal(c, proj_trans_, n_err_, reverse_);
new_c.reserve(c.size());
for (auto const& g : c)
{
geometry::geometry new_g(std::move(reproject(g, proj_trans_, n_err_, reverse_)));
if (!new_g.is<geometry::geometry_empty>())
{
new_c.emplace_back(new_g);
}
}
if (new_c.empty()) if (new_c.empty())
{ {
return std::move(geometry::geometry_empty()); return std::move(geometry_empty());
} }
return std::move(new_c); return std::move(new_c);
} }
private: private:
proj_transform const& proj_trans_; proj_transform const& proj_trans_;
unsigned int & n_err_; unsigned int & n_err_;
@ -248,10 +308,217 @@ struct geom_reproj_visitor {
} // end detail ns } // end detail ns
geometry::geometry reproject(geometry::geometry const& geom, proj_transform const& proj_trans, unsigned int & n_err, bool reverse) geometry reproject_copy(geometry const& geom, proj_transform const& proj_trans, unsigned int & n_err, bool reverse)
{ {
detail::geom_reproj_visitor visit(proj_trans, n_err, reverse); detail::geom_reproj_copy_visitor visit(proj_trans, n_err, reverse);
return util::apply_visitor(visit, geom); return mapnik::util::apply_visitor(visit, geom);
} }
template <typename T>
T reproject_copy(T const& geom, proj_transform const& proj_trans, unsigned int & n_err, bool reverse)
{
return detail::reproject_internal(geom, proj_trans, n_err, reverse);
}
template MAPNIK_DECL geometry_empty reproject_copy(geometry_empty const& geom, proj_transform const& proj_trans, unsigned int & n_err, bool reverse);
template MAPNIK_DECL point reproject_copy(point const& geom, proj_transform const& proj_trans, unsigned int & n_err, bool reverse);
template MAPNIK_DECL line_string reproject_copy(line_string const& geom, proj_transform const& proj_trans, unsigned int & n_err, bool reverse);
template MAPNIK_DECL polygon reproject_copy(polygon const& geom, proj_transform const& proj_trans, unsigned int & n_err, bool reverse);
template MAPNIK_DECL multi_point reproject_copy(multi_point const& geom, proj_transform const& proj_trans, unsigned int & n_err, bool reverse);
template MAPNIK_DECL multi_line_string reproject_copy(multi_line_string const& geom, proj_transform const& proj_trans, unsigned int & n_err, bool reverse);
template MAPNIK_DECL multi_polygon reproject_copy(multi_polygon const& geom, proj_transform const& proj_trans, unsigned int & n_err, bool reverse);
template MAPNIK_DECL geometry_collection reproject_copy(geometry_collection const& geom, proj_transform const& proj_trans, unsigned int & n_err, bool reverse);
template <typename T>
T reproject_copy(T const& geom, projection const& source, projection const& dest, unsigned int & n_err)
{
proj_transform proj_trans(source, dest);
return reproject_copy(geom, proj_trans, n_err, false);
}
template MAPNIK_DECL geometry reproject_copy(geometry const& geom, projection const& source, projection const& dest, unsigned int & n_err);
template MAPNIK_DECL geometry_empty reproject_copy(geometry_empty const& geom, projection const& source, projection const& dest, unsigned int & n_err);
template MAPNIK_DECL point reproject_copy(point const& geom, projection const& source, projection const& dest, unsigned int & n_err);
template MAPNIK_DECL line_string reproject_copy(line_string const& geom, projection const& source, projection const& dest, unsigned int & n_err);
template MAPNIK_DECL polygon reproject_copy(polygon const& geom, projection const& source, projection const& dest, unsigned int & n_err);
template MAPNIK_DECL multi_point reproject_copy(multi_point const& geom, projection const& source, projection const& dest, unsigned int & n_err);
template MAPNIK_DECL multi_line_string reproject_copy(multi_line_string const& geom, projection const& source, projection const& dest, unsigned int & n_err);
template MAPNIK_DECL multi_polygon reproject_copy(multi_polygon const& geom, projection const& source, projection const& dest, unsigned int & n_err);
template MAPNIK_DECL geometry_collection reproject_copy(geometry_collection const& geom, projection const& source, projection const& dest, unsigned int & n_err);
namespace detail {
struct geom_reproj_visitor {
geom_reproj_visitor(proj_transform const & proj_trans, bool reverse)
: proj_trans_(proj_trans), reverse_(reverse) {}
bool operator() (geometry & geom)
{
return mapnik::util::apply_visitor((*this), geom);
}
bool operator() (geometry_empty &) { return true; }
bool operator() (point & p)
{
if (!reverse_)
{
if (!proj_trans_.forward(p))
{
return false;
}
}
else
{
if (!proj_trans_.backward(p))
{
return false;
}
}
return true;
}
bool operator() (line_string & ls)
{
if (!reverse_)
{
if (proj_trans_.forward(ls) > 0)
{
return false;
}
}
else
{
if (proj_trans_.backward(ls) > 0)
{
return false;
}
}
return true;
}
bool operator() (polygon & poly)
{
if (!reverse_)
{
if (proj_trans_.forward(poly.exterior_ring) > 0)
{
return false;
}
}
else
{
if (proj_trans_.backward(poly.exterior_ring) > 0)
{
return false;
}
}
for (auto & lr : poly.interior_rings)
{
if (!reverse_)
{
if (proj_trans_.forward(lr) > 0)
{
return false;
}
}
else
{
if (proj_trans_.backward(lr) > 0)
{
return false;
}
}
}
return true;
}
bool operator() (multi_point & mp)
{
return (*this) (static_cast<line_string &>(mp));
}
bool operator() (multi_line_string & mls)
{
for (auto & ls : mls)
{
if (! (*this) (ls))
{
return false;
}
}
return true;
}
bool operator() (multi_polygon & mpoly)
{
for (auto & poly : mpoly)
{
if(! (*this)(poly))
{
return false;
}
}
return true;
}
bool operator() (geometry_collection & c)
{
for (auto & g : c)
{
if (! (*this)(g) )
{
return false;
}
}
return true;
}
private:
proj_transform const& proj_trans_;
bool reverse_;
};
} // end detail ns
template <typename T>
bool reproject(T & geom, proj_transform const& proj_trans, bool reverse)
{
detail::geom_reproj_visitor visit(proj_trans, reverse);
return visit(geom);
}
template MAPNIK_DECL bool reproject(geometry & geom, proj_transform const& proj_trans, bool reverse);
template MAPNIK_DECL bool reproject(geometry_empty & geom, proj_transform const& proj_trans, bool reverse);
template MAPNIK_DECL bool reproject(point & geom, proj_transform const& proj_trans, bool reverse);
template MAPNIK_DECL bool reproject(line_string & geom, proj_transform const& proj_trans, bool reverse);
template MAPNIK_DECL bool reproject(polygon & geom, proj_transform const& proj_trans, bool reverse);
template MAPNIK_DECL bool reproject(multi_point & geom, proj_transform const& proj_trans, bool reverse);
template MAPNIK_DECL bool reproject(multi_line_string & geom, proj_transform const& proj_trans, bool reverse);
template MAPNIK_DECL bool reproject(multi_polygon & geom, proj_transform const& proj_trans, bool reverse);
template MAPNIK_DECL bool reproject(geometry_collection & geom, proj_transform const& proj_trans, bool reverse);
template <typename T>
bool reproject(T & geom, projection const& source, projection const& dest)
{
proj_transform proj_trans(source, dest);
detail::geom_reproj_visitor visit(proj_trans, false);
return visit(geom);
}
template MAPNIK_DECL bool reproject(geometry & geom, projection const& source, projection const& dest);
template MAPNIK_DECL bool reproject(geometry_empty & geom, projection const& source, projection const& dest);
template MAPNIK_DECL bool reproject(point & geom, projection const& source, projection const& dest);
template MAPNIK_DECL bool reproject(line_string & geom, projection const& source, projection const& dest);
template MAPNIK_DECL bool reproject(polygon & geom, projection const& source, projection const& dest);
template MAPNIK_DECL bool reproject(multi_point & geom, projection const& source, projection const& dest);
template MAPNIK_DECL bool reproject(multi_line_string & geom, projection const& source, projection const& dest);
template MAPNIK_DECL bool reproject(multi_polygon & geom, projection const& source, projection const& dest);
template MAPNIK_DECL bool reproject(geometry_collection & geom, projection const& source, projection const& dest);
} // end geometry ns
} // end mapnik ns } // end mapnik ns

View file

@ -0,0 +1,277 @@
#include "catch.hpp"
//#include "geometry_equal.hpp"
// mapnik
#include <mapnik/geometry.hpp>
#include <mapnik/projection.hpp>
#include <mapnik/proj_transform.hpp>
#include <mapnik/geometry_reprojection.hpp>
#include <mapnik/geometry_correct.hpp>
// std
#include <iostream>
TEST_CASE("geometry reprojection") {
SECTION("test_projection_4326_3857 - Empty Geometry Object") {
using namespace mapnik::geometry;
mapnik::projection source("+init=epsg:4326");
mapnik::projection dest("+init=epsg:3857");
mapnik::proj_transform proj_trans(source, dest);
{
geometry_empty geom;
unsigned int err = 0;
// Test Standard Transform
geometry_empty new_geom = reproject_copy(geom, proj_trans, err);
REQUIRE(err == 0);
// Transform in reverse
new_geom = reproject_copy(geom, proj_trans, err, true);
REQUIRE(err == 0);
// Transform providing projections not transfrom
new_geom = reproject_copy(geom, source, dest, err);
REQUIRE(err == 0);
// Transform providing projections in reverse
new_geom = reproject_copy(geom, dest, source, err);
REQUIRE(err == 0);
// Transform in place
REQUIRE(reproject(new_geom, proj_trans));
// Transform in place reverse
REQUIRE(reproject(new_geom, proj_trans, true));
// Transform in place providing projections
REQUIRE(reproject(new_geom, source, dest));
// Transform in place provoding projections reversed
REQUIRE(reproject(new_geom, dest, source));
}
} // End Section
SECTION("test_projection_4326_3857 - Empty Geometry in Geometry Variant") {
using namespace mapnik::geometry;
mapnik::projection source("+init=epsg:4326");
mapnik::projection dest("+init=epsg:3857");
mapnik::proj_transform proj_trans(source, dest);
{
geometry geom(std::move(geometry_empty()));
unsigned int err = 0;
// Test Standard Transform
geometry new_geom = reproject_copy(geom, proj_trans, err);
REQUIRE(err == 0);
REQUIRE(new_geom.is<geometry_empty>());
// Transform in reverse
new_geom = reproject_copy(geom, proj_trans, err, true);
REQUIRE(err == 0);
REQUIRE(new_geom.is<geometry_empty>());
// Transform providing projections not transfrom
new_geom = reproject_copy(geom, source, dest, err);
REQUIRE(err == 0);
REQUIRE(new_geom.is<geometry_empty>());
// Transform providing projections in reverse
new_geom = reproject_copy(geom, dest, source, err);
REQUIRE(err == 0);
REQUIRE(new_geom.is<geometry_empty>());
// Transform in place
REQUIRE(reproject(new_geom, proj_trans));
// Transform in place reverse
REQUIRE(reproject(new_geom, proj_trans, true));
// Transform in place providing projections
REQUIRE(reproject(new_geom, source, dest));
// Transform in place provoding projections reversed
REQUIRE(reproject(new_geom, dest, source));
}
} // End Section
SECTION("test_projection_4326_3857 - Point Geometry Object") {
using namespace mapnik::geometry;
mapnik::projection source("+init=epsg:4326");
mapnik::projection dest("+init=epsg:3857");
mapnik::proj_transform proj_trans(source, dest);
{
point geom1(-97.552175, 35.522895);
point geom2(-10859458.446776, 4235169.496066);
unsigned int err = 0;
// Test Standard Transform
point new_geom = reproject_copy(geom1, proj_trans, err);
std::cout << std::fixed << new_geom.x << "," << std::fixed << new_geom.y << std::endl;
REQUIRE(err == 0);
REQUIRE(new_geom.x == Approx(geom2.x));
REQUIRE(new_geom.y == Approx(geom2.y));
// Transform in reverse
new_geom = reproject_copy(geom2, proj_trans, err, true);
REQUIRE(err == 0);
REQUIRE(new_geom.x == Approx(geom1.x));
REQUIRE(new_geom.y == Approx(geom1.y));
// Transform providing projections not transfrom
new_geom = reproject_copy(geom1, source, dest, err);
REQUIRE(err == 0);
REQUIRE(new_geom.x == Approx(geom2.x));
REQUIRE(new_geom.y == Approx(geom2.y));
// Transform providing projections in reverse
new_geom = reproject_copy(geom2, dest, source, err);
REQUIRE(err == 0);
REQUIRE(new_geom.x == Approx(geom1.x));
REQUIRE(new_geom.y == Approx(geom1.y));
// Transform in place
point geom3(-97.552175, 35.522895);
REQUIRE(reproject(geom3, proj_trans));
REQUIRE(geom3.x == Approx(geom2.x));
REQUIRE(geom3.y == Approx(geom2.y));
// Transform in place reverse
REQUIRE(reproject(geom3, proj_trans, true));
REQUIRE(geom3.x == Approx(geom1.x));
REQUIRE(geom3.y == Approx(geom1.y));
// Transform in place providing projections
REQUIRE(reproject(geom3, source, dest));
REQUIRE(geom3.x == Approx(geom2.x));
REQUIRE(geom3.y == Approx(geom2.y));
// Transform in place provoding projections reversed
REQUIRE(reproject(geom3, dest, source));
REQUIRE(geom3.x == Approx(geom1.x));
REQUIRE(geom3.y == Approx(geom1.y));
}
} // End Section
/*
SECTION("test_projection_4326_3857 - Point Geometry Object") {
using namespace mapnik::geometry;
mapnik::projection source("+init=epsg:4326");
mapnik::projection dest("+init=epsg:3857");
mapnik::proj_transform proj_trans(source, dest);
{
geometry geom1(point(-97.552175, 35.522895));
geometry geom2(point(-10859458.446776, 4235169.496066));
unsigned int err = 0;
// Test Standard Transform
point new_geom = reproject_copy(geom1, proj_trans, err);
std::cout << std::fixed << new_geom.x << "," << std::fixed << new_geom.y << std::endl;
REQUIRE(err == 0);
REQUIRE(new_geom.x == Approx(geom2_.x));
REQUIRE(new_geom.y == Approx(geom2_.y));
// Transform in reverse
new_geom = reproject_copy(geom2, proj_trans, err, true);
REQUIRE(err == 0);
REQUIRE(new_geom.x == Approx(geom1.x));
REQUIRE(new_geom.y == Approx(geom1.y));
// Transform providing projections not transfrom
new_geom = reproject_copy(geom1, source, dest, err);
REQUIRE(err == 0);
REQUIRE(new_geom.x == Approx(geom2.x));
REQUIRE(new_geom.y == Approx(geom2.y));
// Transform providing projections in reverse
new_geom = reproject_copy(geom2, dest, source, err);
REQUIRE(err == 0);
REQUIRE(new_geom.x == Approx(geom1.x));
REQUIRE(new_geom.y == Approx(geom1.y));
// Transform in place
point geom3(-97.552175, 35.522895);
REQUIRE(reproject(geom3, proj_trans));
REQUIRE(geom3.x == Approx(geom2.x));
REQUIRE(geom3.y == Approx(geom2.y));
// Transform in place reverse
REQUIRE(reproject(geom3, proj_trans, true));
REQUIRE(geom3.x == Approx(geom1.x));
REQUIRE(geom3.y == Approx(geom1.y));
// Transform in place providing projections
REQUIRE(reproject(geom3, source, dest));
REQUIRE(geom3.x == Approx(geom2.x));
REQUIRE(geom3.y == Approx(geom2.y));
// Transform in place provoding projections reversed
REQUIRE(reproject(geom3, dest, source));
REQUIRE(geom3.x == Approx(geom1.x));
REQUIRE(geom3.y == Approx(geom1.y));
}
} // End Section */
/*{
geometry geom(point(0,0));
REQUIRE( mapnik::hit_test(geom,0,0,0) );
}
{
geometry geom(point(0,0));
REQUIRE( mapnik::hit_test(geom,1,0,1) );
}
{
geometry geom(point(0,0));
REQUIRE( mapnik::hit_test(geom,0,1,1) );
}
{
geometry geom(point(0,0));
REQUIRE( mapnik::hit_test(geom,1,1,1.5) );
}
{
line_string line;
line.add_coord(0,0);
line.add_coord(1,1);
line.add_coord(2,2);
geometry geom(line);
REQUIRE( mapnik::hit_test(geom,0,0,1.5) );
}
{
line_string line;
line.add_coord(0,0);
line.add_coord(1,1);
line.add_coord(2,2);
multi_line_string multi_line;
multi_line.emplace_back(std::move(line));
geometry geom(multi_line);
REQUIRE( mapnik::hit_test(geom,0,0,1.5) );
}
{
polygon poly;
linear_ring ring;
ring.add_coord(0,0);
ring.add_coord(-10,0);
ring.add_coord(-10,10);
ring.add_coord(0,10);
ring.add_coord(0,0);
poly.set_exterior_ring(std::move(ring));
geometry geom(poly);
REQUIRE( mapnik::hit_test(geom,-5,5,0) );
multi_polygon mp;
mp.push_back(poly);
geometry geom_mp(mp);
REQUIRE( mapnik::hit_test(geom_mp,-5,5,0) );
correct(geom);
REQUIRE( mapnik::hit_test(geom,-5,5,0) );
correct(geom_mp);
REQUIRE( mapnik::hit_test(geom_mp,-5,5,0) );
geometry_collection gc;
REQUIRE( !mapnik::hit_test(geometry(gc),-5,5,0) );
gc.push_back(geom_mp);
REQUIRE( mapnik::hit_test(geometry(gc),-5,5,0) );
REQUIRE( !mapnik::hit_test(geometry(gc),-50,-50,0) );
gc.emplace_back(point(-50,-50));
REQUIRE( mapnik::hit_test(geometry(gc),-50,-50,0) );
}
{
// polygon with hole
polygon poly;
linear_ring ring;
ring.add_coord(0,0);
ring.add_coord(-10,0);
ring.add_coord(-10,10);
ring.add_coord(0,10);
ring.add_coord(0,0);
poly.set_exterior_ring(std::move(ring));
linear_ring hole;
hole.add_coord(-7,7);
hole.add_coord(-7,3);
hole.add_coord(-3,3);
hole.add_coord(-3,7);
hole.add_coord(-7,7);
poly.add_hole(std::move(hole));
geometry geom(poly);
REQUIRE( !mapnik::hit_test(geom,-5,5,0) );
// add another hole inside the first hole
// which should be considered a hit
linear_ring fill;
fill.add_coord(-6,4);
fill.add_coord(-6,6);
fill.add_coord(-4,6);
fill.add_coord(-4,4);
fill.add_coord(-6,4);
poly.add_hole(std::move(fill));
REQUIRE( mapnik::hit_test(geometry(poly),-5,5,0) );
}*/
} // End Testcase