From 2f35c71606068562f3e28cb58ba82a63a790a9cb Mon Sep 17 00:00:00 2001 From: artemp Date: Tue, 29 Sep 2015 12:19:19 +0100 Subject: [PATCH] mapnik::quad_tree - add methods required for spatial_index construction and serialization remove utils/shapeindex/quadtree.hpp --- include/mapnik/quad_tree.hpp | 167 +++++++++++++++++-- utils/shapeindex/quadtree.hpp | 299 ---------------------------------- 2 files changed, 152 insertions(+), 314 deletions(-) delete mode 100644 utils/shapeindex/quadtree.hpp diff --git a/include/mapnik/quad_tree.hpp b/include/mapnik/quad_tree.hpp index d46faa28c..c99d32a5c 100644 --- a/include/mapnik/quad_tree.hpp +++ b/include/mapnik/quad_tree.hpp @@ -36,14 +36,14 @@ namespace mapnik template class quad_tree : util::noncopyable { + using value_type = T; struct node { - using value_t = T; - using cont_t = std::vector; - using iterator = typename cont_t::iterator; - using const_iterator = typename cont_t::const_iterator; + using cont_type = std::vector; + using iterator = typename cont_type::iterator; + using const_iterator = typename cont_type::const_iterator; box2d extent_; - cont_t cont_; + cont_type cont_; node * children_[4]; explicit node(box2d const& ext) @@ -76,18 +76,28 @@ class quad_tree : util::noncopyable { return cont_.end(); } + + int num_subnodes() const + { + int count = 0; + for (int i = 0; i < 4; ++i) + { + if (children_[i]) ++count; + } + return count; + } ~node () {} }; - using nodes_t = std::vector >; - using cont_t = typename node::cont_t; - using node_data_iterator = typename cont_t::iterator; + using nodes_type = std::vector >; + using cont_type = typename node::cont_type; + using node_data_iterator = typename cont_type::iterator; public: - using iterator = typename nodes_t::iterator; - using const_iterator = typename nodes_t::const_iterator; - using result_t = typename std::vector >; - using query_iterator = typename result_t::iterator; + using iterator = typename nodes_type::iterator; + using const_iterator = typename nodes_type::const_iterator; + using result_type = typename std::vector >; + using query_iterator = typename result_type::iterator; explicit quad_tree(box2d const& ext, unsigned int max_depth = 8, @@ -143,9 +153,39 @@ public: return root_->extent_; } + int count() const + { + return count_nodes(root_); + } + + int count_items() const + { + int count = 0; + count_items(root_, count); + return count; + } + void trim() + { + trim_tree(root_); + } + + template + void write(OutputStream & out) + { + char header[16]; + std::memset(header,0,16); + header[0]='m'; + header[1]='a'; + header[2]='p'; + header[3]='n'; + header[4]='i'; + header[5]='k'; + out.write(header,16); + write_node(out,root_); + } private: - void query_node(box2d const& box, result_t & result, node * node_) const + void query_node(box2d const& box, result_type & result, node * node_) const { if (node_) { @@ -208,10 +248,107 @@ private: ext[3]=box2d(hix - width * ratio_,hiy - height*ratio_,hix,hiy); } + void trim_tree(node * n) + { + if (n) + { + for (int i = 0; i < 4; ++i) + { + trim_tree(n->children_[i]); + } + if (n->num_subnodes() == 1 && n->cont_.size() == 0) + { + for (int i = 0; i < 4; ++i) + { + if (n->children_[i]) + { + n = n->children_[i]; + break; + } + } + } + } + + } + + int count_nodes(node const* n) const + { + if (!n) return 0; + else + { + int count = 1; + for (int i = 0; i < 4; ++i) + { + count += count_nodes(n->children_[i]); + } + return count; + } + } + + void count_items(node const* n,int& count) const + { + if (n) + { + count += n->cont_.size(); + for (int i = 0; i < 4; ++i) + { + count_items(n->children_[i],count); + } + } + } + + int subnode_offset(node const* n) const + { + int offset = 0; + for (int i = 0; i < 4; i++) + { + if (n->children_[i]) + { + offset +=sizeof(box2d) + (n->children_[i]->cont_.size() * sizeof(value_type)) + 3 * sizeof(int); + offset +=subnode_offset(n->children_[i]); + } + } + return offset; + } + + template + void write_node(OutputStream & out, node const* n) const + { + if (n) + { + int offset=subnode_offset(n); + int shape_count=n->cont_.size(); + int recsize=sizeof(box2d) + 3 * sizeof(int) + shape_count * sizeof(value_type); + std::unique_ptr node_record(new char[recsize]); + std::memset(node_record.get(), 0, recsize); + std::memcpy(node_record.get(), &offset, 4); + std::memcpy(node_record.get() + 4, &n->extent_, sizeof(box2d)); + std::memcpy(node_record.get() + 36, &shape_count, 4); + for (int i=0; i < shape_count; ++i) + { + memcpy(node_record.get() + 40 + i * sizeof(value_type), &(n->cont_[i]),sizeof(value_type)); + } + int num_subnodes=0; + for (int i = 0; i < 4; ++i) + { + if (n->children_[i]) + { + ++num_subnodes; + } + } + std::memcpy(node_record.get() + 40 + shape_count * sizeof(value_type),&num_subnodes,4); + out.write(node_record.get(),recsize); + for (int i = 0; i < 4; ++i) + { + write_node(out, n->children_[i]); + } + } + } + const unsigned int max_depth_; const double ratio_; - result_t query_result_; - nodes_t nodes_; + result_type query_result_; + nodes_type nodes_; node * root_; }; diff --git a/utils/shapeindex/quadtree.hpp b/utils/shapeindex/quadtree.hpp deleted file mode 100644 index 46a283c02..000000000 --- a/utils/shapeindex/quadtree.hpp +++ /dev/null @@ -1,299 +0,0 @@ -/***************************************************************************** - * - * This file is part of Mapnik (c++ mapping toolkit) - * - * Copyright (C) 2015 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 - * - *****************************************************************************/ - -#ifndef QUADTREE_HPP -#define QUADTREE_HPP -// stl -#include -#include -#include -#include -#include -// mapnik -#include - -using mapnik::box2d; -using mapnik::coord2d; - -template -struct quadtree_node -{ - using value_type = T; - box2d ext_; - std::vector data_; - quadtree_node* children_[4]; - quadtree_node(box2d const& ext) - : ext_(ext),data_() - { - std::memset(children_, 0, sizeof(quadtree_node*)*4); - } - - ~quadtree_node() - { - for (int i=0;i<4;++i) - { - if (children_[i]) - { - delete children_[i],children_[i]=0; - } - } - } - - int num_subnodes() const - { - int count=0; - for (int i=0;i<4;++i) - { - if (children_[i]) - { - ++count; - } - } - return count; - } -}; - -template -class quadtree -{ - using value_type = T; -private: - quadtree_node* root_; - const int maxdepth_; - const double ratio_; -public: - - quadtree(box2d const& extent, int maxdepth, double ratio) - : root_(new quadtree_node(extent)), - maxdepth_(maxdepth), - ratio_(ratio) {} - - ~quadtree() - { - if (root_) delete root_; - } - - void insert(value_type const& data,box2d const& item_ext) - { - insert(data,item_ext,root_,maxdepth_); - } - - int count() const - { - return count_nodes(root_); - } - - int count_items() const - { - int count=0; - count_items(root_,count); - return count; - } - - void print() const - { - print(root_); - } - - void trim() - { - trim_tree(root_); - } - - void write(std::ostream& out) - { - char header[16]; - std::memset(header,0,16); - header[0]='m'; - header[1]='a'; - header[2]='p'; - header[3]='n'; - header[4]='i'; - header[5]='k'; - out.write(header,16); - write_node(out,root_); - } - -private: - - void trim_tree(quadtree_node*& node) - { - if (node) - { - for (int i=0;i<4;++i) - { - trim_tree(node->children_[i]); - } - - if (node->num_subnodes()==1 && node->data_.size()==0) - { - for (int i=0;i<4;++i) - { - if (node->children_[i]) - { - node=node->children_[i]; - break; - } - } - } - } - } - - int count_nodes(quadtree_node const* node) const - { - if (!node) - { - return 0; - } - else - { - int count = 1; - for (int i=0;i<4;++i) - { - count += count_nodes(node->children_[i]); - } - return count; - } - } - - void count_items(quadtree_node const* node,int& count) const - { - if (node) - { - count += node->data_.size(); - for (int i=0;i<4;++i) - { - count_items(node->children_[i],count); - } - } - } - - int subnode_offset(quadtree_node const* node) const - { - int offset=0; - for (int i = 0; i < 4; i++) - { - if (node->children_[i]) - { - offset +=sizeof(box2d)+(node->children_[i]->data_.size()*sizeof(value_type))+3*sizeof(int); - offset +=subnode_offset(node->children_[i]); - } - } - return offset; - } - - void write_node(std::ostream& out, quadtree_node const* node) const - { - if (node) - { - int offset=subnode_offset(node); - int shape_count=node->data_.size(); - int recsize=sizeof(box2d) + 3 * sizeof(int) + shape_count * sizeof(value_type); - std::unique_ptr node_record(new char[recsize]); - std::memset(node_record.get(), 0, recsize); - std::memcpy(node_record.get(), &offset, 4); - std::memcpy(node_record.get() + 4, &node->ext_, sizeof(box2d)); - std::memcpy(node_record.get() + 36, &shape_count, 4); - for (int i=0; i < shape_count; ++i) - { - memcpy(node_record.get() + 40 + i * sizeof(value_type), &(node->data_[i]),sizeof(value_type)); - } - int num_subnodes=0; - for (int i = 0; i < 4; ++i) - { - if (node->children_[i]) - { - ++num_subnodes; - } - } - std::memcpy(node_record.get() + 40 + shape_count * sizeof(value_type),&num_subnodes,4); - out.write(node_record.get(),recsize); - for (int i = 0;i<4;++i) - { - write_node(out,node->children_[i]); - } - } - } - - void print(quadtree_node const* node,int level=0) const - { - if (node) - { - typename std::vector::const_iterator itr=node->data_.begin(); - std::string pad; - for (int i = 0; i < level; ++i) - { - pad+=" "; - } - std::clog<ext_<data_.end()) - { - std::clog<<*itr<<" "; - ++itr; - } - std::clog<children_[i],level+4); - } - } - } - - void insert(value_type const& data,const box2d& item_ext, quadtree_node * node,int maxdepth) - { - if (node && node->ext_.contains(item_ext)) - { - double width=node->ext_.width(); - double height=node->ext_.height(); - - double lox=node->ext_.minx(); - double loy=node->ext_.miny(); - double hix=node->ext_.maxx(); - double hiy=node->ext_.maxy(); - - box2d ext[4]; - ext[0]=box2d(lox,loy,lox + width * ratio_,loy + height * ratio_); - ext[1]=box2d(hix - width * ratio_,loy,hix,loy + height * ratio_); - ext[2]=box2d(lox,hiy - height*ratio_,lox + width * ratio_,hiy); - ext[3]=box2d(hix - width * ratio_,hiy - height*ratio_,hix,hiy); - - if (maxdepth > 1) - { - for (int i = 0; i < 4; ++i) - { - if (ext[i].contains(item_ext)) - { - if (!node->children_[i]) - { - node->children_[i]=new quadtree_node(ext[i]); - } - insert(data,item_ext,node->children_[i],maxdepth-1); - return; - } - } - } - node->data_.push_back(data); - } - } -}; -#endif //QUADTREE_HPP