Merge pull request #3678 from mapycz/fix-polygon-closing-on-reprojection

fix closing polygons on reprojection
This commit is contained in:
Artem Pavlenko 2017-05-30 19:08:51 +02:00 committed by GitHub
commit 4d7e95c0c0
7 changed files with 292 additions and 24 deletions

View file

@ -26,8 +26,8 @@
#include <mapnik/markers_placements/line.hpp> #include <mapnik/markers_placements/line.hpp>
#include <mapnik/markers_placements/point.hpp> #include <mapnik/markers_placements/point.hpp>
#include <mapnik/markers_placements/interior.hpp> #include <mapnik/markers_placements/interior.hpp>
#include <mapnik/markers_placements/vertext_first.hpp> #include <mapnik/markers_placements/vertex_first.hpp>
#include <mapnik/markers_placements/vertext_last.hpp> #include <mapnik/markers_placements/vertex_last.hpp>
#include <mapnik/symbolizer_enumerations.hpp> #include <mapnik/symbolizer_enumerations.hpp>
namespace mapnik namespace mapnik

View file

@ -41,42 +41,67 @@ public:
return false; return false;
} }
double x0, y0; geometry::point<double> p0;
unsigned command0 = this->locator_.vertex(&x0, &y0); geometry::point<double> p1;
geometry::point<double> p_next;
geometry::point<double> move_to;
unsigned cmd0 = SEG_END;
unsigned cmd1 = SEG_END;
unsigned cmd_next = SEG_END;
if (agg::is_stop(command0)) while ((cmd_next = this->locator_.vertex(&p_next.x, &p_next.y)) != SEG_END)
{
switch (cmd_next)
{
case SEG_MOVETO:
move_to = p_next;
p0 = p_next;
cmd0 = cmd_next;
break;
case SEG_LINETO:
p1 = p0;
cmd1 = cmd0;
p0 = p_next;
cmd0 = cmd_next;
break;
case SEG_CLOSE:
p1 = p0;
cmd1 = cmd0;
p0 = move_to;
cmd0 = cmd_next;
break;
}
}
// Empty geometry
if (cmd0 == SEG_END)
{ {
this->done_ = true; this->done_ = true;
return false; return false;
} }
double next_x, next_y; // Last point
double x1 = x0, y1 = y0; x = p0.x;
unsigned command1 = command0; y = p0.y;
while (!agg::is_stop(command0 = this->locator_.vertex(&next_x, &next_y))) // Line or polygon
if (cmd0 == SEG_LINETO || cmd0 == SEG_CLOSE)
{ {
command1 = command0; angle = std::atan2(p0.y - p1.y, p0.x - p1.x);
x1 = x0;
y1 = y0;
x0 = next_x;
y0 = next_y;
}
x = x0;
y = y0;
if (agg::is_line_to(command1))
{
angle = std::atan2(y0 - y1, x0 - x1);
if (!this->set_direction(angle)) if (!this->set_direction(angle))
{ {
this->done_ = true;
return false; return false;
} }
} }
else
{
angle = 0.0;
}
if (!this->push_to_detector(x, y, angle, ignore_placement)) if (!this->push_to_detector(x, y, angle, ignore_placement))
{ {
this->done_ = true;
return false; return false;
} }

View file

@ -86,7 +86,7 @@ struct transform_path_adapter
while (!ok) while (!ok)
{ {
command = geom_.vertex(x,y); command = geom_.vertex(x,y);
if (command == SEG_END) if (command == SEG_END || command == SEG_CLOSE)
{ {
return command; return command;
} }

@ -1 +1 @@
Subproject commit 75ecac5c3bd44f1c9111d9b3fba785a1713f2444 Subproject commit 85a94e315d0c2d4b3c7248ee9a7fc0197cac2002

View file

@ -0,0 +1,126 @@
#include "catch.hpp"
#include <mapnik/vertex_adapters.hpp>
#include <mapnik/label_collision_detector.hpp>
#include <mapnik/markers_placements/vertex_last.hpp>
using namespace mapnik;
TEST_CASE("marker placement vertex last") {
SECTION("empty geometry") {
mapnik::geometry::line_string<double> g;
using va_type = mapnik::geometry::line_string_vertex_adapter<double>;
va_type va(g);
using detector_type = mapnik::label_collision_detector4;
detector_type detector(mapnik::box2d<double>(0, 0, 100, 100));
using placement_type = mapnik::markers_vertex_last_placement<va_type, detector_type>;
mapnik::markers_placement_params params {
mapnik::box2d<double>(0, 0, 10, 10),
agg::trans_affine(),
0, 0, false, false, DIRECTION_AUTO };
placement_type placement(va, detector, params);
double x, y, angle;
CHECK( !placement.get_point(x, y, angle, true) );
}
SECTION("point") {
mapnik::geometry::point<double> g(2.0, 3.0);
using va_type = mapnik::geometry::point_vertex_adapter<double>;
va_type va(g);
using detector_type = mapnik::label_collision_detector4;
detector_type detector(mapnik::box2d<double>(0, 0, 100, 100));
using placement_type = mapnik::markers_vertex_last_placement<va_type, detector_type>;
mapnik::markers_placement_params params {
mapnik::box2d<double>(0, 0, 10, 10),
agg::trans_affine(),
0, 0, false, false, DIRECTION_AUTO };
placement_type placement(va, detector, params);
double x, y, angle;
CHECK( placement.get_point(x, y, angle, true) );
CHECK( x == Approx(2.0) );
CHECK( y == Approx(3.0) );
CHECK( angle == Approx(0.0) );
CHECK( !placement.get_point(x, y, angle, true) );
}
SECTION("line string") {
mapnik::geometry::line_string<double> g;
g.emplace_back(1.0, 1.0);
g.emplace_back(2.0, 3.0);
using va_type = mapnik::geometry::line_string_vertex_adapter<double>;
va_type va(g);
using detector_type = mapnik::label_collision_detector4;
detector_type detector(mapnik::box2d<double>(0, 0, 100, 100));
using placement_type = mapnik::markers_vertex_last_placement<va_type, detector_type>;
mapnik::markers_placement_params params {
mapnik::box2d<double>(0, 0, 10, 10),
agg::trans_affine(),
0, 0, false, false, DIRECTION_AUTO };
placement_type placement(va, detector, params);
double x, y, angle;
CHECK( placement.get_point(x, y, angle, true) );
CHECK( x == Approx(2.0) );
CHECK( y == Approx(3.0) );
CHECK( angle == Approx(1.1071487178) );
CHECK( !placement.get_point(x, y, angle, true) );
}
SECTION("polygon") {
mapnik::geometry::polygon<double> g;
g.emplace_back();
auto & exterior = g.back();
exterior.emplace_back(2.0, 3.0);
exterior.emplace_back(1.0, 1.0);
exterior.emplace_back(0.0, 2.0);
exterior.emplace_back(2.0, 3.0);
using va_type = mapnik::geometry::polygon_vertex_adapter<double>;
va_type va(g);
using detector_type = mapnik::label_collision_detector4;
detector_type detector(mapnik::box2d<double>(0, 0, 100, 100));
using placement_type = mapnik::markers_vertex_last_placement<va_type, detector_type>;
mapnik::markers_placement_params params {
mapnik::box2d<double>(0, 0, 10, 10),
agg::trans_affine(),
0, 0, false, false, DIRECTION_AUTO };
placement_type placement(va, detector, params);
double x, y, angle;
CHECK( placement.get_point(x, y, angle, true) );
CHECK( x == Approx(2.0) );
CHECK( y == Approx(3.0) );
CHECK( angle == Approx(0.463647609) );
CHECK( !placement.get_point(x, y, angle, true) );
}
}

View file

@ -0,0 +1,117 @@
#include "catch.hpp"
#include <mapnik/transform_path_adapter.hpp>
#include <mapnik/geometry/correct.hpp>
#include <mapnik/vertex_adapters.hpp>
#include <mapnik/transform_path_adapter.hpp>
#include <mapnik/view_transform.hpp>
#include <mapnik/proj_transform.hpp>
#include <mapnik/projection.hpp>
TEST_CASE("transform_path_adapter") {
SECTION("polygon closing - epsg 2330") {
mapnik::geometry::polygon<double> g;
g.emplace_back();
auto & exterior = g.back();
exterior.emplace_back(88.1844308217992, 69.3553916041731);
exterior.emplace_back(88.1846166524913, 69.3552821191223);
exterior.emplace_back(88.1845090893871, 69.3553454342903);
exterior.emplace_back(88.1844308217992, 69.3553916041731);
using va_type = mapnik::geometry::polygon_vertex_adapter<double>;
using path_type = mapnik::transform_path_adapter<mapnik::view_transform, va_type>;
va_type va(g);
mapnik::box2d<double> extent(16310607, 7704513, 16310621, 7704527);
mapnik::view_transform tr(512, 512, extent);
mapnik::projection proj1("+init=epsg:2330");
mapnik::projection proj2("+init=epsg:4326");
mapnik::proj_transform prj_trans(proj1, proj2);
path_type path(tr, va, prj_trans);
double x,y;
unsigned cmd;
cmd = path.vertex(&x, &y);
CHECK( cmd == mapnik::SEG_MOVETO );
CHECK( x == Approx(110.4328050613) );
CHECK( y == Approx(20.2204537392) );
cmd = path.vertex(&x, &y);
CHECK( cmd == mapnik::SEG_LINETO );
CHECK( x == Approx(342.1220560074) );
CHECK( y == Approx(486.732225963) );
cmd = path.vertex(&x, &y);
CHECK( cmd == mapnik::SEG_LINETO );
CHECK( x == Approx(207.9962329183) );
CHECK( y == Approx(216.9376912798) );
// close
cmd = path.vertex(&x, &y);
CHECK( cmd == mapnik::SEG_CLOSE );
CHECK( x == 0 );
CHECK( y == 0 );
// end
cmd = path.vertex(&x, &y);
CHECK( cmd == mapnik::SEG_END );
CHECK( x == 0 );
CHECK( y == 0 );
}
SECTION("polygon closing - epsg 32633") {
mapnik::geometry::polygon<double> g;
g.emplace_back();
auto & exterior = g.back();
exterior.emplace_back(13, 13);
exterior.emplace_back(14, 13);
exterior.emplace_back(14, 14);
exterior.emplace_back(14, 14);
using va_type = mapnik::geometry::polygon_vertex_adapter<double>;
using path_type = mapnik::transform_path_adapter<mapnik::view_transform, va_type>;
va_type va(g);
mapnik::box2d<double> extent(166022, 0, 833978, 9329005);
mapnik::view_transform tr(512, 512, extent);
mapnik::projection proj1("+init=epsg:32633");
mapnik::projection proj2("+init=epsg:4326");
mapnik::proj_transform prj_trans(proj1, proj2);
path_type path(tr, va, prj_trans);
double x,y;
unsigned cmd;
cmd = path.vertex(&x, &y);
CHECK( cmd == mapnik::SEG_MOVETO );
CHECK( x == Approx(89.7250280748) );
CHECK( y == Approx(433.0795069885) );
cmd = path.vertex(&x, &y);
CHECK( cmd == mapnik::SEG_LINETO );
CHECK( x == Approx(172.873973465) );
CHECK( y == Approx(433.1145779929) );
cmd = path.vertex(&x, &y);
CHECK( cmd == mapnik::SEG_LINETO );
CHECK( x == Approx(173.2194366775) );
CHECK( y == Approx(427.0442504759) );
// close
cmd = path.vertex(&x, &y);
CHECK( cmd == mapnik::SEG_CLOSE );
CHECK( x == 0 );
CHECK( y == 0 );
// end
cmd = path.vertex(&x, &y);
CHECK( cmd == mapnik::SEG_END );
CHECK( x == 0 );
CHECK( y == 0 );
}
}