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)
|
|
|
|
*
|
|
|
|
* Copyright (C) 2006 Artem Pavlenko
|
|
|
|
*
|
|
|
|
* This library is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
|
|
* License as published by the Free Software Foundation; either
|
|
|
|
* version 2.1 of the License, or (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This library is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
* Lesser General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
|
|
* License along with this library; if not, write to the Free Software
|
|
|
|
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
|
|
*
|
|
|
|
*****************************************************************************/
|
2006-10-04 13:22:18 +02:00
|
|
|
// $Id$
|
2009-12-16 21:02:06 +01:00
|
|
|
|
2007-10-08 19:42:41 +02:00
|
|
|
// mapnik
|
|
|
|
#include <mapnik/save_map.hpp>
|
2010-07-19 02:21:53 +02:00
|
|
|
#include <mapnik/map.hpp>
|
2007-10-08 19:42:41 +02:00
|
|
|
#include <mapnik/ptree_helpers.hpp>
|
2009-12-16 21:02:06 +01:00
|
|
|
#include <mapnik/expression_string.hpp>
|
2010-03-12 15:49:50 +01:00
|
|
|
#include <mapnik/raster_colorizer.hpp>
|
2010-08-12 02:11:01 +02:00
|
|
|
#include <mapnik/metawriter_json.hpp>
|
2007-10-08 19:42:41 +02:00
|
|
|
|
2006-10-04 13:22:18 +02:00
|
|
|
// boost
|
2006-10-03 10:39:43 +02:00
|
|
|
#include <boost/algorithm/string.hpp>
|
2007-09-25 20:47:12 +02:00
|
|
|
#include <boost/optional.hpp>
|
2006-10-03 10:39:43 +02:00
|
|
|
#include <boost/property_tree/ptree.hpp>
|
|
|
|
#include <boost/property_tree/xml_parser.hpp>
|
2007-10-08 19:42:41 +02:00
|
|
|
|
|
|
|
// stl
|
|
|
|
#include <iostream>
|
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:46:25 +02:00
|
|
|
using boost::property_tree::ptree;
|
|
|
|
using boost::optional;
|
|
|
|
|
|
|
|
void serialize_raster_colorizer(ptree & sym_node,
|
2010-06-02 13:03:30 +02:00
|
|
|
raster_colorizer_ptr const& colorizer,
|
|
|
|
bool explicit_defaults)
|
2010-04-09 20:46:25 +02:00
|
|
|
{
|
|
|
|
ptree & col_node = sym_node.push_back(
|
2010-06-02 13:03:30 +02:00
|
|
|
ptree::value_type("RasterColorizer", ptree() ))->second;
|
2010-04-09 20:46:25 +02:00
|
|
|
|
|
|
|
unsigned i;
|
|
|
|
color_bands const &cb = colorizer->get_color_bands();
|
|
|
|
for (i=0; i<cb.size(); i++) {
|
2010-06-02 13:03:30 +02:00
|
|
|
if (!cb[i].is_interpolated()) {
|
|
|
|
ptree & band_node = col_node.push_back(
|
|
|
|
ptree::value_type("ColorBand", ptree())
|
|
|
|
)->second;
|
|
|
|
set_attr(band_node, "value", cb[i].get_value());
|
|
|
|
if (cb[i].get_value() != cb[i].get_max_value())
|
|
|
|
set_attr(band_node, "max_value", cb[i].get_max_value());
|
|
|
|
set_attr(band_node, "midpoints", cb[i].get_midpoints());
|
|
|
|
optional<color> c = cb[i].get_color();
|
|
|
|
if (c) set_attr(band_node, "color", * c);
|
|
|
|
}
|
2010-04-09 20:46:25 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
class serialize_symbolizer : public boost::static_visitor<>
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
serialize_symbolizer( ptree & r , bool explicit_defaults):
|
2010-06-02 13:03:30 +02:00
|
|
|
rule_(r),
|
|
|
|
explicit_defaults_(explicit_defaults) {}
|
2010-04-09 20:46:25 +02:00
|
|
|
|
|
|
|
void operator () ( const point_symbolizer & sym )
|
|
|
|
{
|
2010-06-02 13:03:30 +02:00
|
|
|
ptree & sym_node = rule_.push_back(
|
|
|
|
ptree::value_type("PointSymbolizer", ptree()))->second;
|
2010-04-09 20:46:25 +02:00
|
|
|
|
2010-06-02 13:03:30 +02:00
|
|
|
add_image_attributes( sym_node, sym );
|
2010-04-09 20:46:25 +02:00
|
|
|
|
2010-06-02 13:03:30 +02:00
|
|
|
point_symbolizer dfl;
|
|
|
|
if (sym.get_allow_overlap() != dfl.get_allow_overlap() || explicit_defaults_ )
|
|
|
|
{
|
|
|
|
set_attr( sym_node, "allow_overlap", sym.get_allow_overlap() );
|
|
|
|
}
|
|
|
|
if ( sym.get_opacity() != dfl.get_opacity() || explicit_defaults_ )
|
|
|
|
{
|
|
|
|
set_attr( sym_node, "opacity", sym.get_opacity() );
|
|
|
|
}
|
2010-08-12 02:11:01 +02:00
|
|
|
add_metawriter_attributes(sym_node, sym);
|
2010-04-09 20:46:25 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void operator () ( const line_symbolizer & sym )
|
|
|
|
{
|
2010-06-02 13:03:30 +02:00
|
|
|
ptree & sym_node = rule_.push_back(
|
|
|
|
ptree::value_type("LineSymbolizer", ptree()))->second;
|
2010-08-19 17:45:53 +02:00
|
|
|
|
|
|
|
const stroke & strk = sym.get_stroke();
|
|
|
|
add_stroke_attributes(sym_node, strk);
|
2010-08-12 02:11:01 +02:00
|
|
|
add_metawriter_attributes(sym_node, sym);
|
2010-06-02 13:03:30 +02:00
|
|
|
}
|
|
|
|
|
2010-04-09 20:46:25 +02:00
|
|
|
void operator () ( const line_pattern_symbolizer & sym )
|
|
|
|
{
|
2010-06-02 13:03:30 +02:00
|
|
|
ptree & sym_node = rule_.push_back(
|
|
|
|
ptree::value_type("LinePatternSymbolizer",
|
|
|
|
ptree()))->second;
|
2010-04-09 20:46:25 +02:00
|
|
|
|
2010-06-02 13:03:30 +02:00
|
|
|
add_image_attributes( sym_node, sym );
|
2010-08-12 02:11:01 +02:00
|
|
|
add_metawriter_attributes(sym_node, sym);
|
2010-04-09 20:46:25 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void operator () ( const polygon_symbolizer & sym )
|
|
|
|
{
|
2010-06-02 13:03:30 +02:00
|
|
|
ptree & sym_node = rule_.push_back(
|
|
|
|
ptree::value_type("PolygonSymbolizer", ptree()))->second;
|
|
|
|
polygon_symbolizer dfl;
|
2010-04-09 20:46:25 +02:00
|
|
|
|
2010-06-02 13:03:30 +02:00
|
|
|
if ( sym.get_fill() != dfl.get_fill() || explicit_defaults_ )
|
|
|
|
{
|
|
|
|
set_attr( sym_node, "fill", sym.get_fill() );
|
|
|
|
}
|
|
|
|
if ( sym.get_opacity() != dfl.get_opacity() || explicit_defaults_ )
|
|
|
|
{
|
|
|
|
set_attr( sym_node, "fill-opacity", sym.get_opacity() );
|
|
|
|
}
|
|
|
|
if ( sym.get_gamma() != dfl.get_gamma() || explicit_defaults_ )
|
|
|
|
{
|
|
|
|
set_attr( sym_node, "gamma", sym.get_gamma() );
|
|
|
|
}
|
2010-08-12 02:11:01 +02:00
|
|
|
add_metawriter_attributes(sym_node, sym);
|
2010-04-09 20:46:25 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void operator () ( const polygon_pattern_symbolizer & sym )
|
|
|
|
{
|
2010-06-02 13:03:30 +02:00
|
|
|
ptree & sym_node = rule_.push_back(
|
|
|
|
ptree::value_type("PolygonPatternSymbolizer",
|
|
|
|
ptree()))->second;
|
2010-06-21 00:36:49 +02:00
|
|
|
polygon_pattern_symbolizer dfl(parse_path(""));
|
|
|
|
|
|
|
|
if ( sym.get_alignment() != dfl.get_alignment() || explicit_defaults_ )
|
|
|
|
{
|
|
|
|
set_attr( sym_node, "alignment", sym.get_alignment() );
|
|
|
|
}
|
2010-04-09 20:46:25 +02:00
|
|
|
|
2010-06-02 13:03:30 +02:00
|
|
|
add_image_attributes( sym_node, sym );
|
2010-08-12 02:11:01 +02:00
|
|
|
add_metawriter_attributes(sym_node, sym);
|
2010-04-09 20:46:25 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void operator () ( const raster_symbolizer & sym )
|
|
|
|
{
|
2010-06-02 13:03:30 +02:00
|
|
|
ptree & sym_node = rule_.push_back(
|
|
|
|
ptree::value_type("RasterSymbolizer", ptree()))->second;
|
|
|
|
raster_symbolizer dfl;
|
|
|
|
|
|
|
|
if ( sym.get_mode() != dfl.get_mode() || explicit_defaults_ )
|
|
|
|
{
|
|
|
|
set_attr( sym_node, "mode", sym.get_mode() );
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( sym.get_scaling() != dfl.get_scaling() || explicit_defaults_ )
|
|
|
|
{
|
|
|
|
set_attr( sym_node, "scaling", sym.get_scaling() );
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( sym.get_opacity() != dfl.get_opacity() || explicit_defaults_ )
|
|
|
|
{
|
|
|
|
set_attr( sym_node, "opacity", sym.get_opacity() );
|
|
|
|
}
|
|
|
|
|
|
|
|
if (sym.get_colorizer()) {
|
|
|
|
serialize_raster_colorizer(sym_node, sym.get_colorizer(),
|
|
|
|
explicit_defaults_);
|
|
|
|
}
|
2010-08-12 02:11:01 +02:00
|
|
|
//Note: raster_symbolizer doesn't support metawriters
|
2010-04-09 20:46:25 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void operator () ( const shield_symbolizer & sym )
|
|
|
|
{
|
2010-06-02 13:03:30 +02:00
|
|
|
ptree & sym_node = rule_.push_back(
|
|
|
|
ptree::value_type("ShieldSymbolizer",
|
|
|
|
ptree()))->second;
|
|
|
|
|
|
|
|
add_font_attributes( sym_node, sym);
|
|
|
|
add_image_attributes( sym_node, sym);
|
2010-08-12 02:11:01 +02:00
|
|
|
add_metawriter_attributes(sym_node, sym);
|
2010-06-02 13:03:30 +02:00
|
|
|
|
|
|
|
// pseudo-default-construct a shield_symbolizer. It is used
|
|
|
|
// to avoid printing of attributes with default values without
|
|
|
|
// repeating the default values here.
|
|
|
|
// maybe add a real, explicit default-ctor?
|
|
|
|
|
|
|
|
//FIXME pls
|
|
|
|
/*
|
|
|
|
shield_symbolizer sym_dfl("<no default>", "<no default>", 0, color(0,0,0), "<no default>", "<no default>");
|
|
|
|
if (sym.get_unlock_image() != sym_dfl.get_unlock_image() || explicit_defaults_ )
|
|
|
|
{
|
|
|
|
set_attr( sym_node, "unlock_image", sym.get_unlock_image() );
|
|
|
|
}
|
|
|
|
if (sym.get_no_text() != sym_dfl.get_no_text() || explicit_defaults_ )
|
|
|
|
{
|
|
|
|
set_attr( sym_node, "no_text", sym.get_no_text() );
|
|
|
|
}
|
|
|
|
*/
|
2010-04-09 20:46:25 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void operator () ( const text_symbolizer & sym )
|
|
|
|
{
|
2010-06-02 13:03:30 +02:00
|
|
|
ptree & sym_node = rule_.push_back(
|
|
|
|
ptree::value_type("TextSymbolizer",
|
|
|
|
ptree()))->second;
|
2010-04-09 20:46:25 +02:00
|
|
|
|
2010-06-02 13:03:30 +02:00
|
|
|
add_font_attributes( sym_node, sym);
|
2010-08-12 02:11:01 +02:00
|
|
|
add_metawriter_attributes(sym_node, sym);
|
2010-04-09 20:46:25 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void operator () ( const building_symbolizer & sym )
|
|
|
|
{
|
2010-06-02 13:03:30 +02:00
|
|
|
ptree & sym_node = rule_.push_back(
|
|
|
|
ptree::value_type("BuildingSymbolizer", ptree()))->second;
|
|
|
|
building_symbolizer dfl;
|
2010-04-09 20:46:25 +02:00
|
|
|
|
2010-06-02 13:03:30 +02:00
|
|
|
if ( sym.get_fill() != dfl.get_fill() || explicit_defaults_ )
|
|
|
|
{
|
|
|
|
set_attr( sym_node, "fill", sym.get_fill() );
|
|
|
|
}
|
|
|
|
if ( sym.get_opacity() != dfl.get_opacity() || explicit_defaults_ )
|
|
|
|
{
|
|
|
|
set_attr( sym_node, "fill-opacity", sym.get_opacity() );
|
|
|
|
}
|
|
|
|
if ( sym.height() != dfl.height() || explicit_defaults_ )
|
|
|
|
{
|
|
|
|
set_attr( sym_node, "height", sym.height() );
|
|
|
|
}
|
2010-08-12 02:11:01 +02:00
|
|
|
add_metawriter_attributes(sym_node, sym);
|
2010-04-09 20:46:25 +02:00
|
|
|
}
|
|
|
|
|
2010-04-15 23:42:28 +02:00
|
|
|
void operator () ( markers_symbolizer const& sym)
|
2010-04-09 20:46:25 +02:00
|
|
|
{
|
2010-04-15 23:42:28 +02:00
|
|
|
ptree & sym_node = rule_.push_back(
|
2010-06-02 13:03:30 +02:00
|
|
|
ptree::value_type("MarkersSymbolizer", ptree()))->second;
|
2010-05-30 05:16:51 +02:00
|
|
|
markers_symbolizer dfl(parse_path("")); //TODO: Parameter?
|
2010-06-02 13:03:30 +02:00
|
|
|
std::string const& filename = path_processor_type::to_string( *sym.get_filename());
|
|
|
|
if ( ! filename.empty() ) {
|
|
|
|
set_attr( sym_node, "file", filename );
|
|
|
|
}
|
2010-05-30 05:16:51 +02:00
|
|
|
if (sym.get_allow_overlap() != dfl.get_allow_overlap() || explicit_defaults_)
|
|
|
|
{
|
|
|
|
set_attr( sym_node, "allow_overlap", sym.get_allow_overlap() );
|
|
|
|
}
|
|
|
|
if (sym.get_spacing() != dfl.get_spacing() || explicit_defaults_)
|
|
|
|
{
|
|
|
|
set_attr( sym_node, "spacing", sym.get_spacing() );
|
|
|
|
}
|
|
|
|
if (sym.get_max_error() != dfl.get_max_error() || explicit_defaults_)
|
|
|
|
{
|
|
|
|
set_attr( sym_node, "max_error", sym.get_max_error() );
|
|
|
|
}
|
|
|
|
if (sym.get_fill() != dfl.get_fill() || explicit_defaults_)
|
|
|
|
{
|
|
|
|
set_attr( sym_node, "fill", sym.get_fill() );
|
|
|
|
}
|
2010-08-19 19:33:01 +02:00
|
|
|
|
|
|
|
const stroke & strk = sym.get_stroke();
|
|
|
|
add_stroke_attributes(sym_node, strk);
|
|
|
|
|
2010-08-12 02:11:01 +02:00
|
|
|
add_metawriter_attributes(sym_node, sym);
|
2010-04-09 20:46:25 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void operator () ( glyph_symbolizer const& sym)
|
|
|
|
{
|
2010-06-02 13:03:30 +02:00
|
|
|
ptree &node = rule_.push_back(
|
|
|
|
ptree::value_type("GlyphSymbolizer", ptree())
|
|
|
|
)->second;
|
2010-04-15 23:42:28 +02:00
|
|
|
|
2010-06-02 13:03:30 +02:00
|
|
|
glyph_symbolizer dfl("<no default>", expression_ptr());
|
|
|
|
|
|
|
|
// face_name
|
|
|
|
set_attr( node, "face_name", sym.get_face_name() );
|
|
|
|
|
|
|
|
// char
|
|
|
|
if (sym.get_char()) {
|
|
|
|
const std::string &str =
|
|
|
|
to_expression_string(*sym.get_char());
|
|
|
|
set_attr( node, "char", str );
|
|
|
|
}
|
|
|
|
|
|
|
|
// angle
|
|
|
|
if (sym.get_angle()) {
|
|
|
|
const std::string &str =
|
|
|
|
to_expression_string(*sym.get_angle());
|
|
|
|
set_attr( node, "angle", str );
|
|
|
|
}
|
|
|
|
|
|
|
|
// value
|
|
|
|
if (sym.get_value()) {
|
|
|
|
const std::string &str =
|
|
|
|
to_expression_string(*sym.get_value());
|
|
|
|
set_attr( node, "value", str );
|
|
|
|
}
|
|
|
|
|
|
|
|
// size
|
|
|
|
if (sym.get_size()) {
|
|
|
|
const std::string &str =
|
|
|
|
to_expression_string(*sym.get_size());
|
|
|
|
set_attr( node, "size", str );
|
|
|
|
}
|
|
|
|
|
|
|
|
// color
|
|
|
|
if (sym.get_color()) {
|
|
|
|
const std::string &str =
|
|
|
|
to_expression_string(*sym.get_color());
|
|
|
|
set_attr( node, "color", str );
|
|
|
|
}
|
|
|
|
|
|
|
|
// colorizer
|
|
|
|
if (sym.get_colorizer()) {
|
|
|
|
serialize_raster_colorizer(node, sym.get_colorizer(),
|
|
|
|
explicit_defaults_);
|
|
|
|
}
|
2010-04-09 20:46:25 +02:00
|
|
|
|
2010-04-15 23:42:28 +02:00
|
|
|
// allow_overlap
|
|
|
|
if (sym.get_allow_overlap() != dfl.get_allow_overlap() || explicit_defaults_ )
|
|
|
|
{
|
|
|
|
set_attr( node, "allow_overlap", sym.get_allow_overlap() );
|
|
|
|
}
|
|
|
|
// avoid_edges
|
|
|
|
if (sym.get_avoid_edges() != dfl.get_avoid_edges() || explicit_defaults_ )
|
|
|
|
{
|
|
|
|
set_attr( node, "avoid_edges", sym.get_avoid_edges() );
|
|
|
|
}
|
|
|
|
|
|
|
|
// displacement
|
|
|
|
position displacement = sym.get_displacement();
|
|
|
|
if ( displacement.get<0>() != dfl.get_displacement().get<0>() || explicit_defaults_ )
|
|
|
|
{
|
|
|
|
set_attr( node, "dx", displacement.get<0>() );
|
|
|
|
}
|
|
|
|
if ( displacement.get<1>() != dfl.get_displacement().get<1>() || explicit_defaults_ )
|
|
|
|
{
|
|
|
|
set_attr( node, "dy", displacement.get<1>() );
|
|
|
|
}
|
|
|
|
|
|
|
|
// halo fill & radius
|
|
|
|
const color & c = sym.get_halo_fill();
|
|
|
|
if ( c != dfl.get_halo_fill() || explicit_defaults_ )
|
|
|
|
{
|
|
|
|
set_attr( node, "halo_fill", c );
|
|
|
|
}
|
|
|
|
|
|
|
|
if (sym.get_halo_radius() != dfl.get_halo_radius() || explicit_defaults_ )
|
|
|
|
{
|
|
|
|
set_attr( node, "halo_radius", sym.get_halo_radius() );
|
|
|
|
}
|
|
|
|
|
|
|
|
// angle_mode
|
|
|
|
if (sym.get_angle_mode() != dfl.get_angle_mode() || explicit_defaults_ )
|
|
|
|
{
|
|
|
|
set_attr( node, "angle_mode", sym.get_angle_mode() );
|
|
|
|
}
|
2010-08-12 02:11:01 +02:00
|
|
|
add_metawriter_attributes(node, sym);
|
2010-04-09 20:46:25 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
serialize_symbolizer();
|
|
|
|
void add_image_attributes(ptree & node, const symbolizer_with_image & sym)
|
|
|
|
{
|
2010-06-02 13:03:30 +02:00
|
|
|
std::string const& filename = path_processor_type::to_string( *sym.get_filename());
|
|
|
|
if ( ! filename.empty() ) {
|
|
|
|
set_attr( node, "file", filename );
|
|
|
|
}
|
2010-06-15 14:27:58 +02:00
|
|
|
|
|
|
|
// TODO !!!
|
2010-04-09 20:46:25 +02:00
|
|
|
}
|
|
|
|
void add_font_attributes(ptree & node, const text_symbolizer & sym)
|
|
|
|
{
|
2010-06-02 13:03:30 +02:00
|
|
|
expression_ptr const& expr = sym.get_name();
|
|
|
|
const std::string & name = to_expression_string(*expr);
|
|
|
|
|
|
|
|
if ( ! name.empty() ) {
|
|
|
|
set_attr( node, "name", name );
|
|
|
|
}
|
|
|
|
const std::string & face_name = sym.get_face_name();
|
|
|
|
if ( ! face_name.empty() ) {
|
|
|
|
set_attr( node, "face_name", face_name );
|
|
|
|
}
|
|
|
|
const std::string & fontset_name = sym.get_fontset().get_name();
|
|
|
|
if ( ! fontset_name.empty() ) {
|
|
|
|
set_attr( node, "fontset_name", fontset_name );
|
|
|
|
}
|
|
|
|
|
|
|
|
set_attr( node, "size", sym.get_text_size() );
|
|
|
|
set_attr( node, "fill", sym.get_fill() );
|
|
|
|
|
|
|
|
// pseudo-default-construct a text_symbolizer. It is used
|
|
|
|
// to avoid printing ofattributes with default values without
|
|
|
|
// repeating the default values here.
|
|
|
|
// maybe add a real, explicit default-ctor?
|
|
|
|
// FIXME
|
|
|
|
text_symbolizer dfl(expression_ptr(), "<no default>",
|
|
|
|
0, color(0,0,0) );
|
|
|
|
|
|
|
|
position displacement = sym.get_displacement();
|
|
|
|
if ( displacement.get<0>() != dfl.get_displacement().get<0>() || explicit_defaults_ )
|
|
|
|
{
|
|
|
|
set_attr( node, "dx", displacement.get<0>() );
|
|
|
|
}
|
|
|
|
if ( displacement.get<1>() != dfl.get_displacement().get<1>() || explicit_defaults_ )
|
|
|
|
{
|
|
|
|
set_attr( node, "dy", displacement.get<1>() );
|
|
|
|
}
|
|
|
|
|
|
|
|
if (sym.get_label_placement() != dfl.get_label_placement() || explicit_defaults_ )
|
|
|
|
{
|
|
|
|
set_attr( node, "placement", sym.get_label_placement() );
|
|
|
|
}
|
|
|
|
|
|
|
|
if (sym.get_vertical_alignment() != dfl.get_vertical_alignment() || explicit_defaults_ )
|
|
|
|
{
|
|
|
|
set_attr( node, "vertical_alignment", sym.get_vertical_alignment() );
|
|
|
|
}
|
|
|
|
|
|
|
|
if (sym.get_halo_radius() != dfl.get_halo_radius() || explicit_defaults_ )
|
|
|
|
{
|
|
|
|
set_attr( node, "halo_radius", sym.get_halo_radius() );
|
|
|
|
}
|
|
|
|
const color & c = sym.get_halo_fill();
|
|
|
|
if ( c != dfl.get_halo_fill() || explicit_defaults_ )
|
|
|
|
{
|
|
|
|
set_attr( node, "halo_fill", c );
|
|
|
|
}
|
|
|
|
if (sym.get_text_ratio() != dfl.get_text_ratio() || explicit_defaults_ )
|
|
|
|
{
|
|
|
|
set_attr( node, "text_ratio", sym.get_text_ratio() );
|
|
|
|
}
|
|
|
|
if (sym.get_wrap_width() != dfl.get_wrap_width() || explicit_defaults_ )
|
|
|
|
{
|
|
|
|
set_attr( node, "wrap_width", sym.get_wrap_width() );
|
|
|
|
}
|
|
|
|
if (sym.get_wrap_before() != dfl.get_wrap_before() || explicit_defaults_ )
|
|
|
|
{
|
|
|
|
set_attr( node, "wrap_before", sym.get_wrap_before() );
|
|
|
|
}
|
|
|
|
if (sym.get_wrap_char() != dfl.get_wrap_char() || explicit_defaults_ )
|
|
|
|
{
|
|
|
|
set_attr( node, "wrap_character", std::string(1, sym.get_wrap_char()) );
|
|
|
|
}
|
2010-09-18 21:10:18 +02:00
|
|
|
if (sym.get_text_transform() != dfl.get_text_transform() || explicit_defaults_ )
|
2010-06-02 13:03:30 +02:00
|
|
|
{
|
2010-09-18 21:10:18 +02:00
|
|
|
set_attr( node, "text_transform", sym.get_text_transform() );
|
2010-06-02 13:03:30 +02:00
|
|
|
}
|
|
|
|
if (sym.get_line_spacing() != dfl.get_line_spacing() || explicit_defaults_ )
|
|
|
|
{
|
|
|
|
set_attr( node, "line_spacing", sym.get_line_spacing() );
|
|
|
|
}
|
|
|
|
if (sym.get_character_spacing() != dfl.get_character_spacing() || explicit_defaults_ )
|
|
|
|
{
|
|
|
|
set_attr( node, "character_spacing", sym.get_character_spacing() );
|
|
|
|
}
|
|
|
|
if (sym.get_label_spacing() != dfl.get_label_spacing() || explicit_defaults_ )
|
|
|
|
{
|
|
|
|
set_attr( node, "spacing", sym.get_label_spacing() );
|
|
|
|
}
|
|
|
|
if (sym.get_minimum_distance() != dfl.get_minimum_distance() || explicit_defaults_ )
|
|
|
|
{
|
|
|
|
set_attr( node, "min_distance", sym.get_minimum_distance() );
|
|
|
|
}
|
2010-11-03 14:18:56 +01:00
|
|
|
if (sym.get_minimum_padding() != dfl.get_minimum_padding() || explicit_defaults_ )
|
|
|
|
{
|
|
|
|
set_attr( node, "min_padding", sym.get_minimum_padding() );
|
|
|
|
}
|
2010-06-02 13:03:30 +02:00
|
|
|
if (sym.get_allow_overlap() != dfl.get_allow_overlap() || explicit_defaults_ )
|
|
|
|
{
|
|
|
|
set_attr( node, "allow_overlap", sym.get_allow_overlap() );
|
|
|
|
}
|
|
|
|
if (sym.get_avoid_edges() != dfl.get_avoid_edges() || explicit_defaults_ )
|
|
|
|
{
|
|
|
|
set_attr( node, "avoid_edges", sym.get_avoid_edges() );
|
|
|
|
}
|
2010-06-15 14:27:58 +02:00
|
|
|
if (sym.get_text_opacity() != dfl.get_text_opacity() || explicit_defaults_ )
|
2010-06-02 13:03:30 +02:00
|
|
|
{
|
2010-06-15 14:27:58 +02:00
|
|
|
set_attr( node, "opacity", sym.get_text_opacity() );
|
2010-06-02 13:03:30 +02:00
|
|
|
}
|
|
|
|
if (sym.get_horizontal_alignment() != dfl.get_horizontal_alignment() || explicit_defaults_ )
|
|
|
|
{
|
|
|
|
set_attr( node, "horizontal_alignment", sym.get_horizontal_alignment() );
|
|
|
|
}
|
|
|
|
if (sym.get_justify_alignment() != dfl.get_justify_alignment() || explicit_defaults_ )
|
|
|
|
{
|
|
|
|
set_attr( node, "justify_alignment", sym.get_justify_alignment() );
|
|
|
|
}
|
2010-04-09 20:46:25 +02:00
|
|
|
}
|
2010-08-12 02:11:01 +02:00
|
|
|
|
2010-08-19 17:45:53 +02:00
|
|
|
|
|
|
|
void add_stroke_attributes(ptree & node, const stroke & strk)
|
|
|
|
{
|
|
|
|
|
|
|
|
stroke dfl = stroke();
|
|
|
|
|
|
|
|
if ( strk.get_color() != dfl.get_color() || explicit_defaults_ )
|
|
|
|
{
|
|
|
|
set_attr( node, "stroke", strk.get_color() );
|
|
|
|
}
|
|
|
|
if ( strk.get_width() != dfl.get_width() || explicit_defaults_ )
|
|
|
|
{
|
|
|
|
set_attr( node, "stroke-width", strk.get_width() );
|
|
|
|
}
|
|
|
|
if ( strk.get_opacity() != dfl.get_opacity() || explicit_defaults_ )
|
|
|
|
{
|
|
|
|
set_attr( node, "stroke-opacity", strk.get_opacity() );
|
|
|
|
}
|
|
|
|
if ( strk.get_line_join() != dfl.get_line_join() || explicit_defaults_ )
|
|
|
|
{
|
|
|
|
set_attr( node, "stroke-linejoin", strk.get_line_join() );
|
|
|
|
}
|
|
|
|
if ( strk.get_line_cap() != dfl.get_line_cap() || explicit_defaults_ )
|
|
|
|
{
|
|
|
|
set_attr( node, "stroke-linecap", strk.get_line_cap() );
|
|
|
|
}
|
|
|
|
if ( ! strk.get_dash_array().empty() )
|
|
|
|
{
|
|
|
|
std::ostringstream os;
|
|
|
|
const dash_array & dashes = strk.get_dash_array();
|
|
|
|
for (unsigned i = 0; i < dashes.size(); ++i) {
|
|
|
|
os << dashes[i].first << ", " << dashes[i].second;
|
|
|
|
if ( i + 1 < dashes.size() ) os << ", ";
|
|
|
|
}
|
|
|
|
set_attr( node, "stroke-dasharray", os.str() );
|
|
|
|
}
|
|
|
|
if ( strk.dash_offset() != dfl.dash_offset() || explicit_defaults_ )
|
|
|
|
{
|
|
|
|
set_attr( node, "stroke-dashoffset", strk.dash_offset());
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
2010-08-12 02:11:01 +02:00
|
|
|
void add_metawriter_attributes(ptree &node, symbolizer_base const& sym)
|
|
|
|
{
|
|
|
|
if (!sym.get_metawriter_name().empty() || explicit_defaults_) {
|
|
|
|
set_attr(node, "meta-writer", sym.get_metawriter_name());
|
|
|
|
}
|
|
|
|
if (!sym.get_metawriter_properties_overrides().empty() || explicit_defaults_) {
|
|
|
|
set_attr(node, "meta-output", sym.get_metawriter_properties_overrides().to_string());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-04-09 20:46:25 +02:00
|
|
|
ptree & rule_;
|
|
|
|
bool explicit_defaults_;
|
|
|
|
};
|
|
|
|
|
|
|
|
void serialize_rule( ptree & style_node, const rule_type & rule, bool explicit_defaults)
|
|
|
|
{
|
|
|
|
ptree & rule_node = style_node.push_back(
|
2010-06-02 13:03:30 +02:00
|
|
|
ptree::value_type("Rule", ptree() ))->second;
|
2010-04-09 20:46:25 +02:00
|
|
|
|
|
|
|
rule_type dfl;
|
|
|
|
if ( rule.get_name() != dfl.get_name() )
|
|
|
|
{
|
2010-06-02 13:03:30 +02:00
|
|
|
set_attr(rule_node, "name", rule.get_name());
|
2010-04-09 20:46:25 +02:00
|
|
|
}
|
|
|
|
if ( rule.get_title() != dfl.get_title() )
|
|
|
|
{
|
2010-06-02 13:03:30 +02:00
|
|
|
set_attr(rule_node, "title", rule.get_title());
|
2010-04-09 20:46:25 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if ( rule.has_else_filter() )
|
|
|
|
{
|
2010-06-02 13:03:30 +02:00
|
|
|
rule_node.push_back( ptree::value_type(
|
|
|
|
"ElseFilter", ptree()));
|
2010-04-09 20:46:25 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2010-06-02 13:03:30 +02:00
|
|
|
// filters were not comparable, perhaps should now compare expressions?
|
|
|
|
expression_ptr const& expr = rule.get_filter();
|
|
|
|
std::string filter = mapnik::to_expression_string(*expr);
|
|
|
|
std::string default_filter = mapnik::to_expression_string(*dfl.get_filter());
|
2010-01-30 01:47:06 +01:00
|
|
|
|
2010-06-02 13:03:30 +02:00
|
|
|
if ( filter != default_filter)
|
|
|
|
{
|
|
|
|
rule_node.push_back( ptree::value_type(
|
|
|
|
"Filter", ptree()))->second.put_value( filter );
|
|
|
|
}
|
2010-04-09 20:46:25 +02:00
|
|
|
}
|
2007-09-25 20:47:12 +02:00
|
|
|
|
2010-04-09 20:46:25 +02:00
|
|
|
if (rule.get_min_scale() != dfl.get_min_scale() )
|
|
|
|
{
|
2010-06-02 13:03:30 +02:00
|
|
|
ptree & min_scale = rule_node.push_back( ptree::value_type(
|
|
|
|
"MinScaleDenominator", ptree()))->second;
|
|
|
|
min_scale.put_value( rule.get_min_scale() );
|
2010-04-09 20:46:25 +02:00
|
|
|
}
|
2007-09-25 20:47:12 +02:00
|
|
|
|
2010-04-09 20:46:25 +02:00
|
|
|
if (rule.get_max_scale() != dfl.get_max_scale() )
|
|
|
|
{
|
2010-06-02 13:03:30 +02:00
|
|
|
ptree & max_scale = rule_node.push_back( ptree::value_type(
|
|
|
|
"MaxScaleDenominator", ptree()))->second;
|
|
|
|
max_scale.put_value( rule.get_max_scale() );
|
2010-04-09 20:46:25 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
rule_type::symbolizers::const_iterator begin = rule.get_symbolizers().begin();
|
|
|
|
rule_type::symbolizers::const_iterator end = rule.get_symbolizers().end();
|
|
|
|
serialize_symbolizer serializer( rule_node, explicit_defaults);
|
|
|
|
std::for_each( begin, end , boost::apply_visitor( serializer ));
|
|
|
|
}
|
|
|
|
|
|
|
|
void serialize_style( ptree & map_node, Map::const_style_iterator style_it, bool explicit_defaults )
|
|
|
|
{
|
|
|
|
const feature_type_style & style = style_it->second;
|
|
|
|
const std::string & name = style_it->first;
|
|
|
|
|
|
|
|
ptree & style_node = map_node.push_back(
|
2010-06-02 13:03:30 +02:00
|
|
|
ptree::value_type("Style", ptree()))->second;
|
2010-04-09 20:46:25 +02:00
|
|
|
|
|
|
|
set_attr(style_node, "name", name);
|
2007-09-25 20:47:12 +02:00
|
|
|
|
2010-04-09 20:46:25 +02:00
|
|
|
rules::const_iterator it = style.get_rules().begin();
|
|
|
|
rules::const_iterator end = style.get_rules().end();
|
|
|
|
for (; it != end; ++it)
|
|
|
|
{
|
2010-06-02 13:03:30 +02:00
|
|
|
serialize_rule( style_node, * it , explicit_defaults);
|
2007-09-25 20:47:12 +02:00
|
|
|
}
|
|
|
|
|
2010-04-09 20:46:25 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void serialize_fontset( ptree & map_node, Map::const_fontset_iterator fontset_it )
|
|
|
|
{
|
|
|
|
const font_set & fontset = fontset_it->second;
|
|
|
|
const std::string & name = fontset_it->first;
|
|
|
|
|
|
|
|
ptree & fontset_node = map_node.push_back(
|
2010-06-02 13:03:30 +02:00
|
|
|
ptree::value_type("FontSet", ptree()))->second;
|
2010-04-09 20:46:25 +02:00
|
|
|
|
|
|
|
set_attr(fontset_node, "name", name);
|
|
|
|
|
|
|
|
std::vector<std::string>::const_iterator it = fontset.get_face_names().begin();
|
|
|
|
std::vector<std::string>::const_iterator end = fontset.get_face_names().end();
|
|
|
|
for (; it != end; ++it)
|
2007-09-25 20:47:12 +02:00
|
|
|
{
|
2010-06-02 13:03:30 +02:00
|
|
|
ptree & font_node = fontset_node.push_back(
|
|
|
|
ptree::value_type("Font", ptree()))->second;
|
|
|
|
set_attr(font_node, "face_name", *it);
|
2010-04-09 20:46:25 +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:46:25 +02:00
|
|
|
}
|
2007-09-25 20:47:12 +02:00
|
|
|
|
2010-04-09 20:46:25 +02:00
|
|
|
void serialize_datasource( ptree & layer_node, datasource_ptr datasource)
|
|
|
|
{
|
|
|
|
ptree & datasource_node = layer_node.push_back(
|
2010-06-02 13:03:30 +02:00
|
|
|
ptree::value_type("Datasource", ptree()))->second;
|
2007-09-25 20:47:12 +02:00
|
|
|
|
2010-04-09 20:46:25 +02:00
|
|
|
parameters::const_iterator it = datasource->params().begin();
|
|
|
|
parameters::const_iterator end = datasource->params().end();
|
|
|
|
for (; it != end; ++it)
|
|
|
|
{
|
2010-06-02 13:03:30 +02:00
|
|
|
boost::property_tree::ptree & param_node = datasource_node.push_back(
|
|
|
|
boost::property_tree::ptree::value_type("Parameter",
|
|
|
|
boost::property_tree::ptree()))->second;
|
|
|
|
param_node.put("<xmlattr>.name", it->first );
|
|
|
|
param_node.put_value( it->second );
|
2007-09-25 20:47:12 +02:00
|
|
|
|
|
|
|
}
|
2010-04-09 20:46:25 +02:00
|
|
|
}
|
2007-09-25 20:47:12 +02:00
|
|
|
|
2010-04-09 20:46:25 +02:00
|
|
|
void serialize_layer( ptree & map_node, const layer & layer, bool explicit_defaults )
|
|
|
|
{
|
|
|
|
ptree & layer_node = map_node.push_back(
|
2010-06-02 13:03:30 +02:00
|
|
|
ptree::value_type("Layer", ptree()))->second;
|
2010-04-09 20:46:25 +02:00
|
|
|
if ( layer.name() != "" )
|
2009-01-17 21:18:41 +01:00
|
|
|
{
|
2010-06-02 13:03:30 +02:00
|
|
|
set_attr( layer_node, "name", layer.name() );
|
2010-04-09 20:46:25 +02:00
|
|
|
}
|
2009-01-17 21:18:41 +01:00
|
|
|
|
2010-04-09 20:46:25 +02:00
|
|
|
if ( layer.abstract() != "" )
|
|
|
|
{
|
2010-06-02 13:03:30 +02:00
|
|
|
set_attr( layer_node, "abstract", layer.abstract() );
|
2010-04-09 20:46:25 +02:00
|
|
|
}
|
2009-01-17 21:18:41 +01:00
|
|
|
|
2010-04-09 20:46:25 +02:00
|
|
|
if ( layer.title() != "" )
|
|
|
|
{
|
2010-06-02 13:03:30 +02:00
|
|
|
set_attr( layer_node, "title", layer.title() );
|
2010-04-09 20:46:25 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if ( layer.srs() != "" )
|
|
|
|
{
|
2010-06-02 13:03:30 +02:00
|
|
|
set_attr( layer_node, "srs", layer.srs() );
|
2010-04-09 20:46:25 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if ( !layer.isActive() || explicit_defaults )
|
|
|
|
{
|
2010-06-02 13:03:30 +02:00
|
|
|
set_attr/*<bool>*/( layer_node, "status", layer.isActive() );
|
2010-04-09 20:46:25 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if ( layer.clear_label_cache() || explicit_defaults )
|
|
|
|
{
|
2010-06-02 13:03:30 +02:00
|
|
|
set_attr/*<bool>*/( layer_node, "clear_label_cache", layer.clear_label_cache() );
|
2010-04-09 20:46:25 +02:00
|
|
|
}
|
2009-01-17 21:18:41 +01:00
|
|
|
|
2010-04-09 20:46:25 +02:00
|
|
|
if ( layer.getMinZoom() )
|
|
|
|
{
|
2010-06-02 13:03:30 +02:00
|
|
|
set_attr( layer_node, "minzoom", layer.getMinZoom() );
|
2010-04-09 20:46:25 +02:00
|
|
|
}
|
2009-01-17 21:18:41 +01:00
|
|
|
|
2010-04-09 20:46:25 +02:00
|
|
|
if ( layer.getMaxZoom() != std::numeric_limits<double>::max() )
|
|
|
|
{
|
2010-06-02 13:03:30 +02:00
|
|
|
set_attr( layer_node, "maxzoom", layer.getMaxZoom() );
|
2009-01-17 21:18:41 +01:00
|
|
|
}
|
|
|
|
|
2010-04-09 20:46:25 +02:00
|
|
|
if ( layer.isQueryable() || explicit_defaults )
|
2007-09-25 20:47:12 +02:00
|
|
|
{
|
2010-06-02 13:03:30 +02:00
|
|
|
set_attr( layer_node, "queryable", layer.isQueryable() );
|
2010-04-09 20:46:25 +02:00
|
|
|
}
|
2007-09-25 20:47:12 +02:00
|
|
|
|
2010-04-09 20:46:25 +02:00
|
|
|
std::vector<std::string> const& style_names = layer.styles();
|
|
|
|
for (unsigned i = 0; i < style_names.size(); ++i)
|
|
|
|
{
|
2010-06-02 13:03:30 +02:00
|
|
|
boost::property_tree::ptree & style_node = layer_node.push_back(
|
|
|
|
boost::property_tree::ptree::value_type("StyleName",
|
|
|
|
boost::property_tree::ptree()))->second;
|
|
|
|
style_node.put_value( style_names[i] );
|
2010-04-09 20:46:25 +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:46:25 +02:00
|
|
|
datasource_ptr datasource = layer.datasource();
|
|
|
|
if ( datasource )
|
|
|
|
{
|
2010-06-02 13:03:30 +02:00
|
|
|
serialize_datasource( layer_node, datasource );
|
2007-09-25 20:47:12 +02:00
|
|
|
}
|
2010-04-09 20:46:25 +02:00
|
|
|
}
|
|
|
|
|
2010-08-12 02:11:01 +02:00
|
|
|
void serialize_metawriter(ptree & map_node, Map::const_metawriter_iterator metawriter_it, bool explicit_defaults)
|
|
|
|
{
|
|
|
|
std::string const& name = metawriter_it->first;
|
|
|
|
metawriter_ptr const& metawriter = metawriter_it->second;
|
|
|
|
|
|
|
|
ptree & metawriter_node = map_node.push_back(
|
|
|
|
ptree::value_type("MetaWriter", ptree()))->second;
|
|
|
|
|
|
|
|
set_attr(metawriter_node, "name", name);
|
|
|
|
|
|
|
|
metawriter_json *json = dynamic_cast<metawriter_json *>(metawriter.get());
|
|
|
|
if (json) {
|
|
|
|
set_attr(metawriter_node, "type", "json");
|
|
|
|
std::string const& filename = path_processor_type::to_string(*(json->get_filename()));
|
|
|
|
if (!filename.empty() || explicit_defaults) {
|
|
|
|
set_attr(metawriter_node, "file", filename);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (!metawriter->get_default_properties().empty() || explicit_defaults) {
|
|
|
|
set_attr(metawriter_node, "default-output", metawriter->get_default_properties().to_string());
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2010-04-09 20:46:25 +02:00
|
|
|
void serialize_map(ptree & pt, Map const & map, bool explicit_defaults)
|
|
|
|
{
|
|
|
|
|
|
|
|
ptree & map_node = pt.push_back(ptree::value_type("Map", ptree() ))->second;
|
2007-09-25 20:47:12 +02:00
|
|
|
|
2010-04-09 20:46:25 +02:00
|
|
|
set_attr( map_node, "srs", map.srs() );
|
|
|
|
|
2010-07-19 13:10:03 +02:00
|
|
|
optional<color> const& c = map.background();
|
2010-04-09 20:46:25 +02:00
|
|
|
if ( c )
|
2007-09-25 20:47:12 +02:00
|
|
|
{
|
2010-07-19 14:01:34 +02:00
|
|
|
set_attr( map_node, "background-color", * c );
|
2010-04-09 20:46:25 +02:00
|
|
|
}
|
2009-01-11 19:55:29 +01:00
|
|
|
|
2010-07-19 13:10:03 +02:00
|
|
|
optional<std::string> const& image_filename = map.background_image();
|
|
|
|
if ( image_filename )
|
|
|
|
{
|
|
|
|
set_attr( map_node, "background-image", *image_filename );
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-04-09 20:46:25 +02:00
|
|
|
unsigned buffer_size = map.buffer_size();
|
|
|
|
if ( buffer_size || explicit_defaults)
|
|
|
|
{
|
2010-06-02 13:03:30 +02:00
|
|
|
set_attr( map_node, "buffer_size", buffer_size );
|
2010-04-09 20:46:25 +02:00
|
|
|
}
|
2009-01-11 19:55:29 +01:00
|
|
|
|
2010-04-09 20:46:25 +02:00
|
|
|
{
|
2010-06-02 13:03:30 +02:00
|
|
|
Map::const_fontset_iterator it = map.fontsets().begin();
|
|
|
|
Map::const_fontset_iterator end = map.fontsets().end();
|
|
|
|
for (; it != end; ++it)
|
|
|
|
{
|
|
|
|
serialize_fontset( map_node, it);
|
|
|
|
}
|
2010-04-09 20:46:25 +02:00
|
|
|
}
|
2009-01-11 19:55:29 +01:00
|
|
|
|
2010-10-07 21:34:36 +02:00
|
|
|
parameters extra_attr = map.get_extra_attributes();
|
|
|
|
parameters::const_iterator p_it = extra_attr.begin();
|
|
|
|
parameters::const_iterator p_end = extra_attr.end();
|
|
|
|
for (; p_it != p_end; ++p_it)
|
|
|
|
{
|
|
|
|
set_attr( map_node, p_it->first, p_it->second );
|
|
|
|
}
|
|
|
|
|
2010-04-09 20:46:25 +02:00
|
|
|
Map::const_style_iterator it = map.styles().begin();
|
|
|
|
Map::const_style_iterator end = map.styles().end();
|
|
|
|
for (; it != end; ++it)
|
|
|
|
{
|
2010-06-02 13:03:30 +02:00
|
|
|
serialize_style( map_node, it, explicit_defaults);
|
2010-04-09 20:46:25 +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:46:25 +02:00
|
|
|
std::vector<layer> const & layers = map.layers();
|
|
|
|
for (unsigned i = 0; i < layers.size(); ++i )
|
|
|
|
{
|
2010-06-02 13:03:30 +02:00
|
|
|
serialize_layer( map_node, layers[i], explicit_defaults );
|
2009-07-24 08:15:58 +02:00
|
|
|
}
|
2010-08-12 02:11:01 +02:00
|
|
|
|
|
|
|
Map::const_metawriter_iterator m_it = map.begin_metawriters();
|
|
|
|
Map::const_metawriter_iterator m_end = map.end_metawriters();
|
|
|
|
for (; m_it != m_end; ++m_it) {
|
|
|
|
serialize_metawriter(map_node, m_it, explicit_defaults);
|
|
|
|
}
|
2010-04-09 20:46:25 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void save_map(Map const & map, std::string const& filename, bool explicit_defaults)
|
|
|
|
{
|
|
|
|
ptree pt;
|
|
|
|
serialize_map(pt,map,explicit_defaults);
|
|
|
|
write_xml(filename,pt,std::locale(),boost::property_tree::xml_writer_make_settings(' ',4));
|
|
|
|
}
|
|
|
|
|
|
|
|
std::string save_map_to_string(Map const & map, bool explicit_defaults)
|
|
|
|
{
|
|
|
|
ptree pt;
|
|
|
|
serialize_map(pt,map,explicit_defaults);
|
|
|
|
std::ostringstream ss;
|
|
|
|
write_xml(ss,pt,boost::property_tree::xml_writer_make_settings(' ',4));
|
|
|
|
return ss.str();
|
|
|
|
}
|
2009-07-24 08:15:58 +02:00
|
|
|
|
2006-10-03 10:39:43 +02:00
|
|
|
}
|