Merge branch 'master' into python-textplacement

This commit is contained in:
Hermann Kraus 2012-02-19 01:00:52 +01:00
commit 76cdd7a254
64 changed files with 383 additions and 218 deletions

View file

@ -28,7 +28,6 @@
#include <mapnik/feature_style_processor.hpp>
#include <mapnik/font_engine_freetype.hpp>
#include <mapnik/label_collision_detector.hpp>
#include <mapnik/placement_finder.hpp>
#include <mapnik/map.hpp>
//#include <mapnik/marker.hpp>

View file

@ -30,7 +30,6 @@
#include <mapnik/feature_style_processor.hpp>
#include <mapnik/font_engine_freetype.hpp>
#include <mapnik/label_collision_detector.hpp>
#include <mapnik/placement_finder.hpp>
#include <mapnik/map.hpp>
//#include <mapnik/marker.hpp>

View file

@ -345,8 +345,8 @@ struct text_renderer : private boost::noncopyable
text_renderer (pixmap_type & pixmap, face_manager<freetype_engine> &font_manager_, stroker & s);
box2d<double> prepare_glyphs(text_path *path);
void render(double x0, double y0);
void render_id(int feature_id,double x0, double y0, double min_radius=1.0);
void render(pixel_position pos);
void render_id(int feature_id, pixel_position pos, double min_radius=1.0);
private:
void render_bitmap(FT_Bitmap *bitmap, unsigned rgba, int x, int y, double opacity)

View file

@ -30,7 +30,6 @@
#include <mapnik/feature_style_processor.hpp>
#include <mapnik/font_engine_freetype.hpp>
#include <mapnik/label_collision_detector.hpp>
#include <mapnik/placement_finder.hpp>
#include <mapnik/map.hpp>
//#include <mapnik/marker.hpp>

View file

@ -0,0 +1,34 @@
/*****************************************************************************
*
* This file is part of Mapnik (c++ mapping toolkit)
*
* Copyright (C) 2012 Artem Pavlenko
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
*****************************************************************************/
#ifndef MAPNIK_PIXEL_POSITION_HPP
#define MAPNIK_PIXEL_POSITION_HPP
/** Store a pixel position. */
struct pixel_position
{
double x;
double y;
pixel_position(double x, double y) : x(x), y(y) { }
pixel_position() : x(0), y(0) { }
};
#endif // MAPNIK_PIXEL_POSITION_HPP

View file

@ -89,6 +89,7 @@ private:
void init_string_size();
void init_alignment();
void adjust_position(text_path *current_placement, double label_x, double label_y);
void add_line(double width, double height, bool first_line);
///General Internals
DetectorT & detector_;
@ -96,8 +97,17 @@ private:
string_info &info_;
text_symbolizer_properties &p;
text_placement_info &pi;
/** Length of the longest line after linebreaks.
* Before find_line_breaks() this is the total length of the string.
*/
double string_width_;
/** Height of the string after linebreaks.
* Before find_line_breaks() this is the total length of the string.
*/
double string_height_;
/** Height of the tallest font in the first line not including line spacing.
* Used to determine the correct offset for the first line.
*/
double first_line_space_;
vertical_alignment_e valign_;
horizontal_alignment_e halign_;

View file

@ -24,7 +24,6 @@
#include <mapnik/text_symbolizer.hpp>
#include <mapnik/shield_symbolizer.hpp>
#include <mapnik/placement_finder.hpp>
#include <mapnik/expression_evaluator.hpp>
#include <mapnik/feature.hpp>
#include <mapnik/marker.hpp>

View file

@ -25,6 +25,7 @@
// mapnik
#include <mapnik/char_info.hpp>
#include <mapnik/pixel_position.hpp>
//stl
#include <vector>
@ -124,18 +125,23 @@ class text_path : boost::noncopyable
struct character_node
{
int c;
double x, y, angle;
pixel_position pos;
double angle;
char_properties *format;
character_node(int c_, double x_, double y_, double angle_, char_properties *format_)
: c(c_), x(x_), y(y_), angle(angle_), format(format_) {}
: c(c_), pos(x_, y_), angle(angle_), format(format_)
{
}
~character_node() {}
void vertex(int *c_, double *x_, double *y_, double *angle_, char_properties **format_)
{
*c_ = c;
*x_ = x;
*y_ = y;
*x_ = pos.x;
*y_ = pos.y;
*angle_ = angle;
*format_ = format;
}
@ -145,16 +151,11 @@ class text_path : boost::noncopyable
public:
typedef std::vector<character_node> character_nodes_t;
character_nodes_t nodes_;
double starting_x;
double starting_y;
// std::pair<unsigned,unsigned> string_dimensions;
pixel_position center;
text_path()
: itr_(0),
starting_x(0),
starting_y(0)
: itr_(0)
{
}

View file

@ -39,6 +39,7 @@ public:
text_symbolizer_properties & add();
text_symbolizer_properties & get(unsigned i);
unsigned size() const;
static text_placements_ptr from_xml(boost::property_tree::ptree const &xml, fontset_map const & fontsets);
private:
std::vector<text_symbolizer_properties> list_;
friend class text_placement_info_list;

View file

@ -38,7 +38,8 @@ namespace mapnik
namespace placements
{
typedef text_placements_ptr (*from_xml_function_ptr)(boost::property_tree::ptree const& xml);
typedef text_placements_ptr (*from_xml_function_ptr)(
boost::property_tree::ptree const& xml, fontset_map const & fontsets);
class registry : public singleton<registry, CreateStatic>,
private boost::noncopyable
@ -47,7 +48,9 @@ public:
registry();
~registry() {}
void register_name(std::string name, from_xml_function_ptr ptr, bool overwrite=false);
text_placements_ptr from_xml(std::string name, boost::property_tree::ptree const& xml);
text_placements_ptr from_xml(std::string name,
boost::property_tree::ptree const& xml,
fontset_map const & fontsets);
private:
std::map<std::string, from_xml_function_ptr> map_;
};

View file

@ -53,6 +53,7 @@ public:
double scale_factor, dimension_type dim, bool has_dimensions) const;
void set_positions(std::string positions);
std::string get_positions();
static text_placements_ptr from_xml(boost::property_tree::ptree const &xml, fontset_map const & fontsets);
private:
std::string positions_;
std::vector<directions_t> direction_;

View file

@ -48,11 +48,13 @@ enum text_transform
};
DEFINE_ENUM(text_transform_e, text_transform);
typedef std::map<std::string, font_set> fontset_map;
struct char_properties
{
char_properties();
/** Construct object from XML. */
void from_xml(boost::property_tree::ptree const &sym, std::map<std::string,font_set> const & fontsets);
void from_xml(boost::property_tree::ptree const &sym, fontset_map const & fontsets);
/** Write object to XML ptree. */
void to_xml(boost::property_tree::ptree &node, bool explicit_defaults, char_properties const &dfl=char_properties()) const;
std::string face_name;
@ -122,7 +124,7 @@ struct text_symbolizer_properties
{
text_symbolizer_properties();
/** Load all values from XML ptree. */
void from_xml(boost::property_tree::ptree const &sym, std::map<std::string,font_set> const & fontsets);
void from_xml(boost::property_tree::ptree const &sym, fontset_map const & fontsets);
/** Save all values to XML ptree (but does not create a new parent node!). */
void to_xml(boost::property_tree::ptree &node, bool explicit_defaults, text_symbolizer_properties const &dfl=text_symbolizer_properties()) const;

View file

@ -26,7 +26,6 @@
#include <mapnik/agg_rasterizer.hpp>
#include <mapnik/marker_cache.hpp>
#include <mapnik/unicode.hpp>
#include <mapnik/placement_finder.hpp>
#include <mapnik/config_error.hpp>
#include <mapnik/font_set.hpp>
#include <mapnik/parse_path.hpp>

View file

@ -57,10 +57,8 @@ void agg_renderer<T>::process(shield_symbolizer const& sym,
std::pair<int, int> marker_pos = helper.get_marker_position(placement->placements[ii]);
render_marker(marker_pos.first, marker_pos.second, helper.get_marker(), helper.get_transform(), sym.get_opacity());
double x = placement->placements[ii].starting_x;
double y = placement->placements[ii].starting_y;
ren.prepare_glyphs(&(placement->placements[ii]));
ren.render(x, y);
ren.render(placement->placements[ii].center);
}
}
}

View file

@ -46,10 +46,8 @@ void agg_renderer<T>::process(text_symbolizer const& sym,
while ((placement = helper.get_placement())) {
for (unsigned int ii = 0; ii < placement->placements.size(); ++ii)
{
double x = placement->placements[ii].starting_x;
double y = placement->placements[ii].starting_y;
ren.prepare_glyphs(&(placement->placements[ii]));
ren.render(x, y);
ren.render(placement->placements[ii].center);
}
}
}

View file

@ -27,7 +27,6 @@
#include <mapnik/cairo_renderer.hpp>
#include <mapnik/image_util.hpp>
#include <mapnik/unicode.hpp>
#include <mapnik/placement_finder.hpp>
#include <mapnik/markers_placement.hpp>
#include <mapnik/arrow.hpp>
#include <mapnik/config_error.hpp>
@ -575,8 +574,8 @@ public:
cairo_face_manager & manager,
face_manager<freetype_engine> &font_manager)
{
double sx = path.starting_x;
double sy = path.starting_y;
double sx = path.center.x;
double sy = path.center.y;
path.rewind();

View file

@ -379,25 +379,25 @@ box2d<double> text_renderer<T>::prepare_glyphs(text_path *path)
}
template <typename T>
void text_renderer<T>::render(double x0, double y0)
void text_renderer<T>::render(pixel_position pos)
{
FT_Error error;
FT_Vector start;
unsigned height = pixmap_.height();
start.x = static_cast<FT_Pos>(x0 * (1 << 6));
start.y = static_cast<FT_Pos>((height - y0) * (1 << 6));
start.x = static_cast<FT_Pos>(pos.x * (1 << 6));
start.y = static_cast<FT_Pos>((height - pos.y) * (1 << 6));
// now render transformed glyphs
typename glyphs_t::iterator pos;
for ( pos = glyphs_.begin(); pos != glyphs_.end();++pos)
typename glyphs_t::iterator itr;
for (itr = glyphs_.begin(); itr != glyphs_.end(); ++itr)
{
double halo_radius = pos->properties->halo_radius;
double halo_radius = itr->properties->halo_radius;
//make sure we've got reasonable values.
if (halo_radius <= 0.0 || halo_radius > 1024.0) continue;
stroker_.init(halo_radius);
FT_Glyph g;
error = FT_Glyph_Copy(pos->image, &g);
error = FT_Glyph_Copy(itr->image, &g);
if (!error)
{
FT_Glyph_Transform(g,0,&start);
@ -407,49 +407,49 @@ void text_renderer<T>::render(double x0, double y0)
{
FT_BitmapGlyph bit = (FT_BitmapGlyph)g;
render_bitmap(&bit->bitmap, pos->properties->halo_fill.rgba(),
render_bitmap(&bit->bitmap, itr->properties->halo_fill.rgba(),
bit->left,
height - bit->top, pos->properties->text_opacity);
height - bit->top, itr->properties->text_opacity);
}
}
FT_Done_Glyph(g);
}
//render actual text
for ( pos = glyphs_.begin(); pos != glyphs_.end();++pos)
for (itr = glyphs_.begin(); itr != glyphs_.end(); ++itr)
{
FT_Glyph_Transform(pos->image,0,&start);
FT_Glyph_Transform(itr->image,0,&start);
error = FT_Glyph_To_Bitmap( &(pos->image),FT_RENDER_MODE_NORMAL,0,1);
error = FT_Glyph_To_Bitmap( &(itr->image),FT_RENDER_MODE_NORMAL,0,1);
if ( ! error )
{
FT_BitmapGlyph bit = (FT_BitmapGlyph)pos->image;
render_bitmap(&bit->bitmap, pos->properties->fill.rgba(),
FT_BitmapGlyph bit = (FT_BitmapGlyph)itr->image;
render_bitmap(&bit->bitmap, itr->properties->fill.rgba(),
bit->left,
height - bit->top, pos->properties->text_opacity);
height - bit->top, itr->properties->text_opacity);
}
}
}
template <typename T>
void text_renderer<T>::render_id(int feature_id,double x0, double y0, double min_radius)
void text_renderer<T>::render_id(int feature_id, pixel_position pos, double min_radius)
{
FT_Error error;
FT_Vector start;
unsigned height = pixmap_.height();
start.x = static_cast<FT_Pos>(x0 * (1 << 6));
start.y = static_cast<FT_Pos>((height - y0) * (1 << 6));
start.x = static_cast<FT_Pos>(pos.x * (1 << 6));
start.y = static_cast<FT_Pos>((height - pos.y) * (1 << 6));
// now render transformed glyphs
typename glyphs_t::iterator pos;
for ( pos = glyphs_.begin(); pos != glyphs_.end();++pos)
typename glyphs_t::iterator itr;
for (itr = glyphs_.begin(); itr != glyphs_.end(); ++itr)
{
stroker_.init(std::max(pos->properties->halo_radius, min_radius));
stroker_.init(std::max(itr->properties->halo_radius, min_radius));
FT_Glyph g;
error = FT_Glyph_Copy(pos->image, &g);
error = FT_Glyph_Copy(itr->image, &g);
if (!error)
{
FT_Glyph_Transform(g,0,&start);
@ -473,11 +473,11 @@ void text_renderer<T>::render_id(int feature_id,double x0, double y0, double min
boost::mutex freetype_engine::mutex_;
#endif
std::map<std::string,std::pair<int,std::string> > freetype_engine::name2file_;
template void text_renderer<image_32>::render(double, double);
template void text_renderer<image_32>::render(pixel_position);
template text_renderer<image_32>::text_renderer(image_32&, face_manager<freetype_engine>&, stroker&);
template box2d<double>text_renderer<image_32>::prepare_glyphs(text_path*);
template void text_renderer<grid>::render_id(int, double, double, double);
template void text_renderer<grid>::render_id(int, pixel_position, double);
template text_renderer<grid>::text_renderer(grid&, face_manager<freetype_engine>&, stroker&);
template box2d<double>text_renderer<grid>::prepare_glyphs(text_path*);
}

View file

@ -31,7 +31,6 @@
#include <mapnik/marker_cache.hpp>
#include <mapnik/unicode.hpp>
#include <mapnik/placement_finder.hpp>
#include <mapnik/config_error.hpp>
#include <mapnik/font_set.hpp>
#include <mapnik/parse_path.hpp>

View file

@ -66,10 +66,8 @@ void grid_renderer<T>::process(shield_symbolizer const& sym,
helper.get_marker(), helper.get_transform(),
sym.get_opacity());
double x = floor(placement->placements[ii].starting_x);
double y = floor(placement->placements[ii].starting_y);
ren.prepare_glyphs(&(placement->placements[ii]));
ren.render_id(feature->id(), x, y, 2);
ren.render_id(feature->id(),placement->placements[ii].center, 2);
}
}
if (placement_found)

View file

@ -47,10 +47,8 @@ void grid_renderer<T>::process(text_symbolizer const& sym,
placement_found = true;
for (unsigned int ii = 0; ii < placement->placements.size(); ++ii)
{
double x = placement->placements[ii].starting_x;
double y = placement->placements[ii].starting_y;
ren.prepare_glyphs(&(placement->placements[ii]));
ren.render_id(feature->id(),x,y,2);
ren.render_id(feature->id(), placement->placements[ii].center,2);
}
}
if (placement_found) pixmap_.add_feature(feature);

View file

@ -47,8 +47,7 @@
#include <mapnik/metawriter_factory.hpp>
#include <mapnik/text_placements/simple.hpp>
#include <mapnik/text_placements/list.hpp>
#include <mapnik/text_placements/registry.hpp>
#include <mapnik/text_placements/dummy.hpp>
#include <mapnik/symbolizer.hpp>
#include <mapnik/rule.hpp>
@ -1263,46 +1262,16 @@ void map_parser::parse_text_symbolizer( rule & rule, ptree const & sym )
try
{
text_placements_ptr placement_finder;
text_placements_list *list = 0;
optional<std::string> placement_type = get_opt_attr<std::string>(sym, "placement-type");
if (placement_type) {
if (*placement_type == "simple") {
placement_finder = text_placements_ptr(
new text_placements_simple(
get_attr<std::string>(sym, "placements", "X")));
} else if (*placement_type == "list") {
list = new text_placements_list();
placement_finder = text_placements_ptr(list);
} else if (*placement_type != "dummy" && *placement_type != "") {
throw config_error(std::string("Unknown placement type '"+*placement_type+"'"));
}
}
if (!placement_finder) {
placement_finder = placements::registry::instance()->from_xml(*placement_type, sym, fontsets_);
} else {
placement_finder = text_placements_ptr(new text_placements_dummy());
placement_finder->defaults.from_xml(sym, fontsets_);
}
placement_finder->defaults.from_xml(sym, fontsets_);
if (strict_ &&
!placement_finder->defaults.format.fontset.size())
ensure_font_face(placement_finder->defaults.format.face_name);
if (list) {
ptree::const_iterator symIter = sym.begin();
ptree::const_iterator endSym = sym.end();
for( ;symIter != endSym; ++symIter) {
if (symIter->first.find('<') != std::string::npos) continue;
if (symIter->first != "Placement")
{
// throw config_error("Unknown element '" + symIter->first + "'"); TODO
continue;
}
ensure_attrs(symIter->second, "TextSymbolizer/Placement", s_common.str());
text_symbolizer_properties & p = list->add();
p.from_xml(symIter->second, fontsets_);
if (strict_ &&
!p.format.fontset.size())
ensure_font_face(p.format.face_name);
}
}
text_symbolizer text_symbol = text_symbolizer(placement_finder);
parse_metawriter_in_symbolizer(text_symbol, sym);
@ -1336,46 +1305,16 @@ void map_parser::parse_shield_symbolizer( rule & rule, ptree const & sym )
try
{
text_placements_ptr placement_finder;
text_placements_list *list = 0;
optional<std::string> placement_type = get_opt_attr<std::string>(sym, "placement-type");
if (placement_type) {
if (*placement_type == "simple") {
placement_finder = text_placements_ptr(
new text_placements_simple(
get_attr<std::string>(sym, "placements", "X")));
} else if (*placement_type == "list") {
list = new text_placements_list();
placement_finder = text_placements_ptr(list);
} else if (*placement_type != "dummy" && *placement_type != "") {
throw config_error(std::string("Unknown placement type '"+*placement_type+"'"));
}
}
if (!placement_finder) {
placement_finder = placements::registry::instance()->from_xml(*placement_type, sym, fontsets_);
} else {
placement_finder = text_placements_ptr(new text_placements_dummy());
}
placement_finder->defaults.from_xml(sym, fontsets_);
if (strict_ &&
!placement_finder->defaults.format.fontset.size())
ensure_font_face(placement_finder->defaults.format.face_name);
if (list) {
ptree::const_iterator symIter = sym.begin();
ptree::const_iterator endSym = sym.end();
for( ;symIter != endSym; ++symIter) {
if (symIter->first.find('<') != std::string::npos) continue;
if (symIter->first != "Placement")
{
// throw config_error("Unknown element '" + symIter->first + "'"); TODO
continue;
}
ensure_attrs(symIter->second, "TextSymbolizer/Placement", s_common);
text_symbolizer_properties & p = list->add();
p.from_xml(symIter->second, fontsets_);
if (strict_&&
!p.format.fontset.size())
ensure_font_face(p.format.face_name);
}
}
shield_symbolizer shield_symbol = shield_symbolizer(placement_finder);
/* Symbolizer specific attributes. */

View file

@ -202,8 +202,8 @@ void metawriter_json_stream::add_text(text_placement_info const& p,
char_properties *format;
current_placement.rewind();
for (int i = 0; i < current_placement.num_nodes(); ++i) {
int cx = current_placement.starting_x;
int cy = current_placement.starting_y;
int cx = current_placement.center.x;
int cy = current_placement.center.y;
current_placement.vertex(&c, &x, &y, &angle, &format);
if (cx+x >= 0 && cx+x < width_ && cy-y >= 0 && cy-y < height_) inside = true;
if (angle > 0.001 || angle < -0.001) straight = false;
@ -225,10 +225,10 @@ void metawriter_json_stream::add_text(text_placement_info const& p,
maxy = std::max(maxy, y+ci.ymax);
miny = std::min(miny, y+ci.ymin);
}
add_box(box2d<double>(current_placement.starting_x+minx,
current_placement.starting_y-miny,
current_placement.starting_x+maxx,
current_placement.starting_y-maxy), feature, t, properties);
add_box(box2d<double>(current_placement.center.x+minx,
current_placement.center.y-miny,
current_placement.center.x+maxx,
current_placement.center.y-maxy), feature, t, properties);
continue;
}
@ -247,8 +247,8 @@ void metawriter_json_stream::add_text(text_placement_info const& p,
double x0, y0, x1, y1, x2, y2, x3, y3;
double sina = sin(angle);
double cosa = cos(angle);
x0 = current_placement.starting_x + x - sina*ci.ymin;
y0 = current_placement.starting_y - y - cosa*ci.ymin;
x0 = current_placement.center.x + x - sina*ci.ymin;
y0 = current_placement.center.y - y - cosa*ci.ymin;
x1 = x0 + ci.width * cosa;
y1 = y0 - ci.width * sina;
x2 = x0 + (ci.width * cosa - ci.height() * sina);

View file

@ -23,7 +23,6 @@
// Mapnik
#include <mapnik/metawriter.hpp>
#include <mapnik/metawriter_inmem.hpp>
#include <mapnik/placement_finder.hpp>
#include <mapnik/text_placements/base.hpp>
// Boost

View file

@ -200,6 +200,7 @@ void placement_finder<DetectorT>::init_string_size()
first_line_space_ = std::max(first_line_space_, ci.line_height-ci.avg_height);
}
string_width_ -= info_.at(info_.num_characters()-1).format->character_spacing; //Remove last space
string_height_ -= first_line_space_; //First line is a bit smaller
}
@ -234,7 +235,7 @@ void placement_finder<DetectorT>::find_line_breaks()
double line_height = 0.0; //Height of tallest char in line
double word_width = 0.0; //Current unfinished word width
double word_height = 0.0;
//line_width, word_width does include char width + spacing, but not the spacing after the last char
//line_width and word_width include char width + spacing, but not the spacing after the last char
for (unsigned int ii = 0; ii < info_.num_characters(); ii++)
{
@ -248,7 +249,7 @@ void placement_finder<DetectorT>::find_line_breaks()
line_width += word_width + last_wrap_char_width;
line_height = std::max(line_height, word_height);
last_wrap_char_width = last_char_spacing + ci.width + ci.format->character_spacing;
last_char_spacing = 0.0;
last_char_spacing = 0.0; //Current one is included in last_wrap_char_width
word_width = 0.0;
word_height = 0.0;
} else {
@ -256,6 +257,7 @@ void placement_finder<DetectorT>::find_line_breaks()
word_width += last_char_spacing + ci.width;
last_char_spacing = ci.format->character_spacing;
word_height = std::max(word_height, ci.line_height + ci.format->line_spacing);
//TODO: I think this calculation could be wrong if height changes for the first word in the second line
if (first_line) first_line_space_ = std::max(first_line_space_, ci.line_height-ci.avg_height);
}
@ -264,10 +266,8 @@ void placement_finder<DetectorT>::find_line_breaks()
(line_width > 0 && ((line_width > wrap_at && !ci.format->wrap_before) ||
((line_width + last_wrap_char_width + word_width) > wrap_at && ci.format->wrap_before)) ))
{
string_width_ = std::max(string_width_, line_width); //Total width is the longest line
string_height_ += line_height;
add_line(line_width, line_height, first_line);
line_breaks_.push_back(last_wrap_char_pos);
line_sizes_.push_back(std::make_pair(line_width, line_height));
line_width = 0.0;
line_height = 0.0;
last_wrap_char_width = 0; //Wrap char supressed
@ -276,9 +276,7 @@ void placement_finder<DetectorT>::find_line_breaks()
}
line_width += last_wrap_char_width + word_width;
line_height = std::max(line_height, word_height);
string_width_ = std::max(string_width_, line_width);
string_height_ += line_height;
line_sizes_.push_back(std::make_pair(line_width, line_height));
add_line(line_width, line_height, first_line);
} else {
//No linebreaks
line_sizes_.push_back(std::make_pair(string_width_, string_height_));
@ -286,6 +284,14 @@ void placement_finder<DetectorT>::find_line_breaks()
line_breaks_.push_back(info_.num_characters());
}
template <typename DetectorT>
void placement_finder<DetectorT>::add_line(double width, double height, bool first_line)
{
if (first_line) height -= first_line_space_;
string_width_ = std::max(string_width_, width); //Total width is the longest line
string_height_ += height;
line_sizes_.push_back(std::make_pair(width, height));
}
template <typename DetectorT>
@ -317,26 +323,28 @@ template <typename DetectorT>
void placement_finder<DetectorT>::adjust_position(text_path *current_placement, double label_x, double label_y)
{
// if needed, adjust for desired vertical alignment
current_placement->starting_y = label_y; // no adjustment, default is MIDDLE
current_placement->center.y = label_y; // no adjustment, default is MIDDLE
if (valign_ == V_TOP)
current_placement->starting_y -= 0.5 * string_height_; // move center up by 1/2 the total height
else if (valign_ == V_BOTTOM) {
current_placement->starting_y += 0.5 * string_height_; // move center down by the 1/2 the total height
current_placement->starting_y -= first_line_space_;
} else if (valign_ == V_MIDDLE) {
current_placement->starting_y -= first_line_space_/2.0;
{
current_placement->center.y -= 0.5 * string_height_; // move center up by 1/2 the total height
} else if (valign_ == V_BOTTOM)
{
current_placement->center.y += 0.5 * string_height_; // move center down by the 1/2 the total height
}
// set horizontal position to middle of text
current_placement->starting_x = label_x; // no adjustment, default is MIDDLE
current_placement->center.x = label_x; // no adjustment, default is MIDDLE
if (halign_ == H_LEFT)
current_placement->starting_x -= 0.5 * string_width_; // move center left by 1/2 the string width
else if (halign_ == H_RIGHT)
current_placement->starting_x += 0.5 * string_width_; // move center right by 1/2 the string width
{
current_placement->center.x -= 0.5 * string_width_; // move center left by 1/2 the string width
} else if (halign_ == H_RIGHT)
{
current_placement->center.x += 0.5 * string_width_; // move center right by 1/2 the string width
}
// adjust text envelope position by user's x-y displacement (dx, dy)
current_placement->starting_x += pi.get_scale_factor() * p.displacement.first;
current_placement->starting_y += pi.get_scale_factor() * p.displacement.second;
current_placement->center.x += pi.get_scale_factor() * p.displacement.first;
current_placement->center.y += pi.get_scale_factor() * p.displacement.second;
}
@ -362,17 +370,22 @@ void placement_finder<DetectorT>::find_point_placement(double label_x, double la
double line_width = line_sizes_[0].first;
double line_height = line_sizes_[0].second;
//TODO: Understand and document this
/* IMPORTANT NOTE:
x and y are relative to the center of the text
coordinate system:
x: grows from left to right
y: grows from bottom to top (opposite of normal computer graphics)
*/
// set for upper left corner of text envelope for the first line, bottom left of first character
y = (string_height_ / 2.0) - line_height;
y = string_height_ / 2.0 - line_height;
// adjust for desired justification
//TODO: Understand and document this
if (p.jalign == J_LEFT)
x = -(string_width_ / 2.0);
else if (p.jalign == J_RIGHT)
x = (string_width_ / 2.0) - line_width;
else
else /* J_MIDDLE */
x = -(line_width / 2.0);
// save each character rendering position and build envelope as go thru loop
@ -416,19 +429,19 @@ void placement_finder<DetectorT>::find_point_placement(double label_x, double la
/*x axis: left to right, y axis: top to bottom (negative values higher)*/
if (pi.has_dimensions)
{
e.init(current_placement->starting_x - (pi.dimensions.first/2.0), // Top Left
current_placement->starting_y - (pi.dimensions.second/2.0),
e.init(current_placement->center.x - (pi.dimensions.first/2.0), // Top Left
current_placement->center.y - (pi.dimensions.second/2.0),
current_placement->starting_x + (pi.dimensions.first/2.0), // Bottom Right
current_placement->starting_y + (pi.dimensions.second/2.0));
current_placement->center.x + (pi.dimensions.first/2.0), // Bottom Right
current_placement->center.y + (pi.dimensions.second/2.0));
}
else
{
e.init(current_placement->starting_x + dx, // Bottom Left
current_placement->starting_y - dy - ci.ymin, /*ymin usually <0 */
e.init(current_placement->center.x + dx, // Bottom Left
current_placement->center.y - dy - ci.ymin, /*ymin usually <0 */
current_placement->starting_x + dx + ci.width, // Top Right
current_placement->starting_y - dy - ci.ymax);
current_placement->center.x + dx + ci.width, // Top Right
current_placement->center.y - dy - ci.ymax);
}
// if there is an overlap with existing envelopes, then exit - no placement
@ -465,10 +478,10 @@ void placement_finder<DetectorT>::find_point_placement(double label_x, double la
{
BOOST_FOREACH(box2d<double> box, pi.additional_boxes)
{
box2d<double> pt(box.minx() + current_placement->starting_x,
box.miny() + current_placement->starting_y,
box.maxx() + current_placement->starting_x,
box.maxy() + current_placement->starting_y);
box2d<double> pt(box.minx() + current_placement->center.x,
box.miny() + current_placement->center.y,
box.maxx() + current_placement->center.x,
box.maxy() + current_placement->center.y);
// abort the whole placement if the additional envelopes can't be placed.
if (!detector_.has_point_placement(pt, p.minimum_distance)) return;
@ -618,8 +631,8 @@ void placement_finder<DetectorT>::find_line_placements(PathT & shape_path)
//Offset all the characters by this angle
for (unsigned i = 0; i < current_placement->nodes_.size(); i++)
{
current_placement->nodes_[i].x += pi.get_scale_factor() * displacement*cos(anglesum+M_PI/2);
current_placement->nodes_[i].y += pi.get_scale_factor() * displacement*sin(anglesum+M_PI/2);
current_placement->nodes_[i].pos.x += pi.get_scale_factor() * displacement*cos(anglesum+M_PI/2);
current_placement->nodes_[i].pos.y += pi.get_scale_factor() * displacement*sin(anglesum+M_PI/2);
}
}
@ -699,8 +712,8 @@ std::auto_ptr<text_path> placement_finder<DetectorT>::get_placement_offset(const
return std::auto_ptr<text_path>(NULL);
}
current_placement->starting_x = old_x + dx*distance/segment_length;
current_placement->starting_y = old_y + dy*distance/segment_length;
current_placement->center.x = old_x + dx*distance/segment_length;
current_placement->center.y = old_y + dy*distance/segment_length;
double angle = atan2(-dy, dx);
bool orientation_forced = (orientation != 0); //Wether the orientation was set by the caller
@ -808,8 +821,8 @@ std::auto_ptr<text_path> placement_finder<DetectorT>::get_placement_offset(const
render_y -= cwidth*sina + (char_height-2)*cosa;
render_angle += M_PI;
}
current_placement->add_node(c,render_x - current_placement->starting_x,
-render_y + current_placement->starting_y,
current_placement->add_node(c,render_x - current_placement->center.x,
-render_y + current_placement->center.y,
render_angle, ci.format);
//Normalise to 0 <= angle < 2PI
@ -856,8 +869,8 @@ bool placement_finder<DetectorT>::test_placement(const std::auto_ptr<text_path>
double x, y, angle;
char_properties *properties;
current_placement->vertex(&c, &x, &y, &angle, &properties);
x = current_placement->starting_x + x;
y = current_placement->starting_y - y;
x = current_placement->center.x + x;
y = current_placement->center.y - y;
double sina = fast_sin(angle);
double cosa = fast_cos(angle);
@ -1011,5 +1024,4 @@ typedef label_collision_detector4 DetectorType;
template class placement_finder<DetectorType>;
template void placement_finder<DetectorType>::find_point_placements<PathType>(PathType &);
template void placement_finder<DetectorType>::find_line_placements<PathType>(PathType &);
} // namespace

View file

@ -1,5 +1,29 @@
/*****************************************************************************
*
* This file is part of Mapnik (c++ mapping toolkit)
*
* Copyright (C) 2011 Artem Pavlenko
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
*****************************************************************************/
// mapnik
#include <mapnik/symbolizer_helpers.hpp>
#include <mapnik/label_collision_detector.hpp>
#include <mapnik/placement_finder.hpp>
namespace mapnik {
@ -231,7 +255,7 @@ text_placement_info_ptr shield_symbolizer_helper<FaceManagerT, DetectorT>::get_p
point_itr_ = points_.begin();
continue; //Reexecute size check
}
position const& pos = placement_->properties.displacement;
position const& text_disp = placement_->properties.displacement;
double label_x = point_itr_->first + shield_pos.first;
double label_y = point_itr_->second + shield_pos.second;
@ -247,14 +271,12 @@ text_placement_info_ptr shield_symbolizer_helper<FaceManagerT, DetectorT>::get_p
}
//Found a label placement but not necessarily also a marker placement
// check to see if image overlaps anything too, there is only ever 1 placement found for points and verticies
double x = floor(placement_->placements[0].starting_x);
double y = floor(placement_->placements[0].starting_y);
if (!sym_.get_unlock_image())
{
// center image at text center position
// remove displacement from image label
double lx = x - pos.first;
double ly = y - pos.second;
double lx = placement_->placements[0].center.x - text_disp.first;
double ly = placement_->placements[0].center.y - text_disp.second;
marker_x_ = lx - 0.5 * marker_w_;
marker_y_ = ly - 0.5 * marker_h_;
marker_ext_.re_center(lx, ly);
@ -340,11 +362,8 @@ std::pair<int, int> shield_symbolizer_helper<FaceManagerT, DetectorT>::get_marke
{
position const& pos = placement_->properties.displacement;
if (placement_->properties.label_placement == LINE_PLACEMENT) {
double x = floor(p.starting_x);
double y = floor(p.starting_y);
double lx = x - pos.first;
double ly = y - pos.second;
double lx = p.center.x - pos.first;
double ly = p.center.y - pos.second;
int px = lx - 0.5*marker_w_;
int py = ly - 0.5*marker_h_;
marker_ext_.re_center(lx, ly);

View file

@ -81,5 +81,25 @@ unsigned text_placements_list::size() const
return list_.size();
}
text_placements_ptr text_placements_list::from_xml(boost::property_tree::ptree const &xml, fontset_map const & fontsets)
{
using boost::property_tree::ptree;
text_placements_list *list = new text_placements_list;
text_placements_ptr ptr = text_placements_ptr(list);
list->defaults.from_xml(xml, fontsets);
ptree::const_iterator itr = xml.begin();
ptree::const_iterator end = xml.end();
for( ;itr != end; ++itr) {
if ((itr->first.find('<') != std::string::npos) || (itr->first != "Placement")) continue;
//TODO: ensure_attrs(symIter->second, "TextSymbolizer/Placement", s_common.str());
text_symbolizer_properties &p = list->add();
p.from_xml(itr->second, fontsets);
//TODO: if (strict_ &&
// !p.format.fontset.size())
// ensure_font_face(p.format.face_name);
}
return ptr;
}
} //ns mapnik

View file

@ -21,6 +21,8 @@
*****************************************************************************/
// mapnik
#include <mapnik/text_placements/registry.hpp>
#include <mapnik/text_placements/simple.hpp>
#include <mapnik/text_placements/list.hpp>
namespace mapnik
{
@ -29,7 +31,8 @@ namespace placements
registry::registry()
{
register_name("simple", &text_placements_simple::from_xml);
register_name("list", &text_placements_list::from_xml);
}
void registry::register_name(std::string name, from_xml_function_ptr ptr, bool overwrite)
@ -41,11 +44,11 @@ void registry::register_name(std::string name, from_xml_function_ptr ptr, bool o
}
}
text_placements_ptr registry::from_xml(std::string name, const boost::property_tree::ptree &xml)
text_placements_ptr registry::from_xml(std::string name, const boost::property_tree::ptree &xml, fontset_map const& fontsets)
{
std::map<std::string, from_xml_function_ptr>::const_iterator itr = map_.find(name);
if (itr == map_.end()) throw config_error("Unknown placement-type '" + name + "'");
return itr->second(xml);
return itr->second(xml, fontsets);
}
} //ns formatting
} //ns mapnik

View file

@ -22,6 +22,7 @@
// mapnik
#include <mapnik/text_placements/simple.hpp>
#include <mapnik/ptree_helpers.hpp>
// boost
#include <boost/spirit/include/qi.hpp>
@ -165,4 +166,12 @@ std::string text_placements_simple::get_positions()
return positions_; //TODO: Build string from data in direction_ and text_sizes_
}
text_placements_ptr text_placements_simple::from_xml(boost::property_tree::ptree const &xml, fontset_map const & fontsets)
{
text_placements_ptr ptr = text_placements_ptr(new text_placements_simple(
get_attr<std::string>(xml, "placements", "X")));
ptr->defaults.from_xml(xml, fontsets);
return ptr;
}
} //ns mapnik

View file

@ -72,7 +72,7 @@ formatting::node_ptr text_symbolizer_properties::format_tree() const
return tree_;
}
void text_symbolizer_properties::from_xml(boost::property_tree::ptree const &sym, std::map<std::string,font_set> const & fontsets)
void text_symbolizer_properties::from_xml(boost::property_tree::ptree const &sym, fontset_map const & fontsets)
{
optional<label_placement_e> placement_ = get_opt_attr<label_placement_e>(sym, "placement");
if (placement_) label_placement = *placement_;
@ -230,7 +230,7 @@ char_properties::char_properties() :
}
void char_properties::from_xml(boost::property_tree::ptree const &sym, std::map<std::string,font_set> const & fontsets)
void char_properties::from_xml(boost::property_tree::ptree const &sym, fontset_map const & fontsets)
{
optional<double> text_size_ = get_opt_attr<double>(sym, "size");
if (text_size_) text_size = *text_size_;

Binary file not shown.

After

Width:  |  Height:  |  Size: 216 B

View file

@ -0,0 +1,36 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="16"
height="16"
id="svg2"
version="1.1"
>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1">
<path
style="fill:none;stroke:#ff0000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
d="M 0,8 16,8"
id="path4387"
inkscape:path-effect="#path-effect4389"
inkscape:original-d="M 0,8 16,8"
inkscape:connector-curvature="0" />
<path
inkscape:connector-curvature="0"
inkscape:original-d="M 8,0 8,16"
inkscape:path-effect="#path-effect4389"
id="path4391"
d="M 8,0 8,16"
style="fill:none;stroke:#ff0000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.2 KiB

View file

@ -1,5 +1,3 @@
rm -f list-[0-9][0-9]0-agg.png
rm -f simple-[0-9][0-9]0-agg.png
rm -f simple-{E,N,NE,NW,N,SE,SW,S,W}-500-agg.png
rm -f list-out.xml simple-out.xml
rm -f *-agg.png
rm -f *-out.xml

View file

@ -0,0 +1,43 @@
import math, operator
import Image
import sys
COMPUTE_THRESHOLD = 16
errors = []
# returns true if pixels are not identical
def compare_pixels(pixel1, pixel2):
r_diff = abs(pixel1[0] - pixel2[0])
g_diff = abs(pixel1[1] - pixel2[1])
b_diff = abs(pixel1[2] - pixel2[2])
if(r_diff > COMPUTE_THRESHOLD or g_diff > COMPUTE_THRESHOLD or b_diff > COMPUTE_THRESHOLD):
return True
else:
return False
# compare tow images and return number of different pixels
def compare(fn1, fn2):
global errors
im1 = Image.open(fn1)
im2 = Image.open(fn2)
diff = 0
pixels = im1.size[0] * im1.size[1]
im1 = im1.getdata()
im2 = im2.getdata()
for i in range(3, pixels - 1, 3):
if(compare_pixels(im1[i], im2[i])):
diff = diff + 1
if diff != 0:
errors.append((fn1, diff))
return diff
def summary():
global errors
if len(errors) != 0:
print "-"*80
print "Summary:"
for error in errors:
print "%s failed: %d different pixels" % error
print "-"*80
sys.exit(1)

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.7 KiB

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.3 KiB

After

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.3 KiB

After

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.9 KiB

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 KiB

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.7 KiB

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.6 KiB

After

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.5 KiB

After

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.6 KiB

After

Width:  |  Height:  |  Size: 3.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.4 KiB

After

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.1 KiB

After

Width:  |  Height:  |  Size: 4.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.1 KiB

After

Width:  |  Height:  |  Size: 4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 883 B

After

Width:  |  Height:  |  Size: 2 KiB

View file

@ -1,19 +1,59 @@
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE Map>
<Map background-color="white" srs="+proj=latlong +datum=WGS84">
<Map background-color="green" srs="+proj=latlong +datum=WGS84">
<Layer name="layer" srs="+proj=latlong +datum=WGS84">
<StyleName>My Style</StyleName>
<Datasource>
<Parameter name="type">shape</Parameter>
<Parameter name="file">points.shp</Parameter>
</Datasource>
</Layer>
<Layer name="layer" srs="+proj=latlong +datum=WGS84">
<StyleName>My Style</StyleName>
<Datasource>
<Parameter name="type">shape</Parameter>
<Parameter name="file">points.shp</Parameter>
</Datasource>
</Layer>
<Style name="My Style">
<Rule>
<ShieldSymbolizer face-name="DejaVu Sans Book" size="16" placement="point" file="../data/svg/rect.svg" dx="0" dy="-5">'x'</ShieldSymbolizer>
</Rule>
</Style>
<Rule>
<Filter>[nr] = '1'</Filter>
<ShieldSymbolizer face-name="DejaVu Sans Book" size="16" placement="point" file="../data/svg/crosshair16x16.svg">'X'</ShieldSymbolizer>
</Rule>
<Rule>
<Filter>[nr] = '2'</Filter>
<ShieldSymbolizer face-name="DejaVu Sans Book" size="16" placement="point" file="../data/svg/crosshair16x16.svg" allow-overlap="true" horizontal-alignment="middle" dx="5">'X'</ShieldSymbolizer>
</Rule>
<Rule>
<Filter>[nr] = '3'</Filter>
<ShieldSymbolizer face-name="DejaVu Sans Book" size="16" placement="point" file="../data/svg/crosshair16x16.svg" vertical-alignment="middle" dy="5">'X'</ShieldSymbolizer>
</Rule>
<Rule>
<Filter>[nr] = '4'</Filter>
<ShieldSymbolizer face-name="DejaVu Sans Book" size="16" placement="point" file="../data/svg/crosshair16x16.svg" dy="0" vertical-alignment="bottom">'X'</ShieldSymbolizer>
</Rule>
<Rule>
<Filter>[nr] = '5'</Filter>
<ShieldSymbolizer face-name="DejaVu Sans Book" size="16" placement="point" file="../data/svg/crosshair16x16.svg" allow-overlap="true" vertical-alignment="top">'X'</ShieldSymbolizer>
</Rule>
<Rule>
<Filter>[nr] = '6'</Filter>
<ShieldSymbolizer face-name="DejaVu Sans Book" size="16" placement="point" file="../data/svg/crosshair16x16.svg" allow-overlap="true" horizontal-alignment="left">'X'</ShieldSymbolizer>
</Rule>
<Rule>
<Filter>[nr] = '7'</Filter>
<ShieldSymbolizer face-name="DejaVu Sans Book" size="16" placement="point" file="../data/svg/crosshair16x16.svg" allow-overlap="true" horizontal-alignment="right">'X'</ShieldSymbolizer>
</Rule>
<Rule>
<Filter>[nr] = '8'</Filter>
<ShieldSymbolizer face-name="DejaVu Sans Book" size="16" placement="point" file="../data/svg/crosshair16x16.svg">'X&#10;X&#10;X'</ShieldSymbolizer>
</Rule>
<Rule>
<Filter>[nr] = '9'</Filter>
<ShieldSymbolizer face-name="DejaVu Sans Book" size="16" placement="point" file="../data/svg/crosshair16x16.svg">'XXX'</ShieldSymbolizer>
</Rule>
<Rule>
<Filter>[nr] = '10'</Filter>
<ShieldSymbolizer face-name="DejaVu Sans Book" size="16" placement="point" file="../data/images/crosshair16x16.png">'X'</ShieldSymbolizer>
</Rule>
<Rule>
<PointSymbolizer allow-overlap="true" file="../data/raster/white-alpha.png"/>
</Rule>
</Style>
</Map>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.2 KiB

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.4 KiB

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.8 KiB

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.3 KiB

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.5 KiB

After

Width:  |  Height:  |  Size: 4.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.8 KiB

After

Width:  |  Height:  |  Size: 5.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.5 KiB

After

Width:  |  Height:  |  Size: 5.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.3 KiB

After

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 1.5 KiB

View file

@ -5,6 +5,7 @@ import mapnik
import cairo
import sys
import os.path
from compare import compare, summary
dirname = os.path.dirname(sys.argv[0])
@ -14,14 +15,21 @@ filenames_one_width = ["simple-E", "simple-NE", "simple-NW", "simple-N",
"simple-SE", "simple-SW", "simple-S", "simple-W",
"formating-1", "formating-2", "formating-3", "formating-4",
"shieldsymbolizer-1", "expressionformat"]
def render(filename, width):
print "Rendering style \"%s\" with width %d" % (filename, width)
m = mapnik.Map(width, 100)
mapnik.load_map(m, os.path.join(dirname, "%s.xml" % filename), False)
bbox = mapnik.Box2d(-0.05, -0.01, 0.95, 0.01)
m.zoom_to_box(bbox)
mapnik.render_to_file(m, '%s-%d-agg.png' % (filename, width))
basefn = '%s-%d' % (filename, width)
mapnik.render_to_file(m, basefn+'-agg.png')
diff = compare(basefn + '-agg.png', basefn + '-reference.png')
if diff == 0:
rms = 'ok'
else:
rms = 'error: %u different pixels' % diff
print "Rendering style \"%s\" with width %d ... %s" % (filename, width, rms)
return m
if len(sys.argv) > 1:
@ -37,3 +45,5 @@ for filename in filenames_one_width:
m = render(filename, 500)
mapnik.save_map(m, "%s-out.xml" % filename)
summary()