From 56fe702bac0a9be9fe989a42d30b0a6dbbdd0932 Mon Sep 17 00:00:00 2001 From: artemp Date: Tue, 7 Jul 2015 14:19:51 +0200 Subject: [PATCH 1/5] agg line_symbolizer - dispatch to appropriate clipper based on geometry_type --- src/agg/process_line_symbolizer.cpp | 24 +++++++++++++++++++----- 1 file changed, 19 insertions(+), 5 deletions(-) diff --git a/src/agg/process_line_symbolizer.cpp b/src/agg/process_line_symbolizer.cpp index e2004e921..2eb476f95 100644 --- a/src/agg/process_line_symbolizer.cpp +++ b/src/agg/process_line_symbolizer.cpp @@ -31,6 +31,7 @@ #include #include #include +#include // agg #include "agg_basics.h" #include "agg_rendering_buffer.h" @@ -164,12 +165,19 @@ void agg_renderer::process(line_symbolizer const& sym, rasterizer_type ras(ren); set_join_caps_aa(sym, ras, feature, common_.vars_); - using vertex_converter_type = vertex_converter; vertex_converter_type converter(clip_box,sym,common_.t_,prj_trans,tr,feature,common_.vars_,common_.scale_factor_); - if (clip) converter.set(); // optional clip (default: true) + if (clip) + { + geometry::geometry_types type = geometry::geometry_type(feature.get_geometry()); + if (type == geometry::geometry_types::Polygon) + converter.template set(); + else if (type == geometry::geometry_types::LineString) + converter.template set(); + } converter.set(); // always transform if (std::fabs(offset) > 0.0) converter.set(); // parallel offset converter.set(); // optional affine transform @@ -183,14 +191,20 @@ void agg_renderer::process(line_symbolizer const& sym, } else { - using vertex_converter_type = vertex_converter; vertex_converter_type converter(clip_box, sym,common_.t_,prj_trans,tr,feature,common_.vars_,common_.scale_factor_); - - if (clip) converter.set(); // optional clip (default: true) + if (clip) + { + geometry::geometry_types type = geometry::geometry_type(feature.get_geometry()); + if (type == geometry::geometry_types::Polygon) + converter.template set(); + else if (type == geometry::geometry_types::LineString) + converter.template set(); + } converter.set(); // always transform if (std::fabs(offset) > 0.0) converter.set(); // parallel offset converter.set(); // optional affine transform From bb815dacf807560e3382027b571d4f0fca6c7872 Mon Sep 17 00:00:00 2001 From: artemp Date: Tue, 7 Jul 2015 14:20:54 +0200 Subject: [PATCH 2/5] offset_converter - skip duplicate SEG_CLOSE (after LINETO (startx,starty)) commands to normalise input --- include/mapnik/offset_converter.hpp | 35 ++++++++++++++++++++--------- 1 file changed, 25 insertions(+), 10 deletions(-) diff --git a/include/mapnik/offset_converter.hpp b/include/mapnik/offset_converter.hpp index 8f3a6f1f3..674562137 100644 --- a/include/mapnik/offset_converter.hpp +++ b/include/mapnik/offset_converter.hpp @@ -53,7 +53,7 @@ struct offset_converter , pre_first_(vertex2d::no_init) , pre_(vertex2d::no_init) , cur_(vertex2d::no_init) - {} + {} enum status { @@ -299,6 +299,7 @@ private: vertex2d v1(vertex2d::no_init); vertex2d v2(vertex2d::no_init); vertex2d w(vertex2d::no_init); + vertex2d start(vertex2d::no_init); vertex2d start_v2(vertex2d::no_init); std::vector points; std::vector close_points; @@ -314,21 +315,35 @@ private: { return status_ = process; } - + while ((v0.cmd = geom_.vertex(&v0.x, &v0.y)) != SEG_END) { - points.push_back(vertex2d(v0.x, v0.y, v0.cmd)); if (v0.cmd == SEG_CLOSE) { is_polygon = true; close_points.push_back(vertex2d(v1.x, v1.y, v1.cmd)); + if (points.size() > 0) + { + auto & prev = points.back(); + if (prev.x == start.x && prev.y == start.y) + { + prev.cmd = SEG_CLOSE; // account for dupes (line_to(move_to) + close_path) in agg poly clipper + continue; + } + } + } + else if (v0.cmd == SEG_MOVETO) + { + start = v0; } v1.x = v0.x; v1.y = v0.y; v1.cmd = v0.cmd; + points.push_back(vertex2d(v0.x, v0.y, v0.cmd)); } // Push SEG_END points.push_back(vertex2d(v0.x, v0.y, v0.cmd)); + std::size_t i = 0; v1 = points[i++]; v2 = points[i++]; @@ -375,11 +390,11 @@ private: { dot = v_x1x0 * v_x1x2 + v_y1y0 * v_y1y2; // dot product det = v_x1x0 * v_y1y2 - v_y1y0 * v_x1x2; // determinant - + joint_angle = std::atan2(det, dot); // atan2(y, x) or atan2(sin, cos) if (joint_angle < 0) joint_angle = joint_angle + 2 * M_PI; joint_angle = std::fmod(joint_angle, 2 * M_PI); - + if (offset_ > 0.0) { joint_angle = 2 * M_PI - joint_angle; @@ -390,7 +405,7 @@ private: if (std::abs(joint_angle) > M_PI) { curve_angle = explement_reflex_angle(angle_b - angle_a); - // Bulge steps should be determined by the inverse of the joint angle. + // Bulge steps should be determined by the inverse of the joint angle. double half_turns = half_turn_segments_ * std::fabs(curve_angle); bulge_steps = 1 + static_cast(std::floor(half_turns / M_PI)); } @@ -470,7 +485,7 @@ private: v_y1y0 = -v_y1y2; // Calculate new angle_a angle_a = std::atan2(v_y1y2, v_x1x2); - + // Calculate the new vector v_x1x2 = v2.x - v1.x; v_y1y2 = v2.y - v1.y; @@ -479,11 +494,11 @@ private: dot = v_x1x0 * v_x1x2 + v_y1y0 * v_y1y2; // dot product det = v_x1x0 * v_y1y2 - v_y1y0 * v_x1x2; // determinant - + joint_angle = std::atan2(det, dot); // atan2(y, x) or atan2(sin, cos) if (joint_angle < 0) joint_angle = joint_angle + 2 * M_PI; joint_angle = std::fmod(joint_angle, 2 * M_PI); - + if (offset_ > 0.0) { joint_angle = 2 * M_PI - joint_angle; @@ -494,7 +509,7 @@ private: if (std::abs(joint_angle) > M_PI) { curve_angle = explement_reflex_angle(angle_b - angle_a); - // Bulge steps should be determined by the inverse of the joint angle. + // Bulge steps should be determined by the inverse of the joint angle. double half_turns = half_turn_segments_ * std::fabs(curve_angle); bulge_steps = 1 + static_cast(std::floor(half_turns / M_PI)); } From 2fd1525269b696f99c4ce925c97123049187a245 Mon Sep 17 00:00:00 2001 From: artemp Date: Tue, 7 Jul 2015 15:02:13 +0200 Subject: [PATCH 3/5] remove redundant check --- include/mapnik/offset_converter.hpp | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/include/mapnik/offset_converter.hpp b/include/mapnik/offset_converter.hpp index 674562137..4a1fabf3b 100644 --- a/include/mapnik/offset_converter.hpp +++ b/include/mapnik/offset_converter.hpp @@ -322,14 +322,11 @@ private: { is_polygon = true; close_points.push_back(vertex2d(v1.x, v1.y, v1.cmd)); - if (points.size() > 0) + auto & prev = points.back(); + if (prev.x == start.x && prev.y == start.y) { - auto & prev = points.back(); - if (prev.x == start.x && prev.y == start.y) - { - prev.cmd = SEG_CLOSE; // account for dupes (line_to(move_to) + close_path) in agg poly clipper - continue; - } + prev.cmd = SEG_CLOSE; // account for dupes (line_to(move_to) + close_path) in agg poly clipper + continue; } } else if (v0.cmd == SEG_MOVETO) From 0a484bf784c1ca17c5d20a50c9ab131dfc70968b Mon Sep 17 00:00:00 2001 From: artemp Date: Tue, 7 Jul 2015 18:37:27 +0200 Subject: [PATCH 4/5] handle Multi-geoms + update cairo and grid renderers update --- src/agg/process_line_symbolizer.cpp | 8 ++++---- src/cairo/process_line_symbolizer.cpp | 11 ++++++++++- src/grid/process_line_symbolizer.cpp | 12 ++++++++++-- 3 files changed, 24 insertions(+), 7 deletions(-) diff --git a/src/agg/process_line_symbolizer.cpp b/src/agg/process_line_symbolizer.cpp index 2eb476f95..b3a01c7e8 100644 --- a/src/agg/process_line_symbolizer.cpp +++ b/src/agg/process_line_symbolizer.cpp @@ -173,9 +173,9 @@ void agg_renderer::process(line_symbolizer const& sym, if (clip) { geometry::geometry_types type = geometry::geometry_type(feature.get_geometry()); - if (type == geometry::geometry_types::Polygon) + if (type == geometry::geometry_types::Polygon || type == geometry::geometry_types::MultiPolygon) converter.template set(); - else if (type == geometry::geometry_types::LineString) + else if (type == geometry::geometry_types::LineString || type == geometry::geometry_types::MultiLineString) converter.template set(); } converter.set(); // always transform @@ -200,9 +200,9 @@ void agg_renderer::process(line_symbolizer const& sym, if (clip) { geometry::geometry_types type = geometry::geometry_type(feature.get_geometry()); - if (type == geometry::geometry_types::Polygon) + if (type == geometry::geometry_types::Polygon || type == geometry::geometry_types::MultiPolygon) converter.template set(); - else if (type == geometry::geometry_types::LineString) + else if (type == geometry::geometry_types::LineString || type == geometry::geometry_types::MultiLineString) converter.template set(); } converter.set(); // always transform diff --git a/src/cairo/process_line_symbolizer.cpp b/src/cairo/process_line_symbolizer.cpp index 1510547e4..ed64d5c01 100644 --- a/src/cairo/process_line_symbolizer.cpp +++ b/src/cairo/process_line_symbolizer.cpp @@ -29,6 +29,7 @@ #include #include #include +#include namespace mapnik { @@ -82,6 +83,7 @@ void cairo_renderer::process(line_symbolizer const& sym, clipping_extent.pad(padding); } using vertex_converter_type = vertex_converter::process(line_symbolizer const& sym, vertex_converter_type converter(clipping_extent,sym,common_.t_,prj_trans,tr,feature,common_.vars_,common_.scale_factor_); - if (clip) converter.set(); // optional clip (default: true) + if (clip) + { + geometry::geometry_types type = geometry::geometry_type(feature.get_geometry()); + if (type == geometry::geometry_types::Polygon || type == geometry::geometry_types::MultiPolygon) + converter.template set(); + else if (type == geometry::geometry_types::LineString || type == geometry::geometry_types::MultiLineString) + converter.template set(); + } converter.set(); // always transform if (std::fabs(offset) > 0.0) converter.set(); // parallel offset converter.set(); // optional affine transform diff --git a/src/grid/process_line_symbolizer.cpp b/src/grid/process_line_symbolizer.cpp index 0dc6f3f6a..c569f6b2c 100644 --- a/src/grid/process_line_symbolizer.cpp +++ b/src/grid/process_line_symbolizer.cpp @@ -31,6 +31,7 @@ #include #include #include +#include // agg #include "agg_rasterizer_scanline_aa.h" #include "agg_renderer_scanline.h" @@ -89,14 +90,21 @@ void grid_renderer::process(line_symbolizer const& sym, padding *= common_.scale_factor_; clipping_extent.pad(padding); } - using vertex_converter_type = vertex_converter; vertex_converter_type converter(clipping_extent,sym,common_.t_,prj_trans,tr,feature,common_.vars_,common_.scale_factor_); - if (clip) converter.set(); // optional clip (default: true) + if (clip) + { + geometry::geometry_types type = geometry::geometry_type(feature.get_geometry()); + if (type == geometry::geometry_types::Polygon || type == geometry::geometry_types::MultiPolygon) + converter.template set(); + else if (type == geometry::geometry_types::LineString || type == geometry::geometry_types::MultiLineString) + converter.template set(); + } converter.set(); // always transform if (std::fabs(offset) > 0.0) converter.set(); // parallel offset converter.set(); // optional affine transform From 73cae70a41b7625da285d5fb95f657f2f9a0ba03 Mon Sep 17 00:00:00 2001 From: artemp Date: Tue, 7 Jul 2015 18:38:25 +0200 Subject: [PATCH 5/5] correctly populate `close_points` when skipping duplicate (coincident vertices) --- include/mapnik/offset_converter.hpp | 27 +++++++++++++++------------ 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/include/mapnik/offset_converter.hpp b/include/mapnik/offset_converter.hpp index 4a1fabf3b..51d43e347 100644 --- a/include/mapnik/offset_converter.hpp +++ b/include/mapnik/offset_converter.hpp @@ -306,41 +306,44 @@ private: bool is_polygon = false; std::size_t cpt = 0; v0.cmd = geom_.vertex(&v0.x, &v0.y); - v1.x = v0.x; - v1.y = v0.y; - v1.cmd = v0.cmd; + v1 = v0; // PUSH INITIAL - points.push_back(vertex2d(v0.x, v0.y, v0.cmd)); + points.push_back(v0); if (v0.cmd == SEG_END) // not enough vertices in source { return status_ = process; } - + start = v0; while ((v0.cmd = geom_.vertex(&v0.x, &v0.y)) != SEG_END) { if (v0.cmd == SEG_CLOSE) { is_polygon = true; - close_points.push_back(vertex2d(v1.x, v1.y, v1.cmd)); auto & prev = points.back(); if (prev.x == start.x && prev.y == start.y) { + prev.x = v0.x; // hack + prev.y = v0.y; prev.cmd = SEG_CLOSE; // account for dupes (line_to(move_to) + close_path) in agg poly clipper + std::size_t size = points.size(); + if (size > 1) close_points.push_back(points[size - 2]); + else close_points.push_back(prev); continue; } + else + { + close_points.push_back(v1); + } } else if (v0.cmd == SEG_MOVETO) { start = v0; } - v1.x = v0.x; - v1.y = v0.y; - v1.cmd = v0.cmd; - points.push_back(vertex2d(v0.x, v0.y, v0.cmd)); + v1 = v0; + points.push_back(v0); } // Push SEG_END - points.push_back(vertex2d(v0.x, v0.y, v0.cmd)); - + points.push_back(vertex2d(v0.x,v0.y,SEG_END)); std::size_t i = 0; v1 = points[i++]; v2 = points[i++];