map_print 0.3.0 → 0.9.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.
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