From 2e76ff1958de5ead81208559c8666377f0927dda Mon Sep 17 00:00:00 2001 From: Dane Springmeyer Date: Mon, 2 Apr 2012 11:57:24 -0700 Subject: [PATCH 01/13] make stroke property on line_symbolizer a reference when accessed from python (not a copy) --- bindings/python/mapnik_line_symbolizer.cpp | 2 +- tests/python_tests/object_test.py | 9 +++++++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/bindings/python/mapnik_line_symbolizer.cpp b/bindings/python/mapnik_line_symbolizer.cpp index 9c7053b90..7ce8d5dc7 100644 --- a/bindings/python/mapnik_line_symbolizer.cpp +++ b/bindings/python/mapnik_line_symbolizer.cpp @@ -60,7 +60,7 @@ void export_line_symbolizer() "Set/get the rasterization method of the line of the point") .add_property("stroke",make_function (&line_symbolizer::get_stroke, - return_value_policy()), + return_value_policy()), &line_symbolizer::set_stroke) .add_property("smooth", &line_symbolizer::smooth, diff --git a/tests/python_tests/object_test.py b/tests/python_tests/object_test.py index cf0920d55..9bcfc0cad 100644 --- a/tests/python_tests/object_test.py +++ b/tests/python_tests/object_test.py @@ -21,6 +21,15 @@ def test_line_symbolizer_init(): s = mapnik.LineSymbolizer() eq_(s.rasterizer, mapnik.line_rasterizer.FULL) +def test_line_symbolizer_stroke_reference(): + l = mapnik.LineSymbolizer(mapnik.Color('green'),0.1) + l.stroke.add_dash(.1,.1) + l.stroke.add_dash(.1,.1) + eq_(l.stroke.get_dashes(), [(.1,.1),(.1,.1)]) + eq_(l.stroke.color,mapnik.Color('green')) + eq_(l.stroke.opacity,1.0) + assert_almost_equal(l.stroke.width,0.1) + # ShieldSymbolizer initialization def test_shieldsymbolizer_init(): s = mapnik.ShieldSymbolizer(mapnik.Expression('[Field Name]'), 'DejaVu Sans Bold', 6, mapnik.Color('#000000'), mapnik.PathExpression('../data/images/dummy.png')) From 39a1477eb2147c7f85d2c9f38645e3f71034402f Mon Sep 17 00:00:00 2001 From: Dane Springmeyer Date: Mon, 30 Jul 2012 23:20:20 -0700 Subject: [PATCH 02/13] allow marker-width and marker-height to apply directly to ellipse rx/ry - maintaining ability to precisely control ellipse dimensions, combine with transforms, and avoid scaling line-widths - refs #1348 and #1347 --- src/agg/process_markers_symbolizer.cpp | 110 ++++++++++++++++++++----- 1 file changed, 89 insertions(+), 21 deletions(-) diff --git a/src/agg/process_markers_symbolizer.cpp b/src/agg/process_markers_symbolizer.cpp index bec7f92e1..bc5f9c851 100644 --- a/src/agg/process_markers_symbolizer.cpp +++ b/src/agg/process_markers_symbolizer.cpp @@ -32,12 +32,16 @@ #include #include #include +#include +#include #include +#include #include #include // agg #include "agg_basics.h" +#include "agg_ellipse.h" #include "agg_rendering_buffer.h" #include "agg_pixfmt_rgba.h" #include "agg_rasterizer_scanline_aa.h" @@ -318,29 +322,92 @@ void agg_renderer::process(markers_symbolizer const& sym, renderer_type, agg::pixfmt_rgba32 > svg_renderer_type; typedef vector_markers_rasterizer_dispatch dispatch_type; - box2d const& bbox = (*mark)->bounding_box(); - setup_label_transform(tr, bbox, feature, sym); - coord2d center = bbox.center(); - agg::trans_affine_translation recenter(-center.x, -center.y); - agg::trans_affine marker_trans = recenter * tr; - boost::optional vector_marker = (*mark)->get_vector_data(); - vertex_stl_adapter stl_storage((*vector_marker)->source()); - svg_path_adapter svg_path(stl_storage); - agg::pod_bvector attributes; - bool result = push_explicit_style( (*vector_marker)->attributes(), attributes, sym); - svg_renderer_type svg_renderer(svg_path, result ? attributes : (*vector_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()) + boost::optional const& stock_vector_marker = (*mark)->get_vector_data(); + expression_ptr const& width_expr = sym.get_width(); + expression_ptr const& height_expr = sym.get_height(); + + // special case for simple ellipse markers + // to allow for full control over rx/ry dimensions + if (filename == "shape://ellipse" + && (width_expr || height_expr)) { - converter.apply(geom); + double width = 0; + double height = 0; + if (width_expr && height_expr) + { + width = boost::apply_visitor(evaluate(feature), *width_expr).to_double(); + height = boost::apply_visitor(evaluate(feature), *height_expr).to_double(); + } + else if (width_expr) + { + width = boost::apply_visitor(evaluate(feature), *width_expr).to_double(); + height = width; + } + else if (height_expr) + { + height = boost::apply_visitor(evaluate(feature), *height_expr).to_double(); + width = height; + } + // create a new marker + svg_storage_type marker_ellipse; + vertex_stl_adapter stl_storage(marker_ellipse.source()); + svg_path_adapter svg_path(stl_storage); + svg_converter_type styled_svg(svg_path, marker_ellipse.attributes()); + styled_svg.push_attr(); + styled_svg.begin_path(); + agg::ellipse c(0, 0, width/2.0, height/2.0); + styled_svg.storage().concat_path(c); + styled_svg.end_path(); + styled_svg.pop_attr(); + double lox,loy,hix,hiy; + styled_svg.bounding_rect(&lox, &loy, &hix, &hiy); + marker_ellipse.set_bounding_box(lox,loy,hix,hiy); + agg::pod_bvector attributes; + bool result = push_explicit_style( (*stock_vector_marker)->attributes(), attributes, sym); + svg_renderer_type svg_renderer(svg_path, result ? attributes : (*stock_vector_marker)->attributes()); + evaluate_transform(tr, feature, sym.get_image_transform()); + box2d bbox = marker_ellipse.bounding_box(); + coord2d center = bbox.center(); + agg::trans_affine_translation recenter(-center.x, -center.y); + agg::trans_affine marker_trans = recenter * tr; + 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 + { + box2d const& bbox = (*mark)->bounding_box(); + setup_label_transform(tr, bbox, feature, sym); + coord2d center = bbox.center(); + agg::trans_affine_translation recenter(-center.x, -center.y); + agg::trans_affine marker_trans = recenter * tr; + vertex_stl_adapter stl_storage((*stock_vector_marker)->source()); + svg_path_adapter svg_path(stl_storage); + agg::pod_bvector attributes; + bool result = push_explicit_style( (*stock_vector_marker)->attributes(), attributes, sym); + svg_renderer_type svg_renderer(svg_path, result ? attributes : (*stock_vector_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 @@ -357,6 +424,7 @@ void agg_renderer::process(markers_symbolizer const& sym, 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 From 6c984b4f13dc5660ccdb2c396d3b688f8251feb4 Mon Sep 17 00:00:00 2001 From: Dane Springmeyer Date: Tue, 31 Jul 2012 16:03:51 -0700 Subject: [PATCH 03/13] add testcase for #1365 --- .../good_maps/marker_ellipse_transform2.xml | 66 +++++++++++++++++++ 1 file changed, 66 insertions(+) create mode 100644 tests/data/good_maps/marker_ellipse_transform2.xml diff --git a/tests/data/good_maps/marker_ellipse_transform2.xml b/tests/data/good_maps/marker_ellipse_transform2.xml new file mode 100644 index 000000000..048353adf --- /dev/null +++ b/tests/data/good_maps/marker_ellipse_transform2.xml @@ -0,0 +1,66 @@ + + + + + + ellipse + + csv + +x,y +2.5,2.5 + + + + + + + + + + frame + + csv + +x,y +0,0 +5,0 +0,5 +5,5 + + + + + \ No newline at end of file From 4d2eb73e3b3a4b787d0e617079d22ea4710e9072 Mon Sep 17 00:00:00 2001 From: Dane Springmeyer Date: Tue, 31 Jul 2012 16:04:42 -0700 Subject: [PATCH 04/13] add tests for complex marker rendering functionality --- .../good_maps/marker_ellipse_transform.xml | 66 ++++++++++++++++++ .../support/mapnik-marker-ellipse-render1.png | Bin 0 -> 15130 bytes 2 files changed, 66 insertions(+) create mode 100644 tests/data/good_maps/marker_ellipse_transform.xml create mode 100644 tests/python_tests/images/support/mapnik-marker-ellipse-render1.png diff --git a/tests/data/good_maps/marker_ellipse_transform.xml b/tests/data/good_maps/marker_ellipse_transform.xml new file mode 100644 index 000000000..e96595619 --- /dev/null +++ b/tests/data/good_maps/marker_ellipse_transform.xml @@ -0,0 +1,66 @@ + + + + + + ellipse + + csv + +x,y +2.5,2.5 + + + + + + + + + + frame + + csv + +x,y +0,0 +5,0 +0,5 +5,5 + + + + + \ No newline at end of file diff --git a/tests/python_tests/images/support/mapnik-marker-ellipse-render1.png b/tests/python_tests/images/support/mapnik-marker-ellipse-render1.png new file mode 100644 index 0000000000000000000000000000000000000000..5a74baad0e4ec3a6f51b74a06db7b060ce8dcd9f GIT binary patch literal 15130 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 aioa$P)jk(7LT{c|Kwd^!x Date: Tue, 31 Jul 2012 16:40:30 -0700 Subject: [PATCH 05/13] move ellipse contruction code to marker_helpers --- include/mapnik/marker_helpers.hpp | 48 +++++++++++++++++++++++--- src/agg/process_markers_symbolizer.cpp | 44 +++++------------------ 2 files changed, 53 insertions(+), 39 deletions(-) diff --git a/include/mapnik/marker_helpers.hpp b/include/mapnik/marker_helpers.hpp index 4d7a2be78..f22dd6ec5 100644 --- a/include/mapnik/marker_helpers.hpp +++ b/include/mapnik/marker_helpers.hpp @@ -27,12 +27,51 @@ #include #include #include +#include +#include + +// agg +#include "agg_ellipse.h" // boost #include namespace mapnik { +template +void build_ellipse(T const& sym, mapnik::feature_impl const& feature, svg_storage_type & marker_ellipse, svg::svg_path_adapter & svg_path) +{ + expression_ptr const& width_expr = sym.get_width(); + expression_ptr const& height_expr = sym.get_height(); + double width = 0; + double height = 0; + if (width_expr && height_expr) + { + width = boost::apply_visitor(evaluate(feature), *width_expr).to_double(); + height = boost::apply_visitor(evaluate(feature), *height_expr).to_double(); + } + else if (width_expr) + { + width = boost::apply_visitor(evaluate(feature), *width_expr).to_double(); + height = width; + } + else if (height_expr) + { + height = boost::apply_visitor(evaluate(feature), *height_expr).to_double(); + width = height; + } + svg::svg_converter_type styled_svg(svg_path, marker_ellipse.attributes()); + styled_svg.push_attr(); + styled_svg.begin_path(); + agg::ellipse c(0, 0, width/2.0, height/2.0); + styled_svg.storage().concat_path(c); + styled_svg.end_path(); + styled_svg.pop_attr(); + double lox,loy,hix,hiy; + styled_svg.bounding_rect(&lox, &loy, &hix, &hiy); + marker_ellipse.set_bounding_box(lox,loy,hix,hiy); +} + template bool push_explicit_style(Attr const& src, Attr & dst, markers_symbolizer const& sym) { @@ -42,10 +81,12 @@ bool push_explicit_style(Attr const& src, Attr & dst, markers_symbolizer const& boost::optional const& fill_opacity = sym.get_fill_opacity(); if (strk || fill || opacity || fill_opacity) { + bool success = false; for(unsigned i = 0; i < src.size(); ++i) { - mapnik::svg::path_attributes attr = src[i]; - + success = true; + dst.push_back(src[i]); + mapnik::svg::path_attributes & attr = dst.last(); if (attr.stroke_flag) { // TODO - stroke attributes need to be boost::optional @@ -87,9 +128,8 @@ bool push_explicit_style(Attr const& src, Attr & dst, markers_symbolizer const& attr.fill_opacity = *fill_opacity; } } - dst.push_back(attr); } - return true; + return success; } return false; } diff --git a/src/agg/process_markers_symbolizer.cpp b/src/agg/process_markers_symbolizer.cpp index bc5f9c851..40c7336a7 100644 --- a/src/agg/process_markers_symbolizer.cpp +++ b/src/agg/process_markers_symbolizer.cpp @@ -33,7 +33,6 @@ #include #include #include -#include #include #include #include @@ -41,7 +40,6 @@ // agg #include "agg_basics.h" -#include "agg_ellipse.h" #include "agg_rendering_buffer.h" #include "agg_pixfmt_rgba.h" #include "agg_rasterizer_scanline_aa.h" @@ -317,12 +315,15 @@ void agg_renderer::process(markers_symbolizer const& sym, { using namespace mapnik::svg; typedef agg::renderer_scanline_aa_solid renderer_type; + typedef agg::pod_bvector svg_attribute_type; typedef svg_renderer, + svg_attribute_type, renderer_type, agg::pixfmt_rgba32 > svg_renderer_type; - typedef vector_markers_rasterizer_dispatch dispatch_type; - + typedef vector_markers_rasterizer_dispatch dispatch_type; boost::optional const& stock_vector_marker = (*mark)->get_vector_data(); expression_ptr const& width_expr = sym.get_width(); expression_ptr const& height_expr = sym.get_height(); @@ -332,38 +333,11 @@ void agg_renderer::process(markers_symbolizer const& sym, if (filename == "shape://ellipse" && (width_expr || height_expr)) { - double width = 0; - double height = 0; - if (width_expr && height_expr) - { - width = boost::apply_visitor(evaluate(feature), *width_expr).to_double(); - height = boost::apply_visitor(evaluate(feature), *height_expr).to_double(); - } - else if (width_expr) - { - width = boost::apply_visitor(evaluate(feature), *width_expr).to_double(); - height = width; - } - else if (height_expr) - { - height = boost::apply_visitor(evaluate(feature), *height_expr).to_double(); - width = height; - } - // create a new marker svg_storage_type marker_ellipse; vertex_stl_adapter stl_storage(marker_ellipse.source()); svg_path_adapter svg_path(stl_storage); - svg_converter_type styled_svg(svg_path, marker_ellipse.attributes()); - styled_svg.push_attr(); - styled_svg.begin_path(); - agg::ellipse c(0, 0, width/2.0, height/2.0); - styled_svg.storage().concat_path(c); - styled_svg.end_path(); - styled_svg.pop_attr(); - double lox,loy,hix,hiy; - styled_svg.bounding_rect(&lox, &loy, &hix, &hiy); - marker_ellipse.set_bounding_box(lox,loy,hix,hiy); - agg::pod_bvector attributes; + build_ellipse(sym, feature, marker_ellipse, svg_path); + svg_attribute_type attributes; bool result = push_explicit_style( (*stock_vector_marker)->attributes(), attributes, sym); svg_renderer_type svg_renderer(svg_path, result ? attributes : (*stock_vector_marker)->attributes()); evaluate_transform(tr, feature, sym.get_image_transform()); @@ -393,7 +367,7 @@ void agg_renderer::process(markers_symbolizer const& sym, agg::trans_affine marker_trans = recenter * tr; vertex_stl_adapter stl_storage((*stock_vector_marker)->source()); svg_path_adapter svg_path(stl_storage); - agg::pod_bvector attributes; + svg_attribute_type attributes; bool result = push_explicit_style( (*stock_vector_marker)->attributes(), attributes, sym); svg_renderer_type svg_renderer(svg_path, result ? attributes : (*stock_vector_marker)->attributes()); dispatch_type rasterizer_dispatch(*current_buffer_,svg_renderer,*ras_ptr, From 3867a75adf90d807d156ee6fb52b1b432c66d718 Mon Sep 17 00:00:00 2001 From: Dane Springmeyer Date: Tue, 31 Jul 2012 16:42:07 -0700 Subject: [PATCH 06/13] comment crashing test --- .../markers_complex_rendering_test.py | 39 +++++++++++++++++++ 1 file changed, 39 insertions(+) create mode 100644 tests/python_tests/markers_complex_rendering_test.py diff --git a/tests/python_tests/markers_complex_rendering_test.py b/tests/python_tests/markers_complex_rendering_test.py new file mode 100644 index 000000000..a3173abbd --- /dev/null +++ b/tests/python_tests/markers_complex_rendering_test.py @@ -0,0 +1,39 @@ +#coding=utf8 +import os +import mapnik +from utilities import execution_path +from nose.tools import * + +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_marker_ellipse_render1(): + m = mapnik.Map(256,256) + mapnik.load_map(m,'../data/good_maps/marker_ellipse_transform.xml') + m.zoom_all() + im = mapnik.Image(m.width,m.height) + mapnik.render(m,im) + actual = '/tmp/mapnik-marker-ellipse-render1.png' + expected = 'images/support/mapnik-marker-ellipse-render1.png' + im.save(actual) + expected_im = mapnik.Image.open(expected) + eq_(im.tostring(),expected_im.tostring(), 'failed comparing actual (%s) and expected (%s)' % (actual,'tests/python_tests/'+ expected)) + +#def test_marker_ellipse_render2(): +# # currently crashes https://github.com/mapnik/mapnik/issues/1365 +# m = mapnik.Map(256,256) +# mapnik.load_map(m,'../data/good_maps/marker_ellipse_transform2.xml') +# m.zoom_all() +# im = mapnik.Image(m.width,m.height) +# mapnik.render(m,im) +# actual = '/tmp/mapnik-marker-ellipse-render2.png' +# expected = 'images/support/mapnik-marker-ellipse-render2.png' +# im.save(actual) +# expected_im = mapnik.Image.open(expected) +# eq_(im.tostring(),expected_im.tostring(), 'failed comparing actual (%s) and expected (%s)' % (actual,'tests/python_tests/'+ expected)) + +if __name__ == "__main__": + setup() + [eval(run)() for run in dir() if 'test_' in run] From 48c391da0d544d44d1fc9ac131cb951011c66b43 Mon Sep 17 00:00:00 2001 From: Dane Springmeyer Date: Tue, 31 Jul 2012 16:56:22 -0700 Subject: [PATCH 07/13] reduce copying of svg attributes via @lightmare - refs #1360 --- include/mapnik/svg/svg_converter.hpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/include/mapnik/svg/svg_converter.hpp b/include/mapnik/svg/svg_converter.hpp index 7e61a09ff..4ba4c4bff 100644 --- a/include/mapnik/svg/svg_converter.hpp +++ b/include/mapnik/svg/svg_converter.hpp @@ -66,10 +66,10 @@ public: { throw std::runtime_error("end_path : The path was not begun"); } - path_attributes attr = cur_attr(); - unsigned idx = attributes_[attributes_.size() - 1].index; + path_attributes& attr = attributes_[attributes_.size() - 1]; + unsigned idx = attr.index; + attr = cur_attr(); attr.index = idx; - attributes_[attributes_.size() - 1] = attr; } void move_to(double x, double y, bool rel=false) // M, m From 64b990ef6c1387f4dde75c2d25645b1ab6227f09 Mon Sep 17 00:00:00 2001 From: Dane Springmeyer Date: Tue, 31 Jul 2012 17:00:24 -0700 Subject: [PATCH 08/13] viewer ignores --- .gitignore | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/.gitignore b/.gitignore index 5d2536c3e..fe40dfa29 100644 --- a/.gitignore +++ b/.gitignore @@ -43,4 +43,11 @@ demo/c++/demo.tif demo/c++/demo.jpg demo/c++/demo.png demo/c++/demo256.png +demo/viewer/Makefile +demo/viewer/Makefile.Debug +demo/viewer/Makefile.Release +demo/viewer/release/ +demo/viewer/ui_about.h +demo/viewer/ui_info.h +demo/viewer/ui_layer_info.h tests/cpp_tests/*-bin From 9d9c525de0eaebfa21a6dad4f71e9ba97f762cba Mon Sep 17 00:00:00 2001 From: Dane Springmeyer Date: Tue, 31 Jul 2012 17:27:52 -0700 Subject: [PATCH 09/13] revert 1dfde78 and properly avoid clipping for point type geometries in markers_symbolizer while moving markers_placement to cpp file to avoid overhead of declaring all possible permutations of vertex convertors - closes #1341 --- include/mapnik/markers_placement.hpp | 219 ++++++++++++++++++++- src/agg/process_markers_symbolizer.cpp | 32 +++- src/build.py | 1 - src/markers_placement.cpp | 253 ------------------------- src/markers_symbolizer.cpp | 10 +- 5 files changed, 243 insertions(+), 272 deletions(-) delete mode 100644 src/markers_placement.cpp diff --git a/include/mapnik/markers_placement.hpp b/include/mapnik/markers_placement.hpp index a0828caba..5ac83a22d 100644 --- a/include/mapnik/markers_placement.hpp +++ b/include/mapnik/markers_placement.hpp @@ -24,13 +24,26 @@ #define MAPNIK_MARKERS_PLACEMENT_HPP // mapnik +#include +#include +#include +#include +#include //round #include // boost #include // agg +#include "agg_basics.h" +#include "agg_conv_clip_polygon.h" +#include "agg_conv_clip_polyline.h" +#include "agg_trans_affine.h" #include "agg_conv_transform.h" +#include "agg_conv_smooth_poly1.h" + +// stl +#include namespace mapnik { @@ -47,12 +60,40 @@ public: * converted to a positive value with similar magnitude, but * choosen to optimize marker placement. 0 = no markers */ - markers_placement(Locator &locator, box2d const& 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) + : locator_(locator), + size_(size), + tr_(tr), + detector_(detector), + max_error_(max_error), + allow_overlap_(allow_overlap) + { + marker_width_ = (size_ * tr_).width(); + if (spacing >= 0) + { + spacing_ = spacing; + } else if (spacing < 0) + { + spacing_ = find_optimal_spacing(-spacing); + } + rewind(); + } + /** Start again at first marker. * \note Returns the same list of markers only works when they were NOT added * to the detector. */ - void rewind(); + void rewind() + { + locator_.rewind(0); + //Get first point + done_ = agg::is_stop(locator_.vertex(&next_x, &next_y)) || spacing_ < marker_width_; + last_x = next_x; + last_y = next_y; // Force request of new segment + error_ = 0; + marker_nr_ = 0; + } + /** Get a point where the marker should be placed. * Each time this function is called a new point is returned. * \param x Return value for x position @@ -61,7 +102,115 @@ public: * \param add_to_detector Add selected position to detector * \return True if a place is found, false if none is found. */ - bool get_point(double & x, double & y, double & angle, bool add_to_detector = true); + bool get_point(double & x, double & y, double & angle, bool add_to_detector = true) + { + if (done_) return false; + unsigned cmd; + /* This functions starts at the position of the previous marker, + walks along the path, counting how far it has to go in spacing_left. + If one marker can't be placed at the position it should go to it is + moved a bit. The error is compensated for in the next call to this + function. + + error > 0: Marker too near to the end of the path. + error = 0: Perfect position. + error < 0: Marker too near to the beginning of the path. + */ + if (marker_nr_++ == 0) + { + //First marker + spacing_left_ = spacing_ / 2; + } else + { + spacing_left_ = spacing_; + } + spacing_left_ -= error_; + error_ = 0; + //Loop exits when a position is found or when no more segments are available + while (true) + { + //Do not place markers too close to the beginning of a segment + if (spacing_left_ < marker_width_/2) + { + set_spacing_left(marker_width_/2); //Only moves forward + } + //Error for this marker is too large. Skip to the next position. + if (abs(error_) > max_error_ * spacing_) + { + if (error_ > spacing_) + { + error_ = 0; //Avoid moving backwards + MAPNIK_LOG_WARN(markers_placement) << "Extremely large error in markers_placement. Please file a bug report."; + } + spacing_left_ += spacing_ - error_; + error_ = 0; + } + double dx = next_x - last_x; + double dy = next_y - last_y; + double segment_length = std::sqrt(dx * dx + dy * dy); + if (segment_length <= spacing_left_) + { + //Segment is to short to place marker. Find next segment + spacing_left_ -= segment_length; + last_x = next_x; + last_y = next_y; + while (agg::is_move_to(cmd = locator_.vertex(&next_x, &next_y))) + { + //Skip over "move" commands + last_x = next_x; + last_y = next_y; + } + if (agg::is_stop(cmd)) + { + done_ = true; + return false; + } + continue; //Try again + } + /* At this point we know the following things: + - segment_length > spacing_left + - error is small enough + - at least half a marker fits into this segment + */ + //Check if marker really fits in this segment + if (segment_length < marker_width_) + { + //Segment to short => Skip this segment + set_spacing_left(segment_length + marker_width_/2); //Only moves forward + continue; + } else if (segment_length - spacing_left_ < marker_width_/2) + { + //Segment is long enough, but we are to close to the end + //Note: This function moves backwards. This could lead to an infinite + // loop when another function adds a positive offset. Therefore we + // only move backwards when there is no offset + if (error_ == 0) + { + set_spacing_left(segment_length - marker_width_/2, true); + } else + { + //Skip this segment + set_spacing_left(segment_length + marker_width_/2); //Only moves forward + } + continue; //Force checking of max_error constraint + } + angle = atan2(dy, dx); + x = last_x + dx * (spacing_left_ / segment_length); + y = last_y + dy * (spacing_left_ / segment_length); + box2d box = perform_transform(angle, x, y); + if (!allow_overlap_ && !detector_.has_placement(box)) + { + //10.0 is the approxmiate number of positions tried and choosen arbitrarily + set_spacing_left(spacing_left_ + spacing_ * max_error_ / 10.0); //Only moves forward + continue; + } + if (add_to_detector) detector_.insert(box); + last_x = x; + last_y = y; + return true; + } + } + private: Locator &locator_; box2d size_; @@ -82,11 +231,69 @@ private: unsigned marker_nr_; /** Rotates the size_ box and translates the position. */ - box2d perform_transform(double angle, double dx, double dy); + box2d perform_transform(double angle, double dx, double dy) + { + double x1 = size_.minx(); + double x2 = size_.maxx(); + double y1 = size_.miny(); + double y2 = size_.maxy(); + agg::trans_affine tr = tr_ * agg::trans_affine_rotation(angle).translate(dx, dy); + double xA = x1, yA = y1, xB = x2, yB = y1, xC = x2, yC = y2, xD = x1, yD = y2; + tr.transform(&xA, &yA); + tr.transform(&xB, &yB); + tr.transform(&xC, &yC); + tr.transform(&xD, &yD); + box2d result(xA, yA, xC, yC); + result.expand_to_include(xB, yB); + result.expand_to_include(xD, yD); + return result; + } + /** Automatically chooses spacing. */ - double find_optimal_spacing(double s); + double find_optimal_spacing(double s) + { + rewind(); + //Calculate total path length + unsigned cmd = agg::path_cmd_move_to; + double length = 0; + while (!agg::is_stop(cmd)) + { + double dx = next_x - last_x; + double dy = next_y - last_y; + length += std::sqrt(dx * dx + dy * dy); + last_x = next_x; + last_y = next_y; + while (agg::is_move_to(cmd = locator_.vertex(&next_x, &next_y))) + { + //Skip over "move" commands + last_x = next_x; + last_y = next_y; + } + } + unsigned points = round(length / s); + if (points == 0) return 0.0; //Path to short + return length / points; + } + /** Set spacing_left_, adjusts error_ and performs sanity checks. */ - void set_spacing_left(double sl, bool allow_negative=false); + void set_spacing_left(double sl, bool allow_negative=false) + { + double delta_error = sl - spacing_left_; + if (!allow_negative && delta_error < 0) + { + MAPNIK_LOG_WARN(markers_placement) << "Unexpected negative error in markers_placement. Please file a bug report."; + return; + } + #ifdef MAPNIK_DEBUG + if (delta_error == 0.0) + { + MAPNIK_LOG_WARN(markers_placement) << "Not moving at all in set_spacing_left()! Please file a bug report."; + } + #endif + error_ += delta_error; + spacing_left_ = sl; + } + }; } diff --git a/src/agg/process_markers_symbolizer.cpp b/src/agg/process_markers_symbolizer.cpp index 40c7336a7..79723f485 100644 --- a/src/agg/process_markers_symbolizer.cpp +++ b/src/agg/process_markers_symbolizer.cpp @@ -295,7 +295,7 @@ void agg_renderer::process(markers_symbolizer const& sym, typedef agg::pixfmt_custom_blend_rgba pixfmt_comp_type; typedef agg::renderer_base renderer_base; typedef label_collision_detector4 detector_type; - typedef boost::mpl::vector conv_types; + typedef boost::mpl::vector conv_types; std::string filename = path_processor_type::evaluate(*sym.get_filename(), feature); @@ -350,7 +350,15 @@ void agg_renderer::process(markers_symbolizer const& sym, 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) + if (sym.clip() && feature.paths().size() > 0) // optional clip (default: true) + { + eGeomType type = feature.paths()[0].type(); + if (type == Polygon) + converter.template set(); + else if (type == LineString) + converter.template set(); + // don't clip if type==Point + } converter.template set(); //always transform if (sym.smooth() > 0.0) converter.template set(); // optional smooth converter BOOST_FOREACH(geometry_type & geom, feature.paths()) @@ -375,7 +383,15 @@ void agg_renderer::process(markers_symbolizer const& sym, 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) + if (sym.clip() && feature.paths().size() > 0) // optional clip (default: true) + { + eGeomType type = feature.paths()[0].type(); + if (type == Polygon) + converter.template set(); + else if (type == LineString) + converter.template set(); + // don't clip if type==Point + } converter.template set(); //always transform if (sym.smooth() > 0.0) converter.template set(); // optional smooth converter BOOST_FOREACH(geometry_type & geom, feature.paths()) @@ -399,7 +415,15 @@ void agg_renderer::process(markers_symbolizer const& sym, 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) + if (sym.clip() && feature.paths().size() > 0) // optional clip (default: true) + { + eGeomType type = feature.paths()[0].type(); + if (type == Polygon) + converter.template set(); + else if (type == LineString) + converter.template set(); + // don't clip if type==Point + } converter.template set(); //always transform if (sym.smooth() > 0.0) converter.template set(); // optional smooth converter diff --git a/src/build.py b/src/build.py index a56aac0ea..5a74be3c3 100644 --- a/src/build.py +++ b/src/build.py @@ -172,7 +172,6 @@ source = Split( json/feature_grammar.cpp json/feature_collection_parser.cpp json/geojson_generator.cpp - markers_placement.cpp processed_text.cpp formatting/base.cpp formatting/expression.cpp diff --git a/src/markers_placement.cpp b/src/markers_placement.cpp deleted file mode 100644 index 6ea4b0e14..000000000 --- a/src/markers_placement.cpp +++ /dev/null @@ -1,253 +0,0 @@ -// mapnik -#include -#include -#include -#include -#include //round -// agg -#include "agg_basics.h" -#include "agg_conv_clip_polyline.h" -#include "agg_trans_affine.h" -#include "agg_conv_transform.h" -#include "agg_conv_smooth_poly1.h" -// stl -#include - -namespace mapnik -{ -template -markers_placement::markers_placement( - 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(); - if (spacing >= 0) - { - spacing_ = spacing; - } else if (spacing < 0) - { - spacing_ = find_optimal_spacing(-spacing); - } - rewind(); -} - -template -double markers_placement::find_optimal_spacing(double s) -{ - rewind(); - //Calculate total path length - unsigned cmd = agg::path_cmd_move_to; - double length = 0; - while (!agg::is_stop(cmd)) - { - double dx = next_x - last_x; - double dy = next_y - last_y; - length += std::sqrt(dx * dx + dy * dy); - last_x = next_x; - last_y = next_y; - while (agg::is_move_to(cmd = locator_.vertex(&next_x, &next_y))) - { - //Skip over "move" commands - last_x = next_x; - last_y = next_y; - } - } - unsigned points = round(length / s); - if (points == 0) return 0.0; //Path to short - return length / points; -} - - -template -void markers_placement::rewind() -{ - locator_.rewind(0); - //Get first point - done_ = agg::is_stop(locator_.vertex(&next_x, &next_y)) || spacing_ < marker_width_; - last_x = next_x; - last_y = next_y; // Force request of new segment - error_ = 0; - marker_nr_ = 0; -} - -template -bool markers_placement::get_point( - double & x, double & y, double & angle, bool add_to_detector) -{ - if (done_) return false; - - unsigned cmd; - - /* This functions starts at the position of the previous marker, - walks along the path, counting how far it has to go in spacing_left. - If one marker can't be placed at the position it should go to it is - moved a bit. The error is compensated for in the next call to this - function. - - error > 0: Marker too near to the end of the path. - error = 0: Perfect position. - error < 0: Marker too near to the beginning of the path. - */ - - if (marker_nr_++ == 0) - { - //First marker - spacing_left_ = spacing_ / 2; - } else - { - spacing_left_ = spacing_; - } - - spacing_left_ -= error_; - error_ = 0; - - //Loop exits when a position is found or when no more segments are available - while (true) - { - //Do not place markers too close to the beginning of a segment - if (spacing_left_ < marker_width_/2) - { - set_spacing_left(marker_width_/2); //Only moves forward - } - //Error for this marker is too large. Skip to the next position. - if (abs(error_) > max_error_ * spacing_) - { - if (error_ > spacing_) - { - error_ = 0; //Avoid moving backwards - - MAPNIK_LOG_WARN(markers_placement) << "Extremely large error in markers_placement. Please file a bug report."; - } - spacing_left_ += spacing_ - error_; - error_ = 0; - } - double dx = next_x - last_x; - double dy = next_y - last_y; - double segment_length = std::sqrt(dx * dx + dy * dy); - if (segment_length <= spacing_left_) - { - //Segment is to short to place marker. Find next segment - spacing_left_ -= segment_length; - last_x = next_x; - last_y = next_y; - while (agg::is_move_to(cmd = locator_.vertex(&next_x, &next_y))) - { - //Skip over "move" commands - last_x = next_x; - last_y = next_y; - } - if (agg::is_stop(cmd)) - { - done_ = true; - return false; - } - continue; //Try again - } - - /* At this point we know the following things: - - segment_length > spacing_left - - error is small enough - - at least half a marker fits into this segment - */ - - //Check if marker really fits in this segment - if (segment_length < marker_width_) - { - //Segment to short => Skip this segment - set_spacing_left(segment_length + marker_width_/2); //Only moves forward - continue; - } else if (segment_length - spacing_left_ < marker_width_/2) - { - //Segment is long enough, but we are to close to the end - - //Note: This function moves backwards. This could lead to an infinite - // loop when another function adds a positive offset. Therefore we - // only move backwards when there is no offset - if (error_ == 0) - { - set_spacing_left(segment_length - marker_width_/2, true); - } else - { - //Skip this segment - set_spacing_left(segment_length + marker_width_/2); //Only moves forward - } - continue; //Force checking of max_error constraint - } - angle = atan2(dy, dx); - x = last_x + dx * (spacing_left_ / segment_length); - y = last_y + dy * (spacing_left_ / segment_length); - - box2d box = perform_transform(angle, x, y); - - if (!allow_overlap_ && !detector_.has_placement(box)) - { - //10.0 is the approxmiate number of positions tried and choosen arbitrarily - set_spacing_left(spacing_left_ + spacing_ * max_error_ / 10.0); //Only moves forward - continue; - } - if (add_to_detector) detector_.insert(box); - last_x = x; - last_y = y; - return true; - } -} - - -template -box2d markers_placement::perform_transform(double angle, double dx, double dy) -{ - double x1 = size_.minx(); - double x2 = size_.maxx(); - double y1 = size_.miny(); - double y2 = size_.maxy(); - - agg::trans_affine tr = tr_ * agg::trans_affine_rotation(angle).translate(dx, dy); - - double xA = x1, yA = y1, xB = x2, yB = y1, xC = x2, yC = y2, xD = x1, yD = y2; - tr.transform(&xA, &yA); - tr.transform(&xB, &yB); - tr.transform(&xC, &yC); - tr.transform(&xD, &yD); - - box2d result(xA, yA, xC, yC); - result.expand_to_include(xB, yB); - result.expand_to_include(xD, yD); - return result; -} - -template -void markers_placement::set_spacing_left(double sl, bool allow_negative) -{ - double delta_error = sl - spacing_left_; - if (!allow_negative && delta_error < 0) - { - MAPNIK_LOG_WARN(markers_placement) << "Unexpected negative error in markers_placement. Please file a bug report."; - - return; - } -#ifdef MAPNIK_DEBUG - if (delta_error == 0.0) - { - MAPNIK_LOG_WARN(markers_placement) << "Not moving at all in set_spacing_left()! Please file a bug report."; - } -#endif - error_ += delta_error; - spacing_left_ = sl; -} - -typedef agg::conv_clip_polyline clipped_geometry_type; -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; -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 diff --git a/src/markers_symbolizer.cpp b/src/markers_symbolizer.cpp index 5ea1c4624..643c7d04b 100644 --- a/src/markers_symbolizer.cpp +++ b/src/markers_symbolizer.cpp @@ -45,10 +45,7 @@ markers_symbolizer::markers_symbolizer() allow_overlap_(false), spacing_(100.0), max_error_(0.2), - marker_p_(MARKER_POINT_PLACEMENT) { - // override the default for clipping in symbolizer base - this->set_clip(false); - } + marker_p_(MARKER_POINT_PLACEMENT) { } markers_symbolizer::markers_symbolizer(path_expression_ptr const& filename) : symbolizer_with_image(filename), @@ -59,10 +56,7 @@ markers_symbolizer::markers_symbolizer(path_expression_ptr const& filename) allow_overlap_(false), spacing_(100.0), max_error_(0.2), - marker_p_(MARKER_POINT_PLACEMENT) { - // override the default for clipping in symbolizer base - this->set_clip(false); - } + marker_p_(MARKER_POINT_PLACEMENT) { } markers_symbolizer::markers_symbolizer(markers_symbolizer const& rhs) : symbolizer_with_image(rhs), From b7aafe51bc2b7b2f3f1590ab0110c6354198a5fe Mon Sep 17 00:00:00 2001 From: Dane Springmeyer Date: Tue, 31 Jul 2012 17:53:20 -0700 Subject: [PATCH 10/13] update markers line placement tests --- tests/data/good_maps/markers_symbolizer_lines.xml | 9 ++++++++- .../data/good_maps/markers_symbolizer_lines_file.xml | 11 +++++++++-- 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/tests/data/good_maps/markers_symbolizer_lines.xml b/tests/data/good_maps/markers_symbolizer_lines.xml index 74adff287..e1f879ad9 100644 --- a/tests/data/good_maps/markers_symbolizer_lines.xml +++ b/tests/data/good_maps/markers_symbolizer_lines.xml @@ -3,7 +3,14 @@ diff --git a/tests/data/good_maps/markers_symbolizer_lines_file.xml b/tests/data/good_maps/markers_symbolizer_lines_file.xml index 39d2f1dbd..e08621485 100644 --- a/tests/data/good_maps/markers_symbolizer_lines_file.xml +++ b/tests/data/good_maps/markers_symbolizer_lines_file.xml @@ -2,8 +2,15 @@ From 3821afd74d72430a2ca8da8f78173e30b0dd2d97 Mon Sep 17 00:00:00 2001 From: Dane Springmeyer Date: Tue, 31 Jul 2012 18:06:52 -0700 Subject: [PATCH 11/13] inherit default placement types from class instance --- src/load_map.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/load_map.cpp b/src/load_map.cpp index 315e85e9a..2f4d9c8e2 100644 --- a/src/load_map.cpp +++ b/src/load_map.cpp @@ -889,7 +889,7 @@ void map_parser::parse_point_symbolizer(rule & rule, xml_node const & sym) symbol.set_ignore_placement(* ignore_placement); } point_placement_e placement = - sym.get_attr("placement", CENTROID_POINT_PLACEMENT); + sym.get_attr("placement", sym.get_point_placement()); symbol.set_point_placement(placement); if (file && !file->empty()) @@ -1064,7 +1064,7 @@ void map_parser::parse_markers_symbolizer(rule & rule, xml_node const& node) sym.set_stroke(strk); } - marker_placement_e placement = node.get_attr("placement", MARKER_POINT_PLACEMENT); + marker_placement_e placement = node.get_attr("placement",sym.get_marker_placement()); sym.set_marker_placement(placement); parse_symbolizer_base(sym, node); rule.append(sym); From 16084ff335b004114996535f2e0a04b12cd91ffb Mon Sep 17 00:00:00 2001 From: Dane Springmeyer Date: Tue, 31 Jul 2012 18:13:50 -0700 Subject: [PATCH 12/13] support both interior placement and point for markers - helps prepare for #952 --- bindings/python/mapnik_markers_symbolizer.cpp | 1 + include/mapnik/markers_symbolizer.hpp | 1 + src/agg/process_markers_symbolizer.cpp | 22 +++++++++++++++---- src/load_map.cpp | 2 +- src/markers_symbolizer.cpp | 1 + 5 files changed, 22 insertions(+), 5 deletions(-) diff --git a/bindings/python/mapnik_markers_symbolizer.cpp b/bindings/python/mapnik_markers_symbolizer.cpp index 9613e7476..2ab881c05 100644 --- a/bindings/python/mapnik_markers_symbolizer.cpp +++ b/bindings/python/mapnik_markers_symbolizer.cpp @@ -92,6 +92,7 @@ void export_markers_symbolizer() mapnik::enumeration_("marker_placement") .value("POINT_PLACEMENT",mapnik::MARKER_POINT_PLACEMENT) + .value("INTERIOR_PLACEMENT",mapnik::MARKER_INTERIOR_PLACEMENT) .value("LINE_PLACEMENT",mapnik::MARKER_LINE_PLACEMENT) ; diff --git a/include/mapnik/markers_symbolizer.hpp b/include/mapnik/markers_symbolizer.hpp index d11cf6f8f..0a441a98d 100644 --- a/include/mapnik/markers_symbolizer.hpp +++ b/include/mapnik/markers_symbolizer.hpp @@ -39,6 +39,7 @@ namespace mapnik { // TODO - consider merging with text_symbolizer label_placement_e enum marker_placement_enum { MARKER_POINT_PLACEMENT, + MARKER_INTERIOR_PLACEMENT, MARKER_LINE_PLACEMENT, marker_placement_enum_MAX }; diff --git a/src/agg/process_markers_symbolizer.cpp b/src/agg/process_markers_symbolizer.cpp index 79723f485..451323f5b 100644 --- a/src/agg/process_markers_symbolizer.cpp +++ b/src/agg/process_markers_symbolizer.cpp @@ -94,11 +94,18 @@ struct vector_markers_rasterizer_dispatch { marker_placement_e placement_method = sym_.get_marker_placement(); - if (placement_method == MARKER_POINT_PLACEMENT) + if (placement_method != MARKER_LINE_PLACEMENT) { double x,y; path.rewind(0); - label::interior_position(path, x, y); + if (placement_method == MARKER_INTERIOR_PLACEMENT) + { + label::interior_position(path, x, y); + } + else + { + label::centroid(path, x, y); + } agg::trans_affine matrix = marker_trans_; matrix.translate(x,y); box2d transformed_bbox = bbox_ * matrix; @@ -231,11 +238,18 @@ struct raster_markers_rasterizer_dispatch marker_placement_e placement_method = sym_.get_marker_placement(); box2d bbox_(0,0, src_.width(),src_.height()); - if (placement_method == MARKER_POINT_PLACEMENT) + if (placement_method != MARKER_LINE_PLACEMENT) { double x,y; path.rewind(0); - label::interior_position(path, x, y); + if (placement_method == MARKER_INTERIOR_PLACEMENT) + { + label::interior_position(path, x, y); + } + else + { + label::centroid(path, x, y); + } agg::trans_affine matrix = marker_trans_; matrix.translate(x,y); box2d transformed_bbox = bbox_ * matrix; diff --git a/src/load_map.cpp b/src/load_map.cpp index 2f4d9c8e2..f834e8202 100644 --- a/src/load_map.cpp +++ b/src/load_map.cpp @@ -889,7 +889,7 @@ void map_parser::parse_point_symbolizer(rule & rule, xml_node const & sym) symbol.set_ignore_placement(* ignore_placement); } point_placement_e placement = - sym.get_attr("placement", sym.get_point_placement()); + sym.get_attr("placement", symbol.get_point_placement()); symbol.set_point_placement(placement); if (file && !file->empty()) diff --git a/src/markers_symbolizer.cpp b/src/markers_symbolizer.cpp index 643c7d04b..9de55e492 100644 --- a/src/markers_symbolizer.cpp +++ b/src/markers_symbolizer.cpp @@ -30,6 +30,7 @@ namespace mapnik { static const char * marker_placement_strings[] = { "point", + "interior", "line", "" }; From a9f99848c238a4c0a4ef461b91abdca77d25fe87 Mon Sep 17 00:00:00 2001 From: Dane Springmeyer Date: Tue, 31 Jul 2012 18:40:53 -0700 Subject: [PATCH 13/13] expose boost::optional for markers_symbolizer (which works as oopposed to boost::optional and boost::optional which are broken --- bindings/python/mapnik_python.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/bindings/python/mapnik_python.cpp b/bindings/python/mapnik_python.cpp index 883946427..71231aa25 100644 --- a/bindings/python/mapnik_python.cpp +++ b/bindings/python/mapnik_python.cpp @@ -608,6 +608,7 @@ BOOST_PYTHON_MODULE(_mapnik) def("has_cairo", &has_cairo, "Get cairo library status"); def("has_pycairo", &has_pycairo, "Get pycairo module status"); + python_optional(); python_optional(); python_optional >(); python_optional();