/MapView/Map/RMGeoHash.m
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