Module: MapKit::ZoomLevel::ClassMethods

Includes:
Math
Defined in:
lib/map-kit-wrapper/zoom_level.rb

Overview

Map conversion methods

Instance Method Summary collapse

Instance Method Details

#coordinate_region_with_map_view(map_view, center_coordinate, zoom_level) ⇒ Object

KMapView cannot display tiles that cross the pole This would involve wrapping the map from top to bottom, something that a Mercator projection just cannot do.



72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
# File 'lib/map-kit-wrapper/zoom_level.rb', line 72

def coordinate_region_with_map_view(map_view, center_coordinate, zoom_level)

  # clamp lat/long values to appropriate ranges
  center_coordinate.latitude = [[-90.0, center_coordinate.latitude].max, 90.0].min
  center_coordinate.longitude = center_coordinate.longitude % 180.0

  # convert center coordiate to pixel space
  center_pixel_x = self.longitude_to_pixel_space_x(center_coordinate.longitude)
  center_pixel_y = self.latitude_to_pixel_space_y(center_coordinate.latitude)

  # determine the scale value from the zoom level
  zoom_exponent = 20 - zoom_level
  zoom_scale = 2 ** zoom_exponent

  # scale the map’s size in pixel space
  map_size_in_pixels = map_view.bounds.size
  scaled_map_width = map_size_in_pixels.width * zoom_scale
  scaled_map_height = map_size_in_pixels.height * zoom_scale

  # figure out the position of the left pixel
  top_left_pixel_x = center_pixel_x - (scaled_map_width / 2)

  # find delta between left and right longitudes
  min_lng = self.pixel_space_x_to_longitude(top_left_pixel_x)
  max_lng = self.pixel_space_x_to_longitude(top_left_pixel_x + scaled_map_width)
  longitude_delta = max_lng - min_lng

  # if we’re at a pole then calculate the distance from the pole towards the equator
  # as MKMapView doesn’t like drawing boxes over the poles
  top_pixel_y = center_pixel_y - (scaled_map_height / 2)
  bottom_pixel_y = center_pixel_y + (scaled_map_height / 2)
  adjusted_center_point = false
  if top_pixel_y > MERCATOR_OFFSET * 2
    top_pixel_y = center_pixel_y - scaled_map_height
    bottom_pixel_y = MERCATOR_OFFSET * 2
    adjusted_center_point = true
  end

  # find delta between top and bottom latitudes
  min_lat = self.pixel_space_y_to_latitude(top_pixel_y)
  max_lat = self.pixel_space_y_to_latitude(bottom_pixel_y)
  latitude_delta = -1 * (max_lat - min_lat)

  # create and return the lat/lng span
  span = MKCoordinateSpanMake(latitude_delta, longitude_delta)
  region = MKCoordinateRegionMake(center_coordinate, span)
  # once again, MKMapView doesn’t like drawing boxes over the poles
  # so adjust the center coordinate to the center of the resulting region
  if adjusted_center_point
    region.center.latitude = self.pixel_space_y_to_latitude((bottom_pixel_y + top_pixel_y) / 2.0)
  end

  region
end

#coordinate_span_with_map_view(map_view, center_coordinate, zoom_level) ⇒ Object



37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
# File 'lib/map-kit-wrapper/zoom_level.rb', line 37

def coordinate_span_with_map_view(map_view, center_coordinate, zoom_level)
  # convert center coordiate to pixel space
  center_pixel_x = self.longitude_to_pixel_space_x(center_coordinate.longitude)
  center_pixel_y = self.latitude_to_pixel_space_y(center_coordinate.latitude)

  # determine the scale value from the zoom level
  zoom_exponent = 20 - zoom_level
  zoom_scale = 2 ** zoom_exponent

  # scale the map’s size in pixel space
  map_size_in_pixels = map_view.bounds.size
  scaled_map_width = map_size_in_pixels.width * zoom_scale
  scaled_map_height = map_size_in_pixels.height * zoom_scale

  # figure out the position of the top-left pixel
  top_left_pixel_x = center_pixel_x - (scaled_map_width / 2)
  top_left_pixel_y = center_pixel_y - (scaled_map_height / 2)

  # find delta between left and right longitudes
  min_lng = self.pixel_space_x_to_longitude(top_left_pixel_x)
  max_lng = self.pixel_space_x_to_longitude(top_left_pixel_x + scaled_map_width)
  longitude_delta = max_lng - min_lng

  # find delta between top and bottom latitudes
  min_lat = self.pixel_space_y_to_latitude(top_left_pixel_y)
  max_lat = self.pixel_space_y_to_latitude(top_left_pixel_y + scaled_map_height)
  latitude_delta = -1 * (max_lat - min_lat)

  # create and return the lat/lng span
  MKCoordinateSpanMake(latitude_delta, longitude_delta)
end

#latitude_to_pixel_space_y(latitude) ⇒ Object



19
20
21
22
23
24
25
26
27
# File 'lib/map-kit-wrapper/zoom_level.rb', line 19

def latitude_to_pixel_space_y(latitude)
  if latitude == 90.0
    0
  elsif latitude == -90.0
    MERCATOR_OFFSET * 2
  else
    (MERCATOR_OFFSET - MERCATOR_RADIUS * log((1 + sin(latitude * PI / 180.0)) / (1 - sin(latitude * PI / 180.0))) / 2.0).round
  end
end

#longitude_to_pixel_space_x(longitude) ⇒ Object



15
16
17
# File 'lib/map-kit-wrapper/zoom_level.rb', line 15

def longitude_to_pixel_space_x(longitude)
  (MERCATOR_OFFSET + MERCATOR_RADIUS * longitude * PI / 180.0).round
end

#pixel_space_x_to_longitude(pixel_x) ⇒ Object



29
30
31
# File 'lib/map-kit-wrapper/zoom_level.rb', line 29

def pixel_space_x_to_longitude(pixel_x)
  ((pixel_x.round - MERCATOR_OFFSET) / MERCATOR_RADIUS) * 180.0 / PI
end

#pixel_space_y_to_latitude(pixel_y) ⇒ Object



33
34
35
# File 'lib/map-kit-wrapper/zoom_level.rb', line 33

def pixel_space_y_to_latitude(pixel_y)
  (PI / 2.0 - 2.0 * atan(exp((pixel_y.round - MERCATOR_OFFSET) / MERCATOR_RADIUS))) * 180.0 / PI
end