From c677b4f47cb1755857590ab7deaee90bf42c8e13 Mon Sep 17 00:00:00 2001 From: Dane Springmeyer Date: Wed, 4 Jul 2012 18:34:04 -0700 Subject: [PATCH 001/133] ensure the bounds used for avoid-edges and minimum-padding is non-buffered - refs #1283 --- include/mapnik/cairo_renderer.hpp | 7 +++++-- src/agg/process_shield_symbolizer.cpp | 5 +++-- src/agg/process_text_symbolizer.cpp | 5 +++-- src/cairo_renderer.cpp | 22 +++++++++++++++++----- src/grid/process_shield_symbolizer.cpp | 4 ++-- src/grid/process_text_symbolizer.cpp | 2 +- 6 files changed, 31 insertions(+), 14 deletions(-) diff --git a/include/mapnik/cairo_renderer.hpp b/include/mapnik/cairo_renderer.hpp index 3fe8f5344..73d5e4f47 100644 --- a/include/mapnik/cairo_renderer.hpp +++ b/include/mapnik/cairo_renderer.hpp @@ -72,7 +72,7 @@ private: class MAPNIK_DECL cairo_renderer_base : private boost::noncopyable { protected: - cairo_renderer_base(Map const& m, Cairo::RefPtr const& context, unsigned offset_x=0, unsigned offset_y=0); + cairo_renderer_base(Map const& m, Cairo::RefPtr const& context, double scale_factor=1.0, unsigned offset_x=0, unsigned offset_y=0); public: ~cairo_renderer_base(); void start_map_processing(Map const& map); @@ -127,6 +127,9 @@ protected: Map const& m_; Cairo::RefPtr context_; + unsigned width_; + unsigned height_; + double scale_factor_; CoordTransform t_; boost::shared_ptr font_engine_; face_manager font_manager_; @@ -141,7 +144,7 @@ class MAPNIK_DECL cairo_renderer : public feature_style_processor const& surface, unsigned offset_x=0, unsigned offset_y=0); + cairo_renderer(Map const& m, Cairo::RefPtr const& surface, double scale_factor=1.0, unsigned offset_x=0, unsigned offset_y=0); void end_map_processing(Map const& map); }; } diff --git a/src/agg/process_shield_symbolizer.cpp b/src/agg/process_shield_symbolizer.cpp index b900c3bca..45e7c04f1 100644 --- a/src/agg/process_shield_symbolizer.cpp +++ b/src/agg/process_shield_symbolizer.cpp @@ -42,9 +42,10 @@ void agg_renderer::process(shield_symbolizer const& sym, shield_symbolizer_helper, label_collision_detector4> helper( sym, feature, prj_trans, - detector_->extent().width(), detector_->extent().height(), + width_, height_, scale_factor_, - t_, font_manager_, *detector_, query_extent_); + t_, font_manager_, *detector_, + query_extent_); text_renderer ren(*current_buffer_, font_manager_, diff --git a/src/agg/process_text_symbolizer.cpp b/src/agg/process_text_symbolizer.cpp index 52ed7a823..2d0988640 100644 --- a/src/agg/process_text_symbolizer.cpp +++ b/src/agg/process_text_symbolizer.cpp @@ -35,9 +35,10 @@ void agg_renderer::process(text_symbolizer const& sym, text_symbolizer_helper, label_collision_detector4> helper( sym, feature, prj_trans, - detector_->extent().width(), detector_->extent().height(), + width_,height_, scale_factor_, - t_, font_manager_, *detector_, query_extent_); + t_, font_manager_, *detector_, + query_extent_); text_renderer ren(*current_buffer_, font_manager_, diff --git a/src/cairo_renderer.cpp b/src/cairo_renderer.cpp index fc07684b7..02794ad49 100644 --- a/src/cairo_renderer.cpp +++ b/src/cairo_renderer.cpp @@ -737,9 +737,16 @@ private: Cairo::RefPtr context_; }; -cairo_renderer_base::cairo_renderer_base(Map const& m, Cairo::RefPtr const& context, unsigned offset_x, unsigned offset_y) +cairo_renderer_base::cairo_renderer_base(Map const& m, + Cairo::RefPtr const& context, + double scale_factor, + unsigned offset_x, + unsigned offset_y) : m_(m), context_(context), + width_(m.width()), + height_(m.height()), + scale_factor_(scale_factor), t_(m.width(),m.height(),m.get_current_extent(),offset_x,offset_y), font_engine_(boost::make_shared()), font_manager_(*font_engine_), @@ -750,14 +757,14 @@ cairo_renderer_base::cairo_renderer_base(Map const& m, Cairo::RefPtr -cairo_renderer::cairo_renderer(Map const& m, Cairo::RefPtr const& context, unsigned offset_x, unsigned offset_y) +cairo_renderer::cairo_renderer(Map const& m, Cairo::RefPtr const& context, double scale_factor, unsigned offset_x, unsigned offset_y) : feature_style_processor(m), cairo_renderer_base(m,context,offset_x,offset_y) { } template <> -cairo_renderer::cairo_renderer(Map const& m, Cairo::RefPtr const& surface, unsigned offset_x, unsigned offset_y) +cairo_renderer::cairo_renderer(Map const& m, Cairo::RefPtr const& surface, double scale_factor, unsigned offset_x, unsigned offset_y) : feature_style_processor(m), cairo_renderer_base(m,Cairo::Context::create(surface),offset_x,offset_y) { @@ -1192,7 +1199,7 @@ void cairo_renderer_base::start_map_processing(Map const& map) shield_symbolizer_helper, label_collision_detector4> helper( sym, feature, prj_trans, - detector_.extent().width(), detector_.extent().height(), + width_, height_, 1.0 /*scale_factor*/, t_, font_manager_, detector_, query_extent_); cairo_context context(context_); @@ -1619,7 +1626,12 @@ void cairo_renderer_base::start_map_processing(Map const& map) mapnik::feature_impl & feature, proj_transform const& prj_trans) { - text_symbolizer_helper, label_collision_detector4> helper(sym, feature, prj_trans, detector_.extent().width(), detector_.extent().height(), 1.0 /*scale_factor*/, t_, font_manager_, detector_, query_extent_); + text_symbolizer_helper, + label_collision_detector4> helper( + sym, feature, prj_trans, + width_, height_, + 1.0 /*scale_factor*/, + t_, font_manager_, detector_, query_extent_); cairo_context context(context_); context.set_operator(sym.comp_op()); diff --git a/src/grid/process_shield_symbolizer.cpp b/src/grid/process_shield_symbolizer.cpp index 820e9b31b..88681293d 100644 --- a/src/grid/process_shield_symbolizer.cpp +++ b/src/grid/process_shield_symbolizer.cpp @@ -47,8 +47,8 @@ void grid_renderer::process(shield_symbolizer const& sym, sym, feature, prj_trans, width_, height_, scale_factor_, - t_, font_manager_, detector_, query_extent); - + t_, font_manager_, detector_, + query_extent); bool placement_found = false; text_renderer ren(pixmap_, diff --git a/src/grid/process_text_symbolizer.cpp b/src/grid/process_text_symbolizer.cpp index 41c7881f4..dc5b58786 100644 --- a/src/grid/process_text_symbolizer.cpp +++ b/src/grid/process_text_symbolizer.cpp @@ -35,7 +35,7 @@ void grid_renderer::process(text_symbolizer const& sym, text_symbolizer_helper, label_collision_detector4> helper( sym, feature, prj_trans, - detector_.extent().width(), detector_.extent().height(), + width_, height_, scale_factor_ * (1.0/pixmap_.get_resolution()), t_, font_manager_, detector_, query_extent); From 847f284a97596583c71cf0a00a51de8879e07bb5 Mon Sep 17 00:00:00 2001 From: artemp Date: Thu, 5 Jul 2012 17:11:52 +0100 Subject: [PATCH 002/133] + make stroke and fill optional + return expression_ptr by const ref + change init order --- include/mapnik/markers_symbolizer.hpp | 24 +++++++++++++----------- src/markers_symbolizer.cpp | 22 +++++++++------------- 2 files changed, 22 insertions(+), 24 deletions(-) diff --git a/include/mapnik/markers_symbolizer.hpp b/include/mapnik/markers_symbolizer.hpp index 90c1442c6..7dde57ddb 100644 --- a/include/mapnik/markers_symbolizer.hpp +++ b/include/mapnik/markers_symbolizer.hpp @@ -31,6 +31,9 @@ #include #include +// boost +#include + namespace mapnik { // TODO - consider merging with text_symbolizer label_placement_e @@ -47,7 +50,7 @@ struct MAPNIK_DECL markers_symbolizer : { public: explicit markers_symbolizer(); - markers_symbolizer(path_expression_ptr filename); + markers_symbolizer(path_expression_ptr const& filename); markers_symbolizer(markers_symbolizer const& rhs); void set_ignore_placement(bool ignore_placement); bool get_ignore_placement() const; @@ -57,26 +60,25 @@ public: double get_spacing() const; void set_max_error(double max_error); double get_max_error() const; - void set_fill(color fill); - color const& get_fill() const; - void set_width(expression_ptr width); - expression_ptr get_width() const; - void set_height(expression_ptr height); - expression_ptr get_height() const; - stroke const& get_stroke() const; + void set_width(expression_ptr const&width); + expression_ptr const& get_width() const; + void set_height(expression_ptr const& height); + expression_ptr const& get_height() const; + void set_fill(color const& fill); + boost::optional get_fill() const; void set_stroke(stroke const& stroke); + boost::optional get_stroke() const; void set_marker_placement(marker_placement_e marker_p); marker_placement_e get_marker_placement() const; - private: bool ignore_placement_; bool allow_overlap_; - color fill_; double spacing_; double max_error_; expression_ptr width_; expression_ptr height_; - stroke stroke_; + boost::optional fill_; + boost::optional stroke_; marker_placement_e marker_p_; }; diff --git a/src/markers_symbolizer.cpp b/src/markers_symbolizer.cpp index 278875984..25713755c 100644 --- a/src/markers_symbolizer.cpp +++ b/src/markers_symbolizer.cpp @@ -41,25 +41,21 @@ markers_symbolizer::markers_symbolizer() symbolizer_base(), ignore_placement_(false), allow_overlap_(false), - fill_(color(0,0,255)), spacing_(100.0), max_error_(0.2), width_(boost::make_shared(10.0)), height_(boost::make_shared(10.0)), - stroke_(), marker_p_(MARKER_LINE_PLACEMENT) {} -markers_symbolizer::markers_symbolizer(path_expression_ptr filename) +markers_symbolizer::markers_symbolizer(path_expression_ptr const& filename) : symbolizer_with_image(filename), symbolizer_base(), ignore_placement_(false), allow_overlap_(false), - fill_(color(0,0,255)), spacing_(100.0), max_error_(0.2), width_(boost::make_shared(10.0)), height_(boost::make_shared(10.0)), - stroke_(), marker_p_(MARKER_LINE_PLACEMENT) {} markers_symbolizer::markers_symbolizer(markers_symbolizer const& rhs) @@ -67,11 +63,11 @@ markers_symbolizer::markers_symbolizer(markers_symbolizer const& rhs) symbolizer_base(rhs), ignore_placement_(rhs.ignore_placement_), allow_overlap_(rhs.allow_overlap_), - fill_(rhs.fill_), spacing_(rhs.spacing_), max_error_(rhs.max_error_), width_(rhs.width_), height_(rhs.height_), + fill_(rhs.fill_), stroke_(rhs.stroke_), marker_p_(rhs.marker_p_) {} @@ -115,37 +111,37 @@ double markers_symbolizer::get_max_error() const return max_error_; } -void markers_symbolizer::set_fill(color fill) +void markers_symbolizer::set_fill(color const& fill) { fill_ = fill; } -color const& markers_symbolizer::get_fill() const +boost::optional markers_symbolizer::get_fill() const { return fill_; } -void markers_symbolizer::set_width(expression_ptr width) +void markers_symbolizer::set_width(expression_ptr const& width) { width_ = width; } -expression_ptr markers_symbolizer::get_width() const +expression_ptr const& markers_symbolizer::get_width() const { return width_; } -void markers_symbolizer::set_height(expression_ptr height) +void markers_symbolizer::set_height(expression_ptr const& height) { height_ = height; } -expression_ptr markers_symbolizer::get_height() const +expression_ptr const& markers_symbolizer::get_height() const { return height_; } -stroke const& markers_symbolizer::get_stroke() const +boost::optional markers_symbolizer::get_stroke() const { return stroke_; } From ebf1ef6bcf6f2a4db12a3c22cd9d1442f6368b91 Mon Sep 17 00:00:00 2001 From: artemp Date: Thu, 5 Jul 2012 17:13:21 +0100 Subject: [PATCH 003/133] + update python bindings for markers_symbolizer --- bindings/python/mapnik_markers_symbolizer.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/bindings/python/mapnik_markers_symbolizer.cpp b/bindings/python/mapnik_markers_symbolizer.cpp index b95fd47c6..cc05b657d 100644 --- a/bindings/python/mapnik_markers_symbolizer.cpp +++ b/bindings/python/mapnik_markers_symbolizer.cpp @@ -123,21 +123,21 @@ void export_markers_symbolizer() &mapnik::get_svg_transform, &mapnik::set_svg_transform) .add_property("width", - &markers_symbolizer::get_width, + make_function(&markers_symbolizer::get_width, + return_value_policy()), &markers_symbolizer::set_width, "Set/get the marker width") .add_property("height", - &markers_symbolizer::get_height, + make_function(&markers_symbolizer::get_height, + return_value_policy()), &markers_symbolizer::set_height, "Set/get the marker height") .add_property("fill", - make_function(&markers_symbolizer::get_fill, - return_value_policy()), + &markers_symbolizer::get_fill, &markers_symbolizer::set_fill, "Set/get the marker fill color") .add_property("stroke", - make_function(&markers_symbolizer::get_stroke, - return_value_policy()), + &markers_symbolizer::get_stroke, &markers_symbolizer::set_stroke, "Set/get the marker stroke (outline)") .add_property("placement", From 9d756165e01164984797c12d9b4b0246dd5b2473 Mon Sep 17 00:00:00 2001 From: artemp Date: Thu, 5 Jul 2012 17:16:11 +0100 Subject: [PATCH 004/133] + update to work with optional stroke (markers) --- src/load_map.cpp | 84 +++++++++++++++++++++++++++--------------------- src/save_map.cpp | 9 ++++-- 2 files changed, 53 insertions(+), 40 deletions(-) diff --git a/src/load_map.cpp b/src/load_map.cpp index ad6f26c82..40e084432 100644 --- a/src/load_map.cpp +++ b/src/load_map.cpp @@ -115,7 +115,7 @@ private: void parse_markers_symbolizer(rule & rule, xml_node const& sym); void parse_raster_colorizer(raster_colorizer_ptr const& rc, xml_node const& node); - void parse_stroke(stroke & strk, xml_node const & sym); + bool parse_stroke(stroke & strk, xml_node const & sym); void ensure_font_face(std::string const& face_name); void find_unused_nodes(xml_node const& root); @@ -441,45 +441,45 @@ void map_parser::parse_style(Map & map, xml_node const& sty) // image filters mapnik::image_filter_grammar > filter_grammar; - + optional filters = sty.get_opt_attr("image-filters"); if (filters) { std::string filter_mode = *filters; std::string::const_iterator itr = filter_mode.begin(); std::string::const_iterator end = filter_mode.end(); - - bool result = boost::spirit::qi::phrase_parse(itr,end, - filter_grammar, - boost::spirit::qi::ascii::space, + + bool result = boost::spirit::qi::phrase_parse(itr,end, + filter_grammar, + boost::spirit::qi::ascii::space, style.image_filters()); if (!result || itr!=end) { throw config_error("failed to parse image-filters: '" + std::string(itr,end) + "'"); - } + } } - - // direct image filters (applied directly on main image buffer - // TODO : consider creating a separate XML node e.g - // - // + + // direct image filters (applied directly on main image buffer + // TODO : consider creating a separate XML node e.g + // + // optional direct_filters = sty.get_opt_attr("direct-image-filters"); if (direct_filters) { std::string filter_mode = *direct_filters; std::string::const_iterator itr = filter_mode.begin(); - std::string::const_iterator end = filter_mode.end(); - bool result = boost::spirit::qi::phrase_parse(itr,end, - filter_grammar, - boost::spirit::qi::ascii::space, + std::string::const_iterator end = filter_mode.end(); + bool result = boost::spirit::qi::phrase_parse(itr,end, + filter_grammar, + boost::spirit::qi::ascii::space, style.direct_image_filters()); if (!result || itr!=end) { throw config_error("failed to parse direct-image-filters: '" + std::string(itr,end) + "'"); - } + } } - + // rules xml_node::const_iterator ruleIter = sty.begin(); xml_node::const_iterator endRule = sty.end(); @@ -839,7 +839,7 @@ void map_parser::parse_symbolizer_base(symbolizer_base &sym, xml_node const &pt) throw config_error("failed to parse comp-op: '" + *comp_op_name + "'"); } } - + optional geometry_transform_wkt = pt.get_opt_attr("geometry-transform"); if (geometry_transform_wkt) { @@ -855,14 +855,14 @@ void map_parser::parse_symbolizer_base(symbolizer_base &sym, xml_node const &pt) } sym.set_transform(tl); } - + optional clip = pt.get_opt_attr("clip"); if (clip) sym.set_clip(*clip); - + // smooth value optional smooth = pt.get_opt_attr("smooth"); if (smooth) sym.set_smooth(*smooth); - + optional writer = pt.get_opt_attr("meta-writer"); if (!writer) return; optional output = pt.get_opt_attr("meta-output"); @@ -878,7 +878,7 @@ void map_parser::parse_point_symbolizer(rule & rule, xml_node const & sym) optional allow_overlap = sym.get_opt_attr("allow-overlap"); optional ignore_placement = sym.get_opt_attr("ignore-placement"); optional opacity = sym.get_opt_attr("opacity"); - + point_symbolizer symbol; if (allow_overlap) { @@ -1019,7 +1019,7 @@ void map_parser::parse_markers_symbolizer(rule & rule, xml_node const& sym) } symbol.set_image_transform(tl); } - + optional c = sym.get_opt_attr("fill"); if (c) symbol.set_fill(*c); optional spacing = sym.get_opt_attr("spacing"); @@ -1052,8 +1052,8 @@ void map_parser::parse_markers_symbolizer(rule & rule, xml_node const& sym) } stroke strk; - parse_stroke(strk,sym); - symbol.set_stroke(strk); + if (parse_stroke(strk,sym)) + symbol.set_stroke(strk); marker_placement_e placement = sym.get_attr("placement", MARKER_LINE_PLACEMENT); symbol.set_marker_placement(placement); @@ -1141,11 +1141,11 @@ void map_parser::parse_polygon_pattern_symbolizer(rule & rule, // pattern alignment pattern_alignment_e p_alignment = sym.get_attr("alignment",LOCAL_ALIGNMENT); symbol.set_alignment(p_alignment); - + // opacity optional opacity = sym.get_opt_attr("opacity"); if (opacity) symbol.set_opacity(*opacity); - + // gamma optional gamma = sym.get_opt_attr("gamma"); if (gamma) symbol.set_gamma(*gamma); @@ -1212,7 +1212,7 @@ void map_parser::parse_shield_symbolizer(rule & rule, xml_node const& sym) } shield_symbolizer shield_symbol = shield_symbolizer(placement_finder); - + optional image_transform_wkt = sym.get_opt_attr("transform"); if (image_transform_wkt) { @@ -1220,7 +1220,7 @@ void map_parser::parse_shield_symbolizer(rule & rule, xml_node const& sym) if (!mapnik::parse_transform(*tl, *image_transform_wkt, sym.get_tree().transform_expr_grammar)) { std::stringstream ss; - ss << "Could not parse transform from '" << *image_transform_wkt + ss << "Could not parse transform from '" << *image_transform_wkt << "', expected transform attribute"; if (strict_) { @@ -1233,7 +1233,7 @@ void map_parser::parse_shield_symbolizer(rule & rule, xml_node const& sym) } shield_symbol.set_image_transform(tl); } - + // shield displacement double shield_dx = sym.get_attr("shield-dx", 0.0); double shield_dy = sym.get_attr("shield-dy", 0.0); @@ -1298,15 +1298,24 @@ void map_parser::parse_shield_symbolizer(rule & rule, xml_node const& sym) } } -void map_parser::parse_stroke(stroke & strk, xml_node const & sym) +bool map_parser::parse_stroke(stroke & strk, xml_node const & sym) { + bool result = false; // stroke color optional c = sym.get_opt_attr("stroke"); - if (c) strk.set_color(*c); + if (c) + { + strk.set_color(*c); + result = true; + } // stroke-width optional width = sym.get_opt_attr("stroke-width"); - if (width) strk.set_width(*width); + if (width && *width > 0) + { + strk.set_width(*width); + result = true; + } // stroke-opacity optional opacity = sym.get_opt_attr("stroke-opacity"); @@ -1361,10 +1370,11 @@ void map_parser::parse_stroke(stroke & strk, xml_node const & sym) "list of floats or 'none' but got '" + (*str) + "'"); } } - + // stroke-miterlimit optional miterlimit = sym.get_opt_attr("stroke-miterlimit"); if (miterlimit) strk.set_miterlimit(*miterlimit); + return result; } void map_parser::parse_line_symbolizer(rule & rule, xml_node const & sym) @@ -1374,7 +1384,7 @@ void map_parser::parse_line_symbolizer(rule & rule, xml_node const & sym) stroke strk; parse_stroke(strk,sym); line_symbolizer symbol = line_symbolizer(strk); - + // offset value optional offset = sym.get_opt_attr("offset"); if (offset) symbol.set_offset(*offset); @@ -1411,7 +1421,7 @@ void map_parser::parse_polygon_symbolizer(rule & rule, xml_node const & sym) // gamma method optional gamma_method = sym.get_opt_attr("gamma-method"); if (gamma_method) poly_sym.set_gamma_method(*gamma_method); - + parse_symbolizer_base(poly_sym, sym); rule.append(poly_sym); } diff --git a/src/save_map.cpp b/src/save_map.cpp index 58fa54e7a..aaaf98873 100644 --- a/src/save_map.cpp +++ b/src/save_map.cpp @@ -304,8 +304,11 @@ public: set_attr( sym_node, "transform", tr_str ); } - const stroke & strk = sym.get_stroke(); - add_stroke_attributes(sym_node, strk); + boost::optional const& strk = sym.get_stroke(); + if (strk) + { + add_stroke_attributes(sym_node, *strk); + } add_metawriter_attributes(sym_node, sym); } @@ -318,7 +321,7 @@ public: std::clog << typeid(sym).name() << " is not supported" << std::endl; #endif } - + private: serialize_symbolizer(); From 59c1f9ac21d93d43acecd54704d34d35982abb53 Mon Sep 17 00:00:00 2001 From: artemp Date: Thu, 5 Jul 2012 17:17:35 +0100 Subject: [PATCH 005/133] + inherit stroke, stroke-width and fill if provided in markers_symbolizer --- src/agg/process_markers_symbolizer.cpp | 59 ++++++++++++++++++++------ 1 file changed, 47 insertions(+), 12 deletions(-) diff --git a/src/agg/process_markers_symbolizer.cpp b/src/agg/process_markers_symbolizer.cpp index 111b03f9b..805bcbe94 100644 --- a/src/agg/process_markers_symbolizer.cpp +++ b/src/agg/process_markers_symbolizer.cpp @@ -49,6 +49,39 @@ namespace mapnik { + +template +bool push_explicit_style(Attr const& src, Attr & dst, markers_symbolizer const& sym) +{ + boost::optional const& strk = sym.get_stroke(); + boost::optional const& fill = sym.get_fill(); + if (strk || fill) + { + for(unsigned i = 0; i < src.size(); ++i) + { + mapnik::svg::path_attributes attr = src[i]; + + if (strk) + { + attr.stroke_width = (*strk).get_width(); + color const& s_color = (*strk).get_color(); + attr.stroke_color = agg::rgba(s_color.red()/255.0,s_color.green()/255.0, + s_color.blue()/255.0,s_color.alpha()/255.0); + } + if (fill) + { + + color const& f_color = *fill; + attr.fill_color = agg::rgba(f_color.red()/255.0,f_color.green()/255.0, + f_color.blue()/255.0,f_color.alpha()/255.0); + } + dst.push_back(attr); + } + return true; + } + return false; +} + template void agg_renderer::process(markers_symbolizer const& sym, mapnik::feature_impl & feature, @@ -96,23 +129,25 @@ void agg_renderer::process(markers_symbolizer const& sym, } boost::optional marker = (*mark)->get_vector_data(); box2d const& bbox = (*marker)->bounding_box(); - coord2d const center = bbox.center(); + coord2d center = bbox.center(); - agg::trans_affine_translation const recenter(-center.x, -center.y); - agg::trans_affine const marker_trans = recenter * tr; + agg::trans_affine_translation recenter(-center.x, -center.y); + agg::trans_affine marker_trans = recenter * tr; using namespace mapnik::svg; vertex_stl_adapter stl_storage((*marker)->source()); svg_path_adapter svg_path(stl_storage); - svg_renderer, - renderer_type, - agg::pixfmt_rgba32 > svg_renderer(svg_path,(*marker)->attributes()); + agg::pod_bvector attributes; + bool result = push_explicit_style( (*marker)->attributes(), attributes, sym); - for (unsigned i=0; i, + renderer_type, + agg::pixfmt_rgba32 > svg_renderer(svg_path, result ? attributes : (*marker)->attributes()); + + BOOST_FOREACH( geometry_type & geom, feature.paths()) { - geometry_type & geom = feature.get_geometry(i); // TODO - merge this code with point_symbolizer rendering if (placement_method == MARKER_POINT_PLACEMENT || geom.num_points() <= 1) { @@ -147,9 +182,9 @@ void agg_renderer::process(markers_symbolizer const& sym, path_type path(t_,clipped,prj_trans); transformed_path_type path_transformed(path,geom_tr); markers_placement placement(path_transformed, bbox, marker_trans, *detector_, - sym.get_spacing() * scale_factor_, - sym.get_max_error(), - sym.get_allow_overlap()); + sym.get_spacing() * scale_factor_, + sym.get_max_error(), + sym.get_allow_overlap()); double x, y, angle; while (placement.get_point(x, y, angle)) { From f7383b81fbb03f0c1d97b382bd58583c488445dc Mon Sep 17 00:00:00 2001 From: Dane Springmeyer Date: Thu, 5 Jul 2012 11:12:46 -0700 Subject: [PATCH 006/133] properly pass the scale_factor to the cairo_renderer_base --- src/cairo_renderer.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/cairo_renderer.cpp b/src/cairo_renderer.cpp index 02794ad49..7c83f16ab 100644 --- a/src/cairo_renderer.cpp +++ b/src/cairo_renderer.cpp @@ -759,14 +759,14 @@ cairo_renderer_base::cairo_renderer_base(Map const& m, template <> cairo_renderer::cairo_renderer(Map const& m, Cairo::RefPtr const& context, double scale_factor, unsigned offset_x, unsigned offset_y) : feature_style_processor(m), - cairo_renderer_base(m,context,offset_x,offset_y) + cairo_renderer_base(m,context,scale_factor,offset_x,offset_y) { } template <> cairo_renderer::cairo_renderer(Map const& m, Cairo::RefPtr const& surface, double scale_factor, unsigned offset_x, unsigned offset_y) : feature_style_processor(m), - cairo_renderer_base(m,Cairo::Context::create(surface),offset_x,offset_y) + cairo_renderer_base(m,Cairo::Context::create(surface),scale_factor,offset_x,offset_y) { } From 906de8e31714cd68b7e7ab6f3db86d8e2f746990 Mon Sep 17 00:00:00 2001 From: Dane Springmeyer Date: Thu, 5 Jul 2012 11:54:43 -0700 Subject: [PATCH 007/133] simplify boost_python library configure checks --- SConstruct | 24 ++++++++++++++---------- bindings/python/build.py | 10 +--------- 2 files changed, 15 insertions(+), 19 deletions(-) diff --git a/SConstruct b/SConstruct index 6c45529d7..b438e2748 100644 --- a/SConstruct +++ b/SConstruct @@ -33,6 +33,8 @@ except: HAS_DISTUTILS = False +py3 = None + # local file to hold custom user configuration variables # Todo check timestamp, reload if changed? SCONS_LOCAL_CONFIG = 'config.py' @@ -302,7 +304,7 @@ opts.AddVariables( ('BOOST_TOOLKIT','Specify boost toolkit, e.g., gcc41.','',False), ('BOOST_ABI', 'Specify boost ABI, e.g., d.','',False), ('BOOST_VERSION','Specify boost version, e.g., 1_35.','',False), - ('BOOST_PYTHON_LIB','Specify library name to specific Boost Python lib (e.g. "boost_python-py26")',''), + ('BOOST_PYTHON_LIB','Specify library name to specific Boost Python lib (e.g. "boost_python-py26")','boost_python'), # Variables for required dependencies ('FREETYPE_CONFIG', 'The path to the freetype-config executable.', 'freetype-config'), @@ -1326,12 +1328,21 @@ if not preconfigured: color_print(4,'Not building with cairo support, pass CAIRO=True to enable') if 'python' in env['BINDINGS']: - # checklibwithheader does not work for boost_python since we can't feed it - # multiple header files, so we fall back on a simple check for boost_python headers + + py3 = 'True' in os.popen('''%s -c "import sys as s;s.stdout.write(str(s.version_info[0] == 3))"''' % env['PYTHON']).read().strip() + + if py3 and env['BOOST_PYTHON_LIB'] == 'boost_python': + env['BOOST_PYTHON_LIB'] = 'boost_python3' + if not conf.CheckHeader(header='boost/python/detail/config.hpp',language='C++'): color_print(1,'Could not find required header files for boost python') env['MISSING_DEPS'].append('boost python') + if not conf.CheckLibWithHeader(libs=[env['BOOST_PYTHON_LIB']], header='boost/python/detail/config.hpp', language='C++'): + color_print(1, 'Could not find library "%s" for boost python bindings' % env['BOOST_PYTHON_LIB']) + env['MISSING_DEPS'].append('boost python') + + if env['CAIRO']: if conf.CheckPKGConfig('0.15.0') and conf.CheckPKG('pycairo'): env['HAS_PYCAIRO'] = True @@ -1469,8 +1480,6 @@ if not preconfigured: color_print(1,"Cannot run python interpreter at '%s', make sure that you have the permissions to execute it." % env['PYTHON']) Exit(1) - py3 = 'True' in os.popen('''%s -c "import sys as s;s.stdout.write(str(s.version_info[0] == 3))"''' % env['PYTHON']).read().strip() - if py3: sys_prefix = '''%s -c "import sys; print(sys.prefix)"''' % env['PYTHON'] else: @@ -1535,11 +1544,6 @@ if not preconfigured: color_print(1,"Python version 2.2 or greater required") Exit(1) - if env['BOOST_PYTHON_LIB']: - if not conf.CheckLibWithHeader(libs=[env['BOOST_PYTHON_LIB']], header='boost/python/detail/config.hpp', language='C++'): - color_print(1, 'Could not find library %s for boost python' % env['BOOST_PYTHON_LIB']) - Exit(1) - color_print(4,'Bindings Python version... %s' % env['PYTHON_VERSION']) color_print(4,'Python %s prefix... %s' % (env['PYTHON_VERSION'], env['PYTHON_SYS_PREFIX'])) color_print(4,'Python bindings will install in... %s' % os.path.normpath(env['PYTHON_INSTALL_LOCATION'])) diff --git a/bindings/python/build.py b/bindings/python/build.py index cee697357..646b2eeaf 100644 --- a/bindings/python/build.py +++ b/bindings/python/build.py @@ -43,15 +43,7 @@ prefix = env['PREFIX'] target_path = os.path.normpath(env['PYTHON_INSTALL_LOCATION'] + os.path.sep + 'mapnik') target_path_deprecated = os.path.normpath(env['PYTHON_INSTALL_LOCATION'] + os.path.sep + 'mapnik2') -libraries = ['mapnik'] - -if env['BOOST_PYTHON_LIB']: - libraries.append(env['BOOST_PYTHON_LIB']) -else: - if is_py3(): - libraries.append('boost_python3%s' % env['BOOST_APPEND']) - else: - libraries.append('boost_python%s' % env['BOOST_APPEND']) +libraries = ['mapnik',env['BOOST_PYTHON_LIB']] # TODO - do solaris/fedora need direct linking too? if env['PLATFORM'] == 'Darwin': From d8c719f05e0ee0e57a3c8dba0ff56a8a9354d4e7 Mon Sep 17 00:00:00 2001 From: Dane Springmeyer Date: Thu, 5 Jul 2012 14:54:58 -0700 Subject: [PATCH 008/133] finish exposing scale_factor to cairo_renderer --- bindings/python/mapnik_python.cpp | 12 +++++++----- demo/viewer/mapwidget.cpp | 2 +- include/mapnik/image_util.hpp | 3 ++- src/image_util.cpp | 9 +++++---- 4 files changed, 15 insertions(+), 11 deletions(-) diff --git a/bindings/python/mapnik_python.cpp b/bindings/python/mapnik_python.cpp index 6020d3b16..beefea959 100644 --- a/bindings/python/mapnik_python.cpp +++ b/bindings/python/mapnik_python.cpp @@ -150,12 +150,13 @@ void render_layer2(const mapnik::Map& map, void render3(const mapnik::Map& map, PycairoSurface* surface, + double scale_factor = 1.0, unsigned offset_x = 0, unsigned offset_y = 0) { python_unblock_auto_block b; Cairo::RefPtr s(new Cairo::Surface(surface->surface)); - mapnik::cairo_renderer ren(map,s,offset_x, offset_y); + mapnik::cairo_renderer ren(map,s,scale_factor,offset_x,offset_y); ren.apply(); } @@ -169,12 +170,13 @@ void render4(const mapnik::Map& map, PycairoSurface* surface) void render5(const mapnik::Map& map, PycairoContext* context, + double scale_factor = 1.0, unsigned offset_x = 0, unsigned offset_y = 0) { python_unblock_auto_block b; Cairo::RefPtr c(new Cairo::Context(context->ctx)); - mapnik::cairo_renderer ren(map,c,offset_x, offset_y); + mapnik::cairo_renderer ren(map,c,scale_factor,offset_x, offset_y); ren.apply(); } @@ -207,7 +209,7 @@ void render_to_file1(const mapnik::Map& map, if (format == "pdf" || format == "svg" || format =="ps" || format == "ARGB32" || format == "RGB24") { #if defined(HAVE_CAIRO) - mapnik::save_to_cairo_file(map,filename,format); + mapnik::save_to_cairo_file(map,filename,format,1.0); #else throw mapnik::ImageWriterException("Cairo backend not available, cannot write to format: " + format); #endif @@ -226,7 +228,7 @@ void render_to_file2(const mapnik::Map& map,const std::string& filename) if (format == "pdf" || format == "svg" || format =="ps") { #if defined(HAVE_CAIRO) - mapnik::save_to_cairo_file(map,filename,format); + mapnik::save_to_cairo_file(map,filename,format,1.0); #else throw mapnik::ImageWriterException("Cairo backend not available, cannot write to format: " + format); #endif @@ -248,7 +250,7 @@ void render_to_file3(const mapnik::Map& map, if (format == "pdf" || format == "svg" || format =="ps" || format == "ARGB32" || format == "RGB24") { #if defined(HAVE_CAIRO) - mapnik::save_to_cairo_file(map,filename,format); + mapnik::save_to_cairo_file(map,filename,format,scale_factor); #else throw mapnik::ImageWriterException("Cairo backend not available, cannot write to format: " + format); #endif diff --git a/demo/viewer/mapwidget.cpp b/demo/viewer/mapwidget.cpp index 220eb5586..295b141fe 100644 --- a/demo/viewer/mapwidget.cpp +++ b/demo/viewer/mapwidget.cpp @@ -570,7 +570,7 @@ void render_cairo(mapnik::Map const& map, double scaling_factor, QPixmap & pix) Cairo::RefPtr image_surface = Cairo::ImageSurface::create(Cairo::FORMAT_ARGB32, map.width(),map.height()); - mapnik::cairo_renderer png_render(map, image_surface); + mapnik::cairo_renderer png_render(map, image_surface, scaling_factor); png_render.apply(); image_32 buf(image_surface); diff --git a/include/mapnik/image_util.hpp b/include/mapnik/image_util.hpp index bb5a563f3..eb8f7561c 100644 --- a/include/mapnik/image_util.hpp +++ b/include/mapnik/image_util.hpp @@ -60,7 +60,8 @@ public: #if defined(HAVE_CAIRO) MAPNIK_DECL void save_to_cairo_file(mapnik::Map const& map, std::string const& filename, - std::string const& type); + std::string const& type, + double scale_factor); #endif template diff --git a/src/image_util.cpp b/src/image_util.cpp index 11987af97..7cebf19e4 100644 --- a/src/image_util.cpp +++ b/src/image_util.cpp @@ -352,18 +352,19 @@ void save_to_file(T const& image, std::string const& filename, rgba_palette cons #if defined(HAVE_CAIRO) // TODO - move to separate cairo_io.hpp -void save_to_cairo_file(mapnik::Map const& map, std::string const& filename) +void save_to_cairo_file(mapnik::Map const& map, std::string const& filename, double scale_factor) { boost::optional type = type_from_filename(filename); if (type) { - save_to_cairo_file(map,filename,*type); + save_to_cairo_file(map,filename,*type,scale_factor); } } void save_to_cairo_file(mapnik::Map const& map, std::string const& filename, - std::string const& type) + std::string const& type, + double scale_factor) { std::ofstream file (filename.c_str(), std::ios::out|std::ios::trunc|std::ios::binary); if (file) @@ -417,7 +418,7 @@ void save_to_cairo_file(mapnik::Map const& map, */ - mapnik::cairo_renderer ren(map, context); + mapnik::cairo_renderer ren(map, context, scale_factor); ren.apply(); if (type == "ARGB32" || type == "RGB24") From 0de815ba03190d97c8e23b0a7e9052e20ec7a716 Mon Sep 17 00:00:00 2001 From: Dane Springmeyer Date: Thu, 5 Jul 2012 16:07:38 -0700 Subject: [PATCH 009/133] remove raster mode serialization and a few std::clog references in save_map and load_map --- src/load_map.cpp | 2 +- src/save_map.cpp | 8 +++++--- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/load_map.cpp b/src/load_map.cpp index 40e084432..b98e7344c 100644 --- a/src/load_map.cpp +++ b/src/load_map.cpp @@ -851,7 +851,7 @@ void map_parser::parse_symbolizer_base(symbolizer_base &sym, xml_node const &pt) if (strict_) throw config_error(ss.str()); // value_error here? else - std::clog << "### WARNING: " << ss.str() << endl; + MAPNIK_LOG_WARN(load_map) << "### WARNING: " << ss; } sym.set_transform(tl); } diff --git a/src/save_map.cpp b/src/save_map.cpp index aaaf98873..5cd1c4756 100644 --- a/src/save_map.cpp +++ b/src/save_map.cpp @@ -21,6 +21,7 @@ *****************************************************************************/ // mapnik +#include #include #include #include @@ -156,10 +157,11 @@ public: ptree::value_type("RasterSymbolizer", ptree()))->second; raster_symbolizer dfl; - if ( sym.get_mode() != dfl.get_mode() || explicit_defaults_ ) + // should be serialized as comp-op now… + /*if ( sym.get_mode() != dfl.get_mode() || explicit_defaults_ ) { set_attr( sym_node, "mode", sym.get_mode() ); - } + }*/ if ( sym.get_scaling() != dfl.get_scaling() || explicit_defaults_ ) { @@ -318,7 +320,7 @@ public: { // not-supported #ifdef MAPNIK_DEBUG - std::clog << typeid(sym).name() << " is not supported" << std::endl; + MAPNIK_LOG_WARN(save_map) << typeid(sym).name() << " is not supported" << std::endl; #endif } From 2f45de8feaaf5dcf6eab44aaabd01cf2ea824953 Mon Sep 17 00:00:00 2001 From: Dane Springmeyer Date: Thu, 5 Jul 2012 17:06:41 -0700 Subject: [PATCH 010/133] serialize comp-op in save_map - refs #1292 --- include/mapnik/image_compositing.hpp | 1 + src/image_compositing.cpp | 11 +++++++++++ src/save_map.cpp | 11 +++++++++++ 3 files changed, 23 insertions(+) diff --git a/include/mapnik/image_compositing.hpp b/include/mapnik/image_compositing.hpp index 65f173ba3..c4fbef407 100644 --- a/include/mapnik/image_compositing.hpp +++ b/include/mapnik/image_compositing.hpp @@ -79,6 +79,7 @@ enum composite_mode_e }; MAPNIK_DECL boost::optional comp_op_from_string(std::string const& name); +MAPNIK_DECL boost::optional comp_op_to_string(composite_mode_e comp_op); template MAPNIK_DECL void composite(T1 & dst, T2 & src, diff --git a/src/image_compositing.cpp b/src/image_compositing.cpp index 8eff43bb5..e6c64100e 100644 --- a/src/image_compositing.cpp +++ b/src/image_compositing.cpp @@ -88,6 +88,17 @@ boost::optional comp_op_from_string(std::string const& name) return mode; } +boost::optional comp_op_to_string(composite_mode_e comp_op) +{ + boost::optional mode; + comp_op_lookup_type::left_const_iterator left_iter = comp_lookup.left.find(comp_op); + if (left_iter != comp_lookup.left.end()) + { + mode.reset(left_iter->second); + } + return mode; +} + template void composite(T1 & dst, T2 & src, composite_mode_e mode, float opacity, diff --git a/src/save_map.cpp b/src/save_map.cpp index 5cd1c4756..6006a903c 100644 --- a/src/save_map.cpp +++ b/src/save_map.cpp @@ -31,6 +31,7 @@ #include #include #include +#include // boost #include @@ -538,6 +539,16 @@ void serialize_style( ptree & map_node, Map::const_style_iterator style_it, bool set_attr(style_node, "opacity", opacity); } + boost::optional comp_op = style.comp_op(); + if (comp_op) + { + set_attr(style_node, "comp-op", *comp_op_to_string(*comp_op)); + } + else if (explicit_defaults) + { + set_attr(style_node, "comp-op", "src-over"); + } + rules::const_iterator it = style.get_rules().begin(); rules::const_iterator end = style.get_rules().end(); for (; it != end; ++it) From 9beceae29855984fc1df10e3a00214487ea98b5c Mon Sep 17 00:00:00 2001 From: Dane Springmeyer Date: Thu, 5 Jul 2012 17:10:00 -0700 Subject: [PATCH 011/133] shuffle base parsing for shields so it is clearer the call is being made --- src/load_map.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/load_map.cpp b/src/load_map.cpp index b98e7344c..27cce14b7 100644 --- a/src/load_map.cpp +++ b/src/load_map.cpp @@ -1263,8 +1263,6 @@ void map_parser::parse_shield_symbolizer(rule & rule, xml_node const& sym) shield_symbol.set_unlock_image(* unlock_image); } - parse_symbolizer_base(shield_symbol, sym); - std::string file = sym.get_attr("file"); if (file.empty()) { @@ -1289,6 +1287,7 @@ void map_parser::parse_shield_symbolizer(rule & rule, xml_node const& sym) throw mapnik::config_error("Failed to parse path_expression '" + file + "'"); } shield_symbol.set_filename(expr); + parse_symbolizer_base(shield_symbol, sym); rule.append(shield_symbol); } catch (const config_error & ex) @@ -1392,7 +1391,6 @@ void map_parser::parse_line_symbolizer(rule & rule, xml_node const & sym) line_rasterizer_e rasterizer = sym.get_attr("rasterizer", RASTERIZER_FULL); symbol.set_rasterizer(rasterizer); - // meta-writer parse_symbolizer_base(symbol, sym); rule.append(symbol); } From c44b92193fa1fbb47da94533d71cca811f5f8824 Mon Sep 17 00:00:00 2001 From: Dane Springmeyer Date: Thu, 5 Jul 2012 17:23:48 -0700 Subject: [PATCH 012/133] serialize all properties shared by all symbolizers --- src/save_map.cpp | 66 ++++++++++++++++++++++++++++-------------------- 1 file changed, 39 insertions(+), 27 deletions(-) diff --git a/src/save_map.cpp b/src/save_map.cpp index 6006a903c..f0e77bdf3 100644 --- a/src/save_map.cpp +++ b/src/save_map.cpp @@ -75,7 +75,7 @@ public: { set_attr( sym_node, "placement", sym.get_point_placement() ); } - add_metawriter_attributes(sym_node, sym); + serialize_symbolizer_base(sym_node, sym); } void operator () ( line_symbolizer const& sym ) @@ -85,13 +85,13 @@ public: const stroke & strk = sym.get_stroke(); add_stroke_attributes(sym_node, strk); - add_metawriter_attributes(sym_node, sym); line_symbolizer dfl; if ( sym.get_rasterizer() != dfl.get_rasterizer() || explicit_defaults_ ) { set_attr( sym_node, "rasterizer", sym.get_rasterizer() ); } + serialize_symbolizer_base(sym_node, sym); } void operator () ( line_pattern_symbolizer const& sym ) @@ -101,7 +101,7 @@ public: ptree()))->second; add_image_attributes( sym_node, sym ); - add_metawriter_attributes(sym_node, sym); + serialize_symbolizer_base(sym_node, sym); } void operator () ( polygon_symbolizer const& sym ) @@ -126,7 +126,7 @@ public: { set_attr( sym_node, "gamma-method", sym.get_gamma_method() ); } - add_metawriter_attributes(sym_node, sym); + serialize_symbolizer_base(sym_node, sym); } void operator () ( polygon_pattern_symbolizer const& sym ) @@ -149,7 +149,7 @@ public: set_attr( sym_node, "gamma-method", sym.get_gamma_method() ); } add_image_attributes( sym_node, sym ); - add_metawriter_attributes(sym_node, sym); + serialize_symbolizer_base(sym_node, sym); } void operator () ( raster_symbolizer const& sym ) @@ -183,7 +183,7 @@ public: serialize_raster_colorizer(sym_node, sym.get_colorizer(), explicit_defaults_); } - //Note: raster_symbolizer doesn't support metawriters + serialize_symbolizer_base(sym_node, sym); } void operator () ( shield_symbolizer const& sym ) @@ -194,7 +194,6 @@ public: add_font_attributes(sym_node, sym); add_image_attributes(sym_node, sym); - add_metawriter_attributes(sym_node, sym); // pseudo-default-construct a shield_symbolizer. It is used // to avoid printing of attributes with default values without @@ -220,7 +219,7 @@ public: { set_attr(sym_node, "shield-dy", displacement.second); } - + serialize_symbolizer_base(sym_node, sym); } void operator () ( text_symbolizer const& sym ) @@ -230,7 +229,7 @@ public: ptree()))->second; add_font_attributes( sym_node, sym); - add_metawriter_attributes(sym_node, sym); + serialize_symbolizer_base(sym_node, sym); } void operator () ( building_symbolizer const& sym ) @@ -252,7 +251,7 @@ public: set_attr( sym_node, "height", mapnik::to_expression_string(*sym.height()) ); } - add_metawriter_attributes(sym_node, sym); + serialize_symbolizer_base(sym_node, sym); } void operator () ( markers_symbolizer const& sym) @@ -313,7 +312,7 @@ public: add_stroke_attributes(sym_node, *strk); } - add_metawriter_attributes(sym_node, sym); + serialize_symbolizer_base(sym_node, sym); } template @@ -328,6 +327,34 @@ public: private: serialize_symbolizer(); + void serialize_symbolizer_base(ptree & node, symbolizer_base const& sym) + { + symbolizer_base dfl = symbolizer_base(); + if (!sym.get_metawriter_name().empty() || explicit_defaults_) { + set_attr(node, "meta-writer", sym.get_metawriter_name()); + } + if (!sym.get_metawriter_properties_overrides().empty() || explicit_defaults_) { + set_attr(node, "meta-output", sym.get_metawriter_properties_overrides().to_string()); + } + if (sym.get_transform()) + { + std::string tr_str = sym.get_transform_string(); + set_attr( node, "geometry-transform", tr_str ); + } + if (sym.clip() != dfl.clip() || explicit_defaults_) + { + set_attr( node, "clip", sym.clip() ); + } + if (sym.smooth() != dfl.smooth() || explicit_defaults_) + { + set_attr( node, "smooth", sym.smooth() ); + } + if (sym.comp_op() != dfl.comp_op() || explicit_defaults_) + { + set_attr( node, "comp-op", *comp_op_to_string(sym.comp_op()) ); + } + } + void serialize_raster_colorizer(ptree & sym_node, raster_colorizer_ptr const& colorizer, bool explicit_defaults) @@ -352,7 +379,7 @@ private: } - void add_image_attributes(ptree & node, const symbolizer_with_image & sym) + void add_image_attributes(ptree & node, symbolizer_with_image const& sym) { if (sym.get_filename()) { @@ -442,21 +469,6 @@ private: } } - void add_metawriter_attributes(ptree & node, symbolizer_base const& sym) - { - if (!sym.get_metawriter_name().empty() || explicit_defaults_) { - set_attr(node, "meta-writer", sym.get_metawriter_name()); - } - if (!sym.get_metawriter_properties_overrides().empty() || explicit_defaults_) { - set_attr(node, "meta-output", sym.get_metawriter_properties_overrides().to_string()); - } - if (sym.get_transform()) - { - std::string tr_str = sym.get_transform_string(); - set_attr( node, "view-transform", tr_str ); - } - } - ptree & rule_; bool explicit_defaults_; }; From 74990138438a8abf3954e1c1d147e9320d72cf24 Mon Sep 17 00:00:00 2001 From: Dane Springmeyer Date: Thu, 5 Jul 2012 17:47:26 -0700 Subject: [PATCH 013/133] deprecate 'mode' on raster_symbolizer and map it to new comp-op - closes #1257 --- include/mapnik/raster_symbolizer.hpp | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/include/mapnik/raster_symbolizer.hpp b/include/mapnik/raster_symbolizer.hpp index 5f47e7053..41561ca9a 100644 --- a/include/mapnik/raster_symbolizer.hpp +++ b/include/mapnik/raster_symbolizer.hpp @@ -25,9 +25,11 @@ // mapnik #include +#include #include #include #include +#include namespace mapnik { @@ -54,11 +56,25 @@ struct MAPNIK_DECL raster_symbolizer : public symbolizer_base std::string const& get_mode() const { + MAPNIK_LOG_ERROR(raster_symbolizer) << "getting 'mode' is deprecated and will be removed in Mapnik 3.x, use 'comp-op' with Mapnik >= 2.1.x"; return mode_; } void set_mode(std::string const& mode) { + MAPNIK_LOG_ERROR(raster_symbolizer) << "setting 'mode' is deprecated and will be removed in Mapnik 3.x, use 'comp-op' with Mapnik >= 2.1.x"; mode_ = mode; + if (mode == "normal") + { + this->set_comp_op(src_over); + } + else + { + boost::optional comp_op = comp_op_from_string(mode); + if (comp_op) + this->set_comp_op(*comp_op); + else + MAPNIK_LOG_ERROR(raster_symbolizer) << "could not convert mode into comp-op"; + } } std::string const& get_scaling() const { From 6e03fd7bb12e1c6c476d03d53ade03214fbb5a5c Mon Sep 17 00:00:00 2001 From: artemp Date: Fri, 6 Jul 2012 13:41:54 +0100 Subject: [PATCH 014/133] + store last 'move_to' coordinates + ensure sub-paths use correct 'last_vertex' when relative move_to commands is used --- include/mapnik/svg/svg_path_adapter.hpp | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/include/mapnik/svg/svg_path_adapter.hpp b/include/mapnik/svg/svg_path_adapter.hpp index 8dfc6fe7c..014a7ea83 100644 --- a/include/mapnik/svg/svg_path_adapter.hpp +++ b/include/mapnik/svg/svg_path_adapter.hpp @@ -257,6 +257,8 @@ private: VertexContainer & m_vertices; unsigned m_iterator; + double m_start_x; + double m_start_y; }; //------------------------------------------------------------------------ @@ -279,13 +281,8 @@ inline void path_adapter::rel_to_abs(double* x, double* y) const { double x2; double y2; - if(is_vertex(m_vertices.last_vertex(&x2, &y2))) - { - *x += x2; - *y += y2; - } - else if (!is_stop(m_vertices.last_command()) && - is_vertex(m_vertices.prev_vertex(&x2, &y2))) + if(is_vertex(m_vertices.last_vertex(&x2, &y2)) + || !is_stop(m_vertices.last_command())) { *x += x2; *y += y2; @@ -297,6 +294,8 @@ inline void path_adapter::rel_to_abs(double* x, double* y) const template inline void path_adapter::move_to(double x, double y) { + m_start_x = x; + m_start_y = y; m_vertices.add_vertex(x, y, path_cmd_move_to); } @@ -535,7 +534,7 @@ inline void path_adapter::end_poly(unsigned flags) { if(is_vertex(m_vertices.last_command())) { - m_vertices.add_vertex(0.0, 0.0, path_cmd_end_poly | flags); + m_vertices.add_vertex(m_start_x, m_start_y, path_cmd_end_poly | flags); } } From 04589282bbe9457e187a003d1789ae1f4b508a07 Mon Sep 17 00:00:00 2001 From: artemp Date: Fri, 6 Jul 2012 13:50:44 +0100 Subject: [PATCH 015/133] + format --- include/mapnik/svg/svg_path_commands.hpp | 342 +++++++++++------------ 1 file changed, 171 insertions(+), 171 deletions(-) diff --git a/include/mapnik/svg/svg_path_commands.hpp b/include/mapnik/svg/svg_path_commands.hpp index 3b1e09dee..e45b5b1c0 100644 --- a/include/mapnik/svg/svg_path_commands.hpp +++ b/include/mapnik/svg/svg_path_commands.hpp @@ -35,232 +35,232 @@ namespace mapnik { namespace svg { - using namespace boost::fusion; +using namespace boost::fusion; - inline double deg2rad(double deg) +inline double deg2rad(double deg) +{ + return (M_PI * deg)/180.0; +} + +template +struct move_to +{ + template + struct result { - return (M_PI * deg)/180.0; + typedef void type; + }; + + explicit move_to(PathType & path) + : path_(path) {} + + template + void operator() (T0 v, T1 rel) const + { + path_.move_to(at_c<0>(v),at_c<1>(v),rel); // impl } - template - struct move_to + PathType & path_; +}; + +template +struct hline_to +{ + template + struct result { - template - struct result - { - typedef void type; - }; - - explicit move_to(PathType & path) - : path_(path) {} - - template - void operator() (T0 v, T1 rel) const - { - path_.move_to(at_c<0>(v),at_c<1>(v),rel); // impl - } - - PathType & path_; + typedef void type; }; - template - struct hline_to + explicit hline_to(PathType & path) + : path_(path) {} + + template + void operator() (T0 const& x, T1 rel) const { - template - struct result - { - typedef void type; - }; + path_.hline_to(x,rel); + } - explicit hline_to(PathType & path) - : path_(path) {} + PathType & path_; +}; - template - void operator() (T0 const& x, T1 rel) const - { - path_.hline_to(x,rel); - } - PathType & path_; +template +struct vline_to +{ + template + struct result + { + typedef void type; }; + explicit vline_to(PathType & path) + : path_(path) {} - template - struct vline_to + template + void operator() (T0 const& y, T1 rel) const { - template - struct result - { - typedef void type; - }; + path_.vline_to(y,rel); + } - explicit vline_to(PathType & path) - : path_(path) {} + PathType & path_; +}; - template - void operator() (T0 const& y, T1 rel) const - { - path_.vline_to(y,rel); - } - - PathType & path_; +template +struct line_to +{ + template + struct result + { + typedef void type; }; - template - struct line_to + explicit line_to(PathType & path) + : path_(path) {} + + template + void operator() (T0 const& v, T1 rel) const { - template - struct result - { - typedef void type; - }; + path_.line_to(at_c<0>(v),at_c<1>(v),rel); // impl + } - explicit line_to(PathType & path) - : path_(path) {} + PathType & path_; +}; - template - void operator() (T0 const& v, T1 rel) const - { - path_.line_to(at_c<0>(v),at_c<1>(v),rel); // impl - } - PathType & path_; +template +struct curve4 +{ + template + struct result + { + typedef void type; }; + explicit curve4(PathType & path) + : path_(path) {} - template - struct curve4 + template + void operator() (T0 const& v0, T1 const& v1, T2 const& v2, T3 rel) const { - template - struct result - { - typedef void type; - }; + path_.curve4(at_c<0>(v0),at_c<1>(v0), + at_c<0>(v1),at_c<1>(v1), + at_c<0>(v2),at_c<1>(v2), + rel); // impl + } - explicit curve4(PathType & path) - : path_(path) {} + PathType & path_; +}; - template - void operator() (T0 const& v0, T1 const& v1, T2 const& v2, T3 rel) const - { - path_.curve4(at_c<0>(v0),at_c<1>(v0), - at_c<0>(v1),at_c<1>(v1), - at_c<0>(v2),at_c<1>(v2), - rel); // impl - } - PathType & path_; +template +struct curve4_smooth +{ + template + struct result + { + typedef void type; }; + explicit curve4_smooth(PathType & path) + : path_(path) {} - template - struct curve4_smooth + template + void operator() (T0 const& v0, T1 const& v1, T2 rel) const { - template - struct result - { - typedef void type; - }; + path_.curve4(at_c<0>(v0),at_c<1>(v0), + at_c<0>(v1),at_c<1>(v1), + rel); // impl + } + PathType & path_; +}; - explicit curve4_smooth(PathType & path) - : path_(path) {} - - template - void operator() (T0 const& v0, T1 const& v1, T2 rel) const - { - path_.curve4(at_c<0>(v0),at_c<1>(v0), - at_c<0>(v1),at_c<1>(v1), - rel); // impl - } - PathType & path_; +template +struct curve3 +{ + template + struct result + { + typedef void type; }; - template - struct curve3 + explicit curve3(PathType & path) + : path_(path) {} + + template + void operator() (T0 const& v0, T1 const& v1, T2 rel) const { - template - struct result - { - typedef void type; - }; + path_.curve3(at_c<0>(v0),at_c<1>(v0), + at_c<0>(v1),at_c<1>(v1), + rel); // impl + } - explicit curve3(PathType & path) - : path_(path) {} + PathType & path_; +}; - template - void operator() (T0 const& v0, T1 const& v1, T2 rel) const - { - path_.curve3(at_c<0>(v0),at_c<1>(v0), - at_c<0>(v1),at_c<1>(v1), - rel); // impl - } - - PathType & path_; +template +struct curve3_smooth +{ + template + struct result + { + typedef void type; }; - template - struct curve3_smooth + explicit curve3_smooth(PathType & path) + : path_(path) {} + + template + void operator() (T0 const& v0, T1 rel) const { - template - struct result - { - typedef void type; - }; + path_.curve3(at_c<0>(v0),at_c<1>(v0), + rel); // impl + } - explicit curve3_smooth(PathType & path) - : path_(path) {} + PathType & path_; +}; - template - void operator() (T0 const& v0, T1 rel) const - { - path_.curve3(at_c<0>(v0),at_c<1>(v0), - rel); // impl - } - - PathType & path_; +template +struct arc_to +{ + template + struct result + { + typedef void type; }; - template - struct arc_to + explicit arc_to(PathType & path) + : path_(path) {} + + template + void operator() (T0 const& rv, T1 const& angle, T2 large_arc_flag, T3 sweep_flag, T4 const& v, T5 rel) const { - template - struct result - { - typedef void type; - }; + path_.arc_to(at_c<0>(rv),at_c<1>(rv), + deg2rad(angle),large_arc_flag,sweep_flag, + at_c<0>(v),at_c<1>(v), + rel); + } - explicit arc_to(PathType & path) - : path_(path) {} + PathType & path_; +}; - template - void operator() (T0 const& rv, T1 const& angle, T2 large_arc_flag, T3 sweep_flag, T4 const& v, T5 rel) const - { - path_.arc_to(at_c<0>(rv),at_c<1>(rv), - deg2rad(angle),large_arc_flag,sweep_flag, - at_c<0>(v),at_c<1>(v), - rel); - } +template +struct close +{ + typedef void result_type; - PathType & path_; - }; + explicit close(PathType & path) + : path_(path) {} - template - struct close + void operator()() const { - typedef void result_type; + path_.close_subpath(); + } - explicit close(PathType & path) - : path_(path) {} + PathType & path_; +}; - void operator()() const - { - path_.close_subpath(); - } - - PathType & path_; - }; - - }} +}} #endif // MAPNIK_SVG_COMMANDS_HPP From a9cb16303fcaa56c88abd65c8d581b7f8fec15aa Mon Sep 17 00:00:00 2001 From: artemp Date: Fri, 6 Jul 2012 13:55:46 +0100 Subject: [PATCH 016/133] + fix member variables names --- include/mapnik/svg/svg_path_adapter.hpp | 244 ++++++++++++------------ 1 file changed, 122 insertions(+), 122 deletions(-) diff --git a/include/mapnik/svg/svg_path_adapter.hpp b/include/mapnik/svg/svg_path_adapter.hpp index 014a7ea83..edf24f27b 100644 --- a/include/mapnik/svg/svg_path_adapter.hpp +++ b/include/mapnik/svg/svg_path_adapter.hpp @@ -47,9 +47,9 @@ public: typedef path_adapter self_type; //-------------------------------------------------------------------- - path_adapter(VertexContainer & vertices) : m_vertices(vertices), m_iterator(0) {} - //void remove_all() { m_vertices.remove_all(); m_iterator = 0; } - //void free_all() { m_vertices.free_all(); m_iterator = 0; } + path_adapter(VertexContainer & vertices) : vertices_(vertices), iterator_(0) {} + //void remove_all() { vertices_.remove_all(); iterator_ = 0; } + //void free_all() { vertices_.free_all(); iterator_ = 0; } // Make path functions //-------------------------------------------------------------------- @@ -109,8 +109,8 @@ public: // Accessors //-------------------------------------------------------------------- - const container_type& vertices() const { return m_vertices; } - container_type& vertices() { return m_vertices; } + const container_type& vertices() const { return vertices_; } + container_type& vertices() { return vertices_; } unsigned total_vertices() const; @@ -160,7 +160,7 @@ public: vs.rewind(path_id); while(!is_stop(cmd = vs.vertex(&x, &y))) { - m_vertices.add_vertex(x, y, cmd); + vertices_.add_vertex(x, y, cmd); } } @@ -185,7 +185,7 @@ public: if(calc_distance(x, y, x0, y0) > vertex_dist_epsilon) { if(is_move_to(cmd)) cmd = path_cmd_line_to; - m_vertices.add_vertex(x, y, cmd); + vertices_.add_vertex(x, y, cmd); } } else @@ -198,12 +198,12 @@ public: { if(is_move_to(cmd)) cmd = path_cmd_line_to; } - m_vertices.add_vertex(x, y, cmd); + vertices_.add_vertex(x, y, cmd); } } while(!is_stop(cmd = vs.vertex(&x, &y))) { - m_vertices.add_vertex(x, y, is_move_to(cmd) ? + vertices_.add_vertex(x, y, is_move_to(cmd) ? unsigned(path_cmd_line_to) : cmd); } @@ -218,16 +218,16 @@ public: template void transform(const Trans& trans, unsigned path_id=0) { - unsigned num_ver = m_vertices.total_vertices(); + unsigned num_ver = vertices_.total_vertices(); for(; path_id < num_ver; path_id++) { double x, y; - unsigned cmd = m_vertices.vertex(path_id, &x, &y); + unsigned cmd = vertices_.vertex(path_id, &x, &y); if(is_stop(cmd)) break; if(is_vertex(cmd)) { trans.transform(&x, &y); - m_vertices.modify_vertex(path_id, x, y); + vertices_.modify_vertex(path_id, x, y); } } } @@ -237,14 +237,14 @@ public: void transform_all_paths(const Trans& trans) { unsigned idx; - unsigned num_ver = m_vertices.total_vertices(); + unsigned num_ver = vertices_.total_vertices(); for(idx = 0; idx < num_ver; idx++) { double x, y; - if(is_vertex(m_vertices.vertex(idx, &x, &y))) + if(is_vertex(vertices_.vertex(idx, &x, &y))) { trans.transform(&x, &y); - m_vertices.modify_vertex(idx, x, y); + vertices_.modify_vertex(idx, x, y); } } } @@ -255,21 +255,21 @@ private: unsigned perceive_polygon_orientation(unsigned start, unsigned end); void invert_polygon(unsigned start, unsigned end); - VertexContainer & m_vertices; - unsigned m_iterator; - double m_start_x; - double m_start_y; + VertexContainer & vertices_; + unsigned iterator_; + double start_x_; + double start_y_; }; //------------------------------------------------------------------------ template unsigned path_adapter::start_new_path() { - if(!is_stop(m_vertices.last_command())) + if(!is_stop(vertices_.last_command())) { - m_vertices.add_vertex(0.0, 0.0, path_cmd_stop); + vertices_.add_vertex(0.0, 0.0, path_cmd_stop); } - return m_vertices.total_vertices(); + return vertices_.total_vertices(); } @@ -277,12 +277,12 @@ unsigned path_adapter::start_new_path() template inline void path_adapter::rel_to_abs(double* x, double* y) const { - if(m_vertices.total_vertices()) + if(vertices_.total_vertices()) { double x2; double y2; - if(is_vertex(m_vertices.last_vertex(&x2, &y2)) - || !is_stop(m_vertices.last_command())) + if(is_vertex(vertices_.last_vertex(&x2, &y2)) + || !is_stop(vertices_.last_command())) { *x += x2; *y += y2; @@ -294,9 +294,9 @@ inline void path_adapter::rel_to_abs(double* x, double* y) const template inline void path_adapter::move_to(double x, double y) { - m_start_x = x; - m_start_y = y; - m_vertices.add_vertex(x, y, path_cmd_move_to); + start_x_ = x; + start_y_ = y; + vertices_.add_vertex(x, y, path_cmd_move_to); } //------------------------------------------------------------------------ @@ -304,14 +304,14 @@ template inline void path_adapter::move_rel(double dx, double dy) { rel_to_abs(&dx, &dy); - m_vertices.add_vertex(dx, dy, path_cmd_move_to); + vertices_.add_vertex(dx, dy, path_cmd_move_to); } //------------------------------------------------------------------------ template inline void path_adapter::line_to(double x, double y) { - m_vertices.add_vertex(x, y, path_cmd_line_to); + vertices_.add_vertex(x, y, path_cmd_line_to); } //------------------------------------------------------------------------ @@ -319,14 +319,14 @@ template inline void path_adapter::line_rel(double dx, double dy) { rel_to_abs(&dx, &dy); - m_vertices.add_vertex(dx, dy, path_cmd_line_to); + vertices_.add_vertex(dx, dy, path_cmd_line_to); } //------------------------------------------------------------------------ template inline void path_adapter::hline_to(double x) { - m_vertices.add_vertex(x, last_y(), path_cmd_line_to); + vertices_.add_vertex(x, last_y(), path_cmd_line_to); } //------------------------------------------------------------------------ @@ -335,14 +335,14 @@ inline void path_adapter::hline_rel(double dx) { double dy = 0; rel_to_abs(&dx, &dy); - m_vertices.add_vertex(dx, dy, path_cmd_line_to); + vertices_.add_vertex(dx, dy, path_cmd_line_to); } //------------------------------------------------------------------------ template inline void path_adapter::vline_to(double y) { - m_vertices.add_vertex(last_x(), y, path_cmd_line_to); + vertices_.add_vertex(last_x(), y, path_cmd_line_to); } //------------------------------------------------------------------------ @@ -351,7 +351,7 @@ inline void path_adapter::vline_rel(double dy) { double dx = 0; rel_to_abs(&dx, &dy); - m_vertices.add_vertex(dx, dy, path_cmd_line_to); + vertices_.add_vertex(dx, dy, path_cmd_line_to); } //------------------------------------------------------------------------ @@ -362,12 +362,12 @@ void path_adapter::arc_to(double rx, double ry, bool sweep_flag, double x, double y) { - if(m_vertices.total_vertices() && is_vertex(m_vertices.last_command())) + if(vertices_.total_vertices() && is_vertex(vertices_.last_command())) { const double epsilon = 1e-30; double x0 = 0.0; double y0 = 0.0; - m_vertices.last_vertex(&x0, &y0); + vertices_.last_vertex(&x0, &y0); rx = fabs(rx); ry = fabs(ry); @@ -419,8 +419,8 @@ template void path_adapter::curve3(double x_ctrl, double y_ctrl, double x_to, double y_to) { - m_vertices.add_vertex(x_ctrl, y_ctrl, path_cmd_curve3); - m_vertices.add_vertex(x_to, y_to, path_cmd_curve3); + vertices_.add_vertex(x_ctrl, y_ctrl, path_cmd_curve3); + vertices_.add_vertex(x_to, y_to, path_cmd_curve3); } //------------------------------------------------------------------------ @@ -430,8 +430,8 @@ void path_adapter::curve3_rel(double dx_ctrl, double dy_ctrl, { rel_to_abs(&dx_ctrl, &dy_ctrl); rel_to_abs(&dx_to, &dy_to); - m_vertices.add_vertex(dx_ctrl, dy_ctrl, path_cmd_curve3); - m_vertices.add_vertex(dx_to, dy_to, path_cmd_curve3); + vertices_.add_vertex(dx_ctrl, dy_ctrl, path_cmd_curve3); + vertices_.add_vertex(dx_to, dy_to, path_cmd_curve3); } //------------------------------------------------------------------------ @@ -440,11 +440,11 @@ void path_adapter::curve3(double x_to, double y_to) { double x0; double y0; - if(is_vertex(m_vertices.last_vertex(&x0, &y0))) + if(is_vertex(vertices_.last_vertex(&x0, &y0))) { double x_ctrl; double y_ctrl; - unsigned cmd = m_vertices.prev_vertex(&x_ctrl, &y_ctrl); + unsigned cmd = vertices_.prev_vertex(&x_ctrl, &y_ctrl); if(is_curve(cmd)) { x_ctrl = x0 + x0 - x_ctrl; @@ -473,9 +473,9 @@ void path_adapter::curve4(double x_ctrl1, double y_ctrl1, double x_ctrl2, double y_ctrl2, double x_to, double y_to) { - m_vertices.add_vertex(x_ctrl1, y_ctrl1, path_cmd_curve4); - m_vertices.add_vertex(x_ctrl2, y_ctrl2, path_cmd_curve4); - m_vertices.add_vertex(x_to, y_to, path_cmd_curve4); + vertices_.add_vertex(x_ctrl1, y_ctrl1, path_cmd_curve4); + vertices_.add_vertex(x_ctrl2, y_ctrl2, path_cmd_curve4); + vertices_.add_vertex(x_to, y_to, path_cmd_curve4); } //------------------------------------------------------------------------ @@ -487,9 +487,9 @@ void path_adapter::curve4_rel(double dx_ctrl1, double dy_ctrl1, rel_to_abs(&dx_ctrl1, &dy_ctrl1); rel_to_abs(&dx_ctrl2, &dy_ctrl2); rel_to_abs(&dx_to, &dy_to); - m_vertices.add_vertex(dx_ctrl1, dy_ctrl1, path_cmd_curve4); - m_vertices.add_vertex(dx_ctrl2, dy_ctrl2, path_cmd_curve4); - m_vertices.add_vertex(dx_to, dy_to, path_cmd_curve4); + vertices_.add_vertex(dx_ctrl1, dy_ctrl1, path_cmd_curve4); + vertices_.add_vertex(dx_ctrl2, dy_ctrl2, path_cmd_curve4); + vertices_.add_vertex(dx_to, dy_to, path_cmd_curve4); } //------------------------------------------------------------------------ @@ -532,9 +532,9 @@ void path_adapter::curve4_rel(double dx_ctrl2, double dy_ctrl2, template inline void path_adapter::end_poly(unsigned flags) { - if(is_vertex(m_vertices.last_command())) + if(is_vertex(vertices_.last_command())) { - m_vertices.add_vertex(m_start_x, m_start_y, path_cmd_end_poly | flags); + vertices_.add_vertex(start_x_, start_y_, path_cmd_end_poly | flags); } } @@ -549,85 +549,85 @@ inline void path_adapter::close_polygon(unsigned flags) template inline unsigned path_adapter::total_vertices() const { - return m_vertices.total_vertices(); + return vertices_.total_vertices(); } //------------------------------------------------------------------------ template inline unsigned path_adapter::last_vertex(double* x, double* y) const { - return m_vertices.last_vertex(x, y); + return vertices_.last_vertex(x, y); } //------------------------------------------------------------------------ template inline unsigned path_adapter::prev_vertex(double* x, double* y) const { - return m_vertices.prev_vertex(x, y); + return vertices_.prev_vertex(x, y); } //------------------------------------------------------------------------ template inline double path_adapter::last_x() const { - return m_vertices.last_x(); + return vertices_.last_x(); } //------------------------------------------------------------------------ template inline double path_adapter::last_y() const { - return m_vertices.last_y(); + return vertices_.last_y(); } //------------------------------------------------------------------------ template inline unsigned path_adapter::vertex(unsigned idx, double* x, double* y) const { - return m_vertices.vertex(idx, x, y); + return vertices_.vertex(idx, x, y); } //------------------------------------------------------------------------ template inline unsigned path_adapter::command(unsigned idx) const { - return m_vertices.command(idx); + return vertices_.command(idx); } //------------------------------------------------------------------------ template void path_adapter::modify_vertex(unsigned idx, double x, double y) { - m_vertices.modify_vertex(idx, x, y); + vertices_.modify_vertex(idx, x, y); } //------------------------------------------------------------------------ template void path_adapter::modify_vertex(unsigned idx, double x, double y, unsigned cmd) { - m_vertices.modify_vertex(idx, x, y, cmd); + vertices_.modify_vertex(idx, x, y, cmd); } //------------------------------------------------------------------------ template void path_adapter::modify_command(unsigned idx, unsigned cmd) { - m_vertices.modify_command(idx, cmd); + vertices_.modify_command(idx, cmd); } //------------------------------------------------------------------------ template inline void path_adapter::rewind(unsigned path_id) { - m_iterator = path_id; + iterator_ = path_id; } //------------------------------------------------------------------------ template inline unsigned path_adapter::vertex(double* x, double* y) { - if(m_iterator >= m_vertices.total_vertices()) return path_cmd_stop; - return m_vertices.vertex(m_iterator++, x, y); + if(iterator_ >= vertices_.total_vertices()) return path_cmd_stop; + return vertices_.vertex(iterator_++, x, y); } //------------------------------------------------------------------------ @@ -643,8 +643,8 @@ unsigned path_adapter::perceive_polygon_orientation(unsigned start, for(i = 0; i < np; i++) { double x1, y1, x2, y2; - m_vertices.vertex(start + i, &x1, &y1); - m_vertices.vertex(start + (i + 1) % np, &x2, &y2); + vertices_.vertex(start + i, &x1, &y1); + vertices_.vertex(start + (i + 1) % np, &x2, &y2); area += x1 * y2 - y1 * x2; } return (area < 0.0) ? path_flags_cw : path_flags_ccw; @@ -655,23 +655,23 @@ template void path_adapter::invert_polygon(unsigned start, unsigned end) { unsigned i; - unsigned tmp_cmd = m_vertices.command(start); + unsigned tmp_cmd = vertices_.command(start); --end; // Make "end" inclusive // Shift all commands to one position for(i = start; i < end; i++) { - m_vertices.modify_command(i, m_vertices.command(i + 1)); + vertices_.modify_command(i, vertices_.command(i + 1)); } // Assign starting command to the ending command - m_vertices.modify_command(end, tmp_cmd); + vertices_.modify_command(end, tmp_cmd); // Reverse the polygon while(end > start) { - m_vertices.swap_vertices(start++, end--); + vertices_.swap_vertices(start++, end--); } } @@ -680,18 +680,18 @@ template void path_adapter::invert_polygon(unsigned start) { // Skip all non-vertices at the beginning - while(start < m_vertices.total_vertices() && - !is_vertex(m_vertices.command(start))) ++start; + while(start < vertices_.total_vertices() && + !is_vertex(vertices_.command(start))) ++start; // Skip all insignificant move_to - while(start+1 < m_vertices.total_vertices() && - is_move_to(m_vertices.command(start)) && - is_move_to(m_vertices.command(start+1))) ++start; + while(start+1 < vertices_.total_vertices() && + is_move_to(vertices_.command(start)) && + is_move_to(vertices_.command(start+1))) ++start; // Find the last vertex unsigned end = start + 1; - while(end < m_vertices.total_vertices() && - !is_next_poly(m_vertices.command(end))) ++end; + while(end < vertices_.total_vertices() && + !is_next_poly(vertices_.command(end))) ++end; invert_polygon(start, end); } @@ -704,18 +704,18 @@ unsigned path_adapter::arrange_polygon_orientation(unsigned start, if(orientation == path_flags_none) return start; // Skip all non-vertices at the beginning - while(start < m_vertices.total_vertices() && - !is_vertex(m_vertices.command(start))) ++start; + while(start < vertices_.total_vertices() && + !is_vertex(vertices_.command(start))) ++start; // Skip all insignificant move_to - while(start+1 < m_vertices.total_vertices() && - is_move_to(m_vertices.command(start)) && - is_move_to(m_vertices.command(start+1))) ++start; + while(start+1 < vertices_.total_vertices() && + is_move_to(vertices_.command(start)) && + is_move_to(vertices_.command(start+1))) ++start; // Find the last vertex unsigned end = start + 1; - while(end < m_vertices.total_vertices() && - !is_next_poly(m_vertices.command(end))) ++end; + while(end < vertices_.total_vertices() && + !is_next_poly(vertices_.command(end))) ++end; if(end - start > 2) { @@ -724,10 +724,10 @@ unsigned path_adapter::arrange_polygon_orientation(unsigned start, // Invert polygon, set orientation flag, and skip all end_poly invert_polygon(start, end); unsigned cmd; - while(end < m_vertices.total_vertices() && - is_end_poly(cmd = m_vertices.command(end))) + while(end < vertices_.total_vertices() && + is_end_poly(cmd = vertices_.command(end))) { - m_vertices.modify_command(end++, set_orientation(cmd, orientation)); + vertices_.modify_command(end++, set_orientation(cmd, orientation)); } } } @@ -741,10 +741,10 @@ unsigned path_adapter::arrange_orientations(unsigned start, { if(orientation != path_flags_none) { - while(start < m_vertices.total_vertices()) + while(start < vertices_.total_vertices()) { start = arrange_polygon_orientation(start, orientation); - if(is_stop(m_vertices.command(start))) + if(is_stop(vertices_.command(start))) { ++start; break; @@ -761,7 +761,7 @@ void path_adapter::arrange_orientations_all_paths(path_flags_e orientation) if(orientation != path_flags_none) { unsigned start = 0; - while(start < m_vertices.total_vertices()) + while(start < vertices_.total_vertices()) { start = arrange_orientations(start, orientation); } @@ -774,12 +774,12 @@ void path_adapter::flip_x(double x1, double x2) { unsigned i; double x, y; - for(i = 0; i < m_vertices.total_vertices(); i++) + for(i = 0; i < vertices_.total_vertices(); i++) { - unsigned cmd = m_vertices.vertex(i, &x, &y); + unsigned cmd = vertices_.vertex(i, &x, &y); if(is_vertex(cmd)) { - m_vertices.modify_vertex(i, x2 - x + x1, y); + vertices_.modify_vertex(i, x2 - x + x1, y); } } } @@ -790,12 +790,12 @@ void path_adapter::flip_y(double y1, double y2) { unsigned i; double x, y; - for(i = 0; i < m_vertices.total_vertices(); i++) + for(i = 0; i < vertices_.total_vertices(); i++) { - unsigned cmd = m_vertices.vertex(i, &x, &y); + unsigned cmd = vertices_.vertex(i, &x, &y); if(is_vertex(cmd)) { - m_vertices.modify_vertex(i, x, y2 - y + y1); + vertices_.modify_vertex(i, x, y2 - y + y1); } } } @@ -804,17 +804,17 @@ void path_adapter::flip_y(double y1, double y2) template void path_adapter::translate(double dx, double dy, unsigned path_id) { - unsigned num_ver = m_vertices.total_vertices(); + unsigned num_ver = vertices_.total_vertices(); for(; path_id < num_ver; path_id++) { double x, y; - unsigned cmd = m_vertices.vertex(path_id, &x, &y); + unsigned cmd = vertices_.vertex(path_id, &x, &y); if(is_stop(cmd)) break; if(is_vertex(cmd)) { x += dx; y += dy; - m_vertices.modify_vertex(path_id, x, y); + vertices_.modify_vertex(path_id, x, y); } } } @@ -824,15 +824,15 @@ template void path_adapter::translate_all_paths(double dx, double dy) { unsigned idx; - unsigned num_ver = m_vertices.total_vertices(); + unsigned num_ver = vertices_.total_vertices(); for(idx = 0; idx < num_ver; idx++) { double x, y; - if(is_vertex(m_vertices.vertex(idx, &x, &y))) + if(is_vertex(vertices_.vertex(idx, &x, &y))) { x += dx; y += dy; - m_vertices.modify_vertex(idx, x, y); + vertices_.modify_vertex(idx, x, y); } } } @@ -846,25 +846,25 @@ public: typedef typename vertex_type::value_type value_type; explicit vertex_stl_adapter(Container & vertices) - : m_vertices(vertices) {} + : vertices_(vertices) {} void add_vertex(double x, double y, unsigned cmd) { - m_vertices.push_back(vertex_type(value_type(x), + vertices_.push_back(vertex_type(value_type(x), value_type(y), int8u(cmd))); } void modify_vertex(unsigned idx, double x, double y) { - vertex_type& v = m_vertices[idx]; + vertex_type& v = vertices_[idx]; v.x = value_type(x); v.y = value_type(y); } void modify_vertex(unsigned idx, double x, double y, unsigned cmd) { - vertex_type& v = m_vertices[idx]; + vertex_type& v = vertices_[idx]; v.x = value_type(x); v.y = value_type(y); v.cmd = int8u(cmd); @@ -872,61 +872,61 @@ public: void modify_command(unsigned idx, unsigned cmd) { - m_vertices[idx].cmd = int8u(cmd); + vertices_[idx].cmd = int8u(cmd); } void swap_vertices(unsigned v1, unsigned v2) { - vertex_type t = m_vertices[v1]; - m_vertices[v1] = m_vertices[v2]; - m_vertices[v2] = t; + vertex_type t = vertices_[v1]; + vertices_[v1] = vertices_[v2]; + vertices_[v2] = t; } unsigned last_command() const { - return m_vertices.size() ? - m_vertices[m_vertices.size() - 1].cmd : + return vertices_.size() ? + vertices_[vertices_.size() - 1].cmd : (unsigned)path_cmd_stop; } unsigned last_vertex(double* x, double* y) const { - if(m_vertices.size() == 0) + if(vertices_.size() == 0) { *x = *y = 0.0; return path_cmd_stop; } - return vertex(m_vertices.size() - 1, x, y); + return vertex(vertices_.size() - 1, x, y); } unsigned prev_vertex(double* x, double* y) const { - if(m_vertices.size() < 2) + if(vertices_.size() < 2) { *x = *y = 0.0; return path_cmd_stop; } - return vertex(m_vertices.size() - 2, x, y); + return vertex(vertices_.size() - 2, x, y); } double last_x() const { - return m_vertices.size() ? m_vertices[m_vertices.size() - 1].x : 0.0; + return vertices_.size() ? vertices_[vertices_.size() - 1].x : 0.0; } double last_y() const { - return m_vertices.size() ? m_vertices[m_vertices.size() - 1].y : 0.0; + return vertices_.size() ? vertices_[vertices_.size() - 1].y : 0.0; } unsigned total_vertices() const { - return m_vertices.size(); + return vertices_.size(); } unsigned vertex(unsigned idx, double* x, double* y) const { - const vertex_type& v = m_vertices[idx]; + const vertex_type& v = vertices_[idx]; *x = v.x; *y = v.y; return v.cmd; @@ -934,11 +934,11 @@ public: unsigned command(unsigned idx) const { - return m_vertices[idx].cmd; + return vertices_[idx].cmd; } private: - Container & m_vertices; + Container & vertices_; }; From ee7f72dcce683b98b5702ea83219d053cce34c77 Mon Sep 17 00:00:00 2001 From: artemp Date: Fri, 6 Jul 2012 14:03:44 +0100 Subject: [PATCH 017/133] + fix compilation issue --- src/save_map.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/save_map.cpp b/src/save_map.cpp index f0e77bdf3..394f822cc 100644 --- a/src/save_map.cpp +++ b/src/save_map.cpp @@ -320,7 +320,7 @@ public: { // not-supported #ifdef MAPNIK_DEBUG - MAPNIK_LOG_WARN(save_map) << typeid(sym).name() << " is not supported" << std::endl; + MAPNIK_LOG_WARN(save_map) << typeid(sym).name() << " is not supported"; #endif } From 18d2c041b5f028fc76601c1153ecb2729f85b21a Mon Sep 17 00:00:00 2001 From: Dane Springmeyer Date: Fri, 6 Jul 2012 07:48:23 -0700 Subject: [PATCH 018/133] respect BOOST_APPEND for boost_python configure check --- SConstruct | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/SConstruct b/SConstruct index b438e2748..fd04d48f0 100644 --- a/SConstruct +++ b/SConstruct @@ -1332,7 +1332,9 @@ if not preconfigured: py3 = 'True' in os.popen('''%s -c "import sys as s;s.stdout.write(str(s.version_info[0] == 3))"''' % env['PYTHON']).read().strip() if py3 and env['BOOST_PYTHON_LIB'] == 'boost_python': - env['BOOST_PYTHON_LIB'] = 'boost_python3' + env['BOOST_PYTHON_LIB'] = 'boost_python3%s' % env['BOOST_APPEND'] + elif env['BOOST_PYTHON_LIB'] == 'boost_python': + env['BOOST_PYTHON_LIB'] = 'boost_python%s' % env['BOOST_APPEND'] if not conf.CheckHeader(header='boost/python/detail/config.hpp',language='C++'): color_print(1,'Could not find required header files for boost python') From 6e5a68f37219e62ccb72101adfe631331988a8b9 Mon Sep 17 00:00:00 2001 From: Dane Springmeyer Date: Fri, 6 Jul 2012 11:35:29 -0700 Subject: [PATCH 019/133] stop defaulting to lib64 on 64 bit unix systems - closes #1297 --- SConstruct | 2 -- 1 file changed, 2 deletions(-) diff --git a/SConstruct b/SConstruct index b438e2748..f82255c7d 100644 --- a/SConstruct +++ b/SConstruct @@ -237,8 +237,6 @@ def sort_paths(items,priority): if platform.dist()[0] in ('Ubuntu','debian'): LIBDIR_SCHEMA='lib' -elif platform.uname()[4] == 'x86_64' and platform.system() == 'Linux': - LIBDIR_SCHEMA='lib64' elif platform.uname()[4] == 'ppc64': LIBDIR_SCHEMA='lib64' else: From b5dc59cabc91ecccb9f5761f2c7db484642f7a65 Mon Sep 17 00:00:00 2001 From: Dane Springmeyer Date: Fri, 6 Jul 2012 11:53:54 -0700 Subject: [PATCH 020/133] remove serialization of get_mode, no longer needed --- src/save_map.cpp | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/save_map.cpp b/src/save_map.cpp index f0e77bdf3..51579f670 100644 --- a/src/save_map.cpp +++ b/src/save_map.cpp @@ -158,12 +158,6 @@ public: ptree::value_type("RasterSymbolizer", ptree()))->second; raster_symbolizer dfl; - // should be serialized as comp-op now… - /*if ( sym.get_mode() != dfl.get_mode() || explicit_defaults_ ) - { - set_attr( sym_node, "mode", sym.get_mode() ); - }*/ - if ( sym.get_scaling() != dfl.get_scaling() || explicit_defaults_ ) { set_attr( sym_node, "scaling", sym.get_scaling() ); From b365923772012a13e70cc331ccb10bbc4faba2b6 Mon Sep 17 00:00:00 2001 From: Dane Springmeyer Date: Fri, 6 Jul 2012 12:58:42 -0700 Subject: [PATCH 021/133] use clang++ and mapnik-config by default to build viewer --- demo/viewer/viewer.pro | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) diff --git a/demo/viewer/viewer.pro b/demo/viewer/viewer.pro index 538419e49..048cfad9c 100644 --- a/demo/viewer/viewer.pro +++ b/demo/viewer/viewer.pro @@ -1,18 +1,11 @@ ###################################################################### # Mapnik viewer - Copyright (C) 2007 Artem Pavlenko ###################################################################### -CC = g++ TEMPLATE = app - -INCLUDEPATH += /usr/local/include/ -INCLUDEPATH += /usr/boost/include/ -INCLUDEPATH += /usr/X11/include/ -INCLUDEPATH += /usr/X11/include/freetype2 -INCLUDEPATH += . - -QMAKE_CXXFLAGS +=' -DDARWIN -Wno-missing-field-initializers -ansi' -unix:LIBS = -L/usr/local/lib -L/usr/X11/lib -lmapnik -lfreetype -unix:LIBS += -lboost_system -licuuc -lboost_filesystem -lboost_regex +QMAKE_CXX = clang++ +QMAKE_CXXFLAGS += $$system(mapnik-config --cflags) +QMAKE_LFLAGS += $$system(mapnik-config --libs) +QMAKE_LFLAGS += $$system(mapnik-config --ldflags --dep-libs) # Input From 3823890b40e2bfaa191b4975b5e4ec587a33a55e Mon Sep 17 00:00:00 2001 From: Dane Springmeyer Date: Fri, 6 Jul 2012 16:45:58 -0700 Subject: [PATCH 022/133] rollback 34c3128b0cea7, move 'scaling' to proper enum, and move image_scaling functions to new cpp/hpp --- bindings/python/mapnik_python.cpp | 2 + bindings/python/mapnik_raster_symbolizer.cpp | 17 +- include/mapnik/image_scaling.hpp | 83 +++++ include/mapnik/image_util.hpp | 33 +- include/mapnik/raster_symbolizer.hpp | 22 +- include/mapnik/warp.hpp | 15 +- src/agg/process_raster_symbolizer.cpp | 51 ++- src/build.py | 1 + src/cairo_renderer.cpp | 50 ++- src/image_scaling.cpp | 359 +++++++++++++++++++ src/image_util.cpp | 321 ----------------- src/load_map.cpp | 23 +- src/save_map.cpp | 5 +- src/warp.cpp | 259 +++++++------ 14 files changed, 686 insertions(+), 555 deletions(-) create mode 100644 include/mapnik/image_scaling.hpp create mode 100644 src/image_scaling.cpp diff --git a/bindings/python/mapnik_python.cpp b/bindings/python/mapnik_python.cpp index beefea959..f30c35017 100644 --- a/bindings/python/mapnik_python.cpp +++ b/bindings/python/mapnik_python.cpp @@ -37,6 +37,7 @@ void export_palette(); void export_image(); void export_image_view(); void export_gamma_method(); +void export_scaling_method(); void export_grid(); void export_grid_view(); void export_map(); @@ -362,6 +363,7 @@ BOOST_PYTHON_MODULE(_mapnik) export_image(); export_image_view(); export_gamma_method(); + export_scaling_method(); export_grid(); export_grid_view(); export_expression(); diff --git a/bindings/python/mapnik_raster_symbolizer.cpp b/bindings/python/mapnik_raster_symbolizer.cpp index dacaea5de..3830dd9f1 100644 --- a/bindings/python/mapnik_raster_symbolizer.cpp +++ b/bindings/python/mapnik_raster_symbolizer.cpp @@ -25,6 +25,7 @@ // mapnik #include +#include using mapnik::raster_symbolizer; @@ -39,13 +40,13 @@ struct raster_symbolizer_pickle_suite : boost::python::pickle_suite */ static boost::python::tuple - getstate(const raster_symbolizer& r) + getstate(raster_symbolizer const& r) { - return boost::python::make_tuple(r.get_mode(),r.get_scaling(),r.get_opacity(),r.get_filter_factor(),r.get_mesh_size()); + return boost::python::make_tuple(r.get_mode(),r.get_scaling_method(),r.get_opacity(),r.get_filter_factor(),r.get_mesh_size()); } static void - setstate (raster_symbolizer& r, boost::python::tuple state) + setstate (raster_symbolizer & r, boost::python::tuple state) { using namespace boost::python; if (len(state) != 5) @@ -58,7 +59,7 @@ struct raster_symbolizer_pickle_suite : boost::python::pickle_suite } r.set_mode(extract(state[0])); - r.set_scaling(extract(state[1])); + r.set_scaling_method(extract(state[1])); r.set_opacity(extract(state[2])); r.set_filter_factor(extract(state[3])); r.set_mesh_size(extract(state[4])); @@ -91,17 +92,15 @@ void export_raster_symbolizer() ) .add_property("scaling", - make_function(&raster_symbolizer::get_scaling,return_value_policy()), - &raster_symbolizer::set_scaling, + &raster_symbolizer::get_scaling_method, + &raster_symbolizer::set_scaling_method, "Get/Set scaling algorithm.\n" - "Possible values are:\n" - "fast, bilinear, and bilinear8\n" "\n" "Usage:\n" "\n" ">>> from mapnik import RasterSymbolizer\n" ">>> r = RasterSymbolizer()\n" - ">>> r.scaling = 'bilinear8'\n" + ">>> r.scaling = 'mapnik.scaling_method.GAUSSIAN'\n" ) .add_property("opacity", diff --git a/include/mapnik/image_scaling.hpp b/include/mapnik/image_scaling.hpp new file mode 100644 index 000000000..89e5fcd69 --- /dev/null +++ b/include/mapnik/image_scaling.hpp @@ -0,0 +1,83 @@ +/***************************************************************************** + * + * This file is part of Mapnik (c++ mapping toolkit) + * + * Copyright (C) 2011 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_IMAGE_SCALING_HPP +#define MAPNIK_IMAGE_SCALING_HPP + +// stl +#include + +#include +#include + +namespace mapnik +{ + +enum scaling_method_e +{ + SCALING_NEAR=0, + SCALING_BILINEAR, + SCALING_BICUBIC, + SCALING_SPLINE16, + SCALING_SPLINE36, + SCALING_HANNING, + SCALING_HAMMING, + SCALING_HERMITE, + SCALING_KAISER, + SCALING_QUADRIC, + SCALING_CATROM, + SCALING_GAUSSIAN, + SCALING_BESSEL, + SCALING_MITCHELL, + SCALING_SINC, + SCALING_LANCZOS, + SCALING_BLACKMAN, + SCALING_BILINEAR8 +}; + +boost::optional scaling_method_from_string(std::string const& name); +boost::optional scaling_method_to_string(scaling_method_e scaling_method); + +template +void scale_image_agg(Image & target, + Image const& source, + scaling_method_e scaling_method, + double scale_factor, + double x_off_f=0, + double y_off_f=0, + double filter_radius=2, + double ratio=1); + +template +void scale_image_bilinear_old(Image & target, + Image const& source, + double x_off_f=0, + double y_off_f=0); + +template +void scale_image_bilinear8(Image & target, + Image const& source, + double x_off_f=0, + double y_off_f=0); + +} +#endif // MAPNIK_IMAGE_SCALING_HPP diff --git a/include/mapnik/image_util.hpp b/include/mapnik/image_util.hpp index eb8f7561c..0f438eeb8 100644 --- a/include/mapnik/image_util.hpp +++ b/include/mapnik/image_util.hpp @@ -61,7 +61,7 @@ public: MAPNIK_DECL void save_to_cairo_file(mapnik::Map const& map, std::string const& filename, std::string const& type, - double scale_factor); + double scale_factor=1.0); #endif template @@ -185,38 +185,7 @@ void add_border(T & image) } } -// IMAGE SCALING -enum scaling_method_e -{ - SCALING_NEAR=0, - SCALING_BILINEAR=1, - SCALING_BICUBIC=2, - SCALING_SPLINE16=3, - SCALING_SPLINE36=4, - SCALING_HANNING=5, - SCALING_HAMMING=6, - SCALING_HERMITE=7, - SCALING_KAISER=8, - SCALING_QUADRIC=9, - SCALING_CATROM=10, - SCALING_GAUSSIAN=11, - SCALING_BESSEL=12, - SCALING_MITCHELL=13, - SCALING_SINC=14, - SCALING_LANCZOS=15, - SCALING_BLACKMAN=16 -}; -scaling_method_e get_scaling_method_by_name (std::string name); - -template -void scale_image_agg (Image& target,const Image& source, scaling_method_e scaling_method, double scale_factor, double x_off_f=0, double y_off_f=0, double filter_radius=2, double ratio=1); - -template -void scale_image_bilinear_old (Image& target,const Image& source, double x_off_f=0, double y_off_f=0); - -template -void scale_image_bilinear8 (Image& target,const Image& source, double x_off_f=0, double y_off_f=0); /////////// save_to_file //////////////////////////////////////////////// class image_32; diff --git a/include/mapnik/raster_symbolizer.hpp b/include/mapnik/raster_symbolizer.hpp index 41561ca9a..192d70a7c 100644 --- a/include/mapnik/raster_symbolizer.hpp +++ b/include/mapnik/raster_symbolizer.hpp @@ -30,6 +30,7 @@ #include #include #include +#include namespace mapnik { @@ -39,7 +40,7 @@ struct MAPNIK_DECL raster_symbolizer : public symbolizer_base raster_symbolizer() : symbolizer_base(), mode_("normal"), - scaling_("fast"), + scaling_(SCALING_NEAR), opacity_(1.0), colorizer_(), filter_factor_(-1), @@ -47,9 +48,9 @@ struct MAPNIK_DECL raster_symbolizer : public symbolizer_base raster_symbolizer(const raster_symbolizer &rhs) : symbolizer_base(rhs), - mode_(rhs.get_mode()), - scaling_(rhs.get_scaling()), - opacity_(rhs.get_opacity()), + mode_(rhs.mode_), + scaling_(rhs.scaling_), + opacity_(rhs.opacity_), colorizer_(rhs.colorizer_), filter_factor_(rhs.filter_factor_), mesh_size_(rhs.mesh_size_) {} @@ -76,11 +77,11 @@ struct MAPNIK_DECL raster_symbolizer : public symbolizer_base MAPNIK_LOG_ERROR(raster_symbolizer) << "could not convert mode into comp-op"; } } - std::string const& get_scaling() const + scaling_method_e get_scaling_method() const { return scaling_; } - void set_scaling(std::string const& scaling) + void set_scaling_method(scaling_method_e scaling) { scaling_ = scaling; } @@ -115,13 +116,9 @@ struct MAPNIK_DECL raster_symbolizer : public symbolizer_base // respect explicitly specified values return filter_factor_; } else { - // No filter factor specified, calculate a sensible default value - // based on the scaling algorithm being employed. - scaling_method_e scaling = get_scaling_method_by_name (scaling_); - double ff = 1.0; - switch(scaling) + switch(scaling_) { case SCALING_NEAR: ff = 1.0; @@ -130,6 +127,7 @@ struct MAPNIK_DECL raster_symbolizer : public symbolizer_base // TODO potentially some of these algorithms would use filter_factor >2.0. // Contributions welcome from someone who knows more about them. case SCALING_BILINEAR: + case SCALING_BILINEAR8: case SCALING_BICUBIC: case SCALING_SPLINE16: case SCALING_SPLINE36: @@ -163,7 +161,7 @@ struct MAPNIK_DECL raster_symbolizer : public symbolizer_base private: std::string mode_; - std::string scaling_; + scaling_method_e scaling_; float opacity_; raster_colorizer_ptr colorizer_; double filter_factor_; diff --git a/include/mapnik/warp.hpp b/include/mapnik/warp.hpp index 035df63c0..f7e5ddcd9 100644 --- a/include/mapnik/warp.hpp +++ b/include/mapnik/warp.hpp @@ -26,16 +26,17 @@ // mapnik #include #include +#include namespace mapnik { -void reproject_raster(raster &target, raster const& source, - proj_transform const& prj_trans, - double offset_x, double offset_y, - unsigned mesh_size, - double filter_radius, - double scale_factor, - std::string scaling_method_name); +void reproject_and_scale_raster(raster & target, + raster const& source, + proj_transform const& prj_trans, + double offset_x, double offset_y, + unsigned mesh_size, + double filter_radius, + scaling_method_e scaling_method); } diff --git a/src/agg/process_raster_symbolizer.cpp b/src/agg/process_raster_symbolizer.cpp index ccf2c3d65..ec4fdc97a 100644 --- a/src/agg/process_raster_symbolizer.cpp +++ b/src/agg/process_raster_symbolizer.cpp @@ -22,6 +22,7 @@ // mapnik #include +#include #include #include #include @@ -44,7 +45,7 @@ void agg_renderer::process(raster_symbolizer const& sym, mapnik::feature_impl & feature, proj_transform const& prj_trans) { - raster_ptr const& source=feature.get_raster(); + raster_ptr const& source = feature.get_raster(); if (source) { // If there's a colorizer defined, use it to color the raster in-place @@ -54,28 +55,44 @@ void agg_renderer::process(raster_symbolizer const& sym, box2d target_ext = box2d(source->ext_); prj_trans.backward(target_ext, PROJ_ENVELOPE_POINTS); - - box2d ext=t_.forward(target_ext); - int start_x = (int)ext.minx(); - int start_y = (int)ext.miny(); - int end_x = (int)ceil(ext.maxx()); - int end_y = (int)ceil(ext.maxy()); + box2d ext = t_.forward(target_ext); + int start_x = static_cast(ext.minx()); + int start_y = static_cast(ext.miny()); + int end_x = static_cast(ceil(ext.maxx())); + int end_y = static_cast(ceil(ext.maxy())); int raster_width = end_x - start_x; int raster_height = end_y - start_y; - double err_offs_x = ext.minx() - start_x; - double err_offs_y = ext.miny() - start_y; - if (raster_width > 0 && raster_height > 0) { image_data_32 target_data(raster_width,raster_height); raster target(target_ext, target_data); - - reproject_raster(target, *source, prj_trans, err_offs_x, err_offs_y, - sym.get_mesh_size(), - sym.calculate_filter_factor(), - scale_factor_, - sym.get_scaling()); - + scaling_method_e scaling_method = sym.get_scaling_method(); + double filter_radius = sym.calculate_filter_factor(); + double offset_x = ext.minx() - start_x; + double offset_y = ext.miny() - start_y; + if (!prj_trans.equal()) + { + reproject_and_scale_raster(target, *source, prj_trans, + offset_x, offset_y, + sym.get_mesh_size(), + filter_radius, + scaling_method); + } + else + { + if (scaling_method == SCALING_BILINEAR8){ + scale_image_bilinear8(target.data_,source->data_, offset_x, offset_y); + } else { + double scaling_ratio = ext.width() / source->data_.width(); + scale_image_agg(target.data_, + source->data_, + scaling_method, + scaling_ratio, + offset_x, + offset_y, + filter_radius); + } + } composite(current_buffer_->data(), target.data_, sym.comp_op(), sym.get_opacity(), start_x, start_y, true); } } diff --git a/src/build.py b/src/build.py index f34a067d8..b995bd24a 100644 --- a/src/build.py +++ b/src/build.py @@ -103,6 +103,7 @@ source = Split( color.cpp conversions.cpp image_compositing.cpp + image_scaling.cpp box2d.cpp building_symbolizer.cpp datasource_cache.cpp diff --git a/src/cairo_renderer.cpp b/src/cairo_renderer.cpp index 094d665b2..70709af8c 100644 --- a/src/cairo_renderer.cpp +++ b/src/cairo_renderer.cpp @@ -1344,32 +1344,46 @@ void cairo_renderer_base::process(raster_symbolizer const& sym, box2d target_ext = box2d(source->ext_); prj_trans.backward(target_ext, PROJ_ENVELOPE_POINTS); - - box2d ext=t_.forward(target_ext); - int start_x = (int)ext.minx(); - int start_y = (int)ext.miny(); - int end_x = (int)ceil(ext.maxx()); - int end_y = (int)ceil(ext.maxy()); + box2d ext = t_.forward(target_ext); + int start_x = static_cast(ext.minx()); + int start_y = static_cast(ext.miny()); + int end_x = static_cast(ceil(ext.maxx())); + int end_y = static_cast(ceil(ext.maxy())); int raster_width = end_x - start_x; int raster_height = end_y - start_y; - double err_offs_x = ext.minx() - start_x; - double err_offs_y = ext.miny() - start_y; - if (raster_width > 0 && raster_height > 0) { - double scale_factor = ext.width() / source->data_.width(); image_data_32 target_data(raster_width,raster_height); raster target(target_ext, target_data); - - reproject_raster(target, *source, prj_trans, err_offs_x, err_offs_y, - sym.get_mesh_size(), - sym.calculate_filter_factor(), - scale_factor, - sym.get_scaling()); - + scaling_method_e scaling_method = sym.get_scaling_method(); + double filter_radius = sym.calculate_filter_factor(); + double offset_x = ext.minx() - start_x; + double offset_y = ext.miny() - start_y; + if (!prj_trans.equal()) + { + reproject_and_scale_raster(target, *source, prj_trans, + offset_x, offset_y, + sym.get_mesh_size(), + filter_radius, + scaling_method); + } + else + { + if (scaling_method == SCALING_BILINEAR8){ + scale_image_bilinear8(target.data_,source->data_, offset_x, offset_y); + } else { + double scaling_ratio = ext.width() / source->data_.width(); + scale_image_agg(target.data_, + source->data_, + scaling_method, + scaling_ratio, + offset_x, + offset_y, + filter_radius); + } + } cairo_context context(context_); context.set_operator(sym.comp_op()); - //TODO -- support for advanced image merging context.add_image(start_x, start_y, target.data_, sym.get_opacity()); } } diff --git a/src/image_scaling.cpp b/src/image_scaling.cpp new file mode 100644 index 000000000..c9ea1e862 --- /dev/null +++ b/src/image_scaling.cpp @@ -0,0 +1,359 @@ +/***************************************************************************** + * + * This file is part of Mapnik (c++ mapping toolkit) + * + * Copyright (C) 2011 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 + * + *****************************************************************************/ + +// mapnik +#include +#include +#include + +// boost +#include +#include + +// agg +#include "agg_image_accessors.h" +#include "agg_pixfmt_rgba.h" +#include "agg_rasterizer_scanline_aa.h" +#include "agg_renderer_scanline.h" +#include "agg_rendering_buffer.h" +#include "agg_scanline_u.h" +#include "agg_span_allocator.h" +#include "agg_span_image_filter_rgba.h" +#include "agg_span_interpolator_linear.h" +#include "agg_trans_affine.h" +#include "agg_image_filters.h" + +namespace mapnik +{ + +typedef boost::bimap scaling_method_lookup_type; +static const scaling_method_lookup_type scaling_lookup = boost::assign::list_of + (SCALING_NEAR,"near") + (SCALING_BILINEAR,"bilinear") + (SCALING_BICUBIC,"bicubic") + (SCALING_SPLINE16,"spline16") + (SCALING_SPLINE36,"spline36") + (SCALING_HANNING,"hanning") + (SCALING_HAMMING,"hamming") + (SCALING_HERMITE,"hermite") + (SCALING_KAISER,"kaiser") + (SCALING_QUADRIC,"quadric") + (SCALING_CATROM,"catrom") + (SCALING_GAUSSIAN,"gaussian") + (SCALING_BESSEL,"bessel") + (SCALING_MITCHELL,"mitchell") + (SCALING_SINC,"sinc") + (SCALING_LANCZOS,"lanczos") + (SCALING_BLACKMAN,"blackman") + (SCALING_BILINEAR8,"bilinear8") + ; + +boost::optional scaling_method_from_string(std::string const& name) +{ + boost::optional mode; + scaling_method_lookup_type::right_const_iterator right_iter = scaling_lookup.right.find(name); + if (right_iter != scaling_lookup.right.end()) + { + mode.reset(right_iter->second); + } + return mode; +} + +boost::optional scaling_method_to_string(scaling_method_e scaling_method) +{ + boost::optional mode; + scaling_method_lookup_type::left_const_iterator left_iter = scaling_lookup.left.find(scaling_method); + if (left_iter != scaling_lookup.left.end()) + { + mode.reset(left_iter->second); + } + return mode; +} + +// this has been replaced by agg impl - see https://trac.mapnik.org/ticket/656 +template +void scale_image_bilinear_old (Image & target,Image const& source, double x_off_f, double y_off_f) +{ + + int source_width=source.width(); + int source_height=source.height(); + + int target_width=target.width(); + int target_height=target.height(); + + if (source_width<1 || source_height<1 || + target_width<1 || target_height<1) return; + int x=0,y=0,xs=0,ys=0; + int tw2 = target_width/2; + int th2 = target_height/2; + int offs_x = rint((source_width-target_width-x_off_f*2*source_width)/2); + int offs_y = rint((source_height-target_height-y_off_f*2*source_height)/2); + unsigned yprt, yprt1, xprt, xprt1; + + //no scaling or subpixel offset + if (target_height == source_height && target_width == source_width && offs_x == 0 && offs_y == 0){ + for (y=0;y=source_height) + ys1--; + if (ys<0) + ys=ys1=0; + if (source_height/2=source_width) + xs1--; + if (xs<0) + xs=xs1=0; + + unsigned a = source(xs,ys); + unsigned b = source(xs1,ys); + unsigned c = source(xs,ys1); + unsigned d = source(xs1,ys1); + unsigned out=0; + unsigned t = 0; + + for(int i=0; i<4; i++){ + unsigned p,r,s; + // X axis + p = a&0xff; + r = b&0xff; + if (p!=r) + r = (r*xprt+p*xprt1+tw2)/target_width; + p = c&0xff; + s = d&0xff; + if (p!=s) + s = (s*xprt+p*xprt1+tw2)/target_width; + // Y axis + if (r!=s) + r = (s*yprt+r*yprt1+th2)/target_height; + // channel up + out |= r << t; + t += 8; + a >>= 8; + b >>= 8; + c >>= 8; + d >>= 8; + } + target(x,y)=out; + } + } +} + + +template +void scale_image_bilinear8 (Image & target,Image const& source, double x_off_f, double y_off_f) +{ + + int source_width=source.width(); + int source_height=source.height(); + + int target_width=target.width(); + int target_height=target.height(); + + if (source_width<1 || source_height<1 || + target_width<1 || target_height<1) return; + int x=0,y=0,xs=0,ys=0; + int tw2 = target_width/2; + int th2 = target_height/2; + int offs_x = rint((source_width-target_width-x_off_f*2*source_width)/2); + int offs_y = rint((source_height-target_height-y_off_f*2*source_height)/2); + unsigned yprt, yprt1, xprt, xprt1; + + //no scaling or subpixel offset + if (target_height == source_height && target_width == source_width && offs_x == 0 && offs_y == 0){ + for (y=0;y=source_height) + ys1--; + if (ys<0) + ys=ys1=0; + if (source_height/2=source_width) + xs1--; + if (xs<0) + xs=xs1=0; + + unsigned a = source(xs,ys); + unsigned b = source(xs1,ys); + unsigned c = source(xs,ys1); + unsigned d = source(xs1,ys1); + unsigned p,r,s; + // X axis + p = a&0xff; + r = b&0xff; + if (p!=r) + r = (r*xprt+p*xprt1+tw2)/target_width; + p = c&0xff; + s = d&0xff; + if (p!=s) + s = (s*xprt+p*xprt1+tw2)/target_width; + // Y axis + if (r!=s) + r = (s*yprt+r*yprt1+th2)/target_height; + target(x,y)=(0xff<<24) | (r<<16) | (r<<8) | r; + } + } +} + +template +void scale_image_agg(Image & target, + Image const& source, + scaling_method_e scaling_method, + double image_ratio, + double x_off_f, + double y_off_f, + double filter_radius, + double ratio) +{ + typedef agg::pixfmt_rgba32 pixfmt; + typedef agg::pixfmt_rgba32_pre pixfmt_pre; + typedef agg::renderer_base renderer_base; + + // define some stuff we'll use soon + agg::rasterizer_scanline_aa<> ras; + agg::scanline_u8 sl; + agg::span_allocator sa; + agg::image_filter_lut filter; + + // initialize source AGG buffer + agg::rendering_buffer rbuf_src((unsigned char*)source.getBytes(), source.width(), source.height(), source.width() * 4); + pixfmt pixf_src(rbuf_src); + typedef agg::image_accessor_clone img_src_type; + img_src_type img_src(pixf_src); + + // initialise destination AGG buffer (with transparency) + agg::rendering_buffer rbuf_dst((unsigned char*)target.getBytes(), target.width(), target.height(), target.width() * 4); + pixfmt_pre pixf_dst(rbuf_dst); + renderer_base rb_dst(pixf_dst); + rb_dst.clear(agg::rgba(0, 0, 0, 0)); + + // create a scaling matrix + agg::trans_affine img_mtx; + img_mtx /= agg::trans_affine_scaling(image_ratio * ratio, image_ratio * ratio); + + // create a linear interpolator for our scaling matrix + typedef agg::span_interpolator_linear<> interpolator_type; + interpolator_type interpolator(img_mtx); + + // draw an anticlockwise polygon to render our image into + double scaled_width = source.width() * image_ratio; + double scaled_height = source.height() * image_ratio; + ras.reset(); + ras.move_to_d(x_off_f, y_off_f); + ras.line_to_d(x_off_f + scaled_width, y_off_f); + ras.line_to_d(x_off_f + scaled_width, y_off_f + scaled_height); + ras.line_to_d(x_off_f, y_off_f + scaled_height); + + switch(scaling_method) + { + case SCALING_NEAR: + { + typedef agg::span_image_filter_rgba_nn span_gen_type; + span_gen_type sg(img_src, interpolator); + agg::render_scanlines_aa(ras, sl, rb_dst, sa, sg); + return; + } + case SCALING_BILINEAR: + filter.calculate(agg::image_filter_bilinear(), true); break; + case SCALING_BICUBIC: + filter.calculate(agg::image_filter_bicubic(), true); break; + case SCALING_SPLINE16: + filter.calculate(agg::image_filter_spline16(), true); break; + case SCALING_SPLINE36: + filter.calculate(agg::image_filter_spline36(), true); break; + case SCALING_HANNING: + filter.calculate(agg::image_filter_hanning(), true); break; + case SCALING_HAMMING: + filter.calculate(agg::image_filter_hamming(), true); break; + case SCALING_HERMITE: + filter.calculate(agg::image_filter_hermite(), true); break; + case SCALING_KAISER: + filter.calculate(agg::image_filter_kaiser(), true); break; + case SCALING_QUADRIC: + filter.calculate(agg::image_filter_quadric(), true); break; + case SCALING_CATROM: + filter.calculate(agg::image_filter_catrom(), true); break; + case SCALING_GAUSSIAN: + filter.calculate(agg::image_filter_gaussian(), true); break; + case SCALING_BESSEL: + filter.calculate(agg::image_filter_bessel(), true); break; + case SCALING_MITCHELL: + filter.calculate(agg::image_filter_mitchell(), true); break; + case SCALING_SINC: + filter.calculate(agg::image_filter_sinc(filter_radius), true); break; + case SCALING_LANCZOS: + filter.calculate(agg::image_filter_lanczos(filter_radius), true); break; + case SCALING_BLACKMAN: + filter.calculate(agg::image_filter_blackman(filter_radius), true); break; + } + typedef mapnik::span_image_resample_rgba_affine span_gen_type; + span_gen_type sg(img_src, interpolator, filter); + agg::render_scanlines_aa(ras, sl, rb_dst, sa, sg); +} + +template void scale_image_agg (image_data_32& target,const image_data_32& source, scaling_method_e scaling_method, double scale_factor, double x_off_f, double y_off_f, double filter_radius, double ratio); + +template void scale_image_bilinear_old (image_data_32& target,const image_data_32& source, double x_off_f, double y_off_f); + +template void scale_image_bilinear8 (image_data_32& target,const image_data_32& source, double x_off_f, double y_off_f); + + +} diff --git a/src/image_util.cpp b/src/image_util.cpp index 7cebf19e4..741e07eda 100644 --- a/src/image_util.cpp +++ b/src/image_util.cpp @@ -35,7 +35,6 @@ extern "C" #include #include #include -#include // jpeg #if defined(HAVE_JPEG) #include @@ -56,20 +55,6 @@ extern "C" #include #include -// agg -#include "agg_image_accessors.h" -#include "agg_pixfmt_rgba.h" -#include "agg_rasterizer_scanline_aa.h" -#include "agg_renderer_scanline.h" -#include "agg_rendering_buffer.h" -#include "agg_scanline_u.h" -//#include "agg_scanline_p.h" -#include "agg_span_allocator.h" -#include "agg_span_image_filter_rgba.h" -#include "agg_span_interpolator_linear.h" -#include "agg_trans_affine.h" -#include "agg_image_filters.h" - namespace mapnik { @@ -477,306 +462,6 @@ template std::string save_to_string > (image_view -void scale_image_bilinear_old (Image& target,const Image& source, double x_off_f, double y_off_f) -{ - - int source_width=source.width(); - int source_height=source.height(); - - int target_width=target.width(); - int target_height=target.height(); - - if (source_width<1 || source_height<1 || - target_width<1 || target_height<1) return; - int x=0,y=0,xs=0,ys=0; - int tw2 = target_width/2; - int th2 = target_height/2; - int offs_x = rint((source_width-target_width-x_off_f*2*source_width)/2); - int offs_y = rint((source_height-target_height-y_off_f*2*source_height)/2); - unsigned yprt, yprt1, xprt, xprt1; - - //no scaling or subpixel offset - if (target_height == source_height && target_width == source_width && offs_x == 0 && offs_y == 0){ - for (y=0;y=source_height) - ys1--; - if (ys<0) - ys=ys1=0; - if (source_height/2=source_width) - xs1--; - if (xs<0) - xs=xs1=0; - - unsigned a = source(xs,ys); - unsigned b = source(xs1,ys); - unsigned c = source(xs,ys1); - unsigned d = source(xs1,ys1); - unsigned out=0; - unsigned t = 0; - - for(int i=0; i<4; i++){ - unsigned p,r,s; - // X axis - p = a&0xff; - r = b&0xff; - if (p!=r) - r = (r*xprt+p*xprt1+tw2)/target_width; - p = c&0xff; - s = d&0xff; - if (p!=s) - s = (s*xprt+p*xprt1+tw2)/target_width; - // Y axis - if (r!=s) - r = (s*yprt+r*yprt1+th2)/target_height; - // channel up - out |= r << t; - t += 8; - a >>= 8; - b >>= 8; - c >>= 8; - d >>= 8; - } - target(x,y)=out; - } - } -} - - -template -void scale_image_bilinear8 (Image& target,const Image& source, double x_off_f, double y_off_f) -{ - - int source_width=source.width(); - int source_height=source.height(); - - int target_width=target.width(); - int target_height=target.height(); - - if (source_width<1 || source_height<1 || - target_width<1 || target_height<1) return; - int x=0,y=0,xs=0,ys=0; - int tw2 = target_width/2; - int th2 = target_height/2; - int offs_x = rint((source_width-target_width-x_off_f*2*source_width)/2); - int offs_y = rint((source_height-target_height-y_off_f*2*source_height)/2); - unsigned yprt, yprt1, xprt, xprt1; - - //no scaling or subpixel offset - if (target_height == source_height && target_width == source_width && offs_x == 0 && offs_y == 0){ - for (y=0;y=source_height) - ys1--; - if (ys<0) - ys=ys1=0; - if (source_height/2=source_width) - xs1--; - if (xs<0) - xs=xs1=0; - - unsigned a = source(xs,ys); - unsigned b = source(xs1,ys); - unsigned c = source(xs,ys1); - unsigned d = source(xs1,ys1); - unsigned p,r,s; - // X axis - p = a&0xff; - r = b&0xff; - if (p!=r) - r = (r*xprt+p*xprt1+tw2)/target_width; - p = c&0xff; - s = d&0xff; - if (p!=s) - s = (s*xprt+p*xprt1+tw2)/target_width; - // Y axis - if (r!=s) - r = (s*yprt+r*yprt1+th2)/target_height; - target(x,y)=(0xff<<24) | (r<<16) | (r<<8) | r; - } - } -} - -template -void scale_image_agg (Image& target,const Image& source, scaling_method_e scaling_method, double scale_factor, double x_off_f, double y_off_f, double filter_radius, double ratio) -{ - typedef agg::pixfmt_rgba32 pixfmt; - typedef agg::pixfmt_rgba32_pre pixfmt_pre; - typedef agg::renderer_base renderer_base; - - // define some stuff we'll use soon - agg::rasterizer_scanline_aa<> ras; - agg::scanline_u8 sl; - agg::span_allocator sa; - agg::image_filter_lut filter; - - // initialize source AGG buffer - agg::rendering_buffer rbuf_src((unsigned char*)source.getBytes(), source.width(), source.height(), source.width() * 4); - pixfmt pixf_src(rbuf_src); - typedef agg::image_accessor_clone img_src_type; - img_src_type img_src(pixf_src); - - // initialise destination AGG buffer (with transparency) - agg::rendering_buffer rbuf_dst((unsigned char*)target.getBytes(), target.width(), target.height(), target.width() * 4); - pixfmt_pre pixf_dst(rbuf_dst); - renderer_base rb_dst(pixf_dst); - rb_dst.clear(agg::rgba(0, 0, 0, 0)); - - // create a scaling matrix - agg::trans_affine img_mtx; - img_mtx /= agg::trans_affine_scaling(scale_factor * ratio, scale_factor * ratio); - - // create a linear interpolator for our scaling matrix - typedef agg::span_interpolator_linear<> interpolator_type; - interpolator_type interpolator(img_mtx); - - // draw an anticlockwise polygon to render our image into - double scaled_width = source.width() * scale_factor; - double scaled_height = source.height() * scale_factor; - ras.reset(); - ras.move_to_d(x_off_f, y_off_f); - ras.line_to_d(x_off_f + scaled_width, y_off_f); - ras.line_to_d(x_off_f + scaled_width, y_off_f + scaled_height); - ras.line_to_d(x_off_f, y_off_f + scaled_height); - - switch(scaling_method) - { - case SCALING_NEAR: - { - typedef agg::span_image_filter_rgba_nn span_gen_type; - span_gen_type sg(img_src, interpolator); - agg::render_scanlines_aa(ras, sl, rb_dst, sa, sg); - return; - } - case SCALING_BILINEAR: - filter.calculate(agg::image_filter_bilinear(), true); break; - case SCALING_BICUBIC: - filter.calculate(agg::image_filter_bicubic(), true); break; - case SCALING_SPLINE16: - filter.calculate(agg::image_filter_spline16(), true); break; - case SCALING_SPLINE36: - filter.calculate(agg::image_filter_spline36(), true); break; - case SCALING_HANNING: - filter.calculate(agg::image_filter_hanning(), true); break; - case SCALING_HAMMING: - filter.calculate(agg::image_filter_hamming(), true); break; - case SCALING_HERMITE: - filter.calculate(agg::image_filter_hermite(), true); break; - case SCALING_KAISER: - filter.calculate(agg::image_filter_kaiser(), true); break; - case SCALING_QUADRIC: - filter.calculate(agg::image_filter_quadric(), true); break; - case SCALING_CATROM: - filter.calculate(agg::image_filter_catrom(), true); break; - case SCALING_GAUSSIAN: - filter.calculate(agg::image_filter_gaussian(), true); break; - case SCALING_BESSEL: - filter.calculate(agg::image_filter_bessel(), true); break; - case SCALING_MITCHELL: - filter.calculate(agg::image_filter_mitchell(), true); break; - case SCALING_SINC: - filter.calculate(agg::image_filter_sinc(filter_radius), true); break; - case SCALING_LANCZOS: - filter.calculate(agg::image_filter_lanczos(filter_radius), true); break; - case SCALING_BLACKMAN: - filter.calculate(agg::image_filter_blackman(filter_radius), true); break; - } - typedef mapnik::span_image_resample_rgba_affine span_gen_type; - span_gen_type sg(img_src, interpolator, filter); - agg::render_scanlines_aa(ras, sl, rb_dst, sa, sg); -} - - void save_to_file(image_32 const& image,std::string const& file) { save_to_file(image.data(), file); @@ -810,10 +495,4 @@ std::string save_to_string(image_32 const& image, return save_to_string(image.data(), type, palette); } -template void scale_image_agg (image_data_32& target,const image_data_32& source, scaling_method_e scaling_method, double scale_factor, double x_off_f, double y_off_f, double filter_radius, double ratio); - -template void scale_image_bilinear_old (image_data_32& target,const image_data_32& source, double x_off_f, double y_off_f); - -template void scale_image_bilinear8 (image_data_32& target,const image_data_32& source, double x_off_f, double y_off_f); - } diff --git a/src/load_map.cpp b/src/load_map.cpp index 27cce14b7..14a7eedb2 100644 --- a/src/load_map.cpp +++ b/src/load_map.cpp @@ -28,6 +28,7 @@ #include #include #include +#include #include #include #include @@ -1468,7 +1469,27 @@ void map_parser::parse_raster_symbolizer(rule & rule, xml_node const & sym) // scaling optional scaling = sym.get_opt_attr("scaling"); - if (scaling) raster_sym.set_scaling(*scaling); + if (scaling) + { + std::string scaling_method = *scaling; + if (scaling_method == "fast") + { + MAPNIK_LOG_ERROR(raster_symbolizer) << "'scaling' value of 'fast' is deprecated and will be removed in Mapnik 3.x, use 'near' with Mapnik >= 2.1.x"; + raster_sym.set_scaling_method(SCALING_NEAR); + } + else + { + boost::optional method = scaling_method_from_string(scaling_method); + if (method) + { + raster_sym.set_scaling_method(*method); + } + else + { + throw config_error("failed to parse 'scaling': '" + *scaling + "'"); + } + } + } // opacity optional opacity = sym.get_opt_attr("opacity"); diff --git a/src/save_map.cpp b/src/save_map.cpp index e7e5923ab..b4b4946a5 100644 --- a/src/save_map.cpp +++ b/src/save_map.cpp @@ -32,6 +32,7 @@ #include #include #include +#include // boost #include @@ -158,9 +159,9 @@ public: ptree::value_type("RasterSymbolizer", ptree()))->second; raster_symbolizer dfl; - if ( sym.get_scaling() != dfl.get_scaling() || explicit_defaults_ ) + if ( sym.get_scaling_method() != dfl.get_scaling_method() || explicit_defaults_ ) { - set_attr( sym_node, "scaling", sym.get_scaling() ); + set_attr( sym_node, "scaling", *scaling_method_to_string(sym.get_scaling_method()) ); } if ( sym.get_opacity() != dfl.get_opacity() || explicit_defaults_ ) diff --git a/src/warp.cpp b/src/warp.cpp index 1033e062a..ee0dc6a05 100644 --- a/src/warp.cpp +++ b/src/warp.cpp @@ -46,162 +46,149 @@ namespace mapnik { -void reproject_raster(raster &target, raster const& source, +void reproject_and_scale_raster(raster & target, raster const& source, proj_transform const& prj_trans, double offset_x, double offset_y, unsigned mesh_size, double filter_radius, - double scale_factor, - std::string scaling_method_name) + scaling_method_e scaling_method) { - if (prj_trans.equal()) { + CoordTransform ts(source.data_.width(), source.data_.height(), + source.ext_); + CoordTransform tt(target.data_.width(), target.data_.height(), + target.ext_, offset_x, offset_y); + unsigned i, j; + unsigned mesh_nx = ceil(source.data_.width()/double(mesh_size)+1); + unsigned mesh_ny = ceil(source.data_.height()/double(mesh_size)+1); - if (scaling_method_name == "bilinear8"){ - scale_image_bilinear8(target.data_,source.data_, - offset_x, offset_y); - } else { - scaling_method_e scaling_method = get_scaling_method_by_name(scaling_method_name); - scale_image_agg(target.data_,source.data_, (scaling_method_e)scaling_method, scale_factor, offset_x, offset_y, filter_radius); + ImageData xs(mesh_nx, mesh_ny); + ImageData ys(mesh_nx, mesh_ny); + + // Precalculate reprojected mesh + for(j=0; j xs(mesh_nx, mesh_ny); - ImageData ys(mesh_nx, mesh_ny); + // Initialize AGG objects + typedef agg::pixfmt_rgba32 pixfmt; + typedef pixfmt::color_type color_type; + typedef agg::renderer_base renderer_base; + typedef agg::pixfmt_rgba32_pre pixfmt_pre; + typedef agg::renderer_base renderer_base_pre; - // Precalculate reprojected mesh - for(j=0; j rasterizer; + agg::scanline_u8 scanline; + agg::rendering_buffer buf((unsigned char*)target.data_.getData(), + target.data_.width(), + target.data_.height(), + target.data_.width()*4); + pixfmt_pre pixf_pre(buf); + renderer_base_pre rb_pre(pixf_pre); + rasterizer.clip_box(0, 0, target.data_.width(), target.data_.height()); + agg::rendering_buffer buf_tile( + (unsigned char*)source.data_.getData(), + source.data_.width(), + source.data_.height(), + source.data_.width() * 4); - // Initialize AGG objects - typedef agg::pixfmt_rgba32 pixfmt; - typedef pixfmt::color_type color_type; - typedef agg::renderer_base renderer_base; - typedef agg::pixfmt_rgba32_pre pixfmt_pre; - typedef agg::renderer_base renderer_base_pre; + pixfmt pixf_tile(buf_tile); - agg::rasterizer_scanline_aa<> rasterizer; - agg::scanline_u8 scanline; - agg::rendering_buffer buf((unsigned char*)target.data_.getData(), - target.data_.width(), - target.data_.height(), - target.data_.width()*4); - pixfmt_pre pixf_pre(buf); - renderer_base_pre rb_pre(pixf_pre); - rasterizer.clip_box(0, 0, target.data_.width(), target.data_.height()); - agg::rendering_buffer buf_tile( - (unsigned char*)source.data_.getData(), - source.data_.width(), - source.data_.height(), - source.data_.width() * 4); + typedef agg::image_accessor_clone img_accessor_type; + img_accessor_type ia(pixf_tile); - pixfmt pixf_tile(buf_tile); + agg::span_allocator sa; - typedef agg::image_accessor_clone img_accessor_type; - img_accessor_type ia(pixf_tile); + // Initialize filter + agg::image_filter_lut filter; + switch(scaling_method) + { + case SCALING_NEAR: break; + case SCALING_BILINEAR8: // TODO - impl this or remove? + case SCALING_BILINEAR: + filter.calculate(agg::image_filter_bilinear(), true); break; + case SCALING_BICUBIC: + filter.calculate(agg::image_filter_bicubic(), true); break; + case SCALING_SPLINE16: + filter.calculate(agg::image_filter_spline16(), true); break; + case SCALING_SPLINE36: + filter.calculate(agg::image_filter_spline36(), true); break; + case SCALING_HANNING: + filter.calculate(agg::image_filter_hanning(), true); break; + case SCALING_HAMMING: + filter.calculate(agg::image_filter_hamming(), true); break; + case SCALING_HERMITE: + filter.calculate(agg::image_filter_hermite(), true); break; + case SCALING_KAISER: + filter.calculate(agg::image_filter_kaiser(), true); break; + case SCALING_QUADRIC: + filter.calculate(agg::image_filter_quadric(), true); break; + case SCALING_CATROM: + filter.calculate(agg::image_filter_catrom(), true); break; + case SCALING_GAUSSIAN: + filter.calculate(agg::image_filter_gaussian(), true); break; + case SCALING_BESSEL: + filter.calculate(agg::image_filter_bessel(), true); break; + case SCALING_MITCHELL: + filter.calculate(agg::image_filter_mitchell(), true); break; + case SCALING_SINC: + filter.calculate(agg::image_filter_sinc(filter_radius), true); break; + case SCALING_LANCZOS: + filter.calculate(agg::image_filter_lanczos(filter_radius), true); break; + case SCALING_BLACKMAN: + filter.calculate(agg::image_filter_blackman(filter_radius), true); break; + } - agg::span_allocator sa; + // Project mesh cells into target interpolating raster inside each one + for(j=0; j + interpolator_type; + interpolator_type interpolator(tr); - unsigned x0 = i * mesh_size; - unsigned y0 = j * mesh_size; - unsigned x1 = (i+1) * mesh_size; - unsigned y1 = (j+1) * mesh_size; - - agg::trans_affine tr(polygon, x0, y0, x1, y1); - if (tr.is_valid()) - { - typedef agg::span_interpolator_linear - interpolator_type; - interpolator_type interpolator(tr); - - if (scaling_method == SCALING_NEAR) { - typedef agg::span_image_filter_rgba_nn - - span_gen_type; - span_gen_type sg(ia, interpolator); - agg::render_scanlines_aa(rasterizer, scanline, rb_pre, - sa, sg); - } else { - typedef mapnik::span_image_resample_rgba_affine - span_gen_type; - span_gen_type sg(ia, interpolator, filter); - agg::render_scanlines_aa(rasterizer, scanline, rb_pre, - sa, sg); - } + if (scaling_method == SCALING_NEAR) { + typedef agg::span_image_filter_rgba_nn + + span_gen_type; + span_gen_type sg(ia, interpolator); + agg::render_scanlines_aa(rasterizer, scanline, rb_pre, + sa, sg); + } else { + typedef mapnik::span_image_resample_rgba_affine + span_gen_type; + span_gen_type sg(ia, interpolator, filter); + agg::render_scanlines_aa(rasterizer, scanline, rb_pre, + sa, sg); } - } + } } } From d721cdb6b9952fc85bc386f231467e30ff211c62 Mon Sep 17 00:00:00 2001 From: Dane Springmeyer Date: Fri, 6 Jul 2012 16:48:37 -0700 Subject: [PATCH 023/133] re-expose raster scaling in tests --- tests/python_tests/raster_symbolizer_test.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/tests/python_tests/raster_symbolizer_test.py b/tests/python_tests/raster_symbolizer_test.py index 2962bab5e..ba3e492cf 100644 --- a/tests/python_tests/raster_symbolizer_test.py +++ b/tests/python_tests/raster_symbolizer_test.py @@ -116,9 +116,7 @@ def test_raster_with_alpha_blends_correctly_with_background(): style = mapnik.Style() rule = mapnik.Rule() symbolizer = mapnik.RasterSymbolizer() - #XXX: This fixes it, see http://trac.mapnik.org/ticket/759#comment:3 - # (and remove comment when this test passes) - #symbolizer.scaling="bilinear_old" + symbolizer.scaling = mapnik.scaling_method.BILINEAR rule.symbols.append(symbolizer) style.rules.append(rule) From 269569250c5b6535f2fdb3e5116050599ca21c70 Mon Sep 17 00:00:00 2001 From: Dane Springmeyer Date: Fri, 6 Jul 2012 17:44:15 -0700 Subject: [PATCH 024/133] use mapnik.Image for visual tests - closes #1296 --- bindings/python/mapnik_image.cpp | 13 +++++++++ tests/visual_tests/compare.py | 45 ++++++++++++++++++-------------- 2 files changed, 38 insertions(+), 20 deletions(-) diff --git a/bindings/python/mapnik_image.cpp b/bindings/python/mapnik_image.cpp index 0de5e35d1..e9934252a 100644 --- a/bindings/python/mapnik_image.cpp +++ b/bindings/python/mapnik_image.cpp @@ -118,6 +118,18 @@ bool painted(mapnik::image_32 const& im) return im.painted(); } +unsigned get_pixel(mapnik::image_32 const& im, int x, int y) +{ + if (x < static_cast(im.width()) && y < static_cast(im.height())) + { + mapnik::image_data_32 const & data = im.data(); + return data(x,y); + } + PyErr_SetString(PyExc_IndexError, "invalid x,y for image dimensions"); + boost::python::throw_error_already_set(); + return 0; +} + void set_pixel(mapnik::image_32 & im, unsigned x, unsigned y, mapnik::color const& c) { im.setPixel(x, y, c.rgba()); @@ -216,6 +228,7 @@ void export_image() .def("premultiply",&image_32::premultiply) .def("demultiply",&image_32::demultiply) .def("set_pixel",&set_pixel) + .def("get_pixel",&get_pixel) //TODO(haoyu) The method name 'tostring' might be confusing since they actually return bytes in Python 3 .def("tostring",&tostring1) diff --git a/tests/visual_tests/compare.py b/tests/visual_tests/compare.py index 4e57127c0..98edde22a 100644 --- a/tests/visual_tests/compare.py +++ b/tests/visual_tests/compare.py @@ -1,8 +1,7 @@ # -*- coding: utf-8 -*- -#import math, operator -import Image import sys +import mapnik COMPUTE_THRESHOLD = 16 @@ -11,37 +10,43 @@ passed = 0 # returns true if pixels are not identical def compare_pixels(pixel1, pixel2): - r_diff = abs(pixel1[0] - pixel2[0]) - g_diff = abs(pixel1[1] - pixel2[1]) - b_diff = abs(pixel1[2] - pixel2[2]) - if(r_diff > COMPUTE_THRESHOLD or g_diff > COMPUTE_THRESHOLD or b_diff > COMPUTE_THRESHOLD): + if pixel1 == pixel2: + return False + # will only work on little endian + r_diff = abs((pixel1 & 0xff) - (pixel2 & 0xff)) + g_diff = abs(((pixel1 >> 8) & 0xff) - ((pixel2 >> 8) & 0xff)) + b_diff = abs(((pixel1 >> 16) & 0xff)- ((pixel2 >> 16) & 0xff)) + a_diff = abs(((pixel1 >> 24) & 0xff) - ((pixel2 >> 24) & 0xff)) + if(r_diff > COMPUTE_THRESHOLD or + g_diff > COMPUTE_THRESHOLD or + b_diff > COMPUTE_THRESHOLD or + a_diff > COMPUTE_THRESHOLD): return True else: return False -# compare tow images and return number of different pixels -def compare(fn1, fn2): +# compare two images and return number of different pixels +def compare(actual, expected): global errors global passed - im1 = Image.open(fn1) + im1 = mapnik.Image.open(actual) try: - im2 = Image.open(fn2) + im2 = mapnik.Image.open(expected) except IOError: - errors.append((None, fn1, fn2)) + errors.append((None, actual, expected)) return -1 diff = 0 - pixels = im1.size[0] * im1.size[1] - delta_pixels = im2.size[0] * im2.size[1] - pixels + pixels = im1.width() * im1.height() + delta_pixels = (im2.width() * im2.height()) - pixels if delta_pixels != 0: - errors.append((delta_pixels, fn1, fn2)) + errors.append((delta_pixels, actual, expected)) return delta_pixels - im1 = im1.getdata() - im2 = im2.getdata() - for i in range(3, pixels - 1, 3): - if(compare_pixels(im1[i], im2[i])): - diff = diff + 1 + for x in range(0,im1.width(),2): + for y in range(0,im1.height(),2): + if compare_pixels(im1.get_pixel(x,y),im2.get_pixel(x,y)): + diff += 1 if diff != 0: - errors.append((diff, fn1, fn2)) + errors.append((diff, actual, expected)) passed += 1 return diff From 17d3414b7a7e3f02d6f6b7b25ceded710651765a Mon Sep 17 00:00:00 2001 From: Dane Springmeyer Date: Fri, 6 Jul 2012 18:08:19 -0700 Subject: [PATCH 025/133] speed up scons by > 2x --- Makefile | 8 ++++---- SConstruct | 6 +++++- configure | 2 +- 3 files changed, 10 insertions(+), 6 deletions(-) diff --git a/Makefile b/Makefile index 0213d0d36..9eb3a50c4 100755 --- a/Makefile +++ b/Makefile @@ -1,13 +1,13 @@ all: mapnik install: - python scons/scons.py install + @python scons/scons.py --silent --config=cache --implicit-deps-unchanged --max-drift=1 install mapnik: - python scons/scons.py + @python scons/scons.py --silent --config=cache --implicit-deps-unchanged --max-drift=1 clean: - python scons/scons.py -c + python scons/scons.py --silent -c --config=cache --implicit-deps-unchanged --max-drift=1 reset: if test -e ".sconf_temp/"; then rm -r ".sconf_temp/"; fi @@ -15,7 +15,7 @@ reset: if test -e "config.cache"; then rm "config.cache"; fi uninstall: - python scons/scons.py uninstall + python scons/scons.py --silent --config=cache --implicit-deps-unchanged --max-drift=1 uninstall test: @echo "*** Running visual tests..." diff --git a/SConstruct b/SConstruct index 30e2eb4a4..68d665468 100644 --- a/SConstruct +++ b/SConstruct @@ -111,6 +111,8 @@ PLUGINS = { # plugins with external dependencies #### SCons build options and initial setup #### env = Environment(ENV=os.environ) +env.Decider('MD5-timestamp') +env.SourceCode(".", None) def color_print(color,text,newline=True): # 1 - red @@ -932,6 +934,8 @@ if not preconfigured: color_print(1,"SCons CONFIG not found: '%s'" % conf) # Recreate the base environment using modified `opts` env = Environment(ENV=os.environ,options=opts) + env.Decider('MD5-timestamp') + env.SourceCode(".", None) env['USE_CONFIG'] = True else: color_print(4,'SCons USE_CONFIG specified as false, will not inherit variables python config file...') @@ -1146,6 +1150,7 @@ if not preconfigured: # if the user is not setting custom boost configuration # enforce boost version greater than or equal to BOOST_MIN_VERSION if not conf.CheckBoost(BOOST_MIN_VERSION): + color_print(4,'Found boost lib version... %s' % env.get('BOOST_LIB_VERSION_FROM_HEADER') ) color_print(1,'Boost version %s or greater is required' % BOOST_MIN_VERSION) if not env['BOOST_VERSION']: env['MISSING_DEPS'].append('boost version >=%s' % BOOST_MIN_VERSION) @@ -1660,7 +1665,6 @@ if not HELP_REQUESTED: # But let's also cache implicit deps... EnsureSConsVersion(0,98) SetOption('implicit_cache', 1) - env.Decider('MD5-timestamp') SetOption('max_drift', 1) else: diff --git a/configure b/configure index ebe8aaf7b..99d1fc22a 100755 --- a/configure +++ b/configure @@ -1,3 +1,3 @@ #!/bin/sh -python scons/scons.py configure "$@" +python scons/scons.py --implicit-cache configure "$@" From b74738dd9167b88483cb93912094ce0d7b920c5b Mon Sep 17 00:00:00 2001 From: Dane Springmeyer Date: Fri, 6 Jul 2012 18:31:36 -0700 Subject: [PATCH 026/133] scons: make a failure to link boost_python non-fatal --- SConstruct | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/SConstruct b/SConstruct index 68d665468..b087233a6 100644 --- a/SConstruct +++ b/SConstruct @@ -1345,8 +1345,8 @@ if not preconfigured: if not conf.CheckLibWithHeader(libs=[env['BOOST_PYTHON_LIB']], header='boost/python/detail/config.hpp', language='C++'): color_print(1, 'Could not find library "%s" for boost python bindings' % env['BOOST_PYTHON_LIB']) - env['MISSING_DEPS'].append('boost python') - + # failing on launchpad, so let's make it a warning for now + #env['MISSING_DEPS'].append('boost python') if env['CAIRO']: if conf.CheckPKGConfig('0.15.0') and conf.CheckPKG('pycairo'): From e18b4580cd72f1a8dcab581f7d58696e794cc4a6 Mon Sep 17 00:00:00 2001 From: Dane Springmeyer Date: Fri, 6 Jul 2012 18:37:48 -0700 Subject: [PATCH 027/133] scons: install and clean should print output --- Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index 9eb3a50c4..863b547bc 100755 --- a/Makefile +++ b/Makefile @@ -1,13 +1,13 @@ all: mapnik install: - @python scons/scons.py --silent --config=cache --implicit-deps-unchanged --max-drift=1 install + @python scons/scons.py --config=cache --implicit-deps-unchanged --max-drift=1 install mapnik: @python scons/scons.py --silent --config=cache --implicit-deps-unchanged --max-drift=1 clean: - python scons/scons.py --silent -c --config=cache --implicit-deps-unchanged --max-drift=1 + python scons/scons.py -c --config=cache --implicit-deps-unchanged --max-drift=1 reset: if test -e ".sconf_temp/"; then rm -r ".sconf_temp/"; fi From cde0c0217dd2fb19373b9b0a211abb7827fdc3bf Mon Sep 17 00:00:00 2001 From: Dane Springmeyer Date: Fri, 6 Jul 2012 18:39:59 -0700 Subject: [PATCH 028/133] add missing file --- bindings/python/mapnik_scaling_method.cpp | 53 +++++++++++++++++++++++ 1 file changed, 53 insertions(+) create mode 100644 bindings/python/mapnik_scaling_method.cpp diff --git a/bindings/python/mapnik_scaling_method.cpp b/bindings/python/mapnik_scaling_method.cpp new file mode 100644 index 000000000..a5ac926c6 --- /dev/null +++ b/bindings/python/mapnik_scaling_method.cpp @@ -0,0 +1,53 @@ +/***************************************************************************** + * + * This file is part of Mapnik (c++ mapping toolkit) + * + * Copyright (C) 2012 Artem Pavlenko, Jean-Francois Doyon + * + * 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 + * + *****************************************************************************/ +//$Id$ + + +#include +#include +#include "mapnik_enumeration.hpp" + +void export_scaling_method() +{ + using namespace boost::python; + + enum_("scaling_method") + .value("NEAR", mapnik::SCALING_NEAR) + .value("BILINEAR", mapnik::SCALING_BILINEAR) + .value("BICUBIC", mapnik::SCALING_BICUBIC) + .value("SPLINE16", mapnik::SCALING_SPLINE16) + .value("SPLINE36", mapnik::SCALING_SPLINE36) + .value("HANNING", mapnik::SCALING_HANNING) + .value("HAMMING", mapnik::SCALING_HAMMING) + .value("HERMITE", mapnik::SCALING_HERMITE) + .value("KAISER", mapnik::SCALING_KAISER) + .value("QUADRIC", mapnik::SCALING_QUADRIC) + .value("CATROM", mapnik::SCALING_CATROM) + .value("GAUSSIAN", mapnik::SCALING_GAUSSIAN) + .value("BESSEL", mapnik::SCALING_BESSEL) + .value("MITCHELL", mapnik::SCALING_MITCHELL) + .value("SINC", mapnik::SCALING_SINC) + .value("LANCZOS", mapnik::SCALING_LANCZOS) + .value("BLACKMAN", mapnik::SCALING_BLACKMAN) + .value("BILINEAR8", mapnik::SCALING_BILINEAR8) + ; +} From 20d935ea1ec3a948d09877942a968c00c85e7cc6 Mon Sep 17 00:00:00 2001 From: artemp Date: Mon, 9 Jul 2012 10:18:41 +0100 Subject: [PATCH 029/133] + remove explicit keyword + make width and height 'optional' - default init (0) + change members order --- include/mapnik/markers_symbolizer.hpp | 16 ++++++++-------- src/markers_symbolizer.cpp | 12 ++++++------ 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/include/mapnik/markers_symbolizer.hpp b/include/mapnik/markers_symbolizer.hpp index 7dde57ddb..e8ba4cd0e 100644 --- a/include/mapnik/markers_symbolizer.hpp +++ b/include/mapnik/markers_symbolizer.hpp @@ -49,9 +49,14 @@ struct MAPNIK_DECL markers_symbolizer : public symbolizer_with_image, public symbolizer_base { public: - explicit markers_symbolizer(); + markers_symbolizer(); markers_symbolizer(path_expression_ptr const& filename); markers_symbolizer(markers_symbolizer const& rhs); + + void set_width(expression_ptr const& width); + expression_ptr const& get_width() const; + void set_height(expression_ptr const& height); + expression_ptr const& get_height() const; void set_ignore_placement(bool ignore_placement); bool get_ignore_placement() const; void set_allow_overlap(bool overlap); @@ -60,10 +65,6 @@ public: double get_spacing() const; void set_max_error(double max_error); double get_max_error() const; - void set_width(expression_ptr const&width); - expression_ptr const& get_width() const; - void set_height(expression_ptr const& height); - expression_ptr const& get_height() const; void set_fill(color const& fill); boost::optional get_fill() const; void set_stroke(stroke const& stroke); @@ -71,16 +72,15 @@ public: void set_marker_placement(marker_placement_e marker_p); marker_placement_e get_marker_placement() const; private: + expression_ptr width_; + expression_ptr height_; bool ignore_placement_; bool allow_overlap_; double spacing_; double max_error_; - expression_ptr width_; - expression_ptr height_; boost::optional fill_; boost::optional stroke_; marker_placement_e marker_p_; - }; } diff --git a/src/markers_symbolizer.cpp b/src/markers_symbolizer.cpp index 25713755c..0627ea70f 100644 --- a/src/markers_symbolizer.cpp +++ b/src/markers_symbolizer.cpp @@ -39,34 +39,34 @@ IMPLEMENT_ENUM( marker_placement_e, marker_placement_strings ) markers_symbolizer::markers_symbolizer() : symbolizer_with_image(path_expression_ptr(new path_expression)), symbolizer_base(), + width_(), + height_(), ignore_placement_(false), allow_overlap_(false), spacing_(100.0), max_error_(0.2), - width_(boost::make_shared(10.0)), - height_(boost::make_shared(10.0)), marker_p_(MARKER_LINE_PLACEMENT) {} markers_symbolizer::markers_symbolizer(path_expression_ptr const& filename) : symbolizer_with_image(filename), symbolizer_base(), + width_(), + height_(), ignore_placement_(false), allow_overlap_(false), spacing_(100.0), max_error_(0.2), - width_(boost::make_shared(10.0)), - height_(boost::make_shared(10.0)), marker_p_(MARKER_LINE_PLACEMENT) {} markers_symbolizer::markers_symbolizer(markers_symbolizer const& rhs) : symbolizer_with_image(rhs), symbolizer_base(rhs), + width_(rhs.width_), + height_(rhs.height_), ignore_placement_(rhs.ignore_placement_), allow_overlap_(rhs.allow_overlap_), spacing_(rhs.spacing_), max_error_(rhs.max_error_), - width_(rhs.width_), - height_(rhs.height_), fill_(rhs.fill_), stroke_(rhs.stroke_), marker_p_(rhs.marker_p_) {} From 58bd55b07566347397c4b2c550e773fd856f73d7 Mon Sep 17 00:00:00 2001 From: artemp Date: Mon, 9 Jul 2012 10:21:12 +0100 Subject: [PATCH 030/133] + allow independent width and height + better namings --- src/load_map.cpp | 78 ++++++++++++++++++++---------------------------- 1 file changed, 32 insertions(+), 46 deletions(-) diff --git a/src/load_map.cpp b/src/load_map.cpp index 14a7eedb2..29496b7f5 100644 --- a/src/load_map.cpp +++ b/src/load_map.cpp @@ -950,13 +950,13 @@ void map_parser::parse_point_symbolizer(rule & rule, xml_node const & sym) } -void map_parser::parse_markers_symbolizer(rule & rule, xml_node const& sym) +void map_parser::parse_markers_symbolizer(rule & rule, xml_node const& node) { try { std::string filename(""); - optional file = sym.get_opt_attr("file"); - optional base = sym.get_opt_attr("base"); + optional file = node.get_opt_attr("file"); + optional base = node.get_opt_attr("base"); if (file && !file->empty()) { @@ -990,21 +990,21 @@ void map_parser::parse_markers_symbolizer(rule & rule, xml_node const& sym) path_expression_ptr expr(boost::make_shared()); if (!filename.empty()) { - if (!parse_path_from_string(expr, filename, sym.get_tree().path_expr_grammar)) + if (!parse_path_from_string(expr, filename, node.get_tree().path_expr_grammar)) { throw mapnik::config_error("Failed to parse path_expression '" + filename + "'"); } } - markers_symbolizer symbol(expr); + markers_symbolizer sym(expr); - optional opacity = sym.get_opt_attr("opacity"); - if (opacity) symbol.set_opacity(*opacity); + optional opacity = node.get_opt_attr("opacity"); + if (opacity) sym.set_opacity(*opacity); - optional image_transform_wkt = sym.get_opt_attr("transform"); + optional image_transform_wkt = node.get_opt_attr("transform"); if (image_transform_wkt) { mapnik::transform_list_ptr tl = boost::make_shared(); - if (!mapnik::parse_transform(*tl, *image_transform_wkt, sym.get_tree().transform_expr_grammar)) + if (!mapnik::parse_transform(*tl, *image_transform_wkt, node.get_tree().transform_expr_grammar)) { std::stringstream ss; ss << "Could not parse transform from '" << *image_transform_wkt @@ -1018,52 +1018,38 @@ void map_parser::parse_markers_symbolizer(rule & rule, xml_node const& sym) MAPNIK_LOG_WARN(load_map) << "map_parser: " << ss; } } - symbol.set_image_transform(tl); + sym.set_image_transform(tl); } - optional c = sym.get_opt_attr("fill"); - if (c) symbol.set_fill(*c); - optional spacing = sym.get_opt_attr("spacing"); - if (spacing) symbol.set_spacing(*spacing); - optional max_error = sym.get_opt_attr("max-error"); - if (max_error) symbol.set_max_error(*max_error); - optional allow_overlap = sym.get_opt_attr("allow-overlap"); - optional ignore_placement = sym.get_opt_attr("ignore-placement"); - if (allow_overlap) symbol.set_allow_overlap(*allow_overlap); - if (ignore_placement) symbol.set_ignore_placement(*ignore_placement); + optional c = node.get_opt_attr("fill"); + if (c) sym.set_fill(*c); + optional spacing = node.get_opt_attr("spacing"); + if (spacing) sym.set_spacing(*spacing); + optional max_error = node.get_opt_attr("max-error"); + if (max_error) sym.set_max_error(*max_error); + optional allow_overlap = node.get_opt_attr("allow-overlap"); + optional ignore_placement = node.get_opt_attr("ignore-placement"); + if (allow_overlap) sym.set_allow_overlap(*allow_overlap); + if (ignore_placement) sym.set_ignore_placement(*ignore_placement); - optional w = sym.get_opt_attr("width"); - optional h = sym.get_opt_attr("height"); + optional width = node.get_opt_attr("width"); + if (width) sym.set_width(*width); - if (w && h) - { - symbol.set_width(*w); - symbol.set_height(*h); - } - else if (w) - { - symbol.set_width(*w); - symbol.set_height(*w); - - } - else if (h) - { - symbol.set_width(*h); - symbol.set_height(*h); - } + optional height = node.get_opt_attr("height"); + if (height) sym.set_height(*height); stroke strk; - if (parse_stroke(strk,sym)) - symbol.set_stroke(strk); + if (parse_stroke(strk,node)) + sym.set_stroke(strk); - marker_placement_e placement = sym.get_attr("placement", MARKER_LINE_PLACEMENT); - symbol.set_marker_placement(placement); - parse_symbolizer_base(symbol, sym); - rule.append(symbol); + marker_placement_e placement = node.get_attr("placement", MARKER_LINE_PLACEMENT); + sym.set_marker_placement(placement); + parse_symbolizer_base(sym, node); + rule.append(sym); } - catch (const config_error & ex) + catch (config_error const& ex) { - ex.append_context("in MarkersSymbolizer", sym); + ex.append_context("in MarkersSymbolizer", node); throw; } } From f656efaa4903eb7c5dbe64518eb0429b2447da16 Mon Sep 17 00:00:00 2001 From: artemp Date: Mon, 9 Jul 2012 10:22:19 +0100 Subject: [PATCH 031/133] + apply dynamic width and/or height + make 'width/height' pair and 'transform' mutually exlusive --- src/agg/process_markers_symbolizer.cpp | 51 +++++++++++++++++++++++--- 1 file changed, 46 insertions(+), 5 deletions(-) diff --git a/src/agg/process_markers_symbolizer.cpp b/src/agg/process_markers_symbolizer.cpp index 805bcbe94..8bd4145c7 100644 --- a/src/agg/process_markers_symbolizer.cpp +++ b/src/agg/process_markers_symbolizer.cpp @@ -82,6 +82,42 @@ bool push_explicit_style(Attr const& src, Attr & dst, markers_symbolizer const& return false; } +template +void setup_label_transform(agg::trans_affine & tr, box2d const& bbox, mapnik::feature_impl const& feature, T const& sym) +{ + int width = 0; + int height = 0; + + expression_ptr const& width_expr = sym.get_width(); + if (width_expr) + width = boost::apply_visitor(evaluate(feature), *width_expr).to_int(); + + expression_ptr const& height_expr = sym.get_height(); + if (height_expr) + height = boost::apply_visitor(evaluate(feature), *height_expr).to_int(); + + if (width > 0 && height > 0) + { + double sx = width/bbox.width(); + double sy = height/bbox.height(); + tr *= agg::trans_affine_scaling(sx,sy); + } + else if (width > 0) + { + double sx = width/bbox.width(); + tr *= agg::trans_affine_scaling(sx); + } + else if (height > 0) + { + double sy = height/bbox.height(); + tr *= agg::trans_affine_scaling(sy); + } + else + { + evaluate_transform(tr, feature, sym.get_image_transform()); + } +} + template void agg_renderer::process(markers_symbolizer const& sym, mapnik::feature_impl & feature, @@ -106,9 +142,6 @@ void agg_renderer::process(markers_symbolizer const& sym, pixf.comp_op(static_cast(sym.comp_op())); renderer_base renb(pixf); renderer_type ren(renb); - agg::trans_affine tr; - evaluate_transform(tr, feature, sym.get_image_transform()); - tr = agg::trans_affine_scaling(scale_factor_) * tr; agg::trans_affine geom_tr; evaluate_transform(geom_tr, feature, sym.get_transform()); @@ -124,13 +157,21 @@ void agg_renderer::process(markers_symbolizer const& sym, if (!(*mark)->is_vector()) { MAPNIK_LOG_DEBUG(agg_renderer) << "agg_renderer: markers_symbolizer does not yet support non-SVG markers"; - return; } + boost::optional marker = (*mark)->get_vector_data(); box2d const& bbox = (*marker)->bounding_box(); - coord2d center = bbox.center(); + + agg::trans_affine tr; + + + setup_label_transform(tr, bbox, feature, sym); + tr = agg::trans_affine_scaling(scale_factor_) * tr; + + + coord2d center = bbox.center(); agg::trans_affine_translation recenter(-center.x, -center.y); agg::trans_affine marker_trans = recenter * tr; From ad7a02695e55b766c495420b034a805a6194e4e0 Mon Sep 17 00:00:00 2001 From: Dane Springmeyer Date: Mon, 9 Jul 2012 13:38:49 -0700 Subject: [PATCH 032/133] fix test markers xml, accidentally changed in 9888ff0d509f56 --- tests/data/good_maps/markers_symbolizer_points_file.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/data/good_maps/markers_symbolizer_points_file.xml b/tests/data/good_maps/markers_symbolizer_points_file.xml index 7814761ce..304adc572 100644 --- a/tests/data/good_maps/markers_symbolizer_points_file.xml +++ b/tests/data/good_maps/markers_symbolizer_points_file.xml @@ -3,7 +3,7 @@ From d98f418c24f3bf065825803f0eb6bf566b961b05 Mon Sep 17 00:00:00 2001 From: Dane Springmeyer Date: Mon, 9 Jul 2012 14:37:26 -0700 Subject: [PATCH 033/133] remove silent from all scons commands --- Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index 863b547bc..d88e216bb 100755 --- a/Makefile +++ b/Makefile @@ -4,7 +4,7 @@ install: @python scons/scons.py --config=cache --implicit-deps-unchanged --max-drift=1 install mapnik: - @python scons/scons.py --silent --config=cache --implicit-deps-unchanged --max-drift=1 + @python scons/scons.py --config=cache --implicit-deps-unchanged --max-drift=1 clean: python scons/scons.py -c --config=cache --implicit-deps-unchanged --max-drift=1 @@ -15,7 +15,7 @@ reset: if test -e "config.cache"; then rm "config.cache"; fi uninstall: - python scons/scons.py --silent --config=cache --implicit-deps-unchanged --max-drift=1 uninstall + python scons/scons.py --config=cache --implicit-deps-unchanged --max-drift=1 uninstall test: @echo "*** Running visual tests..." From cbf821c762ab4ceff59f2ef000abe8c68a3a1388 Mon Sep 17 00:00:00 2001 From: Dane Springmeyer Date: Mon, 9 Jul 2012 17:32:36 -0700 Subject: [PATCH 034/133] move key grid functions to cpp file --- include/mapnik/grid/grid.hpp | 93 ++------------------------------ src/grid/grid.cpp | 102 ++++++++++++++++++++++++++++++++++- 2 files changed, 104 insertions(+), 91 deletions(-) diff --git a/include/mapnik/grid/grid.hpp b/include/mapnik/grid/grid.hpp index 708f8bddc..f199144c4 100644 --- a/include/mapnik/grid/grid.hpp +++ b/include/mapnik/grid/grid.hpp @@ -77,39 +77,9 @@ private: public: - hit_grid(int width, int height, std::string const& key, unsigned int resolution) - :width_(width), - height_(height), - key_(key), - data_(width,height), - resolution_(resolution), - id_name_("__id__"), - painted_(false), - names_(), - f_keys_(), - features_(), - ctx_(boost::make_shared()) - { - f_keys_[base_mask] = ""; - data_.set(base_mask); - } + hit_grid(int width, int height, std::string const& key, unsigned int resolution); - hit_grid(const hit_grid& rhs) - :width_(rhs.width_), - height_(rhs.height_), - key_(rhs.key_), - data_(rhs.data_), - resolution_(rhs.resolution_), - id_name_("__id__"), - painted_(rhs.painted_), - names_(rhs.names_), - f_keys_(rhs.f_keys_), - features_(rhs.features_), - ctx_(rhs.ctx_) - { - f_keys_[base_mask] = ""; - data_.set(base_mask); - } + hit_grid(const hit_grid& rhs); ~hit_grid() {} @@ -128,64 +98,7 @@ public: return id_name_; } - inline void add_feature(mapnik::feature_impl & feature) - { - int feature_id = feature.id(); - // avoid adding duplicate features (e.g. in the case of both a line symbolizer and a polygon symbolizer) - typename feature_key_type::const_iterator feature_pos = f_keys_.find(feature_id); - if (feature_pos != f_keys_.end()) - { - return; - } - - if (ctx_->size() == 0) { - mapnik::feature_impl::iterator itr = feature.begin(); - mapnik::feature_impl::iterator end = feature.end(); - for ( ;itr!=end; ++itr) - { - ctx_->push(boost::get<0>(*itr)); - } - } - // NOTE: currently lookup keys must be strings, - // but this should be revisited - lookup_type lookup_value; - if (key_ == id_name_) - { - mapnik::util::to_string(lookup_value,feature_id); - } - else - { - if (feature.has_key(key_)) - { - lookup_value = feature.get(key_).to_string(); - } - else - { - MAPNIK_LOG_DEBUG(grid) << "hit_grid: Should not get here: key '" << key_ << "' not found in feature properties"; - } - } - - if (!lookup_value.empty()) - { - // TODO - consider shortcutting f_keys if feature_id == lookup_value - // create a mapping between the pixel id and the feature key - f_keys_.insert(std::make_pair(feature_id,lookup_value)); - // if extra fields have been supplied, push them into grid memory - if (!names_.empty()) - { - // it is ~ 2x faster to copy feature attributes compared - // to building up a in-memory cache of feature_ptrs - // https://github.com/mapnik/mapnik/issues/1198 - mapnik::feature_ptr feature2(mapnik::feature_factory::create(ctx_,feature_id)); - feature2->set_data(feature.get_data()); - features_.insert(std::make_pair(lookup_value,feature2)); - } - } - else - { - MAPNIK_LOG_DEBUG(grid) << "hit_grid: Warning - key '" << key_ << "' was blank for " << feature; - } - } + inline void add_feature(mapnik::feature_impl & feature); inline void add_property_name(std::string const& name) { diff --git a/src/grid/grid.cpp b/src/grid/grid.cpp index ade783a7b..baafd9d41 100644 --- a/src/grid/grid.cpp +++ b/src/grid/grid.cpp @@ -26,6 +26,106 @@ namespace mapnik { -template<> const grid::value_type grid::base_mask = std::numeric_limits::min(); +template +const typename hit_grid::value_type hit_grid::base_mask = std::numeric_limits::min(); + +template +hit_grid::hit_grid(int width, int height, std::string const& key, unsigned int resolution) + : width_(width), + height_(height), + key_(key), + data_(width,height), + resolution_(resolution), + id_name_("__id__"), + painted_(false), + names_(), + f_keys_(), + features_(), + ctx_(boost::make_shared()) + { + f_keys_[base_mask] = ""; + data_.set(base_mask); + } + +template +hit_grid::hit_grid(const hit_grid& rhs) + : width_(rhs.width_), + height_(rhs.height_), + key_(rhs.key_), + data_(rhs.data_), + resolution_(rhs.resolution_), + id_name_("__id__"), + painted_(rhs.painted_), + names_(rhs.names_), + f_keys_(rhs.f_keys_), + features_(rhs.features_), + ctx_(rhs.ctx_) + { + f_keys_[base_mask] = ""; + data_.set(base_mask); + } + +template +void hit_grid::add_feature(mapnik::feature_impl & feature) +{ + int feature_id = feature.id(); + // avoid adding duplicate features (e.g. in the case of both a line symbolizer and a polygon symbolizer) + typename feature_key_type::const_iterator feature_pos = f_keys_.find(feature_id); + if (feature_pos != f_keys_.end()) + { + return; + } + + if (ctx_->size() == 0) { + mapnik::feature_impl::iterator itr = feature.begin(); + mapnik::feature_impl::iterator end = feature.end(); + for ( ;itr!=end; ++itr) + { + ctx_->push(boost::get<0>(*itr)); + } + } + // NOTE: currently lookup keys must be strings, + // but this should be revisited + lookup_type lookup_value; + if (key_ == id_name_) + { + mapnik::util::to_string(lookup_value,feature_id); + } + else + { + if (feature.has_key(key_)) + { + lookup_value = feature.get(key_).to_string(); + } + else + { + MAPNIK_LOG_DEBUG(grid) << "hit_grid: Should not get here: key '" << key_ << "' not found in feature properties"; + } + } + + if (!lookup_value.empty()) + { + // TODO - consider shortcutting f_keys if feature_id == lookup_value + // create a mapping between the pixel id and the feature key + f_keys_.insert(std::make_pair(feature_id,lookup_value)); + // if extra fields have been supplied, push them into grid memory + if (!names_.empty()) + { + // it is ~ 2x faster to copy feature attributes compared + // to building up a in-memory cache of feature_ptrs + // https://github.com/mapnik/mapnik/issues/1198 + mapnik::feature_ptr feature2(mapnik::feature_factory::create(ctx_,feature_id)); + feature2->set_data(feature.get_data()); + features_.insert(std::make_pair(lookup_value,feature2)); + } + } + else + { + MAPNIK_LOG_DEBUG(grid) << "hit_grid: Warning - key '" << key_ << "' was blank for " << feature; + } +} + + +template class hit_grid; } From 79ef09d1a3274ff169642b30ebef8f75d5c1251f Mon Sep 17 00:00:00 2001 From: Dane Springmeyer Date: Mon, 9 Jul 2012 18:40:41 -0700 Subject: [PATCH 035/133] create grid feature context with correct sorting - closes #1306 --- include/mapnik/feature.hpp | 5 +++++ src/grid/grid.cpp | 6 +++--- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/include/mapnik/feature.hpp b/include/mapnik/feature.hpp index 7100f8e65..e4799a811 100644 --- a/include/mapnik/feature.hpp +++ b/include/mapnik/feature.hpp @@ -77,6 +77,11 @@ public: return index; } + void add(key_type const& name, size_type index) + { + mapping_.insert(std::make_pair(name, index)); + } + size_type size() const { return mapping_.size(); } const_iterator begin() const { return mapping_.begin();} const_iterator end() const { return mapping_.end();} diff --git a/src/grid/grid.cpp b/src/grid/grid.cpp index baafd9d41..c6c0f89dd 100644 --- a/src/grid/grid.cpp +++ b/src/grid/grid.cpp @@ -77,11 +77,11 @@ void hit_grid::add_feature(mapnik::feature_impl & feature) } if (ctx_->size() == 0) { - mapnik::feature_impl::iterator itr = feature.begin(); - mapnik::feature_impl::iterator end = feature.end(); + context_type::map_type::const_iterator itr = feature.context()->begin(); + context_type::map_type::const_iterator end = feature.context()->end(); for ( ;itr!=end; ++itr) { - ctx_->push(boost::get<0>(*itr)); + ctx_->add(itr->first,itr->second); } } // NOTE: currently lookup keys must be strings, From 73e15f0c757932db9c9afaa5fbb333ac53dcf0a4 Mon Sep 17 00:00:00 2001 From: artemp Date: Tue, 10 Jul 2012 12:48:09 +0100 Subject: [PATCH 036/133] + fix unused parameter warnings --- include/mapnik/value.hpp | 32 ++++++++++++++++++++++++++------ 1 file changed, 26 insertions(+), 6 deletions(-) diff --git a/include/mapnik/value.hpp b/include/mapnik/value.hpp index 185539d3e..d325a3390 100644 --- a/include/mapnik/value.hpp +++ b/include/mapnik/value.hpp @@ -71,19 +71,39 @@ inline void to_utf8(UnicodeString const& input, std::string & target) struct value_null { template - value_null operator+ (T const& other) const { return *this; } + value_null operator+ (T const& other) const + { + boost::ignore_unused_variable_warning(other); + return *this; + } template - value_null operator- (T const& other) const { return *this; } + value_null operator- (T const& other) const + { + boost::ignore_unused_variable_warning(other); + return *this; + } template - value_null operator* (T const& other) const { return *this; } + value_null operator* (T const& other) const + { + boost::ignore_unused_variable_warning(other); + return *this; + } template - value_null operator/ (T const& other) const { return *this; } + value_null operator/ (T const& other) const + { + boost::ignore_unused_variable_warning(other); + return *this; + } template - value_null operator% (T const& other) const { return *this; } + value_null operator% (T const& other) const + { + boost::ignore_unused_variable_warning(other); + return *this; + } }; typedef boost::variant value_base; @@ -352,7 +372,7 @@ struct add : public boost::static_visitor { return lhs + rhs; } - + value_type operator() (UnicodeString const& lhs, value_null rhs) const { boost::ignore_unused_variable_warning(rhs); From c8b2031428a1a2f4bd653717e0bee13d8dcc63d8 Mon Sep 17 00:00:00 2001 From: artemp Date: Tue, 10 Jul 2012 12:48:32 +0100 Subject: [PATCH 037/133] + fix unused parameter warning --- include/mapnik/rule.hpp | 1 + 1 file changed, 1 insertion(+) diff --git a/include/mapnik/rule.hpp b/include/mapnik/rule.hpp index c073de1ef..6acb43cc9 100644 --- a/include/mapnik/rule.hpp +++ b/include/mapnik/rule.hpp @@ -200,6 +200,7 @@ private: template void copy_text_ptr(T & sym) const { + boost::ignore_unused_variable_warning(sym); MAPNIK_LOG_WARN(rule) << "rule: deep copying TextSymbolizers is broken!"; } From e18fe4eccd4fa74fcf89836d52d9cd737da85a02 Mon Sep 17 00:00:00 2001 From: artemp Date: Tue, 10 Jul 2012 12:49:14 +0100 Subject: [PATCH 038/133] + fix unused parameter warning --- include/mapnik/metawriter.hpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/include/mapnik/metawriter.hpp b/include/mapnik/metawriter.hpp index 693a9059a..ac518d28e 100644 --- a/include/mapnik/metawriter.hpp +++ b/include/mapnik/metawriter.hpp @@ -144,7 +144,11 @@ public: */ void set_size(int width, int height) { width_ = width; height_ = height; } /** Set Map object's srs. */ - virtual void set_map_srs(projection const& proj) { /* Not required when working with image coordinates. */ } + virtual void set_map_srs(projection const& proj) + { + boost::ignore_unused_variable_warning(proj); + } + /** Return the list of default properties. */ metawriter_properties const& get_default_properties() const { return dflt_properties_;} protected: From fe8daa4a2a5eeefb11a406915da382802110d8c0 Mon Sep 17 00:00:00 2001 From: artemp Date: Tue, 10 Jul 2012 12:50:27 +0100 Subject: [PATCH 039/133] pass filter_tag by const ref --- include/mapnik/image_filter.hpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/include/mapnik/image_filter.hpp b/include/mapnik/image_filter.hpp index a92b91fc7..58fee0181 100644 --- a/include/mapnik/image_filter.hpp +++ b/include/mapnik/image_filter.hpp @@ -487,7 +487,7 @@ struct filter_visitor : boost::static_visitor : src_(src) {} template - void operator () (T filter_tag) + void operator () (T const& filter_tag) { apply_filter(src_,filter_tag); } @@ -495,7 +495,6 @@ struct filter_visitor : boost::static_visitor Src & src_; }; - }} #endif // MAPNIK_IMAGE_FILTER_HPP From db2bd535de62e3e6702dafeea8bb6e623f5926ad Mon Sep 17 00:00:00 2001 From: artemp Date: Tue, 10 Jul 2012 12:51:08 +0100 Subject: [PATCH 040/133] + impl operator<< for filters + boost::karma based filter generator --- include/mapnik/image_filter_types.hpp | 99 ++++++++++++++++++++++++++- 1 file changed, 97 insertions(+), 2 deletions(-) diff --git a/include/mapnik/image_filter_types.hpp b/include/mapnik/image_filter_types.hpp index f39d8a722..6f00e1e28 100644 --- a/include/mapnik/image_filter_types.hpp +++ b/include/mapnik/image_filter_types.hpp @@ -23,7 +23,12 @@ #ifndef MAPNIK_IMAGE_FILTER_TYPES_HPP #define MAPNIK_IMAGE_FILTER_TYPES_HPP +// boost #include +#include +#include +// stl +#include namespace mapnik { namespace filter { @@ -37,7 +42,7 @@ struct x_gradient {}; struct y_gradient {}; struct invert {}; -struct agg_stack_blur +struct agg_stack_blur { agg_stack_blur(unsigned rx_, unsigned ry_) : rx(rx_),ry(ry_) {} @@ -48,7 +53,6 @@ struct agg_stack_blur unsigned ry; }; - typedef boost::variant filter_type; +inline std::ostream& operator<< (std::ostream& os, blur) +{ + os << "blur"; + return os; +} + +inline std::ostream& operator<< (std::ostream& os, gray) +{ + os << "gray"; + return os; +} + +inline std::ostream& operator<< (std::ostream& os, agg_stack_blur const& filter) +{ + os << "agg-stack-blur:" << filter.rx << ',' << filter.ry; + return os; +} + +inline std::ostream& operator<< (std::ostream& os, emboss) +{ + os << "emboss"; + return os; +} + +inline std::ostream& operator<< (std::ostream& os, sharpen) +{ + os << "sharpen"; + return os; +} + +inline std::ostream& operator<< (std::ostream& os, edge_detect) +{ + os << "edge-detect"; + return os; +} + +inline std::ostream& operator<< (std::ostream& os, sobel) +{ + os << "sobel"; + return os; +} + +inline std::ostream& operator<< (std::ostream& os, x_gradient) +{ + os << "x-gradient"; + return os; +} + +inline std::ostream& operator<< (std::ostream& os, y_gradient) +{ + os << "y-gradient"; + return os; +} + +inline std::ostream& operator<< (std::ostream& os, invert) +{ + os << "invert"; + return os; +} + +template +struct to_string_visitor : boost::static_visitor +{ + to_string_visitor(Out & out) + : out_(out) {} + + template + void operator () (T const& filter_tag) + { + out_ << filter_tag; + } + + Out & out_; +}; + +inline std::ostream& operator<< (std::ostream& os, filter_type const& filter) +{ + to_string_visitor visitor(os); + boost::apply_visitor(visitor, filter); + return os; +} + +template +bool generate_image_filters(OutputIterator& sink, Container const& v) +{ + using boost::spirit::karma::stream; + using boost::spirit::karma::generate; + bool r = generate(sink, stream % ' ', v); + return r; +} + }} #endif // MAPNIK_IMAGE_FILTER_TYPES_HPP From 216768fbc0f35af2430b9fd3c1bbd60e06f86024 Mon Sep 17 00:00:00 2001 From: artemp Date: Tue, 10 Jul 2012 12:52:18 +0100 Subject: [PATCH 041/133] + output image-filters and direct-image-filters --- src/save_map.cpp | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/src/save_map.cpp b/src/save_map.cpp index b4b4946a5..0151ff2a7 100644 --- a/src/save_map.cpp +++ b/src/save_map.cpp @@ -33,7 +33,7 @@ #include #include #include - +#include // boost #include #include @@ -556,6 +556,26 @@ void serialize_style( ptree & map_node, Map::const_style_iterator style_it, bool set_attr(style_node, "comp-op", "src-over"); } + if (style.image_filters().size() > 0) + { + std::string filters_str; + std::back_insert_iterator sink(filters_str); + if (generate_image_filters(sink, style.image_filters())) + { + set_attr(style_node, "image-filters", filters_str); + } + } + + if (style.direct_image_filters().size() > 0) + { + std::string filters_str; + std::back_insert_iterator sink(filters_str); + if (generate_image_filters(sink, style.direct_image_filters())) + { + set_attr(style_node, "direct-image-filters", filters_str); + } + } + rules::const_iterator it = style.get_rules().begin(); rules::const_iterator end = style.get_rules().end(); for (; it != end; ++it) From 6cde3e686490f070c03654154738cd3aed2b7481 Mon Sep 17 00:00:00 2001 From: artemp Date: Tue, 10 Jul 2012 16:58:43 +0100 Subject: [PATCH 042/133] + add scale_factor_ UI (QDoubleSpinBox) --- demo/viewer/mainwindow.cpp | 23 ++++++++++++++++------ demo/viewer/mainwindow.hpp | 3 +++ demo/viewer/mapwidget.cpp | 40 ++++++++++++++++++++++---------------- demo/viewer/mapwidget.hpp | 5 +++-- 4 files changed, 46 insertions(+), 25 deletions(-) diff --git a/demo/viewer/mainwindow.cpp b/demo/viewer/mainwindow.cpp index 6ceaf0656..436a31ddc 100644 --- a/demo/viewer/mainwindow.cpp +++ b/demo/viewer/mainwindow.cpp @@ -32,6 +32,7 @@ #include #include #include +#include // mapnik @@ -97,12 +98,15 @@ MainWindow::MainWindow() //connect mapview to layerlist connect(mapWidget_, SIGNAL(mapViewChanged()),layerTab_, SLOT(update())); // slider - connect(slider_,SIGNAL(valueChanged(int)),mapWidget_,SLOT(zoomToLevel(int))); + connect(slider_,SIGNAL(valueChanged(int)),mapWidget_,SLOT(zoomToLevel(int))); // renderer selector - connect(renderer_selector_,SIGNAL(currentIndexChanged(QString const&)), + connect(renderer_selector_,SIGNAL(currentIndexChanged(QString const&)), mapWidget_, SLOT(updateRenderer(QString const&))); - - // + + // scale factor + connect(scale_factor_,SIGNAL(valueChanged(double)), + mapWidget_, SLOT(updateScaleFactor(double))); + // connect(layerTab_,SIGNAL(update_mapwidget()),mapWidget_,SLOT(updateMap())); connect(layerTab_,SIGNAL(layerSelected(int)), mapWidget_,SLOT(layerSelected(int))); @@ -373,16 +377,23 @@ void MainWindow::createToolBars() fileToolBar->addAction(infoAct); fileToolBar->addAction(reloadAct); fileToolBar->addAction(printAct); - + renderer_selector_ = new QComboBox(fileToolBar); renderer_selector_->setFocusPolicy(Qt::NoFocus); renderer_selector_->addItem("AGG"); #ifdef HAVE_CAIRO renderer_selector_->addItem("Cairo"); #endif - renderer_selector_->addItem("Grid"); + renderer_selector_->addItem("Grid"); fileToolBar->addWidget(renderer_selector_); + scale_factor_ = new QDoubleSpinBox(fileToolBar); + scale_factor_->setMinimum(0.1); + scale_factor_->setMaximum(5.0); + scale_factor_->setSingleStep(0.1); + scale_factor_->setValue(1.0); + + fileToolBar->addWidget(scale_factor_); slider_ = new QSlider(Qt::Horizontal,fileToolBar); slider_->setRange(1,18); slider_->setTickPosition(QSlider::TicksBelow); diff --git a/demo/viewer/mainwindow.hpp b/demo/viewer/mainwindow.hpp index e96fb78f2..25271693b 100644 --- a/demo/viewer/mainwindow.hpp +++ b/demo/viewer/mainwindow.hpp @@ -28,6 +28,7 @@ #include #include #include +#include #include "mapwidget.hpp" @@ -37,6 +38,7 @@ class LayerTab; class StyleTab; class QSlider; class QComboBox; +class QDoubleSpinBox; class MainWindow : public QMainWindow { @@ -108,6 +110,7 @@ private: QStatusBar *status; QSlider * slider_; QComboBox * renderer_selector_; + QDoubleSpinBox * scale_factor_; mapnik::box2d default_extent_; }; diff --git a/demo/viewer/mapwidget.cpp b/demo/viewer/mapwidget.cpp index 295b141fe..218115548 100644 --- a/demo/viewer/mapwidget.cpp +++ b/demo/viewer/mapwidget.cpp @@ -184,16 +184,16 @@ void MapWidget::mousePressEvent(QMouseEvent* e) feature_ptr feat = fs->next(); if (feat) { - + feature_kv_iterator itr(*feat,true); feature_kv_iterator end(*feat); - + for ( ;itr!=end; ++itr) { info.push_back(QPair(QString(boost::get<0>(*itr).c_str()), boost::get<1>(*itr).to_string().c_str())); } - + typedef mapnik::coord_transform path_type; for (unsigned i=0; inum_geometries();++i) @@ -498,12 +498,12 @@ void render_agg(mapnik::Map const& map, double scaling_factor, QPixmap & pix) { unsigned width=map.width(); unsigned height=map.height(); - + image_32 buf(width,height); mapnik::agg_renderer ren(map,buf,scaling_factor); - + try - { + { ren.apply(); QImage image((uchar*)buf.raw_data(),width,height,QImage::Format_ARGB32); pix = QPixmap::fromImage(image.rgbSwapped()); @@ -527,23 +527,23 @@ void render_grid(mapnik::Map const& map, double scaling_factor, QPixmap & pix) { unsigned width=map.width(); unsigned height=map.height(); - + mapnik::grid buf(width,height,"F_CODE", 1); mapnik::grid_renderer ren(map,buf,scaling_factor); - + try - { + { ren.apply(); int * imdata = static_cast(buf.raw_data()); - + QImage image(width,height,QImage::Format_RGB32); for (unsigned i = 0 ; i < height ; ++i) - { + { for (unsigned j = 0 ; j < width ; ++j) { image.setPixel(j,i,qRgb((uint8_t)(imdata[i*width+j]>>8), (uint8_t)(imdata[i*width+j+1]>>8), - (uint8_t)(imdata[i*width+j+2]>>8))); + (uint8_t)(imdata[i*width+j+2]>>8))); } } pix = QPixmap::fromImage(image); @@ -567,12 +567,12 @@ void render_cairo(mapnik::Map const& map, double scaling_factor, QPixmap & pix) { #ifdef HAVE_CAIRO - Cairo::RefPtr image_surface = + Cairo::RefPtr image_surface = Cairo::ImageSurface::create(Cairo::FORMAT_ARGB32, map.width(),map.height()); - + mapnik::cairo_renderer png_render(map, image_surface, scaling_factor); png_render.apply(); - + image_32 buf(image_surface); QImage image((uchar*)buf.raw_data(),buf.width(),buf.height(),QImage::Format_ARGB32); pix = QPixmap::fromImage(image.rgbSwapped()); @@ -588,6 +588,12 @@ void MapWidget::updateRenderer(QString const& txt) updateMap(); } +void MapWidget::updateScaleFactor(double scale_factor) +{ + set_scaling_factor(scale_factor); + updateMap(); +} + void MapWidget::updateMap() { if (map_) @@ -611,7 +617,7 @@ void MapWidget::updateMap() try { - projection prj(map_->srs()); // map projection + projection prj(map_->srs()); // map projection box2d ext = map_->get_current_extent(); double x0 = ext.minx(); double y0 = ext.miny(); @@ -623,7 +629,7 @@ void MapWidget::updateMap() update(); // emit signal to interested widgets emit mapViewChanged(); - } + } catch (...) { std::cerr << "Unknown exception caught!\n"; diff --git a/demo/viewer/mapwidget.hpp b/demo/viewer/mapwidget.hpp index 671cc5ab4..0aab462b8 100644 --- a/demo/viewer/mapwidget.hpp +++ b/demo/viewer/mapwidget.hpp @@ -53,8 +53,8 @@ public: AGG, Cairo, Grid - }; - + }; + private: boost::shared_ptr map_; int selected_; @@ -91,6 +91,7 @@ public slots: void updateMap(); void layerSelected(int); void updateRenderer(QString const& txt); + void updateScaleFactor(double scale_factor); signals: void mapViewChanged(); protected: From 4f507e2fa3358e16316fb09ba9b7e4292b82a4eb Mon Sep 17 00:00:00 2001 From: Dane Springmeyer Date: Tue, 10 Jul 2012 08:59:35 -0700 Subject: [PATCH 043/133] expose the ability to parse an svg from an in-memory string --- include/mapnik/svg/svg_parser.hpp | 2 + src/svg_parser.cpp | 65 +++++++++++++++++++++---------- 2 files changed, 46 insertions(+), 21 deletions(-) diff --git a/include/mapnik/svg/svg_parser.hpp b/include/mapnik/svg/svg_parser.hpp index a3da60fe0..96559b6dc 100644 --- a/include/mapnik/svg/svg_parser.hpp +++ b/include/mapnik/svg/svg_parser.hpp @@ -44,7 +44,9 @@ namespace mapnik { namespace svg { explicit svg_parser(svg_converter_type & path); ~svg_parser(); void parse(std::string const& filename); + void parse_from_string(std::string const& svg); private: + bool parse_reader(xmlTextReaderPtr reader); void process_node(xmlTextReaderPtr reader); void start_element(xmlTextReaderPtr reader); void end_element(xmlTextReaderPtr reader); diff --git a/src/svg_parser.cpp b/src/svg_parser.cpp index eb8dcb5dc..8eda9cf24 100644 --- a/src/svg_parser.cpp +++ b/src/svg_parser.cpp @@ -135,29 +135,52 @@ svg_parser::~svg_parser() {} void svg_parser::parse(std::string const& filename) { xmlTextReaderPtr reader = xmlNewTextReaderFilename(filename.c_str()); - if (reader != 0) + if (reader == NULL) { - int ret = xmlTextReaderRead(reader); - try { - while (ret == 1) - { - process_node(reader); - ret = xmlTextReaderRead(reader); - } - } - catch (std::exception const& ex) - { - xmlFreeTextReader(reader); - throw; - } - xmlFreeTextReader(reader); - if (ret != 0) - { - MAPNIK_LOG_ERROR(svg_parser) << "Failed to parse " << filename; - } - } else { - MAPNIK_LOG_ERROR(svg_parser) << "Unable to open " << filename; + MAPNIK_LOG_ERROR(svg_parser) << "Unable to open '" << filename << "'"; } + else if (!parse_reader(reader)) + { + MAPNIK_LOG_ERROR(svg_parser) << "Unable to parse '" << filename << "'"; + } +} + +void svg_parser::parse_from_string(std::string const& svg) +{ + xmlTextReaderPtr reader = xmlReaderForMemory(svg.c_str(),svg.size(),NULL,NULL, + (XML_PARSE_NOBLANKS | XML_PARSE_NOCDATA | XML_PARSE_NOERROR | XML_PARSE_NOWARNING)); + if (reader == NULL) + { + MAPNIK_LOG_ERROR(svg_parser) << "Unable to parse '" << svg << "'"; + } + else if (!parse_reader(reader)) + { + MAPNIK_LOG_ERROR(svg_parser) << "Unable to parse '" << svg << "'"; + } +} + +bool svg_parser::parse_reader(xmlTextReaderPtr reader) +{ + int ret = xmlTextReaderRead(reader); + try { + while (ret == 1) + { + process_node(reader); + ret = xmlTextReaderRead(reader); + } + } + catch (std::exception const& ex) + { + xmlFreeTextReader(reader); + throw; + } + xmlFreeTextReader(reader); + if (ret != 0) + { + // parsing failure + return false; + } + return true; } void svg_parser::process_node(xmlTextReaderPtr reader) From 5aff56a1928688bb3ce671148ff061ec7f3f75ae Mon Sep 17 00:00:00 2001 From: Dane Springmeyer Date: Tue, 10 Jul 2012 09:36:08 -0700 Subject: [PATCH 044/133] expose ability to clear global caches in python - closes #1022 --- bindings/python/mapnik_python.cpp | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/bindings/python/mapnik_python.cpp b/bindings/python/mapnik_python.cpp index f30c35017..5ec4b93ac 100644 --- a/bindings/python/mapnik_python.cpp +++ b/bindings/python/mapnik_python.cpp @@ -89,6 +89,15 @@ void export_logger(); #include "mapnik_value_converter.hpp" #include "mapnik_threads.hpp" #include "python_optional.hpp" +#include +#include + + +void clear_cache() +{ + mapnik::marker_cache::instance()->clear(); + mapnik::mapped_memory_cache::instance()->clear(); +} #if defined(HAVE_CAIRO) && defined(HAVE_PYCAIRO) #include @@ -393,6 +402,15 @@ BOOST_PYTHON_MODULE(_mapnik) export_label_collision_detector(); export_logger(); + def("clear_cache", &clear_cache, + "\n" + "Clear all global caches of markers and mapped memory regions.\n" + "\n" + "Usage:\n" + ">>> from mapnik import clear_cache\n" + ">>> clear_cache()\n" + ); + def("render_grid",&render_grid, ( arg("map"), arg("layer"), From f79fd4634e19782c13f9fba6fc2e1cac008f03e9 Mon Sep 17 00:00:00 2001 From: Dane Springmeyer Date: Tue, 10 Jul 2012 14:28:52 -0700 Subject: [PATCH 045/133] make markdown files --- plugins/input/templates/{README => README.md} | 0 plugins/input/templates/helloworld/{README => README.md} | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename plugins/input/templates/{README => README.md} (100%) rename plugins/input/templates/helloworld/{README => README.md} (100%) diff --git a/plugins/input/templates/README b/plugins/input/templates/README.md similarity index 100% rename from plugins/input/templates/README rename to plugins/input/templates/README.md diff --git a/plugins/input/templates/helloworld/README b/plugins/input/templates/helloworld/README.md similarity index 100% rename from plugins/input/templates/helloworld/README rename to plugins/input/templates/helloworld/README.md From c227ea8b5f179472fee61f107d2f8196f281a3e4 Mon Sep 17 00:00:00 2001 From: Dane Springmeyer Date: Tue, 10 Jul 2012 14:46:00 -0700 Subject: [PATCH 046/133] add sample Makefile for local dev --- plugins/input/templates/helloworld/Makefile | 30 +++++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 plugins/input/templates/helloworld/Makefile diff --git a/plugins/input/templates/helloworld/Makefile b/plugins/input/templates/helloworld/Makefile new file mode 100644 index 000000000..5ad5c357d --- /dev/null +++ b/plugins/input/templates/helloworld/Makefile @@ -0,0 +1,30 @@ +CXX = clang++ + +CXXFLAGS = $(shell mapnik-config --cflags) + +LIBS = $(shell mapnik-config --libs --ldflags --dep-libs) + +SRC = $(wildcard *.cpp) + +OBJ = $(SRC:.cpp=.o) + +BIN = hello.input + +all : $(SRC) $(BIN) + +$(BIN) : $(OBJ) + $(CXX) -shared $(OBJ) $(LIBS) -o $@ + +.cpp.o : + $(CXX) -c $(CXXFLAGS) $< -o $@ + +.PHONY : clean + +clean: + rm -f $(OBJ) + rm -f $(BIN) + +deploy: + cp hello.input $(shell mapnik-config --input-plugins) + +install: clean all deploy \ No newline at end of file From 86f137fd25237e016bcc4a63e2f160d2c7383906 Mon Sep 17 00:00:00 2001 From: Dane Springmeyer Date: Tue, 10 Jul 2012 14:50:43 -0700 Subject: [PATCH 047/133] recompile stale targets during deploy --- plugins/input/templates/helloworld/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/input/templates/helloworld/Makefile b/plugins/input/templates/helloworld/Makefile index 5ad5c357d..2caf7fcc9 100644 --- a/plugins/input/templates/helloworld/Makefile +++ b/plugins/input/templates/helloworld/Makefile @@ -24,7 +24,7 @@ clean: rm -f $(OBJ) rm -f $(BIN) -deploy: +deploy : all cp hello.input $(shell mapnik-config --input-plugins) install: clean all deploy \ No newline at end of file From d3b375713b269848f3bc1f26a3a9383912aeaecd Mon Sep 17 00:00:00 2001 From: Dane Springmeyer Date: Tue, 10 Jul 2012 14:51:13 -0700 Subject: [PATCH 048/133] properly populate the context --- plugins/input/templates/helloworld/hello_featureset.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/plugins/input/templates/helloworld/hello_featureset.cpp b/plugins/input/templates/helloworld/hello_featureset.cpp index eb3f19a10..b24d4d37e 100644 --- a/plugins/input/templates/helloworld/hello_featureset.cpp +++ b/plugins/input/templates/helloworld/hello_featureset.cpp @@ -16,6 +16,12 @@ mapnik::feature_ptr hello_featureset::next() { if (feature_id_ == 1) { + // let us pretend it just has one column/attribute name + std::string attribute("key"); + + // the featureset context needs to know the field schema + ctx_->push(attribute); + // create a new feature mapnik::feature_ptr feature(mapnik::feature_factory::create(ctx_,feature_id_)); @@ -24,7 +30,7 @@ mapnik::feature_ptr hello_featureset::next() // create an attribute pair of key:value UnicodeString ustr = tr_->transcode("hello world!"); - feature->put("key",ustr); + feature->put(attribute,ustr); // we need a geometry to display so just for fun here // we take the center of the bbox that was used to query From 15a624fa791b97ee2933f951b098658285d79d07 Mon Sep 17 00:00:00 2001 From: Dane Springmeyer Date: Tue, 10 Jul 2012 14:54:05 -0700 Subject: [PATCH 049/133] update readmes for template plugins --- plugins/input/templates/README.md | 10 ++++++---- plugins/input/templates/helloworld/README.md | 6 ++++-- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/plugins/input/templates/README.md b/plugins/input/templates/README.md index 2b80be843..d4232f0c6 100644 --- a/plugins/input/templates/README.md +++ b/plugins/input/templates/README.md @@ -1,13 +1,15 @@ -template plugins ----------------- +## template plugins Directory to hold sample plugin templates. These are NOT intended to be used except for testing by developers. -Build these plugins with: +Build these plugins with the Mapnik build system: -$ scons SAMPLE_INPUT_PLUGINS=True + ./configure SAMPLE_INPUT_PLUGINS=True + make install + +Or develop them locally using the `Makefile` provided. Only an ultra-simple hello world is available currently, but planned are example plugins templates for file-based diff --git a/plugins/input/templates/helloworld/README.md b/plugins/input/templates/helloworld/README.md index 90fbd736f..0b8e4520c 100644 --- a/plugins/input/templates/helloworld/README.md +++ b/plugins/input/templates/helloworld/README.md @@ -1,9 +1,11 @@ -hello world plugin ------------------- +## hello world plugin This is a very simple sample plugin. It is designed to help developers see the skeletal basics needed to achieve a functional datasource plugin. +It is not a model plugin of best practices as much as a model of the bare +minimum you need to have a working plugin that returns a single feature. + Code comments attempt to highlight which code is mandatory, which is simply recommended, and which is purely fluff used to get the plugin to actually show some data. From afa9dc3c7c7f18b2d487bb83427eb1d515861e15 Mon Sep 17 00:00:00 2001 From: Dane Springmeyer Date: Tue, 10 Jul 2012 18:09:19 -0700 Subject: [PATCH 050/133] move svg marker modifiers to hpp file for re-use in other renderers --- include/mapnik/marker_helpers.hpp | 108 +++++++++++++++++++++++++ src/agg/process_markers_symbolizer.cpp | 82 ++----------------- 2 files changed, 113 insertions(+), 77 deletions(-) create mode 100644 include/mapnik/marker_helpers.hpp diff --git a/include/mapnik/marker_helpers.hpp b/include/mapnik/marker_helpers.hpp new file mode 100644 index 000000000..5cc894634 --- /dev/null +++ b/include/mapnik/marker_helpers.hpp @@ -0,0 +1,108 @@ +/***************************************************************************** + * + * This file is part of Mapnik (c++ mapping toolkit) + * + * Copyright (C) 2012 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_MARKER_HELPERS_HPP +#define MAPNIK_MARKER_HELPERS_HPP + +#include +#include +#include +#include + +// boost +#include + +namespace mapnik { + +template +bool push_explicit_style(Attr const& src, Attr & dst, markers_symbolizer const& sym) +{ + boost::optional const& strk = sym.get_stroke(); + boost::optional const& fill = sym.get_fill(); + if (strk || fill) + { + for(unsigned i = 0; i < src.size(); ++i) + { + mapnik::svg::path_attributes attr = src[i]; + + if (strk) + { + attr.stroke_flag = true; + attr.stroke_width = (*strk).get_width(); + color const& s_color = (*strk).get_color(); + attr.stroke_color = agg::rgba(s_color.red()/255.0,s_color.green()/255.0, + s_color.blue()/255.0,s_color.alpha()/255.0); + } + if (fill) + { + + attr.fill_flag = true; + color const& f_color = *fill; + attr.fill_color = agg::rgba(f_color.red()/255.0,f_color.green()/255.0, + f_color.blue()/255.0,f_color.alpha()/255.0); + } + dst.push_back(attr); + } + return true; + } + return false; +} + +template +void setup_label_transform(agg::trans_affine & tr, box2d const& bbox, mapnik::feature_impl const& feature, T const& sym) +{ + int width = 0; + int height = 0; + + expression_ptr const& width_expr = sym.get_width(); + if (width_expr) + width = boost::apply_visitor(evaluate(feature), *width_expr).to_int(); + + expression_ptr const& height_expr = sym.get_height(); + if (height_expr) + height = boost::apply_visitor(evaluate(feature), *height_expr).to_int(); + + if (width > 0 && height > 0) + { + double sx = width/bbox.width(); + double sy = height/bbox.height(); + tr *= agg::trans_affine_scaling(sx,sy); + } + else if (width > 0) + { + double sx = width/bbox.width(); + tr *= agg::trans_affine_scaling(sx); + } + else if (height > 0) + { + double sy = height/bbox.height(); + tr *= agg::trans_affine_scaling(sy); + } + else + { + evaluate_transform(tr, feature, sym.get_image_transform()); + } +} + +} + +#endif //MAPNIK_MARKER_HELPERS_HPP diff --git a/src/agg/process_markers_symbolizer.cpp b/src/agg/process_markers_symbolizer.cpp index 8bd4145c7..c1ebea447 100644 --- a/src/agg/process_markers_symbolizer.cpp +++ b/src/agg/process_markers_symbolizer.cpp @@ -29,95 +29,27 @@ #include #include #include +#include #include #include #include -#include #include +// agg #include "agg_basics.h" #include "agg_rendering_buffer.h" #include "agg_pixfmt_rgba.h" #include "agg_rasterizer_scanline_aa.h" #include "agg_scanline_u.h" -#include "agg_scanline_p.h" #include "agg_path_storage.h" -#include "agg_ellipse.h" -#include "agg_conv_stroke.h" #include "agg_conv_clip_polyline.h" #include "agg_conv_transform.h" +// boost +#include + namespace mapnik { - -template -bool push_explicit_style(Attr const& src, Attr & dst, markers_symbolizer const& sym) -{ - boost::optional const& strk = sym.get_stroke(); - boost::optional const& fill = sym.get_fill(); - if (strk || fill) - { - for(unsigned i = 0; i < src.size(); ++i) - { - mapnik::svg::path_attributes attr = src[i]; - - if (strk) - { - attr.stroke_width = (*strk).get_width(); - color const& s_color = (*strk).get_color(); - attr.stroke_color = agg::rgba(s_color.red()/255.0,s_color.green()/255.0, - s_color.blue()/255.0,s_color.alpha()/255.0); - } - if (fill) - { - - color const& f_color = *fill; - attr.fill_color = agg::rgba(f_color.red()/255.0,f_color.green()/255.0, - f_color.blue()/255.0,f_color.alpha()/255.0); - } - dst.push_back(attr); - } - return true; - } - return false; -} - -template -void setup_label_transform(agg::trans_affine & tr, box2d const& bbox, mapnik::feature_impl const& feature, T const& sym) -{ - int width = 0; - int height = 0; - - expression_ptr const& width_expr = sym.get_width(); - if (width_expr) - width = boost::apply_visitor(evaluate(feature), *width_expr).to_int(); - - expression_ptr const& height_expr = sym.get_height(); - if (height_expr) - height = boost::apply_visitor(evaluate(feature), *height_expr).to_int(); - - if (width > 0 && height > 0) - { - double sx = width/bbox.width(); - double sy = height/bbox.height(); - tr *= agg::trans_affine_scaling(sx,sy); - } - else if (width > 0) - { - double sx = width/bbox.width(); - tr *= agg::trans_affine_scaling(sx); - } - else if (height > 0) - { - double sy = height/bbox.height(); - tr *= agg::trans_affine_scaling(sy); - } - else - { - evaluate_transform(tr, feature, sym.get_image_transform()); - } -} - template void agg_renderer::process(markers_symbolizer const& sym, mapnik::feature_impl & feature, @@ -163,14 +95,10 @@ void agg_renderer::process(markers_symbolizer const& sym, boost::optional marker = (*mark)->get_vector_data(); box2d const& bbox = (*marker)->bounding_box(); - agg::trans_affine tr; - - setup_label_transform(tr, bbox, feature, sym); tr = agg::trans_affine_scaling(scale_factor_) * tr; - coord2d center = bbox.center(); agg::trans_affine_translation recenter(-center.x, -center.y); agg::trans_affine marker_trans = recenter * tr; From 310ed4a05de502c022b2342ce2edbf175284801f Mon Sep 17 00:00:00 2001 From: Dane Springmeyer Date: Tue, 10 Jul 2012 18:11:43 -0700 Subject: [PATCH 051/133] remove references to now unused mapnik::arrow --- include/mapnik/arrow.hpp | 45 ----------------- src/arrow.cpp | 64 ------------------------- src/cairo_renderer.cpp | 1 - src/grid/process_markers_symbolizer.cpp | 1 - workspace/mapnik.pro | 1 - 5 files changed, 112 deletions(-) delete mode 100644 include/mapnik/arrow.hpp delete mode 100644 src/arrow.cpp diff --git a/include/mapnik/arrow.hpp b/include/mapnik/arrow.hpp deleted file mode 100644 index 0391228a5..000000000 --- a/include/mapnik/arrow.hpp +++ /dev/null @@ -1,45 +0,0 @@ -/***************************************************************************** - * - * This file is part of Mapnik (c++ mapping toolkit) - * - * Copyright (C) 2011 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_ARROW_HPP -#define MAPNIK_ARROW_HPP - -#include - -namespace mapnik { - -class arrow -{ -public: - arrow(); - void rewind(unsigned path_id); - unsigned vertex(double* x, double* y); - box2d extent() const; -private: - unsigned pos_; - double x_[7]; - double y_[7]; - unsigned cmd_[9]; -}; -} - -#endif // MAPNIK_ARROW_HPP diff --git a/src/arrow.cpp b/src/arrow.cpp deleted file mode 100644 index 5cd0ff4e1..000000000 --- a/src/arrow.cpp +++ /dev/null @@ -1,64 +0,0 @@ -/***************************************************************************** - * - * This file is part of Mapnik (c++ mapping toolkit) - * - * Copyright (C) 2011 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 - * - *****************************************************************************/ - -#include - -#include - -namespace mapnik { - -arrow::arrow() - : pos_(0) -{ - x_[0] = -7.0; y_[0] = 1.0; cmd_[0] = agg::path_cmd_move_to; - x_[1] = 1.0; y_[1] = 1.0; cmd_[1] = agg::path_cmd_line_to; - x_[2] = 1.0; y_[2] = 3.0; cmd_[2] = agg::path_cmd_line_to; - x_[3] = 7.0; y_[3] = 0.0; cmd_[3] = agg::path_cmd_line_to; - x_[4] = 1.0; y_[4] =-3.0; cmd_[4] = agg::path_cmd_line_to; - x_[5] = 1.0; y_[5] =-1.0; cmd_[5] = agg::path_cmd_line_to; - x_[6] = -7.0; y_[6] =-1.0; cmd_[6] = agg::path_cmd_line_to; - cmd_[7] = agg::path_cmd_end_poly | agg::path_flags_close | agg::path_flags_ccw; - cmd_[8] = agg::path_cmd_stop; -} - -void arrow::rewind(unsigned ) -{ - pos_ = 0; -} - -unsigned arrow::vertex(double* x, double* y) -{ - if(pos_ < 7 ) - { - *x = x_[pos_]; - *y = y_[pos_]; - return cmd_[pos_++]; - } - return agg::path_cmd_stop; -} - -box2d arrow::extent() const -{ - return box2d(-7,-3,7,3); -} -} - diff --git a/src/cairo_renderer.cpp b/src/cairo_renderer.cpp index 70709af8c..9c379596e 100644 --- a/src/cairo_renderer.cpp +++ b/src/cairo_renderer.cpp @@ -28,7 +28,6 @@ #include #include #include -#include #include #include #include diff --git a/src/grid/process_markers_symbolizer.cpp b/src/grid/process_markers_symbolizer.cpp index fd89b7b16..43d4d23bd 100644 --- a/src/grid/process_markers_symbolizer.cpp +++ b/src/grid/process_markers_symbolizer.cpp @@ -34,7 +34,6 @@ #include #include #include -#include // agg #include "agg_rasterizer_scanline_aa.h" diff --git a/workspace/mapnik.pro b/workspace/mapnik.pro index ce6f36356..32b1d2333 100644 --- a/workspace/mapnik.pro +++ b/workspace/mapnik.pro @@ -69,7 +69,6 @@ HEADERS += \ ../include/mapnik/agg_pattern_source.hpp \ ../include/mapnik/agg_rasterizer.hpp \ ../include/mapnik/agg_renderer.hpp \ - ../include/mapnik/arrow.hpp \ ../include/mapnik/attribute.hpp \ ../include/mapnik/attribute_collector.hpp \ ../include/mapnik/attribute_descriptor.hpp \ From c58cbe0341f5be004014dffca2edd5308a1cb28e Mon Sep 17 00:00:00 2001 From: Dane Springmeyer Date: Tue, 10 Jul 2012 18:12:06 -0700 Subject: [PATCH 052/133] remove reference to arrow.cpp --- src/build.py | 1 - 1 file changed, 1 deletion(-) diff --git a/src/build.py b/src/build.py index b995bd24a..c8514b273 100644 --- a/src/build.py +++ b/src/build.py @@ -149,7 +149,6 @@ source = Split( stroke.cpp symbolizer.cpp symbolizer_helpers.cpp - arrow.cpp unicode.cpp markers_symbolizer.cpp metawriter.cpp From 3efab11bdb3569939a8cdd1e23a69c25a1a17f7a Mon Sep 17 00:00:00 2001 From: Dane Springmeyer Date: Tue, 10 Jul 2012 18:39:06 -0700 Subject: [PATCH 053/133] start carrying through the geometry clipping extent in the grid renderer --- include/mapnik/grid/grid_renderer.hpp | 1 + src/grid/grid_renderer.cpp | 1 + 2 files changed, 2 insertions(+) diff --git a/include/mapnik/grid/grid_renderer.hpp b/include/mapnik/grid/grid_renderer.hpp index fe4c65a15..5728371cd 100644 --- a/include/mapnik/grid/grid_renderer.hpp +++ b/include/mapnik/grid/grid_renderer.hpp @@ -119,6 +119,7 @@ private: face_manager font_manager_; label_collision_detector4 detector_; boost::scoped_ptr ras_ptr; + box2d query_extent_; }; } diff --git a/src/grid/grid_renderer.cpp b/src/grid/grid_renderer.cpp index 6f58c9754..c0bb5a7e0 100644 --- a/src/grid/grid_renderer.cpp +++ b/src/grid/grid_renderer.cpp @@ -91,6 +91,7 @@ void grid_renderer::start_layer_processing(layer const& lay, box2d co { detector_.clear(); } + query_extent_ = query_extent; } template From bcc8da4dea61730f47ca8502f831b92e0522add0 Mon Sep 17 00:00:00 2001 From: Dane Springmeyer Date: Tue, 10 Jul 2012 22:31:51 -0700 Subject: [PATCH 054/133] agg markers_symbolizer rendering: only create objects if actually rendering --- src/agg/process_markers_symbolizer.cpp | 28 +++++++++++++------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/src/agg/process_markers_symbolizer.cpp b/src/agg/process_markers_symbolizer.cpp index c1ebea447..953e85bc7 100644 --- a/src/agg/process_markers_symbolizer.cpp +++ b/src/agg/process_markers_symbolizer.cpp @@ -26,7 +26,6 @@ #include #include #include -#include #include #include #include @@ -66,20 +65,7 @@ void agg_renderer::process(markers_symbolizer const& sym, typedef agg::renderer_base renderer_base; typedef agg::renderer_scanline_aa_solid renderer_type; - ras_ptr->reset(); - ras_ptr->gamma(agg::gamma_power()); - agg::scanline_u8 sl; - agg::rendering_buffer buf(current_buffer_->raw_data(), width_, height_, width_ * 4); - pixfmt_comp_type pixf(buf); - pixf.comp_op(static_cast(sym.comp_op())); - renderer_base renb(pixf); - renderer_type ren(renb); - - agg::trans_affine geom_tr; - evaluate_transform(geom_tr, feature, sym.get_transform()); - std::string filename = path_processor_type::evaluate(*sym.get_filename(), feature); - marker_placement_e placement_method = sym.get_marker_placement(); if (!filename.empty()) { @@ -92,6 +78,18 @@ void agg_renderer::process(markers_symbolizer const& sym, return; } + ras_ptr->reset(); + ras_ptr->gamma(agg::gamma_power()); + agg::scanline_u8 sl; + agg::rendering_buffer buf(current_buffer_->raw_data(), width_, height_, width_ * 4); + pixfmt_comp_type pixf(buf); + pixf.comp_op(static_cast(sym.comp_op())); + renderer_base renb(pixf); + renderer_type ren(renb); + + agg::trans_affine geom_tr; + evaluate_transform(geom_tr, feature, sym.get_transform()); + boost::optional marker = (*mark)->get_vector_data(); box2d const& bbox = (*marker)->bounding_box(); @@ -115,6 +113,8 @@ void agg_renderer::process(markers_symbolizer const& sym, renderer_type, agg::pixfmt_rgba32 > svg_renderer(svg_path, result ? attributes : (*marker)->attributes()); + marker_placement_e placement_method = sym.get_marker_placement(); + BOOST_FOREACH( geometry_type & geom, feature.paths()) { // TODO - merge this code with point_symbolizer rendering From e67463661c0dca9b40787da024c8452a37b4f90b Mon Sep 17 00:00:00 2001 From: Dane Springmeyer Date: Tue, 10 Jul 2012 22:32:19 -0700 Subject: [PATCH 055/133] sync grid markers_symbolizer rendering with agg --- src/grid/process_markers_symbolizer.cpp | 151 +++++++++++++++--------- 1 file changed, 93 insertions(+), 58 deletions(-) diff --git a/src/grid/process_markers_symbolizer.cpp b/src/grid/process_markers_symbolizer.cpp index 43d4d23bd..51e166efb 100644 --- a/src/grid/process_markers_symbolizer.cpp +++ b/src/grid/process_markers_symbolizer.cpp @@ -28,6 +28,8 @@ #include #include #include +#include +#include #include #include #include @@ -36,12 +38,17 @@ #include // agg +#include "agg_basics.h" +#include "agg_rendering_buffer.h" +#include "agg_pixfmt_rgba.h" #include "agg_rasterizer_scanline_aa.h" -#include "agg_renderer_scanline.h" -#include "agg_scanline_bin.h" +#include "agg_scanline_u.h" #include "agg_path_storage.h" -#include "agg_ellipse.h" -#include "agg_conv_stroke.h" +#include "agg_conv_clip_polyline.h" +#include "agg_conv_transform.h" + +// boost +#include // stl #include @@ -54,59 +61,68 @@ void grid_renderer::process(markers_symbolizer const& sym, mapnik::feature_impl & feature, proj_transform const& prj_trans) { - typedef coord_transform path_type; - typedef agg::renderer_base ren_base; - typedef agg::renderer_scanline_bin_solid renderer; - agg::scanline_bin sl; + typedef agg::conv_clip_polyline clipped_geometry_type; + typedef coord_transform path_type; + typedef agg::conv_transform transformed_path_type; + typedef agg::renderer_base renderer_base; + typedef agg::renderer_scanline_bin_solid renderer_type; - grid_rendering_buffer buf(pixmap_.raw_data(), width_, height_, width_); - mapnik::pixfmt_gray32 pixf(buf); - - ren_base renb(pixf); - renderer ren(renb); - - ras_ptr->reset(); - - agg::trans_affine tr; - evaluate_transform(tr, feature, sym.get_image_transform()); - unsigned int res = pixmap_.get_resolution(); - tr = agg::trans_affine_scaling(scale_factor_*(1.0/res)) * tr; std::string filename = path_processor_type::evaluate(*sym.get_filename(), feature); marker_placement_e placement_method = sym.get_marker_placement(); if (!filename.empty()) { boost::optional mark = mapnik::marker_cache::instance()->find(filename, true); - if (mark && *mark && (*mark)->is_vector()) + if (mark && *mark) { + if (!(*mark)->is_vector()) + { + MAPNIK_LOG_DEBUG(agg_renderer) << "agg_renderer: markers_symbolizer does not yet support non-SVG markers"; + return; + } + + agg::scanline_bin sl; + grid_rendering_buffer buf(pixmap_.raw_data(), width_, height_, width_); + mapnik::pixfmt_gray32 pixf(buf); + ras_ptr->reset(); + renderer_base renb(pixf); + renderer_type ren(renb); + + agg::trans_affine geom_tr; + evaluate_transform(geom_tr, feature, sym.get_transform()); + boost::optional marker = (*mark)->get_vector_data(); box2d const& bbox = (*marker)->bounding_box(); - double x1 = bbox.minx(); - double y1 = bbox.miny(); - double x2 = bbox.maxx(); - double y2 = bbox.maxy(); - double w = (*mark)->width(); - double h = (*mark)->height(); - // clamp sizes - w = std::max(w,4.0); - h = std::max(w,4.0); - agg::trans_affine recenter = agg::trans_affine_translation(-0.5*(x1+x2),-0.5*(y1+y2)); - tr.transform(&x1,&y1); - tr.transform(&x2,&y2); - box2d extent(x1,y1,x2,y2); + agg::trans_affine tr; + setup_label_transform(tr, bbox, feature, sym); + tr = agg::trans_affine_scaling(scale_factor_*(1.0/pixmap_.get_resolution())) * tr; + // - clamp sizes to >= 4 pixels of interativity + if (tr.scale() < .25) + tr.scale(.25); + + coord2d center = bbox.center(); + agg::trans_affine_translation recenter(-center.x, -center.y); + agg::trans_affine marker_trans = recenter * tr; + using namespace mapnik::svg; vertex_stl_adapter stl_storage((*marker)->source()); svg_path_adapter svg_path(stl_storage); + + agg::pod_bvector attributes; + bool result = push_explicit_style( (*marker)->attributes(), attributes, sym); + svg_renderer, - renderer, - mapnik::pixfmt_gray32 > svg_renderer(svg_path,(*marker)->attributes()); + agg::pod_bvector, + renderer_type, + mapnik::pixfmt_gray32 > svg_renderer(svg_path, result ? attributes : (*marker)->attributes()); + + marker_placement_e placement_method = sym.get_marker_placement(); bool placed = false; - for (unsigned i=0; i::process(markers_symbolizer const& sym, geom.label_interior_position(&x, &y); prj_trans.backward(x,y,z); t_.forward(&x,&y); - extent.re_center(x,y); + geom_tr.transform(&x,&y); + agg::trans_affine matrix = marker_trans; + matrix.translate(x,y); + box2d transformed_bbox = bbox * matrix; if (sym.get_allow_overlap() || - detector_.has_placement(extent)) + detector_.has_placement(transformed_bbox)) { + placed = true; + svg_renderer.render_id(*ras_ptr, sl, renb, feature.id(), matrix, sym.get_opacity(), bbox); + if (/* DEBUG */ 0) + { + //debug_draw_box(buf, transformed_bbox, 0, 0, 0.0); + } - render_marker(feature, - pixmap_.get_resolution(), - pixel_position(x - 0.5 * w, y - 0.5 * h), - **mark, - tr, - sym.get_opacity()); + if (!sym.get_ignore_placement()) + detector_.insert(transformed_bbox); } } - - path_type path(t_,geom,prj_trans); - markers_placement placement(path, bbox, recenter, detector_, - sym.get_spacing() * scale_factor_, - sym.get_max_error(), - sym.get_allow_overlap()); - double x, y, angle; - while (placement.get_point(x, y, angle)) + else { - placed = true; - agg::trans_affine matrix = recenter * tr *agg::trans_affine_rotation(angle) * agg::trans_affine_translation(x, y); - svg_renderer.render_id(*ras_ptr, sl, renb, feature.id(), matrix, sym.get_opacity(),bbox); + clipped_geometry_type clipped(geom); + clipped.clip_box(query_extent_.minx(),query_extent_.miny(),query_extent_.maxx(),query_extent_.maxy()); + path_type path(t_,clipped,prj_trans); + transformed_path_type path_transformed(path,geom_tr); + markers_placement placement(path_transformed, bbox, marker_trans, detector_, + sym.get_spacing() * scale_factor_, + sym.get_max_error(), + sym.get_allow_overlap()); + double x, y, angle; + while (placement.get_point(x, y, angle)) + { + placed = true; + agg::trans_affine matrix = marker_trans; + matrix.rotate(angle); + matrix.translate(x, y); + svg_renderer.render_id(*ras_ptr, sl, renb, feature.id(), matrix, sym.get_opacity(), bbox); + + if (/* DEBUG */ 0) + { + //debug_draw_box(buf, bbox*matrix, 0, 0, 0.0); + } + } } } if (placed) + { pixmap_.add_feature(feature); + } } } } From 75d2d5bdca5f8ff0e8e0983f056f06d90e097a02 Mon Sep 17 00:00:00 2001 From: Dane Springmeyer Date: Tue, 10 Jul 2012 22:34:46 -0700 Subject: [PATCH 056/133] remove duplicate variable --- src/grid/process_markers_symbolizer.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/grid/process_markers_symbolizer.cpp b/src/grid/process_markers_symbolizer.cpp index 51e166efb..349293937 100644 --- a/src/grid/process_markers_symbolizer.cpp +++ b/src/grid/process_markers_symbolizer.cpp @@ -68,7 +68,6 @@ void grid_renderer::process(markers_symbolizer const& sym, typedef agg::renderer_scanline_bin_solid renderer_type; std::string filename = path_processor_type::evaluate(*sym.get_filename(), feature); - marker_placement_e placement_method = sym.get_marker_placement(); if (!filename.empty()) { From cd66495ec5d635df29118d44cfb5255e3c3d5423 Mon Sep 17 00:00:00 2001 From: Dane Springmeyer Date: Tue, 10 Jul 2012 22:36:03 -0700 Subject: [PATCH 057/133] support setting fill and stroke opacity on the fly in svg marker rendering --- include/mapnik/marker_helpers.hpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/include/mapnik/marker_helpers.hpp b/include/mapnik/marker_helpers.hpp index 5cc894634..89fabdbd6 100644 --- a/include/mapnik/marker_helpers.hpp +++ b/include/mapnik/marker_helpers.hpp @@ -47,10 +47,10 @@ bool push_explicit_style(Attr const& src, Attr & dst, markers_symbolizer const& if (strk) { attr.stroke_flag = true; - attr.stroke_width = (*strk).get_width(); - color const& s_color = (*strk).get_color(); + attr.stroke_width = strk->get_width(); + color const& s_color = strk->get_color(); attr.stroke_color = agg::rgba(s_color.red()/255.0,s_color.green()/255.0, - s_color.blue()/255.0,s_color.alpha()/255.0); + s_color.blue()/255.0,(s_color.alpha()*strk->get_opacity())/255.0); } if (fill) { @@ -58,7 +58,7 @@ bool push_explicit_style(Attr const& src, Attr & dst, markers_symbolizer const& attr.fill_flag = true; color const& f_color = *fill; attr.fill_color = agg::rgba(f_color.red()/255.0,f_color.green()/255.0, - f_color.blue()/255.0,f_color.alpha()/255.0); + f_color.blue()/255.0,(f_color.alpha()*sym.get_opacity())/255.0); } dst.push_back(attr); } From 3e895ac6b7205d4490501ce66f83c2ae178fbca3 Mon Sep 17 00:00:00 2001 From: Dane Springmeyer Date: Tue, 10 Jul 2012 22:38:53 -0700 Subject: [PATCH 058/133] implement built in support for ellipse and arrow markers, make markers_symbolizer default to POINT placement and ellipse drawing, add back compatibility for deprecated marker-type property - refs #1285 and #1304 --- bindings/python/mapnik_markers_symbolizer.cpp | 2 +- include/mapnik/marker_cache.hpp | 19 +++- src/load_map.cpp | 28 ++++- src/marker_cache.cpp | 105 +++++++++++++++--- src/markers_symbolizer.cpp | 6 +- 5 files changed, 135 insertions(+), 25 deletions(-) diff --git a/bindings/python/mapnik_markers_symbolizer.cpp b/bindings/python/mapnik_markers_symbolizer.cpp index cc05b657d..698569378 100644 --- a/bindings/python/mapnik_markers_symbolizer.cpp +++ b/bindings/python/mapnik_markers_symbolizer.cpp @@ -97,7 +97,7 @@ void export_markers_symbolizer() ; class_("MarkersSymbolizer", - init<>("Default Markers Symbolizer - blue arrow")) + init<>("Default Markers Symbolizer - circle")) .def (init("")) //.def_pickle(markers_symbolizer_pickle_suite()) .add_property("filename", diff --git a/include/mapnik/marker_cache.hpp b/include/mapnik/marker_cache.hpp index 2e7f57699..b696a00b9 100644 --- a/include/mapnik/marker_cache.hpp +++ b/include/mapnik/marker_cache.hpp @@ -41,14 +41,21 @@ class marker; typedef boost::shared_ptr marker_ptr; -struct MAPNIK_DECL marker_cache : - public singleton , +class MAPNIK_DECL marker_cache : + public singleton , private boost::noncopyable { - - friend class CreateStatic; - static boost::unordered_map cache_; - static bool insert(std::string const& key, marker_ptr); + friend class CreateUsingNew; +private: + marker_cache(); + ~marker_cache(); + static bool insert_marker(std::string const& key, marker_ptr path); + static boost::unordered_map marker_cache_; + static bool insert_svg(std::string const& name, std::string const& svg_string); + static boost::unordered_map svg_cache_; +public: + static std::string known_svg_prefix_; + static bool is_uri(std::string const& path); static boost::optional find(std::string const& key, bool update_cache = false); static void clear(); }; diff --git a/src/load_map.cpp b/src/load_map.cpp index 29496b7f5..bc8d321da 100644 --- a/src/load_map.cpp +++ b/src/load_map.cpp @@ -56,6 +56,7 @@ #include #include #include +#include // boost #include @@ -987,15 +988,35 @@ void map_parser::parse_markers_symbolizer(rule & rule, xml_node const& node) } } - path_expression_ptr expr(boost::make_shared()); + optional marker_type = node.get_opt_attr("marker-type"); + if (marker_type) + { + MAPNIK_LOG_ERROR(markers_symbolizer) << "'marker-type' is deprecated and will be removed in Mapnik 3.x, use file='shape://' to specify known svg shapes"; + // back compatibility with Mapnik 2.0.0 + if (!marker_type->empty() && filename.empty()) + { + if (*marker_type == "ellipse") + { + filename = marker_cache::known_svg_prefix_ + "ellipse"; + } + else if (*marker_type == "arrow") + { + filename = marker_cache::known_svg_prefix_ + "arrow"; + } + } + } + + markers_symbolizer sym; + if (!filename.empty()) { + path_expression_ptr expr(boost::make_shared()); if (!parse_path_from_string(expr, filename, node.get_tree().path_expr_grammar)) { throw mapnik::config_error("Failed to parse path_expression '" + filename + "'"); } + sym.set_filename(expr); } - markers_symbolizer sym(expr); optional opacity = node.get_opt_attr("opacity"); if (opacity) sym.set_opacity(*opacity); @@ -1610,6 +1631,9 @@ void map_parser::ensure_font_face(std::string const& face_name) std::string map_parser::ensure_relative_to_xml(boost::optional opt_path) { + if (marker_cache::is_uri(*opt_path)) + return *opt_path; + if (relative_to_xml_) { boost::filesystem::path xml_path = filename_; diff --git a/src/marker_cache.cpp b/src/marker_cache.cpp index 1c9e9799c..4caab454b 100644 --- a/src/marker_cache.cpp +++ b/src/marker_cache.cpp @@ -45,25 +45,73 @@ namespace mapnik { -boost::unordered_map marker_cache::cache_; +boost::unordered_map marker_cache::marker_cache_; +boost::unordered_map marker_cache::svg_cache_; +std::string marker_cache::known_svg_prefix_ = "shape://"; + +marker_cache::marker_cache() +{ + insert_svg("ellipse", + "" + "" + "" + ""); + insert_svg("arrow", + "" + "" + "" + ""); +} + +marker_cache::~marker_cache() {} void marker_cache::clear() { #ifdef MAPNIK_THREADSAFE mutex::scoped_lock lock(mutex_); #endif - return cache_.clear(); + typedef boost::unordered_map::const_iterator iterator_type; + iterator_type itr = marker_cache_.begin(); + while(itr != marker_cache_.end()) + { + if (!is_uri(itr->first)) + { + marker_cache_.erase(itr++); + } + else + { + ++itr; + } + } } -bool marker_cache::insert(std::string const& uri, marker_ptr path) +bool marker_cache::is_uri(std::string const& path) +{ + return boost::algorithm::starts_with(path,known_svg_prefix_); +} + +bool marker_cache::insert_svg(std::string const& name, std::string const& svg_string) +{ + std::string key = known_svg_prefix_ + name; + typedef boost::unordered_map::const_iterator iterator_type; + iterator_type itr = svg_cache_.find(key); + if (itr == svg_cache_.end()) + { + return svg_cache_.insert(std::make_pair(key,svg_string)).second; + } + return false; +} + +bool marker_cache::insert_marker(std::string const& uri, marker_ptr path) { #ifdef MAPNIK_THREADSAFE mutex::scoped_lock lock(mutex_); #endif - return cache_.insert(std::make_pair(uri,path)).second; + return marker_cache_.insert(std::make_pair(uri,path)).second; } -boost::optional marker_cache::find(std::string const& uri, bool update_cache) +boost::optional marker_cache::find(std::string const& uri, + bool update_cache) { boost::optional result; @@ -71,12 +119,13 @@ boost::optional marker_cache::find(std::string const& uri, bool upda { return result; } + #ifdef MAPNIK_THREADSAFE mutex::scoped_lock lock(mutex_); #endif typedef boost::unordered_map::const_iterator iterator_type; - iterator_type itr = cache_.find(uri); - if (itr != cache_.end()) + iterator_type itr = marker_cache_.find(uri); + if (itr != marker_cache_.end()) { result.reset(itr->second); return result; @@ -84,14 +133,43 @@ boost::optional marker_cache::find(std::string const& uri, bool upda try { - // we can't find marker in cache, lets try to load it from filesystem - boost::filesystem::path path(uri); - if (!exists(path)) + // if uri references a built-in marker + if (is_uri(uri)) { - MAPNIK_LOG_ERROR(marker_cache) << "Marker does not exist: " << uri; + boost::unordered_map::const_iterator mark_itr = svg_cache_.find(uri); + if (mark_itr == svg_cache_.end()) + { + MAPNIK_LOG_ERROR(marker_cache) << "Marker does not exist: " << uri; + return result; + } + std::string known_svg_string = mark_itr->second; + using namespace mapnik::svg; + path_ptr marker_path(boost::make_shared()); + vertex_stl_adapter stl_storage(marker_path->source()); + svg_path_adapter svg_path(stl_storage); + svg_converter_type svg(svg_path, marker_path->attributes()); + svg_parser p(svg); + p.parse_from_string(known_svg_string); + //svg.arrange_orientations(); + double lox,loy,hix,hiy; + svg.bounding_rect(&lox, &loy, &hix, &hiy); + marker_path->set_bounding_box(lox,loy,hix,hiy); + marker_ptr mark(boost::make_shared(marker_path)); + result.reset(mark); + if (update_cache) + { + marker_cache_.insert(std::make_pair(uri,*result)); + } } + // otherwise assume file-based else { + boost::filesystem::path path(uri); + if (!exists(path)) + { + MAPNIK_LOG_ERROR(marker_cache) << "Marker does not exist: " << uri; + return result; + } if (is_svg(uri)) { using namespace mapnik::svg; @@ -109,11 +187,12 @@ boost::optional marker_cache::find(std::string const& uri, bool upda result.reset(mark); if (update_cache) { - cache_.insert(std::make_pair(uri,*result)); + marker_cache_.insert(std::make_pair(uri,*result)); } } else { + // TODO - support reading images from string std::auto_ptr reader(mapnik::get_image_reader(uri)); if (reader.get()) { @@ -131,7 +210,7 @@ boost::optional marker_cache::find(std::string const& uri, bool upda result.reset(mark); if (update_cache) { - cache_.insert(std::make_pair(uri,*result)); + marker_cache_.insert(std::make_pair(uri,*result)); } } else diff --git a/src/markers_symbolizer.cpp b/src/markers_symbolizer.cpp index 0627ea70f..03554e03c 100644 --- a/src/markers_symbolizer.cpp +++ b/src/markers_symbolizer.cpp @@ -37,7 +37,7 @@ static const char * marker_placement_strings[] = { IMPLEMENT_ENUM( marker_placement_e, marker_placement_strings ) markers_symbolizer::markers_symbolizer() - : symbolizer_with_image(path_expression_ptr(new path_expression)), + : symbolizer_with_image(parse_path("shape://ellipse")), symbolizer_base(), width_(), height_(), @@ -45,7 +45,7 @@ markers_symbolizer::markers_symbolizer() allow_overlap_(false), spacing_(100.0), max_error_(0.2), - marker_p_(MARKER_LINE_PLACEMENT) {} + marker_p_(MARKER_POINT_PLACEMENT) {} markers_symbolizer::markers_symbolizer(path_expression_ptr const& filename) : symbolizer_with_image(filename), @@ -56,7 +56,7 @@ markers_symbolizer::markers_symbolizer(path_expression_ptr const& filename) allow_overlap_(false), spacing_(100.0), max_error_(0.2), - marker_p_(MARKER_LINE_PLACEMENT) {} + marker_p_(MARKER_POINT_PLACEMENT) {} markers_symbolizer::markers_symbolizer(markers_symbolizer const& rhs) : symbolizer_with_image(rhs), From 7a63e9fd0bf0e672c4a24e1206550b9864f27e4f Mon Sep 17 00:00:00 2001 From: artemp Date: Wed, 11 Jul 2012 08:40:09 +0100 Subject: [PATCH 059/133] Merge branch 'master', remote-tracking branch 'origin' From 35ab93667f94d03f263653e89d3baa2898449969 Mon Sep 17 00:00:00 2001 From: artemp Date: Wed, 11 Jul 2012 10:13:38 +0100 Subject: [PATCH 060/133] + enforce const + pass arguments by const ref --- include/mapnik/font_engine_freetype.hpp | 2 +- include/mapnik/text_path.hpp | 8 ++++---- src/agg/process_shield_symbolizer.cpp | 4 ++-- src/agg/process_text_symbolizer.cpp | 4 ++-- src/cairo_renderer.cpp | 11 ++++++----- src/font_engine_freetype.cpp | 10 +++++----- src/grid/process_shield_symbolizer.cpp | 7 ++++--- src/grid/process_text_symbolizer.cpp | 4 ++-- 8 files changed, 26 insertions(+), 24 deletions(-) diff --git a/include/mapnik/font_engine_freetype.hpp b/include/mapnik/font_engine_freetype.hpp index b7c716dd5..b1d7b340a 100644 --- a/include/mapnik/font_engine_freetype.hpp +++ b/include/mapnik/font_engine_freetype.hpp @@ -365,7 +365,7 @@ struct text_renderer : private boost::noncopyable stroker & s, composite_mode_e comp_op = src_over, double scale_factor=1.0); - box2d prepare_glyphs(text_path *path); + box2d prepare_glyphs(text_path const& path); void render(pixel_position pos); void render_id(int feature_id, pixel_position pos, double min_radius=1.0); diff --git a/include/mapnik/text_path.hpp b/include/mapnik/text_path.hpp index 90490d154..557519ed2 100644 --- a/include/mapnik/text_path.hpp +++ b/include/mapnik/text_path.hpp @@ -140,7 +140,7 @@ class text_path : boost::noncopyable ~character_node() {} - void vertex(char_info_ptr *c_, double *x_, double *y_, double *angle_) + void vertex(char_info_ptr *c_, double *x_, double *y_, double *angle_) const { *c_ = c; *x_ = pos.x; @@ -149,7 +149,7 @@ class text_path : boost::noncopyable } }; - int itr_; + mutable int itr_; public: typedef std::vector character_nodes_t; pixel_position center; @@ -172,13 +172,13 @@ public: } /** Return node. Always returns a new node. Has no way to report that there are no more nodes. */ - void vertex(char_info_ptr *c, double *x, double *y, double *angle) + void vertex(char_info_ptr *c, double *x, double *y, double *angle) const { nodes_[itr_++].vertex(c, x, y, angle); } /** Start again at first node. */ - void rewind() + void rewind() const { itr_ = 0; } diff --git a/src/agg/process_shield_symbolizer.cpp b/src/agg/process_shield_symbolizer.cpp index 45e7c04f1..490e55f62 100644 --- a/src/agg/process_shield_symbolizer.cpp +++ b/src/agg/process_shield_symbolizer.cpp @@ -54,7 +54,7 @@ void agg_renderer::process(shield_symbolizer const& sym, scale_factor_); while (helper.next()) { - placements_type &placements = helper.placements(); + placements_type const& placements = helper.placements(); for (unsigned int ii = 0; ii < placements.size(); ++ii) { // get_marker_position returns (minx,miny) corner position, @@ -71,7 +71,7 @@ void agg_renderer::process(shield_symbolizer const& sym, sym.get_opacity(), sym.comp_op()); - ren.prepare_glyphs(&(placements[ii])); + ren.prepare_glyphs(placements[ii]); ren.render(placements[ii].center); } } diff --git a/src/agg/process_text_symbolizer.cpp b/src/agg/process_text_symbolizer.cpp index 2d0988640..7bd1fbe77 100644 --- a/src/agg/process_text_symbolizer.cpp +++ b/src/agg/process_text_symbolizer.cpp @@ -48,10 +48,10 @@ void agg_renderer::process(text_symbolizer const& sym, while (helper.next()) { - placements_type &placements = helper.placements(); + placements_type const& placements = helper.placements(); for (unsigned int ii = 0; ii < placements.size(); ++ii) { - ren.prepare_glyphs(&(placements[ii])); + ren.prepare_glyphs(placements[ii]); ren.render(placements[ii].center); } } diff --git a/src/cairo_renderer.cpp b/src/cairo_renderer.cpp index 9c379596e..ec3cd9a51 100644 --- a/src/cairo_renderer.cpp +++ b/src/cairo_renderer.cpp @@ -683,7 +683,7 @@ public: context_->glyph_path(glyphs); } - void add_text(text_path & path, + void add_text(text_path const& path, cairo_face_manager & manager, face_manager &font_manager) { @@ -1201,7 +1201,7 @@ void cairo_renderer_base::process(shield_symbolizer const& sym, while (helper.next()) { - placements_type &placements = helper.placements(); + placements_type const& placements = helper.placements(); for (unsigned int ii = 0; ii < placements.size(); ++ii) { pixel_position marker_pos = helper.get_marker_position(placements[ii]); @@ -1401,7 +1401,7 @@ void cairo_renderer_base::process(markers_symbolizer const& sym, agg::trans_affine tr; evaluate_transform(tr, feature, sym.get_image_transform()); - + tr = agg::trans_affine_scaling(scale_factor_) * tr; std::string filename = path_processor_type::evaluate(*sym.get_filename(), feature); marker_placement_e placement_method = sym.get_marker_placement(); @@ -1491,8 +1491,9 @@ void cairo_renderer_base::process(text_symbolizer const& sym, cairo_context context(context_); context.set_operator(sym.comp_op()); - while (helper.next()) { - placements_type &placements = helper.placements(); + while (helper.next()) + { + placements_type const& placements = helper.placements(); for (unsigned int ii = 0; ii < placements.size(); ++ii) { context.add_text(placements[ii], face_manager_, font_manager_); diff --git a/src/font_engine_freetype.cpp b/src/font_engine_freetype.cpp index 418684cbb..94eb77248 100644 --- a/src/font_engine_freetype.cpp +++ b/src/font_engine_freetype.cpp @@ -327,7 +327,7 @@ text_renderer::text_renderer (pixmap_type & pixmap, scale_factor_(scale_factor) {} template -box2d text_renderer::prepare_glyphs(text_path *path) +box2d text_renderer::prepare_glyphs(text_path const& path) { //clear glyphs glyphs_.clear(); @@ -340,12 +340,12 @@ box2d text_renderer::prepare_glyphs(text_path *path) bbox.xMin = bbox.yMin = 32000; // Initialize these so we can tell if we bbox.xMax = bbox.yMax = -32000; // properly grew the bbox later - for (int i = 0; i < path->num_nodes(); i++) + for (int i = 0; i < path.num_nodes(); i++) { char_info_ptr c; double x, y, angle; - path->vertex(&c, &x, &y, &angle); + path.vertex(&c, &x, &y, &angle); // TODO Enable when we have support for setting verbosity // MAPNIK_LOG_DEBUG(font_engine_freetype) << "text_renderer: prepare_glyphs=" @@ -531,9 +531,9 @@ boost::mutex freetype_engine::mutex_; std::map > freetype_engine::name2file_; template void text_renderer::render(pixel_position); template text_renderer::text_renderer(image_32&, face_manager&, stroker&, composite_mode_e, double); -template box2dtext_renderer::prepare_glyphs(text_path*); +template box2dtext_renderer::prepare_glyphs(text_path const&); template void text_renderer::render_id(int, pixel_position, double ); template text_renderer::text_renderer(grid&, face_manager&, stroker&, composite_mode_e, double); -template box2dtext_renderer::prepare_glyphs(text_path*); +template box2dtext_renderer::prepare_glyphs(text_path const& ); } diff --git a/src/grid/process_shield_symbolizer.cpp b/src/grid/process_shield_symbolizer.cpp index 88681293d..db6ef2921 100644 --- a/src/grid/process_shield_symbolizer.cpp +++ b/src/grid/process_shield_symbolizer.cpp @@ -58,9 +58,10 @@ void grid_renderer::process(shield_symbolizer const& sym, scale_factor_); text_placement_info_ptr placement; - while (helper.next()) { + while (helper.next()) + { placement_found = true; - placements_type &placements = helper.placements(); + placements_type const& placements = helper.placements(); for (unsigned int ii = 0; ii < placements.size(); ++ii) { render_marker(feature, pixmap_.get_resolution(), @@ -68,7 +69,7 @@ void grid_renderer::process(shield_symbolizer const& sym, helper.get_marker(), helper.get_image_transform(), sym.get_opacity()); - ren.prepare_glyphs(&(placements[ii])); + ren.prepare_glyphs(placements[ii]); ren.render_id(feature.id(), placements[ii].center, 2); } } diff --git a/src/grid/process_text_symbolizer.cpp b/src/grid/process_text_symbolizer.cpp index dc5b58786..abde51040 100644 --- a/src/grid/process_text_symbolizer.cpp +++ b/src/grid/process_text_symbolizer.cpp @@ -49,10 +49,10 @@ void grid_renderer::process(text_symbolizer const& sym, while (helper.next()) { placement_found = true; - placements_type &placements = helper.placements(); + placements_type const& placements = helper.placements(); for (unsigned int ii = 0; ii < placements.size(); ++ii) { - ren.prepare_glyphs(&(placements[ii])); + ren.prepare_glyphs(placements[ii]); ren.render_id(feature.id(), placements[ii].center, 2); } } From 8cf9a5a082da4fe73c14ad07c5f5d0b8cbd74941 Mon Sep 17 00:00:00 2001 From: artemp Date: Wed, 11 Jul 2012 10:32:08 +0100 Subject: [PATCH 061/133] + more const correctness --- include/mapnik/metawriter.hpp | 2 +- include/mapnik/metawriter_inmem.hpp | 2 +- include/mapnik/metawriter_json.hpp | 2 +- include/mapnik/placement_finder.hpp | 2 +- include/mapnik/symbolizer_helpers.hpp | 2 +- src/metawriter.cpp | 7 ++++--- src/metawriter_inmem.cpp | 3 +-- src/symbolizer_helpers.cpp | 2 +- 8 files changed, 11 insertions(+), 11 deletions(-) diff --git a/include/mapnik/metawriter.hpp b/include/mapnik/metawriter.hpp index ac518d28e..7041286d1 100644 --- a/include/mapnik/metawriter.hpp +++ b/include/mapnik/metawriter.hpp @@ -110,7 +110,7 @@ public: virtual void add_box(box2d const& box, Feature const& feature, CoordTransform const& t, metawriter_properties const& properties)=0; - virtual void add_text(boost::ptr_vector &placements, + virtual void add_text(boost::ptr_vector const& placements, box2d const& extents, Feature const& feature, CoordTransform const& t, diff --git a/include/mapnik/metawriter_inmem.hpp b/include/mapnik/metawriter_inmem.hpp index ee57f2a6b..6b77bf728 100644 --- a/include/mapnik/metawriter_inmem.hpp +++ b/include/mapnik/metawriter_inmem.hpp @@ -65,7 +65,7 @@ public: virtual void add_box(box2d const& box, Feature const& feature, CoordTransform const& t, metawriter_properties const& properties); - virtual void add_text(boost::ptr_vector &placements, + virtual void add_text(boost::ptr_vector const& placements, box2d const& extents, Feature const& feature, CoordTransform const& t, diff --git a/include/mapnik/metawriter_json.hpp b/include/mapnik/metawriter_json.hpp index 693824921..ab02d81b4 100644 --- a/include/mapnik/metawriter_json.hpp +++ b/include/mapnik/metawriter_json.hpp @@ -45,7 +45,7 @@ public: virtual void add_box(box2d const& box, Feature const& feature, CoordTransform const& t, metawriter_properties const& properties); - virtual void add_text(boost::ptr_vector &placements, + virtual void add_text(boost::ptr_vector const& placements, box2d const& extents, Feature const& feature, CoordTransform const& t, diff --git a/include/mapnik/placement_finder.hpp b/include/mapnik/placement_finder.hpp index dcc207ade..5be68bcbd 100644 --- a/include/mapnik/placement_finder.hpp +++ b/include/mapnik/placement_finder.hpp @@ -80,7 +80,7 @@ public: /** Remove old placements. */ void clear_placements(); - inline placements_type &get_results() { return placements_; } + inline placements_type const& get_results() { return placements_; } /** Additional boxes to take into account when finding placement. * Used for finding line placements where multiple placements are returned. diff --git a/include/mapnik/symbolizer_helpers.hpp b/include/mapnik/symbolizer_helpers.hpp index aafb8864b..60aa93778 100644 --- a/include/mapnik/symbolizer_helpers.hpp +++ b/include/mapnik/symbolizer_helpers.hpp @@ -85,7 +85,7 @@ public: bool next(); /** Get current placement. next() has to be called before! */ - placements_type & placements() const; + placements_type const& placements() const; protected: bool next_point_placement(); bool next_line_placement(); diff --git a/src/metawriter.cpp b/src/metawriter.cpp index f55298807..e37dfa976 100644 --- a/src/metawriter.cpp +++ b/src/metawriter.cpp @@ -177,7 +177,7 @@ void metawriter_json_stream::add_box(box2d const &box, Feature const& fe } void metawriter_json_stream::add_text( - boost::ptr_vector &placements, box2d const& extents, + boost::ptr_vector const& placements, box2d const& extents, Feature const& feature, CoordTransform const& t, metawriter_properties const& properties) { @@ -195,14 +195,15 @@ void metawriter_json_stream::add_text( */ for (unsigned n = 0; n < placements.size(); n++) { - text_path ¤t_placement = placements[n]; + text_path const& current_placement = placements[n]; bool inside = false; /* Part of text is inside rendering region */ bool straight = true; char_info_ptr c; double x, y, angle; current_placement.rewind(); - for (int i = 0; i < current_placement.num_nodes(); ++i) { + for (int i = 0; i < current_placement.num_nodes(); ++i) + { int cx = current_placement.center.x; int cy = current_placement.center.y; current_placement.vertex(&c, &x, &y, &angle); diff --git a/src/metawriter_inmem.cpp b/src/metawriter_inmem.cpp index 744b910dc..7cf0645be 100644 --- a/src/metawriter_inmem.cpp +++ b/src/metawriter_inmem.cpp @@ -71,7 +71,7 @@ metawriter_inmem::add_box(box2d const& box, Feature const& feature, void metawriter_inmem::add_text( - boost::ptr_vector & /*text*/, + boost::ptr_vector const& /*text*/, box2d const& extents, Feature const& feature, CoordTransform const& /*t*/, @@ -146,4 +146,3 @@ metawriter_inmem::inst_end() const { } - diff --git a/src/symbolizer_helpers.cpp b/src/symbolizer_helpers.cpp index 3312ac4c8..0c386c3b8 100644 --- a/src/symbolizer_helpers.cpp +++ b/src/symbolizer_helpers.cpp @@ -247,7 +247,7 @@ bool text_symbolizer_helper::next_placement() } template -placements_type &text_symbolizer_helper::placements() const +placements_type const& text_symbolizer_helper::placements() const { return finder_->get_results(); } From c7960a20935901fc973284a1cae60c95c1d5ca99 Mon Sep 17 00:00:00 2001 From: artemp Date: Wed, 11 Jul 2012 14:47:39 +0100 Subject: [PATCH 062/133] + support clipping on/off in text_symbolizer_helper, shield_symbolizer_helper and process_markers_symbolizer TODO: revisit implementation to avoid code duplication --- include/mapnik/symbolizer_helpers.hpp | 1 + src/agg/process_markers_symbolizer.cpp | 33 ++++++++++++++--- src/agg/process_shield_symbolizer.cpp | 3 +- src/shield_symbolizer.cpp | 1 - src/symbolizer_helpers.cpp | 50 +++++++++++++++++++++++++- 5 files changed, 81 insertions(+), 7 deletions(-) diff --git a/include/mapnik/symbolizer_helpers.hpp b/include/mapnik/symbolizer_helpers.hpp index 60aa93778..bf1376071 100644 --- a/include/mapnik/symbolizer_helpers.hpp +++ b/include/mapnik/symbolizer_helpers.hpp @@ -89,6 +89,7 @@ public: protected: bool next_point_placement(); bool next_line_placement(); + bool next_line_placement_clipped(); bool next_placement(); void initialize_geometries(); void initialize_points(); diff --git a/src/agg/process_markers_symbolizer.cpp b/src/agg/process_markers_symbolizer.cpp index 953e85bc7..e120f1552 100644 --- a/src/agg/process_markers_symbolizer.cpp +++ b/src/agg/process_markers_symbolizer.cpp @@ -54,9 +54,6 @@ void agg_renderer::process(markers_symbolizer const& sym, mapnik::feature_impl & feature, proj_transform const& prj_trans) { - typedef agg::conv_clip_polyline clipped_geometry_type; - typedef coord_transform path_type; - typedef agg::conv_transform transformed_path_type; typedef agg::rgba8 color_type; typedef agg::order_rgba order_type; typedef agg::pixel32_type pixel_type; @@ -144,8 +141,12 @@ void agg_renderer::process(markers_symbolizer const& sym, detector_->insert(transformed_bbox); } } - else + else if (sym.clip()) { + typedef agg::conv_clip_polyline clipped_geometry_type; + typedef coord_transform path_type; + typedef agg::conv_transform transformed_path_type; + clipped_geometry_type clipped(geom); clipped.clip_box(query_extent_.minx(),query_extent_.miny(),query_extent_.maxx(),query_extent_.maxy()); path_type path(t_,clipped,prj_trans); @@ -162,6 +163,30 @@ void agg_renderer::process(markers_symbolizer const& sym, matrix.translate(x, y); svg_renderer.render(*ras_ptr, sl, renb, matrix, sym.get_opacity(), bbox); + if (/* DEBUG */ 0) + { + debug_draw_box(buf, bbox*matrix, 0, 0, 0.0); + } + } + } + else + { + typedef coord_transform path_type; + typedef agg::conv_transform transformed_path_type; + path_type path(t_,geom,prj_trans); + transformed_path_type path_transformed(path,geom_tr); + markers_placement placement(path_transformed, bbox, marker_trans, *detector_, + sym.get_spacing() * scale_factor_, + sym.get_max_error(), + sym.get_allow_overlap()); + double x, y, angle; + while (placement.get_point(x, y, angle)) + { + agg::trans_affine matrix = marker_trans; + matrix.rotate(angle); + matrix.translate(x, y); + svg_renderer.render(*ras_ptr, sl, renb, matrix, sym.get_opacity(), bbox); + if (/* DEBUG */ 0) { debug_draw_box(buf, bbox*matrix, 0, 0, 0.0); diff --git a/src/agg/process_shield_symbolizer.cpp b/src/agg/process_shield_symbolizer.cpp index 490e55f62..f33381f0b 100644 --- a/src/agg/process_shield_symbolizer.cpp +++ b/src/agg/process_shield_symbolizer.cpp @@ -53,7 +53,8 @@ void agg_renderer::process(shield_symbolizer const& sym, sym.comp_op(), scale_factor_); - while (helper.next()) { + while (helper.next()) + { placements_type const& placements = helper.placements(); for (unsigned int ii = 0; ii < placements.size(); ++ii) { diff --git a/src/shield_symbolizer.cpp b/src/shield_symbolizer.cpp index 006ccca83..17238953b 100644 --- a/src/shield_symbolizer.cpp +++ b/src/shield_symbolizer.cpp @@ -88,4 +88,3 @@ position const& shield_symbolizer::get_shield_displacement() const } } - diff --git a/src/symbolizer_helpers.cpp b/src/symbolizer_helpers.cpp index 0c386c3b8..03d584502 100644 --- a/src/symbolizer_helpers.cpp +++ b/src/symbolizer_helpers.cpp @@ -34,6 +34,8 @@ bool text_symbolizer_helper::next() if (!placement_valid_) return false; if (point_placement_) return next_point_placement(); + else if (sym_.clip()) + return next_line_placement_clipped(); else return next_line_placement(); } @@ -52,11 +54,54 @@ bool text_symbolizer_helper::next_line_placement() continue; //Reexecute size check } + typedef coord_transform path_type; + path_type path(t_, **geo_itr_, prj_trans_); + + finder_->clear_placements(); + if (points_on_line_) { + finder_->find_point_placements(path); + } else { + finder_->find_line_placements(path); + } + if (!finder_->get_results().empty()) + { + //Found a placement + if (points_on_line_) + { + finder_->update_detector(); + } + geo_itr_ = geometries_to_process_.erase(geo_itr_); + if (writer_.first) writer_.first->add_text( + finder_->get_results(), finder_->get_extents(), + feature_, t_, writer_.second); + return true; + } + //No placement for this geometry. Keep it in geometries_to_process_ for next try. + geo_itr_++; + } + return false; +} + +template +bool text_symbolizer_helper::next_line_placement_clipped() +{ + while (!geometries_to_process_.empty()) + { + if (geo_itr_ == geometries_to_process_.end()) + { + //Just processed the last geometry. Try next placement. + if (!next_placement()) return false; //No more placements + //Start again from begin of list + geo_itr_ = geometries_to_process_.begin(); + continue; //Reexecute size check + } + typedef agg::conv_clip_polyline clipped_geometry_type; typedef coord_transform path_type; clipped_geometry_type clipped(**geo_itr_); clipped.clip_box(query_extent_.minx(),query_extent_.miny(),query_extent_.maxx(),query_extent_.maxy()); path_type path(t_, clipped, prj_trans_); + finder_->clear_placements(); if (points_on_line_) { finder_->find_point_placements(path); @@ -342,7 +387,10 @@ bool shield_symbolizer_helper::next_line_placement() -0.5 * marker_ext_.height() - pos.second, 0.5 * marker_ext_.width() - pos.first, 0.5 * marker_ext_.height() - pos.second)); - return text_symbolizer_helper::next_line_placement(); + if ( sym_.clip()) + return text_symbolizer_helper::next_line_placement_clipped(); + else + return text_symbolizer_helper::next_line_placement(); } From da775051ea6279f4cff156d3f10db26494e93f91 Mon Sep 17 00:00:00 2001 From: Dane Springmeyer Date: Wed, 11 Jul 2012 18:58:25 -0700 Subject: [PATCH 063/133] allow non const copy access to property_names on grid and grid_view objects --- include/mapnik/grid/grid.hpp | 17 +++++++++++------ include/mapnik/grid/grid_view.hpp | 15 ++++++++++----- 2 files changed, 21 insertions(+), 11 deletions(-) diff --git a/include/mapnik/grid/grid.hpp b/include/mapnik/grid/grid.hpp index f199144c4..61ab244f9 100644 --- a/include/mapnik/grid/grid.hpp +++ b/include/mapnik/grid/grid.hpp @@ -110,7 +110,12 @@ public: return names_; } - inline const feature_type& get_grid_features() const + inline std::set property_names() + { + return names_; + } + + inline feature_type const& get_grid_features() const { return features_; } @@ -120,7 +125,7 @@ public: return features_; } - inline const feature_key_type& get_feature_keys() const + inline feature_key_type const& get_feature_keys() const { return f_keys_; } @@ -130,7 +135,7 @@ public: return f_keys_; } - inline const std::string& get_key() const + inline std::string const& get_key() const { return key_; } @@ -150,7 +155,7 @@ public: resolution_ = res; } - inline const data_type& data() const + inline data_type const& data() const { return data_; } @@ -160,7 +165,7 @@ public: return data_; } - inline const T* raw_data() const + inline T const * raw_data() const { return data_.getData(); } @@ -170,7 +175,7 @@ public: return data_.getData(); } - inline const value_type* getRow(unsigned row) const + inline value_type const * getRow(unsigned row) const { return data_.getRow(row); } diff --git a/include/mapnik/grid/grid_view.hpp b/include/mapnik/grid/grid_view.hpp index 7e18050db..5ef30356b 100644 --- a/include/mapnik/grid/grid_view.hpp +++ b/include/mapnik/grid/grid_view.hpp @@ -142,7 +142,7 @@ public: return id_name_; } - inline const value_type* getRow(unsigned row) const + inline value_type const * getRow(unsigned row) const { return data_.getRow(row + y_) + x_; } @@ -162,22 +162,27 @@ public: return data_.getBytes(); } - std::set const& property_names() const + inline std::set const& property_names() const { return names_; } - inline const feature_type& get_grid_features() const + inline std::set property_names() + { + return names_; + } + + inline feature_type const& get_grid_features() const { return features_; } - inline const feature_key_type& get_feature_keys() const + inline feature_key_type const& get_feature_keys() const { return f_keys_; } - inline const lookup_type& get_key() const + inline lookup_type const& get_key() const { return key_; } From da5d4961f1212f6e583338fbeed78b8629a2e074 Mon Sep 17 00:00:00 2001 From: artemp Date: Thu, 12 Jul 2012 09:54:03 +0100 Subject: [PATCH 064/133] + return from operator= --- include/mapnik/grid/grid_view.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/mapnik/grid/grid_view.hpp b/include/mapnik/grid/grid_view.hpp index 5ef30356b..02271f91e 100644 --- a/include/mapnik/grid/grid_view.hpp +++ b/include/mapnik/grid/grid_view.hpp @@ -115,6 +115,7 @@ public: names_ = rhs.names_; f_keys_ = rhs.f_keys_; features_ = rhs.features_; + return *this; } inline unsigned x() const @@ -211,4 +212,3 @@ typedef hit_grid_view > grid_view; } #endif // MAPNIK_GRID_VIEW_HPP - From 030639a7b8c826d6722c325c737e350e9aa9b7ad Mon Sep 17 00:00:00 2001 From: artemp Date: Thu, 12 Jul 2012 10:18:35 +0100 Subject: [PATCH 065/133] + remove meaningless -> std::set property_names() --- include/mapnik/grid/grid_view.hpp | 5 ----- 1 file changed, 5 deletions(-) diff --git a/include/mapnik/grid/grid_view.hpp b/include/mapnik/grid/grid_view.hpp index 02271f91e..c1d52d15c 100644 --- a/include/mapnik/grid/grid_view.hpp +++ b/include/mapnik/grid/grid_view.hpp @@ -168,11 +168,6 @@ public: return names_; } - inline std::set property_names() - { - return names_; - } - inline feature_type const& get_grid_features() const { return features_; From 279bfe7f0f1daa7434bf65d752dab5df27521f1d Mon Sep 17 00:00:00 2001 From: artemp Date: Thu, 12 Jul 2012 10:21:57 +0100 Subject: [PATCH 066/133] + remove unused mutating methods + cleanup&style --- include/mapnik/grid/grid.hpp | 17 +---------------- src/grid/grid.cpp | 2 +- 2 files changed, 2 insertions(+), 17 deletions(-) diff --git a/include/mapnik/grid/grid.hpp b/include/mapnik/grid/grid.hpp index 61ab244f9..416608e72 100644 --- a/include/mapnik/grid/grid.hpp +++ b/include/mapnik/grid/grid.hpp @@ -79,7 +79,7 @@ public: hit_grid(int width, int height, std::string const& key, unsigned int resolution); - hit_grid(const hit_grid& rhs); + hit_grid(hit_grid const& rhs); ~hit_grid() {} @@ -110,31 +110,16 @@ public: return names_; } - inline std::set property_names() - { - return names_; - } - inline feature_type const& get_grid_features() const { return features_; } - inline feature_type& get_grid_features() - { - return features_; - } - inline feature_key_type const& get_feature_keys() const { return f_keys_; } - inline feature_key_type& get_feature_keys() - { - return f_keys_; - } - inline std::string const& get_key() const { return key_; diff --git a/src/grid/grid.cpp b/src/grid/grid.cpp index c6c0f89dd..9d870379a 100644 --- a/src/grid/grid.cpp +++ b/src/grid/grid.cpp @@ -48,7 +48,7 @@ hit_grid::hit_grid(int width, int height, std::string const& key, unsigned in } template -hit_grid::hit_grid(const hit_grid& rhs) +hit_grid::hit_grid(hit_grid const& rhs) : width_(rhs.width_), height_(rhs.height_), key_(rhs.key_), From d3bc55761b0213e243f36a48062a52a006fd01f6 Mon Sep 17 00:00:00 2001 From: artemp Date: Thu, 12 Jul 2012 10:57:57 +0100 Subject: [PATCH 067/133] + define keys container in client code not in grid/grid_view, e.g doesn't have to be std::map<...> --- bindings/python/python_grid_utils.hpp | 28 +++++++++++++++++---------- include/mapnik/grid/grid.hpp | 1 - include/mapnik/grid/grid_view.hpp | 1 - 3 files changed, 18 insertions(+), 12 deletions(-) diff --git a/bindings/python/python_grid_utils.hpp b/bindings/python/python_grid_utils.hpp index 62d83a9c0..f3d1301ca 100644 --- a/bindings/python/python_grid_utils.hpp +++ b/bindings/python/python_grid_utils.hpp @@ -47,11 +47,14 @@ static void grid2utf(T const& grid_type, boost::python::list& l, std::vector& key_order) { + typedef std::map< typename T::lookup_type, typename T::value_type> keys_type; + typedef typename keys_type::const_iterator keys_iterator; + typename T::data_type const& data = grid_type.data(); typename T::feature_key_type const& feature_keys = grid_type.get_feature_keys(); - typename T::key_type keys; - typename T::key_type::const_iterator key_pos; typename T::feature_key_type::const_iterator feature_pos; + + keys_type keys; // start counting at utf8 codepoint 32, aka space character boost::uint16_t codepoint = 32; @@ -68,7 +71,7 @@ static void grid2utf(T const& grid_type, if (feature_pos != feature_keys.end()) { mapnik::grid::lookup_type val = feature_pos->second; - key_pos = keys.find(val); + keys_iterator key_pos = keys.find(val); if (key_pos == keys.end()) { // Create a new entry for this key. Skip the codepoints that @@ -108,11 +111,13 @@ static void grid2utf(T const& grid_type, std::vector& key_order, unsigned int resolution) { - //typename T::data_type const& data = grid_type.data(); + typedef std::map< typename T::lookup_type, typename T::value_type> keys_type; + typedef typename keys_type::const_iterator keys_iterator; + typename T::feature_key_type const& feature_keys = grid_type.get_feature_keys(); - typename T::key_type keys; - typename T::key_type::const_iterator key_pos; typename T::feature_key_type::const_iterator feature_pos; + + keys_type keys; // start counting at utf8 codepoint 32, aka space character boost::uint16_t codepoint = 32; @@ -130,7 +135,7 @@ static void grid2utf(T const& grid_type, if (feature_pos != feature_keys.end()) { mapnik::grid::lookup_type val = feature_pos->second; - key_pos = keys.find(val); + keys_iterator key_pos = keys.find(val); if (key_pos == keys.end()) { // Create a new entry for this key. Skip the codepoints that @@ -170,11 +175,14 @@ static void grid2utf2(T const& grid_type, std::vector& key_order, unsigned int resolution) { + typedef std::map< typename T::lookup_type, typename T::value_type> keys_type; + typedef typename keys_type::const_iterator keys_iterator; + typename T::data_type const& data = grid_type.data(); typename T::feature_key_type const& feature_keys = grid_type.get_feature_keys(); - typename T::key_type keys; - typename T::key_type::const_iterator key_pos; typename T::feature_key_type::const_iterator feature_pos; + + keys_type keys; // start counting at utf8 codepoint 32, aka space character uint16_t codepoint = 32; @@ -194,7 +202,7 @@ static void grid2utf2(T const& grid_type, if (feature_pos != feature_keys.end()) { mapnik::grid::lookup_type val = feature_pos->second; - key_pos = keys.find(val); + keys_iterator key_pos = keys.find(val); if (key_pos == keys.end()) { // Create a new entry for this key. Skip the codepoints that diff --git a/include/mapnik/grid/grid.hpp b/include/mapnik/grid/grid.hpp index 416608e72..0c89e8173 100644 --- a/include/mapnik/grid/grid.hpp +++ b/include/mapnik/grid/grid.hpp @@ -58,7 +58,6 @@ public: typedef std::string lookup_type; // mapping between pixel id and key typedef std::map feature_key_type; - typedef std::map key_type; typedef std::map feature_type; static const value_type base_mask; diff --git a/include/mapnik/grid/grid_view.hpp b/include/mapnik/grid/grid_view.hpp index c1d52d15c..a33e1656a 100644 --- a/include/mapnik/grid/grid_view.hpp +++ b/include/mapnik/grid/grid_view.hpp @@ -53,7 +53,6 @@ public: typedef typename T::pixel_type pixel_type; typedef std::string lookup_type; typedef std::map feature_key_type; - typedef std::map key_type; typedef std::map feature_type; hit_grid_view(unsigned x, unsigned y, From 461f5cfe088aaaceb9c0665a3b8fedc4993ad580 Mon Sep 17 00:00:00 2001 From: artemp Date: Thu, 12 Jul 2012 15:38:25 +0100 Subject: [PATCH 068/133] + use separate stroke-opacity and fill-opacity --- include/mapnik/svg/svg_converter.hpp | 15 ++++++++------- include/mapnik/svg/svg_path_attributes.hpp | 12 ++++++++---- include/mapnik/svg/svg_renderer.hpp | 8 ++++---- src/cairo_renderer.cpp | 8 ++++---- src/svg_parser.cpp | 3 ++- 5 files changed, 26 insertions(+), 20 deletions(-) diff --git a/include/mapnik/svg/svg_converter.hpp b/include/mapnik/svg/svg_converter.hpp index b2878544e..7e61a09ff 100644 --- a/include/mapnik/svg/svg_converter.hpp +++ b/include/mapnik/svg/svg_converter.hpp @@ -193,7 +193,7 @@ public: } // Attribute setting functions. - void fill(const agg::rgba8& f) + void fill(agg::rgba8 const& f) { path_attributes& attr = cur_attr(); double a = attr.fill_color.opacity(); @@ -202,19 +202,19 @@ public: attr.fill_flag = true; } - void add_fill_gradient(mapnik::gradient& grad) + void add_fill_gradient(mapnik::gradient const& grad) { path_attributes& attr = cur_attr(); attr.fill_gradient = grad; } - void add_stroke_gradient(mapnik::gradient& grad) + void add_stroke_gradient(mapnik::gradient const& grad) { path_attributes& attr = cur_attr(); attr.stroke_gradient = grad; } - void stroke(const agg::rgba8& s) + void stroke(agg::rgba8 const& s) { path_attributes& attr = cur_attr(); double a = attr.stroke_color.opacity(); @@ -264,16 +264,17 @@ public: void fill_opacity(double op) { - cur_attr().fill_color.opacity(op); + cur_attr().fill_opacity = op; } void stroke_opacity(double op) { - cur_attr().stroke_color.opacity(op); + cur_attr().stroke_opacity = op; } void opacity(double op) { - cur_attr().opacity = op; + cur_attr().stroke_opacity = op; + cur_attr().fill_opacity = op; } void line_join(agg::line_join_e join) diff --git a/include/mapnik/svg/svg_path_attributes.hpp b/include/mapnik/svg/svg_path_attributes.hpp index 1c8a61c36..db14ccc28 100644 --- a/include/mapnik/svg/svg_path_attributes.hpp +++ b/include/mapnik/svg/svg_path_attributes.hpp @@ -39,8 +39,9 @@ struct path_attributes { unsigned index; agg::rgba8 fill_color; + double fill_opacity; agg::rgba8 stroke_color; - double opacity; + double stroke_opacity; bool fill_flag; bool stroke_flag; bool even_odd_flag; @@ -58,8 +59,9 @@ struct path_attributes path_attributes() : index(0), fill_color(agg::rgba(0,0,0)), + fill_opacity(1.0), stroke_color(agg::rgba(0,0,0)), - opacity(1.0), + stroke_opacity(1.0), fill_flag(true), stroke_flag(false), even_odd_flag(false), @@ -79,8 +81,9 @@ struct path_attributes path_attributes(const path_attributes& attr) : index(attr.index), fill_color(attr.fill_color), + fill_opacity(attr.fill_opacity), stroke_color(attr.stroke_color), - opacity(attr.opacity), + stroke_opacity(attr.stroke_opacity), fill_flag(attr.fill_flag), stroke_flag(attr.stroke_flag), even_odd_flag(attr.even_odd_flag), @@ -99,8 +102,9 @@ struct path_attributes path_attributes(path_attributes const& attr, unsigned idx) : index(idx), fill_color(attr.fill_color), + fill_opacity(attr.fill_opacity), stroke_color(attr.stroke_color), - opacity(attr.opacity), + stroke_opacity(attr.stroke_opacity), fill_flag(attr.fill_flag), stroke_flag(attr.stroke_flag), even_odd_flag(attr.even_odd_flag), diff --git a/include/mapnik/svg/svg_renderer.hpp b/include/mapnik/svg/svg_renderer.hpp index 7538798ee..278376e42 100644 --- a/include/mapnik/svg/svg_renderer.hpp +++ b/include/mapnik/svg/svg_renderer.hpp @@ -292,13 +292,13 @@ public: if(attr.fill_gradient.get_gradient_type() != NO_GRADIENT) { - render_gradient(ras, sl, ren, attr.fill_gradient, transform, attr.opacity * opacity, symbol_bbox, path_bbox); + render_gradient(ras, sl, ren, attr.fill_gradient, transform, attr.fill_opacity * opacity, symbol_bbox, path_bbox); } else { ras.filling_rule(attr.even_odd_flag ? fill_even_odd : fill_non_zero); color = attr.fill_color; - color.opacity(color.opacity() * attr.opacity * opacity); + color.opacity(color.opacity() * attr.fill_opacity * opacity); ScanlineRenderer ren_s(ren); color.premultiply(); ren_s.color(color); @@ -328,13 +328,13 @@ public: if(attr.stroke_gradient.get_gradient_type() != NO_GRADIENT) { - render_gradient(ras, sl, ren, attr.stroke_gradient, transform, attr.opacity * opacity, symbol_bbox, path_bbox); + render_gradient(ras, sl, ren, attr.stroke_gradient, transform, attr.stroke_opacity * opacity, symbol_bbox, path_bbox); } else { ras.filling_rule(fill_non_zero); color = attr.stroke_color; - color.opacity(color.opacity() * attr.opacity * opacity); + color.opacity(color.opacity() * attr.stroke_opacity * opacity); ScanlineRenderer ren_s(ren); color.premultiply(); ren_s.color(color); diff --git a/src/cairo_renderer.cpp b/src/cairo_renderer.cpp index ec3cd9a51..97d6077fa 100644 --- a/src/cairo_renderer.cpp +++ b/src/cairo_renderer.cpp @@ -1085,14 +1085,14 @@ void cairo_renderer_base::render_marker(pixel_position const& pos, marker const& } if(attr.fill_gradient.get_gradient_type() != NO_GRADIENT) { - cairo_gradient g(attr.fill_gradient,attr.opacity*opacity); + cairo_gradient g(attr.fill_gradient,attr.fill_opacity*opacity); context.set_gradient(g,bbox); context.fill(); } else if(attr.fill_flag) { - double fill_opacity = attr.opacity * opacity * attr.fill_color.opacity(); + double fill_opacity = attr.fill_opacity * opacity * attr.fill_color.opacity(); context.set_color(attr.fill_color.r,attr.fill_color.g,attr.fill_color.b, fill_opacity); context.fill(); } @@ -1107,13 +1107,13 @@ void cairo_renderer_base::render_marker(pixel_position const& pos, marker const& context.set_line_cap(line_cap_enum(attr.line_cap)); context.set_line_join(line_join_enum(attr.line_join)); context.set_miter_limit(attr.miter_limit); - cairo_gradient g(attr.stroke_gradient,attr.opacity*opacity); + cairo_gradient g(attr.stroke_gradient,attr.fill_opacity*opacity); context.set_gradient(g,bbox); context.stroke(); } else if (attr.stroke_flag) { - double stroke_opacity = attr.opacity * opacity * attr.stroke_color.opacity(); + double stroke_opacity = attr.stroke_opacity * opacity * attr.stroke_color.opacity(); context.set_color(attr.stroke_color.r,attr.stroke_color.g,attr.stroke_color.b, stroke_opacity); context.set_line_width(attr.stroke_width); context.set_line_cap(line_cap_enum(attr.line_cap)); diff --git a/src/svg_parser.cpp b/src/svg_parser.cpp index 8eda9cf24..2cd3241dd 100644 --- a/src/svg_parser.cpp +++ b/src/svg_parser.cpp @@ -407,7 +407,8 @@ void svg_parser::parse_attr(const xmlChar * name, const xmlChar * value ) else if(xmlStrEqual(name, BAD_CAST "opacity")) { double opacity = parse_double((const char*)value); - path_.opacity(opacity); + path_.stroke_opacity(opacity); + path_.fill_opacity(opacity); } else if (xmlStrEqual(name, BAD_CAST "visibility")) { From d828377c7c539e14dd032f5225ee31a3579ad503 Mon Sep 17 00:00:00 2001 From: artemp Date: Thu, 12 Jul 2012 20:00:02 +0100 Subject: [PATCH 069/133] + fix operator= typo --- include/mapnik/image_view.hpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/include/mapnik/image_view.hpp b/include/mapnik/image_view.hpp index 1008a6d2a..135125f79 100644 --- a/include/mapnik/image_view.hpp +++ b/include/mapnik/image_view.hpp @@ -61,6 +61,7 @@ public: width_ = rhs.width_; height_ = rhs.height_; data_ = rhs.data_; + return *this; } inline unsigned x() const @@ -77,6 +78,7 @@ public: { return width_; } + inline unsigned height() const { return height_; From 02644aeed11677f797625d2bb35e012ad9c16caf Mon Sep 17 00:00:00 2001 From: Dane Springmeyer Date: Thu, 12 Jul 2012 16:38:13 -0700 Subject: [PATCH 070/133] add explicit bool operator to negate to silence msvc warnings - closes #1307 --- include/mapnik/value.hpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/include/mapnik/value.hpp b/include/mapnik/value.hpp index d325a3390..cfe807d7a 100644 --- a/include/mapnik/value.hpp +++ b/include/mapnik/value.hpp @@ -577,6 +577,11 @@ struct negate : public boost::static_visitor return val; } + value_type operator() (bool val) const + { + return val ? -1 : 0; + } + value_type operator() (UnicodeString const& ustr) const { UnicodeString inplace(ustr); From b20481115fa68632f16bcee30eb0640a6020ec51 Mon Sep 17 00:00:00 2001 From: Dane Springmeyer Date: Thu, 12 Jul 2012 18:39:12 -0700 Subject: [PATCH 071/133] marker width/height should be double --- include/mapnik/marker_helpers.hpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/include/mapnik/marker_helpers.hpp b/include/mapnik/marker_helpers.hpp index 89fabdbd6..fd26b8ca6 100644 --- a/include/mapnik/marker_helpers.hpp +++ b/include/mapnik/marker_helpers.hpp @@ -70,16 +70,16 @@ bool push_explicit_style(Attr const& src, Attr & dst, markers_symbolizer const& template void setup_label_transform(agg::trans_affine & tr, box2d const& bbox, mapnik::feature_impl const& feature, T const& sym) { - int width = 0; - int height = 0; + double width = 0; + double height = 0; expression_ptr const& width_expr = sym.get_width(); if (width_expr) - width = boost::apply_visitor(evaluate(feature), *width_expr).to_int(); + width = boost::apply_visitor(evaluate(feature), *width_expr).to_double(); expression_ptr const& height_expr = sym.get_height(); if (height_expr) - height = boost::apply_visitor(evaluate(feature), *height_expr).to_int(); + height = boost::apply_visitor(evaluate(feature), *height_expr).to_double(); if (width > 0 && height > 0) { From 2fe306e34f655f86e41d299950d60216652f4e1e Mon Sep 17 00:00:00 2001 From: Dane Springmeyer Date: Thu, 12 Jul 2012 18:41:03 -0700 Subject: [PATCH 072/133] fix marker clamping and sync with agg renderer- refs #1309 --- src/grid/process_markers_symbolizer.cpp | 51 ++++++++++++++++--------- 1 file changed, 33 insertions(+), 18 deletions(-) diff --git a/src/grid/process_markers_symbolizer.cpp b/src/grid/process_markers_symbolizer.cpp index 349293937..2094936e6 100644 --- a/src/grid/process_markers_symbolizer.cpp +++ b/src/grid/process_markers_symbolizer.cpp @@ -61,9 +61,6 @@ void grid_renderer::process(markers_symbolizer const& sym, mapnik::feature_impl & feature, proj_transform const& prj_trans) { - typedef agg::conv_clip_polyline clipped_geometry_type; - typedef coord_transform path_type; - typedef agg::conv_transform transformed_path_type; typedef agg::renderer_base renderer_base; typedef agg::renderer_scanline_bin_solid renderer_type; @@ -80,10 +77,10 @@ void grid_renderer::process(markers_symbolizer const& sym, return; } + ras_ptr->reset(); agg::scanline_bin sl; grid_rendering_buffer buf(pixmap_.raw_data(), width_, height_, width_); mapnik::pixfmt_gray32 pixf(buf); - ras_ptr->reset(); renderer_base renb(pixf); renderer_type ren(renb); @@ -96,9 +93,13 @@ void grid_renderer::process(markers_symbolizer const& sym, agg::trans_affine tr; setup_label_transform(tr, bbox, feature, sym); tr = agg::trans_affine_scaling(scale_factor_*(1.0/pixmap_.get_resolution())) * tr; - // - clamp sizes to >= 4 pixels of interativity - if (tr.scale() < .25) - tr.scale(.25); + // - clamp sizes to > 4 pixels of interativity + if (tr.scale() < 0.5) + { + agg::trans_affine tr2; + tr2 *= agg::trans_affine_scaling(0.5); + tr = tr2; + } coord2d center = bbox.center(); agg::trans_affine_translation recenter(-center.x, -center.y); @@ -140,17 +141,16 @@ void grid_renderer::process(markers_symbolizer const& sym, { placed = true; svg_renderer.render_id(*ras_ptr, sl, renb, feature.id(), matrix, sym.get_opacity(), bbox); - if (/* DEBUG */ 0) - { - //debug_draw_box(buf, transformed_bbox, 0, 0, 0.0); - } - if (!sym.get_ignore_placement()) detector_.insert(transformed_bbox); } } - else + else if (sym.clip()) { + typedef agg::conv_clip_polyline clipped_geometry_type; + typedef coord_transform path_type; + typedef agg::conv_transform transformed_path_type; + clipped_geometry_type clipped(geom); clipped.clip_box(query_extent_.minx(),query_extent_.miny(),query_extent_.maxx(),query_extent_.maxy()); path_type path(t_,clipped,prj_trans); @@ -167,11 +167,26 @@ void grid_renderer::process(markers_symbolizer const& sym, matrix.rotate(angle); matrix.translate(x, y); svg_renderer.render_id(*ras_ptr, sl, renb, feature.id(), matrix, sym.get_opacity(), bbox); - - if (/* DEBUG */ 0) - { - //debug_draw_box(buf, bbox*matrix, 0, 0, 0.0); - } + } + } + else + { + typedef coord_transform path_type; + typedef agg::conv_transform transformed_path_type; + path_type path(t_,geom,prj_trans); + transformed_path_type path_transformed(path,geom_tr); + markers_placement placement(path_transformed, bbox, marker_trans, detector_, + sym.get_spacing() * scale_factor_, + sym.get_max_error(), + sym.get_allow_overlap()); + double x, y, angle; + while (placement.get_point(x, y, angle)) + { + placed = true; + agg::trans_affine matrix = marker_trans; + matrix.rotate(angle); + matrix.translate(x, y); + svg_renderer.render_id(*ras_ptr, sl, renb, feature.id(), matrix, sym.get_opacity(), bbox); } } } From 0c3781998943a0def1054987d0834f04876067ed Mon Sep 17 00:00:00 2001 From: Dane Springmeyer Date: Thu, 12 Jul 2012 19:01:31 -0700 Subject: [PATCH 073/133] remove duplicate grid rendering test --- tests/python_tests/render_test.py | 94 ------------------------------- 1 file changed, 94 deletions(-) diff --git a/tests/python_tests/render_test.py b/tests/python_tests/render_test.py index c0808a1a0..19e547f26 100644 --- a/tests/python_tests/render_test.py +++ b/tests/python_tests/render_test.py @@ -95,100 +95,6 @@ def test_render_from_serialization(): if not 'Could not create datasource' in str(e): raise RuntimeError(e) -grid_correct = {"keys": ["", "North West", "North East", "South West", "South East"], "data": {"South East": {"Name": "South East"}, "North East": {"Name": "North East"}, "North West": {"Name": "North West"}, "South West": {"Name": "South West"}}, "grid": [" ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " !!! ### ", " !!!!! ##### ", " !!!!! ##### ", " !!! ### ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " $$$$ %%%% ", " $$$$$ %%%%% ", " $$$$$ %%%%% ", " $$$ %%% ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " "]} - - -def resolve(grid,x,y): - """ Resolve the attributes for a given pixel in a grid. - - js version: - https://github.com/mapbox/mbtiles-spec/blob/master/1.1/utfgrid.md - spec: - https://github.com/mapbox/wax/blob/master/control/lib/gridutil.js - - """ - utf_val = grid['grid'][x][y] - #http://docs.python.org/library/functions.html#ord - codepoint = ord(utf_val) - if (codepoint >= 93): - codepoint-=1 - if (codepoint >= 35): - codepoint-=1 - codepoint -= 32 - key = grid['keys'][codepoint] - return grid['data'].get(key) - - -def test_render_grid(): - ds = mapnik.MemoryDatasource() - context = mapnik.Context() - context.push('Name') - f = mapnik.Feature(context,1) - f['Name'] = 'South East' - f.add_geometries_from_wkt('POINT (143.10 -38.60)') - ds.add_feature(f) - - f = mapnik.Feature(context,2) - f['Name'] = 'South West' - f.add_geometries_from_wkt('POINT (142.48 -38.60)') - ds.add_feature(f) - - f = mapnik.Feature(context,3) - f['Name'] = 'North West' - f.add_geometries_from_wkt('POINT (142.48 -38.38)') - ds.add_feature(f) - - f = mapnik.Feature(context,4) - f['Name'] = 'North East' - f.add_geometries_from_wkt('POINT (143.10 -38.38)') - ds.add_feature(f) - - s = mapnik.Style() - r = mapnik.Rule() - symb = mapnik.MarkersSymbolizer() - symb.width = mapnik.Expression('10') - symb.height = mapnik.Expression('10') - symb.allow_overlap = True - r.symbols.append(symb) - s.rules.append(r) - lyr = mapnik.Layer('Places') - lyr.datasource = ds - lyr.styles.append('places_labels') - m = mapnik.Map(256,256) - m.append_style('places_labels',s) - m.layers.append(lyr) - ul_lonlat = mapnik.Coord(142.30,-38.20) - lr_lonlat = mapnik.Coord(143.40,-38.80) - m.zoom_to_box(mapnik.Box2d(ul_lonlat,lr_lonlat)) - grid = mapnik.render_grid(m,0,key='Name',resolution=4,fields=['Name']) - eq_(grid,grid_correct) - eq_(resolve(grid,0,0),None) - - # check every pixel of the nw symbol - expected = {"Name": "North West"} - - # top row - eq_(resolve(grid,23,9),expected) - eq_(resolve(grid,23,10),expected) - eq_(resolve(grid,23,11),expected) - - # core - eq_(resolve(grid,24,8),expected) - eq_(resolve(grid,24,9),expected) - eq_(resolve(grid,24,10),expected) - eq_(resolve(grid,24,11),expected) - eq_(resolve(grid,24,12),expected) - eq_(resolve(grid,25,8),expected) - eq_(resolve(grid,25,9),expected) - eq_(resolve(grid,25,10),expected) - eq_(resolve(grid,25,11),expected) - eq_(resolve(grid,25,12),expected) - - # bottom row - eq_(resolve(grid,26,9),expected) - eq_(resolve(grid,26,10),expected) - eq_(resolve(grid,26,11),expected) - def test_render_points(): if not mapnik.has_cairo(): return From fad8eff676821642f43c50ac3f7b66c6c4066fb9 Mon Sep 17 00:00:00 2001 From: Dane Springmeyer Date: Thu, 12 Jul 2012 19:01:59 -0700 Subject: [PATCH 074/133] fix scaling of markers when render time resolution != 1 --- src/grid/process_markers_symbolizer.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/grid/process_markers_symbolizer.cpp b/src/grid/process_markers_symbolizer.cpp index 2094936e6..adade0895 100644 --- a/src/grid/process_markers_symbolizer.cpp +++ b/src/grid/process_markers_symbolizer.cpp @@ -92,14 +92,14 @@ void grid_renderer::process(markers_symbolizer const& sym, agg::trans_affine tr; setup_label_transform(tr, bbox, feature, sym); - tr = agg::trans_affine_scaling(scale_factor_*(1.0/pixmap_.get_resolution())) * tr; - // - clamp sizes to > 4 pixels of interativity + // - clamp sizes to > 4 pixels of interactivity if (tr.scale() < 0.5) { agg::trans_affine tr2; tr2 *= agg::trans_affine_scaling(0.5); tr = tr2; } + tr *= agg::trans_affine_scaling(scale_factor_*(1.0/pixmap_.get_resolution())); coord2d center = bbox.center(); agg::trans_affine_translation recenter(-center.x, -center.y); From 34aa050521a18405c6a47c339366a33b66a57104 Mon Sep 17 00:00:00 2001 From: Dane Springmeyer Date: Thu, 12 Jul 2012 19:02:52 -0700 Subject: [PATCH 075/133] update tests to work with new svg-based grid rendering - closes #1304 --- tests/python_tests/render_grid_test.py | 69 ++++++++++++++------------ 1 file changed, 36 insertions(+), 33 deletions(-) diff --git a/tests/python_tests/render_grid_test.py b/tests/python_tests/render_grid_test.py index 3b77ccf3d..acc906a21 100644 --- a/tests/python_tests/render_grid_test.py +++ b/tests/python_tests/render_grid_test.py @@ -10,11 +10,19 @@ try: except ImportError: import simplejson as json -grid_correct = {"keys": ["", "North West", "North East", "South West", "South East"], "data": {"South East": {"Name": "South East"}, "North East": {"Name": "North East"}, "North West": {"Name": "North West"}, "South West": {"Name": "South West"}}, "grid": [" ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " !!! ### ", " !!!!! ##### ", " !!!!! ##### ", " !!! ### ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " $$$$ %%%% ", " $$$$$ %%%%% ", " $$$$$ %%%%% ", " $$$ %%% ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " "]} +# first pass impl where resolution is passed as render +# time rather than encoding time, likely will be deprecated soon +grid_correct_old = {"keys": ["", "North West", "North East", "South West", "South East"], "data": {"South East": {"Name": "South East"}, "North East": {"Name": "North East"}, "North West": {"Name": "North West"}, "South West": {"Name": "South West"}}, "grid": [" ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " !!! ### ", " !!!!! ##### ", " !!!!! ##### ", " !!! ### ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " $$$$ %%%% ", " $$$$$ %%%%% ", " $$$$$ %%%%% ", " $$$ %%% ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " "]} +# now using svg rendering +grid_correct_old2 = {"data": {"North East": {"Name": "North East"}, "North West": {"Name": "North West"}, "South East": {"Name": "South East"}, "South West": {"Name": "South West"}}, "grid": [" ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " !!! ### ", " !!! ### ", " !!! ### ", " !!! ### ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " $$$ %%% ", " $$$ %%% ", " $$$ %%% ", " $ % ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " "], "keys": ["", "North West", "North East", "South West", "South East"]} +# previous rendering using agg ellipse directly grid_correct_new = {"keys": ["", "North West", "North East", "South West", "South East"], "data": {"South East": {"Name": "South East"}, "North East": {"Name": "North East"}, "North West": {"Name": "North West"}, "South West": {"Name": "South West"}}, "grid": [" ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " !! ## ", " !!! ### ", " !! ## ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " $$$ %% ", " $$$ %%% ", " $$ %% ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " "]} +# newer rendering using svg +grid_correct_new2 = {"data": {"North East": {"Name": "North East"}, "North West": {"Name": "North West"}, "South East": {"Name": "South East"}, "South West": {"Name": "South West"}}, "grid": [" ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " !! ## ", " !!! ## ", " !! ## ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " $$ %% ", " $$ %% ", " $ % ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " "], "keys": ["", "North West", "North East", "South West", "South East"]} + def resolve(grid,row,col): """ Resolve the attributes for a given pixel in a grid. """ @@ -71,15 +79,37 @@ def create_grid_map(width,height): m.layers.append(lyr) return m +def show_grids(name,g1,g2): + g1_file = '/tmp/mapnik-%s-actual.json' % name + open(g1_file,'w').write(json.dumps(g1,sort_keys=True)) + g2_file = '/tmp/mapnik-%s-expected.json' % name + open(g2_file,'w').write(json.dumps(g2,sort_keys=True)) + val = 'JSON does not match ->\n' + if g1['grid'] != g2['grid']: + val += ' X grid does not match\n' + else: + val += ' ✓ grid matches\n' + if g1['data'].keys() != g2['data'].keys(): + val += ' X data does not match\n' + else: + val += ' ✓ data matches\n' + if g1['keys'] != g2['keys']: + val += ' X keys do not\n' + else: + val += ' ✓ keys match\n' + val += '\n\t%s\n\t%s' % (g1_file,g2_file) + return val + def test_render_grid(): """ test old method """ width,height = 256,256 m = create_grid_map(width,height) + #print mapnik.save_map_to_string(m) ul_lonlat = mapnik.Coord(142.30,-38.20) lr_lonlat = mapnik.Coord(143.40,-38.80) m.zoom_to_box(mapnik.Box2d(ul_lonlat,lr_lonlat)) grid = mapnik.render_grid(m,0,key='Name',resolution=4,fields=['Name']) - eq_(grid,grid_correct) + eq_(grid,grid_correct_old2,show_grids('old',grid,grid_correct_old2)) eq_(resolve(grid,0,0),None) # check every pixel of the nw symbol @@ -90,23 +120,6 @@ def test_render_grid(): eq_(resolve(grid,23,10),expected) eq_(resolve(grid,23,11),expected) - # core - eq_(resolve(grid,24,8),expected) - eq_(resolve(grid,24,9),expected) - eq_(resolve(grid,24,10),expected) - eq_(resolve(grid,24,11),expected) - eq_(resolve(grid,24,12),expected) - eq_(resolve(grid,25,8),expected) - eq_(resolve(grid,25,9),expected) - eq_(resolve(grid,25,10),expected) - eq_(resolve(grid,25,11),expected) - eq_(resolve(grid,25,12),expected) - - # bottom row - eq_(resolve(grid,26,9),expected) - eq_(resolve(grid,26,10),expected) - eq_(resolve(grid,26,11),expected) - def test_render_grid2(): """ test old against new""" width,height = 256,256 @@ -119,16 +132,7 @@ def test_render_grid2(): grid = mapnik.Grid(m.width,m.height,key='Name') mapnik.render_layer(m,grid,layer=0,fields=['Name']) utf1 = grid.encode('utf',resolution=4) - eq_(utf1,grid_correct_new) - - # old method - to be removed - utf2 = mapnik.render_grid(m,0,key='Name',resolution=4,fields=['Name']) - eq_(utf2,grid_correct) - - # for complex polygons these will not be true - eq_(len(utf2['grid']),len(utf1['grid'])) - eq_(len(utf2['keys']),len(utf1['keys'])) - eq_(len(utf2['data']),len(utf1['data'])) + eq_(utf1,grid_correct_new2,show_grids('new',utf1,grid_correct_new2)) # check a full view is the same as a full image grid_view = grid.view(0,0,width,height) @@ -152,6 +156,8 @@ def test_render_grid2(): grid_feat_id = {'keys': ['', '3', '4', '2', '1'], 'data': {'1': {'Name': 'South East'}, '3': {'Name': u'North West'}, '2': {'Name': 'South West'}, '4': {'Name': 'North East'}}, 'grid': [' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' !! ## ', ' !!! ### ', ' !! ## ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' $$$ %% ', ' $$$ %%% ', ' $$ %% ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ']} +grid_feat_id2 = {"data": {"1": {"Name": "South East"}, "2": {"Name": "South West"}, "3": {"Name": "North West"}, "4": {"Name": "North East"}}, "grid": [" ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " !! ## ", " !!! ## ", " !! ## ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " $$ %% ", " $$ %% ", " $ % ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " "], "keys": ["", "3", "4", "2", "1"]} + def test_render_grid3(): """ test using feature id""" width,height = 256,256 @@ -163,10 +169,7 @@ def test_render_grid3(): grid = mapnik.Grid(m.width,m.height,key='__id__') mapnik.render_layer(m,grid,layer=0,fields=['__id__','Name']) utf1 = grid.encode('utf',resolution=4) - eq_(utf1['keys'],grid_feat_id['keys']) - eq_(utf1['grid'],grid_feat_id['grid']) - eq_(utf1['data'],grid_feat_id['data']) - eq_(utf1,grid_feat_id) + eq_(utf1,grid_feat_id2,show_grids('id',utf1,grid_feat_id2)) # check a full view is the same as a full image grid_view = grid.view(0,0,width,height) # for kicks check at full res too From 214b24ed120ced16ac15e2059ac1993f21d87803 Mon Sep 17 00:00:00 2001 From: Dane Springmeyer Date: Thu, 12 Jul 2012 19:21:04 -0700 Subject: [PATCH 076/133] finish updating marker tests - closes #1304 --- src/load_map.cpp | 3 ++- tests/python_tests/object_test.py | 11 +++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/load_map.cpp b/src/load_map.cpp index bc8d321da..9a1183a89 100644 --- a/src/load_map.cpp +++ b/src/load_map.cpp @@ -991,7 +991,8 @@ void map_parser::parse_markers_symbolizer(rule & rule, xml_node const& node) optional marker_type = node.get_opt_attr("marker-type"); if (marker_type) { - MAPNIK_LOG_ERROR(markers_symbolizer) << "'marker-type' is deprecated and will be removed in Mapnik 3.x, use file='shape://' to specify known svg shapes"; + // TODO - before Mapnik 2.1 release change this from WARN TO ERROR + MAPNIK_LOG_WARN(markers_symbolizer) << "'marker-type' is deprecated and will be removed in Mapnik 3.x, use file='shape://' to specify known svg shapes"; // back compatibility with Mapnik 2.0.0 if (!marker_type->empty() && filename.empty()) { diff --git a/tests/python_tests/object_test.py b/tests/python_tests/object_test.py index 44517286f..7806ada66 100644 --- a/tests/python_tests/object_test.py +++ b/tests/python_tests/object_test.py @@ -127,15 +127,14 @@ def test_markersymbolizer_init(): p = mapnik.MarkersSymbolizer() eq_(p.allow_overlap, False) eq_(p.opacity,1) - eq_(p.filename,'') - eq_(p.marker_type,mapnik.marker_type.ARROW) - eq_(p.placement,mapnik.marker_placement.LINE_PLACEMENT) - eq_(p.fill,mapnik.Color(0,0,255)) + eq_(p.filename,'shape://ellipse') + eq_(p.placement,mapnik.marker_placement.POINT_PLACEMENT) + eq_(p.fill,None) eq_(p.ignore_placement,False) eq_(p.spacing,100) eq_(p.max_error,0.2) - eq_(str(p.width),'10.0') - eq_(str(p.height),'10.0') + eq_(p.width,None) + eq_(p.height,None) p.width = mapnik.Expression('12') p.height = mapnik.Expression('12') From bc8d6568f50b861d2a975b44cfedd2b9dd002bf3 Mon Sep 17 00:00:00 2001 From: Dane Springmeyer Date: Thu, 12 Jul 2012 19:34:39 -0700 Subject: [PATCH 077/133] sync line rendering between grid and agg - refs #1309 --- src/grid/process_line_symbolizer.cpp | 91 +++++++------------------- tests/python_tests/render_grid_test.py | 32 +++++++++ 2 files changed, 56 insertions(+), 67 deletions(-) diff --git a/src/grid/process_line_symbolizer.cpp b/src/grid/process_line_symbolizer.cpp index 606d0a31a..9e18180a4 100644 --- a/src/grid/process_line_symbolizer.cpp +++ b/src/grid/process_line_symbolizer.cpp @@ -27,6 +27,7 @@ #include #include #include +#include // agg #include "agg_rasterizer_scanline_aa.h" @@ -35,6 +36,9 @@ #include "agg_conv_stroke.h" #include "agg_conv_dash.h" +// boost +#include + // stl #include @@ -60,76 +64,29 @@ void grid_renderer::process(line_symbolizer const& sym, stroke const& stroke_ = sym.get_stroke(); - for (unsigned i=0;i ext = query_extent_ * 1.1; + + typedef boost::mpl::vector conv_types; + vertex_converter, grid_rasterizer, line_symbolizer, + CoordTransform, proj_transform, agg::trans_affine, conv_types> + converter(ext,*ras_ptr,sym,t_,prj_trans,tr,scale_factor_); + + if (sym.clip()) converter.set(); // optional clip (default: true) + converter.set(); // always transform + if (fabs(sym.offset()) > 0.0) converter.set(); // parallel offset + converter.set(); // optional affine transform + if (sym.smooth() > 0.0) converter.set(); // optional smooth converter + if (stroke_.has_dash()) converter.set(); + converter.set(); //always stroke + + BOOST_FOREACH( geometry_type & geom, feature.paths()) { - geometry_type & geom = feature.get_geometry(i); if (geom.num_points() > 1) { - path_type path(t_,geom,prj_trans); - - if (stroke_.has_dash()) - { - agg::conv_dash dash(path); - dash_array const& d = stroke_.get_dash_array(); - dash_array::const_iterator itr = d.begin(); - dash_array::const_iterator end = d.end(); - for (;itr != end;++itr) - { - dash.add_dash(itr->first * scale_factor_, - itr->second * scale_factor_); - } - - agg::conv_stroke > stroke(dash); - - line_join_e join=stroke_.get_line_join(); - if ( join == MITER_JOIN) - stroke.generator().line_join(agg::miter_join); - else if( join == MITER_REVERT_JOIN) - stroke.generator().line_join(agg::miter_join); - else if( join == ROUND_JOIN) - stroke.generator().line_join(agg::round_join); - else - stroke.generator().line_join(agg::bevel_join); - - line_cap_e cap=stroke_.get_line_cap(); - if (cap == BUTT_CAP) - stroke.generator().line_cap(agg::butt_cap); - else if (cap == SQUARE_CAP) - stroke.generator().line_cap(agg::square_cap); - else - stroke.generator().line_cap(agg::round_cap); - - stroke.generator().miter_limit(stroke_.get_miterlimit()); - stroke.generator().width(stroke_.get_width() * scale_factor_); - - ras_ptr->add_path(stroke); - - } - else - { - agg::conv_stroke stroke(path); - line_join_e join=stroke_.get_line_join(); - if ( join == MITER_JOIN) - stroke.generator().line_join(agg::miter_join); - else if( join == MITER_REVERT_JOIN) - stroke.generator().line_join(agg::miter_join); - else if( join == ROUND_JOIN) - stroke.generator().line_join(agg::round_join); - else - stroke.generator().line_join(agg::bevel_join); - - line_cap_e cap=stroke_.get_line_cap(); - if (cap == BUTT_CAP) - stroke.generator().line_cap(agg::butt_cap); - else if (cap == SQUARE_CAP) - stroke.generator().line_cap(agg::square_cap); - else - stroke.generator().line_cap(agg::round_cap); - - stroke.generator().miter_limit(stroke_.get_miterlimit()); - stroke.generator().width(stroke_.get_width() * scale_factor_); - ras_ptr->add_path(stroke); - } + converter.apply(geom); } } diff --git a/tests/python_tests/render_grid_test.py b/tests/python_tests/render_grid_test.py index acc906a21..575717660 100644 --- a/tests/python_tests/render_grid_test.py +++ b/tests/python_tests/render_grid_test.py @@ -243,5 +243,37 @@ def test_id_zero(): utf1 = grid.encode('utf',resolution=4) eq_(utf1['keys'],['0']) +line_expected = {"keys": ["", "1"], "data": {"1": {"Name": "1"}}, "grid": [" !", " !! ", " !! ", " !! ", " !! ", " !! ", " !! ", " !! ", " !! ", " !! ", " !! ", " !! ", " !! ", " !! ", " !! ", " !! ", " !! ", " !! ", " !! ", " !! ", " !! ", "!! ", " ! ", " ! ", " ! ", " ! ", " ! ", " ! ", " ! ", " ! ", " ! ", " ! ", " ! ", " ! ", " ! ", " ! ", " ! ", " ! ", " ! ", " ! ", " ! ", " ! ", " ! ", " ! ", " ! ", " ! ", " ! ", " ! ", " ! ", " ! ", " ! ", " ! ", " ! ", " ! ", " ! ", " ! ", " ! ", " ! ", " ! ", " ! ", " ! ", " ! ", " ! ", " ! "]} + +def test_line_rendering(): + ds = mapnik.MemoryDatasource() + context = mapnik.Context() + context.push('Name') + pixel_key = 1 + f = mapnik.Feature(context,pixel_key) + f['Name'] = str(pixel_key) + f.add_geometries_from_wkt('LINESTRING (30 10, 10 30, 40 40)') + ds.add_feature(f) + s = mapnik.Style() + r = mapnik.Rule() + symb = mapnik.LineSymbolizer() + r.symbols.append(symb) + s.rules.append(r) + lyr = mapnik.Layer('Places') + lyr.datasource = ds + lyr.styles.append('places_labels') + width,height = 256,256 + m = mapnik.Map(width,height) + m.append_style('places_labels',s) + m.layers.append(lyr) + m.zoom_all() + #mapnik.render_to_file(m,'test.png') + grid = mapnik.Grid(m.width,m.height,key='__id__') + mapnik.render_layer(m,grid,layer=0,fields=['__id__','Name']) + utf1 = grid.encode() + eq_(utf1,line_expected,show_grids('line',utf1,line_expected)) + #open('test.json','w').write(json.dumps(grid.encode())) + + if __name__ == "__main__": [eval(run)() for run in dir() if 'test_' in run] From 1e6be7abc3914807b0092ad3e5b910bed4274b2d Mon Sep 17 00:00:00 2001 From: artemp Date: Fri, 13 Jul 2012 10:25:12 +0100 Subject: [PATCH 078/133] + add accessor methods --- include/mapnik/placement_finder.hpp | 15 +++++++++------ src/placement_finder.cpp | 4 ++-- src/symbolizer_helpers.cpp | 4 ++-- 3 files changed, 13 insertions(+), 10 deletions(-) diff --git a/include/mapnik/placement_finder.hpp b/include/mapnik/placement_finder.hpp index 5be68bcbd..fb7cd13be 100644 --- a/include/mapnik/placement_finder.hpp +++ b/include/mapnik/placement_finder.hpp @@ -82,12 +82,8 @@ public: inline placements_type const& get_results() { return placements_; } - /** Additional boxes to take into account when finding placement. - * Used for finding line placements where multiple placements are returned. - * Boxes are relative to starting point of current placement. - * Only used for point placements! - */ - std::vector > additional_boxes; + std::vector > & additional_boxes() { return additional_boxes_;} + std::vector > const& additional_boxes() const { return additional_boxes_;} void set_collect_extents(bool collect) { collect_extents_ = collect; } bool get_collect_extents() const { return collect_extents_; } @@ -160,6 +156,13 @@ private: box2d extents_; /** Collect a bounding box of all texts placed. */ bool collect_extents_; + + /** Additional boxes to take into account when finding placement. + * Used for finding line placements where multiple placements are returned. + * Boxes are relative to starting point of current placement. + * Only used for point placements! + */ + std::vector > additional_boxes_; }; } diff --git a/src/placement_finder.cpp b/src/placement_finder.cpp index eefbf1b6e..f5a34b61e 100644 --- a/src/placement_finder.cpp +++ b/src/placement_finder.cpp @@ -500,9 +500,9 @@ void placement_finder::find_point_placement(double label_x, } // check the placement of any additional envelopes - if (!p.allow_overlap && !additional_boxes.empty()) + if (!p.allow_overlap && !additional_boxes_.empty()) { - BOOST_FOREACH(box2d box, additional_boxes) + BOOST_FOREACH(box2d const& box, additional_boxes_) { box2d pt(box.minx() + current_placement->center.x, box.miny() + current_placement->center.y, diff --git a/src/symbolizer_helpers.cpp b/src/symbolizer_helpers.cpp index 03d584502..87516c19d 100644 --- a/src/symbolizer_helpers.cpp +++ b/src/symbolizer_helpers.cpp @@ -380,9 +380,9 @@ template bool shield_symbolizer_helper::next_line_placement() { position const& pos = placement_->properties.displacement; - finder_->additional_boxes.clear(); + finder_->additional_boxes().clear(); //Markers are automatically centered - finder_->additional_boxes.push_back( + finder_->additional_boxes().push_back( box2d(-0.5 * marker_ext_.width() - pos.first, -0.5 * marker_ext_.height() - pos.second, 0.5 * marker_ext_.width() - pos.first, From 0eddc2b5a0d42fb1dcf5c228871eac145c089bbc Mon Sep 17 00:00:00 2001 From: artemp Date: Fri, 13 Jul 2012 11:17:35 +0100 Subject: [PATCH 079/133] + apply scale_factor --- src/cairo_renderer.cpp | 40 +++++++++++++++++++--------------------- 1 file changed, 19 insertions(+), 21 deletions(-) diff --git a/src/cairo_renderer.cpp b/src/cairo_renderer.cpp index 97d6077fa..e3283e775 100644 --- a/src/cairo_renderer.cpp +++ b/src/cairo_renderer.cpp @@ -685,7 +685,8 @@ public: void add_text(text_path const& path, cairo_face_manager & manager, - face_manager &font_manager) + face_manager &font_manager, + double scale_factor = 1.0) { double sx = path.center.x; double sy = path.center.y; @@ -700,7 +701,7 @@ public: path.vertex(&c, &x, &y, &angle); face_set_ptr faces = font_manager.get_face_set(c->format->face_name, c->format->fontset); - float text_size = c->format->text_size; + float text_size = c->format->text_size * scale_factor; faces->set_character_sizes(text_size); glyph_ptr glyph = faces->get_glyph(c->c); @@ -721,7 +722,7 @@ public: set_font_face(manager, glyph->get_face()); glyph_path(glyph->get_index(), sx + x, sy - y); - set_line_width(c->format->halo_radius); + set_line_width(c->format->halo_radius * scale_factor); set_line_join(ROUND_JOIN); set_color(c->format->halo_fill); stroke(); @@ -757,17 +758,13 @@ cairo_renderer_base::cairo_renderer_base(Map const& m, template <> cairo_renderer::cairo_renderer(Map const& m, Cairo::RefPtr const& context, double scale_factor, unsigned offset_x, unsigned offset_y) - : feature_style_processor(m), - cairo_renderer_base(m,context,scale_factor,offset_x,offset_y) -{ -} + : feature_style_processor(m,scale_factor), + cairo_renderer_base(m,context,scale_factor,offset_x,offset_y) {} template <> cairo_renderer::cairo_renderer(Map const& m, Cairo::RefPtr const& surface, double scale_factor, unsigned offset_x, unsigned offset_y) - : feature_style_processor(m), - cairo_renderer_base(m,Cairo::Context::create(surface),scale_factor,offset_x,offset_y) -{ -} + : feature_style_processor(m,scale_factor), + cairo_renderer_base(m,Cairo::Context::create(surface),scale_factor,offset_x,offset_y) {} cairo_renderer_base::~cairo_renderer_base() {} @@ -880,7 +877,7 @@ void cairo_renderer_base::process(building_symbolizer const& sym, if (height_expr) { value_type result = boost::apply_visitor(evaluate(feature), *height_expr); - height = result.to_double(); //scale_factor is always 1.0 atm + height = result.to_double() * scale_factor_; } for (unsigned i = 0; i < feature.num_geometries(); ++i) @@ -987,7 +984,7 @@ void cairo_renderer_base::process(line_symbolizer const& sym, context.set_line_join(stroke_.get_line_join()); context.set_line_cap(stroke_.get_line_cap()); context.set_miter_limit(stroke_.get_miterlimit()); - context.set_line_width(stroke_.get_width()); + context.set_line_width(stroke_.get_width() * scale_factor_); if (stroke_.has_dash()) { context.set_dash(stroke_.get_dash_array()); @@ -1000,7 +997,7 @@ void cairo_renderer_base::process(line_symbolizer const& sym, typedef boost::mpl::vector conv_types; vertex_converter, cairo_context, line_symbolizer, CoordTransform, proj_transform, agg::trans_affine, conv_types> - converter(ext,context,sym,t_,prj_trans,tr,1.0); + converter(ext,context,sym,t_,prj_trans,tr,scale_factor_); if (sym.clip()) converter.set(); // optional clip (default: true) converter.set(); // always transform @@ -1194,7 +1191,7 @@ void cairo_renderer_base::process(shield_symbolizer const& sym, label_collision_detector4> helper( sym, feature, prj_trans, width_, height_, - 1.0 /*scale_factor*/, + scale_factor_, t_, font_manager_, detector_, query_extent_); cairo_context context(context_); context.set_operator(sym.comp_op()); @@ -1208,7 +1205,7 @@ void cairo_renderer_base::process(shield_symbolizer const& sym, render_marker(marker_pos, helper.get_marker(), helper.get_image_transform(), sym.get_opacity()); - context.add_text(placements[ii], face_manager_, font_manager_); + context.add_text(placements[ii], face_manager_, font_manager_, scale_factor_); } } } @@ -1233,7 +1230,7 @@ void cairo_renderer_base::process(line_pattern_symbolizer const& sym, pattern.set_extend(Cairo::EXTEND_REPEAT); pattern.set_filter(Cairo::FILTER_BILINEAR); - context.set_line_width(height); + context.set_line_width(height * scale_factor_); for (unsigned i = 0; i < feature.num_geometries(); ++i) { @@ -1394,7 +1391,7 @@ void cairo_renderer_base::process(markers_symbolizer const& sym, { cairo_context context(context_); context.set_operator(sym.comp_op()); - double scale_factor_ = 1; + //double scale_factor_ = 1; typedef agg::conv_clip_polyline clipped_geometry_type; typedef coord_transform path_type; @@ -1486,8 +1483,9 @@ void cairo_renderer_base::process(text_symbolizer const& sym, label_collision_detector4> helper( sym, feature, prj_trans, width_, height_, - 1.0 /*scale_factor*/, + scale_factor_, t_, font_manager_, detector_, query_extent_); + cairo_context context(context_); context.set_operator(sym.comp_op()); @@ -1496,7 +1494,7 @@ void cairo_renderer_base::process(text_symbolizer const& sym, placements_type const& placements = helper.placements(); for (unsigned int ii = 0; ii < placements.size(); ++ii) { - context.add_text(placements[ii], face_manager_, font_manager_); + context.add_text(placements[ii], face_manager_, font_manager_, scale_factor_); } } } @@ -1505,4 +1503,4 @@ template class cairo_renderer; template class cairo_renderer; } -#endif +#endif // HAVE_CAIRO From e9c5ab3d9426c2e003e8a7685cf840d16e053f98 Mon Sep 17 00:00:00 2001 From: Dane Springmeyer Date: Fri, 13 Jul 2012 16:42:23 -0700 Subject: [PATCH 080/133] sync polygon rendering between agg and grid backends --- src/grid/process_polygon_symbolizer.cpp | 44 +++++++++++++++++-------- 1 file changed, 31 insertions(+), 13 deletions(-) diff --git a/src/grid/process_polygon_symbolizer.cpp b/src/grid/process_polygon_symbolizer.cpp index 68d5f1ae9..87e14d4b4 100644 --- a/src/grid/process_polygon_symbolizer.cpp +++ b/src/grid/process_polygon_symbolizer.cpp @@ -20,6 +20,9 @@ * *****************************************************************************/ +// boost +#include + // mapnik #include #include @@ -27,6 +30,7 @@ #include #include #include +#include // agg #include "agg_rasterizer_scanline_aa.h" @@ -44,10 +48,34 @@ void grid_renderer::process(polygon_symbolizer const& sym, mapnik::feature_impl & feature, proj_transform const& prj_trans) { - typedef coord_transform path_type; + ras_ptr->reset(); + + box2d inflated_extent = query_extent_ * 1.0; + + agg::trans_affine tr; + evaluate_transform(tr, feature, sym.get_transform()); + + typedef boost::mpl::vector conv_types; + vertex_converter, grid_rasterizer, polygon_symbolizer, + CoordTransform, proj_transform, agg::trans_affine, conv_types> + converter(inflated_extent,*ras_ptr,sym,t_,prj_trans,tr,scale_factor_); + + if (sym.clip()) converter.set(); //optional clip (default: true) + converter.set(); //always transform + converter.set(); + if (sym.smooth() > 0.0) converter.set(); // optional smooth converter + + + BOOST_FOREACH( geometry_type & geom, feature.paths()) + { + if (geom.num_points() > 2) + { + converter.apply(geom); + } + } + typedef agg::renderer_base ren_base; typedef agg::renderer_scanline_bin_solid renderer; - agg::scanline_bin sl; grid_rendering_buffer buf(pixmap_.raw_data(), width_, height_, width_); mapnik::pixfmt_gray32 pixf(buf); @@ -55,19 +83,9 @@ void grid_renderer::process(polygon_symbolizer const& sym, ren_base renb(pixf); renderer ren(renb); - ras_ptr->reset(); - for (unsigned i=0;i 2) - { - path_type path(t_,geom,prj_trans); - ras_ptr->add_path(path); - } - } - // render id ren.color(mapnik::gray32(feature.id())); + agg::scanline_bin sl; agg::render_scanlines(*ras_ptr, sl, ren); // add feature properties to grid cache From 89668e7b2685eaed91bbf6cfddca5de90f9d6271 Mon Sep 17 00:00:00 2001 From: Dane Springmeyer Date: Mon, 16 Jul 2012 09:42:01 -0700 Subject: [PATCH 081/133] map bilinear8 to bilinear for now (TODO - add bilinear8 to AGG) --- src/image_scaling.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/image_scaling.cpp b/src/image_scaling.cpp index c9ea1e862..2e5961751 100644 --- a/src/image_scaling.cpp +++ b/src/image_scaling.cpp @@ -312,6 +312,7 @@ void scale_image_agg(Image & target, return; } case SCALING_BILINEAR: + case SCALING_BILINEAR8: filter.calculate(agg::image_filter_bilinear(), true); break; case SCALING_BICUBIC: filter.calculate(agg::image_filter_bicubic(), true); break; From 6d950769549fd2d72e708a49732ed0471e2f20ca Mon Sep 17 00:00:00 2001 From: Dane Springmeyer Date: Mon, 16 Jul 2012 11:51:14 -0700 Subject: [PATCH 082/133] sync grid renderer with agg for text/shields/point - refs #1309 --- include/mapnik/grid/grid_renderer.hpp | 2 +- src/agg/process_point_symbolizer.cpp | 6 ++++- src/grid/grid_renderer.cpp | 4 ++-- src/grid/process_point_symbolizer.cpp | 31 +++++++++++++++----------- src/grid/process_shield_symbolizer.cpp | 22 +++++++++++++----- src/grid/process_text_symbolizer.cpp | 3 +-- 6 files changed, 43 insertions(+), 25 deletions(-) diff --git a/include/mapnik/grid/grid_renderer.hpp b/include/mapnik/grid/grid_renderer.hpp index 5728371cd..1fa66aedf 100644 --- a/include/mapnik/grid/grid_renderer.hpp +++ b/include/mapnik/grid/grid_renderer.hpp @@ -65,7 +65,7 @@ public: void end_layer_processing(layer const& lay); void start_style_processing(feature_type_style const& st) {} void end_style_processing(feature_type_style const& st) {} - void render_marker(mapnik::feature_impl & feature, unsigned int step, pixel_position const& pos, marker const& marker, const agg::trans_affine & tr, double opacity); + void render_marker(mapnik::feature_impl & feature, unsigned int step, pixel_position const& pos, marker const& marker, const agg::trans_affine & tr, double opacity, composite_mode_e comp_op); void process(point_symbolizer const& sym, mapnik::feature_impl & feature, diff --git a/src/agg/process_point_symbolizer.cpp b/src/agg/process_point_symbolizer.cpp index 22395799f..56de677c7 100644 --- a/src/agg/process_point_symbolizer.cpp +++ b/src/agg/process_point_symbolizer.cpp @@ -93,7 +93,11 @@ void agg_renderer::process(point_symbolizer const& sym, detector_->has_placement(label_ext)) { - render_marker(pixel_position(x, y), **marker, tr, sym.get_opacity(), sym.comp_op()); + render_marker(pixel_position(x, y), + **marker, + tr, + sym.get_opacity(), + sym.comp_op()); if (/* DEBUG */ 0) { debug_draw_box(label_ext, 0, 0, 0.0); diff --git a/src/grid/grid_renderer.cpp b/src/grid/grid_renderer.cpp index c0bb5a7e0..fdbe834dd 100644 --- a/src/grid/grid_renderer.cpp +++ b/src/grid/grid_renderer.cpp @@ -101,7 +101,7 @@ void grid_renderer::end_layer_processing(layer const&) } template -void grid_renderer::render_marker(mapnik::feature_impl & feature, unsigned int step, pixel_position const& pos, marker const& marker, agg::trans_affine const& tr, double opacity) +void grid_renderer::render_marker(mapnik::feature_impl & feature, unsigned int step, pixel_position const& pos, marker const& marker, agg::trans_affine const& tr, double opacity, composite_mode_e comp_op) { if (marker.is_vector()) { @@ -126,7 +126,7 @@ void grid_renderer::render_marker(mapnik::feature_impl & feature, unsigned in mtx *= tr; mtx *= agg::trans_affine_scaling(scale_factor_*(1.0/step)); // render the marker at the center of the marker box - mtx.translate(pos.x+0.5 * marker.width(), pos.y+0.5 * marker.height()); + mtx.translate(pos.x, pos.y); using namespace mapnik::svg; vertex_stl_adapter stl_storage((*marker.get_vector_data())->source()); svg_path_adapter svg_path(stl_storage); diff --git a/src/grid/process_point_symbolizer.cpp b/src/grid/process_point_symbolizer.cpp index b7e60b916..7398bf91d 100644 --- a/src/grid/process_point_symbolizer.cpp +++ b/src/grid/process_point_symbolizer.cpp @@ -55,12 +55,20 @@ void grid_renderer::process(point_symbolizer const& sym, if (marker) { + box2d const& bbox = (*marker)->bounding_box(); + coord2d const center = bbox.center(); + agg::trans_affine tr; evaluate_transform(tr, feature, sym.get_image_transform()); + tr = agg::trans_affine_scaling(scale_factor_) * tr; + + agg::trans_affine_translation const recenter(-center.x, -center.y); + agg::trans_affine const recenter_tr = recenter * tr; + box2d label_ext = bbox * recenter_tr; for (unsigned i=0; i::process(point_symbolizer const& sym, prj_trans.backward(x,y,z); t_.forward(&x,&y); - - double w = (*marker)->width() * (1.0/pixmap_.get_resolution()); - double h = (*marker)->height() * (1.0/pixmap_.get_resolution()); - - double px = x - 0.5 * w; - double py = y - 0.5 * h; - box2d label_ext (px, py, px + w, py + h); + label_ext.re_center(x,y); if (sym.get_allow_overlap() || detector_.has_placement(label_ext)) { - render_marker(feature, pixmap_.get_resolution(), - pixel_position(px, py), - **marker, tr, - sym.get_opacity()); + + render_marker(feature, + pixmap_.get_resolution(), + pixel_position(x, y), + **marker, + tr, + sym.get_opacity(), + sym.comp_op()); if (!sym.get_ignore_placement()) detector_.insert(label_ext); } } } - } template void grid_renderer::process(point_symbolizer const&, diff --git a/src/grid/process_shield_symbolizer.cpp b/src/grid/process_shield_symbolizer.cpp index db6ef2921..e57266509 100644 --- a/src/grid/process_shield_symbolizer.cpp +++ b/src/grid/process_shield_symbolizer.cpp @@ -41,14 +41,13 @@ void grid_renderer::process(shield_symbolizer const& sym, mapnik::feature_impl & feature, proj_transform const& prj_trans) { - box2d query_extent; shield_symbolizer_helper, label_collision_detector4> helper( sym, feature, prj_trans, width_, height_, scale_factor_, t_, font_manager_, detector_, - query_extent); + query_extent_); bool placement_found = false; text_renderer ren(pixmap_, @@ -64,10 +63,21 @@ void grid_renderer::process(shield_symbolizer const& sym, placements_type const& placements = helper.placements(); for (unsigned int ii = 0; ii < placements.size(); ++ii) { - render_marker(feature, pixmap_.get_resolution(), - helper.get_marker_position(placements[ii]), - helper.get_marker(), helper.get_image_transform(), - sym.get_opacity()); + // get_marker_position returns (minx,miny) corner position, + // while (currently only) agg_renderer::render_marker newly + // expects center position; + // until all renderers and shield_symbolizer_helper are + // modified accordingly, we must adjust the position here + pixel_position pos = helper.get_marker_position(placements[ii]); + pos.x += 0.5 * helper.get_marker_width(); + pos.y += 0.5 * helper.get_marker_height(); + render_marker(feature, + pixmap_.get_resolution(), + pos, + helper.get_marker(), + helper.get_image_transform(), + sym.get_opacity(), + sym.comp_op()); ren.prepare_glyphs(placements[ii]); ren.render_id(feature.id(), placements[ii].center, 2); diff --git a/src/grid/process_text_symbolizer.cpp b/src/grid/process_text_symbolizer.cpp index abde51040..22e6e7d18 100644 --- a/src/grid/process_text_symbolizer.cpp +++ b/src/grid/process_text_symbolizer.cpp @@ -31,14 +31,13 @@ void grid_renderer::process(text_symbolizer const& sym, mapnik::feature_impl & feature, proj_transform const& prj_trans) { - box2d query_extent; text_symbolizer_helper, label_collision_detector4> helper( sym, feature, prj_trans, width_, height_, scale_factor_ * (1.0/pixmap_.get_resolution()), t_, font_manager_, detector_, - query_extent); + query_extent_); bool placement_found = false; text_renderer ren(pixmap_, From 195b8ad88756c06a22c00b657ca2ab81abec3700 Mon Sep 17 00:00:00 2001 From: artemp Date: Tue, 17 Jul 2012 17:10:24 +0100 Subject: [PATCH 083/133] + affine transform for raster markers - #1279 --- src/agg/agg_renderer.cpp | 103 +++++++++++++++++++++++++++------------ 1 file changed, 72 insertions(+), 31 deletions(-) diff --git a/src/agg/agg_renderer.cpp b/src/agg/agg_renderer.cpp index c7a480780..bff971757 100644 --- a/src/agg/agg_renderer.cpp +++ b/src/agg/agg_renderer.cpp @@ -42,7 +42,11 @@ #include "agg_rendering_buffer.h" #include "agg_pixfmt_rgba.h" #include "agg_scanline_u.h" - +#include "agg_image_filters.h" +#include "agg_trans_bilinear.h" +#include "agg_span_allocator.h" +#include "agg_image_accessors.h" +#include "agg_span_image_filter_rgba.h" // boost #include #include @@ -264,24 +268,24 @@ template void agg_renderer::render_marker(pixel_position const& pos, marker const& marker, agg::trans_affine const& tr, double opacity, composite_mode_e comp_op) { + typedef agg::rgba8 color_type; + typedef agg::order_rgba order_type; + typedef agg::pixel32_type pixel_type; + typedef agg::comp_op_adaptor_rgba blender_type; // comp blender + typedef agg::pixfmt_custom_blend_rgba pixfmt_comp_type; + typedef agg::renderer_base renderer_base; + typedef agg::renderer_scanline_aa_solid renderer_type; + + ras_ptr->reset(); + ras_ptr->gamma(agg::gamma_power()); + agg::scanline_u8 sl; + agg::rendering_buffer buf(current_buffer_->raw_data(), width_, height_, width_ * 4); + pixfmt_comp_type pixf(buf); + pixf.comp_op(static_cast(comp_op)); + renderer_base renb(pixf); + if (marker.is_vector()) { - typedef agg::rgba8 color_type; - typedef agg::order_rgba order_type; - typedef agg::pixel32_type pixel_type; - typedef agg::comp_op_adaptor_rgba blender_type; // comp blender - typedef agg::pixfmt_custom_blend_rgba pixfmt_comp_type; - typedef agg::renderer_base renderer_base; - typedef agg::renderer_scanline_aa_solid renderer_type; - - ras_ptr->reset(); - ras_ptr->gamma(agg::gamma_power()); - agg::scanline_u8 sl; - agg::rendering_buffer buf(current_buffer_->raw_data(), width_, height_, width_ * 4); - pixfmt_comp_type pixf(buf); - pixf.comp_op(static_cast(comp_op)); - renderer_base renb(pixf); - box2d const& bbox = (*marker.get_vector_data())->bounding_box(); coord c = bbox.center(); // center the svg marker on '0,0' @@ -304,12 +308,12 @@ void agg_renderer::render_marker(pixel_position const& pos, marker const& mar } else { - double w = (*marker.get_bitmap_data())->width(); - double h = (*marker.get_bitmap_data())->height(); - double cx = 0.5 * w; - double cy = 0.5 * h; + double width = (*marker.get_bitmap_data())->width(); + double height = (*marker.get_bitmap_data())->height(); + double cx = 0.5 * width; + double cy = 0.5 * height; - if (std::fabs(1.0 - scale_factor_) < 0.001) + if (std::fabs(1.0 - scale_factor_) < 0.001 && tr.is_identity()) { composite(current_buffer_->data(), **marker.get_bitmap_data(), comp_op, opacity, @@ -319,15 +323,52 @@ void agg_renderer::render_marker(pixel_position const& pos, marker const& mar } else { - double scaled_width = w * scale_factor_; - double scaled_height = h * scale_factor_; - image_data_32 buf(std::ceil(scaled_width),std::ceil(scaled_height)); - scale_image_agg(buf, **marker.get_bitmap_data(), SCALING_BILINEAR, scale_factor_); - composite(current_buffer_->data(), buf, - comp_op, opacity, - boost::math::iround(pos.x - 0.5*scaled_width), - boost::math::iround(pos.y - 0.5*scaled_height), - false); + + double p[8]; + double x0 = pos.x - 0.5 * width; + double y0 = pos.y - 0.5 * height; + p[0] = x0; p[1] = y0; + p[2] = x0 + width; p[3] = y0; + p[4] = x0 + width; p[5] = y0 + height; + p[6] = x0; p[7] = y0 + height; + + agg::trans_affine marker_tr; + + marker_tr *= agg::trans_affine_translation(-pos.x,-pos.y); + marker_tr *= tr; + marker_tr *= agg::trans_affine_scaling(scale_factor_); + marker_tr *= agg::trans_affine_translation(pos.x,pos.y); + + marker_tr.transform(&p[0], &p[1]); + marker_tr.transform(&p[2], &p[3]); + marker_tr.transform(&p[4], &p[5]); + marker_tr.transform(&p[6], &p[7]); + + ras_ptr->move_to_d(p[0],p[1]); + ras_ptr->line_to_d(p[2],p[3]); + ras_ptr->line_to_d(p[4],p[5]); + ras_ptr->line_to_d(p[6],p[7]); + + + agg::span_allocator sa; + agg::image_filter_bilinear filter_kernel; + agg::image_filter_lut filter(filter_kernel, false); + + image_data_32 const& src = **marker.get_bitmap_data(); + agg::rendering_buffer marker_buf((unsigned char *)src.getBytes(), + src.width(), + src.height(), + src.width()*4); + agg::pixfmt_rgba32_pre pixf(marker_buf); + + typedef agg::image_accessor_clone img_accessor_type; + typedef agg::span_interpolator_linear interpolator_type; + typedef agg::span_image_filter_rgba_2x2 span_gen_type; + img_accessor_type ia(pixf); + interpolator_type interpolator(agg::trans_affine(p, 0, 0, width, height) ); + span_gen_type sg(ia, interpolator, filter); + agg::render_scanlines_aa(*ras_ptr, sl, renb, sa, sg); } } } From b7630a3eb80861d8eec17be3e7ebe25a0c2c3b32 Mon Sep 17 00:00:00 2001 From: Dane Springmeyer Date: Wed, 18 Jul 2012 14:07:52 -0700 Subject: [PATCH 084/133] default to fully opaque default marker svg - fixes #1326 --- src/marker_cache.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/marker_cache.cpp b/src/marker_cache.cpp index 4caab454b..42be35040 100644 --- a/src/marker_cache.cpp +++ b/src/marker_cache.cpp @@ -54,12 +54,12 @@ marker_cache::marker_cache() insert_svg("ellipse", "" "" - "" + "" ""); insert_svg("arrow", "" "" - "" + "" ""); } From 587f0131a2310882df33bb392e1bb66f04bfba71 Mon Sep 17 00:00:00 2001 From: Dane Springmeyer Date: Wed, 18 Jul 2012 17:29:22 -0700 Subject: [PATCH 085/133] add tests for grid rendering with point_symbolizer --- tests/python_tests/render_grid_test.py | 35 ++++++++++++++++++++++---- 1 file changed, 30 insertions(+), 5 deletions(-) diff --git a/tests/python_tests/render_grid_test.py b/tests/python_tests/render_grid_test.py index 575717660..f2ce75b3c 100644 --- a/tests/python_tests/render_grid_test.py +++ b/tests/python_tests/render_grid_test.py @@ -2,7 +2,7 @@ # -*- coding: utf-8 -*- from nose.tools import * - +from utilities import execution_path import os, mapnik try: @@ -10,6 +10,11 @@ try: except ImportError: import simplejson as json +def setup(): + # All of the paths used are relative, if we run the tests + # from another directory we need to chdir() + os.chdir(execution_path('.')) + # first pass impl where resolution is passed as render # time rather than encoding time, likely will be deprecated soon grid_correct_old = {"keys": ["", "North West", "North East", "South West", "South East"], "data": {"South East": {"Name": "South East"}, "North East": {"Name": "North East"}, "North West": {"Name": "North West"}, "South West": {"Name": "South West"}}, "grid": [" ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " !!! ### ", " !!!!! ##### ", " !!!!! ##### ", " !!! ### ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " $$$$ %%%% ", " $$$$$ %%%%% ", " $$$$$ %%%%% ", " $$$ %%% ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " "]} @@ -39,7 +44,7 @@ def resolve(grid,row,col): return grid['data'].get(key) -def create_grid_map(width,height): +def create_grid_map(width,height,marker=True): ds = mapnik.MemoryDatasource() context = mapnik.Context() context.push('Name') @@ -64,9 +69,12 @@ def create_grid_map(width,height): ds.add_feature(f) s = mapnik.Style() r = mapnik.Rule() - symb = mapnik.MarkersSymbolizer() - symb.width = mapnik.Expression('10') - symb.height = mapnik.Expression('10') + if marker: + symb = mapnik.MarkersSymbolizer() + symb.width = mapnik.Expression('10') + symb.height = mapnik.Expression('10') + else: + symb = mapnik.PointSymbolizer(mapnik.PathExpression('../data/images/dummy.png')) symb.allow_overlap = True r.symbols.append(symb) @@ -274,6 +282,23 @@ def test_line_rendering(): eq_(utf1,line_expected,show_grids('line',utf1,line_expected)) #open('test.json','w').write(json.dumps(grid.encode())) +point_expected = {"keys": ["", "3", "4", "2", "1"], "data": {"1": {"Name": "South East"}, "3": {"Name": "North West"}, "2": {"Name": "South West"}, "4": {"Name": "North East"}}, "grid": [" ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " !!!! #### ", " !!!! #### ", " !!!! #### ", " !!!! #### ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " $$$$ %%%% ", " $$$$ %%%% ", " $$$$ %%%% ", " $$$$ %%%% ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " "]} + +def test_point_symbolizer_grid(): + width,height = 256,256 + m = create_grid_map(width,height,marker=False) + ul_lonlat = mapnik.Coord(142.30,-38.20) + lr_lonlat = mapnik.Coord(143.40,-38.80) + m.zoom_to_box(mapnik.Box2d(ul_lonlat,lr_lonlat)) + #mapnik.render_to_file(m,'test.png') + #print mapnik.save_map_to_string(m) + grid = mapnik.Grid(m.width,m.height) + mapnik.render_layer(m,grid,layer=0,fields=['Name']) + utf1 = grid.encode() + #open('test.json','w').write(json.dumps(grid.encode())) + eq_(utf1,point_expected,show_grids('point-sym',utf1,point_expected)) + if __name__ == "__main__": + setup() [eval(run)() for run in dir() if 'test_' in run] From ee7ebb61f25a79b8d2d972f5abccc6a83a0bb32a Mon Sep 17 00:00:00 2001 From: Rich Wareham Date: Thu, 19 Jul 2012 16:08:25 +0100 Subject: [PATCH 086/133] SConstruct: trivial typo fix 'henche' -> 'hence' --- SConstruct | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SConstruct b/SConstruct index b087233a6..0a5053b5a 100644 --- a/SConstruct +++ b/SConstruct @@ -87,7 +87,7 @@ pretty_dep_names = { # Core plugin build configuration # opts.AddVariables still hardcoded however... PLUGINS = { # plugins with external dependencies - # configured by calling project, henche 'path':None + # configured by calling project, hence 'path':None 'postgis': {'default':True,'path':None,'inc':'libpq-fe.h','lib':'pq','lang':'C'}, 'gdal': {'default':True,'path':None,'inc':'gdal_priv.h','lib':'gdal','lang':'C++'}, 'ogr': {'default':True,'path':None,'inc':'ogrsf_frmts.h','lib':'gdal','lang':'C++'}, From c8cfde58f7de36cf9dd5ab3e5b3da689ecfe9aab Mon Sep 17 00:00:00 2001 From: artemp Date: Thu, 19 Jul 2012 16:22:45 +0100 Subject: [PATCH 087/133] + pass box2d by const ref + make member const& too --- include/mapnik/markers_placement.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/mapnik/markers_placement.hpp b/include/mapnik/markers_placement.hpp index 2524a36d9..bf4f70aa9 100644 --- a/include/mapnik/markers_placement.hpp +++ b/include/mapnik/markers_placement.hpp @@ -47,7 +47,7 @@ public: * converted to a positive value with similar magnitude, but * choosen to optimize marker placement. 0 = no markers */ - markers_placement(Locator &locator, box2d size, agg::trans_affine const& tr, Detector &detector, double spacing, double max_error, bool allow_overlap); + markers_placement(Locator &locator, box2d const& size, agg::trans_affine const& tr, Detector &detector, double spacing, double max_error, bool allow_overlap); /** Start again at first marker. * \note Returns the same list of markers only works when they were NOT added * to the detector. @@ -64,7 +64,7 @@ public: bool get_point(double & x, double & y, double & angle, bool add_to_detector = true); private: Locator &locator_; - box2d size_; + box2d const& size_; agg::trans_affine tr_; Detector &detector_; double spacing_; From 994f9abb01f2951039444584d329c4507a3f992d Mon Sep 17 00:00:00 2001 From: artemp Date: Thu, 19 Jul 2012 16:23:39 +0100 Subject: [PATCH 088/133] + apply _mapnik_ coding style --- include/mapnik/svg/svg_renderer.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/mapnik/svg/svg_renderer.hpp b/include/mapnik/svg/svg_renderer.hpp index 278376e42..fad181e02 100644 --- a/include/mapnik/svg/svg_renderer.hpp +++ b/include/mapnik/svg/svg_renderer.hpp @@ -243,7 +243,7 @@ public: Renderer& ren, agg::trans_affine const& mtx, double opacity, - const box2d &symbol_bbox) + box2d const& symbol_bbox) { using namespace agg; From c0ecb7e980e1f7cf0cabd46614126ca615ff9cdd Mon Sep 17 00:00:00 2001 From: artemp Date: Thu, 19 Jul 2012 16:24:29 +0100 Subject: [PATCH 089/133] + use member variable in ctor --- src/wkb.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/wkb.cpp b/src/wkb.cpp index cfc07530c..f7d9692f3 100644 --- a/src/wkb.cpp +++ b/src/wkb.cpp @@ -76,7 +76,7 @@ public: // try to determine WKB format automatically if (format_ == wkbAuto) { - if (size >= 44 + if (size_ >= 44 && (unsigned char)(wkb_[0]) == (unsigned char)(0x00) && (unsigned char)(wkb_[38]) == (unsigned char)(0x7C)) { From 710b7eb04bc6d625ec098cc5c374122d4fbb62e7 Mon Sep 17 00:00:00 2001 From: artemp Date: Thu, 19 Jul 2012 16:25:37 +0100 Subject: [PATCH 090/133] + instantiate all vertex_converters permutations + pass parameter by const reference --- src/markers_placement.cpp | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/src/markers_placement.cpp b/src/markers_placement.cpp index 94a713cf4..6ea4b0e14 100644 --- a/src/markers_placement.cpp +++ b/src/markers_placement.cpp @@ -9,6 +9,7 @@ #include "agg_conv_clip_polyline.h" #include "agg_trans_affine.h" #include "agg_conv_transform.h" +#include "agg_conv_smooth_poly1.h" // stl #include @@ -16,7 +17,7 @@ namespace mapnik { template markers_placement::markers_placement( - Locator &locator, box2d size, agg::trans_affine const& tr, Detector &detector, double spacing, double max_error, bool allow_overlap) + Locator &locator, box2d const& size, agg::trans_affine const& tr, Detector &detector, double spacing, double max_error, bool allow_overlap) : locator_(locator), size_(size), tr_(tr), detector_(detector), max_error_(max_error), allow_overlap_(allow_overlap) { marker_width_ = (size_ * tr_).width(); @@ -239,9 +240,14 @@ typedef coord_transform path_type; typedef coord_transform clipped_path_type; typedef agg::conv_transform transformed_path_type; -template class markers_placement; -template class markers_placement, label_collision_detector4>; +template class markers_placement; template class markers_placement; +template class markers_placement; +template class markers_placement; template class markers_placement; - +template class markers_placement, label_collision_detector4>; +template class markers_placement, label_collision_detector4>; +template class markers_placement, label_collision_detector4>; +template class markers_placement, label_collision_detector4>; +template class markers_placement, label_collision_detector4>; } //ns mapnik From f6fa57da2641488f444b277199a08ded5f675eae Mon Sep 17 00:00:00 2001 From: artemp Date: Thu, 19 Jul 2012 16:31:47 +0100 Subject: [PATCH 091/133] + add VertexSource based implementations of label position algos --- include/mapnik/geom_util.hpp | 201 +++++++++++++++++++++++++++++++++++ 1 file changed, 201 insertions(+) diff --git a/include/mapnik/geom_util.hpp b/include/mapnik/geom_util.hpp index ce9440dcc..4d90ae380 100644 --- a/include/mapnik/geom_util.hpp +++ b/include/mapnik/geom_util.hpp @@ -32,6 +32,7 @@ // stl #include +#include namespace mapnik { @@ -216,6 +217,206 @@ struct filter_at_point return extent.contains(pt_); } }; + +//////////////////////////////////////////////////////////////////////////// +template +double path_length(PathType & path) +{ + double x0,y0,x1,y1; + path.rewind(0); + unsigned command = path.vertex(&x0,&y0); + if (command == SEG_END) return 0; + double length = 0; + while (SEG_END != (command = path.vertex(&x1, &y1))) + { + length += distance(x0,y0,x1,y1); + x0 = x1; + y0 = y1; + } + return length; +} + +template +bool middle_point(PathType & path, double & x, double & y) +{ + double x0,y0,x1,y1; + double mid_length = 0.5 * path_length(path); + path.rewind(0); + unsigned command = path.vertex(&x0,&y0); + if (command == SEG_END) return false; + double dist = 0.0; + while (SEG_END != (command = path.vertex(&x1, &y1))) + { + double seg_length = distance(x0, y0, x1, y1); + + if ( dist + seg_length >= mid_length) + { + double r = (mid_length - dist)/seg_length; + x = x0 + (x1 - x0) * r; + y = y0 + (y1 - y0) * r; + break; + } + dist += seg_length; + x0 = x1; + y0 = y1; + } + return true; +} + +template +bool centroid(PathType & path, double & x, double & y) +{ + double x0; + double y0; + double x1; + double y1; + double start_x; + double start_y; + + path.rewind(0); + unsigned command = path.vertex(&x0, &y0); + if (command == SEG_END) return false; + + start_x = x0; + start_y = y0; + + double atmp = 0; + double xtmp = 0; + double ytmp = 0; + + while (SEG_END != (command = path.vertex(&x1, &y1))) + { + double dx0 = x0 - start_x; + double dy0 = y0 - start_y; + double dx1 = x1 - start_x; + double dy1 = y1 - start_y; + + double ai = dx0 * dy1 - dx1 * dy0; + atmp += ai; + xtmp += (dx1 + dx0) * ai; + ytmp += (dy1 + dy0) * ai; + x0 = x1; + y0 = y1; + } + + if (atmp != 0) + { + x = (xtmp/(3*atmp)) + start_x; + y = (ytmp/(3*atmp)) + start_y; + } + else + { + x = x0; + y = y0; + } + return true; +} + +template +bool hit_test(PathType & path, double x, double y, double tol) +{ + bool inside=false; + double x0, y0, x1, y1; + path.rewind(0); + unsigned command = path.vertex(&x0, &y0); + if (command == SEG_END) return false; + unsigned count = 0; + while (SEG_END != (command = path.vertex(&x1, &y1))) + { + ++count; + if (command == SEG_MOVETO) + { + x0 = x1; + y0 = y1; + continue; + } + if ((((y1 <= y) && (y < y0)) || + ((y0 <= y) && (y < y1))) && + (x < (x0 - x1) * (y - y1)/ (y0 - y1) + x1)) + inside=!inside; + + x0 = x1; + y0 = y1; + } + + if (count == 0) // one vertex + { + return distance(x, y, x0, y0) <= fabs(tol); + } + return inside; +} + +template +void label_interior_position(PathType & path, double & x, double & y) +{ + // start with the centroid + centroid(path, x,y); + + // if we are not a polygon, or the default is within the polygon we are done + if (hit_test(path,x,y,0.001)) + return; + + // otherwise we find a horizontal line across the polygon and then return the + // center of the widest intersection between the polygon and the line. + + std::vector intersections; // only need to store the X as we know the y + + double x0; + double y0; + path.rewind(0); + unsigned command = path.vertex(&x0, &y0); + double x1,y1; + while (SEG_END != (command = path.vertex(&x1, &y1))) + { + if (command != SEG_MOVETO) + { + // if the segments overlap + if (y0==y1) + { + if (y0==y) + { + double xi = (x0+x1)/2.0; + intersections.push_back(xi); + } + } + // if the path segment crosses the bisector + else if ((y0 <= y && y1 >= y) || + (y0 >= y && y1 <= y)) + { + // then calculate the intersection + double xi = x0; + if (x0 != x1) + { + double m = (y1-y0)/(x1-x0); + double c = y0 - m*x0; + xi = (y-c)/m; + } + + intersections.push_back(xi); + } + } + x0 = x1; + y0 = y1; + } + // no intersections we just return the default + if (intersections.empty()) + return; + x0=intersections[0]; + double max_width = 0; + for (unsigned ii = 1; ii < intersections.size(); ++ii) + { + double x1=intersections[ii]; + double xc=(x0+x1)/2.0; + double width = std::fabs(x1-x0); + if (width > max_width && hit_test(path,xc,y,0)) + { + x=xc; + max_width = width; + break; + } + } +} + } #endif // MAPNIK_GEOM_UTIL_HPP From 9e1914a4df5041b3ebb23aeb9f4aeba3e5cccbb6 Mon Sep 17 00:00:00 2001 From: artemp Date: Thu, 19 Jul 2012 16:36:06 +0100 Subject: [PATCH 092/133] + remove label position alogos from geometry class --- include/mapnik/geometry.hpp | 274 ++---------------------------------- 1 file changed, 9 insertions(+), 265 deletions(-) diff --git a/include/mapnik/geometry.hpp b/include/mapnik/geometry.hpp index 691bf5404..a27c31fba 100644 --- a/include/mapnik/geometry.hpp +++ b/include/mapnik/geometry.hpp @@ -80,13 +80,18 @@ public: return cont_; } + size_type size() const + { + return cont_.size(); + } + box2d envelope() const { box2d result; double x(0); double y(0); rewind(0); - for (unsigned i=0;i intersections; // only need to store the X as we know the y - - double x0=0; - double y0=0; - rewind(0); - unsigned command = vertex(&x0, &y0); - double x1,y1; - while (SEG_END != (command=vertex(&x1, &y1))) - { - if (command != SEG_MOVETO) - { - // if the segments overlap - if (y0==y1) - { - if (y0==*y) - { - double xi = (x0+x1)/2.0; - intersections.push_back(xi); - } - } - // if the path segment crosses the bisector - else if ((y0 <= *y && y1 >= *y) || - (y0 >= *y && y1 <= *y)) - { - // then calculate the intersection - double xi = x0; - if (x0 != x1) - { - double m = (y1-y0)/(x1-x0); - double c = y0 - m*x0; - xi = (*y-c)/m; - } - - intersections.push_back(xi); - } - } - x0 = x1; - y0 = y1; - } - // no intersections we just return the default - if (intersections.empty()) - return; - x0=intersections[0]; - double max_width = 0; - for (unsigned ii = 1; ii < intersections.size(); ++ii) - { - double x1=intersections[ii]; - double xc=(x0+x1)/2.0; - double width = fabs(x1-x0); - if (width > max_width && hit_test(xc,*y,0)) - { - *x=xc; - max_width = width; - } - } - } - - /* center of gravity centroid - - best visually but does not work with multipolygons - */ - void label_position(double *x, double *y) const - { - if (type_ == LineString) - { - middle_point(x,y); - return; - } - - unsigned size = cont_.size(); - if (size < 3) - { - cont_.get_vertex(0,x,y); - return; - } - - double ai; - double atmp = 0; - double xtmp = 0; - double ytmp = 0; - double x0 =0; - double y0 =0; - double x1 =0; - double y1 =0; - double ox =0; - double oy =0; - - unsigned i; - - // Use first point as origin to improve numerical accuracy - cont_.get_vertex(0,&ox,&oy); - - for (i = 0; i < size-1; i++) - { - cont_.get_vertex(i,&x0,&y0); - cont_.get_vertex(i+1,&x1,&y1); - - x0 -= ox; y0 -= oy; - x1 -= ox; y1 -= oy; - - ai = x0 * y1 - x1 * y0; - atmp += ai; - xtmp += (x1 + x0) * ai; - ytmp += (y1 + y0) * ai; - } - if (atmp != 0) - { - *x = (xtmp/(3*atmp)) + ox; - *y = (ytmp/(3*atmp)) + oy; - return; - } - *x=x0; - *y=y0; - } - - /* center of bounding box centroid */ - void label_position2(double *x, double *y) const - { - - box2d box = envelope(); - *x = box.center().x; - *y = box.center().y; - } - - /* summarized distance centroid */ - void label_position3(double *x, double *y) const - { - if (type_ == LineString) - { - middle_point(x,y); - return; - } - - unsigned i = 0; - double l = 0.0; - double tl = 0.0; - double cx = 0.0; - double cy = 0.0; - double x0 = 0.0; - double y0 = 0.0; - double x1 = 0.0; - double y1 = 0.0; - unsigned size = cont_.size(); - for (i = 0; i < size-1; i++) - { - cont_.get_vertex(i,&x0,&y0); - cont_.get_vertex(i+1,&x1,&y1); - l = distance(x0,y0,x1,y1); - cx += l * (x1 + x0)/2; - cy += l * (y1 + y0)/2; - tl += l; - } - *x = cx / tl; - *y = cy / tl; - } - - void middle_point(double *x, double *y) const - { - // calculate mid point on path - double x0=0; - double y0=0; - double x1=0; - double y1=0; - - unsigned size = cont_.size(); - if (size == 1) - { - cont_.get_vertex(0,x,y); - } - else if (size == 2) - { - cont_.get_vertex(0,&x0,&y0); - cont_.get_vertex(1,&x1,&y1); - *x = 0.5 * (x1 + x0); - *y = 0.5 * (y1 + y0); - } - else - { - double len=0.0; - for (unsigned pos = 1; pos < size; ++pos) - { - cont_.get_vertex(pos-1,&x0,&y0); - cont_.get_vertex(pos,&x1,&y1); - double dx = x1 - x0; - double dy = y1 - y0; - len += std::sqrt(dx * dx + dy * dy); - } - double midlen = 0.5 * len; - double dist = 0.0; - for (unsigned pos = 1; pos < size;++pos) - { - cont_.get_vertex(pos-1,&x0,&y0); - cont_.get_vertex(pos,&x1,&y1); - double dx = x1 - x0; - double dy = y1 - y0; - double seg_len = std::sqrt(dx * dx + dy * dy); - if (( dist + seg_len) >= midlen) - { - double r = (midlen - dist)/seg_len; - *x = x0 + (x1 - x0) * r; - *y = y0 + (y1 - y0) * r; - break; - } - dist += seg_len; - } - } - } - void push_vertex(coord_type x, coord_type y, CommandType c) { cont_.push_back(x,y,c); @@ -335,62 +121,20 @@ public: push_vertex(x,y,SEG_MOVETO); } - unsigned num_points() const - { - return cont_.size(); - } - unsigned vertex(double* x, double* y) const { - return cont_.get_vertex(itr_++,x,y); + return cont_.vertex(itr_++,x,y); } - unsigned get_vertex(unsigned pos, double* x, double* y) const + unsigned vertex(std::size_t index, double* x, double* y) const { - return cont_.get_vertex(pos, x, y); + return cont_.vertex(index, x, y); } void rewind(unsigned ) const { itr_=0; } - - bool hit_test(coord_type x, coord_type y, double tol) const - { - if (cont_.size() == 1) { - // Handle points - double x0, y0; - cont_.get_vertex(0, &x0, &y0); - return distance(x, y, x0, y0) <= fabs(tol); - } else if (cont_.size() > 1) { - bool inside=false; - double x0=0; - double y0=0; - rewind(0); - vertex(&x0, &y0); - - unsigned command; - double x1,y1; - while (SEG_END != (command=vertex(&x1, &y1))) - { - if (command == SEG_MOVETO) - { - x0 = x1; - y0 = y1; - continue; - } - if ((((y1 <= y) && (y < y0)) || - ((y0 <= y) && (y < y1))) && - ( x < (x0 - x1) * (y - y1)/ (y0 - y1) + x1)) - inside=!inside; - x0=x1; - y0=y1; - } - return inside; - } - return false; - } - }; typedef geometry geometry_type; From 7b10400be9b50872a785e34eaab4f5a5804598b5 Mon Sep 17 00:00:00 2001 From: artemp Date: Thu, 19 Jul 2012 16:36:44 +0100 Subject: [PATCH 093/133] + update rendering code to work with new labeling methods + rename num_points() to size() + rename get_vertex() to vertex() --- demo/viewer/mapwidget.cpp | 4 +-- include/mapnik/hit_test_filter.hpp | 10 ++++--- .../json/geometry_generator_grammar.hpp | 2 +- .../mapnik/util/geometry_svg_generator.hpp | 2 +- include/mapnik/util/geometry_to_wkb.hpp | 12 ++++----- .../mapnik/util/geometry_wkt_generator.hpp | 2 +- include/mapnik/util/vertex_iterator.hpp | 2 +- include/mapnik/vertex_vector.hpp | 2 +- src/agg/process_building_symbolizer.cpp | 6 ++--- src/agg/process_line_pattern_symbolizer.cpp | 2 +- src/agg/process_line_symbolizer.cpp | 4 +-- src/agg/process_point_symbolizer.cpp | 5 ++-- .../process_polygon_pattern_symbolizer.cpp | 2 +- src/agg/process_polygon_symbolizer.cpp | 2 +- src/cairo_renderer.cpp | 27 +++++++++---------- src/grid/process_building_symbolizer.cpp | 6 ++--- src/grid/process_line_pattern_symbolizer.cpp | 2 +- src/grid/process_line_symbolizer.cpp | 2 +- src/grid/process_markers_symbolizer.cpp | 4 +-- src/grid/process_point_symbolizer.cpp | 5 ++-- .../process_polygon_pattern_symbolizer.cpp | 2 +- src/grid/process_polygon_symbolizer.cpp | 2 +- src/svg/process_symbolizers.cpp | 2 +- src/symbolizer_helpers.cpp | 8 +++--- 24 files changed, 60 insertions(+), 57 deletions(-) diff --git a/demo/viewer/mapwidget.cpp b/demo/viewer/mapwidget.cpp index 218115548..eb57adce9 100644 --- a/demo/viewer/mapwidget.cpp +++ b/demo/viewer/mapwidget.cpp @@ -200,13 +200,13 @@ void MapWidget::mousePressEvent(QMouseEvent* e) { mapnik::geometry_type & geom = feat->get_geometry(i); path_type path(t,geom,prj_trans); - if (geom.num_points() > 0) + if (geom.size() > 0) { QPainterPath qpath; double x,y; path.vertex(&x,&y); qpath.moveTo(x,y); - for (unsigned j = 1; j < geom.num_points(); ++j) + for (unsigned j = 1; j < geom.size(); ++j) { path.vertex(&x,&y); qpath.lineTo(x,y); diff --git a/include/mapnik/hit_test_filter.hpp b/include/mapnik/hit_test_filter.hpp index 461c7daba..483450506 100644 --- a/include/mapnik/hit_test_filter.hpp +++ b/include/mapnik/hit_test_filter.hpp @@ -25,6 +25,9 @@ // mapnik #include +#include +// boost +#include namespace mapnik { class hit_test_filter @@ -35,12 +38,11 @@ public: y_(y), tol_(tol) {} - bool pass(Feature const& feature) + bool pass(Feature & feature) { - for (unsigned i=0;i(coord) = geom.get_vertex(0,&boost::get<1>(coord),&boost::get<2>(coord)); + boost::get<0>(coord) = geom.vertex(0,&boost::get<1>(coord),&boost::get<2>(coord)); return coord; } }; diff --git a/include/mapnik/util/geometry_svg_generator.hpp b/include/mapnik/util/geometry_svg_generator.hpp index 5b1a285bc..7dc8ef120 100644 --- a/include/mapnik/util/geometry_svg_generator.hpp +++ b/include/mapnik/util/geometry_svg_generator.hpp @@ -66,7 +66,7 @@ namespace mapnik { namespace util { geometry_type::value_type const operator() (geometry_type const& geom) const { geometry_type::value_type coord; - boost::get<0>(coord) = geom.get_vertex(0,&boost::get<1>(coord),&boost::get<2>(coord)); + boost::get<0>(coord) = geom.vertex(0,&boost::get<1>(coord),&boost::get<2>(coord)); return coord; } }; diff --git a/include/mapnik/util/geometry_to_wkb.hpp b/include/mapnik/util/geometry_to_wkb.hpp index 4f793bc0b..1252479dc 100644 --- a/include/mapnik/util/geometry_to_wkb.hpp +++ b/include/mapnik/util/geometry_to_wkb.hpp @@ -119,7 +119,7 @@ namespace mapnik { namespace util { wkb_buffer_ptr to_point_wkb( geometry_type const& g, wkbByteOrder byte_order) { - assert(g.num_points() == 1); + assert(g.size() == 1); std::size_t size = 1 + 4 + 8*2 ; // byteOrder + wkbType + Point wkb_buffer_ptr wkb = boost::make_shared(size); boost::interprocess::bufferstream ss(wkb->buffer(), wkb->size(), std::ios::out | std::ios::binary); @@ -127,7 +127,7 @@ namespace mapnik { namespace util { int type = static_cast(mapnik::Point); write(ss,type,4,byte_order); double x,y; - g.get_vertex(0,&x,&y); + g.vertex(0,&x,&y); write(ss,x,8,byte_order); write(ss,y,8,byte_order); assert(ss.good()); @@ -136,7 +136,7 @@ namespace mapnik { namespace util { wkb_buffer_ptr to_line_string_wkb( geometry_type const& g, wkbByteOrder byte_order) { - unsigned num_points = g.num_points(); + unsigned num_points = g.size(); assert(num_points > 1); std::size_t size = 1 + 4 + 4 + 8*2*num_points ; // byteOrder + wkbType + numPoints + Point*numPoints wkb_buffer_ptr wkb = boost::make_shared(size); @@ -148,7 +148,7 @@ namespace mapnik { namespace util { double x,y; for (unsigned i=0; i< num_points; ++i) { - g.get_vertex(i,&x,&y); + g.vertex(i,&x,&y); write(ss,x,8,byte_order); write(ss,y,8,byte_order); } @@ -158,7 +158,7 @@ namespace mapnik { namespace util { wkb_buffer_ptr to_polygon_wkb( geometry_type const& g, wkbByteOrder byte_order) { - unsigned num_points = g.num_points(); + unsigned num_points = g.size(); assert(num_points > 1); typedef std::pair point_type; @@ -169,7 +169,7 @@ namespace mapnik { namespace util { std::size_t size = 1 + 4 + 4 ; // byteOrder + wkbType + numRings for (unsigned i=0; i< num_points; ++i) { - unsigned command = g.get_vertex(i,&x,&y); + unsigned command = g.vertex(i,&x,&y); if (command == SEG_MOVETO) { rings.push_back(new linear_ring); // start new loop diff --git a/include/mapnik/util/geometry_wkt_generator.hpp b/include/mapnik/util/geometry_wkt_generator.hpp index 0318a050d..46780e5fd 100644 --- a/include/mapnik/util/geometry_wkt_generator.hpp +++ b/include/mapnik/util/geometry_wkt_generator.hpp @@ -79,7 +79,7 @@ namespace mapnik { namespace util { geometry_type::value_type const operator() (geometry_type const& geom) const { geometry_type::value_type coord; - boost::get<0>(coord) = geom.get_vertex(0,&boost::get<1>(coord),&boost::get<2>(coord)); + boost::get<0>(coord) = geom.vertex(0,&boost::get<1>(coord),&boost::get<2>(coord)); return coord; } }; diff --git a/include/mapnik/util/vertex_iterator.hpp b/include/mapnik/util/vertex_iterator.hpp index 5cc794078..2d957ef33 100644 --- a/include/mapnik/util/vertex_iterator.hpp +++ b/include/mapnik/util/vertex_iterator.hpp @@ -63,7 +63,7 @@ namespace mapnik { namespace util { void increment() { - boost::get<0>(v_) = vertices_->get_vertex(pos_++, &boost::get<1>(v_), &boost::get<2>(v_)); + boost::get<0>(v_) = vertices_->vertex(pos_++, &boost::get<1>(v_), &boost::get<2>(v_)); } bool equal( vertex_iterator const& other) const diff --git a/include/mapnik/vertex_vector.hpp b/include/mapnik/vertex_vector.hpp index 85bcd8857..97139941b 100644 --- a/include/mapnik/vertex_vector.hpp +++ b/include/mapnik/vertex_vector.hpp @@ -105,7 +105,7 @@ public: *vertex = y; ++pos_; } - unsigned get_vertex(unsigned pos,coord_type* x,coord_type* y) const + unsigned vertex(unsigned pos,coord_type* x,coord_type* y) const { if (pos >= pos_) return SEG_END; unsigned block = pos >> block_shift; diff --git a/src/agg/process_building_symbolizer.cpp b/src/agg/process_building_symbolizer.cpp index 7863fd566..8f82ca2b8 100644 --- a/src/agg/process_building_symbolizer.cpp +++ b/src/agg/process_building_symbolizer.cpp @@ -77,7 +77,7 @@ void agg_renderer::process(building_symbolizer const& sym, for (unsigned i=0;i 2) + if (geom.size() > 2) { boost::scoped_ptr frame(new geometry_type(LineString)); boost::scoped_ptr roof(new geometry_type(Polygon)); @@ -87,7 +87,7 @@ void agg_renderer::process(building_symbolizer const& sym, geom.rewind(0); unsigned cm = geom.vertex(&x0,&y0); - for (unsigned j=1;j::process(building_symbolizer const& sym, } geom.rewind(0); - for (unsigned j=0;j::process(line_pattern_symbolizer const& sym, BOOST_FOREACH(geometry_type & geom, feature.paths()) { - if (geom.num_points() > 1) + if (geom.size() > 1) { converter.apply(geom); } diff --git a/src/agg/process_line_symbolizer.cpp b/src/agg/process_line_symbolizer.cpp index 9edf59b4a..1d5388aa3 100644 --- a/src/agg/process_line_symbolizer.cpp +++ b/src/agg/process_line_symbolizer.cpp @@ -109,7 +109,7 @@ void agg_renderer::process(line_symbolizer const& sym, BOOST_FOREACH( geometry_type & geom, feature.paths()) { - if (geom.num_points() > 1) + if (geom.size() > 1) { converter.apply(geom); } @@ -132,7 +132,7 @@ void agg_renderer::process(line_symbolizer const& sym, BOOST_FOREACH( geometry_type & geom, feature.paths()) { - if (geom.num_points() > 1) + if (geom.size() > 1) { converter.apply(geom); } diff --git a/src/agg/process_point_symbolizer.cpp b/src/agg/process_point_symbolizer.cpp index 56de677c7..0127c3460 100644 --- a/src/agg/process_point_symbolizer.cpp +++ b/src/agg/process_point_symbolizer.cpp @@ -23,6 +23,7 @@ // mapnik #include #include +#include #include #include #include @@ -81,9 +82,9 @@ void agg_renderer::process(point_symbolizer const& sym, double y; double z=0; if (sym.get_point_placement() == CENTROID_POINT_PLACEMENT) - geom.label_position(&x, &y); + centroid(geom, x, y); else - geom.label_interior_position(&x, &y); + label_interior_position(geom ,x, y); prj_trans.backward(x,y,z); t_.forward(&x,&y); diff --git a/src/agg/process_polygon_pattern_symbolizer.cpp b/src/agg/process_polygon_pattern_symbolizer.cpp index f567db071..2a5ec53d3 100644 --- a/src/agg/process_polygon_pattern_symbolizer.cpp +++ b/src/agg/process_polygon_pattern_symbolizer.cpp @@ -151,7 +151,7 @@ void agg_renderer::process(polygon_pattern_symbolizer const& sym, BOOST_FOREACH( geometry_type & geom, feature.paths()) { - if (geom.num_points() > 2) + if (geom.size() > 2) { converter.apply(geom); } diff --git a/src/agg/process_polygon_symbolizer.cpp b/src/agg/process_polygon_symbolizer.cpp index 9f5047162..2b1266659 100644 --- a/src/agg/process_polygon_symbolizer.cpp +++ b/src/agg/process_polygon_symbolizer.cpp @@ -65,7 +65,7 @@ void agg_renderer::process(polygon_symbolizer const& sym, BOOST_FOREACH( geometry_type & geom, feature.paths()) { - if (geom.num_points() > 2) + if (geom.size() > 2) { converter.apply(geom); } diff --git a/src/cairo_renderer.cpp b/src/cairo_renderer.cpp index e3283e775..518c613e7 100644 --- a/src/cairo_renderer.cpp +++ b/src/cairo_renderer.cpp @@ -854,7 +854,7 @@ void cairo_renderer_base::process(polygon_symbolizer const& sym, BOOST_FOREACH( geometry_type & geom, feature.paths()) { - if (geom.num_points() > 2) + if (geom.size() > 2) { converter.apply(geom); } @@ -884,7 +884,7 @@ void cairo_renderer_base::process(building_symbolizer const& sym, { geometry_type const& geom = feature.get_geometry(i); - if (geom.num_points() > 2) + if (geom.size() > 2) { boost::scoped_ptr frame(new geometry_type(LineString)); boost::scoped_ptr roof(new geometry_type(Polygon)); @@ -895,7 +895,7 @@ void cairo_renderer_base::process(building_symbolizer const& sym, geom.rewind(0); unsigned cm = geom.vertex(&x0, &y0); - for (unsigned j = 1; j < geom.num_points(); ++j) + for (unsigned j = 1; j < geom.size(); ++j) { double x=0; double y=0; @@ -942,7 +942,7 @@ void cairo_renderer_base::process(building_symbolizer const& sym, } geom.rewind(0); - for (unsigned j = 0; j < geom.num_points(); ++j) + for (unsigned j = 0; j < geom.size(); ++j) { double x, y; unsigned cm = geom.vertex(&x, &y); @@ -1008,7 +1008,7 @@ void cairo_renderer_base::process(line_symbolizer const& sym, BOOST_FOREACH( geometry_type & geom, feature.paths()) { - if (geom.num_points() > 1) + if (geom.size() > 1) { converter.apply(geom); } @@ -1158,9 +1158,9 @@ void cairo_renderer_base::process(point_symbolizer const& sym, double z = 0; if (sym.get_point_placement() == CENTROID_POINT_PLACEMENT) - geom.label_position(&x, &y); + centroid(geom, x, y); else - geom.label_interior_position(&x, &y); + label_interior_position(geom, x, y); prj_trans.backward(x, y, z); t_.forward(&x, &y); @@ -1236,7 +1236,7 @@ void cairo_renderer_base::process(line_pattern_symbolizer const& sym, { geometry_type & geom = feature.get_geometry(i); - if (geom.num_points() > 1) + if (geom.size() > 1) { clipped_geometry_type clipped(geom); clipped.clip_box(query_extent_.minx(),query_extent_.miny(),query_extent_.maxx(),query_extent_.maxy()); @@ -1316,7 +1316,7 @@ void cairo_renderer_base::process(polygon_pattern_symbolizer const& sym, BOOST_FOREACH( geometry_type & geom, feature.paths()) { - if (geom.num_points() > 2) + if (geom.size() > 2) { converter.apply(geom); } @@ -1433,12 +1433,12 @@ void cairo_renderer_base::process(markers_symbolizer const& sym, { geometry_type & geom = feature.get_geometry(i); // TODO - merge this code with point_symbolizer rendering - if (placement_method == MARKER_POINT_PLACEMENT || geom.num_points() <= 1) + if (placement_method == MARKER_POINT_PLACEMENT || geom.size() <= 1) { double x; double y; double z=0; - geom.label_interior_position(&x, &y); + label_interior_position(geom, x, y); prj_trans.backward(x,y,z); t_.forward(&x,&y); extent.re_center(x,y); @@ -1448,9 +1448,8 @@ void cairo_renderer_base::process(markers_symbolizer const& sym, { render_marker(pixel_position(x - 0.5 * w, y - 0.5 * h) ,**mark, tr, sym.get_opacity()); - // TODO - impl this for markers? - //if (!sym.get_ignore_placement()) - // detector_.insert(label_ext); + if (!sym.get_ignore_placement()) + detector_.insert(extent); } } else diff --git a/src/grid/process_building_symbolizer.cpp b/src/grid/process_building_symbolizer.cpp index e09d17218..d89898d37 100644 --- a/src/grid/process_building_symbolizer.cpp +++ b/src/grid/process_building_symbolizer.cpp @@ -70,7 +70,7 @@ void grid_renderer::process(building_symbolizer const& sym, for (unsigned i=0;i 2) + if (geom.size() > 2) { boost::scoped_ptr frame(new geometry_type(LineString)); boost::scoped_ptr roof(new geometry_type(Polygon)); @@ -78,7 +78,7 @@ void grid_renderer::process(building_symbolizer const& sym, double x0(0); double y0(0); unsigned cm = geom.vertex(&x0,&y0); - for (unsigned j=1;j::process(building_symbolizer const& sym, } geom.rewind(0); - for (unsigned j=0;j::process(line_pattern_symbolizer const& sym, for (unsigned i=0;i 1) + if (geom.size() > 1) { path_type path(t_,geom,prj_trans); agg::conv_stroke stroke(path); diff --git a/src/grid/process_line_symbolizer.cpp b/src/grid/process_line_symbolizer.cpp index 9e18180a4..debb189e9 100644 --- a/src/grid/process_line_symbolizer.cpp +++ b/src/grid/process_line_symbolizer.cpp @@ -84,7 +84,7 @@ void grid_renderer::process(line_symbolizer const& sym, BOOST_FOREACH( geometry_type & geom, feature.paths()) { - if (geom.num_points() > 1) + if (geom.size() > 1) { converter.apply(geom); } diff --git a/src/grid/process_markers_symbolizer.cpp b/src/grid/process_markers_symbolizer.cpp index adade0895..9dae111c6 100644 --- a/src/grid/process_markers_symbolizer.cpp +++ b/src/grid/process_markers_symbolizer.cpp @@ -123,12 +123,12 @@ void grid_renderer::process(markers_symbolizer const& sym, BOOST_FOREACH( geometry_type & geom, feature.paths()) { // TODO - merge this code with point_symbolizer rendering - if (placement_method == MARKER_POINT_PLACEMENT || geom.num_points() <= 1) + if (placement_method == MARKER_POINT_PLACEMENT || geom.size() <= 1) { double x; double y; double z=0; - geom.label_interior_position(&x, &y); + label_interior_position(geom, x, y); prj_trans.backward(x,y,z); t_.forward(&x,&y); geom_tr.transform(&x,&y); diff --git a/src/grid/process_point_symbolizer.cpp b/src/grid/process_point_symbolizer.cpp index 7398bf91d..211a3035d 100644 --- a/src/grid/process_point_symbolizer.cpp +++ b/src/grid/process_point_symbolizer.cpp @@ -26,6 +26,7 @@ #include #include #include +#include #include #include #include @@ -73,9 +74,9 @@ void grid_renderer::process(point_symbolizer const& sym, double y; double z=0; if (sym.get_point_placement() == CENTROID_POINT_PLACEMENT) - geom.label_position(&x, &y); + centroid(geom, x, y); else - geom.label_interior_position(&x, &y); + label_interior_position(geom, x, y); prj_trans.backward(x,y,z); t_.forward(&x,&y); diff --git a/src/grid/process_polygon_pattern_symbolizer.cpp b/src/grid/process_polygon_pattern_symbolizer.cpp index 154a24103..aae06ff45 100644 --- a/src/grid/process_polygon_pattern_symbolizer.cpp +++ b/src/grid/process_polygon_pattern_symbolizer.cpp @@ -60,7 +60,7 @@ void grid_renderer::process(polygon_pattern_symbolizer const& sym, for (unsigned i=0;i 2) + if (geom.size() > 2) { path_type path(t_,geom,prj_trans); ras_ptr->add_path(path); diff --git a/src/grid/process_polygon_symbolizer.cpp b/src/grid/process_polygon_symbolizer.cpp index 87e14d4b4..355e493b3 100644 --- a/src/grid/process_polygon_symbolizer.cpp +++ b/src/grid/process_polygon_symbolizer.cpp @@ -68,7 +68,7 @@ void grid_renderer::process(polygon_symbolizer const& sym, BOOST_FOREACH( geometry_type & geom, feature.paths()) { - if (geom.num_points() > 2) + if (geom.size() > 2) { converter.apply(geom); } diff --git a/src/svg/process_symbolizers.cpp b/src/svg/process_symbolizers.cpp index 1619b6caa..2a1bcbad1 100644 --- a/src/svg/process_symbolizers.cpp +++ b/src/svg/process_symbolizers.cpp @@ -46,7 +46,7 @@ bool svg_renderer::process(rule::symbolizers const& syms, for(unsigned i=0; i 1) + if(geom.size() > 1) { path_type path(t_, geom, prj_trans); generator_.generate_path(path, path_attributes_); diff --git a/src/symbolizer_helpers.cpp b/src/symbolizer_helpers.cpp index 87516c19d..f54e039fb 100644 --- a/src/symbolizer_helpers.cpp +++ b/src/symbolizer_helpers.cpp @@ -179,7 +179,7 @@ void text_symbolizer_helper::initialize_geometries() geometry_type const& geom = feature_.get_geometry(i); // don't bother with empty geometries - if (geom.num_points() == 0) continue; + if (geom.size() == 0) continue; eGeomType type = geom.type(); if (type == Polygon) { @@ -232,7 +232,7 @@ void text_symbolizer_helper::initialize_points() if (how_placed == VERTEX_PLACEMENT) { geom.rewind(0); - for(unsigned i = 0; i < geom.num_points(); i++) + for(unsigned i = 0; i < geom.size(); i++) { geom.vertex(&label_x, &label_y); prj_trans_.backward(label_x, label_y, z); @@ -244,11 +244,11 @@ void text_symbolizer_helper::initialize_points() { if (how_placed == POINT_PLACEMENT) { - geom.label_position(&label_x, &label_y); + centroid(geom, label_x, label_y); } else if (how_placed == INTERIOR_PLACEMENT) { - geom.label_interior_position(&label_x, &label_y); + label_interior_position(geom, label_x, label_y); } else { From ab0722efce871c7d6d6046d8260a4d5dddedf3b8 Mon Sep 17 00:00:00 2001 From: artemp Date: Thu, 19 Jul 2012 16:37:54 +0100 Subject: [PATCH 094/133] + AGG: refactor process_markers_symbolizer to use vertex_converters --- src/agg/process_markers_symbolizer.cpp | 207 ++++++++++++++----------- 1 file changed, 115 insertions(+), 92 deletions(-) diff --git a/src/agg/process_markers_symbolizer.cpp b/src/agg/process_markers_symbolizer.cpp index e120f1552..61710d476 100644 --- a/src/agg/process_markers_symbolizer.cpp +++ b/src/agg/process_markers_symbolizer.cpp @@ -23,9 +23,11 @@ // mapnik #include #include +#include #include #include #include +#include #include #include #include @@ -49,6 +51,97 @@ namespace mapnik { +template +struct markers_rasterizer_dispatch +{ + typedef agg::rgba8 color_type; + typedef agg::order_rgba order_type; + typedef agg::pixel32_type pixel_type; + typedef agg::comp_op_adaptor_rgba_pre blender_type; // comp blender + typedef agg::pixfmt_custom_blend_rgba pixfmt_comp_type; + typedef agg::renderer_base renderer_base; + typedef agg::renderer_scanline_aa_solid renderer_type; + + markers_rasterizer_dispatch(BufferType & image_buffer, + SvgRenderer & svg_renderer, + Rasterizer & ras, + box2d const& bbox, + agg::trans_affine const& marker_trans, + markers_symbolizer const& sym, + Detector & detector, + double scale_factor) + : buf_(image_buffer.raw_data(), image_buffer.width(), image_buffer.height(), image_buffer.width() * 4), + pixf_(buf_), + renb_(pixf_), + svg_renderer_(svg_renderer), + ras_(ras), + bbox_(bbox), + marker_trans_(marker_trans), + sym_(sym), + detector_(detector), + scale_factor_(scale_factor) + { + pixf_.comp_op(static_cast(sym_.comp_op())); + } + + template + void add_path(T & path) + { + marker_placement_e placement_method = sym_.get_marker_placement(); +// std::cout << "add_path called -> " << placement_method << std::endl; +// std::cout << typeid(path).name() << std::endl; + if (placement_method == MARKER_POINT_PLACEMENT) + { + + double x,y; + path.rewind(0); + label_interior_position(path, x, y); +// std::cout << "pos -> " << x << "," << y << std::endl; + agg::trans_affine matrix = marker_trans_; + matrix.translate(x,y); + box2d transformed_bbox = bbox_ * matrix; + + if (sym_.get_allow_overlap() || + detector_.has_placement(transformed_bbox)) + { + svg_renderer_.render(ras_, sl_, renb_, matrix, sym_.get_opacity(), bbox_); + + if (!sym_.get_ignore_placement()) + detector_.insert(transformed_bbox); + } + } + else + { + markers_placement placement(path, bbox_, marker_trans_, detector_, + sym_.get_spacing() * scale_factor_, + sym_.get_max_error(), + sym_.get_allow_overlap()); + double x, y, angle; + while (placement.get_point(x, y, angle)) + { + agg::trans_affine matrix = marker_trans_; + matrix.rotate(angle); + matrix.translate(x, y); + svg_renderer_.render(ras_, sl_, renb_, matrix, sym_.get_opacity(), bbox_); + } + } + } + +private: + agg::scanline_u8 sl_; + agg::rendering_buffer buf_; + pixfmt_comp_type pixf_; + renderer_base renb_; + SvgRenderer & svg_renderer_; + Rasterizer & ras_; + box2d const& bbox_; + agg::trans_affine const& marker_trans_; + markers_symbolizer const& sym_; + Detector & detector_; + double scale_factor_; +}; + + template void agg_renderer::process(markers_symbolizer const& sym, mapnik::feature_impl & feature, @@ -77,12 +170,6 @@ void agg_renderer::process(markers_symbolizer const& sym, ras_ptr->reset(); ras_ptr->gamma(agg::gamma_power()); - agg::scanline_u8 sl; - agg::rendering_buffer buf(current_buffer_->raw_data(), width_, height_, width_ * 4); - pixfmt_comp_type pixf(buf); - pixf.comp_op(static_cast(sym.comp_op())); - renderer_base renb(pixf); - renderer_type ren(renb); agg::trans_affine geom_tr; evaluate_transform(geom_tr, feature, sym.get_transform()); @@ -105,100 +192,36 @@ void agg_renderer::process(markers_symbolizer const& sym, agg::pod_bvector attributes; bool result = push_explicit_style( (*marker)->attributes(), attributes, sym); - svg_renderer, - renderer_type, - agg::pixfmt_rgba32 > svg_renderer(svg_path, result ? attributes : (*marker)->attributes()); + typedef label_collision_detector4 detector_type; + typedef svg_renderer, + renderer_type, + agg::pixfmt_rgba32 > svg_renderer_type; + typedef markers_rasterizer_dispatch markers_rasterizer_dispatch_type; + typedef boost::mpl::vector conv_types; - marker_placement_e placement_method = sym.get_marker_placement(); + svg_renderer_type svg_renderer(svg_path, result ? attributes : (*marker)->attributes()); - BOOST_FOREACH( geometry_type & geom, feature.paths()) + markers_rasterizer_dispatch_type rasterizer_dispatch(*current_buffer_,svg_renderer,*ras_ptr, + bbox, marker_trans, sym, *detector_, scale_factor_); + + + vertex_converter, markers_rasterizer_dispatch_type, markers_symbolizer, + CoordTransform, proj_transform, agg::trans_affine, conv_types> + converter(query_extent_* 1.1,rasterizer_dispatch, sym,t_,prj_trans,tr,scale_factor_); + + if (sym.clip()) converter.template set(); //optional clip (default: true) + converter.template set(); //always transform + if (sym.smooth() > 0.0) converter.template set(); // optional smooth converter + + BOOST_FOREACH(geometry_type & geom, feature.paths()) { - // TODO - merge this code with point_symbolizer rendering - if (placement_method == MARKER_POINT_PLACEMENT || geom.num_points() <= 1) - { - double x; - double y; - double z=0; - geom.label_interior_position(&x, &y); - prj_trans.backward(x,y,z); - t_.forward(&x,&y); - geom_tr.transform(&x,&y); - agg::trans_affine matrix = marker_trans; - matrix.translate(x,y); - box2d transformed_bbox = bbox * matrix; - - if (sym.get_allow_overlap() || - detector_->has_placement(transformed_bbox)) - { - svg_renderer.render(*ras_ptr, sl, renb, matrix, sym.get_opacity(), bbox); - if (/* DEBUG */ 0) - { - debug_draw_box(buf, transformed_bbox, 0, 0, 0.0); - } - - if (!sym.get_ignore_placement()) - detector_->insert(transformed_bbox); - } - } - else if (sym.clip()) - { - typedef agg::conv_clip_polyline clipped_geometry_type; - typedef coord_transform path_type; - typedef agg::conv_transform transformed_path_type; - - clipped_geometry_type clipped(geom); - clipped.clip_box(query_extent_.minx(),query_extent_.miny(),query_extent_.maxx(),query_extent_.maxy()); - path_type path(t_,clipped,prj_trans); - transformed_path_type path_transformed(path,geom_tr); - markers_placement placement(path_transformed, bbox, marker_trans, *detector_, - sym.get_spacing() * scale_factor_, - sym.get_max_error(), - sym.get_allow_overlap()); - double x, y, angle; - while (placement.get_point(x, y, angle)) - { - agg::trans_affine matrix = marker_trans; - matrix.rotate(angle); - matrix.translate(x, y); - svg_renderer.render(*ras_ptr, sl, renb, matrix, sym.get_opacity(), bbox); - - if (/* DEBUG */ 0) - { - debug_draw_box(buf, bbox*matrix, 0, 0, 0.0); - } - } - } - else - { - typedef coord_transform path_type; - typedef agg::conv_transform transformed_path_type; - path_type path(t_,geom,prj_trans); - transformed_path_type path_transformed(path,geom_tr); - markers_placement placement(path_transformed, bbox, marker_trans, *detector_, - sym.get_spacing() * scale_factor_, - sym.get_max_error(), - sym.get_allow_overlap()); - double x, y, angle; - while (placement.get_point(x, y, angle)) - { - agg::trans_affine matrix = marker_trans; - matrix.rotate(angle); - matrix.translate(x, y); - svg_renderer.render(*ras_ptr, sl, renb, matrix, sym.get_opacity(), bbox); - - if (/* DEBUG */ 0) - { - debug_draw_box(buf, bbox*matrix, 0, 0, 0.0); - } - } - } + converter.apply(geom); } } } } - template void agg_renderer::process(markers_symbolizer const&, mapnik::feature_impl &, proj_transform const&); From 8e2774fe84cb0cd2cad31d1112d51d9f0ac5bb17 Mon Sep 17 00:00:00 2001 From: artemp Date: Thu, 19 Jul 2012 16:59:33 +0100 Subject: [PATCH 095/133] + remove debug output --- src/agg/process_markers_symbolizer.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/agg/process_markers_symbolizer.cpp b/src/agg/process_markers_symbolizer.cpp index 61710d476..eb10134d3 100644 --- a/src/agg/process_markers_symbolizer.cpp +++ b/src/agg/process_markers_symbolizer.cpp @@ -88,15 +88,13 @@ struct markers_rasterizer_dispatch void add_path(T & path) { marker_placement_e placement_method = sym_.get_marker_placement(); -// std::cout << "add_path called -> " << placement_method << std::endl; -// std::cout << typeid(path).name() << std::endl; + if (placement_method == MARKER_POINT_PLACEMENT) { double x,y; path.rewind(0); label_interior_position(path, x, y); -// std::cout << "pos -> " << x << "," << y << std::endl; agg::trans_affine matrix = marker_trans_; matrix.translate(x,y); box2d transformed_bbox = bbox_ * matrix; From 4625e509b464eb75d9875edd0ec9c5c8c6a41bb1 Mon Sep 17 00:00:00 2001 From: artemp Date: Thu, 19 Jul 2012 17:10:27 +0100 Subject: [PATCH 096/133] + rename vertex() back to get_vertex() to avoid g++ getting confused --- include/mapnik/geometry.hpp | 4 ++-- include/mapnik/util/vertex_iterator.hpp | 2 +- include/mapnik/vertex_vector.hpp | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/include/mapnik/geometry.hpp b/include/mapnik/geometry.hpp index a27c31fba..20356dc84 100644 --- a/include/mapnik/geometry.hpp +++ b/include/mapnik/geometry.hpp @@ -123,12 +123,12 @@ public: unsigned vertex(double* x, double* y) const { - return cont_.vertex(itr_++,x,y); + return cont_.get_vertex(itr_++,x,y); } unsigned vertex(std::size_t index, double* x, double* y) const { - return cont_.vertex(index, x, y); + return cont_.get_vertex(index, x, y); } void rewind(unsigned ) const diff --git a/include/mapnik/util/vertex_iterator.hpp b/include/mapnik/util/vertex_iterator.hpp index 2d957ef33..5cc794078 100644 --- a/include/mapnik/util/vertex_iterator.hpp +++ b/include/mapnik/util/vertex_iterator.hpp @@ -63,7 +63,7 @@ namespace mapnik { namespace util { void increment() { - boost::get<0>(v_) = vertices_->vertex(pos_++, &boost::get<1>(v_), &boost::get<2>(v_)); + boost::get<0>(v_) = vertices_->get_vertex(pos_++, &boost::get<1>(v_), &boost::get<2>(v_)); } bool equal( vertex_iterator const& other) const diff --git a/include/mapnik/vertex_vector.hpp b/include/mapnik/vertex_vector.hpp index 97139941b..85bcd8857 100644 --- a/include/mapnik/vertex_vector.hpp +++ b/include/mapnik/vertex_vector.hpp @@ -105,7 +105,7 @@ public: *vertex = y; ++pos_; } - unsigned vertex(unsigned pos,coord_type* x,coord_type* y) const + unsigned get_vertex(unsigned pos,coord_type* x,coord_type* y) const { if (pos >= pos_) return SEG_END; unsigned block = pos >> block_shift; From e0c2304d42924891538f61f47f0d29f98d57ee17 Mon Sep 17 00:00:00 2001 From: artemp Date: Thu, 19 Jul 2012 18:44:29 +0100 Subject: [PATCH 097/133] + store size by value --- include/mapnik/markers_placement.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/mapnik/markers_placement.hpp b/include/mapnik/markers_placement.hpp index bf4f70aa9..a0828caba 100644 --- a/include/mapnik/markers_placement.hpp +++ b/include/mapnik/markers_placement.hpp @@ -64,7 +64,7 @@ public: bool get_point(double & x, double & y, double & angle, bool add_to_detector = true); private: Locator &locator_; - box2d const& size_; + box2d size_; agg::trans_affine tr_; Detector &detector_; double spacing_; From 7b3baee3a1299c6f47f5c20d2de571dbff02246d Mon Sep 17 00:00:00 2001 From: Rich Wareham Date: Thu, 19 Jul 2012 19:03:34 +0100 Subject: [PATCH 098/133] python bindings: export Query.resolution property as a tuple Although the mapnik::query class is exposed to the Python bindings, the resolution attribute is a raw boost::tuple. If you attempt to access this tuple from Python, boost complains strongly. This patch adds the required magic to marshal the raw boost::tuple which is query::resolution_type into an honest-to-goodness Python tuple. --- bindings/python/mapnik_query.cpp | 18 +++++++++++++++++ tests/python_tests/query_test.py | 33 ++++++++++++++++++++++++++++++++ 2 files changed, 51 insertions(+) create mode 100644 tests/python_tests/query_test.py diff --git a/bindings/python/mapnik_query.cpp b/bindings/python/mapnik_query.cpp index f2b5c368f..cd49ef967 100644 --- a/bindings/python/mapnik_query.cpp +++ b/bindings/python/mapnik_query.cpp @@ -30,6 +30,8 @@ using mapnik::query; using mapnik::box2d; +namespace python = boost::python; + struct query_pickle_suite : boost::python::pickle_suite { static boost::python::tuple @@ -39,10 +41,26 @@ struct query_pickle_suite : boost::python::pickle_suite } }; +struct resolution_to_tuple +{ + static PyObject* convert(query::resolution_type const& x) + { + python::object tuple(python::make_tuple(x.get<0>(), x.get<1>())); + return python::incref(tuple.ptr()); + } + + static PyTypeObject const* get_pytype() + { + return &PyTuple_Type; + } +}; + void export_query() { using namespace boost::python; + to_python_converter (); + class_("Query", "a spatial query data object", init,query::resolution_type const&,double>() ) .def(init >()) diff --git a/tests/python_tests/query_test.py b/tests/python_tests/query_test.py new file mode 100644 index 000000000..ec636da09 --- /dev/null +++ b/tests/python_tests/query_test.py @@ -0,0 +1,33 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +import os, mapnik + +from nose.tools import * +from utilities import execution_path + +def setup(): + # All of the paths used are relative, if we run the tests + # from another directory we need to chdir() + os.chdir(execution_path('.')) + +def test_query_init(): + bbox = (-180, -90, 180, 90) + query = mapnik.Query(mapnik.Box2d(*bbox)) + r = query.resolution + assert_almost_equal(r[0], 1.0, places=7) + assert_almost_equal(r[1], 1.0, places=7) + +# Converting *from* tuples *to* resolutions is not yet supported +@raises(TypeError) +def test_query_resolution(): + bbox = (-180, -90, 180, 90) + init_res = (4.5, 6.7) + query = mapnik.Query(mapnik.Box2d(*bbox), init_res) + r = query.resolution + assert_almost_equal(r[0], init_res[0], places=7) + assert_almost_equal(r[1], init_res[1], places=7) + +if __name__ == "__main__": + setup() + [eval(run)() for run in dir() if 'test_' in run] From 516f7c75b191ccc7d75269dc0d5a162294d0ba20 Mon Sep 17 00:00:00 2001 From: artemp Date: Fri, 20 Jul 2012 12:28:25 +0100 Subject: [PATCH 099/133] + expose geometry type in expression grammar to allow following filter expressions : [mapnik::geometry_type] = Polygon (#546) --- include/mapnik/attribute.hpp | 21 +++++++++++++++++++++ include/mapnik/attribute_collector.hpp | 5 +++++ include/mapnik/expression_evaluator.hpp | 4 ++++ include/mapnik/expression_grammar.hpp | 24 +++++++++++++++++++----- include/mapnik/expression_node.hpp | 1 + src/expression_string.cpp | 5 +++++ 6 files changed, 55 insertions(+), 5 deletions(-) diff --git a/include/mapnik/attribute.hpp b/include/mapnik/attribute.hpp index b38292c48..a9ae97169 100644 --- a/include/mapnik/attribute.hpp +++ b/include/mapnik/attribute.hpp @@ -25,6 +25,9 @@ // mapnik #include +#include +// boost +#include // stl #include @@ -44,6 +47,24 @@ struct attribute std::string const& name() const { return name_;} }; + +struct geometry_type_attribute +{ + template + V value(F const& f) const + { + int result = 0; + + geometry_container::const_iterator itr = f.paths().begin(); + geometry_container::const_iterator end = f.paths().end(); + for ( ; itr != end; ++itr) + { + result = itr->type(); + } + return result; + } +}; + } #endif // MAPNIK_ATTRIBUTE_HPP diff --git a/include/mapnik/attribute_collector.hpp b/include/mapnik/attribute_collector.hpp index 4cba3a09b..f814d1ac5 100644 --- a/include/mapnik/attribute_collector.hpp +++ b/include/mapnik/attribute_collector.hpp @@ -47,6 +47,11 @@ struct expression_attributes : boost::static_visitor boost::ignore_unused_variable_warning(x); } + void operator() (geometry_type_attribute const& type) const + { + // do nothing + } + void operator() (attribute const& attr) const { names_.insert(attr.name()); diff --git a/include/mapnik/expression_evaluator.hpp b/include/mapnik/expression_evaluator.hpp index a4d199012..e23da962f 100644 --- a/include/mapnik/expression_evaluator.hpp +++ b/include/mapnik/expression_evaluator.hpp @@ -50,6 +50,10 @@ struct evaluate : boost::static_visitor return attr.value(feature_); } + value_type operator() (geometry_type_attribute const& attr) const + { + return attr.value(feature_); + } value_type operator() (binary_node const & x) const { diff --git a/include/mapnik/expression_grammar.hpp b/include/mapnik/expression_grammar.hpp index c74b70d47..8f11aea55 100644 --- a/include/mapnik/expression_grammar.hpp +++ b/include/mapnik/expression_grammar.hpp @@ -29,7 +29,6 @@ // boost #include -#include #include #include @@ -123,6 +122,18 @@ struct regex_replace_impl mapnik::transcoder const& tr_; }; +struct geometry_types : qi::symbols +{ + geometry_types() + { + add + ("point",1) + ("line", 2) + ("polygon",3) + ; + } +}; + template struct expression_grammar : qi::grammar { @@ -150,7 +161,7 @@ struct expression_grammar : qi::grammar using qi::hex; using qi::omit; using standard_wide::char_; - + using standard_wide::no_case; expr = logical_expr.alias(); logical_expr = not_expr [_val = _1] @@ -221,10 +232,12 @@ struct expression_grammar : qi::grammar primary_expr = strict_double [_val = _1] | int_ [_val = _1] - | lit("true") [_val = true] - | lit("false") [_val = false] - | lit("null") [_val = value_null() ] + | no_case[lit("true")] [_val = true] + | no_case[lit("false")] [_val = false] + | no_case[lit("null")] [_val = value_null() ] + | no_case[geom_type][_val = _1 ] | ustring [_val = unicode_(_1) ] + | lit("[mapnik::geometry_type]")[_val = construct()] | attr [_val = construct( _1 ) ] | '(' >> expr [_val = _1 ] >> ')' ; @@ -270,6 +283,7 @@ struct expression_grammar : qi::grammar qi::rule > ustring; qi::symbols unesc_char; qi::rule quote_char; + geometry_types geom_type; }; } // namespace diff --git a/include/mapnik/expression_node.hpp b/include/mapnik/expression_node.hpp index a123297c5..da5f7e2d9 100644 --- a/include/mapnik/expression_node.hpp +++ b/include/mapnik/expression_node.hpp @@ -174,6 +174,7 @@ typedef mapnik::value value_type; typedef boost::variant < value_type, attribute, +geometry_type_attribute, boost::recursive_wrapper >, boost::recursive_wrapper >, boost::recursive_wrapper >, diff --git a/src/expression_string.cpp b/src/expression_string.cpp index 231e7a5d5..87a082af8 100644 --- a/src/expression_string.cpp +++ b/src/expression_string.cpp @@ -50,6 +50,11 @@ struct expression_string : boost::static_visitor str_ += "]"; } + void operator() (geometry_type_attribute const& attr) const + { + str_ += "[mapnik::geometry_type]"; + } + template void operator() (binary_node const& x) const { From 40d1e5c57e69a8ef6a82714e63b5ea71bcf18a53 Mon Sep 17 00:00:00 2001 From: artemp Date: Fri, 20 Jul 2012 12:44:25 +0100 Subject: [PATCH 100/133] Merge branch 'master', remote-tracking branch 'origin' From fd209b2958af837a4cb002fcb862c141f78b52d3 Mon Sep 17 00:00:00 2001 From: artemp Date: Fri, 20 Jul 2012 17:32:38 +0100 Subject: [PATCH 101/133] + put labeling routines into its owm 'label' namespace --- include/mapnik/geom_util.hpp | 8 +++++--- src/agg/process_point_symbolizer.cpp | 3 +-- src/cairo_renderer.cpp | 2 +- src/grid/process_point_symbolizer.cpp | 3 +-- src/symbolizer_helpers.cpp | 4 ++-- 5 files changed, 10 insertions(+), 10 deletions(-) diff --git a/include/mapnik/geom_util.hpp b/include/mapnik/geom_util.hpp index 4d90ae380..808b34b0f 100644 --- a/include/mapnik/geom_util.hpp +++ b/include/mapnik/geom_util.hpp @@ -263,6 +263,8 @@ bool middle_point(PathType & path, double & x, double & y) return true; } +namespace label { + template bool centroid(PathType & path, double & x, double & y) { @@ -347,10 +349,10 @@ bool hit_test(PathType & path, double x, double y, double tol) } template -void label_interior_position(PathType & path, double & x, double & y) +void interior_position(PathType & path, double & x, double & y) { // start with the centroid - centroid(path, x,y); + label::centroid(path, x,y); // if we are not a polygon, or the default is within the polygon we are done if (hit_test(path,x,y,0.001)) @@ -417,6 +419,6 @@ void label_interior_position(PathType & path, double & x, double & y) } } -} +}} #endif // MAPNIK_GEOM_UTIL_HPP diff --git a/src/agg/process_point_symbolizer.cpp b/src/agg/process_point_symbolizer.cpp index 0127c3460..c2b7b7988 100644 --- a/src/agg/process_point_symbolizer.cpp +++ b/src/agg/process_point_symbolizer.cpp @@ -82,7 +82,7 @@ void agg_renderer::process(point_symbolizer const& sym, double y; double z=0; if (sym.get_point_placement() == CENTROID_POINT_PLACEMENT) - centroid(geom, x, y); + label::centroid(geom, x, y); else label_interior_position(geom ,x, y); @@ -119,4 +119,3 @@ template void agg_renderer::process(point_symbolizer const&, proj_transform const&); } - diff --git a/src/cairo_renderer.cpp b/src/cairo_renderer.cpp index 518c613e7..15ec68eb7 100644 --- a/src/cairo_renderer.cpp +++ b/src/cairo_renderer.cpp @@ -1158,7 +1158,7 @@ void cairo_renderer_base::process(point_symbolizer const& sym, double z = 0; if (sym.get_point_placement() == CENTROID_POINT_PLACEMENT) - centroid(geom, x, y); + label::centroid(geom, x, y); else label_interior_position(geom, x, y); diff --git a/src/grid/process_point_symbolizer.cpp b/src/grid/process_point_symbolizer.cpp index 211a3035d..c2cb15fe2 100644 --- a/src/grid/process_point_symbolizer.cpp +++ b/src/grid/process_point_symbolizer.cpp @@ -74,7 +74,7 @@ void grid_renderer::process(point_symbolizer const& sym, double y; double z=0; if (sym.get_point_placement() == CENTROID_POINT_PLACEMENT) - centroid(geom, x, y); + label::centroid(geom, x, y); else label_interior_position(geom, x, y); @@ -105,4 +105,3 @@ template void grid_renderer::process(point_symbolizer const&, proj_transform const&); } - diff --git a/src/symbolizer_helpers.cpp b/src/symbolizer_helpers.cpp index f54e039fb..1cf014bb9 100644 --- a/src/symbolizer_helpers.cpp +++ b/src/symbolizer_helpers.cpp @@ -244,11 +244,11 @@ void text_symbolizer_helper::initialize_points() { if (how_placed == POINT_PLACEMENT) { - centroid(geom, label_x, label_y); + label::centroid(geom, label_x, label_y); } else if (how_placed == INTERIOR_PLACEMENT) { - label_interior_position(geom, label_x, label_y); + label::interior_position(geom, label_x, label_y); } else { From a968150f6b34d6a25e30d22461b66b6d9da930fb Mon Sep 17 00:00:00 2001 From: Dane Springmeyer Date: Fri, 20 Jul 2012 11:18:33 -0700 Subject: [PATCH 102/133] fix compile after geometry util namespacing --- include/mapnik/hit_test_filter.hpp | 2 +- src/agg/process_markers_symbolizer.cpp | 2 +- src/agg/process_point_symbolizer.cpp | 2 +- src/cairo_renderer.cpp | 4 ++-- src/grid/process_markers_symbolizer.cpp | 2 +- src/grid/process_point_symbolizer.cpp | 2 +- 6 files changed, 7 insertions(+), 7 deletions(-) diff --git a/include/mapnik/hit_test_filter.hpp b/include/mapnik/hit_test_filter.hpp index 483450506..792c8c12e 100644 --- a/include/mapnik/hit_test_filter.hpp +++ b/include/mapnik/hit_test_filter.hpp @@ -42,7 +42,7 @@ public: { BOOST_FOREACH(geometry_type & geom, feature.paths()) { - if (hit_test(geom, x_,y_,tol_)) + if (label::hit_test(geom, x_,y_,tol_)) return true; } return false; diff --git a/src/agg/process_markers_symbolizer.cpp b/src/agg/process_markers_symbolizer.cpp index eb10134d3..ce1fc7310 100644 --- a/src/agg/process_markers_symbolizer.cpp +++ b/src/agg/process_markers_symbolizer.cpp @@ -94,7 +94,7 @@ struct markers_rasterizer_dispatch double x,y; path.rewind(0); - label_interior_position(path, x, y); + label::interior_position(path, x, y); agg::trans_affine matrix = marker_trans_; matrix.translate(x,y); box2d transformed_bbox = bbox_ * matrix; diff --git a/src/agg/process_point_symbolizer.cpp b/src/agg/process_point_symbolizer.cpp index c2b7b7988..d1de3f843 100644 --- a/src/agg/process_point_symbolizer.cpp +++ b/src/agg/process_point_symbolizer.cpp @@ -84,7 +84,7 @@ void agg_renderer::process(point_symbolizer const& sym, if (sym.get_point_placement() == CENTROID_POINT_PLACEMENT) label::centroid(geom, x, y); else - label_interior_position(geom ,x, y); + label::interior_position(geom ,x, y); prj_trans.backward(x,y,z); t_.forward(&x,&y); diff --git a/src/cairo_renderer.cpp b/src/cairo_renderer.cpp index 15ec68eb7..e8120444d 100644 --- a/src/cairo_renderer.cpp +++ b/src/cairo_renderer.cpp @@ -1160,7 +1160,7 @@ void cairo_renderer_base::process(point_symbolizer const& sym, if (sym.get_point_placement() == CENTROID_POINT_PLACEMENT) label::centroid(geom, x, y); else - label_interior_position(geom, x, y); + label::interior_position(geom, x, y); prj_trans.backward(x, y, z); t_.forward(&x, &y); @@ -1438,7 +1438,7 @@ void cairo_renderer_base::process(markers_symbolizer const& sym, double x; double y; double z=0; - label_interior_position(geom, x, y); + label::interior_position(geom, x, y); prj_trans.backward(x,y,z); t_.forward(&x,&y); extent.re_center(x,y); diff --git a/src/grid/process_markers_symbolizer.cpp b/src/grid/process_markers_symbolizer.cpp index 9dae111c6..c3a81468d 100644 --- a/src/grid/process_markers_symbolizer.cpp +++ b/src/grid/process_markers_symbolizer.cpp @@ -128,7 +128,7 @@ void grid_renderer::process(markers_symbolizer const& sym, double x; double y; double z=0; - label_interior_position(geom, x, y); + label::interior_position(geom, x, y); prj_trans.backward(x,y,z); t_.forward(&x,&y); geom_tr.transform(&x,&y); diff --git a/src/grid/process_point_symbolizer.cpp b/src/grid/process_point_symbolizer.cpp index c2cb15fe2..d1689f03b 100644 --- a/src/grid/process_point_symbolizer.cpp +++ b/src/grid/process_point_symbolizer.cpp @@ -76,7 +76,7 @@ void grid_renderer::process(point_symbolizer const& sym, if (sym.get_point_placement() == CENTROID_POINT_PLACEMENT) label::centroid(geom, x, y); else - label_interior_position(geom, x, y); + label::interior_position(geom, x, y); prj_trans.backward(x,y,z); t_.forward(&x,&y); From 942fa1233ff5fca2d0dcaed5eba454c0cf4c9863 Mon Sep 17 00:00:00 2001 From: Dane Springmeyer Date: Fri, 20 Jul 2012 12:29:18 -0700 Subject: [PATCH 103/133] add wkb test that currently crashes - refs #1305, #1132 --- tests/python_tests/geometry_io_test.py | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/tests/python_tests/geometry_io_test.py b/tests/python_tests/geometry_io_test.py index b2bce104c..1863f2c40 100644 --- a/tests/python_tests/geometry_io_test.py +++ b/tests/python_tests/geometry_io_test.py @@ -5,6 +5,7 @@ import os,sys from utilities import execution_path from utilities import Todo import mapnik +from binascii import unhexlify def setup(): # All of the paths used are relative, if we run the tests @@ -27,6 +28,22 @@ wkts = [ [2,"MULTIPOLYGON(((-178.32319 71.518365,-178.321586 71.518439,-178.259635 71.510688,-178.304862 71.513129,-178.32319 71.518365)),((-178.32319 71.518365,-178.341544 71.517524,-178.32244 71.505439,-178.215323 71.478034,-178.193473 71.47663,-178.147757 71.485175,-178.124442 71.481879,-178.005729 71.448615,-178.017203 71.441413,-178.054191 71.428778,-178.047049 71.425727,-178.033439 71.417792,-178.026236 71.415107,-178.030082 71.413459,-178.039908 71.40766,-177.970878 71.39643,-177.779837 71.333197,-177.718375 71.305243,-177.706412 71.3039,-177.68212 71.304877,-177.670279 71.301825,-177.655387 71.293158,-177.587577 71.285956,-177.548575 71.294867,-177.531119 71.296332,-177.51409 71.293402,-177.498649 71.284735,-177.506217 71.268622,-177.486991 71.258734,-177.459708 71.249884,-177.443412 71.237006,-177.445914 71.222663,-177.457755 71.209357,-177.507804 71.173774,-177.581168 71.147589,-177.637626 71.117011,-177.684134 71.110968,-177.751883 71.092963,-177.819266 71.084662,-177.877677 71.052558,-177.930472 71.041449,-178.206595 71.038398,-178.310111 71.013617,-178.875907 70.981024,-178.980277 70.95069,-179.342093 70.908026,-179.336234 70.911078,-179.322257 70.921698,-179.364493 70.930243,-179.457511 70.915534,-179.501212 70.919684,-179.666007 70.965461,-179.853385 70.979438,-179.888785 70.993598,-179.907523 70.996772,-179.999989 70.992011,-179.999989 71.024848,-179.999989 71.058661,-179.999989 71.126166,-179.999989 71.187018,-179.999989 71.224189,-179.999989 71.27497,-179.999989 71.312079,-179.999989 71.356024,-179.999989 71.410041,-179.999989 71.487799,-179.999989 71.536689,-179.862845 71.538642,-179.912223 71.555854,-179.900748 71.558478,-179.798819 71.569098,-179.757438 71.583197,-179.735953 71.586432,-179.715445 71.583258,-179.697501 71.577338,-179.678702 71.573676,-179.610831 71.585211,-179.372062 71.569098,-179.326774 71.555487,-179.306815 71.557563,-179.287162 71.562934,-179.24285 71.569098,-179.204642 71.583197,-179.074576 71.600043,-178.395438 71.539008,-178.32319 71.518365)))"] ] +wkbs = [ + [ + 2,"GEOMETRYCOLLECTION(MULTILINESTRING((10 10,20 20,10 40),(40 40,30 30,40 20,30 10)),LINESTRING EMPTY)", + '010700000002000000010500000002000000010200000003000000000000000000244000000000000024400000000000003440000000000000344000000000000024400000000000004440010200000004000000000000000000444000000000000044400000000000003e400000000000003e40000000000000444000000000000034400000000000003e400000000000002440010200000000000000' + ], + [ 0,"select 'LINESTRING EMPTY'::geometry;", '010200000000000000' ], + [ 1,"select 'Point(0 0)'::geometry;", '010100000000000000000000000000000000000000' ], + [ 0, "select 'Point EMPTY'::geometry;", '010400000000000000'] +] + + +def test_wkb_with_empty(): + for wkb in wkbs: + path = mapnik.Path() + path.add_wkb(unhexlify(wkb[2])) + #eq_(wkb[0],path.add_wkb(unhexlify(wkb[2]))) def compare_wkb_from_wkt(wkt,num=None): From 65b03a323081d6f5ed4826fe2ed89a9250341a64 Mon Sep 17 00:00:00 2001 From: Dane Springmeyer Date: Fri, 20 Jul 2012 13:56:21 -0700 Subject: [PATCH 104/133] scons: try to unbreak boost_python lib check on linux --- SConstruct | 106 ++++++++++++++++++++++++++--------------------------- 1 file changed, 52 insertions(+), 54 deletions(-) diff --git a/SConstruct b/SConstruct index 0a5053b5a..60c68a83b 100644 --- a/SConstruct +++ b/SConstruct @@ -1331,9 +1331,60 @@ if not preconfigured: color_print(4,'Not building with cairo support, pass CAIRO=True to enable') if 'python' in env['BINDINGS']: + if not os.access(env['PYTHON'], os.X_OK): + color_print(1,"Cannot run python interpreter at '%s', make sure that you have the permissions to execute it." % env['PYTHON']) + Exit(1) py3 = 'True' in os.popen('''%s -c "import sys as s;s.stdout.write(str(s.version_info[0] == 3))"''' % env['PYTHON']).read().strip() + if py3: + sys_prefix = '''%s -c "import sys; print(sys.prefix)"''' % env['PYTHON'] + else: + sys_prefix = '''%s -c "import sys; print sys.prefix"''' % env['PYTHON'] + env['PYTHON_SYS_PREFIX'] = call(sys_prefix) + + if HAS_DISTUTILS: + if py3: + sys_version = '''%s -c "from distutils.sysconfig import get_python_version; print(get_python_version())"''' % env['PYTHON'] + else: + sys_version = '''%s -c "from distutils.sysconfig import get_python_version; print get_python_version()"''' % env['PYTHON'] + env['PYTHON_VERSION'] = call(sys_version) + + if py3: + py_includes = '''%s -c "from distutils.sysconfig import get_python_inc; print(get_python_inc())"''' % env['PYTHON'] + else: + py_includes = '''%s -c "from distutils.sysconfig import get_python_inc; print get_python_inc()"''' % env['PYTHON'] + env['PYTHON_INCLUDES'] = call(py_includes) + + # Note: we use the plat_specific argument here to make sure to respect the arch-specific site-packages location + if py3: + site_packages = '''%s -c "from distutils.sysconfig import get_python_lib; print(get_python_lib(plat_specific=True))"''' % env['PYTHON'] + else: + site_packages = '''%s -c "from distutils.sysconfig import get_python_lib; print get_python_lib(plat_specific=True)"''' % env['PYTHON'] + env['PYTHON_SITE_PACKAGES'] = call(site_packages) + else: + env['PYTHON_SYS_PREFIX'] = os.popen('''%s -c "import sys; print sys.prefix"''' % env['PYTHON']).read().strip() + env['PYTHON_VERSION'] = os.popen('''%s -c "import sys; print sys.version"''' % env['PYTHON']).read()[0:3] + env['PYTHON_INCLUDES'] = env['PYTHON_SYS_PREFIX'] + '/include/python' + env['PYTHON_VERSION'] + env['PYTHON_SITE_PACKAGES'] = env['DESTDIR'] + os.path.sep + env['PYTHON_SYS_PREFIX'] + os.path.sep + env['LIBDIR_SCHEMA'] + '/python' + env['PYTHON_VERSION'] + '/site-packages/' + + # if user-requested custom prefix fall back to manual concatenation for building subdirectories + if env['PYTHON_PREFIX']: + py_relative_install = env['LIBDIR_SCHEMA'] + '/python' + env['PYTHON_VERSION'] + '/site-packages/' + env['PYTHON_INSTALL_LOCATION'] = env['DESTDIR'] + os.path.sep + env['PYTHON_PREFIX'] + os.path.sep + py_relative_install + else: + env['PYTHON_INSTALL_LOCATION'] = env['DESTDIR'] + os.path.sep + env['PYTHON_SITE_PACKAGES'] + + if py3: + is_64_bit = '''%s -c "import sys; print(sys.maxsize == 9223372036854775807)"''' % env['PYTHON'] + else: + is_64_bit = '''%s -c "import sys; print sys.maxint == 9223372036854775807"''' % env['PYTHON'] + + if is_64_bit: + env['PYTHON_IS_64BIT'] = True + else: + env['PYTHON_IS_64BIT'] = False + if py3 and env['BOOST_PYTHON_LIB'] == 'boost_python': env['BOOST_PYTHON_LIB'] = 'boost_python3%s' % env['BOOST_APPEND'] elif env['BOOST_PYTHON_LIB'] == 'boost_python': @@ -1343,7 +1394,7 @@ if not preconfigured: color_print(1,'Could not find required header files for boost python') env['MISSING_DEPS'].append('boost python') - if not conf.CheckLibWithHeader(libs=[env['BOOST_PYTHON_LIB']], header='boost/python/detail/config.hpp', language='C++'): + if not conf.CheckLibWithHeader(libs=[env['BOOST_PYTHON_LIB'],'python%s' % env['PYTHON_VERSION']], header='boost/python/detail/config.hpp', language='C++'): color_print(1, 'Could not find library "%s" for boost python bindings' % env['BOOST_PYTHON_LIB']) # failing on launchpad, so let's make it a warning for now #env['MISSING_DEPS'].append('boost python') @@ -1481,60 +1532,7 @@ if not preconfigured: env.Append(CXXFLAGS = '-fcatch-undefined-behavior -ftrapv -fwrapv') if 'python' in env['BINDINGS']: - if not os.access(env['PYTHON'], os.X_OK): - color_print(1,"Cannot run python interpreter at '%s', make sure that you have the permissions to execute it." % env['PYTHON']) - Exit(1) - - if py3: - sys_prefix = '''%s -c "import sys; print(sys.prefix)"''' % env['PYTHON'] - else: - sys_prefix = '''%s -c "import sys; print sys.prefix"''' % env['PYTHON'] - env['PYTHON_SYS_PREFIX'] = call(sys_prefix) - - if HAS_DISTUTILS: - if py3: - sys_version = '''%s -c "from distutils.sysconfig import get_python_version; print(get_python_version())"''' % env['PYTHON'] - else: - sys_version = '''%s -c "from distutils.sysconfig import get_python_version; print get_python_version()"''' % env['PYTHON'] - env['PYTHON_VERSION'] = call(sys_version) - - if py3: - py_includes = '''%s -c "from distutils.sysconfig import get_python_inc; print(get_python_inc())"''' % env['PYTHON'] - else: - py_includes = '''%s -c "from distutils.sysconfig import get_python_inc; print get_python_inc()"''' % env['PYTHON'] - env['PYTHON_INCLUDES'] = call(py_includes) - - # Note: we use the plat_specific argument here to make sure to respect the arch-specific site-packages location - if py3: - site_packages = '''%s -c "from distutils.sysconfig import get_python_lib; print(get_python_lib(plat_specific=True))"''' % env['PYTHON'] - else: - site_packages = '''%s -c "from distutils.sysconfig import get_python_lib; print get_python_lib(plat_specific=True)"''' % env['PYTHON'] - env['PYTHON_SITE_PACKAGES'] = call(site_packages) - else: - env['PYTHON_SYS_PREFIX'] = os.popen('''%s -c "import sys; print sys.prefix"''' % env['PYTHON']).read().strip() - env['PYTHON_VERSION'] = os.popen('''%s -c "import sys; print sys.version"''' % env['PYTHON']).read()[0:3] - env['PYTHON_INCLUDES'] = env['PYTHON_SYS_PREFIX'] + '/include/python' + env['PYTHON_VERSION'] - env['PYTHON_SITE_PACKAGES'] = env['DESTDIR'] + os.path.sep + env['PYTHON_SYS_PREFIX'] + os.path.sep + env['LIBDIR_SCHEMA'] + '/python' + env['PYTHON_VERSION'] + '/site-packages/' - - # if user-requested custom prefix fall back to manual concatenation for building subdirectories - if env['PYTHON_PREFIX']: - py_relative_install = env['LIBDIR_SCHEMA'] + '/python' + env['PYTHON_VERSION'] + '/site-packages/' - env['PYTHON_INSTALL_LOCATION'] = env['DESTDIR'] + os.path.sep + env['PYTHON_PREFIX'] + os.path.sep + py_relative_install - else: - env['PYTHON_INSTALL_LOCATION'] = env['DESTDIR'] + os.path.sep + env['PYTHON_SITE_PACKAGES'] - - if py3: - is_64_bit = '''%s -c "import sys; print(sys.maxsize == 9223372036854775807)"''' % env['PYTHON'] - else: - is_64_bit = '''%s -c "import sys; print sys.maxint == 9223372036854775807"''' % env['PYTHON'] - - if is_64_bit: - env['PYTHON_IS_64BIT'] = True - else: - env['PYTHON_IS_64BIT'] = False - majver, minver = env['PYTHON_VERSION'].split('.') - # we don't want the includes it in the main environment... # as they are later set in the python build.py # ugly hack needed until we have env specific conf From b0cb5b04deea949eb7b63e62a6e6bff2f1fad285 Mon Sep 17 00:00:00 2001 From: Dane Springmeyer Date: Fri, 20 Jul 2012 14:57:20 -0700 Subject: [PATCH 105/133] more empty geometry wkb tests - refs #1305, #1333 --- tests/python_tests/geometry_io_test.py | 35 +++++++++++++++++++------- 1 file changed, 26 insertions(+), 9 deletions(-) diff --git a/tests/python_tests/geometry_io_test.py b/tests/python_tests/geometry_io_test.py index 1863f2c40..b54f70f8c 100644 --- a/tests/python_tests/geometry_io_test.py +++ b/tests/python_tests/geometry_io_test.py @@ -29,21 +29,38 @@ wkts = [ ] wkbs = [ - [ - 2,"GEOMETRYCOLLECTION(MULTILINESTRING((10 10,20 20,10 40),(40 40,30 30,40 20,30 10)),LINESTRING EMPTY)", - '010700000002000000010500000002000000010200000003000000000000000000244000000000000024400000000000003440000000000000344000000000000024400000000000004440010200000004000000000000000000444000000000000044400000000000003e400000000000003e40000000000000444000000000000034400000000000003e400000000000002440010200000000000000' + [ 0, "select 'Point EMPTY'::geometry;", '010400000000000000'], + [ 0, "select 'MULTIPOINT EMPTY'::geometry;", '010400000000000000'], + [ 0, "select 'LINESTRING EMPTY'::geometry;", '010200000000000000'], + [ 0, "select 'MULTILINESTRING EMPTY'::geometry;", '010500000000000000'], + [ 0, "select 'Polygon EMPTY'::geometry;", '010300000000000000'], + [ 0, "select 'MULTIPOLYGON EMPTY'::geometry;", '010600000000000000'], + [ 0, "select 'TRIANGLE EMPTY'::geometry;", '011100000000000000'], + + [ 0, "select 'CircularString EMPTY'::geometry;", '010800000000000000'], + [ 0, "select 'CurvePolygon EMPTY'::geometry;", '010A00000000000000'], + [ 0, "select 'CompoundCurve EMPTY'::geometry;", '010900000000000000'], + [ 0, "select 'MultiCurve EMPTY'::geometry;", '010B00000000000000'], + + [ 0, "select 'MultiSurface EMPTY'::geometry;", '010C00000000000000'], + [ 0, "select 'PolyhedralSurface EMPTY'::geometry;", '010F00000000000000'], + [ 0, "select 'TIM EMPTY'::geometry;", '011000000000000000'], + [ 0, "select 'GEOMETRYCOLLECTION EMPTY'::geometry;", '010700000000000000'], + [ 2,"GEOMETRYCOLLECTION(MULTILINESTRING((10 10,20 20,10 40),(40 40,30 30,40 20,30 10)),LINESTRING EMPTY)", '010700000002000000010500000002000000010200000003000000000000000000244000000000000024400000000000003440000000000000344000000000000024400000000000004440010200000004000000000000000000444000000000000044400000000000003e400000000000003e40000000000000444000000000000034400000000000003e400000000000002440010200000000000000' ], - [ 0,"select 'LINESTRING EMPTY'::geometry;", '010200000000000000' ], - [ 1,"select 'Point(0 0)'::geometry;", '010100000000000000000000000000000000000000' ], - [ 0, "select 'Point EMPTY'::geometry;", '010400000000000000'] + [ 0, "GEOMETRYCOLLECTION(LINESTRING EMPTY,LINESTRING EMPTY)", '010700000000000000'], + [ 0, "GEOMETRYCOLLECTION(POINT EMPTY,POINT EMPTY)", '010700000000000000'], + [ 1, "GEOMETRYCOLLECTION(POINT EMPTY,POINT(0 0))", '010700000002000000010400000000000000010100000000000000000000000000000000000000'], + [ 1, "GEOMETRYCOLLECTION(POINT EMPTY,MULTIPOINT(0 0))", '010700000002000000010400000000000000010400000001000000010100000000000000000000000000000000000000'], + [ 0, "select 'LINESTRING EMPTY'::geometry;", '010200000000000000' ], + [ 1, "select 'Point(0 0)'::geometry;", '010100000000000000000000000000000000000000' ], ] - -def test_wkb_with_empty(): +def test_wkb_parsing(): for wkb in wkbs: path = mapnik.Path() path.add_wkb(unhexlify(wkb[2])) - #eq_(wkb[0],path.add_wkb(unhexlify(wkb[2]))) + eq_(wkb[0],len(path)) def compare_wkb_from_wkt(wkt,num=None): From e36081a5c08f67620afcde2cdf57d4742115546c Mon Sep 17 00:00:00 2001 From: Dane Springmeyer Date: Fri, 20 Jul 2012 15:09:01 -0700 Subject: [PATCH 106/133] change geometry_utils::from_wkb to return a bool that signifies if at least one wkb path was parsed - refs #1333 and #1305 --- bindings/python/mapnik_geometry.cpp | 4 +- include/mapnik/wkb.hpp | 2 +- plugins/input/geos/geos_featureset.cpp | 6 +- plugins/input/postgis/postgis_featureset.cpp | 12 +-- plugins/input/sqlite/sqlite_datasource.cpp | 18 ++-- plugins/input/sqlite/sqlite_featureset.cpp | 3 +- plugins/input/sqlite/sqlite_utils.hpp | 97 ++++++++++---------- src/wkb.cpp | 8 +- utils/pgsql2sqlite/pgsql2sqlite.hpp | 4 +- 9 files changed, 77 insertions(+), 77 deletions(-) diff --git a/bindings/python/mapnik_geometry.cpp b/bindings/python/mapnik_geometry.cpp index bc261e153..5731f3098 100644 --- a/bindings/python/mapnik_geometry.cpp +++ b/bindings/python/mapnik_geometry.cpp @@ -60,9 +60,9 @@ void add_wkt_impl(path_type& p, std::string const& wkt) if (!result) throw std::runtime_error("Failed to parse WKT"); } -void add_wkb_impl(path_type& p, std::string const& wkb) +bool add_wkb_impl(path_type& p, std::string const& wkb) { - mapnik::geometry_utils::from_wkb(p, wkb.c_str(), wkb.size()); + return mapnik::geometry_utils::from_wkb(p, wkb.c_str(), wkb.size()); } boost::shared_ptr from_wkt_impl(std::string const& wkt) diff --git a/include/mapnik/wkb.hpp b/include/mapnik/wkb.hpp index a7284bb30..38fa2b259 100644 --- a/include/mapnik/wkb.hpp +++ b/include/mapnik/wkb.hpp @@ -55,7 +55,7 @@ class MAPNIK_DECL geometry_utils : private boost::noncopyable { public: - static void from_wkb (boost::ptr_vector& paths, + static bool from_wkb (boost::ptr_vector& paths, const char* wkb, unsigned size, wkbFormat format = wkbGeneric); diff --git a/plugins/input/geos/geos_featureset.cpp b/plugins/input/geos/geos_featureset.cpp index 6c5ab0ef8..d3058a989 100644 --- a/plugins/input/geos/geos_featureset.cpp +++ b/plugins/input/geos/geos_featureset.cpp @@ -117,10 +117,10 @@ feature_ptr geos_featureset::next() { feature_ptr feature(feature_factory::create(ctx_,identifier_)); - geometry_utils::from_wkb(feature->paths(), + if (geometry_utils::from_wkb(feature->paths(), wkb.data(), - wkb.size()); - if (field_ != "") + wkb.size()) + && field_ != "") { feature->put(field_name_, tr_->transcode(field_.c_str())); } diff --git a/plugins/input/postgis/postgis_featureset.cpp b/plugins/input/postgis/postgis_featureset.cpp index 7c227894e..5ac6e85f4 100644 --- a/plugins/input/postgis/postgis_featureset.cpp +++ b/plugins/input/postgis/postgis_featureset.cpp @@ -62,7 +62,7 @@ postgis_featureset::postgis_featureset(boost::shared_ptr const& rs, feature_ptr postgis_featureset::next() { - if (rs_->next()) + while (rs_->next()) { // new feature unsigned pos = 1; @@ -107,7 +107,9 @@ feature_ptr postgis_featureset::next() // parse geometry int size = rs_->getFieldLength(0); const char *data = rs_->getValue(0); - geometry_utils::from_wkb(feature->paths(), data, size); + if (!geometry_utils::from_wkb(feature->paths(), data, size)) + continue; + totalGeomSize_ += size; int num_attrs = ctx_->size() + 1; @@ -207,11 +209,7 @@ feature_ptr postgis_featureset::next() } return feature; } - else - { - rs_->close(); - return feature_ptr(); - } + return feature_ptr(); } diff --git a/plugins/input/sqlite/sqlite_datasource.cpp b/plugins/input/sqlite/sqlite_datasource.cpp index bab062485..863dea7a4 100644 --- a/plugins/input/sqlite/sqlite_datasource.cpp +++ b/plugins/input/sqlite/sqlite_datasource.cpp @@ -522,17 +522,19 @@ boost::optional sqlite_datasource::get_geometry_ if (data) { boost::ptr_vector paths; - mapnik::geometry_utils::from_wkb(paths, data, size, mapnik::wkbAuto); - mapnik::util::to_ds_type(paths,result); - if (result) + if (mapnik::geometry_utils::from_wkb(paths, data, size, mapnik::wkbAuto)) { - int type = static_cast(*result); - if (multi_type > 0 && multi_type != type) + mapnik::util::to_ds_type(paths,result); + if (result) { - result.reset(mapnik::datasource::Collection); - return result; + int type = static_cast(*result); + if (multi_type > 0 && multi_type != type) + { + result.reset(mapnik::datasource::Collection); + return result; + } + multi_type = type; } - multi_type = type; } } } diff --git a/plugins/input/sqlite/sqlite_featureset.cpp b/plugins/input/sqlite/sqlite_featureset.cpp index 5e822671d..df2203710 100644 --- a/plugins/input/sqlite/sqlite_featureset.cpp +++ b/plugins/input/sqlite/sqlite_featureset.cpp @@ -75,7 +75,8 @@ feature_ptr sqlite_featureset::next() } feature_ptr feature = feature_factory::create(ctx_,rs_->column_integer(1)); - geometry_utils::from_wkb(feature->paths(), data, size, format_); + if (!geometry_utils::from_wkb(feature->paths(), data, size, format_)) + continue; if (!spatial_index_) { diff --git a/plugins/input/sqlite/sqlite_utils.hpp b/plugins/input/sqlite/sqlite_utils.hpp index d9074d09f..891150506 100644 --- a/plugins/input/sqlite/sqlite_utils.hpp +++ b/plugins/input/sqlite/sqlite_utils.hpp @@ -190,21 +190,22 @@ public: if (data) { boost::ptr_vector paths; - mapnik::geometry_utils::from_wkb(paths, data, size, mapnik::wkbAuto); - for (unsigned i=0; i const& bbox = paths[i].envelope(); - - if (bbox.valid()) + for (unsigned i=0; i const& bbox = paths[i].envelope(); + if (bbox.valid()) { - first = false; - extent = bbox; - } - else - { - extent.expand_to_include(bbox); + if (first) + { + first = false; + extent = bbox; + } + else + { + extent.expand_to_include(bbox); + } } } } @@ -276,24 +277,24 @@ public: if (data) { boost::ptr_vector paths; - mapnik::geometry_utils::from_wkb(paths, data, size, mapnik::wkbAuto); mapnik::box2d bbox; - for (unsigned i=0; icolumn_type(1); if (type_oid != SQLITE_INTEGER) { @@ -303,7 +304,6 @@ public: << "' type was: " << type_oid << ""; throw mapnik::datasource_exception(error_msg.str()); } - const sqlite_int64 pkid = rs->column_integer64(1); ps.bind(pkid); } @@ -314,7 +314,6 @@ public: << rs->column_name(1) << "' == " << rs->column_integer64(1); throw mapnik::datasource_exception(error_msg.str()); } - ps.step_next(); one_success = true; } @@ -365,45 +364,41 @@ public: if (data) { boost::ptr_vector paths; - mapnik::geometry_utils::from_wkb(paths, data, size, mapnik::wkbAuto); - for (unsigned i=0; i const& bbox = paths[i].envelope(); - if (bbox.valid()) + for (unsigned i=0; icolumn_type(1); - if (type_oid != SQLITE_INTEGER) + mapnik::box2d const& bbox = paths[i].envelope(); + if (bbox.valid()) + { + const int type_oid = rs->column_type(1); + if (type_oid != SQLITE_INTEGER) + { + std::ostringstream error_msg; + error_msg << "Sqlite Plugin: invalid type for key field '" + << rs->column_name(1) << "' when creating index " + << "type was: " << type_oid << ""; + throw mapnik::datasource_exception(error_msg.str()); + } + const sqlite_int64 pkid = rs->column_integer64(1); + rtree_type entry = rtree_type(); + entry.pkid = pkid; + entry.bbox = bbox; + rtree_list.push_back(entry); + } + else { std::ostringstream error_msg; - error_msg << "Sqlite Plugin: invalid type for key field '" - << rs->column_name(1) << "' when creating index " - << "type was: " << type_oid << ""; + error_msg << "SQLite Plugin: encountered invalid bbox at '" + << rs->column_name(1) << "' == " << rs->column_integer64(1); throw mapnik::datasource_exception(error_msg.str()); } - - const sqlite_int64 pkid = rs->column_integer64(1); - - rtree_type entry = rtree_type(); - entry.pkid = pkid; - entry.bbox = bbox; - rtree_list.push_back(entry); - - } - else - { - std::ostringstream error_msg; - error_msg << "SQLite Plugin: encountered invalid bbox at '" - << rs->column_name(1) << "' == " << rs->column_integer64(1); - throw mapnik::datasource_exception(error_msg.str()); } } } } } - - static bool create_spatial_index2(std::string const& index_db, std::string const& index_table, std::vector const& rtree_list) diff --git a/src/wkb.cpp b/src/wkb.cpp index f7d9692f3..0551034cd 100644 --- a/src/wkb.cpp +++ b/src/wkb.cpp @@ -431,13 +431,17 @@ private: #endif }; -void geometry_utils::from_wkb (boost::ptr_vector& paths, +bool geometry_utils::from_wkb(boost::ptr_vector& paths, const char* wkb, unsigned size, wkbFormat format) { + unsigned geom_count = paths.size(); wkb_reader reader(wkb, size, format); - return reader.read(paths); + reader.read(paths); + if (paths.size() > geom_count) + return true; + return false; } } diff --git a/utils/pgsql2sqlite/pgsql2sqlite.hpp b/utils/pgsql2sqlite/pgsql2sqlite.hpp index faa3f3e40..2d8583caa 100644 --- a/utils/pgsql2sqlite/pgsql2sqlite.hpp +++ b/utils/pgsql2sqlite/pgsql2sqlite.hpp @@ -281,8 +281,8 @@ void pgsql2sqlite(Connection conn, if (oid == geometry_oid) { mapnik::Feature feat(ctx,pkid); - geometry_utils::from_wkb(feat.paths(),buf,size,wkbGeneric); - if (feat.num_geometries() > 0) + if (geometry_utils::from_wkb(feat.paths(),buf,size,wkbGeneric) + && feat.num_geometries() > 0) { geometry_type const& geom=feat.get_geometry(0); box2d bbox = geom.envelope(); From 537ce09336bc0819f404fbe069e72e68d6e855f0 Mon Sep 17 00:00:00 2001 From: Dane Springmeyer Date: Fri, 20 Jul 2012 15:13:36 -0700 Subject: [PATCH 107/133] also test return value from add_wkb --- tests/python_tests/geometry_io_test.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/tests/python_tests/geometry_io_test.py b/tests/python_tests/geometry_io_test.py index b54f70f8c..d48bf18cd 100644 --- a/tests/python_tests/geometry_io_test.py +++ b/tests/python_tests/geometry_io_test.py @@ -59,7 +59,11 @@ wkbs = [ def test_wkb_parsing(): for wkb in wkbs: path = mapnik.Path() - path.add_wkb(unhexlify(wkb[2])) + success = path.add_wkb(unhexlify(wkb[2])) + if wkb[0] > 0: + eq_(success,True) + else: + eq_(success,False) eq_(wkb[0],len(path)) def compare_wkb_from_wkt(wkt,num=None): From cccb916924285a1bfd4757d85f822b60cf69c8df Mon Sep 17 00:00:00 2001 From: Dane Springmeyer Date: Fri, 20 Jul 2012 15:25:14 -0700 Subject: [PATCH 108/133] cleanup wkb descriptions to be proper wkt --- tests/python_tests/geometry_io_test.py | 36 +++++++++++++------------- 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/tests/python_tests/geometry_io_test.py b/tests/python_tests/geometry_io_test.py index d48bf18cd..1eeef4db6 100644 --- a/tests/python_tests/geometry_io_test.py +++ b/tests/python_tests/geometry_io_test.py @@ -29,31 +29,31 @@ wkts = [ ] wkbs = [ - [ 0, "select 'Point EMPTY'::geometry;", '010400000000000000'], - [ 0, "select 'MULTIPOINT EMPTY'::geometry;", '010400000000000000'], - [ 0, "select 'LINESTRING EMPTY'::geometry;", '010200000000000000'], - [ 0, "select 'MULTILINESTRING EMPTY'::geometry;", '010500000000000000'], - [ 0, "select 'Polygon EMPTY'::geometry;", '010300000000000000'], - [ 0, "select 'MULTIPOLYGON EMPTY'::geometry;", '010600000000000000'], - [ 0, "select 'TRIANGLE EMPTY'::geometry;", '011100000000000000'], + [ 0, "Point EMPTY", '010400000000000000'], + [ 0, "MULTIPOINT EMPTY", '010400000000000000'], + [ 0, "LINESTRING EMPTY", '010200000000000000'], + [ 0, "MULTILINESTRING EMPTY", '010500000000000000'], + [ 0, "Polygon EMPTY", '010300000000000000'], + [ 0, "MULTIPOLYGON EMPTY", '010600000000000000'], + [ 0, "TRIANGLE EMPTY", '011100000000000000'], - [ 0, "select 'CircularString EMPTY'::geometry;", '010800000000000000'], - [ 0, "select 'CurvePolygon EMPTY'::geometry;", '010A00000000000000'], - [ 0, "select 'CompoundCurve EMPTY'::geometry;", '010900000000000000'], - [ 0, "select 'MultiCurve EMPTY'::geometry;", '010B00000000000000'], + [ 0, "CircularString EMPTY", '010800000000000000'], + [ 0, "CurvePolygon EMPTY", '010A00000000000000'], + [ 0, "CompoundCurve EMPTY", '010900000000000000'], + [ 0, "MultiCurve EMPTY", '010B00000000000000'], - [ 0, "select 'MultiSurface EMPTY'::geometry;", '010C00000000000000'], - [ 0, "select 'PolyhedralSurface EMPTY'::geometry;", '010F00000000000000'], - [ 0, "select 'TIM EMPTY'::geometry;", '011000000000000000'], - [ 0, "select 'GEOMETRYCOLLECTION EMPTY'::geometry;", '010700000000000000'], - [ 2,"GEOMETRYCOLLECTION(MULTILINESTRING((10 10,20 20,10 40),(40 40,30 30,40 20,30 10)),LINESTRING EMPTY)", '010700000002000000010500000002000000010200000003000000000000000000244000000000000024400000000000003440000000000000344000000000000024400000000000004440010200000004000000000000000000444000000000000044400000000000003e400000000000003e40000000000000444000000000000034400000000000003e400000000000002440010200000000000000' + [ 0, "MultiSurface EMPTY", '010C00000000000000'], + [ 0, "PolyhedralSurface EMPTY", '010F00000000000000'], + [ 0, "TIM EMPTY", '011000000000000000'], + [ 0, "GEOMETRYCOLLECTION EMPTY", '010700000000000000'], + [ 2, "GEOMETRYCOLLECTION(MULTILINESTRING((10 10,20 20,10 40),(40 40,30 30,40 20,30 10)),LINESTRING EMPTY)", '010700000002000000010500000002000000010200000003000000000000000000244000000000000024400000000000003440000000000000344000000000000024400000000000004440010200000004000000000000000000444000000000000044400000000000003e400000000000003e40000000000000444000000000000034400000000000003e400000000000002440010200000000000000' ], [ 0, "GEOMETRYCOLLECTION(LINESTRING EMPTY,LINESTRING EMPTY)", '010700000000000000'], [ 0, "GEOMETRYCOLLECTION(POINT EMPTY,POINT EMPTY)", '010700000000000000'], [ 1, "GEOMETRYCOLLECTION(POINT EMPTY,POINT(0 0))", '010700000002000000010400000000000000010100000000000000000000000000000000000000'], [ 1, "GEOMETRYCOLLECTION(POINT EMPTY,MULTIPOINT(0 0))", '010700000002000000010400000000000000010400000001000000010100000000000000000000000000000000000000'], - [ 0, "select 'LINESTRING EMPTY'::geometry;", '010200000000000000' ], - [ 1, "select 'Point(0 0)'::geometry;", '010100000000000000000000000000000000000000' ], + [ 0, "LINESTRING EMPTY", '010200000000000000' ], + [ 1, "Point(0 0)", '010100000000000000000000000000000000000000' ], ] def test_wkb_parsing(): From e225eaae4bec83b40beb61fdf5081c516f6ffb4d Mon Sep 17 00:00:00 2001 From: Dane Springmeyer Date: Fri, 20 Jul 2012 18:33:14 -0700 Subject: [PATCH 109/133] add c++ test for exceptions --- tests/cpp_tests/build.py | 3 +- tests/cpp_tests/exceptions_test.cpp | 116 ++++++++++++++++++++++++++++ 2 files changed, 118 insertions(+), 1 deletion(-) create mode 100644 tests/cpp_tests/exceptions_test.cpp diff --git a/tests/cpp_tests/build.py b/tests/cpp_tests/build.py index 3750717fd..69add55d4 100644 --- a/tests/cpp_tests/build.py +++ b/tests/cpp_tests/build.py @@ -8,8 +8,9 @@ test_env = env.Clone() headers = env['CPPPATH'] -libraries = copy(env['LIBMAPNIK_LIBS']) +libraries = copy(env['LIBMAPNIK_LIBS']) libraries.append('mapnik') +libraries.append('sqlite3') test_env.Append(CXXFLAGS='-g') diff --git a/tests/cpp_tests/exceptions_test.cpp b/tests/cpp_tests/exceptions_test.cpp new file mode 100644 index 000000000..e3d0e6eb2 --- /dev/null +++ b/tests/cpp_tests/exceptions_test.cpp @@ -0,0 +1,116 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +extern "C" { +#include +} + +int main( int, char*[] ) +{ + try { + mapnik::projection srs("foo"); + // to avoid unused variable warning + srs.params(); + BOOST_TEST(false); + } catch (...) { + BOOST_TEST(true); + } + + mapnik::Map map(256,256); + mapnik::rule r; + r.set_filter(mapnik::parse_expression("[foo]='bar'")); + mapnik::feature_type_style style; + style.add_rule(r); + map.insert_style("style",style); + + std::string csv_plugin("./plugins/input/csv.input"); + if (boost::filesystem::exists(csv_plugin)) { + try { + mapnik::datasource_cache::instance()->register_datasource(csv_plugin); + mapnik::parameters p; + p["type"]="csv"; + p["inline"]="x,y\n0,0"; + mapnik::datasource_ptr ds = mapnik::datasource_cache::instance()->create(p); + //mapnik::datasource_ptr ds = boost::make_shared(); + //mapnik::context_ptr ctx = boost::make_shared(); + //mapnik::feature_ptr feature(mapnik::feature_factory::create(ctx, 1)); + //mapnik::memory_datasource *mem_ds = dynamic_cast(ds.get()); + //mem_ds->push(feature); + mapnik::layer l("layer"); + l.set_datasource(ds); + l.add_style("style"); + mapnik::Map m = map; + m.addLayer(l); + m.zoom_all(); + mapnik::image_32 im(m.width(),m.height()); + mapnik::agg_renderer ren(m,im); + //std::clog << mapnik::save_map_to_string(m) << "\n"; + BOOST_TEST(true); + // should throw here + ren.apply(); + BOOST_TEST(false); + } catch (...) { + BOOST_TEST(true); + } + } + + std::string shape_plugin("./plugins/input/shape.input"); + if (boost::filesystem::exists(shape_plugin)) { + try { + mapnik::datasource_cache::instance()->register_datasource(shape_plugin); + mapnik::parameters p2; + p2["type"]="shape"; + p2["file"]="foo"; + mapnik::datasource_cache::instance()->create(p2); + BOOST_TEST(false); + } catch (...) { + BOOST_TEST(true); + } + } + + /* + // not working, oddly segfaults valgrind + try { + sqlite3_initialize(); + // http://stackoverflow.com/questions/11107703/sqlite3-sigsegvs-with-valgrind + sqlite3_config(SQLITE_CONFIG_HEAP, malloc (1024*1024), 1024*1024, 64); + mapnik::datasource_cache::instance()->register_datasource("./plugins/input/sqlite.input"); + mapnik::parameters p; + p["type"]="sqlite"; + p["file"]="tests/data/sqlite/world.sqlite"; + p["table"]="world_merc"; + mapnik::datasource_cache::instance()->create(p); + sqlite3_shutdown(); + BOOST_TEST(true); + } catch (...) { + BOOST_TEST(false); + } + */ + + if (!::boost::detail::test_errors()) { + std::clog << "C++ exceptions: \x1b[1;32m✓ \x1b[0m\n"; +#if BOOST_VERSION >= 104600 + ::boost::detail::report_errors_remind().called_report_errors_function = true; +#endif + } else { + return ::boost::report_errors(); + } +} From 669c4906d418267aea3f7a783cbd23226cdc91be Mon Sep 17 00:00:00 2001 From: Dane Springmeyer Date: Fri, 20 Jul 2012 18:34:41 -0700 Subject: [PATCH 110/133] avoid c-linkage warning with datasources - closes #1323 --- include/mapnik/datasource.hpp | 4 ++-- plugins/input/csv/csv_datasource.cpp | 2 +- plugins/input/csv/csv_datasource.hpp | 2 +- plugins/input/gdal/gdal_datasource.cpp | 2 +- plugins/input/gdal/gdal_datasource.hpp | 2 +- plugins/input/geojson/geojson_datasource.cpp | 6 ++---- plugins/input/geojson/geojson_datasource.hpp | 5 ++--- plugins/input/geos/geos_datasource.cpp | 2 +- plugins/input/geos/geos_datasource.hpp | 2 +- plugins/input/kismet/kismet_datasource.cpp | 2 +- plugins/input/kismet/kismet_datasource.hpp | 2 +- plugins/input/kismet/kismet_featureset.hpp | 1 - plugins/input/occi/occi_datasource.cpp | 2 +- plugins/input/occi/occi_datasource.hpp | 2 +- plugins/input/ogr/ogr_datasource.cpp | 2 +- plugins/input/ogr/ogr_datasource.hpp | 2 +- plugins/input/osm/osm_datasource.cpp | 2 +- plugins/input/osm/osm_datasource.hpp | 2 +- plugins/input/postgis/postgis_datasource.cpp | 4 ++-- plugins/input/postgis/postgis_datasource.hpp | 2 +- plugins/input/raster/raster_datasource.cpp | 2 +- plugins/input/raster/raster_datasource.hpp | 2 +- plugins/input/rasterlite/rasterlite_datasource.cpp | 2 +- plugins/input/rasterlite/rasterlite_datasource.hpp | 2 +- plugins/input/shape/shape_datasource.cpp | 2 +- plugins/input/shape/shape_datasource.hpp | 2 +- plugins/input/sqlite/sqlite_datasource.cpp | 2 +- plugins/input/sqlite/sqlite_datasource.hpp | 2 +- plugins/input/templates/helloworld/hello_datasource.cpp | 6 ++---- plugins/input/templates/helloworld/hello_datasource.hpp | 2 +- 30 files changed, 34 insertions(+), 40 deletions(-) diff --git a/include/mapnik/datasource.hpp b/include/mapnik/datasource.hpp index 6ae828a94..127265377 100644 --- a/include/mapnik/datasource.hpp +++ b/include/mapnik/datasource.hpp @@ -126,7 +126,7 @@ protected: mutable bool is_bound_; }; -typedef std::string datasource_name(); +typedef const char * datasource_name(); typedef datasource* create_ds(const parameters& params, bool bind); typedef void destroy_ds(datasource *ds); @@ -142,7 +142,7 @@ public: typedef boost::shared_ptr datasource_ptr; #define DATASOURCE_PLUGIN(classname) \ - extern "C" MAPNIK_EXP std::string datasource_name() \ + extern "C" MAPNIK_EXP const char * datasource_name() \ { \ return classname::name(); \ } \ diff --git a/plugins/input/csv/csv_datasource.cpp b/plugins/input/csv/csv_datasource.cpp index 3c5b4b439..0c2d276ed 100644 --- a/plugins/input/csv/csv_datasource.cpp +++ b/plugins/input/csv/csv_datasource.cpp @@ -852,7 +852,7 @@ void csv_datasource::parse_csv(T& stream, } } -std::string csv_datasource::name() +const char * csv_datasource::name() { return "csv"; } diff --git a/plugins/input/csv/csv_datasource.hpp b/plugins/input/csv/csv_datasource.hpp index 86bcfd4f9..22a99a2b8 100644 --- a/plugins/input/csv/csv_datasource.hpp +++ b/plugins/input/csv/csv_datasource.hpp @@ -35,7 +35,7 @@ public: csv_datasource(mapnik::parameters const& params, bool bind=true); virtual ~csv_datasource (); mapnik::datasource::datasource_t type() const; - static std::string name(); + static const char * name(); mapnik::featureset_ptr features(mapnik::query const& q) const; mapnik::featureset_ptr features_at_point(mapnik::coord2d const& pt) const; mapnik::box2d envelope() const; diff --git a/plugins/input/gdal/gdal_datasource.cpp b/plugins/input/gdal/gdal_datasource.cpp index 05fe41626..a324b3825 100644 --- a/plugins/input/gdal/gdal_datasource.cpp +++ b/plugins/input/gdal/gdal_datasource.cpp @@ -200,7 +200,7 @@ datasource::datasource_t gdal_datasource::type() const return datasource::Raster; } -std::string gdal_datasource::name() +const char * gdal_datasource::name() { return "gdal"; } diff --git a/plugins/input/gdal/gdal_datasource.hpp b/plugins/input/gdal/gdal_datasource.hpp index eb196ee28..989b30135 100644 --- a/plugins/input/gdal/gdal_datasource.hpp +++ b/plugins/input/gdal/gdal_datasource.hpp @@ -38,7 +38,7 @@ public: gdal_datasource(mapnik::parameters const& params, bool bind = true); virtual ~gdal_datasource(); mapnik::datasource::datasource_t type() const; - static std::string name(); + static const char * name(); mapnik::featureset_ptr features(mapnik::query const& q) const; mapnik::featureset_ptr features_at_point(mapnik::coord2d const& pt) const; mapnik::box2d envelope() const; diff --git a/plugins/input/geojson/geojson_datasource.cpp b/plugins/input/geojson/geojson_datasource.cpp index 068bf4c1f..3ce9140e8 100644 --- a/plugins/input/geojson/geojson_datasource.cpp +++ b/plugins/input/geojson/geojson_datasource.cpp @@ -106,11 +106,9 @@ void geojson_datasource::bind() const geojson_datasource::~geojson_datasource() { } -std::string const geojson_datasource::name_="geojson"; - -std::string geojson_datasource::name() +const char * geojson_datasource::name() { - return name_; + return "geojson"; } boost::optional geojson_datasource::get_geometry_type() const diff --git a/plugins/input/geojson/geojson_datasource.hpp b/plugins/input/geojson/geojson_datasource.hpp index 079cb7e3c..231339cc0 100644 --- a/plugins/input/geojson/geojson_datasource.hpp +++ b/plugins/input/geojson/geojson_datasource.hpp @@ -44,7 +44,7 @@ public: geojson_datasource(mapnik::parameters const& params, bool bind=true); virtual ~geojson_datasource (); mapnik::datasource::datasource_t type() const; - static std::string name(); + static const char * name(); mapnik::featureset_ptr features(mapnik::query const& q) const; mapnik::featureset_ptr features_at_point(mapnik::coord2d const& pt) const; mapnik::box2d envelope() const; @@ -52,8 +52,7 @@ public: std::map get_statistics() const; boost::optional get_geometry_type() const; void bind() const; -private: - static const std::string name_; +private: mapnik::datasource::datasource_t type_; mutable std::map statistics_; mutable mapnik::layer_descriptor desc_; diff --git a/plugins/input/geos/geos_datasource.cpp b/plugins/input/geos/geos_datasource.cpp index 8dd6fef13..8bd2bcff8 100644 --- a/plugins/input/geos/geos_datasource.cpp +++ b/plugins/input/geos/geos_datasource.cpp @@ -226,7 +226,7 @@ void geos_datasource::bind() const is_bound_ = true; } -std::string geos_datasource::name() +const char * geos_datasource::name() { return "geos"; } diff --git a/plugins/input/geos/geos_datasource.hpp b/plugins/input/geos/geos_datasource.hpp index ba39c44f1..752a89ffc 100644 --- a/plugins/input/geos/geos_datasource.hpp +++ b/plugins/input/geos/geos_datasource.hpp @@ -39,7 +39,7 @@ public: geos_datasource(mapnik::parameters const& params, bool bind = true); virtual ~geos_datasource (); mapnik::datasource::datasource_t type() const; - static std::string name(); + static const char * name(); mapnik::featureset_ptr features(mapnik::query const& q) const; mapnik::featureset_ptr features_at_point(mapnik::coord2d const& pt) const; mapnik::box2d envelope() const; diff --git a/plugins/input/kismet/kismet_datasource.cpp b/plugins/input/kismet/kismet_datasource.cpp index ea5f6a2cd..07607af6d 100644 --- a/plugins/input/kismet/kismet_datasource.cpp +++ b/plugins/input/kismet/kismet_datasource.cpp @@ -122,7 +122,7 @@ kismet_datasource::~kismet_datasource() { } -std::string kismet_datasource::name() +const char * kismet_datasource::name() { return "kismet"; } diff --git a/plugins/input/kismet/kismet_datasource.hpp b/plugins/input/kismet/kismet_datasource.hpp index 1d49475ca..6e54d9c23 100644 --- a/plugins/input/kismet/kismet_datasource.hpp +++ b/plugins/input/kismet/kismet_datasource.hpp @@ -46,7 +46,7 @@ public: kismet_datasource(mapnik::parameters const& params, bool bind = true); virtual ~kismet_datasource (); datasource::datasource_t type() const; - static std::string name(); + static const char * name(); mapnik::featureset_ptr features(mapnik::query const& q) const; mapnik::featureset_ptr features_at_point(mapnik::coord2d const& pt) const; mapnik::box2d envelope() const; diff --git a/plugins/input/kismet/kismet_featureset.hpp b/plugins/input/kismet/kismet_featureset.hpp index 0efdf537c..7fd1ba551 100644 --- a/plugins/input/kismet/kismet_featureset.hpp +++ b/plugins/input/kismet/kismet_featureset.hpp @@ -49,7 +49,6 @@ public: private: std::list const& knd_list_; boost::scoped_ptr tr_; - mapnik::wkbFormat format_; int feature_id_; std::list::const_iterator knd_list_it; mapnik::projection source_; diff --git a/plugins/input/occi/occi_datasource.cpp b/plugins/input/occi/occi_datasource.cpp index d60271e17..daa7dcd4a 100644 --- a/plugins/input/occi/occi_datasource.cpp +++ b/plugins/input/occi/occi_datasource.cpp @@ -352,7 +352,7 @@ void occi_datasource::bind() const is_bound_ = true; } -std::string occi_datasource::name() +const char * occi_datasource::name() { return "occi"; } diff --git a/plugins/input/occi/occi_datasource.hpp b/plugins/input/occi/occi_datasource.hpp index e9507d8b3..bbc57970d 100644 --- a/plugins/input/occi/occi_datasource.hpp +++ b/plugins/input/occi/occi_datasource.hpp @@ -41,7 +41,7 @@ public: occi_datasource(mapnik::parameters const& params, bool bind = true); virtual ~occi_datasource (); mapnik::datasource::datasource_t type() const; - static std::string name(); + static const char * name(); mapnik::featureset_ptr features(mapnik::query const& q) const; mapnik::featureset_ptr features_at_point(mapnik::coord2d const& pt) const; mapnik::box2d envelope() const; diff --git a/plugins/input/ogr/ogr_datasource.cpp b/plugins/input/ogr/ogr_datasource.cpp index 9237f0a0b..c5a973145 100644 --- a/plugins/input/ogr/ogr_datasource.cpp +++ b/plugins/input/ogr/ogr_datasource.cpp @@ -333,7 +333,7 @@ void ogr_datasource::bind() const is_bound_ = true; } -std::string ogr_datasource::name() +const char * ogr_datasource::name() { return "ogr"; } diff --git a/plugins/input/ogr/ogr_datasource.hpp b/plugins/input/ogr/ogr_datasource.hpp index 0b283800f..1898397e0 100644 --- a/plugins/input/ogr/ogr_datasource.hpp +++ b/plugins/input/ogr/ogr_datasource.hpp @@ -42,7 +42,7 @@ public: ogr_datasource(mapnik::parameters const& params, bool bind=true); virtual ~ogr_datasource (); mapnik::datasource::datasource_t type() const; - static std::string name(); + static const char * name(); mapnik::featureset_ptr features(mapnik::query const& q) const; mapnik::featureset_ptr features_at_point(mapnik::coord2d const& pt) const; mapnik::box2d envelope() const; diff --git a/plugins/input/osm/osm_datasource.cpp b/plugins/input/osm/osm_datasource.cpp index 8835e0339..dbc8dfd7d 100644 --- a/plugins/input/osm/osm_datasource.cpp +++ b/plugins/input/osm/osm_datasource.cpp @@ -130,7 +130,7 @@ osm_datasource::~osm_datasource() //delete osm_data_; } -std::string osm_datasource::name() +const char * osm_datasource::name() { return "osm"; } diff --git a/plugins/input/osm/osm_datasource.hpp b/plugins/input/osm/osm_datasource.hpp index dc0c8fe51..1b99718ed 100644 --- a/plugins/input/osm/osm_datasource.hpp +++ b/plugins/input/osm/osm_datasource.hpp @@ -43,7 +43,7 @@ public: osm_datasource(const parameters& params, bool bind = true); virtual ~osm_datasource(); mapnik::datasource::datasource_t type() const; - static std::string name(); + static const char * name(); featureset_ptr features(const query& q) const; featureset_ptr features_at_point(coord2d const& pt) const; box2d envelope() const; diff --git a/plugins/input/postgis/postgis_datasource.cpp b/plugins/input/postgis/postgis_datasource.cpp index b2ae1a46f..3f95865cd 100644 --- a/plugins/input/postgis/postgis_datasource.cpp +++ b/plugins/input/postgis/postgis_datasource.cpp @@ -313,7 +313,7 @@ void postgis_datasource::bind() const { srid_ = -1; - MAPNIK_LOG_DEBUG(postgis) << "postgis_datasource: Table " << table_ << " is using SRID=-1"; + MAPNIK_LOG_DEBUG(postgis) << "postgis_datasource: Table " << table_ << " is using SRID=" << srid_; } // At this point the geometry_field may still not be known @@ -439,7 +439,7 @@ postgis_datasource::~postgis_datasource() } } -std::string postgis_datasource::name() +const char * postgis_datasource::name() { return "postgis"; } diff --git a/plugins/input/postgis/postgis_datasource.hpp b/plugins/input/postgis/postgis_datasource.hpp index afb840c08..f484837c8 100644 --- a/plugins/input/postgis/postgis_datasource.hpp +++ b/plugins/input/postgis/postgis_datasource.hpp @@ -51,7 +51,7 @@ public: postgis_datasource(const parameters ¶ms, bool bind=true); ~postgis_datasource(); mapnik::datasource::datasource_t type() const; - static std::string name(); + static const char * name(); featureset_ptr features(const query& q) const; featureset_ptr features_at_point(coord2d const& pt) const; mapnik::box2d envelope() const; diff --git a/plugins/input/raster/raster_datasource.cpp b/plugins/input/raster/raster_datasource.cpp index f0d98c8b3..efbd38233 100644 --- a/plugins/input/raster/raster_datasource.cpp +++ b/plugins/input/raster/raster_datasource.cpp @@ -159,7 +159,7 @@ mapnik::datasource::datasource_t raster_datasource::type() const return datasource::Raster; } -std::string raster_datasource::name() +const char * raster_datasource::name() { return "raster"; } diff --git a/plugins/input/raster/raster_datasource.hpp b/plugins/input/raster/raster_datasource.hpp index 5e373142a..9b84380e5 100644 --- a/plugins/input/raster/raster_datasource.hpp +++ b/plugins/input/raster/raster_datasource.hpp @@ -34,7 +34,7 @@ public: raster_datasource(const mapnik::parameters& params, bool bind=true); virtual ~raster_datasource(); datasource::datasource_t type() const; - static std::string name(); + static const char * name(); mapnik::featureset_ptr features(const mapnik::query& q) const; mapnik::featureset_ptr features_at_point(mapnik::coord2d const& pt) const; mapnik::box2d envelope() const; diff --git a/plugins/input/rasterlite/rasterlite_datasource.cpp b/plugins/input/rasterlite/rasterlite_datasource.cpp index 3fd3c73ef..bc8817745 100644 --- a/plugins/input/rasterlite/rasterlite_datasource.cpp +++ b/plugins/input/rasterlite/rasterlite_datasource.cpp @@ -166,7 +166,7 @@ rasterlite_datasource::~rasterlite_datasource() { } -std::string rasterlite_datasource::name() +const char * rasterlite_datasource::name() { return "rasterlite"; } diff --git a/plugins/input/rasterlite/rasterlite_datasource.hpp b/plugins/input/rasterlite/rasterlite_datasource.hpp index 18580935e..4971b2d1d 100644 --- a/plugins/input/rasterlite/rasterlite_datasource.hpp +++ b/plugins/input/rasterlite/rasterlite_datasource.hpp @@ -37,7 +37,7 @@ public: rasterlite_datasource(mapnik::parameters const& params, bool bind = true); virtual ~rasterlite_datasource (); mapnik::datasource::datasource_t type() const; - static std::string name(); + static const char * name(); mapnik::featureset_ptr features(mapnik::query const& q) const; mapnik::featureset_ptr features_at_point(mapnik::coord2d const& pt) const; mapnik::box2d envelope() const; diff --git a/plugins/input/shape/shape_datasource.cpp b/plugins/input/shape/shape_datasource.cpp index 5ceb23284..caf401e81 100644 --- a/plugins/input/shape/shape_datasource.cpp +++ b/plugins/input/shape/shape_datasource.cpp @@ -238,7 +238,7 @@ void shape_datasource::init(shape_io& shape) const MAPNIK_LOG_DEBUG(shape) << "shape_datasource: Shape type=" << shape_type_; } -std::string shape_datasource::name() +const char * shape_datasource::name() { return "shape"; } diff --git a/plugins/input/shape/shape_datasource.hpp b/plugins/input/shape/shape_datasource.hpp index 641f9e373..522365dde 100644 --- a/plugins/input/shape/shape_datasource.hpp +++ b/plugins/input/shape/shape_datasource.hpp @@ -45,7 +45,7 @@ public: shape_datasource(const parameters ¶ms, bool bind=true); virtual ~shape_datasource(); datasource::datasource_t type() const; - static std::string name(); + static const char * name(); featureset_ptr features(const query& q) const; featureset_ptr features_at_point(coord2d const& pt) const; box2d envelope() const; diff --git a/plugins/input/sqlite/sqlite_datasource.cpp b/plugins/input/sqlite/sqlite_datasource.cpp index 863dea7a4..0eec7e5f4 100644 --- a/plugins/input/sqlite/sqlite_datasource.cpp +++ b/plugins/input/sqlite/sqlite_datasource.cpp @@ -473,7 +473,7 @@ void sqlite_datasource::parse_attachdb(std::string const& attachdb) const } } -std::string sqlite_datasource::name() +const char * sqlite_datasource::name() { return "sqlite"; } diff --git a/plugins/input/sqlite/sqlite_datasource.hpp b/plugins/input/sqlite/sqlite_datasource.hpp index 11ec7cf7f..c1f840212 100644 --- a/plugins/input/sqlite/sqlite_datasource.hpp +++ b/plugins/input/sqlite/sqlite_datasource.hpp @@ -43,7 +43,7 @@ public: sqlite_datasource(mapnik::parameters const& params, bool bind = true); virtual ~sqlite_datasource (); datasource::datasource_t type() const; - static std::string name(); + static const char * name(); mapnik::featureset_ptr features(mapnik::query const& q) const; mapnik::featureset_ptr features_at_point(mapnik::coord2d const& pt) const; mapnik::box2d envelope() const; diff --git a/plugins/input/templates/helloworld/hello_datasource.cpp b/plugins/input/templates/helloworld/hello_datasource.cpp index 8bcd2283c..897b40829 100644 --- a/plugins/input/templates/helloworld/hello_datasource.cpp +++ b/plugins/input/templates/helloworld/hello_datasource.cpp @@ -39,11 +39,9 @@ void hello_datasource::bind() const hello_datasource::~hello_datasource() { } // This name must match the plugin filename, eg 'hello.input' -std::string const hello_datasource::name_="hello"; - -std::string hello_datasource::name() +const char * hello_datasource::name() { - return name_; + return "hello"; } mapnik::datasource::datasource_t hello_datasource::type() const diff --git a/plugins/input/templates/helloworld/hello_datasource.hpp b/plugins/input/templates/helloworld/hello_datasource.hpp index a2c136246..f2e172f56 100644 --- a/plugins/input/templates/helloworld/hello_datasource.hpp +++ b/plugins/input/templates/helloworld/hello_datasource.hpp @@ -18,7 +18,7 @@ public: mapnik::datasource::datasource_t type() const; // mandatory: name of the plugin - static std::string name(); + static const char * name(); // mandatory: function to query features by box2d // this is called when rendering, specifically in feature_style_processor.hpp From 0e7414ea1dfb1ff5f4a6f75d4fd8deb833d88d89 Mon Sep 17 00:00:00 2001 From: Dane Springmeyer Date: Fri, 20 Jul 2012 19:01:09 -0700 Subject: [PATCH 111/133] ogr plugin: no need to pass dataset pointer --- plugins/input/ogr/ogr_datasource.cpp | 6 +----- plugins/input/ogr/ogr_featureset.cpp | 4 ---- plugins/input/ogr/ogr_featureset.hpp | 5 ----- plugins/input/ogr/ogr_index_featureset.cpp | 2 -- plugins/input/ogr/ogr_index_featureset.hpp | 3 --- 5 files changed, 1 insertion(+), 19 deletions(-) diff --git a/plugins/input/ogr/ogr_datasource.cpp b/plugins/input/ogr/ogr_datasource.cpp index c5a973145..ea35829cf 100644 --- a/plugins/input/ogr/ogr_datasource.cpp +++ b/plugins/input/ogr/ogr_datasource.cpp @@ -502,7 +502,6 @@ featureset_ptr ogr_datasource::features(query const& q) const filter_in_box filter(q.get_bbox()); return featureset_ptr(new ogr_index_featureset(ctx, - *dataset_, *layer, filter, index_name_, @@ -510,8 +509,7 @@ featureset_ptr ogr_datasource::features(query const& q) const } else { - return featureset_ptr(new ogr_featureset (ctx, - *dataset_, + return featureset_ptr(new ogr_featureset(ctx, *layer, q.get_bbox(), desc_.get_encoding())); @@ -546,7 +544,6 @@ featureset_ptr ogr_datasource::features_at_point(coord2d const& pt) const filter_at_point filter(pt); return featureset_ptr(new ogr_index_featureset (ctx, - *dataset_, *layer, filter, index_name_, @@ -559,7 +556,6 @@ featureset_ptr ogr_datasource::features_at_point(coord2d const& pt) const point.setY (pt.y); return featureset_ptr(new ogr_featureset (ctx, - *dataset_, *layer, point, desc_.get_encoding())); diff --git a/plugins/input/ogr/ogr_featureset.cpp b/plugins/input/ogr/ogr_featureset.cpp index de9f185b7..2d675c964 100644 --- a/plugins/input/ogr/ogr_featureset.cpp +++ b/plugins/input/ogr/ogr_featureset.cpp @@ -48,12 +48,10 @@ using mapnik::feature_factory; ogr_featureset::ogr_featureset(mapnik::context_ptr const & ctx, - OGRDataSource & dataset, OGRLayer & layer, OGRGeometry & extent, std::string const& encoding) : ctx_(ctx), - dataset_(dataset), layer_(layer), layerdef_(layer.GetLayerDefn()), tr_(new transcoder(encoding)), @@ -65,12 +63,10 @@ ogr_featureset::ogr_featureset(mapnik::context_ptr const & ctx, } ogr_featureset::ogr_featureset(mapnik::context_ptr const& ctx, - OGRDataSource & dataset, OGRLayer & layer, mapnik::box2d const& extent, std::string const& encoding) : ctx_(ctx), - dataset_(dataset), layer_(layer), layerdef_(layer.GetLayerDefn()), tr_(new transcoder(encoding)), diff --git a/plugins/input/ogr/ogr_featureset.hpp b/plugins/input/ogr/ogr_featureset.hpp index 9ca9b2ad9..fdeb20c29 100644 --- a/plugins/input/ogr/ogr_featureset.hpp +++ b/plugins/input/ogr/ogr_featureset.hpp @@ -38,29 +38,24 @@ class ogr_featureset : public mapnik::Featureset { public: ogr_featureset(mapnik::context_ptr const& ctx, - OGRDataSource & dataset, OGRLayer & layer, OGRGeometry & extent, std::string const& encoding); ogr_featureset(mapnik::context_ptr const& ctx, - OGRDataSource & dataset, OGRLayer & layer, mapnik::box2d const& extent, std::string const& encoding); virtual ~ogr_featureset(); mapnik::feature_ptr next(); - private: mapnik::context_ptr ctx_; - OGRDataSource& dataset_; OGRLayer& layer_; OGRFeatureDefn* layerdef_; boost::scoped_ptr tr_; const char* fidcolumn_; mutable int count_; - }; #endif // OGR_FEATURESET_HPP diff --git a/plugins/input/ogr/ogr_index_featureset.cpp b/plugins/input/ogr/ogr_index_featureset.cpp index 7a37b04b1..98cb9da3b 100644 --- a/plugins/input/ogr/ogr_index_featureset.cpp +++ b/plugins/input/ogr/ogr_index_featureset.cpp @@ -53,13 +53,11 @@ using mapnik::feature_factory; template ogr_index_featureset::ogr_index_featureset(mapnik::context_ptr const & ctx, - OGRDataSource & dataset, OGRLayer & layer, filterT const& filter, std::string const& index_file, std::string const& encoding) : ctx_(ctx), - dataset_(dataset), layer_(layer), layerdef_(layer.GetLayerDefn()), filter_(filter), diff --git a/plugins/input/ogr/ogr_index_featureset.hpp b/plugins/input/ogr/ogr_index_featureset.hpp index cde9c68c5..a285ad3b9 100644 --- a/plugins/input/ogr/ogr_index_featureset.hpp +++ b/plugins/input/ogr/ogr_index_featureset.hpp @@ -33,7 +33,6 @@ class ogr_index_featureset : public mapnik::Featureset { public: ogr_index_featureset(mapnik::context_ptr const& ctx, - OGRDataSource& dataset, OGRLayer& layer, filterT const& filter, std::string const& index_file, @@ -41,10 +40,8 @@ public: virtual ~ogr_index_featureset(); mapnik::feature_ptr next(); - private: mapnik::context_ptr ctx_; - OGRDataSource& dataset_; OGRLayer& layer_; OGRFeatureDefn* layerdef_; filterT filter_; From 9c5dbc20c50ed6f96d301627eb25a1f6b1202064 Mon Sep 17 00:00:00 2001 From: Dane Springmeyer Date: Fri, 20 Jul 2012 15:28:10 -0700 Subject: [PATCH 112/133] properly skip empty geometries - refs #1333 and #1305 an #1132 + remove redundant ar.size() > 0 check + use std::auto_ptr to avoid memory leaks and improve exception safety. --- src/wkb.cpp | 128 ++++++++++++++++++++++++++++------------------------ 1 file changed, 70 insertions(+), 58 deletions(-) diff --git a/src/wkb.cpp b/src/wkb.cpp index 0551034cd..a26122a88 100644 --- a/src/wkb.cpp +++ b/src/wkb.cpp @@ -113,9 +113,6 @@ public: { int type = read_integer(); -#ifdef MAPNIK_LOG - MAPNIK_LOG_DEBUG(wkb_reader) << "wkb_reader: Read=" << wkb_geometry_type_string(type) << "," << type; -#endif switch (type) { case wkbPoint: @@ -246,9 +243,9 @@ private: void read_point(boost::ptr_vector & paths) { - geometry_type* pt = new geometry_type(Point); double x = read_double(); double y = read_double(); + std::auto_ptr pt(new geometry_type(Point)); pt->move_to(x, y); paths.push_back(pt); } @@ -265,9 +262,9 @@ private: void read_point_xyz(boost::ptr_vector & paths) { - geometry_type* pt = new geometry_type(Point); double x = read_double(); double y = read_double(); + std::auto_ptr pt(new geometry_type(Point)); pos_ += 8; // double z = read_double(); pt->move_to(x, y); paths.push_back(pt); @@ -285,16 +282,19 @@ private: void read_linestring(boost::ptr_vector & paths) { - geometry_type* line = new geometry_type(LineString); int num_points = read_integer(); - CoordinateArray ar(num_points); - read_coords(ar); - line->move_to(ar[0].x, ar[0].y); - for (int i = 1; i < num_points; ++i) + if (num_points > 0) { - line->line_to(ar[i].x, ar[i].y); + CoordinateArray ar(num_points); + read_coords(ar); + std::auto_ptr line(new geometry_type(LineString)); + line->move_to(ar[0].x, ar[0].y); + for (int i = 1; i < num_points; ++i) + { + line->line_to(ar[i].x, ar[i].y); + } + paths.push_back(line); } - paths.push_back(line); } void read_multilinestring(boost::ptr_vector & paths) @@ -309,16 +309,19 @@ private: void read_linestring_xyz(boost::ptr_vector & paths) { - geometry_type* line = new geometry_type(LineString); int num_points = read_integer(); - CoordinateArray ar(num_points); - read_coords_xyz(ar); - line->move_to(ar[0].x, ar[0].y); - for (int i = 1; i < num_points; ++i) + if (num_points > 0) { - line->line_to(ar[i].x, ar[i].y); + CoordinateArray ar(num_points); + read_coords_xyz(ar); + std::auto_ptr line(new geometry_type(LineString)); + line->move_to(ar[0].x, ar[0].y); + for (int i = 1; i < num_points; ++i) + { + line->line_to(ar[i].x, ar[i].y); + } + paths.push_back(line); } - paths.push_back(line); } void read_multilinestring_xyz(boost::ptr_vector & paths) @@ -334,22 +337,27 @@ private: void read_polygon(boost::ptr_vector & paths) { - geometry_type* poly = new geometry_type(Polygon); int num_rings = read_integer(); - unsigned capacity = 0; - for (int i = 0; i < num_rings; ++i) + if (num_rings > 0) { - int num_points = read_integer(); - capacity += num_points; - CoordinateArray ar(num_points); - read_coords(ar); - poly->move_to(ar[0].x, ar[0].y); - for (int j = 1; j < num_points; ++j) + std::auto_ptr poly(new geometry_type(Polygon)); + for (int i = 0; i < num_rings; ++i) { - poly->line_to(ar[j].x, ar[j].y); + int num_points = read_integer(); + if (num_points > 0) + { + CoordinateArray ar(num_points); + read_coords(ar); + poly->move_to(ar[0].x, ar[0].y); + for (int j = 1; j < num_points; ++j) + { + poly->line_to(ar[j].x, ar[j].y); + } + } } + if (poly->size() > 2) // ignore if polygon has less than 3 vertices + paths.push_back(poly); } - paths.push_back(poly); } void read_multipolygon(boost::ptr_vector & paths) @@ -364,22 +372,27 @@ private: void read_polygon_xyz(boost::ptr_vector & paths) { - geometry_type* poly = new geometry_type(Polygon); int num_rings = read_integer(); - unsigned capacity = 0; - for (int i = 0; i < num_rings; ++i) + if (num_rings > 0) { - int num_points = read_integer(); - capacity += num_points; - CoordinateArray ar(num_points); - read_coords_xyz(ar); - poly->move_to(ar[0].x, ar[0].y); - for (int j = 1; j < num_points; ++j) + std::auto_ptr poly(new geometry_type(Polygon)); + for (int i = 0; i < num_rings; ++i) { - poly->line_to(ar[j].x, ar[j].y); + int num_points = read_integer(); + if (num_points > 0) + { + CoordinateArray ar(num_points); + read_coords_xyz(ar); + poly->move_to(ar[0].x, ar[0].y); + for (int j = 1; j < num_points; ++j) + { + poly->line_to(ar[j].x, ar[j].y); + } + } } + if (poly->size() > 2) // ignore if polygon has less than 3 vertices + paths.push_back(poly); } - paths.push_back(poly); } void read_multipolygon_xyz(boost::ptr_vector & paths) @@ -402,33 +415,32 @@ private: } } -#ifdef MAPNIK_LOG std::string wkb_geometry_type_string(int type) { std::stringstream s; switch (type) { - case wkbPoint: s << "wkbPoint"; break; - case wkbLineString: s << "wkbLineString"; break; - case wkbPolygon: s << "wkbPolygon"; break; - case wkbMultiPoint: s << "wkbMultiPoint"; break; - case wkbMultiLineString: s << "wkbMultiLineString"; break; - case wkbMultiPolygon: s << "wkbMultiPolygon"; break; - case wkbGeometryCollection: s << "wkbGeometryCollection"; break; - case wkbPointZ: s << "wkbPointZ"; break; - case wkbLineStringZ: s << "wkbLineStringZ"; break; - case wkbPolygonZ: s << "wkbPolygonZ"; break; - case wkbMultiPointZ: s << "wkbMultiPointZ"; break; - case wkbMultiLineStringZ: s << "wkbMultiLineStringZ"; break; - case wkbMultiPolygonZ: s << "wkbMultiPolygonZ"; break; - case wkbGeometryCollectionZ: s << "wkbGeometryCollectionZ"; break; - default: s << "wkbUknown"; break; + case wkbPoint: s << "Point"; break; + case wkbLineString: s << "LineString"; break; + case wkbPolygon: s << "Polygon"; break; + case wkbMultiPoint: s << "MultiPoint"; break; + case wkbMultiLineString: s << "MultiLineString"; break; + case wkbMultiPolygon: s << "MultiPolygon"; break; + case wkbGeometryCollection: s << "GeometryCollection"; break; + case wkbPointZ: s << "PointZ"; break; + case wkbLineStringZ: s << "LineStringZ"; break; + case wkbPolygonZ: s << "PolygonZ"; break; + case wkbMultiPointZ: s << "MultiPointZ"; break; + case wkbMultiLineStringZ: s << "MultiLineStringZ"; break; + case wkbMultiPolygonZ: s << "MultiPolygonZ"; break; + case wkbGeometryCollectionZ: s << "GeometryCollectionZ"; break; + default: s << "wkbUknown(" << type << ")"; break; } return s.str(); } -#endif + }; bool geometry_utils::from_wkb(boost::ptr_vector& paths, From bbd1b052f7571ee79ba186279e0b91aaf8ceb4fd Mon Sep 17 00:00:00 2001 From: Dane Springmeyer Date: Mon, 23 Jul 2012 11:38:59 -0700 Subject: [PATCH 113/133] fix spelling in comment --- include/mapnik/transform_expression.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/mapnik/transform_expression.hpp b/include/mapnik/transform_expression.hpp index 069863470..53170f63f 100644 --- a/include/mapnik/transform_expression.hpp +++ b/include/mapnik/transform_expression.hpp @@ -115,7 +115,7 @@ namespace detail { // boost::spirit::traits::clear(T& val) [with T = boost::variant<...>] // attempts to assign to the variant's current value a default-constructed -// value ot the same type, which not only requires that each value-type is +// value of the same type, which not only requires that each value-type is // default-constructible, but also makes little sense with our variant of // transform nodes... From 450bf40d4da7a4959c248699ff9063cc866ba6a9 Mon Sep 17 00:00:00 2001 From: Dane Springmeyer Date: Mon, 23 Jul 2012 11:41:08 -0700 Subject: [PATCH 114/133] suppress strict-aliasing warnings with older gcc and newer boost - refs #1330 --- SConstruct | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SConstruct b/SConstruct index 60c68a83b..2b0f716e7 100644 --- a/SConstruct +++ b/SConstruct @@ -1526,7 +1526,7 @@ if not preconfigured: if env['DEBUG']: env.Append(CXXFLAGS = gcc_cxx_flags + '-O0 -fno-inline %s' % debug_flags) else: - env.Append(CXXFLAGS = gcc_cxx_flags + '-O%s -finline-functions -Wno-inline -Wno-parentheses -Wno-char-subscripts %s' % (env['OPTIMIZATION'],ndebug_flags)) + env.Append(CXXFLAGS = gcc_cxx_flags + '-O%s -fno-strict-aliasing -finline-functions -Wno-inline -Wno-parentheses -Wno-char-subscripts %s' % (env['OPTIMIZATION'],ndebug_flags)) if env['DEBUG_UNDEFINED']: env.Append(CXXFLAGS = '-fcatch-undefined-behavior -ftrapv -fwrapv') From e13e81c4d54fce5921124b12e35df32e585ed07f Mon Sep 17 00:00:00 2001 From: Dane Springmeyer Date: Mon, 23 Jul 2012 11:43:24 -0700 Subject: [PATCH 115/133] move grid utility functions to cpp file - avoids function 'defined but not used' compiler warnings - refs #1330 --- bindings/python/python_grid_utils.cpp | 505 ++++++++++++++++++++++++++ bindings/python/python_grid_utils.hpp | 449 +---------------------- 2 files changed, 521 insertions(+), 433 deletions(-) create mode 100644 bindings/python/python_grid_utils.cpp diff --git a/bindings/python/python_grid_utils.cpp b/bindings/python/python_grid_utils.cpp new file mode 100644 index 000000000..87379c9fd --- /dev/null +++ b/bindings/python/python_grid_utils.cpp @@ -0,0 +1,505 @@ +/***************************************************************************** + * + * This file is part of Mapnik (c++ mapping toolkit) + * + * Copyright (C) 2011 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 + * + *****************************************************************************/ + +// boost +#include +#include +#include + +// mapnik +#include +#include +#include +#include +#include +#include +#include +#include +#include "mapnik_value_converter.hpp" +#include "python_grid_utils.hpp" + +namespace mapnik { + + +template +void grid2utf(T const& grid_type, + boost::python::list& l, + std::vector& key_order) +{ + typedef std::map< typename T::lookup_type, typename T::value_type> keys_type; + typedef typename keys_type::const_iterator keys_iterator; + + typename T::data_type const& data = grid_type.data(); + typename T::feature_key_type const& feature_keys = grid_type.get_feature_keys(); + typename T::feature_key_type::const_iterator feature_pos; + + keys_type keys; + // start counting at utf8 codepoint 32, aka space character + boost::uint16_t codepoint = 32; + + unsigned array_size = data.width(); + for (unsigned y = 0; y < data.height(); ++y) + { + boost::uint16_t idx = 0; + boost::scoped_array line(new Py_UNICODE[array_size]); + typename T::value_type const* row = data.getRow(y); + for (unsigned x = 0; x < data.width(); ++x) + { + typename T::value_type feature_id = row[x]; + feature_pos = feature_keys.find(feature_id); + if (feature_pos != feature_keys.end()) + { + mapnik::grid::lookup_type val = feature_pos->second; + keys_iterator key_pos = keys.find(val); + if (key_pos == keys.end()) + { + // Create a new entry for this key. Skip the codepoints that + // can't be encoded directly in JSON. + if (codepoint == 34) ++codepoint; // Skip " + else if (codepoint == 92) ++codepoint; // Skip backslash + if (feature_id == mapnik::grid::base_mask) + { + keys[""] = codepoint; + key_order.push_back(""); + } + else + { + keys[val] = codepoint; + key_order.push_back(val); + } + line[idx++] = static_cast(codepoint); + ++codepoint; + } + else + { + line[idx++] = static_cast(key_pos->second); + } + } + // else, shouldn't get here... + } + l.append(boost::python::object( + boost::python::handle<>( + PyUnicode_FromUnicode(line.get(), array_size)))); + } +} + + +template +void grid2utf(T const& grid_type, + boost::python::list& l, + std::vector& key_order, + unsigned int resolution) +{ + typedef std::map< typename T::lookup_type, typename T::value_type> keys_type; + typedef typename keys_type::const_iterator keys_iterator; + + typename T::feature_key_type const& feature_keys = grid_type.get_feature_keys(); + typename T::feature_key_type::const_iterator feature_pos; + + keys_type keys; + // start counting at utf8 codepoint 32, aka space character + boost::uint16_t codepoint = 32; + + // TODO - use double? + unsigned array_size = static_cast(grid_type.width()/resolution); + for (unsigned y = 0; y < grid_type.height(); y=y+resolution) + { + boost::uint16_t idx = 0; + boost::scoped_array line(new Py_UNICODE[array_size]); + mapnik::grid::value_type const* row = grid_type.getRow(y); + for (unsigned x = 0; x < grid_type.width(); x=x+resolution) + { + typename T::value_type feature_id = row[x]; + feature_pos = feature_keys.find(feature_id); + if (feature_pos != feature_keys.end()) + { + mapnik::grid::lookup_type val = feature_pos->second; + keys_iterator key_pos = keys.find(val); + if (key_pos == keys.end()) + { + // Create a new entry for this key. Skip the codepoints that + // can't be encoded directly in JSON. + if (codepoint == 34) ++codepoint; // Skip " + else if (codepoint == 92) ++codepoint; // Skip backslash + if (feature_id == mapnik::grid::base_mask) + { + keys[""] = codepoint; + key_order.push_back(""); + } + else + { + keys[val] = codepoint; + key_order.push_back(val); + } + line[idx++] = static_cast(codepoint); + ++codepoint; + } + else + { + line[idx++] = static_cast(key_pos->second); + } + } + // else, shouldn't get here... + } + l.append(boost::python::object( + boost::python::handle<>( + PyUnicode_FromUnicode(line.get(), array_size)))); + } +} + + +template +void grid2utf2(T const& grid_type, + boost::python::list& l, + std::vector& key_order, + unsigned int resolution) +{ + typedef std::map< typename T::lookup_type, typename T::value_type> keys_type; + typedef typename keys_type::const_iterator keys_iterator; + + typename T::data_type const& data = grid_type.data(); + typename T::feature_key_type const& feature_keys = grid_type.get_feature_keys(); + typename T::feature_key_type::const_iterator feature_pos; + + keys_type keys; + // start counting at utf8 codepoint 32, aka space character + uint16_t codepoint = 32; + + mapnik::grid::data_type target(data.width()/resolution,data.height()/resolution); + mapnik::scale_grid(target,grid_type.data(),0.0,0.0); + + unsigned array_size = target.width(); + for (unsigned y = 0; y < target.height(); ++y) + { + uint16_t idx = 0; + boost::scoped_array line(new Py_UNICODE[array_size]); + mapnik::grid::value_type * row = target.getRow(y); + unsigned x; + for (x = 0; x < target.width(); ++x) + { + feature_pos = feature_keys.find(row[x]); + if (feature_pos != feature_keys.end()) + { + mapnik::grid::lookup_type val = feature_pos->second; + keys_iterator key_pos = keys.find(val); + if (key_pos == keys.end()) + { + // Create a new entry for this key. Skip the codepoints that + // can't be encoded directly in JSON. + if (codepoint == 34) ++codepoint; // Skip " + else if (codepoint == 92) ++codepoint; // Skip backslash + keys[val] = codepoint; + key_order.push_back(val); + line[idx++] = static_cast(codepoint); + ++codepoint; + } + else + { + line[idx++] = static_cast(key_pos->second); + } + } + // else, shouldn't get here... + } + l.append(boost::python::object( + boost::python::handle<>( + PyUnicode_FromUnicode(line.get(), array_size)))); + } +} + + +template +void write_features(T const& grid_type, + boost::python::dict& feature_data, + std::vector const& key_order) +{ + std::string const& key = grid_type.get_key(); + std::set const& attributes = grid_type.property_names(); + typename T::feature_type const& g_features = grid_type.get_grid_features(); + typename T::feature_type::const_iterator feat_itr = g_features.begin(); + typename T::feature_type::const_iterator feat_end = g_features.end(); + bool include_key = (attributes.find(key) != attributes.end()); + for (; feat_itr != feat_end; ++feat_itr) + { + mapnik::feature_ptr feature = feat_itr->second; + boost::optional join_value; + if (key == grid_type.key_name()) + { + join_value = feat_itr->first; + } + else if (feature->has_key(key)) + { + join_value = feature->get(key).to_string(); + } + + if (join_value) + { + // only serialize features visible in the grid + if(std::find(key_order.begin(), key_order.end(), *join_value) != key_order.end()) { + boost::python::dict feat; + bool found = false; + if (key == grid_type.key_name()) + { + // drop key unless requested + if (include_key) { + found = true; + //TODO - add __id__ as data key? + //feat[key] = *join_value; + } + } + + feature_kv_iterator itr = feature->begin(); + feature_kv_iterator end = feature->end(); + for ( ;itr!=end; ++itr) + { + std::string const& key_name = boost::get<0>(*itr); + if (key_name == key) { + // drop key unless requested + if (include_key) { + found = true; + feat[key_name] = boost::get<1>(*itr); + } + } + else if ( (attributes.find(key_name) != attributes.end()) ) + { + found = true; + feat[key_name] = boost::get<1>(*itr); + } + } + + if (found) + { + feature_data[feat_itr->first] = feat; + } + } + } + else + { + MAPNIK_LOG_DEBUG(bindings) << "write_features: Should not get here: key " << key << " not found in grid feature properties"; + } + } +} + +template +void grid_encode_utf(T const& grid_type, + boost::python::dict & json, + bool add_features, + unsigned int resolution) +{ + // convert buffer to utf and gather key order + boost::python::list l; + std::vector key_order; + + if (resolution != 1) { + // resample on the fly - faster, less accurate + mapnik::grid2utf(grid_type,l,key_order,resolution); + + // resample first - slower, more accurate + //mapnik::grid2utf2(grid_type,l,key_order,resolution); + } + else + { + mapnik::grid2utf(grid_type,l,key_order); + } + + // convert key order to proper python list + boost::python::list keys_a; + BOOST_FOREACH ( typename T::lookup_type const& key_id, key_order ) + { + keys_a.append(key_id); + } + + // gather feature data + boost::python::dict feature_data; + if (add_features) { + mapnik::write_features(grid_type,feature_data,key_order); + } + + json["grid"] = l; + json["keys"] = keys_a; + json["data"] = feature_data; + +} + +template +boost::python::dict grid_encode( T const& grid, std::string format, bool add_features, unsigned int resolution) +{ + if (format == "utf") { + boost::python::dict json; + grid_encode_utf(grid,json,add_features,resolution); + return json; + } + else + { + std::stringstream s; + s << "'utf' is currently the only supported encoding format."; + throw mapnik::value_error(s.str()); + } +} + +template boost::python::dict grid_encode( mapnik::grid const& grid, std::string format, bool add_features, unsigned int resolution); +template boost::python::dict grid_encode( mapnik::grid_view const& grid, std::string format, bool add_features, unsigned int resolution); + +/* new approach: key comes from grid object + * grid size should be same as the map + * encoding, resizing handled as method on grid object + * whether features are dumped is determined by argument not 'fields' + */ +void render_layer_for_grid(const mapnik::Map& map, + mapnik::grid& grid, + unsigned layer_idx, // TODO - layer by name or index + boost::python::list const& fields) +{ + std::vector const& layers = map.layers(); + std::size_t layer_num = layers.size(); + if (layer_idx >= layer_num) { + std::ostringstream s; + s << "Zero-based layer index '" << layer_idx << "' not valid, only '" + << layer_num << "' layers are in map\n"; + throw std::runtime_error(s.str()); + } + + // convert python list to std::vector + boost::python::ssize_t num_fields = boost::python::len(fields); + for(boost::python::ssize_t i=0; i name(fields[i]); + if (name.check()) { + grid.add_property_name(name()); + } + else + { + std::stringstream s; + s << "list of field names must be strings"; + throw mapnik::value_error(s.str()); + } + } + + // copy property names + std::set attributes = grid.property_names(); + std::string const& key = grid.get_key(); + + // if key is special __id__ keyword + if (key == grid.key_name()) + { + // TODO - should feature.id() be a first class attribute? + + // if __id__ is requested to be dumped out + // remove it so that datasource queries will not break + if (attributes.find(key) != attributes.end()) + { + attributes.erase(key); + } + } + // if key is not the special __id__ keyword + else if (attributes.find(key) == attributes.end()) + { + // them make sure the datasource query includes this field + attributes.insert(key); + } + + mapnik::grid_renderer ren(map,grid,1.0,0,0); + mapnik::layer const& layer = layers[layer_idx]; + ren.apply(layer,attributes); +} + +/* old, original impl - to be removed after further testing + * grid object is created on the fly at potentially reduced size + */ +boost::python::dict render_grid(const mapnik::Map& map, + unsigned layer_idx, // layer + std::string const& key, // key_name + unsigned int step, // resolution + boost::python::list const& fields) +{ + + std::vector const& layers = map.layers(); + std::size_t layer_num = layers.size(); + if (layer_idx >= layer_num) { + std::ostringstream s; + s << "Zero-based layer index '" << layer_idx << "' not valid, only '" + << layer_num << "' layers are in map\n"; + throw std::runtime_error(s.str()); + } + + unsigned int grid_width = map.width()/step; + unsigned int grid_height = map.height()/step; + + // TODO - no need to pass step here + mapnik::grid grid(grid_width,grid_height,key,step); + + // convert python list to std::vector + boost::python::ssize_t num_fields = boost::python::len(fields); + for(boost::python::ssize_t i=0; i name(fields[i]); + if (name.check()) { + grid.add_property_name(name()); + } + else + { + std::stringstream s; + s << "list of field names must be strings"; + throw mapnik::value_error(s.str()); + } + } + + // copy property names + std::set attributes = grid.property_names(); + + // if key is special __id__ keyword + if (key == grid.key_name()) + { + // TODO - should feature.id() be a first class attribute? + + // if __id__ is requested to be dumped out + // remove it so that datasource queries will not break + if (attributes.find(key) != attributes.end()) + { + attributes.erase(key); + } + } + // if key is not the special __id__ keyword + else if (attributes.find(key) == attributes.end()) + { + // them make sure the datasource query includes this field + attributes.insert(key); + } + + try + { + mapnik::grid_renderer ren(map,grid,1.0,0,0); + mapnik::layer const& layer = layers[layer_idx]; + ren.apply(layer,attributes); + } + catch (...) + { + throw; + } + + bool add_features = false; + if (num_fields > 0) + add_features = true; + // build dictionary and return to python + boost::python::dict json; + grid_encode_utf(grid,json,add_features,1); + return json; +} + +} diff --git a/bindings/python/python_grid_utils.hpp b/bindings/python/python_grid_utils.hpp index f3d1301ca..30ed4ff43 100644 --- a/bindings/python/python_grid_utils.hpp +++ b/bindings/python/python_grid_utils.hpp @@ -24,483 +24,66 @@ // boost #include -#include -#include // mapnik -#include -#include +#include #include -#include -#include -#include -#include -#include -#include "mapnik_value_converter.hpp" - namespace mapnik { template -static void grid2utf(T const& grid_type, +void grid2utf(T const& grid_type, boost::python::list& l, - std::vector& key_order) -{ - typedef std::map< typename T::lookup_type, typename T::value_type> keys_type; - typedef typename keys_type::const_iterator keys_iterator; - - typename T::data_type const& data = grid_type.data(); - typename T::feature_key_type const& feature_keys = grid_type.get_feature_keys(); - typename T::feature_key_type::const_iterator feature_pos; - - keys_type keys; - // start counting at utf8 codepoint 32, aka space character - boost::uint16_t codepoint = 32; - - unsigned array_size = data.width(); - for (unsigned y = 0; y < data.height(); ++y) - { - boost::uint16_t idx = 0; - boost::scoped_array line(new Py_UNICODE[array_size]); - typename T::value_type const* row = data.getRow(y); - for (unsigned x = 0; x < data.width(); ++x) - { - typename T::value_type feature_id = row[x]; - feature_pos = feature_keys.find(feature_id); - if (feature_pos != feature_keys.end()) - { - mapnik::grid::lookup_type val = feature_pos->second; - keys_iterator key_pos = keys.find(val); - if (key_pos == keys.end()) - { - // Create a new entry for this key. Skip the codepoints that - // can't be encoded directly in JSON. - if (codepoint == 34) ++codepoint; // Skip " - else if (codepoint == 92) ++codepoint; // Skip backslash - if (feature_id == mapnik::grid::base_mask) - { - keys[""] = codepoint; - key_order.push_back(""); - } - else - { - keys[val] = codepoint; - key_order.push_back(val); - } - line[idx++] = static_cast(codepoint); - ++codepoint; - } - else - { - line[idx++] = static_cast(key_pos->second); - } - } - // else, shouldn't get here... - } - l.append(boost::python::object( - boost::python::handle<>( - PyUnicode_FromUnicode(line.get(), array_size)))); - } -} + std::vector& key_order); template -static void grid2utf(T const& grid_type, +void grid2utf(T const& grid_type, boost::python::list& l, std::vector& key_order, - unsigned int resolution) -{ - typedef std::map< typename T::lookup_type, typename T::value_type> keys_type; - typedef typename keys_type::const_iterator keys_iterator; - - typename T::feature_key_type const& feature_keys = grid_type.get_feature_keys(); - typename T::feature_key_type::const_iterator feature_pos; - - keys_type keys; - // start counting at utf8 codepoint 32, aka space character - boost::uint16_t codepoint = 32; - - // TODO - use double? - unsigned array_size = static_cast(grid_type.width()/resolution); - for (unsigned y = 0; y < grid_type.height(); y=y+resolution) - { - boost::uint16_t idx = 0; - boost::scoped_array line(new Py_UNICODE[array_size]); - mapnik::grid::value_type const* row = grid_type.getRow(y); - for (unsigned x = 0; x < grid_type.width(); x=x+resolution) - { - typename T::value_type feature_id = row[x]; - feature_pos = feature_keys.find(feature_id); - if (feature_pos != feature_keys.end()) - { - mapnik::grid::lookup_type val = feature_pos->second; - keys_iterator key_pos = keys.find(val); - if (key_pos == keys.end()) - { - // Create a new entry for this key. Skip the codepoints that - // can't be encoded directly in JSON. - if (codepoint == 34) ++codepoint; // Skip " - else if (codepoint == 92) ++codepoint; // Skip backslash - if (feature_id == mapnik::grid::base_mask) - { - keys[""] = codepoint; - key_order.push_back(""); - } - else - { - keys[val] = codepoint; - key_order.push_back(val); - } - line[idx++] = static_cast(codepoint); - ++codepoint; - } - else - { - line[idx++] = static_cast(key_pos->second); - } - } - // else, shouldn't get here... - } - l.append(boost::python::object( - boost::python::handle<>( - PyUnicode_FromUnicode(line.get(), array_size)))); - } -} + unsigned int resolution); template -static void grid2utf2(T const& grid_type, +void grid2utf2(T const& grid_type, boost::python::list& l, std::vector& key_order, - unsigned int resolution) -{ - typedef std::map< typename T::lookup_type, typename T::value_type> keys_type; - typedef typename keys_type::const_iterator keys_iterator; - - typename T::data_type const& data = grid_type.data(); - typename T::feature_key_type const& feature_keys = grid_type.get_feature_keys(); - typename T::feature_key_type::const_iterator feature_pos; - - keys_type keys; - // start counting at utf8 codepoint 32, aka space character - uint16_t codepoint = 32; - - mapnik::grid::data_type target(data.width()/resolution,data.height()/resolution); - mapnik::scale_grid(target,grid_type.data(),0.0,0.0); - - unsigned array_size = target.width(); - for (unsigned y = 0; y < target.height(); ++y) - { - uint16_t idx = 0; - boost::scoped_array line(new Py_UNICODE[array_size]); - mapnik::grid::value_type * row = target.getRow(y); - unsigned x; - for (x = 0; x < target.width(); ++x) - { - feature_pos = feature_keys.find(row[x]); - if (feature_pos != feature_keys.end()) - { - mapnik::grid::lookup_type val = feature_pos->second; - keys_iterator key_pos = keys.find(val); - if (key_pos == keys.end()) - { - // Create a new entry for this key. Skip the codepoints that - // can't be encoded directly in JSON. - if (codepoint == 34) ++codepoint; // Skip " - else if (codepoint == 92) ++codepoint; // Skip backslash - keys[val] = codepoint; - key_order.push_back(val); - line[idx++] = static_cast(codepoint); - ++codepoint; - } - else - { - line[idx++] = static_cast(key_pos->second); - } - } - // else, shouldn't get here... - } - l.append(boost::python::object( - boost::python::handle<>( - PyUnicode_FromUnicode(line.get(), array_size)))); - } -} + unsigned int resolution); template -static void write_features(T const& grid_type, +void write_features(T const& grid_type, boost::python::dict& feature_data, - std::vector const& key_order) -{ - std::string const& key = grid_type.get_key(); - std::set const& attributes = grid_type.property_names(); - typename T::feature_type const& g_features = grid_type.get_grid_features(); - typename T::feature_type::const_iterator feat_itr = g_features.begin(); - typename T::feature_type::const_iterator feat_end = g_features.end(); - bool include_key = (attributes.find(key) != attributes.end()); - for (; feat_itr != feat_end; ++feat_itr) - { - mapnik::feature_ptr feature = feat_itr->second; - boost::optional join_value; - if (key == grid_type.key_name()) - { - join_value = feat_itr->first; - } - else if (feature->has_key(key)) - { - join_value = feature->get(key).to_string(); - } - - if (join_value) - { - // only serialize features visible in the grid - if(std::find(key_order.begin(), key_order.end(), *join_value) != key_order.end()) { - boost::python::dict feat; - bool found = false; - if (key == grid_type.key_name()) - { - // drop key unless requested - if (include_key) { - found = true; - //TODO - add __id__ as data key? - //feat[key] = *join_value; - } - } - - feature_kv_iterator itr = feature->begin(); - feature_kv_iterator end = feature->end(); - for ( ;itr!=end; ++itr) - { - std::string const& key_name = boost::get<0>(*itr); - if (key_name == key) { - // drop key unless requested - if (include_key) { - found = true; - feat[key_name] = boost::get<1>(*itr); - } - } - else if ( (attributes.find(key_name) != attributes.end()) ) - { - found = true; - feat[key_name] = boost::get<1>(*itr); - } - } - - if (found) - { - feature_data[feat_itr->first] = feat; - } - } - } - else - { - MAPNIK_LOG_DEBUG(bindings) << "write_features: Should not get here: key " << key << " not found in grid feature properties"; - } - } -} + std::vector const& key_order); template -static void grid_encode_utf(T const& grid_type, +void grid_encode_utf(T const& grid_type, boost::python::dict & json, bool add_features, - unsigned int resolution) -{ - // convert buffer to utf and gather key order - boost::python::list l; - std::vector key_order; - - if (resolution != 1) { - // resample on the fly - faster, less accurate - mapnik::grid2utf(grid_type,l,key_order,resolution); - - // resample first - slower, more accurate - //mapnik::grid2utf2(grid_type,l,key_order,resolution); - } - else - { - mapnik::grid2utf(grid_type,l,key_order); - } - - // convert key order to proper python list - boost::python::list keys_a; - BOOST_FOREACH ( typename T::lookup_type const& key_id, key_order ) - { - keys_a.append(key_id); - } - - // gather feature data - boost::python::dict feature_data; - if (add_features) { - mapnik::write_features(grid_type,feature_data,key_order); - } - - json["grid"] = l; - json["keys"] = keys_a; - json["data"] = feature_data; - -} + unsigned int resolution); template -static boost::python::dict grid_encode( T const& grid, std::string format, bool add_features, unsigned int resolution) -{ - if (format == "utf") { - boost::python::dict json; - grid_encode_utf(grid,json,add_features,resolution); - return json; - } - else - { - std::stringstream s; - s << "'utf' is currently the only supported encoding format."; - throw mapnik::value_error(s.str()); - } -} +boost::python::dict grid_encode( T const& grid, std::string format, bool add_features, unsigned int resolution); /* new approach: key comes from grid object * grid size should be same as the map * encoding, resizing handled as method on grid object * whether features are dumped is determined by argument not 'fields' */ -static void render_layer_for_grid(const mapnik::Map& map, +void render_layer_for_grid(const mapnik::Map& map, mapnik::grid& grid, unsigned layer_idx, // TODO - layer by name or index - boost::python::list const& fields) -{ - std::vector const& layers = map.layers(); - std::size_t layer_num = layers.size(); - if (layer_idx >= layer_num) { - std::ostringstream s; - s << "Zero-based layer index '" << layer_idx << "' not valid, only '" - << layer_num << "' layers are in map\n"; - throw std::runtime_error(s.str()); - } - - // convert python list to std::vector - boost::python::ssize_t num_fields = boost::python::len(fields); - for(boost::python::ssize_t i=0; i name(fields[i]); - if (name.check()) { - grid.add_property_name(name()); - } - else - { - std::stringstream s; - s << "list of field names must be strings"; - throw mapnik::value_error(s.str()); - } - } - - // copy property names - std::set attributes = grid.property_names(); - std::string const& key = grid.get_key(); - - // if key is special __id__ keyword - if (key == grid.key_name()) - { - // TODO - should feature.id() be a first class attribute? - - // if __id__ is requested to be dumped out - // remove it so that datasource queries will not break - if (attributes.find(key) != attributes.end()) - { - attributes.erase(key); - } - } - // if key is not the special __id__ keyword - else if (attributes.find(key) == attributes.end()) - { - // them make sure the datasource query includes this field - attributes.insert(key); - } - - mapnik::grid_renderer ren(map,grid,1.0,0,0); - mapnik::layer const& layer = layers[layer_idx]; - ren.apply(layer,attributes); -} + boost::python::list const& fields); /* old, original impl - to be removed after further testing * grid object is created on the fly at potentially reduced size */ -static boost::python::dict render_grid(const mapnik::Map& map, +boost::python::dict render_grid(const mapnik::Map& map, unsigned layer_idx, // layer std::string const& key, // key_name unsigned int step, // resolution - boost::python::list const& fields) -{ - - std::vector const& layers = map.layers(); - std::size_t layer_num = layers.size(); - if (layer_idx >= layer_num) { - std::ostringstream s; - s << "Zero-based layer index '" << layer_idx << "' not valid, only '" - << layer_num << "' layers are in map\n"; - throw std::runtime_error(s.str()); - } - - unsigned int grid_width = map.width()/step; - unsigned int grid_height = map.height()/step; - - // TODO - no need to pass step here - mapnik::grid grid(grid_width,grid_height,key,step); - - // convert python list to std::vector - boost::python::ssize_t num_fields = boost::python::len(fields); - for(boost::python::ssize_t i=0; i name(fields[i]); - if (name.check()) { - grid.add_property_name(name()); - } - else - { - std::stringstream s; - s << "list of field names must be strings"; - throw mapnik::value_error(s.str()); - } - } - - // copy property names - std::set attributes = grid.property_names(); - - // if key is special __id__ keyword - if (key == grid.key_name()) - { - // TODO - should feature.id() be a first class attribute? - - // if __id__ is requested to be dumped out - // remove it so that datasource queries will not break - if (attributes.find(key) != attributes.end()) - { - attributes.erase(key); - } - } - // if key is not the special __id__ keyword - else if (attributes.find(key) == attributes.end()) - { - // them make sure the datasource query includes this field - attributes.insert(key); - } - - try - { - mapnik::grid_renderer ren(map,grid,1.0,0,0); - mapnik::layer const& layer = layers[layer_idx]; - ren.apply(layer,attributes); - } - catch (...) - { - throw; - } - - bool add_features = false; - if (num_fields > 0) - add_features = true; - // build dictionary and return to python - boost::python::dict json; - grid_encode_utf(grid,json,add_features,1); - return json; -} - + boost::python::list const& fields); } #endif // MAPNIK_PYTHON_BINDING_GRID_UTILS_INCLUDED From 8f803b9897a57ed5a1e4e15076c424a729f04fab Mon Sep 17 00:00:00 2001 From: Dane Springmeyer Date: Mon, 23 Jul 2012 16:15:27 -0700 Subject: [PATCH 116/133] reduce build time of xml_tree by half and memory usage by 1/3 - refs #1267 --- include/mapnik/expression_grammar.hpp | 142 +-------------------- include/mapnik/expression_node.hpp | 29 ++--- src/build.py | 2 + src/expression_grammar.cpp | 174 ++++++++++++++++++++++++++ src/expression_node.cpp | 52 ++++++++ 5 files changed, 240 insertions(+), 159 deletions(-) create mode 100644 src/expression_grammar.cpp create mode 100644 src/expression_node.cpp diff --git a/include/mapnik/expression_grammar.hpp b/include/mapnik/expression_grammar.hpp index 8f11aea55..0fe062923 100644 --- a/include/mapnik/expression_grammar.hpp +++ b/include/mapnik/expression_grammar.hpp @@ -86,14 +86,7 @@ struct regex_match_impl : tr_(tr) {} template - expr_node operator() (T0 & node, T1 const& pattern) const - { -#if defined(BOOST_REGEX_HAS_ICU) - return regex_match_node(node,tr_.transcode(pattern.c_str())); -#else - return regex_match_node(node,pattern); -#endif - } + expr_node operator() (T0 & node, T1 const& pattern) const; mapnik::transcoder const& tr_; }; @@ -110,14 +103,7 @@ struct regex_replace_impl : tr_(tr) {} template - expr_node operator() (T0 & node, T1 const& pattern, T2 const& format) const - { -#if defined(BOOST_REGEX_HAS_ICU) - return regex_replace_node(node,tr_.transcode(pattern.c_str()),tr_.transcode(format.c_str())); -#else - return regex_replace_node(node,pattern,format); -#endif - } + expr_node operator() (T0 & node, T1 const& pattern, T2 const& format) const; mapnik::transcoder const& tr_; }; @@ -139,134 +125,12 @@ struct expression_grammar : qi::grammar { typedef qi::rule rule_type; - explicit expression_grammar(mapnik::transcoder const& tr) - : expression_grammar::base_type(expr), - unicode_(unicode_impl(tr)), - regex_match_(regex_match_impl(tr)), - regex_replace_(regex_replace_impl(tr)) - { - using boost::phoenix::construct; - using qi::_1; - using qi::_a; - using qi::_b; - using qi::_r1; -#if BOOST_VERSION > 104200 - using qi::no_skip; -#endif - using qi::lexeme; - using qi::_val; - using qi::lit; - using qi::int_; - using qi::double_; - using qi::hex; - using qi::omit; - using standard_wide::char_; - using standard_wide::no_case; - expr = logical_expr.alias(); - - logical_expr = not_expr [_val = _1] - >> - *( ( ( lit("and") | lit("&&")) >> not_expr [_val && _1] ) - | (( lit("or") | lit("||")) >> not_expr [_val || _1]) - ) - ; - - not_expr = - cond_expr [_val = _1 ] - | ((lit("not") | lit('!')) >> cond_expr [ _val = !_1 ]) - ; - - cond_expr = equality_expr [_val = _1] | additive_expr [_val = _1] - ; - - equality_expr = - relational_expr [_val = _1] - >> *( ( (lit("=") | lit("eq") | lit("is")) >> relational_expr [_val == _1]) - | (( lit("!=") | lit("<>") | lit("neq") ) >> relational_expr [_val != _1]) - ) - ; - - regex_match_expr = lit(".match") - >> lit('(') - >> ustring [_val = _1] - >> lit(')') - ; - - regex_replace_expr = - lit(".replace") - >> lit('(') - >> ustring [_a = _1] - >> lit(',') - >> ustring [_b = _1] - >> lit(')') [_val = regex_replace_(_r1,_a,_b)] - ; - - relational_expr = additive_expr[_val = _1] - >> - *( ( (lit("<=") | lit("le") ) >> additive_expr [ _val <= _1 ]) - | ( (lit('<') | lit("lt") ) >> additive_expr [ _val < _1 ]) - | ( (lit(">=") | lit("ge") ) >> additive_expr [ _val >= _1 ]) - | ( (lit('>') | lit("gt") ) >> additive_expr [ _val > _1 ]) - ) - ; - - additive_expr = multiplicative_expr [_val = _1] - >> * ( '+' >> multiplicative_expr[_val += _1] - | '-' >> multiplicative_expr[_val -= _1] - ) - ; - - multiplicative_expr = unary_expr [_val = _1] - >> *( '*' >> unary_expr [_val *= _1] - | '/' >> unary_expr [_val /= _1] - | '%' >> unary_expr [_val %= _1] - | regex_match_expr[_val = regex_match_(_val, _1)] - | regex_replace_expr(_val) [_val = _1] - ) - ; - - unary_expr = primary_expr [_val = _1] - | '+' >> primary_expr [_val = _1] - | '-' >> primary_expr [_val = -_1] - ; - - primary_expr = strict_double [_val = _1] - | int_ [_val = _1] - | no_case[lit("true")] [_val = true] - | no_case[lit("false")] [_val = false] - | no_case[lit("null")] [_val = value_null() ] - | no_case[geom_type][_val = _1 ] - | ustring [_val = unicode_(_1) ] - | lit("[mapnik::geometry_type]")[_val = construct()] - | attr [_val = construct( _1 ) ] - | '(' >> expr [_val = _1 ] >> ')' - ; - - unesc_char.add("\\a", '\a')("\\b", '\b')("\\f", '\f')("\\n", '\n') - ("\\r", '\r')("\\t", '\t')("\\v", '\v')("\\\\", '\\') - ("\\\'", '\'')("\\\"", '\"') - ; - -#if BOOST_VERSION > 104500 - quote_char %= char_('\'') | char_('"'); - ustring %= omit[quote_char[_a = _1]] - >> *(unesc_char | "\\x" >> hex | (char_ - lit(_a))) - >> lit(_a); - attr %= '[' >> no_skip[+~char_(']')] >> ']'; -#else - ustring %= lit('\'') - >> *(unesc_char | "\\x" >> hex | (char_ - lit('\''))) - >> lit('\''); - attr %= '[' >> lexeme[+(char_ - ']')] >> ']'; -#endif - - } + explicit expression_grammar(mapnik::transcoder const& tr); qi::real_parser > strict_double; boost::phoenix::function unicode_; boost::phoenix::function regex_match_; boost::phoenix::function regex_replace_; - // rule_type expr; rule_type equality_expr; rule_type cond_expr; diff --git a/include/mapnik/expression_node.hpp b/include/mapnik/expression_node.hpp index da5f7e2d9..56b70a9ef 100644 --- a/include/mapnik/expression_node.hpp +++ b/include/mapnik/expression_node.hpp @@ -28,12 +28,12 @@ #include // boost -#include -#include #include #if defined(BOOST_REGEX_HAS_ICU) #include #endif +#include +#include #include namespace mapnik @@ -240,12 +240,10 @@ struct binary_node }; #if defined(BOOST_REGEX_HAS_ICU) + struct regex_match_node { - regex_match_node (expr_node const& a, UnicodeString const& ustr) - : expr(a), - pattern(boost::make_u32regex(ustr)) {} - + regex_match_node (expr_node const& a, UnicodeString const& ustr); expr_node expr; boost::u32regex pattern; }; @@ -253,22 +251,17 @@ struct regex_match_node struct regex_replace_node { - regex_replace_node (expr_node const& a, UnicodeString const& ustr, UnicodeString const& f) - : expr(a), - pattern(boost::make_u32regex(ustr)), - format(f) {} - + regex_replace_node (expr_node const& a, UnicodeString const& ustr, UnicodeString const& f); expr_node expr; boost::u32regex pattern; UnicodeString format; }; + #else + struct regex_match_node { - regex_match_node (expr_node const& a, std::string const& str) - : expr(a), - pattern(str) {} - + regex_match_node (expr_node const& a, std::string const& str); expr_node expr; boost::regex pattern; }; @@ -276,11 +269,7 @@ struct regex_match_node struct regex_replace_node { - regex_replace_node (expr_node const& a, std::string const& str, std::string const& f) - : expr(a), - pattern(str), - format(f) {} - + regex_replace_node (expr_node const& a, std::string const& str, std::string const& f); expr_node expr; boost::regex pattern; std::string format; diff --git a/src/build.py b/src/build.py index c8514b273..a89db439a 100644 --- a/src/build.py +++ b/src/build.py @@ -109,6 +109,8 @@ source = Split( datasource_cache.cpp debug.cpp deepcopy.cpp + expression_node.cpp + expression_grammar.cpp expression_string.cpp expression.cpp transform_expression.cpp diff --git a/src/expression_grammar.cpp b/src/expression_grammar.cpp new file mode 100644 index 000000000..fcc2575f8 --- /dev/null +++ b/src/expression_grammar.cpp @@ -0,0 +1,174 @@ +/***************************************************************************** + * + * This file is part of Mapnik (c++ mapping toolkit) + * + * Copyright (C) 2012 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 + * + *****************************************************************************/ + +#include + +namespace mapnik +{ + +template +expr_node regex_match_impl::operator() (T0 & node, T1 const& pattern) const +{ +#if defined(BOOST_REGEX_HAS_ICU) + return regex_match_node(node,tr_.transcode(pattern.c_str())); +#else + return regex_match_node(node,pattern); +#endif +} + +template +expr_node regex_replace_impl::operator() (T0 & node, T1 const& pattern, T2 const& format) const +{ +#if defined(BOOST_REGEX_HAS_ICU) + return regex_replace_node(node,tr_.transcode(pattern.c_str()),tr_.transcode(format.c_str())); +#else + return regex_replace_node(node,pattern,format); +#endif +} + +template +expression_grammar::expression_grammar(mapnik::transcoder const& tr) + : expression_grammar::base_type(expr), + unicode_(unicode_impl(tr)), + regex_match_(regex_match_impl(tr)), + regex_replace_(regex_replace_impl(tr)) +{ + using boost::phoenix::construct; + using qi::_1; + using qi::_a; + using qi::_b; + using qi::_r1; +#if BOOST_VERSION > 104200 + using qi::no_skip; +#endif + using qi::lexeme; + using qi::_val; + using qi::lit; + using qi::int_; + using qi::double_; + using qi::hex; + using qi::omit; + using standard_wide::char_; + using standard_wide::no_case; + expr = logical_expr.alias(); + + logical_expr = not_expr [_val = _1] + >> + *( ( ( lit("and") | lit("&&")) >> not_expr [_val && _1] ) + | (( lit("or") | lit("||")) >> not_expr [_val || _1]) + ) + ; + + not_expr = + cond_expr [_val = _1 ] + | ((lit("not") | lit('!')) >> cond_expr [ _val = !_1 ]) + ; + + cond_expr = equality_expr [_val = _1] | additive_expr [_val = _1] + ; + + equality_expr = + relational_expr [_val = _1] + >> *( ( (lit("=") | lit("eq") | lit("is")) >> relational_expr [_val == _1]) + | (( lit("!=") | lit("<>") | lit("neq") ) >> relational_expr [_val != _1]) + ) + ; + + regex_match_expr = lit(".match") + >> lit('(') + >> ustring [_val = _1] + >> lit(')') + ; + + regex_replace_expr = + lit(".replace") + >> lit('(') + >> ustring [_a = _1] + >> lit(',') + >> ustring [_b = _1] + >> lit(')') [_val = regex_replace_(_r1,_a,_b)] + ; + + relational_expr = additive_expr[_val = _1] + >> + *( ( (lit("<=") | lit("le") ) >> additive_expr [ _val <= _1 ]) + | ( (lit('<') | lit("lt") ) >> additive_expr [ _val < _1 ]) + | ( (lit(">=") | lit("ge") ) >> additive_expr [ _val >= _1 ]) + | ( (lit('>') | lit("gt") ) >> additive_expr [ _val > _1 ]) + ) + ; + + additive_expr = multiplicative_expr [_val = _1] + >> * ( '+' >> multiplicative_expr[_val += _1] + | '-' >> multiplicative_expr[_val -= _1] + ) + ; + + multiplicative_expr = unary_expr [_val = _1] + >> *( '*' >> unary_expr [_val *= _1] + | '/' >> unary_expr [_val /= _1] + | '%' >> unary_expr [_val %= _1] + | regex_match_expr[_val = regex_match_(_val, _1)] + | regex_replace_expr(_val) [_val = _1] + ) + ; + + unary_expr = primary_expr [_val = _1] + | '+' >> primary_expr [_val = _1] + | '-' >> primary_expr [_val = -_1] + ; + + primary_expr = strict_double [_val = _1] + | int_ [_val = _1] + | no_case[lit("true")] [_val = true] + | no_case[lit("false")] [_val = false] + | no_case[lit("null")] [_val = value_null() ] + | no_case[geom_type][_val = _1 ] + | ustring [_val = unicode_(_1) ] + | lit("[mapnik::geometry_type]")[_val = construct()] + | attr [_val = construct( _1 ) ] + | '(' >> expr [_val = _1 ] >> ')' + ; + + unesc_char.add("\\a", '\a')("\\b", '\b')("\\f", '\f')("\\n", '\n') + ("\\r", '\r')("\\t", '\t')("\\v", '\v')("\\\\", '\\') + ("\\\'", '\'')("\\\"", '\"') + ; + +#if BOOST_VERSION > 104500 + quote_char %= char_('\'') | char_('"'); + ustring %= omit[quote_char[_a = _1]] + >> *(unesc_char | "\\x" >> hex | (char_ - lit(_a))) + >> lit(_a); + attr %= '[' >> no_skip[+~char_(']')] >> ']'; +#else + ustring %= lit('\'') + >> *(unesc_char | "\\x" >> hex | (char_ - lit('\''))) + >> lit('\''); + attr %= '[' >> lexeme[+(char_ - ']')] >> ']'; +#endif + +} + +template struct mapnik::expression_grammar; + +} \ No newline at end of file diff --git a/src/expression_node.cpp b/src/expression_node.cpp new file mode 100644 index 000000000..5c997044d --- /dev/null +++ b/src/expression_node.cpp @@ -0,0 +1,52 @@ +/***************************************************************************** + * + * This file is part of Mapnik (c++ mapping toolkit) + * + * Copyright (C) 2012 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 + * + *****************************************************************************/ + +#include + +namespace mapnik +{ + +#if defined(BOOST_REGEX_HAS_ICU) + +regex_match_node::regex_match_node (expr_node const& a, UnicodeString const& ustr) + : expr(a), + pattern(boost::make_u32regex(ustr)) {} + +regex_replace_node::regex_replace_node (expr_node const& a, UnicodeString const& ustr, UnicodeString const& f) + : expr(a), + pattern(boost::make_u32regex(ustr)), + format(f) {} + +#else +regex_match_node::pattern boost::regex; + +regex_match_node::regex_match_node (expr_node const& a, std::string const& str) + : expr(a), + pattern(str) {} + +regex_replace_node::regex_replace_node (expr_node const& a, std::string const& str, std::string const& f) + : expr(a), + pattern(str), + format(f) {} +#endif + +} \ No newline at end of file From 348dfff0c7cefd92ba5893583165ff6500eeb9c7 Mon Sep 17 00:00:00 2001 From: Dane Springmeyer Date: Mon, 23 Jul 2012 17:03:06 -0700 Subject: [PATCH 117/133] move feature_grammar to cpp file reducing compile time mem usage for feature_collection_parser.cpp - refs #1267 --- include/mapnik/json/feature_grammar.hpp | 192 +------------------- src/build.py | 1 + src/json/feature_grammar.cpp | 227 ++++++++++++++++++++++++ 3 files changed, 230 insertions(+), 190 deletions(-) create mode 100644 src/json/feature_grammar.cpp diff --git a/include/mapnik/json/feature_grammar.hpp b/include/mapnik/json/feature_grammar.hpp index b756daead..b56a991b7 100644 --- a/include/mapnik/json/feature_grammar.hpp +++ b/include/mapnik/json/feature_grammar.hpp @@ -25,6 +25,7 @@ // mapnik #include +#include // spirit::qi #include @@ -135,196 +136,7 @@ struct feature_grammar : qi::grammar { - feature_grammar(mapnik::transcoder const& tr) - : feature_grammar::base_type(feature,"feature"), - put_property_(put_property(tr)) - { - using qi::lit; - using qi::int_; - using qi::double_; -#if BOOST_VERSION > 104200 - using qi::no_skip; -#else - using qi::lexeme; -#endif - using standard_wide::char_; - using qi::_val; - using qi::_1; - using qi::_2; - using qi::_3; - using qi::_4; - using qi::_a; - using qi::_b; - using qi::_r1; - using qi::_r2; - using qi::fail; - using qi::on_error; - using qi::_pass; - using qi::eps; - using qi::raw; - - using phoenix::new_; - using phoenix::push_back; - using phoenix::construct; - - // generic json types - value = object | array | string_ - | number - ; - - pairs = key_value % lit(',') - ; - - key_value = (string_ >> lit(':') >> value) - ; - - object = lit('{') - >> *pairs - >> lit('}') - ; - array = lit('[') - >> value >> *(lit(',') >> value) - >> lit(']') - ; - - number %= strict_double - | int_ - | lit("true") [_val = true] - | lit ("false") [_val = false] - | lit("null")[_val = construct()] - ; - - unesc_char.add - ("\\\"", '\"') // quotation mark - ("\\\\", '\\') // reverse solidus - ("\\/", '/') // solidus - ("\\b", '\b') // backspace - ("\\f", '\f') // formfeed - ("\\n", '\n') // newline - ("\\r", '\r') // carrige return - ("\\t", '\t') // tab - ; - - string_ %= lit('"') >> *(unesc_char | "\\u" >> hex4 | (char_ - lit('"'))) >> lit('"') - ; - - // geojson types - - feature_type = lit("\"type\"") - >> lit(':') - >> lit("\"Feature\"") - ; - - feature = lit('{') - >> (feature_type | (lit("\"geometry\"") > lit(':') > geometry(_r1)) | properties(_r1) | key_value) % lit(',') - >> lit('}') - ; - - properties = lit("\"properties\"") - >> lit(':') >> (lit('{') >> attributes(_r1) >> lit('}')) | lit("null") - ; - - attributes = (string_ [_a = _1] >> lit(':') >> attribute_value [put_property_(_r1,_a,_1)]) % lit(',') - ; - - attribute_value %= number | string_ ; - - // Nabialek trick - FIXME: how to bind argument to dispatch rule? - // geometry = lit("\"geometry\"") - // >> lit(':') >> lit('{') - // >> lit("\"type\"") >> lit(':') >> geometry_dispatch[_a = _1] - // >> lit(',') >> lit("\"coordinates\"") >> lit(':') - // >> qi::lazy(*_a) - // >> lit('}') - // ; - // geometry_dispatch.add - // ("\"Point\"",&point_coordinates) - // ("\"LineString\"",&linestring_coordinates) - // ("\"Polygon\"",&polygon_coordinates) - // ; - ////////////////////////////////////////////////////////////////// - - geometry = (lit('{')[_a = 0 ] - >> lit("\"type\"") >> lit(':') >> geometry_dispatch[_a = _1] // <---- should be Nabialek trick! - >> lit(',') - >> (lit("\"coordinates\"") > lit(':') > coordinates(_r1,_a) - | - lit("\"geometries\"") > lit(':') - >> lit('[') >> geometry_collection(_r1) >> lit(']')) - >> lit('}')) - | lit("null") - ; - - geometry_dispatch.add - ("\"Point\"",1) - ("\"LineString\"",2) - ("\"Polygon\"",3) - ("\"MultiPoint\"",4) - ("\"MultiLineString\"",5) - ("\"MultiPolygon\"",6) - ("\"GeometryCollection\"",7) - // - ; - - coordinates = (eps(_r2 == 1) > point_coordinates(extract_geometry_(_r1))) - | (eps(_r2 == 2) > linestring_coordinates(extract_geometry_(_r1))) - | (eps(_r2 == 3) > polygon_coordinates(extract_geometry_(_r1))) - | (eps(_r2 == 4) > multipoint_coordinates(extract_geometry_(_r1))) - | (eps(_r2 == 5) > multilinestring_coordinates(extract_geometry_(_r1))) - | (eps(_r2 == 6) > multipolygon_coordinates(extract_geometry_(_r1))) - ; - - point_coordinates = eps[ _a = new_(Point) ] - > ( point(SEG_MOVETO,_a) [push_back(_r1,_a)] | eps[cleanup_(_a)][_pass = false] ) - ; - - linestring_coordinates = eps[ _a = new_(LineString)] - > -(points(_a) [push_back(_r1,_a)] - | eps[cleanup_(_a)][_pass = false]) - ; - - polygon_coordinates = eps[ _a = new_(Polygon) ] - > ((lit('[') - > -(points(_a) % lit(',')) - > lit(']')) [push_back(_r1,_a)] - | eps[cleanup_(_a)][_pass = false]) - ; - - multipoint_coordinates = lit('[') - > -(point_coordinates(_r1) % lit(',')) - > lit(']') - ; - - multilinestring_coordinates = lit('[') - > -(linestring_coordinates(_r1) % lit(',')) - > lit(']') - ; - - multipolygon_coordinates = lit('[') - > -(polygon_coordinates(_r1) % lit(',')) - > lit(']') - ; - - geometry_collection = *geometry(_r1) >> *(lit(',') >> geometry(_r1)) - ; - - // point - point = lit('[') > -((double_ > lit(',') > double_)[push_vertex_(_r1,_r2,_1,_2)]) > lit(']'); - // points - points = lit('[')[_a = SEG_MOVETO] > -(point (_a,_r1) % lit(',')[_a = SEG_LINETO]) > lit(']'); - on_error - ( - feature - , std::clog - << phoenix::val("Error! Expecting ") - << _4 // what failed? - << phoenix::val(" here: \"") - << construct(_3, _2) // iterators to error-pos, end - << phoenix::val("\"") - << std::endl - ); - - } + feature_grammar(mapnik::transcoder const& tr); // start // generic JSON diff --git a/src/build.py b/src/build.py index a89db439a..2884f6c52 100644 --- a/src/build.py +++ b/src/build.py @@ -165,6 +165,7 @@ source = Split( svg_points_parser.cpp svg_transform_parser.cpp warp.cpp + json/feature_grammar.cpp json/feature_collection_parser.cpp json/geojson_generator.cpp markers_placement.cpp diff --git a/src/json/feature_grammar.cpp b/src/json/feature_grammar.cpp new file mode 100644 index 000000000..59be9386e --- /dev/null +++ b/src/json/feature_grammar.cpp @@ -0,0 +1,227 @@ +/***************************************************************************** + * + * This file is part of Mapnik (c++ mapping toolkit) + * + * Copyright (C) 2012 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 + * + *****************************************************************************/ + +// mapnik +#include +#include + +// boost +#include + +namespace mapnik { namespace json { + +template +feature_grammar::feature_grammar(mapnik::transcoder const& tr) + : feature_grammar::base_type(feature,"feature"), + put_property_(put_property(tr)) +{ + using qi::lit; + using qi::int_; + using qi::double_; +#if BOOST_VERSION > 104200 + using qi::no_skip; +#else + using qi::lexeme; +#endif + using standard_wide::char_; + using qi::_val; + using qi::_1; + using qi::_2; + using qi::_3; + using qi::_4; + using qi::_a; + using qi::_b; + using qi::_r1; + using qi::_r2; + using qi::fail; + using qi::on_error; + using qi::_pass; + using qi::eps; + using qi::raw; + + using phoenix::new_; + using phoenix::push_back; + using phoenix::construct; + + // generic json types + value = object | array | string_ + | number + ; + + pairs = key_value % lit(',') + ; + + key_value = (string_ >> lit(':') >> value) + ; + + object = lit('{') + >> *pairs + >> lit('}') + ; + array = lit('[') + >> value >> *(lit(',') >> value) + >> lit(']') + ; + + number %= strict_double + | int_ + | lit("true") [_val = true] + | lit ("false") [_val = false] + | lit("null")[_val = construct()] + ; + + unesc_char.add + ("\\\"", '\"') // quotation mark + ("\\\\", '\\') // reverse solidus + ("\\/", '/') // solidus + ("\\b", '\b') // backspace + ("\\f", '\f') // formfeed + ("\\n", '\n') // newline + ("\\r", '\r') // carrige return + ("\\t", '\t') // tab + ; + + string_ %= lit('"') >> *(unesc_char | "\\u" >> hex4 | (char_ - lit('"'))) >> lit('"') + ; + + // geojson types + + feature_type = lit("\"type\"") + >> lit(':') + >> lit("\"Feature\"") + ; + + feature = lit('{') + >> (feature_type | (lit("\"geometry\"") > lit(':') > geometry(_r1)) | properties(_r1) | key_value) % lit(',') + >> lit('}') + ; + + properties = lit("\"properties\"") + >> lit(':') >> (lit('{') >> attributes(_r1) >> lit('}')) | lit("null") + ; + + attributes = (string_ [_a = _1] >> lit(':') >> attribute_value [put_property_(_r1,_a,_1)]) % lit(',') + ; + + attribute_value %= number | string_ ; + + // Nabialek trick - FIXME: how to bind argument to dispatch rule? + // geometry = lit("\"geometry\"") + // >> lit(':') >> lit('{') + // >> lit("\"type\"") >> lit(':') >> geometry_dispatch[_a = _1] + // >> lit(',') >> lit("\"coordinates\"") >> lit(':') + // >> qi::lazy(*_a) + // >> lit('}') + // ; + // geometry_dispatch.add + // ("\"Point\"",&point_coordinates) + // ("\"LineString\"",&linestring_coordinates) + // ("\"Polygon\"",&polygon_coordinates) + // ; + ////////////////////////////////////////////////////////////////// + + geometry = (lit('{')[_a = 0 ] + >> lit("\"type\"") >> lit(':') >> geometry_dispatch[_a = _1] // <---- should be Nabialek trick! + >> lit(',') + >> (lit("\"coordinates\"") > lit(':') > coordinates(_r1,_a) + | + lit("\"geometries\"") > lit(':') + >> lit('[') >> geometry_collection(_r1) >> lit(']')) + >> lit('}')) + | lit("null") + ; + + geometry_dispatch.add + ("\"Point\"",1) + ("\"LineString\"",2) + ("\"Polygon\"",3) + ("\"MultiPoint\"",4) + ("\"MultiLineString\"",5) + ("\"MultiPolygon\"",6) + ("\"GeometryCollection\"",7) + // + ; + + coordinates = (eps(_r2 == 1) > point_coordinates(extract_geometry_(_r1))) + | (eps(_r2 == 2) > linestring_coordinates(extract_geometry_(_r1))) + | (eps(_r2 == 3) > polygon_coordinates(extract_geometry_(_r1))) + | (eps(_r2 == 4) > multipoint_coordinates(extract_geometry_(_r1))) + | (eps(_r2 == 5) > multilinestring_coordinates(extract_geometry_(_r1))) + | (eps(_r2 == 6) > multipolygon_coordinates(extract_geometry_(_r1))) + ; + + point_coordinates = eps[ _a = new_(Point) ] + > ( point(SEG_MOVETO,_a) [push_back(_r1,_a)] | eps[cleanup_(_a)][_pass = false] ) + ; + + linestring_coordinates = eps[ _a = new_(LineString)] + > -(points(_a) [push_back(_r1,_a)] + | eps[cleanup_(_a)][_pass = false]) + ; + + polygon_coordinates = eps[ _a = new_(Polygon) ] + > ((lit('[') + > -(points(_a) % lit(',')) + > lit(']')) [push_back(_r1,_a)] + | eps[cleanup_(_a)][_pass = false]) + ; + + multipoint_coordinates = lit('[') + > -(point_coordinates(_r1) % lit(',')) + > lit(']') + ; + + multilinestring_coordinates = lit('[') + > -(linestring_coordinates(_r1) % lit(',')) + > lit(']') + ; + + multipolygon_coordinates = lit('[') + > -(polygon_coordinates(_r1) % lit(',')) + > lit(']') + ; + + geometry_collection = *geometry(_r1) >> *(lit(',') >> geometry(_r1)) + ; + + // point + point = lit('[') > -((double_ > lit(',') > double_)[push_vertex_(_r1,_r2,_1,_2)]) > lit(']'); + // points + points = lit('[')[_a = SEG_MOVETO] > -(point (_a,_r1) % lit(',')[_a = SEG_LINETO]) > lit(']'); + on_error + ( + feature + , std::clog + << phoenix::val("Error! Expecting ") + << _4 // what failed? + << phoenix::val(" here: \"") + << construct(_3, _2) // iterators to error-pos, end + << phoenix::val("\"") + << std::endl + ); + +} + +template struct mapnik::json::feature_grammar; +template struct mapnik::json::feature_grammar >,mapnik::Feature>; + +}} \ No newline at end of file From a1d6579da2acfa20c10e597f81061f53fc2d801f Mon Sep 17 00:00:00 2001 From: Dane Springmeyer Date: Mon, 23 Jul 2012 17:21:29 -0700 Subject: [PATCH 118/133] silence a few compiler warnings --- plugins/input/osm/basiccurl.cpp | 6 ++++-- plugins/input/postgis/postgis_featureset.cpp | 2 +- plugins/input/postgis/postgis_featureset.hpp | 2 +- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/plugins/input/osm/basiccurl.cpp b/plugins/input/osm/basiccurl.cpp index ef8c32f4e..021eacfff 100755 --- a/plugins/input/osm/basiccurl.cpp +++ b/plugins/input/osm/basiccurl.cpp @@ -39,7 +39,6 @@ CURL_LOAD_DATA* grab_http_response(const char* url) CURL_LOAD_DATA* do_grab(CURL* curl,const char* url) { - CURLcode res; CURL_LOAD_DATA* data = (CURL_LOAD_DATA*)malloc(sizeof(CURL_LOAD_DATA)); data->data = NULL; data->nbytes = 0; @@ -48,7 +47,10 @@ CURL_LOAD_DATA* do_grab(CURL* curl,const char* url) curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, response_callback); curl_easy_setopt(curl, CURLOPT_WRITEDATA, data); - res = curl_easy_perform(curl); + CURLcode res = curl_easy_perform(curl); + if (res !=0) { + std::clog << "error grabbing data\n"; + } return data; } diff --git a/plugins/input/postgis/postgis_featureset.cpp b/plugins/input/postgis/postgis_featureset.cpp index 5ac6e85f4..dd121a36d 100644 --- a/plugins/input/postgis/postgis_featureset.cpp +++ b/plugins/input/postgis/postgis_featureset.cpp @@ -112,7 +112,7 @@ feature_ptr postgis_featureset::next() totalGeomSize_ += size; - int num_attrs = ctx_->size() + 1; + unsigned num_attrs = ctx_->size() + 1; for (; pos < num_attrs; ++pos) { std::string name = rs_->getFieldName(pos); diff --git a/plugins/input/postgis/postgis_featureset.hpp b/plugins/input/postgis/postgis_featureset.hpp index 80c011c83..013a7de0f 100644 --- a/plugins/input/postgis/postgis_featureset.hpp +++ b/plugins/input/postgis/postgis_featureset.hpp @@ -55,7 +55,7 @@ private: boost::shared_ptr rs_; context_ptr ctx_; boost::scoped_ptr tr_; - int totalGeomSize_; + unsigned totalGeomSize_; int feature_id_; bool key_field_; }; From 5c20a9f72a546d3e091f020fbaf9212dda6dfb8c Mon Sep 17 00:00:00 2001 From: Dane Springmeyer Date: Mon, 23 Jul 2012 17:29:10 -0700 Subject: [PATCH 119/133] suppress unused variable compiler warnings with gcc --- include/mapnik/geom_util.hpp | 38 ++++++++++++++++--------- include/mapnik/image_filter_types.hpp | 3 -- include/mapnik/util/geometry_to_wkb.hpp | 9 ++++-- plugins/input/osm/basiccurl.cpp | 2 ++ 4 files changed, 33 insertions(+), 19 deletions(-) diff --git a/include/mapnik/geom_util.hpp b/include/mapnik/geom_util.hpp index 808b34b0f..427f36883 100644 --- a/include/mapnik/geom_util.hpp +++ b/include/mapnik/geom_util.hpp @@ -39,7 +39,7 @@ namespace mapnik template bool clip_test(T p,T q,double& tmin,double& tmax) { - double r; + double r(0); bool result=true; if (p<0.0) { @@ -96,7 +96,8 @@ inline bool point_inside_path(double x,double y,Iter start,Iter end) double x0=boost::get<0>(*start); double y0=boost::get<1>(*start); - double x1,y1; + double x1(0); + double y1(0); while (++start!=end) { if ( boost::get<2>(*start) == SEG_MOVETO) @@ -173,7 +174,8 @@ inline bool point_on_path(double x,double y,Iter start,Iter end, double tol) { double x0=boost::get<0>(*start); double y0=boost::get<1>(*start); - double x1,y1; + double x1(0); + double y1(0); while (++start != end) { if ( boost::get<2>(*start) == SEG_MOVETO) @@ -222,7 +224,10 @@ struct filter_at_point template double path_length(PathType & path) { - double x0,y0,x1,y1; + double x0(0); + double y0(0); + double x1(0); + double y1(0); path.rewind(0); unsigned command = path.vertex(&x0,&y0); if (command == SEG_END) return 0; @@ -239,7 +244,10 @@ double path_length(PathType & path) template bool middle_point(PathType & path, double & x, double & y) { - double x0,y0,x1,y1; + double x0(0); + double y0(0); + double x1(0); + double y1(0); double mid_length = 0.5 * path_length(path); path.rewind(0); unsigned command = path.vertex(&x0,&y0); @@ -268,10 +276,10 @@ namespace label { template bool centroid(PathType & path, double & x, double & y) { - double x0; - double y0; - double x1; - double y1; + double x0(0); + double y0(0); + double x1(0); + double y1(0); double start_x; double start_y; @@ -318,7 +326,10 @@ template bool hit_test(PathType & path, double x, double y, double tol) { bool inside=false; - double x0, y0, x1, y1; + double x0(0); + double y0(0); + double x1(0); + double y1(0); path.rewind(0); unsigned command = path.vertex(&x0, &y0); if (command == SEG_END) return false; @@ -363,11 +374,12 @@ void interior_position(PathType & path, double & x, double & y) std::vector intersections; // only need to store the X as we know the y - double x0; - double y0; + double x0(0); + double y0(0); path.rewind(0); unsigned command = path.vertex(&x0, &y0); - double x1,y1; + double x1(0); + double y1(0); while (SEG_END != (command = path.vertex(&x1, &y1))) { if (command != SEG_MOVETO) diff --git a/include/mapnik/image_filter_types.hpp b/include/mapnik/image_filter_types.hpp index 6f00e1e28..bb19f5392 100644 --- a/include/mapnik/image_filter_types.hpp +++ b/include/mapnik/image_filter_types.hpp @@ -46,9 +46,6 @@ struct agg_stack_blur { agg_stack_blur(unsigned rx_, unsigned ry_) : rx(rx_),ry(ry_) {} - // an attempt to support older boost spirit (< 1.46) - agg_stack_blur() - : rx(1),ry(1) {} unsigned rx; unsigned ry; }; diff --git a/include/mapnik/util/geometry_to_wkb.hpp b/include/mapnik/util/geometry_to_wkb.hpp index 1252479dc..3b0159345 100644 --- a/include/mapnik/util/geometry_to_wkb.hpp +++ b/include/mapnik/util/geometry_to_wkb.hpp @@ -126,7 +126,8 @@ namespace mapnik { namespace util { ss.write(reinterpret_cast(&byte_order),1); int type = static_cast(mapnik::Point); write(ss,type,4,byte_order); - double x,y; + double x(0); + double y(0); g.vertex(0,&x,&y); write(ss,x,8,byte_order); write(ss,y,8,byte_order); @@ -145,7 +146,8 @@ namespace mapnik { namespace util { int type = static_cast(mapnik::LineString); write(ss,type,4,byte_order); write(ss,num_points,4,byte_order); - double x,y; + double x(0); + double y(0); for (unsigned i=0; i< num_points; ++i) { g.vertex(i,&x,&y); @@ -165,7 +167,8 @@ namespace mapnik { namespace util { typedef std::vector linear_ring; boost::ptr_vector rings; - double x,y; + double x(0); + double y(0); std::size_t size = 1 + 4 + 4 ; // byteOrder + wkbType + numRings for (unsigned i=0; i< num_points; ++i) { diff --git a/plugins/input/osm/basiccurl.cpp b/plugins/input/osm/basiccurl.cpp index 021eacfff..600f2f30b 100755 --- a/plugins/input/osm/basiccurl.cpp +++ b/plugins/input/osm/basiccurl.cpp @@ -22,6 +22,8 @@ #include "basiccurl.h" +#include + CURL_LOAD_DATA* grab_http_response(const char* url) { CURL_LOAD_DATA* data; From 5014694591110f14f44ee2058b5b0d9379380f93 Mon Sep 17 00:00:00 2001 From: Dane Springmeyer Date: Mon, 23 Jul 2012 17:41:52 -0700 Subject: [PATCH 120/133] allow auto-opening of rendered svg on linux --- utils/svg2png/svg2png.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/utils/svg2png/svg2png.cpp b/utils/svg2png/svg2png.cpp index 63aa5725d..c06ba187f 100644 --- a/utils/svg2png/svg2png.cpp +++ b/utils/svg2png/svg2png.cpp @@ -182,14 +182,16 @@ int main (int argc,char** argv) boost::algorithm::ireplace_last(svg_name,".svg",".png"); mapnik::save_to_file(im.data(),svg_name,"png"); -#ifdef DARWIN if (auto_open) { std::ostringstream s; +#ifdef DARWIN s << "open " << svg_name; +#else + s << "xdg-open " << svg_name; +#endif system(s.str().c_str()); } -#endif std::clog << "rendered to: " << svg_name << "\n"; } } From 1b23838c583d0e0e9c24c72beb8927ae4251cbdd Mon Sep 17 00:00:00 2001 From: Dane Springmeyer Date: Mon, 23 Jul 2012 17:43:21 -0700 Subject: [PATCH 121/133] avoid uninitialized compiler warning --- plugins/input/csv/csv_datasource.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/plugins/input/csv/csv_datasource.cpp b/plugins/input/csv/csv_datasource.cpp index 0c2d276ed..b10729d3a 100644 --- a/plugins/input/csv/csv_datasource.cpp +++ b/plugins/input/csv/csv_datasource.cpp @@ -277,9 +277,9 @@ void csv_datasource::parse_csv(T& stream, bool has_wkt_field = false; bool has_lat_field = false; bool has_lon_field = false; - unsigned wkt_idx; - unsigned lat_idx; - unsigned lon_idx; + unsigned wkt_idx(0); + unsigned lat_idx(0); + unsigned lon_idx(0); if (!manual_headers_.empty()) { From 2ba016b08b8730f5f7d6808d851db4a8956fd626 Mon Sep 17 00:00:00 2001 From: Dane Springmeyer Date: Mon, 23 Jul 2012 17:52:26 -0700 Subject: [PATCH 122/133] make the svg2png return value sensitive to auto_open results --- utils/svg2png/svg2png.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/utils/svg2png/svg2png.cpp b/utils/svg2png/svg2png.cpp index c06ba187f..228387893 100644 --- a/utils/svg2png/svg2png.cpp +++ b/utils/svg2png/svg2png.cpp @@ -55,7 +55,7 @@ int main (int argc,char** argv) bool verbose = false; bool auto_open = false; - bool error = false; + int return_value = 0; std::vector svg_files; mapnik::logger logger; logger.set_severity(mapnik::logger::error); @@ -131,14 +131,14 @@ int main (int argc,char** argv) if (!marker_ptr) { std::clog << "svg2png error: could not open: '" << svg_name << "'\n"; - error = true; + return_value = -1; continue; } mapnik::marker marker = **marker_ptr; if (!marker.is_vector()) { std::clog << "svg2png error: '" << svg_name << "' is not a valid vector!\n"; - error = true; + return_value = -1; continue; } @@ -190,7 +190,9 @@ int main (int argc,char** argv) #else s << "xdg-open " << svg_name; #endif - system(s.str().c_str()); + int ret = system(s.str().c_str()); + if (ret != 0) + return_value = ret; } std::clog << "rendered to: " << svg_name << "\n"; } @@ -206,7 +208,5 @@ int main (int argc,char** argv) // to make sure valgrind output is clean // http://xmlsoft.org/xmlmem.html xmlCleanupParser(); - if (error) - return -1; - return 0; + return return_value; } From 29deca8db89cbc9d6d86c947907f209614393ebc Mon Sep 17 00:00:00 2001 From: Dane Springmeyer Date: Mon, 23 Jul 2012 18:12:10 -0700 Subject: [PATCH 123/133] shave off 4 seconds from xml_node.cpp compile time (16 -> 12) by moving transform grammar to cpp - refs #1267 --- .../mapnik/transform_expression_grammar.hpp | 60 +----------- src/build.py | 1 + src/transform_expression_grammar.cpp | 91 +++++++++++++++++++ 3 files changed, 93 insertions(+), 59 deletions(-) create mode 100644 src/transform_expression_grammar.cpp diff --git a/include/mapnik/transform_expression_grammar.hpp b/include/mapnik/transform_expression_grammar.hpp index fe09f4e5c..4d4afae9f 100644 --- a/include/mapnik/transform_expression_grammar.hpp +++ b/include/mapnik/transform_expression_grammar.hpp @@ -39,65 +39,7 @@ namespace mapnik { struct transform_expression_grammar : qi::grammar { - explicit transform_expression_grammar(expression_grammar const& g) - : transform_expression_grammar::base_type(start) - { - using boost::phoenix::construct; - using qi::_a; using qi::_1; using qi::_4; - using qi::_b; using qi::_2; using qi::_5; - using qi::_c; using qi::_3; using qi::_6; - using qi::_val; - using qi::char_; - using qi::lit; - using qi::no_case; - using qi::no_skip; - - start = transform_ % no_skip[char_(", ")] ; - - transform_ = matrix | translate | scale | rotate | skewX | skewY ; - - matrix = no_case[lit("matrix")] - >> (lit('(') - >> expr >> -lit(',') - >> expr >> -lit(',') - >> expr >> -lit(',') - >> expr >> -lit(',') - >> expr >> -lit(',') - >> expr >> lit(')')) - [ _val = construct(_1,_2,_3,_4,_5,_6) ]; - - translate = no_case[lit("translate")] - >> (lit('(') - >> expr >> -lit(',') - >> -expr >> lit(')')) - [ _val = construct(_1,_2) ]; - - scale = no_case[lit("scale")] - >> (lit('(') - >> expr >> -lit(',') - >> -expr >> lit(')')) - [ _val = construct(_1,_2) ]; - - rotate = no_case[lit("rotate")] - >> lit('(') - >> expr[_a = _1] >> -lit(',') - >> -(expr [_b = _1] >> -lit(',') >> expr[_c = _1]) - >> lit(')') - [ _val = construct(_a,_b,_c) ]; - - skewX = no_case[lit("skewX")] - >> lit('(') - >> expr [ _val = construct(_1) ] - >> lit(')'); - - skewY = no_case[lit("skewY")] - >> lit('(') - >> expr [ _val = construct(_1) ] - >> lit(')'); - - expr = g.expr.alias(); - } - + explicit transform_expression_grammar(expression_grammar const& g); typedef qi::locals, boost::optional > rotate_locals; diff --git a/src/build.py b/src/build.py index 2884f6c52..1ad71687b 100644 --- a/src/build.py +++ b/src/build.py @@ -113,6 +113,7 @@ source = Split( expression_grammar.cpp expression_string.cpp expression.cpp + transform_expression_grammar.cpp transform_expression.cpp feature_kv_iterator.cpp feature_type_style.cpp diff --git a/src/transform_expression_grammar.cpp b/src/transform_expression_grammar.cpp new file mode 100644 index 000000000..026c6c13e --- /dev/null +++ b/src/transform_expression_grammar.cpp @@ -0,0 +1,91 @@ +/***************************************************************************** + * + * This file is part of Mapnik (c++ mapping toolkit) + * + * Copyright (C) 2012 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 + * + *****************************************************************************/ + +#include + +namespace mapnik { + +namespace qi = boost::spirit::qi; + +template +transform_expression_grammar::transform_expression_grammar(expression_grammar const& g) + : transform_expression_grammar::base_type(start) +{ + using boost::phoenix::construct; + using qi::_a; using qi::_1; using qi::_4; + using qi::_b; using qi::_2; using qi::_5; + using qi::_c; using qi::_3; using qi::_6; + using qi::_val; + using qi::char_; + using qi::lit; + using qi::no_case; + using qi::no_skip; + + start = transform_ % no_skip[char_(", ")] ; + + transform_ = matrix | translate | scale | rotate | skewX | skewY ; + + matrix = no_case[lit("matrix")] + >> (lit('(') + >> expr >> -lit(',') + >> expr >> -lit(',') + >> expr >> -lit(',') + >> expr >> -lit(',') + >> expr >> -lit(',') + >> expr >> lit(')')) + [ _val = construct(_1,_2,_3,_4,_5,_6) ]; + + translate = no_case[lit("translate")] + >> (lit('(') + >> expr >> -lit(',') + >> -expr >> lit(')')) + [ _val = construct(_1,_2) ]; + + scale = no_case[lit("scale")] + >> (lit('(') + >> expr >> -lit(',') + >> -expr >> lit(')')) + [ _val = construct(_1,_2) ]; + + rotate = no_case[lit("rotate")] + >> lit('(') + >> expr[_a = _1] >> -lit(',') + >> -(expr [_b = _1] >> -lit(',') >> expr[_c = _1]) + >> lit(')') + [ _val = construct(_a,_b,_c) ]; + + skewX = no_case[lit("skewX")] + >> lit('(') + >> expr [ _val = construct(_1) ] + >> lit(')'); + + skewY = no_case[lit("skewY")] + >> lit('(') + >> expr [ _val = construct(_1) ] + >> lit(')'); + + expr = g.expr.alias(); +} + +template struct mapnik::transform_expression_grammar; + +} \ No newline at end of file From 8de27eaf6f525fb456ca92d1a5590f2da19cb974 Mon Sep 17 00:00:00 2001 From: artemp Date: Tue, 24 Jul 2012 09:43:05 +0100 Subject: [PATCH 124/133] + use assignment op to initialize built-in types. --- include/mapnik/geom_util.hpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/include/mapnik/geom_util.hpp b/include/mapnik/geom_util.hpp index 427f36883..c891320aa 100644 --- a/include/mapnik/geom_util.hpp +++ b/include/mapnik/geom_util.hpp @@ -374,12 +374,12 @@ void interior_position(PathType & path, double & x, double & y) std::vector intersections; // only need to store the X as we know the y - double x0(0); - double y0(0); + double x0 = 0; + double y0 = 0; path.rewind(0); unsigned command = path.vertex(&x0, &y0); - double x1(0); - double y1(0); + double x1 = 0; + double y1 = 0; while (SEG_END != (command = path.vertex(&x1, &y1))) { if (command != SEG_MOVETO) From 553e767169166d92df3d626d7647e85c2ba8b1f5 Mon Sep 17 00:00:00 2001 From: artemp Date: Tue, 24 Jul 2012 09:44:14 +0100 Subject: [PATCH 125/133] + remove const modifiers --- src/agg/process_point_symbolizer.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/agg/process_point_symbolizer.cpp b/src/agg/process_point_symbolizer.cpp index d1de3f843..aac4355a2 100644 --- a/src/agg/process_point_symbolizer.cpp +++ b/src/agg/process_point_symbolizer.cpp @@ -65,14 +65,14 @@ void agg_renderer::process(point_symbolizer const& sym, if (marker) { box2d const& bbox = (*marker)->bounding_box(); - coord2d const center = bbox.center(); + coord2d center = bbox.center(); agg::trans_affine tr; evaluate_transform(tr, feature, sym.get_image_transform()); tr = agg::trans_affine_scaling(scale_factor_) * tr; - agg::trans_affine_translation const recenter(-center.x, -center.y); - agg::trans_affine const recenter_tr = recenter * tr; + agg::trans_affine_translation recenter(-center.x, -center.y); + agg::trans_affine recenter_tr = recenter * tr; box2d label_ext = bbox * recenter_tr; for (unsigned i=0; i Date: Tue, 24 Jul 2012 14:03:52 +0100 Subject: [PATCH 126/133] + formatting.. --- include/mapnik/marker.hpp | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/include/mapnik/marker.hpp b/include/mapnik/marker.hpp index d8b181ad7..d26819892 100644 --- a/include/mapnik/marker.hpp +++ b/include/mapnik/marker.hpp @@ -65,19 +65,21 @@ public: (*bitmap_data_)->set(0xff000000); } - marker(const boost::optional &data) : bitmap_data_(data) + marker(const boost::optional &data) + : bitmap_data_(data) { } - marker(const boost::optional &data) : vector_data_(data) + marker(const boost::optional &data) + : vector_data_(data) { } - marker(const marker& rhs) : bitmap_data_(rhs.bitmap_data_), vector_data_(rhs.vector_data_) - { - } + marker(const marker& rhs) + : bitmap_data_(rhs.bitmap_data_), vector_data_(rhs.vector_data_) + {} box2d bounding_box() const { From 5ac4d2ec93546029cec9779e0423e597fdc08f1b Mon Sep 17 00:00:00 2001 From: artemp Date: Tue, 24 Jul 2012 14:04:25 +0100 Subject: [PATCH 127/133] + add raster markers support --- src/agg/process_markers_symbolizer.cpp | 257 ++++++++++++++++++++----- 1 file changed, 207 insertions(+), 50 deletions(-) diff --git a/src/agg/process_markers_symbolizer.cpp b/src/agg/process_markers_symbolizer.cpp index ce1fc7310..11f90def7 100644 --- a/src/agg/process_markers_symbolizer.cpp +++ b/src/agg/process_markers_symbolizer.cpp @@ -45,14 +45,18 @@ #include "agg_path_storage.h" #include "agg_conv_clip_polyline.h" #include "agg_conv_transform.h" - +#include "agg_image_filters.h" +#include "agg_trans_bilinear.h" +#include "agg_span_allocator.h" +#include "agg_image_accessors.h" +#include "agg_span_image_filter_rgba.h" // boost #include namespace mapnik { template -struct markers_rasterizer_dispatch +struct vector_markers_rasterizer_dispatch { typedef agg::rgba8 color_type; typedef agg::order_rgba order_type; @@ -62,7 +66,7 @@ struct markers_rasterizer_dispatch typedef agg::renderer_base renderer_base; typedef agg::renderer_scanline_aa_solid renderer_type; - markers_rasterizer_dispatch(BufferType & image_buffer, + vector_markers_rasterizer_dispatch(BufferType & image_buffer, SvgRenderer & svg_renderer, Rasterizer & ras, box2d const& bbox, @@ -91,7 +95,6 @@ struct markers_rasterizer_dispatch if (placement_method == MARKER_POINT_PLACEMENT) { - double x,y; path.rewind(0); label::interior_position(path, x, y); @@ -124,7 +127,6 @@ struct markers_rasterizer_dispatch } } } - private: agg::scanline_u8 sl_; agg::rendering_buffer buf_; @@ -139,11 +141,61 @@ private: double scale_factor_; }; +template +void render_raster_marker(Rasterizer & ras, RendererBuffer & renb, agg::scanline_u8 & sl, + pixel_position const& pos, image_data_32 const& src, + agg::trans_affine const& tr,double opacity, + double scale_factor) +{ -template -void agg_renderer::process(markers_symbolizer const& sym, - mapnik::feature_impl & feature, - proj_transform const& prj_trans) + double width = src.width(); + double height = src.height(); + double p[8]; + p[0] = pos.x; p[1] = pos.y; + p[2] = pos.x + width; p[3] = pos.y; + p[4] = pos.x + width; p[5] = pos.y + height; + p[6] = pos.x; p[7] = pos.y + height; + + agg::trans_affine marker_tr; + + marker_tr *= agg::trans_affine_translation(-pos.x,-pos.y); + marker_tr *= tr; + marker_tr *= agg::trans_affine_scaling(scale_factor); + marker_tr *= agg::trans_affine_translation(pos.x,pos.y); + + marker_tr.transform(&p[0], &p[1]); + marker_tr.transform(&p[2], &p[3]); + marker_tr.transform(&p[4], &p[5]); + marker_tr.transform(&p[6], &p[7]); + + ras.move_to_d(p[0],p[1]); + ras.line_to_d(p[2],p[3]); + ras.line_to_d(p[4],p[5]); + ras.line_to_d(p[6],p[7]); + + typedef agg::rgba8 color_type; + agg::span_allocator sa; + agg::image_filter_bilinear filter_kernel; + agg::image_filter_lut filter(filter_kernel, false); + + agg::rendering_buffer marker_buf((unsigned char *)src.getBytes(), + src.width(), + src.height(), + src.width()*4); + agg::pixfmt_rgba32_pre pixf(marker_buf); + + typedef agg::image_accessor_clone img_accessor_type; + typedef agg::span_interpolator_linear interpolator_type; + typedef agg::span_image_filter_rgba_2x2 span_gen_type; + img_accessor_type ia(pixf); + interpolator_type interpolator(agg::trans_affine(p, 0, 0, width, height) ); + span_gen_type sg(ia, interpolator, filter); + agg::render_scanlines_aa(ras, sl, renb, sa, sg); +} + +template +struct raster_markers_rasterizer_dispatch { typedef agg::rgba8 color_type; typedef agg::order_rgba order_type; @@ -153,6 +205,96 @@ void agg_renderer::process(markers_symbolizer const& sym, typedef agg::renderer_base renderer_base; typedef agg::renderer_scanline_aa_solid renderer_type; + raster_markers_rasterizer_dispatch(BufferType & image_buffer, + Rasterizer & ras, + image_data_32 const& src, + agg::trans_affine const& marker_trans, + markers_symbolizer const& sym, + Detector & detector, + double scale_factor) + : buf_(image_buffer.raw_data(), image_buffer.width(), image_buffer.height(), image_buffer.width() * 4), + pixf_(buf_), + renb_(pixf_), + ras_(ras), + src_(src), + marker_trans_(marker_trans), + sym_(sym), + detector_(detector), + scale_factor_(scale_factor) + { + pixf_.comp_op(static_cast(sym_.comp_op())); + } + + template + void add_path(T & path) + { + marker_placement_e placement_method = sym_.get_marker_placement(); + box2d bbox_(0,0, src_.width(),src_.height()); + + if (placement_method == MARKER_POINT_PLACEMENT) + { + double x,y; + path.rewind(0); + label::interior_position(path, x, y); + agg::trans_affine matrix = marker_trans_; + matrix.translate(x,y); + box2d transformed_bbox = bbox_ * matrix; + + if (sym_.get_allow_overlap() || + detector_.has_placement(transformed_bbox)) + { + + render_raster_marker(ras_, renb_, sl_, pixel_position(x,y), src_, + marker_trans_, sym_.get_opacity(), scale_factor_); + if (!sym_.get_ignore_placement()) + detector_.insert(transformed_bbox); + } + } + else + { + markers_placement placement(path, bbox_, marker_trans_, detector_, + sym_.get_spacing() * scale_factor_, + sym_.get_max_error(), + sym_.get_allow_overlap()); + double x, y, angle; + while (placement.get_point(x, y, angle)) + { + agg::trans_affine matrix = marker_trans_; + matrix.rotate(angle); + render_raster_marker(ras_, renb_, sl_, pixel_position(x,y), src_, + matrix, sym_.get_opacity(), scale_factor_); + } + } + } +private: + agg::scanline_u8 sl_; + agg::rendering_buffer buf_; + pixfmt_comp_type pixf_; + renderer_base renb_; + Rasterizer & ras_; + image_data_32 const& src_; + agg::trans_affine const& marker_trans_; + markers_symbolizer const& sym_; + Detector & detector_; + double scale_factor_; +}; + + +template +void agg_renderer::process(markers_symbolizer const& sym, + feature_impl & feature, + proj_transform const& prj_trans) +{ + typedef agg::rgba8 color_type; + typedef agg::order_rgba order_type; + typedef agg::pixel32_type pixel_type; + typedef agg::comp_op_adaptor_rgba_pre blender_type; // comp blender + typedef agg::pixfmt_custom_blend_rgba pixfmt_comp_type; + typedef agg::renderer_base renderer_base; + typedef agg::renderer_scanline_aa_solid renderer_type; + typedef label_collision_detector4 detector_type; + typedef boost::mpl::vector conv_types; + std::string filename = path_processor_type::evaluate(*sym.get_filename(), feature); if (!filename.empty()) @@ -160,61 +302,76 @@ void agg_renderer::process(markers_symbolizer const& sym, boost::optional mark = mapnik::marker_cache::instance()->find(filename, true); if (mark && *mark) { - if (!(*mark)->is_vector()) - { - MAPNIK_LOG_DEBUG(agg_renderer) << "agg_renderer: markers_symbolizer does not yet support non-SVG markers"; - return; - } - ras_ptr->reset(); ras_ptr->gamma(agg::gamma_power()); agg::trans_affine geom_tr; evaluate_transform(geom_tr, feature, sym.get_transform()); - boost::optional marker = (*mark)->get_vector_data(); - box2d const& bbox = (*marker)->bounding_box(); - + box2d const& bbox = (*mark)->bounding_box(); agg::trans_affine tr; setup_label_transform(tr, bbox, feature, sym); tr = agg::trans_affine_scaling(scale_factor_) * tr; - coord2d center = bbox.center(); agg::trans_affine_translation recenter(-center.x, -center.y); agg::trans_affine marker_trans = recenter * tr; - using namespace mapnik::svg; - vertex_stl_adapter stl_storage((*marker)->source()); - svg_path_adapter svg_path(stl_storage); - - agg::pod_bvector attributes; - bool result = push_explicit_style( (*marker)->attributes(), attributes, sym); - - typedef label_collision_detector4 detector_type; - typedef svg_renderer, - renderer_type, - agg::pixfmt_rgba32 > svg_renderer_type; - typedef markers_rasterizer_dispatch markers_rasterizer_dispatch_type; - typedef boost::mpl::vector conv_types; - - svg_renderer_type svg_renderer(svg_path, result ? attributes : (*marker)->attributes()); - - markers_rasterizer_dispatch_type rasterizer_dispatch(*current_buffer_,svg_renderer,*ras_ptr, - bbox, marker_trans, sym, *detector_, scale_factor_); - - - vertex_converter, markers_rasterizer_dispatch_type, markers_symbolizer, - CoordTransform, proj_transform, agg::trans_affine, conv_types> - converter(query_extent_* 1.1,rasterizer_dispatch, sym,t_,prj_trans,tr,scale_factor_); - - if (sym.clip()) converter.template set(); //optional clip (default: true) - converter.template set(); //always transform - if (sym.smooth() > 0.0) converter.template set(); // optional smooth converter - - BOOST_FOREACH(geometry_type & geom, feature.paths()) + if ((*mark)->is_vector()) { - converter.apply(geom); + using namespace mapnik::svg; + boost::optional marker = (*mark)->get_vector_data(); + + + vertex_stl_adapter stl_storage((*marker)->source()); + svg_path_adapter svg_path(stl_storage); + + agg::pod_bvector attributes; + bool result = push_explicit_style( (*marker)->attributes(), attributes, sym); + + typedef svg_renderer, + renderer_type, + agg::pixfmt_rgba32 > svg_renderer_type; + typedef vector_markers_rasterizer_dispatch dispatch_type; + + + svg_renderer_type svg_renderer(svg_path, result ? attributes : (*marker)->attributes()); + + dispatch_type rasterizer_dispatch(*current_buffer_,svg_renderer,*ras_ptr, + bbox, marker_trans, sym, *detector_, scale_factor_); + + + vertex_converter, dispatch_type, markers_symbolizer, + CoordTransform, proj_transform, agg::trans_affine, conv_types> + converter(query_extent_* 1.1,rasterizer_dispatch, sym,t_,prj_trans,tr,scale_factor_); + + if (sym.clip()) converter.template set(); //optional clip (default: true) + converter.template set(); //always transform + if (sym.smooth() > 0.0) converter.template set(); // optional smooth converter + + BOOST_FOREACH(geometry_type & geom, feature.paths()) + { + converter.apply(geom); + } + } + else // raster markers + { + boost::optional marker = (*mark)->get_bitmap_data(); + typedef raster_markers_rasterizer_dispatch dispatch_type; + dispatch_type rasterizer_dispatch(*current_buffer_,*ras_ptr, **marker, + marker_trans, sym, *detector_, scale_factor_); + vertex_converter, dispatch_type, markers_symbolizer, + CoordTransform, proj_transform, agg::trans_affine, conv_types> + converter(query_extent_* 1.1, rasterizer_dispatch, sym,t_,prj_trans,tr,scale_factor_); + + if (sym.clip()) converter.template set(); //optional clip (default: true) + converter.template set(); //always transform + if (sym.smooth() > 0.0) converter.template set(); // optional smooth converter + + BOOST_FOREACH(geometry_type & geom, feature.paths()) + { + converter.apply(geom); + } } } } From 139b5e710fd912766262acd4b00b0bec9ed5c22a Mon Sep 17 00:00:00 2001 From: artemp Date: Tue, 24 Jul 2012 17:34:59 +0100 Subject: [PATCH 128/133] + centroid: return first vertex if num_vertices == 1 --- include/mapnik/geom_util.hpp | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/include/mapnik/geom_util.hpp b/include/mapnik/geom_util.hpp index c891320aa..a8a058b5e 100644 --- a/include/mapnik/geom_util.hpp +++ b/include/mapnik/geom_util.hpp @@ -276,10 +276,10 @@ namespace label { template bool centroid(PathType & path, double & x, double & y) { - double x0(0); - double y0(0); - double x1(0); - double y1(0); + double x0 = 0; + double y0 = 0; + double x1 = 0; + double y1 = 0; double start_x; double start_y; @@ -293,7 +293,7 @@ bool centroid(PathType & path, double & x, double & y) double atmp = 0; double xtmp = 0; double ytmp = 0; - + unsigned count = 1; while (SEG_END != (command = path.vertex(&x1, &y1))) { double dx0 = x0 - start_x; @@ -307,6 +307,14 @@ bool centroid(PathType & path, double & x, double & y) ytmp += (dy1 + dy0) * ai; x0 = x1; y0 = y1; + ++count; + } + + if (count == 1) + { + x = start_x; + y = start_y; + return true; } if (atmp != 0) From ec12d02209dc979594edd05fef26eebfde10a554 Mon Sep 17 00:00:00 2001 From: Dane Springmeyer Date: Tue, 24 Jul 2012 14:01:46 -0700 Subject: [PATCH 129/133] iterate image_filters by const& - refs #1330 --- src/agg/agg_renderer.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/agg/agg_renderer.cpp b/src/agg/agg_renderer.cpp index bff971757..46f048063 100644 --- a/src/agg/agg_renderer.cpp +++ b/src/agg/agg_renderer.cpp @@ -239,7 +239,7 @@ void agg_renderer::end_style_processing(feature_type_style const& st) { blend_from = true; mapnik::filter::filter_visitor visitor(*current_buffer_); - BOOST_FOREACH(mapnik::filter::filter_type filter_tag, st.image_filters()) + BOOST_FOREACH(mapnik::filter::filter_type const& filter_tag, st.image_filters()) { boost::apply_visitor(visitor, filter_tag); } @@ -256,7 +256,7 @@ void agg_renderer::end_style_processing(feature_type_style const& st) // apply any 'direct' image filters mapnik::filter::filter_visitor visitor(pixmap_); - BOOST_FOREACH(mapnik::filter::filter_type filter_tag, st.direct_image_filters()) + BOOST_FOREACH(mapnik::filter::filter_type const& filter_tag, st.direct_image_filters()) { boost::apply_visitor(visitor, filter_tag); } From 25a7c6bc01b1d81aaccf1adaacd379b93963d965 Mon Sep 17 00:00:00 2001 From: Dane Springmeyer Date: Tue, 24 Jul 2012 14:20:57 -0700 Subject: [PATCH 130/133] + use assignment op to initialize built-in types. --- include/mapnik/geom_util.hpp | 34 +++++++++++++++---------------- include/mapnik/geometry.hpp | 4 ++-- include/mapnik/grid/grid_util.hpp | 13 +++++++----- 3 files changed, 27 insertions(+), 24 deletions(-) diff --git a/include/mapnik/geom_util.hpp b/include/mapnik/geom_util.hpp index a8a058b5e..31432aa33 100644 --- a/include/mapnik/geom_util.hpp +++ b/include/mapnik/geom_util.hpp @@ -39,7 +39,7 @@ namespace mapnik template bool clip_test(T p,T q,double& tmin,double& tmax) { - double r(0); + double r = 0; bool result=true; if (p<0.0) { @@ -96,8 +96,8 @@ inline bool point_inside_path(double x,double y,Iter start,Iter end) double x0=boost::get<0>(*start); double y0=boost::get<1>(*start); - double x1(0); - double y1(0); + double x1 = 0; + double y1 = 0; while (++start!=end) { if ( boost::get<2>(*start) == SEG_MOVETO) @@ -174,8 +174,8 @@ inline bool point_on_path(double x,double y,Iter start,Iter end, double tol) { double x0=boost::get<0>(*start); double y0=boost::get<1>(*start); - double x1(0); - double y1(0); + double x1 = 0; + double y1 = 0; while (++start != end) { if ( boost::get<2>(*start) == SEG_MOVETO) @@ -224,10 +224,10 @@ struct filter_at_point template double path_length(PathType & path) { - double x0(0); - double y0(0); - double x1(0); - double y1(0); + double x0 = 0; + double y0 = 0; + double x1 = 0; + double y1 = 0; path.rewind(0); unsigned command = path.vertex(&x0,&y0); if (command == SEG_END) return 0; @@ -244,10 +244,10 @@ double path_length(PathType & path) template bool middle_point(PathType & path, double & x, double & y) { - double x0(0); - double y0(0); - double x1(0); - double y1(0); + double x0 = 0; + double y0 = 0; + double x1 = 0; + double y1 = 0; double mid_length = 0.5 * path_length(path); path.rewind(0); unsigned command = path.vertex(&x0,&y0); @@ -334,10 +334,10 @@ template bool hit_test(PathType & path, double x, double y, double tol) { bool inside=false; - double x0(0); - double y0(0); - double x1(0); - double y1(0); + double x0 = 0; + double y0 = 0; + double x1 = 0; + double y1 = 0; path.rewind(0); unsigned command = path.vertex(&x0, &y0); if (command == SEG_END) return false; diff --git a/include/mapnik/geometry.hpp b/include/mapnik/geometry.hpp index 20356dc84..31bfeb337 100644 --- a/include/mapnik/geometry.hpp +++ b/include/mapnik/geometry.hpp @@ -88,8 +88,8 @@ public: box2d envelope() const { box2d result; - double x(0); - double y(0); + double x = 0; + double y = 0; rewind(0); for (unsigned i=0;i Date: Tue, 24 Jul 2012 14:24:24 -0700 Subject: [PATCH 131/133] svg2png: no need to scale the svg marker down --- utils/svg2png/svg2png.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/utils/svg2png/svg2png.cpp b/utils/svg2png/svg2png.cpp index 228387893..2c9113b08 100644 --- a/utils/svg2png/svg2png.cpp +++ b/utils/svg2png/svg2png.cpp @@ -149,7 +149,6 @@ int main (int argc,char** argv) agg::scanline_u8 sl; double opacity = 1; - double scale_factor_ = .95; int w = marker.width(); int h = marker.height(); if (verbose) @@ -165,8 +164,6 @@ int main (int argc,char** argv) mapnik::coord c = bbox.center(); // center the svg marker on '0,0' agg::trans_affine mtx = agg::trans_affine_translation(-c.x,-c.y); - // apply symbol transformation to get to map space - mtx *= agg::trans_affine_scaling(scale_factor_); // render the marker at the center of the marker box mtx.translate(0.5 * w, 0.5 * h); From 881ff0180ae5780e3fb0ecc81f0c491049a0353d Mon Sep 17 00:00:00 2001 From: Dane Springmeyer Date: Tue, 24 Jul 2012 14:35:19 -0700 Subject: [PATCH 132/133] suppress gcc Wunused-but-set-variable warnings --- include/mapnik/grid/grid_util.hpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/include/mapnik/grid/grid_util.hpp b/include/mapnik/grid/grid_util.hpp index f681debb7..b1b61c661 100644 --- a/include/mapnik/grid/grid_util.hpp +++ b/include/mapnik/grid/grid_util.hpp @@ -26,6 +26,9 @@ // mapnik #include +// boost +#include + namespace mapnik { /* @@ -57,6 +60,8 @@ static inline void scale_grid(mapnik::grid::data_type & target, unsigned yprt1 = 0; unsigned xprt = 0; unsigned xprt1 = 0; + boost::ignore_unused_variable_warning(yprt1); + boost::ignore_unused_variable_warning(xprt1); //no scaling or subpixel offset if (target_height == source_height && target_width == source_width && offs_x == 0 && offs_y == 0){ From 3f444302f04424292cd7e26cd1acc7dc3a0aebd6 Mon Sep 17 00:00:00 2001 From: Dane Springmeyer Date: Tue, 24 Jul 2012 15:04:39 -0700 Subject: [PATCH 133/133] move wkb_generator.cpp to cpp to reduce grammar compilation burden in the python bindings --- .../mapnik/util/geometry_wkt_generator.hpp | 236 +++++------------- src/build.py | 1 + src/wkb_generator.cpp | 141 +++++++++++ 3 files changed, 207 insertions(+), 171 deletions(-) create mode 100644 src/wkb_generator.cpp diff --git a/include/mapnik/util/geometry_wkt_generator.hpp b/include/mapnik/util/geometry_wkt_generator.hpp index 46780e5fd..969b932d6 100644 --- a/include/mapnik/util/geometry_wkt_generator.hpp +++ b/include/mapnik/util/geometry_wkt_generator.hpp @@ -26,8 +26,6 @@ // mapnik #include #include -#include -#include // boost #include @@ -55,161 +53,88 @@ struct is_container namespace mapnik { namespace util { - namespace karma = boost::spirit::karma; - namespace phoenix = boost::phoenix; - - namespace { - - struct get_type - { - template - struct result { typedef int type; }; - - int operator() (geometry_type const& geom) const - { - return static_cast(geom.type()); - } - }; - - struct get_first - { - template - struct result { typedef geometry_type::value_type const type; }; - - geometry_type::value_type const operator() (geometry_type const& geom) const - { - geometry_type::value_type coord; - boost::get<0>(coord) = geom.vertex(0,&boost::get<1>(coord),&boost::get<2>(coord)); - return coord; - } - }; - - - struct multi_geometry_ - { - template - struct result { typedef bool type; }; - - bool operator() (geometry_container const& geom) const - { - return geom.size() > 1 ? true : false; - } - }; - - struct multi_geometry_type - { - template - struct result { typedef boost::tuple type; }; - - boost::tuple operator() (geometry_container const& geom) const - { - unsigned type = 0u; - bool collection = false; - - geometry_container::const_iterator itr = geom.begin(); - geometry_container::const_iterator end = geom.end(); - - for ( ; itr != end; ++itr) - { - if (type != 0 && itr->type() != type) - { - collection = true; - break; - } - type = itr->type(); - } - return boost::tuple(type, collection); - } - }; +namespace karma = boost::spirit::karma; +namespace phoenix = boost::phoenix; +namespace { +struct get_type +{ template - struct wkt_coordinate_policy : karma::real_policies - { - typedef boost::spirit::karma::real_policies base_type; - static int floatfield(T n) { return base_type::fmtflags::fixed; } - static unsigned precision(T n) { return 6 ;} - }; + struct result { typedef int type; }; + int operator() (geometry_type const& geom) const + { + return static_cast(geom.type()); } +}; - template - struct wkt_generator : - karma::grammar +struct get_first +{ + template + struct result { typedef geometry_type::value_type const type; }; + + geometry_type::value_type const operator() (geometry_type const& geom) const { + geometry_type::value_type coord; + boost::get<0>(coord) = geom.vertex(0,&boost::get<1>(coord),&boost::get<2>(coord)); + return coord; + } +}; - wkt_generator(bool single = false) - : wkt_generator::base_type(wkt) - { - using boost::spirit::karma::uint_; - using boost::spirit::karma::_val; - using boost::spirit::karma::_1; - using boost::spirit::karma::lit; - using boost::spirit::karma::_a; - using boost::spirit::karma::_r1; - using boost::spirit::karma::eps; - using boost::spirit::karma::string; - wkt = point | linestring | polygon - ; +struct multi_geometry_ +{ + template + struct result { typedef bool type; }; - point = &uint_(mapnik::Point)[_1 = _type(_val)] - << string[ phoenix::if_ (single) [_1 = "Point("] - .else_[_1 = "("]] - << point_coord [_1 = _first(_val)] << lit(')') - ; + bool operator() (geometry_container const& geom) const + { + return geom.size() > 1 ? true : false; + } +}; - linestring = &uint_(mapnik::LineString)[_1 = _type(_val)] - << string[ phoenix::if_ (single) [_1 = "LineString("] - .else_[_1 = "("]] - << coords - << lit(')') - ; +struct multi_geometry_type +{ + template + struct result { typedef boost::tuple type; }; - polygon = &uint_(mapnik::Polygon)[_1 = _type(_val)] - << string[ phoenix::if_ (single) [_1 = "Polygon("] - .else_[_1 = "("]] - << coords2 - << lit("))") - ; + boost::tuple operator() (geometry_container const& geom) const; +}; - point_coord = &uint_ << coord_type << lit(' ') << coord_type - ; - polygon_coord %= ( &uint_(mapnik::SEG_MOVETO) << eps[_r1 += 1] - << string[ if_ (_r1 > 1) [_1 = "),("] - .else_[_1 = "("] ] | &uint_ << ",") - << coord_type - << lit(' ') - << coord_type - ; +template +struct wkt_coordinate_policy : karma::real_policies +{ + typedef boost::spirit::karma::real_policies base_type; + static int floatfield(T n) { return base_type::fmtflags::fixed; } + static unsigned precision(T n) { return 6 ;} +}; - coords2 %= *polygon_coord(_a) - ; +} - coords = point_coord % lit(',') - ; +template +struct wkt_generator : + karma::grammar +{ + wkt_generator(bool single = false); + // rules + karma::rule wkt; + karma::rule point; + karma::rule linestring; + karma::rule polygon; - } - // rules - karma::rule wkt; - karma::rule point; - karma::rule linestring; - karma::rule polygon; - - karma::rule coords; - karma::rule, geometry_type const& ()> coords2; - karma::rule point_coord; - karma::rule polygon_coord; - - // phoenix functions - phoenix::function _type; - phoenix::function _first; - // - karma::real_generator > coord_type; - - }; + karma::rule coords; + karma::rule, geometry_type const& ()> coords2; + karma::rule point_coord; + karma::rule polygon_coord; + // phoenix functions + phoenix::function _type; + phoenix::function _first; + // + karma::real_generator > coord_type; +}; template @@ -217,38 +142,7 @@ struct wkt_multi_generator : karma::grammar >, geometry_container const& ()> { - wkt_multi_generator() - : wkt_multi_generator::base_type(wkt) - { - using boost::spirit::karma::lit; - using boost::spirit::karma::eps; - using boost::spirit::karma::_val; - using boost::spirit::karma::_1; - using boost::spirit::karma::_a; - - geometry_types.add - (mapnik::Point,"Point") - (mapnik::LineString,"LineString") - (mapnik::Polygon,"Polygon") - ; - - wkt = eps(phoenix::at_c<1>(_a))[_a = _multi_type(_val)] - << lit("GeometryCollection(") << geometry << lit(")") - | eps(is_multi(_val)) << lit("Multi") << geometry_types[_1 = phoenix::at_c<0>(_a)] - << "(" << multi_geometry << ")" - | geometry - ; - - geometry = -(single_geometry % lit(',')) - ; - - single_geometry = geometry_types[_1 = _type(_val)] << path - ; - - multi_geometry = -(path % lit(',')) - ; - - } + wkt_multi_generator(); // rules karma::rule >, geometry_container const& ()> wkt; karma::rule geometry; diff --git a/src/build.py b/src/build.py index 1ad71687b..cf75e6b20 100644 --- a/src/build.py +++ b/src/build.py @@ -144,6 +144,7 @@ source = Split( text_symbolizer.cpp tiff_reader.cpp wkb.cpp + wkb_generator.cpp projection.cpp proj_transform.cpp distance.cpp diff --git a/src/wkb_generator.cpp b/src/wkb_generator.cpp new file mode 100644 index 000000000..68decfc9e --- /dev/null +++ b/src/wkb_generator.cpp @@ -0,0 +1,141 @@ +/***************************************************************************** + * + * This file is part of Mapnik (c++ mapping toolkit) + * + * Copyright (C) 2012 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 + * + *****************************************************************************/ + +#include +#include +#include + +namespace mapnik { namespace util { + +boost::tuple multi_geometry_type::operator() (geometry_container const& geom) const +{ + unsigned type = 0u; + bool collection = false; + + geometry_container::const_iterator itr = geom.begin(); + geometry_container::const_iterator end = geom.end(); + + for ( ; itr != end; ++itr) + { + if (type != 0 && itr->type() != type) + { + collection = true; + break; + } + type = itr->type(); + } + return boost::tuple(type, collection); +} + +template +wkt_generator::wkt_generator(bool single) + : wkt_generator::base_type(wkt) +{ + using boost::spirit::karma::uint_; + using boost::spirit::karma::_val; + using boost::spirit::karma::_1; + using boost::spirit::karma::lit; + using boost::spirit::karma::_a; + using boost::spirit::karma::_r1; + using boost::spirit::karma::eps; + using boost::spirit::karma::string; + + wkt = point | linestring | polygon + ; + + point = &uint_(mapnik::Point)[_1 = _type(_val)] + << string[ phoenix::if_ (single) [_1 = "Point("] + .else_[_1 = "("]] + << point_coord [_1 = _first(_val)] << lit(')') + ; + + linestring = &uint_(mapnik::LineString)[_1 = _type(_val)] + << string[ phoenix::if_ (single) [_1 = "LineString("] + .else_[_1 = "("]] + << coords + << lit(')') + ; + + polygon = &uint_(mapnik::Polygon)[_1 = _type(_val)] + << string[ phoenix::if_ (single) [_1 = "Polygon("] + .else_[_1 = "("]] + << coords2 + << lit("))") + ; + + point_coord = &uint_ << coord_type << lit(' ') << coord_type + ; + + polygon_coord %= ( &uint_(mapnik::SEG_MOVETO) << eps[_r1 += 1] + << string[ if_ (_r1 > 1) [_1 = "),("] + .else_[_1 = "("] ] | &uint_ << ",") + << coord_type + << lit(' ') + << coord_type + ; + + coords2 %= *polygon_coord(_a) + ; + + coords = point_coord % lit(',') + ; +} + +template +wkt_multi_generator::wkt_multi_generator() + : wkt_multi_generator::base_type(wkt) +{ + using boost::spirit::karma::lit; + using boost::spirit::karma::eps; + using boost::spirit::karma::_val; + using boost::spirit::karma::_1; + using boost::spirit::karma::_a; + + geometry_types.add + (mapnik::Point,"Point") + (mapnik::LineString,"LineString") + (mapnik::Polygon,"Polygon") + ; + + wkt = eps(phoenix::at_c<1>(_a))[_a = _multi_type(_val)] + << lit("GeometryCollection(") << geometry << lit(")") + | eps(is_multi(_val)) << lit("Multi") << geometry_types[_1 = phoenix::at_c<0>(_a)] + << "(" << multi_geometry << ")" + | geometry + ; + + geometry = -(single_geometry % lit(',')) + ; + + single_geometry = geometry_types[_1 = _type(_val)] << path + ; + + multi_geometry = -(path % lit(',')) + ; + +} + +template struct mapnik::util::wkt_generator >; +template struct mapnik::util::wkt_multi_generator >; + + +}} \ No newline at end of file