smappy 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/Gemfile ADDED
@@ -0,0 +1,14 @@
1
+ source :rubygems
2
+
3
+ gemspec
4
+
5
+ gem 'rake'
6
+ gem 'rspec'
7
+ gem 'guard'
8
+ gem 'guard-bundler'
9
+ gem 'guard-rspec'
10
+ gem 'guard-spork'
11
+ gem 'rb-fsevent'
12
+ gem 'rb-readline'
13
+ gem 'fakeweb'
14
+ gem 'vcr'
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright 2011 Eet.nu
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,2 @@
1
+ Smappy
2
+ ------
@@ -0,0 +1,36 @@
1
+ require 'bundler'
2
+
3
+ Bundler.setup
4
+ Bundler.require
5
+
6
+ $LOAD_PATH.unshift File.expand_path("../lib", __FILE__)
7
+ require 'smappy'
8
+
9
+ namespace :smappy do
10
+ desc "Generate an example static map"
11
+ task :generate_example do
12
+ # Compare this image to:
13
+ #
14
+ # * Google Maps: http://maps.google.com/maps/api/staticmap?size=500x350&sensor=false&center=50.9985099,5.857652&zoom=15
15
+ # * OpenStreetMap: http://staticmap.openstreetmap.de/staticmap.php?center=50.9985099,5.857652&zoom=15
16
+ #
17
+ map = Smappy::StaticMap.new(center: [50.9985099, 5.857652], zoomlevel: 15)
18
+
19
+ # Cloudmade tiles:
20
+ map.tile_url_template = 'http://a.tile.cloudmade.com/ed3b3505052b442dba7baff14f1ad671/47664/256/%{zoomlevel}/%{x}/%{y}.png'
21
+
22
+ # Google Maps tiles:
23
+ # map.tile_url_template = 'http://mt1.google.com/vt/x=%{x}&y=%{y}&z=%{zoomlevel}'
24
+
25
+ canvas = map.to_image
26
+ drawing = Magick::Draw.new
27
+
28
+ marker = Smappy::Marker.new(map.center.latitude, map.center.longitude)
29
+ position = marker.position_on_map(map)
30
+
31
+ drawing.composite(position[0], position[1], marker.width, marker.height, marker.marker_image)
32
+ drawing.draw(canvas)
33
+
34
+ canvas.write 'tmp/map.png'
35
+ end
36
+ end
@@ -0,0 +1,8 @@
1
+ module Smappy
2
+ VERSION = '0.0.1'
3
+
4
+ autoload :Location, 'smappy/location'
5
+ autoload :Marker, 'smappy/marker'
6
+ autoload :StaticMap, 'smappy/static_map'
7
+ autoload :Tile, 'smappy/tile'
8
+ end
@@ -0,0 +1,58 @@
1
+ module Smappy
2
+ class Location
3
+ attr_accessor :latitude, :longitude
4
+
5
+ def initialize(latitude, longitude)
6
+ self.latitude = latitude
7
+ self.longitude = longitude
8
+ end
9
+
10
+ def to_tile(options = {})
11
+ tile = Tile.new options
12
+ tile.x = tile_x_at_zoomlevel(tile.zoomlevel)
13
+ tile.y = tile_y_at_zoomlevel(tile.zoomlevel)
14
+ tile
15
+ end
16
+
17
+ def position_on_map(map)
18
+ tile = to_tile(zoomlevel: map.zoomlevel)
19
+ x1, y1 = position_on_tile(tile)
20
+ x2, y2 = tile.position_on_map(map)
21
+
22
+ [x1 + x2, y1 + y2]
23
+ end
24
+
25
+ def position_on_tile(tile)
26
+ x = tile_x_at_zoomlevel(tile.zoomlevel)
27
+ y = tile_y_at_zoomlevel(tile.zoomlevel)
28
+
29
+ [x,y].map do |position|
30
+ ((position - position.to_i) * Tile::SIZE).to_i
31
+ end
32
+ end
33
+
34
+ private
35
+
36
+ def tile_y_at_zoomlevel(zoomlevel)
37
+ (
38
+ (
39
+ 1 - Math.log(
40
+ Math.tan(latitude * Math::PI / 180) +
41
+ 1 / Math.cos(latitude * Math::PI / 180)
42
+ ) / Math::PI
43
+ ) / 2 * 2 ** zoomlevel
44
+ )
45
+ end
46
+
47
+ def tile_x_at_zoomlevel(zoomlevel)
48
+ (
49
+ (
50
+ (longitude + 180) / 360
51
+ ) * (
52
+ 2 ** zoomlevel
53
+ )
54
+ )
55
+ end
56
+ end
57
+ end
58
+
@@ -0,0 +1,39 @@
1
+ require 'open-uri'
2
+ require 'rmagick'
3
+
4
+ module Smappy
5
+ class Marker < Location
6
+ DEFAULT_IMAGE = File.expand_path('../../../markers/information_marker.png', __FILE__)
7
+
8
+ attr_accessor :image, :offset
9
+
10
+ def initialize(latitude, longitude)
11
+ @image = DEFAULT_IMAGE
12
+ @offset = [-(width / 2), -height].map(&:to_i)
13
+
14
+ super
15
+ end
16
+
17
+ def width
18
+ marker_image.columns
19
+ end
20
+
21
+ def height
22
+ marker_image.rows
23
+ end
24
+
25
+ def position_on_map(map)
26
+ x, y = super
27
+
28
+ [x + offset[0], y + offset[1]]
29
+ end
30
+
31
+ # UNTESTED:
32
+ def marker_image
33
+ @marker_image ||= (
34
+ data = open(image).read
35
+ Magick::Image.from_blob(data).first
36
+ )
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,83 @@
1
+ require 'rmagick'
2
+
3
+ module Smappy
4
+ class StaticMap
5
+ DEFAULT_OPTIONS = {
6
+ width: 500,
7
+ height: 350,
8
+ zoomlevel: 0,
9
+ center: [0.0, 0.0]
10
+ }
11
+
12
+ attr_accessor :width, :height, :zoomlevel, :center, :tile_url_template
13
+
14
+ def initialize(options = {})
15
+ options = DEFAULT_OPTIONS.merge(options)
16
+ options.each do |key, value|
17
+ send("#{key}=", value) if respond_to?("#{key}=")
18
+ end
19
+ end
20
+
21
+ def center=(new_value)
22
+ if new_value.is_a?(Location)
23
+ @center = new_value
24
+ else
25
+ @center = Location.new(new_value[0], new_value[1])
26
+ end
27
+ end
28
+
29
+ def center_tile
30
+ center.to_tile zoomlevel: zoomlevel
31
+ end
32
+
33
+ def tile_offset
34
+ center.position_on_tile(center_tile).map do |position|
35
+ position - (Tile::SIZE / 2)
36
+ end
37
+ end
38
+
39
+ def tile_options
40
+ {
41
+ zoomlevel: zoomlevel,
42
+ url_template: tile_url_template
43
+ }.delete_if do |key, value|
44
+ value.nil?
45
+ end
46
+ end
47
+
48
+ def tiles
49
+ # How many tiles do we need to fill the image:
50
+ tile_width = (width / Tile::SIZE).to_i + 1
51
+ tile_height = (height / Tile::SIZE).to_i + 1
52
+
53
+ # What are our first and last tiles:
54
+ tile_x_start = (center_tile.x - (tile_width / 2)).to_i
55
+ tile_x_end = tile_x_start + tile_width
56
+ tile_y_start = (center_tile.y - (tile_height / 2)).to_i
57
+ tile_y_end = tile_y_start + tile_height
58
+
59
+ (tile_x_start..tile_x_end).map do |x|
60
+ (tile_y_start..tile_y_end).map do |y|
61
+ Tile.new(tile_options.merge(x: x, y: y))
62
+ end
63
+ end.flatten.reject do |tile|
64
+ x,y = tile.position_on_map(self)
65
+ (x + Tile::SIZE < 0 || x > width) || (y + Tile::SIZE < 0 || y > height)
66
+ end
67
+ end
68
+
69
+ def to_image
70
+ canvas = Magick::Image.new(width, height)
71
+ drawing = Magick::Draw.new
72
+
73
+ tiles.each do |tile|
74
+ position = tile.position_on_map(self)
75
+ drawing.composite(position[0], position[1], Tile::SIZE, Tile::SIZE, tile.to_image)
76
+ end
77
+
78
+ drawing.draw(canvas)
79
+
80
+ canvas
81
+ end
82
+ end
83
+ end
@@ -0,0 +1,52 @@
1
+ require 'open-uri'
2
+ require 'rmagick'
3
+
4
+ module Smappy
5
+ class Tile
6
+ SIZE = 256
7
+
8
+ DEFAULT_OPTIONS = {
9
+ x: 0,
10
+ y: 0,
11
+ zoomlevel: 0,
12
+ url_template: 'http://tile.openstreetmap.org/%{zoomlevel}/%{x}/%{y}.png'
13
+ }.freeze
14
+
15
+ attr_accessor :zoomlevel, :x, :y, :url_template
16
+
17
+ def initialize(options = {})
18
+ options = DEFAULT_OPTIONS.merge(options)
19
+ options.each do |key, value|
20
+ send("#{key}=", value) if respond_to?("#{key}=")
21
+ end
22
+ end
23
+
24
+ def position_on_map(map)
25
+ center_tile_x = (map.width / 2) - (Tile::SIZE / 2) - map.tile_offset[0]
26
+ center_tile_y = (map.height / 2) - (Tile::SIZE / 2) - map.tile_offset[1]
27
+
28
+ offset_x = (map.center_tile.x - x) * Tile::SIZE
29
+ offset_y = (map.center_tile.y - y) * Tile::SIZE
30
+
31
+ [center_tile_x - offset_x,
32
+ center_tile_y - offset_y]
33
+ end
34
+
35
+ def to_image
36
+ data = open(to_url).read
37
+ Magick::Image.from_blob(data).first
38
+ end
39
+
40
+ def x
41
+ @x.to_i
42
+ end
43
+
44
+ def y
45
+ @y.to_i
46
+ end
47
+
48
+ def to_url
49
+ url_template % { zoomlevel: zoomlevel, x: x, y: y }
50
+ end
51
+ end
52
+ end
metadata ADDED
@@ -0,0 +1,64 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: smappy
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Tom-Eric Gerritsen
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2011-12-22 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: rmagick
16
+ requirement: &70211739392100 !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: *70211739392100
25
+ description: Generate static maps of map tiles.
26
+ email:
27
+ executables: []
28
+ extensions: []
29
+ extra_rdoc_files: []
30
+ files:
31
+ - lib/smappy/location.rb
32
+ - lib/smappy/marker.rb
33
+ - lib/smappy/static_map.rb
34
+ - lib/smappy/tile.rb
35
+ - lib/smappy.rb
36
+ - LICENSE
37
+ - Rakefile
38
+ - Gemfile
39
+ - README.md
40
+ homepage:
41
+ licenses: []
42
+ post_install_message:
43
+ rdoc_options: []
44
+ require_paths:
45
+ - lib
46
+ required_ruby_version: !ruby/object:Gem::Requirement
47
+ none: false
48
+ requirements:
49
+ - - ! '>='
50
+ - !ruby/object:Gem::Version
51
+ version: '0'
52
+ required_rubygems_version: !ruby/object:Gem::Requirement
53
+ none: false
54
+ requirements:
55
+ - - ! '>='
56
+ - !ruby/object:Gem::Version
57
+ version: '0'
58
+ requirements: []
59
+ rubyforge_project:
60
+ rubygems_version: 1.8.10
61
+ signing_key:
62
+ specification_version: 3
63
+ summary: Generate static maps.
64
+ test_files: []