| 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 | |
|---|
| 23 | //$Id$ |
|---|
| 24 | |
|---|
| 25 | #ifndef FEATURE_STYLE_PROCESSOR_HPP |
|---|
| 26 | #define FEATURE_STYLE_PROCESSOR_HPP |
|---|
| 27 | |
|---|
| 28 | // mapnik |
|---|
| 29 | #include <mapnik/envelope.hpp> |
|---|
| 30 | #include <mapnik/datasource.hpp> |
|---|
| 31 | #include <mapnik/layer.hpp> |
|---|
| 32 | #include <mapnik/map.hpp> |
|---|
| 33 | #include <mapnik/attribute_collector.hpp> |
|---|
| 34 | #include <mapnik/utils.hpp> |
|---|
| 35 | #include <mapnik/projection.hpp> |
|---|
| 36 | #include <mapnik/scale_denominator.hpp> |
|---|
| 37 | // boost |
|---|
| 38 | #include <boost/progress.hpp> |
|---|
| 39 | //stl |
|---|
| 40 | #include <vector> |
|---|
| 41 | |
|---|
| 42 | namespace mapnik |
|---|
| 43 | { |
|---|
| 44 | template <typename Processor> |
|---|
| 45 | class feature_style_processor |
|---|
| 46 | { |
|---|
| 47 | struct symbol_dispatch : public boost::static_visitor<> |
|---|
| 48 | { |
|---|
| 49 | symbol_dispatch (Processor & output, |
|---|
| 50 | Feature const& f, |
|---|
| 51 | proj_transform const& prj_trans) |
|---|
| 52 | : output_(output), |
|---|
| 53 | f_(f), |
|---|
| 54 | prj_trans_(prj_trans) {} |
|---|
| 55 | |
|---|
| 56 | template <typename T> |
|---|
| 57 | void operator () (T const& sym) const |
|---|
| 58 | { |
|---|
| 59 | output_.process(sym,f_,prj_trans_); |
|---|
| 60 | } |
|---|
| 61 | |
|---|
| 62 | Processor & output_; |
|---|
| 63 | Feature const& f_; |
|---|
| 64 | proj_transform const& prj_trans_; |
|---|
| 65 | }; |
|---|
| 66 | public: |
|---|
| 67 | feature_style_processor(Map const& m) |
|---|
| 68 | : m_(m) {} |
|---|
| 69 | |
|---|
| 70 | void apply() |
|---|
| 71 | { |
|---|
| 72 | #ifdef MAPNIK_DEBUG |
|---|
| 73 | boost::progress_timer t(std::clog); |
|---|
| 74 | #endif |
|---|
| 75 | Processor & p = static_cast<Processor&>(*this); |
|---|
| 76 | p.start_map_processing(m_); |
|---|
| 77 | |
|---|
| 78 | try |
|---|
| 79 | { |
|---|
| 80 | projection proj(m_.srs()); // map projection |
|---|
| 81 | double scale_denom = scale_denominator(m_,proj.is_geographic()); |
|---|
| 82 | #ifdef MAPNIK_DEBUG |
|---|
| 83 | std::clog << "scale denominator = " << scale_denom << "\n"; |
|---|
| 84 | #endif |
|---|
| 85 | std::vector<Layer>::const_iterator itr = m_.layers().begin(); |
|---|
| 86 | std::vector<Layer>::const_iterator end = m_.layers().end(); |
|---|
| 87 | |
|---|
| 88 | while (itr != end) |
|---|
| 89 | { |
|---|
| 90 | if (itr->isVisible(scale_denom)) |
|---|
| 91 | { |
|---|
| 92 | apply_to_layer(*itr, p, proj, scale_denom); |
|---|
| 93 | } |
|---|
| 94 | ++itr; |
|---|
| 95 | } |
|---|
| 96 | } |
|---|
| 97 | catch (proj_init_error& ex) |
|---|
| 98 | { |
|---|
| 99 | std::clog << "proj_init_error:" << ex.what() << "\n"; |
|---|
| 100 | } |
|---|
| 101 | |
|---|
| 102 | p.end_map_processing(m_); |
|---|
| 103 | } |
|---|
| 104 | private: |
|---|
| 105 | void apply_to_layer(Layer const& lay, Processor & p, |
|---|
| 106 | projection const& proj0,double scale_denom) |
|---|
| 107 | { |
|---|
| 108 | p.start_layer_processing(lay); |
|---|
| 109 | boost::shared_ptr<datasource> ds=lay.datasource(); |
|---|
| 110 | if (ds) |
|---|
| 111 | { |
|---|
| 112 | Envelope<double> const& ext=m_.getCurrentExtent(); |
|---|
| 113 | Envelope<double> bbox(ext); |
|---|
| 114 | projection proj1(lay.srs()); |
|---|
| 115 | proj_transform prj_trans(proj0,proj1); |
|---|
| 116 | |
|---|
| 117 | if (proj0 != proj1) { |
|---|
| 118 | Envelope<double> layer_ext = lay.envelope(); |
|---|
| 119 | double lx0 = layer_ext.minx(); |
|---|
| 120 | double ly0 = layer_ext.miny(); |
|---|
| 121 | double lz0 = 0.0; |
|---|
| 122 | double lx1 = layer_ext.maxx(); |
|---|
| 123 | double ly1 = layer_ext.maxy(); |
|---|
| 124 | double lz1 = 0.0; |
|---|
| 125 | // back project layers extent into main map projection |
|---|
| 126 | prj_trans.backward(lx0,ly0,lz0); |
|---|
| 127 | prj_trans.backward(lx1,ly1,lz1); |
|---|
| 128 | // clip query bbox |
|---|
| 129 | lx0 = std::max(ext.minx(),lx0); |
|---|
| 130 | ly0 = std::max(ext.miny(),ly0); |
|---|
| 131 | lx1 = std::min(ext.maxx(),lx1); |
|---|
| 132 | ly1 = std::min(ext.maxy(),ly1); |
|---|
| 133 | |
|---|
| 134 | prj_trans.forward(lx0,ly0,lz0); |
|---|
| 135 | prj_trans.forward(lx1,ly1,lz1); |
|---|
| 136 | bbox = Envelope<double>(lx0,ly0,lx1,ly1); |
|---|
| 137 | } |
|---|
| 138 | double resolution = m_.getWidth()/bbox.width(); |
|---|
| 139 | query q(bbox,resolution); //BBOX query |
|---|
| 140 | |
|---|
| 141 | std::vector<std::string> const& style_names = lay.styles(); |
|---|
| 142 | std::vector<std::string>::const_iterator stylesIter = style_names.begin(); |
|---|
| 143 | std::vector<std::string>::const_iterator stylesEnd = style_names.end(); |
|---|
| 144 | for (;stylesIter != stylesEnd; ++stylesIter) |
|---|
| 145 | { |
|---|
| 146 | std::set<std::string> names; |
|---|
| 147 | attribute_collector<Feature> collector(names); |
|---|
| 148 | std::vector<rule_type*> if_rules; |
|---|
| 149 | std::vector<rule_type*> else_rules; |
|---|
| 150 | |
|---|
| 151 | bool active_rules=false; |
|---|
| 152 | |
|---|
| 153 | boost::optional<feature_type_style const&> style=m_.find_style(*stylesIter); |
|---|
| 154 | if (!style) continue; |
|---|
| 155 | |
|---|
| 156 | const std::vector<rule_type>& rules=(*style).get_rules(); |
|---|
| 157 | std::vector<rule_type>::const_iterator ruleIter=rules.begin(); |
|---|
| 158 | std::vector<rule_type>::const_iterator ruleEnd=rules.end(); |
|---|
| 159 | |
|---|
| 160 | for (;ruleIter!=ruleEnd;++ruleIter) |
|---|
| 161 | { |
|---|
| 162 | if (ruleIter->active(scale_denom)) |
|---|
| 163 | { |
|---|
| 164 | active_rules=true; |
|---|
| 165 | ruleIter->accept(collector); |
|---|
| 166 | |
|---|
| 167 | if (ruleIter->has_else_filter()) |
|---|
| 168 | { |
|---|
| 169 | else_rules.push_back(const_cast<rule_type*>(&(*ruleIter))); |
|---|
| 170 | } |
|---|
| 171 | else |
|---|
| 172 | { |
|---|
| 173 | if_rules.push_back(const_cast<rule_type*>(&(*ruleIter))); |
|---|
| 174 | } |
|---|
| 175 | } |
|---|
| 176 | } |
|---|
| 177 | std::set<std::string>::const_iterator namesIter=names.begin(); |
|---|
| 178 | std::set<std::string>::const_iterator namesEnd =names.end(); |
|---|
| 179 | |
|---|
| 180 | // push all property names |
|---|
| 181 | for (;namesIter!=namesEnd;++namesIter) |
|---|
| 182 | { |
|---|
| 183 | q.add_property_name(*namesIter); |
|---|
| 184 | } |
|---|
| 185 | if (active_rules) |
|---|
| 186 | { |
|---|
| 187 | featureset_ptr fs=ds->features(q); |
|---|
| 188 | if (fs) |
|---|
| 189 | { |
|---|
| 190 | feature_ptr feature; |
|---|
| 191 | while ((feature = fs->next())) |
|---|
| 192 | { |
|---|
| 193 | bool do_else=true; |
|---|
| 194 | std::vector<rule_type*>::const_iterator itr=if_rules.begin(); |
|---|
| 195 | std::vector<rule_type*>::const_iterator end=if_rules.end(); |
|---|
| 196 | for (;itr != end;++itr) |
|---|
| 197 | { |
|---|
| 198 | filter_ptr const& filter=(*itr)->get_filter(); |
|---|
| 199 | if (filter->pass(*feature)) |
|---|
| 200 | { |
|---|
| 201 | do_else=false; |
|---|
| 202 | const symbolizers& symbols = (*itr)->get_symbolizers(); |
|---|
| 203 | symbolizers::const_iterator symIter=symbols.begin(); |
|---|
| 204 | symbolizers::const_iterator symEnd =symbols.end(); |
|---|
| 205 | for (;symIter != symEnd;++symIter) |
|---|
| 206 | { |
|---|
| 207 | boost::apply_visitor |
|---|
| 208 | (symbol_dispatch(p,*feature,prj_trans),*symIter); |
|---|
| 209 | } |
|---|
| 210 | } |
|---|
| 211 | } |
|---|
| 212 | if (do_else) |
|---|
| 213 | { |
|---|
| 214 | //else filter |
|---|
| 215 | std::vector<rule_type*>::const_iterator itr= |
|---|
| 216 | else_rules.begin(); |
|---|
| 217 | std::vector<rule_type*>::const_iterator end= |
|---|
| 218 | else_rules.end(); |
|---|
| 219 | for (;itr != end;++itr) |
|---|
| 220 | { |
|---|
| 221 | const symbolizers& symbols = (*itr)->get_symbolizers(); |
|---|
| 222 | symbolizers::const_iterator symIter= symbols.begin(); |
|---|
| 223 | symbolizers::const_iterator symEnd = symbols.end(); |
|---|
| 224 | |
|---|
| 225 | for (;symIter!=symEnd;++symIter) |
|---|
| 226 | { |
|---|
| 227 | boost::apply_visitor |
|---|
| 228 | (symbol_dispatch(p,*feature,prj_trans),*symIter); |
|---|
| 229 | } |
|---|
| 230 | } |
|---|
| 231 | } |
|---|
| 232 | } |
|---|
| 233 | } |
|---|
| 234 | } |
|---|
| 235 | } |
|---|
| 236 | } |
|---|
| 237 | p.end_layer_processing(lay); |
|---|
| 238 | } |
|---|
| 239 | Map const& m_; |
|---|
| 240 | }; |
|---|
| 241 | } |
|---|
| 242 | |
|---|
| 243 | #endif //FEATURE_STYLE_PROCESSOR_HPP |
|---|