module Gpx2png::Calculations::OsmClassMethods

Constants

TILE_HEIGHT
TILE_WIDTH

Public Instance Methods

calc_zoom(lat_min, lat_max, lon_min, lon_max, width, height) click to toggle source

Lazy calc proper zoom for drawing

# File lib/gpx2png/calculations/osm_class_methods.rb, line 34
def calc_zoom(lat_min, lat_max, lon_min, lon_max, width, height)
  # because I'm lazy! :] and math is not my best side

  last_zoom = 2
  (5..18).each do |zoom|
    # calculate drawing tile size and pixel size
    tile_min = point_on_absolute_image(zoom, [lat_min, lon_min])
    tile_max = point_on_absolute_image(zoom, [lat_max, lon_max])
    current_pixel_x_distance = tile_max[0] - tile_min[0]
    current_pixel_y_distance = tile_min[1] - tile_max[1]
    if current_pixel_x_distance > width or current_pixel_y_distance > height
      logger.debug "Calculated best zoom #{last_zoom.to_s.red}"
      return last_zoom
    end
    last_zoom = zoom
  end
  return 18
end
convert(zoom, coord) click to toggle source

wiki.openstreetmap.org/wiki/Slippy_map_tilenames#X_and_Y Convert latlon deg to OSM tile coords

# File lib/gpx2png/calculations/osm_class_methods.rb, line 10
def convert(zoom, coord)
  lat_deg, lon_deg = coord
  lat_rad = deg2rad(lat_deg)
  x = (((lon_deg + 180) / 360) * (2 ** zoom)).floor
  y = ((1 - Math.log(Math.tan(lat_rad) + 1 / Math.cos(lat_rad)) / Math::PI) /2 * (2 ** zoom)).floor

  logger.debug "Converted #{lat_deg.to_s.green},#{lat_deg.to_s.green} to [#{x.to_s.red},#{y.to_s.red}]"

  return [x, y]
end
point_on_absolute_image(zoom, geo_coord) click to toggle source

Useful for calculating distance on output image It is not position on output image because we don’t know tile coords For upper-left tile

# File lib/gpx2png/calculations/osm_class_methods.rb, line 86
def point_on_absolute_image(zoom, geo_coord)
  _p = point_on_image(zoom, geo_coord)
  _x = _p[:osm_title_coord][0] * TILE_WIDTH + _p[:pixel_offset][0]
  _y = _p[:osm_title_coord][1] * TILE_WIDTH + _p[:pixel_offset][1]

  logger.debug("Point on abs. image: zoom #{zoom.to_s.green}, coord #{geo_coord[0].to_s.green},#{geo_coord[1].to_s.green} => [#{_x.to_s.red}, #{_y.to_s.red}]")

  return [_x, _y]
end
point_on_image(zoom, geo_coord) click to toggle source

Convert latlon deg coords to image point (x,y) and OSM tile coord return where you should put point on tile

# File lib/gpx2png/calculations/osm_class_methods.rb, line 55
def point_on_image(zoom, geo_coord)
  osm_tile_coord = convert(zoom, geo_coord)
  top_left_corner = reverse_convert(zoom, osm_tile_coord)
  bottom_right_corner = reverse_convert(zoom, [
    osm_tile_coord[0] + 1, osm_tile_coord[1] + 1
  ])

  # some line math: y = ax + b

  x_geo = geo_coord[1]
  # offset
  x_offset = x_geo - top_left_corner[1]
  # scale
  x_distance = (bottom_right_corner[1] - top_left_corner[1])
  x = (TILE_WIDTH.to_f * (x_offset / x_distance)).round

  y_geo = geo_coord[0]
  # offset
  y_offset = y_geo - top_left_corner[0]
  # scale
  y_distance = (bottom_right_corner[0] - top_left_corner[0])
  y = (TILE_HEIGHT.to_f * (y_offset / y_distance)).round

  logger.debug("Point on image: zoom #{zoom.to_s.green}, coord #{geo_coord[0].to_s.green},#{geo_coord[1].to_s.green} => [#{x.to_s.red}, #{y.to_s.red}]")

  return { osm_title_coord: osm_tile_coord, pixel_offset: [x, y] }
end
reverse_convert(zoom, coord) click to toggle source

Convert OSM tile coords to latlon deg in top-left corner

# File lib/gpx2png/calculations/osm_class_methods.rb, line 22
def reverse_convert(zoom, coord)
  x, y = coord
  n = 2 ** zoom
  lon_deg = x.to_f / n.to_f * 360.0 - 180.0
  lat_deg = rad2deg(Math.atan(Math.sinh(Math::PI * (1.to_f - 2.to_f * y.to_f / n.to_f))))

  logger.debug "Reverse converted [#{x.to_s.red},#{y.to_s.red}] to #{lat_deg.to_s.green},#{lat_deg.to_s.green}"

  return [lat_deg, lon_deg]
end