//////////////////////////////////////////////////////////////////////////////// /// @brief geo index /// /// @file /// /// DISCLAIMER /// /// Copyright 2010-2011 triagens GmbH, Cologne, Germany /// /// Licensed under the Apache License, Version 2.0 (the "License"); /// you may not use this file except in compliance with the License. /// You may obtain a copy of the License at /// /// http://www.apache.org/licenses/LICENSE-2.0 /// /// Unless required by applicable law or agreed to in writing, software /// distributed under the License is distributed on an "AS IS" BASIS, /// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. /// See the License for the specific language governing permissions and /// limitations under the License. /// /// Copyright holder is triAGENS GmbH, Cologne, Germany /// /// @author R. A. Parker /// @author Copyright 2011, triagens GmbH, Cologne, Germany //////////////////////////////////////////////////////////////////////////////// /* GeoIndex.c - GeoIndex algorithms */ /* Version 2.0 3.12.2011 R. A. Parker */ #ifdef GEO_TRIAGENS #include "GeoIndex/GeoIndex.h" #else #include "GeoIndex2.h" #endif /* Radius of the earth used for distances */ #define EARTHRADIUS 6371000.0 /* How many results to allow for internally */ /* at the start of a "within distance" search */ /* (it grows if it needs to so is not critical */ #define GEORESULTSTART 100000 #define GEOSLOTSTART 50 #define GEOPOTSTART 100 typedef struct { GeoIndex * gi; GeoCoordinate * gc; double x; double y; double z; GeoString gs; GeoFix fixdist[GeoIndexFIXEDPOINTS]; double snmd; GeoFix distrej[GeoIndexFIXEDPOINTS]; } GeoDetailedPoint; typedef struct { int pointsct; int allocpoints; int * slot; double * snmd; } GeoResults; typedef struct { GeoResults * gr; GeoDetailedPoint * gd; int stacksize; int potid[46]; } GeoStack; typedef struct { GeoIndex * gi; int pathlength; int path[46]; } GeoPath; double GeoIndex_distance(GeoCoordinate * c1, GeoCoordinate * c2) { double x1,y1,z1,x2,y2,z2,mole; z1=sin(c1->latitude*M_PI/180.0); x1=cos(c1->latitude*M_PI/180.0)*cos(c1->longitude*M_PI/180.0); y1=cos(c1->latitude*M_PI/180.0)*sin(c1->longitude*M_PI/180.0); z2=sin(c2->latitude*M_PI/180.0); x2=cos(c2->latitude*M_PI/180.0)*cos(c2->longitude*M_PI/180.0); y2=cos(c2->latitude*M_PI/180.0)*sin(c2->longitude*M_PI/180.0); mole=sqrt((x1-x2)*(x1-x2) + (y1-y2)*(y1-y2) + (z1-z2)*(z1-z2)); if(mole > 2.0) mole = 2.0; /* make sure arcsin succeeds! */ return 2.0 * EARTHRADIUS * asin(mole/2.0); } void GeoIndexFreePot(GeoIndex * gi, int pot) { gi->pots[pot].LorLeaf=gi->pots[0].LorLeaf; gi->pots[0].LorLeaf = pot; } int GeoIndexNewPot(GeoIndex * gi) { int newpotct,j; long long x,y; GeoPot * gp; if( gi->pots[0].LorLeaf == 0) { /* do the growth calculation in long long to make sure it doesn't */ /* overflow when the size gets to be near 2^31 */ x = gi->potct; y=100+GeoIndexGROW; x=x*y + 99; y=100; x=x/y; if(x>1000000000L) return -2; newpotct= (int) x; gp = realloc(gi->pots,newpotct*sizeof(GeoPot)); if(gp!=NULL) gi->pots=gp; else return -2; for(j=gi->potct;jpotct=newpotct; } j= gi->pots[0].LorLeaf; gi->pots[0].LorLeaf=gi->pots[j].LorLeaf; return j; } GeoIndex * GeoIndex_new(void) { GeoIndex * gi; int i,j; double lat, lon, x, y, z; gi = malloc(sizeof(GeoIndex)); if(gi==NULL) return gi; /* try to allocate all the things we need */ gi->pots = malloc(GEOPOTSTART*sizeof(GeoPot)); gi->gc = malloc(GEOSLOTSTART*sizeof(GeoCoordinate)); /* if any of them fail, free the ones that succeeded */ /* and then return the NULL pointer for our user */ if ( ( gi->pots == NULL) || ( gi->gc == NULL) ) { if ( gi->pots != NULL) free(gi->pots); if ( gi->gc != NULL) free(gi->gc); free(gi); return NULL; } /* initialize chain of empty slots */ for(i=0;igc[i]).latitude=i+1; else (gi->gc[i]).latitude=0; } /* similarly set up free chain of empty pots */ for(i=0;ipots[i].LorLeaf=i+1; else gi->pots[i].LorLeaf=0; } gi->potct = GEOPOTSTART; gi->slotct = GEOSLOTSTART; /* set up the fixed points structure */ /* this code assumes GeoIndexFIXEDPOINTS is eight! */ for(i=0;ifixed.x)[i]=x; (gi->fixed.y)[i]=y; (gi->fixed.z)[i]=z; } /* set up the root pot */ j=GeoIndexNewPot(gi); gi->pots[j].LorLeaf=0; /* leaf pot */ gi->pots[j].RorPoints=0; /* with no points in it! */ gi->pots[j].middle = 0ll; gi->pots[j].start = 0ll; gi->pots[j].end = 0x1FFFFFFFFFFFFFll; gi->pots[j].level = 1; for(i=0;ipots[j].maxdist[i]=0; return gi; } void GeoIndex_free(GeoIndex * gi) { free(gi->gc); free(gi->pots); free(gi); } /* 2^25 / 90 rounded down. Used to convert */ /* degrees of longitude and latitude into */ /* integers for use making a GeoString */ #define STRINGPERDEGREE 372827.01 #define HILBERTMAX 67108863 #define ARCSINFIX 41720.0 GeoString GeoMkHilbert(GeoCoordinate * c) { double x1,y1; GeoString z; int x,y; int i,nz,temp; y1=c->latitude+90.0; z=0; x1=c->longitude; if(c->longitude < 0.0) { x1=c->longitude+180.0; z=1; } x=(int) (x1*STRINGPERDEGREE); y=(int) (y1*STRINGPERDEGREE); for(i=0;i<26;i++) { z<<=2; nz=((y>>24)&2)+(x>>25); x = (x<<1)&(HILBERTMAX); y = (y<<1)&(HILBERTMAX); if(nz==0) { temp=x; x=y; y=temp; } if(nz==1) { temp=HILBERTMAX-x; x=HILBERTMAX-y; y=temp; z+=3; } if(nz==2) { z+=1; } if(nz==3) { z+=2; } } return z+1ll; } void GeoMkDetail(GeoIndex * gi, GeoDetailedPoint * gd, GeoCoordinate * c) { /* entire routine takes about 0.94 microseconds */ double x1,y1,z1,snmd; int i; gd->gi=gi; gd->gc = c; /* The GeoString computation takes about 0.17 microseconds */ gd->gs=GeoMkHilbert(c); /* This part takes about 0.32 microseconds */ gd->z=sin(c->latitude*M_PI/180.0); gd->x=cos(c->latitude*M_PI/180.0)*cos(c->longitude*M_PI/180.0); gd->y=cos(c->latitude*M_PI/180.0)*sin(c->longitude*M_PI/180.0); /* and this bit takes about 0.45 microseconds */ for(i=0;ifixed.x)[i]; y1=(gi->fixed.y)[i]; z1=(gi->fixed.z)[i]; snmd=(x1-gd->x)*(x1-gd->x)+(y1-gd->y)*(y1-gd->y)+ (z1-gd->z)*(z1-gd->z); (gd->fixdist)[i] = asin(sqrt(snmd)/2.0)*ARCSINFIX; } } double GeoMetersToSNMD(double meters) { double angle,hnmd; angle=0.5*meters/EARTHRADIUS; hnmd=sin(angle); /* half normalized mole distance */ if(angle>=M_PI/2.0) return 4.0; else return hnmd*hnmd*4.0; } void GeoSetDistance(GeoDetailedPoint * gd, double snmd) { GeoFix gf; int i; gd->snmd = snmd; gf = asin(sqrt(snmd)/2.0)*ARCSINFIX; gf++; for(i=0;ifixdist)[i]<=gf) (gd->distrej)[i]=0; else (gd->distrej)[i]=(gd->fixdist)[i]-gf; } } void GeoStackSet (GeoStack * gk, GeoDetailedPoint * gd, GeoResults * gr) { int pot; GeoIndex * gi; GeoPot * gp; gi=gd->gi; gk->gr = gr; gk->gd = gd; gk->stacksize = 0; pot=1; while(1) { gp=gi->pots+pot; if(gp->LorLeaf==0) break; if(gp->middle>gd->gs) { gk->potid[gk->stacksize]=gp->RorPoints; pot=gp->LorLeaf; } else { gk->potid[gk->stacksize]=gp->LorLeaf; pot=gp->RorPoints; } gk->stacksize++; } gk->potid[gk->stacksize]=pot; } GeoResults * GeoResultsCons(int alloc) { GeoResults * gres; int * sa; double * dd; gres=malloc(sizeof(GeoResults)); sa=malloc(alloc*sizeof(int)); dd=malloc(alloc*sizeof(double)); if( (gres==NULL) || (sa==NULL) || (dd==NULL) ) { if(gres!=NULL) free(gres); if(sa!=NULL) free(sa); if(dd!=NULL) free(dd); return NULL; } gres->pointsct = 0; gres->allocpoints = alloc; gres->slot = sa; gres->snmd = dd; /* no need to initialize maxsnmd */ return gres; } void GeoResultsStartCount(GeoResults * gr) { int i; for(i=0;iallocpoints;i++) { gr->slot[i]=0; gr->snmd[i]=10.0; } } void GeoResultsInsertPoint(GeoResults * gr, int slot, double snmd) { int i,j1,j2,temp; if(snmd>=gr->snmd[0]) return; if(gr->slot[0]==0) gr->pointsct++; i=0; /* i is now considered empty */ while(1) { j1=2*i+1; j2=2*i+2; if(j1allocpoints) { if(j2allocpoints) { if(gr->snmd[j1]>gr->snmd[j2]) { temp=j1; j1=j2; j2=temp; } /* so now j2 is >= j1 */ if(gr->snmd[j2]<=snmd) { gr->snmd[i]=snmd; gr->slot[i]=slot; return; } gr->snmd[i]=gr->snmd[j2]; gr->slot[i]=gr->slot[j2]; i=j2; continue; } if(gr->snmd[j1]<=snmd) { gr->snmd[i]=snmd; gr->slot[i]=slot; return; } gr->snmd[i]=gr->snmd[j1]; gr->slot[i]=gr->slot[j1]; i=j1; continue; } gr->snmd[i]=snmd; gr->slot[i]=slot; return; } } int GeoResultsGrow(GeoResults * gr) { int newsiz; int * sa; double * dd; if(gr->pointsct < gr->allocpoints) return 0; /* otherwise grow by about 50% */ newsiz=gr->pointsct + (gr->pointsct/2) + 1; if(newsiz > 1000000000) return -1; sa=realloc(gr->slot, newsiz*sizeof(int)); dd=realloc(gr->snmd, newsiz*sizeof(double)); if( (sa==NULL) || (dd==NULL) ) { if(sa!=NULL) gr->slot = sa; if(dd!=NULL) gr->snmd = dd; return -1; } gr->slot = sa; gr->snmd = dd; gr->allocpoints = newsiz; return 0; } GeoCoordinates * GeoAnswers (GeoIndex * gi, GeoResults * gr) { GeoCoordinates * ans; GeoCoordinate * gc; int i,j,slot; double mole; ans = malloc(sizeof(GeoCoordinates));; gc = malloc(gr->pointsct * sizeof(GeoCoordinate)); if( (ans==NULL) || (gc==NULL) ) { if(ans!=NULL) free(ans); if(gc!=NULL) free(gc); free(gr->slot); free(gr->snmd); free(gr); return NULL; } ans->length = gr->pointsct; ans->coordinates = gc; j=0; for(i=0;iallocpoints;i++) { if(j>=gr->pointsct) break; slot=gr->slot[i]; if(slot==0) continue; ans->coordinates[j].latitude = (gi->gc)[slot].latitude; ans->coordinates[j].longitude = (gi->gc)[slot].longitude; ans->coordinates[j].data = (gi->gc)[slot].data; mole=sqrt(gr->snmd[i]); if(mole > 2.0) mole = 2.0; /* make sure arcsin succeeds! */ gr->snmd[j]= 2.0 * EARTHRADIUS * asin(mole/2.0); j++; } ans->distances = gr->snmd; free(gr->slot); free(gr); return ans; } int GeoPotJunk(GeoDetailedPoint * gd, int pot) { int i; GeoPot * gp; gp=(gd->gi)->pots + pot; for(i=0;imaxdist[i]distrej[i]) return 1; return 0; } double GeoSNMD(GeoDetailedPoint * gd, GeoCoordinate * c) { double x,y,z; z=sin(c->latitude*M_PI/180.0); x=cos(c->latitude*M_PI/180.0)*cos(c->longitude*M_PI/180.0); y=cos(c->latitude*M_PI/180.0)*sin(c->longitude*M_PI/180.0); return (x-gd->x)*(x-gd->x) + (y-gd->y)*(y-gd->y) + (z-gd->z)*(z-gd->z); } GeoCoordinates * GeoIndex_PointsWithinRadius(GeoIndex * gi, GeoCoordinate * c, double d) { GeoResults * gres; GeoCoordinates * answer; GeoDetailedPoint gd; GeoStack gk; GeoPot * gp; int r,pot,slot,i; double snmd,maxsnmd; gres=GeoResultsCons(100); if(gres==NULL) return NULL; GeoMkDetail(gi,&gd,c); GeoStackSet(&gk,&gd,gres); maxsnmd=GeoMetersToSNMD(d); GeoSetDistance(&gd,maxsnmd); gk.stacksize++; while(gk.stacksize>=1) { gk.stacksize--; pot=gk.potid[gk.stacksize]; if(GeoPotJunk(&gd,pot)) continue; gp=gi->pots+pot; if(gp->LorLeaf==0) { for(i=0;iRorPoints;i++) { slot=gp->points[i]; snmd=GeoSNMD(&gd,gi->gc+slot); if(snmd>maxsnmd) continue; r = GeoResultsGrow(gres); if(r==-1) { free(gres->snmd); free(gres->slot); free(gres); return NULL; } gres->slot[gres->pointsct]=slot; gres->snmd[gres->pointsct]=snmd; gres->pointsct++; } } else { gk.potid[gk.stacksize++]=gp->LorLeaf; gk.potid[gk.stacksize++]=gp->RorPoints; } } answer=GeoAnswers(gi,gres); return answer; /* note - this may be NULL */ } GeoCoordinates * GeoIndex_NearestCountPoints(GeoIndex * gi, GeoCoordinate * c, int count) { GeoResults * gr; GeoDetailedPoint gd; GeoCoordinates * answer; GeoStack gk; GeoPot * gp; int pot,slot,i,left; double snmd; gr=GeoResultsCons(count); if(gr==NULL) return NULL; GeoMkDetail(gi,&gd,c); GeoStackSet(&gk,&gd,gr); GeoResultsStartCount(gr); left=count; while(gk.stacksize>=0) { pot=gk.potid[gk.stacksize--]; gp=gi->pots+pot; if(left<=0) { GeoSetDistance(&gd,gr->snmd[0]); if(GeoPotJunk(&gd,pot)) continue; } if(gp->LorLeaf==0) { for(i=0;iRorPoints;i++) { slot=gp->points[i]; snmd=GeoSNMD(&gd,gi->gc+slot); GeoResultsInsertPoint(gr,slot,snmd); left--; if(left<-1) left=-1; } } else { if(gd.gs>gp->middle) { gk.potid[++gk.stacksize]=gp->LorLeaf; gk.potid[++gk.stacksize]=gp->RorPoints; } else { gk.potid[++gk.stacksize]=gp->RorPoints; gk.potid[++gk.stacksize]=gp->LorLeaf; } } } answer=GeoAnswers(gi,gr); return answer; /* note - this may be NULL */ } void GeoIndexFreeSlot(GeoIndex * gi, int slot) { gi->gc[slot].latitude=gi->gc[0].latitude; gi->gc[0].latitude = slot; } int GeoIndexNewSlot(GeoIndex * gi) { int newslotct,j; long long x,y; GeoCoordinate * gc; if(gi->gc[0].latitude == 0.0) { /* do the growth calculation in long long to make sure it doesn't */ /* overflow when the size gets to be near 2^31 */ x = gi->slotct; y=100+GeoIndexGROW; x=x*y + 99; y=100; x=x/y; if(x>2000000000L) return -2; newslotct= (int) x; gc = realloc(gi->gc,newslotct*sizeof(GeoCoordinate)); if(gc!=NULL) gi->gc=gc; else return -2; for(j=gi->slotct;jslotct=newslotct; } j= (int) (gi->gc[0].latitude); gi->gc[0].latitude=gi->gc[j].latitude; return j; } int GeoFind(GeoPath * gt, GeoDetailedPoint * gd) { int pot,pot1; int i; int slot; GeoIndex * gi; GeoCoordinate * gc; GeoPot * gp; gi = gd->gi; gt->gi = gi; pot=1; gt->pathlength=0; while(1) { gp=gi->pots+pot; gt->path[gt->pathlength]=pot; gt->pathlength++; if(gp->LorLeaf == 0) break; if(gp->middle > gd->gs) pot=gp->LorLeaf; else pot=gp->RorPoints; } /* so we have a pot such that top is bigger but bottom isn't */ while(1) /* so look for an exact match */ { for(i=0;iRorPoints;i++) { slot=gp->points[i]; gc=gi->gc+slot; if( ( (gd->gc)->latitude ==gc->latitude ) && ( (gd->gc)->longitude==gc->longitude) && ( (gd->gc)->data ==gc->data ) ) { gt->path[gt->pathlength]=i; return 1; } } if(gp->startgs) break; /* need to find the predecessor of this pot */ /* this is expected to be a rare event, so */ /* no time is wasted to simplify this! */ while(1) { gt->pathlength--; pot1=gt->path[gt->pathlength-1]; gp=gi->pots+pot1; if(pot==gp->RorPoints) break; /* cannot go off the front */ pot=pot1; } gp=gi->pots+pot1; pot=gp->LorLeaf; /* now we have a pot whose iterated right child we want */ while(1) { gp=gi->pots+pot; gt->path[gt->pathlength]=pot; gt->pathlength++; if(gp->LorLeaf == 0) break; pot=gp->RorPoints; } } return 2; } void GeoPopulateMaxdist(GeoIndex * gi, GeoPot * gp, GeoString * gsa) { int i,j; GeoDetailedPoint gd; gsa[0]=0x1FFFFFFFFFFFFFll; gsa[1]=0ll; for(j=0;jmaxdist[j]=0; for(i=0;iRorPoints;i++) { GeoMkDetail(gi,&gd,gi->gc+gp->points[i]); for(j=0;jgp->maxdist[j]) gp->maxdist[j] = gd.fixdist[j]; if(gd.gsgsa[1]) gsa[1]=gd.gs; } gp->level=1; } int GeoGetPot(GeoPath * gt, int height) { return gt->path[gt->pathlength-height]; } void GeoAdjust(GeoIndex * gi, int potx) /* the kids are alright */ { int poty,potz; /* x = (yz) */ int i; GeoPot * gpx; GeoPot * gpy; GeoPot * gpz; gpx=gi->pots + potx; poty=gpx->LorLeaf; gpy=gi->pots + poty; potz=gpx->RorPoints; gpz=gi->pots + potz; gpx->start=gpy->start; gpx->end =gpz->end; gpx->middle=gpz->start; gpx->level=gpy->level; if( (gpz->level) > gpx->level) gpx->level = gpz->level; gpx->level++; for(i=0;imaxdist[i]=gpy->maxdist[i]; if( gpx->maxdist[i]maxdist[i]) gpx->maxdist[i]=gpz->maxdist[i]; } } void RotateLeft(GeoIndex * gi, int pote) { int pota,potb,potc,potd; GeoPot * gpd; GeoPot * gpe; gpe=gi->pots + pote; potd=gpe->RorPoints; gpd=gi->pots + potd; pota=gpe->LorLeaf; potb=gpd->LorLeaf; potc=gpd->RorPoints; gpd->LorLeaf=pota; gpd->RorPoints=potb; GeoAdjust(gi,potd); gpe->LorLeaf=potd; gpe->RorPoints=potc; GeoAdjust(gi,pote); } void RotateRight(GeoIndex * gi, int pote) { int pota,potb,potc,potd; GeoPot * gpd; GeoPot * gpe; gpe=gi->pots + pote; potd=gpe->LorLeaf; gpd=gi->pots + potd; pota=gpd->LorLeaf; potb=gpd->RorPoints; potc=gpe->RorPoints; gpd->LorLeaf=potb; gpd->RorPoints=potc; GeoAdjust(gi,potd); gpe->LorLeaf=pota; gpe->RorPoints=potd; GeoAdjust(gi,pote); } int GeoIndex_insert(GeoIndex * gi, GeoCoordinate * c) { int i,j,js,slot,pot,pot1,pot2; int potx,pota,poty,potz; int lvx,lv1,lva,lvy,lvz; int height,rebalance; GeoDetailedPoint gd; GeoPath gt; GeoPot * gp; GeoPot * gp1; GeoPot * gp2; GeoPot * gpx; GeoPot * gpy; GeoPot * gpz; GeoPot * gpa; GeoString gsa[2]; GeoString mings, gs; rebalance=0; if(c->longitude < -180.0) return -3; if(c->longitude > 180.0) return -3; if(c->latitude < -90.0) return -3; if(c->latitude > 90.0) return -3; GeoMkDetail(gi,&gd,c); i = GeoFind(>,&gd); if(i==1) return -1; pot=gt.path[gt.pathlength-1]; gp=gi->pots + pot; /* new point, so we try to put it in */ slot=GeoIndexNewSlot(gi); if(slot==-2) return -2; /* no room :( */ gi->gc[slot].latitude =c->latitude; gi->gc[slot].longitude=c->longitude; gi->gc[slot].data =c->data; /* check first if we are going to need two new pots, and */ /* if we are, go get them now before we get too tangled */ if(gp->RorPoints == GeoIndexPOTSIZE) { rebalance=1; pot1=GeoIndexNewPot(gi); pot2=GeoIndexNewPot(gi); gp=gi->pots + pot; /* may have re-alloced! */ if( (pot1==-2) || (pot2==-2) ) { GeoIndexFreeSlot(gi,slot); if(pot1!=-2) GeoIndexFreePot(gi,pot1); if(pot2!=-2) GeoIndexFreePot(gi,pot2); return -2; } gp1=gi->pots + pot1; gp2=gi->pots + pot2; /* pot is old one, pot1 and pot2 are the new ones */ gp1->LorLeaf=0; /* leaf pot */ gp1->RorPoints=0; /* no points in it yet */ /* first move the points from pot to pot2 */ gp2->LorLeaf=0; /* leaf pot */ gp2->RorPoints=gp->RorPoints; for(i=0;iRorPoints;i++) gp2->points[i]=gp->points[i]; /* move the first half of the points from pot2 to pot1 */ for(i=0;iRorPoints;j++) { gs=GeoMkHilbert(gi->gc + gp2->points[j]); if(gspoints[gp1->RorPoints]=gp2->points[js]; gp2->points[js]=gp2->points[gp2->RorPoints-1]; gp2->RorPoints--; gp1->RorPoints++; } GeoPopulateMaxdist(gi,gp2,gsa); mings=gsa[0]; GeoPopulateMaxdist(gi,gp1,gsa); mings=(mings+gsa[1])/2ll; gp1->start=gp->start; gp1->end=mings; gp2->start=mings; gp2->end=gp->end; gp->LorLeaf=pot1; gp->RorPoints=pot2; GeoAdjust(gi,pot); gt.pathlength++; if(gd.gspoints[gp->RorPoints]=slot; gp->RorPoints++; /* now propagate the maxdistances */ for(i=0;i=0) { if(gd.fixdist[i] > gi->pots[gt.path[j]].maxdist[i]) gi->pots[gt.path[j]].maxdist[i] = gd.fixdist[i]; else break; j--; } } /* just need to balance the tree */ if(rebalance==0) return 0; height=2; while(1) { potx=GeoGetPot(>,height); gpx=gi->pots + potx; lvx=gpx->level; if(potx==1) break; /* root pot ? */ pot1=GeoGetPot(>,height+1); /* pot1=parent(x) */ gp1=gi->pots + pot1; lv1=gp1->level; if(lv1>lvx) break; if(gp1->LorLeaf==potx) /* gpx is the left child? */ { pota=gp1->RorPoints; /* 1 = (xa) */ gpa=gi->pots+pota; lva=gpa->level; if( (lva+1) == lv1) /* so it is legal to up lev(1) */ { gp1->level++; height++; continue; } poty=gpx->RorPoints; gpy=gi->pots + poty; lvy=gpy->level; potz=gpx->LorLeaf; gpz=gi->pots + potz; lvz=gpz->level; if(lvy<=lvz) { RotateRight(gi,pot1); height++; continue; } RotateLeft(gi,potx); RotateRight(gi,pot1); } else /* gpx is the right child */ { pota=gp1->LorLeaf; /* 1 = (ax) */ gpa=gi->pots+pota; lva=gpa->level; if( (lva+1) == lv1) /* so it is legal to up lev(1) */ { gp1->level++; height++; continue; } poty=gpx->LorLeaf; gpy=gi->pots + poty; lvy=gpy->level; potz=gpx->RorPoints; gpz=gi->pots + potz; lvz=gpz->level; if(lvy<=lvz) { RotateLeft(gi,pot1); height++; continue; } RotateRight(gi,potx); RotateLeft(gi,pot1); } } return 0; } int GeoIndex_remove(GeoIndex * gi, GeoCoordinate * c) { GeoDetailedPoint gd; GeoPot * gp; GeoPath gt; int i,pot,potix,slot,pathix; GeoMkDetail(gi,&gd,c); i = GeoFind(>,&gd); if(i!=1) return -1; pot=gt.path[gt.pathlength-1]; gp=gi->pots + pot; potix = gt.path[gt.pathlength]; slot=gp->points[potix]; GeoIndexFreeSlot(gi,slot); gp->points[potix]=gp->points[gp->RorPoints-1]; gp->RorPoints--; if( (2*gp->RorPoints)0) { pathix--; pot=gt.path[pathix]; GeoAdjust(gi,pot); } return 0; } void GeoIndex_CoordinatesFree(GeoCoordinates * clist) { free(clist->coordinates); free(clist->distances); free(clist); } int GeoIndex_hint(GeoIndex * gi, int hint) { return 0; } #ifdef DEBUG void RecursivePotDump (GeoIndex * gi, FILE * f, int pot) { int i; GeoPot * gp; GeoCoordinate * gc; gp=gi->pots + pot; fprintf(f,"GP. pot %d level %d Kids %d %d\n", pot, gp->level, gp->LorLeaf,gp->RorPoints); fprintf(f,"strings %llx %llx %llx\n",gp->start,gp->middle,gp->end); fprintf(f,"maxdists "); for(i=0;imaxdist[i]); fprintf(f,"\n"); if(gp->LorLeaf==0) { fprintf(f,"Leaf pot containing %d points . . .\n",gp->RorPoints); for(i=0;iRorPoints;i++) { fprintf(f,"Child %d Point %d ",i,gp->points[i]); gc=gi->gc + gp->points[i]; fprintf(f,"Lat. %9.4f, Long. %9.4f", gc->latitude, gc->longitude); #if DEBUG==2 fprintf(f," %s",(char *) gc->data); #endif fprintf(f,"\n"); } } else { fprintf(f,"\nPot %d - Left Child of pot %d\n", gp->LorLeaf,pot); RecursivePotDump (gi,f,gp->LorLeaf); fprintf(f,"\nPot %d - Right Child of pot %d\n", gp->RorPoints,pot); RecursivePotDump (gi,f,gp->RorPoints); } } void GeoIndex_INDEXDUMP (GeoIndex * gi, FILE * f) { fprintf(f,"Dump of entire index. %d pots and %d slots allocated\n", gi->potct, gi->slotct); RecursivePotDump(gi,f,1); } int GeoIndex_INDEXVALID(GeoIndex * gi) { return 0; } #endif /* end of GeoIndex.c */