/* This file is part of Mapnik (c++ mapping toolkit) * Copyright (C) 2005 Artem Pavlenko * * Mapnik is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ //$Id: quadtree.hh 17 2005-03-08 23:58:43Z pavlenko $ #ifndef QUADTREE_HH #define QUADTREE_HH #include "envelope.hpp" #include #include using namespace mapnik; template struct quadtree_node { Envelope ext_; std::vector data_; quadtree_node* children_[4]; quadtree_node(const Envelope& ext) : ext_(ext),data_() { 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 { private: quadtree_node* root_; const int maxdepth_; const double ratio_; public: quadtree(const Envelope& extent,int maxdepth,double ratio) : root_(new quadtree_node(extent)), maxdepth_(maxdepth), ratio_(ratio){} ~quadtree() { if (root_) delete root_; } void insert(const T& data,const Envelope& 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]; memset(header,0,16); header[0]='m'; header[1]='a'; header[2]='p'; header[4]='n'; header[5]='i'; header[6]='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(const quadtree_node* 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(const quadtree_node* 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(const quadtree_node* node) const { int offset=0; for (int i=0;i<4;i++) { if (node->children_[i]) { offset +=sizeof(Envelope)+(node->children_[i]->data_.size()*sizeof(T))+3*sizeof(int); offset +=subnode_offset(node->children_[i]); } } return offset; } void write_node(std::ostream& out,const quadtree_node* node) const { if (node) { int offset=subnode_offset(node); int shape_count=node->data_.size(); int recsize=sizeof(Envelope) + 3 * sizeof(int) + shape_count * sizeof(T); char* node_record=new char[recsize]; memset(node_record,0,recsize); memcpy(node_record,&offset,4); memcpy(node_record+4,&node->ext_,sizeof(Envelope)); memcpy(node_record+36,&shape_count,4); for (int i=0;idata_[i]),sizeof(T)); } int num_subnodes=0; for (int i=0;i<4;++i) { if (node->children_[i]) { ++num_subnodes; } } memcpy(node_record + 40 + shape_count * sizeof(T),&num_subnodes,4); out.write(node_record,recsize); delete [] node_record; for (int i=0;i<4;++i) { write_node(out,node->children_[i]); } } } void print(const quadtree_node* node,int level=0) const { if (node) { typename std::vector::const_iterator itr=node->data_.begin(); std::string pad; for (int i=0;iext_<data_.end()) { std::cout<<*itr<<" "; ++itr; } std::cout<children_[i],level+4); } } } void insert(const T& data,const Envelope& item_ext,quadtree_node* node,int maxdepth) { if (node && node->ext_.contains(item_ext)) { coord2d c=node->ext_.center(); 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(); Envelope ext[4]; ext[0]=Envelope(lox,loy,lox + width * ratio_,loy + height * ratio_); ext[1]=Envelope(hix - width * ratio_,loy,hix,loy + height * ratio_); ext[2]=Envelope(lox,hiy - height*ratio_,lox + width * ratio_,hiy); ext[3]=Envelope(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_HH