Class: Geo3d::Quaternion

Inherits:
Object
  • Object
show all
Defined in:
lib/geo3d/quaternion.rb

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(*args) ⇒ Quaternion

Returns a new instance of Quaternion.



5
6
7
8
9
10
11
# File 'lib/geo3d/quaternion.rb', line 5

def initialize *args
  @x, @y, @z, @w = 0.0, 0.0, 0.0, 0.0
  @x = args[0].to_f if args.size > 0
  @y = args[1].to_f if args.size > 1
  @z = args[2].to_f if args.size > 2
  @w = args[3].to_f if args.size > 3
end

Instance Attribute Details

#wObject

Returns the value of attribute w.



3
4
5
# File 'lib/geo3d/quaternion.rb', line 3

def w
  @w
end

#xObject

Returns the value of attribute x.



3
4
5
# File 'lib/geo3d/quaternion.rb', line 3

def x
  @x
end

#yObject

Returns the value of attribute y.



3
4
5
# File 'lib/geo3d/quaternion.rb', line 3

def y
  @y
end

#zObject

Returns the value of attribute z.



3
4
5
# File 'lib/geo3d/quaternion.rb', line 3

def z
  @z
end

Class Method Details

.from_axis(rotation_axis, radians = 0) ⇒ Object



49
50
51
52
53
54
55
56
57
58
# File 'lib/geo3d/quaternion.rb', line 49

def self.from_axis rotation_axis, radians = 0
  radians = Geo3d::Utils.normalize_angle radians  #todo: is this cheating?....
  normalized_rotation_axis = rotation_axis.zero_w.normalize
  q = self.new
  q.x = Math.sin(radians / 2.0) * normalized_rotation_axis.x
  q.y = Math.sin(radians / 2.0) * normalized_rotation_axis.y
  q.z = Math.sin(radians / 2.0) * normalized_rotation_axis.z
  q.w = Math.cos(radians / 2.0)
  q
end

.from_axis_degrees(rotation_axis, degrees = 0) ⇒ Object



60
61
62
# File 'lib/geo3d/quaternion.rb', line 60

def self.from_axis_degrees rotation_axis, degrees = 0
  from_axis rotation_axis, Geo3d::Utils.to_radians(degrees)
end

.from_matrix(pm) ⇒ Object



64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
# File 'lib/geo3d/quaternion.rb', line 64

def self.from_matrix pm
  pout = self.new

  #puts "trace is #{pm.trace}"
  if false && pm.trace > 1.0
    sq_root_of_trace = Math.sqrt pm.trace
    pout.x = (pm._23 - pm._32) / (2.0 * sq_root_of_trace)
    pout.y = (pm._31 - pm._13) / (2.0 * sq_root_of_trace)
    pout.z = (pm._12- pm._21) / (2.0 * sq_root_of_trace)
    pout.w = sq_root_of_trace / 2.0
    #puts "a and pout is #{pout.inspect}"

    return pout
  end
  maxi = 0
  maxdiag = pm._11


  for i in 1..2
    if pm[i, i] > maxdiag #todo: indexing might need to be fixed > maxdiag
      maxi = i
      maxdiag = pm[i, i] #todo: indexing might need to be fixed
    end
  end
  case maxi
    when 0
      s = 2.0 * Math.sqrt(1.0 + pm._11 - pm._22 - pm._33)
      pout.x = 0.25 * s
      pout.y = (pm._12 + pm._21) / s
      pout.z = (pm._13 + pm._31) / s
      pout.w = (pm._23 - pm._32) / s

    when 1
      s = 2.0 * Math.sqrt(1.0 + pm._22 - pm._11 - pm._33)
      pout.x = (pm._12 + pm._21) / s
      pout.y = 0.25 * s
      pout.z = (pm._23 + pm._32) / s
      pout.w = (pm._31 - pm._13) / s

    when 2
      s = 2.0 * Math.sqrt(1.0 + pm._33 - pm._11 - pm._22)
      pout.x = (pm._13 + pm._31) / s
      pout.y = (pm._23 + pm._32) / s
      pout.z = 0.25 * s
      pout.w = (pm._12 - pm._21) / s
  end
  #puts "b"
  pout
end

.identityObject



212
213
214
# File 'lib/geo3d/quaternion.rb', line 212

def self.identity
  self.new 0, 0, 0, 1
end

Instance Method Details

#!=(vec) ⇒ Object



45
46
47
# File 'lib/geo3d/quaternion.rb', line 45

def != vec
  !(self == vec)
end

#*(v) ⇒ Object



122
123
124
125
126
127
128
129
130
131
132
133
134
# File 'lib/geo3d/quaternion.rb', line 122

def * v
  if Quaternion == v.class
    quat = v
    out = self.class.new
    out.w = w * quat.w - x * quat.x - y * quat.y - z * quat.z
    out.x = w * quat.x + x * quat.w + y * quat.z - z * quat.y
    out.y = w * quat.y - x * quat.z + y * quat.w + z * quat.x
    out.z = w * quat.z + x * quat.y - y * quat.x + z * quat.w
    out
  else
    self.class.new x*v, y*v, z*v, w*v
  end
end

#+(quat) ⇒ Object



114
115
116
# File 'lib/geo3d/quaternion.rb', line 114

def + quat
  self.class.new x + quat.x, y + quat.y, z + quat.z, w + quat.w
end

#+@Object



33
34
35
# File 'lib/geo3d/quaternion.rb', line 33

def +@
  self.class.new x, y, z, w
end

#-(quat) ⇒ Object



118
119
120
# File 'lib/geo3d/quaternion.rb', line 118

def - quat
  self.class.new x - quat.x, y - quat.y, z - quat.z, w - quat.w
end

#-@Object



37
38
39
# File 'lib/geo3d/quaternion.rb', line 37

def -@
  self.class.new -x, -y, -z, -w
end

#/(v) ⇒ Object



136
137
138
# File 'lib/geo3d/quaternion.rb', line 136

def / v
  self.class.new x/v, y/v, z/v, w/v
end

#==(q) ⇒ Object



41
42
43
# File 'lib/geo3d/quaternion.rb', line 41

def == q
  Geo3d::Utils.float_cmp(x, q.x) && Geo3d::Utils.float_cmp(y, q.y) && Geo3d::Utils.float_cmp(z, q.z) && Geo3d::Utils.float_cmp(w, q.w)
end

#angleObject



159
160
161
# File 'lib/geo3d/quaternion.rb', line 159

def angle
  Math.acos(normalize.w) * 2.0
end

#angle_degreesObject



163
164
165
# File 'lib/geo3d/quaternion.rb', line 163

def angle_degrees
  Geo3d::Utils.to_degrees angle
end

#axisObject



155
156
157
# File 'lib/geo3d/quaternion.rb', line 155

def axis
  Vector.new( *(normalize / Math.sin( angle / 2.0 )).to_a ).zero_w
end

#conjugateObject



195
196
197
# File 'lib/geo3d/quaternion.rb', line 195

def conjugate
  self.class.new -x, -y, -z, w
end

#dot(quat) ⇒ Object



175
176
177
# File 'lib/geo3d/quaternion.rb', line 175

def dot quat
  x * quat.x + y * quat.y + z * quat.z + w * quat.w
end

#identity?Boolean

Returns:

  • (Boolean)


208
209
210
# File 'lib/geo3d/quaternion.rb', line 208

def identity?
  self == self.class.identity
end

#inverseObject



199
200
201
202
203
204
205
206
# File 'lib/geo3d/quaternion.rb', line 199

def inverse
  norm = length_squared
  if norm.zero?
    self.class.new 0, 0, 0, 0
  else
    conjugate / norm
  end
end

#lengthObject



171
172
173
# File 'lib/geo3d/quaternion.rb', line 171

def length
  Math.sqrt length_squared
end

#length_squaredObject



167
168
169
# File 'lib/geo3d/quaternion.rb', line 167

def length_squared
  dot self
end

#normalizeObject



189
190
191
192
193
# File 'lib/geo3d/quaternion.rb', line 189

def normalize
  q = self.class.new x, y, z, w
  q.normalize!
  q
end

#normalize!Object



179
180
181
182
183
184
185
186
187
# File 'lib/geo3d/quaternion.rb', line 179

def normalize!
  len = length
  if length > 0
    @x /= len
    @y /= len
    @z /= len
    @w /= len
  end
end

#to_aObject



13
14
15
# File 'lib/geo3d/quaternion.rb', line 13

def to_a
  [x,y,z,w]
end

#to_matrixObject



140
141
142
143
144
145
146
147
148
149
150
151
152
153
# File 'lib/geo3d/quaternion.rb', line 140

def to_matrix
  v = normalize
  matrix = Matrix.identity
  matrix._11 = 1.0 - 2.0 * (v.y * v.y + v.z * v.z)
  matrix._12 = 2.0 * (v.x * v.y + v.z * v.w)
  matrix._13 = 2.0 * (v.x * v.z - v.y * v.w)
  matrix._21 = 2.0 * (v.x * v.y - v.z * v.w)
  matrix._22 = 1.0 - 2.0 * (v.x * v.x + v.z * v.z)
  matrix._23 = 2.0 * (v.y * v.z + v.x * v.w)
  matrix._31 = 2.0 * (v.x * v.z + v.y * v.w)
  matrix._32 = 2.0 * (v.y * v.z - v.x * v.w)
  matrix._33 = 1.0 - 2.0 * (v.x * v.x + v.y * v.y)
  matrix
end