Merge branch 'master' of github.com:mapnik/mapnik

This commit is contained in:
Dane Springmeyer 2012-08-14 09:04:06 -07:00
commit d7d088cc97
9 changed files with 516 additions and 273 deletions

View file

@ -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")
;
}

View file

@ -109,6 +109,13 @@ 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

View file

@ -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<double> const& b);
protected:
Map const& m_;
Cairo::RefPtr<Cairo::Context> context_;

View file

@ -113,10 +113,10 @@ struct vector_markers_rasterizer_dispatch
}
else
{
markers_placement<T, label_collision_detector4> placement(path, bbox_, marker_trans_, detector_,
sym_.get_spacing() * scale_factor_,
sym_.get_max_error(),
sym_.get_allow_overlap());
markers_placement<T, Detector> 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<img_accessor_type,
interpolator_type> span_gen_type;
typedef agg::renderer_scanline_aa_alpha<renderer_base,
agg::span_allocator<agg::rgba8>,
agg::span_allocator<color_type>,
span_gen_type> renderer_type;
img_accessor_type ia(pixf);
interpolator_type interpolator(agg::trans_affine(p, 0, 0, width, height) );

View file

@ -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;

View file

@ -143,6 +143,7 @@ void agg_renderer<T>::process(building_symbolizer const& sym,
path_type path(t_,*frame,prj_trans);
agg::conv_stroke<path_type> 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);

View file

@ -42,7 +42,7 @@
#include <mapnik/config.hpp>
#include <mapnik/text_path.hpp>
#include <mapnik/vertex_converters.hpp>
#include <mapnik/marker_helpers.hpp>
// cairo
#include <cairomm/context.h>
#include <cairomm/surface.h>
@ -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<double> 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<svg::path_attributes> const & attributes,
agg::trans_affine const& tr, double opacity, bool recenter)
{
using namespace mapnik::svg;
box2d<double> bbox = vmarker.bounding_box();
agg::trans_affine mtx = tr;
if (recenter)
{
coord<double,2> 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<svg_path_storage> 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<double> bbox;
bbox = (*marker.get_vector_data())->bounding_box();
agg::trans_affine mtx = tr;
if (recenter)
{
coord<double,2> 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<CoordTransform,geometry_type> path_type;
agg::trans_affine transform;
mapnik::svg_path_ptr vmarker = *marker.get_vector_data();
using namespace mapnik::svg;
agg::pod_bvector<path_attributes> 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<svg_path_storage> 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<svg::path_attributes> 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 <typename Context, typename SvgPath, typename Attributes, typename Detector>
struct markers_dispatch
{
markers_dispatch(Context & ctx,
SvgPath & marker,
Attributes const& attributes,
Detector & detector,
markers_symbolizer const& sym,
box2d<double> 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 <typename T>
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<double> 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<T, label_collision_detector4> 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<double> const& bbox_;
agg::trans_affine const& marker_trans_;
double scale_factor_;
};
template <typename Context, typename ImageMarker, typename Detector>
struct markers_dispatch_2
{
markers_dispatch_2(Context & ctx,
ImageMarker & marker,
Detector & detector,
markers_symbolizer const& sym,
box2d<double> 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 <typename T>
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<double> 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<T, label_collision_detector4> 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<double> 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<clip_line_tag,clip_poly_tag,transform_tag,smooth_tag> conv_types;
cairo_context context(context_);
context.set_operator(sym.comp_op());
typedef agg::conv_clip_polyline<geometry_type> clipped_geometry_type;
typedef coord_transform<CoordTransform,clipped_geometry_type> 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<marker_ptr> 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<double> 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<path_attributes> svg_attributes_type;
typedef detail::markers_dispatch<cairo_context, mapnik::svg_storage_type,
svg_attributes_type,label_collision_detector4> dispatch_type;
return;
}
boost::optional<svg_path_ptr> marker = (*mark)->get_vector_data();
box2d<double> 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<svg_path_ptr> 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<double> 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<feature.num_geometries(); ++i)
{
geometry_type & geom = feature.get_geometry(i);
// TODO - merge this code with point_symbolizer rendering
if (placement_method == MARKER_POINT_PLACEMENT || geom.size() <= 1)
// special case for simple ellipse markers
// to allow for full control over rx/ry dimensions
if (filename == "shape://ellipse"
&& (width_expr || height_expr))
{
double x;
double y;
double z=0;
label::interior_position(geom, x, y);
prj_trans.backward(x,y,z);
t_.forward(&x,&y);
extent.re_center(x,y);
svg_storage_type marker_ellipse;
vertex_stl_adapter<svg_path_storage> 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<double> 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<box2d<double>, 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<clip_poly_tag>();
else if (type == LineString)
converter.set<clip_line_tag>();
// don't clip if type==Point
}
converter.set<transform_tag>(); //always transform
if (sym.smooth() > 0.0) converter.set<smooth_tag>(); // 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<path_type, label_collision_detector4> 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<box2d<double>, 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<clip_poly_tag>();
else if (type == LineString)
converter.set<clip_line_tag>();
// don't clip if type==Point
}
converter.set<transform_tag>(); //always transform
if (sym.smooth() > 0.0) converter.set<smooth_tag>(); // optional smooth converter
BOOST_FOREACH(geometry_type & geom, feature.paths())
{
converter.apply(geom);
}
}
}
else // raster markers
{
typedef detail::markers_dispatch_2<cairo_context,
mapnik::image_ptr,
label_collision_detector4> dispatch_type;
boost::optional<mapnik::image_ptr> marker = (*mark)->get_bitmap_data();
if ( marker )
{
dispatch_type dispatch(context, *marker,
detector_, sym, bbox, tr, scale_factor_);
vertex_converter<box2d<double>, 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<clip_poly_tag>();
else if (type == LineString)
converter.set<clip_line_tag>();
// don't clip if type==Point
}
converter.set<transform_tag>(); //always transform
if (sym.smooth() > 0.0) converter.set<smooth_tag>(); // optional smooth converter
BOOST_FOREACH(geometry_type & geom, feature.paths())
{
converter.apply(geom);
}
}
context.fill();
}
}
}

View file

@ -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<mapnik::transform_list>();
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<std::string,std::string>::const_iterator itr = file_sources_.find(*base);
if (itr!=file_sources_.end())
{
std::map<std::string,std::string>::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<std::string> marker_type = node.get_opt_attr<std::string>("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<mapnik::transform_list>();
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<mapnik::transform_list>();
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);
}

View file

@ -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))