cartocss_helper 1.2.1 → 4.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/lib/cartocss_helper.rb +56 -71
- data/lib/cartocss_helper/configuration.rb +84 -37
- data/lib/cartocss_helper/data_file_handling.rb +32 -35
- data/lib/cartocss_helper/git.rb +17 -27
- data/lib/cartocss_helper/heuristic.rb +39 -41
- data/lib/cartocss_helper/image_generator.rb +36 -38
- data/lib/cartocss_helper/notes_downloader.rb +46 -0
- data/lib/cartocss_helper/overpass_downloader.rb +42 -0
- data/lib/cartocss_helper/overpass_query_generator.rb +248 -0
- data/lib/cartocss_helper/renderer_handler.rb +116 -0
- data/lib/cartocss_helper/style_specific/default_osm_style.rb +722 -546
- data/lib/cartocss_helper/style_specific/style_specific.rb +4 -3
- data/lib/cartocss_helper/tag_lister.rb +136 -112
- data/lib/cartocss_helper/util/filehelper.rb +1 -1
- data/lib/cartocss_helper/util/generic_cached_downloader.rb +49 -0
- data/lib/cartocss_helper/util/generic_downloader.rb +65 -0
- data/lib/cartocss_helper/util/logger.rb +30 -0
- data/lib/cartocss_helper/util/rest-client_wrapper.rb +53 -0
- data/lib/cartocss_helper/util/systemhelper.rb +55 -0
- data/lib/cartocss_helper/validator.rb +142 -81
- data/lib/cartocss_helper/visualise_changes_diff_from_images.rb +36 -34
- data/lib/cartocss_helper/visualise_changes_image_generation.rb +72 -100
- data/lib/data/testing_locations.rb +17 -15
- data/readme.md +34 -9
- metadata +140 -39
- data/lib/cartocss_helper/downloader.rb +0 -301
- data/lib/cartocss_helper/tilemill_handler.rb +0 -38
@@ -0,0 +1,30 @@
|
|
1
|
+
require 'logger'
|
2
|
+
|
3
|
+
module Log
|
4
|
+
@@_logger_ = Logger.new(STDOUT)
|
5
|
+
|
6
|
+
def self.logger
|
7
|
+
@@_logger_
|
8
|
+
end
|
9
|
+
|
10
|
+
def self.info(message = '')
|
11
|
+
logger.info(message)
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.warn(message = '')
|
15
|
+
logger.warn(message)
|
16
|
+
end
|
17
|
+
|
18
|
+
@@_logger_.formatter = proc do |_severity, _datetime, _progname, msg|
|
19
|
+
fileLine = ''
|
20
|
+
caller.each do |clr|
|
21
|
+
unless /\/logger.rb:/ =~ clr
|
22
|
+
fileLine = clr
|
23
|
+
break
|
24
|
+
end
|
25
|
+
end
|
26
|
+
fileLine = fileLine.split(':in `', 2)[0]
|
27
|
+
fileLine.sub!(/:(\d)/, '(\1')
|
28
|
+
"#{fileLine}) : #{msg}\n"
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
require 'rest-client'
|
2
|
+
require_relative 'generic_downloader.rb'
|
3
|
+
|
4
|
+
class RestClientWrapper
|
5
|
+
def initialize
|
6
|
+
@last_url_fetched = nil
|
7
|
+
end
|
8
|
+
|
9
|
+
def fetch_data_from_url(url, request_timeout)
|
10
|
+
wait if url == @last_url_fetched
|
11
|
+
@last_url_fetched = url
|
12
|
+
return execute_fetch_data_from_url(url, request_timeout)
|
13
|
+
# http://www.rubydoc.info/gems/rest-client/1.8.0/RestClient/Exception
|
14
|
+
rescue RestClient::RequestTimeout => e
|
15
|
+
raise RequestTimeout, e.to_s
|
16
|
+
rescue RestClient::ExceptionWithResponse => e
|
17
|
+
raise_exception_about_returned_response(e)
|
18
|
+
rescue RestClient::MaxRedirectsReached, RestClient::SSLCertificateNotVerified, RestClient::ServerBrokeConnection, SocketError, URI::InvalidURIError
|
19
|
+
raise ExceptionWithoutResponse.new(e), e.to_s
|
20
|
+
rescue ArgumentError => e
|
21
|
+
raise_issue_359_exception(e)
|
22
|
+
rescue => e
|
23
|
+
puts 'unhandled exception! It is a clear bug!'
|
24
|
+
puts "<#{e.class} error happened>"
|
25
|
+
raise e, e.to_s
|
26
|
+
end
|
27
|
+
|
28
|
+
def execute_fetch_data_from_url(url, request_timeout)
|
29
|
+
data = RestClient::Request.execute(method: :get, url: url, timeout: request_timeout)
|
30
|
+
# see https://github.com/rest-client/rest-client/issues/370, will be fixed in 2.0
|
31
|
+
# published versions listed on https://rubygems.org/gems/rest-client/versions/
|
32
|
+
return String.new(data)
|
33
|
+
end
|
34
|
+
|
35
|
+
def raise_issue_359_exception(e)
|
36
|
+
raise BuggyRestClient, "ArgumentError from rest-client, most likely caused by https://github.com/rest-client/rest-client/issues/359 (requesting GBs of data) [#{e}]"
|
37
|
+
end
|
38
|
+
|
39
|
+
def raise_exception_about_returned_response(e)
|
40
|
+
failure = ExceptionWithResponse.new(e)
|
41
|
+
failure.http_code = e.http_code
|
42
|
+
failure.response = e.response
|
43
|
+
raise failure, e.to_s
|
44
|
+
end
|
45
|
+
|
46
|
+
def wait
|
47
|
+
progressbar = ProgressBar.create
|
48
|
+
100.times do
|
49
|
+
sleep 4
|
50
|
+
progressbar.increment
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
class FailedCommandException < StandardError
|
2
|
+
end
|
3
|
+
|
4
|
+
module SystemHelper
|
5
|
+
def check_error_code(command, stderr, status, allowed_return_codes)
|
6
|
+
returned = status.exitstatus
|
7
|
+
return if status.success?
|
8
|
+
return if allowed_return_codes.include?(returned)
|
9
|
+
explanation = "failed command #{command} due to error code #{returned}. stderr was #{stderr}"
|
10
|
+
raise FailedCommandException.new(explanation)
|
11
|
+
end
|
12
|
+
|
13
|
+
def check_stderr(command, stderr, status, ignore_stderr_presence)
|
14
|
+
return if ignore_stderr_presence
|
15
|
+
return if stderr == ''
|
16
|
+
returned = status.exitstatus
|
17
|
+
explanation = "failed command #{command} due to < #{stderr}> on stderr. return code was #{returned}"
|
18
|
+
raise FailedCommandException.new(explanation)
|
19
|
+
end
|
20
|
+
|
21
|
+
def execute_command(command, debug = false, allowed_return_codes: [], ignore_stderr_presence: false)
|
22
|
+
puts command if debug
|
23
|
+
stdout, stderr, status = Open3.capture3(command)
|
24
|
+
|
25
|
+
check_error_code(command, stderr, status, allowed_return_codes)
|
26
|
+
check_stderr(command, stderr, status, ignore_stderr_presence)
|
27
|
+
|
28
|
+
return stderr + stdout
|
29
|
+
end
|
30
|
+
|
31
|
+
def self.not_enough_free_space
|
32
|
+
minimum_gb = 2
|
33
|
+
available_gb = get_available_space_for_cache_in_gb
|
34
|
+
if available_gb < minimum_gb
|
35
|
+
puts "get_available_space_for_cache_in_gb: #{available_gb}, minimum_gb: #{minimum_gb}"
|
36
|
+
return true
|
37
|
+
else
|
38
|
+
return false
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def get_available_space_for_cache_in_gb
|
43
|
+
stat = Sys::Filesystem.stat(CartoCSSHelper::Configuration.get_path_to_folder_for_cache)
|
44
|
+
return stat.block_size * stat.blocks_available / 1024 / 1024 / 1024
|
45
|
+
end
|
46
|
+
|
47
|
+
def delete_file(filename, reason)
|
48
|
+
open(CartoCSSHelper::Configuration.get_path_to_folder_for_output + 'deleting_files_log.txt', 'a') do |file|
|
49
|
+
message = "deleting #{filename}, #{File.size(filename) / 1024 / 1024}MB - #{reason}"
|
50
|
+
puts message
|
51
|
+
file.puts(message)
|
52
|
+
File.delete(filename)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
@@ -10,15 +10,32 @@ include CartoCSSHelper::Configuration
|
|
10
10
|
module CartoCSSHelper
|
11
11
|
module Validator
|
12
12
|
def run_tests(git_branch)
|
13
|
-
run_expected_rendering_test(git_branch)
|
14
13
|
run_dy_test(git_branch)
|
14
|
+
run_missing_name_test(git_branch)
|
15
|
+
run_expected_rendering_test(git_branch, true)
|
15
16
|
run_closed_way_test(git_branch)
|
17
|
+
run_expected_rendering_test(git_branch)
|
18
|
+
run_unwanted_name_test(git_branch)
|
16
19
|
end
|
17
20
|
|
18
|
-
def run_expected_rendering_test(git_branch)
|
21
|
+
def run_expected_rendering_test(git_branch, quick_and_more_prone_to_errors = false)
|
19
22
|
Git.checkout git_branch
|
20
23
|
puts 'unexpectedly rendered/unrendered keys:'
|
21
|
-
compare_expected_with_real_rendering
|
24
|
+
compare_expected_with_real_rendering(quick_and_more_prone_to_errors)
|
25
|
+
puts
|
26
|
+
end
|
27
|
+
|
28
|
+
def run_missing_name_test(git_branch)
|
29
|
+
Git.checkout git_branch
|
30
|
+
puts 'Check whatever names are displayed:'
|
31
|
+
run_global_check(:check_missing_names)
|
32
|
+
puts
|
33
|
+
end
|
34
|
+
|
35
|
+
def run_unwanted_name_test(git_branch)
|
36
|
+
Git.checkout git_branch
|
37
|
+
puts 'Check whatever names are displayed:'
|
38
|
+
run_global_check(:check_unwanted_names)
|
22
39
|
puts
|
23
40
|
end
|
24
41
|
|
@@ -36,137 +53,181 @@ module CartoCSSHelper
|
|
36
53
|
puts
|
37
54
|
end
|
38
55
|
|
39
|
-
def compare_expected_with_real_rendering
|
56
|
+
def compare_expected_with_real_rendering(quick_and_more_prone_to_errors = false)
|
40
57
|
list_of_documented = CartoCSSHelper::Configuration.get_style_specific_data.list_of_documented_tags
|
41
58
|
info = Info.new
|
42
|
-
list_of_rendered = info.get_render_state_of_tags
|
59
|
+
list_of_rendered = info.get_render_state_of_tags(quick_and_more_prone_to_errors)
|
43
60
|
|
61
|
+
puts 'ensure_that_tags_documented_and_rendered_have_the_same_state'
|
44
62
|
ensure_that_tags_documented_and_rendered_have_the_same_state(list_of_documented, list_of_rendered)
|
63
|
+
|
64
|
+
puts 'ensure_that_all_rendered_tags_are_documented'
|
45
65
|
ensure_that_all_rendered_tags_are_documented(list_of_documented, list_of_rendered)
|
66
|
+
|
67
|
+
puts 'ensure_that_all_documented_are_really_rendered'
|
46
68
|
ensure_that_all_documented_are_really_rendered(list_of_documented, list_of_rendered)
|
47
69
|
end
|
48
70
|
|
49
71
|
def ensure_that_tags_documented_and_rendered_have_the_same_state(list_of_documented, list_of_rendered)
|
50
|
-
list_of_rendered.each
|
72
|
+
list_of_rendered.each do |tag_info|
|
51
73
|
compare_expected_with_tag_data list_of_documented, tag_info
|
52
|
-
|
74
|
+
end
|
53
75
|
end
|
54
76
|
|
55
77
|
def ensure_that_all_rendered_tags_are_documented(list_of_documented, list_of_rendered)
|
56
|
-
list_of_rendered.each
|
57
|
-
if tag_info.
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
end
|
66
|
-
end
|
67
|
-
}
|
78
|
+
list_of_rendered.each do |tag_info|
|
79
|
+
next if is_tag_documented(list_of_documented, tag_info.key, tag_info.value)
|
80
|
+
puts 'documented'
|
81
|
+
puts "\tmissing"
|
82
|
+
puts 'real'
|
83
|
+
print "\t"
|
84
|
+
tag_info.print
|
85
|
+
puts
|
86
|
+
end
|
68
87
|
end
|
69
88
|
|
70
89
|
def ensure_that_all_documented_are_really_rendered(list_of_documented, list_of_rendered)
|
71
|
-
list_of_documented.each
|
72
|
-
if
|
73
|
-
|
74
|
-
print "\t"
|
75
|
-
documented.print
|
76
|
-
puts 'real'
|
77
|
-
puts "\tmissing"
|
78
|
-
puts
|
90
|
+
list_of_documented.each do |documented|
|
91
|
+
if Info.get_expected_state(documented.key, documented.value) == :ignored
|
92
|
+
next
|
79
93
|
end
|
80
|
-
|
94
|
+
next if is_tag_documented(list_of_rendered, documented.key, documented.value)
|
95
|
+
puts 'documented'
|
96
|
+
print "\t"
|
97
|
+
documented.print
|
98
|
+
puts 'real'
|
99
|
+
puts "\tmissing"
|
100
|
+
puts
|
101
|
+
end
|
81
102
|
end
|
82
103
|
|
83
104
|
def is_tag_documented(list, key, value)
|
84
|
-
list.each
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
end
|
89
|
-
end
|
90
|
-
}
|
105
|
+
list.each do |tag_info|
|
106
|
+
next unless key == tag_info.key
|
107
|
+
return true if value == tag_info.value
|
108
|
+
end
|
91
109
|
return false
|
92
110
|
end
|
93
111
|
|
94
112
|
def compare_expected_with_tag_data(list_of_expected, tag_info)
|
95
|
-
list_of_expected.each
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
end
|
107
|
-
return
|
108
|
-
end
|
113
|
+
list_of_expected.each do |expected|
|
114
|
+
next unless expected.key == tag_info.key
|
115
|
+
next unless expected.value == tag_info.value
|
116
|
+
if expected.equal? tag_info
|
117
|
+
puts 'expected'
|
118
|
+
print "\t"
|
119
|
+
expected.print
|
120
|
+
puts 'real'
|
121
|
+
print "\t"
|
122
|
+
tag_info.print
|
123
|
+
puts
|
109
124
|
end
|
110
|
-
|
125
|
+
return
|
126
|
+
end
|
111
127
|
end
|
112
128
|
|
113
129
|
def run_global_check(function)
|
114
|
-
Heuristic.get_tags.each
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
130
|
+
Heuristic.get_tags.each do |element|
|
131
|
+
key = element[0]
|
132
|
+
value = element[1]
|
133
|
+
state = Info.get_expected_state(key, value)
|
134
|
+
tags = { key => value }
|
135
|
+
next if state == :ignore
|
136
|
+
if state == :composite
|
137
|
+
tags.merge!(Info.get_expected_composite(key, value))
|
138
|
+
end
|
139
|
+
(Configuration.get_max_z..Configuration.get_max_z).each do |zlevel| # get_min_z should be used - but as renderer is extremely slow this hack was used TODO
|
140
|
+
send(function, tags, zlevel)
|
141
|
+
end
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
def check_problems_with_closed_line(tags, zlevel, on_water = false)
|
146
|
+
way = Scene.new(tags, zlevel, on_water, 'way', true)
|
147
|
+
closed_way = Scene.new(tags, zlevel, on_water, 'closed_way', true)
|
148
|
+
empty = Scene.new({}, zlevel, on_water, 'node', true)
|
126
149
|
if way.is_output_different(empty)
|
127
|
-
|
128
|
-
|
150
|
+
puts tags unless closed_way.is_output_different(empty)
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
154
|
+
def check_missing_names(tags, zlevel, interactive = false, on_water = false)
|
155
|
+
not_required = CartoCSSHelper::Configuration.get_style_specific_data.name_label_is_not_required
|
156
|
+
return if not_required.include?(tags)
|
157
|
+
['node', 'closed_way', 'way'].each do |type|
|
158
|
+
next if not_required.include?(tags.merge({ type: type }))
|
159
|
+
unless is_object_displaying_anything_as_this_object_type tags, zlevel, on_water, type
|
160
|
+
# puts key+"="+value+" - not displayed as node on z#{zlevel}"
|
161
|
+
next
|
162
|
+
end
|
163
|
+
tags.delete('name') if tags['name'] != nil
|
164
|
+
unless is_object_displaying_name_as_this_object_type tags, 'a', zlevel, on_water, type
|
165
|
+
puts "#{tags} - label is missing on z#{zlevel} #{type}"
|
166
|
+
next
|
129
167
|
end
|
130
168
|
end
|
131
169
|
end
|
132
170
|
|
133
|
-
def
|
134
|
-
|
135
|
-
|
171
|
+
def check_unwanted_names(tags, zlevel, interactive = false, on_water = false)
|
172
|
+
['node', 'closed_way', 'way'].each do |type|
|
173
|
+
not_required = CartoCSSHelper::Configuration.get_style_specific_data.name_label_is_not_required
|
174
|
+
next unless not_required.include?(tags) || not_required.include?(tags.merge({ type: type }))
|
175
|
+
unless is_object_displaying_anything_as_this_object_type tags, zlevel, on_water, type
|
176
|
+
# puts key+"="+value+" - not displayed as node on z#{zlevel}"
|
177
|
+
next
|
178
|
+
end
|
179
|
+
tags.delete('name') if tags['name'] != nil
|
180
|
+
if is_object_displaying_name_as_this_object_type tags, 'a', zlevel, on_water, type
|
181
|
+
puts "#{tags} - label is unxpectedly displayed on z#{zlevel} #{type}"
|
182
|
+
end
|
183
|
+
end
|
184
|
+
end
|
185
|
+
|
186
|
+
def check_dy(tags, zlevel, interactive = false, on_water = false)
|
187
|
+
unless is_object_displaying_anything_as_node tags, zlevel, on_water
|
188
|
+
# puts key+"="+value+" - not displayed as node on z#{zlevel}"
|
136
189
|
return
|
137
190
|
end
|
138
|
-
|
139
|
-
#puts key+"="+value+" - label is missing on z#{zlevel} nodes"
|
191
|
+
unless is_object_displaying_name_as_node tags, 'a', zlevel, on_water
|
192
|
+
# puts key+"="+value+" - label is missing on z#{zlevel} nodes"
|
140
193
|
return
|
141
194
|
end
|
142
195
|
test_name = 'ÉÉÉÉÉÉ ÉÉÉÉÉÉ ÉÉÉÉÉÉ'
|
143
|
-
|
144
|
-
puts
|
196
|
+
until is_object_displaying_name_as_node tags, test_name, zlevel, on_water
|
197
|
+
puts "#{tags} - name is missing for name '#{test_name}' on z#{zlevel}"
|
145
198
|
if interactive
|
146
199
|
puts 'press enter'
|
147
200
|
gets
|
148
201
|
else
|
149
202
|
return
|
150
203
|
end
|
151
|
-
with_name = Scene.new({key => value, 'name' => test_name}, zlevel, on_water, 'node')
|
204
|
+
with_name = Scene.new({ key => value, 'name' => test_name }, zlevel, on_water, 'node', true)
|
152
205
|
with_name.flush_cache
|
153
206
|
puts 'calculating'
|
154
207
|
end
|
155
|
-
#puts key+"="+value+" - name is OK for name '#{name}'"
|
208
|
+
# puts key+"="+value+" - name is OK for name '#{name}'"
|
156
209
|
end
|
157
210
|
|
158
|
-
def
|
159
|
-
name_tags = {
|
160
|
-
with_name = Scene.new(name_tags, zlevel, on_water,
|
161
|
-
nameless_tags =
|
162
|
-
nameless = Scene.new(nameless_tags, zlevel, on_water,
|
211
|
+
def is_object_displaying_name_as_this_object_type(tags, name, zlevel, on_water, type)
|
212
|
+
name_tags = tags.merge({ 'name' => name })
|
213
|
+
with_name = Scene.new(name_tags, zlevel, on_water, type, true)
|
214
|
+
nameless_tags = tags
|
215
|
+
nameless = Scene.new(nameless_tags, zlevel, on_water, type, true)
|
163
216
|
return with_name.is_output_different(nameless)
|
164
217
|
end
|
165
218
|
|
166
|
-
def
|
167
|
-
|
168
|
-
|
219
|
+
def is_object_displaying_name_as_node(tags, name, zlevel, on_water)
|
220
|
+
is_object_displaying_name_as_this_object_type(tags, name, zlevel, on_water, 'node')
|
221
|
+
end
|
222
|
+
|
223
|
+
def is_object_displaying_anything_as_this_object_type(tags, zlevel, on_water, type)
|
224
|
+
object = Scene.new(tags, zlevel, on_water, type, true)
|
225
|
+
empty = Scene.new({}, zlevel, on_water, type, true)
|
169
226
|
return object.is_output_different(empty)
|
170
227
|
end
|
228
|
+
|
229
|
+
def is_object_displaying_anything_as_node(tags, zlevel, on_water)
|
230
|
+
return is_object_displaying_anything_as_this_object_type(tags, zlevel, on_water, 'node')
|
231
|
+
end
|
171
232
|
end
|
172
233
|
end
|
@@ -7,9 +7,10 @@ module CartoCSSHelper
|
|
7
7
|
@file_location = file_location
|
8
8
|
@description = description
|
9
9
|
end
|
10
|
+
|
10
11
|
def identical(another_image)
|
11
|
-
#Returns true if the contents of a file A and a file B are identical.
|
12
|
-
return FileUtils.compare_file(
|
12
|
+
# Returns true if the contents of a file A and a file B are identical.
|
13
|
+
return FileUtils.compare_file(file_location, another_image.file_location)
|
13
14
|
end
|
14
15
|
end
|
15
16
|
|
@@ -22,6 +23,7 @@ module CartoCSSHelper
|
|
22
23
|
@right_file_location = right_image.file_location
|
23
24
|
@description = left_image.description
|
24
25
|
end
|
26
|
+
|
25
27
|
def merge_description_from_next_image(image)
|
26
28
|
@description << ', ' << image.description
|
27
29
|
end
|
@@ -36,7 +38,7 @@ module CartoCSSHelper
|
|
36
38
|
@image_size = image_size
|
37
39
|
@margin = 10
|
38
40
|
@standard_pointsize = 10
|
39
|
-
@header_space = @standard_pointsize*1.5
|
41
|
+
@header_space = @standard_pointsize * 1.5
|
40
42
|
@diff_note_space = @standard_pointsize
|
41
43
|
|
42
44
|
render
|
@@ -44,13 +46,13 @@ module CartoCSSHelper
|
|
44
46
|
|
45
47
|
def compress(before, after)
|
46
48
|
returned = [PairOfComparedImages.new(before[0], after[0])]
|
47
|
-
(1...before.length).each
|
48
|
-
if before[i].identical(before[i-1]) && after[i].identical(after[i-1])
|
49
|
+
(1...before.length).each do |i|
|
50
|
+
if before[i].identical(before[i - 1]) && after[i].identical(after[i - 1])
|
49
51
|
returned[-1].merge_description_from_next_image(before[i])
|
50
52
|
else
|
51
53
|
returned.push(PairOfComparedImages.new(before[i], after[i]))
|
52
54
|
end
|
53
|
-
|
55
|
+
end
|
54
56
|
return returned
|
55
57
|
end
|
56
58
|
|
@@ -58,17 +60,16 @@ module CartoCSSHelper
|
|
58
60
|
create_canvas
|
59
61
|
offset = 0
|
60
62
|
render_header
|
61
|
-
offset += @header_space + @margin*1.5
|
62
|
-
|
63
|
-
offset += @diff_note_space + @margin*0.5
|
63
|
+
offset += @header_space + @margin * 1.5
|
64
|
+
offset += @diff_note_space + @margin * 0.5
|
64
65
|
render_images_with_labels offset
|
65
|
-
offset +=
|
66
|
+
offset += @compared.length * (@margin + @image_size)
|
66
67
|
render_footer offset
|
67
68
|
end
|
68
69
|
|
69
70
|
def create_canvas
|
70
71
|
y = get_needed_y
|
71
|
-
x = @image_size*2+3
|
72
|
+
x = @image_size * 2 + 3 * @margin
|
72
73
|
|
73
74
|
@canvas = Magick::Image.new(x, y)
|
74
75
|
end
|
@@ -76,48 +77,49 @@ module CartoCSSHelper
|
|
76
77
|
def get_needed_y
|
77
78
|
y = 0
|
78
79
|
y += @header_space
|
79
|
-
y += @margin*1.5
|
80
|
+
y += @margin * 1.5
|
80
81
|
y += @diff_note_space
|
81
|
-
y += @margin*0.5
|
82
|
-
y +=
|
82
|
+
y += @margin * 0.5
|
83
|
+
y += @compared.length * (@image_size + @margin)
|
83
84
|
y += @diff_note_space
|
84
85
|
return y
|
85
86
|
end
|
86
87
|
|
87
88
|
def render_header
|
88
89
|
header_drawer = Magick::Draw.new
|
89
|
-
header_drawer.pointsize(@header_space*3/5)
|
90
|
+
header_drawer.pointsize(@header_space * 3 / 5)
|
90
91
|
header_drawer.text(@margin, @header_space, @header)
|
91
92
|
header_drawer.draw(@canvas)
|
92
93
|
end
|
93
94
|
|
94
|
-
def render_diff_note(y_offset)
|
95
|
-
drawer = Magick::Draw.new
|
96
|
-
drawer.pointsize(@diff_note_space)
|
97
|
-
#drawer.text(@margin, y_offset, 'before')
|
98
|
-
drawer.draw(@canvas)
|
99
|
-
#drawer.text(@margin*2 + @image_size, y_offset, 'after')
|
100
|
-
drawer.draw(@canvas)
|
101
|
-
end
|
102
|
-
|
103
95
|
def render_images_with_labels(y_offset)
|
104
|
-
(0...@compared.length).each
|
96
|
+
(0...@compared.length).each do |i|
|
105
97
|
render_row_of_labelled_images(@compared[i], y_offset + i * (@margin + @image_size))
|
106
|
-
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
def read_image_from_disk(filename)
|
102
|
+
return Magick::Image.read(filename)[0]
|
103
|
+
rescue Magick::ImageMagickError => e
|
104
|
+
# for example on loading corrupted empty file (for example CartoCSSHelper was interuppted during writing to disk...)
|
105
|
+
puts "reading image <#{filename}> from disk failed"
|
106
|
+
puts e.class
|
107
|
+
puts e
|
108
|
+
raise e
|
107
109
|
end
|
108
110
|
|
109
111
|
def render_row_of_labelled_images(processed, y_offset)
|
110
|
-
left_image =
|
111
|
-
right_image =
|
112
|
+
left_image = read_image_from_disk(processed.left_file_location)
|
113
|
+
right_image = read_image_from_disk(processed.right_file_location)
|
112
114
|
drawer = Magick::Draw.new
|
113
|
-
drawer.pointsize(@diff_note_space*4/5)
|
115
|
+
drawer.pointsize(@diff_note_space * 4 / 5)
|
114
116
|
if left_image == right_image
|
115
|
-
drawer.text(@margin + @image_size/2, y_offset, "#{processed.description} - unchanged")
|
117
|
+
drawer.text(@margin + @image_size / 2, y_offset, "#{processed.description} - unchanged")
|
116
118
|
drawer.draw(@canvas)
|
117
119
|
else
|
118
120
|
drawer.text(@margin, y_offset, "#{processed.description} - before")
|
119
121
|
drawer.draw(@canvas)
|
120
|
-
drawer.text(@margin*2 + @image_size, y_offset, "#{processed.description} - after")
|
122
|
+
drawer.text(@margin * 2 + @image_size, y_offset, "#{processed.description} - after")
|
121
123
|
drawer.draw(@canvas)
|
122
124
|
end
|
123
125
|
render_row_of_images(y_offset, left_image, right_image)
|
@@ -133,17 +135,17 @@ module CartoCSSHelper
|
|
133
135
|
# noinspection RubyResolve
|
134
136
|
def render_row_of_images(y_offset, left_image, right_image)
|
135
137
|
if left_image == right_image
|
136
|
-
@canvas.composite!(left_image, @margin*1.5 + @image_size/2, y_offset, Magick::OverCompositeOp)
|
138
|
+
@canvas.composite!(left_image, @margin * 1.5 + @image_size / 2, y_offset, Magick::OverCompositeOp)
|
137
139
|
else
|
138
140
|
@canvas.composite!(left_image, @margin, y_offset, Magick::OverCompositeOp)
|
139
|
-
@canvas.composite!(right_image, @margin*2
|
141
|
+
@canvas.composite!(right_image, @margin * 2 + @image_size, y_offset, Magick::OverCompositeOp)
|
140
142
|
end
|
141
143
|
end
|
142
144
|
|
143
145
|
def render_footer(y_offset)
|
144
146
|
label_drawer = Magick::Draw.new
|
145
147
|
label_drawer.pointsize(@standard_pointsize)
|
146
|
-
label_drawer.text(@margin, y_offset, 'generated using https://github.com/
|
148
|
+
label_drawer.text(@margin, y_offset, 'generated using https://github.com/matkoniecz/CartoCSSHelper')
|
147
149
|
label_drawer.draw(@canvas)
|
148
150
|
end
|
149
151
|
|