PageRenderTime 38ms CodeModel.GetById 19ms RepoModel.GetById 0ms 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. static NSString *BASE32 = @"0123456789bcdefghjkmnpqrstuvwxyz";
  30. static NSString *NEIGHBORS[4][2] =
  31. { { @"bc01fg45238967deuvhjyznpkmstqrwx",@"p0r21436x8zb9dcf5h7kjnmqesgutwvy" }, // right
  32. { @"238967debc01fg45kmstqrwxuvhjyznp",@"14365h7k9dcfesgujnmqp0r2twvyx8zb" }, // left
  33. { @"p0r21436x8zb9dcf5h7kjnmqesgutwvy",@"bc01fg45238967deuvhjyznpkmstqrwx" }, // top
  34. { @"14365h7k9dcfesgujnmqp0r2twvyx8zb",@"238967debc01fg45kmstqrwxuvhjyznp" } }; // bottom
  35. static NSString *BORDERS[4][2] =
  36. { { @"bcfguvyz",@"prxz" }, // right
  37. { @"0145hjnp", @"028b" }, // left
  38. { @"prxz",@"bcfguvyz" }, // top
  39. { @"028b", @"0145hjnp" } }; // bottom
  40. @implementation RMGeoHash
  41. + (NSString *) fromLocation: (CLLocationCoordinate2D) loc withPrecision: (NSInteger)precision
  42. {
  43. BOOL is_even = TRUE;
  44. int bit=0, ch=0;
  45. NSMutableString *geohash = [[[NSMutableString string] retain] autorelease];
  46. CLLocationCoordinate2D loc1 = { -kMaxLat, -kMaxLong };
  47. CLLocationCoordinate2D loc2 = { kMaxLat, kMaxLong };
  48. CLLocationDegrees mid;
  49. int hashLen = 0;
  50. while (hashLen < precision) {
  51. if (is_even) {
  52. mid = (loc1.longitude + loc2.longitude) / 2;
  53. if (loc.longitude > mid) {
  54. ch |= 1<<(4-bit);
  55. loc1.longitude = mid;
  56. } else
  57. loc2.longitude = mid;
  58. } else {
  59. mid = (loc1.latitude + loc2.latitude) / 2;
  60. if (loc.latitude > mid) {
  61. ch |= 1<<(4-bit);
  62. loc1.latitude = mid;
  63. } else
  64. loc2.latitude = mid;
  65. }
  66. is_even = !is_even;
  67. if (bit < 4)
  68. bit++;
  69. else {
  70. [geohash appendString: [BASE32 substringWithRange:NSMakeRange(ch, 1)]];
  71. hashLen++;
  72. bit = 0;
  73. ch = 0;
  74. }
  75. }
  76. return geohash;
  77. }
  78. + (void) convert: (NSString *)geohash toMin: (CLLocationCoordinate2D *)loc1 max: (CLLocationCoordinate2D *)loc2
  79. {
  80. BOOL is_even = TRUE;
  81. loc1->latitude = -kMaxLat;
  82. loc1->longitude = -kMaxLong;
  83. loc2->latitude = kMaxLat;
  84. loc2->longitude = kMaxLong;
  85. NSRange range;
  86. int cd, mask;
  87. int geohashLen = [geohash length];
  88. for (int i=0; i<geohashLen; i++) {
  89. range = [BASE32 rangeOfString: [geohash substringWithRange:NSMakeRange(i, 1)]];
  90. cd = range.location;
  91. for (int j=0; j<5; j++) {
  92. mask = 1<<(4-j);
  93. if (is_even) {
  94. if(cd&mask){
  95. loc1->longitude = (loc1->longitude + loc2->longitude)/2;
  96. } else {
  97. loc2->longitude = (loc1->longitude + loc2->longitude)/2;
  98. }
  99. } else {
  100. if(cd&mask){
  101. loc1->latitude = (loc1->latitude + loc2->latitude)/2;
  102. } else {
  103. loc2->latitude = (loc1->latitude + loc2->latitude)/2;
  104. }
  105. }
  106. is_even = !is_even;
  107. }
  108. }
  109. }
  110. + (NSString *) adjacentOf: (NSString *)srcHash inDir: (RMGeoHashAtDirection) dir
  111. {
  112. int srcHashLen = [srcHash length];
  113. NSString *lastChr = [srcHash substringFromIndex: srcHashLen - 1];
  114. int type = srcHashLen & 0x1;
  115. NSString *base = [srcHash substringToIndex: srcHashLen - 1];
  116. NSRange range = [BORDERS[dir][type] rangeOfString: lastChr];
  117. if (range.location != NSNotFound) {
  118. base = [RMGeoHash adjacentOf: base inDir: dir];
  119. }
  120. range = [NEIGHBORS[dir][type] rangeOfString: lastChr];
  121. return [base stringByAppendingString: [BASE32 substringWithRange:NSMakeRange(range.location, 1)]];
  122. }
  123. + (NSArray *) withNeighbors: (NSString *)locHashcode
  124. {
  125. NSMutableArray *neighborsHash = [[[NSMutableArray arrayWithCapacity: 9] retain] autorelease];
  126. NSString *neighborHash, *neighborHashRight, *neighborHashLeft;
  127. [neighborsHash addObject: locHashcode];
  128. neighborHash = [RMGeoHash adjacentOf:locHashcode inDir: RMGeoHashAtTop];
  129. [neighborsHash addObject: neighborHash];
  130. neighborHash = [RMGeoHash adjacentOf:locHashcode inDir: RMGeoHashAtBottom];
  131. [neighborsHash addObject: neighborHash];
  132. neighborHashLeft = [RMGeoHash adjacentOf:locHashcode inDir: RMGeoHashAtLeft];
  133. [neighborsHash addObject: neighborHashLeft];
  134. neighborHashRight = [RMGeoHash adjacentOf:locHashcode inDir: RMGeoHashAtRight];
  135. [neighborsHash addObject: neighborHashRight];
  136. neighborHash = [RMGeoHash adjacentOf: neighborHashLeft inDir: RMGeoHashAtTop];
  137. [neighborsHash addObject: neighborHash];
  138. neighborHash = [RMGeoHash adjacentOf: neighborHashLeft inDir: RMGeoHashAtBottom];
  139. [neighborsHash addObject: neighborHash];
  140. neighborHash = [RMGeoHash adjacentOf: neighborHashRight inDir: RMGeoHashAtTop];
  141. [neighborsHash addObject: neighborHash];
  142. neighborHash = [RMGeoHash adjacentOf: neighborHashRight inDir: RMGeoHashAtBottom];
  143. [neighborsHash addObject: neighborHash];
  144. return neighborsHash;
  145. }
  146. @end