00001 #include "cuik-kdtree.h"
00002
00003 #include "definitions.h"
00004 #include "vector.h"
00005 #include "random.h"
00006 #include "assert.h"
00007
00042 #define TRUE_MEDIAN 0
00043
00058 TKDtree *BuildKDTree(Trectangle *ambient,unsigned int m,double r,
00059 unsigned int n,double **points,unsigned int *ids);
00060
00075 void SearchKDtree(double dr2,unsigned int *topology,double *p,double *d2,
00076 unsigned int *id,TKDtree *kdt);
00077
00093 void SearchInBallKDtree(double dr2,unsigned int *topology,double *p,double r2,
00094 unsigned int *n,unsigned int *m,
00095 unsigned int **id,TKDtree *kdt);
00096
00097
00098
00099
00100
00101 TKDtree *BuildKDTree(Trectangle *ambient,unsigned int m,double r,
00102 unsigned int n,double **points,unsigned int *ids)
00103 {
00104 TKDtree *kdt;
00105
00106 NEW(kdt,1,TKDtree);
00107
00108 kdt->nd=GetRectangleDim(ambient);
00109 kdt->n=n;
00110 kdt->m=m;
00111 kdt->r=r;
00112 CopyRectangle(&(kdt->ambient),ambient);
00113
00114 if (n<m)
00115 {
00116 unsigned int i;
00117
00118 kdt->isLeaf=TRUE;
00119
00120 kdt->height=1;
00121
00122 NEW(kdt->p,kdt->m+1,double *);
00123 NEW(kdt->id,kdt->m+1,unsigned int);
00124
00125 if (n==0)
00126 kdt->volume=0.0;
00127 else
00128 {
00129 for(i=0;i<n;i++)
00130 {
00131 kdt->p[i]=points[i];
00132 kdt->id[i]=ids[i];
00133 if (i==0)
00134 InitRectangleFromPoint(kdt->nd,points[i],&(kdt->boundingBox));
00135 else
00136 ExpandRectangle(points[i],&(kdt->boundingBox));
00137 }
00138 kdt->volume=EnlargeRectangleWithLimits(r,
00139 &(kdt->ambient),
00140 &(kdt->boundingBox),
00141 &(kdt->samplingArea));
00142 }
00143 kdt->nextLeaf=NULL;
00144
00145 #ifndef NDEBUG
00146
00147 kdt->splitDim=NO_UINT;
00148 kdt->splitValue=INF;
00149 kdt->left=NULL;
00150 kdt->right=NULL;
00151 kdt->leftLeaf=NULL;
00152 kdt->rightLeaf=NULL;
00153 #endif
00154 }
00155 else
00156 {
00157 signed int i,j;
00158 double *ps;
00159 unsigned int is;
00160 TKDtree *kdtLeft,*kdtRight;
00161 double u,l;
00162
00163 kdt->isLeaf=FALSE;
00164
00165
00166 kdt->splitDim=GetRectangleSplitDim(&(kdt->ambient));
00167
00168 #if (TRUE_MEDIAN)
00169 {
00170 unsigned int med,right,left;
00171 double val;
00172
00173
00174 med=(unsigned int)n/2;
00175 left=0;
00176 right=n;
00177 i=0;
00178 while (i!=med)
00179 {
00180
00181
00182 val=points[left][kdt->splitDim];
00183
00184
00185
00186
00187
00188
00189
00190
00191
00192
00193
00194
00195
00196
00197 i=left+1;
00198 while ((i<right)&&(points[i][kdt->splitDim]<val))
00199 i++;
00200
00201 j=i+1;
00202 while (j<right)
00203 {
00204 if (points[j][kdt->splitDim]<val)
00205 {
00206 SWAP(points[i],points[j],ps);
00207 SWAP(ids[i],ids[j],is);
00208 i++;
00209 }
00210 j++;
00211 }
00212 if (left!=i-1)
00213 {
00214
00215 SWAP(points[left],points[i-1],ps);
00216 SWAP(ids[left],ids[i-1],is);
00217 }
00218 if (i<med)
00219 left=i;
00220 else
00221 {
00222 if (i>med)
00223 right=i;
00224 }
00225 }
00226 kdt->splitValue=points[i][kdt->splitDim];
00227 }
00228 #else
00229
00230 kdt->splitValue=0.0;
00231 for(i=0;i<n;i++)
00232 kdt->splitValue+=points[i][kdt->splitDim];
00233 kdt->splitValue/=(double)n;
00234
00235
00236
00237 i=0;
00238 j=n-1;
00239 do {
00240 while ((i<n)&&(points[i][kdt->splitDim]<kdt->splitValue))
00241 i++;
00242 while ((j>=0)&&(points[j][kdt->splitDim]>=kdt->splitValue))
00243 j--;
00244 if ((i<n)&&(j>=0)&&(i<j)&&
00245 (points[i][kdt->splitDim]>=kdt->splitValue)&&
00246 (points[j][kdt->splitDim]<kdt->splitValue))
00247 {
00248 SWAP(points[i],points[j],ps);
00249 SWAP(ids[i],ids[j],is);
00250 }
00251 } while (i<j);
00252 #endif
00253
00254
00255
00256
00257
00258
00259
00260 GetRectangleLimits(kdt->splitDim,&l,&u,&(kdt->ambient));
00261
00262 SetRectangleUpperLimit(kdt->splitDim,kdt->splitValue,&(kdt->ambient));
00263 kdtLeft=BuildKDTree(&(kdt->ambient),m,r,i,points,ids);
00264
00265 SetRectangleLimits(kdt->splitDim,kdt->splitValue,u,&(kdt->ambient));
00266 kdtRight=BuildKDTree(&(kdt->ambient),m,r,n-i,&(points[i]),&(ids[i]));
00267
00268 SetRectangleLowerLimit(kdt->splitDim,l,&(kdt->ambient));
00269
00270
00271 kdt->left=(void *)kdtLeft;
00272 kdt->right=(void *)kdtRight;
00273
00274 kdt->leftLeaf=(kdtLeft->isLeaf?(void*)kdtLeft:kdtLeft->leftLeaf);
00275 kdt->rightLeaf=(kdtRight->isLeaf?(void*)kdtRight:kdtRight->rightLeaf);
00276
00277
00278 kdt->volume=kdtLeft->volume+kdtRight->volume;
00279
00280
00281 kdt->height=1+(kdtLeft->height>kdtRight->height?
00282 kdtLeft->height:
00283 kdtRight->height);
00284
00285
00286 if (kdtLeft->isLeaf)
00287 {
00288 if (kdtRight->isLeaf)
00289 kdtLeft->nextLeaf=(void *)kdtRight;
00290 else
00291 kdtLeft->nextLeaf=kdtRight->leftLeaf;
00292 }
00293 else
00294 {
00295 if (kdtRight->isLeaf)
00296 KDTPTR(kdtLeft->rightLeaf)->nextLeaf=(void *)kdtRight;
00297 else
00298 KDTPTR(kdtLeft->rightLeaf)->nextLeaf=kdtRight->leftLeaf;
00299 }
00300
00301 #ifndef NDEBUG
00302
00303 kdt->nextLeaf=NULL;
00304 kdt->p=NULL;
00305 kdt->id=NULL;
00306 #endif
00307 }
00308
00309 return(kdt);
00310 }
00311
00312 void SearchKDtree(double dr2,unsigned int *topology,double *p,double *d2,
00313 unsigned int *id,TKDtree *kdt)
00314 {
00315 if (kdt->isLeaf)
00316 {
00317 if (SquaredDistanceToRectangle(*d2,p,topology,&(kdt->boundingBox))<*d2)
00318 {
00319 unsigned int i;
00320 double dp;
00321
00322 for(i=0;i<kdt->n;i++)
00323 {
00324 dp=VectorSquaredDistanceTopologyMin(*d2,kdt->nd,topology,p,kdt->p[i]);
00325 if (dp<*d2)
00326 {
00327 *d2=dp;
00328 *id=kdt->id[i];
00329 }
00330 }
00331 }
00332 }
00333 else
00334 {
00335 TKDtree *t1,*t2;
00336 double dt0,dt1,dt2,d,v;
00337
00338 v=p[kdt->splitDim];
00339 if (v<=kdt->splitValue)
00340 {
00341
00342 t1=KDTPTR(kdt->left);
00343 t2=KDTPTR(kdt->right);
00344 }
00345 else
00346 {
00347
00348 t1=KDTPTR(kdt->right);
00349 t2=KDTPTR(kdt->left);
00350 }
00351
00352 dt0=dr2-SquaredDistanceToRectangleDimension(kdt->splitDim,v,topology,
00353 &(kdt->ambient));
00354
00355 dt1=SquaredDistanceToRectangleDimension(kdt->splitDim,v,topology,
00356 &(t1->ambient));
00357 d=dt0+dt1;
00358 if (d<*d2)
00359 SearchKDtree(d,topology,p,d2,id,t1);
00360
00361 dt2=SquaredDistanceToRectangleDimension(kdt->splitDim,v,topology,
00362 &(t2->ambient));
00363 d=dt0+dt2;
00364 if (d<*d2)
00365 SearchKDtree(d,topology,p,d2,id,t2);
00366 }
00367 }
00368
00369 void SearchInBallKDtree(double dr2,unsigned int *topology,double *p,double r2,
00370 unsigned int *n,unsigned int *m,
00371 unsigned int **id,TKDtree *kdt)
00372 {
00373 if (kdt->isLeaf)
00374 {
00375 if (SquaredDistanceToRectangle(r2,p,topology,&(kdt->boundingBox))<r2)
00376 {
00377 unsigned int i;
00378
00379 for(i=0;i<kdt->n;i++)
00380 {
00381 if (VectorSquaredDistanceTopologyMin(r2,kdt->nd,topology,p,kdt->p[i])<r2)
00382 {
00383 if (*n==*m)
00384 MEM_DUP(*id,*m,unsigned int);
00385 (*id)[*n]=kdt->id[i];
00386 (*n)++;
00387 }
00388 }
00389 }
00390 }
00391 else
00392 {
00393 TKDtree *t;
00394 double d,dt,v;
00395
00396 v=p[kdt->splitDim];
00397 dt=dr2-SquaredDistanceToRectangleDimension(kdt->splitDim,v,topology,
00398 &(kdt->ambient));
00399
00400 t=KDTPTR(kdt->left);
00401 d=dt+SquaredDistanceToRectangleDimension(kdt->splitDim,v,topology,
00402 &(t->ambient));
00403 if (d<r2)
00404 SearchInBallKDtree(d,topology,p,r2,n,m,id,t);
00405
00406 t=KDTPTR(kdt->right);
00407 d=dt+SquaredDistanceToRectangleDimension(kdt->splitDim,v,topology,
00408 &(t->ambient));
00409 if (d<r2)
00410 SearchInBallKDtree(d,topology,p,r2,n,m,id,t);
00411 }
00412 }
00413
00414
00415
00416
00417
00418 TKDtree *InitKDTree(Trectangle *ambient,unsigned int m,double r,
00419 unsigned int n,double **points,unsigned int *ids)
00420 {
00421 assert(m>=2);
00422 assert(r>0);
00423
00424 return(BuildKDTree(ambient,m,r,n,points,ids));
00425 }
00426
00427 void AddPoint2KDtree(unsigned int *topology,double *point,unsigned int id,TKDtree **kdt)
00428 {
00429 TKDtree *t;
00430
00431 t=*kdt;
00432
00433 if (t->isLeaf)
00434 {
00435 t->p[t->n]=point;
00436 t->id[t->n]=id;
00437 t->n++;
00438 if (t->n>t->m)
00439 {
00440 TKDtree *nt;
00441
00442 nt=BuildKDTree(&(t->ambient),t->m,t->r,t->n,t->p,t->id);
00443 DeleteKDtree(t);
00444 *kdt=nt;
00445 }
00446 else
00447 {
00448 if (t->n==1)
00449 InitRectangleFromPoint(t->nd,point,&(t->boundingBox));
00450 else
00451 ExpandRectangle(point,&(t->boundingBox));
00452 t->volume=EnlargeRectangleWithLimits(t->r,
00453 &(t->ambient),
00454 &(t->boundingBox),
00455 &(t->samplingArea));
00456 }
00457 }
00458 else
00459 {
00460 TKDtree *kdtLeft,*kdtRight;
00461
00462 if (point[t->splitDim]<=t->splitValue)
00463 AddPoint2KDtree(topology,point,id,(TKDtree **)&(t->left));
00464 else
00465 AddPoint2KDtree(topology,point,id,(TKDtree **)&(t->right));
00466
00467 t->n++;
00468
00469 kdtLeft=KDTPTR(t->left);
00470 kdtRight=KDTPTR(t->right);
00471
00472
00473
00474
00475
00476
00477 t->leftLeaf=(kdtLeft->isLeaf?(void*)kdtLeft:kdtLeft->leftLeaf);
00478 t->rightLeaf=(kdtRight->isLeaf?(void*)kdtRight:kdtRight->rightLeaf);
00479
00480
00481 if (kdtLeft->isLeaf)
00482 {
00483 if (kdtRight->isLeaf)
00484 kdtLeft->nextLeaf=(void *)kdtRight;
00485 else
00486 kdtLeft->nextLeaf=kdtRight->leftLeaf;
00487 }
00488 else
00489 {
00490 if (kdtRight->isLeaf)
00491 KDTPTR(kdtLeft->rightLeaf)->nextLeaf=(void *)kdtRight;
00492 else
00493 KDTPTR(kdtLeft->rightLeaf)->nextLeaf=kdtRight->leftLeaf;
00494 }
00495
00496
00497 if ((KDTPTR(t->left)->height>KDTPTR(t->right)->height*2)||
00498 (KDTPTR(t->right)->height>KDTPTR(t->left)->height*2))
00499 {
00500 double **p;
00501 unsigned int *id;
00502 TKDtree *l,*nt;
00503 unsigned int i,j;
00504
00505
00506 NEW(p,t->n,double *);
00507 NEW(id,t->n,unsigned int);
00508 l=KDTPTR(t->leftLeaf);
00509 i=0;
00510 while(i<t->n)
00511 {
00512 for(j=0;j<l->n;j++)
00513 {
00514 p[i]=l->p[j];
00515 id[i]=l->id[j];
00516 i++;
00517 }
00518 l=KDTPTR(l->nextLeaf);
00519 }
00520
00521
00522 nt=BuildKDTree(&(t->ambient),t->m,t->r,t->n,p,id);
00523 DeleteKDtree(t);
00524 *kdt=nt;
00525
00526 free(p);
00527 free(id);
00528 }
00529 else
00530 {
00531
00532 t->volume=kdtLeft->volume+kdtRight->volume;
00533 t->height=1+(kdtLeft->height>kdtRight->height?
00534 kdtLeft->height:kdtRight->height);
00535 }
00536 }
00537 }
00538
00539 unsigned int NearestNeighbour(unsigned int *topology,double *point,TKDtree *kdt)
00540 {
00541 unsigned int id;
00542 double d;
00543
00544 assert(kdt->n>0);
00545
00546 id=NO_UINT;
00547 d=INF;
00548 SearchKDtree(0.0,topology,point,&d,&id,kdt);
00549
00550 assert(id!=NO_UINT);
00551
00552 return(id);
00553 }
00554
00555 void NeighboursInBall(unsigned int *topology,double *point,double r,
00556 unsigned int *n,unsigned int **ids,TKDtree *kdt)
00557 {
00558 unsigned int m;
00559
00560 assert(kdt->n>0);
00561
00562 m=100;
00563 NEW(*ids,m,unsigned int);
00564 *n=0;
00565
00566 SearchInBallKDtree(0.0,topology,point,r*r,n,&m,ids,kdt);
00567
00568 if (*n==0)
00569 free(*ids);
00570 }
00571
00572 void SampleInKDtree(double *point,TKDtree *kdt)
00573 {
00574 if (kdt->isLeaf)
00575 RandomPointInRectangle(point,&(kdt->samplingArea));
00576 else
00577 {
00578 double r;
00579
00580 r=randomDouble()*kdt->volume;
00581
00582 if (r<KDTPTR(kdt->left)->volume)
00583 SampleInKDtree(point,KDTPTR(kdt->left));
00584 else
00585 SampleInKDtree(point,KDTPTR(kdt->right));
00586 }
00587 }
00588
00589 void DeleteKDtree(TKDtree *kdt)
00590 {
00591 if (kdt->isLeaf)
00592 {
00593 free(kdt->p);
00594 free(kdt->id);
00595 DeleteRectangle(&(kdt->boundingBox));
00596 DeleteRectangle(&(kdt->samplingArea));
00597 }
00598 else
00599 {
00600 DeleteKDtree(KDTPTR(kdt->left));
00601 DeleteKDtree(KDTPTR(kdt->right));
00602 }
00603 DeleteRectangle(&(kdt->ambient));
00604 free(kdt);
00605 }
Follow us!