google-maps-stitch-bin 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/bin/tiler ADDED
@@ -0,0 +1,82 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ $LOAD_PATH.unshift File.join(File.dirname(__FILE__), '..', 'lib')
4
+
5
+ require 'optparse'
6
+ require 'tiler'
7
+
8
+ ###require File.expand_path(File.join(File.dirname(__FILE__), "..", "lib", "tiler"))
9
+
10
+ options = {}
11
+
12
+ optparse = OptionParser.new do |opts|
13
+
14
+ opts.banner = "Usage: tiler.rb [options] ..."
15
+
16
+ opts.on('--start_lat LAT', Float, 'Latitude of startpoint (top left)' ) do |start_lat|
17
+ options[:start_lat] = start_lat
18
+ end
19
+
20
+ opts.on('--start_lon LON', Float, 'Longitude of startpoint (top left)' ) do |start_lon|
21
+ options[:start_lon] = start_lon
22
+ end
23
+
24
+ opts.on('--end_lat LAT', Float, 'Latitude of endpoint (bottom right)' ) do |end_lat|
25
+ options[:end_lat] = end_lat
26
+ end
27
+
28
+ opts.on('--end_lon LON', Float, 'Longitude of endoint (bottom right)' ) do |end_lon|
29
+ options[:end_lon] = end_lon
30
+ end
31
+
32
+ opts.on('--zoom ZOOM_LEVEL', Integer, 'Zoom Level in Google maps') do |zoom|
33
+ if (1..18).include?(zoom)
34
+ options[:zoom] = zoom
35
+ else
36
+ raise OptionParser::InvalidArgument
37
+ end
38
+ end
39
+
40
+ opts.on('--source SOURCE', String, '"map" or "sattelite". Default is "sattelite"') do |source|
41
+ if ["map", "sattelite"].include?(source)
42
+ options[:source] = source
43
+ else
44
+ raise OptionParser::InvalidArgument
45
+ end
46
+ end
47
+
48
+ opts.on('--output FILEPATH', String, 'select output file') do |output|
49
+ options[:output] = output
50
+ end
51
+
52
+
53
+ opts.on( '-h', '--help', 'Display this help' ) do
54
+ puts opts
55
+ exit
56
+ end
57
+ end
58
+
59
+
60
+ begin
61
+ optparse.parse!
62
+ mandatory_opts = [:output, :start_lat, :start_lon, :end_lat, :end_lon, :zoom ]
63
+ missing_opts = mandatory_opts.select { |param| options[param].nil? }
64
+
65
+ if !missing_opts.empty?
66
+ puts
67
+ puts "Missing options: #{missing_opts.join(', ')}"
68
+ puts
69
+ puts optparse
70
+ exit
71
+ end
72
+
73
+ rescue OptionParser::InvalidArgument, OptionParser::InvalidOption, OptionParser::MissingArgument => e
74
+ puts
75
+ puts e.inspect
76
+ puts
77
+ puts optparse
78
+ exit
79
+ end
80
+
81
+ tiler = Tiler.new(options)
82
+ tiler.run
data/lib/tiler/tile.rb ADDED
@@ -0,0 +1,37 @@
1
+ require "tempfile"
2
+ class Tile
3
+
4
+ attr_reader :x, :y, :z
5
+
6
+ attr_accessor :file
7
+
8
+ def initialize(args)
9
+ @x = args[:x]
10
+ @y = args[:y]
11
+ @z = args[:z]
12
+ @source = args[:source] || "sattelite"
13
+ end
14
+
15
+ def remote_url
16
+ "https://khms0.google.com/kh/v=143&src=app&x=#{x}&y=#{y}&z=#{z.to_s}"
17
+ end
18
+
19
+ def download
20
+ open(remote_url) do |image|
21
+ file = Tempfile.new("x_#{x}_y_#{y}_z_#{z}")
22
+ file.write(image.read)
23
+ puts "downloaded #{remote_url} to #{file.path}"
24
+ @file = file
25
+ @local_file_name = file.path
26
+ end
27
+ end
28
+
29
+ def local_file_name
30
+ @local_file_name
31
+ end
32
+
33
+ def downloaded?
34
+ !@local_file_name.nil?
35
+ end
36
+
37
+ end
@@ -0,0 +1,81 @@
1
+ class TilesCollection
2
+
3
+ attr_accessor :zoom, :source, :output_file
4
+ attr_reader :start, :end
5
+
6
+ def initialize(args)
7
+ @zoom = args[:zoom]
8
+ @source = args[:source] || "sattelite"
9
+ @start_x = args[:start_x]
10
+ @start_y = args[:start_y]
11
+ @end_x = args[:end_x]
12
+ @end_y = args[:end_y]
13
+ @output = args[:output]
14
+ save_tiles
15
+ end
16
+
17
+ def tile(x,y)
18
+ @tiles[y][x]
19
+ end
20
+
21
+ def rows
22
+ @start_y.upto(@end_y)
23
+ end
24
+
25
+ def columns
26
+ @start_x.upto(@end_x)
27
+ end
28
+
29
+ def all
30
+ @tiles
31
+ end
32
+
33
+ def flatten
34
+ rows.map do |y|
35
+ columns.map do |x|
36
+ tile(x,y)
37
+ end
38
+ end.flatten
39
+ end
40
+
41
+ def save_tile(x,y,tile)
42
+ @tiles[y] = {} unless @tiles[y]
43
+ @tiles[y][x] = tile
44
+ end
45
+
46
+ def save_tiles
47
+ @tiles = {}
48
+ rows.map do |y|
49
+ columns.map do |x|
50
+ save_tile(x,y,Tile.new(x: x, y: y, z: @zoom))
51
+ end
52
+ end
53
+ end
54
+
55
+ def download
56
+ flatten.each{ |tile| tile.download }
57
+ end
58
+
59
+ def cleanup
60
+ flatten.each do |tile|
61
+ tile.file.close
62
+ tile.file.unlink
63
+ end
64
+ end
65
+
66
+ def stitch
67
+ output_data = Magick::ImageList.new
68
+ columns.each do |column|
69
+ col = Magick::ImageList.new
70
+ rows.each do |row|
71
+ begin
72
+ col.push(Magick::Image.read(tile(column,row).local_file_name).first)
73
+ rescue
74
+ debugger
75
+ end
76
+ end
77
+ output_data.push(col.append(true))
78
+ end
79
+ output_data.append(false).write(@output)
80
+ end
81
+ end
data/lib/tiler.rb ADDED
@@ -0,0 +1,102 @@
1
+ require 'simple_mercator_location'
2
+ require 'open-uri'
3
+ require 'tiler/tile'
4
+ require 'tiler/tiles'
5
+ require 'RMagick'
6
+ require 'debugger'
7
+
8
+
9
+ class Tiler
10
+
11
+ extend Forwardable
12
+
13
+ attr_accessor :zoom,
14
+ :source,
15
+ :output,
16
+ :start_x,
17
+ :start_y,
18
+ :end_x,
19
+ :end_y,
20
+ :start_lat,
21
+ :start_lon,
22
+ :end_lat,
23
+ :end_lon
24
+
25
+
26
+ def_delegator :tiles, :download
27
+ def_delegator :tiles, :stitch
28
+ def_delegator :tiles, :cleanup
29
+
30
+
31
+ def initialize(args = {})
32
+ set_rectangle(args)
33
+ args = defaults.merge(args)
34
+
35
+ self.zoom = args[:zoom]
36
+ self.source = args[:source]
37
+ self.output = args[:output]
38
+ end
39
+
40
+ def defaults
41
+ { zoom: 1, source: "sattelite", start_x: 0, start_y: 0, end_x: 0, end_y: 0}
42
+ end
43
+
44
+ def tiles
45
+ @tiles ||= TilesCollection.new(zoom: zoom, source: source, start_x: start_x, start_y: start_y, end_x: end_x, end_y: end_y, output: output)
46
+ end
47
+
48
+ def run
49
+ download
50
+ stitch
51
+ cleanup
52
+ end
53
+
54
+ private
55
+
56
+ def set_rectangle(args)
57
+ if given_lat_lon?(args)
58
+ set_lat_lon(args)
59
+ set_x_y_from_lat_lon(args)
60
+ elsif given_x_y?(args)
61
+ set_x_y(args)
62
+ end
63
+ end
64
+
65
+ def set_x_y_from_lat_lon(args)
66
+ start = SimpleMercatorLocation.new(lat: args[:start_lat], lon: args[:start_lon], zoom: args[:zoom])
67
+ finish = SimpleMercatorLocation.new(lat: args[:end_lat], lon: args[:end_lon], zoom: args[:zoom])
68
+ self.start_x = start.to_tile.first
69
+ self.start_y = start.to_tile.last
70
+ self.end_x = finish.to_tile.first
71
+ self.end_y = finish.to_tile.last
72
+ end
73
+
74
+ def set_x_y(args)
75
+ self.start_x = args[:start_x]
76
+ self.start_y = args[:start_y]
77
+ self.end_x = args[:end_x]
78
+ self.end_y = args[:end_y]
79
+ end
80
+
81
+ def set_lat_lon(args)
82
+ self.start_lat = args[:start_lat]
83
+ self.start_lon = args[:start_lon]
84
+ self.end_lat = args[:end_lat]
85
+ self.end_lon = args[:end_lon]
86
+ end
87
+
88
+ def given_x_y?(args)
89
+ args.has_key?(:start_x) && args[:start_x].is_a?(Integer) &&
90
+ args.has_key?(:start_y) && args[:start_y].is_a?(Integer) &&
91
+ args.has_key?(:end_x) && args[:end_x].is_a?(Integer) &&
92
+ args.has_key?(:end_y) && args[:end_y].is_a?(Integer)
93
+ end
94
+
95
+ def given_lat_lon?(args)
96
+ args.has_key?(:start_lat) && args[:start_lat].is_a?(Float) &&
97
+ args.has_key?(:start_lon) && args[:start_lon].is_a?(Float) &&
98
+ args.has_key?(:end_lat) && args[:end_lat].is_a?(Float) &&
99
+ args.has_key?(:end_lon) && args[:end_lon].is_a?(Float)
100
+ end
101
+
102
+ end
@@ -0,0 +1,36 @@
1
+ require 'spec_helper'
2
+
3
+ describe Tiler do
4
+
5
+
6
+ describe :initialize do
7
+ context "called without args" do
8
+ it "should not throw an error" do
9
+ expect{Tiler.new}.to_not raise_error
10
+ end
11
+ end
12
+
13
+ context "called with args" do
14
+ it "sets instance variables" do
15
+ t = Tiler.new(zoom: 4)
16
+ expect(t.zoom).to eql 4
17
+ end
18
+ end
19
+ end
20
+
21
+ describe :run do
22
+ let(:tiler) { Tiler.new }
23
+
24
+ before :each do
25
+ tiler.stub :download
26
+ tiler.stub :stitch
27
+ tiler.stub :cleanup
28
+ tiler.stub :create_collection
29
+ end
30
+
31
+ it "calls Tiler#download" do
32
+ expect(tiler).to receive(:download).exactly(1).times
33
+ tiler.run
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,20 @@
1
+ require "rspec"
2
+ require "awesome_print"
3
+ require "debugger"
4
+
5
+ RSpec.configure do |config|
6
+ config.color_enabled = true
7
+ config.filter_run :focus => true
8
+ config.run_all_when_everything_filtered = true
9
+ config.treat_symbols_as_metadata_keys_with_true_values = true
10
+ end
11
+
12
+ def timed(name)
13
+ start = Time.now
14
+ puts "\n[STARTED: #{name}]"
15
+ yield if block_given?
16
+ finish = Time.now
17
+ puts "[FINISHED: #{name} in #{(finish - start) * 1000} milliseconds]"
18
+ end
19
+
20
+ require "tiler"
metadata ADDED
@@ -0,0 +1,70 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: google-maps-stitch-bin
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Roman Lehnert
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2013-12-29 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: rspec
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ~>
20
+ - !ruby/object:Gem::Version
21
+ version: '2.5'
22
+ type: :development
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ~>
28
+ - !ruby/object:Gem::Version
29
+ version: '2.5'
30
+ description: ''
31
+ email: roman.lehnert@googlemail.com
32
+ executables:
33
+ - tiler
34
+ extensions: []
35
+ extra_rdoc_files: []
36
+ files:
37
+ - lib/tiler/tile.rb
38
+ - lib/tiler/tiles.rb
39
+ - lib/tiler.rb
40
+ - spec/lib/tiler_spec.rb
41
+ - spec/spec_helper.rb
42
+ - bin/tiler
43
+ homepage: ''
44
+ licenses:
45
+ - MIT
46
+ post_install_message:
47
+ rdoc_options: []
48
+ require_paths:
49
+ - lib
50
+ required_ruby_version: !ruby/object:Gem::Requirement
51
+ none: false
52
+ requirements:
53
+ - - ! '>='
54
+ - !ruby/object:Gem::Version
55
+ version: '0'
56
+ required_rubygems_version: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ! '>='
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ requirements: []
63
+ rubyforge_project:
64
+ rubygems_version: 1.8.25
65
+ signing_key:
66
+ specification_version: 3
67
+ summary: Get images from google maps
68
+ test_files:
69
+ - spec/lib/tiler_spec.rb
70
+ - spec/spec_helper.rb