gpx2exif 0.0.4 → 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/Gemfile +1 -1
- data/Gemfile.lock +3 -8
- data/README.md +28 -0
- data/Rakefile +1 -1
- data/VERSION +1 -1
- data/bin/generate_garmin_waypoints +1 -1
- data/bin/geotag_all_images +2 -2
- data/bin/geotag_simulate +2 -2
- data/bin/gpx2png +57 -0
- data/lib/geotagger.rb +9 -0
- data/lib/{gpx2exif → geotagger}/exif_editor.rb +6 -6
- data/lib/{gpx2exif/geo_manager.rb → geotagger/geotagger.rb} +16 -10
- data/lib/geotagger/track_importer.rb +33 -0
- data/lib/gpx2exif.rb +3 -7
- data/lib/gpx2png/base.rb +30 -0
- data/lib/gpx2png/gpx2png.rb +210 -0
- data/lib/gpx2png/osm.rb +51 -0
- data/lib/gpx2png/osm_base.rb +280 -0
- data/lib/gpx2png/renderers/chunky_png_renderer.rb +61 -0
- data/lib/gpx2png/renderers/rmagick_renderer.rb +134 -0
- data/lib/gpx_utils.rb +9 -0
- data/lib/gpx_utils/track_importer.rb +63 -0
- data/lib/{garmin_utils/waypoint_list_generator.rb → gpx_utils/waypoints_exporter.rb} +2 -2
- data/lib/{garmin_utils/gpx_waypoint_parser.rb → gpx_utils/waypoints_importer.rb} +3 -3
- data/lib/mini_exiftool/mini_exiftool.rb +450 -0
- metadata +35 -23
- data/lib/garmin_utils.rb +0 -7
- data/lib/gpx2exif/gpx_parser.rb +0 -71
data/Gemfile
CHANGED
data/Gemfile.lock
CHANGED
@@ -1,9 +1,3 @@
|
|
1
|
-
GIT
|
2
|
-
remote: git://github.com/akwiatkowski/mini_exiftool.git
|
3
|
-
revision: e2ca8e0c3de9190bd08520d6c4204d510963eb54
|
4
|
-
specs:
|
5
|
-
mini_exiftool (1.5.1)
|
6
|
-
|
7
1
|
GEM
|
8
2
|
remote: http://rubygems.org/
|
9
3
|
specs:
|
@@ -14,8 +8,9 @@ GEM
|
|
14
8
|
bundler (~> 1.0)
|
15
9
|
git (>= 1.2.5)
|
16
10
|
rake
|
11
|
+
mini_exiftool (1.5.1)
|
17
12
|
multi_json (1.3.6)
|
18
|
-
nokogiri (1.5.
|
13
|
+
nokogiri (1.5.5)
|
19
14
|
rake (0.9.2.2)
|
20
15
|
rspec (2.3.0)
|
21
16
|
rspec-core (~> 2.3.0)
|
@@ -37,7 +32,7 @@ DEPENDENCIES
|
|
37
32
|
builder
|
38
33
|
bundler (~> 1.0.0)
|
39
34
|
jeweler (~> 1.6.4)
|
40
|
-
mini_exiftool
|
35
|
+
mini_exiftool
|
41
36
|
nokogiri
|
42
37
|
rspec (~> 2.3.0)
|
43
38
|
simplecov
|
data/README.md
CHANGED
@@ -65,6 +65,34 @@ How to use it
|
|
65
65
|
|
66
66
|
generate_garmin_waypoints -y samples/sample_yaml_pois.yml -o file.gpx
|
67
67
|
|
68
|
+
|
69
|
+
Render track with OpenStreetMap
|
70
|
+
---------------------
|
71
|
+
|
72
|
+
You can "convert" your tracks to images using this command.
|
73
|
+
|
74
|
+
How to use it
|
75
|
+
-------------
|
76
|
+
|
77
|
+
1. Please check if you have installed RMagick gem.
|
78
|
+
|
79
|
+
2. Run command.
|
80
|
+
|
81
|
+
gpx2png -g <input GPX file> -s <image size, format: WIDTHxHEIGHT> -o <output PPNG file>
|
82
|
+
|
83
|
+
Example:
|
84
|
+
|
85
|
+
gpx2png -g spec/fixtures/sample.gpx -s 800x600 -o map.png
|
86
|
+
|
87
|
+
3. You can specify zoom.
|
88
|
+
|
89
|
+
gpx2png -g <input GPX file> -z <zoom, best results if between 9 and 15, max 18> -o <output PPNG file>
|
90
|
+
|
91
|
+
Example:
|
92
|
+
|
93
|
+
gpx2png -g spec/fixtures/sample.gpx -z 11 -o map.png
|
94
|
+
|
95
|
+
|
68
96
|
Contributing to gpx2xif
|
69
97
|
-------------------------------
|
70
98
|
|
data/Rakefile
CHANGED
@@ -22,7 +22,7 @@ Jeweler::Tasks.new do |gem|
|
|
22
22
|
gem.email = "bobikx@poczta.fm"
|
23
23
|
gem.authors = ["Aleksander Kwiatkowski"]
|
24
24
|
# dependencies defined in Gemfile
|
25
|
-
gem.executables = ['geotag_all_images', 'geotag_simulate']
|
25
|
+
gem.executables = ['geotag_all_images', 'geotag_simulate', 'generate_garmin_waypoints', 'gpx2png']
|
26
26
|
|
27
27
|
gem.files = FileList[
|
28
28
|
"[A-Z]*", "{bin,generators,lib,test}/**/*"
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.0
|
1
|
+
0.1.0
|
data/bin/geotag_all_images
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
|
3
3
|
require 'rubygems'
|
4
|
-
require '
|
4
|
+
require 'geotagger/geotagger'
|
5
5
|
|
6
6
|
puts "Are you sure? It is evil script which probably eat photos of your dog and family. Uppercase 'yes' and enter if you want to continue."
|
7
7
|
str = gets
|
@@ -12,7 +12,7 @@ time_offset = time_offset.to_i
|
|
12
12
|
|
13
13
|
exit(0) unless str.strip == 'YES'
|
14
14
|
|
15
|
-
g =
|
15
|
+
g = Geotagger::Geotagger.new(verbose: true)
|
16
16
|
g.add_all_files(time_offset)
|
17
17
|
g.match_up
|
18
18
|
g.save!
|
data/bin/geotag_simulate
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
|
3
3
|
require 'rubygems'
|
4
|
-
require '
|
4
|
+
require 'geotagger/geotagger'
|
5
5
|
|
6
6
|
#puts "Are you sure? It is evil script which probably eat photos of your dog and family. Uppercase 'yes' and enter if you want to continue."
|
7
7
|
#str = gets
|
@@ -11,7 +11,7 @@ puts "Do you want to add offset to image time? Default is 0 seconds."
|
|
11
11
|
time_offset = gets
|
12
12
|
time_offset = time_offset.to_i
|
13
13
|
|
14
|
-
g =
|
14
|
+
g = Geotagger::Geotagger.new(verbose: true)
|
15
15
|
g.add_all_files(time_offset)
|
16
16
|
g.match_up
|
17
17
|
g.simulate
|
data/bin/gpx2png
ADDED
@@ -0,0 +1,57 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'rubygems'
|
4
|
+
require 'gpx2exif'
|
5
|
+
require 'gpx2png/osm'
|
6
|
+
require 'optparse'
|
7
|
+
|
8
|
+
options = { }
|
9
|
+
OptionParser.new do |opts|
|
10
|
+
opts.banner = "Usage: gpx2png [options]"
|
11
|
+
|
12
|
+
opts.on("-g", "--gpx FILE", "Input GPX file") do |v|
|
13
|
+
options[:gpx] = v
|
14
|
+
end
|
15
|
+
opts.on("-z", "--zoom ZOOM", "Set zoom") do |v|
|
16
|
+
options[:zoom] = v
|
17
|
+
end
|
18
|
+
opts.on("-s", "--size WIDTHxHEIGHT", "Set output image size (better result)") do |v|
|
19
|
+
options[:size] = v
|
20
|
+
end
|
21
|
+
opts.on("-o", "--output FILE", "Output image file") do |v|
|
22
|
+
options[:output_file] = v
|
23
|
+
end
|
24
|
+
end.parse!
|
25
|
+
|
26
|
+
unless options[:gpx]
|
27
|
+
puts "Input GPX file needed"
|
28
|
+
@fail = true
|
29
|
+
end
|
30
|
+
unless options[:output_file]
|
31
|
+
puts "Output image file needed"
|
32
|
+
@fail = true
|
33
|
+
end
|
34
|
+
if options[:zoom].nil? and options[:size].nil?
|
35
|
+
puts "Zoom or image size needed"
|
36
|
+
@fail = true
|
37
|
+
end
|
38
|
+
|
39
|
+
unless @fail
|
40
|
+
g = GpxUtils::TrackImporter.new
|
41
|
+
g.add_file(options[:gpx])
|
42
|
+
|
43
|
+
e = Gpx2png::Osm.new
|
44
|
+
e.coords = g.coords
|
45
|
+
|
46
|
+
if options[:size]
|
47
|
+
# constant size
|
48
|
+
options[:size] =~ /(\d+)x(\d+)/
|
49
|
+
e.fixed_size($1.to_i, $1.to_i)
|
50
|
+
else
|
51
|
+
# constant zoom
|
52
|
+
e.zoom = options[:zoom].to_i
|
53
|
+
e.renderer_options = {crop_enabled: true}
|
54
|
+
end
|
55
|
+
|
56
|
+
e.save(options[:output_file])
|
57
|
+
end
|
data/lib/geotagger.rb
ADDED
@@ -3,12 +3,13 @@ require 'mini_exiftool'
|
|
3
3
|
|
4
4
|
$:.unshift(File.dirname(__FILE__))
|
5
5
|
|
6
|
-
module
|
6
|
+
module Geotagger
|
7
7
|
class ExifEditor
|
8
8
|
|
9
|
-
def initialize
|
9
|
+
def initialize(options = {})
|
10
10
|
@images = Array.new
|
11
11
|
@global_time_offset = 0
|
12
|
+
@verbose = options[:verbose]
|
12
13
|
end
|
13
14
|
|
14
15
|
attr_reader :images
|
@@ -20,7 +21,7 @@ module Gpx2exif
|
|
20
21
|
:time => get_photo_time(path) + time_offset + @global_time_offset
|
21
22
|
}
|
22
23
|
@images << i
|
23
|
-
puts "Added file #{path}, time #{i[:time]}"
|
24
|
+
puts "Added file #{path}, time #{i[:time]}" if @verbose
|
24
25
|
end
|
25
26
|
|
26
27
|
def get_photo_time(path)
|
@@ -54,14 +55,13 @@ module Gpx2exif
|
|
54
55
|
photo.save
|
55
56
|
|
56
57
|
photo2 = MiniExiftool.new path
|
57
|
-
puts " - coord saved lat #{photo2['GPSLatitude']} lon #{photo2['GPSLongitude']}"
|
58
|
+
puts " - coord saved lat #{photo2['GPSLatitude']} lon #{photo2['GPSLongitude']}" if @verbose
|
58
59
|
|
59
60
|
# exiftool -GPSMapDatum="WGS-84" -gps:GPSLatitude="34,57,57"
|
60
61
|
# -gps:GPSLatitudeRef="N" -gps:GPSLongitude="83,17,59" -gps:GPSLongitudeRef="W"
|
61
62
|
# -gps:GPSAltitudeRef="0" -GPSAltitude=1426 -gps:GPSMeasureMode=2 -City="RabunBald"
|
62
63
|
# -State="North Carolina" -Country="USA" ~/Desktop/RabunBaldSummit_NC.jpg
|
63
|
-
|
64
64
|
end
|
65
65
|
|
66
66
|
end
|
67
|
-
end
|
67
|
+
end
|
@@ -1,15 +1,21 @@
|
|
1
1
|
require 'rubygems'
|
2
|
+
require 'gpx_utils'
|
3
|
+
require 'geotagger/exif_editor'
|
4
|
+
require 'geotagger/track_importer'
|
2
5
|
|
3
6
|
$:.unshift(File.dirname(__FILE__))
|
4
7
|
|
5
|
-
module
|
6
|
-
class
|
8
|
+
module Geotagger
|
9
|
+
class Geotagger
|
7
10
|
|
8
|
-
def initialize
|
11
|
+
def initialize(options = {})
|
12
|
+
@verbose = options[:verbose]
|
9
13
|
@ee = ExifEditor.new
|
10
|
-
@
|
14
|
+
@ti = TrackImporter.new
|
15
|
+
@ti.verbose = @verbose
|
11
16
|
end
|
12
17
|
|
18
|
+
# Add all GPX and images with
|
13
19
|
def add_all_files(time_offset = 0)
|
14
20
|
# add all GPX
|
15
21
|
Dir.glob("**/*.GPX", File::FNM_CASEFOLD).each do |f|
|
@@ -26,7 +32,7 @@ module Gpx2exif
|
|
26
32
|
end
|
27
33
|
|
28
34
|
def add_gpx_file(path)
|
29
|
-
@
|
35
|
+
@ti.add_file(path)
|
30
36
|
end
|
31
37
|
|
32
38
|
def add_image(path, time_offset = 0)
|
@@ -35,10 +41,10 @@ module Gpx2exif
|
|
35
41
|
|
36
42
|
def match_up
|
37
43
|
@ee.images.each do |i|
|
38
|
-
puts "* searching for #{i[:path]}, time #{i[:time]}"
|
39
|
-
i[:coord] = @
|
44
|
+
puts "* searching for #{i[:path]}, time #{i[:time]}" if @verbose
|
45
|
+
i[:coord] = @ti.find_by_time(i[:time])
|
40
46
|
if i[:coord].nil?
|
41
|
-
puts " - not found"
|
47
|
+
puts " - not found" if @verbose
|
42
48
|
end
|
43
49
|
end
|
44
50
|
|
@@ -48,7 +54,7 @@ module Gpx2exif
|
|
48
54
|
def save!
|
49
55
|
@ee.images.each do |i|
|
50
56
|
if not i[:coord].nil?
|
51
|
-
puts "! saving for #{i[:path]}"
|
57
|
+
puts "! saving for #{i[:path]}" if @verbose
|
52
58
|
@ee.set_photo_coords_internal(i)
|
53
59
|
end
|
54
60
|
|
@@ -57,7 +63,7 @@ module Gpx2exif
|
|
57
63
|
|
58
64
|
def simulate
|
59
65
|
to_process = @ee.images.select { |i| not i[:coord].nil? }
|
60
|
-
puts "Result: to update #{to_process.size} from #{@ee.images.size}"
|
66
|
+
puts "Result: to update #{to_process.size} from #{@ee.images.size}" if @verbose
|
61
67
|
end
|
62
68
|
|
63
69
|
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'nokogiri'
|
3
|
+
|
4
|
+
$:.unshift(File.dirname(__FILE__))
|
5
|
+
|
6
|
+
# Simple parsing GPX file
|
7
|
+
module Geotagger
|
8
|
+
class TrackImporter < GpxUtils::TrackImporter
|
9
|
+
|
10
|
+
THRESHOLD = 5*60
|
11
|
+
|
12
|
+
attr_accessor :verbose
|
13
|
+
|
14
|
+
# Only import valid coords
|
15
|
+
def self.coord_valid?(lat, lon, elevation, time)
|
16
|
+
return true if lat and lon and time
|
17
|
+
return false
|
18
|
+
end
|
19
|
+
|
20
|
+
def find_by_time(time)
|
21
|
+
selected_coords = @coords.select { |c| (c[:time].localtime - time.localtime).abs < THRESHOLD }
|
22
|
+
selected_coords = selected_coords.sort { |a, b| (a[:time].localtime - time.localtime).abs <=> (b[:time].localtime - time.localtime).abs }
|
23
|
+
puts " - found #{selected_coords.size} coords within #{THRESHOLD}s from image time" if @verbose
|
24
|
+
if selected_coords.size > 0
|
25
|
+
puts " - best is #{selected_coords.first[:time].localtime}, time offset #{selected_coords.first[:time].localtime - time.localtime}" if @verbose
|
26
|
+
puts " - lat #{selected_coords.first[:lat]} lon #{selected_coords.first[:lon]}" if @verbose
|
27
|
+
end
|
28
|
+
|
29
|
+
return selected_coords.first
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
33
|
+
end
|
data/lib/gpx2exif.rb
CHANGED
data/lib/gpx2png/base.rb
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
|
3
|
+
$:.unshift(File.dirname(__FILE__))
|
4
|
+
|
5
|
+
module Gpx2png
|
6
|
+
class Base
|
7
|
+
|
8
|
+
def initialize
|
9
|
+
@coords = Array.new
|
10
|
+
@zoom = 9
|
11
|
+
@verbose = true
|
12
|
+
end
|
13
|
+
|
14
|
+
def add(lat, lon)
|
15
|
+
@coords << { lat: lat, lon: lon }
|
16
|
+
end
|
17
|
+
|
18
|
+
attr_accessor :zoom, :color, :coords
|
19
|
+
|
20
|
+
# Some math stuff
|
21
|
+
def self.rad2deg(rad)
|
22
|
+
return rad * 180.0 / Math::PI
|
23
|
+
end
|
24
|
+
|
25
|
+
def self.deg2rad(deg)
|
26
|
+
return deg * Math::PI / 180.0
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,210 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'chunky_png'
|
3
|
+
require 'net/http'
|
4
|
+
require "uri"
|
5
|
+
|
6
|
+
|
7
|
+
$:.unshift(File.dirname(__FILE__))
|
8
|
+
|
9
|
+
module Gpx2png
|
10
|
+
class Gpx2png
|
11
|
+
|
12
|
+
TILE_WIDTH = 256
|
13
|
+
TILE_HEIGHT = 256
|
14
|
+
|
15
|
+
def initialize
|
16
|
+
@coords = Array.new
|
17
|
+
@zoom = 9
|
18
|
+
@color = ChunkyPNG::Color.from_hex('#FF0000')
|
19
|
+
end
|
20
|
+
|
21
|
+
def add(lat, lon)
|
22
|
+
@coords << { lat: lat, lon: lon }
|
23
|
+
end
|
24
|
+
|
25
|
+
attr_accessor :zoom, :color, :coords
|
26
|
+
|
27
|
+
def dev
|
28
|
+
zoom = 15
|
29
|
+
@coords.collect { |c|
|
30
|
+
{
|
31
|
+
url: self.class.url(zoom, [c[:lat], c[:lon]]),
|
32
|
+
tile: self.class.convert(zoom, [c[:lat], c[:lon]]),
|
33
|
+
return: self.class.reverse_convert(zoom,
|
34
|
+
self.class.convert(zoom, [c[:lat], c[:lon]])
|
35
|
+
),
|
36
|
+
point: self.class.point_on_image(zoom, [c[:lat], c[:lon]])
|
37
|
+
}
|
38
|
+
}
|
39
|
+
end
|
40
|
+
|
41
|
+
def to_png(filename)
|
42
|
+
download_and_join_tiles
|
43
|
+
@full_image.save(filename)
|
44
|
+
filename
|
45
|
+
end
|
46
|
+
|
47
|
+
# http://wiki.openstreetmap.org/wiki/Slippy_map_tilenames#X_and_Y
|
48
|
+
def self.convert(zoom, coord)
|
49
|
+
lat_deg, lon_deg = coord
|
50
|
+
lat_rad = deg2rad(lat_deg)
|
51
|
+
x = (((lon_deg + 180) / 360) * (2 ** zoom)).floor
|
52
|
+
y = ((1 - Math.log(Math.tan(lat_rad) + 1 / Math.cos(lat_rad)) / Math::PI) /2 * (2 ** zoom)).floor
|
53
|
+
|
54
|
+
return [x, y]
|
55
|
+
end
|
56
|
+
|
57
|
+
def self.url_convert(zoom, coord, server = 'b.')
|
58
|
+
x, y = convert(zoom, coord)
|
59
|
+
url(zoom, [x, y], server)
|
60
|
+
end
|
61
|
+
|
62
|
+
def self.url(zoom, coord, server = 'b.')
|
63
|
+
x, y = coord
|
64
|
+
url = "http://#{server}tile.openstreetmap.org\/#{zoom}\/#{x}\/#{y}.png"
|
65
|
+
return url
|
66
|
+
end
|
67
|
+
|
68
|
+
# top-left corner
|
69
|
+
def self.reverse_convert(zoom, coord)
|
70
|
+
x, y = coord
|
71
|
+
n = 2 ** zoom
|
72
|
+
lon_deg = x.to_f / n.to_f * 360.0 - 180.0
|
73
|
+
lat_deg = rad2deg(Math.atan(Math.sinh(Math::PI * (1.to_f - 2.to_f * y.to_f / n.to_f))))
|
74
|
+
return [lat_deg, lon_deg]
|
75
|
+
end
|
76
|
+
|
77
|
+
# return where you should put point on tile
|
78
|
+
def self.point_on_image(zoom, geo_coord)
|
79
|
+
osm_tile_coord = convert(zoom, geo_coord)
|
80
|
+
top_left_corner = reverse_convert(zoom, osm_tile_coord)
|
81
|
+
bottom_right_corner = reverse_convert(zoom, [
|
82
|
+
osm_tile_coord[0] + 1, osm_tile_coord[1] + 1
|
83
|
+
])
|
84
|
+
|
85
|
+
# some line y = ax + b math
|
86
|
+
|
87
|
+
x_geo = geo_coord[1]
|
88
|
+
# offset
|
89
|
+
x_offset = x_geo - top_left_corner[1]
|
90
|
+
# scale
|
91
|
+
x_distance = (bottom_right_corner[1] - top_left_corner[1])
|
92
|
+
x = (TILE_WIDTH.to_f * (x_offset / x_distance)).round
|
93
|
+
|
94
|
+
y_geo = geo_coord[0]
|
95
|
+
# offset
|
96
|
+
y_offset = y_geo - top_left_corner[0]
|
97
|
+
# scale
|
98
|
+
y_distance = (bottom_right_corner[0] - top_left_corner[0])
|
99
|
+
y = (TILE_HEIGHT.to_f * (y_offset / y_distance)).round
|
100
|
+
|
101
|
+
return { osm_title_coord: osm_tile_coord, pixel_offset: [x, y] }
|
102
|
+
end
|
103
|
+
|
104
|
+
|
105
|
+
attr_reader :lat_min, :lat_max, :lon_min, :lon_max
|
106
|
+
attr_reader :tile_x_distance, :tile_y_distance
|
107
|
+
|
108
|
+
def download_and_join_tiles
|
109
|
+
@lat_min = @coords.collect { |c| c[:lat] }.min
|
110
|
+
@lat_max = @coords.collect { |c| c[:lat] }.max
|
111
|
+
@lon_min = @coords.collect { |c| c[:lon] }.min
|
112
|
+
@lon_max = @coords.collect { |c| c[:lon] }.max
|
113
|
+
|
114
|
+
@border_tiles = [
|
115
|
+
self.class.convert(@zoom, [@lat_min, @lon_min]),
|
116
|
+
self.class.convert(@zoom, [@lat_max, @lon_max])
|
117
|
+
]
|
118
|
+
|
119
|
+
@tile_x_range = (@border_tiles[0][0])..(@border_tiles[1][0])
|
120
|
+
@tile_y_range = (@border_tiles[1][1])..(@border_tiles[0][1])
|
121
|
+
|
122
|
+
# new image
|
123
|
+
@full_image_x = (1 + @tile_x_range.max - @tile_x_range.min) * TILE_WIDTH
|
124
|
+
@full_image_y = (1 + @tile_y_range.max - @tile_y_range.min) * TILE_HEIGHT
|
125
|
+
puts "Output image dimension #{@full_image_x}x#{@full_image_y}"
|
126
|
+
@full_image = ChunkyPNG::Image.new(
|
127
|
+
@full_image_x,
|
128
|
+
@full_image_y,
|
129
|
+
ChunkyPNG::Color::WHITE
|
130
|
+
)
|
131
|
+
|
132
|
+
# {:x, :y, :blob}
|
133
|
+
@images = Array.new
|
134
|
+
|
135
|
+
@tile_x_range.each do |x|
|
136
|
+
@tile_y_range.each do |y|
|
137
|
+
url = self.class.url(@zoom, [x,y])
|
138
|
+
|
139
|
+
# blob time
|
140
|
+
uri = URI.parse(url)
|
141
|
+
response = Net::HTTP.get_response(uri)
|
142
|
+
blob = response.body
|
143
|
+
image = ChunkyPNG::Image.from_blob(blob)
|
144
|
+
|
145
|
+
@images << {
|
146
|
+
url: url,
|
147
|
+
image: image,
|
148
|
+
x: x,
|
149
|
+
y: y
|
150
|
+
}
|
151
|
+
|
152
|
+
# compose image
|
153
|
+
x_offset = (x - @tile_x_range.min) * TILE_WIDTH
|
154
|
+
y_offset = (y - @tile_y_range.min) * TILE_HEIGHT
|
155
|
+
@full_image.compose!(
|
156
|
+
image,
|
157
|
+
x_offset,
|
158
|
+
y_offset
|
159
|
+
)
|
160
|
+
|
161
|
+
puts "processed #{x - @tile_x_range.min}x#{y - @tile_y_range.min} (max #{@tile_x_range.max - @tile_x_range.min}x#{@tile_y_range.max - @tile_y_range.min})"
|
162
|
+
end
|
163
|
+
end
|
164
|
+
|
165
|
+
# sweet, image is joined
|
166
|
+
|
167
|
+
# add some coords to the map
|
168
|
+
(1...@coords.size).each do |i|
|
169
|
+
lat_from = @coords[i-1][:lat]
|
170
|
+
lon_from = @coords[i-1][:lon]
|
171
|
+
|
172
|
+
lat_to = @coords[i][:lat]
|
173
|
+
lon_to = @coords[i][:lon]
|
174
|
+
|
175
|
+
point_from = self.class.point_on_image(@zoom, [lat_from, lon_from])
|
176
|
+
point_to = self.class.point_on_image(@zoom, [lat_to, lon_to])
|
177
|
+
# { osm_title_coord: osm_tile_coord, pixel_offset: [x, y] }
|
178
|
+
|
179
|
+
# first point
|
180
|
+
bitmap_xa = (point_from[:osm_title_coord][0] - @tile_x_range.min) * TILE_WIDTH + point_from[:pixel_offset][0]
|
181
|
+
bitmap_ya = (point_from[:osm_title_coord][1] - @tile_y_range.min) * TILE_HEIGHT + point_from[:pixel_offset][1]
|
182
|
+
bitmap_xb = (point_to[:osm_title_coord][0] - @tile_x_range.min) * TILE_WIDTH + point_to[:pixel_offset][0]
|
183
|
+
bitmap_yb = (point_to[:osm_title_coord][1] - @tile_y_range.min) * TILE_HEIGHT + point_to[:pixel_offset][1]
|
184
|
+
|
185
|
+
@full_image.line(
|
186
|
+
bitmap_xa, bitmap_ya,
|
187
|
+
bitmap_xb, bitmap_yb,
|
188
|
+
@color
|
189
|
+
)
|
190
|
+
|
191
|
+
end
|
192
|
+
end
|
193
|
+
|
194
|
+
def expand_map
|
195
|
+
# TODO expand min and max ranges
|
196
|
+
end
|
197
|
+
|
198
|
+
|
199
|
+
# Some math stuff
|
200
|
+
def self.rad2deg(rad)
|
201
|
+
return rad * 180.0 / Math::PI
|
202
|
+
end
|
203
|
+
|
204
|
+
def self.deg2rad(deg)
|
205
|
+
return deg * Math::PI / 180.0
|
206
|
+
end
|
207
|
+
|
208
|
+
|
209
|
+
end
|
210
|
+
end
|