map_print 0.3.0 → 0.9.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 73eaf58e1ffe788eac9f34f197ba18e682548f15
4
- data.tar.gz: 3746ee55d0e44f920ce4db99259bf544451abf2e
3
+ metadata.gz: 071baa0acdcea17783abc5c2a0cd40b5a7bead82
4
+ data.tar.gz: 397e7e367a66af93f2abc590aaf462fb4afa94d5
5
5
  SHA512:
6
- metadata.gz: 9a44c54c8f966d3253229399532f431f04b1e56c1d5489af27799075700db9dd2677de5b8f292d50f56f89016aa70fade5fd743cc242207d393b8b512e1e04a2
7
- data.tar.gz: 838a40807d303bda6cf4d11fc361959909d1c115e83167512a9b728831f176ac14ae04ea449bc2e543c76edfa4f28910437876bc5f25163c845c914a68046eda
6
+ metadata.gz: e77dcb704714848b51dc7a2bde3f0e0c42557a0735284f005cccdf3608395e33b93f7ac2bfaefa27e508d26a947c5e71d971bff3f3032060829a4d2d0836fccc
7
+ data.tar.gz: 4afb485eb8225eec40a8d50d8853f4f8d456df08e1b87a610b9acf6fc89f833873a6d81fc80e71f8afc52a182a01bd1e50d81c6bfed58fba10e0f9f92899d63b
data/.gitignore CHANGED
@@ -1,5 +1,7 @@
1
1
  *.gem
2
+ *.log
2
3
  *.rbc
4
+ /cache/
3
5
  /.config
4
6
  /coverage/
5
7
  /InstalledFiles
data/.travis.yml ADDED
@@ -0,0 +1,4 @@
1
+ language: ruby
2
+ rvm:
3
+ - 2.0.0
4
+ - 2.1
data/Gemfile CHANGED
@@ -2,3 +2,5 @@ source 'https://rubygems.org'
2
2
 
3
3
  # Specify your gem's dependencies in map_print.gemspec
4
4
  gemspec
5
+
6
+ gem 'codeclimate-test-reporter', group: :test, require: nil
data/Gemfile.lock CHANGED
@@ -1,8 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- map_print (0.2.1)
5
- geo-distance (~> 0.1)
4
+ map_print (0.9.0)
6
5
  mini_magick (~> 4.3)
7
6
  parallel (~> 1.6)
8
7
  prawn (~> 2.0)
@@ -12,30 +11,16 @@ PATH
12
11
  GEM
13
12
  remote: https://rubygems.org/
14
13
  specs:
15
- activesupport (4.2.5)
16
- i18n (~> 0.7)
17
- json (~> 1.7, >= 1.7.7)
18
- minitest (~> 5.1)
19
- thread_safe (~> 0.3, >= 0.3.4)
20
- tzinfo (~> 1.1)
21
- geo-distance (0.2.0)
22
- geo_point (~> 0.2.5)
23
- geo_units (~> 0.2.4.1)
24
- geo_calc (0.7.6)
25
- activesupport (>= 3.0.1)
26
- geo_units (~> 0.2.1)
27
- i18n
28
- require_all (~> 1.2.0)
29
- sugar-high (~> 0.4.6.3)
30
- geo_point (0.2.5)
31
- geo_calc (~> 0.7.5)
32
- geo_units (~> 0.2.1)
33
- geo_units (0.2.4.1)
34
- sugar-high (~> 0.4.6.2)
35
- i18n (0.7.0)
14
+ addressable (2.4.0)
15
+ codeclimate-test-reporter (0.4.8)
16
+ simplecov (>= 0.7.1, < 1.0.0)
17
+ crack (0.4.3)
18
+ safe_yaml (~> 1.0.0)
19
+ docile (1.1.5)
20
+ hashdiff (0.2.3)
36
21
  json (1.8.3)
37
- mini_magick (4.3.6)
38
- minitest (5.8.2)
22
+ mini_magick (4.4.0)
23
+ minitest (5.8.4)
39
24
  parallel (1.6.1)
40
25
  pdf-core (0.6.0)
41
26
  prawn (2.0.2)
@@ -44,24 +29,31 @@ GEM
44
29
  prawn-fast-png (0.2.3)
45
30
  prawn
46
31
  rmagick
47
- rake (10.4.2)
48
- require_all (1.2.1)
32
+ rake (10.5.0)
49
33
  rmagick (2.15.4)
50
- sugar-high (0.4.6.4)
34
+ safe_yaml (1.0.4)
35
+ simplecov (0.11.2)
36
+ docile (~> 1.1.0)
37
+ json (~> 1.8)
38
+ simplecov-html (~> 0.10.0)
39
+ simplecov-html (0.10.0)
51
40
  thor (0.19.1)
52
- thread_safe (0.3.5)
53
41
  ttfunk (1.4.0)
54
- tzinfo (1.2.2)
55
- thread_safe (~> 0.1)
42
+ webmock (1.22.6)
43
+ addressable (>= 2.3.6)
44
+ crack (>= 0.3.2)
45
+ hashdiff
56
46
 
57
47
  PLATFORMS
58
48
  ruby
59
49
 
60
50
  DEPENDENCIES
61
51
  bundler (~> 1.10)
52
+ codeclimate-test-reporter
62
53
  map_print!
63
54
  minitest (~> 5.8)
64
55
  rake (~> 10.0)
56
+ webmock (= 1.22.6)
65
57
 
66
58
  BUNDLED WITH
67
59
  1.10.6
data/README.md CHANGED
@@ -1,6 +1,9 @@
1
1
  # MapPrint
2
2
 
3
3
  [![Gem Version](https://badge.fury.io/rb/map_print.svg)](https://badge.fury.io/rb/map_print)
4
+ [![Build Status](https://travis-ci.org/afast/map_print.svg)](https://travis-ci.org/afast/map_print)
5
+ [![Code Climate](https://codeclimate.com/github/afast/map_print/badges/gpa.svg)](https://codeclimate.com/github/afast/map_print)
6
+ [![Test Coverage](https://codeclimate.com/github/afast/map_print/badges/coverage.svg)](https://codeclimate.com/github/afast/map_print/coverage)
4
7
 
5
8
  MapPrint allows for exporting many map sources and GeoJSON to a pdf file. Allowing to specify map element, text/image elements as well as printing a legend with the reference and a scale bar.
6
9
 
@@ -34,15 +37,62 @@ This is intended to be more of a testing method as it doesn't support all the op
34
37
 
35
38
  ### In ruby code
36
39
 
37
- The mos common usage you'll be expecting is to create a new instance with the map configuration and then call `print` with the output path. MapPrint will take the map configuration, generate the map and write the output to the output path. In the example below `./map.png`.
40
+ The most common usage will be creating a new instance with the map configuration and then call `print` with the output path. MapPrint will take the map configuration, generate the map and write the output to the output path. In the example below `./map.png`.
38
41
 
39
42
  ```ruby
40
- MapPrint::Core.new(map_configuration).print('./map.png')```
43
+ MapPrint::Core.new(map_configuration).print('./map.png')
44
+ ```
45
+
46
+ `map_configuration` is a hash which contains all the necessary fields to print a map.
47
+ For detailed information about what `map_print` expects in a hash please look at the [wiki](https://github.com/afast/map_print/wiki).
48
+
49
+ The minimum hash to generate a PNG:
50
+
51
+ ```ruby
52
+ map_configuration = {
53
+ png_options: {
54
+ width: 800,
55
+ height: 1000
56
+ },
57
+ map: {
58
+ sw: {
59
+ lat: -35.026862,
60
+ lng: -58.425003
61
+ },
62
+ ne: {
63
+ lat: -29.980172,
64
+ lng: -52.959305
65
+ },
66
+ zoom: 9,
67
+ layers: [{type: 'osm'}]
68
+ }
69
+ }
70
+ ```
71
+
72
+ The minimum hash to generate a PDF:
41
73
 
42
- `map_configuration` is a hash with the following options:
74
+ ```ruby
75
+ map_configuration = {
76
+ format: 'pdf',
77
+ map: {
78
+ sw: {
79
+ lat: -35.026862,
80
+ lng: -58.425003
81
+ },
82
+ ne: {
83
+ lat: -29.980172,
84
+ lng: -52.959305
85
+ },
86
+ zoom: 9,
87
+ layers: [{type: 'osm'}]
88
+ }
89
+ }
90
+ ```
91
+
92
+ A full example showing all the available options:
43
93
 
44
94
  ```ruby
45
- BASIC_MAP = {
95
+ map_configuration = {
46
96
  format: 'pdf', # pdf or png
47
97
  pdf_options: {
48
98
  page_size: 'A4', # A0-10, B0-10, C0-10
@@ -123,12 +173,29 @@ BASIC_MAP = {
123
173
  text: "some text",
124
174
  position: {x: 50, y: 50 },
125
175
  box_size: {width: 50, height: 50},
126
- options: {}
176
+ options: {
177
+ fill_color: '#ffffff',
178
+ color: '#000000',
179
+ font: 'Arial',
180
+ pointsize: '16',
181
+ gravity: 'NorthWest',
182
+ }
127
183
  }
128
184
  ],
129
- legend: { # not supported yet
185
+ legend: {
130
186
  position: {x: 50, y: 50},
131
187
  size: {width: 50, height: 50},
188
+ image_size: {width: 16, height: 16},
189
+ textbox_size: {width: 40, height: 16},
190
+ textbox_style: {
191
+ fill_color: '#ffffff',
192
+ color: '#000000',
193
+ font: 'Arial',
194
+ pointsize: '16',
195
+ gravity: 'NorthWest',
196
+ },
197
+ orientation: 'horizontal', # horizontal, vertical
198
+ overflow: 'hidden', # expand, hidden, compact
132
199
  columns: 5,
133
200
  rows: 5,
134
201
  elements: [{
@@ -136,10 +203,14 @@ BASIC_MAP = {
136
203
  text: 'text'
137
204
  }]
138
205
  },
139
- scalebar: { # not supported yet
206
+ scalebar: {
140
207
  unit: 'meters', # meters, km, miles, feet
141
- position: {x: 50, y: 50},
142
- size: {width: 50, height: 50}
208
+ position: {x: 500, y: 550},
209
+ size: {width: 200, height: 40},
210
+ padding: {top: 5, right: 5, bottom: 5, left: 5},
211
+ bar_height: 10,
212
+ background_color: 'black',
213
+ background_opacity: 0.4
143
214
  }
144
215
  }
145
216
  ```
@@ -1,3 +1,4 @@
1
+ require_relative 'logger'
1
2
  require_relative 'lat_lng'
2
3
  require_relative 'tiles/tile'
3
4
  require_relative 'tiles/tile_factory'
@@ -29,6 +30,10 @@ module MapPrint
29
30
  @texts = args[:texts]
30
31
  @legend = args[:legend]
31
32
  @scalebar = args[:scalebar]
33
+ raise ParameterError.new("Please indicate the southwest point for the map ({map: {sw: {lat: -35.026862, lng: -58.425003}}})") unless @map && @map[:sw] && @map[:sw][:lat] && @map[:sw][:lng]
34
+ raise ParameterError.new("Please indicate the northeast point for the map ({map: {ne: {lat: -29.980172, lng: -52.959305}}})") unless @map[:ne] && @map[:ne][:lat] && @map[:ne][:lng]
35
+ raise ParameterError.new("Please indicate the zoom level for the map ({map: {zoom: 9})") unless @map[:zoom]
36
+ raise ParameterError.new("Please indicate layers to be printed for the map ({map: {layers: [{type: 'osm'}]})") unless @map[:layers].is_a?(Array)
32
37
  end
33
38
 
34
39
  def print(output_path)
@@ -36,10 +41,9 @@ module MapPrint
36
41
 
37
42
  if @format == 'pdf'
38
43
  handler = PdfHandler.new(self)
39
- elsif @format == 'png'
40
- handler = PngHandler.new(self)
41
44
  else
42
- raise "Unsupported format: #{@format}"
45
+ Logger.warn 'Did not specify format, defaulting to png'
46
+ handler = PngHandler.new(self)
43
47
  end
44
48
 
45
49
  handler.print
@@ -47,11 +51,7 @@ module MapPrint
47
51
  end
48
52
 
49
53
  def print_layers
50
- file = LayerHandler.new(@map[:layers], @map[:sw], @map[:ne], @map[:zoom]).process
51
-
52
- FileUtils.cp file.path, 'layers.png' if defined?(DEBUG)
53
-
54
- file
54
+ LayerHandler.new(@map[:layers], @map[:sw], @map[:ne], @map[:zoom]).process
55
55
  end
56
56
 
57
57
  def print_geojson(map_image)
@@ -67,12 +67,15 @@ module MapPrint
67
67
  end
68
68
 
69
69
  def print_scalebar
70
+ if @scalebar
71
+ ScalebarHandler.new(@scalebar, @map[:zoom]).process
72
+ end
70
73
  end
71
74
 
72
- def print_legend_on_pdf(pdf)
73
- end
74
-
75
- def print_legend_on_png(png)
75
+ def print_legend
76
+ if @legend
77
+ LegendHandler.new(@legend).process
78
+ end
76
79
  end
77
80
  end
78
81
  end
@@ -0,0 +1,20 @@
1
+ module MapPrint
2
+ class GeoJSONHandlerError < StandardError; end
3
+ class InvalidGeoJSON < GeoJSONHandlerError; end
4
+ class NoPointImage < GeoJSONHandlerError; end
5
+ class NoGeometryPresent < GeoJSONHandlerError; end
6
+ class FeatureNotImplemented < GeoJSONHandlerError; end
7
+
8
+ class LegendHandlerError < StandardError; end
9
+ class NoLegendData < LegendHandlerError; end
10
+ class InvalidSize < LegendHandlerError; end
11
+ class MissingLayoutInformation < LegendHandlerError; end
12
+
13
+ class ScalebarHandlerError < StandardError; end
14
+ class NoScalebarData < ScalebarHandlerError; end
15
+ class InvalidScalebarSize < ScalebarHandlerError; end
16
+ class InvalidScalebarZoom < ScalebarHandlerError; end
17
+
18
+ class CoreError < StandardError; end
19
+ class ParameterError < CoreError; end
20
+ end
@@ -10,6 +10,8 @@ module MapPrint
10
10
  @height = height
11
11
  @width = width
12
12
  @geojson = JSON[geojson]
13
+ rescue JSON::GeneratorError, JSON::ParserError
14
+ raise InvalidGeoJSON.new("Invalid GeoJSON: #{geojson.inspect}")
13
15
  end
14
16
 
15
17
  def process
@@ -25,23 +27,26 @@ module MapPrint
25
27
  tempfile.close
26
28
  end
27
29
 
30
+ private
28
31
  def draw_geojson
29
32
  if @geojson['type'] == 'Feature'
30
33
  feature(@geojson['geometry'], @geojson['properties'])
31
34
  elsif @geojson['type'] == 'FeatureCollection'
32
35
  feature_collection(@geojson['features'])
33
36
  else
34
- puts "Warning, expected type Feature with #{@geojson['type']} inside geometry and drawing properties, like: {'type': 'Feature', 'geometry':#{@geojson.to_json}, 'properties':{'image': 'path/or/url/to/image'}}"
37
+ Logger.warn "Warning, expected type Feature with #{@geojson['type'].inspect} inside geometry and drawing properties, like: {'type': 'Feature', 'geometry':#{@geojson.to_json}, 'properties':{'image': 'path/or/url/to/image'}}"
35
38
  end
36
39
  end
37
40
 
38
41
  def feature(geometry, properties={})
42
+ raise NoGeometryPresent.new("No geometry present for this feature") if geometry.nil?
39
43
  case geometry['type']
40
44
  when 'Feature'
41
45
  feature(geometry['geometry'], geometry['properties'])
42
46
  when 'FeatureCollection'
43
47
  feature_collection(geometry['features'])
44
48
  when 'Point'
49
+ raise NoPointImage.new("Missing image in point geometry") unless properties && properties['image']
45
50
  point(geometry, properties['image'])
46
51
  when 'LineString'
47
52
  line_string(geometry, properties)
@@ -55,7 +60,11 @@ module MapPrint
55
60
  multi_polygon(geometry, properties)
56
61
  when 'GeometryCollection'
57
62
  geometry_collection(geometry, properties)
63
+ else
64
+ Logger.warn "Feature type '#{geometry['type']}' not implemented!"
58
65
  end
66
+ rescue GeoJSONHandlerError => ex
67
+ Logger.warn ex
59
68
  end
60
69
 
61
70
  def feature_collection(features)
@@ -103,7 +112,22 @@ module MapPrint
103
112
  end
104
113
  end
105
114
 
106
- private
115
+ def multi_point(geometry, properties)
116
+ raise FeatureNotImplemented.new("Please consider contributing!")
117
+ end
118
+
119
+ def multi_line_string(geometry, properties)
120
+ raise FeatureNotImplemented.new("Please consider contributing!")
121
+ end
122
+
123
+ def multi_polygon(geometry, properties)
124
+ raise FeatureNotImplemented.new("Please consider contributing!")
125
+ end
126
+
127
+ def geometry_collection(geometry, properties)
128
+ raise FeatureNotImplemented.new("Please consider contributing!")
129
+ end
130
+
107
131
  def draw_options(properties, line=true)
108
132
  options = ''
109
133
  if properties['stroke'] || properties['stroke'].nil?
@@ -1,7 +1,30 @@
1
1
  module MapPrint
2
2
  class LatLng
3
+ EARTH_RADIUS_IN_METERS = 6_376_772.71
4
+
3
5
  attr_accessor :lat, :lng
4
6
 
7
+ class << self
8
+ def distance_between(from, to)
9
+ return 0.0 if from == to # fixes a "zero-distance" bug
10
+
11
+ distance_between_sphere(from, to)
12
+ end
13
+
14
+ def distance_between_sphere(from, to)
15
+ lat_sin = Math.sin(deg2rad(from.lat)) * Math.sin(deg2rad(to.lat))
16
+ lat_cos = Math.cos(deg2rad(from.lat)) * Math.cos(deg2rad(to.lat))
17
+ lng_cos = Math.cos(deg2rad(to.lng) - deg2rad(from.lng))
18
+ EARTH_RADIUS_IN_METERS * Math.acos(lat_sin + lat_cos * lng_cos)
19
+ rescue Errno::EDOM
20
+ 0.0
21
+ end
22
+
23
+ def deg2rad(degrees)
24
+ degrees.to_f / 180.0 * Math::PI
25
+ end
26
+ end
27
+
5
28
  def initialize(lat, lng)
6
29
  @lat = lat
7
30
  @lng = lng
@@ -18,7 +41,9 @@ module MapPrint
18
41
  @get_slippy_map_tile_number = {x: x.to_i, y: y.to_i, offset: {x: x - x.to_i, y: y - y.to_i}}
19
42
  end
20
43
 
21
- def diff_in_meters(lat_lng)
44
+ def distance_to(other)
45
+ self.class.distance_between(self, other)
22
46
  end
47
+ alias_method :distance_from, :distance_to
23
48
  end
24
49
  end
@@ -1,21 +1,21 @@
1
1
  module MapPrint
2
2
  class LayerHandler
3
3
  PROVIDERS = {
4
- 'bing' => MapPrint::Providers::Bing,
5
- 'osm' => MapPrint::Providers::OpenStreetMap
4
+ 'bing' => Providers::Bing,
5
+ 'osm' => Providers::OpenStreetMap
6
6
  }
7
7
 
8
8
  def initialize(layers, south_west, north_east, zoom)
9
9
  @layers = layers.sort_by { |layer| layer[:level] }
10
- @south_west = MapPrint::LatLng.new(south_west[:lat], south_west[:lng])
11
- @north_east = MapPrint::LatLng.new(north_east[:lat], north_east[:lng])
10
+ @south_west = LatLng.new(south_west[:lat], south_west[:lng])
11
+ @north_east = LatLng.new(north_east[:lat], north_east[:lng])
12
12
  @zoom = zoom
13
13
  end
14
14
 
15
15
  def process
16
16
  @layers.each do |layer|
17
17
  provider_class = PROVIDERS[layer[:type]]
18
- provider = provider_class.new(@south_west, @north_east, @zoom, layer[:urls].first)
18
+ provider = provider_class.new(@south_west, @north_east, @zoom, layer[:urls] && layer[:urls].first)
19
19
  layer[:image] = provider.download
20
20
  end
21
21
 
@@ -1,9 +1,108 @@
1
1
  module MapPrint
2
2
  class LegendHandler
3
- def initialize(legend, file)
3
+ def initialize(legend)
4
+ @legend = legend
5
+ validate_data!
4
6
  end
5
7
 
6
8
  def process
9
+ size = @legend[:size]
10
+ tempfile = Tempfile.new ['legend', '.png']
11
+ `convert -size #{size[:width]}x#{size[:height]} xc:white #{tempfile.path}`
12
+ image = MiniMagick::Image.new tempfile.path
13
+
14
+ x_step = size[:width] / @legend[:columns]
15
+ y_step = size[:height] / @legend[:rows]
16
+ image_geometry = ''
17
+ textbox_offset = 0
18
+ text_size = "#{@legend[:textbox_size][:width]}x#{@legend[:textbox_size][:height]}" if @legend[:textbox_size]
19
+
20
+ if @legend[:image_size]
21
+ image_geometry += "#{@legend[:image_size][:width]}x#{@legend[:image_size][:height]}"
22
+ textbox_offset += @legend[:image_size][:width] if @legend[:image_size][:width]
23
+ end
24
+ textbox_offset += @legend[:textbox_offset] if @legend[:textbox_offset]
25
+
26
+ if @legend[:orientation] == 'vertical'
27
+ print_vertical(image, x_step, y_step, image_geometry, textbox_offset, text_size)
28
+ else
29
+ print_horizontal(image, x_step, y_step, image_geometry, textbox_offset, text_size)
30
+ end
31
+ image
32
+ end
33
+
34
+ private
35
+ def validate_data!
36
+ raise NoLegendData.new('No legend data present') if @legend.nil? || @legend.empty?
37
+ raise InvalidSize.new('No legend width present') unless @legend[:size] && @legend[:size][:width]
38
+ raise InvalidSize.new('No legend height present') unless @legend[:size][:height]
39
+ raise MissingLayoutInformation.new('Missing column layout information') unless @legend[:columns]
40
+ raise MissingLayoutInformation.new('Missing rows layout information') unless @legend[:rows]
41
+ end
42
+
43
+ def print_vertical(legend_image, x_step, y_step, image_geometry, textbox_offset, text_size)
44
+ return unless @legend[:elements].is_a?(Array)
45
+ x = 0
46
+ y = 0
47
+ z = 1
48
+
49
+ @legend[:elements].each do |legend_item|
50
+ image_file = MiniMagick::Image.open(legend_item[:image])
51
+ result = legend_image.composite(image_file) do |c|
52
+ c.geometry image_geometry + "+#{x}+#{y}"
53
+ end
54
+ result.write legend_image.path
55
+
56
+ position = "#{x + textbox_offset},#{y}"
57
+ draw_text(legend_image, legend_item[:text], position, text_size)
58
+
59
+ if z % @legend[:rows] == 0
60
+ x += x_step
61
+ y = 0
62
+ else
63
+ y += y_step
64
+ end
65
+ z += 1
66
+ end
67
+ end
68
+
69
+ def print_horizontal(legend_image, x_step, y_step, image_geometry, textbox_offset, text_size)
70
+ return unless @legend[:elements].is_a?(Array)
71
+ x = 0
72
+ y = 0
73
+ z = 1
74
+
75
+ @legend[:elements].each do |legend_item|
76
+ image_file = MiniMagick::Image.open(legend_item[:image])
77
+ result = legend_image.composite(image_file) do |c|
78
+ c.geometry image_geometry + "+#{x}+#{y}"
79
+ end
80
+ result.write legend_image.path
81
+
82
+ position = "#{x + textbox_offset},#{y}"
83
+ draw_text(legend_image, legend_item[:text], position, text_size)
84
+
85
+ if z % @legend[:columns] == 0
86
+ y += y_step
87
+ x = 0
88
+ else
89
+ x += x_step
90
+ end
91
+ z += 1
92
+ end
93
+ end
94
+
95
+ def draw_text(image, text, position, text_size)
96
+ options = @legend[:textbox_style] || {}
97
+ image.combine_options do |c|
98
+ c.fill options[:fill_color] if options[:fill_color]
99
+ c.stroke options[:color] if options[:color]
100
+ c.font options[:font] || 'Arial'
101
+ c.pointsize options[:pointsize] if options[:pointsize]
102
+ c.gravity options[:gravity] || 'NorthWest'
103
+ c.size text_size
104
+ c.draw "text #{position} '#{text}'"
105
+ end
7
106
  end
8
107
  end
9
108
  end
@@ -0,0 +1,52 @@
1
+ require 'singleton'
2
+ require 'logger'
3
+
4
+ module MapPrint
5
+ class Logger
6
+ include Singleton
7
+
8
+ def initialize
9
+ @logger = ::Logger.new File.new('map_print.log', 'a+')
10
+ end
11
+
12
+ def debug(*args)
13
+ @logger.debug *args
14
+ end
15
+
16
+ def info(*args)
17
+ @logger.info *args
18
+ end
19
+
20
+ def warn(*args)
21
+ @logger.warn *args
22
+ end
23
+
24
+ def error(*args)
25
+ @logger.error *args
26
+ end
27
+
28
+ def fatal(*args)
29
+ @logger.fatal *args
30
+ end
31
+
32
+ def self.debug(*args)
33
+ self.instance.debug *args
34
+ end
35
+
36
+ def self.info(*args)
37
+ self.instance.info *args
38
+ end
39
+
40
+ def self.warn(*args)
41
+ self.instance.warn *args
42
+ end
43
+
44
+ def self.error(*args)
45
+ self.instance.error *args
46
+ end
47
+
48
+ def self.fatal(*args)
49
+ self.instance.fatal *args
50
+ end
51
+ end
52
+ end
@@ -16,19 +16,31 @@ module MapPrint
16
16
  print_map
17
17
  print_images(@context.images, @pdf)
18
18
  print_texts(@context.texts, @pdf)
19
- # print_legend_on_pdf(@pdf)
19
+
20
+ scalebar_image = @context.print_scalebar
21
+ if scalebar_image
22
+ @pdf.image scalebar_image.path, at: [@context.scalebar[:position][:x], @pdf.bounds.top - @context.scalebar[:position][:y]]
23
+ end
24
+
25
+ legend_image = @context.print_legend
26
+ if legend_image
27
+ @pdf.image legend_image.path, at: [@context.legend[:position][:x], @pdf.bounds.top - @context.legend[:position][:y]]
28
+ end
20
29
 
21
30
  @pdf.render_file(@context.output_path)
22
31
  end
23
32
 
33
+ private
24
34
  def print_map
25
35
  map_image = @context.print_layers
26
36
  map_image = @context.print_geojson(MiniMagick::Image.new(map_image.path))
27
37
 
28
- size = @context.map[:size]
38
+ size = @context.map[:size] || {}
29
39
  size[:width] ||= map_image.width
30
40
  size[:height] ||= map_image.height
31
- @pdf.image map_image.path, at: [@context.map[:position][:x], @pdf.bounds.top - @context.map[:position][:y]], fit: size.values
41
+
42
+ position = @context.map[:position] || {}
43
+ @pdf.image map_image.path, at: [position[:x] || 0, @pdf.bounds.top - (position[:y] || 0)], fit: size.values
32
44
  end
33
45
  end
34
46
  end
@@ -2,7 +2,7 @@ module MapPrint
2
2
  module PdfHandlers
3
3
  module Images
4
4
  def print_images(images, pdf)
5
- images.each do |image|
5
+ (images || []).each do |image|
6
6
  if image[:path] =~ /https?:\/\//
7
7
  image_file = open(image[:path])
8
8
  else
@@ -2,7 +2,7 @@ module MapPrint
2
2
  module PdfHandlers
3
3
  module Texts
4
4
  def print_texts(texts, pdf)
5
- texts.each do |text|
5
+ (texts || []).each do |text|
6
6
  pdf.text_box text[:text], text_options(text)
7
7
  end
8
8
  end
@@ -11,14 +11,25 @@ module MapPrint
11
11
  end
12
12
 
13
13
  def print
14
- `convert -size #{@context.png_options[:width]}x#{@context.png_options[:height]} xc:#{@context.png_options[:background_color]} #{@context.output_path}`
14
+ raise ParameterError.new('Missing png_options width attribute') unless @context.png_options && @context.png_options[:width]
15
+ raise ParameterError.new('Missing png_options height attribute') unless @context.png_options[:height]
16
+ `convert -size #{@context.png_options[:width]}x#{@context.png_options[:height]} xc:#{@context.png_options[:background_color] || 'transparent'} #{@context.output_path}`
15
17
  @png = MiniMagick::Image.new @context.output_path
16
18
 
17
19
  print_map
18
20
 
19
21
  print_images(@context.images, @png)
20
22
  print_texts(@context.texts, @png)
21
- # print_legend_on_png
23
+
24
+ scalebar_image = @context.print_scalebar
25
+ if scalebar_image
26
+ overlay_image(MiniMagick::Image.new(scalebar_image.path), @context.scalebar[:position])
27
+ end
28
+
29
+ legend_image = @context.print_legend
30
+ if legend_image
31
+ overlay_image(MiniMagick::Image.new(legend_image.path), @context.legend[:position])
32
+ end
22
33
  end
23
34
 
24
35
  def print_map
@@ -33,12 +44,16 @@ module MapPrint
33
44
  geometry += size[:height].to_s if size[:height]
34
45
  end
35
46
 
36
- if @context.map[:position]
37
- geometry += "+#{@context.map[:position][:x] || 0}+#{@context.map[:position][:y] || 0}"
38
- end
47
+ overlay_image(map_image, @context.map[:position], geometry)
48
+ end
49
+
50
+ private
51
+ def overlay_image(image, position, size_geometry='')
52
+ geometry = size_geometry
53
+ geometry += "+#{position[:x] || 0}+#{position[:y] || 0}" if position
39
54
 
40
- result = @png.composite(map_image) do |c|
41
- c.geometry geometry
55
+ result = @png.composite(image) do |c|
56
+ c.geometry geometry unless geometry.nil? || geometry.empty?
42
57
  end
43
58
  result.write @context.output_path
44
59
  end
@@ -2,7 +2,7 @@ module MapPrint
2
2
  module PngHandlers
3
3
  module Images
4
4
  def print_images(images, png)
5
- images.each do |image|
5
+ (images || []).each do |image|
6
6
  image_file = MiniMagick::Image.open(image[:path])
7
7
 
8
8
  geometry = ''
@@ -2,7 +2,7 @@ module MapPrint
2
2
  module PngHandlers
3
3
  module Texts
4
4
  def print_texts(texts, png)
5
- texts.each do |text|
5
+ (texts || []).each do |text|
6
6
  position = "#{text[:position][:x]},#{text[:position][:y]}"
7
7
 
8
8
  draw_text(png, text[:text], position, text[:options])
@@ -2,12 +2,9 @@ require 'tempfile'
2
2
 
3
3
  module MapPrint
4
4
  module Providers
5
-
6
5
  class Base
7
6
 
8
- attr_accessor :provider
9
-
10
- attr_accessor :south_west, :north_east, :zoom
7
+ attr_accessor :provider, :south_west, :north_east, :zoom
11
8
 
12
9
  def initialize(south_west, north_east, zoom, base_url=nil)
13
10
  @south_west, @north_east, @zoom = south_west, north_east, zoom
@@ -48,8 +45,6 @@ module MapPrint
48
45
  file.close
49
46
  result_file
50
47
  end
51
-
52
48
  end
53
-
54
49
  end
55
50
  end
@@ -1,9 +1,111 @@
1
+ require_relative 'png_handlers/texts'
1
2
  module MapPrint
2
3
  class ScalebarHandler
3
- def initialize(scalebar, file)
4
+ include MapPrint::PngHandlers::Texts
5
+
6
+ ZOOM_METERS_PER_PIXEL = {
7
+ 0 => 156543.03,
8
+ 1 => 78271.52,
9
+ 2 => 39135.76,
10
+ 3 => 19567.88,
11
+ 4 => 9783.94,
12
+ 5 => 4891.97,
13
+ 6 => 2445.98,
14
+ 7 => 1222.99,
15
+ 8 => 611.50,
16
+ 9 => 305.75,
17
+ 10 => 152.87,
18
+ 11 => 76.437,
19
+ 12 => 38.219,
20
+ 13 => 19.109,
21
+ 14 => 9.5546,
22
+ 15 => 4.7773,
23
+ 16 => 2.3887,
24
+ 17 => 1.1943,
25
+ 18 => 0.5972
26
+ }
27
+ def initialize(scalebar, zoom)
28
+ @scalebar = scalebar
29
+ @zoom = zoom
30
+ if @scalebar[:padding]
31
+ @padding_left = @scalebar[:padding][:left] || 0
32
+ @padding_right = @scalebar[:padding][:right] || 0
33
+ @padding_top = @scalebar[:padding][:top] || 0
34
+ @padding_bottom = @scalebar[:padding][:bottom] || 0
35
+ else
36
+ @padding_left = 0
37
+ @padding_right = 0
38
+ @padding_top = 0
39
+ @padding_bottom = 0
40
+ end
41
+ validate_data!
4
42
  end
5
43
 
6
44
  def process
45
+ size = @scalebar[:size]
46
+ tempfile = Tempfile.new ['scalebar', '.png']
47
+ `convert -alpha on -channel a -evaluate set #{(@scalebar[:background_opacity] || 1) *100}% -density 300 -size #{size[:width]}x#{size[:height]} xc:#{@scalebar[:background_color] || 'transparent'} #{tempfile.path}`
48
+ image = MiniMagick::Image.new tempfile.path
49
+
50
+ pixels_for_distance = get_distance_in_units
51
+ quarter = (size[:width] - @padding_left - @padding_right) / 4
52
+
53
+ y_position = size[:height] - (@scalebar[:bar_height] || 10) - @padding_bottom
54
+ image.combine_options do |c|
55
+ c.stroke 'black'
56
+ c.fill 'white'
57
+ c.draw "rectangle #{@padding_left},#{size[:height] - @padding_bottom} #{@padding_left + quarter},#{y_position}"
58
+ c.fill 'black'
59
+ c.draw "rectangle #{@padding_left + quarter},#{size[:height] - @padding_bottom} #{@padding_left + 2*quarter},#{y_position}"
60
+ c.fill 'white'
61
+ c.draw "rectangle #{@padding_left + 2*quarter},#{size[:height] - @padding_bottom} #{@padding_left + 3*quarter},#{y_position}"
62
+ c.fill 'black'
63
+ c.draw "rectangle #{@padding_left + 3*quarter},#{size[:height] - @padding_bottom} #{@padding_left + 4*quarter},#{y_position}"
64
+ end
65
+
66
+ text_options = { pointsize: 12, gravity: 'NorthWest' }
67
+ draw_text(image, "0", "#{@padding_left},#{@padding_top}", text_options)
68
+ draw_text(image, (pixels_for_distance/4).round(-2).to_s, "#{-quarter + @padding_left - @padding_right},#{@padding_top}", text_options.merge(gravity: 'North'))
69
+ draw_text(image, (pixels_for_distance/2).round(-2).to_s, "#{@padding_left - @padding_right},#{@padding_top}", text_options.merge(gravity: 'North'))
70
+ draw_text(image, (pixels_for_distance*0.75).round(-2).to_s + distance_units_to_s, "#{@padding_right},#{@padding_top}", text_options.merge(gravity: 'NorthEast'))
71
+
72
+ image
73
+ end
74
+
75
+ private
76
+ def validate_data!
77
+ raise NoScalebarData.new('No scalebar data present') if @scalebar.nil? || @scalebar.empty?
78
+ raise InvalidScalebarSize.new('No scalebar width present') unless @scalebar[:size] && @scalebar[:size][:width]
79
+ raise InvalidScalebarSize.new('No scalebar height present') unless @scalebar[:size][:height]
80
+ raise InvalidScalebarZoom.new('Zoom must be between 0..18') unless (0..18).include?(@zoom)
81
+ end
82
+
83
+ def get_distance_in_units
84
+ padding = @padding_left + @padding_right
85
+ meters = (@scalebar[:size][:width] - padding) * ZOOM_METERS_PER_PIXEL[@zoom]
86
+ case @scalebar[:units]
87
+ when 'km'
88
+ meters / 1000
89
+ when 'miles'
90
+ meters * 0.0006213712
91
+ when 'feet'
92
+ meters * 3.28084
93
+ else # asssume meters
94
+ meters
95
+ end
96
+ end
97
+
98
+ def distance_units_to_s
99
+ case @scalebar[:units]
100
+ when 'km'
101
+ 'km'
102
+ when 'miles'
103
+ 'mi'
104
+ when 'feet'
105
+ 'ft'
106
+ else
107
+ 'm'
108
+ end
7
109
  end
8
110
  end
9
111
  end
@@ -1,7 +1,5 @@
1
1
  module MapPrint
2
-
3
2
  class OSMTile < Tile
4
-
5
3
  def provider_name
6
4
  'osm'
7
5
  end
@@ -15,7 +13,5 @@ module MapPrint
15
13
  def tile_url
16
14
  @base_url.gsub('${x}', @x.to_s).gsub('${y}', @y.to_s).gsub('${z}', @z.to_s)
17
15
  end
18
-
19
16
  end
20
-
21
17
  end
@@ -54,14 +54,9 @@ module MapPrint
54
54
 
55
55
  def get_pixel_difference(lat_lng)
56
56
  tile_lat_lng = tile_number_to_lat_lng
57
- puts '================'
58
- puts lat_lng.lat
59
- puts lat_lng.lng
60
- puts tile_lat_lng
61
- puts '================'
62
-
63
- x_pixels = GeoDistance.distance(lat_lng.lat, lat_lng.lng, lat_lng.lat, tile_lat_lng[:lng]).meters.number / METERS_PER_PIXELS[@z]
64
- y_pixels = GeoDistance.distance(lat_lng.lat, lat_lng.lng, tile_lat_lng[:lat], lat_lng.lng).meters.number / METERS_PER_PIXELS[@z]
57
+
58
+ x_pixels = lat_lng.distance_to(LatLng.new(lat_lng.lat, tile_lat_lng[:lng])) / METERS_PER_PIXELS[@z]
59
+ y_pixels = lat_lng.distance_to(LatLng.new(tile_lat_lng[:lat], lat_lng.lng)) / METERS_PER_PIXELS[@z]
65
60
 
66
61
  { x: x_pixels, y: y_pixels }
67
62
  end
@@ -30,6 +30,14 @@ module MapPrint
30
30
  end
31
31
  end
32
32
 
33
+ def x_size
34
+ x_array.size
35
+ end
36
+
37
+ def y_size
38
+ y_array.size
39
+ end
40
+
33
41
  def tiles
34
42
  return @tiles if @tiles
35
43
 
@@ -43,14 +51,7 @@ module MapPrint
43
51
  @tiles
44
52
  end
45
53
 
46
- def x_size
47
- x_array.size
48
- end
49
-
50
- def y_size
51
- y_array.size
52
- end
53
-
54
+ private
54
55
  def ne_offset
55
56
  @ne_lat_lng.get_slippy_map_tile_number(@zoom)[:offset]
56
57
  end
@@ -75,16 +76,12 @@ module MapPrint
75
76
  @y_array ||= y1 < y2 ? y1..y2 : (y2..y1).to_a
76
77
  end
77
78
 
78
- private
79
-
80
79
  def tile_class
81
80
  if @type == 'osm'
82
81
  OSMTile
83
- elsif @type =~ 'bing'
82
+ elsif @type =~ /bing/
84
83
  BingTile
85
84
  end
86
85
  end
87
-
88
86
  end
89
-
90
87
  end
@@ -1,3 +1,3 @@
1
1
  module MapPrint
2
- VERSION = '0.3.0'
2
+ VERSION = '0.9.0'
3
3
  end
data/lib/map_print.rb CHANGED
@@ -1,8 +1,8 @@
1
1
  require 'prawn'
2
2
  require 'mini_magick'
3
- require 'geo-distance'
4
3
  require 'parallel'
5
4
 
6
5
  require_relative 'base'
7
6
  require_relative 'map_print/version'
7
+ require_relative 'map_print/exceptions'
8
8
  require_relative 'map_print/core'
data/map_print.gemspec CHANGED
@@ -30,10 +30,10 @@ Gem::Specification.new do |spec|
30
30
  spec.add_development_dependency 'bundler', '~> 1.10'
31
31
  spec.add_development_dependency 'rake', '~> 10.0'
32
32
  spec.add_development_dependency 'minitest', '~> 5.8'
33
+ spec.add_development_dependency 'webmock', '1.22.6'
33
34
  spec.add_dependency 'prawn', '~> 2.0'
34
35
  spec.add_dependency 'prawn-fast-png', '~> 0.2.3'
35
36
  spec.add_dependency 'mini_magick', '~> 4.3'
36
- spec.add_dependency 'geo-distance', '~> 0.1'
37
37
  spec.add_dependency 'parallel', '~> 1.6'
38
38
  spec.add_dependency 'thor', '~> 0.19'
39
39
  end
data/minimum_map.pdf ADDED
Binary file
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: map_print
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.0
4
+ version: 0.9.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Andreas Fast
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-01-02 00:00:00.000000000 Z
11
+ date: 2016-02-11 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -52,6 +52,20 @@ dependencies:
52
52
  - - "~>"
53
53
  - !ruby/object:Gem::Version
54
54
  version: '5.8'
55
+ - !ruby/object:Gem::Dependency
56
+ name: webmock
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - '='
60
+ - !ruby/object:Gem::Version
61
+ version: 1.22.6
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - '='
67
+ - !ruby/object:Gem::Version
68
+ version: 1.22.6
55
69
  - !ruby/object:Gem::Dependency
56
70
  name: prawn
57
71
  requirement: !ruby/object:Gem::Requirement
@@ -94,20 +108,6 @@ dependencies:
94
108
  - - "~>"
95
109
  - !ruby/object:Gem::Version
96
110
  version: '4.3'
97
- - !ruby/object:Gem::Dependency
98
- name: geo-distance
99
- requirement: !ruby/object:Gem::Requirement
100
- requirements:
101
- - - "~>"
102
- - !ruby/object:Gem::Version
103
- version: '0.1'
104
- type: :runtime
105
- prerelease: false
106
- version_requirements: !ruby/object:Gem::Requirement
107
- requirements:
108
- - - "~>"
109
- - !ruby/object:Gem::Version
110
- version: '0.1'
111
111
  - !ruby/object:Gem::Dependency
112
112
  name: parallel
113
113
  requirement: !ruby/object:Gem::Requirement
@@ -150,6 +150,7 @@ files:
150
150
  - ".gitignore"
151
151
  - ".ruby-gemset"
152
152
  - ".ruby-version"
153
+ - ".travis.yml"
153
154
  - Gemfile
154
155
  - Gemfile.lock
155
156
  - LICENSE.txt
@@ -161,12 +162,12 @@ files:
161
162
  - lib/base.rb
162
163
  - lib/map_print.rb
163
164
  - lib/map_print/core.rb
165
+ - lib/map_print/exceptions.rb
164
166
  - lib/map_print/geo_json_handler.rb
165
167
  - lib/map_print/lat_lng.rb
166
168
  - lib/map_print/layer_handler.rb
167
169
  - lib/map_print/legend_handler.rb
168
- - lib/map_print/osm/tile.rb
169
- - lib/map_print/osm/tile_factory.rb
170
+ - lib/map_print/logger.rb
170
171
  - lib/map_print/pdf_handler.rb
171
172
  - lib/map_print/pdf_handlers/images.rb
172
173
  - lib/map_print/pdf_handlers/texts.rb
@@ -183,7 +184,7 @@ files:
183
184
  - lib/map_print/tiles/tile_factory.rb
184
185
  - lib/map_print/version.rb
185
186
  - map_print.gemspec
186
- - marker.png
187
+ - minimum_map.pdf
187
188
  homepage: http://github.com/afast/map_print
188
189
  licenses:
189
190
  - MIT
@@ -1,125 +0,0 @@
1
- require 'open-uri'
2
- require 'fileutils'
3
-
4
- module MapPrint
5
- module OSM
6
- class Tile
7
-
8
- BIT_TO_QUADKEY = { [false, false] => "0", [false, true] => "1", [true, false] => "2", [true, true] => "3"}
9
-
10
- METERS_PER_PIXELS = {
11
- 0 => 26862156543.031,
12
- 1 => 8078271.521,
13
- 2 => 7739135.761,
14
- 3 => 6919567.881,
15
- 4 => 889783.941,
16
- 5 => 214891.9771,
17
- 6 => 222445.9801721,
18
- 7 => 161731222.991,
19
- 8 => 11611.5001,
20
- 9 => 52305.751,
21
- 10 => 152.871,
22
- 11 => 76.4371,
23
- 12 => 38.2191,
24
- 13 => 519.1091,
25
- 14 => 9.55461,
26
- 15 => 4.77731,
27
- 16 => 2.38871,
28
- 17 => 1.19431,
29
- 18 => 0.5972
30
- }
31
-
32
- class << self
33
-
34
- def meters_per_pixel(zoom)
35
- METERS_PER_PIXELS[zoom]
36
- end
37
-
38
- end
39
-
40
- def initialize(x, y, z, base_url)
41
- @base_url = base_url
42
- @x = x
43
- @y = y
44
- @z = z
45
- end
46
-
47
- def coords
48
- {x: @x, y: @y, z: @z}
49
- end
50
-
51
- def download
52
- unless File.exists?(file_path)
53
- content = open(get_url).read
54
- write_file(content)
55
- end
56
- end
57
-
58
- def get_pixel_difference(lat_lng)
59
- tile_lat_lng = tile_number_to_lat_lng
60
-
61
- x_pixels = GeoDistance.distance(lat_lng.lat, lat_lng.lng, lat_lng.lat, tile_lat_lng[:lng]).meters.number / METERS_PER_PIXELS[@z]
62
- y_pixels = GeoDistance.distance(lat_lng.lat, lat_lng.lng, tile_lat_lng[:lat], lat_lng.lng).meters.number / METERS_PER_PIXELS[@z]
63
-
64
- { x: x_pixels, y: y_pixels }
65
- end
66
-
67
- def tile_number_to_lat_lng
68
- n = 2.0 ** @z
69
- lon_deg = @x / n * 360.0 - 180.0
70
- lat_rad = Math::atan(Math::sinh(Math::PI * (1 - 2 * @y / n)))
71
- lat_deg = 180.0 * (lat_rad / Math::PI)
72
-
73
- { lat: lat_deg, lng: lon_deg }
74
- end
75
-
76
- def file_path
77
- File.join(folder_name, "#{@y}.png")
78
- end
79
-
80
- def tile2quad
81
- quadkey_chars = []
82
-
83
- tx = @x.to_i
84
- ty = @y.to_i
85
-
86
- @z.times do
87
- quadkey_chars.push BIT_TO_QUADKEY[[ty.odd?, tx.odd?]] # bit order y,x
88
- tx >>= 1 ; ty >>= 1
89
- end
90
-
91
- quadkey_chars.join.reverse
92
- end
93
-
94
- private
95
-
96
- def write_file(content)
97
- FileUtils.mkdir_p(folder_name)
98
-
99
- File.open file_path, 'wb' do |f|
100
- f.write content
101
- end
102
- end
103
-
104
- def provider_name
105
- if @base_url =~ /openstreetmap/
106
- 'osm'
107
- elsif @base_url =~ /virtualearth/
108
- 'bing'
109
- end
110
- end
111
-
112
- def folder_name
113
- "cache/#{provider_name}/#{@z}/#{@x}"
114
- end
115
-
116
- def get_url
117
- if provider_name == 'osm'
118
- @base_url.gsub('${x}', @x.to_s).gsub('${y}', @y.to_s).gsub('${z}', @z.to_s)
119
- elsif provider_name == 'bing'
120
- @base_url.gsub('${quadkey}', tile2quad)
121
- end
122
- end
123
- end
124
- end
125
- end
@@ -1,75 +0,0 @@
1
- module MapPrint
2
- module OSM
3
- class TileFactory
4
-
5
- def initialize(base_url, sw_lat_lng, ne_lat_lng, zoom)
6
- @base_url = base_url
7
- @sw_lat_lng = sw_lat_lng
8
- @ne_lat_lng = ne_lat_lng
9
- @zoom = zoom
10
- end
11
-
12
- def px_offset
13
- return @px_offset if @px_offset
14
- offset = {}
15
-
16
- offset[:top] = (ne_offset[:y] * 256).to_i
17
- offset[:right] = 256 - (ne_offset[:x] * 256).to_i
18
- offset[:bottom] = 256 - (sw_offset[:y] * 256).to_i
19
- offset[:left] = (sw_offset[:x] * 256).to_i
20
- @px_offset = offset
21
- end
22
-
23
- def download
24
- Parallel.each(tiles, in_processes: 20) do |tile|
25
- tile.download
26
- end
27
- end
28
-
29
- def tiles
30
- return @tiles if @tiles
31
-
32
- @tiles = []
33
- y_array.each do |y|
34
- x_array.each do |x|
35
- @tiles << Tile.new(x, y, @zoom, @base_url)
36
- end
37
- end
38
-
39
- @tiles
40
- end
41
-
42
- def x_size
43
- x_array.size
44
- end
45
-
46
- def y_size
47
- y_array.size
48
- end
49
-
50
- def ne_offset
51
- @ne_lat_lng.get_slippy_map_tile_number(@zoom)[:offset]
52
- end
53
-
54
- def sw_offset
55
- @sw_lat_lng.get_slippy_map_tile_number(@zoom)[:offset]
56
- end
57
-
58
- def x_array
59
- return @x_array if @x_array
60
-
61
- x1 = @sw_lat_lng.get_slippy_map_tile_number(@zoom)[:x]
62
- x2 = @ne_lat_lng.get_slippy_map_tile_number(@zoom)[:x]
63
- @x_array ||= x1 < x2 ? x1..x2 : (x2..x1).to_a
64
- end
65
-
66
- def y_array
67
- return @y_array if @y_array
68
-
69
- y1 = @sw_lat_lng.get_slippy_map_tile_number(@zoom)[:y]
70
- y2 = @ne_lat_lng.get_slippy_map_tile_number(@zoom)[:y]
71
- @y_array ||= y1 < y2 ? y1..y2 : (y2..y1).to_a
72
- end
73
- end
74
- end
75
- end
data/marker.png DELETED
Binary file