Class: Raster

Inherits:
Object
  • Object
show all
Defined in:
lib/skrift/raster.rb

Defined Under Namespace

Classes: Cell, Vector

Instance Method Summary collapse

Constructor Details

#initialize(width, height) ⇒ Raster

Returns a new instance of Raster.



11
12
13
14
15
# File 'lib/skrift/raster.rb', line 11

def initialize width, height
  @width = width
  @height = height
  @cells = (0..(width*height-1)).map { Cell[0.0,0.0] }
end

Instance Method Details

#draw_line(origin, goal) ⇒ Object

Draws a line into the buffer. Uses a custom 2D raycasting algorithm to do so.



30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
# File 'lib/skrift/raster.rb', line 30

def draw_line(origin, goal)
  prev_distance = 0.0
  num_steps = 0
  delta = goal-origin
  dir_x = delta[0] <=> 0
  dir_y = delta[1] <=> 0
  next_crossing = Vector[0.0,0.0]
  pixel = Vector[0,0]
  return if dir_y == 0

  crossing_incr_x = dir_x != 0 ? (1.0 / delta[0]).abs : 1.0
  crossing_incr_y = (1.0 / delta[1]).abs

  if dir_x == 0
    pixel[0] = origin[0].floor
    next_crossing[0] = 100.0
  else
    if dir_x > 0
      pixel[0] = origin[0].floor
      next_crossing[0] = crossing_incr_x - (origin[0] - pixel[0]) * crossing_incr_x
      num_steps += goal[0].ceil - origin[0].floor - 1
    else
      pixel[0] = origin[0].ceil - 1
      next_crossing[0] = (origin[0] - pixel[0]) * crossing_incr_x
      num_steps += origin[0].ceil - goal[0].floor - 1
    end
  end

  if dir_y > 0
    pixel[1] = origin[1].floor
    next_crossing[1] = crossing_incr_y - (origin[1] - pixel[1]) * crossing_incr_y
    num_steps += goal[1].ceil - origin[1].floor - 1
  else
    pixel[1] = origin[1].ceil - 1
    next_crossing[1] = (origin[1] - pixel[1]) * crossing_incr_y
    num_steps += origin[1].ceil - goal[1].floor - 1
  end

  next_distance = next_crossing.min
  half_delta_x = 0.5 * delta[0]
  setcell = ->(nd) do
    x_average = origin[0] + (prev_distance + nd) * half_delta_x - pixel[0]
    y_difference = (nd - prev_distance).to_f * delta[1]
    cell = @cells[pixel[1] * @width + pixel[0]]
    cell.cover += y_difference
    cell.area  += (1.0 - x_average) * y_difference
  end
  num_steps.times do
    setcell.call(next_distance)
    prev_distance = next_distance
    along_x = next_crossing[0] < next_crossing[1]
    pixel += along_x ? Vector[dir_x,0] : Vector[0,dir_y]
    next_crossing += along_x ? Vector[crossing_incr_x, 0.0] : [0.0, crossing_incr_y]
    next_distance = next_crossing.min
  end
  setcell.call(1.0)
end

#post_processObject

Integrate the values in the buffer to arrive at the final grayscale image.



18
19
20
21
22
23
24
25
26
27
# File 'lib/skrift/raster.rb', line 18

def post_process
  accum = 0.0
  (@width*@height).times.collect do |i|
    cell = @cells[i]
    value = (accum + cell.area).abs
    value = [value, 1.0].min * 255.0 + 0.5
    accum += cell.cover
    value.to_i & 0xff
  end
end