Class: RTanque::Heading

Inherits:
Numeric
  • Object
show all
Defined in:
lib/rtanque/heading.rb

Overview

A Heading represents an angle. Basically a wrapper around Float bound to (0..Math::PI * 2)

0.0 == RTanque::Heading::NORTH is 'up'

Basic Usage

RTanque::Heading.new(Math::PI)
# => <RTanque::Heading: 1.0rad 180.0deg>

RTanque::Heading.new(Math::PI) + RTanque::Heading.new(Math::PI)
# => <RTanque::Heading: 0.0rad 0.0deg>

RTanque::Heading.new(Math::PI / 2.0) + Math::PI
# => <RTanque::Heading: 1.5rad 270.0deg>

RTanque::Heading.new(0.0) == 0
# => true

Utility Methods

RTanque::Heading.new_from_degrees(180.0)
# => <RTanque::Heading: 1.0rad 180.0deg>

RTanque::Heading.new(Math::PI).to_degrees
# => 180.0

RTanque::Heading.new_between_points(RTanque::Point.new(0,0), RTanque::Point.new(2,3))
# => <RTanque::Heading: 0.1871670418109988rad 33.690067525979785deg>

RTanque::Heading.new_from_degrees(1).delta(RTanque::Heading.new_from_degrees(359))
# => -0.034906585039886195

Constant Summary

FULL_ANGLE =
Math::PI * 2.0
HALF_ANGLE =
Math::PI
EIGHTH_ANGLE =
Math::PI / 4.0
ONE_DEGREE =
FULL_ANGLE / 360.0
FULL_RANGE =
(0..FULL_ANGLE)
NORTH =
N =         0.0
NORTH_EAST =
NE =   1.0 * EIGHTH_ANGLE
EAST =
E =          2.0 * EIGHTH_ANGLE
SOUTH_EAST =
SE =   3.0 * EIGHTH_ANGLE
SOUTH =
S =         4.0 * EIGHTH_ANGLE
SOUTH_WEST =
SW =   5.0 * EIGHTH_ANGLE
WEST =
W =          6.0 * EIGHTH_ANGLE
NORTH_WEST =
NW =   7.0 * EIGHTH_ANGLE

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(radians = NORTH) ⇒ Heading

Creates a new RTanque::Heading



69
70
71
72
73
# File 'lib/rtanque/heading.rb', line 69

def initialize(radians = NORTH)
  @radians = radians.to_f % FULL_ANGLE
  @memoized = {} # allow memoization since @some_var ||= x doesn't work when frozen
  self.freeze
end

Instance Attribute Details

#radiansObject (readonly)

Returns the value of attribute radians



65
66
67
# File 'lib/rtanque/heading.rb', line 65

def radians
  @radians
end

Class Method Details

.delta_between_points(from_point, from_point_heading, to_point) ⇒ Object



56
57
58
59
# File 'lib/rtanque/heading.rb', line 56

def self.delta_between_points(from_point, from_point_heading, to_point)
  rel_heading = self.new_between_points(from_point, to_point)
  self.new(from_point_heading).delta(rel_heading)
end

.new_between_points(from_point, to_point) ⇒ Object



52
53
54
# File 'lib/rtanque/heading.rb', line 52

def self.new_between_points(from_point, to_point)
  self.new(from_point == to_point ? 0.0 : Math.atan2(to_point.x - from_point.x, to_point.y - from_point.y))
end

.new_from_degrees(degrees) ⇒ Object



48
49
50
# File 'lib/rtanque/heading.rb', line 48

def self.new_from_degrees(degrees)
  self.new((degrees / 180.0) * Math::PI)
end

.randObject



61
62
63
# File 'lib/rtanque/heading.rb', line 61

def self.rand
  self.new(Kernel.rand * FULL_ANGLE)
end

Instance Method Details

#*(other_heading) ⇒ RTanque::Heading



122
123
124
# File 'lib/rtanque/heading.rb', line 122

def *(other_heading)
  self.class.new(self.radians * other_heading.to_f)
end

#+(other_heading) ⇒ RTanque::Heading



110
111
112
# File 'lib/rtanque/heading.rb', line 110

def +(other_heading)
  self.class.new(self.radians + other_heading.to_f)
end

#+@RTanque::Heading

unary operator



134
135
136
# File 'lib/rtanque/heading.rb', line 134

def +@
  self.class.new(+self.radians)
end

#-(other_heading) ⇒ RTanque::Heading



116
117
118
# File 'lib/rtanque/heading.rb', line 116

def -(other_heading)
  self.+(-other_heading)
end

#-@RTanque::Heading

unary operator



140
141
142
# File 'lib/rtanque/heading.rb', line 140

def -@
  self.class.new(-self.radians)
end

#/(other_heading) ⇒ RTanque::Heading



128
129
130
# File 'lib/rtanque/heading.rb', line 128

def /(other_heading)
  self.*(1.0 / other_heading)
end

#<=>(other_heading) ⇒ Boolean



104
105
106
# File 'lib/rtanque/heading.rb', line 104

def <=>(other_heading)
  self.to_f <=> other_heading.to_f
end

#==(other_heading) ⇒ Boolean



91
92
93
# File 'lib/rtanque/heading.rb', line 91

def ==(other_heading)
  self.to_f == other_heading.to_f
end

#cloneRTanque::Heading



85
86
87
# File 'lib/rtanque/heading.rb', line 85

def clone
  self.class.new(self.radians)
end

#delta(to) ⇒ Float

difference between self and to respecting negative angles



78
79
80
81
82
# File 'lib/rtanque/heading.rb', line 78

def delta(to)
  diff = (to.to_f - self.to_f).abs % FULL_ANGLE
  diff = -(FULL_ANGLE - diff) if diff > Math::PI
  to.to_f < self.to_f ? -diff : diff
end

#eql?(other_heading) ⇒ Boolean

continue with Numeric's pattern



98
99
100
# File 'lib/rtanque/heading.rb', line 98

def eql?(other_heading)
  other_heading.instance_of?(self.class) && self.==(other_heading)
end

#inspectObject



148
149
150
# File 'lib/rtanque/heading.rb', line 148

def inspect
  "<#{self.class.name}: #{self.radians}rad #{self.to_degrees}deg>"
end

#to_degreesFloat



158
159
160
# File 'lib/rtanque/heading.rb', line 158

def to_degrees
  @memoized[:to_degrees] ||= (self.radians * 180.0) / Math::PI
end

#to_fFloat



153
154
155
# File 'lib/rtanque/heading.rb', line 153

def to_f
  self.radians
end

#to_sObject



144
145
146
# File 'lib/rtanque/heading.rb', line 144

def to_s
  self.to_f
end