Compare commits
54 commits
Author | SHA1 | Date | |
---|---|---|---|
|
e06e50a61f | ||
|
2dce39fa8f | ||
|
adb07a7407 | ||
|
7fe38520b7 | ||
|
3e70226a69 | ||
|
ab3525cfc4 | ||
|
855ff06159 | ||
|
c930807b9f | ||
|
bb0133e929 | ||
|
96414f9262 | ||
|
c6fd387469 | ||
|
42d7263cab | ||
|
88f8d9951c | ||
|
7f0c745366 | ||
|
098f9de2aa | ||
|
ae28268ba8 | ||
|
cf70b9959a | ||
|
3f51e17737 | ||
|
d8128a04f8 | ||
|
abaca39738 | ||
|
e99f8be047 | ||
|
66aaa4f70c | ||
|
8b649f7555 | ||
|
3f54120354 | ||
|
9d209cf959 | ||
|
2fb39d23b4 | ||
|
17dd295a1d | ||
|
c921a67fd4 | ||
|
41a650e568 | ||
|
664e05b2ca | ||
|
33dcd5a459 | ||
|
3e938cbfaa | ||
|
19522ac509 | ||
|
93f58b1ef3 | ||
|
3d7575c282 | ||
|
f99190cbdd | ||
|
3ec3a7cd66 | ||
|
e9cb647423 | ||
|
9cccf2ba77 | ||
|
9728f346f4 | ||
|
499c6aca70 | ||
|
13a437232d | ||
|
0b2f2f8ee0 | ||
|
4a0933e34a | ||
|
219c5f5809 | ||
|
924f3fb19c | ||
|
29a0d6133b | ||
|
36a5e0d857 | ||
|
e221168e4e | ||
|
78790e6692 | ||
|
62b74002cb | ||
|
00a4ab0528 | ||
|
f27578d41c | ||
|
d617403b33 |
73 changed files with 1008 additions and 241 deletions
20
.travis.yml
Normal file
20
.travis.yml
Normal file
|
@ -0,0 +1,20 @@
|
|||
language: cpp
|
||||
|
||||
compiler:
|
||||
- clang
|
||||
- gcc
|
||||
|
||||
before_install:
|
||||
- echo 'yes' | sudo add-apt-repository ppa:mapnik/boost
|
||||
- sudo apt-get update -qq
|
||||
- sudo apt-get install -qq make libboost-dev libboost-filesystem-dev libboost-program-options-dev libboost-python-dev libboost-regex-dev libboost-system-dev libboost-thread-dev python-nose libicu-dev libpng-dev libjpeg-dev libtiff-dev libwebp-dev libz-dev libfreetype6-dev libxml2-dev libproj-dev libcairo-dev python-cairo-dev libsqlite3-dev postgresql-server-dev*
|
||||
|
||||
script:
|
||||
- ./configure CXX=${CXX} CC=${CC} DEMO=False BINDINGS='python' CAIRO=False FAST=True && JOBS=2 make
|
||||
- make test-local
|
||||
|
||||
notifications:
|
||||
irc:
|
||||
channels:
|
||||
- "irc.freenode.org#mapnik"
|
||||
use_notice: true
|
11
CHANGELOG.md
11
CHANGELOG.md
|
@ -7,6 +7,17 @@ Developers: Please commit along with changes.
|
|||
For a complete change history, see the git log.
|
||||
|
||||
|
||||
## Unreleased
|
||||
|
||||
- Added serialization of `line-offset` to save_map (#1562)
|
||||
|
||||
- Added support for controlling rendering behavior of markers on multi-geometries `marker-multi-policy` (#1555,#1573)
|
||||
|
||||
- Add DebugSymbolizer (#1366)
|
||||
|
||||
- Added support for literal types in PostGIS Plugin (#1464)
|
||||
|
||||
|
||||
## Mapnik 2.1.0
|
||||
|
||||
Released Aug 23, 2012
|
||||
|
|
2
Makefile
2
Makefile
|
@ -25,7 +25,7 @@ test:
|
|||
@python tests/visual_tests/test.py -q || true
|
||||
@echo "*** Running C++ tests..."
|
||||
@for FILE in tests/cpp_tests/*-bin; do \
|
||||
$${FILE}; \
|
||||
$${FILE} || exit 1;\
|
||||
done
|
||||
@echo "*** Running python tests..."
|
||||
@python tests/run_tests.py -q
|
||||
|
|
19
SConstruct
19
SConstruct
|
@ -350,7 +350,7 @@ opts.AddVariables(
|
|||
|
||||
# Other variables
|
||||
BoolVariable('SHAPE_MEMORY_MAPPED_FILE', 'Utilize memory-mapped files in Shapefile Plugin (higher memory usage, better performance)', 'True'),
|
||||
('SYSTEM_FONTS','Provide location for python bindings to register fonts (if given aborts installation of bundled DejaVu fonts)',''),
|
||||
('SYSTEM_FONTS','Provide location for python bindings to register fonts (if provided then the bundled DejaVu fonts are not installed)',''),
|
||||
('LIB_DIR_NAME','Name to use for the subfolder beside libmapnik where fonts and plugins are installed','mapnik'),
|
||||
PathVariable('PYTHON','Full path to Python executable used to build bindings', sys.executable),
|
||||
BoolVariable('FRAMEWORK_PYTHON', 'Link against Framework Python on Mac OS X', 'True'),
|
||||
|
@ -962,6 +962,7 @@ if not preconfigured:
|
|||
env['PLUGINS'] = PLUGINS
|
||||
env['EXTRA_FREETYPE_LIBS'] = []
|
||||
env['SQLITE_LINKFLAGS'] = []
|
||||
env['PYTHON_INCLUDES'] = []
|
||||
# previously a leading / was expected for LIB_DIR_NAME
|
||||
# now strip it to ensure expected behavior
|
||||
if env['LIB_DIR_NAME'].startswith(os.path.sep):
|
||||
|
@ -1355,7 +1356,14 @@ if not preconfigured:
|
|||
py_includes = '''%s -c "from distutils.sysconfig import get_python_inc; print(get_python_inc())"''' % env['PYTHON']
|
||||
else:
|
||||
py_includes = '''%s -c "from distutils.sysconfig import get_python_inc; print get_python_inc()"''' % env['PYTHON']
|
||||
env['PYTHON_INCLUDES'] = call(py_includes)
|
||||
env['PYTHON_INCLUDES'].append(call(py_includes))
|
||||
|
||||
# also append platform specific includes
|
||||
if py3:
|
||||
py_plat_includes = '''%s -c "from distutils.sysconfig import get_python_inc; print(get_python_inc(plat_specific=True))"''' % env['PYTHON']
|
||||
else:
|
||||
py_plat_includes = '''%s -c "from distutils.sysconfig import get_python_inc; print get_python_inc(plat_specific=True)"''' % env['PYTHON']
|
||||
env['PYTHON_INCLUDES'].append(call(py_plat_includes))
|
||||
|
||||
# Note: we use the plat_specific argument here to make sure to respect the arch-specific site-packages location
|
||||
if py3:
|
||||
|
@ -1366,7 +1374,7 @@ if not preconfigured:
|
|||
else:
|
||||
env['PYTHON_SYS_PREFIX'] = os.popen('''%s -c "import sys; print sys.prefix"''' % env['PYTHON']).read().strip()
|
||||
env['PYTHON_VERSION'] = os.popen('''%s -c "import sys; print sys.version"''' % env['PYTHON']).read()[0:3]
|
||||
env['PYTHON_INCLUDES'] = env['PYTHON_SYS_PREFIX'] + '/include/python' + env['PYTHON_VERSION']
|
||||
env['PYTHON_INCLUDES'] = [env['PYTHON_SYS_PREFIX'] + '/include/python' + env['PYTHON_VERSION']]
|
||||
env['PYTHON_SITE_PACKAGES'] = env['DESTDIR'] + os.path.sep + env['PYTHON_SYS_PREFIX'] + os.path.sep + env['LIBDIR_SCHEMA'] + '/python' + env['PYTHON_VERSION'] + '/site-packages/'
|
||||
|
||||
# if user-requested custom prefix fall back to manual concatenation for building subdirectories
|
||||
|
@ -1444,7 +1452,7 @@ if not preconfigured:
|
|||
# fetch the mapnik version header in order to set the
|
||||
# ABI version used to build libmapnik.so on linux in src/build.py
|
||||
abi = conf.GetMapnikLibVersion()
|
||||
abi_fallback = "2.1.0"
|
||||
abi_fallback = "2.1.1-pre"
|
||||
if not abi:
|
||||
color_print(1,'Problem encountered parsing mapnik version, falling back to %s' % abi_fallback)
|
||||
abi = abi_fallback
|
||||
|
@ -1532,7 +1540,8 @@ if not preconfigured:
|
|||
# as they are later set in the python build.py
|
||||
# ugly hack needed until we have env specific conf
|
||||
backup = env.Clone().Dictionary()
|
||||
env.AppendUnique(CPPPATH = os.path.realpath(env['PYTHON_INCLUDES']))
|
||||
for pyinc in env['PYTHON_INCLUDES']:
|
||||
env.AppendUnique(CPPPATH = os.path.realpath(pyinc))
|
||||
|
||||
if not conf.CheckHeader(header='Python.h',language='C'):
|
||||
color_print(1,'Could not find required header files for the Python language (version %s)' % env['PYTHON_VERSION'])
|
||||
|
|
|
@ -698,6 +698,18 @@ class PythonDatasource(object):
|
|||
return itertools.imap(make_it, features, itertools.count(1))
|
||||
|
||||
class _TextSymbolizer(TextSymbolizer,_injector):
|
||||
@property
|
||||
def name(self):
|
||||
if isinstance(self.properties.format_tree, FormattingText):
|
||||
return self.properties.format_tree.text
|
||||
else:
|
||||
# There is no single expression which could be returned as name
|
||||
raise RuntimeError("TextSymbolizer uses complex formatting features, but old compatibility interface is used to access it. Use self.properties.format_tree instead.")
|
||||
|
||||
@name.setter
|
||||
def name(self, name):
|
||||
self.properties.format_tree = FormattingText(name)
|
||||
|
||||
@property
|
||||
def text_size(self):
|
||||
warnings.warn("'text_size' is deprecated, use format.text_size",
|
||||
|
|
|
@ -33,8 +33,13 @@ using mapnik::font_set;
|
|||
void export_fontset ()
|
||||
{
|
||||
using namespace boost::python;
|
||||
class_<font_set>("FontSet", init<>("default fontset constructor")
|
||||
class_<font_set>("FontSet", init<std::string const&>("default fontset constructor")
|
||||
)
|
||||
.add_property("name",
|
||||
make_function(&font_set::get_name,return_value_policy<copy_const_reference>()),
|
||||
&font_set::set_name,
|
||||
"Get/Set the name of the FontSet.\n"
|
||||
)
|
||||
.def("add_face_name",&font_set::add_face_name,
|
||||
(arg("name")),
|
||||
"Add a face-name to the fontset.\n"
|
||||
|
|
|
@ -89,6 +89,12 @@ void export_markers_symbolizer()
|
|||
.value("LINE_PLACEMENT",mapnik::MARKER_LINE_PLACEMENT)
|
||||
;
|
||||
|
||||
mapnik::enumeration_<mapnik::marker_multi_policy_e>("marker_multi_policy")
|
||||
.value("EACH",mapnik::MARKER_EACH_MULTI)
|
||||
.value("WHOLE",mapnik::MARKER_WHOLE_MULTI)
|
||||
.value("LARGEST",mapnik::MARKER_LARGEST_MULTI)
|
||||
;
|
||||
|
||||
class_<markers_symbolizer>("MarkersSymbolizer",
|
||||
init<>("Default Markers Symbolizer - circle"))
|
||||
.def (init<mapnik::path_expression_ptr>("<path expression ptr>"))
|
||||
|
@ -143,6 +149,10 @@ void export_markers_symbolizer()
|
|||
&markers_symbolizer::get_marker_placement,
|
||||
&markers_symbolizer::set_marker_placement,
|
||||
"Set/get the marker placement")
|
||||
.add_property("multi_policy",
|
||||
&markers_symbolizer::get_marker_multi_policy,
|
||||
&markers_symbolizer::set_marker_multi_policy,
|
||||
"Set/get the marker multi geometry rendering policy")
|
||||
.add_property("comp_op",
|
||||
&markers_symbolizer::comp_op,
|
||||
&markers_symbolizer::set_comp_op,
|
||||
|
|
|
@ -295,6 +295,16 @@ void runtime_error_translator(std::runtime_error const & ex)
|
|||
PyErr_SetString(PyExc_RuntimeError, ex.what());
|
||||
}
|
||||
|
||||
void out_of_range_error_translator(std::out_of_range const & ex)
|
||||
{
|
||||
PyErr_SetString(PyExc_IndexError, ex.what());
|
||||
}
|
||||
|
||||
void standard_error_translator(std::exception const & ex)
|
||||
{
|
||||
PyErr_SetString(PyExc_RuntimeError, ex.what());
|
||||
}
|
||||
|
||||
unsigned mapnik_version()
|
||||
{
|
||||
return MAPNIK_VERSION;
|
||||
|
@ -364,6 +374,8 @@ BOOST_PYTHON_MODULE(_mapnik)
|
|||
using mapnik::save_map_to_string;
|
||||
using mapnik::render_grid;
|
||||
|
||||
register_exception_translator<std::exception>(&standard_error_translator);
|
||||
register_exception_translator<std::out_of_range>(&out_of_range_error_translator);
|
||||
register_exception_translator<mapnik::config_error>(&config_error_translator);
|
||||
register_exception_translator<mapnik::value_error>(&value_error_translator);
|
||||
register_exception_translator<std::runtime_error>(&runtime_error_translator);
|
||||
|
@ -617,6 +629,7 @@ BOOST_PYTHON_MODULE(_mapnik)
|
|||
def("has_pycairo", &has_pycairo, "Get pycairo module status");
|
||||
|
||||
python_optional<mapnik::stroke>();
|
||||
python_optional<mapnik::font_set>();
|
||||
python_optional<mapnik::color>();
|
||||
python_optional<mapnik::box2d<double> >();
|
||||
python_optional<mapnik::composite_mode_e>();
|
||||
|
|
|
@ -22,11 +22,15 @@
|
|||
|
||||
// boost
|
||||
#include <boost/python.hpp>
|
||||
#include <boost/foreach.hpp>
|
||||
|
||||
// mapnik
|
||||
#include <mapnik/query.hpp>
|
||||
#include <mapnik/box2d.hpp>
|
||||
|
||||
#include <string>
|
||||
#include <set>
|
||||
|
||||
using mapnik::query;
|
||||
using mapnik::box2d;
|
||||
|
||||
|
@ -46,11 +50,30 @@ struct resolution_to_tuple
|
|||
}
|
||||
};
|
||||
|
||||
struct names_to_list
|
||||
{
|
||||
static PyObject* convert(std::set<std::string> const& names)
|
||||
{
|
||||
boost::python::list l;
|
||||
BOOST_FOREACH( std::string const& name, names )
|
||||
{
|
||||
l.append(name);
|
||||
}
|
||||
return python::incref(l.ptr());
|
||||
}
|
||||
|
||||
static PyTypeObject const* get_pytype()
|
||||
{
|
||||
return &PyList_Type;
|
||||
}
|
||||
};
|
||||
|
||||
void export_query()
|
||||
{
|
||||
using namespace boost::python;
|
||||
|
||||
to_python_converter<query::resolution_type, resolution_to_tuple> ();
|
||||
to_python_converter<std::set<std::string>, names_to_list> ();
|
||||
|
||||
class_<query>("Query", "a spatial query data object",
|
||||
init<box2d<double>,query::resolution_type const&,double>() )
|
||||
|
|
|
@ -193,7 +193,11 @@ struct ListNodeWrap: formatting::list_node, wrapper<formatting::list_node>
|
|||
ListNodeWrap(object l) : formatting::list_node(), wrapper<formatting::list_node>()
|
||||
{
|
||||
stl_input_iterator<formatting::node_ptr> begin(l), end;
|
||||
children_.insert(children_.end(), begin, end);
|
||||
while (begin != end)
|
||||
{
|
||||
children_.push_back(*begin);
|
||||
++begin;
|
||||
}
|
||||
}
|
||||
|
||||
/* TODO: Add constructor taking variable number of arguments.
|
||||
|
@ -402,9 +406,9 @@ void export_text_placement()
|
|||
class_with_converter<char_properties>
|
||||
("CharProperties")
|
||||
.def_readwrite_convert("text_transform", &char_properties::text_transform)
|
||||
.def_readwrite_convert("fontset", &char_properties::fontset)
|
||||
.def(init<char_properties const&>()) //Copy constructor
|
||||
.def_readwrite("face_name", &char_properties::face_name)
|
||||
.def_readwrite("fontset", &char_properties::fontset)
|
||||
.def_readwrite("text_size", &char_properties::text_size)
|
||||
.def_readwrite("character_spacing", &char_properties::character_spacing)
|
||||
.def_readwrite("line_spacing", &char_properties::line_spacing)
|
||||
|
|
2
deps/agg/include/agg_conv_adaptor_vcgen.h
vendored
2
deps/agg/include/agg_conv_adaptor_vcgen.h
vendored
|
@ -29,6 +29,7 @@ namespace agg
|
|||
|
||||
void rewind(unsigned) {}
|
||||
unsigned vertex(double*, double*) { return path_cmd_stop; }
|
||||
unsigned type() const { return 0; }
|
||||
};
|
||||
|
||||
|
||||
|
@ -64,6 +65,7 @@ namespace agg
|
|||
}
|
||||
|
||||
unsigned vertex(double* x, double* y);
|
||||
unsigned type() const { return m_source->type(); }
|
||||
|
||||
private:
|
||||
// Prohibit copying
|
||||
|
|
1
deps/agg/include/agg_conv_adaptor_vpgen.h
vendored
1
deps/agg/include/agg_conv_adaptor_vpgen.h
vendored
|
@ -33,6 +33,7 @@ namespace agg
|
|||
|
||||
void rewind(unsigned path_id);
|
||||
unsigned vertex(double* x, double* y);
|
||||
unsigned type() const { return m_source->type(); }
|
||||
|
||||
private:
|
||||
conv_adaptor_vpgen(const conv_adaptor_vpgen<VertexSource, VPGen>&);
|
||||
|
|
1
deps/agg/include/agg_conv_clip_polygon.h
vendored
1
deps/agg/include/agg_conv_clip_polygon.h
vendored
|
@ -51,6 +51,7 @@ namespace agg
|
|||
double y1() const { return base_type::vpgen().y1(); }
|
||||
double x2() const { return base_type::vpgen().x2(); }
|
||||
double y2() const { return base_type::vpgen().y2(); }
|
||||
unsigned type() const { return base_type::type(); }
|
||||
|
||||
private:
|
||||
conv_clip_polygon(const conv_clip_polygon<VertexSource>&);
|
||||
|
|
1
deps/agg/include/agg_conv_clip_polyline.h
vendored
1
deps/agg/include/agg_conv_clip_polyline.h
vendored
|
@ -51,6 +51,7 @@ namespace agg
|
|||
double y1() const { return base_type::vpgen().y1(); }
|
||||
double x2() const { return base_type::vpgen().x2(); }
|
||||
double y2() const { return base_type::vpgen().y2(); }
|
||||
unsigned type() const { return base_type::type(); }
|
||||
|
||||
private:
|
||||
conv_clip_polyline(const conv_clip_polyline<VertexSource>&);
|
||||
|
|
2
deps/agg/include/agg_conv_smooth_poly1.h
vendored
2
deps/agg/include/agg_conv_smooth_poly1.h
vendored
|
@ -42,6 +42,7 @@ namespace agg
|
|||
|
||||
void smooth_value(double v) { base_type::generator().smooth_value(v); }
|
||||
double smooth_value() const { return base_type::generator().smooth_value(); }
|
||||
unsigned type() const { return base_type::type(); }
|
||||
|
||||
private:
|
||||
conv_smooth_poly1(const conv_smooth_poly1<VertexSource>&);
|
||||
|
@ -64,6 +65,7 @@ namespace agg
|
|||
|
||||
void smooth_value(double v) { m_smooth.generator().smooth_value(v); }
|
||||
double smooth_value() const { return m_smooth.generator().smooth_value(); }
|
||||
unsigned type() const { return m_smooth.type(); }
|
||||
|
||||
private:
|
||||
conv_smooth_poly1_curve(const conv_smooth_poly1_curve<VertexSource>&);
|
||||
|
|
|
@ -22,15 +22,12 @@ import glob
|
|||
|
||||
Import('env')
|
||||
|
||||
# grab all the deja vu fonts
|
||||
includes = glob.glob('*/*/*.ttf')
|
||||
|
||||
# grab single unifont ttf (available at http://unifoundry.com/unifont.html)
|
||||
includes.extend(glob.glob('unifont*.ttf'))
|
||||
|
||||
target_path = env['MAPNIK_FONTS_DEST']
|
||||
|
||||
if 'uninstall' not in COMMAND_LINE_TARGETS and not env['SYSTEM_FONTS']:
|
||||
env.Alias(target='install', source=env.Install(target_path, includes))
|
||||
|
||||
env['create_uninstall_target'](env, target_path)
|
||||
if not env['SYSTEM_FONTS']:
|
||||
# grab all the deja vu fonts
|
||||
includes = glob.glob('*/*/*.ttf')
|
||||
# grab single unifont ttf (available at http://unifoundry.com/unifont.html)
|
||||
includes.extend(glob.glob('unifont*.ttf'))
|
||||
target_path = env['MAPNIK_FONTS_DEST']
|
||||
if 'uninstall' not in COMMAND_LINE_TARGETS:
|
||||
env.Alias(target='install', source=env.Install(target_path, includes))
|
||||
env['create_uninstall_target'](env, target_path)
|
||||
|
|
|
@ -81,6 +81,11 @@ struct MAPNIK_DECL coord_transform
|
|||
geom_.rewind(pos);
|
||||
}
|
||||
|
||||
unsigned type() const
|
||||
{
|
||||
return static_cast<unsigned>(geom_.type());
|
||||
}
|
||||
|
||||
Geometry const& geom() const
|
||||
{
|
||||
return geom_;
|
||||
|
|
|
@ -333,11 +333,11 @@ public:
|
|||
return face_set;
|
||||
}
|
||||
|
||||
face_set_ptr get_face_set(std::string const& name, font_set const& fset)
|
||||
face_set_ptr get_face_set(std::string const& name, boost::optional<font_set> fset)
|
||||
{
|
||||
if (fset.size() > 0)
|
||||
if (fset && fset->size() > 0)
|
||||
{
|
||||
return get_face_set(fset);
|
||||
return get_face_set(*fset);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
@ -35,11 +35,11 @@ namespace mapnik
|
|||
class MAPNIK_DECL font_set
|
||||
{
|
||||
public:
|
||||
font_set();
|
||||
font_set(std::string const& name);
|
||||
font_set(font_set const& rhs);
|
||||
font_set& operator=(font_set const& rhs);
|
||||
unsigned size() const;
|
||||
void set_name(std::string const& name);
|
||||
std::string const& get_name() const;
|
||||
void add_face_name(std::string);
|
||||
std::vector<std::string> const& get_face_names() const;
|
||||
|
|
|
@ -329,6 +329,73 @@ bool centroid(PathType & path, double & x, double & y)
|
|||
return true;
|
||||
}
|
||||
|
||||
// Compute centroid over a set of paths
|
||||
template <typename Iter>
|
||||
bool centroid_geoms(Iter start, Iter end, double & x, double & y)
|
||||
{
|
||||
double x0 = 0.0;
|
||||
double y0 = 0.0;
|
||||
double x1 = 0.0;
|
||||
double y1 = 0.0;
|
||||
double start_x = x0;
|
||||
double start_y = y0;
|
||||
|
||||
double atmp = 0.0;
|
||||
double xtmp = 0.0;
|
||||
double ytmp = 0.0;
|
||||
unsigned count = 0;
|
||||
|
||||
while (start!=end)
|
||||
{
|
||||
typename Iter::value_type & path = *start++;
|
||||
path.rewind(0);
|
||||
unsigned command = path.vertex(&x0, &y0);
|
||||
if (command == SEG_END) continue;
|
||||
|
||||
if ( ! count++ ) {
|
||||
start_x = x0;
|
||||
start_y = y0;
|
||||
}
|
||||
|
||||
while (SEG_END != (command = path.vertex(&x1, &y1)))
|
||||
{
|
||||
double dx0 = x0 - start_x;
|
||||
double dy0 = y0 - start_y;
|
||||
double dx1 = x1 - start_x;
|
||||
double dy1 = y1 - start_y;
|
||||
double ai = dx0 * dy1 - dx1 * dy0;
|
||||
atmp += ai;
|
||||
xtmp += (dx1 + dx0) * ai;
|
||||
ytmp += (dy1 + dy0) * ai;
|
||||
x0 = x1;
|
||||
y0 = y1;
|
||||
++count;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (count == 0) return false;
|
||||
|
||||
if (count <= 2) {
|
||||
x = (start_x + x0) * 0.5;
|
||||
y = (start_y + y0) * 0.5;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (atmp != 0)
|
||||
{
|
||||
x = (xtmp/(3*atmp)) + start_x;
|
||||
y = (ytmp/(3*atmp)) + start_y;
|
||||
}
|
||||
else
|
||||
{
|
||||
x = x0;
|
||||
y = y0;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename PathType>
|
||||
bool hit_test(PathType & path, double x, double y, double tol)
|
||||
{
|
||||
|
|
|
@ -78,11 +78,17 @@ struct raster_markers_rasterizer_dispatch_grid
|
|||
{
|
||||
marker_placement_e placement_method = sym_.get_marker_placement();
|
||||
box2d<double> bbox_(0,0, src_.width(),src_.height());
|
||||
if (placement_method != MARKER_LINE_PLACEMENT)
|
||||
if (placement_method != MARKER_LINE_PLACEMENT ||
|
||||
path.type() == Point)
|
||||
{
|
||||
double x = 0;
|
||||
double y = 0;
|
||||
if (placement_method == MARKER_INTERIOR_PLACEMENT)
|
||||
if (path.type() == LineString)
|
||||
{
|
||||
if (!label::middle_point(path, x, y))
|
||||
return;
|
||||
}
|
||||
else if (placement_method == MARKER_INTERIOR_PLACEMENT)
|
||||
{
|
||||
if (!label::interior_position(path, x, y))
|
||||
return;
|
||||
|
@ -209,11 +215,17 @@ struct vector_markers_rasterizer_dispatch_grid
|
|||
void add_path(T & path)
|
||||
{
|
||||
marker_placement_e placement_method = sym_.get_marker_placement();
|
||||
if (placement_method != MARKER_LINE_PLACEMENT)
|
||||
if (placement_method != MARKER_LINE_PLACEMENT ||
|
||||
path.type() == Point)
|
||||
{
|
||||
double x = 0;
|
||||
double y = 0;
|
||||
if (placement_method == MARKER_INTERIOR_PLACEMENT)
|
||||
if (path.type() == LineString)
|
||||
{
|
||||
if (!label::middle_point(path, x, y))
|
||||
return;
|
||||
}
|
||||
else if (placement_method == MARKER_INTERIOR_PLACEMENT)
|
||||
{
|
||||
if (!label::interior_position(path, x, y))
|
||||
return;
|
||||
|
|
|
@ -75,7 +75,7 @@ inline std::ostream& operator<< (std::ostream& os, gray)
|
|||
|
||||
inline std::ostream& operator<< (std::ostream& os, agg_stack_blur const& filter)
|
||||
{
|
||||
os << "agg-stack-blur:" << filter.rx << ',' << filter.ry;
|
||||
os << "agg-stack-blur(" << filter.rx << ',' << filter.ry << ')';
|
||||
return os;
|
||||
}
|
||||
|
||||
|
|
|
@ -91,7 +91,7 @@ struct feature_collection_grammar :
|
|||
> lit(']')
|
||||
;
|
||||
|
||||
feature = eps[_a = construct<feature_ptr>(new_<feature_impl>(ctx_,generate_id_()))]
|
||||
feature = eps[_a = phoenix::construct<mapnik::feature_ptr>(new_<mapnik::feature_impl>(ctx_,generate_id_()))]
|
||||
>> feature_g(*_a)[push_back(_r1,_a)]
|
||||
;
|
||||
|
||||
|
|
|
@ -87,11 +87,17 @@ struct vector_markers_rasterizer_dispatch
|
|||
{
|
||||
marker_placement_e placement_method = sym_.get_marker_placement();
|
||||
|
||||
if (placement_method != MARKER_LINE_PLACEMENT)
|
||||
if (placement_method != MARKER_LINE_PLACEMENT ||
|
||||
path.type() == Point)
|
||||
{
|
||||
double x = 0;
|
||||
double y = 0;
|
||||
if (placement_method == MARKER_INTERIOR_PLACEMENT)
|
||||
if (path.type() == LineString)
|
||||
{
|
||||
if (!label::middle_point(path, x, y))
|
||||
return;
|
||||
}
|
||||
else if (placement_method == MARKER_INTERIOR_PLACEMENT)
|
||||
{
|
||||
if (!label::interior_position(path, x, y))
|
||||
return;
|
||||
|
@ -183,11 +189,17 @@ struct raster_markers_rasterizer_dispatch
|
|||
marker_placement_e placement_method = sym_.get_marker_placement();
|
||||
box2d<double> bbox_(0,0, src_.width(),src_.height());
|
||||
|
||||
if (placement_method != MARKER_LINE_PLACEMENT)
|
||||
if (placement_method != MARKER_LINE_PLACEMENT ||
|
||||
path.type() == Point)
|
||||
{
|
||||
double x = 0;
|
||||
double y = 0;
|
||||
if (placement_method == MARKER_INTERIOR_PLACEMENT)
|
||||
if (path.type() == LineString)
|
||||
{
|
||||
if (!label::middle_point(path, x, y))
|
||||
return;
|
||||
}
|
||||
else if (placement_method == MARKER_INTERIOR_PLACEMENT)
|
||||
{
|
||||
if (!label::interior_position(path, x, y))
|
||||
return;
|
||||
|
@ -398,6 +410,68 @@ void setup_transform_scaling(agg::trans_affine & tr, box2d<double> const& bbox,
|
|||
}
|
||||
}
|
||||
|
||||
// Apply markers to a feature with multiple geometries
|
||||
template <typename Converter>
|
||||
void apply_markers_multi(feature_impl & feature, Converter& converter, markers_symbolizer const& sym)
|
||||
{
|
||||
std::size_t geom_count = feature.paths().size();
|
||||
if (geom_count == 1)
|
||||
{
|
||||
converter.apply(feature.paths()[0]);
|
||||
}
|
||||
else if (geom_count > 1)
|
||||
{
|
||||
marker_multi_policy_e multi_policy = sym.get_marker_multi_policy();
|
||||
marker_placement_e placement = sym.get_marker_placement();
|
||||
if (placement == MARKER_POINT_PLACEMENT &&
|
||||
multi_policy == MARKER_WHOLE_MULTI)
|
||||
{
|
||||
double x, y;
|
||||
if (label::centroid_geoms(feature.paths().begin(), feature.paths().end(), x, y))
|
||||
{
|
||||
geometry_type pt(Point);
|
||||
pt.move_to(x, y);
|
||||
// unset any clipping since we're now dealing with a point
|
||||
converter.template unset<clip_poly_tag>();
|
||||
converter.apply(pt);
|
||||
}
|
||||
}
|
||||
else if ((placement == MARKER_POINT_PLACEMENT || placement == MARKER_INTERIOR_PLACEMENT) &&
|
||||
multi_policy == MARKER_LARGEST_MULTI)
|
||||
{
|
||||
// Only apply to path with largest envelope area
|
||||
// TODO: consider using true area for polygon types
|
||||
double maxarea = 0;
|
||||
geometry_type* largest = 0;
|
||||
BOOST_FOREACH(geometry_type & geom, feature.paths())
|
||||
{
|
||||
const box2d<double>& env = geom.envelope();
|
||||
double area = env.width() * env.height();
|
||||
if (area > maxarea)
|
||||
{
|
||||
maxarea = area;
|
||||
largest = &geom;
|
||||
}
|
||||
}
|
||||
if (largest)
|
||||
{
|
||||
converter.apply(*largest);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (multi_policy != MARKER_EACH_MULTI && placement != MARKER_POINT_PLACEMENT)
|
||||
{
|
||||
MAPNIK_LOG_WARN(marker_symbolizer) << "marker_multi_policy != 'each' has no effect with marker_placement != 'point'";
|
||||
}
|
||||
BOOST_FOREACH(geometry_type & path, feature.paths())
|
||||
{
|
||||
converter.apply(path);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif //MAPNIK_MARKER_HELPERS_HPP
|
||||
|
|
|
@ -46,6 +46,15 @@ enum marker_placement_enum {
|
|||
|
||||
DEFINE_ENUM( marker_placement_e, marker_placement_enum );
|
||||
|
||||
enum marker_multi_policy_enum {
|
||||
MARKER_EACH_MULTI, // each component in a multi gets its marker
|
||||
MARKER_WHOLE_MULTI, // consider all components of a multi as a whole
|
||||
MARKER_LARGEST_MULTI, // only the largest component of a multi gets a marker
|
||||
marker_multi_policy_enum_MAX
|
||||
};
|
||||
|
||||
DEFINE_ENUM( marker_multi_policy_e, marker_multi_policy_enum );
|
||||
|
||||
struct MAPNIK_DECL markers_symbolizer :
|
||||
public symbolizer_with_image, public symbolizer_base
|
||||
{
|
||||
|
@ -74,6 +83,8 @@ public:
|
|||
boost::optional<stroke> get_stroke() const;
|
||||
void set_marker_placement(marker_placement_e marker_p);
|
||||
marker_placement_e get_marker_placement() const;
|
||||
void set_marker_multi_policy(marker_multi_policy_e marker_p);
|
||||
marker_multi_policy_e get_marker_multi_policy() const;
|
||||
private:
|
||||
expression_ptr width_;
|
||||
expression_ptr height_;
|
||||
|
@ -86,6 +97,7 @@ private:
|
|||
boost::optional<float> opacity_;
|
||||
boost::optional<stroke> stroke_;
|
||||
marker_placement_e marker_p_;
|
||||
marker_multi_policy_e marker_mp_;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -33,9 +33,7 @@
|
|||
|
||||
namespace mapnik
|
||||
{
|
||||
using std::pair;
|
||||
using std::vector;
|
||||
typedef vector<pair<double,double> > dash_array;
|
||||
typedef std::vector<std::pair<double,double> > dash_array;
|
||||
|
||||
// if you add new tokens, don't forget to add them to the corresponding
|
||||
// string array in the cpp file.
|
||||
|
|
|
@ -33,6 +33,7 @@
|
|||
#include <map>
|
||||
|
||||
// boost
|
||||
#include <boost/optional.hpp>
|
||||
#include <boost/property_tree/ptree.hpp>
|
||||
|
||||
namespace mapnik
|
||||
|
@ -58,7 +59,7 @@ struct char_properties
|
|||
/** 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;
|
||||
font_set fontset;
|
||||
boost::optional<font_set> fontset;
|
||||
float text_size;
|
||||
double character_spacing;
|
||||
double line_spacing; //Largest total height (fontsize+line_spacing) per line is chosen
|
||||
|
|
|
@ -92,7 +92,7 @@ struct MAPNIK_DECL text_symbolizer : public symbolizer_base
|
|||
void set_text_size(float size);
|
||||
std::string const& get_face_name() const func_deprecated;
|
||||
void set_face_name(std::string face_name);
|
||||
font_set const& get_fontset() const func_deprecated;
|
||||
boost::optional<font_set> const& get_fontset() const func_deprecated;
|
||||
void set_fontset(font_set const& fset);
|
||||
color const& get_fill() const func_deprecated;
|
||||
void set_fill(color const& fill);
|
||||
|
|
|
@ -38,6 +38,7 @@
|
|||
#if BOOST_VERSION >= 104500
|
||||
#include <boost/config/warning_disable.hpp>
|
||||
#include <boost/spirit/include/karma.hpp>
|
||||
#include <boost/math/special_functions/trunc.hpp> // trunc to avoid needing C++11
|
||||
#else
|
||||
#include <boost/lexical_cast.hpp>
|
||||
#endif
|
||||
|
@ -67,8 +68,80 @@ template <typename T>
|
|||
struct double_policy : boost::spirit::karma::real_policies<T>
|
||||
{
|
||||
typedef boost::spirit::karma::real_policies<T> base_type;
|
||||
static int floatfield(T n) { return base_type::fmtflags::fixed; }
|
||||
static unsigned precision(T n) { return 16 ;}
|
||||
|
||||
static int floatfield(T n) {
|
||||
using namespace boost::spirit; // for traits
|
||||
|
||||
if (traits::test_zero(n))
|
||||
return base_type::fmtflags::fixed;
|
||||
|
||||
T abs_n = traits::get_absolute_value(n);
|
||||
return (abs_n >= 1e16 || abs_n < 1e-4)
|
||||
? base_type::fmtflags::scientific : base_type::fmtflags::fixed;
|
||||
}
|
||||
|
||||
static unsigned precision(T n) {
|
||||
if ( n == 0.0 ) return 0;
|
||||
using namespace boost::spirit; // for traits
|
||||
return static_cast<unsigned>(14 - boost::math::trunc(log10(traits::get_absolute_value(n))));
|
||||
}
|
||||
|
||||
template <typename OutputIterator>
|
||||
static bool dot(OutputIterator& sink, T n, unsigned precision) {
|
||||
if (n == 0.0) return true; // avoid trailing zeroes
|
||||
return base_type::dot(sink, n, precision);
|
||||
}
|
||||
|
||||
template <typename OutputIterator>
|
||||
static bool fraction_part (OutputIterator& sink, T n
|
||||
, unsigned precision_, unsigned precision)
|
||||
{
|
||||
// NOTE: copied from karma only to avoid trailing zeroes
|
||||
// (maybe a bug ?)
|
||||
|
||||
// allow for ADL to find the correct overload for floor and log10
|
||||
using namespace std;
|
||||
|
||||
using namespace boost::spirit; // for traits
|
||||
using namespace boost::spirit::karma; // for char_inserter
|
||||
using namespace boost; // for remove_const
|
||||
|
||||
if ( traits::test_zero(n) ) return true; // this part added to karma
|
||||
|
||||
// The following is equivalent to:
|
||||
// generate(sink, right_align(precision, '0')[ulong], n);
|
||||
// but it's spelled out to avoid inter-modular dependencies.
|
||||
|
||||
typename remove_const<T>::type digits =
|
||||
(traits::test_zero(n) ? 0 : floor(log10(n))) + 1;
|
||||
bool r = true;
|
||||
for (/**/; r && digits < precision_; digits = digits + 1)
|
||||
r = char_inserter<>::call(sink, '0');
|
||||
if (precision && r)
|
||||
r = int_inserter<10>::call(sink, n);
|
||||
return r;
|
||||
}
|
||||
|
||||
template <typename CharEncoding, typename Tag, typename OutputIterator>
|
||||
static bool exponent (OutputIterator& sink, long n)
|
||||
{
|
||||
// NOTE: copied from karma to force sign in exponent
|
||||
const bool force_sign = true;
|
||||
|
||||
using namespace boost::spirit; // for traits
|
||||
using namespace boost::spirit::karma; // for char_inserter, sign_inserter
|
||||
|
||||
long abs_n = traits::get_absolute_value(n);
|
||||
bool r = char_inserter<CharEncoding, Tag>::call(sink, 'e') &&
|
||||
sign_inserter::call(sink, traits::test_zero(n)
|
||||
, traits::test_negative(n), force_sign);
|
||||
|
||||
// the C99 Standard requires at least two digits in the exponent
|
||||
if (r && abs_n < 10)
|
||||
r = char_inserter<CharEncoding, Tag>::call(sink, '0');
|
||||
return r && int_inserter<10>::call(sink, abs_n);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
@ -77,7 +150,7 @@ template <>
|
|||
inline bool to_string(std::string & str, double value)
|
||||
{
|
||||
namespace karma = boost::spirit::karma;
|
||||
typedef boost::spirit::karma::real_generator<double, double_policy<double> > double_type;
|
||||
typedef karma::real_generator<double, double_policy<double> > double_type;
|
||||
std::back_insert_iterator<std::string> sink(str);
|
||||
return karma::generate(sink, double_type(), value);
|
||||
}
|
||||
|
|
|
@ -23,13 +23,13 @@
|
|||
#ifndef MAPNIK_VERSION_HPP
|
||||
#define MAPNIK_VERSION_HPP
|
||||
|
||||
#define MAPNIK_VERSION_IS_RELEASE 1
|
||||
#define MAPNIK_VERSION_IS_RELEASE 0
|
||||
|
||||
#define MAPNIK_MAJOR_VERSION 2
|
||||
#define MAPNIK_MINOR_VERSION 1
|
||||
#define MAPNIK_PATCH_VERSION 0
|
||||
#define MAPNIK_PATCH_VERSION 1
|
||||
|
||||
// translates to 200100
|
||||
// translates to 200101
|
||||
#define MAPNIK_VERSION (MAPNIK_MAJOR_VERSION*100000) + (MAPNIK_MINOR_VERSION*100) + (MAPNIK_PATCH_VERSION)
|
||||
|
||||
#ifndef MAPNIK_STRINGIFY
|
||||
|
|
|
@ -347,6 +347,16 @@ struct vertex_converter : private boost::noncopyable
|
|||
disp_.vec_[index]=1;
|
||||
}
|
||||
|
||||
template <typename Conv>
|
||||
void unset()
|
||||
{
|
||||
typedef typename boost::mpl::find<conv_types,Conv>::type iter;
|
||||
typedef typename boost::mpl::end<conv_types>::type end;
|
||||
std::size_t index = boost::mpl::distance<iter,end>::value - 1;
|
||||
if (index < disp_.vec_.size())
|
||||
disp_.vec_[index]=0;
|
||||
}
|
||||
|
||||
|
||||
detail::dispatcher<args_type,conv_types> disp_;
|
||||
};
|
||||
|
|
|
@ -53,7 +53,7 @@ public:
|
|||
{
|
||||
std::ostringstream s;
|
||||
s << "Postgis Plugin: ";
|
||||
if (conn_ )
|
||||
if (conn_)
|
||||
{
|
||||
std::string msg = PQerrorMessage(conn_);
|
||||
if (! msg.empty())
|
||||
|
@ -64,13 +64,13 @@ public:
|
|||
{
|
||||
s << "unable to connect to postgres server";
|
||||
}
|
||||
PQfinish(conn_);
|
||||
}
|
||||
else
|
||||
{
|
||||
s << "unable to connect to postgres server";
|
||||
}
|
||||
s << "\n" << connection_str;
|
||||
|
||||
throw mapnik::datasource_exception(s.str());
|
||||
}
|
||||
}
|
||||
|
@ -152,7 +152,7 @@ public:
|
|||
|
||||
bool isOK() const
|
||||
{
|
||||
return (PQstatus(conn_) != CONNECTION_BAD);
|
||||
return (!closed_) && (PQstatus(conn_) != CONNECTION_BAD);
|
||||
}
|
||||
|
||||
void close()
|
||||
|
|
|
@ -127,11 +127,12 @@ void postgis_datasource::bind() const
|
|||
if (pool)
|
||||
{
|
||||
shared_ptr<Connection> conn = pool->borrowObject();
|
||||
if (conn && conn->isOK())
|
||||
{
|
||||
PoolGuard<shared_ptr<Connection>,
|
||||
shared_ptr< Pool<Connection,ConnectionCreator> > > guard(conn, pool);
|
||||
if (!conn) return;
|
||||
|
||||
PoolGuard<shared_ptr<Connection>,
|
||||
shared_ptr< Pool<Connection,ConnectionCreator> > > guard(conn, pool);
|
||||
if (conn->isOK())
|
||||
{
|
||||
desc_.set_encoding(conn->client_encoding());
|
||||
|
||||
if (geometry_table_.empty())
|
||||
|
@ -391,6 +392,7 @@ void postgis_datasource::bind() const
|
|||
case 1042: // bpchar
|
||||
case 1043: // varchar
|
||||
case 25: // text
|
||||
case 705: // literal
|
||||
desc_.add_descriptor(attribute_descriptor(fld_name, mapnik::String));
|
||||
break;
|
||||
default: // should not get here
|
||||
|
@ -434,6 +436,7 @@ postgis_datasource::~postgis_datasource()
|
|||
if (conn)
|
||||
{
|
||||
conn->close();
|
||||
pool->returnObject(conn);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -654,7 +657,10 @@ featureset_ptr postgis_datasource::features(const query& q) const
|
|||
s << "\"" << geometryColumn_ << "\"";
|
||||
|
||||
if (simplify_geometries_) {
|
||||
const double tolerance = std::min(px_gw, px_gh) / 2.0;
|
||||
// 1/20 of pixel seems to be a good compromise to avoid
|
||||
// drop of collapsed polygons.
|
||||
// See https://github.com/mapnik/mapnik/issues/1639
|
||||
const double tolerance = std::min(px_gw, px_gh) / 20.0;
|
||||
s << ", " << tolerance << ")";
|
||||
}
|
||||
|
||||
|
@ -702,7 +708,17 @@ featureset_ptr postgis_datasource::features(const query& q) const
|
|||
}
|
||||
else
|
||||
{
|
||||
throw mapnik::datasource_exception("Postgis Plugin: bad connection");
|
||||
std::string err_msg = "Postgis Plugin:";
|
||||
if (conn)
|
||||
{
|
||||
err_msg += " Bad connection";
|
||||
pool->returnObject(conn);
|
||||
}
|
||||
else
|
||||
{
|
||||
err_msg += " Null connection";
|
||||
}
|
||||
throw mapnik::datasource_exception(err_msg);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -725,10 +741,11 @@ featureset_ptr postgis_datasource::features_at_point(coord2d const& pt) const
|
|||
if (pool)
|
||||
{
|
||||
shared_ptr<Connection> conn = pool->borrowObject();
|
||||
if (conn && conn->isOK())
|
||||
{
|
||||
PoolGuard<shared_ptr<Connection>, shared_ptr< Pool<Connection,ConnectionCreator> > > guard(conn, pool);
|
||||
if (!conn) return featureset_ptr();
|
||||
PoolGuard<shared_ptr<Connection>, shared_ptr< Pool<Connection,ConnectionCreator> > > guard(conn, pool);
|
||||
|
||||
if (conn->isOK())
|
||||
{
|
||||
if (geometryColumn_.empty())
|
||||
{
|
||||
std::ostringstream s_error;
|
||||
|
@ -815,10 +832,10 @@ box2d<double> postgis_datasource::envelope() const
|
|||
if (pool)
|
||||
{
|
||||
shared_ptr<Connection> conn = pool->borrowObject();
|
||||
if (conn && conn->isOK())
|
||||
if (!conn) return extent_;
|
||||
PoolGuard<shared_ptr<Connection>, shared_ptr< Pool<Connection,ConnectionCreator> > > guard(conn, pool);
|
||||
if (conn->isOK())
|
||||
{
|
||||
PoolGuard<shared_ptr<Connection>, shared_ptr< Pool<Connection,ConnectionCreator> > > guard(conn, pool);
|
||||
|
||||
std::ostringstream s;
|
||||
|
||||
boost::optional<mapnik::boolean> estimate_extent =
|
||||
|
@ -916,10 +933,10 @@ boost::optional<mapnik::datasource::geometry_t> postgis_datasource::get_geometry
|
|||
if (pool)
|
||||
{
|
||||
shared_ptr<Connection> conn = pool->borrowObject();
|
||||
if (conn && conn->isOK())
|
||||
if (!conn) return result;
|
||||
PoolGuard<shared_ptr<Connection>, shared_ptr< Pool<Connection,ConnectionCreator> > > guard(conn, pool);
|
||||
if (conn->isOK())
|
||||
{
|
||||
PoolGuard<shared_ptr<Connection>, shared_ptr< Pool<Connection,ConnectionCreator> > > guard(conn, pool);
|
||||
|
||||
std::ostringstream s;
|
||||
std::string g_type;
|
||||
|
||||
|
|
|
@ -174,6 +174,7 @@ feature_ptr postgis_featureset::next()
|
|||
|
||||
case 25: //text
|
||||
case 1043: //varchar
|
||||
case 705: //literal
|
||||
{
|
||||
feature->put(name, tr_->transcode(buf));
|
||||
break;
|
||||
|
|
|
@ -15,6 +15,7 @@ plugin_sources = Split(
|
|||
"""
|
||||
%(PLUGIN_NAME)s_datasource.cpp
|
||||
%(PLUGIN_NAME)s_featureset.cpp
|
||||
%(PLUGIN_NAME)s_utils.cpp
|
||||
""" % locals()
|
||||
)
|
||||
|
||||
|
@ -25,12 +26,7 @@ libraries = ['mapnik',env['BOOST_PYTHON_LIB'],boost_system,env['ICU_LIB_NAME']]
|
|||
# python plugin is used by a app in python using mapnik's python bindings
|
||||
# we explicitly link to libpython here so that this plugin
|
||||
# can be used from a pure C++ calling application or a different binding language
|
||||
python_link_flag = '-lpython%s' % env['PYTHON_VERSION']
|
||||
|
||||
if env['PLATFORM'] == 'Darwin':
|
||||
if env['PYTHON_DYNAMIC_LOOKUP']:
|
||||
python_link_flag = '-undefined dynamic_lookup'
|
||||
elif env['FRAMEWORK_PYTHON']:
|
||||
if env['PLATFORM'] == 'Darwin' and env['FRAMEWORK_PYTHON']:
|
||||
if env['FRAMEWORK_SEARCH_PATH']:
|
||||
python_link_flag = '-F%s -framework Python -Z' % env['FRAMEWORK_SEARCH_PATH']
|
||||
else:
|
||||
|
@ -41,6 +37,11 @@ if env['PLATFORM'] == 'Darwin':
|
|||
python_link_flag = '-F/System/Library/Frameworks/ -framework Python -Z'
|
||||
else:
|
||||
python_link_flag = '-F/ -framework Python'
|
||||
else:
|
||||
# on linux the linkflags end up to early in the compile flags to work correctly
|
||||
python_link_flag = ''
|
||||
# so instead add to libraries
|
||||
libraries.append('python%s' % env['PYTHON_VERSION'])
|
||||
|
||||
if env['CUSTOM_LDFLAGS']:
|
||||
linkflags = '%s %s' % (env['CUSTOM_LDFLAGS'], python_link_flag)
|
||||
|
|
|
@ -62,147 +62,170 @@ mapnik::layer_descriptor python_datasource::get_descriptor() const
|
|||
void python_datasource::bind() const
|
||||
{
|
||||
using namespace boost;
|
||||
using namespace boost::python;
|
||||
|
||||
if (is_bound_) return;
|
||||
|
||||
// if no factory callable is defined, bind is a nop
|
||||
if (factory_.empty()) return;
|
||||
|
||||
// split factory at ':' to parse out module and callable
|
||||
std::vector<std::string> factory_split;
|
||||
split(factory_split, factory_, is_any_of(":"));
|
||||
if ((factory_split.size() < 1) || (factory_split.size() > 2))
|
||||
{
|
||||
// FIMXE: is this appropriate error reporting?
|
||||
std::cerr << "python: factory string must be of the form '[module:]callable' when parsing \""
|
||||
<< factory_ << '"' << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
// extract the module and the callable
|
||||
str module_name("__main__"), callable_name;
|
||||
if (factory_split.size() == 1)
|
||||
{
|
||||
callable_name = str(factory_split[0]);
|
||||
}
|
||||
else
|
||||
{
|
||||
module_name = str(factory_split[0]);
|
||||
callable_name = str(factory_split[1]);
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
// split factory at ':' to parse out module and callable
|
||||
std::vector<std::string> factory_split;
|
||||
split(factory_split, factory_, is_any_of(":"));
|
||||
if ((factory_split.size() < 1) || (factory_split.size() > 2))
|
||||
{
|
||||
throw mapnik::datasource_exception(
|
||||
std::string("python: factory string must be of the form '[module:]callable' when parsing \"")
|
||||
+ factory_ + '"');
|
||||
}
|
||||
// extract the module and the callable
|
||||
boost::python::str module_name("__main__"), callable_name;
|
||||
if (factory_split.size() == 1)
|
||||
{
|
||||
callable_name = boost::python::str(factory_split[0]);
|
||||
}
|
||||
else
|
||||
{
|
||||
module_name = boost::python::str(factory_split[0]);
|
||||
callable_name = boost::python::str(factory_split[1]);
|
||||
}
|
||||
ensure_gil lock;
|
||||
|
||||
// import the main module from Python (in case we're embedding the
|
||||
// interpreter directly) and also import the callable.
|
||||
object main_module = import("__main__");
|
||||
object callable_module = import(module_name);
|
||||
object callable = callable_module.attr(callable_name);
|
||||
|
||||
boost::python::object main_module = boost::python::import("__main__");
|
||||
boost::python::object callable_module = boost::python::import(module_name);
|
||||
boost::python::object callable = callable_module.attr(callable_name);
|
||||
// prepare the arguments
|
||||
dict kwargs;
|
||||
boost::python::dict kwargs;
|
||||
typedef std::map<std::string, std::string>::value_type kv_type;
|
||||
BOOST_FOREACH(const kv_type& kv, kwargs_)
|
||||
{
|
||||
kwargs[str(kv.first)] = str(kv.second);
|
||||
kwargs[boost::python::str(kv.first)] = boost::python::str(kv.second);
|
||||
}
|
||||
|
||||
// get our wrapped data source
|
||||
datasource_ = callable(*boost::python::make_tuple(), **kwargs);
|
||||
}
|
||||
catch ( boost::python::error_already_set )
|
||||
{
|
||||
throw mapnik::datasource_exception(extractException());
|
||||
}
|
||||
|
||||
is_bound_ = true;
|
||||
}
|
||||
|
||||
mapnik::datasource::datasource_t python_datasource::type() const
|
||||
{
|
||||
using namespace boost::python;
|
||||
|
||||
typedef boost::optional<mapnik::datasource::geometry_t> return_type;
|
||||
|
||||
if (!is_bound_) bind();
|
||||
|
||||
ensure_gil lock;
|
||||
try
|
||||
{
|
||||
ensure_gil lock;
|
||||
boost::python::object data_type = datasource_.attr("data_type");
|
||||
long data_type_integer = boost::python::extract<long>(data_type);
|
||||
return mapnik::datasource::datasource_t(data_type_integer);
|
||||
}
|
||||
catch ( boost::python::error_already_set )
|
||||
{
|
||||
throw mapnik::datasource_exception(extractException());
|
||||
}
|
||||
|
||||
object data_type = datasource_.attr("data_type");
|
||||
long data_type_integer = extract<long>(data_type);
|
||||
return mapnik::datasource::datasource_t(data_type_integer);
|
||||
}
|
||||
|
||||
mapnik::box2d<double> python_datasource::envelope() const
|
||||
{
|
||||
using namespace boost::python;
|
||||
|
||||
if (!is_bound_) bind();
|
||||
|
||||
ensure_gil lock;
|
||||
return extract<mapnik::box2d<double> >(datasource_.attr("envelope"));
|
||||
try
|
||||
{
|
||||
ensure_gil lock;
|
||||
return boost::python::extract<mapnik::box2d<double> >(datasource_.attr("envelope"));
|
||||
}
|
||||
catch ( boost::python::error_already_set )
|
||||
{
|
||||
throw mapnik::datasource_exception(extractException());
|
||||
}
|
||||
}
|
||||
|
||||
boost::optional<mapnik::datasource::geometry_t> python_datasource::get_geometry_type() const
|
||||
{
|
||||
using namespace boost::python;
|
||||
|
||||
typedef boost::optional<mapnik::datasource::geometry_t> return_type;
|
||||
|
||||
if (!is_bound_) bind();
|
||||
|
||||
ensure_gil lock;
|
||||
|
||||
// if the datasource object has no geometry_type attribute, return a 'none' value
|
||||
if (!PyObject_HasAttrString(datasource_.ptr(), "geometry_type"))
|
||||
return return_type();
|
||||
|
||||
object py_geometry_type = datasource_.attr("geometry_type");
|
||||
|
||||
// if the attribute value is 'None', return a 'none' value
|
||||
if (py_geometry_type.ptr() == object().ptr())
|
||||
return return_type();
|
||||
|
||||
long geom_type_integer = extract<long>(py_geometry_type);
|
||||
return mapnik::datasource::geometry_t(geom_type_integer);
|
||||
try
|
||||
{
|
||||
ensure_gil lock;
|
||||
// if the datasource object has no geometry_type attribute, return a 'none' value
|
||||
if (!PyObject_HasAttrString(datasource_.ptr(), "geometry_type"))
|
||||
{
|
||||
return return_type();
|
||||
}
|
||||
boost::python::object py_geometry_type = datasource_.attr("geometry_type");
|
||||
// if the attribute value is 'None', return a 'none' value
|
||||
if (py_geometry_type.ptr() == boost::python::object().ptr())
|
||||
{
|
||||
return return_type();
|
||||
}
|
||||
long geom_type_integer = boost::python::extract<long>(py_geometry_type);
|
||||
return mapnik::datasource::geometry_t(geom_type_integer);
|
||||
}
|
||||
catch ( boost::python::error_already_set )
|
||||
{
|
||||
throw mapnik::datasource_exception(extractException());
|
||||
}
|
||||
}
|
||||
|
||||
mapnik::featureset_ptr python_datasource::features(mapnik::query const& q) const
|
||||
{
|
||||
using namespace boost::python;
|
||||
|
||||
if (!is_bound_) bind();
|
||||
|
||||
// if the query box intersects our world extent then query for features
|
||||
if (envelope().intersects(q.get_bbox()))
|
||||
try
|
||||
{
|
||||
ensure_gil lock;
|
||||
|
||||
object features(datasource_.attr("features")(q));
|
||||
|
||||
// if 'None' was returned, return an empty feature set
|
||||
if(features.ptr() == object().ptr())
|
||||
return mapnik::featureset_ptr();
|
||||
|
||||
return boost::make_shared<python_featureset>(features);
|
||||
// if the query box intersects our world extent then query for features
|
||||
if (envelope().intersects(q.get_bbox()))
|
||||
{
|
||||
ensure_gil lock;
|
||||
boost::python::object features(datasource_.attr("features")(q));
|
||||
// if 'None' was returned, return an empty feature set
|
||||
if(features.ptr() == boost::python::object().ptr())
|
||||
{
|
||||
return mapnik::featureset_ptr();
|
||||
}
|
||||
return boost::make_shared<python_featureset>(features);
|
||||
}
|
||||
// otherwise return an empty featureset pointer
|
||||
return mapnik::featureset_ptr();
|
||||
}
|
||||
catch ( boost::python::error_already_set )
|
||||
{
|
||||
throw mapnik::datasource_exception(extractException());
|
||||
}
|
||||
|
||||
// otherwise return an empty featureset pointer
|
||||
return mapnik::featureset_ptr();
|
||||
}
|
||||
|
||||
mapnik::featureset_ptr python_datasource::features_at_point(mapnik::coord2d const& pt) const
|
||||
{
|
||||
using namespace boost::python;
|
||||
|
||||
if (!is_bound_) bind();
|
||||
|
||||
ensure_gil lock;
|
||||
try
|
||||
{
|
||||
ensure_gil lock;
|
||||
boost::python::object features(datasource_.attr("features_at_point")(pt));
|
||||
// if we returned none, return an empty set
|
||||
if(features.ptr() == boost::python::object().ptr())
|
||||
{
|
||||
return mapnik::featureset_ptr();
|
||||
}
|
||||
// otherwise, return a feature set which can iterate over the iterator
|
||||
return boost::make_shared<python_featureset>(features);
|
||||
}
|
||||
catch ( boost::python::error_already_set )
|
||||
{
|
||||
throw mapnik::datasource_exception(extractException());
|
||||
}
|
||||
|
||||
object features(datasource_.attr("features_at_point")(pt));
|
||||
|
||||
// if we returned none, return an empty set
|
||||
if(features.ptr() == object().ptr())
|
||||
return mapnik::featureset_ptr();
|
||||
|
||||
// otherwise, return a feature set which can iterate over the iterator
|
||||
return boost::make_shared<python_featureset>(features);
|
||||
}
|
23
plugins/input/python/python_utils.cpp
Normal file
23
plugins/input/python/python_utils.cpp
Normal file
|
@ -0,0 +1,23 @@
|
|||
#include "python_utils.hpp"
|
||||
|
||||
std::string extractException()
|
||||
{
|
||||
using namespace boost::python;
|
||||
|
||||
PyObject *exc,*val,*tb;
|
||||
PyErr_Fetch(&exc,&val,&tb);
|
||||
PyErr_NormalizeException(&exc,&val,&tb);
|
||||
handle<> hexc(exc),hval(allow_null(val)),htb(allow_null(tb));
|
||||
if(!hval)
|
||||
{
|
||||
return extract<std::string>(str(hexc));
|
||||
}
|
||||
else
|
||||
{
|
||||
object traceback(import("traceback"));
|
||||
object format_exception(traceback.attr("format_exception"));
|
||||
object formatted_list(format_exception(hexc,hval,htb));
|
||||
object formatted(str("").join(formatted_list));
|
||||
return extract<std::string>(formatted);
|
||||
}
|
||||
}
|
|
@ -13,4 +13,6 @@ class ensure_gil
|
|||
PyGILState_STATE gil_state_;
|
||||
};
|
||||
|
||||
std::string extractException();
|
||||
|
||||
#endif // PYTHON_UTILS_HPP
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
#include <mapnik/agg_rasterizer.hpp>
|
||||
|
||||
#include <mapnik/debug.hpp>
|
||||
#include <mapnik/feature.hpp>
|
||||
#include <mapnik/geom_util.hpp>
|
||||
#include <mapnik/expression_evaluator.hpp>
|
||||
#include <mapnik/vertex_converters.hpp>
|
||||
|
@ -136,10 +137,7 @@ void agg_renderer<T>::process(markers_symbolizer const& sym,
|
|||
}
|
||||
converter.template set<transform_tag>(); //always transform
|
||||
if (sym.smooth() > 0.0) converter.template set<smooth_tag>(); // optional smooth converter
|
||||
BOOST_FOREACH(geometry_type & geom, feature.paths())
|
||||
{
|
||||
converter.apply(geom);
|
||||
}
|
||||
apply_markers_multi(feature, converter, sym);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -172,10 +170,7 @@ void agg_renderer<T>::process(markers_symbolizer const& sym,
|
|||
}
|
||||
converter.template set<transform_tag>(); //always transform
|
||||
if (sym.smooth() > 0.0) converter.template set<smooth_tag>(); // optional smooth converter
|
||||
BOOST_FOREACH(geometry_type & geom, feature.paths())
|
||||
{
|
||||
converter.apply(geom);
|
||||
}
|
||||
apply_markers_multi(feature, converter, sym);
|
||||
}
|
||||
}
|
||||
else // raster markers
|
||||
|
@ -207,11 +202,7 @@ void agg_renderer<T>::process(markers_symbolizer const& sym,
|
|||
}
|
||||
converter.template set<transform_tag>(); //always transform
|
||||
if (sym.smooth() > 0.0) converter.template set<smooth_tag>(); // optional smooth converter
|
||||
|
||||
BOOST_FOREACH(geometry_type & geom, feature.paths())
|
||||
{
|
||||
converter.apply(geom);
|
||||
}
|
||||
apply_markers_multi(feature, converter, sym);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1494,11 +1494,17 @@ struct markers_dispatch
|
|||
{
|
||||
marker_placement_e placement_method = sym_.get_marker_placement();
|
||||
|
||||
if (placement_method != MARKER_LINE_PLACEMENT)
|
||||
if (placement_method != MARKER_LINE_PLACEMENT ||
|
||||
path.type() == Point)
|
||||
{
|
||||
double x = 0;
|
||||
double y = 0;
|
||||
if (placement_method == MARKER_INTERIOR_PLACEMENT)
|
||||
if (path.type() == LineString)
|
||||
{
|
||||
if (!label::middle_point(path, x, y))
|
||||
return;
|
||||
}
|
||||
else if (placement_method == MARKER_INTERIOR_PLACEMENT)
|
||||
{
|
||||
if (!label::interior_position(path, x, y))
|
||||
return;
|
||||
|
@ -1577,11 +1583,17 @@ struct markers_dispatch_2
|
|||
{
|
||||
marker_placement_e placement_method = sym_.get_marker_placement();
|
||||
|
||||
if (placement_method != MARKER_LINE_PLACEMENT)
|
||||
if (placement_method != MARKER_LINE_PLACEMENT ||
|
||||
path.type() == Point)
|
||||
{
|
||||
double x = 0;
|
||||
double y = 0;
|
||||
if (placement_method == MARKER_INTERIOR_PLACEMENT)
|
||||
if (path.type() == LineString)
|
||||
{
|
||||
if (!label::middle_point(path, x, y))
|
||||
return;
|
||||
}
|
||||
else if (placement_method == MARKER_INTERIOR_PLACEMENT)
|
||||
{
|
||||
if (!label::interior_position(path, x, y))
|
||||
return;
|
||||
|
@ -1706,10 +1718,7 @@ void cairo_renderer_base::process(markers_symbolizer const& sym,
|
|||
}
|
||||
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);
|
||||
}
|
||||
apply_markers_multi(feature, converter, sym);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -1734,10 +1743,7 @@ void cairo_renderer_base::process(markers_symbolizer const& sym,
|
|||
}
|
||||
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);
|
||||
}
|
||||
apply_markers_multi(feature, converter, sym);
|
||||
}
|
||||
}
|
||||
else // raster markers
|
||||
|
@ -1767,10 +1773,7 @@ void cairo_renderer_base::process(markers_symbolizer const& sym,
|
|||
}
|
||||
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);
|
||||
}
|
||||
apply_markers_multi(feature, converter, sym);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -60,14 +60,10 @@ logger::severity_type logger::severity_level_ =
|
|||
#if MAPNIK_DEFAULT_LOG_SEVERITY == 0
|
||||
logger::debug
|
||||
#elif MAPNIK_DEFAULT_LOG_SEVERITY == 1
|
||||
logger::info
|
||||
#elif MAPNIK_DEFAULT_LOG_SEVERITY == 2
|
||||
logger::warn
|
||||
#elif MAPNIK_DEFAULT_LOG_SEVERITY == 3
|
||||
#elif MAPNIK_DEFAULT_LOG_SEVERITY == 2
|
||||
logger::error
|
||||
#elif MAPNIK_DEFAULT_LOG_SEVERITY == 4
|
||||
logger::fatal
|
||||
#elif MAPNIK_DEFAULT_LOG_SEVERITY == 5
|
||||
#elif MAPNIK_DEFAULT_LOG_SEVERITY == 3
|
||||
logger::none
|
||||
#else
|
||||
#error "Wrong default log severity level specified!"
|
||||
|
|
|
@ -207,6 +207,7 @@ void feature_style_processor<Processor>::apply_to_layer(layer const& lay, Proces
|
|||
double scale_denom,
|
||||
std::set<std::string>& names)
|
||||
{
|
||||
try {
|
||||
std::vector<std::string> const& style_names = lay.styles();
|
||||
|
||||
unsigned int num_styles = style_names.size();
|
||||
|
@ -477,6 +478,15 @@ void feature_style_processor<Processor>::apply_to_layer(layer const& lay, Proces
|
|||
#endif
|
||||
|
||||
p.end_layer_processing(lay);
|
||||
|
||||
} catch (std::exception const& e) {
|
||||
// Include layer name in exception
|
||||
// see https://github.com/mapnik/mapnik/issues/1924
|
||||
std::ostringstream m;
|
||||
m << lay.name() << ": " << e.what();
|
||||
throw std::runtime_error(m.str().c_str());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -29,8 +29,6 @@
|
|||
|
||||
namespace mapnik
|
||||
{
|
||||
font_set::font_set()
|
||||
: name_("") {}
|
||||
|
||||
font_set::font_set(std::string const& name)
|
||||
: name_(name) {}
|
||||
|
@ -61,6 +59,11 @@ void font_set::add_face_name(std::string face_name)
|
|||
face_names_.push_back(face_name);
|
||||
}
|
||||
|
||||
void font_set::set_name(std::string const& name)
|
||||
{
|
||||
name_ = name;
|
||||
}
|
||||
|
||||
std::string const& font_set::get_name() const
|
||||
{
|
||||
return name_;
|
||||
|
|
|
@ -163,10 +163,7 @@ void grid_renderer<T>::process(markers_symbolizer const& sym,
|
|||
}
|
||||
converter.template set<transform_tag>(); //always transform
|
||||
if (sym.smooth() > 0.0) converter.template set<smooth_tag>(); // optional smooth converter
|
||||
BOOST_FOREACH(geometry_type & geom, feature.paths())
|
||||
{
|
||||
converter.apply(geom);
|
||||
}
|
||||
apply_markers_multi(feature, converter, sym);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -208,10 +205,7 @@ void grid_renderer<T>::process(markers_symbolizer const& sym,
|
|||
}
|
||||
converter.template set<transform_tag>(); //always transform
|
||||
if (sym.smooth() > 0.0) converter.template set<smooth_tag>(); // optional smooth converter
|
||||
BOOST_FOREACH(geometry_type & geom, feature.paths())
|
||||
{
|
||||
converter.apply(geom);
|
||||
}
|
||||
apply_markers_multi(feature, converter, sym);
|
||||
}
|
||||
}
|
||||
else // raster markers
|
||||
|
@ -256,10 +250,7 @@ void grid_renderer<T>::process(markers_symbolizer const& sym,
|
|||
}
|
||||
converter.template set<transform_tag>(); //always transform
|
||||
if (sym.smooth() > 0.0) converter.template set<smooth_tag>(); // optional smooth converter
|
||||
BOOST_FOREACH(geometry_type & geom, feature.paths())
|
||||
{
|
||||
converter.apply(geom);
|
||||
}
|
||||
apply_markers_multi(feature, converter, sym);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,12 +20,17 @@
|
|||
*
|
||||
*****************************************************************************/
|
||||
|
||||
// TODO https://github.com/mapnik/mapnik/issues/1658
|
||||
#include <boost/version.hpp>
|
||||
#if BOOST_VERSION >= 105200
|
||||
#define BOOST_SPIRIT_USE_PHOENIX_V3
|
||||
#endif
|
||||
|
||||
// mapnik
|
||||
#include <mapnik/json/feature_collection_parser.hpp>
|
||||
#include <mapnik/json/feature_collection_grammar.hpp>
|
||||
|
||||
// boost
|
||||
#include <boost/version.hpp>
|
||||
#include <boost/spirit/include/qi.hpp>
|
||||
#include <boost/spirit/include/support_multi_pass.hpp>
|
||||
|
||||
|
|
|
@ -514,7 +514,7 @@ void map_parser::parse_fontset(Map & map, xml_node const& fset)
|
|||
|
||||
// XXX Hack because map object isn't accessible by text_symbolizer
|
||||
// when it's parsed
|
||||
fontsets_.insert(pair<std::string, font_set>(name, fontset));
|
||||
fontsets_.insert(std::pair<std::string, font_set>(name, fontset));
|
||||
}
|
||||
catch (const config_error & ex)
|
||||
{
|
||||
|
@ -1027,6 +1027,10 @@ void map_parser::parse_markers_symbolizer(rule & rule, xml_node const& node)
|
|||
|
||||
marker_placement_e placement = node.get_attr<marker_placement_e>("placement",sym.get_marker_placement());
|
||||
sym.set_marker_placement(placement);
|
||||
|
||||
marker_multi_policy_e mpolicy = node.get_attr<marker_multi_policy_e>("multi-policy",sym.get_marker_multi_policy());
|
||||
sym.set_marker_multi_policy(mpolicy);
|
||||
|
||||
parse_symbolizer_base(sym, node);
|
||||
rule.append(sym);
|
||||
}
|
||||
|
@ -1148,7 +1152,7 @@ void map_parser::parse_text_symbolizer(rule & rule, xml_node const& sym)
|
|||
placement_finder->defaults.from_xml(sym, fontsets_);
|
||||
}
|
||||
if (strict_ &&
|
||||
!placement_finder->defaults.format.fontset.size())
|
||||
!placement_finder->defaults.format.fontset)
|
||||
{
|
||||
ensure_font_face(placement_finder->defaults.format.face_name);
|
||||
}
|
||||
|
@ -1177,7 +1181,7 @@ void map_parser::parse_shield_symbolizer(rule & rule, xml_node const& sym)
|
|||
}
|
||||
placement_finder->defaults.from_xml(sym, fontsets_);
|
||||
if (strict_ &&
|
||||
!placement_finder->defaults.format.fontset.size())
|
||||
!placement_finder->defaults.format.fontset)
|
||||
{
|
||||
ensure_font_face(placement_finder->defaults.format.face_name);
|
||||
}
|
||||
|
|
|
@ -159,6 +159,10 @@ boost::optional<feature_type_style const&> Map::find_style(std::string const& na
|
|||
|
||||
bool Map::insert_fontset(std::string const& name, font_set const& fontset)
|
||||
{
|
||||
if (fontset.get_name() != name)
|
||||
{
|
||||
throw mapnik::config_error("Fontset name must match the name used to reference it on the map");
|
||||
}
|
||||
return fontsets_.insert(make_pair(name, fontset)).second;
|
||||
}
|
||||
|
||||
|
|
|
@ -37,6 +37,15 @@ static const char * marker_placement_strings[] = {
|
|||
|
||||
IMPLEMENT_ENUM( marker_placement_e, marker_placement_strings )
|
||||
|
||||
static const char * marker_multi_policy_strings[] = {
|
||||
"each",
|
||||
"whole",
|
||||
"largest",
|
||||
""
|
||||
};
|
||||
|
||||
IMPLEMENT_ENUM( marker_multi_policy_e, marker_multi_policy_strings )
|
||||
|
||||
markers_symbolizer::markers_symbolizer()
|
||||
: symbolizer_with_image(parse_path("shape://ellipse")),
|
||||
symbolizer_base(),
|
||||
|
@ -46,7 +55,10 @@ markers_symbolizer::markers_symbolizer()
|
|||
allow_overlap_(false),
|
||||
spacing_(100.0),
|
||||
max_error_(0.2),
|
||||
marker_p_(MARKER_POINT_PLACEMENT) { }
|
||||
marker_p_(MARKER_POINT_PLACEMENT),
|
||||
// TODO: consider defaulting to MARKER_WHOLE_MULTI,
|
||||
// for backward compatibility with 2.0.0
|
||||
marker_mp_(MARKER_EACH_MULTI) { }
|
||||
|
||||
markers_symbolizer::markers_symbolizer(path_expression_ptr const& filename)
|
||||
: symbolizer_with_image(filename),
|
||||
|
@ -57,7 +69,10 @@ markers_symbolizer::markers_symbolizer(path_expression_ptr const& filename)
|
|||
allow_overlap_(false),
|
||||
spacing_(100.0),
|
||||
max_error_(0.2),
|
||||
marker_p_(MARKER_POINT_PLACEMENT) { }
|
||||
marker_p_(MARKER_POINT_PLACEMENT),
|
||||
// TODO: consider defaulting to MARKER_WHOLE_MULTI,
|
||||
// for backward compatibility with 2.0.0
|
||||
marker_mp_(MARKER_EACH_MULTI) { }
|
||||
|
||||
markers_symbolizer::markers_symbolizer(markers_symbolizer const& rhs)
|
||||
: symbolizer_with_image(rhs),
|
||||
|
@ -71,7 +86,8 @@ markers_symbolizer::markers_symbolizer(markers_symbolizer const& rhs)
|
|||
fill_(rhs.fill_),
|
||||
fill_opacity_(rhs.fill_opacity_),
|
||||
stroke_(rhs.stroke_),
|
||||
marker_p_(rhs.marker_p_) {}
|
||||
marker_p_(rhs.marker_p_),
|
||||
marker_mp_(rhs.marker_mp_) {}
|
||||
|
||||
void markers_symbolizer::set_ignore_placement(bool ignore_placement)
|
||||
{
|
||||
|
@ -173,4 +189,14 @@ marker_placement_e markers_symbolizer::get_marker_placement() const
|
|||
return marker_p_;
|
||||
}
|
||||
|
||||
void markers_symbolizer::set_marker_multi_policy(marker_multi_policy_e marker_mp)
|
||||
{
|
||||
marker_mp_ = marker_mp;
|
||||
}
|
||||
|
||||
marker_multi_policy_e markers_symbolizer::get_marker_multi_policy() const
|
||||
{
|
||||
return marker_mp_;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -65,22 +65,22 @@ string_info &processed_text::get_string_info()
|
|||
face_set_ptr faces = font_manager_.get_face_set(p.face_name, p.fontset);
|
||||
if (faces->size() == 0)
|
||||
{
|
||||
if (!p.fontset.get_name().empty())
|
||||
if (p.fontset && !p.fontset->get_name().empty())
|
||||
{
|
||||
if (p.fontset.size())
|
||||
if (p.fontset->size())
|
||||
{
|
||||
if (!p.face_name.empty())
|
||||
{
|
||||
throw config_error("Unable to find specified font face '" + p.face_name + "' in font set: '" + p.fontset.get_name() + "'");
|
||||
throw config_error("Unable to find specified font face '" + p.face_name + "' in font set: '" + p.fontset->get_name() + "'");
|
||||
}
|
||||
else
|
||||
{
|
||||
throw config_error("No valid font face could be loaded for font set: '" + p.fontset.get_name() + "'");
|
||||
throw config_error("No valid font face could be loaded for font set: '" + p.fontset->get_name() + "'");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
throw config_error("Font set '" + p.fontset.get_name() + "' does not contain any Font face-name entries");
|
||||
throw config_error("Font set '" + p.fontset->get_name() + "' does not contain any Font face-name entries");
|
||||
}
|
||||
}
|
||||
else if (!p.face_name.empty())
|
||||
|
|
|
@ -98,6 +98,10 @@ public:
|
|||
{
|
||||
set_attr( sym_node, "rasterizer", sym.get_rasterizer() );
|
||||
}
|
||||
if ( sym.offset() != dfl.offset() || explicit_defaults_ )
|
||||
{
|
||||
set_attr( sym_node, "offset", sym.offset() );
|
||||
}
|
||||
serialize_symbolizer_base(sym_node, sym);
|
||||
}
|
||||
|
||||
|
@ -311,6 +315,10 @@ public:
|
|||
{
|
||||
set_attr( sym_node, "placement", sym.get_marker_placement() );
|
||||
}
|
||||
if ( sym.get_marker_multi_policy() != dfl.get_marker_multi_policy() || explicit_defaults_ )
|
||||
{
|
||||
set_attr( sym_node, "multi-policy", sym.get_marker_multi_policy() );
|
||||
}
|
||||
if (sym.get_image_transform())
|
||||
{
|
||||
std::string tr_str = sym.get_image_transform_string();
|
||||
|
|
|
@ -293,11 +293,11 @@ void char_properties::from_xml(xml_node const& sym, fontset_map const& fontsets)
|
|||
throw config_error("Unable to find any fontset named '" + *fontset_name_ + "'", sym);
|
||||
}
|
||||
}
|
||||
if (!face_name.empty() && !fontset.get_name().empty())
|
||||
if (!face_name.empty() && fontset)
|
||||
{
|
||||
throw config_error("Can't have both face-name and fontset-name", sym);
|
||||
}
|
||||
if (face_name.empty() && fontset.get_name().empty())
|
||||
if (face_name.empty() && !fontset)
|
||||
{
|
||||
throw config_error("Must have face-name or fontset-name", sym);
|
||||
}
|
||||
|
@ -305,11 +305,9 @@ void char_properties::from_xml(xml_node const& sym, fontset_map const& fontsets)
|
|||
|
||||
void char_properties::to_xml(boost::property_tree::ptree &node, bool explicit_defaults, char_properties const &dfl) const
|
||||
{
|
||||
std::string const& fontset_name = fontset.get_name();
|
||||
std::string const& dfl_fontset_name = dfl.fontset.get_name();
|
||||
if (fontset_name != dfl_fontset_name || explicit_defaults)
|
||||
if (fontset)
|
||||
{
|
||||
set_attr(node, "fontset-name", fontset_name);
|
||||
set_attr(node, "fontset-name", fontset->get_name());
|
||||
}
|
||||
|
||||
if (face_name != dfl.face_name || explicit_defaults)
|
||||
|
|
|
@ -173,7 +173,7 @@ void text_symbolizer::set_fontset(font_set const& fontset)
|
|||
placement_options_->defaults.format.fontset = fontset;
|
||||
}
|
||||
|
||||
font_set const& text_symbolizer::get_fontset() const
|
||||
boost::optional<font_set> const& text_symbolizer::get_fontset() const
|
||||
{
|
||||
return placement_options_->defaults.format.fontset;
|
||||
}
|
||||
|
|
|
@ -486,6 +486,7 @@ compile_get_attr(std::string);
|
|||
compile_get_attr(filter_mode_e);
|
||||
compile_get_attr(point_placement_e);
|
||||
compile_get_attr(marker_placement_e);
|
||||
compile_get_attr(marker_multi_policy_e);
|
||||
compile_get_attr(pattern_alignment_e);
|
||||
compile_get_attr(line_rasterizer_e);
|
||||
compile_get_attr(colorizer_mode);
|
||||
|
|
133
tests/cpp_tests/conversions_test.cpp
Normal file
133
tests/cpp_tests/conversions_test.cpp
Normal file
|
@ -0,0 +1,133 @@
|
|||
#include <boost/version.hpp>
|
||||
#include <mapnik/util/conversions.hpp>
|
||||
#include <boost/detail/lightweight_test.hpp>
|
||||
#include <iostream>
|
||||
|
||||
int main( int, char*[] )
|
||||
{
|
||||
using mapnik::util::to_string;
|
||||
|
||||
try
|
||||
{
|
||||
std::string out;
|
||||
|
||||
// Test double
|
||||
to_string(out, double(0));
|
||||
BOOST_TEST_EQ( out, "0" );
|
||||
out.clear();
|
||||
|
||||
to_string(out, double(1));
|
||||
BOOST_TEST_EQ( out, "1" );
|
||||
out.clear();
|
||||
|
||||
to_string(out, double(-1));
|
||||
BOOST_TEST_EQ( out, "-1" );
|
||||
out.clear();
|
||||
|
||||
to_string(out, double(0.1));
|
||||
BOOST_TEST_EQ( out, "0.1" );
|
||||
out.clear();
|
||||
|
||||
to_string(out, double(-0.1));
|
||||
BOOST_TEST_EQ( out, "-0.1" );
|
||||
out.clear();
|
||||
|
||||
to_string(out, double(0.123));
|
||||
BOOST_TEST_EQ( out, "0.123" );
|
||||
out.clear();
|
||||
|
||||
to_string(out, double(-0.123));
|
||||
BOOST_TEST_EQ( out, "-0.123" );
|
||||
out.clear();
|
||||
|
||||
to_string(out, double(1e-06));
|
||||
BOOST_TEST_EQ( out, "1e-06" );
|
||||
out.clear();
|
||||
|
||||
to_string(out, double(-1e-06));
|
||||
BOOST_TEST_EQ( out, "-1e-06" );
|
||||
out.clear();
|
||||
|
||||
to_string(out, double(1e-05));
|
||||
BOOST_TEST_EQ( out, "1e-05" );
|
||||
out.clear();
|
||||
|
||||
to_string(out, double(-1e-05));
|
||||
BOOST_TEST_EQ( out, "-1e-05" );
|
||||
out.clear();
|
||||
|
||||
to_string(out, double(0.0001));
|
||||
BOOST_TEST_EQ( out, "0.0001" );
|
||||
out.clear();
|
||||
|
||||
to_string(out, double(-0.0001));
|
||||
BOOST_TEST_EQ( out, "-0.0001" );
|
||||
out.clear();
|
||||
|
||||
to_string(out, double(0.0001234567890123456));
|
||||
// TODO: https://github.com/mapnik/mapnik/issues/1676
|
||||
//BOOST_TEST_EQ( out, "0.0001234567890123456" );
|
||||
out.clear();
|
||||
|
||||
to_string(out, double(-0.0001234567890123456));
|
||||
// TODO: https://github.com/mapnik/mapnik/issues/1676
|
||||
//BOOST_TEST_EQ( out, "-0.0001234567890123456" );
|
||||
out.clear();
|
||||
|
||||
to_string(out, double(1000000000000000));
|
||||
BOOST_TEST_EQ( out, "1000000000000000" );
|
||||
out.clear();
|
||||
|
||||
to_string(out, double(-1000000000000000));
|
||||
BOOST_TEST_EQ( out, "-1000000000000000" );
|
||||
out.clear();
|
||||
|
||||
to_string(out, double(10000000000000.1));
|
||||
BOOST_TEST_EQ( out, "10000000000000.1" );
|
||||
out.clear();
|
||||
|
||||
to_string(out, double(1.00001));
|
||||
BOOST_TEST_EQ( out, "1.00001" );
|
||||
out.clear();
|
||||
|
||||
to_string(out, double(67.65));
|
||||
BOOST_TEST_EQ( out, "67.65" );
|
||||
out.clear();
|
||||
|
||||
to_string(out, double(67.35));
|
||||
BOOST_TEST_EQ( out, "67.35" );
|
||||
out.clear();
|
||||
|
||||
to_string(out, double(1234000000000000));
|
||||
BOOST_TEST_EQ( out, "1234000000000000" );
|
||||
out.clear();
|
||||
|
||||
to_string(out, double(1.234e+16));
|
||||
BOOST_TEST_EQ( out, "1.234e+16" );
|
||||
out.clear();
|
||||
|
||||
to_string(out, double(-1.234e+16));
|
||||
BOOST_TEST_EQ( out, "-1.234e+16" );
|
||||
out.clear();
|
||||
|
||||
// Test int
|
||||
|
||||
to_string(out, int(2));
|
||||
BOOST_TEST_EQ( out, "2" );
|
||||
out.clear();
|
||||
}
|
||||
catch (std::exception const & ex)
|
||||
{
|
||||
std::clog << "C++ type conversions problem: " << ex.what() << "\n";
|
||||
BOOST_TEST(false);
|
||||
}
|
||||
|
||||
if (!::boost::detail::test_errors()) {
|
||||
std::clog << "C++ type conversions: \x1b[1;32m✓ \x1b[0m\n";
|
||||
#if BOOST_VERSION >= 104600
|
||||
::boost::detail::report_errors_remind().called_report_errors_function = true;
|
||||
#endif
|
||||
} else {
|
||||
return ::boost::report_errors();
|
||||
}
|
||||
}
|
|
@ -31,6 +31,9 @@ int main( int, char*[] )
|
|||
BOOST_TEST( x == 25 );
|
||||
BOOST_TEST( y == 25 );
|
||||
|
||||
// TODO - centroid and interior should be equal but they appear not to be (check largest)
|
||||
// MULTIPOLYGON(((-52 40,-60 32,-68 40,-60 48,-52 40)),((-60 50,-80 30,-100 49.9999999999999,-80.0000000000001 70,-60 50)),((-52 60,-60 52,-68 60,-60 68,-52 60)))
|
||||
|
||||
if (!::boost::detail::test_errors()) {
|
||||
std::clog << "C++ label algorithms: \x1b[1;32m✓ \x1b[0m\n";
|
||||
#if BOOST_VERSION >= 104600
|
||||
|
|
|
@ -169,13 +169,17 @@ def test_float_precision():
|
|||
context = mapnik.Context()
|
||||
context.push('num')
|
||||
f = mapnik.Feature(context,0)
|
||||
f["num"] = 1.0000
|
||||
eq_(f["num"],1.0000)
|
||||
expr = mapnik.Expression("[num] = 1.0000")
|
||||
f["num1"] = 1.0000
|
||||
f["num2"] = 1.0001
|
||||
eq_(f["num1"],1.0000)
|
||||
eq_(f["num2"],1.0001)
|
||||
expr = mapnik.Expression("[num1] = 1.0000")
|
||||
eq_(expr.evaluate(f),True)
|
||||
expr = mapnik.Expression("[num].match('.*0$')")
|
||||
expr = mapnik.Expression("[num1].match('1')")
|
||||
eq_(expr.evaluate(f),True)
|
||||
expr = mapnik.Expression("[num].match('.*0$')")
|
||||
expr = mapnik.Expression("[num2] = 1.0001")
|
||||
eq_(expr.evaluate(f),True)
|
||||
expr = mapnik.Expression("[num2].match('1.0001')")
|
||||
eq_(expr.evaluate(f),True)
|
||||
|
||||
def test_string_matching_on_precision():
|
||||
|
|
|
@ -14,7 +14,7 @@ def setup():
|
|||
|
||||
wkts = [
|
||||
[1,"POINT(30 10)"],
|
||||
[1,"POINT(30.0 10.0)"],
|
||||
[1,"POINT(30 10)"],
|
||||
[1,"POINT(30.1 10.1)"],
|
||||
[1,"LINESTRING(30 10,10 30,40 40)"],
|
||||
[1,"POLYGON((30 10,10 20,20 40,40 40,30 10))"],
|
||||
|
@ -61,7 +61,7 @@ wkbs = [
|
|||
]
|
||||
|
||||
geojson = [
|
||||
[1,'{"type":"Point","coordinates":[30.0,10.0]}'],
|
||||
[1,'{"type":"Point","coordinates":[30,10]}'],
|
||||
[1,'{"type":"Point","coordinates":[30.0,10.0]}'],
|
||||
[1,'{"type":"Point","coordinates":[30.1,10.1]}'],
|
||||
[1,'{"type":"LineString","coordinates":[[30.0,10.0],[10.0,30.0],[40.0,40.0]]}'],
|
||||
|
|
|
@ -97,7 +97,7 @@ def test_text_symbolizer():
|
|||
|
||||
# old args required method
|
||||
ts = mapnik.TextSymbolizer(mapnik.Expression('[Field_Name]'), 'Font Name', 8, mapnik.Color('black'))
|
||||
# eq_(str(ts.name), str(mapnik2.Expression('[Field_Name]'))) name field is no longer supported
|
||||
eq_(str(ts.name), str(mapnik.Expression('[Field_Name]')))
|
||||
eq_(ts.format.face_name, 'Font Name')
|
||||
eq_(ts.format.text_size, 8)
|
||||
eq_(ts.format.fill, mapnik.Color('black'))
|
||||
|
@ -112,7 +112,7 @@ def test_shield_symbolizer_init():
|
|||
eq_(s.allow_overlap, False)
|
||||
eq_(s.avoid_edges, False)
|
||||
eq_(s.character_spacing,0)
|
||||
#eq_(str(s.name), str(mapnik2.Expression('[Field Name]'))) name field is no longer supported
|
||||
eq_(str(s.name), str(mapnik.Expression('[Field Name]')))
|
||||
eq_(s.face_name, 'DejaVu Sans Bold')
|
||||
eq_(s.allow_overlap, False)
|
||||
eq_(s.fill, mapnik.Color('#000000'))
|
||||
|
@ -155,7 +155,7 @@ def test_shield_symbolizer_init():
|
|||
# 11c34b1: default transform list is empty, not identity matrix
|
||||
eq_(s.transform, '')
|
||||
|
||||
eq_(len(s.fontset.names), 0)
|
||||
eq_(s.fontset, None)
|
||||
|
||||
# ShieldSymbolizer missing image file
|
||||
# images paths are now PathExpressions are evaluated at runtime
|
||||
|
@ -170,11 +170,11 @@ def test_shield_symbolizer_modify():
|
|||
def check_transform(expr, expect_str=None):
|
||||
s.transform = expr
|
||||
eq_(s.transform, expr if expect_str is None else expect_str)
|
||||
check_transform("matrix(1 2 3 4 5 6)", "matrix(1.0, 2.0, 3.0, 4.0, 5.0, 6.0)")
|
||||
check_transform("matrix(1 2 3 4 5 6)", "matrix(1, 2, 3, 4, 5, 6)")
|
||||
check_transform("matrix(1, 2, 3, 4, 5, 6 +7)", "matrix(1, 2, 3, 4, 5, (6+7))")
|
||||
check_transform("rotate([a])")
|
||||
check_transform("rotate([a] -2)", "rotate(([a]-2))")
|
||||
check_transform("rotate([a] -2 -3)", "rotate([a], -2.0, -3.0)")
|
||||
check_transform("rotate([a] -2 -3)", "rotate([a], -2, -3)")
|
||||
check_transform("rotate([a] -2 -3 -4)", "rotate(((([a]-2)-3)-4))")
|
||||
check_transform("rotate([a] -2, 3, 4)", "rotate(([a]-2), 3, 4)")
|
||||
check_transform("translate([tx]) rotate([a])")
|
||||
|
@ -209,6 +209,7 @@ def test_markers_symbolizer():
|
|||
eq_(p.fill_opacity,None)
|
||||
eq_(p.filename,'shape://ellipse')
|
||||
eq_(p.placement,mapnik.marker_placement.POINT_PLACEMENT)
|
||||
eq_(p.multi_policy,mapnik.marker_multi_policy.EACH)
|
||||
eq_(p.fill,None)
|
||||
eq_(p.ignore_placement,False)
|
||||
eq_(p.spacing,100)
|
||||
|
@ -239,10 +240,14 @@ def test_markers_symbolizer():
|
|||
p.allow_overlap = True
|
||||
p.opacity = 0.5
|
||||
p.fill_opacity = 0.5
|
||||
p.placement = mapnik.marker_placement.LINE_PLACEMENT
|
||||
p.multi_policy = mapnik.marker_multi_policy.WHOLE
|
||||
|
||||
eq_(p.allow_overlap, True)
|
||||
eq_(p.opacity, 0.5)
|
||||
eq_(p.fill_opacity, 0.5)
|
||||
eq_(p.multi_policy,mapnik.marker_multi_policy.WHOLE)
|
||||
eq_(p.placement,mapnik.marker_placement.LINE_PLACEMENT)
|
||||
|
||||
#https://github.com/mapnik/mapnik/issues/1285
|
||||
#https://github.com/mapnik/mapnik/issues/1427
|
||||
|
|
|
@ -17,6 +17,10 @@ def test_query_init():
|
|||
r = query.resolution
|
||||
assert_almost_equal(r[0], 1.0, places=7)
|
||||
assert_almost_equal(r[1], 1.0, places=7)
|
||||
# https://github.com/mapnik/mapnik/issues/1762
|
||||
eq_(query.property_names,[])
|
||||
query.add_property_name('migurski')
|
||||
eq_(query.property_names,['migurski'])
|
||||
|
||||
# Converting *from* tuples *to* resolutions is not yet supported
|
||||
@raises(TypeError)
|
||||
|
|
|
@ -17,6 +17,25 @@ def test_loading_fontset_from_map():
|
|||
eq_(len(fs.names),2)
|
||||
eq_(list(fs.names),['DejaVu Sans Book','DejaVu Sans Oblique'])
|
||||
|
||||
def test_loading_fontset_from_python():
|
||||
m = mapnik.Map(256,256)
|
||||
fset = mapnik.FontSet('foo')
|
||||
fset.add_face_name('Comic Sans')
|
||||
fset.add_face_name('Papyrus')
|
||||
eq_(fset.name,'foo')
|
||||
fset.name = 'my-set'
|
||||
eq_(fset.name,'my-set')
|
||||
m.append_fontset('my-set', fset)
|
||||
sty = mapnik.Style()
|
||||
rule = mapnik.Rule()
|
||||
tsym = mapnik.TextSymbolizer()
|
||||
eq_(tsym.fontset,None)
|
||||
tsym.fontset = fset
|
||||
rule.symbols.append(tsym)
|
||||
sty.rules.append(rule)
|
||||
m.append_style('Style',sty)
|
||||
serialized_map = mapnik.save_map_to_string(m)
|
||||
eq_('fontset-name="my-set"' in serialized_map,True)
|
||||
|
||||
if __name__ == "__main__":
|
||||
setup()
|
||||
|
|
|
@ -5,7 +5,7 @@ import sys
|
|||
try:
|
||||
import nose
|
||||
except ImportError:
|
||||
sys.stderr.write("Unable to run python tests: the third party 'nose' module is required\nTo install 'nose' do:\n\tsudo pip install nose (or on debian systems: apt-get install python-nose\n")
|
||||
sys.stderr.write("Unable to run python tests: the third party 'nose' module is required\nTo install 'nose' do:\n\tsudo pip install nose (or on debian systems: apt-get install python-nose)\n")
|
||||
sys.exit(1)
|
||||
|
||||
from python_tests.utilities import TodoPlugin
|
||||
|
|
3
tests/visual_tests/data/marker-multi-policy.csv
Normal file
3
tests/visual_tests/data/marker-multi-policy.csv
Normal file
|
@ -0,0 +1,3 @@
|
|||
i|wkt
|
||||
1|MULTIPOLYGON(((90 40,50 0,10 40,50 80,90 40)),((190 40,150 0,110 40,150 80,190 40)),((190 140,150 100,110 140,150 180,190 140)))
|
||||
2|MULTIPOLYGON(((48 130,40 122,32 130,40 138,48 130)),((40 140,20 120,0 140,20 160,40 140)),((48 150,40 142,32 150,40 158,48 150)))
|
|
2
tests/visual_tests/data/marker-on-line.csv
Normal file
2
tests/visual_tests/data/marker-on-line.csv
Normal file
|
@ -0,0 +1,2 @@
|
|||
i|wkt
|
||||
1|LINESTRING(-10 0, 0 20, 10 0, 15 5)
|
|
2
tests/visual_tests/data/whole-centroid.csv
Normal file
2
tests/visual_tests/data/whole-centroid.csv
Normal file
File diff suppressed because one or more lines are too long
BIN
tests/visual_tests/images/marker-multi-policy-600-reference.png
Normal file
BIN
tests/visual_tests/images/marker-multi-policy-600-reference.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 8.4 KiB |
BIN
tests/visual_tests/images/marker-on-line-600-reference.png
Normal file
BIN
tests/visual_tests/images/marker-on-line-600-reference.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 3.7 KiB |
Binary file not shown.
After Width: | Height: | Size: 2.3 KiB |
BIN
tests/visual_tests/images/whole-centroid-600-reference.png
Normal file
BIN
tests/visual_tests/images/whole-centroid-600-reference.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 14 KiB |
36
tests/visual_tests/styles/marker-multi-policy.xml
Normal file
36
tests/visual_tests/styles/marker-multi-policy.xml
Normal file
|
@ -0,0 +1,36 @@
|
|||
<Map maximum-extent="0,0,190,180">
|
||||
<Style name="each">
|
||||
<Rule>
|
||||
<Filter>[i] = 1</Filter>
|
||||
<MarkersSymbolizer placement="point" fill="red" width="30" allow-overlap="true"/>
|
||||
</Rule>
|
||||
</Style>
|
||||
<Style name="whole">
|
||||
<Rule>
|
||||
<Filter>[i] = 1</Filter>
|
||||
<MarkersSymbolizer placement="point" multi-policy="whole" fill="yellow" width="20" allow-overlap="true"/>
|
||||
</Rule>
|
||||
</Style>
|
||||
<Style name="largest">
|
||||
<Rule>
|
||||
<Filter>[i] = 2</Filter>
|
||||
<MarkersSymbolizer placement="point" multi-policy="largest" fill="blue" width="10" allow-overlap="true"/>
|
||||
</Rule>
|
||||
</Style>
|
||||
<Style name="boundary">
|
||||
<Rule>
|
||||
<LineSymbolizer />
|
||||
</Rule>
|
||||
</Style>
|
||||
<Layer name="multi">
|
||||
<StyleName>boundary</StyleName>
|
||||
<StyleName>each</StyleName>
|
||||
<StyleName>whole</StyleName>
|
||||
<StyleName>largest</StyleName>
|
||||
<Datasource>
|
||||
<Parameter name="type">csv</Parameter>
|
||||
<Parameter name="file">../data/marker-multi-policy.csv</Parameter>
|
||||
<Parameter name="separator">|</Parameter>
|
||||
</Datasource>
|
||||
</Layer>
|
||||
</Map>
|
21
tests/visual_tests/styles/marker-on-line.xml
Normal file
21
tests/visual_tests/styles/marker-on-line.xml
Normal file
|
@ -0,0 +1,21 @@
|
|||
<Map>
|
||||
<Style name="line" filter-mode="first" >
|
||||
<Rule>
|
||||
<LineSymbolizer stroke="#000000" />
|
||||
</Rule>
|
||||
</Style>
|
||||
<Style name="point-placement" filter-mode="first" >
|
||||
<Rule>
|
||||
<MarkersSymbolizer placement="point" marker-type="ellipse" fill="blue" />
|
||||
</Rule>
|
||||
</Style>
|
||||
<Layer name="carto_tests">
|
||||
<StyleName>line</StyleName>
|
||||
<StyleName>point-placement</StyleName>
|
||||
<Datasource>
|
||||
<Parameter name="type">csv</Parameter>
|
||||
<Parameter name="file">../data/marker-on-line.csv</Parameter>
|
||||
<Parameter name="separator">|</Parameter>
|
||||
</Datasource>
|
||||
</Layer>
|
||||
</Map>
|
|
@ -0,0 +1,36 @@
|
|||
<!DOCTYPE Map>
|
||||
<Map background-color="white" srs="+init=epsg:4326" minimum-version="0.7.2">
|
||||
|
||||
<Style name="1">
|
||||
<Rule>
|
||||
<Filter>[id]=1</Filter>
|
||||
<MarkersSymbolizer fill="darkgreen" opacity=".7" width="15" height="10" stroke="green" stroke-width="7" stroke-opacity=".2" placement="line" marker-type="ellipse"/>
|
||||
</Rule>
|
||||
<Rule>
|
||||
<Filter>[id]=2</Filter>
|
||||
<MarkersSymbolizer fill="darkorange" opacity=".7" width="20" height="10" stroke="orange" stroke-width="7" stroke-opacity=".2" placement="line" marker-type="ellipse"/>
|
||||
</Rule>
|
||||
<Rule>
|
||||
<Filter>[id]=3</Filter>
|
||||
<MarkersSymbolizer fill="darkred" opacity=".7" width="20" height="10" stroke="orange" stroke-width="7" stroke-opacity=".2" placement="line" marker-type="ellipse"/>
|
||||
</Rule>
|
||||
</Style>
|
||||
<Layer name="point" srs="+init=epsg:4326">
|
||||
<StyleName>1</StyleName>
|
||||
<Datasource>
|
||||
<Parameter name="type">csv</Parameter>
|
||||
<Parameter name="inline">
|
||||
x,y,id
|
||||
0,0,1
|
||||
5,0,1
|
||||
5,5,1
|
||||
0,5,1
|
||||
2.5,2.5,2
|
||||
2.5,3,3
|
||||
2.5,2,3
|
||||
3,2.5,3
|
||||
2,2.5,3
|
||||
</Parameter>
|
||||
</Datasource>
|
||||
</Layer>
|
||||
</Map>
|
21
tests/visual_tests/styles/whole-centroid.xml
Normal file
21
tests/visual_tests/styles/whole-centroid.xml
Normal file
|
@ -0,0 +1,21 @@
|
|||
<Map maximum-extent="736908, 4390316, 2060771, 5942346">
|
||||
<Style name="whole">
|
||||
<Rule>
|
||||
<MarkersSymbolizer placement="point" multi-policy="whole" fill="yellow" width="20" allow-overlap="true"/>
|
||||
</Rule>
|
||||
</Style>
|
||||
<Style name="boundary">
|
||||
<Rule>
|
||||
<LineSymbolizer />
|
||||
</Rule>
|
||||
</Style>
|
||||
<Layer name="multi">
|
||||
<StyleName>boundary</StyleName>
|
||||
<StyleName>whole</StyleName>
|
||||
<Datasource>
|
||||
<Parameter name="type">csv</Parameter>
|
||||
<Parameter name="file">../data/whole-centroid.csv</Parameter>
|
||||
<Parameter name="separator">|</Parameter>
|
||||
</Datasource>
|
||||
</Layer>
|
||||
</Map>
|
|
@ -27,6 +27,14 @@ files = [
|
|||
{'name': "lines-2", 'sizes': sizes_few_square},
|
||||
{'name': "lines-3", 'sizes': sizes_few_square},
|
||||
{'name': "lines-shield", 'sizes': sizes_few_square},
|
||||
{'name': "marker-multi-policy", 'sizes':[(600,400)],
|
||||
'bbox': mapnik.Box2d(0, 0, 190, 180)},
|
||||
{'name': "marker-on-line", 'sizes':[(600,400)],
|
||||
'bbox': mapnik.Box2d(-10, 0, 15, 20)},
|
||||
{'name': "marker_line_placement_on_points", 'sizes':[(500,100)],
|
||||
'bbox': mapnik.Box2d(0, 0, 5, 5)},
|
||||
{'name': "whole-centroid", 'sizes':[(600,400)],
|
||||
'bbox': mapnik.Box2d(736908, 4390316, 2060771, 5942346)},
|
||||
{'name': "simple-E"},
|
||||
{'name': "simple-NE"},
|
||||
{'name': "simple-NW"},
|
||||
|
|
Loading…
Reference in a new issue