PageRenderTime 37ms CodeModel.GetById 8ms RepoModel.GetById 0ms app.codeStats 0ms

/MapView/Map/RMProjection.m

http://github.com/route-me/route-me
Objective C | 202 lines | 135 code | 37 blank | 30 comment | 21 complexity | d16b609ac19155d3fe70132ea85d927c MD5 | raw file
  1. //
  2. // RMProjection.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 "proj_api.h"
  29. #import "RMProjection.h"
  30. NS_INLINE RMLatLong RMPixelPointAsLatLong(RMProjectedPoint xypoint) {
  31. union _ {RMProjectedPoint xy; RMLatLong latLong;};
  32. return ((union _ *)&xypoint)->latLong;
  33. }
  34. @implementation RMProjection
  35. @synthesize internalProjection;
  36. @synthesize planetBounds;
  37. @synthesize projectionWrapsHorizontally;
  38. - (id) initWithString: (NSString*)params InBounds: (RMProjectedRect) projBounds
  39. {
  40. if (![super init])
  41. return nil;
  42. internalProjection = pj_init_plus([params UTF8String]);
  43. if (internalProjection == NULL)
  44. {
  45. RMLog(@"Unhandled error creating projection. String is %@", params);
  46. [self release];
  47. return nil;
  48. }
  49. planetBounds = projBounds;
  50. projectionWrapsHorizontally = YES;
  51. return self;
  52. }
  53. - (id) initWithString: (NSString*)params
  54. {
  55. RMProjectedRect theBounds;
  56. theBounds = RMMakeProjectedRect(0,0,0,0);
  57. return [self initWithString:params InBounds:theBounds];
  58. }
  59. -(id)init
  60. {
  61. return [self initWithString:@"+proj=latlong +ellps=WGS84"];
  62. }
  63. -(void)dealloc
  64. {
  65. if (internalProjection)
  66. pj_free(internalProjection);
  67. [super dealloc];
  68. }
  69. - (RMProjectedPoint) wrapPointHorizontally: (RMProjectedPoint) aPoint
  70. {
  71. if (!projectionWrapsHorizontally
  72. || planetBounds.size.width == 0.0f || planetBounds.size.height == 0.0f)
  73. return aPoint;
  74. while (aPoint.easting < planetBounds.origin.easting)
  75. aPoint.easting += planetBounds.size.width;
  76. while (aPoint.easting > (planetBounds.origin.easting + planetBounds.size.width))
  77. aPoint.easting -= planetBounds.size.width;
  78. return aPoint;
  79. }
  80. -(RMProjectedPoint) constrainPointToBounds: (RMProjectedPoint) aPoint
  81. {
  82. if (planetBounds.size.width == 0.0f || planetBounds.size.height == 0.0f)
  83. return aPoint;
  84. [self wrapPointHorizontally:aPoint];
  85. if (aPoint.northing < planetBounds.origin.northing)
  86. aPoint.northing = planetBounds.origin.northing;
  87. else if (aPoint.northing > (planetBounds.origin.northing + planetBounds.size.height))
  88. aPoint.northing = planetBounds.origin.northing + planetBounds.size.height;
  89. return aPoint;
  90. }
  91. - (RMProjectedPoint)latLongToPoint:(RMLatLong)aLatLong
  92. {
  93. projUV uv = {
  94. aLatLong.longitude * DEG_TO_RAD,
  95. aLatLong.latitude * DEG_TO_RAD
  96. };
  97. projUV result = pj_fwd(uv, internalProjection);
  98. RMProjectedPoint result_point = {
  99. result.u,
  100. result.v,
  101. };
  102. return result_point;
  103. }
  104. - (RMLatLong)pointToLatLong:(RMProjectedPoint)aPoint
  105. {
  106. projUV uv = {
  107. aPoint.easting,
  108. aPoint.northing,
  109. };
  110. projUV result = pj_inv(uv, internalProjection);
  111. RMLatLong result_coordinate = {
  112. result.v * RAD_TO_DEG,
  113. result.u * RAD_TO_DEG,
  114. };
  115. return result_coordinate;
  116. }
  117. static RMProjection* _google = nil;
  118. static RMProjection* _latlong = nil;
  119. static RMProjection* _osgb = nil;
  120. + (RMProjection*)googleProjection
  121. {
  122. if (_google)
  123. {
  124. return _google;
  125. }
  126. else
  127. {
  128. /// \bug magic numbers embedded in code, this one's probably ok
  129. RMProjectedRect theBounds = RMMakeProjectedRect(-20037508.34, -20037508.34, 20037508.34 * 2, 20037508.34 * 2);
  130. _google = [[RMProjection alloc] initWithString:@"+title= Google Mercator EPSG:900913\
  131. +proj=merc +a=6378137 +b=6378137 +lat_ts=0.0 +lon_0=0.0 +x_0=0.0 +y_0=0 +k=1.0 +units=m +nadgrids=@null +no_defs"
  132. InBounds: theBounds];
  133. return _google;
  134. }
  135. }
  136. + (RMProjection*)EPSGLatLong
  137. {
  138. if (_latlong)
  139. {
  140. return _latlong;
  141. }
  142. else
  143. {
  144. RMProjectedRect theBounds = RMMakeProjectedRect(-kMaxLong, -kMaxLat, 360, kMaxLong);
  145. /// \bug magic numbers embedded in code, this one's probably ok
  146. _latlong = [[RMProjection alloc] initWithString:@"+proj=latlong +ellps=WGS84" InBounds: theBounds];
  147. return _latlong;
  148. }
  149. }
  150. +(RMProjection*) OSGB
  151. {
  152. if (_osgb)
  153. {
  154. return _osgb;
  155. }
  156. else
  157. {// OSGB36 and tmerc
  158. /// \bug TODO: This should use the new initWithString:InBounds: method... but I don't know what the bounds are!
  159. /// \bug magic numbers embedded in code, this one's probably ok
  160. _osgb = [[RMProjection alloc] initWithString:@"+proj=tmerc +lat_0=49 +lon_0=-2 +k=0.999601 +x_0=400000 +y_0=-100000 +ellps=airy +datum=OSGB36 +units=m +no_defs"];
  161. _osgb.projectionWrapsHorizontally = NO;
  162. return _osgb;
  163. }
  164. }
  165. @end