lighttroupe/luz

View on GitHub
utils/vector3.rb

Summary

Maintainability
A
3 hrs
Test Coverage
class Vector3
    attr_accessor :x, :y, :z

    def self.new_from_string(str)
        x, y, z = str.split(',').collect { |v| v.to_f }
        self.new(x, y, z)
    end

    def initialize(x=0.0, y=0.0, z=0.0)
        set(x, y, z)
    end

    def set(x, y=nil, z=nil)
        if y && z
            @x, @y, @z = x, y, z
        else
            @x, @y, @z = x.x, x.y, x.z        # treat x as a point
        end
        self
    end

    def ==(point)
        return false unless point.is_a? Vector3
        @x == point.x && @y == point.y && @z == point.z
    end

    def -(point)
        Vector3.new(x - point.x, y - point.y, z - point.z)
    end

    def +(point)
        Vector3.new(x + point.x, y + point.y, z + point.z)
    end

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

    def *(float)
        Vector3.new(x * float, y * float, z * float)
    end

    def /(float)
        Vector3.new(x / float, y / float, z / float)
    end

    def dot(point)
        (point.x * @x) + (point.y * @y) + (point.z * @z)
    end

    def cross(point)
        Vector3.new(@y * point.z - @z * point.y, @z * point.x - @x * point.z, @x * point.y - @y * point.x)
    end

    def unit
        l = self.length
        return Vector3.new if l == 0.0
        Vector3.new(x / l, y / l, z / l)
    end

    def normalize!
        l = self.length
        return set(0.0,0.0,0.0) if l == 0.0
        return set(x / l, y / l, z / l)
    end

    def normalize
        l = self.length
        return set(0.0,0.0,0.0) if l == 0.0
        return set(x / l, y / l, z / l)
    end

    def length
        (x.squared + y.squared + z.squared).square_root
    end

    def distance_to(point)
        ((@x - point.x).squared + (@y - point.y).squared + (@z - point.z).squared).square_root
    end

    def distance_squared_to(point)
        ((@x - point.x).squared + (@y - point.y).squared + (@z - point.z).squared)
    end

    def distance_to_within?(point, distance)
        ((@x - point.x)**2 + (@y - point.y)**2 + (@z - point.z)**2) < (distance**2)
    end

    def vector_to(point)
        (point - self)
    end

    def to_vector
        Vector.new(:x => @x, :y => @y, :z => @z)
    end

    def zero?
        @x == 0.0 && @y == 0.0 && @z == 0.0
    end

    def to_s
        "#{@x}, #{@y}, #{@z}"
    end

    def left
        Vector3.new(@y, -@x, @z)
    end

    TWO_PI = (Math::PI * 2.0)
    def fuzzy_angle
        return 0.0 if (@x == 0.0 && @y == 0.0)
        Math.atan2(@x, @y) / (TWO_PI) % 1.0
    end
end