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
- 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)
- 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
test:
@echo "*** Running visual tests"
@echo "*** Running visual tests..."
@python tests/visual_tests/test.py -q
@echo "*** Running C++ tests..."
@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'},
# 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...
'shape': {'default':True,'path':None,'inc':None,'lib':None,'lang':'C++'},
@ -242,7 +242,6 @@ else:
LIBDIR_SCHEMA='lib'
def pretty_dep(dep):
pretty = pretty_dep_names.get(dep)
if pretty:

View file

@ -23,6 +23,7 @@
#include <boost/python.hpp>
#include <mapnik/debug.hpp>
#include <mapnik/utils.hpp>
#include "mapnik_enumeration.hpp"
void export_logger()
{
@ -37,6 +38,15 @@ void export_logger()
.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> >,
boost::noncopyable>("logger",no_init)
.def_readonly("Info", logger::info)

View file

@ -124,5 +124,15 @@ void export_markers_symbolizer()
&markers_symbolizer::get_height,
&markers_symbolizer::set_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",
&feature_type_style::get_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 {
/*
Global logger class that holds the configuration of severity, format
and file/console redirection.
*/
class MAPNIK_DECL logger :
public singleton<logger,CreateStatic>,
private boost::noncopyable
@ -153,6 +157,9 @@ namespace mapnik {
namespace detail {
/*
Default sink, it regulates access to clog
*/
template<class Ch, class Tr, class A>
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,
logger::severity_type Severity,
class Ch = char,
@ -223,14 +236,67 @@ namespace mapnik {
#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::debug> base_log_debug;
typedef base_log<clog_sink, logger::warn> base_log_warn;
typedef base_log<clog_sink, logger::error> base_log_error;
typedef base_log<clog_sink, logger::fatal> base_log_fatal;
typedef base_log_always<clog_sink, logger::error> base_log_error;
typedef base_log_always<clog_sink, logger::fatal> base_log_fatal;
} // namespace detail
// real interfaces
class MAPNIK_DECL info : public detail::base_log_info {
public:
@ -262,6 +328,7 @@ namespace mapnik {
fatal(const char* object_name) : detail::base_log_fatal(object_name) {}
};
// logging helpers
#define MAPNIK_LOG_INFO(s) mapnik::info(#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;
#if BOOST_VERSION > 104200
using qi::no_skip;
#else
using qi::lexeme;
#endif
using qi::lexeme;
using qi::_val;
using qi::lit;
using qi::int_;

View file

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

View file

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

View file

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

View file

@ -23,6 +23,12 @@
#ifndef MAPNIK_IMAGE_COMPOSITING_HPP
#define MAPNIK_IMAGE_COMPOSITING_HPP
#include <mapnik/config.hpp>
#ifdef _MSC_VER
#include <mapnik/image_data.hpp>
#endif
// agg
namespace mapnik
@ -64,7 +70,11 @@ enum composite_mode_e
};
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

View file

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

View file

@ -140,7 +140,7 @@ class label_collision_detector4 : boost::noncopyable
public:
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) {}
box2d<double> box;

View file

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

View file

@ -80,17 +80,22 @@ struct rgba
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)
: 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) {
r = U2RED(c);
g = U2GREEN(c);
b = U2BLUE(c);
a = U2ALPHA(c);
}
inline rgba(unsigned const& c)
: r(U2RED(c)),
g(U2GREEN(c)),
b(U2BLUE(c)),
a(U2ALPHA(c)) {}
inline bool operator==(const rgba& y) const
{

View file

@ -47,8 +47,8 @@ template <typename Iterator> struct path_expression_grammar;
MAPNIK_DECL path_expression_ptr parse_path(std::string const & str);
MAPNIK_DECL bool parse_path_from_string(path_expression_ptr const& path,
std::string const & str,
path_expression_grammar<std::string::const_iterator> const& g);
std::string const & str,
path_expression_grammar<std::string::const_iterator> const& g);
template <typename T>

View file

@ -86,23 +86,20 @@ class quad_tree : boost::noncopyable
typedef typename node::cont_t cont_t;
typedef typename cont_t::iterator node_data_iterator;
nodes_t nodes_;
node * root_;
const unsigned int max_depth_;
const double ratio_;
public:
typedef typename nodes_t::iterator iterator;
typedef typename nodes_t::const_iterator const_iterator;
typedef typename boost::ptr_vector<T,boost::view_clone_allocator> result_t;
typedef typename result_t::iterator query_iterator;
result_t query_result_;
explicit quad_tree(box2d<double> const& ext,
unsigned int max_depth = 8,
double ratio = 0.55)
: max_depth_(max_depth),
ratio_(ratio)
ratio_(ratio),
query_result_(),
nodes_()
{
nodes_.push_back(new node(ext));
root_ = &nodes_[0];
@ -219,6 +216,13 @@ private:
ext[2]=box2d<double>(lox,hiy - height*ratio_,lox + width * ratio_,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:
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,
resolution_type const& resolution,
@ -57,7 +49,8 @@ public:
resolution_(resolution),
scale_denominator_(scale_denominator),
filter_factor_(1.0),
unbuffered_bbox_(unbuffered_bbox)
unbuffered_bbox_(unbuffered_bbox),
names_()
{}
query(box2d<double> const& bbox,
@ -67,7 +60,8 @@ public:
resolution_(resolution),
scale_denominator_(scale_denominator),
filter_factor_(1.0),
unbuffered_bbox_(bbox)
unbuffered_bbox_(bbox),
names_()
{}
query(box2d<double> const& bbox)
@ -75,7 +69,8 @@ public:
resolution_(resolution_type(1.0,1.0)),
scale_denominator_(1.0),
filter_factor_(1.0),
unbuffered_bbox_(bbox)
unbuffered_bbox_(bbox),
names_()
{}
query(query const& other)
@ -94,8 +89,8 @@ public:
resolution_=other.resolution_;
scale_denominator_=other.scale_denominator_;
filter_factor_=other.filter_factor_;
names_=other.names_;
unbuffered_bbox_=other.unbuffered_bbox_;
names_=other.names_;
return *this;
}
@ -119,12 +114,12 @@ public:
return unbuffered_bbox_;
}
void set_unbuffered_bbox(const box2d<double>& bbox)
void set_unbuffered_bbox(box2d<double> const& bbox)
{
unbuffered_bbox_ = bbox;
}
void set_bbox(const box2d<double>& bbox)
void set_bbox(box2d<double> const& bbox)
{
bbox_ = bbox;
}
@ -148,6 +143,14 @@ public:
{
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();
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);
}
@ -384,7 +385,7 @@ public:
{
ras.reset();
if(fabs(curved_trans_contour.width()) < 0.0001)
if(fabs(curved_trans_contour.width()) <= 1)
{
ras.add_path(curved_trans, attr.index);
}

View file

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

View file

@ -29,16 +29,73 @@
// stl
#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 {
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(const char * 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 string2float(std::string const& value, float & result);
MAPNIK_DECL bool string2float(const char * value, float & result);
MAPNIK_DECL bool string2float(std::string const& 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;
vertex_iterator()
: v_(SEG_END,0,0)
: v_(SEG_END,0,0),
vertices_(),
pos_(0)
{}
explicit vertex_iterator(container_type const& vertices)
@ -74,8 +76,8 @@ namespace mapnik { namespace util {
return v_;
}
container_type const *vertices_;
value_type v_;
container_type const *vertices_;
unsigned pos_;
};

View file

@ -36,8 +36,6 @@
// stl
#include <iostream>
#include <string>
#include <sstream>
#include <iomanip>
#include <cmath>
// uci
@ -338,20 +336,34 @@ struct add : public boost::static_visitor<V>
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>
value_type operator() (UnicodeString const& lhs, R const& rhs) const
{
std::basic_ostringstream<char> out;
out << rhs;
return lhs + UnicodeString(out.str().c_str());
std::string val;
if (util::to_string(val,rhs))
return lhs + UnicodeString(val.c_str());
return lhs;
}
template <typename L>
value_type operator() (L const& lhs , UnicodeString const& rhs) const
{
std::basic_ostringstream<char> out;
out << lhs;
return UnicodeString(out.str().c_str()) + rhs;
std::string val;
if (util::to_string(val,lhs))
return UnicodeString(val.c_str()) + rhs;
return rhs;
}
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>
{
template <typename T>
std::string operator() (T val) const
{
std::stringstream ss;
ss << val;
return ss.str();
std::string str;
util::to_string(str, val);
return str;
}
// specializations
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::stringstream ss;
ss << std::setprecision(16) << val;
return ss.str();
std::string str;
util::to_string(str, val); // TODO set precision(16)
return str;
}
std::string operator() (value_null const& val) const
@ -576,9 +588,9 @@ struct to_unicode : public boost::static_visitor<UnicodeString>
template <typename T>
UnicodeString operator() (T val) const
{
std::basic_ostringstream<char> out;
out << val;
return UnicodeString(out.str().c_str());
std::string str;
util::to_string(str,val);
return UnicodeString(str.c_str());
}
// specializations
@ -589,9 +601,9 @@ struct to_unicode : public boost::static_visitor<UnicodeString>
UnicodeString operator() (double val) const
{
std::basic_ostringstream<char> out;
out << std::setprecision(16) << val;
return UnicodeString(out.str().c_str());
std::string str;
util::to_string(str,val);
return UnicodeString(str.c_str());
}
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::stringstream ss;
ss << std::setprecision(16) << val;
return ss.str();
std::string output;
util::to_string(output,val); // TODO precision(16)
return output;
}
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 ret(0);
mapnik::util::string2double(val,ret);
return ret;
double result;
if (util::string2double(val,result))
return result;
return 0;
}
double operator() (UnicodeString const& val) const
{
std::string utf8;
to_utf8(val,utf8);
double ret(0);
mapnik::util::string2double(utf8,ret);
return ret;
return operator()(utf8);
}
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 ret(0);
mapnik::util::string2int(val,ret);
return ret;
int result;
if (util::string2int(val,result))
return result;
return 0;
}
int operator() (UnicodeString const& val) const
{
std::string utf8;
to_utf8(val,utf8);
int ret(0);
mapnik::util::string2int(utf8,ret);
return ret;
return operator()(utf8);
}
int operator() (value_null const& val) const

View file

@ -31,12 +31,14 @@ namespace mapnik {
class value_error : public std::exception
{
public:
value_error() {}
value_error() :
what_() {}
value_error( std::string const& what ) :
what_( what )
{
}
virtual ~value_error() 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())
{
OGRLayer* layer = layer_.layer();
// only new either reset of setNext
//layer->ResetReading();
layer->SetNextByIndex(0);
ogr_feature_ptr feat(layer->GetNextFeature());
if ((*feat) != NULL)
{

View file

@ -67,6 +67,7 @@ postgis_datasource::postgis_datasource(parameters const& params, bool bind)
type_(datasource::Vector),
srid_(*params_.get<int>("srid", 0)),
extent_initialized_(false),
simplify_geometries_(false),
desc_(*params_.get<std::string>("type"), "utf-8"),
creator_(params.get<std::string>("host"),
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")),
bbox_token_("!bbox!"),
scale_denom_token_("!scale_denominator!"),
pixel_width_token_("!pixel_width!"),
pixel_height_token_("!pixel_height!"),
persist_connection_(*params_.get<mapnik::boolean>("persist_connection", true)),
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)
@ -114,6 +117,9 @@ void postgis_datasource::bind() const
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> simplify_opt = params_.get<mapnik::boolean>("simplify_geometries", false);
simplify_geometries_ = simplify_opt && *simplify_opt;
ConnectionManager* mgr = ConnectionManager::instance();
mgr->registerPool(creator_, *initial_size, *max_size);
@ -233,23 +239,23 @@ void postgis_datasource::bind() const
std::ostringstream s;
s << "SELECT a.attname, a.attnum, t.typname, t.typname in ('int2','int4','int8') "
"AS is_int FROM pg_class c, pg_attribute a, pg_type t, pg_namespace n, pg_index i "
"WHERE a.attnum > 0 AND a.attrelid = c.oid "
"AND a.atttypid = t.oid AND c.relnamespace = n.oid "
"AND c.oid = i.indrelid AND i.indisprimary = 't' "
"AND t.typname !~ '^geom' AND c.relname ="
"AS is_int FROM pg_class c, pg_attribute a, pg_type t, pg_namespace n, pg_index i "
"WHERE a.attnum > 0 AND a.attrelid = c.oid "
"AND a.atttypid = t.oid AND c.relnamespace = n.oid "
"AND c.oid = i.indrelid AND i.indisprimary = 't' "
"AND t.typname !~ '^geom' AND c.relname ="
<< " '" << mapnik::sql_utils::unquote_double(geometry_table_) << "' "
//"AND a.attnum = ANY (i.indkey) " // postgres >= 8.1
//"AND a.attnum = ANY (i.indkey) " // postgres >= 8.1
<< "AND (i.indkey[0]=a.attnum OR i.indkey[1]=a.attnum OR i.indkey[2]=a.attnum "
"OR i.indkey[3]=a.attnum OR i.indkey[4]=a.attnum OR i.indkey[5]=a.attnum "
"OR i.indkey[6]=a.attnum OR i.indkey[7]=a.attnum OR i.indkey[8]=a.attnum "
"OR i.indkey[9]=a.attnum) ";
if (! schema_.empty())
{
s << "AND n.nspname='"
<< mapnik::sql_utils::unquote_double(schema_)
<< "' ";
}
"OR i.indkey[3]=a.attnum OR i.indkey[4]=a.attnum OR i.indkey[5]=a.attnum "
"OR i.indkey[6]=a.attnum OR i.indkey[7]=a.attnum OR i.indkey[8]=a.attnum "
"OR i.indkey[9]=a.attnum) ";
if (! schema_.empty())
{
s << "AND n.nspname='"
<< mapnik::sql_utils::unquote_double(schema_)
<< "' ";
}
s << "ORDER BY a.attnum";
shared_ptr<ResultSet> rs_key = conn->executeQuery(s.str());
@ -299,8 +305,8 @@ void postgis_datasource::bind() const
if (*autodetect_key_field && key_field_.empty())
{
throw mapnik::datasource_exception(std::string("PostGIS Plugin: Error: primary key required")
+ " but could not be detected for table '" +
geometry_table_ + "', please supply 'key_field' option to specify field to use for primary key");
+ " but could not be detected for table '" +
geometry_table_ + "', please supply 'key_field' option to specify field to use for primary key");
}
if (srid_ == 0)
@ -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());
}
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;
}
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 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());
}
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_))
{
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;
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>();
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;
@ -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);
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;

View file

@ -61,7 +61,7 @@ public:
private:
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;
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;
@ -85,10 +85,13 @@ private:
mutable int srid_;
mutable bool extent_initialized_;
mutable mapnik::box2d<double> extent_;
mutable bool simplify_geometries_;
mutable layer_descriptor desc_;
ConnectionCreator<Connection> creator_;
const std::string bbox_token_;
const std::string scale_denom_token_;
const std::string pixel_width_token_;
const std::string pixel_height_token_;
bool persist_connection_;
bool extent_from_subquery_;
// params below are for testing purposes only (will likely be removed at any time)

View file

@ -53,7 +53,7 @@ shape_index_featureset<filterT>::shape_index_featureset(filterT const& filter,
{
shape_.shp().skip(100);
setup_attributes(ctx_, attribute_names, shape_name, shape_,attr_ids_);
boost::shared_ptr<shape_file> index = shape_.index();
if (index)
{

View file

@ -80,13 +80,8 @@ else:
else:
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':
mapnik_libname = env.subst(env['MAPNIK_LIB_NAME'])
if env['FULL_LIB_PATH']:
lib_path = '%s/%s' % (env['MAPNIK_LIB_BASE'],mapnik_libname)
else:
@ -94,13 +89,15 @@ if env['PLATFORM'] == 'Darwin':
mapnik_lib_link_flag += ' -Wl,-install_name,%s' % lib_path
_d = {'version':env['MAPNIK_VERSION_STRING'].replace('-pre','')}
mapnik_lib_link_flag += ' -current_version %(version)s -compatibility_version %(version)s' % _d
elif env['PLATFORM'] == 'SunOS':
if env['CXX'].startswith('CC'):
mapnik_lib_link_flag += ' -R. -h %s' % mapnik_libname
else:
mapnik_lib_link_flag += ' -Wl,-h,%s' % mapnik_libname
else: # Linux and others
mapnik_lib_link_flag += ' -Wl,-rpath-link,. -Wl,-soname,%s' % mapnik_libname
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'):
mapnik_lib_link_flag += ' -R. -h %s' % mapnik_libname
else:
mapnik_lib_link_flag += ' -Wl,-h,%s' % mapnik_libname
else: # Linux and others
mapnik_lib_link_flag += ' -Wl,-rpath-link,. -Wl,-soname,%s' % mapnik_libname
source = Split(
"""
@ -324,16 +321,22 @@ if env['CUSTOM_LDFLAGS']:
else:
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
env['LIBMAPNIK_LIBS'] = copy(lib_env['LIBS'])
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
def symlink(env, target, source):
trgt = str(target[0])
@ -345,38 +348,34 @@ if env['PLATFORM'] != 'Darwin':
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)
if 'uninstall' not in COMMAND_LINE_TARGETS:
result = env.InstallAs(target=target, source=mapnik)
env.Alias(target='install', source=result)
if result:
env.AddPostAction(result, ldconfig)
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)
env.Alias(target='install', source=result)
if result:
env.AddPostAction(result, ldconfig)
# Install symlinks
target1 = os.path.join(env['MAPNIK_LIB_BASE_DEST'], "%s.%d.%d" % (os.path.basename(str(mapnik[0])),int(major), int(minor)))
target2 = os.path.join(env['MAPNIK_LIB_BASE_DEST'], os.path.basename(str(mapnik[0])))
target1 = os.path.join(env['MAPNIK_LIB_BASE_DEST'], "%s.%d.%d" % \
(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 'install' in COMMAND_LINE_TARGETS:
link1 = env.Command(target1, target, symlink)
env.Alias(target='install', source=link1)
link2 = env.Command(target2, target1, symlink)
env.Alias(target='install', source=link2)
link1 = env.Command(target1, target, symlink)
env.Alias(target='install', source=link1)
link2 = env.Command(target2, target1, symlink)
env.Alias(target='install', source=link2)
# delete in reverse order..
env['create_uninstall_target'](env, target2)
env['create_uninstall_target'](env, target1)
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')
svg_includes = glob.glob('../include/mapnik/svg/*.hpp')
wkt_includes = glob.glob('../include/mapnik/wkt/*.hpp')

View file

@ -102,9 +102,13 @@ bool freetype_engine::register_font(std::string const& file_name)
// http://www.freetype.org/freetype2/docs/reference/ft2-base_interface.html#FT_FaceRec
if (face->family_name && face->style_name)
{
success = true;
std::string name = std::string(face->family_name) + " " + std::string(face->style_name);
name2file_.insert(std::make_pair(name, std::make_pair(i,file_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)));
}
}
else
{
@ -142,17 +146,27 @@ bool freetype_engine::register_fonts(std::string const& dir, bool recurse)
for (boost::filesystem::directory_iterator itr(dir); itr != end_itr; ++itr)
{
#if (BOOST_FILESYSTEM_VERSION == 3)
std::string const& file_name = itr->path().string();
std::string file_name = itr->path().string();
#else // v2
std::string const& file_name = itr->string();
std::string file_name = itr->string();
#endif
if (boost::filesystem::is_directory(*itr) && recurse)
{
success = register_fonts(file_name, true);
}
else if (boost::filesystem::is_regular_file(file_name) && is_font_file(file_name))
else
{
success = mapnik::freetype_engine::register_font(file_name);
#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);
}
}
}
return success;

View file

@ -135,11 +135,15 @@ public:
xmlError * error = xmlCtxtGetLastError( ctx_ );
std::ostringstream os;
os << "XML document not well formed";
int line=0;
std::string file;
if (error)
{
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_);

View file

@ -98,7 +98,7 @@ private:
void parse_metawriter_in_symbolizer(symbolizer_base &sym, xml_node const& pt);
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);
@ -455,44 +455,62 @@ void map_parser::parse_fontset(Map & map, xml_node const& fset)
{
name = fset.get_attr<std::string>("name");
font_set fontset(name);
xml_node::const_iterator itr = fset.begin();
xml_node::const_iterator end = fset.end();
bool success = false;
for (; itr != end; ++itr)
{
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);
// XXX Hack because map object isn't accessible by text_symbolizer
// when it's parsed
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);
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");
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);
return true;
}
else if (strict_)
{
throw config_error("Failed to find font face '" +
*face_name + "'");
}
fset.add_face_name(*face_name);
}
else
{
throw config_error("Must have 'face-name' set", f);
}
return false;
}
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
{
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];
try
mapnik::datasource_ptr ds = layer.datasource();
if (ds)
{
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();
if (ds)
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));
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 << ")";
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));
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_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();
}
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();
tr.backward(&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();
CoordTransform tr = view_transform();
tr.backward(&x,&y);
return query_point(index,x,y);
}
Map::~Map() {}

View file

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

View file

@ -33,19 +33,20 @@
namespace mapnik {
#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_;
#endif
projection::projection(std::string const& params)
: params_(params)
{
init(); //
init();
}
projection::projection(projection const& rhs)
: params_(rhs.params_)
{
init(); //
init();
}
projection& projection::operator=(projection const& rhs)
@ -158,9 +159,9 @@ std::string projection::expanded() const
return std::string("");
}
void projection::swap (projection& rhs)
void projection::swap(projection& rhs)
{
std::swap(params_,rhs.params_);
init ();
init();
}
}

View file

@ -428,11 +428,21 @@ void svg_parser::parse_path(xmlTextReaderPtr reader)
if (value)
{
path_.begin_path();
if (!mapnik::svg::parse_path((const char*) value, path_))
{
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();
xmlFree(value);
@ -450,7 +460,7 @@ void svg_parser::parse_polygon(xmlTextReaderPtr reader)
if (!mapnik::svg::parse_points((const char*) value, path_))
{
xmlFree(value);
throw std::runtime_error("Failed to parse <polygon>\n");
throw std::runtime_error("Failed to parse <polygon>");
}
path_.close_subpath();
path_.end_path();
@ -469,7 +479,7 @@ void svg_parser::parse_polyline(xmlTextReaderPtr reader)
if (!mapnik::svg::parse_points((const char*) value, path_))
{
xmlFree(value);
throw std::runtime_error("Failed to parse <polygon>\n");
throw std::runtime_error("Failed to parse <polygon>");
}
path_.end_path();

View file

@ -113,8 +113,9 @@ public:
{
int type = read_integer();
#ifdef MAPNIK_LOG
MAPNIK_LOG_DEBUG(wkb_reader) << "wkb_reader: Read=" << wkb_geometry_type_string(type) << "," << type;
#endif
switch (type)
{
case wkbPoint:
@ -401,6 +402,7 @@ private:
}
}
#ifdef MAPNIK_LOG
std::string wkb_geometry_type_string(int type)
{
std::stringstream s;
@ -426,6 +428,7 @@ private:
return s.str();
}
#endif
};
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>
namespace fs = boost::filesystem;
using fs::path;
@ -9,79 +7,72 @@ namespace sys = boost::system;
#include <iostream>
#include <mapnik/font_engine_freetype.hpp>
// --------------------------------------------------------------------------//
int main( int, char*[] )
{
std::string fontdir("fonts/");
BOOST_TEST( fs::exists( fontdir ) );
BOOST_TEST( fs::is_directory( fontdir ) );
// font registration() tests ----------------------------------------------//
std::vector<std::string> face_names;
std::string fontdir("fonts/");
BOOST_TEST( fs::exists( fontdir ) );
BOOST_TEST( fs::is_directory( fontdir ) );
std::string foo("foo");
std::vector<std::string> face_names;
// fake directories
BOOST_TEST( !mapnik::freetype_engine::register_fonts(foo , true ) );
face_names = mapnik::freetype_engine::face_names();
BOOST_TEST( face_names.size() == 0 );
BOOST_TEST( !mapnik::freetype_engine::register_fonts(foo) );
face_names = mapnik::freetype_engine::face_names();
BOOST_TEST( face_names.size() == 0 );
std::string foo("foo");
// directories without fonts
std::string src("src");
// an empty directory will not return true
// we need to register at least one font and not fail on any
// to return true
BOOST_TEST( mapnik::freetype_engine::register_font(src) == false );
BOOST_TEST( mapnik::freetype_engine::register_fonts(src, true) == false );
BOOST_TEST( mapnik::freetype_engine::face_names().size() == 0 );
// fake directories
BOOST_TEST( !mapnik::freetype_engine::register_fonts(foo , true ) );
face_names = mapnik::freetype_engine::face_names();
BOOST_TEST( face_names.size() == 0 );
BOOST_TEST( !mapnik::freetype_engine::register_fonts(foo) );
face_names = mapnik::freetype_engine::face_names();
BOOST_TEST( face_names.size() == 0 );
// bogus, emtpy file that looks like font
BOOST_TEST( mapnik::freetype_engine::register_font("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 );
// directories without fonts
std::string src("src");
// an empty directory will not return true
// we need to register at least one font and not fail on any
// to return true
BOOST_TEST( mapnik::freetype_engine::register_font(src) == false );
BOOST_TEST( mapnik::freetype_engine::register_fonts(src, true) == false );
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_fonts("tests/data/fonts/intentionally-broken.ttf") == false );
BOOST_TEST( mapnik::freetype_engine::face_names().size() == 0 );
// bogus, emtpy file that looks like font
BOOST_TEST( mapnik::freetype_engine::register_font("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 );
// register unifont, since we know it sits in the root fonts/ dir
BOOST_TEST( mapnik::freetype_engine::register_fonts(fontdir) );
face_names = mapnik::freetype_engine::face_names();
//std::clog << "number of registered fonts: " << face_names.size() << std::endl;
BOOST_TEST( face_names.size() > 0 );
BOOST_TEST( face_names.size() == 1 );
//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::face_names().size() == 0 );
// re-register unifont, should not have any affect
BOOST_TEST( mapnik::freetype_engine::register_fonts(fontdir, false) );
face_names = mapnik::freetype_engine::face_names();
//std::clog << "number of registered fonts: " << face_names.size() << std::endl;
BOOST_TEST( face_names.size() == 1 );
// register unifont, since we know it sits in the root fonts/ dir
BOOST_TEST( mapnik::freetype_engine::register_fonts(fontdir) );
face_names = mapnik::freetype_engine::face_names();
//std::clog << "number of registered fonts: " << face_names.size() << std::endl;
BOOST_TEST( face_names.size() > 0 );
BOOST_TEST( face_names.size() == 1 );
// register a single dejavu font
std::string dejavu_bold_oblique("tests/data/fonts/DejaVuSansMono-BoldOblique.ttf");
BOOST_TEST( mapnik::freetype_engine::register_font(dejavu_bold_oblique) );
face_names = mapnik::freetype_engine::face_names();
//std::clog << "number of registered fonts: " << face_names.size() << std::endl;
BOOST_TEST( face_names.size() == 2 );
// re-register unifont, should not have any affect
BOOST_TEST( mapnik::freetype_engine::register_fonts(fontdir, false) );
face_names = mapnik::freetype_engine::face_names();
//std::clog << "number of registered fonts: " << face_names.size() << std::endl;
BOOST_TEST( face_names.size() == 1 );
// recurse to find all dejavu fonts
BOOST_TEST( mapnik::freetype_engine::register_fonts(fontdir, true) );
face_names = mapnik::freetype_engine::face_names();
//std::clog << "number of registered fonts: " << face_names.size() << std::endl;
BOOST_TEST( face_names.size() == 22 );
// register a single dejavu font
std::string dejavu_bold_oblique("tests/data/fonts/DejaVuSansMono-BoldOblique.ttf");
BOOST_TEST( mapnik::freetype_engine::register_font(dejavu_bold_oblique) );
face_names = mapnik::freetype_engine::face_names();
//std::clog << "number of registered fonts: " << face_names.size() << std::endl;
BOOST_TEST( face_names.size() == 2 );
// recurse to find all dejavu fonts
BOOST_TEST( mapnik::freetype_engine::register_fonts(fontdir, true) );
face_names = mapnik::freetype_engine::face_names();
//std::clog << "number of registered fonts: " << face_names.size() << std::endl;
BOOST_TEST( face_names.size() == 22 );
if (!::boost::detail::test_errors()) {
std::clog << "C++ fonts registration: \x1b[1;32m✓ \x1b[0m\n";
} else {
return ::boost::report_errors();
}
if (!::boost::detail::test_errors()) {
std::clog << "C++ fonts registration: \x1b[1;32m✓ \x1b[0m\n";
} else {
return ::boost::report_errors();
}
}

View file

@ -7,71 +7,71 @@
int main( int, char*[] )
{
mapnik::parameters params;
// true
params["bool"] = true;
BOOST_TEST( (params.get<mapnik::boolean>("bool") && *params.get<mapnik::boolean>("bool") == true));
mapnik::parameters params;
params["bool"] = "true";
BOOST_TEST( (params.get<mapnik::boolean>("bool") && *params.get<mapnik::boolean>("bool") == true));
// true
params["bool"] = true;
BOOST_TEST( (params.get<mapnik::boolean>("bool") && *params.get<mapnik::boolean>("bool") == true));
params["bool"] = 1;
BOOST_TEST( (params.get<mapnik::boolean>("bool") && *params.get<mapnik::boolean>("bool") == true));
params["bool"] = "true";
BOOST_TEST( (params.get<mapnik::boolean>("bool") && *params.get<mapnik::boolean>("bool") == true));
params["bool"] = "1";
BOOST_TEST( (params.get<mapnik::boolean>("bool") && *params.get<mapnik::boolean>("bool") == true));
params["bool"] = 1;
BOOST_TEST( (params.get<mapnik::boolean>("bool") && *params.get<mapnik::boolean>("bool") == true));
params["bool"] = "True";
BOOST_TEST( (params.get<mapnik::boolean>("bool") && *params.get<mapnik::boolean>("bool") == true));
params["bool"] = "1";
BOOST_TEST( (params.get<mapnik::boolean>("bool") && *params.get<mapnik::boolean>("bool") == true));
params["bool"] = "on";
BOOST_TEST( (params.get<mapnik::boolean>("bool") && *params.get<mapnik::boolean>("bool") == true));
params["bool"] = "True";
BOOST_TEST( (params.get<mapnik::boolean>("bool") && *params.get<mapnik::boolean>("bool") == true));
params["bool"] = "yes";
BOOST_TEST( (params.get<mapnik::boolean>("bool") && *params.get<mapnik::boolean>("bool") == true));
params["bool"] = "on";
BOOST_TEST( (params.get<mapnik::boolean>("bool") && *params.get<mapnik::boolean>("bool") == true));
// false
params["bool"] = false;
BOOST_TEST( (params.get<mapnik::boolean>("bool") && *params.get<mapnik::boolean>("bool") == false) );
params["bool"] = "yes";
BOOST_TEST( (params.get<mapnik::boolean>("bool") && *params.get<mapnik::boolean>("bool") == true));
params["bool"] = "false";
BOOST_TEST( (params.get<mapnik::boolean>("bool") && *params.get<mapnik::boolean>("bool") == false) );
// false
params["bool"] = false;
BOOST_TEST( (params.get<mapnik::boolean>("bool") && *params.get<mapnik::boolean>("bool") == false) );
params["bool"] = 0;
BOOST_TEST( (params.get<mapnik::boolean>("bool") && *params.get<mapnik::boolean>("bool") == false));
params["bool"] = "false";
BOOST_TEST( (params.get<mapnik::boolean>("bool") && *params.get<mapnik::boolean>("bool") == false) );
params["bool"] = "0";
BOOST_TEST( (params.get<mapnik::boolean>("bool") && *params.get<mapnik::boolean>("bool") == false));
params["bool"] = 0;
BOOST_TEST( (params.get<mapnik::boolean>("bool") && *params.get<mapnik::boolean>("bool") == false));
params["bool"] = "False";
BOOST_TEST( (params.get<mapnik::boolean>("bool") && *params.get<mapnik::boolean>("bool") == false));
params["bool"] = "0";
BOOST_TEST( (params.get<mapnik::boolean>("bool") && *params.get<mapnik::boolean>("bool") == false));
params["bool"] = "off";
BOOST_TEST( (params.get<mapnik::boolean>("bool") && *params.get<mapnik::boolean>("bool") == false));
params["bool"] = "False";
BOOST_TEST( (params.get<mapnik::boolean>("bool") && *params.get<mapnik::boolean>("bool") == false));
params["bool"] = "no";
BOOST_TEST( (params.get<mapnik::boolean>("bool") && *params.get<mapnik::boolean>("bool") == false));
params["bool"] = "off";
BOOST_TEST( (params.get<mapnik::boolean>("bool") && *params.get<mapnik::boolean>("bool") == false));
// strings
params["string"] = "hello";
BOOST_TEST( (params.get<std::string>("string") && *params.get<std::string>("string") == "hello") );
params["bool"] = "no";
BOOST_TEST( (params.get<mapnik::boolean>("bool") && *params.get<mapnik::boolean>("bool") == false));
// int
params["int"] = 1;
BOOST_TEST( (params.get<int>("int") && *params.get<int>("int") == 1) );
// strings
params["string"] = "hello";
BOOST_TEST( (params.get<std::string>("string") && *params.get<std::string>("string") == "hello") );
// double
params["double"] = 1.5;
BOOST_TEST( (params.get<double>("double") && *params.get<double>("double") == 1.5) );
// int
params["int"] = 1;
BOOST_TEST( (params.get<int>("int") && *params.get<int>("int") == 1) );
// value_null
params["null"] = mapnik::value_null();
//BOOST_TEST( (params.get<mapnik::value_null>("null")/* && *params.get<mapnik::value_null>("null") == mapnik::value_null()*/) );
// double
params["double"] = 1.5;
BOOST_TEST( (params.get<double>("double") && *params.get<double>("double") == 1.5) );
if (!::boost::detail::test_errors()) {
std::clog << "C++ parameters: \x1b[1;32m✓ \x1b[0m\n";
} else {
return ::boost::report_errors();
}
// value_null
params["null"] = mapnik::value_null();
//BOOST_TEST( (params.get<mapnik::value_null>("null")/* && *params.get<mapnik::value_null>("null") == mapnik::value_null()*/) );
if (!::boost::detail::test_errors()) {
std::clog << "C++ parameters: \x1b[1;32m✓ \x1b[0m\n";
} else {
return ::boost::report_errors();
}
}

View file

@ -1,7 +1,7 @@
#define BOOST_TEST_MODULE background_color_test
/*
* This test module contains several generators for
* This test module contains several generators for
* the implementation of a background color in SVG
* using a rectangle.
*/
@ -25,16 +25,16 @@ namespace repository = boost::spirit::repository;
namespace fusion = boost::fusion;
using namespace karma;
struct F
struct F
{
F() :
x(0),
y(0),
width(100),
height(100),
bgcolor("#ffffff"),
expected_output("<rect x=\"0\" y=\"0\" width=\"100px\" height=\"100px\" style=\"fill: #ffffff\"/>") {}
x(0),
y(0),
width(100),
height(100),
bgcolor("#ffffff"),
expected_output("<rect x=\"0\" y=\"0\" width=\"100px\" height=\"100px\" style=\"fill: #ffffff\"/>") {}
~F() {}
const int x;
@ -61,14 +61,14 @@ struct F
BOOST_FIXTURE_TEST_CASE(bgcolor_stream_test_case, F)
{
actual_output
<< format(
"<rect x=\"" << int_ << "\" "
<< "y=\"" << int_ << "\" "
<< "width=\"" << int_ << string << "\" "
<< "height=\"" << int_ << string << "\" "
<< "style=\"fill: " << string << "\""
<< "/>",
x, y, width, "px", height, "px", bgcolor);
<< format(
"<rect x=\"" << int_ << "\" "
<< "y=\"" << int_ << "\" "
<< "width=\"" << int_ << string << "\" "
<< "height=\"" << int_ << string << "\" "
<< "style=\"fill: " << string << "\""
<< "/>",
x, y, width, "px", height, "px", bgcolor);
BOOST_CHECK_EQUAL(actual_output.str(), expected_output);
}
@ -79,7 +79,7 @@ BOOST_FIXTURE_TEST_CASE(bgcolor_stream_test_case, F)
*
* Notice that the generators' attribute list contains also tuples.
* Tuples are needed to specify each confix's attributes that contain
* more than one generator, like confix()[int_ << string] (this
* more than one generator, like confix()[int_ << string] (this
* generator needs a tuple: tuple<int, string>).
*
* The difference between this generator and the one in test case
@ -92,15 +92,15 @@ BOOST_FIXTURE_TEST_CASE(bgcolor_stream_confix_test_case, F)
using fusion::tuple;
actual_output
<< format(
"<rect x=" << confix('"', '"')[int_]
<< " y=" << confix('"', '"')[int_]
<< " width=" << confix('"', '"')[int_ << string]
<< " height=" << confix('"', '"')[int_ << string]
<< " style=" << confix('"', '"')["fill: " << string]
<< "/>",
x, y, tuple<int, std::string>(width, "px"), tuple<int, std::string>(height, "px"), bgcolor);
<< format(
"<rect x=" << confix('"', '"')[int_]
<< " y=" << confix('"', '"')[int_]
<< " width=" << confix('"', '"')[int_ << string]
<< " height=" << confix('"', '"')[int_ << string]
<< " style=" << confix('"', '"')["fill: " << string]
<< "/>",
x, y, tuple<int, std::string>(width, "px"), tuple<int, std::string>(height, "px"), bgcolor);
BOOST_CHECK_EQUAL(actual_output.str(), expected_output);
}
@ -109,11 +109,11 @@ BOOST_FIXTURE_TEST_CASE(bgcolor_stream_confix_test_case, F)
* using confix. notice that a confix generator can be part of another
* confix generator's expression.
*
* Notice also that the attribute list is the same as in
* 'bgcolor_stream_confix_test_case'. From this one can see that each
* generator is meant to have a list of attributes if it has more than one.
* Notice also that the attribute list is the same as in
* 'bgcolor_stream_confix_test_case'. From this one can see that each
* generator is meant to have a list of attributes if it has more than one.
*
* If the generator is nested inside another generator, the former's attribute
* If the generator is nested inside another generator, the former's attribute
* list will be another list (a tuple, for example) inside the latter's.
*/
BOOST_FIXTURE_TEST_CASE(bgcolor_stream_confix_complete_test_case, F)
@ -122,15 +122,15 @@ BOOST_FIXTURE_TEST_CASE(bgcolor_stream_confix_complete_test_case, F)
using fusion::tuple;
actual_output
<< format(
confix('<', "/>")[
"rect x=" << confix('"', '"')[int_]
<< " y=" << confix('"', '"')[int_]
<< " width=" << confix('"', '"')[int_ << string]
<< " height=" << confix('"', '"')[int_ << string]
<< " style=" << confix('"', '"')["fill: " << string]],
x, y, tuple<int, std::string>(width, "px"), tuple<int, std::string>(height, "px"), bgcolor);
<< format(
confix('<', "/>")[
"rect x=" << confix('"', '"')[int_]
<< " y=" << confix('"', '"')[int_]
<< " width=" << confix('"', '"')[int_ << string]
<< " height=" << confix('"', '"')[int_ << string]
<< " style=" << confix('"', '"')["fill: " << string]],
x, y, tuple<int, std::string>(width, "px"), tuple<int, std::string>(height, "px"), bgcolor);
BOOST_CHECK_EQUAL(actual_output.str(), expected_output);
}
@ -152,14 +152,14 @@ BOOST_FIXTURE_TEST_CASE(bgcolor_stream_iterator_test_case, F)
std::ostream_iterator<char> actual_output_iterator(actual_output);
generate(
actual_output_iterator,
confix("<", "/>")[
"rect x=" << confix('"', '"')[int_]
<< " y=" << confix('"', '"')[int_]
<< " width=" << confix('"', '"')[int_ << string]
<< " height=" << confix('"', '"')[int_ << string]
<< " style=" << confix('"', '"')["fill: " << string]],
x, y, tuple<int, std::string>(width, "px"), tuple<int, std::string>(height, "px"), bgcolor);
actual_output_iterator,
confix("<", "/>")[
"rect x=" << confix('"', '"')[int_]
<< " y=" << confix('"', '"')[int_]
<< " width=" << confix('"', '"')[int_ << string]
<< " height=" << confix('"', '"')[int_ << string]
<< " style=" << confix('"', '"')["fill: " << string]],
x, y, tuple<int, std::string>(width, "px"), tuple<int, std::string>(height, "px"), bgcolor);
BOOST_CHECK_EQUAL(actual_output.str(), expected_output);
}

View file

@ -37,21 +37,21 @@ BOOST_AUTO_TEST_CASE(combined_test_case)
svg_ren renderer(map, output_stream_iterator);
renderer.apply();
/*std::string expected_output =
svg_ren::XML_DECLARATION
+ "\n"
+ svg_ren::SVG_DTD
+ "\n"
+ "<svg width=\"800px\" height=\"600px\" version=\"1.1\" xmlns=\""
+ svg_ren::SVG_NAMESPACE_URL
+ "\">"
+"\n"
+"<rect x=\"0\" y=\"0\" width=\"800px\" height=\"600px\" style=\"fill: #ffffff\"/>"
+"\n"
+"</svg>";
/*std::string expected_output =
svg_ren::XML_DECLARATION
+ "\n"
+ svg_ren::SVG_DTD
+ "\n"
+ "<svg width=\"800px\" height=\"600px\" version=\"1.1\" xmlns=\""
+ svg_ren::SVG_NAMESPACE_URL
+ "\">"
+"\n"
+"<rect x=\"0\" y=\"0\" width=\"800px\" height=\"600px\" style=\"fill: #ffffff\"/>"
+"\n"
+"</svg>";
std::string actual_output = output_stream.str();
BOOST_CHECK_EQUAL(actual_output, expected_output);
std::string actual_output = output_stream.str();
BOOST_CHECK_EQUAL(actual_output, expected_output);
*/
}

View file

@ -51,15 +51,15 @@ BOOST_AUTO_TEST_CASE(file_output_test_case)
if(output_stream)
{
std::ostream_iterator<char> output_stream_iterator(output_stream);
svg_ren renderer(map, output_stream_iterator);
renderer.apply();
output_stream.close();
filesystem::path output_filename_path =
filesystem::path output_filename_path =
filesystem::system_complete(filesystem::path(".")) / filesystem::path(output_filename);
BOOST_CHECK_MESSAGE(filesystem::exists(output_filename_path), "File '"+output_filename_path.string()+"' was created.");
}
else

View file

@ -25,54 +25,54 @@ namespace filesystem = boost::filesystem;
using namespace mapnik;
void prepare_map(Map& m)
{
{
const std::string mapnik_dir("/usr/local/lib/mapnik/");
std::cout << " looking for 'shape.input' plugin in... " << mapnik_dir << "input/" << "\n";
datasource_cache::instance()->register_datasources(mapnik_dir + "input/");
datasource_cache::instance()->register_datasources(mapnik_dir + "input/");
// create styles
// Provinces (polygon)
feature_type_style provpoly_style;
rule provpoly_rule_on;
provpoly_rule_on.set_filter(parse_expression("[NAME_EN] = 'Ontario'"));
provpoly_rule_on.append(polygon_symbolizer(color(250, 190, 183)));
provpoly_style.add_rule(provpoly_rule_on);
rule provpoly_rule_qc;
provpoly_rule_qc.set_filter(parse_expression("[NOM_FR] = 'Québec'"));
provpoly_rule_qc.append(polygon_symbolizer(color(217, 235, 203)));
provpoly_style.add_rule(provpoly_rule_qc);
m.insert_style("provinces",provpoly_style);
// Provinces (polyline)
feature_type_style provlines_style;
stroke provlines_stk (color(0,0,0),1.0);
provlines_stk.add_dash(8, 4);
provlines_stk.add_dash(2, 2);
provlines_stk.add_dash(2, 2);
rule provlines_rule;
provlines_rule.append(line_symbolizer(provlines_stk));
provlines_style.add_rule(provlines_rule);
m.insert_style("provlines",provlines_style);
// Drainage
// Drainage
feature_type_style qcdrain_style;
rule qcdrain_rule;
qcdrain_rule.set_filter(parse_expression("[HYC] = 8"));
qcdrain_rule.append(polygon_symbolizer(color(153, 204, 255)));
qcdrain_style.add_rule(qcdrain_rule);
m.insert_style("drainage",qcdrain_style);
// Roads 3 and 4 (The "grey" roads)
feature_type_style roads34_style;
feature_type_style roads34_style;
rule roads34_rule;
roads34_rule.set_filter(parse_expression("[CLASS] = 3 or [CLASS] = 4"));
stroke roads34_rule_stk(color(171,158,137),2.0);
@ -80,9 +80,9 @@ void prepare_map(Map& m)
roads34_rule_stk.set_line_join(ROUND_JOIN);
roads34_rule.append(line_symbolizer(roads34_rule_stk));
roads34_style.add_rule(roads34_rule);
m.insert_style("smallroads",roads34_style);
// Roads 2 (The thin yellow ones)
feature_type_style roads2_style_1;
rule roads2_rule_1;
@ -92,9 +92,9 @@ void prepare_map(Map& m)
roads2_rule_stk_1.set_line_join(ROUND_JOIN);
roads2_rule_1.append(line_symbolizer(roads2_rule_stk_1));
roads2_style_1.add_rule(roads2_rule_1);
m.insert_style("road-border", roads2_style_1);
feature_type_style roads2_style_2;
rule roads2_rule_2;
roads2_rule_2.set_filter(parse_expression("[CLASS] = 2"));
@ -103,9 +103,9 @@ void prepare_map(Map& m)
roads2_rule_stk_2.set_line_join(ROUND_JOIN);
roads2_rule_2.append(line_symbolizer(roads2_rule_stk_2));
roads2_style_2.add_rule(roads2_rule_2);
m.insert_style("road-fill", roads2_style_2);
// Roads 1 (The big orange ones, the highways)
feature_type_style roads1_style_1;
rule roads1_rule_1;
@ -116,7 +116,7 @@ void prepare_map(Map& m)
roads1_rule_1.append(line_symbolizer(roads1_rule_stk_1));
roads1_style_1.add_rule(roads1_rule_1);
m.insert_style("highway-border", roads1_style_1);
feature_type_style roads1_style_2;
rule roads1_rule_2;
roads1_rule_2.set_filter(parse_expression("[CLASS] = 1"));
@ -125,21 +125,21 @@ void prepare_map(Map& m)
roads1_rule_stk_2.set_line_join(ROUND_JOIN);
roads1_rule_2.append(line_symbolizer(roads1_rule_stk_2));
roads1_style_2.add_rule(roads1_rule_2);
m.insert_style("highway-fill", roads1_style_2);
m.insert_style("highway-fill", roads1_style_2);
// layers
// Provincial polygons
{
parameters p;
p["type"]="shape";
p["file"]="../../../demo/data/boundaries";
layer lyr("Provinces");
layer lyr("Provinces");
lyr.set_datasource(datasource_cache::instance()->create(p));
lyr.add_style("provinces");
lyr.add_style("provinces");
m.addLayer(lyr);
}
// Drainage
{
parameters p;
@ -147,46 +147,46 @@ void prepare_map(Map& m)
p["file"]="../../../demo/data/qcdrainage";
layer lyr("Quebec Hydrography");
lyr.set_datasource(datasource_cache::instance()->create(p));
lyr.add_style("drainage");
lyr.add_style("drainage");
m.addLayer(lyr);
}
{
parameters p;
p["type"]="shape";
p["file"]="../../../demo/data/ontdrainage";
layer lyr("Ontario Hydrography");
layer lyr("Ontario Hydrography");
lyr.set_datasource(datasource_cache::instance()->create(p));
lyr.add_style("drainage");
lyr.add_style("drainage");
m.addLayer(lyr);
}
// Provincial boundaries
{
parameters p;
p["type"]="shape";
p["file"]="../../../demo/data/boundaries_l";
layer lyr("Provincial borders");
layer lyr("Provincial borders");
lyr.set_datasource(datasource_cache::instance()->create(p));
lyr.add_style("provlines");
lyr.add_style("provlines");
m.addLayer(lyr);
}
// Roads
{
parameters p;
p["type"]="shape";
p["file"]="../../../demo/data/roads";
layer lyr("Roads");
p["file"]="../../../demo/data/roads";
layer lyr("Roads");
lyr.set_datasource(datasource_cache::instance()->create(p));
lyr.add_style("smallroads");
lyr.add_style("road-border");
lyr.add_style("road-fill");
lyr.add_style("highway-border");
lyr.add_style("highway-fill");
m.addLayer(lyr);
m.addLayer(lyr);
}
}
@ -197,19 +197,19 @@ void render_to_file(Map const& m, const std::string output_filename)
if(output_stream)
{
typedef svg_renderer<std::ostream_iterator<char> > svg_ren;
std::ostream_iterator<char> output_stream_iterator(output_stream);
svg_ren renderer(m, output_stream_iterator);
renderer.apply();
output_stream.close();
filesystem::path output_filename_path =
filesystem::path output_filename_path =
filesystem::system_complete(filesystem::path(".")) / filesystem::path(output_filename);
BOOST_CHECK_MESSAGE(filesystem::exists(output_filename_path),
"File '"+output_filename_path.string()+"' was created.");
BOOST_CHECK_MESSAGE(filesystem::exists(output_filename_path),
"File '"+output_filename_path.string()+"' was created.");
}
else
{
@ -220,12 +220,12 @@ void render_to_file(Map const& m, const std::string output_filename)
BOOST_AUTO_TEST_CASE(path_element_test_case_1)
{
Map m(800,600);
m.set_background(color_factory::from_string("steelblue"));
m.set_background(color_factory::from_string("steelblue"));
prepare_map(m);
//m.zoom_to_box(box2d<double>(1405120.04127408, -247003.813399447,
//1706357.31328276, -25098.593149577));
m.zoom_all();
//1706357.31328276, -25098.593149577));
m.zoom_all();
render_to_file(m, "path_element_test_case_1.svg");
}

View file

@ -1,7 +1,7 @@
#define BOOST_TEST_MODULE root_element_test
/*
* This test module contains several generators for
* This test module contains several generators for
* the SVG root element.
*/
@ -24,14 +24,14 @@ namespace repository = boost::spirit::repository;
namespace fusion = boost::fusion;
using namespace karma;
struct F
struct F
{
F() :
width(100),
height(100),
version(1.1),
xmlns("http://www.w3.org/2000/svg"),
expected_output("<svg width=\"100px\" height=\"100px\" version=\"1.1\" xmlns=\"http://www.w3.org/2000/svg\">") {}
width(100),
height(100),
version(1.1),
xmlns("http://www.w3.org/2000/svg"),
expected_output("<svg width=\"100px\" height=\"100px\" version=\"1.1\" xmlns=\"http://www.w3.org/2000/svg\">") {}
~F() {}
@ -58,13 +58,13 @@ struct F
BOOST_FIXTURE_TEST_CASE(bgcolor_stream_test_case, F)
{
actual_output
<< format(
"<svg width=\"" << int_ << string << "\" "
<< "height=\"" << int_ << string << "\" "
<< "version=\"" << float_ << "\" "
<< "xmlns=\"" << string << "\""
<< ">",
width, "px", height, "px", version, xmlns);
<< format(
"<svg width=\"" << int_ << string << "\" "
<< "height=\"" << int_ << string << "\" "
<< "version=\"" << float_ << "\" "
<< "xmlns=\"" << string << "\""
<< ">",
width, "px", height, "px", version, xmlns);
BOOST_CHECK_EQUAL(actual_output.str(), expected_output);
}
@ -75,7 +75,7 @@ BOOST_FIXTURE_TEST_CASE(bgcolor_stream_test_case, F)
*
* Notice that the generators' attribute list contains also tuples.
* Tuples are needed to specify each confix's attributes that contain
* more than one generator, like confix()[int_ << string] (this
* more than one generator, like confix()[int_ << string] (this
* generator needs a tuple: tuple<int, string>).
*
* The difference between this generator and the one in test case
@ -88,14 +88,14 @@ BOOST_FIXTURE_TEST_CASE(bgcolor_stream_confix_test_case, F)
using fusion::tuple;
actual_output
<< format(
"<svg width=" << confix('"', '"')[int_ << string]
<< " height=" << confix('"', '"')[int_ << string]
<< " version=" << confix('"', '"')[float_]
<< " xmlns=" << confix('"', '"')[string]
<< ">",
tuple<int, std::string>(width, "px"), tuple<int, std::string>(height, "px"), version, xmlns);
<< format(
"<svg width=" << confix('"', '"')[int_ << string]
<< " height=" << confix('"', '"')[int_ << string]
<< " version=" << confix('"', '"')[float_]
<< " xmlns=" << confix('"', '"')[string]
<< ">",
tuple<int, std::string>(width, "px"), tuple<int, std::string>(height, "px"), version, xmlns);
BOOST_CHECK_EQUAL(actual_output.str(), expected_output);
}
@ -104,11 +104,11 @@ BOOST_FIXTURE_TEST_CASE(bgcolor_stream_confix_test_case, F)
* using confix. notice that a confix generator can be part of another
* confix generator's expression.
*
* Notice also that the attribute list is the same as in
* 'bgcolor_stream_confix_test_case'. From this one can see that each
* generator is meant to have a list of attributes if it has more than one.
* Notice also that the attribute list is the same as in
* 'bgcolor_stream_confix_test_case'. From this one can see that each
* generator is meant to have a list of attributes if it has more than one.
*
* If the generator is nested inside another generator, the former's attribute
* If the generator is nested inside another generator, the former's attribute
* list will be another list (a tuple, for example) inside the latter's.
*/
BOOST_FIXTURE_TEST_CASE(bgcolor_stream_confix_complete_test_case, F)
@ -117,14 +117,14 @@ BOOST_FIXTURE_TEST_CASE(bgcolor_stream_confix_complete_test_case, F)
using fusion::tuple;
actual_output
<< format(
confix('<', ">")[
"svg width=" << confix('"', '"')[int_ << string]
<< " height=" << confix('"', '"')[int_ << string]
<< " version=" << confix('"', '"')[float_]
<< " xmlns=" << confix('"', '"')[string]],
tuple<int, std::string>(width, "px"), tuple<int, std::string>(height, "px"), version, xmlns);
<< format(
confix('<', ">")[
"svg width=" << confix('"', '"')[int_ << string]
<< " height=" << confix('"', '"')[int_ << string]
<< " version=" << confix('"', '"')[float_]
<< " xmlns=" << confix('"', '"')[string]],
tuple<int, std::string>(width, "px"), tuple<int, std::string>(height, "px"), version, xmlns);
BOOST_CHECK_EQUAL(actual_output.str(), expected_output);
}
@ -146,13 +146,13 @@ BOOST_FIXTURE_TEST_CASE(bgcolor_stream_iterator_test_case, F)
std::ostream_iterator<char> actual_output_iterator(actual_output);
generate(
actual_output_iterator,
confix("<", ">")[
"svg width=" << confix('"', '"')[int_ << string]
<< " height=" << confix('"', '"')[int_ << string]
<< " version=" << confix('"', '"')[float_]
<< " xmlns=" << confix('"', '"')[string]],
tuple<int, std::string>(width, "px"), tuple<int, std::string>(height, "px"), version, xmlns);
actual_output_iterator,
confix("<", ">")[
"svg width=" << confix('"', '"')[int_ << string]
<< " height=" << confix('"', '"')[int_ << string]
<< " version=" << confix('"', '"')[float_]
<< " xmlns=" << confix('"', '"')[string]],
tuple<int, std::string>(width, "px"), tuple<int, std::string>(height, "px"), version, xmlns);
BOOST_CHECK_EQUAL(actual_output.str(), expected_output);
}

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.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
# images paths are now PathExpressions are evaluated at runtime
# 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.layers.append(lyr)
# point inside raster extent with valid data
x, y = 427417, 4477517
x, y = 556113.0,4381428.0 # center of extent of raster
_map.zoom_all()
features = _map.query_point(0,x,y).features
assert len(features) == 1
feat = features[0]
center = feat.envelope().center()
assert center.x==x and center.y==y, center
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
assert len(features) == 0

View file

@ -71,6 +71,88 @@ if 'sqlite' in mapnik.DatasourceCache.instance().plugin_names():
eq_(os.path.exists(index),True)
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__":
setup()

View file

@ -27,13 +27,13 @@ def compare(fn1, fn2):
try:
im2 = Image.open(fn2)
except IOError:
errors.append((fn1, None))
errors.append((fn1, None, fn2))
return -1
diff = 0
pixels = im1.size[0] * im1.size[1]
delta_pixels = im2.size[0] * im2.size[1] - pixels
if delta_pixels != 0:
errors.append((fn1, delta_pixels))
errors.append((fn1, delta_pixels, fn2))
return delta_pixels
im1 = im1.getdata()
im2 = im2.getdata()
@ -41,7 +41,7 @@ def compare(fn1, fn2):
if(compare_pixels(im1[i], im2[i])):
diff = diff + 1
if diff != 0:
errors.append((fn1, diff))
errors.append((fn1, diff, fn2))
passed += 1
return diff
@ -55,7 +55,7 @@ def summary():
if (error[1] is None):
print "Could not verify %s: No reference image found!" % error[0]
else:
print "%s failed: %d different pixels" % error
print "%s failed: %d different pixels \n\t%s (expected)" % error
sys.exit(1)
else:
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)
else:
m.zoom_all()
basefn = os.path.join(dirname, "images", '%s-%d' % (filename, width))
mapnik.render_to_file(m, basefn+'-agg.png')
diff = compare(basefn + '-agg.png', basefn + '-reference.png')
expected = os.path.join(dirname, "images", '%s-%d-reference.png' % (filename, width))
if not os.path.exists('/tmp/mapnik-visual-images'):
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:
print "-"*80
print '\x1b[33mError:\x1b[0m %u different pixels' % diff

View file

@ -3,7 +3,7 @@
# batch format *.{hpp,cpp} files
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"
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 = []
boost_program_options = 'boost_program_options%s' % env['BOOST_APPEND']
@ -49,7 +54,7 @@ if env['SQLITE_LINKFLAGS']:
if env['RUNTIME_LINK'] == 'static':
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']))
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'])
boost_program_options = 'boost_program_options%s' % env['BOOST_APPEND']
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']))

View file

@ -23,8 +23,10 @@
#include <iostream>
#include <sstream>
#include <vector>
//#include <string>
#include <string>
#include <mapnik/version.hpp>
#include <mapnik/debug.hpp>
#include <mapnik/marker.hpp>
#include <mapnik/marker_cache.hpp>
#include <mapnik/image_util.hpp>
@ -44,13 +46,19 @@
#include "agg_pixfmt_rgba.h"
#include "agg_scanline_u.h"
#include <libxml/parser.h> // for xmlInitParser(), xmlCleanupParser()
int main (int argc,char** argv)
{
namespace po = boost::program_options;
bool verbose=false;
bool verbose = false;
bool auto_open = false;
bool error = false;
std::vector<std::string> svg_files;
mapnik::logger logger;
logger.set_severity(mapnik::logger::error);
try
{
@ -59,6 +67,7 @@ int main (int argc,char** argv)
("help,h", "produce usage message")
("version,V","print version string")
("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")
;
@ -70,7 +79,7 @@ int main (int argc,char** argv)
if (vm.count("version"))
{
std::clog<<"version 0.3.0" << std::endl;
std::clog <<"version " << MAPNIK_VERSION_STRING << std::endl;
return 1;
}
@ -79,11 +88,17 @@ int main (int argc,char** argv)
std::clog << desc << std::endl;
return 1;
}
if (vm.count("verbose"))
{
verbose = true;
}
if (vm.count("open"))
{
auto_open = true;
}
if (vm.count("svg"))
{
svg_files=vm["svg"].as< std::vector<std::string> >();
@ -100,66 +115,97 @@ int main (int argc,char** argv)
std::clog << "no svg files to render" << std::endl;
return 0;
}
xmlInitParser();
while (itr != svg_files.end())
{
std::string svg_name (*itr++);
boost::optional<mapnik::marker_ptr> marker_ptr = mapnik::marker_cache::instance()->find(svg_name, false);
if (marker_ptr) {
mapnik::marker marker = **marker_ptr;
if (marker.is_vector()) {
typedef agg::pixfmt_rgba32_plain pixfmt;
typedef agg::renderer_base<pixfmt> renderer_base;
typedef agg::renderer_scanline_aa_solid<renderer_base> renderer_solid;
agg::rasterizer_scanline_aa<> ras_ptr;
agg::scanline_u8 sl;
double opacity = 1;
double scale_factor_ = .95;
int w = marker.width();
int h = marker.height();
mapnik::image_32 im(w,h);
agg::rendering_buffer buf(im.raw_data(), w, h, w * 4);
pixfmt pixf(buf);
renderer_base renb(pixf);
mapnik::box2d<double> const& bbox = (*marker.get_vector_data())->bounding_box();
mapnik::coord<double,2> c = bbox.center();
// center the svg marker on '0,0'
agg::trans_affine mtx = agg::trans_affine_translation(-c.x,-c.y);
// apply symbol transformation to get to map space
mtx *= agg::trans_affine_scaling(scale_factor_);
// render the marker at the center of the marker box
mtx.translate(0.5 * w, 0.5 * h);
mapnik::svg::vertex_stl_adapter<mapnik::svg::svg_path_storage> stl_storage((*marker.get_vector_data())->source());
mapnik::svg::svg_path_adapter svg_path(stl_storage);
mapnik::svg::svg_renderer<mapnik::svg::svg_path_adapter,
agg::pod_bvector<mapnik::svg::path_attributes>,
renderer_solid,
agg::pixfmt_rgba32_plain > svg_renderer_this(svg_path,
(*marker.get_vector_data())->attributes());
svg_renderer_this.render(ras_ptr, sl, renb, mtx, opacity, bbox);
boost::algorithm::ireplace_last(svg_name,".svg",".png");
mapnik::save_to_file<mapnik::image_data_32>(im.data(),svg_name,"png");
std::ostringstream s;
s << "open " << svg_name;
return system(s.str().c_str());
}
if (verbose)
{
std::clog << "found: " << svg_name << "\n";
}
boost::optional<mapnik::marker_ptr> 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;
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::renderer_base<pixfmt> renderer_base;
typedef agg::renderer_scanline_aa_solid<renderer_base> renderer_solid;
agg::rasterizer_scanline_aa<> ras_ptr;
agg::scanline_u8 sl;
double opacity = 1;
double scale_factor_ = .95;
int w = marker.width();
int h = marker.height();
if (verbose)
{
std::clog << "found width of '" << w << "' and height of '" << h << "'\n";
}
mapnik::image_32 im(w,h);
agg::rendering_buffer buf(im.raw_data(), w, h, w * 4);
pixfmt pixf(buf);
renderer_base renb(pixf);
mapnik::box2d<double> const& bbox = (*marker.get_vector_data())->bounding_box();
mapnik::coord<double,2> c = bbox.center();
// center the svg marker on '0,0'
agg::trans_affine mtx = agg::trans_affine_translation(-c.x,-c.y);
// apply symbol transformation to get to map space
mtx *= agg::trans_affine_scaling(scale_factor_);
// render the marker at the center of the marker box
mtx.translate(0.5 * w, 0.5 * h);
mapnik::svg::vertex_stl_adapter<mapnik::svg::svg_path_storage> stl_storage((*marker.get_vector_data())->source());
mapnik::svg::svg_path_adapter svg_path(stl_storage);
mapnik::svg::svg_renderer<mapnik::svg::svg_path_adapter,
agg::pod_bvector<mapnik::svg::path_attributes>,
renderer_solid,
agg::pixfmt_rgba32_plain > svg_renderer_this(svg_path,
(*marker.get_vector_data())->attributes());
svg_renderer_this.render(ras_ptr, sl, renb, mtx, opacity, bbox);
boost::algorithm::ireplace_last(svg_name,".svg",".png");
mapnik::save_to_file<mapnik::image_data_32>(im.data(),svg_name,"png");
#ifdef DARWIN
if (auto_open)
{
std::ostringstream s;
s << "open " << svg_name;
system(s.str().c_str());
}
#endif
std::clog << "rendered to: " << svg_name << "\n";
}
}
catch (...)
{
std::clog << "Exception of unknown type!" << std::endl;
xmlCleanupParser();
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;
}