diff --git a/bindings/python/mapnik_line_symbolizer.cpp b/bindings/python/mapnik_line_symbolizer.cpp index e87c52bec..bbf49164c 100644 --- a/bindings/python/mapnik_line_symbolizer.cpp +++ b/bindings/python/mapnik_line_symbolizer.cpp @@ -63,5 +63,9 @@ void export_line_symbolizer() &line_symbolizer::smooth, &line_symbolizer::set_smooth, "smooth value (0..1.0)") + .add_property("offset", + &line_symbolizer::offset, + &line_symbolizer::set_offset, + "offset value") ; } diff --git a/docs/contributing.markdown b/docs/contributing.markdown index 6bc272f18..c6938e3e5 100644 --- a/docs/contributing.markdown +++ b/docs/contributing.markdown @@ -92,7 +92,7 @@ If you see bits of code around that do not follow these please don't hesitate to #### Use C++ style casts static_cast(value); // yes - + (int)value; // no #### Use const keyword after the type @@ -109,22 +109,29 @@ If you see bits of code around that do not follow these please don't hesitate to #### Shared pointers should be created with [boost::make_shared](http://www.boost.org/doc/libs/1_47_0/libs/smart_ptr/make_shared.html) where possible +#### Use assignment operator for zero initialized numbers + + double num = 0; // please + + double num(0); // no + + #### Function definitions should not be separated from their arguments: void foo(int a) // please - + void foo (int a) // no #### Separate arguments by a single space: void foo(int a, float b) // please - + void foo(int a,float b) // no #### Space between operators: if (a == b) // please - + if(a==b) // no #### Braces should always be used: @@ -136,7 +143,7 @@ If you see bits of code around that do not follow these please don't hesitate to if (!file) throw mapnik::datasource_exception("not found"); // no - + #### Braces should be on a separate line: diff --git a/include/mapnik/cairo_renderer.hpp b/include/mapnik/cairo_renderer.hpp index 30741427c..c8bfc88a7 100644 --- a/include/mapnik/cairo_renderer.hpp +++ b/include/mapnik/cairo_renderer.hpp @@ -122,8 +122,10 @@ public: // nothing to do } -protected: void render_marker(pixel_position const& pos, marker const& marker, const agg::trans_affine & mtx, double opacity=1.0, bool recenter=true); + void render_box(box2d const& b); +protected: + Map const& m_; Cairo::RefPtr context_; diff --git a/include/mapnik/marker_helpers.hpp b/include/mapnik/marker_helpers.hpp index 825680a2f..439bd8c43 100644 --- a/include/mapnik/marker_helpers.hpp +++ b/include/mapnik/marker_helpers.hpp @@ -113,10 +113,10 @@ struct vector_markers_rasterizer_dispatch } else { - markers_placement placement(path, bbox_, marker_trans_, detector_, - sym_.get_spacing() * scale_factor_, - sym_.get_max_error(), - sym_.get_allow_overlap()); + 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)) { @@ -251,7 +251,7 @@ struct raster_markers_rasterizer_dispatch typedef agg::span_image_filter_rgba_2x2 span_gen_type; typedef agg::renderer_scanline_aa_alpha, + agg::span_allocator, span_gen_type> renderer_type; img_accessor_type ia(pixf); interpolator_type interpolator(agg::trans_affine(p, 0, 0, width, height) ); diff --git a/plugins/input/gdal/gdal_featureset.cpp b/plugins/input/gdal/gdal_featureset.cpp index 008194ff9..2b67bbcc5 100644 --- a/plugins/input/gdal/gdal_featureset.cpp +++ b/plugins/input/gdal/gdal_featureset.cpp @@ -344,8 +344,8 @@ feature_ptr gdal_featureset::get_feature(mapnik::query const& q) { MAPNIK_LOG_DEBUG(gdal) << "gdal_featureset: Processing rgb bands..."; - int hasNoData(0); - double nodata(0); + int hasNoData = 0; + double nodata = 0.0; if (nodata_value_) { hasNoData = 1; diff --git a/src/agg/process_building_symbolizer.cpp b/src/agg/process_building_symbolizer.cpp index 4184bc42f..4c8916df6 100644 --- a/src/agg/process_building_symbolizer.cpp +++ b/src/agg/process_building_symbolizer.cpp @@ -143,6 +143,7 @@ void agg_renderer::process(building_symbolizer const& sym, path_type path(t_,*frame,prj_trans); agg::conv_stroke stroke(path); + stroke.width(scale_factor_); ras_ptr->add_path(stroke); ren.color(agg::rgba8(int(r*0.8), int(g*0.8), int(b*0.8), int(255 * sym.get_opacity()))); agg::render_scanlines(*ras_ptr, sl, ren); diff --git a/src/cairo_renderer.cpp b/src/cairo_renderer.cpp index 08ef1e84f..cfe8f174c 100644 --- a/src/cairo_renderer.cpp +++ b/src/cairo_renderer.cpp @@ -42,7 +42,7 @@ #include #include #include - +#include // cairo #include #include @@ -623,6 +623,24 @@ public: context_->restore(); } + void add_image(agg::trans_affine const& tr, image_data_32 & data, double opacity = 1.0) + { + cairo_pattern pattern(data); + if (!tr.is_identity()) + { + double m[6]; + tr.store_to(m); + Cairo::Matrix cairo_matrix(m[0],m[1],m[2],m[3],m[4],m[5]); + cairo_matrix.invert(); + pattern.set_matrix(cairo_matrix); + } + context_->save(); + context_->set_source(pattern.pattern()); + context_->paint_with_alpha(opacity); + context_->restore(); + } + + void set_font_face(cairo_face_manager & manager, face_ptr face) { context_->set_font_face(manager.get_face(face)->face()); @@ -1017,6 +1035,117 @@ void cairo_renderer_base::process(line_symbolizer const& sym, context.stroke(); } +void cairo_renderer_base::render_box(box2d const& b) +{ + cairo_context context(context_); + context.move_to(b.minx(), b.miny()); + context.line_to(b.minx(), b.maxy()); + context.line_to(b.maxx(), b.maxy()); + context.line_to(b.maxx(), b.miny()); + context.close_path(); + + context.stroke(); +} + +void render_vector_marker(cairo_context & context, pixel_position const& pos, mapnik::svg_storage_type & vmarker, + agg::pod_bvector const & attributes, + agg::trans_affine const& tr, double opacity, bool recenter) +{ + using namespace mapnik::svg; + box2d bbox = vmarker.bounding_box(); + + agg::trans_affine mtx = tr; + + if (recenter) + { + coord c = bbox.center(); + mtx = agg::trans_affine_translation(-c.x,-c.y); + mtx *= tr; + mtx.translate(pos.x, pos.y); + } + + agg::trans_affine transform; + + for(unsigned i = 0; i < attributes.size(); ++i) + { + mapnik::svg::path_attributes const& attr = attributes[i]; + if (!attr.visibility_flag) + continue; + + context.save(); + + transform = attr.transform; + transform *= mtx; + + // TODO - this 'is_valid' check is not used in the AGG renderer and also + // appears to lead to bogus results with + // tests/data/good_maps/markers_symbolizer_lines_file.xml + if (/*transform.is_valid() && */ !transform.is_identity()) + { + double m[6]; + transform.store_to(m); + context.transform(Cairo::Matrix(m[0],m[1],m[2],m[3],m[4],m[5])); + } + + vertex_stl_adapter stl_storage(vmarker.source()); + svg_path_adapter svg_path(stl_storage); + + if (attr.fill_flag || attr.fill_gradient.get_gradient_type() != NO_GRADIENT) + { + context.add_agg_path(svg_path,attr.index); + if (attr.even_odd_flag) + { + context.set_fill_rule(Cairo::FILL_RULE_EVEN_ODD); + } + else + { + context.set_fill_rule(Cairo::FILL_RULE_WINDING); + } + if(attr.fill_gradient.get_gradient_type() != NO_GRADIENT) + { + 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.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(); + } + } + + if (attr.stroke_gradient.get_gradient_type() != NO_GRADIENT || attr.stroke_flag) + { + context.add_agg_path(svg_path,attr.index); + if(attr.stroke_gradient.get_gradient_type() != NO_GRADIENT) + { + context.set_line_width(attr.stroke_width); + 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.fill_opacity*opacity); + context.set_gradient(g,bbox); + context.stroke(); + } + else if (attr.stroke_flag) + { + 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)); + context.set_line_join(line_join_enum(attr.line_join)); + context.set_miter_limit(attr.miter_limit); + context.stroke(); + } + } + + context.restore(); + } +} + + void cairo_renderer_base::render_marker(pixel_position const& pos, marker const& marker, const agg::trans_affine & tr, double opacity, bool recenter) { @@ -1024,103 +1153,11 @@ void cairo_renderer_base::render_marker(pixel_position const& pos, marker const& if (marker.is_vector()) { - box2d bbox; - bbox = (*marker.get_vector_data())->bounding_box(); - - agg::trans_affine mtx = tr; - - if (recenter) - { - coord c = bbox.center(); - // center the svg marker on '0,0' - mtx = agg::trans_affine_translation(-c.x,-c.y); - // apply symbol transformation to get to map space - mtx *= tr; - // render the marker at the center of the marker box - mtx.translate(pos.x+0.5 * marker.width(), pos.y+0.5 * marker.height()); - } - - typedef coord_transform path_type; - agg::trans_affine transform; mapnik::svg_path_ptr vmarker = *marker.get_vector_data(); - using namespace mapnik::svg; - agg::pod_bvector const & attributes_ = vmarker->attributes(); - for(unsigned i = 0; i < attributes_.size(); ++i) + if (vmarker) { - mapnik::svg::path_attributes const& attr = attributes_[i]; - if (!attr.visibility_flag) - continue; - - context.save(); - - transform = attr.transform; - transform *= mtx; - - // TODO - this 'is_valid' check is not used in the AGG renderer and also - // appears to lead to bogus results with - // tests/data/good_maps/markers_symbolizer_lines_file.xml - if (/*transform.is_valid() && */ !transform.is_identity()) - { - double m[6]; - transform.store_to(m); - context.transform(Cairo::Matrix(m[0],m[1],m[2],m[3],m[4],m[5])); - } - - vertex_stl_adapter stl_storage(vmarker->source()); - svg_path_adapter svg_path(stl_storage); - - if (attr.fill_flag || attr.fill_gradient.get_gradient_type() != NO_GRADIENT) - { - context.add_agg_path(svg_path,attr.index); - if (attr.even_odd_flag) - { - context.set_fill_rule(Cairo::FILL_RULE_EVEN_ODD); - } - else - { - context.set_fill_rule(Cairo::FILL_RULE_WINDING); - } - if(attr.fill_gradient.get_gradient_type() != NO_GRADIENT) - { - 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.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(); - } - } - - if (attr.stroke_gradient.get_gradient_type() != NO_GRADIENT || attr.stroke_flag) - { - context.add_agg_path(svg_path,attr.index); - if(attr.stroke_gradient.get_gradient_type() != NO_GRADIENT) - { - context.set_line_width(attr.stroke_width); - 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.fill_opacity*opacity); - context.set_gradient(g,bbox); - context.stroke(); - } - else if (attr.stroke_flag) - { - 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)); - context.set_line_join(line_join_enum(attr.line_join)); - context.set_miter_limit(attr.miter_limit); - context.stroke(); - } - } - - context.restore(); + agg::pod_bvector const & attributes = vmarker->attributes(); + render_vector_marker(context, pos, *vmarker, attributes, tr, opacity, recenter); } } else if (marker.is_bitmap()) @@ -1385,89 +1422,304 @@ void cairo_renderer_base::process(raster_symbolizer const& sym, } } +namespace detail { + +template +struct markers_dispatch +{ + markers_dispatch(Context & ctx, + SvgPath & marker, + Attributes const& attributes, + Detector & detector, + markers_symbolizer const& sym, + box2d const& bbox, + agg::trans_affine const& marker_trans, + double scale_factor) + :ctx_(ctx), + marker_(marker), + attributes_(attributes), + detector_(detector), + sym_(sym), + bbox_(bbox), + marker_trans_(marker_trans), + scale_factor_(scale_factor) {} + + + template + void add_path(T & path) + { + marker_placement_e placement_method = sym_.get_marker_placement(); + + if (placement_method != MARKER_LINE_PLACEMENT) + { + double x,y; + path.rewind(0); + if (placement_method == MARKER_INTERIOR_PLACEMENT) + { + label::interior_position(path, x, y); + } + else + { + label::centroid(path, x, y); + } + coord2d center = bbox_.center(); + agg::trans_affine matrix = agg::trans_affine_translation(-center.x, -center.y); + matrix *= marker_trans_; + matrix *=agg::trans_affine_translation(x, y); + + box2d transformed_bbox = bbox_ * matrix; + + if (sym_.get_allow_overlap() || + detector_.has_placement(transformed_bbox)) + { + render_vector_marker(ctx_, pixel_position(x,y), marker_, attributes_, marker_trans_, sym_.get_opacity(), true); + + 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_vector_marker(ctx_, pixel_position(x,y),marker_, attributes_, matrix, sym_.get_opacity(), true); + + } + } + } + + Context & ctx_; + SvgPath & marker_; + Attributes const& attributes_; + Detector & detector_; + markers_symbolizer const& sym_; + box2d const& bbox_; + agg::trans_affine const& marker_trans_; + double scale_factor_; +}; + +template +struct markers_dispatch_2 +{ + markers_dispatch_2(Context & ctx, + ImageMarker & marker, + Detector & detector, + markers_symbolizer const& sym, + box2d const& bbox, + agg::trans_affine const& marker_trans, + double scale_factor) + :ctx_(ctx), + marker_(marker), + detector_(detector), + sym_(sym), + bbox_(bbox), + marker_trans_(marker_trans), + scale_factor_(scale_factor) {} + + + template + void add_path(T & path) + { + marker_placement_e placement_method = sym_.get_marker_placement(); + + if (placement_method != MARKER_LINE_PLACEMENT) + { + double x,y; + path.rewind(0); + if (placement_method == MARKER_INTERIOR_PLACEMENT) + { + label::interior_position(path, x, y); + } + else + { + label::centroid(path, x, y); + } + coord2d center = bbox_.center(); + agg::trans_affine matrix = agg::trans_affine_translation(-center.x, -center.y); + matrix *= marker_trans_; + matrix *=agg::trans_affine_translation(x, y); + + box2d transformed_bbox = bbox_ * matrix; + + if (sym_.get_allow_overlap() || + detector_.has_placement(transformed_bbox)) + { + ctx_.add_image(matrix, *marker_, sym_.get_opacity()); + 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)) + { + coord2d center = bbox_.center(); + agg::trans_affine matrix = agg::trans_affine_translation(-center.x, -center.y); + matrix *= marker_trans_; + matrix *= agg::trans_affine_rotation(angle); + matrix *= agg::trans_affine_translation(x, y); + ctx_.add_image(matrix, *marker_, sym_.get_opacity()); + } + } + } + + Context & ctx_; + ImageMarker & marker_; + Detector & detector_; + markers_symbolizer const& sym_; + box2d const& bbox_; + agg::trans_affine const& marker_trans_; + double scale_factor_; +}; + +} void cairo_renderer_base::process(markers_symbolizer const& sym, mapnik::feature_impl & feature, proj_transform const& prj_trans) { + typedef boost::mpl::vector conv_types; + cairo_context context(context_); context.set_operator(sym.comp_op()); - typedef agg::conv_clip_polyline clipped_geometry_type; - typedef coord_transform path_type; + agg::trans_affine tr = agg::trans_affine_scaling(scale_factor_); - 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(); if (!filename.empty()) { boost::optional mark = mapnik::marker_cache::instance()->find(filename, true); if (mark && *mark) { - if (!(*mark)->is_vector()) + agg::trans_affine geom_tr; + evaluate_transform(geom_tr, feature, sym.get_transform()); + box2d const& bbox = (*mark)->bounding_box(); + setup_label_transform(tr, bbox, feature, sym); + + if ((*mark)->is_vector()) { - MAPNIK_LOG_DEBUG(cairo_renderer) << "cairo_renderer_base: markers_symbolizer does not yet support non-SVG markers"; + using namespace mapnik::svg; + typedef agg::pod_bvector svg_attributes_type; + typedef detail::markers_dispatch dispatch_type; - return; - } - 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(); + boost::optional const& stock_vector_marker = (*mark)->get_vector_data(); - 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); - using namespace mapnik::svg; + expression_ptr const& width_expr = sym.get_width(); + expression_ptr const& height_expr = sym.get_height(); - for (unsigned i=0; i stl_storage(marker_ellipse.source()); + svg_path_adapter svg_path(stl_storage); + build_ellipse(sym, feature, marker_ellipse, svg_path); + svg_attributes_type attributes; + bool result = push_explicit_style( (*stock_vector_marker)->attributes(), attributes, sym); + agg::trans_affine marker_tr = agg::trans_affine_scaling(scale_factor_); + evaluate_transform(marker_tr, feature, sym.get_image_transform()); + box2d bbox = marker_ellipse.bounding_box(); - if (sym.get_allow_overlap() || - detector_.has_placement(extent)) + dispatch_type dispatch(context, marker_ellipse, result?attributes:(*stock_vector_marker)->attributes(), + detector_, sym, bbox, marker_tr, scale_factor_); + vertex_converter, dispatch_type, markers_symbolizer, + CoordTransform, proj_transform, agg::trans_affine, conv_types> + converter(query_extent_, dispatch, sym, t_, prj_trans, marker_tr, scale_factor_); + + if (sym.clip() && feature.paths().size() > 0) // optional clip (default: true) { - render_marker(pixel_position(x - 0.5 * w, y - 0.5 * h) ,**mark, tr, 1); - - if (!sym.get_ignore_placement()) - detector_.insert(extent); + eGeomType type = feature.paths()[0].type(); + if (type == Polygon) + converter.set(); + else if (type == LineString) + converter.set(); + // don't clip if type==Point + } + converter.set(); //always transform + if (sym.smooth() > 0.0) converter.set(); // optional smooth converter + BOOST_FOREACH(geometry_type & geom, feature.paths()) + { + converter.apply(geom); } } else { - 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); - markers_placement placement(path, extent, recenter * tr, 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)) + svg_attributes_type attributes; + bool result = push_explicit_style( (*stock_vector_marker)->attributes(), attributes, sym); + + dispatch_type dispatch(context, **stock_vector_marker, result?attributes:(*stock_vector_marker)->attributes(), + detector_, sym, bbox, tr, scale_factor_); + vertex_converter, dispatch_type, markers_symbolizer, + CoordTransform, proj_transform, agg::trans_affine, conv_types> + converter(query_extent_, dispatch, sym, t_, prj_trans, tr, scale_factor_); + + if (sym.clip() && feature.paths().size() > 0) // optional clip (default: true) { - agg::trans_affine matrix = recenter * tr * agg::trans_affine_rotation(angle) * agg::trans_affine_translation(x, y); - render_marker(pixel_position(x - 0.5 * w, y - 0.5 * h), **mark, matrix, 1,false); + eGeomType type = feature.paths()[0].type(); + if (type == Polygon) + converter.set(); + else if (type == LineString) + converter.set(); + // don't clip if type==Point + } + converter.set(); //always transform + if (sym.smooth() > 0.0) converter.set(); // optional smooth converter + BOOST_FOREACH(geometry_type & geom, feature.paths()) + { + converter.apply(geom); + } + } + } + else // raster markers + { + typedef detail::markers_dispatch_2 dispatch_type; + boost::optional marker = (*mark)->get_bitmap_data(); + if ( marker ) + { + dispatch_type dispatch(context, *marker, + detector_, sym, bbox, tr, scale_factor_); + + vertex_converter, dispatch_type, markers_symbolizer, + CoordTransform, proj_transform, agg::trans_affine, conv_types> + converter(query_extent_, dispatch, sym, t_, prj_trans, tr, scale_factor_); + + if (sym.clip() && feature.paths().size() > 0) // optional clip (default: true) + { + eGeomType type = feature.paths()[0].type(); + if (type == Polygon) + converter.set(); + else if (type == LineString) + converter.set(); + // don't clip if type==Point + } + converter.set(); //always transform + if (sym.smooth() > 0.0) converter.set(); // optional smooth converter + BOOST_FOREACH(geometry_type & geom, feature.paths()) + { + converter.apply(geom); } } - context.fill(); } } } diff --git a/src/load_map.cpp b/src/load_map.cpp index 09e2c0504..d98c0f94d 100644 --- a/src/load_map.cpp +++ b/src/load_map.cpp @@ -224,14 +224,14 @@ void map_parser::parse_map(Map & map, xml_node const& pt, std::string const& bas else { std::ostringstream s_err; - s_err << "failed to parse 'maximum-extent'"; + s_err << "failed to parse Map maximum-extent '" << *maximum_extent << "'"; if (strict_) { throw config_error(s_err.str()); } else { - MAPNIK_LOG_WARN(load_map) << "map_parser: " << s_err.str(); + MAPNIK_LOG_ERROR(load_map) << "map_parser: " << s_err.str(); } } } @@ -648,16 +648,16 @@ void map_parser::parse_layer(Map & map, xml_node const& node) } else { - std::ostringstream s_err; - s_err << "failed to parse 'maximum-extent' in layer " << name; - if (strict_) - { - throw config_error(s_err.str()); - } - else - { - MAPNIK_LOG_WARN(load_map) << "map_parser: " << s_err.str(); - } + std::ostringstream s_err; + s_err << "failed to parse Layer maximum-extent '" << *maximum_extent << "' for '" << name << "'"; + if (strict_) + { + throw config_error(s_err.str()); + } + else + { + MAPNIK_LOG_ERROR(load_map) << "map_parser: " << s_err.str(); + } } } @@ -872,11 +872,9 @@ void map_parser::parse_symbolizer_base(symbolizer_base &sym, xml_node const &pt) if (!mapnik::parse_transform(*tl, *geometry_transform_wkt, pt.get_tree().transform_expr_grammar)) { std::stringstream ss; - ss << "Could not parse transform from '" << geometry_transform_wkt << "', expected transform attribute"; - if (strict_) - throw config_error(ss.str()); // value_error here? - else - MAPNIK_LOG_WARN(load_map) << "### WARNING: " << ss; + ss << "Could not parse transform from '" << *geometry_transform_wkt + << "', expected transform attribute"; + throw config_error(ss.str()); } sym.set_transform(tl); } @@ -948,17 +946,7 @@ void map_parser::parse_point_symbolizer(rule & rule, xml_node const & sym) mapnik::transform_list_ptr tl = boost::make_shared(); 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 - << "', expected transform attribute"; - if (strict_) - { - throw config_error(ss.str()); // value_error here? - } - else - { - MAPNIK_LOG_WARN(load_map) << "map_parser: " << ss; - } + throw mapnik::config_error("Failed to parse transform: '" + *image_transform_wkt + "'"); } symbol.set_image_transform(tl); } @@ -984,31 +972,16 @@ void map_parser::parse_markers_symbolizer(rule & rule, xml_node const& node) if (file && !file->empty()) { - try + if (base) { - if (base) + std::map::const_iterator itr = file_sources_.find(*base); + if (itr!=file_sources_.end()) { - std::map::const_iterator itr = file_sources_.find(*base); - if (itr!=file_sources_.end()) - { - *file = itr->second + "/" + *file; - } + *file = itr->second + "/" + *file; } + } - filename = ensure_relative_to_xml(file); - } - catch (...) - { - std::string msg("Failed to load marker file '" + *file + "'!"); - if (strict_) - { - throw config_error(msg); - } - else - { - MAPNIK_LOG_WARN(load_map) << "map_parser: " << msg; - } - } + filename = ensure_relative_to_xml(file); } optional marker_type = node.get_opt_attr("marker-type"); @@ -1055,17 +1028,7 @@ void map_parser::parse_markers_symbolizer(rule & rule, xml_node const& node) mapnik::transform_list_ptr tl = boost::make_shared(); 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 - << "', expected transform attribute"; - if (strict_) - { - throw config_error(ss.str()); // value_error here? - } - else - { - MAPNIK_LOG_WARN(load_map) << "map_parser: " << ss; - } + throw mapnik::config_error("Failed to parse transform: '" + *image_transform_wkt + "'"); } sym.set_image_transform(tl); } @@ -1257,17 +1220,7 @@ void map_parser::parse_shield_symbolizer(rule & rule, xml_node const& sym) mapnik::transform_list_ptr tl = boost::make_shared(); 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 - << "', expected transform attribute"; - if (strict_) - { - throw config_error(ss.str()); // value_error here? - } - else - { - MAPNIK_LOG_WARN(load_map) << "map_parser: " << ss; - } + throw mapnik::config_error("Failed to parse transform: '" + *image_transform_wkt + "'"); } shield_symbol.set_image_transform(tl); } diff --git a/tests/python_tests/render_grid_test.py b/tests/python_tests/render_grid_test.py index 2a9369946..74f27900d 100644 --- a/tests/python_tests/render_grid_test.py +++ b/tests/python_tests/render_grid_test.py @@ -15,6 +15,51 @@ def setup(): # from another directory we need to chdir() os.chdir(execution_path('.')) +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 show_grids2(name,g1,g2): + g2_expected = '../data/grids/mapnik-%s-actual.json' % name + if not os.path.exists(g2_expected): + # create test fixture based on actual results + open(g2_expected,'a+').write(json.dumps(g1,sort_keys=True)) + return + g1_file = '/tmp/mapnik-%s-actual.json' % name + open(g1_file,'w').write(json.dumps(g1,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_expected) + return val + # 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": [" ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " !!! ### ", " !!!!! ##### ", " !!!!! ##### ", " !!! ### ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " $$$$ %%%% ", " $$$$$ %%%%% ", " $$$$$ %%%%% ", " $$$ %%% ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " "]} @@ -44,7 +89,7 @@ def resolve(grid,row,col): return grid['data'].get(key) -def create_grid_map(width,height,marker=True): +def create_grid_map(width,height,sym): ds = mapnik.MemoryDatasource() context = mapnik.Context() context.push('Name') @@ -69,15 +114,8 @@ def create_grid_map(width,height,marker=True): ds.add_feature(f) s = mapnik.Style() r = mapnik.Rule() - 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) - + sym.allow_overlap = True + r.symbols.append(sym) s.rules.append(r) lyr = mapnik.Layer('Places') lyr.datasource = ds @@ -87,31 +125,14 @@ def create_grid_map(width,height,marker=True): 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_old(): """ test old method """ width,height = 256,256 - m = create_grid_map(width,height) + symb = mapnik.PointSymbolizer(mapnik.PathExpression('../data/images/dummy.png')) + sym = mapnik.MarkersSymbolizer() + sym.width = mapnik.Expression('10') + sym.height = mapnik.Expression('10') + m = create_grid_map(width,height,sym) #print mapnik.save_map_to_string(m) ul_lonlat = mapnik.Coord(142.30,-38.20) lr_lonlat = mapnik.Coord(143.40,-38.80) @@ -131,7 +152,10 @@ def test_render_grid_old(): def test_render_grid_new(): """ test old against new""" width,height = 256,256 - m = create_grid_map(width,height) + sym = mapnik.MarkersSymbolizer() + sym.width = mapnik.Expression('10') + sym.height = mapnik.Expression('10') + m = create_grid_map(width,height,sym) 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)) @@ -169,7 +193,10 @@ grid_feat_id2 = {"data": {"1": {"Name": "South East"}, "2": {"Name": "South West def test_render_grid3(): """ test using feature id""" width,height = 256,256 - m = create_grid_map(width,height) + sym = mapnik.MarkersSymbolizer() + sym.width = mapnik.Expression('10') + sym.height = mapnik.Expression('10') + m = create_grid_map(width,height,sym) 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)) @@ -280,22 +307,19 @@ def test_line_rendering(): 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())) point_expected = {"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_point_symbolizer_grid(): width,height = 256,256 - m = create_grid_map(width,height,marker=False) + sym = mapnik.PointSymbolizer(mapnik.PathExpression('../data/images/dummy.png')) + m = create_grid_map(width,height,sym) 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))