modified the old arrow_symbolizer interface on glyph_symbolizer and documented it
This commit is contained in:
parent
fc3a1beeef
commit
31c3d20e43
4 changed files with 144 additions and 207 deletions
|
@ -1,6 +1,7 @@
|
|||
#include <mapnik/glyph_symbolizer.hpp>
|
||||
|
||||
#include <boost/python.hpp>
|
||||
#include <boost/tuple/tuple.hpp>
|
||||
#include <mapnik/glyph_symbolizer.hpp>
|
||||
|
||||
using mapnik::glyph_symbolizer;
|
||||
using mapnik::position;
|
||||
|
@ -20,22 +21,33 @@ list get_displacement_list(const glyph_symbolizer& t)
|
|||
void export_glyph_symbolizer()
|
||||
{
|
||||
class_<glyph_symbolizer>("GlyphSymbolizer",
|
||||
init<std::string const&,std::string const&>())
|
||||
init<std::string,mapnik::expression_ptr>())
|
||||
.add_property("face_name",
|
||||
make_function(&glyph_symbolizer::get_face_name,return_value_policy<copy_const_reference>()),
|
||||
&glyph_symbolizer::set_face_name)
|
||||
make_function(&glyph_symbolizer::get_face_name,
|
||||
return_value_policy<copy_const_reference>()),
|
||||
&glyph_symbolizer::set_face_name,
|
||||
"Get/Set the name of the font face (eg:\"DejaVu Sans "
|
||||
"Book\") which contains the glyph"
|
||||
)
|
||||
.add_property("char",
|
||||
make_function(&glyph_symbolizer::get_char,return_value_policy<copy_const_reference>()),
|
||||
&glyph_symbolizer::set_char)
|
||||
.add_property("angle_offset",
|
||||
&glyph_symbolizer::get_angle_offset,
|
||||
&glyph_symbolizer::set_angle_offset)
|
||||
&glyph_symbolizer::get_char,
|
||||
&glyph_symbolizer::set_char,
|
||||
"Get/Set the char expression. The char is the unicode "
|
||||
"character indexing the glyph in the font referred by "
|
||||
"face_name."
|
||||
)
|
||||
.add_property("allow_overlap",
|
||||
&glyph_symbolizer::get_allow_overlap,
|
||||
&glyph_symbolizer::set_allow_overlap)
|
||||
&glyph_symbolizer::set_allow_overlap,
|
||||
"Get/Set the flag which controls if glyphs should "
|
||||
"overlap any symbols previously rendered"
|
||||
)
|
||||
.add_property("avoid_edges",
|
||||
&glyph_symbolizer::get_avoid_edges,
|
||||
&glyph_symbolizer::set_avoid_edges)
|
||||
&glyph_symbolizer::set_avoid_edges,
|
||||
"Get/Set the flag which controls if glyphs should be "
|
||||
"partially drawn beside the edge of a tile."
|
||||
)
|
||||
.def("get_displacement", get_displacement_list)
|
||||
.def("set_displacement", &glyph_symbolizer::set_displacement)
|
||||
.add_property("halo_fill",
|
||||
|
@ -45,31 +57,38 @@ void export_glyph_symbolizer()
|
|||
.add_property("halo_radius",
|
||||
&glyph_symbolizer::get_halo_radius,
|
||||
&glyph_symbolizer::set_halo_radius)
|
||||
.add_property("value_attr", make_function(
|
||||
&glyph_symbolizer::get_value_attr,
|
||||
return_value_policy<copy_const_reference>()),
|
||||
&glyph_symbolizer::set_value_attr)
|
||||
.add_property("azimuth_attr", make_function(
|
||||
&glyph_symbolizer::get_azimuth_attr,
|
||||
return_value_policy<copy_const_reference>()),
|
||||
&glyph_symbolizer::set_azimuth_attr)
|
||||
.add_property("size",
|
||||
&glyph_symbolizer::get_size,
|
||||
&glyph_symbolizer::set_size,
|
||||
"Get/Set the size expression used to size the glyph."
|
||||
)
|
||||
.add_property("angle",
|
||||
&glyph_symbolizer::get_angle,
|
||||
&glyph_symbolizer::set_angle,
|
||||
"Get/Set the angle expression used to rotate the glyph "
|
||||
"along its center."
|
||||
)
|
||||
.add_property("value",
|
||||
&glyph_symbolizer::get_value,
|
||||
&glyph_symbolizer::set_value,
|
||||
"Get/set the value expression which will be used to "
|
||||
"retrieve a a value for the colorizer to use to choose "
|
||||
"a color."
|
||||
)
|
||||
.add_property("color",
|
||||
&glyph_symbolizer::get_color,
|
||||
&glyph_symbolizer::set_color,
|
||||
"Get/Set the color expression used to color the glyph. "
|
||||
"(See also the 'colorizer' attribute)"
|
||||
|
||||
)
|
||||
.add_property("colorizer",
|
||||
&glyph_symbolizer::get_colorizer,
|
||||
&glyph_symbolizer::set_colorizer,
|
||||
"Get/Set the RasterColorizer used to color the arrows.\n"
|
||||
"\n"
|
||||
"Usage:\n"
|
||||
"\n"
|
||||
">>> from mapnik import GlyphSymbolizer, RasterColorizer\n"
|
||||
">>> sym = GlyphSymbolizer()\n"
|
||||
">>> sym.colorizer = RasterColorizer()\n"
|
||||
">>> for value, color in [\n"
|
||||
"... (0, \"#000000\"),\n"
|
||||
"... (10, \"#ff0000\"),\n"
|
||||
"... (40, \"#00ff00\"),\n"
|
||||
"... ]:\n"
|
||||
"... sym.colorizer.append_band(value, color)\n"
|
||||
"Get/Set the RasterColorizer used to color the glyph "
|
||||
"depending on the 'value' expression (which must be "
|
||||
"defined).\n"
|
||||
"Only needed if no explicit color is provided"
|
||||
)
|
||||
;
|
||||
;
|
||||
}
|
||||
|
|
|
@ -1,103 +1,54 @@
|
|||
#ifndef ARROW_SYMBOLIZER_HPP
|
||||
#define ARROW_SYMBOLIZER_HPP
|
||||
|
||||
// mapnik
|
||||
#include <mapnik/raster_colorizer.hpp>
|
||||
#include <mapnik/text_symbolizer.hpp>
|
||||
#include <mapnik/expression_node.hpp>
|
||||
#include <mapnik/text_path.hpp>
|
||||
#include <mapnik/unicode.hpp>
|
||||
#include <mapnik/config_error.hpp>
|
||||
#include <mapnik/font_engine_freetype.hpp>
|
||||
|
||||
// boost
|
||||
#include <boost/tuple/tuple.hpp>
|
||||
|
||||
namespace mapnik
|
||||
{
|
||||
struct MAPNIK_DECL glyph_symbolizer
|
||||
{
|
||||
glyph_symbolizer(std::string const& face_name, std::string const& c)
|
||||
|
||||
typedef boost::tuple<double,double> position;
|
||||
|
||||
struct MAPNIK_DECL glyph_symbolizer
|
||||
{
|
||||
glyph_symbolizer(std::string face_name, expression_ptr c)
|
||||
: face_name_(face_name),
|
||||
char_(c),
|
||||
angle_offset_(0.0),
|
||||
min_size_(10),
|
||||
max_size_(100),
|
||||
min_value_(0),
|
||||
max_value_(1),
|
||||
angle_(),
|
||||
value_(),
|
||||
size_(),
|
||||
color_(),
|
||||
colorizer_(),
|
||||
allow_overlap_(false),
|
||||
avoid_edges_(false),
|
||||
displacement_(0.0, 0.0),
|
||||
halo_fill_(color(255,255,255)),
|
||||
halo_radius_(0),
|
||||
azimuth_attr_("azimuth"),
|
||||
value_attr_("value")
|
||||
{
|
||||
if (get_min_size() > get_max_size())
|
||||
throw config_error("Invalid size range");
|
||||
}
|
||||
halo_radius_(0) {}
|
||||
|
||||
std::string const& get_face_name() const
|
||||
{
|
||||
return face_name_;
|
||||
}
|
||||
|
||||
void set_face_name(std::string face_name)
|
||||
{
|
||||
face_name_ = face_name;
|
||||
}
|
||||
|
||||
std::string const& get_char() const
|
||||
expression_ptr get_char() const
|
||||
{
|
||||
return char_;
|
||||
}
|
||||
|
||||
void set_char(std::string c)
|
||||
void set_char(expression_ptr c)
|
||||
{
|
||||
char_ = c;
|
||||
}
|
||||
|
||||
double get_angle_offset() const
|
||||
{
|
||||
return angle_offset_;
|
||||
}
|
||||
void set_angle_offset(double angle)
|
||||
{
|
||||
angle_offset_ = angle;
|
||||
}
|
||||
|
||||
float get_min_value() const
|
||||
{
|
||||
return min_value_;
|
||||
}
|
||||
void set_min_value(float min_value)
|
||||
{
|
||||
min_value_ = min_value;
|
||||
}
|
||||
|
||||
float get_max_value() const
|
||||
{
|
||||
return max_value_;
|
||||
}
|
||||
void set_max_value(float max_value)
|
||||
{
|
||||
max_value_ = max_value;
|
||||
}
|
||||
|
||||
unsigned get_min_size() const
|
||||
{
|
||||
return min_size_;
|
||||
}
|
||||
void set_min_size(unsigned min_size)
|
||||
{
|
||||
min_size_ = min_size;
|
||||
}
|
||||
|
||||
unsigned get_max_size() const
|
||||
{
|
||||
return max_size_;
|
||||
}
|
||||
void set_max_size(unsigned max_size)
|
||||
{
|
||||
max_size_ = max_size;
|
||||
}
|
||||
|
||||
bool get_allow_overlap() const
|
||||
{
|
||||
return allow_overlap_;
|
||||
|
@ -106,6 +57,7 @@ namespace mapnik
|
|||
{
|
||||
allow_overlap_ = allow_overlap;
|
||||
}
|
||||
|
||||
bool get_avoid_edges() const
|
||||
{
|
||||
return avoid_edges_;
|
||||
|
@ -114,6 +66,7 @@ namespace mapnik
|
|||
{
|
||||
avoid_edges_ = avoid_edges;
|
||||
}
|
||||
|
||||
void set_displacement(double x, double y)
|
||||
{
|
||||
displacement_ = boost::make_tuple(x,y);
|
||||
|
@ -122,6 +75,7 @@ namespace mapnik
|
|||
{
|
||||
return displacement_;
|
||||
}
|
||||
|
||||
void set_halo_fill(color const& fill)
|
||||
{
|
||||
halo_fill_ = fill;
|
||||
|
@ -130,6 +84,7 @@ namespace mapnik
|
|||
{
|
||||
return halo_fill_;
|
||||
}
|
||||
|
||||
void set_halo_radius(unsigned radius)
|
||||
{
|
||||
halo_radius_ = radius;
|
||||
|
@ -140,19 +95,40 @@ namespace mapnik
|
|||
return halo_radius_;
|
||||
}
|
||||
|
||||
std::string const& get_azimuth_attr() const
|
||||
expression_ptr get_angle() const
|
||||
{
|
||||
return azimuth_attr_;
|
||||
return angle_;
|
||||
}
|
||||
void set_angle(expression_ptr angle)
|
||||
{
|
||||
angle_ = angle;
|
||||
}
|
||||
|
||||
void set_azimuth_attr(std::string azimuth_attr)
|
||||
expression_ptr get_value() const
|
||||
{
|
||||
azimuth_attr_ = azimuth_attr;
|
||||
return value_;
|
||||
}
|
||||
void set_value(expression_ptr value)
|
||||
{
|
||||
value_ = value;
|
||||
}
|
||||
|
||||
std::string const& get_value_attr() const
|
||||
expression_ptr get_size() const
|
||||
{
|
||||
return value_attr_;
|
||||
return size_;
|
||||
}
|
||||
void set_size(expression_ptr size)
|
||||
{
|
||||
size_ = size;
|
||||
}
|
||||
|
||||
expression_ptr get_color() const
|
||||
{
|
||||
return color_;
|
||||
}
|
||||
void set_color(expression_ptr color)
|
||||
{
|
||||
color_ = color;
|
||||
}
|
||||
|
||||
raster_colorizer_ptr get_colorizer() const
|
||||
|
@ -164,40 +140,26 @@ namespace mapnik
|
|||
colorizer_ = colorizer;
|
||||
}
|
||||
|
||||
void set_value_attr(std::string value_attr)
|
||||
{
|
||||
value_attr_ = value_attr;
|
||||
}
|
||||
|
||||
/*
|
||||
* helpers
|
||||
*/
|
||||
|
||||
text_path_ptr get_text_path(face_set_ptr const& faces,
|
||||
Feature const& feature) const;
|
||||
unsigned int get_size(double value) const;
|
||||
double get_angle(Feature const& feature) const;
|
||||
double get_value(Feature const& feature) const;
|
||||
|
||||
|
||||
|
||||
private:
|
||||
private:
|
||||
std::string face_name_;
|
||||
std::string char_;
|
||||
double angle_offset_;
|
||||
unsigned min_size_;
|
||||
unsigned max_size_;
|
||||
float min_value_;
|
||||
float max_value_;
|
||||
expression_ptr char_;
|
||||
expression_ptr angle_;
|
||||
expression_ptr value_;
|
||||
expression_ptr size_;
|
||||
expression_ptr color_;
|
||||
raster_colorizer_ptr colorizer_;
|
||||
bool allow_overlap_;
|
||||
bool avoid_edges_;
|
||||
position displacement_;
|
||||
color halo_fill_;
|
||||
unsigned halo_radius_;
|
||||
std::string azimuth_attr_;
|
||||
std::string value_attr_;
|
||||
};
|
||||
};
|
||||
|
||||
}; // end mapnik namespace
|
||||
|
||||
#endif
|
||||
|
|
|
@ -9,61 +9,7 @@ namespace mapnik
|
|||
text_path_ptr glyph_symbolizer::get_text_path(face_set_ptr const& faces,
|
||||
Feature const& feature) const
|
||||
{
|
||||
// Calculate face rotation angle and box offset adjustments
|
||||
typedef std::pair<unsigned,unsigned> dimension_t;
|
||||
|
||||
// Get string_info with arrow glyph
|
||||
string_info info(UnicodeString(get_char().c_str()));
|
||||
faces->get_string_info(info);
|
||||
if (info.num_characters() != 1)
|
||||
{
|
||||
throw config_error("'char' length must be exactly 1");
|
||||
}
|
||||
|
||||
character_info ci = info.at(0);
|
||||
dimension_t cdim = faces->character_dimensions(ci.character);
|
||||
double cwidth = (static_cast<double>(cdim.first))/2.0;
|
||||
double cheight = (static_cast<double>(cdim.second))/2.0;
|
||||
double angle = get_angle(feature);
|
||||
double xoff = cwidth*cos(angle) - cheight*sin(angle);
|
||||
double yoff = cwidth*sin(angle) + cheight*cos(angle);
|
||||
|
||||
text_path_ptr path_ptr = text_path_ptr(new text_path());
|
||||
path_ptr->add_node(ci.character, -xoff, -yoff, angle);
|
||||
return path_ptr;
|
||||
}
|
||||
|
||||
unsigned int glyph_symbolizer::get_size(double value) const
|
||||
{
|
||||
double scale = (get_max_size()-get_min_size()) /
|
||||
(get_max_value()-get_min_value());
|
||||
double size = get_min_size() + (value - get_min_value())*scale;
|
||||
if (size > get_max_size())
|
||||
{
|
||||
// size too large, clip it
|
||||
size = get_max_size();
|
||||
}
|
||||
return static_cast<unsigned>(floor(size));
|
||||
}
|
||||
|
||||
double glyph_symbolizer::get_angle(Feature const& feature) const
|
||||
{
|
||||
// Returns the angle of rotation of the glyph in radians
|
||||
std::string key = get_azimuth_attr();
|
||||
double azimuth = feature[key].to_double();
|
||||
azimuth = std::fmod(azimuth, 360.0);
|
||||
if (azimuth<0) azimuth += 360.0;
|
||||
azimuth *= (M_PI/180.0);
|
||||
double angle = atan2(cos(azimuth), sin(azimuth));
|
||||
angle += get_angle_offset() * (M_PI/180.0);
|
||||
angle = std::fmod(angle, 2*M_PI);
|
||||
if (angle<0) angle += 2*M_PI;
|
||||
return angle;
|
||||
}
|
||||
|
||||
double glyph_symbolizer::get_value(Feature const& feature) const
|
||||
{
|
||||
std::string key = get_value_attr();
|
||||
return feature[key].to_double();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#!/usr/bin/env python
|
||||
|
||||
from nose.tools import *
|
||||
from utilities import execution_path, save_data
|
||||
from utilities import execution_path, save_data, Todo
|
||||
|
||||
import os, mapnik2
|
||||
|
||||
|
@ -11,7 +11,7 @@ def setup():
|
|||
os.chdir(execution_path('.'))
|
||||
|
||||
|
||||
def test_arrows_symbolizer():
|
||||
def test_glyph_symbolizer():
|
||||
srs = '+init=epsg:32630'
|
||||
lyr = mapnik2.Layer('arrows')
|
||||
lyr.datasource = mapnik2.Shapefile(
|
||||
|
@ -21,16 +21,11 @@ def test_arrows_symbolizer():
|
|||
_map = mapnik2.Map(256,256, srs)
|
||||
style = mapnik2.Style()
|
||||
rule = mapnik2.Rule()
|
||||
rule.filter = mapnik2.Expression("[value] > 0 and [azimuth]>-1") #XXX Need to mention an attribute in the expression
|
||||
sym = mapnik2.GlyphSymbolizer("DejaVu Sans Condensed", "A")
|
||||
sym.angle_offset = -90
|
||||
sym.min_value = 1
|
||||
sym.max_value = 100
|
||||
sym.min_size = 1
|
||||
sym.max_size = 100
|
||||
sym = mapnik2.GlyphSymbolizer("DejaVu Sans Condensed", mapnik2.Expression("'A'"))
|
||||
sym.allow_overlap = True
|
||||
# Assigning a colorizer to the RasterSymbolizer tells the later
|
||||
# that it should use it to colorize the raw data raster
|
||||
sym.angle = mapnik2.Expression("[azimuth]-90")
|
||||
sym.value = mapnik2.Expression("[value]")
|
||||
sym.size = mapnik2.Expression("[value]")
|
||||
sym.colorizer = mapnik2.RasterColorizer()
|
||||
for value, color in [
|
||||
( 0, "#0044cc"),
|
||||
|
@ -49,9 +44,24 @@ def test_arrows_symbolizer():
|
|||
|
||||
im = mapnik2.Image(_map.width,_map.height)
|
||||
mapnik2.render(_map, im)
|
||||
save_data('test_arrows_symbolizer.png', im.tostring('png'))
|
||||
save_data('test_glyph_symbolizer.png', im.tostring('png'))
|
||||
imdata = im.tostring()
|
||||
assert len(imdata) > 0
|
||||
|
||||
raise Todo("Implement the process methods of the agg/cairo renderers for GlyphSymbolizer")
|
||||
|
||||
# we have features with 20 as a value so check that they're colored
|
||||
assert '\xff\xff\xff\x00' in imdata
|
||||
|
||||
def test_load_save_map():
|
||||
raise Todo("Implement XML de/serialization for GlyphSymbolizer")
|
||||
|
||||
map = mapnik2.Map(256,256)
|
||||
in_map = "../data/good_maps/glyph_symbolizer.xml"
|
||||
mapnik2.load_map(map, in_map)
|
||||
|
||||
out_map = mapnik2.save_map_to_string(map)
|
||||
assert 'GlyphSymbolizer' in out_map
|
||||
assert 'RasterSymbolizer' in out_map
|
||||
assert 'RasterColorizer' in out_map
|
||||
assert 'ColorBand' in out_map
|
||||
|
|
Loading…
Reference in a new issue