root/branches/0.7.1-dev/src/save_map.cpp @ 1679

Revision 1679, 22.6 kB (checked in by dane, 6 months ago)

properly serialize the map_buffer when saving map

Line 
1/*****************************************************************************
2 *
3 * This file is part of Mapnik (c++ mapping toolkit)
4 *
5 * Copyright (C) 2006 Artem Pavlenko
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
20 *
21 *****************************************************************************/
22// $Id$
23// mapnik
24#include <mapnik/save_map.hpp>
25#include <mapnik/image_util.hpp>
26#include <mapnik/ptree_helpers.hpp>
27
28// boost
29#include <boost/algorithm/string.hpp>
30#include <boost/lexical_cast.hpp>
31#include <boost/tokenizer.hpp>
32#include <boost/optional.hpp>
33#include <boost/property_tree/ptree.hpp>
34#include <boost/property_tree/xml_parser.hpp>
35
36// stl
37#include <iostream>
38
39namespace mapnik
40{
41    using boost::property_tree::ptree;
42    using boost::optional;
43
44    class serialize_symbolizer : public boost::static_visitor<>
45    {
46        public:
47            serialize_symbolizer( ptree & r , bool explicit_defaults):
48            rule_(r),
49            explicit_defaults_(explicit_defaults) {}
50
51            void operator () ( const  point_symbolizer & sym )
52            {
53                ptree & sym_node = rule_.push_back(
54                        ptree::value_type("PointSymbolizer", ptree()))->second;
55
56                add_image_attributes( sym_node, sym );
57
58                point_symbolizer dfl;
59                if (sym.get_allow_overlap() != dfl.get_allow_overlap() || explicit_defaults_ )
60                {
61                    set_attr( sym_node, "allow_overlap", sym.get_allow_overlap() );
62                }
63                if ( sym.get_opacity() != dfl.get_opacity() || explicit_defaults_ )
64                {
65                    set_attr( sym_node, "opacity", sym.get_opacity() );
66                }
67            }
68
69            void operator () ( const line_symbolizer & sym )
70            {
71                ptree & sym_node = rule_.push_back(
72                        ptree::value_type("LineSymbolizer", ptree()))->second;
73                const stroke & strk = sym.get_stroke();
74                stroke dfl = stroke();
75
76                if ( strk.get_color() != dfl.get_color() || explicit_defaults_ )
77                {
78                    set_css( sym_node, "stroke", strk.get_color() );
79                }
80                if ( strk.get_width() != dfl.get_width() || explicit_defaults_ )
81                {
82                    set_css( sym_node, "stroke-width", strk.get_width() );
83                }
84                if ( strk.get_opacity() != dfl.get_opacity() || explicit_defaults_ )
85                {
86                    set_css( sym_node, "stroke-opacity", strk.get_opacity() );
87                }
88                if ( strk.get_line_join() != dfl.get_line_join() || explicit_defaults_ )
89                {
90                    set_css( sym_node, "stroke-linejoin", strk.get_line_join() );
91                }
92                if ( strk.get_line_cap() != dfl.get_line_cap() || explicit_defaults_ )
93                {
94                    set_css( sym_node, "stroke-linecap", strk.get_line_cap() );
95                }
96                if ( ! strk.get_dash_array().empty() )
97                {
98                    std::ostringstream os;
99                    const dash_array & dashes = strk.get_dash_array();
100                    for (unsigned i = 0; i < dashes.size(); ++i) {
101                        os << dashes[i].first << ", " << dashes[i].second;
102                        if ( i + 1 < dashes.size() ) os << ", ";
103                    }
104                    set_css( sym_node, "stroke-dasharray", os.str() );
105                }
106            }
107
108            void operator () ( const line_pattern_symbolizer & sym )
109            {
110                ptree & sym_node = rule_.push_back(
111                        ptree::value_type("LinePatternSymbolizer",
112                        ptree()))->second;
113
114                add_image_attributes( sym_node, sym );
115            }
116
117            void operator () ( const polygon_symbolizer & sym )
118            {
119                ptree & sym_node = rule_.push_back(
120                        ptree::value_type("PolygonSymbolizer", ptree()))->second;
121                polygon_symbolizer dfl;
122
123                if ( sym.get_fill() != dfl.get_fill() || explicit_defaults_ )
124                {
125                    set_css( sym_node, "fill", sym.get_fill() );
126                }
127                if ( sym.get_opacity() != dfl.get_opacity() || explicit_defaults_ )
128                {
129                    set_css( sym_node, "fill-opacity", sym.get_opacity() );
130                }
131                if ( sym.get_gamma() != dfl.get_gamma() || explicit_defaults_ )
132                {
133                    set_css( sym_node, "gamma", sym.get_gamma() );
134                }
135            }
136
137            void operator () ( const polygon_pattern_symbolizer & sym )
138            {
139                ptree & sym_node = rule_.push_back(
140                        ptree::value_type("PolygonPatternSymbolizer",
141                        ptree()))->second;
142
143                add_image_attributes( sym_node, sym );
144            }
145
146            void operator () ( const raster_symbolizer & sym )
147            {
148                ptree & sym_node = rule_.push_back(
149                        ptree::value_type("RasterSymbolizer", ptree()))->second;
150                raster_symbolizer dfl;
151
152                if ( sym.get_mode() != dfl.get_mode() || explicit_defaults_ )
153                {
154                    set_css( sym_node, "mode", sym.get_mode() );
155                }
156                if ( sym.get_scaling() != dfl.get_scaling() || explicit_defaults_ )
157                {
158                    set_css( sym_node, "scaling", sym.get_scaling() );
159                }
160                if ( sym.get_opacity() != dfl.get_opacity() || explicit_defaults_ )
161                {
162                    set_css( sym_node, "opacity", sym.get_opacity() );
163                }
164            }
165
166            void operator () ( const shield_symbolizer & sym )
167            {
168                ptree & sym_node = rule_.push_back(
169                        ptree::value_type("ShieldSymbolizer",
170                        ptree()))->second;
171
172                add_font_attributes( sym_node, sym);
173                add_image_attributes( sym_node, sym);
174
175                // pseudo-default-construct a shield_symbolizer. It is used
176                // to avoid printing of attributes with default values without
177                // repeating the default values here.
178                // maybe add a real, explicit default-ctor?
179                shield_symbolizer sym_dfl("<no default>", "<no default>", 0, color(0,0,0), "<no default>", "<no default>", 0, 0 );
180                if (sym.get_unlock_image() != sym_dfl.get_unlock_image() || explicit_defaults_ )
181                {
182                    set_attr( sym_node, "unlock_image", sym.get_unlock_image() );
183                }
184                if (sym.get_no_text() != sym_dfl.get_no_text() || explicit_defaults_ )
185                {
186                    set_attr( sym_node, "no_text", sym.get_no_text() );
187                }
188            }
189
190            void operator () ( const text_symbolizer & sym )
191            {
192                ptree & sym_node = rule_.push_back(
193                        ptree::value_type("TextSymbolizer",
194                        ptree()))->second;
195
196                add_font_attributes( sym_node, sym);
197
198            }
199
200            void operator () ( const building_symbolizer & sym )
201            {
202                ptree & sym_node = rule_.push_back(
203                        ptree::value_type("BuildingSymbolizer", ptree()))->second;
204                building_symbolizer dfl;
205
206                if ( sym.get_fill() != dfl.get_fill() || explicit_defaults_ )
207                {
208                    set_css( sym_node, "fill", sym.get_fill() );
209                }
210                if ( sym.get_opacity() != dfl.get_opacity() || explicit_defaults_ )
211                {
212                    set_css( sym_node, "fill-opacity", sym.get_opacity() );
213                }
214                if ( sym.height() != dfl.height() || explicit_defaults_ )
215                {
216                    set_css( sym_node, "height", sym.height() );
217                }
218            }
219
220          void operator () ( markers_symbolizer const& )
221          {
222             // FIXME!!!!!
223          }
224        private:
225            serialize_symbolizer();
226            void add_image_attributes(ptree & node, const symbolizer_with_image & sym)
227            {
228                const std::string & filename = sym.get_filename();
229                if ( ! filename.empty() ) {
230                    set_attr( node, "file", filename );
231                    set_attr( node, "type", guess_type( filename ) );
232
233                    boost::shared_ptr<ImageData32> img = sym.get_image();
234                    if ( img )
235                    {
236                        if ( img->width() > 0)
237                        {
238                            set_attr( node, "width", img->width() );
239                        }
240                        if ( img->height() > 0)
241                        {
242                            set_attr( node, "height", img->height() );
243                        }
244                    }
245
246                }
247            }
248            void add_font_attributes(ptree & node, const text_symbolizer & sym)
249            {
250                const std::string & name = sym.get_name();
251                if ( ! name.empty() ) {
252                    set_attr( node, "name", name );
253                }
254                const std::string & face_name = sym.get_face_name();
255                if ( ! face_name.empty() ) {
256                    set_attr( node, "face_name", face_name );
257                }
258                const std::string & fontset_name = sym.get_fontset().get_name();
259                if ( ! fontset_name.empty() ) {
260                    set_attr( node, "fontset_name", fontset_name );
261                }
262
263                set_attr( node, "size", sym.get_text_size() );
264                set_attr( node, "fill", sym.get_fill() );
265
266                // pseudo-default-construct a text_symbolizer. It is used
267                // to avoid printing ofattributes with default values without
268                // repeating the default values here.
269                // maybe add a real, explicit default-ctor?
270                text_symbolizer dfl("<no default>", "<no default>",
271                                    0, color(0,0,0) );
272
273                position displacement = sym.get_displacement();
274                if ( displacement.get<0>() != dfl.get_displacement().get<0>() || explicit_defaults_ )
275                {
276                    set_attr( node, "dx", displacement.get<0>() );
277                }
278                if ( displacement.get<1>() != dfl.get_displacement().get<1>() || explicit_defaults_ )
279                {
280                    set_attr( node, "dy", displacement.get<1>() );
281                }
282
283                if (sym.get_label_placement() != dfl.get_label_placement() || explicit_defaults_ )
284                {
285                    set_attr( node, "placement", sym.get_label_placement() );
286                }
287
288                if (sym.get_vertical_alignment() != dfl.get_vertical_alignment() || explicit_defaults_ )
289                {
290                    set_attr( node, "vertical_alignment", sym.get_vertical_alignment() );
291                }
292
293                if (sym.get_halo_radius() != dfl.get_halo_radius() || explicit_defaults_ )
294                {
295                    set_attr( node, "halo_radius", sym.get_halo_radius() );
296                }
297                const color & c = sym.get_halo_fill();
298                if ( c != dfl.get_halo_fill() || explicit_defaults_ )
299                {
300                    set_attr( node, "halo_fill", c );
301                }
302                if (sym.get_text_ratio() != dfl.get_text_ratio() || explicit_defaults_ )
303                {
304                    set_attr( node, "text_ratio", sym.get_text_ratio() );
305                }
306                if (sym.get_wrap_width() != dfl.get_wrap_width() || explicit_defaults_ )
307                {
308                    set_attr( node, "wrap_width", sym.get_wrap_width() );
309                }
310                if (sym.get_wrap_before() != dfl.get_wrap_before() || explicit_defaults_ )
311                {
312                    set_attr( node, "wrap_before", sym.get_wrap_before() );
313                }
314                if (sym.get_wrap_char() != dfl.get_wrap_char() || explicit_defaults_ )
315                {
316                    set_attr( node, "wrap_character", std::string(1, sym.get_wrap_char()) );
317                }
318                if (sym.get_text_convert() != dfl.get_text_convert() || explicit_defaults_ )
319                {
320                    set_attr( node, "text_convert", sym.get_text_convert() );
321                }
322                if (sym.get_line_spacing() != dfl.get_line_spacing() || explicit_defaults_ )
323                {
324                    set_attr( node, "line_spacing", sym.get_line_spacing() );
325                }
326                if (sym.get_character_spacing() != dfl.get_character_spacing() || explicit_defaults_ )
327                {
328                    set_attr( node, "character_spacing", sym.get_character_spacing() );
329                }
330                if (sym.get_label_spacing() != dfl.get_label_spacing() || explicit_defaults_ )
331                {
332                    set_attr( node, "spacing", sym.get_label_spacing() );
333                }
334                if (sym.get_minimum_distance() != dfl.get_minimum_distance() || explicit_defaults_ )
335                {
336                    set_attr( node, "min_distance", sym.get_minimum_distance() );
337                }
338                if (sym.get_allow_overlap() != dfl.get_allow_overlap() || explicit_defaults_ )
339                {
340                    set_attr( node, "allow_overlap", sym.get_allow_overlap() );
341                }
342                if (sym.get_avoid_edges() != dfl.get_avoid_edges() || explicit_defaults_ )
343                {
344                    set_attr( node, "avoid_edges", sym.get_avoid_edges() );
345                }
346                if (sym.get_opacity() != dfl.get_opacity() || explicit_defaults_ )
347                {
348                    set_attr( node, "opacity", sym.get_opacity() );
349                }
350                if (sym.get_horizontal_alignment() != dfl.get_horizontal_alignment() || explicit_defaults_ )
351                {
352                    set_attr( node, "horizontal_alignment", sym.get_horizontal_alignment() );
353                }
354                if (sym.get_justify_alignment() != dfl.get_justify_alignment() || explicit_defaults_ )
355                {
356                    set_attr( node, "justify_alignment", sym.get_justify_alignment() );
357                }
358            }
359            ptree & rule_;
360            bool explicit_defaults_;
361    };
362
363    void serialize_rule( ptree & style_node, const rule_type & rule, bool explicit_defaults)
364    {
365        ptree & rule_node = style_node.push_back(
366                ptree::value_type("Rule", ptree() ))->second;
367
368        rule_type dfl;
369        if ( rule.get_name() != dfl.get_name() )
370        {
371            set_attr(rule_node, "name", rule.get_name());
372        }
373        if ( rule.get_title() != dfl.get_title() )
374        {
375            set_attr(rule_node, "title", rule.get_title());
376        }
377
378        if ( rule.has_else_filter() )
379        {
380            rule_node.push_back( ptree::value_type(
381                    "ElseFilter", ptree()));
382        }
383        else
384        {
385            // filters are not comparable, so compare strings for now
386            std::string filter = rule.get_filter()->to_string();
387            std::string default_filter = dfl.get_filter()->to_string();
388            if ( filter != default_filter)
389            {
390                rule_node.push_back( ptree::value_type(
391                            "Filter", ptree()))->second.put_own( filter );
392            }
393        }
394
395        if (rule.get_min_scale() != dfl.get_min_scale() )
396        {
397            ptree & min_scale = rule_node.push_back( ptree::value_type(
398                    "MinScaleDenominator", ptree()))->second;
399            min_scale.put_own( rule.get_min_scale() );
400        }
401
402        if (rule.get_max_scale() != dfl.get_max_scale() )
403        {
404            ptree & max_scale = rule_node.push_back( ptree::value_type(
405                    "MaxScaleDenominator", ptree()))->second;
406            max_scale.put_own( rule.get_max_scale() );
407        }
408
409        symbolizers::const_iterator begin = rule.get_symbolizers().begin();
410        symbolizers::const_iterator end = rule.get_symbolizers().end();
411        serialize_symbolizer serializer( rule_node, explicit_defaults);
412        std::for_each( begin, end , boost::apply_visitor( serializer ));
413    }
414
415    void serialize_style( ptree & map_node, Map::const_style_iterator style_it, bool explicit_defaults )
416    {
417        const feature_type_style & style = style_it->second;
418        const std::string & name = style_it->first;
419
420        ptree & style_node = map_node.push_back(
421                ptree::value_type("Style", ptree()))->second;
422
423        set_attr(style_node, "name", name);
424
425        rules::const_iterator it = style.get_rules().begin();
426        rules::const_iterator end = style.get_rules().end();
427        for (; it != end; ++it)
428        {
429            serialize_rule( style_node, * it , explicit_defaults);
430        }
431
432    }
433
434    void serialize_fontset( ptree & map_node, Map::const_fontset_iterator fontset_it )
435    {
436        const FontSet & fontset = fontset_it->second;
437        const std::string & name = fontset_it->first;
438
439        ptree & fontset_node = map_node.push_back(
440                ptree::value_type("FontSet", ptree()))->second;
441
442        set_attr(fontset_node, "name", name);
443
444        std::vector<std::string>::const_iterator it = fontset.get_face_names().begin();
445        std::vector<std::string>::const_iterator end = fontset.get_face_names().end();
446        for (; it != end; ++it)
447        {
448            ptree & font_node = fontset_node.push_back(
449                    ptree::value_type("Font", ptree()))->second;
450            set_attr(font_node, "face_name", *it);
451        }
452
453    }
454
455    void serialize_datasource( ptree & layer_node, datasource_ptr datasource)
456    {
457        ptree & datasource_node = layer_node.push_back(
458                ptree::value_type("Datasource", ptree()))->second;
459
460        parameters::const_iterator it = datasource->params().begin();
461        parameters::const_iterator end = datasource->params().end();
462        for (; it != end; ++it)
463        {
464            boost::property_tree::ptree & param_node = datasource_node.push_back(
465                    boost::property_tree::ptree::value_type("Parameter",
466                    boost::property_tree::ptree()))->second;
467            param_node.put("<xmlattr>.name", it->first );
468            param_node.put_own( it->second );
469
470        }
471    }
472
473    void serialize_layer( ptree & map_node, const Layer & layer, bool explicit_defaults )
474    {
475        ptree & layer_node = map_node.push_back(
476                ptree::value_type("Layer", ptree()))->second;
477        if ( layer.name() != "" )
478        {
479            set_attr( layer_node, "name", layer.name() );
480        }
481
482        if ( layer.abstract() != "" )
483        {
484            set_attr( layer_node, "abstract", layer.abstract() );
485        }
486
487        if ( layer.title() != "" )
488        {
489            set_attr( layer_node, "title", layer.title() );
490        }
491
492        if ( layer.srs() != "" )
493        {
494            set_attr( layer_node, "srs", layer.srs() );
495        }
496
497        if ( !layer.isActive() || explicit_defaults )
498        {
499            set_attr/*<bool>*/( layer_node, "status", layer.isActive() );
500        }
501       
502        if ( layer.clear_label_cache() || explicit_defaults )
503        {       
504            set_attr/*<bool>*/( layer_node, "clear_label_cache", layer.clear_label_cache() );
505        }
506
507        if ( layer.getMinZoom() )
508        {
509            set_attr( layer_node, "minzoom", layer.getMinZoom() );
510        }
511
512        if ( layer.getMaxZoom() != std::numeric_limits<double>::max() )
513        {
514            set_attr( layer_node, "maxzoom", layer.getMaxZoom() );
515        }
516
517        if ( layer.isQueryable() || explicit_defaults )
518        {
519            set_attr( layer_node, "queryable", layer.isQueryable() );
520        }
521
522        std::vector<std::string> const& style_names = layer.styles();
523        for (unsigned i = 0; i < style_names.size(); ++i)
524        {
525            boost::property_tree::ptree & style_node = layer_node.push_back(
526                    boost::property_tree::ptree::value_type("StyleName",
527                    boost::property_tree::ptree()))->second;
528            style_node.put_own( style_names[i] );
529        }
530
531        datasource_ptr datasource = layer.datasource();
532        if ( datasource )
533        {
534            serialize_datasource( layer_node, datasource );
535        }
536    }
537
538    void serialize_map(ptree & pt, Map const & map, bool explicit_defaults)
539    {
540
541        ptree & map_node = pt.push_back(ptree::value_type("Map", ptree() ))->second;
542
543        set_attr( map_node, "srs", map.srs() );
544
545        optional<color> c = map.background();
546        if ( c )
547        {
548            set_attr( map_node, "bgcolor", * c );
549        }
550
551        unsigned buffer_size = map.buffer_size();
552        if ( buffer_size || explicit_defaults)
553        {
554            set_attr( map_node, "buffer_size", buffer_size ); 
555        }
556
557        {
558            Map::const_fontset_iterator it = map.fontsets().begin();
559            Map::const_fontset_iterator end = map.fontsets().end();
560            for (; it != end; ++it)
561            {
562                serialize_fontset( map_node, it);
563            }
564        }
565
566        Map::const_style_iterator it = map.styles().begin();
567        Map::const_style_iterator end = map.styles().end();
568        for (; it != end; ++it)
569        {
570            serialize_style( map_node, it, explicit_defaults);
571        }
572
573        std::vector<Layer> const & layers = map.layers();
574        for (unsigned i = 0; i < layers.size(); ++i )
575        {
576            serialize_layer( map_node, layers[i], explicit_defaults );
577        }
578    }
579
580    void save_map(Map const & map, std::string const& filename, bool explicit_defaults)
581    {
582        ptree pt;
583        serialize_map(pt,map,explicit_defaults);
584        write_xml(filename,pt);
585    }
586
587    std::string save_map_to_string(Map const & map, bool explicit_defaults)
588    {
589        ptree pt;
590        serialize_map(pt,map,explicit_defaults);
591        std::ostringstream ss;
592        write_xml(ss,pt);
593        return ss.str();
594    }
595
596}
Note: See TracBrowser for help on using the browser.