# Container class for the core SVG data. # # These methods should never need to be called directly. # @private class USPSFlags::Core def self.trident_spec(fly: 24, unit: "in") trident_config = USPSFlags::Config.trident hoist = (fly*Rational(2,3)) hoist = hoist == hoist.to_i ? hoist.to_i : hoist fly_fraction = "" hoist_fraction = "" if fly == fly.to_i fly = fly.to_i else fly, fly_fraction = fly.to_simplified_a end if hoist == hoist.to_i hoist = hoist.to_i else hoist, hoist_fraction = hoist.to_simplified_a end label_font_size = if Math.sqrt(fly) > 24 USPSFlags::Config::BASE_FLY * Math.log(24, Math.sqrt(fly)) / 60 else USPSFlags::Config::BASE_FLY / 60 end unit_text = unit.nil? ? "" : "#{unit}" barb_label = Rational(trident_config[:main_point_barb]) * fly / USPSFlags::Config::BASE_FLY barb_label = barb_label == barb_label.to_i ? barb_label.to_i : barb_label.to_simplified_s barb_label = "#{barb_label}#{unit_text}" svg = "" svg << <<~SVG #{USPSFlags::Core.field} United States Power Squadrons® Officer Flag Trident Specification All measurements are relative to a field with fly of #{fly} #{fly_fraction} #{unit_text} and hoist of #{hoist} #{hoist_fraction} #{unit_text}. Measurements not specified are the same as on the short trident. SVG box_width = USPSFlags::Config::BASE_FLY*5/32 box_left = (USPSFlags::Config::BASE_FLY*27/32)/2 box_right = (USPSFlags::Config::BASE_FLY*37/32)/2 box_top = USPSFlags::Config::BASE_HOIST/4 box_bottom = USPSFlags::Config::BASE_HOIST*3/4 svg << <<~SVG Short Squadron Officers #{self.trident(:s)} #{USPSFlags::Helpers.v_arrow(box_right+trident_config[:bar_width], box_top, box_top+trident_config[:bar_width], box_right, box_right, fly: fly, unit: unit, font_size: label_font_size)} #{USPSFlags::Helpers.v_arrow(box_right+trident_config[:bar_width], box_top+trident_config[:bar_width], box_top+trident_config[:bar_width]*2+trident_config[:point_height]+trident_config[:side_spike_height], nil, box_right, fly: fly, unit: unit, font_size: label_font_size)} #{USPSFlags::Helpers.v_arrow(box_right+trident_config[:bar_width], box_top+trident_config[:bar_width]*2+trident_config[:point_height]+trident_config[:side_spike_height], box_top+trident_config[:bar_width]*3+trident_config[:point_height]+trident_config[:side_spike_height], nil, trident_config[:center_point]+trident_config[:hash_width]/2, fly: fly, unit: unit, font_size: label_font_size)} #{USPSFlags::Helpers.v_arrow(box_right+trident_config[:bar_width], box_top+trident_config[:bar_width]*3+trident_config[:point_height]+trident_config[:side_spike_height], box_top+trident_config[:bar_width]*4+trident_config[:point_height]+trident_config[:side_spike_height], nil, trident_config[:center_point]+trident_config[:hash_width]/2, fly: fly, unit: unit, font_size: label_font_size)} #{USPSFlags::Helpers.v_arrow(box_right+trident_config[:bar_width], box_top+trident_config[:bar_width]*4+trident_config[:point_height]+trident_config[:side_spike_height], box_bottom, nil, box_right, fly: fly, unit: unit, font_size: label_font_size)} #{USPSFlags::Helpers.v_arrow(box_left-trident_config[:bar_width]*5.25, box_top, box_bottom, box_left, box_left, fly: fly, unit: unit, font_size: label_font_size)} #{USPSFlags::Helpers.v_arrow(box_left-trident_config[:bar_width]*0.75, box_top, box_top+trident_config[:point_height], nil, trident_config[:center_point]-trident_config[:bar_width], fly: fly, unit: unit, label_offset: -USPSFlags::Config::BASE_FLY/26, label_offset_y: -USPSFlags::Config::BASE_FLY/100, font_size: label_font_size, label_align: "middle")} #{USPSFlags::Helpers.v_arrow(box_left-trident_config[:bar_width]*1.5, box_top+trident_config[:bar_width], box_top+trident_config[:bar_width]+trident_config[:point_height], box_left, box_left+trident_config[:bar_width], fly: fly, unit: unit, label_offset: -USPSFlags::Config::BASE_FLY/24, font_size: label_font_size, label_align: "middle")} #{USPSFlags::Helpers.h_arrow(box_bottom+trident_config[:bar_width], trident_config[:center_point]-trident_config[:bar_width]/2, trident_config[:center_point]+trident_config[:bar_width]/2, box_bottom, box_bottom, fly: fly, unit: unit, font_size: label_font_size)} #{USPSFlags::Helpers.h_arrow(box_bottom+trident_config[:bar_width]*2.5, trident_config[:center_point]-trident_config[:hash_width]/2, trident_config[:center_point]+trident_config[:hash_width]/2, box_top+trident_config[:bar_width]*4+trident_config[:point_height]+trident_config[:side_spike_height], box_top+trident_config[:bar_width]*4+trident_config[:point_height]+trident_config[:side_spike_height], fly: fly, unit: unit, font_size: label_font_size)} #{USPSFlags::Helpers.h_arrow(box_bottom+trident_config[:bar_width]*4, box_left, box_right, box_bottom, box_bottom, fly: fly, unit: unit, font_size: label_font_size)} #{USPSFlags::Helpers.h_arrow(box_top-trident_config[:bar_width], box_left, box_left+trident_config[:bar_width]*3/2, box_top, box_top+trident_config[:bar_width]+trident_config[:point_height], fly: fly, unit: unit, label_offset: -USPSFlags::Config::BASE_FLY/60, font_size: label_font_size)} #{USPSFlags::Helpers.h_arrow(box_top-trident_config[:bar_width]*2.5, trident_config[:center_point]-trident_config[:bar_width], trident_config[:center_point]+trident_config[:bar_width], box_top+trident_config[:point_height], box_top+trident_config[:point_height], fly: fly, unit: unit, label_offset: -USPSFlags::Config::BASE_FLY/60, font_size: label_font_size)} #{barb_label} SVG box_top = USPSFlags::Config::BASE_HOIST*3/16 box_bottom = USPSFlags::Config::BASE_HOIST*13/16 svg << <<~SVG Delta District Officers #{self.trident(:d)} #{USPSFlags::Helpers.v_arrow(box_right+trident_config[:bar_width], box_bottom-trident_config[:delta_from_bottom]-trident_config[:bar_width]-trident_config[:delta_gap_height], box_bottom-trident_config[:delta_from_bottom]-trident_config[:bar_width], trident_config[:center_point], trident_config[:center_point]+trident_config[:delta_gap_width], fly: fly, unit: unit, font_size: label_font_size)} #{USPSFlags::Helpers.v_arrow(box_right+trident_config[:bar_width], box_bottom-trident_config[:delta_from_bottom]-trident_config[:bar_width], box_bottom-trident_config[:delta_from_bottom], nil, box_right, fly: fly, unit: unit, font_size: label_font_size)} #{USPSFlags::Helpers.v_arrow(box_right+trident_config[:bar_width], box_bottom-trident_config[:delta_from_bottom], box_bottom, nil, box_right, fly: fly, unit: unit, font_size: label_font_size)} #{USPSFlags::Helpers.v_arrow(box_left-trident_config[:bar_width]*1.5, box_top, box_bottom, box_left, box_left, fly: fly, unit: unit, label_offset: -USPSFlags::Config::BASE_FLY/30, label_offset_y: -USPSFlags::Config::BASE_FLY*2/11, font_size: label_font_size, label_align: "middle")} SVG box_top = USPSFlags::Config::BASE_HOIST/8 box_bottom = USPSFlags::Config::BASE_HOIST*7/8 svg << <<~SVG Circle Staff Commanders Only #{self.trident(:stf)} #{USPSFlags::Helpers.v_arrow(box_right+trident_config[:bar_width], box_top+trident_config[:crossbar_from_top]+trident_config[:bar_width]*2, box_top+trident_config[:crossbar_from_top]+trident_config[:width], trident_config[:center_point], trident_config[:center_point], fly: fly, unit: unit, font_size: label_font_size)} #{USPSFlags::Helpers.v_arrow(box_right+trident_config[:bar_width], box_top+trident_config[:crossbar_from_top]+trident_config[:width], box_top+trident_config[:crossbar_from_top]+trident_config[:bar_width]+trident_config[:width], nil, trident_config[:center_point]+trident_config[:bar_width]/2, fly: fly, unit: unit, font_size: label_font_size)} #{USPSFlags::Helpers.v_arrow(box_right+trident_config[:bar_width], box_top+trident_config[:crossbar_from_top]+trident_config[:bar_width]+trident_config[:width], box_bottom, nil, box_right, fly: fly, unit: unit, font_size: label_font_size)} #{USPSFlags::Helpers.v_arrow(box_left-trident_config[:bar_width]*1.5, box_top, box_bottom, box_left, box_left, fly: fly, unit: unit, label_offset: -USPSFlags::Config::BASE_FLY/30, label_offset_y: -USPSFlags::Config::BASE_FLY/4.5, font_size: label_font_size, label_align: "middle")} SVG svg << <<~SVG Long National Officers #{self.trident(:n)} #{USPSFlags::Helpers.v_arrow(box_right+trident_config[:bar_width], box_top+trident_config[:crossbar_from_top]+trident_config[:bar_width]*3, box_bottom, trident_config[:center_point]+trident_config[:hash_width]/2, box_right, fly: fly, unit: unit, font_size: label_font_size)} #{USPSFlags::Helpers.v_arrow(box_left-trident_config[:bar_width]*1.5, box_top, box_bottom, box_left, box_left, fly: fly, unit: unit, label_offset: -USPSFlags::Config::BASE_FLY/30, label_offset_y: -USPSFlags::Config::BASE_FLY/4.5, font_size: label_font_size, label_align: "middle")} SVG svg end def self.headers(width: nil, height: nil, pennant: false, scale: nil, title: "USPS Flag") if width.nil? || height.nil? scale = 3 if scale.nil? width ||= USPSFlags::Config::BASE_FLY / scale height = (width*Rational(2,3)).to_i view_width = USPSFlags::Config::BASE_FLY view_height = USPSFlags::Config::BASE_HOIST if pennant height = height/4 view_height = USPSFlags::Config::BASE_HOIST/4 end else if scale.nil? view_width = width view_height = height else view_width = width * scale view_height = height * scale end end generated_at = Time.now.strftime("%Y%m%d.%H%S%z") svg = "" svg << <<~SVG #{title} Julian Fiander #{generated_at} SVG unless title == "US Ensign" svg << <<~SVG This image is a registered trademark of United States Power Squadrons. http://www.usps.org/national/itcom/trademark.html SVG end svg << <<~SVG SVG svg end def self.footer <<~FOOTER FOOTER end def self.field(style: :regular, color: :white, fly: USPSFlags::Config::BASE_FLY) case color when :white border = true color_code = "#FFFFFF" past_mid_color = USPSFlags::Config::BLUE past_tail_color = USPSFlags::Config::RED when :red border = false color_code = USPSFlags::Config::RED past_mid_color = "#FFFFFF" past_tail_color = USPSFlags::Config::BLUE when :blue border = false color_code = USPSFlags::Config::BLUE past_mid_color = "#FFFFFF" past_tail_color = USPSFlags::Config::RED end border_svg = border ? "stroke=\"#000000\" stroke-width=\"#{USPSFlags::Config::BASE_FLY/600}\" " : "" hoist = (fly * 2) / 3 case style when :regular <<~FIELD FIELD when :swallowtail <<~FIELD FIELD when :past <<~FIELD FIELD end end def self.trident(type, color: :blue, field_color: nil) valid_types = [:s, :d, :stf, :n] raise "Error: Invalid trident type. Options are #{valid_types}." unless valid_types.include? type trident_config = USPSFlags::Config.trident main_spike_overhang = trident_config[:bar_width] / 2 side_spike_overhang = trident_config[:bar_width] / 2 top_point = ((USPSFlags::Config::BASE_HOIST - trident_config[:height][type]) / 2) crossbar_top = top_point + trident_config[:crossbar_from_top] hash_from_top = trident_config[:crossbar_from_top] + (trident_config[:bar_width] * 2) circle_from_top = trident_config[:crossbar_from_top] + trident_config[:bar_width]*123/128 + trident_config[:width]/2 main_length = trident_config[:height][type] - (trident_config[:point_height] - trident_config[:main_point_barb]) trident_segments = [ { # Main spike [trident_config[:center_point], top_point] => [ [trident_config[:bar_width], trident_config[:point_height]], [-main_spike_overhang, -trident_config[:main_point_barb]], [0, main_length], [-(trident_config[:bar_width]), 0], [0, -main_length], [-main_spike_overhang, trident_config[:main_point_barb]], [trident_config[:bar_width], -trident_config[:point_height]] ] }, { # Crossbar [(trident_config[:center_point] - trident_config[:width]/2), (crossbar_top)] => [ [trident_config[:width], 0], [0, trident_config[:bar_width]], [-trident_config[:width], 0], [0, -trident_config[:bar_width]] ] }, { # Left spike [(trident_config[:center_point] - trident_config[:width]/2), (crossbar_top + 1)] => [ [0, -(trident_config[:side_spike_height]+trident_config[:point_height])], [(trident_config[:bar_width]+side_spike_overhang), trident_config[:point_height]], [-side_spike_overhang, 0], [0, trident_config[:side_spike_height]] ] }, { # Right spike [(trident_config[:center_point] + trident_config[:width]/2), (crossbar_top + 1)] => [ [0, -(trident_config[:side_spike_height]+trident_config[:point_height])], [-(trident_config[:bar_width]+side_spike_overhang), trident_config[:point_height]], [side_spike_overhang, 0], [0, trident_config[:side_spike_height]] ] } ] case color when :white color_code = "#FFFFFF" field_color_code = case field_color when :red USPSFlags::Config::RED when :blue USPSFlags::Config::BLUE end when :red color_code = USPSFlags::Config::RED field_color_code = "#FFFFFF" when :blue color_code = USPSFlags::Config::BLUE field_color_code = "#FFFFFF" end svg = "" svg << "" if type == :d svg << "" if type == :stf trident_segments.each do |segment| start = segment.keys.first points = segment.values.first svg << "\n" end svg << "" if [:d, :stf].include?(type) if type == :d # Delta hash svg << <<~SVG SVG elsif type == :stf # Circle hash svg << <<~SVG SVG else # Standard hash lower_hash = [ [trident_config[:hash_width], 0], [0, trident_config[:bar_width]], [-trident_config[:hash_width], 0], [0, -trident_config[:bar_width]] ] svg << "\n" # # V/C crossing, marks @ 15/32 up # vc_cross_marker = USPSFlags::Config::BASE_HOIST*7/8-(USPSFlags::Config::BASE_HOIST/8+trident_config[:crossbar_from_top]+trident_config[:bar_width]*3)*15/32 # svg << "" # # C/C crossing, marks @ 1/3 up # cc_cross_marker = USPSFlags::Config::BASE_HOIST*7/8-(USPSFlags::Config::BASE_HOIST/8+trident_config[:crossbar_from_top]+trident_config[:bar_width]*3)*1/3 # svg << "" end svg end def self.anchor(color = :red) case color when :red color_code = "#BF0D3E" when :white color_code = "#FFFFFF" end <<~SVG SVG end def self.lighthouse <<~SVG SVG end def self.binoculars(type) color = case type when :d USPSFlags::Config::RED when :n USPSFlags::Config::BLUE end <<~SVG SVG end def self.trumpet(type) color = type == :n ? USPSFlags::Config::BLUE : USPSFlags::Config::RED count = type == :s ? 1 : 2 trumpet = "" if count == 2 <<~SVG #{trumpet} #{trumpet} SVG else trumpet end end def self.pennant(type = "cruise") fly = USPSFlags::Config::BASE_FLY hoist = USPSFlags::Config::BASE_HOIST/4 if type.upcase == "OIC" svg = <<~SVG SVG elsif type.upcase == "CRUISE" svg = <<~FIELD FIELD svg << "" svg << self.star svg << "" svg end end def self.ensign field = <<~SVG SVG # anchor = self.anchor(:white) star_circle = "" (0..13).each do |i| rotation = i * (360.0 / 13) star_circle << <<~SVG #{self.star} SVG end <<~SVG #{field} #{anchor} #{star_circle} SVG end def self.star points = [ [117.555, 81.805], [-41.47, -137.085], [114.125, -86.525], [-143.185, -2.915], [-47.025, -135.28], [-47.025, 135.28], [-143.185, 2.915], [114.125, 86.525], [-41.47, 137.085], [117.555, -81.805] ] svg = "\n" svg end def self.wheel <<~SVG SVG end def self.us base_hoist = 2000.to_f base_fly = base_hoist*1.91 canton_hoist = base_hoist*7/13 canton_fly = canton_hoist*Math.sqrt(2) star_offset = 20 # Half of scaled star height svg = "" svg << <<~SVG SVG [1,3,5,7,9].each do |r| [1,3,5,7,9,11].each do |c| svg << <<~SVG #{self.star} SVG end end [2,4,6,8].each do |r| [2,4,6,8,10].each do |c| svg << <<~SVG #{self.star} SVG end end # star_diameter = base_hoist*4/5/13 # svg << <<~SVG # # SVG svg end end