Skip to content

Instantly share code, notes, and snippets.

@gouthamvel
Created May 29, 2014 05:56
Show Gist options
  • Save gouthamvel/c1cd65685aab2aeecf16 to your computer and use it in GitHub Desktop.
Save gouthamvel/c1cd65685aab2aeecf16 to your computer and use it in GitHub Desktop.
Displacement calculation when bearing and distance with point relation are given.
# displacement calculation
# Instructions
# A car travels from one point to the next. It starts at point A, then moves to point B, then C and so on. Between each point it travels in a straight line. The car's travel is described in the input string in the following format:
# <<start_point>|<end_point>>[<heading>:<distance>],...
# Heading values can be 0 through 355 degrees (in increments of 5)
# For example, input might be:
# <A|B>[160:72],<B|C>[40:38],<C|D>[95:118]
# The path is considered non cyclic and the order of points may vary like
# <B|C>[40:38],<C|D>[95:118],<A|B>[160:72]
require 'tsort'
class Hash
include TSort
alias tsort_each_node each_key
def tsort_each_child(node, &block)
fetch(node).each(&block)
end
end
class Point
attr_accessor :name
def initialize(name, cords={angle: 0, distance: 0})
@name = name
@angle = cords[:angle] * Math::PI / 180
@distance = cords[:distance]
end
def coordinates_from(from_coordinates)
[from_coordinates[0] + @distance*Math.cos(@angle), from_coordinates[1] + @distance*Math.sin(@angle)].map { |e| e.round(3) }
end
def to_s
"#{@name}:(#{@angle}:#{@distance})"
end
end
class PointsChain
attr_accessor :mapping, :points
def initialize(input)
@points = {}
@sorted_points = {}
@mapping = {}
@processed_input = input.split(',').map {|string| create_point_params(string)}
@processed_input.each do |args|
add Point.new(args[0], angle: args[2], distance: args[3]), args[1]
end
end
def add(point, destination)
@points[point.name] = point
@mapping[destination] ||= []
@mapping[point.name] ||= []
@mapping[point.name] << destination
end
def sorted_points(order=:asc)
if order == :asc
@mapping.tsort.reverse.map {|name| @points[name] }.compact
else
@mapping.tsort.map {|name| @points[name] }.compact
end
end
def final_coordinates
sorted_points.inject([0,0]) do |coordinates, point|
point.coordinates_from(coordinates)
end
end
private
def parse_regex
/<(\w)\|(\w)>\[(\d*)\:(\d*)\],*/
end
def create_point_params(string)
values = string.match(parse_regex).captures
[values[0], values[1], values[2].to_i, values[3].to_f]
end
end
input = "<B|C>[40:38],<C|D>[95:118],<A|B>[160:72]" if ENV['VEL_DEV']
chain = PointsChain.new(input)
cords = chain.final_coordinates
displacement = cords[0]/2 + cords[1]/2
distance = chain.points.values.uniq{|p| p.name }.inject(0){|dist, point| dist + point.distance}
puts "distance #{distance}"
puts "displacement #{displacement}"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment