PageRenderTime 56ms CodeModel.GetById 1ms app.highlight 51ms RepoModel.GetById 1ms app.codeStats 0ms

/MapView/Map/RMGeoHash.m

http://github.com/route-me/route-me
Objective C | 164 lines | 120 code | 18 blank | 26 comment | 17 complexity | 110dd113fd7cc77caab8529b6cc2fcc0 MD5 | raw file
  1//
  2//  RMGeoHash.m
  3//
  4// Copyright (c) 2008-2009, Route-Me Contributors
  5// All rights reserved.
  6//
  7// Redistribution and use in source and binary forms, with or without
  8// modification, are permitted provided that the following conditions are met:
  9//
 10// * Redistributions of source code must retain the above copyright notice, this
 11//   list of conditions and the following disclaimer.
 12// * Redistributions in binary form must reproduce the above copyright notice,
 13//   this list of conditions and the following disclaimer in the documentation
 14//   and/or other materials provided with the distribution.
 15//
 16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 17// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 18// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 19// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
 20// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 21// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 22// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 23// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 24// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 25// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 26// POSSIBILITY OF SUCH DAMAGE.
 27#import "RMGlobalConstants.h"
 28#import "RMGeoHash.h"
 29
 30static NSString *BASE32 = @"0123456789bcdefghjkmnpqrstuvwxyz";
 31
 32static NSString *NEIGHBORS[4][2] = 
 33{ { @"bc01fg45238967deuvhjyznpkmstqrwx",@"p0r21436x8zb9dcf5h7kjnmqesgutwvy" },	// right
 34{ @"238967debc01fg45kmstqrwxuvhjyznp",@"14365h7k9dcfesgujnmqp0r2twvyx8zb" },	// left
 35{ @"p0r21436x8zb9dcf5h7kjnmqesgutwvy",@"bc01fg45238967deuvhjyznpkmstqrwx" },	// top
 36{ @"14365h7k9dcfesgujnmqp0r2twvyx8zb",@"238967debc01fg45kmstqrwxuvhjyznp" } };	// bottom
 37
 38static NSString *BORDERS[4][2] = 
 39{ { @"bcfguvyz",@"prxz" },	// right
 40{ @"0145hjnp", @"028b" },	// left
 41{ @"prxz",@"bcfguvyz" },	// top
 42{ @"028b", @"0145hjnp" } };	// bottom
 43
 44@implementation RMGeoHash
 45
 46+ (NSString *) fromLocation: (CLLocationCoordinate2D) loc withPrecision: (NSInteger)precision 
 47{	
 48	BOOL is_even = TRUE;
 49	int bit=0, ch=0;
 50	NSMutableString *geohash = [[[NSMutableString string] retain] autorelease];
 51	
 52	CLLocationCoordinate2D loc1 = { -kMaxLat, -kMaxLong };
 53	CLLocationCoordinate2D loc2 = { kMaxLat, kMaxLong };
 54	CLLocationDegrees mid;
 55	
 56	int hashLen = 0;
 57	while (hashLen < precision) {
 58		if (is_even) {
 59			mid = (loc1.longitude + loc2.longitude) / 2;
 60			if (loc.longitude > mid) {
 61				ch |= 1<<(4-bit);
 62				loc1.longitude = mid;
 63			} else
 64				loc2.longitude = mid;
 65		} else {
 66			mid = (loc1.latitude + loc2.latitude) / 2;
 67			if (loc.latitude > mid) {
 68				ch |= 1<<(4-bit);
 69				loc1.latitude = mid;
 70			} else
 71				loc2.latitude = mid;
 72		}
 73		is_even = !is_even;
 74		if (bit < 4)
 75			bit++;
 76		else {
 77			[geohash appendString: [BASE32 substringWithRange:NSMakeRange(ch, 1)]];
 78			hashLen++;
 79			bit = 0;
 80			ch = 0;
 81		}
 82	}
 83	return geohash;
 84}
 85
 86+ (void) convert: (NSString *)geohash toMin: (CLLocationCoordinate2D *)loc1 max: (CLLocationCoordinate2D *)loc2 
 87{
 88	BOOL is_even = TRUE;	
 89	loc1->latitude  =  -kMaxLat;
 90	loc1->longitude = -kMaxLong;
 91	loc2->latitude = kMaxLat;
 92	loc2->longitude = kMaxLong;
 93	NSRange	range;
 94	int cd, mask;
 95	int geohashLen = [geohash length];
 96	for (int i=0; i<geohashLen; i++) {
 97		range = [BASE32 rangeOfString: [geohash substringWithRange:NSMakeRange(i, 1)]];
 98		cd = range.location;		
 99		for (int j=0; j<5; j++) {
100			mask = 1<<(4-j);
101			if (is_even) {
102				if(cd&mask){
103					loc1->longitude = (loc1->longitude + loc2->longitude)/2;
104				} else {
105					loc2->longitude = (loc1->longitude + loc2->longitude)/2;
106				}
107			} else {
108				if(cd&mask){
109					loc1->latitude = (loc1->latitude + loc2->latitude)/2;
110				} else {
111					loc2->latitude = (loc1->latitude + loc2->latitude)/2;
112				}
113			}
114			is_even = !is_even;
115		}
116	}
117}
118
119+ (NSString *) adjacentOf: (NSString *)srcHash inDir: (RMGeoHashAtDirection) dir 
120{
121	int srcHashLen = [srcHash length];
122	NSString *lastChr = [srcHash substringFromIndex: srcHashLen - 1];
123	int type = srcHashLen & 0x1;
124	NSString *base = [srcHash substringToIndex: srcHashLen - 1];
125	NSRange range = [BORDERS[dir][type] rangeOfString: lastChr];
126	if (range.location != NSNotFound) {
127		base = [RMGeoHash adjacentOf: base inDir: dir];
128	}
129	range = [NEIGHBORS[dir][type] rangeOfString: lastChr];
130	return [base stringByAppendingString: [BASE32 substringWithRange:NSMakeRange(range.location, 1)]];
131}
132
133
134+ (NSArray *) withNeighbors: (NSString *)locHashcode 
135{	
136	NSMutableArray *neighborsHash = [[[NSMutableArray arrayWithCapacity: 9] retain] autorelease];
137	
138	NSString *neighborHash, *neighborHashRight, *neighborHashLeft;
139	
140	[neighborsHash addObject: locHashcode];
141	
142	neighborHash = [RMGeoHash adjacentOf:locHashcode inDir: RMGeoHashAtTop];
143	[neighborsHash addObject: neighborHash];
144	neighborHash = [RMGeoHash adjacentOf:locHashcode inDir: RMGeoHashAtBottom];
145	[neighborsHash addObject: neighborHash];
146	
147	neighborHashLeft = [RMGeoHash adjacentOf:locHashcode inDir: RMGeoHashAtLeft];
148	[neighborsHash addObject: neighborHashLeft];
149	neighborHashRight = [RMGeoHash adjacentOf:locHashcode inDir: RMGeoHashAtRight];
150	[neighborsHash addObject: neighborHashRight];
151	
152	neighborHash = [RMGeoHash adjacentOf: neighborHashLeft inDir: RMGeoHashAtTop];
153	[neighborsHash addObject: neighborHash];
154	neighborHash = [RMGeoHash adjacentOf: neighborHashLeft inDir: RMGeoHashAtBottom];
155	[neighborsHash addObject: neighborHash];
156	neighborHash = [RMGeoHash adjacentOf: neighborHashRight inDir: RMGeoHashAtTop];
157	[neighborsHash addObject: neighborHash];
158	neighborHash = [RMGeoHash adjacentOf: neighborHashRight inDir: RMGeoHashAtBottom];
159	[neighborsHash addObject: neighborHash];
160	
161	return neighborsHash;
162}
163
164@end