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::smooth,
&line_symbolizer::set_smooth, &line_symbolizer::set_smooth,
"smooth value (0..1.0)") "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 #### 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: #### Function definitions should not be separated from their arguments:
void foo(int a) // please void foo(int a) // please

View file

@ -122,8 +122,10 @@ public:
// nothing to do // 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_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_; Map const& m_;
Cairo::RefPtr<Cairo::Context> context_; Cairo::RefPtr<Cairo::Context> context_;

View file

@ -113,7 +113,7 @@ struct vector_markers_rasterizer_dispatch
} }
else else
{ {
markers_placement<T, label_collision_detector4> placement(path, bbox_, marker_trans_, detector_, markers_placement<T, Detector> placement(path, bbox_, marker_trans_, detector_,
sym_.get_spacing() * scale_factor_, sym_.get_spacing() * scale_factor_,
sym_.get_max_error(), sym_.get_max_error(),
sym_.get_allow_overlap()); sym_.get_allow_overlap());
@ -251,7 +251,7 @@ struct raster_markers_rasterizer_dispatch
typedef agg::span_image_filter_rgba_2x2<img_accessor_type, typedef agg::span_image_filter_rgba_2x2<img_accessor_type,
interpolator_type> span_gen_type; interpolator_type> span_gen_type;
typedef agg::renderer_scanline_aa_alpha<renderer_base, typedef agg::renderer_scanline_aa_alpha<renderer_base,
agg::span_allocator<agg::rgba8>, agg::span_allocator<color_type>,
span_gen_type> renderer_type; span_gen_type> renderer_type;
img_accessor_type ia(pixf); img_accessor_type ia(pixf);
interpolator_type interpolator(agg::trans_affine(p, 0, 0, width, height) ); 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..."; MAPNIK_LOG_DEBUG(gdal) << "gdal_featureset: Processing rgb bands...";
int hasNoData(0); int hasNoData = 0;
double nodata(0); double nodata = 0.0;
if (nodata_value_) if (nodata_value_)
{ {
hasNoData = 1; hasNoData = 1;

View file

@ -143,6 +143,7 @@ void agg_renderer<T>::process(building_symbolizer const& sym,
path_type path(t_,*frame,prj_trans); path_type path(t_,*frame,prj_trans);
agg::conv_stroke<path_type> stroke(path); agg::conv_stroke<path_type> stroke(path);
stroke.width(scale_factor_);
ras_ptr->add_path(stroke); 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()))); 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); agg::render_scanlines(*ras_ptr, sl, ren);

View file

@ -42,7 +42,7 @@
#include <mapnik/config.hpp> #include <mapnik/config.hpp>
#include <mapnik/text_path.hpp> #include <mapnik/text_path.hpp>
#include <mapnik/vertex_converters.hpp> #include <mapnik/vertex_converters.hpp>
#include <mapnik/marker_helpers.hpp>
// cairo // cairo
#include <cairomm/context.h> #include <cairomm/context.h>
#include <cairomm/surface.h> #include <cairomm/surface.h>
@ -623,6 +623,24 @@ public:
context_->restore(); 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) void set_font_face(cairo_face_manager & manager, face_ptr face)
{ {
context_->set_font_face(manager.get_face(face)->face()); context_->set_font_face(manager.get_face(face)->face());
@ -1017,37 +1035,40 @@ void cairo_renderer_base::process(line_symbolizer const& sym,
context.stroke(); context.stroke();
} }
void cairo_renderer_base::render_marker(pixel_position const& pos, marker const& marker, const agg::trans_affine & tr, double opacity, bool recenter) void cairo_renderer_base::render_box(box2d<double> const& b)
{ {
cairo_context context(context_); 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();
if (marker.is_vector()) 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)
{ {
box2d<double> bbox; using namespace mapnik::svg;
bbox = (*marker.get_vector_data())->bounding_box(); box2d<double> bbox = vmarker.bounding_box();
agg::trans_affine mtx = tr; agg::trans_affine mtx = tr;
if (recenter) if (recenter)
{ {
coord<double,2> c = bbox.center(); coord<double,2> c = bbox.center();
// center the svg marker on '0,0'
mtx = agg::trans_affine_translation(-c.x,-c.y); mtx = agg::trans_affine_translation(-c.x,-c.y);
// apply symbol transformation to get to map space
mtx *= tr; mtx *= tr;
// render the marker at the center of the marker box mtx.translate(pos.x, pos.y);
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; agg::trans_affine transform;
mapnik::svg_path_ptr vmarker = *marker.get_vector_data();
using namespace mapnik::svg; for(unsigned i = 0; i < attributes.size(); ++i)
agg::pod_bvector<path_attributes> const & attributes_ = vmarker->attributes();
for(unsigned i = 0; i < attributes_.size(); ++i)
{ {
mapnik::svg::path_attributes const& attr = attributes_[i]; mapnik::svg::path_attributes const& attr = attributes[i];
if (!attr.visibility_flag) if (!attr.visibility_flag)
continue; continue;
@ -1066,7 +1087,7 @@ void cairo_renderer_base::render_marker(pixel_position const& pos, marker const&
context.transform(Cairo::Matrix(m[0],m[1],m[2],m[3],m[4],m[5])); 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()); vertex_stl_adapter<svg_path_storage> stl_storage(vmarker.source());
svg_path_adapter svg_path(stl_storage); svg_path_adapter svg_path(stl_storage);
if (attr.fill_flag || attr.fill_gradient.get_gradient_type() != NO_GRADIENT) if (attr.fill_flag || attr.fill_gradient.get_gradient_type() != NO_GRADIENT)
@ -1123,6 +1144,22 @@ void cairo_renderer_base::render_marker(pixel_position const& pos, marker const&
context.restore(); context.restore();
} }
} }
void cairo_renderer_base::render_marker(pixel_position const& pos, marker const& marker, const agg::trans_affine & tr, double opacity, bool recenter)
{
cairo_context context(context_);
if (marker.is_vector())
{
mapnik::svg_path_ptr vmarker = *marker.get_vector_data();
if (vmarker)
{
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()) else if (marker.is_bitmap())
{ {
context.add_image(pos.x, pos.y, **marker.get_bitmap_data(), opacity); context.add_image(pos.x, pos.y, **marker.get_bitmap_data(), opacity);
@ -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, void cairo_renderer_base::process(markers_symbolizer const& sym,
mapnik::feature_impl & feature, mapnik::feature_impl & feature,
proj_transform const& prj_trans) 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_); cairo_context context(context_);
context.set_operator(sym.comp_op()); context.set_operator(sym.comp_op());
typedef agg::conv_clip_polyline<geometry_type> clipped_geometry_type; agg::trans_affine tr = agg::trans_affine_scaling(scale_factor_);
typedef coord_transform<CoordTransform,clipped_geometry_type> path_type;
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); std::string filename = path_processor_type::evaluate(*sym.get_filename(), feature);
marker_placement_e placement_method = sym.get_marker_placement();
if (!filename.empty()) if (!filename.empty())
{ {
boost::optional<marker_ptr> mark = mapnik::marker_cache::instance()->find(filename, true); boost::optional<marker_ptr> mark = mapnik::marker_cache::instance()->find(filename, true);
if (mark && *mark) 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";
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();
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; 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;
for (unsigned i=0; i<feature.num_geometries(); ++i) boost::optional<svg_path_ptr> const& stock_vector_marker = (*mark)->get_vector_data();
{
geometry_type & geom = feature.get_geometry(i);
// TODO - merge this code with point_symbolizer rendering
if (placement_method == MARKER_POINT_PLACEMENT || geom.size() <= 1)
{
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);
if (sym.get_allow_overlap() || expression_ptr const& width_expr = sym.get_width();
detector_.has_placement(extent)) expression_ptr const& height_expr = sym.get_height();
{
render_marker(pixel_position(x - 0.5 * w, y - 0.5 * h) ,**mark, tr, 1);
if (!sym.get_ignore_placement()) // special case for simple ellipse markers
detector_.insert(extent); // to allow for full control over rx/ry dimensions
if (filename == "shape://ellipse"
&& (width_expr || height_expr))
{
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();
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)
{
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 else
{ {
clipped_geometry_type clipped(geom); svg_attributes_type attributes;
clipped.clip_box(query_extent_.minx(),query_extent_.miny(),query_extent_.maxx(),query_extent_.maxy()); bool result = push_explicit_style( (*stock_vector_marker)->attributes(), attributes, sym);
path_type path(t_,clipped,prj_trans);
markers_placement<path_type, label_collision_detector4> placement(path, extent, recenter * tr, detector_, dispatch_type dispatch(context, **stock_vector_marker, result?attributes:(*stock_vector_marker)->attributes(),
sym.get_spacing() * scale_factor_, detector_, sym, bbox, tr, scale_factor_);
sym.get_max_error(), vertex_converter<box2d<double>, dispatch_type, markers_symbolizer,
sym.get_allow_overlap()); CoordTransform, proj_transform, agg::trans_affine, conv_types>
double x, y, angle; converter(query_extent_, dispatch, sym, t_, prj_trans, tr, scale_factor_);
while (placement.get_point(x, y, angle))
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); eGeomType type = feature.paths()[0].type();
render_marker(pixel_position(x - 0.5 * w, y - 0.5 * h), **mark, matrix, 1,false); 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 else
{ {
std::ostringstream s_err; std::ostringstream s_err;
s_err << "failed to parse 'maximum-extent'"; s_err << "failed to parse Map maximum-extent '" << *maximum_extent << "'";
if (strict_) if (strict_)
{ {
throw config_error(s_err.str()); throw config_error(s_err.str());
} }
else else
{ {
MAPNIK_LOG_WARN(load_map) << "map_parser: " << s_err.str(); MAPNIK_LOG_ERROR(load_map) << "map_parser: " << s_err.str();
} }
} }
} }
@ -649,14 +649,14 @@ void map_parser::parse_layer(Map & map, xml_node const& node)
else else
{ {
std::ostringstream s_err; std::ostringstream s_err;
s_err << "failed to parse 'maximum-extent' in layer " << name; s_err << "failed to parse Layer maximum-extent '" << *maximum_extent << "' for '" << name << "'";
if (strict_) if (strict_)
{ {
throw config_error(s_err.str()); throw config_error(s_err.str());
} }
else else
{ {
MAPNIK_LOG_WARN(load_map) << "map_parser: " << s_err.str(); 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)) if (!mapnik::parse_transform(*tl, *geometry_transform_wkt, pt.get_tree().transform_expr_grammar))
{ {
std::stringstream ss; std::stringstream ss;
ss << "Could not parse transform from '" << geometry_transform_wkt << "', expected transform attribute"; ss << "Could not parse transform from '" << *geometry_transform_wkt
if (strict_) << "', expected transform attribute";
throw config_error(ss.str()); // value_error here? throw config_error(ss.str());
else
MAPNIK_LOG_WARN(load_map) << "### WARNING: " << ss;
} }
sym.set_transform(tl); 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>(); 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)) if (!mapnik::parse_transform(*tl, *image_transform_wkt, sym.get_tree().transform_expr_grammar))
{ {
std::stringstream ss; throw mapnik::config_error("Failed to parse transform: '" + *image_transform_wkt + "'");
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;
}
} }
symbol.set_image_transform(tl); symbol.set_image_transform(tl);
} }
@ -983,8 +971,6 @@ void map_parser::parse_markers_symbolizer(rule & rule, xml_node const& node)
optional<std::string> base = node.get_opt_attr<std::string>("base"); optional<std::string> base = node.get_opt_attr<std::string>("base");
if (file && !file->empty()) if (file && !file->empty())
{
try
{ {
if (base) if (base)
{ {
@ -997,19 +983,6 @@ void map_parser::parse_markers_symbolizer(rule & rule, xml_node const& node)
filename = ensure_relative_to_xml(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;
}
}
}
optional<std::string> marker_type = node.get_opt_attr<std::string>("marker-type"); optional<std::string> marker_type = node.get_opt_attr<std::string>("marker-type");
if (marker_type) if (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>(); 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)) if (!mapnik::parse_transform(*tl, *image_transform_wkt, node.get_tree().transform_expr_grammar))
{ {
std::stringstream ss; throw mapnik::config_error("Failed to parse transform: '" + *image_transform_wkt + "'");
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;
}
} }
sym.set_image_transform(tl); 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>(); 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)) if (!mapnik::parse_transform(*tl, *image_transform_wkt, sym.get_tree().transform_expr_grammar))
{ {
std::stringstream ss; throw mapnik::config_error("Failed to parse transform: '" + *image_transform_wkt + "'");
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;
}
} }
shield_symbol.set_image_transform(tl); shield_symbol.set_image_transform(tl);
} }

View file

@ -15,6 +15,51 @@ def setup():
# from another directory we need to chdir() # from another directory we need to chdir()
os.chdir(execution_path('.')) 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 # first pass impl where resolution is passed as render
# time rather than encoding time, likely will be deprecated soon # 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": [" ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " !!! ### ", " !!!!! ##### ", " !!!!! ##### ", " !!! ### ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " $$$$ %%%% ", " $$$$$ %%%%% ", " $$$$$ %%%%% ", " $$$ %%% ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " ", " "]} 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) return grid['data'].get(key)
def create_grid_map(width,height,marker=True): def create_grid_map(width,height,sym):
ds = mapnik.MemoryDatasource() ds = mapnik.MemoryDatasource()
context = mapnik.Context() context = mapnik.Context()
context.push('Name') context.push('Name')
@ -69,15 +114,8 @@ def create_grid_map(width,height,marker=True):
ds.add_feature(f) ds.add_feature(f)
s = mapnik.Style() s = mapnik.Style()
r = mapnik.Rule() r = mapnik.Rule()
if marker: sym.allow_overlap = True
symb = mapnik.MarkersSymbolizer() r.symbols.append(sym)
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)
s.rules.append(r) s.rules.append(r)
lyr = mapnik.Layer('Places') lyr = mapnik.Layer('Places')
lyr.datasource = ds lyr.datasource = ds
@ -87,31 +125,14 @@ def create_grid_map(width,height,marker=True):
m.layers.append(lyr) m.layers.append(lyr)
return m 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(): def test_render_grid_old():
""" test old method """ """ test old method """
width,height = 256,256 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) #print mapnik.save_map_to_string(m)
ul_lonlat = mapnik.Coord(142.30,-38.20) ul_lonlat = mapnik.Coord(142.30,-38.20)
lr_lonlat = mapnik.Coord(143.40,-38.80) lr_lonlat = mapnik.Coord(143.40,-38.80)
@ -131,7 +152,10 @@ def test_render_grid_old():
def test_render_grid_new(): def test_render_grid_new():
""" test old against new""" """ test old against new"""
width,height = 256,256 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) ul_lonlat = mapnik.Coord(142.30,-38.20)
lr_lonlat = mapnik.Coord(143.40,-38.80) lr_lonlat = mapnik.Coord(143.40,-38.80)
m.zoom_to_box(mapnik.Box2d(ul_lonlat,lr_lonlat)) 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(): def test_render_grid3():
""" test using feature id""" """ test using feature id"""
width,height = 256,256 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) ul_lonlat = mapnik.Coord(142.30,-38.20)
lr_lonlat = mapnik.Coord(143.40,-38.80) lr_lonlat = mapnik.Coord(143.40,-38.80)
m.zoom_to_box(mapnik.Box2d(ul_lonlat,lr_lonlat)) 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']) mapnik.render_layer(m,grid,layer=0,fields=['__id__','Name'])
utf1 = grid.encode() utf1 = grid.encode()
eq_(utf1,line_expected,show_grids('line',utf1,line_expected)) 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"]} 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(): def test_point_symbolizer_grid():
width,height = 256,256 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) ul_lonlat = mapnik.Coord(142.30,-38.20)
lr_lonlat = mapnik.Coord(143.40,-38.80) lr_lonlat = mapnik.Coord(143.40,-38.80)
m.zoom_to_box(mapnik.Box2d(ul_lonlat,lr_lonlat)) 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) grid = mapnik.Grid(m.width,m.height)
mapnik.render_layer(m,grid,layer=0,fields=['Name']) mapnik.render_layer(m,grid,layer=0,fields=['Name'])
utf1 = grid.encode() utf1 = grid.encode()
#open('test.json','w').write(json.dumps(grid.encode()))
eq_(utf1,point_expected,show_grids('point-sym',utf1,point_expected)) eq_(utf1,point_expected,show_grids('point-sym',utf1,point_expected))