- merged strict-xml-branch r530:532 to trunk:

- libxml2 support
    - strict error handling while parsing XML map files
    - implemented save_map()
    - removed some duplicate defaults
    - all symbolizers with icons share a common base class now
This commit is contained in:
David 2007-09-25 18:47:12 +00:00
parent 49e6d1d7bf
commit b2df387a9d
42 changed files with 2482 additions and 811 deletions

View file

@ -27,12 +27,13 @@ if platform.uname()[4] == 'x86_64':
else:
LIBDIR_SCHEMA='lib'
opts = Options()
opts = Options('config.py')
opts.Add('PREFIX', 'The install path "prefix"', '/usr/local')
opts.Add(PathOption('BOOST_INCLUDES', 'Search path for boost include files', '/usr/include'))
opts.Add(PathOption('BOOST_LIBS', 'Search path for boost library files', '/usr/' + LIBDIR_SCHEMA))
opts.Add('BOOST_TOOLKIT','Specify boost toolkit e.g. gcc41.','',False)
opts.Add(('FREETYPE_CONFIG', 'The path to the freetype-config executable.', 'freetype-config'))
opts.Add(('XML2_CONFIG', 'The path to the xml2-config executable.', 'xml2-config'))
opts.Add(PathOption('FRIBIDI_INCLUDES', 'Search path for fribidi include files', '/usr/include'))
opts.Add(PathOption('FRIBIDI_LIBS','Search path for fribidi include files','/usr/' + LIBDIR_SCHEMA))
opts.Add(PathOption('PNG_INCLUDES', 'Search path for libpng include files', '/usr/include'))
@ -56,7 +57,7 @@ opts.Add(BoolOption('DEBUG', 'Compile a debug version of mapnik', 'False'))
opts.Add('DESTDIR', 'The root directory to install into. Useful mainly for binary package building', '/')
opts.Add(BoolOption('BIDI', 'BIDI support', 'False'))
opts.Add(EnumOption('THREADING','Set threading support','multi', ['multi','single']))
opts.Add(EnumOption('XMLPARSER','Set xml parser ','tinyxml', ['tinyxml','spirit']))
opts.Add(EnumOption('XMLPARSER','Set xml parser ','tinyxml', ['tinyxml','spirit','libxml2']))
env = Environment(ENV=os.environ, options=opts)
@ -105,6 +106,9 @@ if env['BIDI']:
if env['XMLPARSER'] == 'tinyxml':
env.Append(CXXFLAGS = '-DBOOST_PROPERTY_TREE_XML_PARSER_TINYXML -DTIXML_USE_STL')
elif env['XMLPARSER'] == 'libxml2':
env.ParseConfig(env['XML2_CONFIG'] + ' --libs --cflags')
env.Append(CXXFLAGS = '-DHAVE_LIBXML2');
C_LIBSHEADERS = [
['m', 'math.h', True],
@ -224,10 +228,12 @@ env = conf.Finish()
if env['PLATFORM'] == 'Darwin': pthread = ''
else: pthread = '-pthread'
common_cxx_flags = '-ansi -Wall %s -ftemplate-depth-100 -D%s ' % (pthread, env['PLATFORM'].upper());
if env['DEBUG']:
env.Append(CXXFLAGS = '-ansi -Wall %s -ftemplate-depth-100 -O0 -fno-inline -g -DDEBUG -DMAPNIK_DEBUG -D%s ' % (pthread, env['PLATFORM'].upper()))
env.Append(CXXFLAGS = common_cxx_flags + '-O0 -fno-inline -g -DDEBUG -DMAPNIK_DEBUG')
else:
env.Append(CXXFLAGS = '-ansi -Wall %s -ftemplate-depth-100 -O2 -finline-functions -Wno-inline -DNDEBUG -D%s' % (pthread,env['PLATFORM'].upper()))
env.Append(CXXFLAGS = common_cxx_flags + '-O2 -finline-functions -Wno-inline -DNDEBUG')
# Install some free default fonts

View file

@ -90,7 +90,10 @@ DatasourceCache.instance().register_datasources('%s' % inputpluginspath)
from mapnik import FontEngine
from glob import glob
fonts = glob('%s/*.ttf' % fontscollectionpath)
map(FontEngine.instance().register_font, fonts)
if len( fonts ) == 0:
print "### WARNING: No ttf files found in '%s'." % fontscollectionpath
else:
map(FontEngine.instance().register_font, fonts)
#set dlopen flags back to the original
setdlopenflags(flags)

View file

@ -24,6 +24,7 @@
#include <boost/python.hpp>
#include <boost/get_pointer.hpp>
#include <boost/python/detail/api_placeholder.hpp>
#include <boost/python/exception_translator.hpp>
void export_color();
void export_coord();
@ -58,6 +59,7 @@ void export_projection();
#include <mapnik/agg_renderer.hpp>
#include <mapnik/graphics.hpp>
#include <mapnik/load_map.hpp>
#include <mapnik/config_error.hpp>
#include <mapnik/save_map.hpp>
@ -95,14 +97,21 @@ double scale_denominator(mapnik::Map const &map, bool geographic)
return mapnik::scale_denominator(map, geographic);
}
void translator(mapnik::config_error const & ex) {
PyErr_SetString(PyExc_UserWarning, ex.what());
}
BOOST_PYTHON_FUNCTION_OVERLOADS(load_map_overloads, load_map, 2, 3);
BOOST_PYTHON_MODULE(_mapnik)
{
using namespace boost::python;
using mapnik::load_map;
using mapnik::save_map;
register_exception_translator<mapnik::config_error>(translator);
export_query();
export_feature();
export_featureset();
@ -137,8 +146,8 @@ BOOST_PYTHON_MODULE(_mapnik)
def("render",&render2);
def("scale_denominator", &scale_denominator);
def("load_map",&load_map,"load Map object from XML");
def("save_map",&load_map,"sace Map object to XML");
def("load_map", & load_map, load_map_overloads());
def("save_map", & save_map, "save Map object to XML");
using mapnik::symbolizer;
class_<symbolizer>("Symbolizer",no_init)

View file

@ -30,12 +30,12 @@ void export_stroke ()
using namespace mapnik;
using namespace boost::python;
enum_<line_cap_e>("line_cap")
enum_<line_cap_enum>("line_cap")
.value("BUTT_CAP",BUTT_CAP)
.value("SQUARE_CAP",SQUARE_CAP)
.value("ROUND_CAP",ROUND_CAP)
;
enum_<line_join_e>("line_join")
enum_<line_join_enum>("line_join")
.value("MITER_JOIN",MITER_JOIN)
.value("MITER_REVERT_JOIN",MITER_REVERT_JOIN)
.value("ROUND_JOIN",ROUND_JOIN)

View file

@ -32,9 +32,9 @@ void export_text_symbolizer()
using mapnik::text_symbolizer;
using mapnik::Color;
enum_<mapnik::label_placement_e>("label_placement")
.value("LINE_PLACEMENT",mapnik::line_placement)
.value("POINT_PLACEMENT",mapnik::point_placement)
enum_<mapnik::label_placement_enum>("label_placement")
.value("LINE_PLACEMENT",mapnik::LINE_PLACEMENT)
.value("POINT_PLACEMENT",mapnik::POINT_PLACEMENT)
;
class_<text_symbolizer>("TextSymbolizer",

View file

@ -104,6 +104,11 @@ namespace mapnik {
return abgr_ == other.abgr_;
}
inline bool operator!=(Color const& other) const
{
return abgr_ != other.abgr_;
}
inline std::string to_string() const
{
std::stringstream ss;

View file

@ -27,6 +27,7 @@
#include <mapnik/config.hpp>
#include <mapnik/css_color_parser.hpp>
#include <mapnik/config_error.hpp>
using namespace boost::spirit;
@ -40,8 +41,11 @@ namespace mapnik {
actions<Color> a(color);
css_color_grammar<actions<Color> > grammar(a);
parse_info<> info = parse(css_color, grammar, space_p);
if (info.full) return color;
return Color(0,0,0);
if ( ! info.full) {
throw config_error(std::string("Failed to parse color value: ") +
"Expected a color, but got '" + css_color + "'");
}
return color;
}
private:
color_factory();

View file

@ -0,0 +1,47 @@
#ifndef MAPNIK_CONFIG_ERROR_INCLUDED
#define MAPNIK_CONFIG_ERROR_INCLUDED
#include <iostream>
#include <sstream>
namespace mapnik {
class config_error : public std::exception
{
public:
config_error() {}
config_error( const std::string & what ) :
what_( what )
{
}
virtual ~config_error() throw() {};
virtual const char * what() const throw()
{
std::ostringstream os;
os << what_;
if ( ! context_.empty() )
{
os << std::endl << context_;
}
os << ".";
return os.str().c_str();
}
void append_context(const std::string & ctx) const
{
if ( ! context_.empty() )
{
context_ += " ";
}
context_ += ctx;
}
protected:
std::string what_;
mutable std::string context_;
};
}
#endif // MAPNIK_CONFIG_ERROR_INCLUDED

View file

@ -52,9 +52,9 @@ namespace mapnik {
class MAPNIK_DECL datasource_exception : public std::exception
{
private:
const std::string message_;
std::string message_;
public:
datasource_exception(const std::string& message=std::string())
datasource_exception(const std::string& message=std::string("no reason"))
:message_(message) {}
~datasource_exception() throw() {}

View file

@ -0,0 +1,291 @@
#ifndef MAPNIK_ENUMERATION_INCLUDED
#define MAPNIK_ENUMERATION_INCLUDED
#include <vector>
#include <bitset>
#include <iostream>
namespace mapnik {
class illegal_enum_value : public std::exception
{
public:
illegal_enum_value() {}
illegal_enum_value( const std::string & what ) :
what_( what )
{
}
virtual ~illegal_enum_value() throw() {};
virtual const char * what() const throw()
{
return what_.c_str();
}
protected:
std::string what_;
};
/** Slim wrapper for enumerations. It creates a new type from a native enum and
* a char pointer array. It almost exactly behaves like a native enumeration
* type. It supports string conversion through stream operators. This is usefull
* for debugging, serialization/deserialization and also helps with implementing
* language bindings. The two convinient macros DEFINE_ENUM() and IMPLEMENT_ENUM()
* are provided to help with instanciation.
*
* @par Limitations:
* - The enum must start at zero.
* - The enum must be consecutive.
* - The enum must be terminated with a special token consisting of the enum's
* name plus "_MAX".
* - The corresponding char pointer array must be terminated with an empty string.
* - The names must only consist of characters and digits (<i>a-z, A-Z, 0-9</i>),
* underscores (<i>_</i>) and dashes (<i>-</i>).
*
*
* @warning At the moment the verify() method is called during static initialization.
* It quits the application with exit code 1 if any error is detected. The other solution
* i thought of is to do the checks at compile time (using boost::mpl).
*
* @par Example:
* The following code goes into the header file:
* @code
* enum fruit_enum {
* APPLE,
* CHERRY,
* BANANA,
* PASSION_FRUIT,
* fruit_enum_MAX
* };
*
* static const char * fruit_strings[] = {
* "apple",
* "cherry",
* "banana",
* "passion_fruit",
* ""
* };
*
* DEFINE_ENUM( fruit, fruit_enum);
* @endcode
* In the corresponding cpp file do:
* @code
* IMPLEMENT_ENUM( fruit, fruit_strings );
* @endcode
* And here is how to use the resulting type Fruit
* @code
*
* int
* main(int argc, char * argv[]) {
* fruit f(APPLE);
* switch ( f ) {
* case BANANA:
* case APPLE:
* cerr << "No thanks. I hate " << f << "s" << endl;
* break;
* default:
* cerr << "Hmmm ... yummy " << f << endl;
* break;
* }
*
* f = CHERRY;
*
* fruit_enum native_enum = f;
*
* f.from_string("passion_fruit");
*
* for (unsigned i = 0; i < fruit::MAX; ++i) {
* cerr << i << " = " << fruit::get_string(i) << endl;
* }
*
* f.from_string("elephant"); // throws illegal_enum_value
*
* return 0;
* }
* @endcode
*/
template <class ENUM, int THE_MAX>
class enumeration {
public:
typedef ENUM Native;
enumeration() {};
enumeration( ENUM v ) : value_(v) {}
enumeration( const enumeration & other ) : value_(other.value_) {}
/** Assignment operator for native enum values. */
void operator=(ENUM v)
{
value_ = v;
}
/** Assignment operator. */
void operator=(const enumeration & other)
{
value_ = other.value_;
}
/** Conversion operator for native enum values. */
operator ENUM() const
{
return value_;
}
enum Max
{
MAX = THE_MAX
};
ENUM max() const
{
return THE_MAX;
}
/** Converts @p str to an enum.
* @throw illegal_enum_value @p str is not a legal identifier.
* */
void from_string(const std::string & str)
{
for (unsigned i = 0; i < THE_MAX; ++i)
{
if (str == our_strings_[i])
{
value_ = static_cast<ENUM>(i);
return;
}
}
throw illegal_enum_value(std::string("Illegal enumeration value '") +
str + "' for enum " + our_name_);
}
/** Parses the input stream @p is for a word consisting of characters and
* digits (<i>a-z, A-Z, 0-9</i>) and underscores (<i>_</i>).
* The failbit of the stream is set if the word is not a valid identifier.
*/
std::istream & parse(std::istream & is)
{
std::string word;
char c;
while ( is.peek() != std::char_traits< char >::eof())
{
is >> c;
if ( isspace(c) && word.empty() )
{
continue;
}
if ( isalnum(c) || (c == '_') || c == '-' )
{
word += c;
}
else
{
is.unget();
break;
}
}
try
{
from_string( word );
}
catch (const illegal_enum_value & ex)
{
is.setstate(std::ios::failbit);
}
return is;
}
/** Returns the current value as a string identifier. */
std::string as_string() const
{
return our_strings_[value_];
}
/** Prints the string identifier to the output stream @p os. */
std::ostream & print(std::ostream & os = std::cerr) const
{
return os << our_strings_[value_];
}
/** Static helper function to iterate over valid identifiers. */
static const char * get_string(unsigned i)
{
return our_strings_[i];
}
/** Performs some simple checks and quits the application if
* any error is detected. Tries to print helpful error messages.
*/
static bool verify(const char * filename, unsigned line_no)
{
for (unsigned i = 0; i < THE_MAX; ++i)
{
if (our_strings_[i] == 0 )
{
std::cerr << "### FATAL: Not enough strings for enum "
<< our_name_ << " defined in file '" << filename
<< "' at line " << line_no << std::endl;
exit(1);
}
}
if ( std::string("") != our_strings_[THE_MAX])
{
std::cerr << "### FATAL: The string array for enum " << our_name_
<< " defined in file '" << filename << "' at line " << line_no
<< " has too many items or is not terminated with an "
<< "empty string." << std::endl;
exit(1);
}
return true;
}
static const char * get_name()
{
return our_name_;
}
private:
ENUM value_;
static const char ** our_strings_ ;
static const char * our_name_ ;
static bool our_verified_flag_;
};
/** ostream operator for enumeration
* @relates mapnik::enumeration
*/
template <class ENUM, int THE_MAX>
std::ostream &
operator<<(std::ostream & os, const mapnik::enumeration<ENUM, THE_MAX> & e)
{
e.print( os );
return os;
}
/** istream operator for enumeration
* @relates mapnik::enumeration
*/
template <class ENUM, int THE_MAX>
std::istream &
operator>>(std::istream & is, mapnik::enumeration<ENUM, THE_MAX> & e)
{
e.parse( is );
return is;
}
} // end of namespace
/** Helper macro. Creates a typedef.
* @relates mapnik::enumeration
*/
#define DEFINE_ENUM( name, e) \
typedef mapnik::enumeration<e, e ## _MAX> name;
/** Helper macro. Runs the verify() method during static initialization.
* @relates mapnik::enumeration
*/
#define IMPLEMENT_ENUM( name, strings ) \
template <> const char ** name ::our_strings_ = strings; \
template <> const char * name ::our_name_ = #name; \
template <> bool name ::our_verified_flag_( name ::verify(__FILE__, __LINE__));
#endif // MAPNIK_ENUMERATION_INCLUDED

View file

@ -25,6 +25,7 @@
#ifndef FILTER_FACTORY_HPP
#define FILTER_FACTORY_HPP
#include <mapnik/config_error.hpp>
#include <mapnik/filter_parser.hpp>
namespace mapnik
@ -41,14 +42,23 @@ namespace mapnik
stack<shared_ptr<expression<FeatureT> > > exps;
filter_grammar<FeatureT> grammar(filters,exps);
char const *text = str.c_str();
parse_info<> info = parse(text,text+strlen(text),grammar,space_p);
if (info.full && !filters.empty())
parse_info<> info = parse(text, grammar, space_p);
if ( ! info.full) {
std::ostringstream os;
os << "Failed to parse filter expression:" << std::endl
<< str << std::endl
<< "Parsing aborted at '" << info.stop << "'";
throw config_error( os.str() );
}
if ( ! filters.empty())
{
return filters.top();
}
else
{
clog << "failed at :" << info.stop << "\n";
// XXX: do we ever get here? [DS]
return filter_ptr(new none_filter<FeatureT>());
}
}

View file

@ -29,6 +29,9 @@
#include <stack>
#include <iostream>
// boost
//#define BOOST_SPIRIT_DEBUG
#include <boost/shared_ptr.hpp>
#include <boost/spirit/core.hpp>
#include <boost/spirit/symbols.hpp>
@ -404,7 +407,7 @@ namespace mapnik
[compose_filter<FeatureT,mapnik::less_than<value> >(self.filters,self.exprs)]
| (L"<=" >> expression)
[compose_filter<FeatureT,less_than_or_equal<value> >(self.filters,self.exprs)]
| regex );
/* | regex */);
equation = relation >> *( ( L'=' >> relation)
[compose_filter<FeatureT,mapnik::equals<value> >(self.filters,self.exprs)]
@ -417,7 +420,26 @@ namespace mapnik
or_expr = and_expr >> *(L"or" >> and_expr)[compose_or_filter<FeatureT>(self.filters)];
filter_statement = or_expr;
filter_statement = or_expr >> *(space_p) >> end_p;
#ifdef BOOST_SPIRIT_DEBUG
BOOST_SPIRIT_DEBUG_RULE( factor );
BOOST_SPIRIT_DEBUG_RULE( term );
BOOST_SPIRIT_DEBUG_RULE( expression );
BOOST_SPIRIT_DEBUG_RULE( relation );
BOOST_SPIRIT_DEBUG_RULE( equation );
BOOST_SPIRIT_DEBUG_RULE( not_expr );
BOOST_SPIRIT_DEBUG_RULE( and_expr );
BOOST_SPIRIT_DEBUG_RULE( or_expr );
BOOST_SPIRIT_DEBUG_RULE( filter_statement );
BOOST_SPIRIT_DEBUG_RULE( literal );
BOOST_SPIRIT_DEBUG_RULE( number );
BOOST_SPIRIT_DEBUG_RULE( string_ );
BOOST_SPIRIT_DEBUG_RULE( property );
BOOST_SPIRIT_DEBUG_RULE( function );
BOOST_SPIRIT_DEBUG_RULE( regex );
#endif
}
boost::spirit::rule<ScannerT> const& start() const
@ -444,6 +466,8 @@ namespace mapnik
symbols<string> func1_op;
symbols<string> func2_op;
symbols<string> spatial_op;
};
stack<shared_ptr<filter<FeatureT> > >& filters;
stack<shared_ptr<expression<FeatureT> > >& exprs;

View file

@ -0,0 +1,9 @@
#ifndef LOAD_MAP_XML2_INCLUDED
#define LOAD_MAP_XML2_INCLUDED
namespace mapnik
{
void read_xml2( std::string const & filename, boost::property_tree::ptree & pt);
}
#endif // LOAD_MAP_XML2_INCLUDED

View file

@ -26,19 +26,17 @@
#include <boost/shared_ptr.hpp>
#include <mapnik/graphics.hpp>
#include <mapnik/symbolizer.hpp>
namespace mapnik
{
struct MAPNIK_DECL line_pattern_symbolizer
struct MAPNIK_DECL line_pattern_symbolizer :
public symbolizer_with_image
{
line_pattern_symbolizer(std::string const& file,
std::string const& type,
unsigned width,unsigned height);
line_pattern_symbolizer(line_pattern_symbolizer const& rhs);
ImageData32 const& get_pattern() const;
private:
boost::shared_ptr<ImageData32> pattern_;
};
}

View file

@ -29,7 +29,7 @@
namespace mapnik
{
MAPNIK_DECL void load_map(Map & map, std::string const& filename);
MAPNIK_DECL void load_map(Map & map, std::string const& filename, bool strict = false);
}
#endif // LOAD_MAP_HPP

View file

@ -26,23 +26,22 @@
#include <boost/shared_ptr.hpp>
#include <mapnik/graphics.hpp>
#include <mapnik/symbolizer.hpp>
namespace mapnik
{
struct MAPNIK_DECL point_symbolizer
struct MAPNIK_DECL point_symbolizer :
public symbolizer_with_image
{
explicit point_symbolizer();
point_symbolizer(std::string const& file,
std::string const& type,
unsigned width,unsigned height);
point_symbolizer(point_symbolizer const& rhs);
void set_data (boost::shared_ptr<ImageData32> symbol);
boost::shared_ptr<ImageData32> const& get_data() const;
void set_allow_overlap(bool overlap);
bool get_allow_overlap() const;
private:
boost::shared_ptr<ImageData32> symbol_;
bool overlap_;
};
}

View file

@ -26,10 +26,12 @@
#include <boost/shared_ptr.hpp>
#include <mapnik/graphics.hpp>
#include <mapnik/symbolizer.hpp>
namespace mapnik
{
struct MAPNIK_DECL polygon_pattern_symbolizer
struct MAPNIK_DECL polygon_pattern_symbolizer :
public symbolizer_with_image
{
polygon_pattern_symbolizer(std::string const& file,
@ -37,10 +39,6 @@ namespace mapnik
unsigned width,unsigned height);
polygon_pattern_symbolizer(polygon_pattern_symbolizer const& rhs);
ImageData32 const& get_pattern() const;
private:
boost::shared_ptr<ImageData32> pattern_;
};
}

View file

@ -0,0 +1,338 @@
#ifndef MAPNIK_CONFIG_HELPERS_INCLUDED
#define MAPNIK_CONFIG_HELPERS_INCLUDED
#include <iostream>
#include <sstream>
#include <boost/property_tree/ptree.hpp>
#include <boost/lexical_cast.hpp>
#include <boost/optional.hpp>
#include <mapnik/enumeration.hpp>
#include <mapnik/config_error.hpp>
#include <mapnik/color_factory.hpp>
namespace mapnik {
template <typename T>
T get(const boost::property_tree::ptree & node, const std::string & name, bool is_attribute,
const T & default_value);
template <typename T>
T get(const boost::property_tree::ptree & node, const std::string & name, bool is_attribute);
template <typename T>
T get_own(const boost::property_tree::ptree & node, const std::string & name);
template <typename T>
boost::optional<T> get_optional(const boost::property_tree::ptree & node, const std::string & name,
bool is_attribute);
template <typename T>
boost::optional<T> get_opt_attr( const boost::property_tree::ptree & node,
const std::string & name)
{
return get_optional<T>( node, name, true);
}
template <typename T>
boost::optional<T> get_opt_child( const boost::property_tree::ptree & node,
const std::string & name)
{
return get_optional<T>( node, name, false);
}
template <typename T>
T get_attr( const boost::property_tree::ptree & node, const std::string & name,
const T & default_value )
{
return get<T>( node, name, true, default_value);
}
template <typename T>
T get_attr( const boost::property_tree::ptree & node, const std::string & name )
{
return get<T>( node, name, true );
}
template <typename T>
T get_css( const boost::property_tree::ptree & node, const std::string & name )
{
return get_own<T>( node, std::string("CSS parameter '") + name + "'");
}
/** Stream input operator for Color values */
template <typename charT, typename traits>
std::basic_istream<charT, traits> &
operator >> ( std::basic_istream<charT, traits> & s, mapnik::Color & c )
{
std::string word;
s >> word;
if ( s )
{
try
{
c = mapnik::color_factory::from_string( word.c_str() );
}
catch (...)
{
s.setstate( std::ios::failbit );
}
}
return s;
}
template <typename charT, typename traits>
std::basic_ostream<charT, traits> &
operator << ( std::basic_ostream<charT, traits> & s, const mapnik::Color & c )
{
std::string hex_string( c.to_hex_string() );
s << hex_string;
return s;
}
/** Helper for class bool */
class boolean {
public:
boolean() {}
boolean(bool b) : b_(b) {}
boolean(const boolean & b) : b_(b.b_) {}
operator bool() const
{
return b_;
}
boolean & operator = (const boolean & other)
{
b_ = other.b_;
return * this;
}
boolean & operator = (bool other)
{
b_ = other;
return * this;
}
private:
bool b_;
};
/** Special stream input operator for boolean values */
template <typename charT, typename traits>
std::basic_istream<charT, traits> &
operator >> ( std::basic_istream<charT, traits> & s, boolean & b )
{
std::string word;
s >> word;
if ( s )
{
if ( word == "true" || word == "yes" || word == "on" ||
word == "1")
{
b = true;
}
else if ( word == "false" || word == "no" || word == "off" ||
word == "0")
{
b = false;
}
else
{
s.setstate( std::ios::failbit );
}
}
return s;
}
template <typename charT, typename traits>
std::basic_ostream<charT, traits> &
operator << ( std::basic_ostream<charT, traits> & s, const boolean & b )
{
s << ( b ? "true" : "false" );
return s;
}
template <typename T>
void set_attr(boost::property_tree::ptree & pt, const std::string & name, const T & v)
{
pt.put("<xmlattr>." + name, v);
}
/*
template <>
void set_attr<bool>(boost::property_tree::ptree & pt, const std::string & name, const bool & v)
{
pt.put("<xmlattr>." + name, boolean(v));
}
*/
class boolean;
template <typename T>
void set_css(boost::property_tree::ptree & pt, const std::string & name, const T & v)
{
boost::property_tree::ptree & css_node = pt.push_back(
boost::property_tree::ptree::value_type("CssParameter",
boost::property_tree::ptree()))->second;
css_node.put("<xmlattr>.name", name );
css_node.put_own( v );
}
template <typename T>
struct name_trait
{
static const char * name()
{
return "<unknown>";
}
// missing name_trait for type ...
// if you get here you are probably using a new type
// in the XML file. Just add a name trait for the new
// type below.
BOOST_STATIC_ASSERT( sizeof(T) == 0 );
};
#define DEFINE_NAME_TRAIT_WITH_NAME( type, type_name ) \
template <> \
struct name_trait<type> \
{ \
static const char * name() { return "type " type_name; } \
};
#define DEFINE_NAME_TRAIT( type ) \
DEFINE_NAME_TRAIT_WITH_NAME( type, #type );
DEFINE_NAME_TRAIT( double );
DEFINE_NAME_TRAIT( float );
DEFINE_NAME_TRAIT( unsigned );
DEFINE_NAME_TRAIT( boolean );
DEFINE_NAME_TRAIT_WITH_NAME( int, "integer" );
DEFINE_NAME_TRAIT_WITH_NAME( std::string, "string" );
DEFINE_NAME_TRAIT_WITH_NAME( Color, "color" );
template <typename ENUM, int MAX>
struct name_trait< enumeration<ENUM, MAX> >
{
typedef enumeration<ENUM, MAX> Enum;
static const char * name()
{
std::string value_list("one of [");
for (unsigned i = 0; i < Enum::MAX; ++i)
{
value_list += Enum::get_string( i );
if ( i + 1 < Enum::MAX ) value_list += ", ";
}
value_list += "]";
return value_list.c_str();
}
};
template <typename T>
T get(const boost::property_tree::ptree & node, const std::string & name, bool is_attribute,
const T & default_value)
{
boost::optional<std::string> str;
if (is_attribute)
{
str = node.get_optional<std::string>( std::string("<xmlattr>.") + name );
}
else
{
str = node.get_optional<std::string>(name );
}
if ( str ) {
try
{
return boost::lexical_cast<T>( * str );
}
catch (const boost::bad_lexical_cast & ex)
{
throw config_error(string("Failed to parse ") +
(is_attribute ? "attribute" : "child node") + " '" +
name + "'. Expected " + name_trait<T>::name() +
" but got '" + *str + "'");
}
} else {
return default_value;
}
}
template <typename T>
T get(const boost::property_tree::ptree & node, const std::string & name, bool is_attribute)
{
boost::optional<std::string> str;
if (is_attribute)
{
str = node.get_optional<std::string>( std::string("<xmlattr>.") + name);
}
else
{
str = node.get_optional<std::string>(name);
}
if ( ! str ) {
throw config_error(string("Required ") +
(is_attribute ? "attribute " : "child node ") +
"'" + name + "' is missing");
}
try
{
return boost::lexical_cast<T>( *str );
}
catch (const boost::bad_lexical_cast & ex)
{
throw config_error(string("Failed to parse ") +
(is_attribute ? "attribute" : "child node") + " '" +
name + "'. Expected " + name_trait<T>::name() +
" but got '" + *str + "'");
}
}
template <typename T>
T get_own(const boost::property_tree::ptree & node, const std::string & name)
{
try
{
return node.get_own<T>();
}
catch (...)
{
throw config_error(string("Failed to parse ") +
name + ". Expected " + name_trait<T>::name() +
" but got '" + node.data() + "'");
}
}
template <typename T>
boost::optional<T> get_optional(const boost::property_tree::ptree & node, const std::string & name,
bool is_attribute)
{
boost::optional<std::string> str;
if (is_attribute)
{
str = node.get_optional<std::string>( std::string("<xmlattr>.") + name);
}
else
{
str = node.get_optional<std::string>(name);
}
boost::optional<T> result;
if ( str ) {
try
{
result = boost::lexical_cast<T>( *str );
}
catch (const boost::bad_lexical_cast & ex)
{
throw config_error(string("Failed to parse ") +
(is_attribute ? "attribute" : "child node") + " '" +
name + "'. Expected " + name_trait<T>::name() +
" but got '" + *str + "'");
}
}
return result;
}
} // end of namespace mapnik
#endif // MAPNIK_CONFIG_HELPERS_INCLUDED

View file

@ -25,13 +25,16 @@
#ifndef SHIELD_SYMBOLIZER_HPP
#define SHIELD_SYMBOLIZER_HPP
#include <boost/shared_ptr.hpp>
#include <mapnik/graphics.hpp>
#include <mapnik/text_symbolizer.hpp>
#include <mapnik/symbolizer.hpp>
#include <boost/shared_ptr.hpp>
namespace mapnik
{
struct MAPNIK_DECL shield_symbolizer : public text_symbolizer
struct MAPNIK_DECL shield_symbolizer : public text_symbolizer,
public symbolizer_with_image
{
shield_symbolizer(std::string const& name,
std::string const& face_name,
@ -41,13 +44,6 @@ namespace mapnik
std::string const& type,
unsigned width,unsigned height);
void set_background_image(boost::shared_ptr<ImageData32>);
boost::shared_ptr<ImageData32> const& get_background_image() const;
private:
boost::shared_ptr<ImageData32> background_image_;
};
}

View file

@ -27,6 +27,7 @@
#include <vector>
// mapnik
#include <mapnik/color.hpp>
#include <mapnik/enumeration.hpp>
namespace mapnik
{
@ -34,21 +35,31 @@ namespace mapnik
using std::vector;
typedef vector<pair<float,float> > dash_array;
enum line_cap_e
// if you add new tokens, don't forget to add them to the corresponding
// string array in the cpp file too.
enum line_cap_enum
{
BUTT_CAP,
SQUARE_CAP,
ROUND_CAP
ROUND_CAP,
line_cap_enum_MAX
};
enum line_join_e
DEFINE_ENUM( line_cap_e, line_cap_enum );
// if you add new tokens, don't forget to add them to the corresponding
// string array in the cpp file too.
enum line_join_enum
{
MITER_JOIN,
MITER_REVERT_JOIN,
ROUND_JOIN,
BEVEL_JOIN
BEVEL_JOIN,
line_join_enum_MAX
};
DEFINE_ENUM( line_join_e, line_join_enum );
class stroke
{
Color c_;
@ -58,112 +69,34 @@ namespace mapnik
line_join_e line_join_;
dash_array dash_;
public:
explicit stroke()
: c_(0,0,0),
width_(1.0),
opacity_(1.0),
line_cap_(BUTT_CAP),
line_join_(MITER_JOIN),
dash_() {}
explicit stroke();
stroke(Color const& c, float width=1.0);
stroke(stroke const& other);
stroke& operator=(const stroke& rhs);
stroke(Color const& c, float width=1.0)
: c_(c),
width_(width),
opacity_(1.0),
line_cap_(BUTT_CAP),
line_join_(MITER_JOIN),
dash_() {}
void set_color(const Color& c);
stroke(stroke const& other)
: c_(other.c_),
width_(other.width_),
opacity_(other.opacity_),
line_cap_(other.line_cap_),
line_join_(other.line_join_),
dash_(other.dash_) {}
Color const& get_color() const;
stroke& operator=(const stroke& rhs)
{
stroke tmp(rhs);
swap(tmp);
return *this;
}
float get_width() const;
void set_width(float w);
void set_opacity(float opacity);
void set_color(const Color& c)
{
c_=c;
}
float get_opacity() const;
Color const& get_color() const
{
return c_;
}
void set_line_cap(line_cap_e line_cap);
line_cap_e get_line_cap() const;
float get_width() const
{
return width_;
}
void set_width(float w)
{
width_=w;
}
void set_line_join(line_join_e line_join);
line_join_e get_line_join() const;
void set_opacity(float opacity)
{
if (opacity > 1.0) opacity_=1.0;
else if (opacity < 0.0) opacity_=0.0;
else opacity_=opacity;
}
void add_dash(float dash,float gap);
bool has_dash() const;
float get_opacity() const
{
return opacity_;
}
void set_line_cap(line_cap_e line_cap)
{
line_cap_=line_cap;
}
line_cap_e get_line_cap() const
{
return line_cap_;
}
void set_line_join(line_join_e line_join)
{
line_join_=line_join;
}
line_join_e get_line_join() const
{
return line_join_;
}
void add_dash(float dash,float gap)
{
dash_.push_back(std::make_pair(dash,gap));
}
bool has_dash() const
{
return dash_.size()>0 ? true : false ;
}
dash_array const& get_dash_array() const
{
return dash_;
}
dash_array const& get_dash_array() const;
private:
void swap(const stroke& other) throw()
{
c_=other.c_;
width_=other.width_;
opacity_=other.opacity_;
line_cap_=other.line_cap_;
line_join_=other.line_join_;
dash_ = other.dash_;
}
void swap(const stroke& other) throw();
};
}

View file

@ -24,8 +24,31 @@
#ifndef SYMBOLIZER_HPP
#define SYMBOLIZER_HPP
#include <boost/shared_ptr.hpp>
#include <mapnik/graphics.hpp>
namespace mapnik
{
class symbolizer_with_image {
public:
boost::shared_ptr<ImageData32> get_image() const;
const std::string & get_filename() const;
void set_image( boost::shared_ptr<ImageData32> symbol);
virtual ~symbolizer_with_image() {};
protected:
symbolizer_with_image(boost::shared_ptr<ImageData32> img);
symbolizer_with_image(std::string const& file,
std::string const& type,
unsigned width,unsigned height);
symbolizer_with_image(symbolizer_with_image const& rhs);
boost::shared_ptr<ImageData32> image_;
std::string image_filename_;
};
}
#endif //SYMBOLIZER_HPP

View file

@ -30,22 +30,25 @@
#include <boost/tuple/tuple.hpp>
#include <boost/shared_ptr.hpp>
// mapnik
#include <mapnik/enumeration.hpp>
#include <mapnik/color.hpp>
#include <mapnik/graphics.hpp>
namespace mapnik
{
enum label_placement_e {
point_placement=1,
line_placement=2
enum label_placement_enum {
POINT_PLACEMENT,
LINE_PLACEMENT,
label_placement_enum_MAX
};
DEFINE_ENUM( label_placement_e, label_placement_enum );
typedef boost::tuple<double,double> position;
struct MAPNIK_DECL text_symbolizer
{
text_symbolizer(std::string const& name,std::string const& face_name,
unsigned size,Color const& fill);
unsigned size, Color const& fill);
text_symbolizer(text_symbolizer const& rhs);
text_symbolizer& operator=(text_symbolizer const& rhs);
std::string const& get_name() const;

View file

@ -25,6 +25,8 @@
#ifndef CONNECTION_HPP
#define CONNECTION_HPP
#include <mapnik/datasource.hpp>
extern "C"
{
#include "libpq-fe.h"
@ -41,10 +43,18 @@ class Connection
Connection(std::string const& connection_str)
{
conn_=PQconnectdb(connection_str.c_str());
if (PQstatus(conn_) == CONNECTION_BAD)
if (PQstatus(conn_) != CONNECTION_OK)
{
std::clog << "connection ["<< connection_str<< "] failed\n"
<< PQerrorMessage(conn_)<< std::endl;
std::string s("PSQL error");
if (conn_ )
{
std::string msg = PQerrorMessage( conn_ );
if ( ! msg.empty() )
{
s += ":\n" + msg.substr( 0, msg.size() - 1 );
}
}
throw mapnik::datasource_exception( s );
}
}

View file

@ -46,8 +46,8 @@ source = Split(
image_util.cpp
layer.cpp
line_pattern_symbolizer.cpp
load_map.cpp
map.cpp
load_map.cpp
memory.cpp
params.cpp
placement_finder.cpp
@ -65,15 +65,25 @@ source = Split(
distance.cpp
scale_denominator.cpp
memory_datasource.cpp
stroke.cpp
symbolizer.cpp
"""
)
source += Split(
if env['XMLPARSER'] == 'tinyxml':
source += Split(
"""
../tinyxml/tinystr.cpp
../tinyxml/tinyxml.cpp
../tinyxml/tinyxmlerror.cpp
../tinyxml/tinyxmlparser.cpp
""")
elif env['XMLPARSER'] == 'libxml2':
source += Split(
"""
libxml2_loader.cpp
""")
mapnik = env.SharedLibrary('mapnik', source, LIBS=libraries, LINKFLAGS=linkflags)

View file

@ -218,7 +218,8 @@ namespace mapnik
boost::scoped_ptr<geometry2d> roof(new polygon_impl);
std::deque<segment_t> face_segments;
double x0,y0;
double x0(0);
double y0(0);
for (unsigned j=0;j<geom.num_points();++j)
{
double x,y;
@ -397,7 +398,7 @@ namespace mapnik
double x;
double y;
double z=0;
boost::shared_ptr<ImageData32> const& data = sym.get_data();
boost::shared_ptr<ImageData32> const& data = sym.get_image();
if ( data )
{
for (unsigned i=0;i<feature.num_geometries();++i)
@ -431,7 +432,7 @@ namespace mapnik
proj_transform const& prj_trans)
{
std::wstring text = feature[sym.get_name()].to_unicode();
boost::shared_ptr<ImageData32> const& data = sym.get_background_image();
boost::shared_ptr<ImageData32> const& data = sym.get_image();
if (text.length() > 0 && data)
{
face_ptr face = font_manager_.get_face(sym.get_face_name());
@ -487,7 +488,7 @@ namespace mapnik
typedef agg::renderer_outline_image<renderer_base, pattern_type> renderer_type;
typedef agg::rasterizer_outline_aa<renderer_type> rasterizer_type;
ImageData32 const& pat = sym.get_pattern();
ImageData32 pat = * sym.get_image();
renderer_base ren_base(pixf_);
agg::pattern_filter_bilinear_rgba8 filter;
pattern_source source(pat);
@ -532,7 +533,7 @@ namespace mapnik
ren_base renb(pixf_);
agg::scanline_u8 sl;
ImageData32 const& pattern = sym.get_pattern();
ImageData32 const& pattern = * sym.get_image();
unsigned w=pattern.width();
unsigned h=pattern.height();
agg::row_accessor<agg::int8u> pattern_rbuf((agg::int8u*)pattern.getBytes(),w,h,w*4);

View file

@ -30,6 +30,7 @@
#include <boost/algorithm/string.hpp>
// mapnik
#include <mapnik/datasource_cache.hpp>
#include <mapnik/config_error.hpp>
// ltdl
#include <ltdl.h>
@ -46,7 +47,7 @@ namespace mapnik
datasource_cache::datasource_cache()
{
if (lt_dlinit()) throw;
if (lt_dlinit()) throw std::runtime_error("lt_dlinit() failed");
}
datasource_cache::~datasource_cache()
@ -58,47 +59,41 @@ namespace mapnik
bool datasource_cache::registered_=false;
datasource_ptr datasource_cache::create(const parameters& params)
{
datasource_ptr ds;
try
{
boost::optional<std::string> type = params.get<std::string>("type");
if (type)
if ( ! type)
{
throw config_error(string("Could not create datasource. Required ") +
"parameter 'type' is missing");
}
datasource_ptr ds;
map<string,boost::shared_ptr<PluginInfo> >::iterator itr=plugins_.find(*type);
if (itr!=plugins_.end())
if ( itr == plugins_.end() )
{
if (itr->second->handle())
throw config_error(string("Could not create datasource. No plugin ") +
"found for type '" + * type + "'");
}
if ( ! itr->second->handle())
{
throw std::runtime_error(string("Cannot load library: ") +
lt_dlerror());
}
create_ds* create_datasource =
(create_ds*) lt_dlsym(itr->second->handle(), "create");
if (!create_datasource)
if ( ! create_datasource)
{
std::clog << "Cannot load symbols: " << lt_dlerror() << std::endl;
throw std::runtime_error(string("Cannot load symbols: ") +
lt_dlerror());
}
else
{
ds=datasource_ptr(create_datasource(params), datasource_deleter());
}
}
else
{
std::clog << "Cannot load library: " << lt_dlerror() << std::endl;
}
}
}
#ifdef MAPNIK_DEBUG
std::clog<<"datasource="<<ds<<" type="<<type<<std::endl;
#endif
}
catch (datasource_exception& ex)
{
std::clog << ex.what() << "\n";
}
catch (...)
{
std::clog << " exception caught\n";
}
return ds;
}

View file

@ -23,6 +23,9 @@
#include <mapnik/font_engine_freetype.hpp>
using std::cerr;
using std::endl;
namespace mapnik
{
freetype_engine::freetype_engine()
@ -30,7 +33,7 @@ namespace mapnik
FT_Error error = FT_Init_FreeType( &library_ );
if (error)
{
throw std::runtime_error("can not load FreeType2 library");
throw std::runtime_error("Failed to initialize FreeType2 library");
}
}
@ -43,6 +46,7 @@ namespace mapnik
{
mutex::scoped_lock lock(mapnik::singleton<freetype_engine,
mapnik::CreateStatic>::mutex_);
//cerr << "freetype_engine::register_font() '" << file_name << "'" << endl;
FT_Face face;
FT_Error error = FT_New_Face (library_,file_name.c_str(),0,&face);
if ( !error )

180
src/libxml2_loader.cpp Normal file
View file

@ -0,0 +1,180 @@
/*****************************************************************************
*
* This file is part of Mapnik (c++ mapping toolkit)
*
* Copyright (C) 2007 Artem Pavlenko
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
*****************************************************************************/
#include <libxml/parser.h>
#include <libxml/tree.h>
#include <libxml/parserInternals.h>
#include <boost/utility.hpp>
#include <boost/property_tree/ptree.hpp>
#include <boost/filesystem/operations.hpp>
#include <mapnik/config_error.hpp>
#include <iostream>
using boost::property_tree::ptree;
using namespace std;
namespace mapnik
{
class libxml2_loader : boost::noncopyable
{
public:
libxml2_loader() :
ctx_( 0 )
{
LIBXML_TEST_VERSION;
}
~libxml2_loader()
{
if (ctx_ && ctx_->myDoc)
{
xmlFreeDoc( ctx_->myDoc );
}
if (ctx_)
{
xmlFreeParserCtxt(ctx_);
}
}
void load( const std::string & filename, ptree & pt )
{
boost::filesystem::path path(filename);
if ( ! boost::filesystem::exists( path ) ) {
throw config_error(string("Could not load map file '") +
filename + "': File does not exist");
}
ctx_ = xmlCreateFileParserCtxt( filename.c_str() );
if ( ! ctx_ )
{
throw std::runtime_error("Failed to create parser context.");
}
ctx_->replaceEntities = true;
ctx_->keepBlanks = false;
xmlCtxtUseOptions( ctx_, XML_PARSE_NOERROR | XML_PARSE_NOENT | XML_PARSE_NOBLANKS |
XML_PARSE_DTDLOAD);
xmlParseDocument( ctx_ );
if ( ! ctx_->wellFormed )
{
xmlError * error = xmlCtxtGetLastError( ctx_ );
std::ostringstream os;
os << "XML document not well formed";
if (error)
{
os << ": " << std::endl << error->message;
// remove CR
std::string msg = os.str().substr(0, os.str().size() - 1);
config_error ex( msg );
os.str("");
os << "in file '" << error->file << "' at line "
<< error->line;
ex.append_context( os.str() );
throw ex;
}
}
/*
if ( ! ctx->valid )
{
std::clog << "### ERROR: Failed to validate DTD."
<< std::endl;
}
*/
xmlNode * root( 0 );
root = xmlDocGetRootElement( ctx_->myDoc );
if ( ! root ) {
throw config_error("XML document is empty.");
}
populate_tree( root, pt );
}
private:
void append_attributes( xmlAttr * attributes, ptree & pt)
{
if (attributes)
{
ptree::iterator it = pt.push_back( ptree::value_type( "<xmlattr>", ptree() ));
ptree & attr_list = it->second;
xmlAttr * cur_attr = attributes;
for (; cur_attr; cur_attr = cur_attr->next )
{
ptree::iterator it = attr_list.push_back(
ptree::value_type( (char*)cur_attr->name, ptree() ));
it->second.put_own( (char*) cur_attr->children->content );
}
}
}
void populate_tree( xmlNode * node, ptree & pt )
{
xmlNode * cur_node = node;
for (; cur_node; cur_node = cur_node->next )
{
switch (cur_node->type)
{
case XML_ELEMENT_NODE:
{
ptree::iterator it = pt.push_back( ptree::value_type(
(char*)cur_node->name, ptree() ));
append_attributes( cur_node->properties, it->second);
populate_tree( cur_node->children, it->second );
}
break;
case XML_TEXT_NODE:
pt.put_own( (char*) cur_node->content );
break;
case XML_COMMENT_NODE:
{
ptree::iterator it = pt.push_back(
ptree::value_type( "<xmlcomment>", ptree() ));
it->second.put_own( (char*) cur_node->content );
}
break;
default:
break;
}
}
}
xmlParserCtxtPtr ctx_;
};
void read_xml2( std::string const & filename, boost::property_tree::ptree & pt)
{
libxml2_loader loader;
loader.load( filename, pt );
}
} // end of namespace mapnik

View file

@ -33,25 +33,10 @@ namespace mapnik
line_pattern_symbolizer::line_pattern_symbolizer(std::string const& file,
std::string const& type,
unsigned width,unsigned height)
: pattern_(new ImageData32(width,height))
{
try
{
std::auto_ptr<ImageReader> reader(get_image_reader(type,file));
if (reader.get())
reader->read(0,0,*pattern_);
}
catch (...)
{
std::clog << "exception caught..." << std::endl;
}
}
: symbolizer_with_image( file, type, width, height )
{ }
line_pattern_symbolizer::line_pattern_symbolizer(line_pattern_symbolizer const& rhs)
: pattern_(rhs.pattern_) {}
: symbolizer_with_image(rhs) {}
ImageData32 const& line_pattern_symbolizer::get_pattern() const
{
return *pattern_;
}
}

File diff suppressed because it is too large Load diff

View file

@ -70,8 +70,8 @@ namespace mapnik
minimum_distance(sym.get_minimum_distance()),
avoid_edges(sym.get_avoid_edges()),
has_dimensions(true),
dimensions(std::make_pair(sym.get_background_image()->width(),
sym.get_background_image()->height()))
dimensions(std::make_pair(sym.get_image()->width(),
sym.get_image()->height()))
{
}
@ -205,16 +205,16 @@ namespace mapnik
double distance = p->get_total_distance();
if (p->label_placement == line_placement && string_width > distance)
if (p->label_placement == LINE_PLACEMENT && string_width > distance)
{
//Empty!
return ideal_label_distances;
}
int num_labels = 0;
if (p->label_spacing && p->label_placement == line_placement)
if (p->label_spacing && p->label_placement == LINE_PLACEMENT)
num_labels = static_cast<int> (floor(distance / (p->label_spacing + string_width)));
else if (p->label_spacing && p->label_placement == point_placement)
else if (p->label_spacing && p->label_placement == POINT_PLACEMENT)
num_labels = static_cast<int> (floor(distance / p->label_spacing));
if (p->force_odd_labels && num_labels%2 == 0)
@ -225,7 +225,7 @@ namespace mapnik
double ideal_spacing = distance/num_labels;
double middle; //try draw text centered
if (p->label_placement == line_placement)
if (p->label_placement == LINE_PLACEMENT)
middle = (distance / 2.0) - (string_width/2.0);
else // (p->label_placement == point_placement)
middle = distance / 2.0;
@ -289,9 +289,9 @@ namespace mapnik
}
p->clear_envelopes();
// check position +- delta for valid placement
if ((p->label_placement == line_placement &&
if ((p->label_placement == LINE_PLACEMENT &&
build_path_follow(p, *itr + (i*s)) ) ||
(p->label_placement == point_placement &&
(p->label_placement == POINT_PLACEMENT &&
build_path_horizontal(p, *itr + (i*s))) )
{
update_detector(p);

View file

@ -67,17 +67,9 @@ namespace mapnik
height_(0),
bit_depth_(0),
color_type_(0)
{
try
{
init();
}
catch (const ImageReaderException& e)
{
std::clog << e.what() << '\n';
throw;
}
}
PngReader::~PngReader() {}

View file

@ -33,48 +33,25 @@
namespace mapnik
{
point_symbolizer::point_symbolizer()
: symbol_(new ImageData32(4,4)),
: symbolizer_with_image(boost::shared_ptr<ImageData32>(new ImageData32(4,4))),
overlap_(false)
{
//default point symbol is black 4x4px square
symbol_->set(0xff000000);
image_->set(0xff000000);
}
point_symbolizer::point_symbolizer(std::string const& file,
std::string const& type,
unsigned width,unsigned height)
: symbol_(new ImageData32(width,height)),
: symbolizer_with_image(file, type, width, height),
overlap_(false)
{
try
{
boost::scoped_ptr<ImageReader> reader(get_image_reader(type,file));
if (reader.get())
{
reader->read(0,0,*symbol_);
}
}
catch (...)
{
std::clog<<"exception caught..." << std::endl;
}
}
{ }
point_symbolizer::point_symbolizer(point_symbolizer const& rhs)
: symbol_(rhs.symbol_),
: symbolizer_with_image(rhs),
overlap_(rhs.overlap_)
{}
void point_symbolizer::set_data( boost::shared_ptr<ImageData32> symbol)
{
symbol_ = symbol;
}
boost::shared_ptr<ImageData32> const& point_symbolizer::get_data() const
{
return symbol_;
}
void point_symbolizer::set_allow_overlap(bool overlap)
{
overlap_ = overlap;

View file

@ -31,24 +31,11 @@ namespace mapnik
polygon_pattern_symbolizer::polygon_pattern_symbolizer(std::string const& file,
std::string const& type,
unsigned width,unsigned height)
: pattern_(new ImageData32(width,height))
: symbolizer_with_image( file, type, width, height )
{
try
{
std::auto_ptr<ImageReader> reader(get_image_reader(type,file));
if (reader.get())
reader->read(0,0,*pattern_);
}
catch (...)
{
std::clog << "exception caught...\n";
}
}
polygon_pattern_symbolizer::polygon_pattern_symbolizer(polygon_pattern_symbolizer const& rhs)
: pattern_(rhs.pattern_) {}
: symbolizer_with_image(rhs) {}
ImageData32 const& polygon_pattern_symbolizer::get_pattern() const
{
return *pattern_;
}
}

View file

@ -26,18 +26,394 @@
#include <boost/algorithm/string.hpp>
#include <boost/lexical_cast.hpp>
#include <boost/tokenizer.hpp>
#include <boost/optional.hpp>
#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/xml_parser.hpp>
// mapnik
#include <mapnik/save_map.hpp>
#include <mapnik/ptree_helpers.hpp>
namespace mapnik
{
void save_map(Map & map, std::string const& filename)
{
using boost::property_tree::ptree;
using boost::optional;
std::string guess_type( const std::string & filename )
{
std::string::size_type idx = filename.find_last_of(".");
if ( idx != std::string::npos ) {
return filename.substr( idx + 1 );
}
return "<unknown>";
}
class serialize_symbolizer : public boost::static_visitor<>
{
public:
serialize_symbolizer( ptree & r ) : rule_(r) {}
void operator () ( const point_symbolizer & sym )
{
ptree & sym_node = rule_.push_back(
ptree::value_type("PointSymbolizer", ptree()))->second;
add_image_attributes( sym_node, sym );
}
void operator () ( const line_symbolizer & sym )
{
ptree & sym_node = rule_.push_back(
ptree::value_type("LineSymbolizer", ptree()))->second;
const stroke & strk = sym.get_stroke();
stroke dfl = stroke();
if ( strk.get_color() != dfl.get_color() )
{
set_css( sym_node, "stroke", strk.get_color() );
}
if ( strk.get_width() != dfl.get_width() )
{
set_css( sym_node, "stroke-width", strk.get_width() );
}
if ( strk.get_opacity() != dfl.get_opacity() )
{
set_css( sym_node, "stroke-opacity", strk.get_opacity() );
}
if ( strk.get_line_join() != dfl.get_line_join() )
{
set_css( sym_node, "stroke-linejoin", strk.get_line_join() );
}
if ( strk.get_line_cap() != dfl.get_line_cap() )
{
set_css( sym_node, "stroke-linecap", strk.get_line_cap() );
}
if ( ! strk.get_dash_array().empty() )
{
std::ostringstream os;
const dash_array & dashes = strk.get_dash_array();
for (unsigned i = 0; i < dashes.size(); ++i) {
os << dashes[i].first << ", " << dashes[i].second;
if ( i + 1 < dashes.size() ) os << ", ";
}
set_css( sym_node, "stroke-dasharray", os.str() );
}
}
void operator () ( const line_pattern_symbolizer & sym )
{
ptree & sym_node = rule_.push_back(
ptree::value_type("LinePatternSymbolizer",
ptree()))->second;
add_image_attributes( sym_node, sym );
}
void operator () ( const polygon_symbolizer & sym )
{
ptree & sym_node = rule_.push_back(
ptree::value_type("PolygonSymbolizer", ptree()))->second;
polygon_symbolizer dfl;
if ( sym.get_fill() != dfl.get_fill() )
{
set_css( sym_node, "fill", sym.get_fill() );
}
if ( sym.get_opacity() != dfl.get_opacity() )
{
set_css( sym_node, "opacity", sym.get_opacity() );
}
}
void operator () ( const polygon_pattern_symbolizer & sym )
{
ptree & sym_node = rule_.push_back(
ptree::value_type("PolygonPatternSymbolizer",
ptree()))->second;
add_image_attributes( sym_node, sym );
}
void operator () ( const raster_symbolizer & sym )
{
rule_.push_back(
ptree::value_type("RasterSymbolizer", ptree()));
}
void operator () ( const shield_symbolizer & sym )
{
ptree & sym_node = rule_.push_back(
ptree::value_type("ShieldSymbolizer",
ptree()))->second;
add_font_attributes( sym_node, sym);
add_image_attributes( sym_node, sym);
}
void operator () ( const text_symbolizer & sym )
{
ptree & sym_node = rule_.push_back(
ptree::value_type("TextSymbolizer",
ptree()))->second;
add_font_attributes( sym_node, sym);
}
void operator () ( const building_symbolizer & sym )
{
ptree & sym_node = rule_.push_back(
ptree::value_type("BuildingSymbolizer", ptree()))->second;
building_symbolizer dfl;
if ( sym.get_fill() != dfl.get_fill() )
{
set_css( sym_node, "fill", sym.get_fill() );
}
if ( sym.get_opacity() != dfl.get_opacity() )
{
set_css( sym_node, "fill-opacity", sym.get_opacity() );
}
}
private:
serialize_symbolizer();
void add_image_attributes(ptree & node, const symbolizer_with_image & sym)
{
const std::string & filename = sym.get_filename();
if ( ! filename.empty() ) {
set_attr( node, "file", filename );
set_attr( node, "type", guess_type( filename ) );
boost::shared_ptr<ImageData32> img = sym.get_image();
if ( img )
{
if ( img->width() > 0)
{
set_attr( node, "width", img->width() );
}
if ( img->height() > 0)
{
set_attr( node, "height", img->height() );
}
}
}
}
void add_font_attributes(ptree & node, const text_symbolizer & sym)
{
const std::string & name = sym.get_name();
if ( ! name.empty() ) {
set_attr( node, "name", name );
}
const std::string & face_name = sym.get_face_name();
if ( ! face_name.empty() ) {
set_attr( node, "face_name", face_name );
}
set_attr( node, "size", sym.get_text_size() );
set_attr( node, "fill", sym.get_fill() );
// pseudo-default-construct a text_symbolizer. It is used
// to avoid printing ofattributes with default values without
// repeating the default values here.
// maybe add a real, explicit default-ctor?
text_symbolizer dfl("<no default>", "<no default>",
0, Color(0,0,0) );
position displacement = sym.get_displacement();
if ( displacement.get<0>() != dfl.get_displacement().get<0>() )
{
set_attr( node, "dx", displacement.get<0>() );
}
if ( displacement.get<1>() != dfl.get_displacement().get<1>() )
{
set_attr( node, "dy", displacement.get<1>() );
}
if (sym.get_label_placement() != dfl.get_label_placement() )
{
set_attr( node, "placement", sym.get_label_placement() );
}
if (sym.get_halo_radius() != dfl.get_halo_radius())
{
set_attr( node, "halo_radius", sym.get_halo_radius() );
}
const Color & c = sym.get_halo_fill();
if ( c != dfl.get_halo_fill() )
{
set_attr( node, "halo_fill", c );
}
if (sym.get_text_ratio() != dfl.get_text_ratio() )
{
set_attr( node, "text_ratio", sym.get_text_ratio() );
}
if (sym.get_wrap_width() != dfl.get_wrap_width())
{
set_attr( node, "wrap_width", sym.get_wrap_width() );
}
if (sym.get_label_spacing() != dfl.get_label_spacing())
{
set_attr( node, "spacing", sym.get_label_spacing() );
}
if (sym.get_minimum_distance() != dfl.get_minimum_distance())
{
set_attr( node, "min_distance", sym.get_minimum_distance() );
}
if (sym.get_allow_overlap() != dfl.get_allow_overlap() )
{
set_attr( node, "allow_overlap", sym.get_allow_overlap() );
}
}
ptree & rule_;
};
void serialize_rule( ptree & style_node, const rule_type & rule)
{
ptree & rule_node = style_node.push_back(
ptree::value_type("Rule", ptree() ))->second;
rule_type dfl;
if ( rule.get_name() != dfl.get_name() )
{
set_attr(rule_node, "name", rule.get_name());
}
if ( rule.get_title() != dfl.get_title() )
{
set_attr(rule_node, "title", rule.get_title());
}
if ( rule.has_else_filter() )
{
rule_node.push_back( ptree::value_type(
"ElseFilter", ptree()));
}
else
{
// filters are not comparable, so compare strings for now
std::string filter = rule.get_filter()->to_string();
std::string default_filter = dfl.get_filter()->to_string();
if ( filter != default_filter)
{
rule_node.push_back( ptree::value_type(
"Filter", ptree()))->second.put_own( filter );
}
}
if (rule.get_min_scale() != dfl.get_min_scale())
{
ptree & min_scale = rule_node.push_back( ptree::value_type(
"MinScaleDenominator", ptree()))->second;
min_scale.put_own( rule.get_min_scale() );
}
if (rule.get_max_scale() != dfl.get_max_scale() )
{
ptree & max_scale = rule_node.push_back( ptree::value_type(
"MaxScaleDenominator", ptree()))->second;
max_scale.put_own( rule.get_max_scale() );
}
symbolizers::const_iterator begin = rule.get_symbolizers().begin();
symbolizers::const_iterator end = rule.get_symbolizers().end();
serialize_symbolizer serializer( rule_node );
std::for_each( begin, end , boost::apply_visitor( serializer ));
}
void serialize_style( ptree & map_node, Map::const_style_iterator style_it )
{
const feature_type_style & style = style_it->second;
const std::string & name = style_it->first;
ptree & style_node = map_node.push_back(
ptree::value_type("Style", ptree()))->second;
set_attr(style_node, "name", name);
rules::const_iterator it = style.get_rules().begin();
rules::const_iterator end = style.get_rules().end();
for (; it != end; ++it)
{
serialize_rule( style_node, * it );
}
}
void serialize_datasource( ptree & layer_node, datasource_ptr datasource)
{
ptree & datasource_node = layer_node.push_back(
ptree::value_type("Datasource", ptree()))->second;
parameters::const_iterator it = datasource->params().begin();
parameters::const_iterator end = datasource->params().end();
for (; it != end; ++it)
{
boost::property_tree::ptree & param_node = datasource_node.push_back(
boost::property_tree::ptree::value_type("Parameter",
boost::property_tree::ptree()))->second;
param_node.put("<xmlattr>.name", it->first );
param_node.put_own( it->second );
}
}
void serialize_layer( ptree & map_node, const Layer & layer )
{
ptree & layer_node = map_node.push_back(
ptree::value_type("Layer", ptree()))->second;
if ( layer.name() != "" )
{
set_attr( layer_node, "name", layer.name() );
}
if ( layer.srs() != "" )
{
set_attr( layer_node, "srs", layer.srs() );
}
set_attr/*<bool>*/( layer_node, "status", layer.isActive() );
set_attr/*<bool>*/( layer_node, "clear_label_cache", layer.clear_label_cache() );
std::vector<std::string> const& style_names = layer.styles();
for (unsigned i = 0; i < style_names.size(); ++i)
{
boost::property_tree::ptree & style_node = layer_node.push_back(
boost::property_tree::ptree::value_type("StyleName",
boost::property_tree::ptree()))->second;
style_node.put_own( style_names[i] );
}
datasource_ptr datasource = layer.datasource();
if ( datasource )
{
serialize_datasource( layer_node, datasource );
}
}
void save_map(Map const & map, std::string const& filename)
{
ptree pt;
// TODO
ptree & map_node = pt.push_back(ptree::value_type("Map", ptree() ))->second;
set_attr( map_node, "srs", map.srs() );
optional<Color> c = map.background();
if ( c )
{
set_attr( map_node, "bgcolor", * c );
}
Map::const_style_iterator it = map.styles().begin();
Map::const_style_iterator end = map.styles().end();
for (; it != end; ++it)
{
serialize_style( map_node, it);
}
std::vector<Layer> const & layers = map.layers();
for (unsigned i = 0; i < layers.size(); ++i )
{
serialize_layer( map_node, layers[i] );
}
write_xml(filename,pt);
}
}

View file

@ -43,30 +43,8 @@ namespace mapnik
std::string const& type,
unsigned width,unsigned height)
: text_symbolizer(name, face_name, size, fill),
background_image_(new ImageData32(width, height))
symbolizer_with_image( file, type, width, height )
{
try
{
boost::scoped_ptr<ImageReader> reader(get_image_reader(type,file));
if (reader.get())
{
reader->read(0,0,*background_image_);
}
}
catch (...)
{
std::clog << "exception caught..." << std::endl;
}
}
void shield_symbolizer::set_background_image(boost::shared_ptr<ImageData32> background_image)
{
background_image_ = background_image;
}
boost::shared_ptr<ImageData32> const& shield_symbolizer::get_background_image() const
{
return background_image_;
}
}

153
src/stroke.cpp Normal file
View file

@ -0,0 +1,153 @@
/*****************************************************************************
*
* This file is part of Mapnik (c++ mapping toolkit)
*
* Copyright (C) 2006 Artem Pavlenko
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
*****************************************************************************/
#include <mapnik/stroke.hpp>
static const char * line_cap_strings[] = {
"butt",
"square",
"round",
""
};
IMPLEMENT_ENUM( mapnik::line_cap_e, line_cap_strings );
static const char * line_join_strings[] = {
"miter",
"miter_revert",
"round",
"bevel",
""
};
IMPLEMENT_ENUM( mapnik::line_join_e, line_join_strings );
namespace mapnik
{
stroke::stroke()
: c_(0,0,0),
width_(1.0),
opacity_(1.0),
line_cap_(BUTT_CAP),
line_join_(MITER_JOIN),
dash_() {}
stroke::stroke(Color const& c, float width)
: c_(c),
width_(width),
opacity_(1.0),
line_cap_(BUTT_CAP),
line_join_(MITER_JOIN),
dash_() {}
stroke::stroke(stroke const& other)
: c_(other.c_),
width_(other.width_),
opacity_(other.opacity_),
line_cap_(other.line_cap_),
line_join_(other.line_join_),
dash_(other.dash_) {}
stroke & stroke::operator=(const stroke& rhs)
{
stroke tmp(rhs);
swap(tmp);
return *this;
}
void stroke::set_color(const Color& c)
{
c_=c;
}
Color const& stroke::get_color() const
{
return c_;
}
float stroke::get_width() const
{
return width_;
}
void stroke::set_width(float w)
{
width_=w;
}
void stroke::set_opacity(float opacity)
{
if (opacity > 1.0) opacity_=1.0;
else if (opacity < 0.0) opacity_=0.0;
else opacity_=opacity;
}
float stroke::get_opacity() const
{
return opacity_;
}
void stroke::set_line_cap(line_cap_e line_cap)
{
line_cap_=line_cap;
}
line_cap_e stroke::get_line_cap() const
{
return line_cap_;
}
void stroke::set_line_join(line_join_e line_join)
{
line_join_=line_join;
}
line_join_e stroke::get_line_join() const
{
return line_join_;
}
void stroke::add_dash(float dash,float gap)
{
dash_.push_back(std::make_pair(dash,gap));
}
bool stroke::has_dash() const
{
return ! dash_.empty();
}
dash_array const& stroke::get_dash_array() const
{
return dash_;
}
void stroke::swap(const stroke& other) throw()
{
c_=other.c_;
width_=other.width_;
opacity_=other.opacity_;
line_cap_=other.line_cap_;
line_join_=other.line_join_;
dash_ = other.dash_;
}
}

66
src/symbolizer.cpp Normal file
View file

@ -0,0 +1,66 @@
/*****************************************************************************
*
* This file is part of Mapnik (c++ mapping toolkit)
*
* Copyright (C) 2006 Artem Pavlenko
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*
*****************************************************************************/
//$Id$
#include <mapnik/symbolizer.hpp>
#include <mapnik/image_reader.hpp>
#include <iostream>
namespace mapnik {
symbolizer_with_image::symbolizer_with_image(boost::shared_ptr<ImageData32> img) :
image_( img ) {}
symbolizer_with_image::symbolizer_with_image(std::string const& file,
std::string const& type, unsigned width,unsigned height)
: image_(new ImageData32(width,height)),
image_filename_( file )
{
std::auto_ptr<ImageReader> reader(get_image_reader(type,file));
if (reader.get())
reader->read(0,0,*image_);
}
symbolizer_with_image::symbolizer_with_image( symbolizer_with_image const& rhs)
: image_(rhs.image_), image_filename_(rhs.image_filename_) {}
boost::shared_ptr<ImageData32> symbolizer_with_image::get_image() const
{
return image_;
}
void symbolizer_with_image::set_image(boost::shared_ptr<ImageData32> symbol)
{
image_ = symbol;
}
const std::string & symbolizer_with_image::get_filename() const
{
return image_filename_;
}
} // end of namespace mapnik

View file

@ -29,6 +29,14 @@
//mapnik
#include <mapnik/text_symbolizer.hpp>
static const char * label_placement_strings[] = {
"point",
"line",
""
};
IMPLEMENT_ENUM( mapnik::label_placement_e, label_placement_strings );
namespace mapnik
{
text_symbolizer::text_symbolizer(std::string const& name, std::string const& face_name, unsigned size,Color const& fill)
@ -44,7 +52,7 @@ namespace mapnik
fill_(fill),
halo_fill_(Color(255,255,255)),
halo_radius_(0),
label_p_(point_placement),
label_p_(POINT_PLACEMENT),
anchor_(0.0,0.5),
displacement_(0.0,0.0),
avoid_edges_(false),

View file

@ -87,21 +87,14 @@ namespace mapnik
rows_per_strip_(0),
tile_width_(0),
tile_height_(0)
{
try
{
init();
}
catch (ImageReaderException& ex)
{
std::clog<<ex.what()<<std::endl;
throw;
}
}
void TiffReader::init()
{
// TODO: error handling
TIFF* tif = load_if_exists(file_name_);
if (!tif) return;