Merge branch 'master' of github.com:mapnik/mapnik

This commit is contained in:
Dane Springmeyer 2012-05-03 21:56:55 -04:00
commit f556aa14a6
55 changed files with 1167 additions and 616 deletions

View file

@ -9,6 +9,12 @@ For a complete change history, see the SVN log.
## Mapnik 2.1.0 ## Mapnik 2.1.0
- PostGIS: Added 'simplify_geometries' option - will trigger ST_Simplify on geometries before returning to Mapnik (#1179)
- Improved error feedback for invalid values passed to map.query_point
- Fixed rendering of thin svg lines (#1129)
- Improved logging/debugging system with release logs and file redirection (#937 and partially #986, #467) - Improved logging/debugging system with release logs and file redirection (#937 and partially #986, #467)
- GDAL: allow setting nodata value on the fly (will override value if nodata is set in data) (#1161) - GDAL: allow setting nodata value on the fly (will override value if nodata is set in data) (#1161)

View file

@ -18,7 +18,7 @@ uninstall:
python scons/scons.py uninstall python scons/scons.py uninstall
test: test:
@echo "*** Running visual tests" @echo "*** Running visual tests..."
@python tests/visual_tests/test.py -q @python tests/visual_tests/test.py -q
@echo "*** Running C++ tests..." @echo "*** Running C++ tests..."
@for FILE in tests/cpp_tests/*-bin; do \ @for FILE in tests/cpp_tests/*-bin; do \

View file

@ -96,7 +96,7 @@ PLUGINS = { # plugins with external dependencies
'rasterlite': {'default':False,'path':'RASTERLITE','inc':['sqlite3.h','rasterlite.h'],'lib':'rasterlite','lang':'C'}, 'rasterlite': {'default':False,'path':'RASTERLITE','inc':['sqlite3.h','rasterlite.h'],'lib':'rasterlite','lang':'C'},
# todo: osm plugin does also depend on libxml2 (but there is a separate check for that) # todo: osm plugin does also depend on libxml2 (but there is a separate check for that)
'osm': {'default':False,'path':None,'inc':'curl/curl.h','lib':'curl','lang':'C'}, 'osm': {'default':True,'path':None,'inc':'curl/curl.h','lib':'curl','lang':'C'},
# plugins without external dependencies requiring CheckLibWithHeader... # plugins without external dependencies requiring CheckLibWithHeader...
'shape': {'default':True,'path':None,'inc':None,'lib':None,'lang':'C++'}, 'shape': {'default':True,'path':None,'inc':None,'lib':None,'lang':'C++'},
@ -242,7 +242,6 @@ else:
LIBDIR_SCHEMA='lib' LIBDIR_SCHEMA='lib'
def pretty_dep(dep): def pretty_dep(dep):
pretty = pretty_dep_names.get(dep) pretty = pretty_dep_names.get(dep)
if pretty: if pretty:

View file

@ -23,6 +23,7 @@
#include <boost/python.hpp> #include <boost/python.hpp>
#include <mapnik/debug.hpp> #include <mapnik/debug.hpp>
#include <mapnik/utils.hpp> #include <mapnik/utils.hpp>
#include "mapnik_enumeration.hpp"
void export_logger() void export_logger()
{ {
@ -37,6 +38,15 @@ void export_logger()
.staticmethod("instance") .staticmethod("instance")
; ;
enum_<mapnik::logger::severity_type>("severity_type")
.value("Info", logger::info)
.value("Debug", logger::debug)
.value("Warn", logger::warn)
.value("Error", logger::error)
.value("Fatal", logger::fatal)
.value("None", logger::none)
;
class_<logger,bases<singleton<logger,CreateStatic> >, class_<logger,bases<singleton<logger,CreateStatic> >,
boost::noncopyable>("logger",no_init) boost::noncopyable>("logger",no_init)
.def_readonly("Info", logger::info) .def_readonly("Info", logger::info)

View file

@ -124,5 +124,15 @@ void export_markers_symbolizer()
&markers_symbolizer::get_height, &markers_symbolizer::get_height,
&markers_symbolizer::set_height, &markers_symbolizer::set_height,
"Set/get the marker height") "Set/get the marker height")
.add_property("fill",
make_function(&markers_symbolizer::get_fill,
return_value_policy<copy_const_reference>()),
&markers_symbolizer::set_fill,
"Set/get the marker fill color")
.add_property("stroke",
make_function(&markers_symbolizer::get_stroke,
return_value_policy<copy_const_reference>()),
&markers_symbolizer::set_stroke,
"Set/get the marker stroke (outline)")
; ;
} }

View file

@ -102,7 +102,7 @@ void export_style()
.add_property("filter_mode", .add_property("filter_mode",
&feature_type_style::get_filter_mode, &feature_type_style::get_filter_mode,
&feature_type_style::set_filter_mode, &feature_type_style::set_filter_mode,
"Set/get the placement of the label") "Set/get the filter mode of the style")
; ;
} }

View file

@ -44,6 +44,10 @@
namespace mapnik { namespace mapnik {
/*
Global logger class that holds the configuration of severity, format
and file/console redirection.
*/
class MAPNIK_DECL logger : class MAPNIK_DECL logger :
public singleton<logger,CreateStatic>, public singleton<logger,CreateStatic>,
private boost::noncopyable private boost::noncopyable
@ -153,6 +157,9 @@ namespace mapnik {
namespace detail { namespace detail {
/*
Default sink, it regulates access to clog
*/
template<class Ch, class Tr, class A> template<class Ch, class Tr, class A>
class clog_sink class clog_sink
{ {
@ -170,6 +177,12 @@ namespace mapnik {
}; };
/*
Base log class, should not log anything when no MAPNIK_LOG is defined
This is used for info/debug/warn reporting that should not output
anything when not compiling for speed.
*/
template<template <class Ch, class Tr, class A> class OutputPolicy, template<template <class Ch, class Tr, class A> class OutputPolicy,
logger::severity_type Severity, logger::severity_type Severity,
class Ch = char, class Ch = char,
@ -223,14 +236,67 @@ namespace mapnik {
#endif #endif
}; };
/*
Base log class that always log, regardless of MAPNIK_LOG.
This is used for error/fatal reporting that should always log something
*/
template<template <class Ch, class Tr, class A> class OutputPolicy,
logger::severity_type Severity,
class Ch = char,
class Tr = std::char_traits<Ch>,
class A = std::allocator<Ch> >
class base_log_always : public boost::noncopyable
{
public:
typedef OutputPolicy<Ch, Tr, A> output_policy;
base_log_always() {}
base_log_always(const char* object_name)
{
if (object_name != NULL)
{
object_name_ = object_name;
}
}
~base_log_always()
{
if (check_severity())
{
output_policy()(Severity, streambuf_);
}
}
template<class T>
base_log_always &operator<<(const T &x)
{
streambuf_ << x;
return *this;
}
private:
inline bool check_severity()
{
return Severity >= logger::get_object_severity(object_name_);
}
typename output_policy::stream_buffer streambuf_;
std::string object_name_;
};
typedef base_log<clog_sink, logger::info> base_log_info; typedef base_log<clog_sink, logger::info> base_log_info;
typedef base_log<clog_sink, logger::debug> base_log_debug; typedef base_log<clog_sink, logger::debug> base_log_debug;
typedef base_log<clog_sink, logger::warn> base_log_warn; typedef base_log<clog_sink, logger::warn> base_log_warn;
typedef base_log<clog_sink, logger::error> base_log_error; typedef base_log_always<clog_sink, logger::error> base_log_error;
typedef base_log<clog_sink, logger::fatal> base_log_fatal; typedef base_log_always<clog_sink, logger::fatal> base_log_fatal;
} // namespace detail } // namespace detail
// real interfaces // real interfaces
class MAPNIK_DECL info : public detail::base_log_info { class MAPNIK_DECL info : public detail::base_log_info {
public: public:
@ -262,6 +328,7 @@ namespace mapnik {
fatal(const char* object_name) : detail::base_log_fatal(object_name) {} fatal(const char* object_name) : detail::base_log_fatal(object_name) {}
}; };
// logging helpers // logging helpers
#define MAPNIK_LOG_INFO(s) mapnik::info(#s) #define MAPNIK_LOG_INFO(s) mapnik::info(#s)
#define MAPNIK_LOG_DEBUG(s) mapnik::debug(#s) #define MAPNIK_LOG_DEBUG(s) mapnik::debug(#s)

View file

@ -141,9 +141,8 @@ struct expression_grammar : qi::grammar<Iterator, expr_node(), space_type>
using qi::_r1; using qi::_r1;
#if BOOST_VERSION > 104200 #if BOOST_VERSION > 104200
using qi::no_skip; using qi::no_skip;
#else
using qi::lexeme;
#endif #endif
using qi::lexeme;
using qi::_val; using qi::_val;
using qi::lit; using qi::lit;
using qi::int_; using qi::int_;

View file

@ -39,7 +39,8 @@ class layer_descriptor
public: public:
layer_descriptor(std::string const& name, std::string const& encoding) layer_descriptor(std::string const& name, std::string const& encoding)
: name_(name), : name_(name),
encoding_(encoding) {} encoding_(encoding),
desc_ar_() {}
layer_descriptor(layer_descriptor const& other) layer_descriptor(layer_descriptor const& other)
: name_(other.name_), : name_(other.name_),

View file

@ -266,7 +266,8 @@ class MAPNIK_DECL face_manager : private boost::noncopyable
public: public:
face_manager(T & engine) face_manager(T & engine)
: engine_(engine), : engine_(engine),
stroker_(engine_.create_stroker()) {} stroker_(engine_.create_stroker()),
face_ptr_cache_() {}
face_ptr get_face(std::string const& name) face_ptr get_face(std::string const& name)
{ {
@ -303,16 +304,19 @@ public:
face_set_ptr face_set = boost::make_shared<font_face_set>(); face_set_ptr face_set = boost::make_shared<font_face_set>();
for (std::vector<std::string>::const_iterator name = names.begin(); name != names.end(); ++name) for (std::vector<std::string>::const_iterator name = names.begin(); name != names.end(); ++name)
{ {
if (face_ptr face = get_face(*name)) face_ptr face = get_face(*name);
if (face)
{ {
face_set->add(face); face_set->add(face);
} }
#ifdef MAPNIK_LOG
else else
{ {
MAPNIK_LOG_ERROR(font_engine_freetype) MAPNIK_LOG_DEBUG(font_engine_freetype)
<< "Failed to find face '" << *name << "Failed to find face '" << *name
<< "' in font set '" << fset.get_name() << "'\n"; << "' in font set '" << fset.get_name() << "'\n";
} }
#endif
} }
return face_set; return face_set;
} }
@ -335,9 +339,9 @@ public:
} }
private: private:
face_ptr_cache_type face_ptr_cache_;
font_engine_type & engine_; font_engine_type & engine_;
stroker_ptr stroker_; stroker_ptr stroker_;
face_ptr_cache_type face_ptr_cache_;
}; };
template <typename T> template <typename T>

View file

@ -63,13 +63,13 @@ private:
unsigned width_; unsigned width_;
unsigned height_; unsigned height_;
std::string key_; std::string key_;
feature_key_type f_keys_;
feature_type features_;
data_type data_; data_type data_;
std::set<std::string> names_;
unsigned int resolution_; unsigned int resolution_;
std::string id_name_; std::string id_name_;
bool painted_; bool painted_;
std::set<std::string> names_;
feature_key_type f_keys_;
feature_type features_;
public: public:
@ -80,7 +80,10 @@ public:
data_(width,height), data_(width,height),
resolution_(resolution), resolution_(resolution),
id_name_("__id__"), id_name_("__id__"),
painted_(false) painted_(false),
names_(),
f_keys_(),
features_()
{ {
// this only works if each datasource's // this only works if each datasource's
// feature count starts at 1 // feature count starts at 1
@ -94,7 +97,10 @@ public:
data_(rhs.data_), data_(rhs.data_),
resolution_(rhs.resolution_), resolution_(rhs.resolution_),
id_name_("__id__"), id_name_("__id__"),
painted_(rhs.painted_) painted_(rhs.painted_),
names_(rhs.names_),
f_keys_(rhs.f_keys_),
features_(rhs.features_)
{ {
f_keys_[0] = ""; f_keys_[0] = "";
} }

View file

@ -23,6 +23,12 @@
#ifndef MAPNIK_IMAGE_COMPOSITING_HPP #ifndef MAPNIK_IMAGE_COMPOSITING_HPP
#define MAPNIK_IMAGE_COMPOSITING_HPP #define MAPNIK_IMAGE_COMPOSITING_HPP
#include <mapnik/config.hpp>
#ifdef _MSC_VER
#include <mapnik/image_data.hpp>
#endif
// agg // agg
namespace mapnik namespace mapnik
@ -64,7 +70,11 @@ enum composite_mode_e
}; };
template <typename T1, typename T2> template <typename T1, typename T2>
void composite(T1 & im, T2 & im2, composite_mode_e mode); MAPNIK_DECL void composite(T1 & im, T2 & im2, composite_mode_e mode);
#ifdef _MSC_VER
template MAPNIK_DECL void composite<mapnik::image_data_32,mapnik::image_data_32>(mapnik::image_data_32 & im, mapnik::image_data_32 & im2, composite_mode_e mode);
#endif
} }
#endif // MAPNIK_IMAGE_COMPOSITING_HPP #endif // MAPNIK_IMAGE_COMPOSITING_HPP

View file

@ -23,6 +23,7 @@
#ifndef MAPNIK_GEOJSON_GENERATOR_HPP #ifndef MAPNIK_GEOJSON_GENERATOR_HPP
#define MAPNIK_GEOJSON_GENERATOR_HPP #define MAPNIK_GEOJSON_GENERATOR_HPP
#include <mapnik/config.hpp>
#include <mapnik/feature.hpp> #include <mapnik/feature.hpp>
#include <boost/scoped_ptr.hpp> #include <boost/scoped_ptr.hpp>
#include <boost/utility.hpp> #include <boost/utility.hpp>
@ -35,7 +36,7 @@ namespace mapnik { namespace json {
template <typename OutputIterator> struct feature_generator_grammar; template <typename OutputIterator> struct feature_generator_grammar;
template <typename OutputIterator> struct multi_geometry_generator_grammar; template <typename OutputIterator> struct multi_geometry_generator_grammar;
class feature_generator : private boost::noncopyable class MAPNIK_DECL feature_generator : private boost::noncopyable
{ {
typedef std::back_insert_iterator<std::string> sink_type; typedef std::back_insert_iterator<std::string> sink_type;
public: public:
@ -46,7 +47,7 @@ private:
boost::scoped_ptr<feature_generator_grammar<sink_type> > grammar_; boost::scoped_ptr<feature_generator_grammar<sink_type> > grammar_;
}; };
class geometry_generator : private boost::noncopyable class MAPNIK_DECL geometry_generator : private boost::noncopyable
{ {
typedef std::back_insert_iterator<std::string> sink_type; typedef std::back_insert_iterator<std::string> sink_type;
public: public:
@ -59,7 +60,7 @@ private:
#else #else
class feature_generator : private boost::noncopyable class MAPNIK_DECL feature_generator : private boost::noncopyable
{ {
public: public:
feature_generator() {} feature_generator() {}
@ -67,7 +68,7 @@ public:
bool generate(std::string & geojson, mapnik::Feature const& f); bool generate(std::string & geojson, mapnik::Feature const& f);
}; };
class geometry_generator : private boost::noncopyable class MAPNIK_DECL geometry_generator : private boost::noncopyable
{ {
public: public:
geometry_generator() {} geometry_generator() {}

View file

@ -140,7 +140,7 @@ class label_collision_detector4 : boost::noncopyable
public: public:
struct label struct label
{ {
label(box2d<double> const& b) : box(b) {} label(box2d<double> const& b) : box(b), text() {}
label(box2d<double> const& b, UnicodeString const& t) : box(b), text(t) {} label(box2d<double> const& b, UnicodeString const& t) : box(b), text(t) {}
box2d<double> box; box2d<double> box;

View file

@ -50,13 +50,18 @@ public:
typedef std::map<std::string, UnicodeString> property_map; typedef std::map<std::string, UnicodeString> property_map;
typedef property_map::const_iterator const_iterator; typedef property_map::const_iterator const_iterator;
metawriter_property_map() {} metawriter_property_map() :
m_(),
not_found_() {}
UnicodeString const& operator[](std::string const& key) const; UnicodeString const& operator[](std::string const& key) const;
UnicodeString& operator[](std::string const& key) {return m_[key];} UnicodeString& operator[](std::string const& key) {return m_[key];}
std::map<std::string, UnicodeString>::const_iterator find(std::string const& key) const std::map<std::string, UnicodeString>::const_iterator find(std::string const& key) const
{ {
return m_.find(key); return m_.find(key);
} }
std::map<std::string, UnicodeString>::const_iterator end() const std::map<std::string, UnicodeString>::const_iterator end() const
{ {
return m_.end(); return m_.end();
@ -66,6 +71,7 @@ public:
{ {
return (*this)[key]; return (*this)[key];
} }
private: private:
property_map m_; property_map m_;
UnicodeString not_found_; UnicodeString not_found_;

View file

@ -80,17 +80,22 @@ struct rgba
byte a; byte a;
inline rgba(byte r_, byte g_, byte b_, byte a_) inline rgba(byte r_, byte g_, byte b_, byte a_)
: r(r_), g(g_), b(b_), a(a_) {} : r(r_),
g(g_),
b(b_),
a(a_) {}
inline rgba(rgb const& c) inline rgba(rgb const& c)
: r(c.r), g(c.g), b(c.b), a(0xFF) {} : r(c.r),
g(c.g),
b(c.b),
a(0xFF) {}
inline rgba(unsigned const& c) { inline rgba(unsigned const& c)
r = U2RED(c); : r(U2RED(c)),
g = U2GREEN(c); g(U2GREEN(c)),
b = U2BLUE(c); b(U2BLUE(c)),
a = U2ALPHA(c); a(U2ALPHA(c)) {}
}
inline bool operator==(const rgba& y) const inline bool operator==(const rgba& y) const
{ {

View file

@ -86,23 +86,20 @@ class quad_tree : boost::noncopyable
typedef typename node::cont_t cont_t; typedef typename node::cont_t cont_t;
typedef typename cont_t::iterator node_data_iterator; typedef typename cont_t::iterator node_data_iterator;
nodes_t nodes_;
node * root_;
const unsigned int max_depth_;
const double ratio_;
public: public:
typedef typename nodes_t::iterator iterator; typedef typename nodes_t::iterator iterator;
typedef typename nodes_t::const_iterator const_iterator; typedef typename nodes_t::const_iterator const_iterator;
typedef typename boost::ptr_vector<T,boost::view_clone_allocator> result_t; typedef typename boost::ptr_vector<T,boost::view_clone_allocator> result_t;
typedef typename result_t::iterator query_iterator; typedef typename result_t::iterator query_iterator;
result_t query_result_;
explicit quad_tree(box2d<double> const& ext, explicit quad_tree(box2d<double> const& ext,
unsigned int max_depth = 8, unsigned int max_depth = 8,
double ratio = 0.55) double ratio = 0.55)
: max_depth_(max_depth), : max_depth_(max_depth),
ratio_(ratio) ratio_(ratio),
query_result_(),
nodes_()
{ {
nodes_.push_back(new node(ext)); nodes_.push_back(new node(ext));
root_ = &nodes_[0]; root_ = &nodes_[0];
@ -219,6 +216,13 @@ private:
ext[2]=box2d<double>(lox,hiy - height*ratio_,lox + width * ratio_,hiy); ext[2]=box2d<double>(lox,hiy - height*ratio_,lox + width * ratio_,hiy);
ext[3]=box2d<double>(hix - width * ratio_,hiy - height*ratio_,hix,hiy); ext[3]=box2d<double>(hix - width * ratio_,hiy - height*ratio_,hix,hiy);
} }
const unsigned int max_depth_;
const double ratio_;
result_t query_result_;
nodes_t nodes_;
node * root_;
}; };
} }

View file

@ -40,14 +40,6 @@ class query
{ {
public: public:
typedef boost::tuple<double,double> resolution_type; typedef boost::tuple<double,double> resolution_type;
private:
box2d<double> bbox_;
resolution_type resolution_;
double scale_denominator_;
double filter_factor_;
box2d<double> unbuffered_bbox_;
std::set<std::string> names_;
public:
query(box2d<double> const& bbox, query(box2d<double> const& bbox,
resolution_type const& resolution, resolution_type const& resolution,
@ -57,7 +49,8 @@ public:
resolution_(resolution), resolution_(resolution),
scale_denominator_(scale_denominator), scale_denominator_(scale_denominator),
filter_factor_(1.0), filter_factor_(1.0),
unbuffered_bbox_(unbuffered_bbox) unbuffered_bbox_(unbuffered_bbox),
names_()
{} {}
query(box2d<double> const& bbox, query(box2d<double> const& bbox,
@ -67,7 +60,8 @@ public:
resolution_(resolution), resolution_(resolution),
scale_denominator_(scale_denominator), scale_denominator_(scale_denominator),
filter_factor_(1.0), filter_factor_(1.0),
unbuffered_bbox_(bbox) unbuffered_bbox_(bbox),
names_()
{} {}
query(box2d<double> const& bbox) query(box2d<double> const& bbox)
@ -75,7 +69,8 @@ public:
resolution_(resolution_type(1.0,1.0)), resolution_(resolution_type(1.0,1.0)),
scale_denominator_(1.0), scale_denominator_(1.0),
filter_factor_(1.0), filter_factor_(1.0),
unbuffered_bbox_(bbox) unbuffered_bbox_(bbox),
names_()
{} {}
query(query const& other) query(query const& other)
@ -94,8 +89,8 @@ public:
resolution_=other.resolution_; resolution_=other.resolution_;
scale_denominator_=other.scale_denominator_; scale_denominator_=other.scale_denominator_;
filter_factor_=other.filter_factor_; filter_factor_=other.filter_factor_;
names_=other.names_;
unbuffered_bbox_=other.unbuffered_bbox_; unbuffered_bbox_=other.unbuffered_bbox_;
names_=other.names_;
return *this; return *this;
} }
@ -119,12 +114,12 @@ public:
return unbuffered_bbox_; return unbuffered_bbox_;
} }
void set_unbuffered_bbox(const box2d<double>& bbox) void set_unbuffered_bbox(box2d<double> const& bbox)
{ {
unbuffered_bbox_ = bbox; unbuffered_bbox_ = bbox;
} }
void set_bbox(const box2d<double>& bbox) void set_bbox(box2d<double> const& bbox)
{ {
bbox_ = bbox; bbox_ = bbox;
} }
@ -148,6 +143,14 @@ public:
{ {
return names_; return names_;
} }
private:
box2d<double> bbox_;
resolution_type resolution_;
double scale_denominator_;
double filter_factor_;
box2d<double> unbuffered_bbox_;
std::set<std::string> names_;
}; };
} }

View file

@ -279,7 +279,8 @@ public:
{ {
ras.reset(); ras.reset();
if(fabs(curved_trans_contour.width()) < 0.0001) // https://github.com/mapnik/mapnik/issues/1129
if(fabs(curved_trans_contour.width()) <= 1)
{ {
ras.add_path(curved_trans, attr.index); ras.add_path(curved_trans, attr.index);
} }
@ -384,7 +385,7 @@ public:
{ {
ras.reset(); ras.reset();
if(fabs(curved_trans_contour.width()) < 0.0001) if(fabs(curved_trans_contour.width()) <= 1)
{ {
ras.add_path(curved_trans, attr.index); ras.add_path(curved_trans, attr.index);
} }

View file

@ -157,6 +157,6 @@ private:
std::string base_message_; std::string base_message_;
}; };
}; }
#endif // MAPNIK_TIMER_HPP #endif // MAPNIK_TIMER_HPP

View file

@ -29,16 +29,73 @@
// stl // stl
#include <string> #include <string>
// boost
#include <boost/version.hpp>
#if BOOST_VERSION >= 104500
#include <boost/config/warning_disable.hpp>
#include <boost/spirit/include/karma.hpp>
#else
#include <boost/lexical_cast.hpp>
#endif
namespace mapnik { namespace util { namespace mapnik { namespace util {
MAPNIK_DECL bool string2int(std::string const& value, int & result); MAPNIK_DECL bool string2int(const char * value, int & result);
MAPNIK_DECL bool string2int(const char * value, int & result); MAPNIK_DECL bool string2int(std::string const& value, int & result);
MAPNIK_DECL bool string2double(std::string const& value, double & result); MAPNIK_DECL bool string2double(std::string const& value, double & result);
MAPNIK_DECL bool string2double(const char * value, double & result); MAPNIK_DECL bool string2double(const char * value, double & result);
MAPNIK_DECL bool string2float(std::string const& value, float & result); MAPNIK_DECL bool string2float(std::string const& value, float & result);
MAPNIK_DECL bool string2float(const char * value, float & result); MAPNIK_DECL bool string2float(const char * value, float & result);
#if BOOST_VERSION >= 104500
// generic
template <typename T>
bool to_string(std::string & str, T value)
{
namespace karma = boost::spirit::karma;
std::back_insert_iterator<std::string> sink(str);
return karma::generate(sink, value);
}
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 ;}
};
// specialisation for double
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;
std::back_insert_iterator<std::string> sink(str);
return karma::generate(sink, double_type(), value);
}
#else
template <typename T>
bool to_string(std::string & str, T value)
{
try
{
str = boost::lexical_cast<T>(value);
return true;
}
catch (std::exception const& ex)
{
return false;
}
}
#endif
}} }}

View file

@ -46,7 +46,9 @@ namespace mapnik { namespace util {
typedef vertex_vector<T> container_type; typedef vertex_vector<T> container_type;
vertex_iterator() vertex_iterator()
: v_(SEG_END,0,0) : v_(SEG_END,0,0),
vertices_(),
pos_(0)
{} {}
explicit vertex_iterator(container_type const& vertices) explicit vertex_iterator(container_type const& vertices)
@ -74,8 +76,8 @@ namespace mapnik { namespace util {
return v_; return v_;
} }
container_type const *vertices_;
value_type v_; value_type v_;
container_type const *vertices_;
unsigned pos_; unsigned pos_;
}; };

View file

@ -36,8 +36,6 @@
// stl // stl
#include <iostream> #include <iostream>
#include <string> #include <string>
#include <sstream>
#include <iomanip>
#include <cmath> #include <cmath>
// uci // uci
@ -338,20 +336,34 @@ struct add : public boost::static_visitor<V>
return lhs + rhs; return lhs + rhs;
} }
value_type operator() (UnicodeString const& lhs, value_null rhs) const
{
boost::ignore_unused_variable_warning(rhs);
return lhs;
}
value_type operator() (value_null lhs, UnicodeString const& rhs) const
{
boost::ignore_unused_variable_warning(lhs);
return rhs;
}
template <typename R> template <typename R>
value_type operator() (UnicodeString const& lhs, R const& rhs) const value_type operator() (UnicodeString const& lhs, R const& rhs) const
{ {
std::basic_ostringstream<char> out; std::string val;
out << rhs; if (util::to_string(val,rhs))
return lhs + UnicodeString(out.str().c_str()); return lhs + UnicodeString(val.c_str());
return lhs;
} }
template <typename L> template <typename L>
value_type operator() (L const& lhs , UnicodeString const& rhs) const value_type operator() (L const& lhs , UnicodeString const& rhs) const
{ {
std::basic_ostringstream<char> out; std::string val;
out << lhs; if (util::to_string(val,lhs))
return UnicodeString(out.str().c_str()) + rhs; return UnicodeString(val.c_str()) + rhs;
return rhs;
} }
template <typename T1, typename T2> template <typename T1, typename T2>
@ -540,14 +552,14 @@ struct to_bool : public boost::static_visitor<bool>
struct to_string : public boost::static_visitor<std::string> struct to_string : public boost::static_visitor<std::string>
{ {
template <typename T> template <typename T>
std::string operator() (T val) const std::string operator() (T val) const
{ {
std::stringstream ss; std::string str;
ss << val; util::to_string(str, val);
return ss.str(); return str;
} }
// specializations // specializations
std::string operator() (UnicodeString const& val) const std::string operator() (UnicodeString const& val) const
{ {
@ -558,9 +570,9 @@ struct to_string : public boost::static_visitor<std::string>
std::string operator() (double val) const std::string operator() (double val) const
{ {
std::stringstream ss; std::string str;
ss << std::setprecision(16) << val; util::to_string(str, val); // TODO set precision(16)
return ss.str(); return str;
} }
std::string operator() (value_null const& val) const std::string operator() (value_null const& val) const
@ -576,9 +588,9 @@ struct to_unicode : public boost::static_visitor<UnicodeString>
template <typename T> template <typename T>
UnicodeString operator() (T val) const UnicodeString operator() (T val) const
{ {
std::basic_ostringstream<char> out; std::string str;
out << val; util::to_string(str,val);
return UnicodeString(out.str().c_str()); return UnicodeString(str.c_str());
} }
// specializations // specializations
@ -589,9 +601,9 @@ struct to_unicode : public boost::static_visitor<UnicodeString>
UnicodeString operator() (double val) const UnicodeString operator() (double val) const
{ {
std::basic_ostringstream<char> out; std::string str;
out << std::setprecision(16) << val; util::to_string(str,val);
return UnicodeString(out.str().c_str()); return UnicodeString(str.c_str());
} }
UnicodeString operator() (value_null const& val) const UnicodeString operator() (value_null const& val) const
@ -612,9 +624,9 @@ struct to_expression_string : public boost::static_visitor<std::string>
std::string operator() (double val) const std::string operator() (double val) const
{ {
std::stringstream ss; std::string output;
ss << std::setprecision(16) << val; util::to_string(output,val); // TODO precision(16)
return ss.str(); return output;
} }
std::string operator() (bool val) const std::string operator() (bool val) const
@ -651,17 +663,17 @@ struct to_double : public boost::static_visitor<double>
double operator() (std::string const& val) const double operator() (std::string const& val) const
{ {
double ret(0); double result;
mapnik::util::string2double(val,ret); if (util::string2double(val,result))
return ret; return result;
return 0;
} }
double operator() (UnicodeString const& val) const double operator() (UnicodeString const& val) const
{ {
std::string utf8; std::string utf8;
to_utf8(val,utf8); to_utf8(val,utf8);
double ret(0); return operator()(utf8);
mapnik::util::string2double(utf8,ret);
return ret;
} }
double operator() (value_null const& val) const double operator() (value_null const& val) const
@ -685,17 +697,17 @@ struct to_int : public boost::static_visitor<double>
int operator() (std::string const& val) const int operator() (std::string const& val) const
{ {
int ret(0); int result;
mapnik::util::string2int(val,ret); if (util::string2int(val,result))
return ret; return result;
return 0;
} }
int operator() (UnicodeString const& val) const int operator() (UnicodeString const& val) const
{ {
std::string utf8; std::string utf8;
to_utf8(val,utf8); to_utf8(val,utf8);
int ret(0); return operator()(utf8);
mapnik::util::string2int(utf8,ret);
return ret;
} }
int operator() (value_null const& val) const int operator() (value_null const& val) const

View file

@ -31,12 +31,14 @@ namespace mapnik {
class value_error : public std::exception class value_error : public std::exception
{ {
public: public:
value_error() {} value_error() :
what_() {}
value_error( std::string const& what ) : value_error( std::string const& what ) :
what_( what ) what_( what )
{ {
} }
virtual ~value_error() throw() {}; virtual ~value_error() throw() {};
virtual const char * what() const throw() virtual const char * what() const throw()

View file

@ -386,6 +386,9 @@ boost::optional<mapnik::datasource::geometry_t> ogr_datasource::get_geometry_typ
if (dataset_ && layer_.is_valid()) if (dataset_ && layer_.is_valid())
{ {
OGRLayer* layer = layer_.layer(); OGRLayer* layer = layer_.layer();
// only new either reset of setNext
//layer->ResetReading();
layer->SetNextByIndex(0);
ogr_feature_ptr feat(layer->GetNextFeature()); ogr_feature_ptr feat(layer->GetNextFeature());
if ((*feat) != NULL) if ((*feat) != NULL)
{ {

View file

@ -67,6 +67,7 @@ postgis_datasource::postgis_datasource(parameters const& params, bool bind)
type_(datasource::Vector), type_(datasource::Vector),
srid_(*params_.get<int>("srid", 0)), srid_(*params_.get<int>("srid", 0)),
extent_initialized_(false), extent_initialized_(false),
simplify_geometries_(false),
desc_(*params_.get<std::string>("type"), "utf-8"), desc_(*params_.get<std::string>("type"), "utf-8"),
creator_(params.get<std::string>("host"), creator_(params.get<std::string>("host"),
params.get<std::string>("port"), params.get<std::string>("port"),
@ -76,6 +77,8 @@ postgis_datasource::postgis_datasource(parameters const& params, bool bind)
params.get<std::string>("connect_timeout", "4")), params.get<std::string>("connect_timeout", "4")),
bbox_token_("!bbox!"), bbox_token_("!bbox!"),
scale_denom_token_("!scale_denominator!"), scale_denom_token_("!scale_denominator!"),
pixel_width_token_("!pixel_width!"),
pixel_height_token_("!pixel_height!"),
persist_connection_(*params_.get<mapnik::boolean>("persist_connection", true)), persist_connection_(*params_.get<mapnik::boolean>("persist_connection", true)),
extent_from_subquery_(*params_.get<mapnik::boolean>("extent_from_subquery", false)), extent_from_subquery_(*params_.get<mapnik::boolean>("extent_from_subquery", false)),
// params below are for testing purposes only (will likely be removed at any time) // params below are for testing purposes only (will likely be removed at any time)
@ -114,6 +117,9 @@ void postgis_datasource::bind() const
boost::optional<int> max_size = params_.get<int>("max_size", 10); boost::optional<int> max_size = params_.get<int>("max_size", 10);
boost::optional<mapnik::boolean> autodetect_key_field = params_.get<mapnik::boolean>("autodetect_key_field", false); boost::optional<mapnik::boolean> autodetect_key_field = params_.get<mapnik::boolean>("autodetect_key_field", false);
boost::optional<mapnik::boolean> simplify_opt = params_.get<mapnik::boolean>("simplify_geometries", false);
simplify_geometries_ = simplify_opt && *simplify_opt;
ConnectionManager* mgr = ConnectionManager::instance(); ConnectionManager* mgr = ConnectionManager::instance();
mgr->registerPool(creator_, *initial_size, *max_size); mgr->registerPool(creator_, *initial_size, *max_size);
@ -493,10 +499,24 @@ std::string postgis_datasource::populate_tokens(const std::string& sql) const
boost::algorithm::replace_all(populated_sql, scale_denom_token_, ss.str()); boost::algorithm::replace_all(populated_sql, scale_denom_token_, ss.str());
} }
if (boost::algorithm::icontains(sql, pixel_width_token_))
{
std::ostringstream ss;
ss << 0;
boost::algorithm::replace_all(populated_sql, pixel_width_token_, ss.str());
}
if (boost::algorithm::icontains(sql, pixel_height_token_))
{
std::ostringstream ss;
ss << 0;
boost::algorithm::replace_all(populated_sql, pixel_height_token_, ss.str());
}
return populated_sql; return populated_sql;
} }
std::string postgis_datasource::populate_tokens(const std::string& sql, double scale_denom, box2d<double> const& env) const std::string postgis_datasource::populate_tokens(const std::string& sql, double scale_denom, box2d<double> const& env, double pixel_width, double pixel_height) const
{ {
std::string populated_sql = sql; std::string populated_sql = sql;
std::string box = sql_bbox(env); std::string box = sql_bbox(env);
@ -508,6 +528,20 @@ std::string postgis_datasource::populate_tokens(const std::string& sql, double s
boost::algorithm::replace_all(populated_sql, scale_denom_token_, ss.str()); boost::algorithm::replace_all(populated_sql, scale_denom_token_, ss.str());
} }
if (boost::algorithm::icontains(sql, pixel_width_token_))
{
std::ostringstream ss;
ss << pixel_width;
boost::algorithm::replace_all(populated_sql, pixel_width_token_, ss.str());
}
if (boost::algorithm::icontains(sql, pixel_height_token_))
{
std::ostringstream ss;
ss << pixel_height;
boost::algorithm::replace_all(populated_sql, pixel_height_token_, ss.str());
}
if (boost::algorithm::icontains(populated_sql, bbox_token_)) if (boost::algorithm::icontains(populated_sql, bbox_token_))
{ {
boost::algorithm::replace_all(populated_sql, bbox_token_, box); boost::algorithm::replace_all(populated_sql, bbox_token_, box);
@ -607,7 +641,24 @@ featureset_ptr postgis_datasource::features(const query& q) const
} }
std::ostringstream s; std::ostringstream s;
s << "SELECT ST_AsBinary(\"" << geometryColumn_ << "\") AS geom";
const double px_gw = 1.0 / boost::get<0>(q.resolution());
const double px_gh = 1.0 / boost::get<1>(q.resolution());
s << "SELECT ST_AsBinary(";
if (simplify_geometries_) {
s << "ST_Simplify(";
}
s << "\"" << geometryColumn_ << "\"";
if (simplify_geometries_) {
const double tolerance = std::min(px_gw, px_gh) / 2.0;
s << ", " << tolerance << ")";
}
s << ") AS geom";
mapnik::context_ptr ctx = boost::make_shared<mapnik::context_type>(); mapnik::context_ptr ctx = boost::make_shared<mapnik::context_type>();
std::set<std::string> const& props = q.property_names(); std::set<std::string> const& props = q.property_names();
@ -637,7 +688,7 @@ featureset_ptr postgis_datasource::features(const query& q) const
} }
} }
std::string table_with_bbox = populate_tokens(table_, scale_denom, box); std::string table_with_bbox = populate_tokens(table_, scale_denom, box, px_gw, px_gh);
s << " FROM " << table_with_bbox; s << " FROM " << table_with_bbox;
@ -730,7 +781,7 @@ featureset_ptr postgis_datasource::features_at_point(coord2d const& pt) const
} }
box2d<double> box(pt.x, pt.y, pt.x, pt.y); box2d<double> box(pt.x, pt.y, pt.x, pt.y);
std::string table_with_bbox = populate_tokens(table_, FMAX, box); std::string table_with_bbox = populate_tokens(table_, FMAX, box, 0, 0);
s << " FROM " << table_with_bbox; s << " FROM " << table_with_bbox;

View file

@ -61,7 +61,7 @@ public:
private: private:
std::string sql_bbox(box2d<double> const& env) const; std::string sql_bbox(box2d<double> const& env) const;
std::string populate_tokens(const std::string& sql, double scale_denom, box2d<double> const& env) const; std::string populate_tokens(const std::string& sql, double scale_denom, box2d<double> const& env, double pixel_width, double pixel_height) const;
std::string populate_tokens(const std::string& sql) const; std::string populate_tokens(const std::string& sql) const;
static std::string unquote(const std::string& sql); static std::string unquote(const std::string& sql);
boost::shared_ptr<IResultSet> get_resultset(boost::shared_ptr<Connection> const &conn, std::string const& sql) const; boost::shared_ptr<IResultSet> get_resultset(boost::shared_ptr<Connection> const &conn, std::string const& sql) const;
@ -85,10 +85,13 @@ private:
mutable int srid_; mutable int srid_;
mutable bool extent_initialized_; mutable bool extent_initialized_;
mutable mapnik::box2d<double> extent_; mutable mapnik::box2d<double> extent_;
mutable bool simplify_geometries_;
mutable layer_descriptor desc_; mutable layer_descriptor desc_;
ConnectionCreator<Connection> creator_; ConnectionCreator<Connection> creator_;
const std::string bbox_token_; const std::string bbox_token_;
const std::string scale_denom_token_; const std::string scale_denom_token_;
const std::string pixel_width_token_;
const std::string pixel_height_token_;
bool persist_connection_; bool persist_connection_;
bool extent_from_subquery_; bool extent_from_subquery_;
// params below are for testing purposes only (will likely be removed at any time) // params below are for testing purposes only (will likely be removed at any time)

View file

@ -80,13 +80,8 @@ else:
else: else:
lib_env['LIBS'].append([lib for lib in env['LIBS'] if lib.startswith('agg')]) lib_env['LIBS'].append([lib for lib in env['LIBS'] if lib.startswith('agg')])
if env['PLATFORM'] == 'Darwin':
mapnik_libname = 'libmapnik.dylib'
else:
mapnik_libname = 'libmapnik.so.' + ("%d.%d" % (int(ABI_VERSION[0]),int(ABI_VERSION[1])))
if env['PLATFORM'] == 'Darwin': if env['PLATFORM'] == 'Darwin':
mapnik_libname = env.subst(env['MAPNIK_LIB_NAME'])
if env['FULL_LIB_PATH']: if env['FULL_LIB_PATH']:
lib_path = '%s/%s' % (env['MAPNIK_LIB_BASE'],mapnik_libname) lib_path = '%s/%s' % (env['MAPNIK_LIB_BASE'],mapnik_libname)
else: else:
@ -94,12 +89,14 @@ if env['PLATFORM'] == 'Darwin':
mapnik_lib_link_flag += ' -Wl,-install_name,%s' % lib_path mapnik_lib_link_flag += ' -Wl,-install_name,%s' % lib_path
_d = {'version':env['MAPNIK_VERSION_STRING'].replace('-pre','')} _d = {'version':env['MAPNIK_VERSION_STRING'].replace('-pre','')}
mapnik_lib_link_flag += ' -current_version %(version)s -compatibility_version %(version)s' % _d mapnik_lib_link_flag += ' -current_version %(version)s -compatibility_version %(version)s' % _d
elif env['PLATFORM'] == 'SunOS': else: # unix, non-macos
mapnik_libname = env.subst(env['MAPNIK_LIB_NAME']) + (".%d.%d" % (int(ABI_VERSION[0]),int(ABI_VERSION[1])))
if env['PLATFORM'] == 'SunOS':
if env['CXX'].startswith('CC'): if env['CXX'].startswith('CC'):
mapnik_lib_link_flag += ' -R. -h %s' % mapnik_libname mapnik_lib_link_flag += ' -R. -h %s' % mapnik_libname
else: else:
mapnik_lib_link_flag += ' -Wl,-h,%s' % mapnik_libname mapnik_lib_link_flag += ' -Wl,-h,%s' % mapnik_libname
else: # Linux and others else: # Linux and others
mapnik_lib_link_flag += ' -Wl,-rpath-link,. -Wl,-soname,%s' % mapnik_libname mapnik_lib_link_flag += ' -Wl,-rpath-link,. -Wl,-soname,%s' % mapnik_libname
source = Split( source = Split(
@ -324,16 +321,22 @@ if env['CUSTOM_LDFLAGS']:
else: else:
linkflags = mapnik_lib_link_flag linkflags = mapnik_lib_link_flag
if env['LINKING'] == 'static':
mapnik = lib_env.StaticLibrary('mapnik', source, LINKFLAGS=linkflags)
else:
mapnik = lib_env.SharedLibrary('mapnik', source, LINKFLAGS=linkflags)
# cache library values for other builds to use # cache library values for other builds to use
env['LIBMAPNIK_LIBS'] = copy(lib_env['LIBS']) env['LIBMAPNIK_LIBS'] = copy(lib_env['LIBS'])
env['LIBMAPNIK_CXXFLAGS'] = libmapnik_cxxflags env['LIBMAPNIK_CXXFLAGS'] = libmapnik_cxxflags
if env['PLATFORM'] != 'Darwin': if env['PLATFORM'] == 'Darwin':
target_path = env['MAPNIK_LIB_BASE_DEST']
if 'uninstall' not in COMMAND_LINE_TARGETS:
if env['LINKING'] == 'static':
mapnik = lib_env.StaticLibrary('mapnik', source, LINKFLAGS=linkflags)
else:
mapnik = lib_env.SharedLibrary('mapnik', source, LINKFLAGS=linkflags)
result = env.Install(target_path, mapnik)
env.Alias(target='install', source=result)
env['create_uninstall_target'](env, os.path.join(target_path,env.subst(env['MAPNIK_LIB_NAME'])))
else:
# Symlink command, only works if both files are in same directory # Symlink command, only works if both files are in same directory
def symlink(env, target, source): def symlink(env, target, source):
trgt = str(target[0]) trgt = str(target[0])
@ -345,10 +348,14 @@ if env['PLATFORM'] != 'Darwin':
major, minor, micro = ABI_VERSION major, minor, micro = ABI_VERSION
soFile = "%s.%d.%d.%d" % (os.path.basename(str(mapnik[0])), int(major), int(minor), int(micro)) soFile = "%s.%d.%d.%d" % (os.path.basename(env.subst(env['MAPNIK_LIB_NAME'])), int(major), int(minor), int(micro))
target = os.path.join(env['MAPNIK_LIB_BASE_DEST'], soFile) target = os.path.join(env['MAPNIK_LIB_BASE_DEST'], soFile)
if 'uninstall' not in COMMAND_LINE_TARGETS: if 'uninstall' not in COMMAND_LINE_TARGETS:
if env['LINKING'] == 'static':
mapnik = lib_env.StaticLibrary('mapnik', source, LINKFLAGS=linkflags)
else:
mapnik = lib_env.SharedLibrary('mapnik', source, LINKFLAGS=linkflags)
result = env.InstallAs(target=target, source=mapnik) result = env.InstallAs(target=target, source=mapnik)
env.Alias(target='install', source=result) env.Alias(target='install', source=result)
if result: if result:
@ -356,10 +363,10 @@ if env['PLATFORM'] != 'Darwin':
# Install symlinks # Install symlinks
target1 = os.path.join(env['MAPNIK_LIB_BASE_DEST'], "%s.%d.%d" % (os.path.basename(str(mapnik[0])),int(major), int(minor))) target1 = os.path.join(env['MAPNIK_LIB_BASE_DEST'], "%s.%d.%d" % \
target2 = os.path.join(env['MAPNIK_LIB_BASE_DEST'], os.path.basename(str(mapnik[0]))) (os.path.basename(env.subst(env['MAPNIK_LIB_NAME'])),int(major), int(minor)))
target2 = os.path.join(env['MAPNIK_LIB_BASE_DEST'], os.path.basename(env.subst(env['MAPNIK_LIB_NAME'])))
if 'uninstall' not in COMMAND_LINE_TARGETS: if 'uninstall' not in COMMAND_LINE_TARGETS:
if 'install' in COMMAND_LINE_TARGETS:
link1 = env.Command(target1, target, symlink) link1 = env.Command(target1, target, symlink)
env.Alias(target='install', source=link1) env.Alias(target='install', source=link1)
link2 = env.Command(target2, target1, symlink) link2 = env.Command(target2, target1, symlink)
@ -369,14 +376,6 @@ if env['PLATFORM'] != 'Darwin':
env['create_uninstall_target'](env, target1) env['create_uninstall_target'](env, target1)
env['create_uninstall_target'](env, target) env['create_uninstall_target'](env, target)
else:
target_path = env['MAPNIK_LIB_BASE_DEST']
if 'uninstall' not in COMMAND_LINE_TARGETS:
result = env.Install(target_path, mapnik)
env.Alias(target='install', source=result)
env['create_uninstall_target'](env, os.path.join(target_path,mapnik_libname))
includes = glob.glob('../include/mapnik/*.hpp') includes = glob.glob('../include/mapnik/*.hpp')
svg_includes = glob.glob('../include/mapnik/svg/*.hpp') svg_includes = glob.glob('../include/mapnik/svg/*.hpp')
wkt_includes = glob.glob('../include/mapnik/wkt/*.hpp') wkt_includes = glob.glob('../include/mapnik/wkt/*.hpp')

View file

@ -102,10 +102,14 @@ bool freetype_engine::register_font(std::string const& file_name)
// http://www.freetype.org/freetype2/docs/reference/ft2-base_interface.html#FT_FaceRec // http://www.freetype.org/freetype2/docs/reference/ft2-base_interface.html#FT_FaceRec
if (face->family_name && face->style_name) if (face->family_name && face->style_name)
{ {
success = true;
std::string name = std::string(face->family_name) + " " + std::string(face->style_name); std::string name = std::string(face->family_name) + " " + std::string(face->style_name);
// skip fonts with leading . in name
if (!boost::algorithm::starts_with(name,"."))
{
success = true;
name2file_.insert(std::make_pair(name, std::make_pair(i,file_name))); name2file_.insert(std::make_pair(name, std::make_pair(i,file_name)));
} }
}
else else
{ {
std::ostringstream s; std::ostringstream s;
@ -142,19 +146,29 @@ bool freetype_engine::register_fonts(std::string const& dir, bool recurse)
for (boost::filesystem::directory_iterator itr(dir); itr != end_itr; ++itr) for (boost::filesystem::directory_iterator itr(dir); itr != end_itr; ++itr)
{ {
#if (BOOST_FILESYSTEM_VERSION == 3) #if (BOOST_FILESYSTEM_VERSION == 3)
std::string const& file_name = itr->path().string(); std::string file_name = itr->path().string();
#else // v2 #else // v2
std::string const& file_name = itr->string(); std::string file_name = itr->string();
#endif #endif
if (boost::filesystem::is_directory(*itr) && recurse) if (boost::filesystem::is_directory(*itr) && recurse)
{ {
success = register_fonts(file_name, true); success = register_fonts(file_name, true);
} }
else if (boost::filesystem::is_regular_file(file_name) && is_font_file(file_name)) else
{
#if (BOOST_FILESYSTEM_VERSION == 3)
std::string base_name = itr->path().filename().string();
#else // v2
std::string base_name = itr->filename();
#endif
if (!boost::algorithm::starts_with(base_name,".") &&
boost::filesystem::is_regular_file(file_name) &&
is_font_file(file_name))
{ {
success = mapnik::freetype_engine::register_font(file_name); success = mapnik::freetype_engine::register_font(file_name);
} }
} }
}
return success; return success;
} }

View file

@ -135,11 +135,15 @@ public:
xmlError * error = xmlCtxtGetLastError( ctx_ ); xmlError * error = xmlCtxtGetLastError( ctx_ );
std::ostringstream os; std::ostringstream os;
os << "XML document not well formed"; os << "XML document not well formed";
int line=0;
std::string file;
if (error) if (error)
{ {
os << ": " << std::endl << error->message; os << ": " << std::endl << error->message;
line = error->line;
file = error->file;
} }
throw config_error(os.str(), error->line, error->file); throw config_error(os.str(), line, file);
} }
int iXIncludeReturn = xmlXIncludeProcessFlags(doc, options_); int iXIncludeReturn = xmlXIncludeProcessFlags(doc, options_);

View file

@ -98,7 +98,7 @@ private:
void parse_metawriter_in_symbolizer(symbolizer_base &sym, xml_node const& pt); void parse_metawriter_in_symbolizer(symbolizer_base &sym, xml_node const& pt);
void parse_fontset(Map & map, xml_node const & fset); void parse_fontset(Map & map, xml_node const & fset);
void parse_font(font_set & fset, xml_node const& f); bool parse_font(font_set & fset, xml_node const& f);
void parse_rule(feature_type_style & style, xml_node const & r); void parse_rule(feature_type_style & style, xml_node const & r);
@ -455,44 +455,62 @@ void map_parser::parse_fontset(Map & map, xml_node const& fset)
{ {
name = fset.get_attr<std::string>("name"); name = fset.get_attr<std::string>("name");
font_set fontset(name); font_set fontset(name);
xml_node::const_iterator itr = fset.begin(); xml_node::const_iterator itr = fset.begin();
xml_node::const_iterator end = fset.end(); xml_node::const_iterator end = fset.end();
bool success = false;
for (; itr != end; ++itr) for (; itr != end; ++itr)
{ {
if (itr->is("Font")) if (itr->is("Font"))
{ {
parse_font(fontset, *itr); if (parse_font(fontset, *itr))
{
success = true;
} }
} }
}
// if not at least one face-name is valid
if (!success)
{
throw mapnik::config_error("no valid fonts could be loaded");
}
map.insert_fontset(name, fontset); map.insert_fontset(name, fontset);
// XXX Hack because map object isn't accessible by text_symbolizer // XXX Hack because map object isn't accessible by text_symbolizer
// when it's parsed // when it's parsed
fontsets_.insert(pair<std::string, font_set>(name, fontset)); fontsets_.insert(pair<std::string, font_set>(name, fontset));
} catch (const config_error & ex) { }
catch (const config_error & ex)
{
ex.append_context(std::string("in FontSet '") + name + "'", fset); ex.append_context(std::string("in FontSet '") + name + "'", fset);
throw; throw;
} }
} }
void map_parser::parse_font(font_set &fset, xml_node const& f) bool map_parser::parse_font(font_set &fset, xml_node const& f)
{ {
optional<std::string> face_name = f.get_opt_attr<std::string>("face-name"); optional<std::string> face_name = f.get_opt_attr<std::string>("face-name");
if (face_name) if (face_name)
{ {
if (strict_) face_ptr face = font_manager_.get_face(*face_name);
if (face)
{ {
ensure_font_face(*face_name);
}
fset.add_face_name(*face_name); fset.add_face_name(*face_name);
return true;
}
else if (strict_)
{
throw config_error("Failed to find font face '" +
*face_name + "'");
}
} }
else else
{ {
throw config_error("Must have 'face-name' set", f); throw config_error("Must have 'face-name' set", f);
} }
return false;
} }
void map_parser::parse_layer(Map & map, xml_node const& lay) void map_parser::parse_layer(Map & map, xml_node const& lay)

View file

@ -564,85 +564,66 @@ CoordTransform Map::view_transform() const
featureset_ptr Map::query_point(unsigned index, double x, double y) const featureset_ptr Map::query_point(unsigned index, double x, double y) const
{ {
if ( index< layers_.size()) if (!current_extent_.valid())
{
throw std::runtime_error("query_point: map extent is not intialized, you need to set a valid extent before querying");
}
if (!current_extent_.intersects(x,y))
{
throw std::runtime_error("query_point: x,y coords do not intersect map extent");
}
if (index < layers_.size())
{ {
mapnik::layer const& layer = layers_[index]; mapnik::layer const& layer = layers_[index];
try
{
double z = 0;
mapnik::projection dest(srs_);
mapnik::projection source(layer.srs());
proj_transform prj_trans(source,dest);
prj_trans.backward(x,y,z);
double minx = current_extent_.minx();
double miny = current_extent_.miny();
double maxx = current_extent_.maxx();
double maxy = current_extent_.maxy();
prj_trans.backward(minx,miny,z);
prj_trans.backward(maxx,maxy,z);
double tol = (maxx - minx) / width_ * 3;
mapnik::datasource_ptr ds = layer.datasource(); mapnik::datasource_ptr ds = layer.datasource();
if (ds) if (ds)
{ {
MAPNIK_LOG_DEBUG(map) << "map: Query at point tol=" << tol << "(" << x << "," << y << ")"; mapnik::projection dest(srs_);
mapnik::projection source(layer.srs());
proj_transform prj_trans(source,dest);
double z = 0;
if (!prj_trans.equal() && !prj_trans.backward(x,y,z))
{
throw std::runtime_error("query_point: could not project x,y into layer srs");
}
// TODO - pass tolerance to features_at_point as well
featureset_ptr fs = ds->features_at_point(mapnik::coord2d(x,y)); featureset_ptr fs = ds->features_at_point(mapnik::coord2d(x,y));
if (fs) if (fs)
{
mapnik::box2d<double> map_ex = current_extent_;
if (maximum_extent_) {
map_ex.clip(*maximum_extent_);
}
if (!prj_trans.backward(map_ex,PROJ_ENVELOPE_POINTS))
{
std::ostringstream s;
s << "query_point: could not project map extent '" << map_ex
<< "' into layer srs for tolerance calculation";
throw std::runtime_error(s.str());
}
double tol = (map_ex.maxx() - map_ex.minx()) / width_ * 3;
MAPNIK_LOG_DEBUG(map) << "map: Query at point tol=" << tol << "(" << x << "," << y << ")";
return boost::make_shared<filter_featureset<hit_test_filter> >(fs, return boost::make_shared<filter_featureset<hit_test_filter> >(fs,
hit_test_filter(x,y,tol)); hit_test_filter(x,y,tol));
} }
} }
catch (...)
{
MAPNIK_LOG_ERROR(map) << "Exception caught in \"query_point\"";
} }
else
{
std::ostringstream s;
s << "Invalid layer index passed to query_point: '" << index << "'";
if (layers_.size() > 0) s << " for map with " << layers_.size() << " layers(s)";
else s << " (map has no layers)";
throw std::out_of_range(s.str());
} }
return featureset_ptr(); return featureset_ptr();
} }
featureset_ptr Map::query_map_point(unsigned index, double x, double y) const featureset_ptr Map::query_map_point(unsigned index, double x, double y) const
{ {
if ( index< layers_.size())
{
mapnik::layer const& layer = layers_[index];
CoordTransform tr = view_transform(); CoordTransform tr = view_transform();
tr.backward(&x,&y); tr.backward(&x,&y);
return query_point(index,x,y);
try
{
mapnik::projection dest(srs_);
mapnik::projection source(layer.srs());
proj_transform prj_trans(source,dest);
double z = 0;
prj_trans.backward(x,y,z);
double minx = current_extent_.minx();
double miny = current_extent_.miny();
double maxx = current_extent_.maxx();
double maxy = current_extent_.maxy();
prj_trans.backward(minx,miny,z);
prj_trans.backward(maxx,maxy,z);
double tol = (maxx - minx) / width_ * 3;
mapnik::datasource_ptr ds = layer.datasource();
if (ds)
{
MAPNIK_LOG_DEBUG(map) << "map: Query at point tol=" << tol << "(" << x << "," << y << ")";
featureset_ptr fs = ds->features_at_point(mapnik::coord2d(x,y));
if (fs)
return boost::make_shared<filter_featureset<hit_test_filter> >(fs,
hit_test_filter(x,y,tol));
}
}
catch (...)
{
MAPNIK_LOG_ERROR(map) << "Exception caught in \"query_map_point\"";
}
}
return featureset_ptr();
} }
Map::~Map() {} Map::~Map() {}

View file

@ -73,43 +73,37 @@ boost::optional<marker_ptr> marker_cache::find(std::string const& uri, bool upda
return result; return result;
} }
try
{
// we can't find marker in cache, lets try to load it from filesystem // we can't find marker in cache, lets try to load it from filesystem
boost::filesystem::path path(uri); boost::filesystem::path path(uri);
if (exists(path)) if (!exists(path))
{
MAPNIK_LOG_ERROR(marker_cache) << "Marker does not exist: " << uri;
}
else
{ {
if (is_svg(uri)) if (is_svg(uri))
{ {
using namespace mapnik::svg; using namespace mapnik::svg;
try
{
path_ptr marker_path(boost::make_shared<svg_storage_type>()); path_ptr marker_path(boost::make_shared<svg_storage_type>());
vertex_stl_adapter<svg_path_storage> stl_storage(marker_path->source()); vertex_stl_adapter<svg_path_storage> stl_storage(marker_path->source());
svg_path_adapter svg_path(stl_storage); svg_path_adapter svg_path(stl_storage);
svg_converter_type svg(svg_path, marker_path->attributes()); svg_converter_type svg(svg_path, marker_path->attributes());
svg_parser p(svg); svg_parser p(svg);
p.parse(uri); p.parse(uri);
//svg.arrange_orientations(); //svg.arrange_orientations();
double lox,loy,hix,hiy; double lox,loy,hix,hiy;
svg.bounding_rect(&lox, &loy, &hix, &hiy); svg.bounding_rect(&lox, &loy, &hix, &hiy);
marker_path->set_bounding_box(lox,loy,hix,hiy); marker_path->set_bounding_box(lox,loy,hix,hiy);
marker_ptr mark(boost::make_shared<marker>(marker_path)); marker_ptr mark(boost::make_shared<marker>(marker_path));
result.reset(mark); result.reset(mark);
if (update_cache) if (update_cache)
{ {
cache_.insert(std::make_pair(uri,*result)); cache_.insert(std::make_pair(uri,*result));
} }
return result;
}
catch (...)
{
MAPNIK_LOG_ERROR(marker_cache) << "Exception caught while loading SVG: " << uri;
}
} }
else else
{
try
{ {
std::auto_ptr<mapnik::image_reader> reader(mapnik::get_image_reader(uri)); std::auto_ptr<mapnik::image_reader> reader(mapnik::get_image_reader(uri));
if (reader.get()) if (reader.get())
@ -126,17 +120,20 @@ boost::optional<marker_ptr> marker_cache::find(std::string const& uri, bool upda
cache_.insert(std::make_pair(uri,*result)); cache_.insert(std::make_pair(uri,*result));
} }
} }
}
catch (...)
{
MAPNIK_LOG_ERROR(marker_cache) << "Exception caught while loading image: " << uri;
}
}
}
else else
{ {
MAPNIK_LOG_WARN(marker_cache) << "Marker does not exist: " << uri; MAPNIK_LOG_ERROR(marker_cache) << "could not intialize reader for: '" << uri << "'";
}
}
}
}
catch (std::exception const& ex)
{
MAPNIK_LOG_ERROR(marker_cache) << "Exception caught while loading: '" << uri << "' (" << ex.what() << ")";
}
catch (...)
{
MAPNIK_LOG_ERROR(marker_cache) << "Exception caught while loading: '" << uri << "'";
} }
return result; return result;
} }

View file

@ -33,19 +33,20 @@
namespace mapnik { namespace mapnik {
#if defined(MAPNIK_THREADSAFE) && PJ_VERSION < 480 #if defined(MAPNIK_THREADSAFE) && PJ_VERSION < 480
#warning mapnik is building against < proj 4.8, reprojection will be faster if you use >= 4.8
boost::mutex projection::mutex_; boost::mutex projection::mutex_;
#endif #endif
projection::projection(std::string const& params) projection::projection(std::string const& params)
: params_(params) : params_(params)
{ {
init(); // init();
} }
projection::projection(projection const& rhs) projection::projection(projection const& rhs)
: params_(rhs.params_) : params_(rhs.params_)
{ {
init(); // init();
} }
projection& projection::operator=(projection const& rhs) projection& projection::operator=(projection const& rhs)
@ -158,9 +159,9 @@ std::string projection::expanded() const
return std::string(""); return std::string("");
} }
void projection::swap (projection& rhs) void projection::swap(projection& rhs)
{ {
std::swap(params_,rhs.params_); std::swap(params_,rhs.params_);
init (); init();
} }
} }

View file

@ -428,11 +428,21 @@ void svg_parser::parse_path(xmlTextReaderPtr reader)
if (value) if (value)
{ {
path_.begin_path(); path_.begin_path();
if (!mapnik::svg::parse_path((const char*) value, path_)) if (!mapnik::svg::parse_path((const char*) value, path_))
{ {
xmlFree(value); xmlFree(value);
throw std::runtime_error("can't parse PATH\n"); xmlChar *id_value;
id_value = xmlTextReaderGetAttribute(reader, BAD_CAST "id");
if (id_value)
{
std::string id_string((const char *) id_value);
xmlFree(id_value);
throw std::runtime_error(std::string("unable to parse invalid svg <path> with id '") + id_string + "'");
}
else
{
throw std::runtime_error("unable to parse invalid svg <path>");
}
} }
path_.end_path(); path_.end_path();
xmlFree(value); xmlFree(value);
@ -450,7 +460,7 @@ void svg_parser::parse_polygon(xmlTextReaderPtr reader)
if (!mapnik::svg::parse_points((const char*) value, path_)) if (!mapnik::svg::parse_points((const char*) value, path_))
{ {
xmlFree(value); xmlFree(value);
throw std::runtime_error("Failed to parse <polygon>\n"); throw std::runtime_error("Failed to parse <polygon>");
} }
path_.close_subpath(); path_.close_subpath();
path_.end_path(); path_.end_path();
@ -469,7 +479,7 @@ void svg_parser::parse_polyline(xmlTextReaderPtr reader)
if (!mapnik::svg::parse_points((const char*) value, path_)) if (!mapnik::svg::parse_points((const char*) value, path_))
{ {
xmlFree(value); xmlFree(value);
throw std::runtime_error("Failed to parse <polygon>\n"); throw std::runtime_error("Failed to parse <polygon>");
} }
path_.end_path(); path_.end_path();

View file

@ -113,8 +113,9 @@ public:
{ {
int type = read_integer(); int type = read_integer();
#ifdef MAPNIK_LOG
MAPNIK_LOG_DEBUG(wkb_reader) << "wkb_reader: Read=" << wkb_geometry_type_string(type) << "," << type; MAPNIK_LOG_DEBUG(wkb_reader) << "wkb_reader: Read=" << wkb_geometry_type_string(type) << "," << type;
#endif
switch (type) switch (type)
{ {
case wkbPoint: case wkbPoint:
@ -401,6 +402,7 @@ private:
} }
} }
#ifdef MAPNIK_LOG
std::string wkb_geometry_type_string(int type) std::string wkb_geometry_type_string(int type)
{ {
std::stringstream s; std::stringstream s;
@ -426,6 +428,7 @@ private:
return s.str(); return s.str();
} }
#endif
}; };
void geometry_utils::from_wkb (boost::ptr_vector<geometry_type>& paths, void geometry_utils::from_wkb (boost::ptr_vector<geometry_type>& paths,

View file

@ -1,5 +1,3 @@
//#include <boost/config/warning_disable.hpp>
#include <boost/filesystem/convenience.hpp> #include <boost/filesystem/convenience.hpp>
namespace fs = boost::filesystem; namespace fs = boost::filesystem;
using fs::path; using fs::path;
@ -9,15 +7,8 @@ namespace sys = boost::system;
#include <iostream> #include <iostream>
#include <mapnik/font_engine_freetype.hpp> #include <mapnik/font_engine_freetype.hpp>
// --------------------------------------------------------------------------//
int main( int, char*[] ) int main( int, char*[] )
{ {
// font registration() tests ----------------------------------------------//
std::string fontdir("fonts/"); std::string fontdir("fonts/");
BOOST_TEST( fs::exists( fontdir ) ); BOOST_TEST( fs::exists( fontdir ) );
@ -49,9 +40,9 @@ int main( int, char*[] )
BOOST_TEST( mapnik::freetype_engine::register_fonts("tests/data/fonts/fake.ttf") == false ); BOOST_TEST( mapnik::freetype_engine::register_fonts("tests/data/fonts/fake.ttf") == false );
BOOST_TEST( mapnik::freetype_engine::face_names().size() == 0 ); BOOST_TEST( mapnik::freetype_engine::face_names().size() == 0 );
//BOOST_TEST( mapnik::freetype_engine::register_font("tests/data/fonts/intentionally-broken.ttf") == false ); BOOST_TEST( mapnik::freetype_engine::register_font("tests/data/fonts/intentionally-broken.ttf") == false );
//BOOST_TEST( mapnik::freetype_engine::register_fonts("tests/data/fonts/intentionally-broken.ttf") == false ); BOOST_TEST( mapnik::freetype_engine::register_fonts("tests/data/fonts/intentionally-broken.ttf") == false );
//BOOST_TEST( mapnik::freetype_engine::face_names().size() == 0 ); BOOST_TEST( mapnik::freetype_engine::face_names().size() == 0 );
// register unifont, since we know it sits in the root fonts/ dir // register unifont, since we know it sits in the root fonts/ dir
BOOST_TEST( mapnik::freetype_engine::register_fonts(fontdir) ); BOOST_TEST( mapnik::freetype_engine::register_fonts(fontdir) );

View file

@ -0,0 +1,107 @@
#!/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('.'))
# map has no layers
@raises(IndexError)
def test_map_query_throw1():
m = mapnik.Map(256,256)
m.zoom_to_box(mapnik.Box2d(-1,-1,0,0))
m.query_point(0,0,0)
# only positive indexes
@raises(IndexError)
def test_map_query_throw2():
m = mapnik.Map(256,256)
m.query_point(-1,0,0)
# map has never been zoomed (nodata)
@raises(RuntimeError)
def test_map_query_throw3():
m = mapnik.Map(256,256)
m.query_point(0,0,0)
# map has never been zoomed (even with data)
@raises(RuntimeError)
def test_map_query_throw4():
m = mapnik.Map(256,256)
mapnik.load_map(m,'../data/good_maps/agg_poly_gamma_map.xml')
m.query_point(0,0,0)
# invalid coords in general (do not intersect)
@raises(RuntimeError)
def test_map_query_throw5():
m = mapnik.Map(256,256)
mapnik.load_map(m,'../data/good_maps/agg_poly_gamma_map.xml')
m.zoom_all()
m.query_point(0,9999999999999999,9999999999999999)
# invalid coords for back projecting
@raises(RuntimeError)
def test_map_query_throw6():
m = mapnik.Map(256,256)
mapnik.load_map(m,'../data/good_maps/merc2wgs84_reprojection.xml')
wgs84_bounds = mapnik.Box2d(-180,-90,180,90)
m.maximum_extent = wgs84_bounds
m.zoom_all()
m.query_point(0,-180,-90)
def test_map_query_works1():
m = mapnik.Map(256,256)
mapnik.load_map(m,'../data/good_maps/wgs842merc_reprojection.xml')
merc_bounds = mapnik.Box2d(-20037508.34,-20037508.34,20037508.34,20037508.34)
m.maximum_extent = merc_bounds
m.zoom_all()
fs = m.query_point(0,-11012435.5376, 4599674.6134) # somewhere in kansas
feat = fs.next()
eq_(feat.attributes['NAME_FORMA'],u'United States of America')
def test_map_query_works2():
m = mapnik.Map(256,256)
mapnik.load_map(m,'../data/good_maps/merc2wgs84_reprojection.xml')
wgs84_bounds = mapnik.Box2d(-179.999999975,-85.0511287776,179.999999975,85.0511287776)
m.maximum_extent = wgs84_bounds
# caution - will go square due to evil aspect_fix_mode backhandedness
m.zoom_all()
#mapnik.render_to_file(m,'works2.png')
# valid that aspec_fix_mode modified the bbox
eq_(m.envelope(),mapnik.Box2d(-179.999999975,-179.999999975,179.999999975,179.999999975))
fs = m.query_point(0,-98.9264, 38.1432) # somewhere in kansas
feat = fs.next()
eq_(feat.attributes['NAME'],u'United States')
def test_map_query_in_pixels_works1():
m = mapnik.Map(256,256)
mapnik.load_map(m,'../data/good_maps/wgs842merc_reprojection.xml')
merc_bounds = mapnik.Box2d(-20037508.34,-20037508.34,20037508.34,20037508.34)
m.maximum_extent = merc_bounds
m.zoom_all()
fs = m.query_map_point(0,55,100) # somewhere in middle of us
feat = fs.next()
eq_(feat.attributes['NAME_FORMA'],u'United States of America')
def test_map_query_in_pixels_works2():
m = mapnik.Map(256,256)
mapnik.load_map(m,'../data/good_maps/merc2wgs84_reprojection.xml')
wgs84_bounds = mapnik.Box2d(-179.999999975,-85.0511287776,179.999999975,85.0511287776)
m.maximum_extent = wgs84_bounds
# caution - will go square due to evil aspect_fix_mode backhandedness
m.zoom_all()
# valid that aspec_fix_mode modified the bbox
eq_(m.envelope(),mapnik.Box2d(-179.999999975,-179.999999975,179.999999975,179.999999975))
fs = m.query_map_point(0,55,100) # somewhere in middle of us
feat = fs.next()
eq_(feat.attributes['NAME'],u'United States')
if __name__ == "__main__":
setup()
[eval(run)() for run in dir() if 'test_' in run]

View file

@ -113,6 +113,27 @@ def test_pointsymbolizer_init():
eq_(p.ignore_placement,True) eq_(p.ignore_placement,True)
eq_(p.placement, mapnik.point_placement.INTERIOR) eq_(p.placement, mapnik.point_placement.INTERIOR)
# PointSymbolizer initialization
def test_markersymbolizer_init():
p = mapnik.MarkersSymbolizer()
eq_(p.allow_overlap, False)
eq_(p.opacity,1)
eq_(p.filename,'')
stroke = mapnik.Stroke()
stroke.color = mapnik.Color('black')
stroke.width = 1.0
p.stroke = stroke
p.fill = mapnik.Color('white')
p.allow_overlap = True
p.opacity = 0.5
eq_(p.allow_overlap, True)
eq_(p.opacity, 0.5)
# PointSymbolizer missing image file # PointSymbolizer missing image file
# images paths are now PathExpressions are evaluated at runtime # images paths are now PathExpressions are evaluated at runtime
# so it does not make sense to throw... # so it does not make sense to throw...

View file

@ -69,17 +69,20 @@ def test_dataraster_query_point():
_map = mapnik.Map(256,256, srs) _map = mapnik.Map(256,256, srs)
_map.layers.append(lyr) _map.layers.append(lyr)
# point inside raster extent with valid data x, y = 556113.0,4381428.0 # center of extent of raster
x, y = 427417, 4477517 _map.zoom_all()
features = _map.query_point(0,x,y).features features = _map.query_point(0,x,y).features
assert len(features) == 1 assert len(features) == 1
feat = features[0] feat = features[0]
center = feat.envelope().center() center = feat.envelope().center()
assert center.x==x and center.y==y, center assert center.x==x and center.y==y, center
value = feat['value'] value = feat['value']
assert value == 21.0, value assert value == 18.0, value
# point outside raster extent # point inside map extent but outside raster extent
current_box = _map.envelope()
current_box.expand_to_include(-427417,4477517)
_map.zoom_to_box(current_box)
features = _map.query_point(0,-427417,4477517).features features = _map.query_point(0,-427417,4477517).features
assert len(features) == 0 assert len(features) == 0

View file

@ -71,6 +71,88 @@ if 'sqlite' in mapnik.DatasourceCache.instance().plugin_names():
eq_(os.path.exists(index),True) eq_(os.path.exists(index),True)
os.unlink(index) os.unlink(index)
def test_geometry_round_trip():
test_db = '/tmp/mapnik-sqlite-point.db'
ogr_metadata = True
# create test db
conn = sqlite3.connect(test_db)
cur = conn.cursor()
cur.execute('''
CREATE TABLE IF NOT EXISTS point_table
(id INTEGER PRIMARY KEY AUTOINCREMENT, geometry BLOB, name varchar)
''')
# optional: but nice if we want to read with ogr
if ogr_metadata:
cur.execute('''CREATE TABLE IF NOT EXISTS geometry_columns (
f_table_name VARCHAR,
f_geometry_column VARCHAR,
geometry_type INTEGER,
coord_dimension INTEGER,
srid INTEGER,
geometry_format VARCHAR )''')
cur.execute('''INSERT INTO geometry_columns
(f_table_name, f_geometry_column, geometry_format,
geometry_type, coord_dimension, srid) VALUES
('point_table','geometry','WKB', 1, 1, 4326)''')
conn.commit()
cur.close()
# add a point as wkb (using mapnik) to match how an ogr created db looks
x = -122 # longitude
y = 48 # latitude
wkt = 'POINT(%s %s)' % (x,y)
# little endian wkb (mapnik will auto-detect and ready either little or big endian (XDR))
wkb = mapnik.Path.from_wkt(wkt).to_wkb(mapnik.wkbByteOrder.NDR)
values = (None,sqlite3.Binary(wkb),"test point")
cur = conn.cursor()
cur.execute('''INSERT into "point_table" (id,geometry,name) values (?,?,?)''',values)
conn.commit()
cur.close()
def make_wkb_point(x,y):
import struct
byteorder = 1; # little endian
endianess = ''
if byteorder == 1:
endianess = '<'
else:
endianess = '>'
geom_type = 1; # for a point
return struct.pack('%sbldd' % endianess, byteorder, geom_type, x, y)
# confirm the wkb matches a manually formed wkb
wkb2 = make_wkb_point(x,y)
eq_(wkb,wkb2)
# ensure we can read this data back out properly with mapnik
ds = mapnik.Datasource(**{'type':'sqlite','file':test_db, 'table':'point_table'})
fs = ds.featureset()
feat = fs.next()
eq_(feat.id(),1)
eq_(feat['name'],'test point')
geoms = feat.geometries()
eq_(len(geoms),1)
eq_(geoms.to_wkt(),'Point(-122.0 48.0)')
# ensure it matches data read with just sqlite
cur = conn.cursor()
cur.execute('''SELECT * from point_table''')
conn.commit()
result = cur.fetchone()
cur.close()
feat_id = result[0]
eq_(feat_id,1)
name = result[2]
eq_(name,'test point')
geom_wkb_blob = result[1]
eq_(str(geom_wkb_blob),geoms.to_wkb(mapnik.wkbByteOrder.NDR))
new_geom = mapnik.Path.from_wkb(str(geom_wkb_blob))
eq_(new_geom.to_wkt(),geoms.to_wkt())
# cleanup
os.unlink(test_db)
os.unlink(test_db + '.index')
if __name__ == "__main__": if __name__ == "__main__":
setup() setup()

View file

@ -27,13 +27,13 @@ def compare(fn1, fn2):
try: try:
im2 = Image.open(fn2) im2 = Image.open(fn2)
except IOError: except IOError:
errors.append((fn1, None)) errors.append((fn1, None, fn2))
return -1 return -1
diff = 0 diff = 0
pixels = im1.size[0] * im1.size[1] pixels = im1.size[0] * im1.size[1]
delta_pixels = im2.size[0] * im2.size[1] - pixels delta_pixels = im2.size[0] * im2.size[1] - pixels
if delta_pixels != 0: if delta_pixels != 0:
errors.append((fn1, delta_pixels)) errors.append((fn1, delta_pixels, fn2))
return delta_pixels return delta_pixels
im1 = im1.getdata() im1 = im1.getdata()
im2 = im2.getdata() im2 = im2.getdata()
@ -41,7 +41,7 @@ def compare(fn1, fn2):
if(compare_pixels(im1[i], im2[i])): if(compare_pixels(im1[i], im2[i])):
diff = diff + 1 diff = diff + 1
if diff != 0: if diff != 0:
errors.append((fn1, diff)) errors.append((fn1, diff, fn2))
passed += 1 passed += 1
return diff return diff
@ -55,7 +55,7 @@ def summary():
if (error[1] is None): if (error[1] is None):
print "Could not verify %s: No reference image found!" % error[0] print "Could not verify %s: No reference image found!" % error[0]
else: else:
print "%s failed: %d different pixels" % error print "%s failed: %d different pixels \n\t%s (expected)" % error
sys.exit(1) sys.exit(1)
else: else:
print 'All %s tests passed: \x1b[1;32m✓ \x1b[0m' % passed print 'All %s tests passed: \x1b[1;32m✓ \x1b[0m' % passed

View file

@ -57,9 +57,12 @@ def render(filename, width, height, bbox, quiet=False):
m.zoom_to_box(bbox) m.zoom_to_box(bbox)
else: else:
m.zoom_all() m.zoom_all()
basefn = os.path.join(dirname, "images", '%s-%d' % (filename, width)) expected = os.path.join(dirname, "images", '%s-%d-reference.png' % (filename, width))
mapnik.render_to_file(m, basefn+'-agg.png') if not os.path.exists('/tmp/mapnik-visual-images'):
diff = compare(basefn + '-agg.png', basefn + '-reference.png') os.makedirs('/tmp/mapnik-visual-images')
actual = os.path.join("/tmp/mapnik-visual-images", '%s-%d-agg.png' % (filename, width))
mapnik.render_to_file(m, actual)
diff = compare(actual, expected)
if diff > 0: if diff > 0:
print "-"*80 print "-"*80
print '\x1b[33mError:\x1b[0m %u different pixels' % diff print '\x1b[33mError:\x1b[0m %u different pixels' % diff

View file

@ -3,7 +3,7 @@
# batch format *.{hpp,cpp} files # batch format *.{hpp,cpp} files
MAPNIK_DIR=`pwd` MAPNIK_DIR=`pwd`
DIRS="$MAPNIK_DIR/plugins $MAPNIK_DIR/demo/c++ $MAPNIK_DIR/src $MAPNIK_DIR/include $MAPNIK_DIR/bindings $MAPNIK_DIR/utils" DIRS="$MAPNIK_DIR/plugins $MAPNIK_DIR/demo/c++ $MAPNIK_DIR/src $MAPNIK_DIR/include $MAPNIK_DIR/bindings $MAPNIK_DIR/utils $MAPNIK_DIR/tests"
EMACS="emacs" EMACS="emacs"
for file in $(find $DIRS -name '*.cpp' -o -name '*.hpp') for file in $(find $DIRS -name '*.cpp' -o -name '*.hpp')

View file

@ -35,8 +35,13 @@ source = Split(
""" """
) )
headers = ['#plugins/input/postgis'] + env['CPPPATH'] program_env['CXXFLAGS'] = copy(env['LIBMAPNIK_CXXFLAGS'])
if env['HAS_CAIRO']:
program_env.PrependUnique(CPPPATH=env['CAIROMM_CPPPATHS'])
program_env.Append(CXXFLAGS = '-DHAVE_CAIRO')
program_env.PrependUnique(CPPPATH=['#plugins/input/postgis'])
libraries = [] libraries = []
boost_program_options = 'boost_program_options%s' % env['BOOST_APPEND'] boost_program_options = 'boost_program_options%s' % env['BOOST_APPEND']
@ -49,7 +54,7 @@ if env['SQLITE_LINKFLAGS']:
if env['RUNTIME_LINK'] == 'static': if env['RUNTIME_LINK'] == 'static':
libraries.extend(['ldap','pam','ssl','crypto','krb5']) libraries.extend(['ldap','pam','ssl','crypto','krb5'])
pgsql2sqlite = program_env.Program('pgsql2sqlite', source, CPPPATH=headers, LIBS=libraries, LINKFLAGS=linkflags) pgsql2sqlite = program_env.Program('pgsql2sqlite', source, LIBS=libraries, LINKFLAGS=linkflags)
Depends(pgsql2sqlite, env.subst('../../src/%s' % env['MAPNIK_LIB_NAME'])) Depends(pgsql2sqlite, env.subst('../../src/%s' % env['MAPNIK_LIB_NAME']))
if 'uninstall' not in COMMAND_LINE_TARGETS: if 'uninstall' not in COMMAND_LINE_TARGETS:

View file

@ -33,13 +33,17 @@ source = Split(
""" """
) )
headers = env['CPPPATH'] program_env['CXXFLAGS'] = copy(env['LIBMAPNIK_CXXFLAGS'])
if env['HAS_CAIRO']:
program_env.PrependUnique(CPPPATH=env['CAIROMM_CPPPATHS'])
program_env.Append(CXXFLAGS = '-DHAVE_CAIRO')
libraries = copy(env['LIBMAPNIK_LIBS']) libraries = copy(env['LIBMAPNIK_LIBS'])
boost_program_options = 'boost_program_options%s' % env['BOOST_APPEND'] boost_program_options = 'boost_program_options%s' % env['BOOST_APPEND']
libraries.extend([boost_program_options,'mapnik']) libraries.extend([boost_program_options,'mapnik'])
svg2png = program_env.Program('svg2png', source, CPPPATH=headers, LIBS=libraries, LINKFLAGS=env['CUSTOM_LDFLAGS']) svg2png = program_env.Program('svg2png', source, LIBS=libraries, LINKFLAGS=env['CUSTOM_LDFLAGS'])
Depends(svg2png, env.subst('../../src/%s' % env['MAPNIK_LIB_NAME'])) Depends(svg2png, env.subst('../../src/%s' % env['MAPNIK_LIB_NAME']))

View file

@ -23,8 +23,10 @@
#include <iostream> #include <iostream>
#include <sstream> #include <sstream>
#include <vector> #include <vector>
//#include <string> #include <string>
#include <mapnik/version.hpp>
#include <mapnik/debug.hpp>
#include <mapnik/marker.hpp> #include <mapnik/marker.hpp>
#include <mapnik/marker_cache.hpp> #include <mapnik/marker_cache.hpp>
#include <mapnik/image_util.hpp> #include <mapnik/image_util.hpp>
@ -44,13 +46,19 @@
#include "agg_pixfmt_rgba.h" #include "agg_pixfmt_rgba.h"
#include "agg_scanline_u.h" #include "agg_scanline_u.h"
#include <libxml/parser.h> // for xmlInitParser(), xmlCleanupParser()
int main (int argc,char** argv) int main (int argc,char** argv)
{ {
namespace po = boost::program_options; namespace po = boost::program_options;
bool verbose=false; bool verbose = false;
bool auto_open = false;
bool error = false;
std::vector<std::string> svg_files; std::vector<std::string> svg_files;
mapnik::logger logger;
logger.set_severity(mapnik::logger::error);
try try
{ {
@ -59,6 +67,7 @@ int main (int argc,char** argv)
("help,h", "produce usage message") ("help,h", "produce usage message")
("version,V","print version string") ("version,V","print version string")
("verbose,v","verbose output") ("verbose,v","verbose output")
("open","automatically open the file after rendering (os x only)")
("svg",po::value<std::vector<std::string> >(),"svg file to read") ("svg",po::value<std::vector<std::string> >(),"svg file to read")
; ;
@ -70,7 +79,7 @@ int main (int argc,char** argv)
if (vm.count("version")) if (vm.count("version"))
{ {
std::clog<<"version 0.3.0" << std::endl; std::clog <<"version " << MAPNIK_VERSION_STRING << std::endl;
return 1; return 1;
} }
@ -79,11 +88,17 @@ int main (int argc,char** argv)
std::clog << desc << std::endl; std::clog << desc << std::endl;
return 1; return 1;
} }
if (vm.count("verbose")) if (vm.count("verbose"))
{ {
verbose = true; verbose = true;
} }
if (vm.count("open"))
{
auto_open = true;
}
if (vm.count("svg")) if (vm.count("svg"))
{ {
svg_files=vm["svg"].as< std::vector<std::string> >(); svg_files=vm["svg"].as< std::vector<std::string> >();
@ -100,16 +115,32 @@ int main (int argc,char** argv)
std::clog << "no svg files to render" << std::endl; std::clog << "no svg files to render" << std::endl;
return 0; return 0;
} }
xmlInitParser();
while (itr != svg_files.end()) while (itr != svg_files.end())
{ {
std::string svg_name (*itr++); std::string svg_name (*itr++);
if (verbose)
{
std::clog << "found: " << svg_name << "\n";
}
boost::optional<mapnik::marker_ptr> marker_ptr = mapnik::marker_cache::instance()->find(svg_name, false); boost::optional<mapnik::marker_ptr> marker_ptr =
if (marker_ptr) { mapnik::marker_cache::instance()->find(svg_name, false);
if (!marker_ptr)
{
std::clog << "svg2png error: could not open: '" << svg_name << "'\n";
error = true;
continue;
}
mapnik::marker marker = **marker_ptr; mapnik::marker marker = **marker_ptr;
if (marker.is_vector()) { if (!marker.is_vector())
{
std::clog << "svg2png error: '" << svg_name << "' is not a valid vector!\n";
error = true;
continue;
}
typedef agg::pixfmt_rgba32_plain pixfmt; typedef agg::pixfmt_rgba32_plain pixfmt;
typedef agg::renderer_base<pixfmt> renderer_base; typedef agg::renderer_base<pixfmt> renderer_base;
@ -121,6 +152,10 @@ int main (int argc,char** argv)
double scale_factor_ = .95; double scale_factor_ = .95;
int w = marker.width(); int w = marker.width();
int h = marker.height(); int h = marker.height();
if (verbose)
{
std::clog << "found width of '" << w << "' and height of '" << h << "'\n";
}
mapnik::image_32 im(w,h); mapnik::image_32 im(w,h);
agg::rendering_buffer buf(im.raw_data(), w, h, w * 4); agg::rendering_buffer buf(im.raw_data(), w, h, w * 4);
pixfmt pixf(buf); pixfmt pixf(buf);
@ -147,19 +182,30 @@ int main (int argc,char** argv)
boost::algorithm::ireplace_last(svg_name,".svg",".png"); boost::algorithm::ireplace_last(svg_name,".svg",".png");
mapnik::save_to_file<mapnik::image_data_32>(im.data(),svg_name,"png"); mapnik::save_to_file<mapnik::image_data_32>(im.data(),svg_name,"png");
#ifdef DARWIN
if (auto_open)
{
std::ostringstream s; std::ostringstream s;
s << "open " << svg_name; s << "open " << svg_name;
return system(s.str().c_str()); system(s.str().c_str());
}
} }
#endif
std::clog << "rendered to: " << svg_name << "\n";
} }
} }
catch (...) catch (...)
{ {
std::clog << "Exception of unknown type!" << std::endl; std::clog << "Exception of unknown type!" << std::endl;
xmlCleanupParser();
return -1; return -1;
} }
// only call this once, on exit
// to make sure valgrind output is clean
// http://xmlsoft.org/xmlmem.html
xmlCleanupParser();
if (error)
return -1;
return 0; return 0;
} }