diff --git a/include/mapnik/stroke.hpp b/include/mapnik/stroke.hpp index ad6f701be..192efcdf3 100644 --- a/include/mapnik/stroke.hpp +++ b/include/mapnik/stroke.hpp @@ -31,73 +31,76 @@ namespace mapnik { - using std::pair; - using std::vector; - typedef vector > dash_array; +using std::pair; +using std::vector; +typedef vector > dash_array; - // if you add new tokens, don't forget to add them to the corresponding - // string array in the cpp file. - enum line_cap_enum - { - BUTT_CAP, - SQUARE_CAP, - ROUND_CAP, - line_cap_enum_MAX - }; +// if you add new tokens, don't forget to add them to the corresponding +// string array in the cpp file. +enum line_cap_enum +{ + BUTT_CAP, + SQUARE_CAP, + ROUND_CAP, + line_cap_enum_MAX +}; - DEFINE_ENUM( line_cap_e, line_cap_enum ); +DEFINE_ENUM( line_cap_e, line_cap_enum ); - // if you add new tokens, don't forget to add them to the corresponding - // string array in the cpp file. - enum line_join_enum - { - MITER_JOIN, - MITER_REVERT_JOIN, - ROUND_JOIN, - BEVEL_JOIN, - line_join_enum_MAX - }; +// if you add new tokens, don't forget to add them to the corresponding +// string array in the cpp file. +enum line_join_enum +{ + MITER_JOIN, + MITER_REVERT_JOIN, + ROUND_JOIN, + BEVEL_JOIN, + line_join_enum_MAX +}; - DEFINE_ENUM( line_join_e, line_join_enum ); +DEFINE_ENUM( line_join_e, line_join_enum ); - class MAPNIK_DECL stroke - { - color c_; - float width_; - float opacity_; // 0.0 - 1.0 - line_cap_e line_cap_; - line_join_e line_join_; - dash_array dash_; - public: - explicit stroke(); - stroke(color const& c, float width=1.0); - stroke(stroke const& other); - stroke& operator=(const stroke& rhs); +class MAPNIK_DECL stroke +{ + color c_; + double width_; + double opacity_; // 0.0 - 1.0 + line_cap_e line_cap_; + line_join_e line_join_; + dash_array dash_; + double dash_offset_; +public: + explicit stroke(); + stroke(color const& c, double width=1.0); + stroke(stroke const& other); + stroke& operator=(const stroke& rhs); - void set_color(const color& c); + void set_color(const color& c); - color const& get_color() const; + color const& get_color() const; - float get_width() const; - void set_width(float w); - void set_opacity(float opacity); + double get_width() const; + void set_width(double w); + void set_opacity(double opacity); - float get_opacity() const; + double get_opacity() const; - void set_line_cap(line_cap_e line_cap); - line_cap_e get_line_cap() const; + void set_line_cap(line_cap_e line_cap); + line_cap_e get_line_cap() const; - void set_line_join(line_join_e line_join); - line_join_e get_line_join() const; + void set_line_join(line_join_e line_join); + line_join_e get_line_join() const; - void add_dash(float dash,float gap); - bool has_dash() const; + void add_dash(double dash,double gap); + bool has_dash() const; + void set_dash_offset(double offset); + double dash_offset() const; + + dash_array const& get_dash_array() const; - dash_array const& get_dash_array() const; - - private: - void swap(const stroke& other) throw(); - }; +private: + void swap(const stroke& other) throw(); +}; } #endif //STROKE_HPP diff --git a/src/agg_renderer.cpp b/src/agg_renderer.cpp index 062e58daf..cb856f6da 100644 --- a/src/agg_renderer.cpp +++ b/src/agg_renderer.cpp @@ -347,7 +347,7 @@ void agg_renderer::process(line_symbolizer const& sym, renderer ren(renb); ras_ptr->reset(); ras_ptr->gamma(agg::gamma_linear()); - + agg::scanline_p8 sl; for (unsigned i=0;i::process(line_symbolizer const& sym, stroke.generator().miter_limit(4.0); stroke.generator().width(stroke_.get_width()); - + ras_ptr->add_path(stroke); } diff --git a/src/load_map.cpp b/src/load_map.cpp index 0f628c2af..9918f1a2b 100644 --- a/src/load_map.cpp +++ b/src/load_map.cpp @@ -1007,12 +1007,12 @@ namespace mapnik // max_char_angle_delta optional max_char_angle_delta = - get_opt_attr(sym, "max_char_angle_delta"); + get_opt_attr(sym, "max_char_angle_delta"); if (max_char_angle_delta) { text_symbol.set_max_char_angle_delta( * max_char_angle_delta); } - + // horizontal alignment horizontal_alignment_e halign = get_attr(sym, "horizontal_alignment", H_MIDDLE); text_symbol.set_horizontal_alignment(halign); @@ -1258,92 +1258,63 @@ namespace mapnik try { stroke strk; - ptree::const_iterator cssIter = sym.begin(); - ptree::const_iterator endCss = sym.end(); - - for(; cssIter != endCss; ++cssIter) - { - ptree::value_type const& css_tag = *cssIter; - ptree const & css = cssIter->second; - - if (css_tag.first == "CssParameter") - { - std::string css_name = get_attr(css, "name"); - if (css_name == "stroke") - { - color c = get_css(css, css_name); - strk.set_color(c); - } - else if (css_name == "stroke-width") - { - float width = get_css(css, css_name); - strk.set_width(width); - } - else if (css_name == "stroke-opacity") - { - float opacity = get_css(css, css_name); - strk.set_opacity(opacity); - } - else if (css_name == "stroke-linejoin") - { - line_join_e line_join = get_css(css, css_name); - strk.set_line_join( line_join ); - } - else if (css_name == "stroke-linecap") - { - line_cap_e line_cap = get_css(css, css_name); - strk.set_line_cap( line_cap ); - } - else if (css_name == "stroke-dasharray") - { - tokenizer<> tok ( css.data() ); - std::vector dash_array; - tokenizer<>::iterator itr = tok.begin(); - for (; itr != tok.end(); ++itr) - { - try - { - float f = boost::lexical_cast(*itr); - dash_array.push_back(f); - } - catch ( boost::bad_lexical_cast &) - { - throw config_error(std::string("Failed to parse CSS ") + - "parameter '" + css_name + "'. Expected a " + - "list of floats but got '" + css.data() + "'"); - } - } - if (dash_array.size()) - { - size_t size = dash_array.size(); - if ( size % 2) - { - for (size_t i=0; i < size ;++i) - { - dash_array.push_back(dash_array[i]); - } - } - std::vector::const_iterator pos = dash_array.begin(); - while (pos != dash_array.end()) - { - strk.add_dash(*pos,*(pos + 1)); - pos +=2; - } - } - } - else - { - throw config_error(std::string("Failed to parse unknown CSS ") + - "parameter '" + css_name + "'"); - } - } - else if (css_tag.first != "" && - css_tag.first != "" ) - { - throw config_error(std::string("Unknown child node. ") + - "Expected 'CssParameter' but got '" + css_tag.first + "'"); - } - } + // stroke color + optional c= get_opt_attr(sym, "stroke"); + if (c) strk.set_color(*c); + // stroke-width + optional width = get_opt_attr(sym, "stroke-width"); + if (width) strk.set_width(*width); + // stroke-opacity + optional opacity = get_opt_attr(sym, "stroke-opacity"); + if (opacity) strk.set_opacity(*opacity); + // stroke-linejoin + optional line_join = get_opt_attr(sym, "stroke-linejoin"); + if (line_join) strk.set_line_join(*line_join); + // stroke-linecap + optional line_cap = get_opt_attr(sym, "stroke-linecap"); + if (line_cap) strk.set_line_cap(*line_cap); + // stroke-dashaffset + optional offset = get_opt_attr(sym, "stroke-dashoffet"); + if (offset) strk.set_dash_offset(*offset); + // stroke-dasharray + optional str = get_opt_attr(sym,"stroke-dasharray"); + if (str) + { + tokenizer<> tok (*str); + std::vector dash_array; + tokenizer<>::iterator itr = tok.begin(); + for (; itr != tok.end(); ++itr) + { + try + { + double f = boost::lexical_cast(*itr); + dash_array.push_back(f); + } + catch ( boost::bad_lexical_cast &) + { + 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) + { + dash_array.push_back(dash_array[i]); + } + } + std::vector::const_iterator pos = dash_array.begin(); + while (pos != dash_array.end()) + { + strk.add_dash(*pos,*(pos + 1)); + pos +=2; + } + } + } rule.append(line_symbolizer(strk)); } catch (const config_error & ex) @@ -1353,7 +1324,7 @@ namespace mapnik } } - + void map_parser::parse_polygon_symbolizer( rule_type & rule, ptree const & sym ) { try diff --git a/src/save_map.cpp b/src/save_map.cpp index 2130f688b..e8d490a44 100644 --- a/src/save_map.cpp +++ b/src/save_map.cpp @@ -41,652 +41,656 @@ namespace mapnik { - using boost::property_tree::ptree; - using boost::optional; - - void serialize_raster_colorizer(ptree & sym_node, - raster_colorizer_ptr const& colorizer, - bool explicit_defaults) - { - ptree & col_node = sym_node.push_back( - ptree::value_type("RasterColorizer", ptree() ))->second; - - unsigned i; - color_bands const &cb = colorizer->get_color_bands(); - for (i=0; isecond; - set_attr(band_node, "value", cb[i].get_value()); - set_attr(band_node, "midpoints", cb[i].get_midpoints()); - optional c = cb[i].get_color(); - if (c) set_attr(band_node, "color", * c); - } - } - - } - - class serialize_symbolizer : public boost::static_visitor<> - { - public: - serialize_symbolizer( ptree & r , bool explicit_defaults): - rule_(r), - explicit_defaults_(explicit_defaults) {} - - void operator () ( const point_symbolizer & sym ) - { - ptree & sym_node = rule_.push_back( - ptree::value_type("PointSymbolizer", ptree()))->second; - - add_image_attributes( sym_node, sym ); - - 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() ); - } - } - - void operator () ( const line_symbolizer & sym ) - { - ptree & sym_node = rule_.push_back( - ptree::value_type("LineSymbolizer", ptree()))->second; - const stroke & strk = sym.get_stroke(); - stroke dfl = stroke(); - - if ( strk.get_color() != dfl.get_color() || explicit_defaults_ ) - { - set_css( sym_node, "stroke", strk.get_color() ); - } - if ( strk.get_width() != dfl.get_width() || explicit_defaults_ ) - { - set_css( sym_node, "stroke-width", strk.get_width() ); - } - if ( strk.get_opacity() != dfl.get_opacity() || explicit_defaults_ ) - { - set_css( sym_node, "stroke-opacity", strk.get_opacity() ); - } - if ( strk.get_line_join() != dfl.get_line_join() || explicit_defaults_ ) - { - set_css( sym_node, "stroke-linejoin", strk.get_line_join() ); - } - if ( strk.get_line_cap() != dfl.get_line_cap() || explicit_defaults_ ) - { - set_css( sym_node, "stroke-linecap", strk.get_line_cap() ); - } - if ( ! strk.get_dash_array().empty() ) - { - std::ostringstream os; - const dash_array & dashes = strk.get_dash_array(); - for (unsigned i = 0; i < dashes.size(); ++i) { - os << dashes[i].first << ", " << dashes[i].second; - if ( i + 1 < dashes.size() ) os << ", "; - } - set_css( sym_node, "stroke-dasharray", os.str() ); - } - } - - void operator () ( const line_pattern_symbolizer & sym ) - { - ptree & sym_node = rule_.push_back( - ptree::value_type("LinePatternSymbolizer", - ptree()))->second; - - add_image_attributes( sym_node, sym ); - } - - void operator () ( const polygon_symbolizer & sym ) - { - ptree & sym_node = rule_.push_back( - ptree::value_type("PolygonSymbolizer", ptree()))->second; - polygon_symbolizer dfl; - - if ( sym.get_fill() != dfl.get_fill() || explicit_defaults_ ) - { - set_css( sym_node, "fill", sym.get_fill() ); - } - if ( sym.get_opacity() != dfl.get_opacity() || explicit_defaults_ ) - { - set_css( sym_node, "fill-opacity", sym.get_opacity() ); - } - if ( sym.get_gamma() != dfl.get_gamma() || explicit_defaults_ ) - { - set_css( sym_node, "gamma", sym.get_gamma() ); - } - } - - void operator () ( const polygon_pattern_symbolizer & sym ) - { - ptree & sym_node = rule_.push_back( - ptree::value_type("PolygonPatternSymbolizer", - ptree()))->second; - - add_image_attributes( sym_node, sym ); - } - - void operator () ( const raster_symbolizer & sym ) - { - 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_css( sym_node, "mode", sym.get_mode() ); - } - if ( sym.get_scaling() != dfl.get_scaling() || explicit_defaults_ ) - { - set_css( sym_node, "scaling", sym.get_scaling() ); - } - if ( sym.get_opacity() != dfl.get_opacity() || explicit_defaults_ ) - { - set_css( sym_node, "opacity", sym.get_opacity() ); - } - if (sym.get_colorizer()) { - serialize_raster_colorizer(sym_node, sym.get_colorizer(), - explicit_defaults_); - } - - } - - void operator () ( const shield_symbolizer & sym ) - { - ptree & sym_node = rule_.push_back( - ptree::value_type("ShieldSymbolizer", - ptree()))->second; - - add_font_attributes( sym_node, sym); - add_image_attributes( sym_node, sym); - - // 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("", "", 0, color(0,0,0), "", ""); - 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() ); - } - */ - } - - void operator () ( const text_symbolizer & sym ) - { - ptree & sym_node = rule_.push_back( - ptree::value_type("TextSymbolizer", - ptree()))->second; - - add_font_attributes( sym_node, sym); - - } - - void operator () ( const building_symbolizer & sym ) - { - ptree & sym_node = rule_.push_back( - ptree::value_type("BuildingSymbolizer", ptree()))->second; - building_symbolizer dfl; - - if ( sym.get_fill() != dfl.get_fill() || explicit_defaults_ ) - { - set_css( sym_node, "fill", sym.get_fill() ); - } - if ( sym.get_opacity() != dfl.get_opacity() || explicit_defaults_ ) - { - set_css( sym_node, "fill-opacity", sym.get_opacity() ); - } - if ( sym.height() != dfl.height() || explicit_defaults_ ) - { - set_css( sym_node, "height", sym.height() ); - } - } - - void operator () ( markers_symbolizer const& ) - { - // FIXME!!!!! - } - - void operator () ( glyph_symbolizer const& sym) - { - ptree &node = rule_.push_back( - ptree::value_type("GlyphSymbolizer", ptree()) - )->second; - - // 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_); - } - - // allow_overlap - set_attr( node, "allow_overlap", sym.get_allow_overlap() ); - - // avoid_edges - set_attr( node, "avoid_edges", sym.get_avoid_edges() ); - - // displacement - position displacement = sym.get_displacement(); - set_attr( node, "dx", displacement.get<0>() ); - set_attr( node, "dy", displacement.get<1>() ); - - // halo fill & radius - set_attr( node, "halo_fill", sym.get_halo_fill() ); - set_attr( node, "halo_radius", sym.get_halo_radius() ); - - // angle_mode - set_attr( node, "angle_mode", sym.get_angle_mode() ); - - } - - private: - serialize_symbolizer(); - void add_image_attributes(ptree & node, const symbolizer_with_image & sym) - { - const std::string & filename = path_processor_type::to_string( *sym.get_filename()); - if ( ! filename.empty() ) { - set_attr( node, "file", filename ); - } - } - void add_font_attributes(ptree & node, const text_symbolizer & sym) - { - 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(), "", - 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()) ); - } - if (sym.get_text_convert() != dfl.get_text_convert() || explicit_defaults_ ) - { - set_attr( node, "text_convert", sym.get_text_convert() ); - } - 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() ); - } - 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() ); - } - if (sym.get_opacity() != dfl.get_opacity() || explicit_defaults_ ) - { - set_attr( node, "opacity", sym.get_opacity() ); - } - 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() ); - } - } - 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( - ptree::value_type("Rule", ptree() ))->second; - - rule_type dfl; - if ( rule.get_name() != dfl.get_name() ) - { - set_attr(rule_node, "name", rule.get_name()); - } - if ( rule.get_title() != dfl.get_title() ) - { - set_attr(rule_node, "title", rule.get_title()); - } - - if ( rule.has_else_filter() ) - { - rule_node.push_back( ptree::value_type( - "ElseFilter", ptree())); - } - else - { - // filters 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()); - - if ( filter != default_filter) - { - rule_node.push_back( ptree::value_type( - "Filter", ptree()))->second.put_value( filter ); - } - } - - if (rule.get_min_scale() != dfl.get_min_scale() ) - { - ptree & min_scale = rule_node.push_back( ptree::value_type( - "MinScaleDenominator", ptree()))->second; - min_scale.put_value( rule.get_min_scale() ); - } - - if (rule.get_max_scale() != dfl.get_max_scale() ) - { - ptree & max_scale = rule_node.push_back( ptree::value_type( - "MaxScaleDenominator", ptree()))->second; - max_scale.put_value( rule.get_max_scale() ); - } - - 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( - ptree::value_type("Style", ptree()))->second; - - set_attr(style_node, "name", name); - - rules::const_iterator it = style.get_rules().begin(); - rules::const_iterator end = style.get_rules().end(); - for (; it != end; ++it) - { - serialize_rule( style_node, * it , explicit_defaults); - } - - } - - 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( - ptree::value_type("FontSet", ptree()))->second; - - set_attr(fontset_node, "name", name); - - std::vector::const_iterator it = fontset.get_face_names().begin(); - std::vector::const_iterator end = fontset.get_face_names().end(); - for (; it != end; ++it) - { - ptree & font_node = fontset_node.push_back( - ptree::value_type("Font", ptree()))->second; - set_attr(font_node, "face_name", *it); - } - - } - - void serialize_datasource( ptree & layer_node, datasource_ptr datasource) - { - ptree & datasource_node = layer_node.push_back( - ptree::value_type("Datasource", ptree()))->second; - - parameters::const_iterator it = datasource->params().begin(); - parameters::const_iterator end = datasource->params().end(); - for (; it != end; ++it) - { - boost::property_tree::ptree & param_node = datasource_node.push_back( - boost::property_tree::ptree::value_type("Parameter", - boost::property_tree::ptree()))->second; - param_node.put(".name", it->first ); - param_node.put_value( it->second ); - - } - } - - void serialize_layer( ptree & map_node, const layer & layer, bool explicit_defaults ) - { - ptree & layer_node = map_node.push_back( - ptree::value_type("Layer", ptree()))->second; - if ( layer.name() != "" ) - { - set_attr( layer_node, "name", layer.name() ); - } - - if ( layer.abstract() != "" ) - { - set_attr( layer_node, "abstract", layer.abstract() ); - } - - if ( layer.title() != "" ) - { - set_attr( layer_node, "title", layer.title() ); - } - - if ( layer.srs() != "" ) - { - set_attr( layer_node, "srs", layer.srs() ); - } - - if ( !layer.isActive() || explicit_defaults ) - { - set_attr/**/( layer_node, "status", layer.isActive() ); - } - - if ( layer.clear_label_cache() || explicit_defaults ) - { - set_attr/**/( layer_node, "clear_label_cache", layer.clear_label_cache() ); - } - - if ( layer.getMinZoom() ) - { - set_attr( layer_node, "minzoom", layer.getMinZoom() ); - } - - if ( layer.getMaxZoom() != std::numeric_limits::max() ) - { - set_attr( layer_node, "maxzoom", layer.getMaxZoom() ); - } - - if ( layer.isQueryable() || explicit_defaults ) - { - set_attr( layer_node, "queryable", layer.isQueryable() ); - } - - std::vector const& style_names = layer.styles(); - for (unsigned i = 0; i < style_names.size(); ++i) - { - boost::property_tree::ptree & style_node = layer_node.push_back( - boost::property_tree::ptree::value_type("StyleName", - boost::property_tree::ptree()))->second; - style_node.put_value( style_names[i] ); - } - - datasource_ptr datasource = layer.datasource(); - if ( datasource ) - { - serialize_datasource( layer_node, datasource ); - } - } - - void serialize_map(ptree & pt, Map const & map, bool explicit_defaults) - { - - ptree & map_node = pt.push_back(ptree::value_type("Map", ptree() ))->second; - - set_attr( map_node, "srs", map.srs() ); - - optional c = map.background(); - if ( c ) - { - set_attr( map_node, "bgcolor", * c ); - } - - unsigned buffer_size = map.buffer_size(); - if ( buffer_size || explicit_defaults) - { - set_attr( map_node, "buffer_size", buffer_size ); - } - - { - 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); - } - } - - Map::const_style_iterator it = map.styles().begin(); - Map::const_style_iterator end = map.styles().end(); - for (; it != end; ++it) - { - serialize_style( map_node, it, explicit_defaults); - } - - std::vector const & layers = map.layers(); - for (unsigned i = 0; i < layers.size(); ++i ) - { - serialize_layer( map_node, layers[i], explicit_defaults ); - } - } - - 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(); +using boost::property_tree::ptree; +using boost::optional; + +void serialize_raster_colorizer(ptree & sym_node, + raster_colorizer_ptr const& colorizer, + bool explicit_defaults) +{ + ptree & col_node = sym_node.push_back( + ptree::value_type("RasterColorizer", ptree() ))->second; + + unsigned i; + color_bands const &cb = colorizer->get_color_bands(); + for (i=0; isecond; + set_attr(band_node, "value", cb[i].get_value()); + set_attr(band_node, "midpoints", cb[i].get_midpoints()); + optional c = cb[i].get_color(); + if (c) set_attr(band_node, "color", * c); + } } } + +class serialize_symbolizer : public boost::static_visitor<> +{ +public: + serialize_symbolizer( ptree & r , bool explicit_defaults): + rule_(r), + explicit_defaults_(explicit_defaults) {} + + void operator () ( const point_symbolizer & sym ) + { + ptree & sym_node = rule_.push_back( + ptree::value_type("PointSymbolizer", ptree()))->second; + + add_image_attributes( sym_node, sym ); + + 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() ); + } + } + + void operator () ( const line_symbolizer & sym ) + { + ptree & sym_node = rule_.push_back( + ptree::value_type("LineSymbolizer", ptree()))->second; + const stroke & strk = sym.get_stroke(); + stroke dfl = stroke(); + + if ( strk.get_color() != dfl.get_color() || explicit_defaults_ ) + { + set_css( sym_node, "stroke", strk.get_color() ); + } + if ( strk.get_width() != dfl.get_width() || explicit_defaults_ ) + { + set_css( sym_node, "stroke-width", strk.get_width() ); + } + if ( strk.get_opacity() != dfl.get_opacity() || explicit_defaults_ ) + { + set_css( sym_node, "stroke-opacity", strk.get_opacity() ); + } + if ( strk.get_line_join() != dfl.get_line_join() || explicit_defaults_ ) + { + set_css( sym_node, "stroke-linejoin", strk.get_line_join() ); + } + if ( strk.get_line_cap() != dfl.get_line_cap() || explicit_defaults_ ) + { + set_css( sym_node, "stroke-linecap", strk.get_line_cap() ); + } + if ( ! strk.get_dash_array().empty() ) + { + std::ostringstream os; + const dash_array & dashes = strk.get_dash_array(); + for (unsigned i = 0; i < dashes.size(); ++i) { + os << dashes[i].first << ", " << dashes[i].second; + if ( i + 1 < dashes.size() ) os << ", "; + } + set_css( sym_node, "stroke-dasharray", os.str() ); + } + if ( strk.dash_offset() != dfl.dash_offset() || explicit_defaults_ ) + { + set_css( sym_node, "stroke-dashoffset", strk.dash_offset()); + } + } + + void operator () ( const line_pattern_symbolizer & sym ) + { + ptree & sym_node = rule_.push_back( + ptree::value_type("LinePatternSymbolizer", + ptree()))->second; + + add_image_attributes( sym_node, sym ); + } + + void operator () ( const polygon_symbolizer & sym ) + { + ptree & sym_node = rule_.push_back( + ptree::value_type("PolygonSymbolizer", ptree()))->second; + polygon_symbolizer dfl; + + if ( sym.get_fill() != dfl.get_fill() || explicit_defaults_ ) + { + set_css( sym_node, "fill", sym.get_fill() ); + } + if ( sym.get_opacity() != dfl.get_opacity() || explicit_defaults_ ) + { + set_css( sym_node, "fill-opacity", sym.get_opacity() ); + } + if ( sym.get_gamma() != dfl.get_gamma() || explicit_defaults_ ) + { + set_css( sym_node, "gamma", sym.get_gamma() ); + } + } + + void operator () ( const polygon_pattern_symbolizer & sym ) + { + ptree & sym_node = rule_.push_back( + ptree::value_type("PolygonPatternSymbolizer", + ptree()))->second; + + add_image_attributes( sym_node, sym ); + } + + void operator () ( const raster_symbolizer & sym ) + { + 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_css( sym_node, "mode", sym.get_mode() ); + } + if ( sym.get_scaling() != dfl.get_scaling() || explicit_defaults_ ) + { + set_css( sym_node, "scaling", sym.get_scaling() ); + } + if ( sym.get_opacity() != dfl.get_opacity() || explicit_defaults_ ) + { + set_css( sym_node, "opacity", sym.get_opacity() ); + } + if (sym.get_colorizer()) { + serialize_raster_colorizer(sym_node, sym.get_colorizer(), + explicit_defaults_); + } + + } + + void operator () ( const shield_symbolizer & sym ) + { + ptree & sym_node = rule_.push_back( + ptree::value_type("ShieldSymbolizer", + ptree()))->second; + + add_font_attributes( sym_node, sym); + add_image_attributes( sym_node, sym); + + // 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("", "", 0, color(0,0,0), "", ""); + 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() ); + } + */ + } + + void operator () ( const text_symbolizer & sym ) + { + ptree & sym_node = rule_.push_back( + ptree::value_type("TextSymbolizer", + ptree()))->second; + + add_font_attributes( sym_node, sym); + + } + + void operator () ( const building_symbolizer & sym ) + { + ptree & sym_node = rule_.push_back( + ptree::value_type("BuildingSymbolizer", ptree()))->second; + building_symbolizer dfl; + + if ( sym.get_fill() != dfl.get_fill() || explicit_defaults_ ) + { + set_css( sym_node, "fill", sym.get_fill() ); + } + if ( sym.get_opacity() != dfl.get_opacity() || explicit_defaults_ ) + { + set_css( sym_node, "fill-opacity", sym.get_opacity() ); + } + if ( sym.height() != dfl.height() || explicit_defaults_ ) + { + set_css( sym_node, "height", sym.height() ); + } + } + + void operator () ( markers_symbolizer const& ) + { + // FIXME!!!!! + } + + void operator () ( glyph_symbolizer const& sym) + { + ptree &node = rule_.push_back( + ptree::value_type("GlyphSymbolizer", ptree()) + )->second; + + // 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_); + } + + // allow_overlap + set_attr( node, "allow_overlap", sym.get_allow_overlap() ); + + // avoid_edges + set_attr( node, "avoid_edges", sym.get_avoid_edges() ); + + // displacement + position displacement = sym.get_displacement(); + set_attr( node, "dx", displacement.get<0>() ); + set_attr( node, "dy", displacement.get<1>() ); + + // halo fill & radius + set_attr( node, "halo_fill", sym.get_halo_fill() ); + set_attr( node, "halo_radius", sym.get_halo_radius() ); + + // angle_mode + set_attr( node, "angle_mode", sym.get_angle_mode() ); + + } + +private: + serialize_symbolizer(); + void add_image_attributes(ptree & node, const symbolizer_with_image & sym) + { + const std::string & filename = path_processor_type::to_string( *sym.get_filename()); + if ( ! filename.empty() ) { + set_attr( node, "file", filename ); + } + } + void add_font_attributes(ptree & node, const text_symbolizer & sym) + { + 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(), "", + 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()) ); + } + if (sym.get_text_convert() != dfl.get_text_convert() || explicit_defaults_ ) + { + set_attr( node, "text_convert", sym.get_text_convert() ); + } + 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() ); + } + 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() ); + } + if (sym.get_opacity() != dfl.get_opacity() || explicit_defaults_ ) + { + set_attr( node, "opacity", sym.get_opacity() ); + } + 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() ); + } + } + 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( + ptree::value_type("Rule", ptree() ))->second; + + rule_type dfl; + if ( rule.get_name() != dfl.get_name() ) + { + set_attr(rule_node, "name", rule.get_name()); + } + if ( rule.get_title() != dfl.get_title() ) + { + set_attr(rule_node, "title", rule.get_title()); + } + + if ( rule.has_else_filter() ) + { + rule_node.push_back( ptree::value_type( + "ElseFilter", ptree())); + } + else + { + // filters 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()); + + if ( filter != default_filter) + { + rule_node.push_back( ptree::value_type( + "Filter", ptree()))->second.put_value( filter ); + } + } + + if (rule.get_min_scale() != dfl.get_min_scale() ) + { + ptree & min_scale = rule_node.push_back( ptree::value_type( + "MinScaleDenominator", ptree()))->second; + min_scale.put_value( rule.get_min_scale() ); + } + + if (rule.get_max_scale() != dfl.get_max_scale() ) + { + ptree & max_scale = rule_node.push_back( ptree::value_type( + "MaxScaleDenominator", ptree()))->second; + max_scale.put_value( rule.get_max_scale() ); + } + + 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( + ptree::value_type("Style", ptree()))->second; + + set_attr(style_node, "name", name); + + rules::const_iterator it = style.get_rules().begin(); + rules::const_iterator end = style.get_rules().end(); + for (; it != end; ++it) + { + serialize_rule( style_node, * it , explicit_defaults); + } + +} + +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( + ptree::value_type("FontSet", ptree()))->second; + + set_attr(fontset_node, "name", name); + + std::vector::const_iterator it = fontset.get_face_names().begin(); + std::vector::const_iterator end = fontset.get_face_names().end(); + for (; it != end; ++it) + { + ptree & font_node = fontset_node.push_back( + ptree::value_type("Font", ptree()))->second; + set_attr(font_node, "face_name", *it); + } + +} + +void serialize_datasource( ptree & layer_node, datasource_ptr datasource) +{ + ptree & datasource_node = layer_node.push_back( + ptree::value_type("Datasource", ptree()))->second; + + parameters::const_iterator it = datasource->params().begin(); + parameters::const_iterator end = datasource->params().end(); + for (; it != end; ++it) + { + boost::property_tree::ptree & param_node = datasource_node.push_back( + boost::property_tree::ptree::value_type("Parameter", + boost::property_tree::ptree()))->second; + param_node.put(".name", it->first ); + param_node.put_value( it->second ); + + } +} + +void serialize_layer( ptree & map_node, const layer & layer, bool explicit_defaults ) +{ + ptree & layer_node = map_node.push_back( + ptree::value_type("Layer", ptree()))->second; + if ( layer.name() != "" ) + { + set_attr( layer_node, "name", layer.name() ); + } + + if ( layer.abstract() != "" ) + { + set_attr( layer_node, "abstract", layer.abstract() ); + } + + if ( layer.title() != "" ) + { + set_attr( layer_node, "title", layer.title() ); + } + + if ( layer.srs() != "" ) + { + set_attr( layer_node, "srs", layer.srs() ); + } + + if ( !layer.isActive() || explicit_defaults ) + { + set_attr/**/( layer_node, "status", layer.isActive() ); + } + + if ( layer.clear_label_cache() || explicit_defaults ) + { + set_attr/**/( layer_node, "clear_label_cache", layer.clear_label_cache() ); + } + + if ( layer.getMinZoom() ) + { + set_attr( layer_node, "minzoom", layer.getMinZoom() ); + } + + if ( layer.getMaxZoom() != std::numeric_limits::max() ) + { + set_attr( layer_node, "maxzoom", layer.getMaxZoom() ); + } + + if ( layer.isQueryable() || explicit_defaults ) + { + set_attr( layer_node, "queryable", layer.isQueryable() ); + } + + std::vector const& style_names = layer.styles(); + for (unsigned i = 0; i < style_names.size(); ++i) + { + boost::property_tree::ptree & style_node = layer_node.push_back( + boost::property_tree::ptree::value_type("StyleName", + boost::property_tree::ptree()))->second; + style_node.put_value( style_names[i] ); + } + + datasource_ptr datasource = layer.datasource(); + if ( datasource ) + { + serialize_datasource( layer_node, datasource ); + } +} + +void serialize_map(ptree & pt, Map const & map, bool explicit_defaults) +{ + + ptree & map_node = pt.push_back(ptree::value_type("Map", ptree() ))->second; + + set_attr( map_node, "srs", map.srs() ); + + optional c = map.background(); + if ( c ) + { + set_attr( map_node, "bgcolor", * c ); + } + + unsigned buffer_size = map.buffer_size(); + if ( buffer_size || explicit_defaults) + { + set_attr( map_node, "buffer_size", buffer_size ); + } + + { + 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); + } + } + + Map::const_style_iterator it = map.styles().begin(); + Map::const_style_iterator end = map.styles().end(); + for (; it != end; ++it) + { + serialize_style( map_node, it, explicit_defaults); + } + + std::vector const & layers = map.layers(); + for (unsigned i = 0; i < layers.size(); ++i ) + { + serialize_layer( map_node, layers[i], explicit_defaults ); + } +} + +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(); +} + +}