class Astromapper::Svg

Public Class Methods

new(filename) click to toggle source
# File lib/astromapper/svg.rb, line 6
def initialize(filename)
  @rows     = 40
  @columns  = 32
  @source_filename = filename
  sectorname = filename.gsub(File.extname(filename), '')
  @svg_filename    = sectorname + '.svg'
  @side    = 40
  @factor  = 1.732
  @height  = (@side * @factor * (@rows + 0.5)).ceil
  @width   = (@side * (@columns * 1.5 + 0.5)).ceil
  @mark    = 13
  @zones   = []
  @volumes = []
  # @routes  = {}
  @routes = []
  @slopes = {}
  @name = config['name']

  @hex = {
    :side_h => (@side * (@factor / 2)).tweak,
    :side_w => (@side / 2).tweak,
    :width  => @side
  }
end

Public Instance Methods

build_routes() click to toggle source
# File lib/astromapper/svg.rb, line 55
def build_routes
  routes = ["<g class='routes'>"]
  keys = @volumes.map do |v|
    v[0..3]
  end.sort
  @slopes = {}
  paths = {
    "0"  => (-4..4).to_a,
    "1"  => (-3..3).to_a,
    "2"  => (-3..3).to_a,
    "3"  => (-2..2).to_a,
    "4"  => (-2..2).to_a,
  }
  keys.each do |k|
    x = k[0..1].to_i
    y = k[2..3].to_i
    @slopes[k] = []
    paths.keys.each do |pk|
      [pk.to_i, pk.to_i * -1].each do |m|
        paths[pk].each do |n|
          x1 = (x + m)
          y1 = (y + n)
          c = "%02d%02d" % [x1, y1]
          k = "%02d%02d" % [x, y]
          puts "#{k}:#{c} (#{x}, #{y}) (#{x1}, #{y1}) / (#{pk}:#{paths[pk].inspect}):(#{m}:#{n})"
          routes << calc_route(keys,x,x1,y,y1)
        end
      end
    end
  end
  routes << "</g>"
  routes.compact.join("\n")
end
calc_route(keys,x,x1,y,y1) click to toggle source
# File lib/astromapper/svg.rb, line 33
def calc_route(keys,x,x1,y,y1)
  route = nil
  c = "%02d%02d" % [x1, y1]
  k = "%02d%02d" % [x, y]
  # puts "#{k}:#{c} (#{x}, #{y}) (#{x1}, #{y1})"
  # Calcuate Route Distance
  d = Math.sqrt((x - x1)**2 + (y - y1)**2).round(0)
  return route if d == 0

  # Calculate Route Slope to avoid slope collisions
  s = ((x1 - x) == 0) ? 0 :  ((y1 - y) / (x1 - x))
  # return route if (@slopes[k].include?(s))

  if (keys.include?(c) and !@routes.include?("#{k}#{c}"))
    a = center_of(k)
    b = center_of(c)
    @slopes[k] << s
    @routes << "#{c}#{k}" # reverse look-up.
    route = "<!-- #{k} > #{c} --><line class='line#{d}' x1='#{a[0]}' y1='#{a[1]}' x2='#{b[0]}' y2='#{b[1]}' />"
  end
  return route
end
center_of(locx) click to toggle source
# File lib/astromapper/svg.rb, line 191
def center_of(locx)
  column = locx[0..1].to_i
  row    = locx[2..3].to_i
  x      = @side + ((column - 1) * @side * 1.5) # 40 + ((COL - 1) * 60 )
  y      = (row - 1) * @side * @factor + (@side * @factor / (1 + (column % 2)))
  return [x.tweak,y.tweak]
end
config() click to toggle source
# File lib/astromapper/svg.rb, line 3
def config
  Astromapper.config
end
consulate(c) click to toggle source
# File lib/astromapper/svg.rb, line 323
def consulate(c);
    return "<!-- Consulate --><text class='symbol' x='#{(c[0]-(@side/1.5)).to_i}' y='#{(c[1]+(@side/7)).to_i}'>\u2691</text>\n"
end
convert() click to toggle source
# File lib/astromapper/svg.rb, line 88
def convert
  from_file

  svg = []
  svg << header
  svg << tract_marks
  svg << hex_grid
  svg << build_routes
  svg << @volumes.map {|v| world(v) }
  svg << volumes
  svg << frame
  svg << footer
  File.open(@svg_filename,'w').write(svg.flatten.join("\n"))
end
draw_belt(c) click to toggle source
# File lib/astromapper/svg.rb, line 262
def draw_belt(c)
  output = "    <g class='belt'>\n"
  7.times do
    x = c[0] + Random.rand(@side/3) - @side/6
    y = c[1] + Random.rand(@side/3) - @side/6
    output += "      <circle class='belt' cx='#{x.to_i}' cy='#{y.to_i}' r='#{(@side/15).tweak}' />\n"
  end
  output + "    </g>\n"
end
draw_planet(c,w) click to toggle source
# File lib/astromapper/svg.rb, line 258
def draw_planet(c,w)
  k = (w[3] == '0') ? 'Desert' : 'Planet'
   "    <circle class='planet' cx='#{c[0].to_i}' cy='#{c[1].to_i}' r='#{(@side/7).to_i}' />\n"
end
frame(k='Frame') click to toggle source
# File lib/astromapper/svg.rb, line 271
def frame(k='Frame')
  style = k.to_sym
  z = 0; w = @width.to_i - 0; h = @height.to_i - z;
  "    <polyline class='frame' points='#{z},#{z} #{w},#{z} #{w},#{h} #{z},#{h} #{z},#{z}' />"
end
from_file() click to toggle source
# File lib/astromapper/svg.rb, line 30
def from_file
  File.open(@source_filename,'r').readlines.each { |line| @volumes << line if /^\d{4}/.match(line) }
end
gas_giant(c) click to toggle source
# File lib/astromapper/svg.rb, line 311
    def gas_giant(c)
      x = (c[0]+(@side/1.8)).tweak; y = (c[1]+(@side/3)).tweak;
      return<<-GIANT
      <g class='gas-giant'><!-- Has Gas Giant -->
        <ellipse cx='#{x.to_i}' cy='#{y.to_i}' rx='#{(@side/(@mark * 0.5)).to_i}' ry='#{(@side/@mark * 0.3).tweak}' />
        <circle cx='#{x.to_i}' cy='#{y.to_i}' r='#{(@side/(@mark * 1.2)).to_i}' />
      </g>
      GIANT
    end
header() click to toggle source
# File lib/astromapper/svg.rb, line 105
    def header
      return<<-EOS
<?xml version="1.0" standalone="no"?>
  <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
    "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg width="#{@width}px" height="#{@height}px" version="1.1" xmlns="http://www.w3.org/2000/svg">
  <desc>Subsector Map Grid</desc>
  <style>
    svg {
      fill: #FFF;
    }
    text {
      text-anchor: middle;
      fill: #567;
      font: 8px sans-serif;
    }
    text.tract {
      text-anchor: left;
      fill: #eed;
      font: 120px sans-serif;
    }
    text.namestamp {
      font-size: 13px;
    }
    text.symbol {
      font-size: 14px;
      fill: #222;
    }
    g.volumes text {
      fill: #DDD;
    }
    line {
      opacity: 0.5;
      stroke-linecap: round;
    }
    line.line1 {
      stroke: #666;
      stroke-width:4;
    }
    line.line2 {
      stroke: #69C;
      stroke-width:3;
    }
    line.line3 {
      stroke: #C96;
      stroke-width:2;
      stroke-dasharray: 5, 5, 1, 5;
    }
    line.line4 {
      stroke: #C66;
      stroke-width:1;
      stroke-dasharray: 2,6;
    }
    polyline {
      fill: none;
      stroke: #DDD;
      stroke-width: 1;
    }
    g.gas-giant {
      stroke: #034;
    }
    g.gas-giant circle {
      fill:   #034;
      stroke: #034;
      stroke-width:1;
    }
    g.gas-giant ellipse {
      stroke: #034;
      stroke-width: 1;
    }
    circle {
      fill: #222;
      stroke: #fff;
      stroke-width: 1;
    }
    .zone {
      fill: none;
      stroke: #B90;
      stroke-width: 3;
      stroke-dasharray: 3,6;
      stroke-linecap: round;
    }
  </style>
  <rect width='#{@width}' height='#{@height}' />
      EOS
    end
hex_grid() click to toggle source
# File lib/astromapper/svg.rb, line 334
def hex_grid; (@rows * 3 + 2).times.map { |j| hex_row((j/2).floor, (j % 2 != 0)) };
end
hex_row(row, top=false) click to toggle source
# File lib/astromapper/svg.rb, line 339
def hex_row(row, top=false)
  ly = (row * 2 * @hex[:side_h]) + @hex[:side_h]
  points = []
  x = 0; y = 0
  (@columns/2).ceil.times do |j|
    x = j * @side * 3
    y = ly
    points << "#{x.to_i},#{y.to_i}"

    x += @hex[:side_w]
    y = (top) ? y - @hex[:side_h] : y + @hex[:side_h]
    points << "#{x.to_i},#{y.to_i}"

    x += @hex[:width]
    points << "#{x.to_i},#{y.to_i}"

    x += @hex[:side_w]
    y = (top) ? y + @hex[:side_h] : y - @hex[:side_h]
    points << "#{x.to_i},#{y.to_i}"

    x += @hex[:width]
    points << "#{x.to_i},#{y.to_i}"
  end
  x += @hex[:side_w]
  y = (top) ? y - @hex[:side_h] : y + @hex[:side_h]
  points << "#{x.to_i},#{y.to_i}"
  "    <polyline points='#{points.join(' ')}' />"
end
namestamp() click to toggle source
# File lib/astromapper/svg.rb, line 336
def namestamp
  return "<text class='namestamp' x='30' y='2800'>#{@name}</text>"
end
navy_base(c) click to toggle source
pirates(c) click to toggle source
# File lib/astromapper/svg.rb, line 320
def pirates(c);
    return "<!-- Pirates --><text class='symbol' x='#{(c[0]-(@side/3.1)).to_i}' y='#{(c[1]+(@side/7)).to_i}'>\u2620</text>\n"
end
polygon(x, y, sx, sy, sides=4) click to toggle source
# File lib/astromapper/svg.rb, line 307
def polygon(x, y, sx, sy, sides=4)
  polygon = star_coords(sx, sy, sides).map { |c| "#{(x + c[0]).to_i},#{(y.tweak+c[1]).to_i}" }
  "    <polygon points='#{polygon.join(' ')}' />\n"
end
scout_base(c) click to toggle source
# File lib/astromapper/svg.rb, line 326
def scout_base(c);
    return "<!-- Scout Base --><text class='symbol' x='#{(c[0]-(@side/1.8)).to_i}' y='#{(c[1]+(@side/2.4)).to_i}'>\u269C</text>\n"
  '<!-- SB -->' + polygon(c[0]-(@side/1.8),c[1]+(@side/3.7), @side/(@mark/2), @side/@mark, 3);
end
star_coords(r1,r2,points) click to toggle source
# File lib/astromapper/svg.rb, line 198
def star_coords(r1,r2,points)
  pangle = 2*@@pi/points
  sangle = @@pi/points
  oangle = @@pi/-2
  coords = []
  points.times do |j|
    coords << [r1 * Math::cos(pangle * j + oangle), r1 * Math::sin(pangle * j + oangle)]
    coords << [r2 * Math::cos((pangle * j) + sangle + oangle), r2 * Math::sin((pangle * j) + sangle + oangle)]
  end
  return coords
end
stars(c,stars) click to toggle source
# File lib/astromapper/svg.rb, line 247
def stars(c,stars)
  output = ''
  x = (c[0]+(@side/1.8)).tweak + 2
  y = (c[1]-(@side/3)).tweak + 3
  stars.split('/').each do |star|
    output += "    <text x='#{x.to_i}' y='#{y.to_i}'>#{star[0..1].strip}</text>\n"
    x += 3
    y += 7
  end
  output
end
tract_marks() click to toggle source
# File lib/astromapper/svg.rb, line 276
def tract_marks
  height = (@height / 4).floor
  width  = (@width / 4).ceil
  # width -= 2

  output = ''
  letters = ('A'..'P').to_a
  5.times do |r|
    h1 = ((height.floor * r) - (8*r)).to_i; h2 = (h1 + height - 8).to_i
    w2 = 0
    4.times do |c|
      w1 = w2.to_i; w2 += (width - [-4,4,5,-4][c]).to_i
      output += "    <text class='tract' x='#{w1 + 70}' y='#{h1 + 110}'>#{letters.shift}</text>\n"
      output += "    <polyline class='tract' points='#{w1},#{h1} #{w2},#{h1} #{w2},#{h2} #{w1},#{h2} #{w1},#{h1}' />\n"
      # raise output
    end
  end
  output += namestamp
  return output
end
volumes() click to toggle source
# File lib/astromapper/svg.rb, line 296
def volumes
  output = "<g class='volumes'>"
  (@rows+2).times do |r|
    (@columns+1).times do |c|
      x = @side + ((c-1) * @side * 1.5)
      y = (c % 2 == 1) ? (r-1) * @side * @factor + (0.2 * @side) : (r-1) * @side * @factor + @hex[:side_h]+ (0.2 * @side)
      output += "<text x='#{x.to_i}' y='#{y.to_i}'>%02d%02d</text>\n" % [c,r]
    end
  end
  output += "</g>"
end
world(volume) click to toggle source
# File lib/astromapper/svg.rb, line 209
def world(volume)
  # TAB 0 - World Details
  # 0. Location
  # 1. UWP
  # 2. Temp
  # 3. NSG (Features)
  # 4. Travel Zone
  # TAB 1 - Trade Codes
  # TAB 2 - Factions
  # TAB 3 - Name
  #1101 A505223-B  ..G.. »·IC,Lo,Va       »N,O,N   »·G0V  »Omivarium
  details, trades, factions, star, name = volume.split(/\t/)

  locx, uwp, temp, nsg, zone = details.split(/\s+/)

  spaceport = uwp[0]
  size      = uwp[1]
  c         = center_of(locx) # get Location's x,y Coordinates
  curve = @side / 2

  output =  "<!-- Volume: #{volume.strip.gsub(/\t/,' // ')} -->\n"
  output +=  (size == '0') ? draw_belt(c) : draw_planet(c,uwp)
  output += "    <text class='spaceport' x='#{c[0].to_i}' y='#{(c[1] + @side / 2).to_i}'>#{spaceport.strip}</text>\n"
  output += "    <text x='#{c[0].to_i}' y='#{(c[1]+(@side/1.3)).to_i}'>#{uwp.strip}</text>\n"
  output += "    <text x='#{c[0].to_i}' y='#{(c[1]-(@side/2.1)).to_i}'>#{name.strip}</text>\n"
  unless zone == '..'
    style = zone + '_zone'
    output += "    <path class='zone' d='M #{(c[0] - curve/2).to_i} #{(c[1] - (curve/1.4)).to_i} a #{curve} #{curve} 0 1 0 20 0' />\n"
  end
  output += navy_base(c)  if nsg.include?('N')
  output += scout_base(c) if nsg.include?('S')
  output += gas_giant(c)  if nsg.include?('G')
  output += consulate(c)  if nsg.include?('C')
  output += pirates(c)    if nsg.include?('P')
  output += stars(c,star)
  output

end