2006-10-03 10:39:43 +02:00
|
|
|
/*****************************************************************************
|
Patch from David Eastcott :
1. Modified Text Symbolizer
a) corrected line fragment centering (for 2nd and subsequent lines, when line breaks occur).
b) adjusted vertical alignment calculation so that:
i) middle -> has the center of the text line(s) at the point origin
ii) bottom -> has the text line(s) below the point origin
iii) top -> has the text line(s) above the point origin
c) added new text_symbolizer attribute: 'wrap_before', value range: true/false, default == false
allows line breaks at first wrap_char before wrap_width as an alternative to the original
which was to create the line break at the first wrap_char after wrap_width
d) added new text_symbolizer attribute: 'horizontal_alignment', value range: left/middle/right, default == middle
i) left -> has all text line(s) to left of the point origin
ii) middle -> has all text line(s) centered on the the point origin
iii) right -> has all text line(s) to the right of the point origin
NOTE: dx, dy position adjustments are applied after alignments and before Justify.
e) added new text_symbolizer attribute: 'justify_alignment', value range: left/middle/right, default == middle
i) left -> after alignments, has all text line(s) are left justified (left to right reading)
ii) middle -> after alignments, has all text line(s) center justified
iii) right -> after alignments, has all text line(s) right justified (right to left reading)
f) added new text_symbolizer attribute: 'opacity', value range: 0.0 thru 1.0; 1.0 == fully opaque
g) modified positioning to compensate for both line_spacing and character_spacing, to ensure proper
centering of the text envelope. Also ensure that centering occurs correctly even if no wrapping
occurs. Line spacing is uniform and consistent and compensates for errors between text_size and
the actual size (ci.height is inconsistent, depending on case and character); fixes issue with
multi-line text where some lines have a slight gap and others are compressed together.
2. Modified shield_symbolizer
a) added the attributes:
i) allow_overlap
ii) vertical_alignment
iii) horizontal_alignment
iv) justify_alignment
v) wrap_width
vi) wrap_character
vii) wrap_before
viii) text_convert
ix) line_spacing
x) character_spacing
xi) opacity
b) added new shield_symbolizer attribute: 'unlock_image', value range: true/false, default == false
i) false == image and text placement behaviour same as before
ii) true == image placement independant of text, image is always centered at geometry point, text placed per attributes,
dx/dy only affect text.
Allows user to create point markers with text, but both the text and image rendering collision detection are done
as a pair (they come and go together - solves problem if using point_symbolizer and text_symbolizers where one or the
other are omitted due to overlaps, but not both)
c) extended choices for the attribute 'placement' to include vertex; effect is limited to the shield_symbolizer
Allows an attempted placement at every vertex available, gives additional shield placement volume when using line geometry
d) ensured that the text placement was not updating the detector unless a shield image was actually placed.
e) added new shield_symbolizer attribute: 'no_text', value range: true/false, default = false
When set true, the text for the feature is ignored ('space' subsituted) so that pure graphic symbols can be used
and no text is rendered over top of them.
2009-10-19 15:52:53 +02:00
|
|
|
*
|
2006-10-03 10:39:43 +02:00
|
|
|
* This file is part of Mapnik (c++ mapping toolkit)
|
|
|
|
*
|
2010-04-09 20:47:19 +02:00
|
|
|
* Copyright (C) 2010 Artem Pavlenko
|
2006-10-03 10:39:43 +02:00
|
|
|
*
|
|
|
|
* 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
|
|
|
|
*
|
|
|
|
*****************************************************************************/
|
2006-10-04 13:22:18 +02:00
|
|
|
// mapnik
|
2007-10-08 19:42:41 +02:00
|
|
|
#include <mapnik/load_map.hpp>
|
|
|
|
|
2009-12-05 04:58:48 +01:00
|
|
|
#include <mapnik/version.hpp>
|
2007-09-25 20:47:12 +02:00
|
|
|
#include <mapnik/image_reader.hpp>
|
2006-10-04 13:22:18 +02:00
|
|
|
#include <mapnik/color.hpp>
|
|
|
|
#include <mapnik/color_factory.hpp>
|
2011-08-29 23:07:45 +02:00
|
|
|
#include <mapnik/symbolizer.hpp>
|
|
|
|
#include <mapnik/feature_type_style.hpp>
|
2009-12-16 21:02:06 +01:00
|
|
|
|
2006-10-04 13:22:18 +02:00
|
|
|
#include <mapnik/layer.hpp>
|
|
|
|
#include <mapnik/datasource_cache.hpp>
|
2007-09-25 20:47:12 +02:00
|
|
|
#include <mapnik/font_engine_freetype.hpp>
|
2008-06-29 12:58:48 +02:00
|
|
|
#include <mapnik/font_set.hpp>
|
2006-10-04 13:22:18 +02:00
|
|
|
|
2007-09-25 20:47:12 +02:00
|
|
|
#include <mapnik/ptree_helpers.hpp>
|
2010-07-15 02:20:50 +02:00
|
|
|
#ifdef HAVE_LIBXML2
|
2007-09-25 20:47:12 +02:00
|
|
|
#include <mapnik/libxml2_loader.hpp>
|
2010-07-15 02:20:50 +02:00
|
|
|
#endif
|
2007-10-08 19:42:41 +02:00
|
|
|
|
2009-12-16 21:02:06 +01:00
|
|
|
#include <mapnik/filter_factory.hpp>
|
2010-06-18 17:39:32 +02:00
|
|
|
#include <mapnik/parse_path.hpp>
|
2010-03-12 15:49:34 +01:00
|
|
|
#include <mapnik/raster_colorizer.hpp>
|
2009-12-16 21:02:06 +01:00
|
|
|
|
2010-06-01 17:27:19 +02:00
|
|
|
#include <mapnik/svg/svg_path_parser.hpp>
|
|
|
|
|
2011-03-16 14:32:04 +01:00
|
|
|
#include <mapnik/metawriter_factory.hpp>
|
2010-07-06 02:37:05 +02:00
|
|
|
|
2011-02-28 14:17:46 +01:00
|
|
|
#include <mapnik/text_placements_simple.hpp>
|
|
|
|
|
2007-10-08 19:42:41 +02:00
|
|
|
// boost
|
|
|
|
#include <boost/optional.hpp>
|
|
|
|
#include <boost/algorithm/string.hpp>
|
|
|
|
#include <boost/lexical_cast.hpp>
|
|
|
|
#include <boost/tokenizer.hpp>
|
|
|
|
#include <boost/property_tree/ptree.hpp>
|
|
|
|
#include <boost/property_tree/xml_parser.hpp>
|
|
|
|
#include <boost/static_assert.hpp>
|
2009-05-01 03:59:01 +02:00
|
|
|
#include <boost/filesystem/operations.hpp>
|
|
|
|
|
2010-06-01 17:27:19 +02:00
|
|
|
// agg
|
|
|
|
#include "agg_trans_affine.h"
|
|
|
|
|
2007-10-08 19:42:41 +02:00
|
|
|
// stl
|
|
|
|
#include <iostream>
|
2006-10-03 10:39:43 +02:00
|
|
|
|
2006-10-04 13:22:18 +02:00
|
|
|
using boost::lexical_cast;
|
|
|
|
using boost::bad_lexical_cast;
|
|
|
|
using boost::tokenizer;
|
2007-09-25 20:47:12 +02:00
|
|
|
using boost::property_tree::ptree;
|
|
|
|
|
|
|
|
using std::cerr;
|
|
|
|
using std::endl;
|
2006-10-03 10:39:43 +02:00
|
|
|
|
Patch from David Eastcott :
1. Modified Text Symbolizer
a) corrected line fragment centering (for 2nd and subsequent lines, when line breaks occur).
b) adjusted vertical alignment calculation so that:
i) middle -> has the center of the text line(s) at the point origin
ii) bottom -> has the text line(s) below the point origin
iii) top -> has the text line(s) above the point origin
c) added new text_symbolizer attribute: 'wrap_before', value range: true/false, default == false
allows line breaks at first wrap_char before wrap_width as an alternative to the original
which was to create the line break at the first wrap_char after wrap_width
d) added new text_symbolizer attribute: 'horizontal_alignment', value range: left/middle/right, default == middle
i) left -> has all text line(s) to left of the point origin
ii) middle -> has all text line(s) centered on the the point origin
iii) right -> has all text line(s) to the right of the point origin
NOTE: dx, dy position adjustments are applied after alignments and before Justify.
e) added new text_symbolizer attribute: 'justify_alignment', value range: left/middle/right, default == middle
i) left -> after alignments, has all text line(s) are left justified (left to right reading)
ii) middle -> after alignments, has all text line(s) center justified
iii) right -> after alignments, has all text line(s) right justified (right to left reading)
f) added new text_symbolizer attribute: 'opacity', value range: 0.0 thru 1.0; 1.0 == fully opaque
g) modified positioning to compensate for both line_spacing and character_spacing, to ensure proper
centering of the text envelope. Also ensure that centering occurs correctly even if no wrapping
occurs. Line spacing is uniform and consistent and compensates for errors between text_size and
the actual size (ci.height is inconsistent, depending on case and character); fixes issue with
multi-line text where some lines have a slight gap and others are compressed together.
2. Modified shield_symbolizer
a) added the attributes:
i) allow_overlap
ii) vertical_alignment
iii) horizontal_alignment
iv) justify_alignment
v) wrap_width
vi) wrap_character
vii) wrap_before
viii) text_convert
ix) line_spacing
x) character_spacing
xi) opacity
b) added new shield_symbolizer attribute: 'unlock_image', value range: true/false, default == false
i) false == image and text placement behaviour same as before
ii) true == image placement independant of text, image is always centered at geometry point, text placed per attributes,
dx/dy only affect text.
Allows user to create point markers with text, but both the text and image rendering collision detection are done
as a pair (they come and go together - solves problem if using point_symbolizer and text_symbolizers where one or the
other are omitted due to overlaps, but not both)
c) extended choices for the attribute 'placement' to include vertex; effect is limited to the shield_symbolizer
Allows an attempted placement at every vertex available, gives additional shield placement volume when using line geometry
d) ensured that the text placement was not updating the detector unless a shield image was actually placed.
e) added new shield_symbolizer attribute: 'no_text', value range: true/false, default = false
When set true, the text for the feature is ignored ('space' subsituted) so that pure graphic symbols can be used
and no text is rendered over top of them.
2009-10-19 15:52:53 +02:00
|
|
|
namespace mapnik
|
2006-10-03 10:39:43 +02:00
|
|
|
{
|
2010-04-09 20:47:19 +02:00
|
|
|
using boost::optional;
|
|
|
|
|
|
|
|
class map_parser : boost::noncopyable {
|
|
|
|
public:
|
2010-05-27 12:20:10 +02:00
|
|
|
map_parser( bool strict, std::string const& filename = "" ) :
|
2010-06-02 13:03:30 +02:00
|
|
|
strict_( strict ),
|
|
|
|
filename_( filename ),
|
|
|
|
relative_to_xml_(true),
|
|
|
|
font_manager_(font_engine_) {}
|
2010-04-09 20:47:19 +02:00
|
|
|
|
2011-05-26 01:48:07 +02:00
|
|
|
void parse_map(Map & map, ptree const & sty, std::string const& base_path="");
|
2010-04-09 20:47:19 +02:00
|
|
|
private:
|
2010-08-10 08:01:16 +02:00
|
|
|
void parse_map_include( Map & map, ptree const & include);
|
2010-07-06 02:37:05 +02:00
|
|
|
void parse_style(Map & map, ptree const & sty);
|
|
|
|
void parse_layer(Map & map, ptree const & lay);
|
|
|
|
void parse_metawriter(Map & map, ptree const & lay);
|
|
|
|
void parse_metawriter_in_symbolizer(symbolizer_base &sym, ptree const &pt);
|
2010-05-27 12:20:10 +02:00
|
|
|
|
|
|
|
void parse_fontset(Map & map, ptree const & fset);
|
|
|
|
void parse_font(font_set & fset, ptree const & f);
|
|
|
|
|
2010-07-06 02:37:05 +02:00
|
|
|
void parse_rule(feature_type_style & style, ptree const & r);
|
2010-05-27 12:20:10 +02:00
|
|
|
|
2011-01-13 22:35:01 +01:00
|
|
|
void parse_point_symbolizer(rule & rule, ptree const & sym);
|
|
|
|
void parse_line_pattern_symbolizer(rule & rule, ptree const & sym);
|
|
|
|
void parse_polygon_pattern_symbolizer(rule & rule, ptree const & sym);
|
|
|
|
void parse_text_symbolizer(rule & rule, ptree const & sym);
|
|
|
|
void parse_shield_symbolizer(rule & rule, ptree const & sym);
|
|
|
|
void parse_line_symbolizer(rule & rule, ptree const & sym);
|
|
|
|
void parse_polygon_symbolizer(rule & rule, ptree const & sym);
|
|
|
|
void parse_building_symbolizer(rule & rule, ptree const & sym );
|
|
|
|
void parse_raster_symbolizer(rule & rule, ptree const & sym );
|
|
|
|
void parse_markers_symbolizer(rule & rule, ptree const & sym );
|
|
|
|
void parse_glyph_symbolizer(rule & rule, ptree const & sym );
|
2010-05-27 12:20:10 +02:00
|
|
|
|
|
|
|
void parse_raster_colorizer(raster_colorizer_ptr const& rc, ptree const& node );
|
2010-08-19 14:20:30 +02:00
|
|
|
void parse_stroke(stroke & strk, ptree const & sym);
|
2010-05-27 12:20:10 +02:00
|
|
|
|
|
|
|
void ensure_font_face( const std::string & face_name );
|
|
|
|
|
|
|
|
std::string ensure_relative_to_xml( boost::optional<std::string> opt_path );
|
2011-02-05 04:15:17 +01:00
|
|
|
void ensure_attrs( ptree const& sym, std::string name, std::string attrs);
|
2010-05-27 12:20:10 +02:00
|
|
|
|
|
|
|
bool strict_;
|
|
|
|
std::string filename_;
|
|
|
|
bool relative_to_xml_;
|
|
|
|
std::map<std::string,parameters> datasource_templates_;
|
|
|
|
freetype_engine font_engine_;
|
|
|
|
face_manager<freetype_engine> font_manager_;
|
|
|
|
std::map<std::string,std::string> file_sources_;
|
|
|
|
std::map<std::string,font_set> fontsets_;
|
2010-07-06 02:37:05 +02:00
|
|
|
|
2010-04-09 20:47:19 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
void load_map(Map & map, std::string const& filename, bool strict)
|
|
|
|
{
|
2010-05-27 12:20:10 +02:00
|
|
|
ptree pt;
|
2007-09-25 20:47:12 +02:00
|
|
|
#ifdef HAVE_LIBXML2
|
2010-05-27 12:20:10 +02:00
|
|
|
read_xml2(filename, pt);
|
2007-09-25 20:47:12 +02:00
|
|
|
#else
|
2010-05-27 12:20:10 +02:00
|
|
|
try
|
|
|
|
{
|
2010-06-02 13:03:30 +02:00
|
|
|
read_xml(filename, pt);
|
2010-05-27 12:20:10 +02:00
|
|
|
}
|
|
|
|
catch (const boost::property_tree::xml_parser_error & ex)
|
|
|
|
{
|
2010-06-02 13:03:30 +02:00
|
|
|
throw config_error( ex.what() );
|
2010-05-27 12:20:10 +02:00
|
|
|
}
|
2007-09-25 20:47:12 +02:00
|
|
|
#endif
|
2010-05-27 12:20:10 +02:00
|
|
|
map_parser parser( strict, filename);
|
|
|
|
parser.parse_map(map, pt);
|
2010-04-09 20:47:19 +02:00
|
|
|
}
|
2009-01-16 00:51:07 +01:00
|
|
|
|
2011-05-26 01:48:07 +02:00
|
|
|
void load_map_string(Map & map, std::string const& str, bool strict, std::string const& base_path)
|
2010-04-09 20:47:19 +02:00
|
|
|
{
|
2010-05-27 12:20:10 +02:00
|
|
|
ptree pt;
|
2009-01-16 00:51:07 +01:00
|
|
|
#ifdef HAVE_LIBXML2
|
2011-05-26 01:48:07 +02:00
|
|
|
if (!base_path.empty())
|
|
|
|
read_xml2_string(str, pt, base_path); // accept base_path passed into function
|
|
|
|
else
|
|
|
|
read_xml2_string(str, pt, map.base_path()); // default to map base_path
|
2009-01-16 00:51:07 +01:00
|
|
|
#else
|
2010-05-27 12:20:10 +02:00
|
|
|
try
|
|
|
|
{
|
2010-06-02 13:03:30 +02:00
|
|
|
std::istringstream s(str);
|
2011-05-26 01:48:07 +02:00
|
|
|
// TODO - support base_path?
|
2010-06-02 13:03:30 +02:00
|
|
|
read_xml(s,pt);
|
2010-05-27 12:20:10 +02:00
|
|
|
}
|
|
|
|
catch (const boost::property_tree::xml_parser_error & ex)
|
|
|
|
{
|
2010-06-02 13:03:30 +02:00
|
|
|
throw config_error( ex.what() ) ;
|
2010-05-27 12:20:10 +02:00
|
|
|
}
|
2009-01-16 00:51:07 +01:00
|
|
|
#endif
|
2007-09-25 20:47:12 +02:00
|
|
|
|
2011-05-26 01:48:07 +02:00
|
|
|
map_parser parser( strict, base_path);
|
|
|
|
parser.parse_map(map, pt, base_path);
|
2010-04-09 20:47:19 +02:00
|
|
|
}
|
2007-09-25 20:47:12 +02:00
|
|
|
|
2011-05-26 01:48:07 +02:00
|
|
|
void map_parser::parse_map( Map & map, ptree const & pt, std::string const& base_path )
|
2010-04-09 20:47:19 +02:00
|
|
|
{
|
2010-05-27 12:20:10 +02:00
|
|
|
try
|
|
|
|
{
|
2010-06-02 13:03:30 +02:00
|
|
|
ptree const & map_node = pt.get_child("Map");
|
2010-04-09 20:47:19 +02:00
|
|
|
|
2011-02-05 04:15:17 +01:00
|
|
|
std::ostringstream s("");
|
|
|
|
s << "background-color,"
|
|
|
|
<< "background-image,"
|
|
|
|
<< "srs,"
|
|
|
|
<< "buffer-size,"
|
|
|
|
<< "paths-from-xml,"
|
|
|
|
<< "minimum-version,"
|
2011-04-14 04:32:51 +02:00
|
|
|
<< "font-directory,"
|
2011-05-26 01:48:07 +02:00
|
|
|
<< "maximum-extent,"
|
|
|
|
<< "base";
|
2011-02-05 04:15:17 +01:00
|
|
|
ensure_attrs(map_node, "Map", s.str());
|
|
|
|
|
2010-06-02 13:03:30 +02:00
|
|
|
try
|
|
|
|
{
|
2010-10-07 21:34:36 +02:00
|
|
|
parameters extra_attr;
|
|
|
|
|
2011-01-25 21:47:56 +01:00
|
|
|
// Check if relative paths should be interpreted as relative to/from XML location
|
|
|
|
// Default is true, and map_parser::ensure_relative_to_xml will be called to modify path
|
2011-02-05 04:15:17 +01:00
|
|
|
optional<boolean> paths_from_xml = get_opt_attr<boolean>(map_node, "paths-from-xml");
|
2011-01-25 21:47:56 +01:00
|
|
|
if (paths_from_xml)
|
|
|
|
{
|
|
|
|
relative_to_xml_ = *paths_from_xml;
|
|
|
|
}
|
|
|
|
|
2011-05-26 01:48:07 +02:00
|
|
|
optional<std::string> base_path_from_xml = get_opt_attr<std::string>(map_node, "base");
|
|
|
|
if (!base_path.empty())
|
|
|
|
{
|
|
|
|
map.set_base_path( base_path );
|
|
|
|
}
|
|
|
|
else if (base_path_from_xml)
|
|
|
|
{
|
|
|
|
map.set_base_path( *base_path_from_xml );
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
boost::filesystem::path xml_path(filename_);
|
|
|
|
// TODO - should we make this absolute?
|
|
|
|
#if (BOOST_FILESYSTEM_VERSION == 3)
|
2011-06-13 23:42:44 +02:00
|
|
|
std::string base = xml_path.parent_path().string();
|
2011-05-26 01:48:07 +02:00
|
|
|
#else // v2
|
2011-06-13 23:42:44 +02:00
|
|
|
std::string base = xml_path.branch_path().string();
|
2011-05-26 01:48:07 +02:00
|
|
|
#endif
|
|
|
|
|
|
|
|
map.set_base_path( base );
|
|
|
|
}
|
|
|
|
|
2010-07-19 14:01:34 +02:00
|
|
|
optional<color> bgcolor = get_opt_attr<color>(map_node, "background-color");
|
2010-07-19 13:10:03 +02:00
|
|
|
if (bgcolor)
|
|
|
|
{
|
2010-06-02 13:03:30 +02:00
|
|
|
map.set_background( * bgcolor );
|
|
|
|
}
|
2010-07-19 13:10:03 +02:00
|
|
|
|
2011-06-24 02:53:00 +02:00
|
|
|
optional<std::string> image_filename = get_opt_attr<std::string>(map_node, "background-image");
|
2010-07-19 13:10:03 +02:00
|
|
|
if (image_filename)
|
|
|
|
{
|
2011-01-25 21:47:56 +01:00
|
|
|
map.set_background_image(ensure_relative_to_xml(image_filename));
|
2010-07-19 13:10:03 +02:00
|
|
|
}
|
|
|
|
|
2010-06-02 13:03:30 +02:00
|
|
|
map.set_srs( get_attr(map_node, "srs", map.srs() ));
|
2010-04-09 20:47:19 +02:00
|
|
|
|
2011-02-05 04:15:17 +01:00
|
|
|
optional<unsigned> buffer_size = get_opt_attr<unsigned>(map_node,"buffer-size");
|
2010-06-02 13:03:30 +02:00
|
|
|
if (buffer_size)
|
|
|
|
{
|
|
|
|
map.set_buffer_size(*buffer_size);
|
|
|
|
}
|
2010-04-09 20:47:19 +02:00
|
|
|
|
2011-04-14 04:32:51 +02:00
|
|
|
optional<std::string> maximum_extent = get_opt_attr<std::string>(map_node,"maximum-extent");
|
|
|
|
if (maximum_extent)
|
|
|
|
{
|
|
|
|
box2d<double> box;
|
|
|
|
if (box.from_string(*maximum_extent))
|
|
|
|
{
|
|
|
|
map.set_maximum_extent(box);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
std::ostringstream s;
|
|
|
|
s << "failed to parse 'maximum-extent'";
|
|
|
|
if ( strict_ )
|
|
|
|
throw config_error(s.str());
|
|
|
|
else
|
|
|
|
std::clog << "### WARNING: " << s.str() << std::endl;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-02-05 04:15:17 +01:00
|
|
|
optional<std::string> font_directory = get_opt_attr<std::string>(map_node,"font-directory");
|
2010-10-07 03:49:07 +02:00
|
|
|
if (font_directory)
|
|
|
|
{
|
2011-02-05 04:15:17 +01:00
|
|
|
extra_attr["font-directory"] = *font_directory;
|
2010-10-07 03:49:07 +02:00
|
|
|
freetype_engine::register_fonts( ensure_relative_to_xml(font_directory), false);
|
|
|
|
}
|
|
|
|
|
2011-02-05 04:15:17 +01:00
|
|
|
optional<std::string> min_version_string = get_opt_attr<std::string>(map_node, "minimum-version");
|
2010-01-26 23:54:03 +01:00
|
|
|
|
2010-06-02 13:03:30 +02:00
|
|
|
if (min_version_string)
|
|
|
|
{
|
2011-02-05 04:15:17 +01:00
|
|
|
extra_attr["minimum-version"] = *min_version_string;
|
2010-06-02 13:03:30 +02:00
|
|
|
boost::char_separator<char> sep(".");
|
|
|
|
boost::tokenizer<boost::char_separator<char> > tokens(*min_version_string,sep);
|
|
|
|
unsigned i = 0;
|
|
|
|
bool success = false;
|
|
|
|
int n[3];
|
|
|
|
for (boost::tokenizer<boost::char_separator<char> >::iterator beg=tokens.begin();
|
|
|
|
beg!=tokens.end();++beg)
|
|
|
|
{
|
|
|
|
try
|
|
|
|
{
|
|
|
|
n[i] = boost::lexical_cast<int>(boost::trim_copy(*beg));
|
|
|
|
}
|
|
|
|
catch (boost::bad_lexical_cast & ex)
|
|
|
|
{
|
|
|
|
std::clog << *beg << " : " << ex.what() << "\n";
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (i==2)
|
|
|
|
{
|
|
|
|
success = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
++i;
|
|
|
|
}
|
|
|
|
if (success)
|
|
|
|
{
|
|
|
|
int min_version = (n[0] * 100000) + (n[1] * 100) + (n[2]);
|
|
|
|
if (min_version > MAPNIK_VERSION)
|
|
|
|
{
|
|
|
|
throw config_error(std::string("This map uses features only present in Mapnik version ") + *min_version_string + " and newer");
|
|
|
|
}
|
2010-05-27 12:20:10 +02:00
|
|
|
|
2010-06-02 13:03:30 +02:00
|
|
|
}
|
2010-05-27 12:20:10 +02:00
|
|
|
|
2010-06-02 13:03:30 +02:00
|
|
|
}
|
2010-10-07 21:34:36 +02:00
|
|
|
map.set_extra_attributes(extra_attr);
|
2010-06-02 13:03:30 +02:00
|
|
|
}
|
|
|
|
catch (const config_error & ex)
|
|
|
|
{
|
|
|
|
ex.append_context("(in node Map)");
|
|
|
|
throw;
|
|
|
|
}
|
2011-01-04 16:22:49 +01:00
|
|
|
|
2010-08-10 08:01:16 +02:00
|
|
|
parse_map_include( map, map_node );
|
|
|
|
}
|
|
|
|
catch (const boost::property_tree::ptree_bad_path &)
|
|
|
|
{
|
|
|
|
throw config_error("Not a map file. Node 'Map' not found.");
|
|
|
|
}
|
|
|
|
}
|
2011-01-04 16:22:49 +01:00
|
|
|
|
2010-08-10 08:01:16 +02:00
|
|
|
void map_parser::parse_map_include( Map & map, ptree const & include )
|
|
|
|
{
|
2011-01-04 16:22:49 +01:00
|
|
|
ptree::const_iterator itr = include.begin();
|
|
|
|
ptree::const_iterator end = include.end();
|
2010-06-02 13:03:30 +02:00
|
|
|
|
2011-01-04 16:22:49 +01:00
|
|
|
for (; itr != end; ++itr)
|
|
|
|
{
|
|
|
|
ptree::value_type const& v = *itr;
|
2010-06-02 13:03:30 +02:00
|
|
|
|
2011-01-04 16:22:49 +01:00
|
|
|
if (v.first == "Include")
|
|
|
|
{
|
|
|
|
parse_map_include( map, v.second );
|
|
|
|
}
|
|
|
|
else if (v.first == "Style")
|
|
|
|
{
|
|
|
|
parse_style( map, v.second );
|
|
|
|
}
|
|
|
|
else if (v.first == "Layer")
|
|
|
|
{
|
|
|
|
parse_layer(map, v.second );
|
|
|
|
}
|
|
|
|
else if (v.first == "FontSet")
|
|
|
|
{
|
|
|
|
parse_fontset(map, v.second);
|
|
|
|
}
|
|
|
|
else if (v.first == "MetaWriter")
|
|
|
|
{
|
|
|
|
parse_metawriter(map, v.second);
|
|
|
|
}
|
|
|
|
else if (v.first == "FileSource")
|
|
|
|
{
|
2011-06-24 02:53:00 +02:00
|
|
|
std::string name = get_attr<std::string>( v.second, "name");
|
|
|
|
std::string value = get_value<std::string>( v.second, "");
|
2011-01-04 16:22:49 +01:00
|
|
|
file_sources_[name] = value;
|
|
|
|
}
|
|
|
|
else if (v.first == "Datasource")
|
|
|
|
{
|
2011-06-24 02:53:00 +02:00
|
|
|
std::string name = get_attr(v.second, "name", std::string("Unnamed"));
|
2011-01-04 16:22:49 +01:00
|
|
|
parameters params;
|
|
|
|
ptree::const_iterator paramIter = v.second.begin();
|
|
|
|
ptree::const_iterator endParam = v.second.end();
|
|
|
|
for (; paramIter != endParam; ++paramIter)
|
2010-06-02 13:03:30 +02:00
|
|
|
{
|
2011-01-04 16:22:49 +01:00
|
|
|
ptree const& param = paramIter->second;
|
2010-06-02 13:03:30 +02:00
|
|
|
|
2011-01-04 16:22:49 +01:00
|
|
|
if (paramIter->first == "Parameter")
|
|
|
|
{
|
2011-06-24 02:53:00 +02:00
|
|
|
std::string name = get_attr<std::string>(param, "name");
|
|
|
|
std::string value = get_value<std::string>( param,
|
2011-01-04 16:22:49 +01:00
|
|
|
"datasource parameter");
|
|
|
|
params[name] = value;
|
|
|
|
}
|
|
|
|
else if( paramIter->first != "<xmlattr>" &&
|
|
|
|
paramIter->first != "<xmlcomment>" )
|
|
|
|
{
|
|
|
|
throw config_error(std::string("Unknown child node in ") +
|
|
|
|
"'Datasource'. Expected 'Parameter' but got '" +
|
|
|
|
paramIter->first + "'");
|
2010-06-02 13:03:30 +02:00
|
|
|
}
|
|
|
|
}
|
2011-01-04 16:22:49 +01:00
|
|
|
datasource_templates_[name] = params;
|
2010-06-02 13:03:30 +02:00
|
|
|
}
|
2011-01-04 16:22:49 +01:00
|
|
|
else if (v.first != "<xmlcomment>" &&
|
|
|
|
v.first != "<xmlattr>")
|
|
|
|
{
|
|
|
|
throw config_error(std::string("Unknown child node in 'Map': '") +
|
|
|
|
v.first + "'");
|
|
|
|
}
|
|
|
|
}
|
2010-08-10 08:01:16 +02:00
|
|
|
|
|
|
|
|
2010-07-06 02:37:05 +02:00
|
|
|
map.init_metawriters();
|
2010-04-09 20:47:19 +02:00
|
|
|
}
|
2007-09-25 20:47:12 +02:00
|
|
|
|
2010-04-09 20:47:19 +02:00
|
|
|
void map_parser::parse_style( Map & map, ptree const & sty )
|
|
|
|
{
|
2011-02-05 04:15:17 +01:00
|
|
|
std::ostringstream s("");
|
|
|
|
s << "name,"
|
|
|
|
<< "filter-mode";
|
|
|
|
ensure_attrs(sty, "Style", s.str());
|
|
|
|
|
2011-06-24 02:53:00 +02:00
|
|
|
std::string name("<missing name>");
|
2010-04-09 20:47:19 +02:00
|
|
|
try
|
2008-06-29 12:58:48 +02:00
|
|
|
{
|
2011-06-24 02:53:00 +02:00
|
|
|
name = get_attr<std::string>(sty, "name");
|
2010-06-02 13:03:30 +02:00
|
|
|
feature_type_style style;
|
|
|
|
|
2011-02-01 23:55:50 +01:00
|
|
|
filter_mode_e filter_mode = get_attr<filter_mode_e>(sty, "filter-mode", FILTER_ALL);
|
|
|
|
style.set_filter_mode(filter_mode);
|
|
|
|
|
2010-06-02 13:03:30 +02:00
|
|
|
ptree::const_iterator ruleIter = sty.begin();
|
|
|
|
ptree::const_iterator endRule = sty.end();
|
|
|
|
|
|
|
|
for (; ruleIter!=endRule; ++ruleIter)
|
|
|
|
{
|
|
|
|
ptree::value_type const& rule_tag = *ruleIter;
|
|
|
|
if (rule_tag.first == "Rule")
|
|
|
|
{
|
|
|
|
parse_rule( style, rule_tag.second );
|
|
|
|
}
|
|
|
|
else if (rule_tag.first != "<xmlcomment>" &&
|
|
|
|
rule_tag.first != "<xmlattr>" )
|
|
|
|
{
|
|
|
|
throw config_error(std::string("Unknown child node in 'Style'. ") +
|
|
|
|
"Expected 'Rule' but got '" + rule_tag.first + "'");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
map.insert_style(name, style);
|
2010-04-09 20:47:19 +02:00
|
|
|
|
|
|
|
} catch (const config_error & ex) {
|
2010-06-02 13:03:30 +02:00
|
|
|
if ( ! name.empty() ) {
|
2011-06-24 02:53:00 +02:00
|
|
|
ex.append_context(std::string("in style '") + name + "'");
|
2010-07-06 02:37:05 +02:00
|
|
|
}
|
2011-06-24 02:53:00 +02:00
|
|
|
ex.append_context(std::string("in map '") + filename_ + "'");
|
2010-07-06 02:37:05 +02:00
|
|
|
throw;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void map_parser::parse_metawriter(Map & map, ptree const & pt)
|
|
|
|
{
|
2011-07-23 02:11:01 +02:00
|
|
|
ensure_attrs(pt, "MetaWriter", "name,type,file,default-output,output-empty,pixel-coordinates");
|
2011-06-24 02:53:00 +02:00
|
|
|
std::string name("<missing name>");
|
2010-07-06 02:37:05 +02:00
|
|
|
metawriter_ptr writer;
|
|
|
|
try
|
|
|
|
{
|
2011-06-24 02:53:00 +02:00
|
|
|
name = get_attr<std::string>(pt, "name");
|
2011-03-16 14:32:04 +01:00
|
|
|
writer = metawriter_create(pt);
|
2010-07-06 02:37:05 +02:00
|
|
|
map.insert_metawriter(name, writer);
|
2011-03-16 14:32:04 +01:00
|
|
|
|
2010-07-06 02:37:05 +02:00
|
|
|
} catch (const config_error & ex) {
|
|
|
|
if (!name.empty()) {
|
2011-06-24 02:53:00 +02:00
|
|
|
ex.append_context(std::string("in meta writer '") + name + "'");
|
2010-06-02 13:03:30 +02:00
|
|
|
}
|
2011-06-24 02:53:00 +02:00
|
|
|
ex.append_context(std::string("in map '") + filename_ + "'");
|
2010-06-02 13:03:30 +02:00
|
|
|
throw;
|
2008-06-29 12:58:48 +02:00
|
|
|
}
|
2010-04-09 20:47:19 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void map_parser::parse_fontset( Map & map, ptree const & fset )
|
|
|
|
{
|
2011-02-05 04:15:17 +01:00
|
|
|
ensure_attrs(fset, "FontSet", "name,Font");
|
2011-06-24 02:53:00 +02:00
|
|
|
std::string name("<missing name>");
|
2010-04-09 20:47:19 +02:00
|
|
|
try
|
|
|
|
{
|
2011-06-24 02:53:00 +02:00
|
|
|
name = get_attr<std::string>(fset, "name");
|
2010-06-02 13:03:30 +02:00
|
|
|
font_set fontset(name);
|
|
|
|
|
|
|
|
ptree::const_iterator itr = fset.begin();
|
|
|
|
ptree::const_iterator end = fset.end();
|
|
|
|
|
|
|
|
for (; itr != end; ++itr)
|
|
|
|
{
|
|
|
|
ptree::value_type const& font_tag = *itr;
|
|
|
|
|
|
|
|
if (font_tag.first == "Font")
|
|
|
|
{
|
|
|
|
parse_font(fontset, font_tag.second);
|
|
|
|
}
|
|
|
|
else if (font_tag.first != "<xmlcomment>" &&
|
|
|
|
font_tag.first != "<xmlattr>" )
|
|
|
|
{
|
|
|
|
throw config_error(std::string("Unknown child node in 'FontSet'. ") +
|
|
|
|
"Expected 'Font' but got '" + font_tag.first + "'");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
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));
|
2010-04-09 20:47:19 +02:00
|
|
|
} catch (const config_error & ex) {
|
2010-06-02 13:03:30 +02:00
|
|
|
if ( ! name.empty() ) {
|
2011-06-24 02:53:00 +02:00
|
|
|
ex.append_context(std::string("in FontSet '") + name + "'");
|
2010-06-02 13:03:30 +02:00
|
|
|
}
|
2011-06-24 02:53:00 +02:00
|
|
|
ex.append_context(std::string("in map '") + filename_ + "'");
|
2010-06-02 13:03:30 +02:00
|
|
|
throw;
|
2010-04-09 20:47:19 +02:00
|
|
|
}
|
|
|
|
}
|
2008-06-29 12:58:48 +02:00
|
|
|
|
2010-04-09 20:47:19 +02:00
|
|
|
void map_parser::parse_font(font_set & fset, ptree const & f)
|
|
|
|
{
|
2011-02-05 04:15:17 +01:00
|
|
|
ensure_attrs(f, "Font", "face-name");
|
|
|
|
|
2011-06-24 02:53:00 +02:00
|
|
|
std::string face_name = get_attr(f, "face-name", std::string());
|
2008-06-29 12:58:48 +02:00
|
|
|
|
2010-04-09 20:47:19 +02:00
|
|
|
if ( strict_ )
|
2007-09-25 20:47:12 +02:00
|
|
|
{
|
2010-06-02 13:03:30 +02:00
|
|
|
ensure_font_face( face_name );
|
2007-09-25 20:47:12 +02:00
|
|
|
}
|
|
|
|
|
2010-04-09 20:47:19 +02:00
|
|
|
fset.add_face_name(face_name);
|
|
|
|
}
|
|
|
|
|
|
|
|
void map_parser::parse_layer( Map & map, ptree const & lay )
|
|
|
|
{
|
|
|
|
std::string name;
|
2011-02-05 04:15:17 +01:00
|
|
|
std::ostringstream s("");
|
|
|
|
s << "name,"
|
|
|
|
<< "srs,"
|
|
|
|
<< "status,"
|
|
|
|
<< "title,"
|
|
|
|
<< "abstract,"
|
|
|
|
<< "minzoom,"
|
|
|
|
<< "maxzoom,"
|
|
|
|
<< "queryable,"
|
2011-08-31 02:25:03 +02:00
|
|
|
<< "clear-label-cache,"
|
2011-08-31 01:10:10 +02:00
|
|
|
<< "cache-features";
|
2011-02-05 04:15:17 +01:00
|
|
|
ensure_attrs(lay, "Layer", s.str());
|
2010-04-09 20:47:19 +02:00
|
|
|
try
|
2007-09-25 20:47:12 +02:00
|
|
|
{
|
2011-06-24 02:53:00 +02:00
|
|
|
name = get_attr(lay, "name", std::string("Unnamed"));
|
2010-06-02 13:03:30 +02:00
|
|
|
|
|
|
|
// XXX if no projection is given inherit from map? [DS]
|
|
|
|
std::string srs = get_attr(lay, "srs", map.srs());
|
|
|
|
|
|
|
|
layer lyr(name, srs);
|
|
|
|
|
|
|
|
optional<boolean> status = get_opt_attr<boolean>(lay, "status");
|
|
|
|
if (status)
|
|
|
|
{
|
|
|
|
lyr.setActive( * status );
|
|
|
|
}
|
|
|
|
|
2011-06-24 02:53:00 +02:00
|
|
|
optional<std::string> title = get_opt_attr<std::string>(lay, "title");
|
2010-06-02 13:03:30 +02:00
|
|
|
if (title)
|
|
|
|
{
|
|
|
|
lyr.set_title( * title );
|
|
|
|
}
|
|
|
|
|
2011-06-24 02:53:00 +02:00
|
|
|
optional<std::string> abstract = get_opt_attr<std::string>(lay, "abstract");
|
2010-06-02 13:03:30 +02:00
|
|
|
if (abstract)
|
|
|
|
{
|
|
|
|
lyr.set_abstract( * abstract );
|
|
|
|
}
|
|
|
|
|
|
|
|
optional<double> minZoom = get_opt_attr<double>(lay, "minzoom");
|
|
|
|
if (minZoom)
|
|
|
|
{
|
|
|
|
lyr.setMinZoom( * minZoom );
|
|
|
|
}
|
|
|
|
|
|
|
|
optional<double> maxZoom = get_opt_attr<double>(lay, "maxzoom");
|
|
|
|
if (maxZoom)
|
|
|
|
{
|
|
|
|
lyr.setMaxZoom( * maxZoom );
|
|
|
|
}
|
|
|
|
|
|
|
|
optional<boolean> queryable = get_opt_attr<boolean>(lay, "queryable");
|
|
|
|
if (queryable)
|
|
|
|
{
|
|
|
|
lyr.setQueryable( * queryable );
|
|
|
|
}
|
|
|
|
|
|
|
|
optional<boolean> clear_cache =
|
2011-02-05 04:15:17 +01:00
|
|
|
get_opt_attr<boolean>(lay, "clear-label-cache");
|
2010-06-02 13:03:30 +02:00
|
|
|
if (clear_cache)
|
|
|
|
{
|
|
|
|
lyr.set_clear_label_cache( * clear_cache );
|
|
|
|
}
|
|
|
|
|
2011-03-01 18:09:29 +01:00
|
|
|
optional<boolean> cache_features =
|
|
|
|
get_opt_attr<boolean>(lay, "cache-features");
|
|
|
|
if (cache_features)
|
|
|
|
{
|
|
|
|
lyr.set_cache_features( * cache_features );
|
|
|
|
}
|
|
|
|
|
2010-06-02 13:03:30 +02:00
|
|
|
|
|
|
|
ptree::const_iterator itr2 = lay.begin();
|
|
|
|
ptree::const_iterator end2 = lay.end();
|
|
|
|
|
|
|
|
for(; itr2 != end2; ++itr2)
|
|
|
|
{
|
|
|
|
ptree::value_type const& child = *itr2;
|
|
|
|
|
|
|
|
if (child.first == "StyleName")
|
|
|
|
{
|
2011-02-05 04:15:17 +01:00
|
|
|
ensure_attrs(child.second, "StyleName", "none");
|
|
|
|
std::string style_name = child.second.data();
|
|
|
|
if (style_name.empty())
|
|
|
|
{
|
|
|
|
std::ostringstream ss;
|
|
|
|
ss << "StyleName is empty in Layer: '" << lyr.name() << "'";
|
|
|
|
if (strict_)
|
|
|
|
throw config_error(ss.str());
|
|
|
|
else
|
|
|
|
std::clog << "### WARNING: " << ss.str() << std::endl;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
lyr.add_style(style_name);
|
|
|
|
}
|
2010-06-02 13:03:30 +02:00
|
|
|
}
|
|
|
|
else if (child.first == "Datasource")
|
|
|
|
{
|
2011-02-05 04:15:17 +01:00
|
|
|
ensure_attrs(child.second, "Datasource", "base");
|
2010-06-02 13:03:30 +02:00
|
|
|
parameters params;
|
|
|
|
optional<std::string> base = get_opt_attr<std::string>( child.second, "base" );
|
|
|
|
if( base )
|
|
|
|
{
|
|
|
|
std::map<std::string,parameters>::const_iterator base_itr = datasource_templates_.find(*base);
|
|
|
|
if (base_itr!=datasource_templates_.end())
|
|
|
|
params = base_itr->second;
|
|
|
|
}
|
|
|
|
|
|
|
|
ptree::const_iterator paramIter = child.second.begin();
|
|
|
|
ptree::const_iterator endParam = child.second.end();
|
|
|
|
for (; paramIter != endParam; ++paramIter)
|
|
|
|
{
|
|
|
|
ptree const& param = paramIter->second;
|
|
|
|
|
|
|
|
if (paramIter->first == "Parameter")
|
|
|
|
{
|
2011-02-05 04:15:17 +01:00
|
|
|
ensure_attrs(param, "Parameter", "name");
|
2011-06-24 02:53:00 +02:00
|
|
|
std::string name = get_attr<std::string>(param, "name");
|
|
|
|
std::string value = get_value<std::string>( param,
|
2010-06-02 13:03:30 +02:00
|
|
|
"datasource parameter");
|
|
|
|
params[name] = value;
|
|
|
|
}
|
|
|
|
else if( paramIter->first != "<xmlattr>" &&
|
|
|
|
paramIter->first != "<xmlcomment>" )
|
|
|
|
{
|
|
|
|
throw config_error(std::string("Unknown child node in ") +
|
|
|
|
"'Datasource'. Expected 'Parameter' but got '" +
|
|
|
|
paramIter->first + "'");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-01-25 21:47:56 +01:00
|
|
|
boost::optional<std::string> base_param = params.get<std::string>("base");
|
|
|
|
boost::optional<std::string> file_param = params.get<std::string>("file");
|
2010-06-02 13:03:30 +02:00
|
|
|
|
2011-01-25 21:47:56 +01:00
|
|
|
if (base_param){
|
|
|
|
params["base"] = ensure_relative_to_xml(base_param);
|
2010-06-02 13:03:30 +02:00
|
|
|
}
|
2011-01-25 21:47:56 +01:00
|
|
|
|
|
|
|
else if (file_param){
|
|
|
|
params["file"] = ensure_relative_to_xml(file_param);
|
2010-06-02 13:03:30 +02:00
|
|
|
}
|
2010-04-09 20:47:19 +02:00
|
|
|
|
2010-06-02 13:03:30 +02:00
|
|
|
//now we are ready to create datasource
|
|
|
|
try
|
|
|
|
{
|
|
|
|
boost::shared_ptr<datasource> ds =
|
|
|
|
datasource_cache::instance()->create(params);
|
|
|
|
lyr.set_datasource(ds);
|
|
|
|
}
|
|
|
|
|
2011-08-30 01:51:15 +02:00
|
|
|
catch (const std::exception & ex )
|
2010-06-02 13:03:30 +02:00
|
|
|
{
|
|
|
|
throw config_error( ex.what() );
|
|
|
|
}
|
|
|
|
|
|
|
|
catch (...)
|
|
|
|
{
|
2011-08-30 01:51:15 +02:00
|
|
|
throw config_error("Unknown exception occured attempting to create datasoure for layer '" + lyr.name() + "'");
|
2010-06-02 13:03:30 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (child.first != "<xmlattr>" &&
|
|
|
|
child.first != "<xmlcomment>")
|
|
|
|
{
|
|
|
|
throw config_error(std::string("Unknown child node in 'Layer'. ") +
|
|
|
|
"Expected 'StyleName' or 'Datasource' but got '" +
|
|
|
|
child.first + "'");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
map.addLayer(lyr);
|
2010-04-09 20:47:19 +02:00
|
|
|
|
2011-01-04 16:22:49 +01:00
|
|
|
}
|
|
|
|
catch (const config_error & ex)
|
|
|
|
{
|
|
|
|
if ( ! name.empty() )
|
|
|
|
{
|
2010-06-02 13:03:30 +02:00
|
|
|
ex.append_context(std::string("(encountered during parsing of layer '") + name + "' in map '" + filename_ + "')");
|
|
|
|
}
|
|
|
|
throw;
|
2007-09-25 20:47:12 +02:00
|
|
|
}
|
2010-04-09 20:47:19 +02:00
|
|
|
}
|
2007-09-25 20:47:12 +02:00
|
|
|
|
2010-04-09 20:47:19 +02:00
|
|
|
void map_parser::parse_rule( feature_type_style & style, ptree const & r )
|
|
|
|
{
|
2011-02-05 04:15:17 +01:00
|
|
|
ensure_attrs(r, "Rule", "name,title");
|
2010-04-09 20:47:19 +02:00
|
|
|
std::string name;
|
|
|
|
try
|
2007-09-25 20:47:12 +02:00
|
|
|
{
|
2011-06-24 02:53:00 +02:00
|
|
|
name = get_attr( r, "name", std::string());
|
|
|
|
std::string title = get_attr( r, "title", std::string());
|
2010-06-02 13:03:30 +02:00
|
|
|
|
2011-01-13 22:35:01 +01:00
|
|
|
rule rule(name,title);
|
2010-06-02 13:03:30 +02:00
|
|
|
|
|
|
|
optional<std::string> filter_expr =
|
2011-06-24 02:53:00 +02:00
|
|
|
get_opt_child<std::string>( r, "Filter");
|
2010-06-02 13:03:30 +02:00
|
|
|
if (filter_expr)
|
|
|
|
{
|
|
|
|
// TODO - can we use encoding defined for XML document for filter expressions?
|
|
|
|
rule.set_filter(parse_expression(*filter_expr,"utf8"));
|
|
|
|
}
|
|
|
|
|
|
|
|
optional<std::string> else_filter =
|
2011-06-24 02:53:00 +02:00
|
|
|
get_opt_child<std::string>(r, "ElseFilter");
|
2010-06-02 13:03:30 +02:00
|
|
|
if (else_filter)
|
|
|
|
{
|
|
|
|
rule.set_else(true);
|
|
|
|
}
|
|
|
|
|
2011-08-30 19:38:27 +02:00
|
|
|
optional<std::string> also_filter =
|
|
|
|
get_opt_child<std::string>(r, "AlsoFilter");
|
|
|
|
if (also_filter)
|
|
|
|
{
|
|
|
|
rule.set_also(true);
|
|
|
|
}
|
|
|
|
|
2010-06-02 13:03:30 +02:00
|
|
|
optional<double> min_scale =
|
|
|
|
get_opt_child<double>(r, "MinScaleDenominator");
|
|
|
|
if (min_scale)
|
|
|
|
{
|
|
|
|
rule.set_min_scale(*min_scale);
|
|
|
|
}
|
|
|
|
|
|
|
|
optional<double> max_scale =
|
|
|
|
get_opt_child<double>(r, "MaxScaleDenominator");
|
|
|
|
if (max_scale)
|
|
|
|
{
|
|
|
|
rule.set_max_scale(*max_scale);
|
|
|
|
}
|
|
|
|
|
|
|
|
ptree::const_iterator symIter = r.begin();
|
|
|
|
ptree::const_iterator endSym = r.end();
|
|
|
|
|
|
|
|
for( ;symIter != endSym; ++symIter)
|
|
|
|
{
|
|
|
|
ptree::value_type const& sym = *symIter;
|
|
|
|
|
|
|
|
if ( sym.first == "PointSymbolizer")
|
|
|
|
{
|
|
|
|
parse_point_symbolizer( rule, sym.second );
|
|
|
|
}
|
|
|
|
else if ( sym.first == "LinePatternSymbolizer")
|
|
|
|
{
|
|
|
|
parse_line_pattern_symbolizer( rule, sym.second );
|
|
|
|
}
|
|
|
|
else if ( sym.first == "PolygonPatternSymbolizer")
|
|
|
|
{
|
|
|
|
parse_polygon_pattern_symbolizer( rule, sym.second );
|
|
|
|
}
|
|
|
|
else if ( sym.first == "TextSymbolizer")
|
|
|
|
{
|
|
|
|
parse_text_symbolizer( rule, sym.second );
|
|
|
|
}
|
|
|
|
else if ( sym.first == "ShieldSymbolizer")
|
|
|
|
{
|
|
|
|
parse_shield_symbolizer( rule, sym.second );
|
|
|
|
}
|
|
|
|
else if ( sym.first == "LineSymbolizer")
|
|
|
|
{
|
|
|
|
parse_line_symbolizer( rule, sym.second );
|
|
|
|
}
|
|
|
|
else if ( sym.first == "PolygonSymbolizer")
|
|
|
|
{
|
|
|
|
parse_polygon_symbolizer( rule, sym.second );
|
|
|
|
}
|
|
|
|
else if ( sym.first == "BuildingSymbolizer")
|
|
|
|
{
|
|
|
|
parse_building_symbolizer( rule, sym.second );
|
|
|
|
}
|
|
|
|
else if ( sym.first == "RasterSymbolizer")
|
|
|
|
{
|
|
|
|
parse_raster_symbolizer( rule, sym.second );
|
|
|
|
}
|
|
|
|
else if ( sym.first == "MarkersSymbolizer")
|
|
|
|
{
|
|
|
|
parse_markers_symbolizer(rule, sym.second);
|
|
|
|
}
|
|
|
|
else if ( sym.first == "GlyphSymbolizer")
|
|
|
|
{
|
|
|
|
parse_glyph_symbolizer( rule, sym.second );
|
|
|
|
}
|
|
|
|
|
|
|
|
else if ( sym.first != "MinScaleDenominator" &&
|
|
|
|
sym.first != "MaxScaleDenominator" &&
|
|
|
|
sym.first != "Filter" &&
|
|
|
|
sym.first != "ElseFilter" &&
|
2011-08-30 19:38:27 +02:00
|
|
|
sym.first != "AlsoFilter" &&
|
2010-06-02 13:03:30 +02:00
|
|
|
sym.first != "<xmlcomment>" &&
|
|
|
|
sym.first != "<xmlattr>" )
|
|
|
|
{
|
|
|
|
throw config_error(std::string("Unknown symbolizer '") +
|
|
|
|
sym.first + "'");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
style.add_rule(rule);
|
2010-04-09 20:47:19 +02:00
|
|
|
|
|
|
|
}
|
|
|
|
catch (const config_error & ex)
|
|
|
|
{
|
2010-06-02 13:03:30 +02:00
|
|
|
if ( ! name.empty() )
|
|
|
|
{
|
2011-06-24 02:53:00 +02:00
|
|
|
ex.append_context(std::string("in rule '") + name + "' in map '" + filename_ + "')");
|
2010-06-02 13:03:30 +02:00
|
|
|
}
|
|
|
|
throw;
|
2010-04-09 20:47:19 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-07-06 02:37:05 +02:00
|
|
|
void map_parser::parse_metawriter_in_symbolizer(symbolizer_base &sym, ptree const &pt)
|
|
|
|
{
|
2011-06-24 02:53:00 +02:00
|
|
|
optional<std::string> writer = get_opt_attr<std::string>(pt, "meta-writer");
|
2010-07-06 02:37:05 +02:00
|
|
|
if (!writer) return;
|
2011-06-24 02:53:00 +02:00
|
|
|
optional<std::string> output = get_opt_attr<std::string>(pt, "meta-output");
|
2010-07-14 12:34:18 +02:00
|
|
|
sym.add_metawriter(*writer, output);
|
2010-07-06 02:37:05 +02:00
|
|
|
}
|
|
|
|
|
2011-01-13 22:35:01 +01:00
|
|
|
void map_parser::parse_point_symbolizer( rule & rule, ptree const & sym )
|
2010-04-09 20:47:19 +02:00
|
|
|
{
|
|
|
|
try
|
|
|
|
{
|
2011-02-05 04:15:17 +01:00
|
|
|
std::stringstream s;
|
2011-04-26 19:33:41 +02:00
|
|
|
s << "file,base,allow-overlap,ignore-placement,opacity,placement,transform,meta-writer,meta-output";
|
2011-04-18 03:11:38 +02:00
|
|
|
|
2011-06-24 02:53:00 +02:00
|
|
|
optional<std::string> file = get_opt_attr<std::string>(sym, "file");
|
|
|
|
optional<std::string> base = get_opt_attr<std::string>(sym, "base");
|
2010-06-02 13:03:30 +02:00
|
|
|
optional<boolean> allow_overlap =
|
2011-02-05 04:15:17 +01:00
|
|
|
get_opt_attr<boolean>(sym, "allow-overlap");
|
2010-10-15 04:15:40 +02:00
|
|
|
optional<boolean> ignore_placement =
|
2011-02-05 04:15:17 +01:00
|
|
|
get_opt_attr<boolean>(sym, "ignore-placement");
|
2010-06-02 13:03:30 +02:00
|
|
|
optional<float> opacity =
|
|
|
|
get_opt_attr<float>(sym, "opacity");
|
|
|
|
|
2011-06-24 02:53:00 +02:00
|
|
|
optional<std::string> transform_wkt = get_opt_attr<std::string>(sym, "transform");
|
2010-06-02 13:03:30 +02:00
|
|
|
|
|
|
|
if (file)
|
|
|
|
{
|
2011-02-05 04:15:17 +01:00
|
|
|
ensure_attrs(sym, "PointSymbolizer", s.str());
|
2010-06-02 13:03:30 +02:00
|
|
|
try
|
|
|
|
{
|
|
|
|
if( base )
|
|
|
|
{
|
|
|
|
std::map<std::string,std::string>::const_iterator itr = file_sources_.find(*base);
|
|
|
|
if (itr!=file_sources_.end())
|
|
|
|
{
|
|
|
|
*file = itr->second + "/" + *file;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-01-25 21:47:56 +01:00
|
|
|
*file = ensure_relative_to_xml(file);
|
2010-06-02 13:03:30 +02:00
|
|
|
|
|
|
|
point_symbolizer symbol(parse_path(*file));
|
2010-07-06 02:37:05 +02:00
|
|
|
|
2010-06-02 13:03:30 +02:00
|
|
|
if (allow_overlap)
|
|
|
|
{
|
|
|
|
symbol.set_allow_overlap( * allow_overlap );
|
|
|
|
}
|
|
|
|
if (opacity)
|
|
|
|
{
|
|
|
|
symbol.set_opacity( * opacity );
|
|
|
|
}
|
2010-10-15 04:15:40 +02:00
|
|
|
if (ignore_placement)
|
|
|
|
{
|
|
|
|
symbol.set_ignore_placement( * ignore_placement );
|
|
|
|
}
|
2011-02-01 09:16:32 +01:00
|
|
|
point_placement_e placement =
|
|
|
|
get_attr<point_placement_e>(sym, "placement", CENTROID_POINT_PLACEMENT);
|
|
|
|
symbol.set_point_placement( placement );
|
|
|
|
|
2010-06-02 13:03:30 +02:00
|
|
|
if (transform_wkt)
|
|
|
|
{
|
|
|
|
agg::trans_affine tr;
|
2010-12-11 02:10:45 +01:00
|
|
|
if (!mapnik::svg::parse_transform(*transform_wkt,tr))
|
|
|
|
{
|
|
|
|
std::stringstream ss;
|
2011-02-05 04:15:17 +01:00
|
|
|
ss << "Could not parse transform from '" << transform_wkt
|
|
|
|
<< "', expected string like: 'matrix(1, 0, 0, 1, 0, 0)'";
|
2010-12-11 02:10:45 +01:00
|
|
|
if (strict_)
|
|
|
|
throw config_error(ss.str()); // value_error here?
|
|
|
|
else
|
2011-06-24 02:53:00 +02:00
|
|
|
std::clog << "### WARNING: " << ss << endl;
|
2010-12-11 02:10:45 +01:00
|
|
|
}
|
2010-06-02 13:03:30 +02:00
|
|
|
boost::array<double,6> matrix;
|
|
|
|
tr.store_to(&matrix[0]);
|
|
|
|
symbol.set_transform(matrix);
|
|
|
|
}
|
2010-08-10 14:03:45 +02:00
|
|
|
|
|
|
|
parse_metawriter_in_symbolizer(symbol, sym);
|
2010-06-02 13:03:30 +02:00
|
|
|
rule.append(symbol);
|
|
|
|
}
|
|
|
|
catch (image_reader_exception const & ex )
|
|
|
|
{
|
2011-06-24 02:53:00 +02:00
|
|
|
std::string msg("Failed to load image file '" + * file +
|
2010-06-02 13:03:30 +02:00
|
|
|
"': " + ex.what());
|
|
|
|
if (strict_)
|
|
|
|
{
|
|
|
|
throw config_error(msg);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2011-06-24 02:53:00 +02:00
|
|
|
std::clog << "### WARNING: " << msg << endl;
|
2010-06-02 13:03:30 +02:00
|
|
|
}
|
|
|
|
}
|
2010-04-09 20:47:19 +02:00
|
|
|
|
2010-04-15 08:09:21 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2011-02-05 04:15:17 +01:00
|
|
|
ensure_attrs(sym, "PointSymbolizer", s.str());
|
2010-04-15 08:09:21 +02:00
|
|
|
point_symbolizer symbol;
|
2010-07-06 02:37:05 +02:00
|
|
|
|
2010-04-15 08:09:21 +02:00
|
|
|
if (allow_overlap)
|
|
|
|
{
|
2010-06-02 13:03:30 +02:00
|
|
|
symbol.set_allow_overlap( * allow_overlap );
|
2010-04-15 08:09:21 +02:00
|
|
|
}
|
|
|
|
if (opacity)
|
|
|
|
{
|
2010-06-02 13:03:30 +02:00
|
|
|
symbol.set_opacity( * opacity );
|
2010-04-15 08:09:21 +02:00
|
|
|
}
|
2010-10-15 04:15:40 +02:00
|
|
|
if (ignore_placement)
|
|
|
|
{
|
|
|
|
symbol.set_ignore_placement( * ignore_placement );
|
|
|
|
}
|
2011-02-01 09:16:32 +01:00
|
|
|
point_placement_e placement =
|
|
|
|
get_attr<point_placement_e>(sym, "placement", CENTROID_POINT_PLACEMENT);
|
|
|
|
symbol.set_point_placement( placement );
|
2010-08-10 14:03:45 +02:00
|
|
|
|
|
|
|
parse_metawriter_in_symbolizer(symbol, sym);
|
2010-04-15 08:09:21 +02:00
|
|
|
rule.append(symbol);
|
|
|
|
}
|
2010-04-09 20:47:19 +02:00
|
|
|
}
|
|
|
|
catch (const config_error & ex)
|
|
|
|
{
|
2010-06-02 13:03:30 +02:00
|
|
|
ex.append_context("in PointSymbolizer");
|
|
|
|
throw;
|
2007-09-25 20:47:12 +02:00
|
|
|
}
|
2010-04-09 20:47:19 +02:00
|
|
|
}
|
2007-09-25 20:47:12 +02:00
|
|
|
|
2010-05-27 16:21:31 +02:00
|
|
|
|
2011-01-13 22:35:01 +01:00
|
|
|
void map_parser::parse_markers_symbolizer( rule & rule, ptree const & sym )
|
2010-05-27 16:21:31 +02:00
|
|
|
{
|
|
|
|
try
|
|
|
|
{
|
2010-05-30 05:16:51 +02:00
|
|
|
std::string filename("");
|
2011-06-24 02:53:00 +02:00
|
|
|
optional<std::string> file = get_opt_attr<std::string>(sym, "file");
|
|
|
|
optional<std::string> base = get_opt_attr<std::string>(sym, "base");
|
|
|
|
optional<std::string> transform_wkt = get_opt_attr<std::string>(sym, "transform");
|
2011-02-05 04:15:17 +01:00
|
|
|
|
|
|
|
std::stringstream s;
|
|
|
|
//s << "file,opacity,spacing,max-error,allow-overlap,placement,";
|
|
|
|
s << "file,base,transform,fill,opacity,"
|
|
|
|
<< "spacing,max-error,allow-overlap,"
|
|
|
|
<< "width,height,placement,marker-type,"
|
|
|
|
<< "stroke,stroke-width,stroke-opacity,stroke-linejoin,"
|
2011-05-17 02:33:24 +02:00
|
|
|
<< "stroke-linecap,stroke-dash-offset,stroke-dasharray,"
|
|
|
|
// note: stroke-gamma intentionally left off here as markers do not support them
|
2011-04-18 03:11:38 +02:00
|
|
|
<< "meta-writer,meta-output";
|
2011-02-09 08:51:52 +01:00
|
|
|
ensure_attrs(sym, "MarkersSymbolizer", s.str());
|
2011-02-05 04:15:17 +01:00
|
|
|
|
2010-05-30 05:16:51 +02:00
|
|
|
if (file)
|
|
|
|
{
|
2011-02-05 04:15:17 +01:00
|
|
|
//s << "base,transform";
|
|
|
|
//ensure_attrs(sym, "MarkersSymbolizer", s.str());
|
2010-05-30 05:16:51 +02:00
|
|
|
try
|
|
|
|
{
|
|
|
|
if (base)
|
|
|
|
{
|
|
|
|
std::map<std::string,std::string>::const_iterator itr = file_sources_.find(*base);
|
|
|
|
if (itr!=file_sources_.end())
|
|
|
|
{
|
|
|
|
*file = itr->second + "/" + *file;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-01-25 21:47:56 +01:00
|
|
|
filename = ensure_relative_to_xml(file);
|
2010-05-30 05:16:51 +02:00
|
|
|
}
|
|
|
|
catch (...)
|
|
|
|
{
|
2011-06-24 02:53:00 +02:00
|
|
|
std::string msg("Failed to load marker file '" + *file + "'!");
|
2010-05-30 05:16:51 +02:00
|
|
|
if (strict_)
|
|
|
|
{
|
|
|
|
throw config_error(msg);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2011-06-24 02:53:00 +02:00
|
|
|
std::clog << "### WARNING: " << msg << endl;
|
2010-05-30 05:16:51 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2011-02-05 04:15:17 +01:00
|
|
|
/*else
|
|
|
|
{
|
|
|
|
//s << "fill,marker-type,width,height";
|
|
|
|
//ensure_attrs(sym, "MarkersSymbolizer", s.str());
|
|
|
|
}*/
|
2010-05-27 16:21:31 +02:00
|
|
|
|
2010-05-30 05:16:51 +02:00
|
|
|
markers_symbolizer symbol(parse_path(filename));
|
|
|
|
optional<float> opacity = get_opt_attr<float>(sym, "opacity");
|
2010-06-15 15:36:33 +02:00
|
|
|
if (opacity) symbol.set_opacity( *opacity );
|
|
|
|
|
2010-06-03 14:35:31 +02:00
|
|
|
if (transform_wkt)
|
|
|
|
{
|
|
|
|
agg::trans_affine tr;
|
2010-12-11 02:10:45 +01:00
|
|
|
if (!mapnik::svg::parse_transform(*transform_wkt,tr))
|
|
|
|
{
|
|
|
|
std::stringstream ss;
|
2011-02-05 04:15:17 +01:00
|
|
|
ss << "Could not parse transform from '" << transform_wkt
|
|
|
|
<< "', expected string like: 'matrix(1, 0, 0, 1, 0, 0)'";
|
2010-12-11 02:10:45 +01:00
|
|
|
if (strict_)
|
|
|
|
throw config_error(ss.str()); // value_error here?
|
|
|
|
else
|
2011-06-24 02:53:00 +02:00
|
|
|
std::clog << "### WARNING: " << ss << endl;
|
2010-12-11 02:10:45 +01:00
|
|
|
}
|
2010-06-03 14:35:31 +02:00
|
|
|
boost::array<double,6> matrix;
|
|
|
|
tr.store_to(&matrix[0]);
|
|
|
|
symbol.set_transform(matrix);
|
|
|
|
}
|
|
|
|
|
2010-05-30 05:16:51 +02:00
|
|
|
optional<color> c = get_opt_attr<color>(sym, "fill");
|
|
|
|
if (c) symbol.set_fill(*c);
|
|
|
|
optional<double> spacing = get_opt_attr<double>(sym, "spacing");
|
|
|
|
if (spacing) symbol.set_spacing(*spacing);
|
2011-02-05 04:15:17 +01:00
|
|
|
optional<double> max_error = get_opt_attr<double>(sym, "max-error");
|
2010-05-30 05:16:51 +02:00
|
|
|
if (max_error) symbol.set_max_error(*max_error);
|
2011-02-05 04:15:17 +01:00
|
|
|
optional<boolean> allow_overlap = get_opt_attr<boolean>(sym, "allow-overlap");
|
2010-05-30 05:16:51 +02:00
|
|
|
if (allow_overlap) symbol.set_allow_overlap(*allow_overlap);
|
2010-08-10 14:03:45 +02:00
|
|
|
|
2010-08-19 19:33:01 +02:00
|
|
|
optional<double> w = get_opt_attr<double>(sym, "width");
|
|
|
|
optional<double> h = get_opt_attr<double>(sym, "height");
|
2010-10-15 02:14:18 +02:00
|
|
|
if (w && h)
|
|
|
|
{
|
|
|
|
symbol.set_width(*w);
|
|
|
|
symbol.set_height(*h);
|
|
|
|
}
|
|
|
|
else if (w)
|
|
|
|
{
|
|
|
|
symbol.set_width(*w);
|
|
|
|
symbol.set_height(*w);
|
|
|
|
|
|
|
|
}
|
|
|
|
else if (h)
|
|
|
|
{
|
|
|
|
symbol.set_width(*h);
|
|
|
|
symbol.set_height(*h);
|
|
|
|
}
|
2010-08-19 19:33:01 +02:00
|
|
|
|
|
|
|
stroke strk;
|
|
|
|
parse_stroke(strk,sym);
|
|
|
|
symbol.set_stroke(strk);
|
|
|
|
|
|
|
|
marker_placement_e placement = get_attr<marker_placement_e>(sym, "placement", MARKER_LINE_PLACEMENT);
|
|
|
|
symbol.set_marker_placement( placement );
|
|
|
|
|
|
|
|
marker_type_e dfl_marker_type = ARROW;
|
|
|
|
|
|
|
|
if (placement == MARKER_POINT_PLACEMENT)
|
|
|
|
dfl_marker_type = ELLIPSE;
|
|
|
|
|
2011-02-05 04:15:17 +01:00
|
|
|
marker_type_e marker_type = get_attr<marker_type_e>(sym, "marker-type", dfl_marker_type);
|
2010-08-19 19:33:01 +02:00
|
|
|
symbol.set_marker_type( marker_type );
|
|
|
|
|
2010-08-10 14:03:45 +02:00
|
|
|
parse_metawriter_in_symbolizer(symbol, sym);
|
2010-05-30 05:16:51 +02:00
|
|
|
rule.append(symbol);
|
2010-05-27 16:21:31 +02:00
|
|
|
}
|
|
|
|
catch (const config_error & ex)
|
|
|
|
{
|
2010-05-30 05:16:51 +02:00
|
|
|
ex.append_context("in MarkersSymbolizer");
|
|
|
|
throw;
|
2010-05-27 16:21:31 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-01-13 22:35:01 +01:00
|
|
|
void map_parser::parse_line_pattern_symbolizer( rule & rule, ptree const & sym )
|
2010-04-09 20:47:19 +02:00
|
|
|
{
|
2011-02-05 04:15:17 +01:00
|
|
|
ensure_attrs(sym, "LinePatternSymbolizer", "file,base,meta-writer,meta-output");
|
2010-04-09 20:47:19 +02:00
|
|
|
try
|
2007-09-25 20:47:12 +02:00
|
|
|
{
|
2011-06-24 02:53:00 +02:00
|
|
|
std::string file = get_attr<std::string>(sym, "file");
|
|
|
|
optional<std::string> base = get_opt_attr<std::string>(sym, "base");
|
2009-12-16 21:02:06 +01:00
|
|
|
|
2010-06-02 13:03:30 +02:00
|
|
|
try
|
|
|
|
{
|
|
|
|
if( base )
|
|
|
|
{
|
|
|
|
std::map<std::string,std::string>::const_iterator itr = file_sources_.find(*base);
|
|
|
|
if (itr!=file_sources_.end())
|
|
|
|
{
|
|
|
|
file = itr->second + "/" + file;
|
|
|
|
}
|
|
|
|
}
|
2010-04-09 20:47:19 +02:00
|
|
|
|
2011-01-25 21:47:56 +01:00
|
|
|
file = ensure_relative_to_xml(file);
|
2010-04-09 20:47:19 +02:00
|
|
|
|
2010-06-02 13:03:30 +02:00
|
|
|
line_pattern_symbolizer symbol(parse_path(file));
|
2010-08-10 14:03:45 +02:00
|
|
|
|
|
|
|
parse_metawriter_in_symbolizer(symbol, sym);
|
2010-06-02 13:03:30 +02:00
|
|
|
rule.append(symbol);
|
|
|
|
}
|
|
|
|
catch (image_reader_exception const & ex )
|
|
|
|
{
|
2011-06-24 02:53:00 +02:00
|
|
|
std::string msg("Failed to load image file '" + file +
|
2010-06-02 13:03:30 +02:00
|
|
|
"': " + ex.what());
|
|
|
|
if (strict_)
|
|
|
|
{
|
|
|
|
throw config_error(msg);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2011-06-24 02:53:00 +02:00
|
|
|
std::clog << "### WARNING: " << msg << endl;
|
2010-06-02 13:03:30 +02:00
|
|
|
}
|
|
|
|
}
|
2007-09-25 20:47:12 +02:00
|
|
|
}
|
2010-04-09 20:47:19 +02:00
|
|
|
catch (const config_error & ex)
|
|
|
|
{
|
2010-06-02 13:03:30 +02:00
|
|
|
ex.append_context("in LinePatternSymbolizer");
|
|
|
|
throw;
|
2010-04-09 20:47:19 +02:00
|
|
|
}
|
|
|
|
}
|
2007-09-25 20:47:12 +02:00
|
|
|
|
2011-01-13 22:35:01 +01:00
|
|
|
void map_parser::parse_polygon_pattern_symbolizer( rule & rule,
|
2010-06-02 13:03:30 +02:00
|
|
|
ptree const & sym )
|
2010-04-09 20:47:19 +02:00
|
|
|
{
|
2011-06-29 00:37:35 +02:00
|
|
|
ensure_attrs(sym, "PolygonPatternSymbolizer", "file,base,alignment,gamma,meta-writer,meta-output");
|
2010-04-09 20:47:19 +02:00
|
|
|
try
|
2007-09-25 20:47:12 +02:00
|
|
|
{
|
2011-06-24 02:53:00 +02:00
|
|
|
std::string file = get_attr<std::string>(sym, "file");
|
|
|
|
optional<std::string> base = get_opt_attr<std::string>(sym, "base");
|
2010-06-02 13:03:30 +02:00
|
|
|
|
|
|
|
try
|
|
|
|
{
|
|
|
|
if( base )
|
|
|
|
{
|
|
|
|
std::map<std::string,std::string>::iterator itr = file_sources_.find(*base);
|
|
|
|
if (itr!=file_sources_.end())
|
|
|
|
{
|
|
|
|
file = itr->second + "/" + file;
|
|
|
|
}
|
|
|
|
}
|
2011-01-25 21:47:56 +01:00
|
|
|
|
|
|
|
file = ensure_relative_to_xml(file);
|
2010-06-21 00:36:49 +02:00
|
|
|
|
2010-06-02 13:03:30 +02:00
|
|
|
polygon_pattern_symbolizer symbol(parse_path(file));
|
2010-06-21 00:36:49 +02:00
|
|
|
|
|
|
|
// pattern alignment
|
|
|
|
pattern_alignment_e p_alignment = get_attr<pattern_alignment_e>(sym, "alignment",LOCAL_ALIGNMENT);
|
|
|
|
symbol.set_alignment(p_alignment);
|
|
|
|
|
2011-06-29 00:37:35 +02:00
|
|
|
// gamma
|
|
|
|
optional<double> gamma = get_opt_attr<double>(sym, "gamma");
|
|
|
|
if (gamma) symbol.set_gamma(*gamma);
|
|
|
|
|
2010-08-10 14:03:45 +02:00
|
|
|
parse_metawriter_in_symbolizer(symbol, sym);
|
2010-06-02 13:03:30 +02:00
|
|
|
rule.append(symbol);
|
|
|
|
}
|
|
|
|
catch (image_reader_exception const & ex )
|
|
|
|
{
|
2011-06-24 02:53:00 +02:00
|
|
|
std::string msg("Failed to load image file '" + file +
|
2010-06-02 13:03:30 +02:00
|
|
|
"': " + ex.what());
|
|
|
|
if (strict_)
|
|
|
|
{
|
|
|
|
throw config_error(msg);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2011-06-24 02:53:00 +02:00
|
|
|
std::clog << "### WARNING: " << msg << endl;
|
2010-06-02 13:03:30 +02:00
|
|
|
}
|
|
|
|
}
|
2007-09-25 20:47:12 +02:00
|
|
|
}
|
2010-04-09 20:47:19 +02:00
|
|
|
catch (const config_error & ex)
|
|
|
|
{
|
2010-06-02 13:03:30 +02:00
|
|
|
ex.append_context("in PolygonPatternSymbolizer");
|
|
|
|
throw;
|
2010-04-09 20:47:19 +02:00
|
|
|
}
|
|
|
|
}
|
2007-09-25 20:47:12 +02:00
|
|
|
|
2011-01-13 22:35:01 +01:00
|
|
|
void map_parser::parse_text_symbolizer( rule & rule, ptree const & sym )
|
2010-04-09 20:47:19 +02:00
|
|
|
{
|
2011-02-05 04:15:17 +01:00
|
|
|
std::stringstream s;
|
|
|
|
s << "name,face-name,fontset-name,size,fill,orientation,"
|
|
|
|
<< "dx,dy,placement,vertical-alignment,halo-fill,"
|
|
|
|
<< "halo-radius,text-ratio,wrap-width,wrap-before,"
|
|
|
|
<< "wrap-character,text-transform,line-spacing,"
|
|
|
|
<< "label-position-tolerance,character-spacing,"
|
2011-09-04 19:33:48 +02:00
|
|
|
<< "spacing,minimum-distance,minimum-padding,minimum-path-length,"
|
2011-02-05 04:15:17 +01:00
|
|
|
<< "avoid-edges,allow-overlap,opacity,max-char-angle-delta,"
|
|
|
|
<< "horizontal-alignment,justify-alignment,"
|
2011-04-18 03:11:38 +02:00
|
|
|
<< "placements,placement-type,"
|
|
|
|
<< "meta-writer,meta-output";
|
2011-02-05 04:15:17 +01:00
|
|
|
|
|
|
|
ensure_attrs(sym, "TextSymbolizer", s.str());
|
2010-04-09 20:47:19 +02:00
|
|
|
try
|
2007-09-25 20:47:12 +02:00
|
|
|
{
|
2011-02-28 14:17:46 +01:00
|
|
|
text_placements_ptr placement_finder;
|
|
|
|
optional<std::string> placement_type = get_opt_attr<std::string>(sym, "placement-type");
|
|
|
|
if (placement_type) {
|
|
|
|
if (*placement_type == "simple") {
|
|
|
|
placement_finder = text_placements_ptr(
|
|
|
|
new text_placements_simple(
|
|
|
|
get_attr<std::string>(sym, "placements", "X")));
|
2011-03-11 15:18:34 +01:00
|
|
|
} else if (*placement_type != "dummy" && *placement_type != "") {
|
|
|
|
throw config_error(std::string("Unknown placement type '"+*placement_type+"'"));
|
2011-02-28 14:17:46 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
if (!placement_finder) {
|
|
|
|
placement_finder = text_placements_ptr(new text_placements_dummy());
|
|
|
|
}
|
|
|
|
|
2011-06-24 02:53:00 +02:00
|
|
|
std::string name = get_attr<std::string>(sym, "name");
|
2010-06-02 13:03:30 +02:00
|
|
|
|
|
|
|
optional<std::string> face_name =
|
2011-02-05 04:15:17 +01:00
|
|
|
get_opt_attr<std::string>(sym, "face-name");
|
2010-06-02 13:03:30 +02:00
|
|
|
|
|
|
|
optional<std::string> fontset_name =
|
2011-02-05 04:15:17 +01:00
|
|
|
get_opt_attr<std::string>(sym, "fontset-name");
|
2010-06-02 13:03:30 +02:00
|
|
|
|
|
|
|
unsigned size = get_attr(sym, "size", 10U);
|
|
|
|
|
|
|
|
color c = get_attr(sym, "fill", color(0,0,0));
|
|
|
|
|
2011-02-28 14:17:46 +01:00
|
|
|
text_symbolizer text_symbol = text_symbolizer(parse_expression(name, "utf8"), size, c, placement_finder);
|
2010-06-02 13:03:30 +02:00
|
|
|
|
|
|
|
optional<std::string> orientation = get_opt_attr<std::string>(sym, "orientation");
|
|
|
|
if (orientation)
|
|
|
|
{
|
|
|
|
text_symbol.set_orientation(parse_expression(*orientation, "utf8"));
|
|
|
|
}
|
|
|
|
|
|
|
|
if (fontset_name && face_name)
|
|
|
|
{
|
2011-02-11 22:32:47 +01:00
|
|
|
throw config_error(std::string("Can't have both face-name and fontset-name"));
|
2010-06-02 13:03:30 +02:00
|
|
|
}
|
|
|
|
else if (fontset_name)
|
|
|
|
{
|
|
|
|
std::map<std::string,font_set>::const_iterator itr = fontsets_.find(*fontset_name);
|
|
|
|
if (itr != fontsets_.end())
|
|
|
|
{
|
|
|
|
text_symbol.set_fontset(itr->second);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
throw config_error("Unable to find any fontset named '" + *fontset_name + "'");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (face_name)
|
|
|
|
{
|
|
|
|
if ( strict_ )
|
|
|
|
{
|
|
|
|
ensure_font_face(*face_name);
|
|
|
|
}
|
|
|
|
text_symbol.set_face_name(*face_name);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2011-02-11 22:32:47 +01:00
|
|
|
throw config_error(std::string("Must have face-name or fontset-name"));
|
2010-06-02 13:03:30 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
double dx = get_attr(sym, "dx", 0.0);
|
|
|
|
double dy = get_attr(sym, "dy", 0.0);
|
|
|
|
text_symbol.set_displacement(dx,dy);
|
|
|
|
|
|
|
|
label_placement_e placement =
|
|
|
|
get_attr<label_placement_e>(sym, "placement", POINT_PLACEMENT);
|
|
|
|
text_symbol.set_label_placement( placement );
|
2010-09-18 21:10:18 +02:00
|
|
|
|
2010-06-02 13:03:30 +02:00
|
|
|
// vertical alignment
|
2011-02-28 14:17:46 +01:00
|
|
|
vertical_alignment_e default_vertical_alignment = V_AUTO;
|
2010-01-11 01:36:51 +01:00
|
|
|
|
2011-02-05 04:15:17 +01:00
|
|
|
vertical_alignment_e valign = get_attr<vertical_alignment_e>(sym, "vertical-alignment", default_vertical_alignment);
|
2010-06-02 13:03:30 +02:00
|
|
|
text_symbol.set_vertical_alignment(valign);
|
|
|
|
|
|
|
|
// halo fill and radius
|
2011-02-05 04:15:17 +01:00
|
|
|
optional<color> halo_fill = get_opt_attr<color>(sym, "halo-fill");
|
2010-06-02 13:03:30 +02:00
|
|
|
if (halo_fill)
|
|
|
|
{
|
|
|
|
text_symbol.set_halo_fill( * halo_fill );
|
|
|
|
}
|
2010-06-16 17:15:13 +02:00
|
|
|
optional<double> halo_radius =
|
2011-02-05 04:15:17 +01:00
|
|
|
get_opt_attr<double>(sym, "halo-radius");
|
2010-06-02 13:03:30 +02:00
|
|
|
if (halo_radius)
|
|
|
|
{
|
|
|
|
text_symbol.set_halo_radius(*halo_radius);
|
|
|
|
}
|
2010-06-16 17:15:13 +02:00
|
|
|
|
2010-06-02 13:03:30 +02:00
|
|
|
// text ratio and wrap width
|
|
|
|
optional<unsigned> text_ratio =
|
2011-02-05 04:15:17 +01:00
|
|
|
get_opt_attr<unsigned>(sym, "text-ratio");
|
2010-06-02 13:03:30 +02:00
|
|
|
if (text_ratio)
|
|
|
|
{
|
|
|
|
text_symbol.set_text_ratio(*text_ratio);
|
|
|
|
}
|
|
|
|
|
|
|
|
optional<unsigned> wrap_width =
|
2011-02-05 04:15:17 +01:00
|
|
|
get_opt_attr<unsigned>(sym, "wrap-width");
|
2010-06-02 13:03:30 +02:00
|
|
|
if (wrap_width)
|
|
|
|
{
|
|
|
|
text_symbol.set_wrap_width(*wrap_width);
|
|
|
|
}
|
|
|
|
|
|
|
|
optional<boolean> wrap_before =
|
2011-02-05 04:15:17 +01:00
|
|
|
get_opt_attr<boolean>(sym, "wrap-before");
|
2010-06-02 13:03:30 +02:00
|
|
|
if (wrap_before)
|
|
|
|
{
|
|
|
|
text_symbol.set_wrap_before(*wrap_before);
|
|
|
|
}
|
|
|
|
|
|
|
|
// character used to break long strings
|
|
|
|
optional<std::string> wrap_char =
|
2011-02-05 04:15:17 +01:00
|
|
|
get_opt_attr<std::string>(sym, "wrap-character");
|
2010-06-02 13:03:30 +02:00
|
|
|
if (wrap_char && (*wrap_char).size() > 0)
|
|
|
|
{
|
|
|
|
text_symbol.set_wrap_char((*wrap_char)[0]);
|
|
|
|
}
|
|
|
|
|
|
|
|
// text conversion before rendering
|
2010-09-18 21:10:18 +02:00
|
|
|
text_transform_e tconvert =
|
2011-02-05 04:15:17 +01:00
|
|
|
get_attr<text_transform_e>(sym, "text-transform", NONE);
|
2010-09-18 21:10:18 +02:00
|
|
|
text_symbol.set_text_transform(tconvert);
|
2010-06-02 13:03:30 +02:00
|
|
|
|
|
|
|
// spacing between text lines
|
2011-02-05 04:15:17 +01:00
|
|
|
optional<unsigned> line_spacing = get_opt_attr<unsigned>(sym, "line-spacing");
|
2010-06-02 13:03:30 +02:00
|
|
|
if (line_spacing)
|
|
|
|
{
|
|
|
|
text_symbol.set_line_spacing(*line_spacing);
|
|
|
|
}
|
|
|
|
|
2011-01-04 16:22:49 +01:00
|
|
|
// tolerance between label spacing along line
|
2011-02-05 04:15:17 +01:00
|
|
|
optional<unsigned> label_position_tolerance = get_opt_attr<unsigned>(sym, "label-position-tolerance");
|
2011-01-04 16:22:49 +01:00
|
|
|
if (label_position_tolerance)
|
|
|
|
{
|
2010-12-01 18:40:33 +01:00
|
|
|
text_symbol.set_label_position_tolerance(*label_position_tolerance);
|
2011-01-04 16:22:49 +01:00
|
|
|
}
|
2010-12-01 18:40:33 +01:00
|
|
|
|
2010-06-02 13:03:30 +02:00
|
|
|
// spacing between characters in text
|
2011-02-05 04:15:17 +01:00
|
|
|
optional<unsigned> character_spacing = get_opt_attr<unsigned>(sym, "character-spacing");
|
2010-06-02 13:03:30 +02:00
|
|
|
if (character_spacing)
|
|
|
|
{
|
|
|
|
text_symbol.set_character_spacing(*character_spacing);
|
|
|
|
}
|
|
|
|
|
|
|
|
// spacing between repeated labels on lines
|
|
|
|
optional<unsigned> spacing = get_opt_attr<unsigned>(sym, "spacing");
|
|
|
|
if (spacing)
|
|
|
|
{
|
|
|
|
text_symbol.set_label_spacing(*spacing);
|
|
|
|
}
|
|
|
|
|
|
|
|
// minimum distance between labels
|
2011-02-05 04:15:17 +01:00
|
|
|
optional<unsigned> min_distance = get_opt_attr<unsigned>(sym, "minimum-distance");
|
2010-06-02 13:03:30 +02:00
|
|
|
if (min_distance)
|
|
|
|
{
|
|
|
|
text_symbol.set_minimum_distance(*min_distance);
|
|
|
|
}
|
2010-11-03 14:18:56 +01:00
|
|
|
|
|
|
|
// minimum distance from edge of the map
|
2011-02-05 04:15:17 +01:00
|
|
|
optional<unsigned> min_padding = get_opt_attr<unsigned>(sym, "minimum-padding");
|
2010-11-03 14:19:04 +01:00
|
|
|
if (min_padding)
|
2010-11-03 14:18:56 +01:00
|
|
|
{
|
|
|
|
text_symbol.set_minimum_padding(*min_padding);
|
|
|
|
}
|
|
|
|
|
2011-09-04 19:33:48 +02:00
|
|
|
// minimum path length
|
|
|
|
optional<unsigned> min_path_length = get_opt_attr<unsigned>(sym, "minimum-path-length");
|
|
|
|
if (min_path_length)
|
|
|
|
{
|
|
|
|
text_symbol.set_minimum_path_length(*min_path_length);
|
|
|
|
}
|
|
|
|
|
2010-06-02 13:03:30 +02:00
|
|
|
// do not render labels around edges
|
|
|
|
optional<boolean> avoid_edges =
|
2011-02-05 04:15:17 +01:00
|
|
|
get_opt_attr<boolean>(sym, "avoid-edges");
|
2010-06-02 13:03:30 +02:00
|
|
|
if (avoid_edges)
|
|
|
|
{
|
|
|
|
text_symbol.set_avoid_edges( * avoid_edges);
|
|
|
|
}
|
|
|
|
|
|
|
|
// allow_overlap
|
|
|
|
optional<boolean> allow_overlap =
|
2011-02-05 04:15:17 +01:00
|
|
|
get_opt_attr<boolean>(sym, "allow-overlap");
|
2010-06-02 13:03:30 +02:00
|
|
|
if (allow_overlap)
|
|
|
|
{
|
|
|
|
text_symbol.set_allow_overlap( * allow_overlap );
|
|
|
|
}
|
|
|
|
|
|
|
|
// opacity
|
|
|
|
optional<double> opacity =
|
|
|
|
get_opt_attr<double>(sym, "opacity");
|
|
|
|
if (opacity)
|
|
|
|
{
|
2010-06-15 14:27:58 +02:00
|
|
|
text_symbol.set_text_opacity( * opacity );
|
2010-06-02 13:03:30 +02:00
|
|
|
}
|
2010-06-15 14:27:58 +02:00
|
|
|
|
2010-06-02 13:03:30 +02:00
|
|
|
// max_char_angle_delta
|
|
|
|
optional<double> max_char_angle_delta =
|
2011-02-05 04:15:17 +01:00
|
|
|
get_opt_attr<double>(sym, "max-char-angle-delta");
|
2010-06-02 13:03:30 +02:00
|
|
|
if (max_char_angle_delta)
|
|
|
|
{
|
2010-09-24 14:55:08 +02:00
|
|
|
text_symbol.set_max_char_angle_delta( (*max_char_angle_delta)*(M_PI/180));
|
2010-06-02 13:03:30 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// horizontal alignment
|
2011-02-28 14:17:46 +01:00
|
|
|
horizontal_alignment_e halign = get_attr<horizontal_alignment_e>(sym, "horizontal-alignment", H_AUTO);
|
2010-06-02 13:03:30 +02:00
|
|
|
text_symbol.set_horizontal_alignment(halign);
|
|
|
|
|
|
|
|
// justify alignment
|
2011-02-05 04:15:17 +01:00
|
|
|
justify_alignment_e jalign = get_attr<justify_alignment_e>(sym, "justify-alignment", J_MIDDLE);
|
2010-06-02 13:03:30 +02:00
|
|
|
text_symbol.set_justify_alignment(jalign);
|
|
|
|
|
2010-08-10 14:03:45 +02:00
|
|
|
parse_metawriter_in_symbolizer(text_symbol, sym);
|
2010-06-02 13:03:30 +02:00
|
|
|
rule.append(text_symbol);
|
2007-09-25 20:47:12 +02:00
|
|
|
}
|
2010-04-09 20:47:19 +02:00
|
|
|
catch (const config_error & ex)
|
|
|
|
{
|
2010-06-02 13:03:30 +02:00
|
|
|
ex.append_context("in TextSymbolizer");
|
|
|
|
throw;
|
2010-04-09 20:47:19 +02:00
|
|
|
}
|
|
|
|
}
|
2007-09-25 20:47:12 +02:00
|
|
|
|
2011-01-13 22:35:01 +01:00
|
|
|
void map_parser::parse_shield_symbolizer( rule & rule, ptree const & sym )
|
2010-04-09 20:47:19 +02:00
|
|
|
{
|
2011-02-05 04:15:17 +01:00
|
|
|
|
|
|
|
std::stringstream s;
|
|
|
|
//std::string a[] = {"a","b"};
|
|
|
|
s << "name,face-name,fontset-name,size,fill,"
|
|
|
|
<< "dx,dy,placement,vertical-alignment,halo-fill,"
|
|
|
|
<< "halo-radius,text-ratio,wrap-width,wrap-before,"
|
|
|
|
<< "wrap-character,text-transform,line-spacing,"
|
|
|
|
<< "label-position-tolerance,character-spacing,"
|
|
|
|
<< "spacing,minimum-distance,minimum-padding,"
|
|
|
|
<< "avoid-edges,allow-overlap,opacity,max-char-angle-delta,"
|
|
|
|
<< "horizontal-alignment,justify-alignment,"
|
|
|
|
// additional for shield
|
|
|
|
/* transform instead of orientation */
|
2011-04-18 03:11:38 +02:00
|
|
|
<< "file,base,transform,shield-dx,shield-dy,"
|
2011-02-05 04:15:17 +01:00
|
|
|
<< "text-opacity,unlock-image,no-text,"
|
|
|
|
<< "meta-writer,meta-output";
|
|
|
|
|
|
|
|
ensure_attrs(sym, "ShieldSymbolizer", s.str());
|
2010-04-09 20:47:19 +02:00
|
|
|
try
|
2007-09-25 20:47:12 +02:00
|
|
|
{
|
2011-06-24 02:53:00 +02:00
|
|
|
std::string name = get_attr<std::string>(sym, "name");
|
2010-06-02 13:03:30 +02:00
|
|
|
|
|
|
|
optional<std::string> face_name =
|
2011-02-05 04:15:17 +01:00
|
|
|
get_opt_attr<std::string>(sym, "face-name");
|
2010-06-02 13:03:30 +02:00
|
|
|
|
|
|
|
optional<std::string> fontset_name =
|
2011-02-05 04:15:17 +01:00
|
|
|
get_opt_attr<std::string>(sym, "fontset-name");
|
2010-06-02 13:03:30 +02:00
|
|
|
|
|
|
|
unsigned size = get_attr(sym, "size", 10U);
|
|
|
|
color fill = get_attr(sym, "fill", color(0,0,0));
|
|
|
|
|
2011-06-24 02:53:00 +02:00
|
|
|
std::string image_file = get_attr<std::string>(sym, "file");
|
|
|
|
optional<std::string> base = get_opt_attr<std::string>(sym, "base");
|
2010-06-10 16:11:48 +02:00
|
|
|
|
2011-06-24 02:53:00 +02:00
|
|
|
optional<std::string> transform_wkt = get_opt_attr<std::string>(sym, "transform");
|
2010-06-02 13:03:30 +02:00
|
|
|
try
|
|
|
|
{
|
|
|
|
if( base )
|
|
|
|
{
|
|
|
|
std::map<std::string,std::string>::const_iterator itr = file_sources_.find(*base);
|
|
|
|
if (itr!=file_sources_.end())
|
|
|
|
{
|
|
|
|
image_file = itr->second + "/" + image_file;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-01-25 21:47:56 +01:00
|
|
|
image_file = ensure_relative_to_xml(image_file);
|
2010-04-09 20:47:19 +02:00
|
|
|
|
2010-06-02 13:03:30 +02:00
|
|
|
shield_symbolizer shield_symbol(parse_expression(name, "utf8"),size,fill,parse_path(image_file));
|
2009-12-16 21:02:06 +01:00
|
|
|
|
2010-06-02 13:03:30 +02:00
|
|
|
if (fontset_name && face_name)
|
|
|
|
{
|
2011-02-05 04:15:17 +01:00
|
|
|
throw config_error(std::string("Can't have both face-name and fontset-name"));
|
2010-06-02 13:03:30 +02:00
|
|
|
}
|
|
|
|
else if (fontset_name)
|
|
|
|
{
|
|
|
|
std::map<std::string,font_set>::const_iterator itr = fontsets_.find(*fontset_name);
|
|
|
|
if (itr != fontsets_.end())
|
|
|
|
{
|
|
|
|
shield_symbol.set_fontset(itr->second);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
throw config_error("Unable to find any fontset named '" + *fontset_name + "'");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (face_name)
|
|
|
|
{
|
|
|
|
if ( strict_ )
|
|
|
|
{
|
|
|
|
ensure_font_face(*face_name);
|
|
|
|
}
|
|
|
|
shield_symbol.set_face_name(*face_name);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2011-02-05 04:15:17 +01:00
|
|
|
throw config_error(std::string("Must have face-name or fontset-name"));
|
2010-06-02 13:03:30 +02:00
|
|
|
}
|
2010-06-28 23:32:30 +02:00
|
|
|
// text displacement (relative to shield_displacement)
|
2010-06-02 13:03:30 +02:00
|
|
|
double dx = get_attr(sym, "dx", 0.0);
|
|
|
|
double dy = get_attr(sym, "dy", 0.0);
|
|
|
|
shield_symbol.set_displacement(dx,dy);
|
2010-06-28 23:32:30 +02:00
|
|
|
// shield displacement
|
2011-02-05 04:15:17 +01:00
|
|
|
double shield_dx = get_attr(sym, "shield-dx", 0.0);
|
|
|
|
double shield_dy = get_attr(sym, "shield-dy", 0.0);
|
2010-06-28 23:32:30 +02:00
|
|
|
shield_symbol.set_shield_displacement(shield_dx,shield_dy);
|
|
|
|
|
2010-06-02 13:03:30 +02:00
|
|
|
label_placement_e placement =
|
|
|
|
get_attr<label_placement_e>(sym, "placement", POINT_PLACEMENT);
|
|
|
|
shield_symbol.set_label_placement( placement );
|
|
|
|
|
|
|
|
// don't render shields around edges
|
|
|
|
optional<boolean> avoid_edges =
|
2011-02-05 04:15:17 +01:00
|
|
|
get_opt_attr<boolean>(sym, "avoid-edges");
|
2010-06-02 13:03:30 +02:00
|
|
|
if (avoid_edges)
|
|
|
|
{
|
|
|
|
shield_symbol.set_avoid_edges( *avoid_edges);
|
|
|
|
}
|
|
|
|
|
|
|
|
// halo fill and radius
|
2011-02-05 04:15:17 +01:00
|
|
|
optional<color> halo_fill = get_opt_attr<color>(sym, "halo-fill");
|
2010-06-02 13:03:30 +02:00
|
|
|
if (halo_fill)
|
|
|
|
{
|
|
|
|
shield_symbol.set_halo_fill( * halo_fill );
|
|
|
|
}
|
2010-06-16 17:15:13 +02:00
|
|
|
optional<double> halo_radius =
|
2011-02-05 04:15:17 +01:00
|
|
|
get_opt_attr<double>(sym, "halo-radius");
|
2010-06-02 13:03:30 +02:00
|
|
|
if (halo_radius)
|
|
|
|
{
|
|
|
|
shield_symbol.set_halo_radius(*halo_radius);
|
|
|
|
}
|
|
|
|
|
|
|
|
// minimum distance between labels
|
2011-02-05 04:15:17 +01:00
|
|
|
optional<unsigned> min_distance = get_opt_attr<unsigned>(sym, "minimum-distance");
|
2010-06-02 13:03:30 +02:00
|
|
|
if (min_distance)
|
|
|
|
{
|
|
|
|
shield_symbol.set_minimum_distance(*min_distance);
|
|
|
|
}
|
|
|
|
|
2010-11-03 14:18:56 +01:00
|
|
|
// minimum distance from edge of the map
|
2011-02-05 04:15:17 +01:00
|
|
|
optional<unsigned> min_padding = get_opt_attr<unsigned>(sym, "minimum-padding");
|
2010-11-03 14:19:04 +01:00
|
|
|
if (min_padding)
|
2010-11-03 14:18:56 +01:00
|
|
|
{
|
|
|
|
shield_symbol.set_minimum_padding(*min_padding);
|
|
|
|
}
|
|
|
|
|
2010-06-02 13:03:30 +02:00
|
|
|
// spacing between repeated labels on lines
|
|
|
|
optional<unsigned> spacing = get_opt_attr<unsigned>(sym, "spacing");
|
|
|
|
if (spacing)
|
|
|
|
{
|
|
|
|
shield_symbol.set_label_spacing(*spacing);
|
|
|
|
}
|
|
|
|
|
|
|
|
// allow_overlap
|
|
|
|
optional<boolean> allow_overlap =
|
2011-02-05 04:15:17 +01:00
|
|
|
get_opt_attr<boolean>(sym, "allow-overlap");
|
2010-06-02 13:03:30 +02:00
|
|
|
if (allow_overlap)
|
|
|
|
{
|
|
|
|
shield_symbol.set_allow_overlap( * allow_overlap );
|
|
|
|
}
|
|
|
|
|
|
|
|
// vertical alignment
|
2011-02-28 14:17:46 +01:00
|
|
|
vertical_alignment_e valign = get_attr<vertical_alignment_e>(sym, "vertical-alignment", V_MIDDLE);
|
2010-06-02 13:03:30 +02:00
|
|
|
shield_symbol.set_vertical_alignment(valign);
|
|
|
|
|
|
|
|
// horizontal alignment
|
2011-02-05 04:15:17 +01:00
|
|
|
horizontal_alignment_e halign = get_attr<horizontal_alignment_e>(sym, "horizontal-alignment", H_MIDDLE);
|
2010-06-02 13:03:30 +02:00
|
|
|
shield_symbol.set_horizontal_alignment(halign);
|
|
|
|
|
|
|
|
// justify alignment
|
2011-02-05 04:15:17 +01:00
|
|
|
justify_alignment_e jalign = get_attr<justify_alignment_e>(sym, "justify-alignment", J_MIDDLE);
|
2010-06-02 13:03:30 +02:00
|
|
|
shield_symbol.set_justify_alignment(jalign);
|
|
|
|
|
|
|
|
optional<unsigned> wrap_width =
|
2011-02-05 04:15:17 +01:00
|
|
|
get_opt_attr<unsigned>(sym, "wrap-width");
|
2010-06-02 13:03:30 +02:00
|
|
|
if (wrap_width)
|
|
|
|
{
|
|
|
|
shield_symbol.set_wrap_width(*wrap_width);
|
|
|
|
}
|
|
|
|
|
|
|
|
optional<boolean> wrap_before =
|
2011-02-05 04:15:17 +01:00
|
|
|
get_opt_attr<boolean>(sym, "wrap-before");
|
2010-06-02 13:03:30 +02:00
|
|
|
if (wrap_before)
|
|
|
|
{
|
|
|
|
shield_symbol.set_wrap_before(*wrap_before);
|
|
|
|
}
|
|
|
|
|
|
|
|
// character used to break long strings
|
|
|
|
optional<std::string> wrap_char =
|
2011-02-05 04:15:17 +01:00
|
|
|
get_opt_attr<std::string>(sym, "wrap-character");
|
2010-06-02 13:03:30 +02:00
|
|
|
if (wrap_char && (*wrap_char).size() > 0)
|
|
|
|
{
|
|
|
|
shield_symbol.set_wrap_char((*wrap_char)[0]);
|
|
|
|
}
|
|
|
|
|
|
|
|
// text conversion before rendering
|
2010-09-18 21:10:18 +02:00
|
|
|
text_transform_e tconvert =
|
2011-02-05 04:15:17 +01:00
|
|
|
get_attr<text_transform_e>(sym, "text-transform", NONE);
|
2010-09-18 21:10:18 +02:00
|
|
|
shield_symbol.set_text_transform(tconvert);
|
2010-06-02 13:03:30 +02:00
|
|
|
|
|
|
|
// spacing between text lines
|
2011-02-05 04:15:17 +01:00
|
|
|
optional<unsigned> line_spacing = get_opt_attr<unsigned>(sym, "line-spacing");
|
2010-06-02 13:03:30 +02:00
|
|
|
if (line_spacing)
|
|
|
|
{
|
|
|
|
shield_symbol.set_line_spacing(*line_spacing);
|
|
|
|
}
|
|
|
|
|
|
|
|
// spacing between characters in text
|
2011-02-05 04:15:17 +01:00
|
|
|
optional<unsigned> character_spacing = get_opt_attr<unsigned>(sym, "character-spacing");
|
2010-06-02 13:03:30 +02:00
|
|
|
if (character_spacing)
|
|
|
|
{
|
|
|
|
shield_symbol.set_character_spacing(*character_spacing);
|
|
|
|
}
|
|
|
|
|
|
|
|
// opacity
|
|
|
|
optional<double> opacity =
|
|
|
|
get_opt_attr<double>(sym, "opacity");
|
|
|
|
if (opacity)
|
|
|
|
{
|
|
|
|
shield_symbol.set_opacity( * opacity );
|
|
|
|
}
|
2010-06-15 14:27:58 +02:00
|
|
|
|
|
|
|
// text-opacity
|
|
|
|
optional<double> text_opacity =
|
|
|
|
get_opt_attr<double>(sym, "text-opacity");
|
2010-06-15 15:36:33 +02:00
|
|
|
if (text_opacity)
|
2010-06-15 14:27:58 +02:00
|
|
|
{
|
|
|
|
shield_symbol.set_text_opacity( * text_opacity );
|
|
|
|
}
|
2010-06-02 13:03:30 +02:00
|
|
|
|
2010-06-10 16:11:48 +02:00
|
|
|
if (transform_wkt)
|
|
|
|
{
|
|
|
|
agg::trans_affine tr;
|
2010-12-11 02:10:45 +01:00
|
|
|
if (!mapnik::svg::parse_transform(*transform_wkt,tr))
|
|
|
|
{
|
|
|
|
std::stringstream ss;
|
|
|
|
ss << "Could not parse transform from '" << transform_wkt << "', expected string like: 'matrix(1, 0, 0, 1, 0, 0)'";
|
|
|
|
if (strict_)
|
|
|
|
throw config_error(ss.str()); // value_error here?
|
|
|
|
else
|
2011-06-24 02:53:00 +02:00
|
|
|
std::clog << "### WARNING: " << ss << endl;
|
2010-12-11 02:10:45 +01:00
|
|
|
}
|
2010-06-10 16:11:48 +02:00
|
|
|
boost::array<double,6> matrix;
|
|
|
|
tr.store_to(&matrix[0]);
|
|
|
|
shield_symbol.set_transform(matrix);
|
|
|
|
}
|
|
|
|
|
2010-06-02 13:03:30 +02:00
|
|
|
// unlock_image
|
|
|
|
optional<boolean> unlock_image =
|
2011-02-05 04:15:17 +01:00
|
|
|
get_opt_attr<boolean>(sym, "unlock-image");
|
2010-06-02 13:03:30 +02:00
|
|
|
if (unlock_image)
|
|
|
|
{
|
|
|
|
shield_symbol.set_unlock_image( * unlock_image );
|
|
|
|
}
|
|
|
|
|
|
|
|
// no text
|
|
|
|
optional<boolean> no_text =
|
2011-02-05 04:15:17 +01:00
|
|
|
get_opt_attr<boolean>(sym, "no-text");
|
2010-06-02 13:03:30 +02:00
|
|
|
if (no_text)
|
|
|
|
{
|
|
|
|
shield_symbol.set_no_text( * no_text );
|
|
|
|
}
|
|
|
|
|
2010-08-10 14:03:45 +02:00
|
|
|
parse_metawriter_in_symbolizer(shield_symbol, sym);
|
2010-06-02 13:03:30 +02:00
|
|
|
rule.append(shield_symbol);
|
|
|
|
}
|
|
|
|
catch (image_reader_exception const & ex )
|
|
|
|
{
|
2011-06-24 02:53:00 +02:00
|
|
|
std::string msg("Failed to load image file '" + image_file +
|
2010-06-02 13:03:30 +02:00
|
|
|
"': " + ex.what());
|
|
|
|
if (strict_)
|
|
|
|
{
|
|
|
|
throw config_error(msg);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2011-06-24 02:53:00 +02:00
|
|
|
std::clog << "### WARNING: " << msg << endl;
|
2010-06-02 13:03:30 +02:00
|
|
|
}
|
|
|
|
}
|
2010-04-09 20:47:19 +02:00
|
|
|
|
2007-09-25 20:47:12 +02:00
|
|
|
}
|
2010-04-09 20:47:19 +02:00
|
|
|
catch (const config_error & ex)
|
|
|
|
{
|
2010-06-02 13:03:30 +02:00
|
|
|
ex.append_context("in ShieldSymbolizer");
|
|
|
|
throw;
|
2010-04-09 20:47:19 +02:00
|
|
|
}
|
|
|
|
}
|
2007-09-25 20:47:12 +02:00
|
|
|
|
2010-08-19 14:20:30 +02:00
|
|
|
void map_parser::parse_stroke(stroke & strk, ptree const & sym)
|
2010-04-09 20:47:19 +02:00
|
|
|
{
|
2010-08-19 14:20:30 +02:00
|
|
|
// stroke color
|
|
|
|
optional<color> c = get_opt_attr<color>(sym, "stroke");
|
|
|
|
if (c) strk.set_color(*c);
|
2011-05-17 02:33:24 +02:00
|
|
|
|
2010-08-19 14:20:30 +02:00
|
|
|
// stroke-width
|
|
|
|
optional<double> width = get_opt_attr<double>(sym, "stroke-width");
|
|
|
|
if (width) strk.set_width(*width);
|
2011-05-17 02:33:24 +02:00
|
|
|
|
2010-08-19 14:20:30 +02:00
|
|
|
// stroke-opacity
|
|
|
|
optional<double> opacity = get_opt_attr<double>(sym, "stroke-opacity");
|
|
|
|
if (opacity) strk.set_opacity(*opacity);
|
2011-05-17 02:33:24 +02:00
|
|
|
|
2010-08-19 14:20:30 +02:00
|
|
|
// stroke-linejoin
|
|
|
|
optional<line_join_e> line_join = get_opt_attr<line_join_e>(sym, "stroke-linejoin");
|
|
|
|
if (line_join) strk.set_line_join(*line_join);
|
2011-05-17 02:33:24 +02:00
|
|
|
|
2010-08-19 14:20:30 +02:00
|
|
|
// stroke-linecap
|
|
|
|
optional<line_cap_e> line_cap = get_opt_attr<line_cap_e>(sym, "stroke-linecap");
|
|
|
|
if (line_cap) strk.set_line_cap(*line_cap);
|
2011-05-17 02:33:24 +02:00
|
|
|
|
2011-02-02 02:46:14 +01:00
|
|
|
// stroke-gamma
|
|
|
|
optional<double> gamma = get_opt_attr<double>(sym, "stroke-gamma");
|
|
|
|
if (gamma) strk.set_gamma(*gamma);
|
2011-05-17 02:33:24 +02:00
|
|
|
|
|
|
|
// stroke-dash-offset
|
|
|
|
optional<double> dash_offset = get_opt_attr<double>(sym, "stroke-dash-offset");
|
|
|
|
if (dash_offset) strk.set_dash_offset(*dash_offset);
|
|
|
|
|
2010-08-19 14:20:30 +02:00
|
|
|
// stroke-dasharray
|
2011-06-24 02:53:00 +02:00
|
|
|
optional<std::string> str = get_opt_attr<std::string>(sym,"stroke-dasharray");
|
2010-08-19 14:20:30 +02:00
|
|
|
if (str)
|
2007-09-25 20:47:12 +02:00
|
|
|
{
|
2010-08-19 14:20:30 +02:00
|
|
|
tokenizer<> tok (*str);
|
|
|
|
std::vector<double> dash_array;
|
|
|
|
tokenizer<>::iterator itr = tok.begin();
|
|
|
|
for (; itr != tok.end(); ++itr)
|
2010-06-02 13:03:30 +02:00
|
|
|
{
|
2010-08-19 14:20:30 +02:00
|
|
|
try
|
2010-06-02 13:03:30 +02:00
|
|
|
{
|
2010-08-19 14:20:30 +02:00
|
|
|
double f = boost::lexical_cast<double>(*itr);
|
|
|
|
dash_array.push_back(f);
|
2010-06-02 13:03:30 +02:00
|
|
|
}
|
2010-08-19 14:20:30 +02:00
|
|
|
catch ( boost::bad_lexical_cast &)
|
2010-06-02 13:03:30 +02:00
|
|
|
{
|
2010-08-19 14:20:30 +02:00
|
|
|
throw config_error(std::string("Failed to parse dasharray ") +
|
|
|
|
"'. Expected a " +
|
|
|
|
"list of floats but got '" + (*str) + "'");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (dash_array.size())
|
|
|
|
{
|
|
|
|
size_t size = dash_array.size();
|
|
|
|
if ( size % 2)
|
|
|
|
{
|
|
|
|
for (size_t i=0; i < size ;++i)
|
2010-06-02 13:03:30 +02:00
|
|
|
{
|
2010-08-19 14:20:30 +02:00
|
|
|
dash_array.push_back(dash_array[i]);
|
2010-06-02 13:03:30 +02:00
|
|
|
}
|
|
|
|
}
|
2010-08-19 14:20:30 +02:00
|
|
|
std::vector<double>::const_iterator pos = dash_array.begin();
|
|
|
|
while (pos != dash_array.end())
|
|
|
|
{
|
|
|
|
strk.add_dash(*pos,*(pos + 1));
|
|
|
|
pos +=2;
|
|
|
|
}
|
2010-06-02 13:03:30 +02:00
|
|
|
}
|
2010-08-19 14:20:30 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-01-13 22:35:01 +01:00
|
|
|
void map_parser::parse_line_symbolizer( rule & rule, ptree const & sym )
|
2010-08-19 14:20:30 +02:00
|
|
|
{
|
2011-02-05 04:15:17 +01:00
|
|
|
std::stringstream s;
|
2011-04-18 03:11:38 +02:00
|
|
|
s << "stroke,stroke-width,stroke-opacity,stroke-linejoin,"
|
2011-05-17 02:33:24 +02:00
|
|
|
<< "stroke-linecap,stroke-gamma,stroke-dash-offset,stroke-dasharray,"
|
2011-09-10 01:45:49 +02:00
|
|
|
<< "rasterizer,"
|
2011-04-18 03:11:38 +02:00
|
|
|
<< "meta-writer,meta-output";
|
|
|
|
|
2011-02-05 04:15:17 +01:00
|
|
|
ensure_attrs(sym, "LineSymbolizer", s.str());
|
2010-08-19 14:20:30 +02:00
|
|
|
try
|
|
|
|
{
|
|
|
|
stroke strk;
|
|
|
|
parse_stroke(strk,sym);
|
2010-08-10 14:03:45 +02:00
|
|
|
line_symbolizer symbol = line_symbolizer(strk);
|
|
|
|
|
2011-09-10 01:45:49 +02:00
|
|
|
// rasterizer method
|
|
|
|
line_rasterizer_e rasterizer = get_attr<line_rasterizer_e>(sym, "rasterizer", RASTERIZER_FULL);
|
|
|
|
//optional<line_rasterizer_e> rasterizer_method = get_opt_attr<line_rasterizer_e>(sym, "full");
|
|
|
|
symbol.set_rasterizer(rasterizer);
|
|
|
|
|
2010-08-10 14:03:45 +02:00
|
|
|
parse_metawriter_in_symbolizer(symbol, sym);
|
|
|
|
rule.append(symbol);
|
2007-09-25 20:47:12 +02:00
|
|
|
}
|
2010-04-09 20:47:19 +02:00
|
|
|
catch (const config_error & ex)
|
|
|
|
{
|
2010-06-02 13:03:30 +02:00
|
|
|
ex.append_context("in LineSymbolizer");
|
|
|
|
throw;
|
2010-04-09 20:47:19 +02:00
|
|
|
}
|
|
|
|
}
|
2007-09-25 20:47:12 +02:00
|
|
|
|
2010-04-09 20:46:25 +02:00
|
|
|
|
2011-01-13 22:35:01 +01:00
|
|
|
void map_parser::parse_polygon_symbolizer( rule & rule, ptree const & sym )
|
2010-04-09 20:47:19 +02:00
|
|
|
{
|
2011-02-05 04:15:17 +01:00
|
|
|
ensure_attrs(sym, "PolygonSymbolizer", "fill,fill-opacity,gamma,meta-writer,meta-output");
|
2010-04-09 20:47:19 +02:00
|
|
|
try
|
2007-09-25 20:47:12 +02:00
|
|
|
{
|
2010-06-02 13:03:30 +02:00
|
|
|
polygon_symbolizer poly_sym;
|
|
|
|
// fill
|
|
|
|
optional<color> fill = get_opt_attr<color>(sym, "fill");
|
|
|
|
if (fill) poly_sym.set_fill(*fill);
|
|
|
|
// fill-opacity
|
|
|
|
optional<double> opacity = get_opt_attr<double>(sym, "fill-opacity");
|
|
|
|
if (opacity) poly_sym.set_opacity(*opacity);
|
|
|
|
// gamma
|
|
|
|
optional<double> gamma = get_opt_attr<double>(sym, "gamma");
|
|
|
|
if (gamma) poly_sym.set_gamma(*gamma);
|
2010-08-10 14:03:45 +02:00
|
|
|
|
|
|
|
parse_metawriter_in_symbolizer(poly_sym, sym);
|
2010-06-02 13:03:30 +02:00
|
|
|
rule.append(poly_sym);
|
2007-09-25 20:47:12 +02:00
|
|
|
}
|
2010-04-09 20:47:19 +02:00
|
|
|
catch (const config_error & ex)
|
|
|
|
{
|
2010-06-02 13:03:30 +02:00
|
|
|
ex.append_context("in PolygonSymbolizer");
|
|
|
|
throw;
|
2010-04-09 20:47:19 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-01-13 22:35:01 +01:00
|
|
|
void map_parser::parse_building_symbolizer( rule & rule, ptree const & sym )
|
2010-04-09 20:47:19 +02:00
|
|
|
{
|
2011-02-05 04:15:17 +01:00
|
|
|
ensure_attrs(sym, "PolygonSymbolizer", "fill,fill-opacity,height,meta-writer,meta-output");
|
|
|
|
try
|
|
|
|
{
|
2010-06-02 13:03:30 +02:00
|
|
|
building_symbolizer building_sym;
|
|
|
|
|
|
|
|
// fill
|
|
|
|
optional<color> fill = get_opt_attr<color>(sym, "fill");
|
|
|
|
if (fill) building_sym.set_fill(*fill);
|
|
|
|
// fill-opacity
|
|
|
|
optional<double> opacity = get_opt_attr<double>(sym, "fill-opacity");
|
|
|
|
if (opacity) building_sym.set_opacity(*opacity);
|
|
|
|
// height
|
2011-02-05 04:15:17 +01:00
|
|
|
// TODO - expression
|
2010-06-02 13:03:30 +02:00
|
|
|
optional<double> height = get_opt_attr<double>(sym, "height");
|
2011-01-28 21:46:49 +01:00
|
|
|
if (height) building_sym.set_height(*height);
|
2010-06-02 13:03:30 +02:00
|
|
|
|
2010-08-10 14:03:45 +02:00
|
|
|
parse_metawriter_in_symbolizer(building_sym, sym);
|
2010-06-02 13:03:30 +02:00
|
|
|
rule.append(building_sym);
|
2010-04-09 20:47:19 +02:00
|
|
|
}
|
|
|
|
catch (const config_error & ex)
|
2007-09-25 20:47:12 +02:00
|
|
|
{
|
2010-06-02 13:03:30 +02:00
|
|
|
ex.append_context("in BuildingSymbolizer");
|
|
|
|
throw;
|
Patch from David Eastcott :
1. Modified Text Symbolizer
a) corrected line fragment centering (for 2nd and subsequent lines, when line breaks occur).
b) adjusted vertical alignment calculation so that:
i) middle -> has the center of the text line(s) at the point origin
ii) bottom -> has the text line(s) below the point origin
iii) top -> has the text line(s) above the point origin
c) added new text_symbolizer attribute: 'wrap_before', value range: true/false, default == false
allows line breaks at first wrap_char before wrap_width as an alternative to the original
which was to create the line break at the first wrap_char after wrap_width
d) added new text_symbolizer attribute: 'horizontal_alignment', value range: left/middle/right, default == middle
i) left -> has all text line(s) to left of the point origin
ii) middle -> has all text line(s) centered on the the point origin
iii) right -> has all text line(s) to the right of the point origin
NOTE: dx, dy position adjustments are applied after alignments and before Justify.
e) added new text_symbolizer attribute: 'justify_alignment', value range: left/middle/right, default == middle
i) left -> after alignments, has all text line(s) are left justified (left to right reading)
ii) middle -> after alignments, has all text line(s) center justified
iii) right -> after alignments, has all text line(s) right justified (right to left reading)
f) added new text_symbolizer attribute: 'opacity', value range: 0.0 thru 1.0; 1.0 == fully opaque
g) modified positioning to compensate for both line_spacing and character_spacing, to ensure proper
centering of the text envelope. Also ensure that centering occurs correctly even if no wrapping
occurs. Line spacing is uniform and consistent and compensates for errors between text_size and
the actual size (ci.height is inconsistent, depending on case and character); fixes issue with
multi-line text where some lines have a slight gap and others are compressed together.
2. Modified shield_symbolizer
a) added the attributes:
i) allow_overlap
ii) vertical_alignment
iii) horizontal_alignment
iv) justify_alignment
v) wrap_width
vi) wrap_character
vii) wrap_before
viii) text_convert
ix) line_spacing
x) character_spacing
xi) opacity
b) added new shield_symbolizer attribute: 'unlock_image', value range: true/false, default == false
i) false == image and text placement behaviour same as before
ii) true == image placement independant of text, image is always centered at geometry point, text placed per attributes,
dx/dy only affect text.
Allows user to create point markers with text, but both the text and image rendering collision detection are done
as a pair (they come and go together - solves problem if using point_symbolizer and text_symbolizers where one or the
other are omitted due to overlaps, but not both)
c) extended choices for the attribute 'placement' to include vertex; effect is limited to the shield_symbolizer
Allows an attempted placement at every vertex available, gives additional shield placement volume when using line geometry
d) ensured that the text placement was not updating the detector unless a shield image was actually placed.
e) added new shield_symbolizer attribute: 'no_text', value range: true/false, default = false
When set true, the text for the feature is ignored ('space' subsituted) so that pure graphic symbols can be used
and no text is rendered over top of them.
2009-10-19 15:52:53 +02:00
|
|
|
}
|
2010-04-09 20:47:19 +02:00
|
|
|
}
|
|
|
|
|
2011-01-13 22:35:01 +01:00
|
|
|
void map_parser::parse_raster_symbolizer( rule & rule, ptree const & sym )
|
2010-04-09 20:47:19 +02:00
|
|
|
{
|
2011-02-05 04:15:17 +01:00
|
|
|
// no support for meta-writer,meta-output
|
2011-05-04 03:57:37 +02:00
|
|
|
ensure_attrs(sym, "RasterSymbolizer", "mode,scaling,opacity,filter-factor");
|
2010-04-09 20:47:19 +02:00
|
|
|
try
|
|
|
|
{
|
2010-06-02 13:03:30 +02:00
|
|
|
raster_symbolizer raster_sym;
|
|
|
|
|
|
|
|
// mode
|
|
|
|
optional<std::string> mode = get_opt_attr<std::string>(sym, "mode");
|
|
|
|
if (mode) raster_sym.set_mode(*mode);
|
|
|
|
|
|
|
|
// scaling
|
|
|
|
optional<std::string> scaling = get_opt_attr<std::string>(sym, "scaling");
|
|
|
|
if (scaling) raster_sym.set_scaling(*scaling);
|
|
|
|
|
|
|
|
// opacity
|
|
|
|
optional<double> opacity = get_opt_attr<double>(sym, "opacity");
|
|
|
|
if (opacity) raster_sym.set_opacity(*opacity);
|
|
|
|
|
2011-01-27 04:47:54 +01:00
|
|
|
// filter factor
|
2011-02-05 04:15:17 +01:00
|
|
|
optional<double> filter_factor = get_opt_attr<double>(sym, "filter-factor");
|
2011-01-27 04:47:54 +01:00
|
|
|
if (filter_factor) raster_sym.set_filter_factor(*filter_factor);
|
|
|
|
|
2010-06-02 13:03:30 +02:00
|
|
|
ptree::const_iterator cssIter = sym.begin();
|
|
|
|
ptree::const_iterator endCss = sym.end();
|
|
|
|
|
|
|
|
for(; cssIter != endCss; ++cssIter)
|
|
|
|
{
|
|
|
|
ptree::value_type const& css_tag = *cssIter;
|
|
|
|
|
|
|
|
if (css_tag.first == "RasterColorizer")
|
|
|
|
{
|
|
|
|
raster_colorizer_ptr colorizer(new raster_colorizer());
|
|
|
|
raster_sym.set_colorizer(colorizer);
|
|
|
|
parse_raster_colorizer(colorizer, css_tag.second);
|
|
|
|
}
|
|
|
|
else if (css_tag.first != "<xmlcomment>" &&
|
|
|
|
css_tag.first != "<xmlattr>" )
|
|
|
|
{
|
|
|
|
throw config_error(std::string("Unknown child node. ") +
|
|
|
|
"Expected 'RasterColorizer' but got '" + css_tag.first + "'");
|
|
|
|
}
|
|
|
|
}
|
2010-08-12 02:11:01 +02:00
|
|
|
//Note: raster_symbolizer doesn't support metawriters
|
2010-06-02 13:03:30 +02:00
|
|
|
rule.append(raster_sym);
|
2010-04-09 20:47:19 +02:00
|
|
|
}
|
|
|
|
catch (const config_error & ex)
|
2009-03-29 13:05:20 +02:00
|
|
|
{
|
2010-06-02 13:03:30 +02:00
|
|
|
ex.append_context("in RasterSymbolizer");
|
|
|
|
throw;
|
2010-03-12 15:49:34 +01:00
|
|
|
}
|
2010-04-09 20:47:19 +02:00
|
|
|
}
|
2010-03-19 12:19:43 +01:00
|
|
|
|
2011-02-05 04:15:17 +01:00
|
|
|
void map_parser::parse_glyph_symbolizer(rule & rule, ptree const & sym)
|
2010-04-09 20:47:19 +02:00
|
|
|
{
|
2011-02-05 04:15:17 +01:00
|
|
|
ensure_attrs(sym, "GlyphSymbolizer", "face-name,char,angle,angle-mode,value,size,color,halo-fill,halo-radius,allow-overlap,avoid-edges,dx,dy,meta-writer,meta-output");
|
2010-04-09 20:47:19 +02:00
|
|
|
try
|
2010-03-19 12:19:43 +01:00
|
|
|
{
|
2010-06-02 13:03:30 +02:00
|
|
|
// Parse required constructor args
|
2011-02-05 04:15:17 +01:00
|
|
|
std::string face_name = get_attr<std::string>(sym, "face-name");
|
2010-06-02 13:03:30 +02:00
|
|
|
std::string _char = get_attr<std::string>(sym, "char");
|
|
|
|
|
|
|
|
glyph_symbolizer glyph_sym = glyph_symbolizer(
|
|
|
|
face_name,
|
|
|
|
parse_expression(_char, "utf8")
|
|
|
|
);
|
|
|
|
|
|
|
|
//
|
|
|
|
// parse and set optional attrs.
|
|
|
|
//
|
|
|
|
|
|
|
|
// angle
|
|
|
|
optional<std::string> angle =
|
|
|
|
get_opt_attr<std::string>(sym, "angle");
|
|
|
|
if (angle)
|
|
|
|
glyph_sym.set_angle(parse_expression(*angle, "utf8"));
|
|
|
|
|
|
|
|
angle_mode_e angle_mode =
|
2011-02-05 04:15:17 +01:00
|
|
|
get_attr<angle_mode_e>(sym, "angle-mode", TRIGONOMETRIC);
|
2010-06-02 13:03:30 +02:00
|
|
|
glyph_sym.set_angle_mode(angle_mode);
|
|
|
|
|
|
|
|
// value
|
|
|
|
optional<std::string> value =
|
|
|
|
get_opt_attr<std::string>(sym, "value");
|
|
|
|
if (value)
|
|
|
|
glyph_sym.set_value(parse_expression(*value, "utf8"));
|
|
|
|
|
|
|
|
// size
|
2010-08-10 16:46:39 +02:00
|
|
|
std::string size =
|
|
|
|
get_attr<std::string>(sym, "size");
|
2010-08-10 17:31:14 +02:00
|
|
|
glyph_sym.set_size(parse_expression(size, "utf8"));
|
2010-06-02 13:03:30 +02:00
|
|
|
|
|
|
|
// color
|
|
|
|
optional<std::string> _color =
|
|
|
|
get_opt_attr<std::string>(sym, "color");
|
|
|
|
if (_color)
|
|
|
|
glyph_sym.set_color(parse_expression(*_color, "utf8"));
|
|
|
|
|
|
|
|
// halo_fill
|
2011-02-05 04:15:17 +01:00
|
|
|
optional<color> halo_fill = get_opt_attr<color>(sym, "halo-fill");
|
2010-06-02 13:03:30 +02:00
|
|
|
if (halo_fill)
|
|
|
|
glyph_sym.set_halo_fill(*halo_fill);
|
|
|
|
|
|
|
|
// halo_radius
|
2010-06-16 17:15:13 +02:00
|
|
|
optional<double> halo_radius = get_opt_attr<double>(
|
2010-06-02 13:03:30 +02:00
|
|
|
sym,
|
2011-02-05 04:15:17 +01:00
|
|
|
"halo-radius");
|
2010-06-02 13:03:30 +02:00
|
|
|
if (halo_radius)
|
|
|
|
glyph_sym.set_halo_radius(*halo_radius);
|
2010-06-16 17:15:13 +02:00
|
|
|
|
2010-06-02 13:03:30 +02:00
|
|
|
// allow_overlap
|
|
|
|
optional<boolean> allow_overlap = get_opt_attr<boolean>(
|
|
|
|
sym,
|
2011-02-05 04:15:17 +01:00
|
|
|
"allow-overlap"
|
2010-06-02 13:03:30 +02:00
|
|
|
);
|
|
|
|
if (allow_overlap)
|
|
|
|
glyph_sym.set_allow_overlap(*allow_overlap);
|
|
|
|
|
|
|
|
// avoid_edges
|
|
|
|
optional<boolean> avoid_edges = get_opt_attr<boolean>(
|
|
|
|
sym,
|
2011-02-05 04:15:17 +01:00
|
|
|
"avoid-edges"
|
2010-06-02 13:03:30 +02:00
|
|
|
);
|
|
|
|
if (avoid_edges)
|
|
|
|
glyph_sym.set_avoid_edges(*avoid_edges);
|
|
|
|
|
|
|
|
// displacement
|
|
|
|
optional<double> dx = get_opt_attr<double>(sym, "dx");
|
|
|
|
optional<double> dy = get_opt_attr<double>(sym, "dy");
|
|
|
|
if (dx && dy)
|
|
|
|
glyph_sym.set_displacement(*dx, *dy);
|
|
|
|
|
|
|
|
// colorizer
|
|
|
|
ptree::const_iterator childIter = sym.begin();
|
|
|
|
ptree::const_iterator endChild = sym.end();
|
|
|
|
|
|
|
|
for (; childIter != endChild; ++childIter)
|
|
|
|
{
|
|
|
|
ptree::value_type const& tag = *childIter;
|
|
|
|
|
|
|
|
if (tag.first == "RasterColorizer")
|
|
|
|
{
|
|
|
|
raster_colorizer_ptr colorizer(new raster_colorizer());
|
|
|
|
glyph_sym.set_colorizer(colorizer);
|
|
|
|
parse_raster_colorizer(colorizer, tag.second);
|
|
|
|
}
|
|
|
|
else if (tag.first!="<xmlcomment>" && tag.first!="<xmlattr>" )
|
|
|
|
{
|
|
|
|
throw config_error(std::string("Unknown child node. ") +
|
|
|
|
"Expected 'RasterColorizer' but got '" +
|
|
|
|
tag.first + "'");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-08-10 14:03:45 +02:00
|
|
|
parse_metawriter_in_symbolizer(glyph_sym, sym);
|
2010-06-02 13:03:30 +02:00
|
|
|
rule.append(glyph_sym);
|
2010-04-09 20:47:19 +02:00
|
|
|
}
|
|
|
|
catch (const config_error & ex)
|
2010-03-12 15:49:34 +01:00
|
|
|
{
|
2010-06-02 13:03:30 +02:00
|
|
|
ex.append_context("in GlyphSymbolizer");
|
|
|
|
throw;
|
2009-03-29 13:05:20 +02:00
|
|
|
}
|
2010-04-09 20:47:19 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void map_parser::parse_raster_colorizer(raster_colorizer_ptr const& rc,
|
2010-06-02 13:03:30 +02:00
|
|
|
ptree const& node )
|
2010-04-09 20:47:19 +02:00
|
|
|
{
|
|
|
|
try
|
|
|
|
{
|
2011-05-04 03:57:37 +02:00
|
|
|
ensure_attrs(node, "RasterColorizer", "default-mode,default-color,epsilon");
|
2011-05-04 02:20:17 +02:00
|
|
|
// mode
|
|
|
|
colorizer_mode default_mode =
|
|
|
|
get_attr<colorizer_mode>(node, "default-mode", COLORIZER_LINEAR);
|
|
|
|
|
|
|
|
if(default_mode == COLORIZER_INHERIT) {
|
|
|
|
throw config_error("RasterColorizer mode must not be INHERIT. ");
|
|
|
|
}
|
|
|
|
rc->set_default_mode( default_mode );
|
2010-06-02 13:03:30 +02:00
|
|
|
|
2011-05-04 02:20:17 +02:00
|
|
|
// default colour
|
|
|
|
optional<color> default_color = get_opt_attr<color>(node, "default-color");
|
|
|
|
if (default_color)
|
2010-06-02 13:03:30 +02:00
|
|
|
{
|
2011-05-04 02:20:17 +02:00
|
|
|
rc->set_default_color( *default_color );
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// epsilon
|
|
|
|
optional<float> eps = get_opt_attr<float>(node, "epsilon");
|
|
|
|
if (eps)
|
|
|
|
{
|
|
|
|
if(*eps < 0) {
|
|
|
|
throw config_error("RasterColorizer epsilon must be > 0. ");
|
|
|
|
}
|
|
|
|
rc->set_epsilon( *eps );
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
ptree::const_iterator stopIter = node.begin();
|
|
|
|
ptree::const_iterator endStop = node.end();
|
|
|
|
float maximumValue = -std::numeric_limits<float>::max();
|
2010-06-02 13:03:30 +02:00
|
|
|
|
2011-05-04 02:20:17 +02:00
|
|
|
for(; stopIter != endStop; ++stopIter)
|
|
|
|
{
|
|
|
|
ptree::value_type const& stop_tag = *stopIter;
|
|
|
|
ptree const & stop = stopIter->second;
|
|
|
|
|
|
|
|
if (stop_tag.first == "stop")
|
2010-06-02 13:03:30 +02:00
|
|
|
{
|
2011-05-04 03:57:37 +02:00
|
|
|
ensure_attrs(stop_tag.second, "stop", "color,mode,value");
|
2011-05-04 02:20:17 +02:00
|
|
|
// colour is optional.
|
|
|
|
optional<color> stopcolor = get_opt_attr<color>(stop, "color");
|
|
|
|
if (!stopcolor) {
|
|
|
|
*stopcolor = *default_color;
|
|
|
|
}
|
|
|
|
|
|
|
|
// mode default to INHERIT
|
|
|
|
colorizer_mode mode =
|
|
|
|
get_attr<colorizer_mode>(stop, "mode", COLORIZER_INHERIT);
|
|
|
|
|
|
|
|
// value is required, and it must be bigger than the previous
|
|
|
|
optional<float> value =
|
|
|
|
get_opt_attr<float>(stop, "value");
|
|
|
|
|
|
|
|
if(!value) {
|
|
|
|
throw config_error("stop tag missing value");
|
2010-06-02 13:03:30 +02:00
|
|
|
}
|
2011-05-04 02:20:17 +02:00
|
|
|
|
|
|
|
if(value < maximumValue) {
|
|
|
|
throw config_error("stop tag values must be in ascending order");
|
2010-06-02 13:03:30 +02:00
|
|
|
}
|
2011-05-04 02:20:17 +02:00
|
|
|
maximumValue = *value;
|
|
|
|
|
|
|
|
|
|
|
|
//append the stop
|
|
|
|
colorizer_stop tmpStop;
|
|
|
|
tmpStop.set_color(*stopcolor);
|
|
|
|
tmpStop.set_mode(mode);
|
|
|
|
tmpStop.set_value(*value);
|
|
|
|
|
|
|
|
rc->add_stop(tmpStop);
|
2010-06-02 13:03:30 +02:00
|
|
|
}
|
2011-05-04 02:20:17 +02:00
|
|
|
else if (stop_tag.first != "<xmlcomment>" &&
|
|
|
|
stop_tag.first != "<xmlattr>" )
|
2010-06-02 13:03:30 +02:00
|
|
|
{
|
|
|
|
throw config_error(std::string("Unknown child node. ") +
|
2011-05-04 02:20:17 +02:00
|
|
|
"Expected 'stop' but got '" + stop_tag.first + "'");
|
2010-06-02 13:03:30 +02:00
|
|
|
}
|
2010-05-06 09:21:11 +02:00
|
|
|
}
|
2010-04-09 20:47:19 +02:00
|
|
|
}
|
|
|
|
catch (const config_error & ex)
|
2007-09-25 20:47:12 +02:00
|
|
|
{
|
2010-06-02 13:03:30 +02:00
|
|
|
ex.append_context("in RasterColorizer");
|
|
|
|
throw;
|
2007-09-25 20:47:12 +02:00
|
|
|
}
|
2010-04-09 20:47:19 +02:00
|
|
|
}
|
Patch from David Eastcott :
1. Modified Text Symbolizer
a) corrected line fragment centering (for 2nd and subsequent lines, when line breaks occur).
b) adjusted vertical alignment calculation so that:
i) middle -> has the center of the text line(s) at the point origin
ii) bottom -> has the text line(s) below the point origin
iii) top -> has the text line(s) above the point origin
c) added new text_symbolizer attribute: 'wrap_before', value range: true/false, default == false
allows line breaks at first wrap_char before wrap_width as an alternative to the original
which was to create the line break at the first wrap_char after wrap_width
d) added new text_symbolizer attribute: 'horizontal_alignment', value range: left/middle/right, default == middle
i) left -> has all text line(s) to left of the point origin
ii) middle -> has all text line(s) centered on the the point origin
iii) right -> has all text line(s) to the right of the point origin
NOTE: dx, dy position adjustments are applied after alignments and before Justify.
e) added new text_symbolizer attribute: 'justify_alignment', value range: left/middle/right, default == middle
i) left -> after alignments, has all text line(s) are left justified (left to right reading)
ii) middle -> after alignments, has all text line(s) center justified
iii) right -> after alignments, has all text line(s) right justified (right to left reading)
f) added new text_symbolizer attribute: 'opacity', value range: 0.0 thru 1.0; 1.0 == fully opaque
g) modified positioning to compensate for both line_spacing and character_spacing, to ensure proper
centering of the text envelope. Also ensure that centering occurs correctly even if no wrapping
occurs. Line spacing is uniform and consistent and compensates for errors between text_size and
the actual size (ci.height is inconsistent, depending on case and character); fixes issue with
multi-line text where some lines have a slight gap and others are compressed together.
2. Modified shield_symbolizer
a) added the attributes:
i) allow_overlap
ii) vertical_alignment
iii) horizontal_alignment
iv) justify_alignment
v) wrap_width
vi) wrap_character
vii) wrap_before
viii) text_convert
ix) line_spacing
x) character_spacing
xi) opacity
b) added new shield_symbolizer attribute: 'unlock_image', value range: true/false, default == false
i) false == image and text placement behaviour same as before
ii) true == image placement independant of text, image is always centered at geometry point, text placed per attributes,
dx/dy only affect text.
Allows user to create point markers with text, but both the text and image rendering collision detection are done
as a pair (they come and go together - solves problem if using point_symbolizer and text_symbolizers where one or the
other are omitted due to overlaps, but not both)
c) extended choices for the attribute 'placement' to include vertex; effect is limited to the shield_symbolizer
Allows an attempted placement at every vertex available, gives additional shield placement volume when using line geometry
d) ensured that the text placement was not updating the detector unless a shield image was actually placed.
e) added new shield_symbolizer attribute: 'no_text', value range: true/false, default = false
When set true, the text for the feature is ignored ('space' subsituted) so that pure graphic symbols can be used
and no text is rendered over top of them.
2009-10-19 15:52:53 +02:00
|
|
|
|
2010-04-09 20:47:19 +02:00
|
|
|
void map_parser::ensure_font_face( const std::string & face_name )
|
|
|
|
{
|
|
|
|
if ( ! font_manager_.get_face( face_name ) )
|
2009-05-01 03:59:01 +02:00
|
|
|
{
|
2010-06-02 13:03:30 +02:00
|
|
|
throw config_error("Failed to find font face '" +
|
|
|
|
face_name + "'");
|
2010-04-09 20:47:19 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
std::string map_parser::ensure_relative_to_xml( boost::optional<std::string> opt_path )
|
|
|
|
{
|
2011-01-25 21:47:56 +01:00
|
|
|
if (relative_to_xml_)
|
2011-01-04 16:22:49 +01:00
|
|
|
{
|
2011-01-25 21:47:56 +01:00
|
|
|
boost::filesystem::path xml_path = filename_;
|
|
|
|
boost::filesystem::path rel_path = *opt_path;
|
|
|
|
if ( !rel_path.has_root_path() )
|
|
|
|
{
|
|
|
|
#if (BOOST_FILESYSTEM_VERSION == 3)
|
2011-05-26 01:48:07 +02:00
|
|
|
// TODO - normalize is now deprecated, use make_preferred?
|
|
|
|
boost::filesystem::path full = boost::filesystem::absolute(xml_path.parent_path()/rel_path);
|
2011-01-25 21:47:56 +01:00
|
|
|
#else // v2
|
|
|
|
boost::filesystem::path full = boost::filesystem::complete(xml_path.branch_path()/rel_path).normalize();
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef MAPNIK_DEBUG
|
|
|
|
std::clog << "\nModifying relative paths to be relative to xml...\n";
|
|
|
|
std::clog << "original base path: " << *opt_path << "\n";
|
|
|
|
std::clog << "relative base path: " << full.string() << "\n";
|
|
|
|
#endif
|
|
|
|
return full.string();
|
|
|
|
}
|
2009-05-01 03:59:01 +02:00
|
|
|
}
|
2010-04-09 20:47:19 +02:00
|
|
|
return *opt_path;
|
|
|
|
}
|
2009-05-01 03:59:01 +02:00
|
|
|
|
2011-02-05 04:15:17 +01:00
|
|
|
void map_parser::ensure_attrs(ptree const& sym, std::string name, std::string attrs)
|
|
|
|
{
|
|
|
|
|
|
|
|
typedef ptree::key_type::value_type Ch;
|
|
|
|
//typedef boost::property_tree::xml_parser::xmlattr<Ch> x_att;
|
|
|
|
|
|
|
|
std::set<std::string> attr_set;
|
|
|
|
boost::split(attr_set, attrs, boost::is_any_of(","));
|
|
|
|
for (ptree::const_iterator itr = sym.begin(); itr != sym.end(); ++itr)
|
|
|
|
{
|
|
|
|
//ptree::value_type const& v = *itr;
|
|
|
|
if (itr->first == boost::property_tree::xml_parser::xmlattr<Ch>())
|
|
|
|
{
|
|
|
|
optional<const ptree &> attribs = sym.get_child_optional( boost::property_tree::xml_parser::xmlattr<Ch>() );
|
|
|
|
if (attribs)
|
|
|
|
{
|
|
|
|
std::ostringstream s("");
|
|
|
|
s << "### " << name << " properties warning: ";
|
|
|
|
int missing = 0;
|
|
|
|
for (ptree::const_iterator it = attribs.get().begin(); it != attribs.get().end(); ++it)
|
|
|
|
{
|
|
|
|
std::string name = it->first;
|
|
|
|
bool found = (attr_set.find(name) != attr_set.end());
|
|
|
|
if (!found)
|
|
|
|
{
|
|
|
|
if (missing) s << ",";
|
|
|
|
s << "'" << name << "'";
|
|
|
|
++missing;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (missing) {
|
|
|
|
if (missing > 1) s << " are";
|
|
|
|
else s << " is";
|
|
|
|
s << " invalid, acceptable values are:\n'" << attrs << "'\n";
|
|
|
|
std::clog << s.str();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-09-25 20:47:12 +02:00
|
|
|
} // end of namespace mapnik
|