class Tiler

Public Class Methods

new(image_width, image_height, scale, hue, sat_major, sat_minor, projection_lambda) click to toggle source
# File lib/tiler.rb, line 88
def initialize image_width, image_height, scale, hue, sat_major, sat_minor, projection_lambda
  
  # We colour based on face orientation index,
  # 0 and 1 being white
  # 2 and 4 based on hue
  # 3 and 5 based on the compliment of hue

  @h1 = hue
  @h2 = (hue + 360/2) % 360
  
  @colors = [
    ChunkyPNG::Color.from_hsv(0, 0, 1),
    ChunkyPNG::Color.from_hsv(0, 0.0, 1),
    ChunkyPNG::Color.from_hsv(@h1, sat_major, 0.9),
    ChunkyPNG::Color.from_hsv(@h2, sat_major, 0.9),
    ChunkyPNG::Color.from_hsv(@h1, sat_minor, 0.6),
    ChunkyPNG::Color.from_hsv(@h2, sat_minor, 0.6)
  ]

  @image_width = image_width
  @image_height = image_height

  # (ox,oy) describes the centre of the image
  @ox = @image_width/2
  @oy = @image_height/2

  # Scale is the length in pixels of the unit distance when rendered
  @scale = scale

  # Construct the projection of 4 dimensional space onto the output image
  # (cononical_x[i],cononical_y[i]) describes the projection of e_i
  @canonical_x = []
  @canonical_y = []
  for i in 0..3 do
    c = projection_lambda ** i
    @canonical_x << c.real
    @canonical_y << c.imaginary
  end

  # Add an initial face to the list of faces
  @all_faces = [Face.new(Vector[0, 0, 0, 0], 2, 3)]

end

Public Instance Methods

tile(ticks, filename) click to toggle source
# File lib/tiler.rb, line 140
def tile ticks, filename
      
  # Iterate all faces ticks times
  for i in 1 .. ticks
    new_list = []
    @all_faces.each do |face|
      new_list << face
      ret = face.tick @@translation_matrix
      new_list << ret unless ret.nil?
    end
    @all_faces = new_list
  end

  # (global_xo, global_yo) is a translation of the entire rendered surface
  # we do this to centre on a region that is actually tiled
  
  @global_xo = 0
  @global_yo = 0

  # For now we focus on the average position of all faces
  @all_faces.each do |face|
    p = to_image_space(face.pos.to_a, @ox, @oy)
    @global_xo += (@ox - p[:x])/@all_faces.length
    @global_yo += (@oy - p[:y])/@all_faces.length
  end

  # Draw
  puts "Tiledenticon: Drawing image"
  
  # Create a new, blank image
  image = ChunkyPNG::Image.new @image_width, @image_height, @colors[5]

  draw_x = @global_xo + @ox
  draw_y = @global_yo + @oy

  @all_faces.each_with_index do |face, i|
    print "Tiledenticon: Face #{i}\r"

    # Generate the points to a from each face for rendering

    p1 = to_image_space  face.pos.to_a, draw_x, draw_y

    p2_m = face.pos.to_a
    p2_m[face.min_axis] += 1
    p2 = to_image_space p2_m, draw_x, draw_y

    p3_m = face.pos.to_a
    p3_m[face.max_axis] += 1
    p3 = to_image_space p3_m, draw_x, draw_y

    p4_m = face.pos.to_a
    p4_m[face.min_axis] += 1
    p4_m[face.max_axis] += 1
    p4 = to_image_space p4_m, draw_x, draw_y

    points = ChunkyPNG::Vector.new([p1, p2, p4, p3])

    # Pick colour based on colour scheme in @colors array and the direcion the
    # face is orientated
    color = @colors[min_max_to_i face.min_axis, face.max_axis]

    image.polygon(points, ChunkyPNG::Color::TRANSPARENT, color) 
  end

  puts "\nTiledenticon: Saving image to #{filename}"
  image.save(filename, :interlace => false)
end
to_image_space(p, origin_x, origin_y) click to toggle source

Convert a positional vector 4 to image space

# File lib/tiler.rb, line 133
def to_image_space p, origin_x, origin_y
  {x: (origin_x - @scale * (p[0] * @canonical_x[0] + p[1] * @canonical_x[1] + 
               p[2] * @canonical_x[2] + p[3] * @canonical_x[3])),
   y: (origin_y + @scale * (p[0] * @canonical_y[0] + p[1] * @canonical_y[1] + 
               p[2] * @canonical_y[2] + p[3] * @canonical_y[3]))};
end