class SolidRuby::Helpers::Triangle

Helper class for creating triangles, given three inputs

(at least 1 side + angles)

The triangle can then either be used as a Polygon, or it can be thrown away and used just for calcuation of the triangle order is assumed as follows:

@a is opposite @alpha, @b is opposite @beta, @c is opposite @gamma
Angles go clockwise with @alpha at the origin
Sides go clockwise with @a along the X axis, and @c along Y

Attributes

a[RW]
alpha[RW]
b[RW]
beta[RW]
c[RW]
gamma[RW]
has_alt_solution[RW]

Public Class Methods

new(args = {}) click to toggle source
Calls superclass method
# File lib/solidruby/helpers/triangle.rb, line 27
def initialize(args = {})
  use_alt_solution = args[:alt_solution] || false

  if args.reject{|k| k == :alt_solution}.count != 3
    raise "Triangle requires exactly 3 inputs"
  elsif args[:a].nil? && args[:b].nil? && args[:c].nil?
    raise "Triangle requires at least 1 side length"
  end

  #try to solve twice to see if we have two solutions
  sol_count = 0
  solution = solve(args, false)
  sol_count += 1 unless solution.nil?
  solution_alt = solve(args, true)
  sol_count += 1 unless solution_alt.nil?

  raise "Could not solve triangle." if sol_count == 0

  @has_alt_solution = sol_count == 2 ? true : false

  if use_alt_solution
    update(solution_alt)
  else
    update(solution)
  end

  #consturct triangle polygon
  args = {points: [
    [0.0, 0.0],
    [@b, 0.0],
    [@c * Math.cos(radians(@alpha)), height(:beta)],
    [0.0, 0.0]]}

  super(args)
end

Public Instance Methods

height(angle) click to toggle source
# File lib/solidruby/helpers/triangle.rb, line 63
def height(angle)
  case angle
  when :alpha
    ang = @beta
    side = @c
  when :beta
    ang = @alpha
    side = @c
  else
    ang = @alpha
    side = @b
  end
  Math.sin(radians(ang)) * side.to_f
end

Private Instance Methods

solve(triangle_params, alt_solution) click to toggle source

Solve for any missing angles/sides

# File lib/solidruby/helpers/triangle.rb, line 88
def solve(triangle_params, alt_solution)
  alpha = triangle_params[:alpha]
  beta = triangle_params[:beta]
  gamma = triangle_params[:gamma]
  a = triangle_params[:a]
  b = triangle_params[:b]
  c = triangle_params[:c]

  #find side for SAS case
  a = solve_side_from_single_angle(b, c, alpha) if a.nil?
  b = solve_side_from_single_angle(a, c, beta) if b.nil?
  c = solve_side_from_single_angle(a, b, gamma) if c.nil?

  #find one angle (SSS case)
  alpha = solve_angle_from_sides(b, c, a) if alpha.nil?
  beta = solve_angle_from_sides(a, c, b) if beta.nil?
  gamma = solve_angle_from_sides(a, b, c) if gamma.nil?

  #now we know at least one angle, find the next one (SSA case)
  alpha = solve_angle_from_angle(a, b, beta, alt_solution) if alpha.nil?
  alpha = solve_angle_from_angle(a, c, gamma, alt_solution) if alpha.nil?
  beta = solve_angle_from_angle(b, a, alpha, alt_solution) if beta.nil?
  beta = solve_angle_from_angle(b, c, gamma, alt_solution) if beta.nil?
  gamma = solve_angle_from_angle(c, a, alpha, alt_solution) if gamma.nil?
  gamma = solve_angle_from_angle(c, b, beta, alt_solution) if gamma.nil?

  #now we know at least two angles, solve the third one
  alpha = sub_angles(beta, gamma) if alpha.nil?
  beta = sub_angles(alpha, gamma) if beta.nil?
  gamma = sub_angles(alpha, beta) if gamma.nil?

  #we know all the angles, now find any unknown sides
  a = solve_side(alpha, b, beta) if a.nil?
  a = solve_side(alpha, c, gamma) if a.nil?
  b = solve_side(beta, a, alpha) if b.nil?
  b = solve_side(beta, c, gamma) if b.nil?
  c = solve_side(gamma, a, alpha) if c.nil?
  c = solve_side(gamma, b, beta) if c.nil?

  return nil if a.nil? || b.nil? || c.nil? || alpha.nil? || beta.nil? || gamma.nil?
  {a: a, b: b, c: c, alpha: alpha, beta: beta, gamma: gamma}
end
solve_angle_from_angle(opp_side, adj_side, adj_angle, alt_solution) click to toggle source
# File lib/solidruby/helpers/triangle.rb, line 143
def solve_angle_from_angle(opp_side, adj_side, adj_angle, alt_solution)
  return nil if opp_side.nil? || adj_side.nil? || adj_angle.nil?

  res = degrees(Math.asin(opp_side * Math.sin(radians(adj_angle)) / adj_side))
  res = 180 - res if alt_solution
  res
end
solve_angle_from_sides(adj_side, adj_side2, opp_side) click to toggle source
# File lib/solidruby/helpers/triangle.rb, line 136
def solve_angle_from_sides(adj_side, adj_side2, opp_side)
  return nil if adj_side.nil? || adj_side2.nil? || opp_side.nil? ||
    adj_side == 0 || adj_side2 == 0 || opp_side == 0

  degrees(Math.acos((adj_side**2 + adj_side2**2 - opp_side**2) / (2.0 * adj_side * adj_side2)))
end
solve_side(opp_angle, adj_side, adj_opp_angle) click to toggle source
# File lib/solidruby/helpers/triangle.rb, line 157
def solve_side(opp_angle, adj_side, adj_opp_angle)
  return nil if opp_angle.nil? || adj_side.nil? || adj_opp_angle.nil?

  (Math.sin(radians(opp_angle)) * adj_side)/Math.sin(radians(adj_opp_angle))
end
solve_side_from_single_angle(side1, side2, angle) click to toggle source
# File lib/solidruby/helpers/triangle.rb, line 151
def solve_side_from_single_angle(side1, side2, angle)
  return nil if side1.nil? || side2.nil? || angle.nil?

  Math.sqrt(side1**2 + side2**2 - 2 * side1 * side2 * Math.cos(radians(angle)))
end
sub_angles(angle1, angle2) click to toggle source
# File lib/solidruby/helpers/triangle.rb, line 131
def sub_angles(angle1, angle2)
  return nil if angle1.nil? || angle2.nil?
  180 - angle1 - angle2
end
update(params) click to toggle source
# File lib/solidruby/helpers/triangle.rb, line 79
def update(params)
  @alpha = params[:alpha]
  @beta = params[:beta]
  @gamma = params[:gamma]
  @a = params[:a]
  @b = params[:b]
  @c = params[:c]
end