lib/cyberarm_engine/vector.rb in cyberarm_engine-0.19.0 vs lib/cyberarm_engine/vector.rb in cyberarm_engine-0.19.1
- old
+ new
@@ -1,293 +1,293 @@
-module CyberarmEngine
- class Vector
- ##
- # Creates a up vector
- #
- # Vector.new(0, 1, 0)
- #
- # @return [CyberarmEngine::Vector]
- def self.up
- Vector.new(0, 1, 0)
- end
-
- ##
- # Creates a down vector
- #
- # Vector.new(0, -1, 0)
- #
- # @return [CyberarmEngine::Vector]
- def self.down
- Vector.new(0, -1, 0)
- end
-
- ##
- # Creates a left vector
- #
- # Vector.new(-1, 0, 0)
- #
- # @return [CyberarmEngine::Vector]
- def self.left
- Vector.new(-1, 0, 0)
- end
-
- ##
- # Creates a right vector
- #
- # Vector.new(1, 0, 0)
- #
- # @return [CyberarmEngine::Vector]
- def self.right
- Vector.new(1, 0, 0)
- end
-
- ##
- # Creates a forward vector
- #
- # Vector.new(0, 0, 1)
- #
- # @return [CyberarmEngine::Vector]
- def self.forward
- Vector.new(0, 0, 1)
- end
-
- ##
- # Creates a backward vector
- #
- # Vector.new(0, 0, -1)
- #
- # @return [CyberarmEngine::Vector]
- def self.backward
- Vector.new(0, 0, -1)
- end
-
- attr_accessor :x, :y, :z, :weight
-
- def initialize(x = 0, y = 0, z = 0, weight = 0)
- @x = x
- @y = y
- @z = z
- @weight = weight
- end
-
- alias w weight
- alias w= weight=
-
- # @return [Boolean]
- def ==(other)
- if other.is_a?(Numeric)
- @x == other &&
- @y == other &&
- @z == other &&
- @weight == other
- elsif other.is_a?(Vector)
- @x == other.x &&
- @y == other.y &&
- @z == other.z &&
- @weight == other.weight
- else
- other == self
- end
- end
-
- # Create a new vector using {x} and {y} values
- # @return [CyberarmEngine::Vector]
- def xy
- Vector.new(@x, @y)
- end
-
- # Performs math operation, excluding {weight}
- private def operator(function, other)
- if other.is_a?(Numeric)
- Vector.new(
- @x.send(:"#{function}", other),
- @y.send(:"#{function}", other),
- @z.send(:"#{function}", other)
- )
- else
- Vector.new(
- @x.send(:"#{function}", other.x),
- @y.send(:"#{function}", other.y),
- @z.send(:"#{function}", other.z)
- )
- end
- end
-
- # Adds Vector and Numeric or Vector and Vector, excluding {weight}
- # @return [CyberarmEngine::Vector]
- def +(other)
- operator("+", other)
- end
-
- # Subtracts Vector and Numeric or Vector and Vector, excluding {weight}
- # @return [CyberarmEngine::Vector]
- def -(other)
- operator("-", other)
- end
-
- # Multiplies Vector and Numeric or Vector and Vector, excluding {weight}
- # @return [CyberarmEngine::Vector]
- def *(other)
- operator("*", other)
- end
-
- def multiply_transform(transform)
- e = transform.elements
-
- x = @x * e[0] + @y * e[1] + @z * e[2] + 1 * e[3]
- y = @x * e[4] + @y * e[5] + @z * e[6] + 1 * e[7]
- z = @x * e[8] + @y * e[9] + @z * e[10] + 1 * e[11]
- w = @x * e[12] + @y * e[13] + @z * e[14] + 1 * e[15]
-
- Vector.new(x / 1, y / 1, z / 1, w / 1)
- end
-
- # Divides Vector and Numeric or Vector and Vector, excluding {weight}
- # @return [CyberarmEngine::Vector]
- def /(other)
- # Duplicated to protect from DivideByZero
- if other.is_a?(Numeric)
- Vector.new(
- (@x == 0 ? 0 : @x / other),
- (@y == 0 ? 0 : @y / other),
- (@z == 0 ? 0 : @z / other)
- )
- else
- Vector.new(
- (@x == 0 ? 0 : @x / other.x),
- (@y == 0 ? 0 : @y / other.y),
- (@z == 0 ? 0 : @z / other.z)
- )
- end
- end
-
- # dot product of {Vector}
- # @return [Integer|Float]
- def dot(other)
- product = 0
-
- a = to_a
- b = other.to_a
-
- 3.times do |i|
- product += (a[i] * b[i])
- end
-
- product
- end
-
- # cross product of {Vector}
- # @return [CyberarmEngine::Vector]
- def cross(other)
- a = to_a
- b = other.to_a
-
- Vector.new(
- b[2] * a[1] - b[1] * a[2],
- b[0] * a[2] - b[2] * a[0],
- b[1] * a[0] - b[0] * a[1]
- )
- end
-
- # returns degrees
- # @return [Float]
- def angle(other)
- Math.acos(normalized.dot(other.normalized)) * 180 / Math::PI
- end
-
- # returns magnitude of Vector, ignoring #weight
- # @return [Float]
- def magnitude
- Math.sqrt((@x * @x) + (@y * @y) + (@z * @z))
- end
-
- ##
- # returns normalized {Vector}
- #
- # @example
- # CyberarmEngine::Vector.new(50, 21.2, 45).normalized
- # # => <CyberarmEngine::Vector:0x001 @x=0.7089... @y=0.3005... @z=0.6380... @weight=0>
- #
- # @return [CyberarmEngine::Vector]
- def normalized
- mag = magnitude
- self / Vector.new(mag, mag, mag)
- end
-
- # returns a direction {Vector}
- #
- # z is pitch
- #
- # y is yaw
- #
- # x is roll
- # @return [CyberarmEngine::Vector]
- def direction
- _x = -Math.sin(@y.degrees_to_radians) * Math.cos(@z.degrees_to_radians)
- _y = Math.sin(@z.degrees_to_radians)
- _z = Math.cos(@y.degrees_to_radians) * Math.cos(@z.degrees_to_radians)
-
- Vector.new(_x, _y, _z)
- end
-
- # returns an inverse {Vector}
- # @return [CyberarmEngine::Vector]
- def inverse
- Vector.new(1.0 / @x, 1.0 / @y, 1.0 / @z)
- end
-
- # Adds up values of {x}, {y}, and {z}
- # @return [Integer|Float]
- def sum
- @x + @y + @z
- end
-
- ##
- # Linear interpolation: smoothly transition between two {Vector}
- #
- # CyberarmEngine::Vector.new(100, 100, 100).lerp( CyberarmEngine::Vector.new(0, 0, 0), 0.75 )
- # # => <CyberarmEngine::Vector:0x0001 @x=75.0, @y=75.0, @z=75.0, @weight=0>
- #
- # @param other [CyberarmEngine::Vector | Integer | Float] value to subtract from
- # @param factor [Float] how complete transition to _other_ is, in range [0.0..1.0]
- # @return [CyberarmEngine::Vector]
- def lerp(other, factor)
- (self - other) * factor.clamp(0.0, 1.0)
- end
-
- # 2D distance using X and Y
- # @return [Float]
- def distance(other)
- Math.sqrt((@x - other.x)**2 + (@y - other.y)**2)
- end
-
- # 2D distance using X and Z
- # @return [Float]
- def gl_distance2d(other)
- Math.sqrt((@x - other.x)**2 + (@z - other.z)**2)
- end
-
- # 3D distance using X, Y, and Z
- # @return [Float]
- def distance3d(other)
- Math.sqrt((@x - other.x)**2 + (@y - other.y)**2 + (@z - other.z)**2)
- end
-
- # Converts {Vector} to Array
- # @return [Array]
- def to_a
- [@x, @y, @z, @weight]
- end
-
- # Converts {Vector} to String
- # @return [String]
- def to_s
- "X: #{@x}, Y: #{@y}, Z: #{@z}, Weight: #{@weight}"
- end
-
- # Converts {Vector} to Hash
- # @return [Hash]
- def to_h
- { x: @x, y: @y, z: @z, weight: @weight }
- end
- end
-end
+module CyberarmEngine
+ class Vector
+ ##
+ # Creates a up vector
+ #
+ # Vector.new(0, 1, 0)
+ #
+ # @return [CyberarmEngine::Vector]
+ def self.up
+ Vector.new(0, 1, 0)
+ end
+
+ ##
+ # Creates a down vector
+ #
+ # Vector.new(0, -1, 0)
+ #
+ # @return [CyberarmEngine::Vector]
+ def self.down
+ Vector.new(0, -1, 0)
+ end
+
+ ##
+ # Creates a left vector
+ #
+ # Vector.new(-1, 0, 0)
+ #
+ # @return [CyberarmEngine::Vector]
+ def self.left
+ Vector.new(-1, 0, 0)
+ end
+
+ ##
+ # Creates a right vector
+ #
+ # Vector.new(1, 0, 0)
+ #
+ # @return [CyberarmEngine::Vector]
+ def self.right
+ Vector.new(1, 0, 0)
+ end
+
+ ##
+ # Creates a forward vector
+ #
+ # Vector.new(0, 0, 1)
+ #
+ # @return [CyberarmEngine::Vector]
+ def self.forward
+ Vector.new(0, 0, 1)
+ end
+
+ ##
+ # Creates a backward vector
+ #
+ # Vector.new(0, 0, -1)
+ #
+ # @return [CyberarmEngine::Vector]
+ def self.backward
+ Vector.new(0, 0, -1)
+ end
+
+ attr_accessor :x, :y, :z, :weight
+
+ def initialize(x = 0, y = 0, z = 0, weight = 0)
+ @x = x
+ @y = y
+ @z = z
+ @weight = weight
+ end
+
+ alias w weight
+ alias w= weight=
+
+ # @return [Boolean]
+ def ==(other)
+ if other.is_a?(Numeric)
+ @x == other &&
+ @y == other &&
+ @z == other &&
+ @weight == other
+ elsif other.is_a?(Vector)
+ @x == other.x &&
+ @y == other.y &&
+ @z == other.z &&
+ @weight == other.weight
+ else
+ other == self
+ end
+ end
+
+ # Create a new vector using {x} and {y} values
+ # @return [CyberarmEngine::Vector]
+ def xy
+ Vector.new(@x, @y)
+ end
+
+ # Performs math operation, excluding {weight}
+ private def operator(function, other)
+ if other.is_a?(Numeric)
+ Vector.new(
+ @x.send(:"#{function}", other),
+ @y.send(:"#{function}", other),
+ @z.send(:"#{function}", other)
+ )
+ else
+ Vector.new(
+ @x.send(:"#{function}", other.x),
+ @y.send(:"#{function}", other.y),
+ @z.send(:"#{function}", other.z)
+ )
+ end
+ end
+
+ # Adds Vector and Numeric or Vector and Vector, excluding {weight}
+ # @return [CyberarmEngine::Vector]
+ def +(other)
+ operator("+", other)
+ end
+
+ # Subtracts Vector and Numeric or Vector and Vector, excluding {weight}
+ # @return [CyberarmEngine::Vector]
+ def -(other)
+ operator("-", other)
+ end
+
+ # Multiplies Vector and Numeric or Vector and Vector, excluding {weight}
+ # @return [CyberarmEngine::Vector]
+ def *(other)
+ operator("*", other)
+ end
+
+ def multiply_transform(transform)
+ e = transform.elements
+
+ x = @x * e[0] + @y * e[1] + @z * e[2] + 1 * e[3]
+ y = @x * e[4] + @y * e[5] + @z * e[6] + 1 * e[7]
+ z = @x * e[8] + @y * e[9] + @z * e[10] + 1 * e[11]
+ w = @x * e[12] + @y * e[13] + @z * e[14] + 1 * e[15]
+
+ Vector.new(x / 1, y / 1, z / 1, w / 1)
+ end
+
+ # Divides Vector and Numeric or Vector and Vector, excluding {weight}
+ # @return [CyberarmEngine::Vector]
+ def /(other)
+ # Duplicated to protect from DivideByZero
+ if other.is_a?(Numeric)
+ Vector.new(
+ (@x == 0 ? 0 : @x / other),
+ (@y == 0 ? 0 : @y / other),
+ (@z == 0 ? 0 : @z / other)
+ )
+ else
+ Vector.new(
+ (@x == 0 ? 0 : @x / other.x),
+ (@y == 0 ? 0 : @y / other.y),
+ (@z == 0 ? 0 : @z / other.z)
+ )
+ end
+ end
+
+ # dot product of {Vector}
+ # @return [Integer|Float]
+ def dot(other)
+ product = 0
+
+ a = to_a
+ b = other.to_a
+
+ 3.times do |i|
+ product += (a[i] * b[i])
+ end
+
+ product
+ end
+
+ # cross product of {Vector}
+ # @return [CyberarmEngine::Vector]
+ def cross(other)
+ a = to_a
+ b = other.to_a
+
+ Vector.new(
+ b[2] * a[1] - b[1] * a[2],
+ b[0] * a[2] - b[2] * a[0],
+ b[1] * a[0] - b[0] * a[1]
+ )
+ end
+
+ # returns degrees
+ # @return [Float]
+ def angle(other)
+ Math.acos(normalized.dot(other.normalized)) * 180 / Math::PI
+ end
+
+ # returns magnitude of Vector, ignoring #weight
+ # @return [Float]
+ def magnitude
+ Math.sqrt((@x * @x) + (@y * @y) + (@z * @z))
+ end
+
+ ##
+ # returns normalized {Vector}
+ #
+ # @example
+ # CyberarmEngine::Vector.new(50, 21.2, 45).normalized
+ # # => <CyberarmEngine::Vector:0x001 @x=0.7089... @y=0.3005... @z=0.6380... @weight=0>
+ #
+ # @return [CyberarmEngine::Vector]
+ def normalized
+ mag = magnitude
+ self / Vector.new(mag, mag, mag)
+ end
+
+ # returns a direction {Vector}
+ #
+ # z is pitch
+ #
+ # y is yaw
+ #
+ # x is roll
+ # @return [CyberarmEngine::Vector]
+ def direction
+ _x = -Math.sin(@y.degrees_to_radians) * Math.cos(@z.degrees_to_radians)
+ _y = Math.sin(@z.degrees_to_radians)
+ _z = Math.cos(@y.degrees_to_radians) * Math.cos(@z.degrees_to_radians)
+
+ Vector.new(_x, _y, _z)
+ end
+
+ # returns an inverse {Vector}
+ # @return [CyberarmEngine::Vector]
+ def inverse
+ Vector.new(1.0 / @x, 1.0 / @y, 1.0 / @z)
+ end
+
+ # Adds up values of {x}, {y}, and {z}
+ # @return [Integer|Float]
+ def sum
+ @x + @y + @z
+ end
+
+ ##
+ # Linear interpolation: smoothly transition between two {Vector}
+ #
+ # CyberarmEngine::Vector.new(100, 100, 100).lerp( CyberarmEngine::Vector.new(0, 0, 0), 0.75 )
+ # # => <CyberarmEngine::Vector:0x0001 @x=75.0, @y=75.0, @z=75.0, @weight=0>
+ #
+ # @param other [CyberarmEngine::Vector | Integer | Float] value to subtract from
+ # @param factor [Float] how complete transition to _other_ is, in range [0.0..1.0]
+ # @return [CyberarmEngine::Vector]
+ def lerp(other, factor)
+ (self - other) * factor.clamp(0.0, 1.0)
+ end
+
+ # 2D distance using X and Y
+ # @return [Float]
+ def distance(other)
+ Math.sqrt((@x - other.x)**2 + (@y - other.y)**2)
+ end
+
+ # 2D distance using X and Z
+ # @return [Float]
+ def gl_distance2d(other)
+ Math.sqrt((@x - other.x)**2 + (@z - other.z)**2)
+ end
+
+ # 3D distance using X, Y, and Z
+ # @return [Float]
+ def distance3d(other)
+ Math.sqrt((@x - other.x)**2 + (@y - other.y)**2 + (@z - other.z)**2)
+ end
+
+ # Converts {Vector} to Array
+ # @return [Array]
+ def to_a
+ [@x, @y, @z, @weight]
+ end
+
+ # Converts {Vector} to String
+ # @return [String]
+ def to_s
+ "X: #{@x}, Y: #{@y}, Z: #{@z}, Weight: #{@weight}"
+ end
+
+ # Converts {Vector} to Hash
+ # @return [Hash]
+ def to_h
+ { x: @x, y: @y, z: @z, weight: @weight }
+ end
+ end
+end