00001 00002 // File: quadtree.cpp // 00003 // Description: source file for quadtree management (Cquadtree class) // 00004 // This file is part of the SISCone project. // 00005 // For more details, see http://projects.hepforge.org/siscone // 00006 // // 00007 // Copyright (c) 2006 Gavin Salam and Gregory Soyez // 00008 // // 00009 // This program is free software; you can redistribute it and/or modify // 00010 // it under the terms of the GNU General Public License as published by // 00011 // the Free Software Foundation; either version 2 of the License, or // 00012 // (at your option) any later version. // 00013 // // 00014 // This program is distributed in the hope that it will be useful, // 00015 // but WITHOUT ANY WARRANTY; without even the implied warranty of // 00016 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // 00017 // GNU General Public License for more details. // 00018 // // 00019 // You should have received a copy of the GNU General Public License // 00020 // along with this program; if not, write to the Free Software // 00021 // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA // 00022 // // 00023 // $Revision:: 123 $// 00024 // $Date:: 2007-02-28 20:52:16 -0500 (Wed, 28 Feb 2007) $// 00026 00027 #include "quadtree.h" 00028 #include <math.h> 00029 #include <stdio.h> 00030 #include <iostream> 00031 00032 namespace siscone{ 00033 00034 using namespace std; 00035 00036 /******************************************************************* 00037 * Cquadtree implementation * 00038 * Implementation of a 2D quadtree. * 00039 * This class implements the traditional two-dimensional quadtree. * 00040 * The elements at each node are of 'Cmomentum' type. * 00041 *******************************************************************/ 00042 00043 // default ctor 00044 //-------------- 00045 Cquadtree::Cquadtree(){ 00046 v = NULL; 00047 00048 children[0][0] = children[0][1] = children[1][0] = children[1][1] = NULL; 00049 has_child = false; 00050 } 00051 00052 00053 // ctor with initialisation (see init for details) 00054 //-------------------------- 00055 Cquadtree::Cquadtree(double _x, double _y, double _half_size_x, double _half_size_y){ 00056 v = NULL; 00057 00058 children[0][0] = children[0][1] = children[1][0] = children[1][1] = NULL; 00059 has_child = false; 00060 00061 init(_x, _y, _half_size_x, _half_size_y); 00062 } 00063 00064 00065 // default destructor 00066 // at destruction, everything is destroyed except 00067 // physical values at the leaves 00068 //------------------------------------------------ 00069 Cquadtree::~Cquadtree(){ 00070 if (has_child){ 00071 if (v!=NULL) delete v; 00072 delete children[0][0]; 00073 delete children[0][1]; 00074 delete children[1][0]; 00075 delete children[1][1]; 00076 } 00077 } 00078 00079 00080 /* 00081 * init the tree. 00082 * By initializing the tree, we mean setting the cell parameters 00083 * and preparing the object to act as a seed for a new tree. 00084 * - _x x-position of the center 00085 * - _y y-position of the center 00086 * - half_size_x half x-size of the cell 00087 * - half_size_y half y-size of the cell 00088 * return 0 on success, 1 on error. Note that if the cell 00089 * is already filled, we return an error. 00090 ******************************************************************/ 00091 int Cquadtree::init(double _x, double _y, double _half_size_x, double _half_size_y){ 00092 if (v!=NULL) 00093 return 1; 00094 00095 centre_x = _x; 00096 centre_y = _y; 00097 half_size_x = _half_size_x; 00098 half_size_y = _half_size_y; 00099 00100 return 0; 00101 } 00102 00103 00104 /* 00105 * adding a particle to the tree. 00106 * This method adds one vector to the quadtree structure which 00107 * is updated consequently. 00108 * - v vector to add 00109 * return 0 on success 1 on error 00110 ******************************************************************/ 00111 int Cquadtree::add(Cmomentum *v_add){ 00112 // Description of the method: 00113 // -------------------------- 00114 // the addition process goes as follows: 00115 // 1. check if the cell is empty, in which case, add the particle 00116 // here and leave. 00117 // 2. If there is a unique particle already inside, 00118 // (a) create children 00119 // (b) forward the existing particle to the appropriate child 00120 // 3. Add current particle to this cell and forward to the 00121 // adequate child 00122 // NOTE: we assume in the whole procedure that the particle is 00123 // indeed inside the cell ! 00124 00125 // step 1: the case of empty cells 00126 if (v==NULL){ 00127 v = v_add; 00128 return 0; 00129 } 00130 00131 // step 2: additional work if 1! particle already present 00132 // we use the fact that only 1-particle systems have no child 00133 if (!has_child){ 00134 double new_half_size_x = 0.5*half_size_x; 00135 double new_half_size_y = 0.5*half_size_y; 00136 // create children 00137 children[0][0] = new Cquadtree(centre_x-new_half_size_x, centre_y-new_half_size_y, 00138 new_half_size_x, new_half_size_y); 00139 children[0][1] = new Cquadtree(centre_x-new_half_size_x, centre_y+new_half_size_y, 00140 new_half_size_x, new_half_size_y); 00141 children[1][0] = new Cquadtree(centre_x+new_half_size_x, centre_y-new_half_size_y, 00142 new_half_size_x, new_half_size_y); 00143 children[1][1] = new Cquadtree(centre_x+new_half_size_x, centre_y+new_half_size_y, 00144 new_half_size_x, new_half_size_y); 00145 00146 has_child = true; 00147 00148 // forward to child 00149 //? The following line assumes 'true'==1 and 'false'==0 00150 // Note: v being a single particle, eta and phi are correct 00151 children[v->eta>centre_x][v->phi>centre_y]->add(v); 00152 00153 // copy physical params 00154 v = new Cmomentum(*v); 00155 } 00156 00157 // step 3: add new particle 00158 // Note: v_add being a single particle, eta and phi are correct 00159 children[v_add->eta>centre_x][v_add->phi>centre_y]->add(v_add); 00160 *v+=*v_add; 00161 00162 return 0; 00163 } 00164 00165 00166 /* 00167 * circle intersection. 00168 * computes the intersection with a circle of given centre and radius. 00169 * The output takes the form of a quadtree with all squares included 00170 * in the circle. 00171 * - cx circle centre x coordinate 00172 * - cy circle centre y coordinate 00173 * - cR2 circle radius SQUARED 00174 * return the checksum for the intersection 00175 ******************************************************************/ 00176 Creference Cquadtree::circle_intersect(double cx, double cy, double cR2){ 00177 // Description of the method: 00178 // -------------------------- 00179 // 1. check if cell is empty => no intersection 00180 // 2. if cell has 1! particle, check if it is inside the circle. 00181 // If yes, add it and return, if not simply return. 00182 // 3. check if the circle intersects the square. If not, return. 00183 // 4. check if the square is inside the circle. 00184 // If yes, add it to qt and return. 00185 // 5. check intersections with children. 00186 00187 // step 1: if there is no particle inside te square, no reason to go further 00188 if (v==NULL) 00189 return Creference(); 00190 00191 double dx, dy; 00192 00193 // step 2: if there is only one particle inside the square, test if it is in 00194 // the circle, in which case return associated reference 00195 if (!has_child){ 00196 // compute the distance 00197 // Note: v has only one particle => eta and phi are defined 00198 dx = cx - v->eta; 00199 dy = fabs(cy - v->phi); 00200 if (dy>M_PI) 00201 dy -= 2.0*M_PI; 00202 00203 // test distance 00204 if (dx*dx+dy*dy<cR2){ 00205 return v->ref; 00206 } 00207 00208 return Creference(); 00209 } 00210 00211 // step 3: check if there is an intersection 00212 //double ryp, rym; 00213 double dx_c, dy_c; 00214 00215 // store distance with the centre of the square 00216 dx_c = fabs(cx-centre_x); 00217 dy_c = fabs(cy-centre_y); 00218 if (dy_c>M_PI) dy_c = 2.0*M_PI-dy_c; 00219 00220 // compute (minimal) the distance (pay attention to the periodicity in phi). 00221 dx = dx_c-half_size_x; 00222 if (dx<0) dx=0; 00223 dy = dy_c-half_size_y; 00224 if (dy<0) dy=0; 00225 00226 // check the distance 00227 if (dx*dx+dy*dy>=cR2){ 00228 // no intersection 00229 return Creference(); 00230 } 00231 00232 // step 4: check if included 00233 00234 // compute the (maximal) distance 00235 dx = dx_c+half_size_x; 00236 dy = dy_c+half_size_y; 00237 if (dy>M_PI) dy = M_PI; 00238 00239 // compute the distance 00240 if (dx*dx+dy*dy<cR2){ 00241 return v->ref; 00242 } 00243 00244 // step 5: the square is not fully in. Recurse to children 00245 return children[0][0]->circle_intersect(cx, cy, cR2) 00246 + children[0][1]->circle_intersect(cx, cy, cR2) 00247 + children[1][0]->circle_intersect(cx, cy, cR2) 00248 + children[1][1]->circle_intersect(cx, cy, cR2); 00249 } 00250 00251 00252 /* 00253 * output a data file for drawing the grid. 00254 * This can be used to output a data file containing all the 00255 * grid subdivisions. The file contents is as follows: 00256 * first and second columns give center of the cell, the third 00257 * gives the size. 00258 * - flux opened stream to write to 00259 * return 0 on success, 1 on error 00260 ******************************************************************/ 00261 int Cquadtree::save(FILE *flux){ 00262 00263 if (flux==NULL) 00264 return 1; 00265 00266 if (has_child){ 00267 fprintf(flux, "%le\t%le\t%le\t%le\n", centre_x, centre_y, half_size_x, half_size_y); 00268 children[0][0]->save(flux); 00269 children[0][1]->save(flux); 00270 children[1][0]->save(flux); 00271 children[1][1]->save(flux); 00272 } 00273 00274 return 0; 00275 } 00276 00277 00278 /* 00279 * output a data file for drawing the tree leaves. 00280 * This can be used to output a data file containing all the 00281 * tree leaves. The file contents is as follows: 00282 * first and second columns give center of the cell, the third 00283 * gives the size. 00284 * - flux opened stream to write to 00285 * return 0 on success, 1 on error 00286 ******************************************************************/ 00287 int Cquadtree::save_leaves(FILE *flux){ 00288 00289 if (flux==NULL) 00290 return 1; 00291 00292 if (has_child){ 00293 if (children[0][0]!=NULL) children[0][0]->save_leaves(flux); 00294 if (children[0][1]!=NULL) children[0][1]->save_leaves(flux); 00295 if (children[1][0]!=NULL) children[1][0]->save_leaves(flux); 00296 if (children[1][1]!=NULL) children[1][1]->save_leaves(flux); 00297 } else { 00298 fprintf(flux, "%le\t%le\t%le\t%le\n", centre_x, centre_y, half_size_x, half_size_y); 00299 } 00300 00301 return 0; 00302 } 00303 00304 }