root/branches/0.7.1-dev/include/mapnik/octree.hpp @ 1680

Revision 1680, 9.7 kB (checked in by dane, 6 months ago)

apply mapnik-0.7.1.mr.hextree2.diff (slighly modified to accept format='png:key=val' as well as format='png256:key=val' while still maintaining default behavior of just format 'png' or 'png256' - also updated rundemo.py with a few examples

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
24#ifndef _OCTREE_HPP_
25#define _OCTREE_HPP_
26
27// mapnik
28#include <mapnik/global.hpp>
29
30// boost
31#include <boost/utility.hpp>
32
33// stl
34#include <vector>
35#include <iostream>
36#include <deque>
37
38namespace mapnik {
39       
40   typedef boost::uint8_t byte ;
41   struct rgb   
42   {
43         byte r;
44         byte g;
45         byte b;
46         rgb(byte r_, byte g_, byte b_)
47            : r(r_), g(g_), b(b_) {}
48   };
49
50   struct RGBPolicy
51   {
52         const static unsigned MAX_LEVELS = 6;
53         const static unsigned MIN_LEVELS = 2;
54         inline static unsigned index_from_level(unsigned level, rgb const& c)
55         {
56            unsigned shift = 7 - level;
57            return (((c.r >> shift) & 1) << 2) 
58               | (((c.g >> shift) & 1) << 1) 
59               | ((c.b >> shift) & 1);
60         }
61   };
62
63   template <typename T, typename InsertPolicy = RGBPolicy >
64   class octree : private boost::noncopyable
65   {   
66         struct node
67         {
68               node ()
69                  :  reds(0),
70                     greens(0),
71                     blues(0),
72                     count(0),
73                     count_cum(0),
74                     children_count(0),
75                     index(0)
76               {
77                  memset(&children_[0],0,sizeof(children_));
78               }
79
80               ~node ()
81               {
82                  for (unsigned i = 0;i < 8; ++i) {
83                     if (children_[i] != 0) delete children_[i],children_[i]=0;
84                  }
85               }
86
87               bool is_leaf() const { return count == 0; }
88               node * children_[8];
89               boost::uint64_t reds;
90               boost::uint64_t greens;
91               boost::uint64_t blues;
92               unsigned count;
93               double reduce_cost;
94               unsigned count_cum;
95               byte  children_count;
96               byte  index;
97         };
98         struct node_cmp
99         {
100               bool operator() ( const node * lhs,const node* rhs) const
101               {
102                  return lhs->reduce_cost < rhs->reduce_cost;
103               }
104         };
105
106         std::deque<node*> reducible_[InsertPolicy::MAX_LEVELS];
107         unsigned max_colors_;
108         unsigned colors_;
109         unsigned offset_;
110         unsigned leaf_level_;
111         bool has_alfa_;
112
113      public:
114         explicit octree(unsigned max_colors=256)
115            : max_colors_(max_colors),
116              colors_(0),
117              offset_(0),
118              leaf_level_(InsertPolicy::MAX_LEVELS),
119              has_alfa_(false),
120              root_(new node())
121         {}
122
123         ~octree() { delete root_;}
124
125         void setMaxColors(unsigned max_colors)
126         {
127            max_colors_ = max_colors;
128         }
129
130         void setOffset(unsigned offset)
131         {
132            offset_ = offset;
133         }
134
135         unsigned getOffset()
136         {
137            return offset_;
138         }
139
140         void hasAlfa(bool v)
141         {
142            has_alfa_=v;
143         }
144
145         bool hasAlfa()
146         {
147            return has_alfa_;
148         }
149
150         void insert(T const& data)
151         {
152            unsigned level = 0;
153            node * cur_node = root_;
154            while (true) {
155               cur_node->count_cum++;
156               cur_node->reds   += data.r;
157               cur_node->greens += data.g;
158               cur_node->blues  += data.b;
159
160               if ( cur_node->count > 0 || level == leaf_level_)
161               {
162                  cur_node->count  += 1;
163                  if (cur_node->count == 1) ++colors_;
164                  //if (colors_ >= max_colors_ - 1)
165                  //reduce();
166                  break;
167               }
168
169               unsigned idx = InsertPolicy::index_from_level(level,data);
170               if (cur_node->children_[idx] == 0) {
171                  cur_node->children_count++;
172                  cur_node->children_[idx] = new node();
173                  if (level < leaf_level_-1)
174                  {
175                     reducible_[level+1].push_back(cur_node->children_[idx]);
176                  }
177               }
178               cur_node = cur_node->children_[idx];
179               ++level;
180            }
181         }
182
183         int quantize(rgb const& c) const
184         {
185            unsigned level = 0;
186            node * cur_node = root_;
187            while (cur_node)
188            {
189               if (cur_node->children_count == 0) 
190                    return cur_node->index + offset_;
191               unsigned idx = InsertPolicy::index_from_level(level,c);
192               cur_node = cur_node->children_[idx];
193               ++level;
194            }
195            return -1;
196         }
197
198         void create_palette(std::vector<rgb> & palette)
199         {
200            if (has_alfa_)
201            {
202               max_colors_--;
203               palette.push_back(rgb(0,0,0));
204            }
205            reduce();
206            palette.reserve(colors_);
207            create_palette(palette, root_);
208         }
209         
210         void computeCost(node *r)
211         {
212            r->reduce_cost = 0;
213            if (r->children_count==0)
214               return;
215
216            double mean_r = r->reds   / r->count_cum;
217            double mean_g = r->greens / r->count_cum;
218            double mean_b = r->blues  / r->count_cum;
219            for (unsigned idx=0; idx < 8; ++idx) if (r->children_[idx] != 0)
220            {
221               double dr,dg,db;
222               computeCost(r->children_[idx]);
223
224               dr = r->children_[idx]->reds   / r->children_[idx]->count_cum - mean_r;
225               dg = r->children_[idx]->greens / r->children_[idx]->count_cum - mean_g;
226               db = r->children_[idx]->blues  / r->children_[idx]->count_cum - mean_b;
227               
228               r->reduce_cost += r->children_[idx]->reduce_cost;
229               r->reduce_cost += (dr*dr + dg*dg + db*db) * r->children_[idx]->count_cum;
230            }
231         }
232
233         void reduce()
234         {
235            computeCost(root_);
236            reducible_[0].push_back(root_);
237           
238            // sort reducible by reduce_cost
239            for (unsigned i=0;i<InsertPolicy::MAX_LEVELS;++i)
240            {
241               std::sort(reducible_[i].begin(), reducible_[i].end(),node_cmp());
242            }
243            while ( colors_ > max_colors_ && colors_ > 1)
244            {
245               while (leaf_level_ >0  && reducible_[leaf_level_-1].size() == 0)
246               {
247                  --leaf_level_;
248               }
249
250               if (leaf_level_ <= 0) return;
251
252               // select best of all reducible:
253               unsigned red_idx = leaf_level_-1;
254               unsigned bestv = (*reducible_[red_idx].begin())->reduce_cost;
255               for(unsigned i=red_idx; i>=InsertPolicy::MIN_LEVELS; i--) if (!reducible_[i].empty()){
256                   node *nd = *reducible_[i].begin();
257                   unsigned gch = 0;
258                   for(unsigned idx=0; idx<8; idx++){
259                       if (nd->children_[idx])
260                           gch += nd->children_[idx]->children_count;
261                   }
262                   if (gch==0 && nd->reduce_cost < bestv){
263                       bestv = nd->reduce_cost;
264                       red_idx = i;
265                   }
266               }
267
268               typename std::deque<node*>::iterator pos = reducible_[red_idx].begin();
269               node * cur_node = *pos;
270               unsigned num_children = 0;
271               for (unsigned idx=0; idx < 8; ++idx)
272               {
273                  if (cur_node->children_[idx] != 0)
274                  {
275                     cur_node->children_count--;
276                     ++num_children;
277                     cur_node->count  += cur_node->children_[idx]->count;
278                     //todo: case of nonleaf children, if someday sorting by reduce_cost doesn't handle it
279                     delete cur_node->children_[idx], cur_node->children_[idx]=0;
280                  }
281               }
282               
283               reducible_[red_idx].erase(pos);
284               if (num_children > 0 ) 
285               {
286                  colors_ -= (num_children - 1);
287               }
288            }
289         }
290       
291         void create_palette(std::vector<rgb> & palette, node * itr) const
292         {
293            if (itr->count != 0)
294            {
295               unsigned count = itr->count;
296               palette.push_back(rgb(byte(itr->reds/float(count)),
297                                     byte(itr->greens/float(count)),
298                                     byte(itr->blues/float(count))));
299               itr->index = palette.size() - 1;
300            }
301            for (unsigned i=0; i < 8 ;++i)
302            {
303               if (itr->children_[i] != 0) 
304                  create_palette(palette, itr->children_[i]);
305            } 
306         }
307      private: 
308         node * root_;         
309   };
310} // namespace mapnik
311
312#endif /* _OCTREE_HPP_ */
Note: See TracBrowser for help on using the browser.