class Pippa::Map
An image-based map class that can be overlain with dots of given area and location given by pixel coordinates, lat/lon, or zipcode (courtesy of federalgovernmentzipcodes.us).
Constants
- TWO_SQRT_1_PI
Attributes
Dot shape. Either :square (default) or :circle
Dot fill color
Dot fill opacity
Height of the map image in pixels
RMagick image for direct manipulation, for example drawing lines and labels
Boolean saying whether to merge markers to eliminate overlaps during rendering.
Base size of dot edges in pixels; defaults to 1. Therefore a unit area is one pixel.
Dot border stroke color name
Dot border stroke width
Width of the map image in pixels
Public Class Methods
Make a new map with given name. See the file maps/_info
or call Pippa#map_names for all possible.
# File lib/pippa.rb, line 143 def initialize(name = 'World') # Set up drawing standards. @point_size = 1 @fill = 'DarkRed' @stroke = 'gray25' @fill_opacity = 0.85 @stroke_width = 1 @anti_alias = false @dot_kind = :square @merge = false @dots = [] # Look up global info or return if none. return unless @map_info = Map.info[:map][name] @image = Image.read("#{File.dirname(__FILE__)}/pippa/maps/#{@map_info[0]}").first @width, @height = @image.columns, @image.rows # Look up projection info, if any. @projection_info = Map.info[:projection][name] end
Write the test map produced by zipcode_map
as png and jpg files.
# File lib/pippa.rb, line 356 def self.write_zipcode_maps(dot_kind = :circle) m = zipcode_map(dot_kind) File.open('spec/data/zipcodes.png', 'wb') { |f| f.write(m.to_png) } m.write_jpg('spec/data/zipcodes.jpg') end
Make a map showing all the zip codes in the USA with dots of fixed area. Also a couple of additional dots.
# File lib/pippa.rb, line 339 def self.zipcode_map(dot_kind = :circle) generator = Random.new(42) # Force same on every run for testing. m = Map.new('USA') m.point_size = 1.5 m.dot_kind = dot_kind m.merge = true Pippa.zips.each_key.each do |zip| m.add_at_zip(zip, 1) end m.fill = 'red' m.fill_opacity = 1 m.add_at_lat_lon(41, -74, 300) # West Point, NY m.add_at_lat_lon(38, -122, 300) # Berkeley, CA m end
Public Instance Methods
Add a dot on the map at given latitude and longitude with given area.
Attributes¶ ↑
-
lat
- Dot latitude -
lon
- Dot longitude -
area
- Optional area, defaults to single pixel
Examples¶ ↑
Make a map and put a dot at West Point, NY.
map = Map.new('USA') map.add_at_lat_lon(41, -74, 100) map.write_png('map.png')
# File lib/pippa.rb, line 217 def add_at_lat_lon(lat, lon, area = 0) add_dot(*lat_lon_to_xy(lat, lon), area) end
Add a dot on the map at given 5-digit zip code.
Attributes¶ ↑
-
zip
- Zipcode -
area
- Optional area, defaults to single pixel
Examples¶ ↑
Make a map and put a dot at West Point, NY.
map = Map.new('USA') map.add_at_zip('10996', 100) map.write_png('map.png')
# File lib/pippa.rb, line 236 def add_at_zip(zip, area = 0) data = Pippa.zips[zip] add_at_lat_lon(data[:lat], data[:lon], area) if data end
Add a dot of given area at the given pixel coordinates.
Attributes¶ ↑
-
x
- Dot x-pixel coordinate -
y
- Dot y-pixel coordinate -
area
- Optional area, defaults to single pixel
Examples¶ ↑
Make a map and put a dot in the middle.
map = Map.new('USA') map.add_dot(map.width/2, map.height/2, 100) map.write_png('map.png')
# File lib/pippa.rb, line 180 def add_dot(x, y, area = 0) @dots << [x, y, area] end
Return the pixel-xy coordinate on this map of a given latitude and longitude.
Attributes¶ ↑
-
lat
- Given latitude -
lon
- Given longitude
Examples¶ ↑
Get the pixel coordinate of West Point, NY.
map = Map.new('USA') x, y = map.lat_lon_to_xy(41, -74)
# File lib/pippa.rb, line 197 def lat_lon_to_xy(lat, lon) set_projection unless @lat_lon_to_xy @lat_lon_to_xy.call(lat, lon) end
# File lib/pippa.rb, line 244 def merged_dots require 'lulu' list = Lulu::MarkerList.new list.set_info(@dot_kind, @point_size) @dots.each {|dot| list.add(*dot) } list.merge list.markers end
Force rendering of all dots added so far onto the map. Then forget them so they’re never rendered again.
# File lib/pippa.rb, line 255 def render return if @image.nil? || @dots.empty? if @merge @dots = merged_dots else @dots.sort! {|a, b| b[2] <=> a[2] } # by area, smallest last end gc = new_gc @dots.each do |x, y, area| diam = @point_size * Math.sqrt(area) diam *= TWO_SQRT_1_PI if @dot_kind == :circle x, y, diam = x.round, y.round, diam.round unless @anti_alias if diam <= 1 gc.point(x, y) else if @dot_kind == :circle gc.circle(x, y, x + diam / 2, y) else h = diam / 2 x1 = x - h y1 = y - h gc.rectangle(x1, y1, x1 + diam, y1 + diam) end end end gc.draw(@image) @dots = [] end
Return true iff we respond to given method. Takes care of to_??? and write_???? converters and writers of graphic formats.
# File lib/pippa.rb, line 286 def respond_to? (sym, include_private = false) conversion_to_format(sym) || writer_to_format(sym) ? true : super end
Return map as a blob with Magick format xxx
. Get a full list of formats with this:
Magick.formats.each {|k,v| puts k if v.include?('*') }
# File lib/pippa.rb, line 300
Write map as graphic file in Magick format xxx. File suffix is not added automatically. Get a full list of formats with this:
Magick.formats.each {|k,v| puts k if v.include?('w') }
# File lib/pippa.rb, line 291