class Qrio::SamplingGrid

Attributes

angles[R]
block_height[R]
block_width[R]
bottom_left[R]
bounds[R]
finder_patterns[R]
matrix[R]
orientation[R]
origin_corner[R]
provisional_version[R]
top_right[R]

Public Class Methods

new(matrix, finder_patterns) click to toggle source
# File lib/qrio/sampling_grid.rb, line 8
def initialize(matrix, finder_patterns)
  @matrix          = matrix
  @finder_patterns = finder_patterns
  @angles          = []

  find_origin_corner
  detect_orientation
end

Public Instance Methods

build_finder_pattern_neighbors() click to toggle source
# File lib/qrio/sampling_grid.rb, line 77
def build_finder_pattern_neighbors
  @finder_patterns.each do |source|
    @finder_patterns.each do |destination|
      next if source.center == destination.center
      @angles << Neighbor.new(source, destination)
    end
  end
end
detect_orientation() click to toggle source

which way is the QR rotated?

0) normal - shared finder patterns in top left
1)        - shared finder patterns in top right
2)        - shared finder patterns in bottom right
3)        - shared finder patterns in bottom left
# File lib/qrio/sampling_grid.rb, line 48
def detect_orientation
  # TODO : handle multiple possible matches
  other_corners = non_origin_finder_patterns

  dc = other_corners.map(&:distance).inject(0){|s,d| s + d } / 2.0
  threshold = dc / 2.0

  other_corners = other_corners.map(&:destination)

  set_block_dimensions(@origin_corner, *other_corners)
  @provisional_version = ((dc / @block_width).round - 10) / 4

  xs = other_corners.map{|fp| fp.center.first }
  ys = other_corners.map{|fp| fp.center.last }

  above = ys.select{|y| y < (@origin_corner.center.last - threshold) }
  left  = xs.select{|x| x < (@origin_corner.center.first - threshold) }

  @orientation = if above.any?
    left.any? ? 2 : 3
  else
    left.any? ? 1 : 0
  end
end
extracted_pixels() { |round, round| ... } click to toggle source
# File lib/qrio/sampling_grid.rb, line 128
def extracted_pixels
  start_x = @origin_corner.center.first - (@block_width  * 3.0)
  start_y = @origin_corner.center.last  - (@block_height * 3.0)

  dest_x = @bottom_left.center.first - (@block_width * 3.0)
  dest_y = @top_right.center.last  - (@block_height * 3.0)

  # TODO : take bottom right alignment pattern into consideration
  dy = (dest_y - start_y) / logical_width
  dx = (dest_x - start_x) / logical_height

  logical_height.round.times do |row_index|
    row_start_x = start_x + row_index * dx
    row_start_y = start_y + (row_index * @block_height)

    logical_width.round.times do |col_index|
      x = row_start_x + (col_index * @block_width)
      y = row_start_y + (col_index * dy)

      yield x.round, y.round
    end
  end
end
find_origin_corner(normalized=false) click to toggle source
# File lib/qrio/sampling_grid.rb, line 17
def find_origin_corner(normalized=false)
  build_finder_pattern_neighbors

  shared_corners = @finder_patterns.select do |fp|
    fp.neighbors.select(&:right_angle?).count > 1
  end

  # TODO : handle multiple possible matches
  if @origin_corner = shared_corners.first
    if normalized
      # we have correct orientation, identify fp positions
      @top_right = non_origin_finder_patterns.map(&:destination).detect{|fp| fp.center.last < @matrix.height / 2.0 }
      @bottom_left = non_origin_finder_patterns.map(&:destination).detect{|fp| fp.center.first < @matrix.width / 2.0 }
    else
      set_bounds
    end
  end
end
logical_height() click to toggle source
# File lib/qrio/sampling_grid.rb, line 95
def logical_height
  @matrix.height / @block_height
end
logical_width() click to toggle source
# File lib/qrio/sampling_grid.rb, line 91
def logical_width
  @matrix.width / @block_width
end
non_origin_finder_patterns() click to toggle source
# File lib/qrio/sampling_grid.rb, line 73
def non_origin_finder_patterns
  @origin_corner.neighbors.select(&:right_angle?)[0,2]
end
normalize() click to toggle source
# File lib/qrio/sampling_grid.rb, line 99
def normalize
  @matrix = @matrix.extract(*@bounds.to_point_size)
  translate(*@bounds.top_left)

  if @orientation > 0
    (4 - @orientation).times do
      rotate
    end
  end

  find_origin_corner(true)
end
rotate() click to toggle source
# File lib/qrio/sampling_grid.rb, line 123
def rotate
  @matrix = @matrix.rotate
  @finder_patterns.map!{|f| f.rotate(@bounds.width, @bounds.height) }
end
set_block_dimensions(*finder_patterns) click to toggle source
# File lib/qrio/sampling_grid.rb, line 86
def set_block_dimensions(*finder_patterns)
  @block_width  = finder_patterns.inject(0){|s,f| s + f.width } / 21.0
  @block_height = finder_patterns.inject(0){|s,f| s + f.height } / 21.0
end
set_bounds() click to toggle source
# File lib/qrio/sampling_grid.rb, line 36
def set_bounds
  @bounds = @origin_corner.dup
  @bounds.neighbors.select(&:right_angle?).each do |n|
    @bounds = @bounds.union(n.destination)
  end
end
translate(x, y) click to toggle source
# File lib/qrio/sampling_grid.rb, line 112
def translate(x, y)
  @angles = []
  other_corners = non_origin_finder_patterns.map(&:destination)

  @origin_corner = @origin_corner.translate(x, y)
  translated = [@origin_corner]
  translated += other_corners.map{|c| c.translate(x, y) }

  @finder_patterns = translated
end