module Silicium::Geometry

Constants

Point

Represents a point as two coordinates in two-dimensional space

Point3d

Represents a point as three coordinates in three-dimensional space

Public Instance Methods

clockwise(a, b, c) click to toggle source

Determines if a clockwise crawl is performed for defined order of points

# File lib/geometry.rb, line 83
def clockwise(a, b, c)
  oriented_area(a, b, c).negative?
end
counter_clockwise(a, b, c) click to toggle source

Determines if a counter-clockwise crawl is performed for defined order of points

# File lib/geometry.rb, line 90
def counter_clockwise(a, b, c)
  oriented_area(a, b, c).positive?
end
cut_by_eq(line_equation) click to toggle source
# File lib/geometry.rb, line 147
def cut_by_eq(line_equation)
  line_equation.slice(line_equation.index('='), line_equation.length).sub('=', '')
end
directing_vector3d(line_equation) click to toggle source

Creates an array- directing vector in three-dimensional space . The equation is specified in the canonical form. Example, (x-0) / 26 = (y + 300) / * (- 15) = (z-200) / 51

Important: mandatory order of variables: x, y, z

# File lib/geometry.rb, line 169
def directing_vector3d(line_equation)
  process_line_by_coordinates(line_equation, :process_cf)
end
distance_point_line2d(p1, p2, a) click to toggle source

The distance from a point to a line on a plane The line is defined by two points en.wikipedia.org/wiki/Distance_from_a_point_to_a_line

# File lib/geometry.rb, line 60
def distance_point_line2d(p1, p2, a)
  line_segment_length = distance_point_to_point2d(p1, p2)
  ((p2.y - p1.y) * a.x - (p2.x - p1.x) * a.y + p2.x * p1.y - p2.y * p1.x).abs / (line_segment_length * 1.0)
end
distance_point_line_equation2d(a, b, c, p) click to toggle source

The distance from a point to a line on a plane Line defined by an equation return 0 if the equation does not define a line.

# File lib/geometry.rb, line 69
def distance_point_line_equation2d(a, b, c, p)
  if a == 0 and b == 0
    return 0
  end
  (a * p.x + b * p.y + c).abs / Math.sqrt(a**2 + b**2)
end
distance_point_to_point2d(a, b) click to toggle source

Calculates the distance from given points in two-dimensional space

# File lib/geometry.rb, line 19
def distance_point_to_point2d(a, b)
  Math.sqrt((b.x - a.x)**2 + (b.y - a.y)**2)
end
distance_point_to_point3d(a, b) click to toggle source

Calculates the distance from given points in three-dimensional space

# File lib/geometry.rb, line 52
def distance_point_to_point3d(a, b)
  Math.sqrt((b.x - a.x)**2 + (b.y - a.y)**2 + (b.z - a.z)**2)
end
height_point_3d(line_equation) click to toggle source

Creates an array of coordinates of the point ([x, y, z] on the line given by the equation in the canonical form. Example, (x-0) / 26 = (y + 300) / * (- 15) = (z-200) / 51

Important: mandatory order of variables: x, y, z

# File lib/geometry.rb, line 201
def height_point_3d(line_equation)
  process_line_by_coordinates(line_equation, :process_free_member)
end
insert_eq(line_equation) click to toggle source
# File lib/geometry.rb, line 232
def insert_eq(line_equation)
  line_equation.gsub(' ', '').insert(line_equation.length, '=')
end
minimal_convex_hull_2d(points) click to toggle source

Returns an array containing points that are included in the minimal convex hull for a given array of points e-maxx.ru/algo/convex_hull_graham

# File lib/geometry.rb, line 110
def minimal_convex_hull_2d(points)
  return points if not_polygon?(points)

  points.sort_by! { |p| [p.x, p.y] }
  first = points[0]
  last = points.last
  up = [first]
  down = [first]

  (1...points.size).each do |i|
    point = points[i]
    is_last = i == points.size - 1
    if is_last || clockwise(first, point, last)
      put_point_in_part(up, point, :clockwise)
    end
    if is_last || counter_clockwise(first, point, last)
      put_point_in_part(down, point, :counter_clockwise)
    end
  end

  hull = up
  (1..(down.size - 2)).reverse_each do |j|
    hull.push(down[j])
  end
  hull
end
needed_variables_order?(before, after) click to toggle source
# File lib/geometry.rb, line 176
def needed_variables_order?(before, after)
  before < after
end
not_polygon?(points) click to toggle source
# File lib/geometry.rb, line 94
def not_polygon?(points)
  points.empty? || points.size == 1 || points.size == 2
end
oriented_area(a, b, c) click to toggle source
# File lib/geometry.rb, line 76
def oriented_area(a, b, c)
  a.x * (b.y - c.y) + b.x * (c.y - a.y) + c.x * (a.y - b.y)
end
point_to_line_distance_3d(point, line_eq) click to toggle source

Calculates the distance from a point given by a Point3d structure to a straight line given by a canonical equation. Example, (x-0) / 26 = (y + 300) / * (- 15) = (z-200) / 51

Important: mandatory order of variables: x, y, z

# File lib/geometry.rb, line 223
def point_to_line_distance_3d(point, line_eq)
  dir_vector = directing_vector3d(line_eq)
  line_point = height_point_3d(line_eq)
  height_vector = [line_point[0] - point.x, line_point[1] - point.y, line_point[2] - point.z]

  height_on_dir = vectors_product(height_vector, dir_vector)
  vector_length(height_on_dir) / vector_length(dir_vector)
end
process_cf(line_equation, variable) click to toggle source
# File lib/geometry.rb, line 137
def process_cf(line_equation, variable)
  if line_equation.include?(variable)
    before = line_equation.index('/') + 1
    after = line_equation.index('=')
    line_equation.slice(before..after).gsub('=', '').sub('*', '').gsub('(', '').gsub(')', '').to_f
  else
    0.0
  end
end
process_free_member(line_equation, variable) click to toggle source
# File lib/geometry.rb, line 180
def process_free_member(line_equation, variable)
  if line_equation.include?(variable)
    before = line_equation.index(variable) + 1
    after = line_equation.index('/')

    unless needed_variables_order?(before, after)
      throw VariablesOrderException
    end

    line_equation.slice(before..after).gsub('/', '').to_f * (-1)
  else
    0.0
  end
end
process_line_by_coordinates(line_equation, func) click to toggle source
# File lib/geometry.rb, line 151
def process_line_by_coordinates(line_equation, func)
  copy_line = insert_eq(line_equation)
  func = method(func)
  res = []
  res[0] = func.call(copy_line, 'x')
  copy_line = cut_by_eq(copy_line)
  res[1] = func.call(copy_line, 'y')
  copy_line = cut_by_eq(copy_line)
  res[2] = func.call(copy_line, 'z')
  res
end
put_point_in_part(part, point, direction) click to toggle source
# File lib/geometry.rb, line 98
def put_point_in_part(part, point, direction)
  direction = method(direction)
  while part.size >= 2 && !direction.call(part[part.size - 2], part[part.size - 1], point)
    part.pop
  end
  part.push(point)
end
vector_length(vector) click to toggle source
# File lib/geometry.rb, line 213
def vector_length(vector)
  Math.sqrt(vector[0]**2 + vector[1]**2 + vector[2]**2)
end
vectors_product(v1, v2) click to toggle source
# File lib/geometry.rb, line 205
def vectors_product(v1, v2)
  res = Array.new(3)
  (0..2).each do |i|
    res[i] = v1[(i + 1) % 3] * v2[(i + 2) % 3] - v1[(i + 2) % 3] * v2[(i + 1) % 3]
  end
  res
end