usps_flags 0.1.26 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -8,18 +8,18 @@ class USPSFlags::Generate
8
8
  # @param [Boolean] field Whether to generate the flag field (including any border).
9
9
  # @param [String] scale The image scale divisor factor.
10
10
  # @return [String] Returns the SVG data.
11
- def get(flag, outfile: nil, scale: nil, field: true)
11
+ def svg(flag, outfile: nil, scale: nil, field: true)
12
12
  flag = flag.upcase.delete("/", "_", "PENNANT")
13
13
  if ["CRUISE", "OIC"].include?(flag)
14
- pennant(type: flag, outfile: outfile, scale: scale)
14
+ USPSFlags::Generate::Flag.pennant(type: flag, outfile: outfile, scale: scale)
15
15
  elsif flag == "ENSIGN"
16
- ensign(outfile: outfile, scale: scale)
16
+ USPSFlags::Generate::Flag.ensign(outfile: outfile, scale: scale)
17
17
  elsif flag == "US"
18
- us(outfile: outfile, scale: scale)
18
+ USPSFlags::Generate::Flag.us(outfile: outfile, scale: scale)
19
19
  elsif flag == "WHEEL"
20
- wheel(outfile: outfile, scale: scale)
20
+ USPSFlags::Generate::Flag.wheel(outfile: outfile, scale: scale)
21
21
  else
22
- flag(rank: flag, outfile: outfile, scale: scale, field: field)
22
+ USPSFlags::Generate::Flag.officer(rank: flag, outfile: outfile, scale: scale, field: field)
23
23
  end
24
24
  end
25
25
 
@@ -55,13 +55,12 @@ class USPSFlags::Generate
55
55
  def all(svg: true, png: true, zips: true, reset: true)
56
56
  remove_static_files if reset
57
57
 
58
- max_length = USPSFlags::Helpers.valid_flags(:all).map(&:length).max
59
58
  puts "\nSVGs generate a single file.",
60
59
  "PNGs generate full-res, 1500w, 1000w, 500w, and thumbnail files.",
61
60
  "Corresponding rank insignia (including smaller sizes) are also generated, as appropriate."
62
61
  USPSFlags::Helpers.log "\n#{Time.now.strftime('%Y%m%d.%H%M%S%z')} – Generating static files...\n\n"
63
- USPSFlags::Helpers.log "Flag | SVG | PNG | Run time\n".rjust(max_length+31),
64
- "\n".rjust(max_length+32, "-")
62
+ USPSFlags::Helpers.log "Flag | SVG | PNG | Run time\n".rjust(USPSFlags::Helpers.max_flag_name_length+31),
63
+ "\n".rjust(USPSFlags::Helpers.max_flag_name_length+32, "-")
65
64
 
66
65
  overall_start_time = Time.now
67
66
 
@@ -113,234 +112,62 @@ class USPSFlags::Generate
113
112
  # @return [String] Returns the SVG data.
114
113
  def spec(outfile: nil, fly: nil, unit: nil, scale: nil)
115
114
  fly = fly.nil? ? USPSFlags::Config::BASE_FLY : fly
116
- final_svg = ""
117
- final_svg << USPSFlags::Core.headers(scale: scale, title: "USPS Trident Specifications")
118
- final_svg << USPSFlags::Core.trident_spec(fly: fly, unit: unit)
119
- final_svg << USPSFlags::Core.footer
115
+ svg = ""
116
+ svg << USPSFlags::Core.headers(scale: scale, title: "USPS Trident Specifications")
117
+ svg << USPSFlags::Core.trident_spec(fly: fly, unit: unit)
118
+ svg << USPSFlags::Core.footer
120
119
 
121
- if outfile.nil?
122
- puts final_svg, "\n"
123
- else
124
- f = ::File.new(outfile, "w+")
125
- f.write(final_svg)
126
- f.close
127
- end
128
- final_svg
120
+ USPSFlags::Helpers.output(svg, outfile: outfile)
129
121
  end
130
122
 
131
123
  private
132
- def flag(rank: nil, width: USPSFlags::Config::BASE_FLY, outfile: nil, scale: nil, field: true)
133
- raise "Error: No rank specified." if rank.nil?
134
- rank = rank.to_s.upcase
135
-
136
- final_svg = ""
137
- final_svg << USPSFlags::Core.headers(scale: scale, title: rank)
138
-
139
- rank.slice!(0) if !field && USPSFlags::Helpers.valid_flags(:past).include?(rank)
140
- rank = "CDR" if rank == "C"
141
-
142
- flag_details = USPSFlags::Helpers.flag_details(rank)
143
- trident_color = field ? :white : flag_details[:color]
144
-
145
- final_svg << USPSFlags::Core.field(style: flag_details[:style], color: flag_details[:color]) if field
146
-
147
- final_svg << "<g transform=\"translate(-150, 400)\"><g transform=\"scale(0.58333)\">" if flag_details[:style] == :past
148
-
149
- if flag_details[:type] == :n && flag_details[:count] == 3
150
- # The side C/C tridents are angled 45 degrees, and intersect the central one at 1/3 up from the bottom
151
- trident = USPSFlags::Core.trident(flag_details[:type], color: trident_color)
152
- x_distance = USPSFlags::Config::BASE_FLY*4/39
153
- y_distance = USPSFlags::Config::BASE_FLY*5/78
154
- final_svg << "<g transform=\"translate(-#{x_distance}, #{y_distance})\"><g transform=\"rotate(-45, #{USPSFlags::Config::BASE_FLY/2}, #{USPSFlags::Config::BASE_HOIST/2})\">\n#{trident}</g></g>"
155
- final_svg << "\n#{trident}"
156
- final_svg << "<g transform=\"translate(#{x_distance}, #{y_distance})\"><g transform=\"rotate(45, #{USPSFlags::Config::BASE_FLY/2}, #{USPSFlags::Config::BASE_HOIST/2})\">\n#{trident}</g></g>"
157
- elsif flag_details[:type] == :n && flag_details[:count] == 2
158
- # V/C tridents are angled 45 degrees, and intersect at 15/32 up from the bottom
159
- trident = USPSFlags::Core.trident(flag_details[:type], color: trident_color)
160
- x_distance = USPSFlags::Config::BASE_FLY*4/55
161
- final_svg << "<g transform=\"translate(-#{x_distance})\"><g transform=\"rotate(-45, #{USPSFlags::Config::BASE_FLY/2}, #{USPSFlags::Config::BASE_HOIST/2})\">\n#{trident}</g></g>"
162
- final_svg << "<g transform=\"translate(#{x_distance})\"><g transform=\"rotate(45, #{USPSFlags::Config::BASE_FLY/2}, #{USPSFlags::Config::BASE_HOIST/2})\">\n#{trident}</g></g>"
163
- elsif [:s, :d].include?(flag_details[:type]) && flag_details[:count] == 3
164
- # Cdr and D/C tridents are spaced 1/2 the fly apart with the central one 1/4 the fly above the sides
165
- trident = USPSFlags::Core.trident(flag_details[:type], color: trident_color, field_color: flag_details[:color])
166
- x_distance = USPSFlags::Config::BASE_FLY/4
167
- y_distance = USPSFlags::Config::BASE_FLY/16
168
- final_svg << "<g transform=\"translate(-#{x_distance}, #{y_distance})\">\n#{trident}</g>"
169
- final_svg << "<g transform=\"translate(0, -#{y_distance+1})\">\n#{trident}</g>"
170
- final_svg << "<g transform=\"translate(#{x_distance}, #{y_distance})\">\n#{trident}</g>"
171
- elsif [:s, :d].include?(flag_details[:type]) && flag_details[:count] == 2
172
- # Lt/C and D/Lt/C tridents are spaced 1/3 the fly apart
173
- trident = USPSFlags::Core.trident(flag_details[:type], color: trident_color, field_color: flag_details[:color])
174
- x_distance = USPSFlags::Config::BASE_FLY/6
175
- final_svg << "<g transform=\"translate(-#{x_distance})\">\n#{trident}</g>"
176
- final_svg << "<g transform=\"translate(#{x_distance})\">\n#{trident}</g>"
177
- elsif [:s, :d, :stf, :n].include?(flag_details[:type]) && %w[LT DLT].include?(rank)
178
- # Swallowtail tridents need to move towards the hoist due to the tails
179
- x_distance = USPSFlags::Config::BASE_FLY/10 if field
180
- final_svg << "<g transform=\"translate(-#{x_distance})\">" if field
181
- final_svg << USPSFlags::Core.trident(flag_details[:type], field_color: flag_details[:color], color: :red)
182
- final_svg << "</g>" if field
183
- elsif [:s, :d, :stf, :n].include?(flag_details[:type])
184
- # All other tridents are centered on the field
185
- final_svg << USPSFlags::Core.trident(flag_details[:type], field_color: flag_details[:color])
186
- else
187
- # Special Flags
188
- # Paths were designed for a base fly of 3000 pixels, but the base was changed for more useful fractions.
189
- final_svg << "<g transform=\"translate(#{USPSFlags::Config::BASE_FLY/10})\">" unless field
190
- final_svg << "<g transform=\"scale(#{Rational(USPSFlags::Config::BASE_FLY,3000).to_f})\">"
191
- case flag_details[:type]
192
- when :a
193
- final_svg << USPSFlags::Core.binoculars(flag_details[:level])
194
- when :f
195
- final_svg << USPSFlags::Core.trumpet(flag_details[:level])
196
- when :fc
197
- final_svg << USPSFlags::Core.anchor
198
- when :pc
199
- final_svg << USPSFlags::Core.lighthouse
200
- end
201
- final_svg << "</g>"
202
- final_svg << "</g>" unless field
203
- end
204
-
205
- final_svg << "</g></g>" if flag_details[:style] == :past
206
-
207
- final_svg << USPSFlags::Core.footer
208
-
209
- if outfile.nil?
210
- puts final_svg, "\n"
211
- elsif outfile != ""
212
- f = ::File.new(outfile, "w+")
213
- f.write(final_svg)
214
- f.close
215
- end
216
- final_svg
217
- end
218
-
219
- def pennant(type: "CRUISE", outfile: nil, scale: nil)
220
- type = type.upcase
221
- final_svg = ""
222
- title = case type
223
- when "CRUISE"
224
- "Cruise Pennant"
225
- when "OIC"
226
- "Officer-in-Charge Pennant"
227
- end
228
- final_svg << USPSFlags::Core.headers(pennant: true, scale: scale, title: title)
229
- final_svg << USPSFlags::Core.pennant(type)
230
- final_svg << USPSFlags::Core.footer
231
-
232
- if outfile.nil?
233
- puts final_svg, "\n"
234
- elsif outfile != ""
235
- f = ::File.new(outfile, "w+")
236
- f.write(final_svg)
237
- f.close
238
- end
239
- final_svg
240
- end
241
-
242
- def ensign(outfile: nil, scale: nil)
243
- final_svg = ""
244
- final_svg << USPSFlags::Core.headers(scale: scale, title: "USPS Ensign")
245
- final_svg << USPSFlags::Core.ensign
246
- final_svg << USPSFlags::Core.footer
247
-
248
- if outfile.nil?
249
- puts final_svg, "\n"
250
- elsif outfile != ""
251
- f = ::File.new(outfile, "w+")
252
- f.write(final_svg)
253
- f.close
254
- end
255
- final_svg
256
- end
257
-
258
- def wheel(outfile: nil, scale: nil)
259
- width = 4327.4667
260
- height = 4286.9333
261
- final_svg = ""
262
- final_svg << USPSFlags::Core.headers(width: width, height: height, scale: scale, title: "USPS Ensign Wheel")
263
- final_svg << USPSFlags::Core.wheel
264
- final_svg << USPSFlags::Core.footer
265
-
266
- if outfile.nil?
267
- puts final_svg, "\n"
268
- elsif outfile != ""
269
- f = ::File.new(outfile, "w+")
270
- f.write(final_svg)
271
- f.close
272
- end
273
- final_svg
274
- end
275
-
276
- def us(outfile: nil, scale: nil)
277
- base_hoist = 2000.to_f
278
- base_fly = base_hoist * 1.91
279
- hoist = scale.nil? ? base_hoist : (base_hoist / scale)
280
- fly = hoist * 1.91
281
- final_svg = ""
282
- final_svg << USPSFlags::Core.headers(width: fly, height: hoist, scale: scale, title: "US Ensign")
283
- final_svg << USPSFlags::Core.us
284
- final_svg << USPSFlags::Core.footer
285
-
286
- if outfile.nil?
287
- puts final_svg, "\n"
288
- elsif outfile != ""
289
- f = ::File.new(outfile, "w+")
290
- f.write(final_svg)
291
- f.close
292
- end
293
- final_svg
294
- end
295
-
296
124
  def remove_static_files
297
125
  ["SVG", "PNG", "ZIP"].each { |dir| ::FileUtils.rm_rf(Dir.glob("#{USPSFlags::Config.flags_dir}/#{dir}/*")) }
298
126
  ["SVG/insignia", "PNG/insignia"].each { |dir| ::FileUtils.mkdir_p("#{USPSFlags::Config.flags_dir}/#{dir}") }
299
127
  USPSFlags::Helpers.log "\n - Cleared previous files.\n"
300
128
  end
301
129
 
302
- def get_file_paths(flag)
303
- svg_file = "#{USPSFlags::Config.flags_dir}/SVG/#{flag}.svg"
304
- png_file = svg_file.gsub("/SVG/", "/PNG/").gsub(".svg", ".png")
305
- svg_ins_file = svg_file.gsub("/SVG/", "/SVG/insignia/")
306
- png_ins_file = png_file.gsub("/PNG/", "/PNG/insignia/")
130
+ def set_file_paths(flag)
131
+ @svg_file = "#{USPSFlags::Config.flags_dir}/SVG/#{flag}.svg"
132
+ @png_file = @svg_file.gsub("/SVG/", "/PNG/").gsub(".svg", ".png")
133
+ @svg_ins_file = @svg_file.gsub("/SVG/", "/SVG/insignia/")
134
+ @png_ins_file = @svg_file.gsub("/SVG/", "/PNG/insignia/").gsub(".svg", ".png")
135
+ [@svg_file, @png_file, @svg_ins_file, @png_ins_file]
307
136
  end
308
137
 
309
138
  def generate_static_images_for(flag, svg: true, png: true)
310
139
  start_time = Time.now
311
- USPSFlags::Helpers.log " | | _ _ _ _ _ | \r".rjust(max_length+31, " ")
140
+ USPSFlags::Helpers.log " | | _ _ _ _ _ | \r".rjust(USPSFlags::Helpers.max_flag_name_length+31, " ")
312
141
  flag = flag.upcase
313
- USPSFlags::Helpers.log "#{flag.rjust(max_length)} |"
142
+ USPSFlags::Helpers.log "#{flag.rjust(USPSFlags::Helpers.max_flag_name_length)} |"
314
143
 
315
- svg_file, png_file, svg_ins_file, png_ins_file = get_file_paths(flag)
316
-
317
- past = (flag[0] == "P" && flag != "PORTCAP")
144
+ set_file_paths(flag)
318
145
 
319
146
  if svg
320
- generate_static_svg(flag, svg_file)
147
+ generate_static_svg(flag)
321
148
  else
322
149
  USPSFlags::Helpers.log "-"
323
150
  end
324
151
 
325
152
  if png
326
- generate_static_png(flag, png_file)
153
+ generate_static_png(flag)
327
154
  else
328
155
  USPSFlags::Helpers.log "- "
329
156
  end
157
+
330
158
  run_time = (Time.now - start_time).round(4).to_s[(0..5)].ljust(6, "0")
331
159
  USPSFlags::Helpers.log " | #{run_time} s\n"
332
160
  end
333
161
 
334
162
  def generate_static_svg(flag)
335
- svg_file, png_file, svg_ins_file, png_ins_file = get_file_paths(flag)
336
163
  begin
337
164
  USPSFlags::Helpers.log " "
338
- get flag, outfile: svg_file, scale: 1
165
+ svg flag, outfile: @svg_file, scale: 1
339
166
  USPSFlags::Helpers.log "S"
340
- if past || !USPSFlags::Helpers.valid_flags(:insignia).include?(flag)
167
+ if USPSFlags::Helpers.valid_flags(:past).include?(flag) || !USPSFlags::Helpers.valid_flags(:insignia).include?(flag)
341
168
  USPSFlags::Helpers.log "-"
342
169
  else
343
- get flag, field: false, outfile: svg_ins_file, scale: 1
170
+ svg flag, field: false, outfile: @svg_ins_file, scale: 1
344
171
  USPSFlags::Helpers.log "I"
345
172
  end
346
173
  rescue => e
@@ -349,38 +176,35 @@ class USPSFlags::Generate
349
176
  end
350
177
 
351
178
  def generate_static_png(flag)
352
- svg_file, png_file, svg_ins_file, png_ins_file = get_file_paths(flag)
353
179
  USPSFlags::Helpers.log " | "
354
180
  begin
355
181
  USPSFlags::Helpers.log "…\b"
356
- png(File.read(svg_file), outfile: png_file) unless ::File.exist?(png_file)
182
+ png(File.read(@svg_file), outfile: @png_file) unless ::File.exist?(@png_file)
357
183
  USPSFlags::Helpers.log "F"
358
- if past || !insignia_flags.include?(flag)
184
+ if USPSFlags::Helpers.valid_flags(:past).include?(flag) || !USPSFlags::Helpers.valid_flags(:insignia).include?(flag)
359
185
  USPSFlags::Helpers.log "-"
360
186
  else
361
187
  USPSFlags::Helpers.log "…\b"
362
- png(File.read(svg_ins_file), outfile: png_ins_file, trim: true) unless ::File.exist?(png_ins_file)
188
+ png(File.read(@svg_ins_file), outfile: @png_ins_file, trim: true) unless ::File.exist?(@png_ins_file)
363
189
  USPSFlags::Helpers.log "I"
364
190
  end
365
191
  USPSFlags::Helpers.png_sizes.keys.each do |size|
366
- if ::File.exist?("#{USPSFlags::Config.flags_dir}/PNG/#{flag}.#{size}.png")
192
+ USPSFlags::Helpers.log(".") and next if ::File.exist?("#{USPSFlags::Config.flags_dir}/PNG/#{flag}.#{size}.png")
193
+
194
+ USPSFlags::Helpers.log "…\b"
195
+ size, size_key = USPSFlags::Helpers.size_and_key(size: size, flag: flag)
196
+ USPSFlags::Helpers.resize_png(@png_ins_file, flag: flag, size: size, size_key: size_key) if USPSFlags::Helpers.valid_flags(:insignia).include?(flag)
197
+ USPSFlags::Helpers.log USPSFlags::Helpers.png_sizes[size_key]
198
+ if ::File.exist?(@png_ins_file) && ::File.exist?("#{USPSFlags::Config.flags_dir}/PNG/insignia/#{flag}.#{size}.png")
367
199
  USPSFlags::Helpers.log "."
368
- else
200
+ elsif ::File.exist?(@png_ins_file) && MiniMagick::Image.open(@png_ins_file)[:width] > size && USPSFlags::Helpers.valid_flags(:insignia).include?(flag)
369
201
  USPSFlags::Helpers.log "…\b"
370
- size, size_key = USPSFlags::Helpers.size_and_key(size: size, flag: flag)
371
- USPSFlags::Helpers.resize_png(png_ins_file, flag: flag, size: size, size_key: size_key)
372
- USPSFlags::Helpers.log USPSFlags::Helpers.png_sizes[size_key]
373
- if ::File.exist?(png_ins_file) && ::File.exist?("#{USPSFlags::Config.flags_dir}/PNG/insignia/#{flag}.#{size}.png")
374
- USPSFlags::Helpers.log "."
375
- elsif ::File.exist?(png_ins_file) && MiniMagick::Image.open(png_ins_file)[:width] > size
376
- USPSFlags::Helpers.log "…\b"
377
- USPSFlags::Helpers.resize_png(png_ins_file, flag: flag, size: size, size_key: size_key)
378
- USPSFlags::Helpers.log "i"
379
- elsif ::File.exist?(png_ins_file)
380
- USPSFlags::Helpers.log "+"
381
- else
382
- USPSFlags::Helpers.log "-"
383
- end
202
+ USPSFlags::Helpers.resize_png(@png_ins_file, flag: flag, size: size, size_key: size_key)
203
+ USPSFlags::Helpers.log "i"
204
+ elsif ::File.exist?(@png_ins_file)
205
+ USPSFlags::Helpers.log "+"
206
+ else
207
+ USPSFlags::Helpers.log "-"
384
208
  end
385
209
  end
386
210
  rescue => e
@@ -0,0 +1,71 @@
1
+ # SVG building helpers.
2
+ #
3
+ # These methods should never need to be called directly, except when designing new flags.
4
+ # @private
5
+ class USPSFlags::Helpers::Builders
6
+ class << self
7
+ # Displays an overlay grid with regularly spaced locator markers.
8
+ #
9
+ # This is useful for adjusting or creating new SVG data generators, but should not otherwise need to be called.
10
+ # @private
11
+ def grid(width: USPSFlags::Config::BASE_FLY, height: USPSFlags::Config::BASE_HOIST)
12
+ <<~SVG
13
+ <circle cx="0" cy="0" r="#{width/60}" fill="#000000" fill-opacity="0.4" />
14
+ <circle cx="#{width}" cy="0" r="#{width/60}" fill="#000000" fill-opacity="0.4" />
15
+ <circle cx="#{width}" cy="#{height}" r="#{width/60}" fill="#000000" fill-opacity="0.4" />
16
+ <circle cx="0" cy="#{height}" r="#{width/60}" fill="#000000" fill-opacity="0.4" />
17
+
18
+ <circle cx="#{width*1/4}" cy="#{height/2}" r="#{width/60}" fill="#999999" fill-opacity="0.4" />
19
+ <circle cx="#{width*3/4}" cy="#{height/2}" r="#{width/60}" fill="#999999" fill-opacity="0.4" />
20
+
21
+ <circle cx="#{width/2}" cy="#{height*1/4}" r="#{width/60}" fill="#999999" fill-opacity="0.4" />
22
+ <circle cx="#{width/2}" cy="#{height/2}" r="#{width/60}" fill="#000000" fill-opacity="0.4" />
23
+ <circle cx="#{width/2}" cy="#{height/2}" r="#{width/75}" fill="#CCCCCC" fill-opacity="0.4" />
24
+ <circle cx="#{width/2}" cy="#{height/2}" r="#{width/100}" fill="#000000" fill-opacity="0.4" />
25
+ <circle cx="#{width/2}" cy="#{height*3/4}" r="#{width/60}" fill="#999999" fill-opacity="0.4" />
26
+
27
+ <line x1="0" y1="0" x2="#{width}" y2="0" stroke="#333333" stroke-width="#{width/600}" stroke-opacity="0.5" />
28
+ <line x1="0" y1="#{height*1/4}" x2="#{width}" y2="#{height*1/4}" stroke="#333333" stroke-width="#{width/600}" stroke-opacity="0.5" />
29
+ <line x1="0" y1="#{height/2}" x2="#{width}" y2="#{height/2}" stroke="#333333" stroke-width="#{width/600}" stroke-opacity="0.5" />
30
+ <line x1="0" y1="#{height*3/4}" x2="#{width}" y2="#{height*3/4}" stroke="#333333" stroke-width="#{width/600}" stroke-opacity="0.5" />
31
+ <line x1="0" y1="#{height}" x2="#{width}" y2="#{height}" stroke="#333333" stroke-width="#{width/600}" stroke-opacity="0.5" />
32
+
33
+ <line y1="0" x1="0" y2="#{height}" x2="0" stroke="#333333" stroke-width="#{width/600}" stroke-opacity="0.5" />
34
+ <line y1="0" x1="#{width*1/6}" y2="#{height}" x2="#{width*1/6}" stroke="#333333" stroke-width="#{width/600}" stroke-opacity="0.5" />
35
+ <line y1="0" x1="#{width*2/6}" y2="#{height}" x2="#{width*2/6}" stroke="#333333" stroke-width="#{width/600}" stroke-opacity="0.5" />
36
+ <line y1="0" x1="#{width*3/6}" y2="#{height}" x2="#{width*3/6}" stroke="#333333" stroke-width="#{width/600}" stroke-opacity="0.5" />
37
+ <line y1="0" x1="#{width*4/6}" y2="#{height}" x2="#{width*4/6}" stroke="#333333" stroke-width="#{width/600}" stroke-opacity="0.5" />
38
+ <line y1="0" x1="#{width*5/6}" y2="#{height}" x2="#{width*5/6}" stroke="#333333" stroke-width="#{width/600}" stroke-opacity="0.5" />
39
+ <line y1="0" x1="#{width}" y2="#{height}" x2="#{width}" stroke="#333333" stroke-width="#{width/600}" stroke-opacity="0.5" />
40
+
41
+ <line x1="#{width/2}" y1="#{height*1/4}" x2="#{width*3/4}" y2="#{height/2}" stroke="#999999" stroke-width="#{width/600}" stroke-opacity="0.5" />
42
+ <line x1="#{width*3/4}" y1="#{height/2}" x2="#{width/2}" y2="#{height*3/4}" stroke="#999999" stroke-width="#{width/600}" stroke-opacity="0.5" />
43
+ <line x1="#{width/2}" y1="#{height*3/4}" x2="#{width*1/4}" y2="#{height/2}" stroke="#999999" stroke-width="#{width/600}" stroke-opacity="0.5" />
44
+ <line x1="#{width*1/4}" y1="#{height/2}" x2="#{width/2}" y2="#{height*1/4}" stroke="#999999" stroke-width="#{width/600}" stroke-opacity="0.5" />
45
+
46
+ SVG
47
+ end
48
+
49
+ # Displays an overlay indicator of concentric circles and radiating lines.
50
+ #
51
+ # This is useful for adjusting or creating new SVG data generators, but should not otherwise need to be called.
52
+ # @private
53
+ def locator
54
+ <<~SVG
55
+ <circle cx="0" cy="0" r="#{USPSFlags::Config::BASE_FLY*2}" fill="#000000" fill-opacity="0.4" />
56
+ <circle cx="0" cy="0" r="#{USPSFlags::Config::BASE_FLY}" fill="#333333" fill-opacity="0.4" />
57
+ <circle cx="0" cy="0" r="#{USPSFlags::Config::BASE_FLY/2}" fill="#666666" fill-opacity="0.4" />
58
+ <circle cx="0" cy="0" r="#{USPSFlags::Config::BASE_FLY/4}" fill="#999999" fill-opacity="0.4" />
59
+ <circle cx="0" cy="0" r="#{USPSFlags::Config::BASE_FLY/8}" fill="#CCCCCC" fill-opacity="0.4" />
60
+ <circle cx="0" cy="0" r="#{USPSFlags::Config::BASE_FLY/16}" fill="#FFFFFF" fill-opacity="0.4" />
61
+
62
+ <line x1="-#{USPSFlags::Config::BASE_FLY}" y1="-#{USPSFlags::Config::BASE_HOIST}" x2="#{USPSFlags::Config::BASE_FLY}" y2="#{USPSFlags::Config::BASE_HOIST}" stroke="#FFFFFF" stroke-width="#{USPSFlags::Config::BASE_FLY/600}" />
63
+ <line x1="-#{USPSFlags::Config::BASE_FLY}" y1="#{USPSFlags::Config::BASE_HOIST}" x2="#{USPSFlags::Config::BASE_FLY}" y2="-#{USPSFlags::Config::BASE_HOIST}" stroke="#FFFFFF" stroke-width="#{USPSFlags::Config::BASE_FLY/600}" />
64
+ <line x1="0" y1="#{USPSFlags::Config::BASE_HOIST}" x2="0" y2="-#{USPSFlags::Config::BASE_HOIST}" stroke="#FFFFFF" stroke-width="#{USPSFlags::Config::BASE_FLY/600}" />
65
+ <line x1="-#{USPSFlags::Config::BASE_FLY}" y1="0" x2="#{USPSFlags::Config::BASE_FLY}" y2="0" stroke="#FFFFFF" stroke-width="#{USPSFlags::Config::BASE_FLY/600}" />
66
+
67
+ <rect x="0" y="0" width="#{USPSFlags::Config::BASE_FLY/30}" height="#{USPSFlags::Config::BASE_FLY/30}" fill="#333333" fill-opacity="0.6" />
68
+ SVG
69
+ end
70
+ end
71
+ end
@@ -0,0 +1,81 @@
1
+ # Trident specification sheet arrows.
2
+ #
3
+ # These methods should never need to be called directly.
4
+ # @private
5
+ class USPSFlags::Helpers::SpecArrows
6
+ class << self
7
+ # Creates a vertical arrow for the trident spec sheet.
8
+ #
9
+ # This is used USPSFlags::Core.trident_spec, and should never need to be called directly.
10
+ # @private
11
+ def vertical(x, top, bottom, pointer_top = nil, pointer_bottom = nil, label: nil, label_offset: (USPSFlags::Config::BASE_FLY/120), label_offset_y: 0, label_align: "left", color: "#CCCCCC", stroke_width: (USPSFlags::Config::BASE_FLY/600), stroke_dash: "10, 10", font_size: (USPSFlags::Config::BASE_FLY/60), arrow_size: (USPSFlags::Config::BASE_FLY/120), fly: USPSFlags::Config::BASE_FLY, unit: nil)
12
+ label = bottom - top if label.nil?
13
+ label = label.to_i if label - label.to_i == 0
14
+ label = Rational(label) * fly / USPSFlags::Config::BASE_FLY
15
+ if label == label.to_i
16
+ label = label.to_i
17
+ label_fraction = ""
18
+ else
19
+ label, label_fraction = label.to_simplified_a
20
+ end
21
+ svg = ""
22
+ unless pointer_top.nil?
23
+ svg << <<~SVG
24
+ <line x1="#{x}" y1="#{top}" x2="#{pointer_top}" y2="#{top}" stroke="#{color}" stroke-width="#{stroke_width}" stroke-dasharray="#{stroke_dash}" />
25
+ SVG
26
+ end
27
+ unless pointer_bottom.nil?
28
+ svg << <<~SVG
29
+ <line x1="#{x}" y1="#{bottom}" x2="#{pointer_bottom}" y2="#{bottom}" stroke="#{color}" stroke-width="#{stroke_width}" stroke-dasharray="#{stroke_dash}" />
30
+ SVG
31
+ end
32
+
33
+ svg << <<~SVG
34
+ <path d="M#{x} #{top} l #{arrow_size} #{arrow_size} M#{x} #{top} l -#{arrow_size} #{arrow_size} M#{x} #{top} l 0 #{bottom - top} l #{arrow_size} -#{arrow_size} M#{x} #{bottom} l -#{arrow_size} -#{arrow_size}" stroke="#{color}" stroke-width="#{stroke_width}" fill="none" />
35
+ <g>
36
+ <style><![CDATA[tspan{font-size: #{USPSFlags::Config::FRACTION_SCALE}%;}]]></style>
37
+ <text x="#{x + label_offset}" y="#{(top+bottom)/2+(USPSFlags::Config::BASE_HOIST/150)+label_offset_y}" font-family="sans-serif" font-size="#{font_size}px" fill="#041E42" text-anchor="#{label_align}">#{label} <tspan>#{label_fraction}</tspan> #{unit}</text>
38
+ </g>
39
+ SVG
40
+
41
+ svg
42
+ end
43
+
44
+ # Creates a horizontal arrow for the trident spec sheet.
45
+ #
46
+ # This is used USPSFlags::Core.trident_spec, and should never need to be called directly.
47
+ # @private
48
+ def horizontal(y, left, right, pointer_left = nil, pointer_right = nil, label: nil, label_offset: (USPSFlags::Config::BASE_FLY/45), label_offset_x: 0, label_align: "middle", color: "#CCCCCC", stroke_width: (USPSFlags::Config::BASE_FLY/600), stroke_dash: "10, 10", font_size: (USPSFlags::Config::BASE_FLY/60), arrow_size: (USPSFlags::Config::BASE_FLY/120), fly: USPSFlags::Config::BASE_FLY, unit: nil)
49
+ label = right - left if label.nil?
50
+ label = label.to_i if label - label.to_i == 0
51
+ label = Rational(label) * fly / USPSFlags::Config::BASE_FLY
52
+ if label == label.to_i
53
+ label = label.to_i
54
+ label_fraction = ""
55
+ else
56
+ label, label_fraction = label.to_simplified_a
57
+ end
58
+ svg = ""
59
+ unless pointer_left.nil?
60
+ svg << <<~SVG
61
+ <line x1="#{left}" y1="#{y}" x2="#{left}" y2="#{pointer_left}" stroke="#{color}" stroke-width="#{stroke_width}" stroke-dasharray="#{stroke_dash}" />
62
+ SVG
63
+ end
64
+ unless pointer_right.nil?
65
+ svg << <<~SVG
66
+ <line x1="#{right}" y1="#{y}" x2="#{right}" y2="#{pointer_right}" stroke="#{color}" stroke-width="#{stroke_width}" stroke-dasharray="#{stroke_dash}" />
67
+ SVG
68
+ end
69
+
70
+ svg << <<~SVG
71
+ <path d="M#{left} #{y} l #{arrow_size} #{arrow_size} M#{left} #{y} l #{arrow_size} -#{arrow_size} M#{left} #{y} l #{right - left} 0 l -#{arrow_size} -#{arrow_size} M#{right} #{y} l -#{arrow_size} #{arrow_size}" stroke="#{color}" stroke-width="#{stroke_width}" fill="none" />
72
+ <g>
73
+ <style><![CDATA[tspan{font-size: #{USPSFlags::Config::FRACTION_SCALE}%;}]]></style>
74
+ <text x="#{(left+right)/2+label_offset_x}" y="#{y + label_offset}" font-family="sans-serif" font-size="#{font_size}px" fill="#041E42" text-anchor="#{label_align}">#{label} <tspan>#{label_fraction}</tspan> #{unit}</text>
75
+ </g>
76
+ SVG
77
+
78
+ svg
79
+ end
80
+ end
81
+ end