Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Loading…

Conv simplify #1514

Merged
merged 36 commits into from

1 participant

@artemp
Owner

updated #1385

Konstantin K... and others added some commits
Konstantin Käfer simplify-tolerance property boilerplate dcd7a07
Konstantin Käfer otf visvalingam/whyatt simplification 483ba77
Konstantin Käfer don't crash on empty geometries eace6ee
Konstantin Käfer add facilities to choose the simplification algorithm 22150f9
Konstantin Käfer use a set to make visvalingam a lot faster b243f03
Konstantin Käfer Merge branch 'master' of git://github.com/mapnik/mapnik into conv_sim…
…plify

Conflicts:
	src/cairo_renderer.cpp
4e1423c
Konstantin Käfer Merge branch 'master' into conv_simplify
Conflicts:
	bindings/python/mapnik_line_symbolizer.cpp
	bindings/python/mapnik_polygon_symbolizer.cpp
13c46b6
Konstantin Käfer Merge branch 'master' of git://github.com/mapnik/mapnik into conv_sim…
…plify
f5ed45f
Konstantin Käfer Merge branch 'expose_feature_style_processor' into conv_simplify fd3aa8a
Konstantin Käfer copy algorithm value when copying symbolizer 49a07c6
Konstantin Käfer Merge branch 'master' into conv_simplify
Conflicts:
	include/mapnik/vertex_converters.hpp
ae865a5
@artemp artemp Merge branch 'conv_simplify' of git://github.com/kkaefer/mapnik into …
…kkaefer-conv_simplify
5f8bb42
@artemp artemp + make client methods non-static in classes derived from
  mapnik::singleton<> (TODO: apply to all)
+ ensure client methods are accessed through instance() method
8fa0742
@artemp artemp Merge branch 'master' into conv_simplify
Conflicts:
	bindings/python/mapnik_markers_symbolizer.cpp
	plugins/input/ogr/ogr_index_featureset.cpp
	plugins/input/shape/dbfile.cpp
	plugins/input/shape/shapefile.hpp
	src/load_map.cpp
29423cf
@artemp artemp Merge branch 'master' into conv_simplify f5b4ff9
@artemp artemp + zhao-saalfield intial impl (TODO: optimize) 06bae0a
@artemp artemp Merge branch 'master' into conv_simplify f66d4b1
@artemp artemp + discard 'almost' adjacent vertices
+ enforce 'min_size' in output path
820a0e9
@artemp artemp + check sleve_cont has at least two vertices d42c88a
@artemp artemp Merge branch 'master' into conv_simplify fb8f50b
@artemp artemp Merge branch 'master' into conv_simplify 01ae1a1
@artemp artemp Merge branch 'master' into conv_simplify 09d1112
@artemp artemp Merge remote-tracking branch 'origin/master' into conv_simplify a7c02cf
@artemp artemp Merge branch 'master' into conv_simplify 32d52a1
@artemp artemp + only log transform evaluation if trans_expr is not null fe011a9
@artemp artemp + work-in-progress.. a537c58
@artemp artemp Merge branch 'master' into conv_simplify d7abfc2
@artemp artemp + cleanups: use preincrement iterators in for loop etc .. 8228d99
@artemp artemp + formatting 03315ff
@artemp artemp + make WKT generator templated on geometry type - the goal is to be able
  to use generator for any type that implements 'vertex' concept
42bcf4e
@artemp artemp Merge branch 'master' into conv_simplify 98c3c82
@artemp artemp Merge remote-tracking branch 'origin' into conv_simplify 780ea26
@artemp artemp Merge branch 'master' into conv_simplify fbafbd9
@artemp artemp Merge branch 'master' into conv_simplify 30f14e0
@artemp artemp + make rewind() const f03e08b
@artemp artemp + use format_ 037c1a8
@artemp artemp merged commit f298af6 into from
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on Aug 14, 2012
  1. simplify-tolerance property boilerplate

    Konstantin Käfer authored
  2. otf visvalingam/whyatt simplification

    Konstantin Käfer authored
Commits on Aug 16, 2012
  1. don't crash on empty geometries

    Konstantin Käfer authored
  2. add facilities to choose the simplification algorithm

    Konstantin Käfer authored
  3. use a set to make visvalingam a lot faster

    Konstantin Käfer authored
Commits on Aug 24, 2012
  1. Merge branch 'master' of git://github.com/mapnik/mapnik into conv_sim…

    Konstantin Käfer authored
    …plify
    
    Conflicts:
    	src/cairo_renderer.cpp
  2. Merge branch 'master' into conv_simplify

    Konstantin Käfer authored
    Conflicts:
    	bindings/python/mapnik_line_symbolizer.cpp
    	bindings/python/mapnik_polygon_symbolizer.cpp
Commits on Aug 25, 2012
  1. Merge branch 'master' of git://github.com/mapnik/mapnik into conv_sim…

    Konstantin Käfer authored
    …plify
  2. Merge branch 'expose_feature_style_processor' into conv_simplify

    Konstantin Käfer authored
  3. copy algorithm value when copying symbolizer

    Konstantin Käfer authored
Commits on Aug 28, 2012
  1. Merge branch 'master' into conv_simplify

    Konstantin Käfer authored
    Conflicts:
    	include/mapnik/vertex_converters.hpp
Commits on Sep 6, 2012
  1. @artemp
Commits on Sep 7, 2012
  1. @artemp

    + make client methods non-static in classes derived from

    artemp authored
      mapnik::singleton<> (TODO: apply to all)
    + ensure client methods are accessed through instance() method
  2. @artemp

    Merge branch 'master' into conv_simplify

    artemp authored
    Conflicts:
    	bindings/python/mapnik_markers_symbolizer.cpp
    	plugins/input/ogr/ogr_index_featureset.cpp
    	plugins/input/shape/dbfile.cpp
    	plugins/input/shape/shapefile.hpp
    	src/load_map.cpp
Commits on Sep 10, 2012
  1. @artemp
Commits on Sep 12, 2012
  1. @artemp
Commits on Sep 13, 2012
  1. @artemp
  2. @artemp

    + discard 'almost' adjacent vertices

    artemp authored
    + enforce 'min_size' in output path
Commits on Sep 14, 2012
  1. @artemp
  2. @artemp
Commits on Sep 17, 2012
  1. @artemp
Commits on Sep 18, 2012
  1. @artemp
Commits on Sep 19, 2012
  1. @artemp
Commits on Sep 25, 2012
  1. @artemp
Commits on Sep 26, 2012
  1. @artemp
  2. @artemp

    + work-in-progress..

    artemp authored
Commits on Sep 27, 2012
  1. @artemp
  2. @artemp
  3. @artemp

    + formatting

    artemp authored
  4. @artemp

    + make WKT generator templated on geometry type - the goal is to be able

    artemp authored
      to use generator for any type that implements 'vertex' concept
  5. @artemp
Commits on Sep 28, 2012
  1. @artemp
Commits on Oct 1, 2012
  1. @artemp
  2. @artemp
  3. @artemp

    + make rewind() const

    artemp authored
  4. @artemp

    + use format_

    artemp authored
This page is out of date. Refresh to see the latest.
View
4 bindings/python/mapnik_line_symbolizer.cpp
@@ -48,6 +48,10 @@ void export_line_symbolizer()
(&line_symbolizer::get_stroke,
return_value_policy<reference_existing_object>()),
&line_symbolizer::set_stroke)
+ .add_property("simplify_tolerance",
+ &line_symbolizer::simplify_tolerance,
+ &line_symbolizer::set_simplify_tolerance,
+ "simplification tolerance measure")
.add_property("offset",
&line_symbolizer::offset,
&line_symbolizer::set_offset,
View
4 bindings/python/mapnik_polygon_symbolizer.cpp
@@ -60,6 +60,10 @@ void export_polygon_symbolizer()
&polygon_symbolizer::smooth,
&polygon_symbolizer::set_smooth,
"Set/get the polygon geometry's smooth value")
+ .add_property("simplify_tolerance",
+ &polygon_symbolizer::simplify_tolerance,
+ &polygon_symbolizer::set_simplify_tolerance,
+ "simplfication tolerance measure")
;
}
View
25 include/mapnik/simplify.hpp
@@ -0,0 +1,25 @@
+#ifndef MAPNIK_SIMPLIFY_HPP
+#define MAPNIK_SIMPLIFY_HPP
+
+#include <mapnik/debug.hpp>
+
+// Boost
+#include <boost/optional.hpp>
+
+namespace mapnik
+{
+
+enum simplify_algorithm_e
+{
+ radial_distance = 0,
+ douglas_peucker,
+ visvalingam_whyatt,
+ zhao_saalfeld
+};
+
+MAPNIK_DECL boost::optional<simplify_algorithm_e> simplify_algorithm_from_string(std::string const& name);
+MAPNIK_DECL boost::optional<std::string> simplify_algorithm_to_string(simplify_algorithm_e algorithm);
+
+}
+
+#endif // MAPNIK_SIMPLIFY_HPP
View
452 include/mapnik/simplify_converter.hpp
@@ -0,0 +1,452 @@
+#ifndef MAPNIK_SIMPLIFY_CONVERTER_HPP
+#define MAPNIK_SIMPLIFY_CONVERTER_HPP
+
+#include <mapnik/debug.hpp>
+#include <mapnik/box2d.hpp>
+#include <mapnik/vertex.hpp>
+#include <mapnik/simplify.hpp>
+
+// STL
+#include <limits>
+#include <set>
+#include <vector>
+#include <deque>
+// Boost
+#include <boost/optional.hpp>
+
+namespace mapnik
+{
+
+struct weighted_vertex : private boost::noncopyable
+{
+ vertex2d coord;
+ double weight;
+ weighted_vertex *prev;
+ weighted_vertex *next;
+
+ weighted_vertex(vertex2d coord_) :
+ coord(coord_),
+ weight(std::numeric_limits<double>::infinity()),
+ prev(NULL),
+ next(NULL) {}
+
+ double nominalWeight()
+ {
+ if (prev == NULL || next == NULL || coord.cmd != SEG_LINETO) {
+ return std::numeric_limits<double>::infinity();
+ }
+ vertex2d const& A = prev->coord;
+ vertex2d const& B = next->coord;
+ vertex2d const& C = coord;
+ return std::abs((double)((A.x - C.x) * (B.y - A.y) - (A.x - B.x) * (C.y - A.y))) / 2.0;
+ }
+
+ struct ascending_sort
+ {
+ bool operator() (const weighted_vertex *a, const weighted_vertex *b)
+ {
+ return b->weight > a->weight;
+ }
+ };
+};
+
+struct sleeve
+{
+ vertex2d v[5];
+
+ sleeve(vertex2d const& v0, vertex2d const& v1, double offset)
+ {
+ double a = atan2((v1.y - v0.y), (v1.x - v0.x));
+ double dx = offset * cos(a);
+ double dy = offset * sin(a);
+ v[0].x = v0.x + dy;
+ v[0].y = v0.y - dx;
+ v[1].x = v0.x - dy;
+ v[1].y = v0.y + dx;
+ v[2].x = v1.x - dy;
+ v[2].y = v1.y + dx;
+ v[3].x = v1.x + dy;
+ v[3].y = v1.y - dx;
+ v[4].x = v0.x + dy;
+ v[4].y = v0.y - dx;
+ }
+
+ bool inside(vertex2d const& q)
+ {
+ bool inside=false;
+
+ for (unsigned i=0;i<4;++i)
+ {
+ if ((((v[i+1].y <= q.y) && (q.y < v[i].y)) ||
+ ((v[i].y <= q.y) && (q.y < v[i+1].y))) &&
+ (q.x < (v[i].x - v[i+1].x) * (q.y - v[i+1].y)/ (v[i].y - v[i+1].y) + v[i+1].x))
+ inside=!inside;
+ }
+ return inside;
+ }
+ void print()
+ {
+ std::cerr << "LINESTRING("
+ << v[0].x << " " << -v[0].y << ","
+ << v[1].x << " " << -v[1].y << ","
+ << v[2].x << " " << -v[2].y << ","
+ << v[3].x << " " << -v[3].y << ","
+ << v[0].x << " " << -v[0].y << ")" << std::endl;
+
+ }
+};
+
+template <typename Geometry>
+struct MAPNIK_DECL simplify_converter
+{
+public:
+ simplify_converter(Geometry& geom)
+ : geom_(geom),
+ tolerance_(0.0),
+ status_(initial),
+ algorithm_(radial_distance),
+ pos_(0)
+ {}
+
+ enum status
+ {
+ initial,
+ process,
+ closing,
+ end,
+ cache
+ };
+
+ simplify_algorithm_e get_simplify_algorithm()
+ {
+ return algorithm_;
+ }
+
+ void set_simplify_algorithm(simplify_algorithm_e value)
+ {
+ if (algorithm_ != value)
+ {
+ algorithm_ = value;
+ reset();
+ }
+ }
+
+ double get_simplify_tolerance()
+ {
+ return tolerance_;
+ }
+
+ void set_simplify_tolerance(double value)
+ {
+ if (tolerance_ != value) {
+ tolerance_ = value;
+ reset();
+ }
+ }
+
+ void reset()
+ {
+ geom_.rewind(0);
+ vertices_.clear();
+ status_ = initial;
+ pos_ = 0;
+ }
+
+ void rewind(unsigned int) const
+ {
+ pos_ = 0;
+ }
+
+ unsigned vertex(double* x, double* y)
+ {
+ if (tolerance_ == 0.0)
+ return geom_.vertex(x, y);
+
+ if (status_ == initial)
+ init_vertices();
+
+ return output_vertex(x, y);
+ }
+
+private:
+ unsigned output_vertex(double* x, double* y)
+ {
+ switch (algorithm_)
+ {
+ case visvalingam_whyatt:
+ return output_vertex_cached(x, y);
+ case radial_distance:
+ return output_vertex_distance(x, y);
+ case zhao_saalfeld:
+ return output_vertex_sleeve(x, y);
+ default:
+ throw std::runtime_error("simplification algorithm not yet implemented");
+ }
+
+ return SEG_END;
+ }
+
+ unsigned output_vertex_cached(double* x, double* y) {
+ if (pos_ >= vertices_.size())
+ return SEG_END;
+
+ previous_vertex_ = vertices_[pos_];
+ *x = previous_vertex_.x;
+ *y = previous_vertex_.y;
+ pos_++;
+ return previous_vertex_.cmd;
+ }
+
+ unsigned output_vertex_distance(double* x, double* y) {
+ if (status_ == closing) {
+ status_ = end;
+ return SEG_CLOSE;
+ }
+
+ vertex2d last(vertex2d::no_init);
+ vertex2d vtx(vertex2d::no_init);
+ while ((vtx.cmd = geom_.vertex(&vtx.x, &vtx.y)) != SEG_END)
+ {
+ if (vtx.cmd == SEG_LINETO) {
+ if (distance_to_previous(vtx) > tolerance_) {
+ // Only output a vertex if it's far enough away from the previous
+ break;
+ } else {
+ last = vtx;
+ // continue
+ }
+ } else if (vtx.cmd == SEG_CLOSE) {
+ if (last.cmd == vertex2d::no_init) {
+ // The previous vertex was already output in the previous call.
+ // We can now safely output SEG_CLOSE.
+ status_ = end;
+ } else {
+ // We eliminated the previous point because it was too close, but
+ // we have to output it now anyway, since this is the end of the
+ // vertex stream. Make sure that we output SEG_CLOSE in the next call.
+ vtx = last;
+ status_ = closing;
+ }
+ break;
+ } else if (vtx.cmd == SEG_MOVETO) {
+ break;
+ } else {
+ throw std::runtime_error("Unknown vertex command");
+ }
+ }
+
+ previous_vertex_ = vtx;
+ *x = vtx.x;
+ *y = vtx.y;
+ return vtx.cmd;
+ }
+
+ template <typename Iterator>
+ bool fit_sleeve(Iterator itr,Iterator end, vertex2d const& v)
+ {
+ sleeve s(*itr,v,tolerance_);
+ ++itr; // skip first vertex
+ for (; itr!=end; ++itr)
+ {
+ if (!s.inside(*itr))
+ {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ unsigned output_vertex_sleeve(double* x, double* y)
+ {
+ vertex2d vtx(vertex2d::no_init);
+ std::size_t min_size = 1;
+ while ((vtx.cmd = geom_.vertex(&vtx.x, &vtx.y)) != SEG_END)
+ {
+ //if ((std::fabs(vtx.x - previous_vertex_.x) < 0.5) &&
+ // (std::fabs(vtx.y - previous_vertex_.y) < 0.5))
+ // continue;
+
+ if (status_ == cache &&
+ vertices_.size() >= min_size)
+ status_ = process;
+
+ previous_vertex_ = vtx;
+
+ if (vtx.cmd == SEG_MOVETO)
+ {
+ if (sleeve_cont_.size() > 1)
+ {
+ vertices_.push_back(sleeve_cont_.back());
+ sleeve_cont_.clear();
+ }
+ vertices_.push_back(vtx);
+ sleeve_cont_.push_back(vtx);
+ if (status_ == process) break;
+ }
+ else if (vtx.cmd == SEG_LINETO)
+ {
+ if (sleeve_cont_.size() > 1 && !fit_sleeve(sleeve_cont_.begin(), sleeve_cont_.end(), vtx))
+ {
+ vertex2d last = vtx;
+ vtx = sleeve_cont_.back();
+ sleeve_cont_.clear();
+ sleeve_cont_.push_back(vtx);
+ sleeve_cont_.push_back(last);
+ vertices_.push_back(vtx);
+ if (status_ == process) break;
+ }
+ else
+ {
+ sleeve_cont_.push_back(vtx);
+ }
+ }
+ else if (vtx.cmd == SEG_CLOSE)
+ {
+ if (sleeve_cont_.size() > 1)
+ {
+ vertices_.push_back(sleeve_cont_.back());
+ sleeve_cont_.clear();
+ }
+ vertices_.push_back(vtx);
+ if (status_ == process) break;
+ }
+ }
+
+ if (status_ == cache)
+ {
+ if (vertices_.size() < min_size)
+ return SEG_END;
+ status_ = process;
+ }
+
+ if (vtx.cmd == SEG_END)
+ {
+ if (sleeve_cont_.size() > 1)
+ {
+ vertices_.push_back(sleeve_cont_.back());
+ }
+ sleeve_cont_.clear();
+ vertices_.push_back(vtx);
+ }
+
+ if (vertices_.size() > 0)
+ {
+ vertex2d v = vertices_.front();
+ vertices_.pop_front();
+ *x = v.x;
+ *y = v.y;
+ return v.cmd;
+ }
+ return SEG_END;
+ }
+
+ double distance_to_previous(vertex2d const& vtx) {
+ double dx = previous_vertex_.x - vtx.x;
+ double dy = previous_vertex_.y - vtx.y;
+ return dx * dx + dy * dy;
+ }
+
+ status init_vertices()
+ {
+ if (status_ != initial) // already initialized
+ return status_;
+
+ reset();
+
+ switch (algorithm_) {
+ case visvalingam_whyatt:
+ return init_vertices_visvalingam_whyatt();
+ case radial_distance:
+ // Use
+ vertices_.push_back(vertex2d(vertex2d::no_init));
+ return status_ = process;
+ case zhao_saalfeld:
+ return status_ = cache;
+ default:
+ throw std::runtime_error("simplification algorithm not yet implemented");
+ }
+ }
+
+ status init_vertices_visvalingam_whyatt()
+ {
+ typedef std::set<weighted_vertex *, weighted_vertex::ascending_sort> VertexSet;
+ typedef std::vector<weighted_vertex *> VertexList;
+
+ std::vector<weighted_vertex *> v_list;
+ vertex2d vtx(vertex2d::no_init);
+ while ((vtx.cmd = geom_.vertex(&vtx.x, &vtx.y)) != SEG_END)
+ {
+ v_list.push_back(new weighted_vertex(vtx));
+ }
+
+ if (v_list.empty()) {
+ return status_ = process;
+ }
+
+ // Connect the vertices in a linked list and insert them into the set.
+ VertexSet v;
+ for (VertexList::iterator i = v_list.begin(); i != v_list.end(); ++i)
+ {
+ (*i)->prev = i == v_list.begin() ? NULL : *(i - 1);
+ (*i)->next = i + 1 == v_list.end() ? NULL : *(i + 1);
+ (*i)->weight = (*i)->nominalWeight();
+ v.insert(*i);
+ }
+
+ // Use Visvalingam-Whyatt algorithm to calculate each point's weight.
+ while (v.size() > 0)
+ {
+ VertexSet::iterator lowest = v.begin();
+ weighted_vertex *removed = *lowest;
+ if (removed->weight >= tolerance_) {
+ break;
+ }
+
+ v.erase(lowest);
+
+ // Connect adjacent vertices with each other
+ if (removed->prev) removed->prev->next = removed->next;
+ if (removed->next) removed->next->prev = removed->prev;
+ // Adjust weight and reinsert prev/next to move them to their correct position.
+ if (removed->prev) {
+ v.erase(removed->prev);
+ removed->prev->weight = std::max(removed->weight, removed->prev->nominalWeight());
+ v.insert(removed->prev);
+ }
+ if (removed->next) {
+ v.erase(removed->next);
+ removed->next->weight = std::max(removed->weight, removed->next->nominalWeight());
+ v.insert(removed->next);
+ }
+ }
+
+ v.clear();
+
+ // Traverse the remaining list and insert them into the vertex cache.
+ for (VertexList::iterator i = v_list.begin(); i != v_list.end(); ++i)
+ {
+ if ((*i)->weight >= tolerance_)
+ {
+ vertices_.push_back((*i)->coord);
+ }
+ delete *i;
+ }
+
+ // Initialization finished.
+ return status_ = process;
+ }
+
+ Geometry& geom_;
+ double tolerance_;
+ status status_;
+ simplify_algorithm_e algorithm_;
+ std::deque<vertex2d> vertices_;
+ std::deque<vertex2d> sleeve_cont_;
+ vertex2d previous_vertex_;
+ mutable size_t pos_;
+};
+
+
+}
+
+#endif // MAPNIK_SIMPLIFY_CONVERTER_HPP
View
7 include/mapnik/symbolizer.hpp
@@ -28,6 +28,7 @@
#include <mapnik/parse_path.hpp>
#include <mapnik/image_compositing.hpp>
#include <mapnik/transform_expression.hpp>
+#include <mapnik/simplify.hpp>
// boost
#include <boost/array.hpp>
@@ -55,12 +56,18 @@ class MAPNIK_DECL symbolizer_base
std::string get_transform_string() const;
void set_clip(bool clip);
bool clip() const;
+ void set_simplify_algorithm(simplify_algorithm_e algorithm);
+ simplify_algorithm_e simplify_algorithm() const;
+ void set_simplify_tolerance(double simplify_tolerance);
+ double simplify_tolerance() const;
void set_smooth(double smooth);
double smooth() const;
private:
composite_mode_e comp_op_;
transform_type affine_transform_;
bool clip_;
+ simplify_algorithm_e simplify_algorithm_value_;
+ double simplify_tolerance_value_;
double smooth_value_;
};
View
1  include/mapnik/utils.hpp
@@ -140,6 +140,7 @@ template <typename T,
{
if (destroyed_)
{
+ destroyed_ = false;
onDeadReference();
}
else
View
17 include/mapnik/vertex_converters.hpp
@@ -48,9 +48,9 @@
#include <boost/array.hpp>
// mapnik
-#include <mapnik/ctrans.hpp>
#include <mapnik/agg_helpers.hpp>
#include <mapnik/offset_converter.hpp>
+#include <mapnik/simplify_converter.hpp>
// agg
#include "agg_conv_clip_polygon.h"
@@ -60,12 +60,14 @@
#include "agg_conv_dash.h"
#include "agg_conv_transform.h"
+
namespace mapnik {
struct transform_tag {};
struct clip_line_tag {};
struct clip_poly_tag {};
struct smooth_tag {};
+struct simplify_tag {};
struct stroke_tag {};
struct dash_tag {};
struct affine_transform_tag {};
@@ -98,6 +100,19 @@ struct converter_traits<T,mapnik::smooth_tag>
}
};
+template <typename T>
+struct converter_traits<T,mapnik::simplify_tag>
+{
+ typedef T geometry_type;
+ typedef simplify_converter<geometry_type> conv_type;
+
+ template <typename Args>
+ static void setup(geometry_type & geom, Args const& args)
+ {
+ geom.set_simplify_algorithm(boost::fusion::at_c<2>(args).simplify_algorithm());
+ geom.set_simplify_tolerance(boost::fusion::at_c<2>(args).simplify_tolerance());
+ }
+};
template <typename T>
struct converter_traits<T, mapnik::clip_line_tag>
View
2  plugins/input/sqlite/sqlite_datasource.cpp
@@ -524,7 +524,7 @@ boost::optional<mapnik::datasource::geometry_t> sqlite_datasource::get_geometry_
if (data)
{
boost::ptr_vector<mapnik::geometry_type> paths;
- if (mapnik::geometry_utils::from_wkb(paths, data, size, mapnik::wkbAuto))
+ if (mapnik::geometry_utils::from_wkb(paths, data, size, format_))
{
mapnik::util::to_ds_type(paths,result);
if (result)
View
3  src/agg/process_line_pattern_symbolizer.cpp
@@ -109,13 +109,14 @@ void agg_renderer<T>::process(line_pattern_symbolizer const& sym,
clipping_extent.init(x0 - padding, y0 - padding, x1 + padding , y1 + padding);
}
- typedef boost::mpl::vector<clip_line_tag,transform_tag,smooth_tag> conv_types;
+ typedef boost::mpl::vector<clip_line_tag,transform_tag,simplify_tag,smooth_tag> conv_types;
vertex_converter<box2d<double>, rasterizer_type, line_pattern_symbolizer,
CoordTransform, proj_transform, agg::trans_affine, conv_types>
converter(clipping_extent,ras,sym,t_,prj_trans,tr,scale_factor_);
if (sym.clip()) converter.set<clip_line_tag>(); //optional clip (default: true)
converter.set<transform_tag>(); //always transform
+ if (sym.simplify_tolerance() > 0.0) converter.set<simplify_tag>(); // optional simplify converter
if (sym.smooth() > 0.0) converter.set<smooth_tag>(); // optional smooth converter
BOOST_FOREACH(geometry_type & geom, feature.paths())
View
4 src/agg/process_line_symbolizer.cpp
@@ -76,7 +76,7 @@ void agg_renderer<T>::process(line_symbolizer const& sym,
typedef agg::renderer_base<pixfmt_comp_type> renderer_base;
typedef boost::mpl::vector<clip_line_tag, transform_tag,
offset_transform_tag, affine_transform_tag,
- smooth_tag, dash_tag, stroke_tag> conv_types;
+ simplify_tag, smooth_tag, dash_tag, stroke_tag> conv_types;
pixfmt_comp_type pixf(buf);
pixf.comp_op(static_cast<agg::comp_op_e>(sym.comp_op()));
@@ -121,6 +121,7 @@ void agg_renderer<T>::process(line_symbolizer const& sym,
converter.set<transform_tag>(); // always transform
if (fabs(sym.offset()) > 0.0) converter.set<offset_transform_tag>(); // parallel offset
converter.set<affine_transform_tag>(); // optional affine transform
+ if (sym.simplify_tolerance() > 0.0) converter.set<simplify_tag>(); // optional simplify converter
if (sym.smooth() > 0.0) converter.set<smooth_tag>(); // optional smooth converter
BOOST_FOREACH( geometry_type & geom, feature.paths())
@@ -141,6 +142,7 @@ void agg_renderer<T>::process(line_symbolizer const& sym,
converter.set<transform_tag>(); // always transform
if (fabs(sym.offset()) > 0.0) converter.set<offset_transform_tag>(); // parallel offset
converter.set<affine_transform_tag>(); // optional affine transform
+ if (sym.simplify_tolerance() > 0.0) converter.set<simplify_tag>(); // optional simplify converter
if (sym.smooth() > 0.0) converter.set<smooth_tag>(); // optional smooth converter
if (stroke_.has_dash()) converter.set<dash_tag>();
converter.set<stroke_tag>(); //always stroke
View
3  src/agg/process_polygon_pattern_symbolizer.cpp
@@ -139,13 +139,14 @@ void agg_renderer<T>::process(polygon_pattern_symbolizer const& sym,
agg::trans_affine tr;
evaluate_transform(tr, feature, sym.get_transform());
- typedef boost::mpl::vector<clip_poly_tag,transform_tag,smooth_tag> conv_types;
+ typedef boost::mpl::vector<clip_poly_tag,transform_tag,simplify_tag,smooth_tag> conv_types;
vertex_converter<box2d<double>, rasterizer, polygon_pattern_symbolizer,
CoordTransform, proj_transform, agg::trans_affine, conv_types>
converter(query_extent_,*ras_ptr,sym,t_,prj_trans,tr,scale_factor_);
if (prj_trans.equal() && sym.clip()) converter.set<clip_poly_tag>(); //optional clip (default: true)
converter.set<transform_tag>(); //always transform
+ if (sym.simplify_tolerance() > 0.0) converter.set<simplify_tag>(); // optional simplify converter
if (sym.smooth() > 0.0) converter.set<smooth_tag>(); // optional smooth converter
BOOST_FOREACH( geometry_type & geom, feature.paths())
View
3  src/agg/process_polygon_symbolizer.cpp
@@ -51,7 +51,7 @@ void agg_renderer<T>::process(polygon_symbolizer const& sym,
agg::trans_affine tr;
evaluate_transform(tr, feature, sym.get_transform());
- typedef boost::mpl::vector<clip_poly_tag,transform_tag,affine_transform_tag,smooth_tag> conv_types;
+ typedef boost::mpl::vector<clip_poly_tag,transform_tag,affine_transform_tag,simplify_tag,smooth_tag> conv_types;
vertex_converter<box2d<double>, rasterizer, polygon_symbolizer,
CoordTransform, proj_transform, agg::trans_affine, conv_types>
converter(query_extent_,*ras_ptr,sym,t_,prj_trans,tr,scale_factor_);
@@ -59,6 +59,7 @@ void agg_renderer<T>::process(polygon_symbolizer const& sym,
if (prj_trans.equal() && sym.clip()) converter.set<clip_poly_tag>(); //optional clip (default: true)
converter.set<transform_tag>(); //always transform
converter.set<affine_transform_tag>();
+ if (sym.simplify_tolerance() > 0.0) converter.set<simplify_tag>(); // optional simplify converter
if (sym.smooth() > 0.0) converter.set<smooth_tag>(); // optional smooth converter
BOOST_FOREACH( geometry_type & geom, feature.paths())
View
1  src/build.py
@@ -151,6 +151,7 @@ def ldconfig(*args,**kwargs):
proj_transform.cpp
distance.cpp
scale_denominator.cpp
+ simplify.cpp
memory_datasource.cpp
stroke.cpp
symbolizer.cpp
View
9 src/cairo_renderer.cpp
@@ -865,7 +865,7 @@ void cairo_renderer_base::process(polygon_symbolizer const& sym,
agg::trans_affine tr;
evaluate_transform(tr, feature, sym.get_transform());
- typedef boost::mpl::vector<clip_poly_tag,transform_tag,affine_transform_tag,smooth_tag> conv_types;
+ typedef boost::mpl::vector<clip_poly_tag,transform_tag,affine_transform_tag,simplify_tag,smooth_tag> conv_types;
vertex_converter<box2d<double>, cairo_context, polygon_symbolizer,
CoordTransform, proj_transform, agg::trans_affine, conv_types>
converter(query_extent_,context,sym,t_,prj_trans,tr,1.0);
@@ -873,6 +873,7 @@ void cairo_renderer_base::process(polygon_symbolizer const& sym,
if (prj_trans.equal() && sym.clip()) converter.set<clip_poly_tag>(); //optional clip (default: true)
converter.set<transform_tag>(); //always transform
converter.set<affine_transform_tag>();
+ if (sym.simplify_tolerance() > 0.0) converter.set<simplify_tag>(); // optional simplify converter
if (sym.smooth() > 0.0) converter.set<smooth_tag>(); // optional smooth converter
BOOST_FOREACH( geometry_type & geom, feature.paths())
@@ -989,7 +990,7 @@ void cairo_renderer_base::process(line_symbolizer const& sym,
{
typedef boost::mpl::vector<clip_line_tag, transform_tag,
offset_transform_tag, affine_transform_tag,
- smooth_tag, dash_tag, stroke_tag> conv_types;
+ simplify_tag, smooth_tag, dash_tag, stroke_tag> conv_types;
cairo_context context(context_);
mapnik::stroke const& stroke_ = sym.get_stroke();
context.set_operator(sym.comp_op());
@@ -1030,6 +1031,7 @@ void cairo_renderer_base::process(line_symbolizer const& sym,
converter.set<transform_tag>(); // always transform
if (fabs(sym.offset()) > 0.0) converter.set<offset_transform_tag>(); // parallel offset
converter.set<affine_transform_tag>(); // optional affine transform
+ if (sym.simplify_tolerance() > 0.0) converter.set<simplify_tag>(); // optional simplify converter
if (sym.smooth() > 0.0) converter.set<smooth_tag>(); // optional smooth converter
BOOST_FOREACH( geometry_type & geom, feature.paths())
@@ -1386,7 +1388,7 @@ void cairo_renderer_base::process(polygon_pattern_symbolizer const& sym,
agg::trans_affine tr;
evaluate_transform(tr, feature, sym.get_transform());
- typedef boost::mpl::vector<clip_poly_tag,transform_tag,affine_transform_tag,smooth_tag> conv_types;
+ typedef boost::mpl::vector<clip_poly_tag,transform_tag,affine_transform_tag,simplify_tag,smooth_tag> conv_types;
vertex_converter<box2d<double>, cairo_context, polygon_pattern_symbolizer,
CoordTransform, proj_transform, agg::trans_affine, conv_types>
converter(query_extent_,context,sym,t_,prj_trans,tr, scale_factor_);
@@ -1394,6 +1396,7 @@ void cairo_renderer_base::process(polygon_pattern_symbolizer const& sym,
if (prj_trans.equal() && sym.clip()) converter.set<clip_poly_tag>(); //optional clip (default: true)
converter.set<transform_tag>(); //always transform
converter.set<affine_transform_tag>();
+ if (sym.simplify_tolerance() > 0.0) converter.set<simplify_tag>(); // optional simplify converter
if (sym.smooth() > 0.0) converter.set<smooth_tag>(); // optional smooth converter
BOOST_FOREACH( geometry_type & geom, feature.paths())
View
3  src/grid/process_line_symbolizer.cpp
@@ -54,7 +54,7 @@ void grid_renderer<T>::process(line_symbolizer const& sym,
typedef agg::renderer_scanline_bin_solid<renderer_base> renderer_type;
typedef boost::mpl::vector<clip_line_tag, transform_tag,
offset_transform_tag, affine_transform_tag,
- smooth_tag, dash_tag, stroke_tag> conv_types;
+ simplify_tag, smooth_tag, dash_tag, stroke_tag> conv_types;
agg::scanline_bin sl;
grid_rendering_buffer buf(pixmap_.raw_data(), width_, height_, width_);
@@ -93,6 +93,7 @@ void grid_renderer<T>::process(line_symbolizer const& sym,
converter.set<transform_tag>(); // always transform
if (fabs(sym.offset()) > 0.0) converter.set<offset_transform_tag>(); // parallel offset
converter.set<affine_transform_tag>(); // optional affine transform
+ if (sym.simplify_tolerance() > 0.0) converter.set<simplify_tag>(); // optional simplify converter
if (sym.smooth() > 0.0) converter.set<smooth_tag>(); // optional smooth converter
if (stroke_.has_dash()) converter.set<dash_tag>();
converter.set<stroke_tag>(); //always stroke
View
3  src/grid/process_polygon_symbolizer.cpp
@@ -53,7 +53,7 @@ void grid_renderer<T>::process(polygon_symbolizer const& sym,
agg::trans_affine tr;
evaluate_transform(tr, feature, sym.get_transform());
- typedef boost::mpl::vector<clip_poly_tag,transform_tag,affine_transform_tag,smooth_tag> conv_types;
+ typedef boost::mpl::vector<clip_poly_tag,transform_tag,affine_transform_tag,simplify_tag,smooth_tag> conv_types;
vertex_converter<box2d<double>, grid_rasterizer, polygon_symbolizer,
CoordTransform, proj_transform, agg::trans_affine, conv_types>
converter(query_extent_,*ras_ptr,sym,t_,prj_trans,tr,scale_factor_);
@@ -61,6 +61,7 @@ void grid_renderer<T>::process(polygon_symbolizer const& sym,
if (prj_trans.equal() && sym.clip()) converter.set<clip_poly_tag>(); //optional clip (default: true)
converter.set<transform_tag>(); //always transform
converter.set<affine_transform_tag>();
+ if (sym.simplify_tolerance() > 0.0) converter.set<simplify_tag>(); // optional simplify converter
if (sym.smooth() > 0.0) converter.set<smooth_tag>(); // optional smooth converter
View
19 src/load_map.cpp
@@ -858,6 +858,25 @@ void map_parser::parse_symbolizer_base(symbolizer_base &sym, xml_node const &pt)
optional<boolean> clip = pt.get_opt_attr<boolean>("clip");
if (clip) sym.set_clip(*clip);
+ // simplify algorithm
+ optional<std::string> simplify_algorithm_name = pt.get_opt_attr<std::string>("simplify-algorithm");
+ if (simplify_algorithm_name)
+ {
+ optional<simplify_algorithm_e> simplify_algorithm = simplify_algorithm_from_string(*simplify_algorithm_name);
+ if (simplify_algorithm)
+ {
+ sym.set_simplify_algorithm(*simplify_algorithm);
+ }
+ else
+ {
+ throw config_error("failed to parse simplify-algorithm: '" + *simplify_algorithm_name + "'");
+ }
+ }
+
+ // simplify value
+ optional<double> simplify_tolerance = pt.get_opt_attr<double>("simplify-tolerance");
+ if (simplify_tolerance) sym.set_simplify_tolerance(*simplify_tolerance);
+
// smooth value
optional<double> smooth = pt.get_opt_attr<double>("smooth");
if (smooth) sym.set_smooth(*smooth);
View
8 src/save_map.cpp
@@ -350,6 +350,14 @@ class serialize_symbolizer : public boost::static_visitor<>
{
set_attr( node, "clip", sym.clip() );
}
+ if (sym.simplify_algorithm() != dfl.simplify_algorithm() || explicit_defaults_)
+ {
+ set_attr( node, "simplify-algorithm", *simplify_algorithm_to_string(sym.simplify_algorithm()) );
+ }
+ if (sym.simplify_tolerance() != dfl.simplify_tolerance() || explicit_defaults_)
+ {
+ set_attr( node, "simplify-tolerance", sym.simplify_tolerance() );
+ }
if (sym.smooth() != dfl.smooth() || explicit_defaults_)
{
set_attr( node, "smooth", sym.smooth() );
View
41 src/simplify.cpp
@@ -0,0 +1,41 @@
+// mapnik
+#include <mapnik/simplify.hpp>
+
+// boost
+#include <boost/assign/list_of.hpp>
+#include <boost/bimap.hpp>
+
+namespace mapnik
+{
+
+typedef boost::bimap<simplify_algorithm_e, std::string> simplify_algorithm_lookup_type;
+static const simplify_algorithm_lookup_type simplify_lookup = boost::assign::list_of<simplify_algorithm_lookup_type::relation>
+ (radial_distance,"radial-distance")
+ (douglas_peucker,"douglas-peucker")
+ (visvalingam_whyatt,"visvalingam-whyatt")
+ (zhao_saalfeld,"zhao-saalfeld")
+ ;
+
+boost::optional<simplify_algorithm_e> simplify_algorithm_from_string(std::string const& name)
+{
+ boost::optional<simplify_algorithm_e> algo;
+ simplify_algorithm_lookup_type::right_const_iterator right_iter = simplify_lookup.right.find(name);
+ if (right_iter != simplify_lookup.right.end())
+ {
+ algo.reset(right_iter->second);
+ }
+ return algo;
+}
+
+boost::optional<std::string> simplify_algorithm_to_string(simplify_algorithm_e value)
+{
+ boost::optional<std::string> algo;
+ simplify_algorithm_lookup_type::left_const_iterator left_iter = simplify_lookup.left.find(value);
+ if (left_iter != simplify_lookup.left.end())
+ {
+ algo.reset(left_iter->second);
+ }
+ return algo;
+}
+
+}
View
24 src/symbolizer.cpp
@@ -44,6 +44,8 @@ void evaluate_transform(agg::trans_affine& tr, Feature const& feature,
symbolizer_base::symbolizer_base()
: comp_op_(src_over),
clip_(true),
+ simplify_algorithm_value_(radial_distance),
+ simplify_tolerance_value_(0.0),
smooth_value_(0.0)
{
}
@@ -53,6 +55,8 @@ symbolizer_base::symbolizer_base(symbolizer_base const& other)
: comp_op_(other.comp_op_),
affine_transform_(other.affine_transform_),
clip_(other.clip_),
+ simplify_algorithm_value_(other.simplify_algorithm_value_),
+ simplify_tolerance_value_(other.simplify_tolerance_value_),
smooth_value_(other.smooth_value_) {}
void symbolizer_base::set_comp_op(composite_mode_e comp_op)
@@ -100,6 +104,26 @@ bool symbolizer_base::clip() const
return clip_;
}
+void symbolizer_base::set_simplify_algorithm(simplify_algorithm_e algo)
+{
+ simplify_algorithm_value_ = algo;
+}
+
+simplify_algorithm_e symbolizer_base::simplify_algorithm() const
+{
+ return simplify_algorithm_value_;
+}
+
+void symbolizer_base::set_simplify_tolerance(double simplify_tolerance)
+{
+ simplify_tolerance_value_ = simplify_tolerance;
+}
+
+double symbolizer_base::simplify_tolerance() const
+{
+ return simplify_tolerance_value_;
+}
+
void symbolizer_base::set_smooth(double smooth)
{
smooth_value_ = smooth;
Something went wrong with that request. Please try again.