The <=> method (the spaceship operator) is defined here to sort by y-coordinate and to choose the left-most in case of a match. This means that enumerations of Points can be sorted. This isn’t necessarily a good idea but it is suitable for finding the pivot point.
class Point attr_reader,:y def initialize(x,y) @x = x @y = y end def <=>(other) return -1 if @y < other.y return 1 if @y > other.y return -1 if @x < other.x return 1 if @x > other.x 0 end def inspect() "(#{@x},#{@y})" end end
An explicit inspect method is defined to make checking of results a bit easier on the eyes.
Ruby’s built in enumeration sorting is equivalent to Haskell’s sortBy strategy, either by writing a spaceship operator or passing a block to sort that returns a suitable value.
def sort_by_angle
# 1. Find the origin or lowest point
initial_sort = @vertices.sort
origin = initial_sort[0]
# 2. Sort all points by the angle each point makes with the origin
[origin] + initial_sort[1..-1].sort! {|v, pivot| compare_angles(origin, v, pivot)}
end
def compare_angles(origin, p1, p2)
p = (p1.x - origin.x)*(p1.y - p2.y)
q = (p1.y - origin.y)*(p1.x - p2.x)
return -1 if p < q
return 1 if p > q
return -1 if p1.y > p2.y
return 1 if p1.y < p2.y
0
end