Merge branch 'geometry_cleanup'

This commit is contained in:
Dane Springmeyer 2011-12-22 12:42:05 -08:00
commit 323c36db61
16 changed files with 421 additions and 92 deletions

View file

@ -650,6 +650,7 @@ __all__ = [
'Feature',
'Featureset',
'FontEngine',
'FontSet',
'Geometry2d',
'GlyphSymbolizer',
'Image',

View file

@ -87,6 +87,14 @@ void (box2d<double>::*re_center_p2)(coord<double,2> const& ) = &box2d<double>::r
// clip
void (box2d<double>::*clip)(box2d<double> const&) = &box2d<double>::clip;
// deepcopy
box2d<double> box2d_deepcopy(box2d<double> & obj, boost::python::dict memo)
{
// FIXME::ignore memo for now
box2d<double> result(obj);
return result;
}
void export_envelope()
{
using namespace boost::python;
@ -270,5 +278,7 @@ void export_envelope()
.def("__getitem__",&box2d<double>::operator[])
.def("valid",&box2d<double>::valid)
.def_pickle(envelope_pickle_suite())
.def("__deepcopy__", &box2d_deepcopy)
;
}

View file

@ -31,7 +31,7 @@
#include <mapnik/map.hpp>
#include <mapnik/feature_type_style.hpp>
#include <mapnik/metawriter_inmem.hpp>
#include <mapnik/util/deepcopy.hpp>
#include "mapnik_enumeration.hpp"
#include "python_optional.hpp"
@ -122,7 +122,8 @@ std::vector<layer> const& (Map::*layers_const)() const = &Map::layers;
mapnik::parameters& (Map::*attr_nonconst)() = &Map::get_extra_attributes;
mapnik::parameters& (Map::*params_nonconst)() = &Map::get_extra_parameters;
mapnik::feature_type_style find_style (mapnik::Map const& m, std::string const& name)
mapnik::feature_type_style find_style(mapnik::Map const& m, std::string const& name)
{
boost::optional<mapnik::feature_type_style const&> style = m.find_style(name);
if (!style)
@ -133,6 +134,17 @@ mapnik::feature_type_style find_style (mapnik::Map const& m, std::string const&
return *style;
}
mapnik::font_set find_fontset(mapnik::Map const& m, std::string const& name)
{
boost::optional<mapnik::font_set const&> fontset = m.find_fontset(name);
if (!fontset)
{
PyErr_SetString(PyExc_KeyError, "Invalid font_set name");
boost::python::throw_error_already_set();
}
return *fontset;
}
bool has_metawriter(mapnik::Map const& m)
{
if (m.metawriters().size() >=1)
@ -175,6 +187,15 @@ mapnik::featureset_ptr query_map_point(mapnik::Map const& m, int index, double x
return m.query_map_point(idx, x, y);
}
// deepcopy
mapnik::Map map_deepcopy(mapnik::Map & m, boost::python::dict memo)
{
// FIXME: ignore memo for now
mapnik::Map result;
mapnik::util::deepcopy(m, result);
return result;
}
void export_map()
{
@ -193,6 +214,7 @@ void export_map()
;
python_optional<mapnik::color> ();
python_optional<mapnik::box2d<double> > ();
class_<std::vector<layer> >("Layers")
.def(vector_indexing_suite<std::vector<layer> >())
;
@ -229,6 +251,11 @@ void export_map()
"False # you can only append styles with unique names\n"
)
.def("append_fontset",&Map::insert_fontset,
(arg("fontset")),
"Add a FontSet to the map."
)
.def("buffered_envelope",
&Map::get_buffered_extent,
"Get the Box2d() of the Map given\n"
@ -261,9 +288,14 @@ void export_map()
"...'maxy', 'minx', 'miny', 'width'\n"
)
.def("find_fontset",find_fontset,
(arg("name")),
"Find a fontset by name."
)
.def("find_style",
find_style,
(arg("style_name")),
(arg("name")),
"Query the Map for a style by name and return\n"
"a style object if found or raise KeyError\n"
"style if not found.\n"
@ -452,6 +484,7 @@ void export_map()
"about the hit areas rendered on the map.\n"
)
.def("__deepcopy__",&map_deepcopy)
.add_property("extra_attributes",make_function(attr_nonconst,return_value_policy<reference_existing_object>()),"TODO")
.add_property("parameters",make_function(params_nonconst,return_value_policy<reference_existing_object>()),"TODO")

View file

@ -47,6 +47,7 @@ void export_style();
void export_stroke();
void export_feature();
void export_featureset();
void export_fontset();
void export_datasource();
void export_datasource_cache();
void export_symbolizer();
@ -397,6 +398,7 @@ BOOST_PYTHON_MODULE(_mapnik)
export_geometry();
export_feature();
export_featureset();
export_fontset();
export_datasource();
export_parameters();
export_color();

View file

@ -218,7 +218,7 @@ public:
* @param name The name of the fontset.
* @return The fontset if found. If not found return the default map fontset.
*/
font_set const& find_fontset(std::string const& name) const;
boost::optional<font_set const&> find_fontset(std::string const& name) const;
/*! \brief Get all fontsets
* @return Const reference to fontsets

View file

@ -39,6 +39,7 @@
#include <mapnik/expression_string.hpp>
// boost
#include <boost/concept_check.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/make_shared.hpp>
#include <boost/variant.hpp>
@ -125,6 +126,8 @@ typedef boost::variant<point_symbolizer,
glyph_symbolizer> symbolizer;
class rule
{
public:
@ -138,6 +141,104 @@ private:
expression_ptr filter_;
bool else_filter_;
bool also_filter_;
struct deepcopy_symbolizer : public boost::static_visitor<>
{
void operator () (markers_symbolizer & sym) const
{
copy_path_ptr(sym);
}
void operator () (point_symbolizer & sym) const
{
copy_path_ptr(sym);
}
void operator () (polygon_pattern_symbolizer & sym) const
{
copy_path_ptr(sym);
}
void operator () (line_pattern_symbolizer & sym) const
{
copy_path_ptr(sym);
}
void operator () (raster_symbolizer & sym) const
{
raster_colorizer_ptr old_colorizer = sym.get_colorizer();
raster_colorizer_ptr new_colorizer = raster_colorizer_ptr();
new_colorizer->set_stops(old_colorizer->get_stops());
new_colorizer->set_default_mode(old_colorizer->get_default_mode());
new_colorizer->set_default_color(old_colorizer->get_default_color());
new_colorizer->set_epsilon(old_colorizer->get_epsilon());
sym.set_colorizer(new_colorizer);
}
void operator () (text_symbolizer & sym) const
{
copy_text_ptr(sym);
}
void operator () (shield_symbolizer & sym) const
{
copy_path_ptr(sym);
copy_text_ptr(sym);
}
void operator () (building_symbolizer & sym) const
{
copy_height_ptr(sym);
}
template <typename T> void operator () (T &sym) const
{
boost::ignore_unused_variable_warning(sym);
}
private:
template <class T>
void copy_path_ptr(T & sym) const
{
std::string path = path_processor_type::to_string(*sym.get_filename());
sym.set_filename( parse_path(path) );
}
template <class T>
void copy_text_ptr(T & sym) const
{
std::string name = to_expression_string(*sym.get_name());
sym.set_name( parse_expression(name) );
// FIXME - orientation doesn't appear to be initialized in constructor?
//std::string orientation = to_expression_string(*sym->get_orientation());
//sym->set_orientation( parse_expression(orientation) );
float text_size = sym.get_text_size();
position displace = sym.get_displacement();
vertical_alignment_e valign = sym.get_vertical_alignment();
horizontal_alignment_e halign = sym.get_horizontal_alignment();
justify_alignment_e jalign = sym.get_justify_alignment();
text_placements_ptr placements = text_placements_ptr(boost::make_shared<text_placements_dummy>());
sym.set_placement_options( placements );
sym.set_text_size(text_size);
sym.set_displacement(displace);
sym.set_vertical_alignment(valign);
sym.set_horizontal_alignment(halign);
sym.set_justify_alignment(jalign);
}
template <class T>
void copy_height_ptr(T & sym) const
{
std::string height_expr = to_expression_string(sym.height());
sym.set_height(parse_expression(height_expr,"utf8"));
}
};
public:
rule()
: name_(),
@ -169,48 +270,17 @@ public:
also_filter_(rhs.also_filter_)
{
if (deep_copy) {
//std::string expr = to_expression_string(rhs.filter_);
//filter_ = parse_expression(expr,"utf8");
symbolizers::iterator it = syms_.begin(),
end = syms_.end();
std::string expr = to_expression_string(*filter_);
filter_ = parse_expression(expr,"utf8");
symbolizers::const_iterator it = syms_.begin();
symbolizers::const_iterator end = syms_.end();
// FIXME - metawriter_ptr?
for(; it != end; ++it) {
/*if (polygon_symbolizer *sym = boost::get<polygon_symbolizer>(&(*it))) {
// no shared pointers
} else if (line_symbolizer *sym = boost::get<line_symbolizer>(&(*it))) {
// no shared pointers
} else if (building_symbolizer *sym = boost::get<building_symbolizer>(&(*it))) {
// no shared pointers
}*/
if (markers_symbolizer *sym = boost::get<markers_symbolizer>(&(*it))) {
copy_path_ptr(sym);
} else if (point_symbolizer *sym = boost::get<point_symbolizer>(&(*it))) {
copy_path_ptr(sym);
} else if (polygon_pattern_symbolizer *sym = boost::get<polygon_pattern_symbolizer>(&(*it))) {
copy_path_ptr(sym);
} else if (line_pattern_symbolizer *sym = boost::get<line_pattern_symbolizer>(&(*it))) {
copy_path_ptr(sym);
} else if (raster_symbolizer *sym = boost::get<raster_symbolizer>(&(*it))) {
raster_colorizer_ptr old_colorizer = sym->get_colorizer(),
new_colorizer = raster_colorizer_ptr();
new_colorizer->set_stops( old_colorizer->get_stops());
new_colorizer->set_default_mode( old_colorizer->get_default_mode() );
new_colorizer->set_default_color( old_colorizer->get_default_color() );
new_colorizer->set_epsilon( old_colorizer->get_epsilon() );
sym->set_colorizer(new_colorizer);
} else if (shield_symbolizer *sym = boost::get<shield_symbolizer>(&(*it))) {
copy_path_ptr(sym);
copy_text_ptr(sym);
} else if (text_symbolizer *sym = boost::get<text_symbolizer>(&(*it))) {
copy_text_ptr(sym);
}
for(; it != end; ++it)
{
boost::apply_visitor(deepcopy_symbolizer(),*it);
}
}
}
@ -340,40 +410,7 @@ private:
filter_=rhs.filter_;
else_filter_=rhs.else_filter_;
also_filter_=rhs.also_filter_;
}
template <class T>
void copy_path_ptr(T* sym)
{
std::string path = path_processor_type::to_string(*sym->get_filename());
sym->set_filename( parse_path(path) );
}
template <class T>
void copy_text_ptr(T* sym)
{
std::string name = to_expression_string(*sym->get_name());
sym->set_name( parse_expression(name) );
// FIXME - orientation doesn't appear to be initialized in constructor?
//std::string orientation = to_expression_string(*sym->get_orientation());
//sym->set_orientation( parse_expression(orientation) );
float text_size = sym->get_text_size();
position displace = sym->get_displacement();
vertical_alignment_e valign = sym->get_vertical_alignment();
horizontal_alignment_e halign = sym->get_horizontal_alignment();
justify_alignment_e jalign = sym->get_justify_alignment();
text_placements_ptr placements = text_placements_ptr(boost::make_shared<text_placements_dummy>());
sym->set_placement_options( placements );
sym->set_text_size(text_size);
sym->set_displacement(displace);
sym->set_vertical_alignment(valign);
sym->set_horizontal_alignment(halign);
sym->set_justify_alignment(jalign);
}
}
};
}

View file

@ -0,0 +1,37 @@
/*****************************************************************************
*
* 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
*
*****************************************************************************/
//$Id$
#ifndef MAPNIK_DEEPCOPY_HPP
#define MAPNIK_DEEPCOPY_HPP
#include <mapnik/map.hpp>
namespace mapnik { namespace util {
// poor man deepcopy implementation
void deepcopy(Map const& map_in, Map & map_out);
}}
#endif // MAPNIK_DEEPSOPY_HPP

View file

@ -106,6 +106,7 @@ source = Split(
color.cpp
box2d.cpp
datasource_cache.cpp
deepcopy.cpp
expression_string.cpp
filter_factory.cpp
feature_type_style.cpp

127
src/deepcopy.cpp Normal file
View file

@ -0,0 +1,127 @@
/*****************************************************************************
*
* 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
*
*****************************************************************************/
//$Id$
#include <mapnik/map.hpp>
#include <mapnik/feature.hpp>
#include <mapnik/layer.hpp>
#include <mapnik/rule.hpp>
#include <mapnik/symbolizer.hpp>
#include <mapnik/params.hpp>
#include <mapnik/filter_factory.hpp>
#include <mapnik/datasource_cache.hpp>
#include <mapnik/util/deepcopy.hpp>
// boost
#include <boost/optional.hpp>
#include <boost/foreach.hpp>
namespace mapnik { namespace util {
// poor man's deepcopy implementation
void deepcopy(Map const& map_in, Map & map_out)
{
// * width_(rhs.width_),
// * height_(rhs.height_),
// * srs_(rhs.srs_),
// * buffer_size_(rhs.buffer_size_),
// * background_(rhs.background_),
// * background_image_(rhs.background_image_),
// * styles_(rhs.styles_),
// metawriters_(rhs.metawriters_),
// fontsets_(rhs.fontsets_),
// * layers_(rhs.layers_),
// aspectFixMode_(rhs.aspectFixMode_),
// current_extent_(rhs.current_extent_),
// * maximum_extent_(rhs.maximum_extent_),
// * base_path_(rhs.base_path_),
// extra_attr_(rhs.extra_attr_),
// extra_params_(rhs.extra_params_)
// width, height
map_out.resize(map_in.width(), map_in.height());
// srs
map_out.set_srs(map_in.srs());
// buffer_size
map_out.set_buffer_size(map_in.buffer_size());
// background
boost::optional<color> background = map_in.background();
if (background)
{
map_out.set_background(*background);
}
// background_image
boost::optional<std::string> background_image = map_in.background_image();
if (background_image)
{
map_out.set_background_image(*background_image);
}
// maximum extent
boost::optional<box2d<double> > max_extent = map_in.maximum_extent();
if (max_extent)
{
map_out.set_maximum_extent(*max_extent);
}
// base_path
map_out.set_base_path(map_in.base_path());
// fontsets
typedef std::map<std::string,font_set> fontsets;
BOOST_FOREACH ( fontsets::value_type const& kv,map_in.fontsets())
{
map_out.insert_fontset(kv.first,kv.second);
}
BOOST_FOREACH ( layer const& lyr_in, map_in.layers())
{
layer lyr_out(lyr_in);
datasource_ptr ds_in = lyr_in.datasource();
if (ds_in)
{
parameters p(ds_in->params());
// TODO : re-use datasource extent if already set.
datasource_ptr ds_out = datasource_cache::create(p);
if (ds_out)
{
lyr_out.set_datasource(ds_out);
}
}
map_out.addLayer(lyr_out);
}
typedef std::map<std::string, feature_type_style> style_cont;
typedef style_cont::value_type value_type;
style_cont const& styles = map_in.styles();
BOOST_FOREACH ( value_type const& kv, styles )
{
feature_type_style const& style_in = kv.second;
feature_type_style style_out(style_in,true); // deep copy
map_out.insert_style(kv.first, style_out);
}
}
}}

View file

@ -560,14 +560,19 @@ void map_parser::parse_font(font_set & fset, ptree const & f)
{
ensure_attrs(f, "Font", "face-name");
std::string face_name = get_attr(f, "face-name", std::string());
if ( strict_ )
optional<std::string> face_name = get_opt_attr<std::string>(f, "face-name");
if (face_name)
{
ensure_font_face( face_name );
if ( strict_ )
{
ensure_font_face(*face_name);
}
fset.add_face_name(*face_name);
}
else
{
throw config_error(std::string("Must have 'face-name' set"));
}
fset.add_face_name(face_name);
}
void map_parser::parse_layer( Map & map, ptree const & lay )

View file

@ -204,14 +204,14 @@ bool Map::insert_fontset(std::string const& name, font_set const& fontset)
{
return fontsets_.insert(make_pair(name, fontset)).second;
}
font_set const& Map::find_fontset(std::string const& name) const
boost::optional<font_set const&> Map::find_fontset(std::string const& name) const
{
std::map<std::string,font_set>::const_iterator itr = fontsets_.find(name);
if (itr!=fontsets_.end())
return itr->second;
static font_set default_fontset;
return default_fontset;
if (itr != fontsets_.end())
return boost::optional<font_set const&>(itr->second);
else
return boost::optional<font_set const&>() ;
}
std::map<std::string,font_set> const& Map::fontsets() const

View file

@ -0,0 +1,9 @@
<Map>
<FontSet name="book-fonts">
<Font face-name="DejaVu Sans Book" />
<Font face-name="DejaVu Sans Oblique" />
<Font face-name="does not exist" />
</FontSet>
</Map>

View file

@ -0,0 +1,44 @@
#!/usr/bin/env python
from nose.tools import *
from utilities import execution_path
from copy import deepcopy
import os, mapnik
def setup():
# All of the paths used are relative, if we run the tests
# from another directory we need to chdir()
os.chdir(execution_path('.'))
def test_map_deepcopy1():
m1 = mapnik.Map(256,256)
m1.append_style('style',mapnik.Style())
m1.append_fontset('fontset',mapnik.FontSet())
m2 = deepcopy(m1)
eq_(m2.width, m1.width)
eq_(m2.height, m2.height)
eq_(m2.srs, m1.srs)
eq_(m2.base, m1.base)
eq_(m2.background, m1.background)
eq_(m2.buffer_size, m1.buffer_size)
eq_(m2.aspect_fix_mode, m1.aspect_fix_mode)
eq_(m2.envelope(),m1.envelope())
eq_(m2.buffered_envelope(),m1.buffered_envelope())
eq_(m2.scale(),m1.scale())
eq_(m2.scale_denominator(),m1.scale_denominator())
eq_(m2.maximum_extent,m1.maximum_extent)
eq_(id(m2.has_metawriter()),id(m1.has_metawriter()))
eq_(id(m2.view_transform()),id(m1.view_transform()))
eq_(id(m2.extra_attributes),id(m1.extra_attributes))
eq_(id(m2.parameters),id(m1.parameters))
eq_(id(m2.layers),id(m1.layers))
eq_(id(m2.layers),id(m1.layers))
eq_(id(m2.find_style('style')),id(m2.find_style('style')))
eq_(id(m2.find_fontset('fontset')),id(m2.find_fontset('fontset')))
if __name__ == "__main__":
setup()
[eval(run)() for run in dir() if 'test_' in run]

View file

@ -71,8 +71,7 @@ def test_shieldsymbolizer_init():
eq_(s.transform, 'matrix(1, 0, 0, 1, 0, 0)')
raise Todo("FontSet pickling support needed: http://trac.mapnik.org/ticket/348")
eq_(s.fontset, '')
eq_(len(s.fontset.names), 0)
# ShieldSymbolizer missing image file

View file

@ -118,8 +118,7 @@ def test_textsymbolizer_pickle():
# r2300
eq_(s.minimum_padding, 0.0)
raise Todo("FontSet pickling support needed: http://trac.mapnik.org/ticket/348")
eq_(ts.fontset, ts2.fontset)
eq_(len(ts.fontset.names), 0)
def test_map_pickle():

View file

@ -0,0 +1,25 @@
#!/usr/bin/env python
from nose.tools import *
from utilities import execution_path
from copy import deepcopy
import os, mapnik
def setup():
# All of the paths used are relative, if we run the tests
# from another directory we need to chdir()
os.chdir(execution_path('.'))
def test_loading_fontset_from_map():
m = mapnik.Map(256,256)
mapnik.load_map(m,'../data/good_maps/fontset.xml')
fs = m.find_fontset('book-fonts')
eq_(len(fs.names),3)
eq_(list(fs.names),['DejaVu Sans Book','DejaVu Sans Oblique', 'does not exist'])
if __name__ == "__main__":
setup()
[eval(run)() for run in dir() if 'test_' in run]