funfriend/src/vec2.cr

182 lines
3.3 KiB
Crystal

require "math"
include Math
module Funfriend
struct Vec2
property x : Float64
property y : Float64
def initialize(@x = 0.0, @y = 0.0)
end
def initialize(xy : Int32)
@x = @y = xy
end
def initialize(xy : Float64)
@x = @y = xy
end
def initialize(xy : NamedTuple(x: Int32, y: Int32))
initialize(xy[:x], xy[:y])
end
def initialize(xy : NamedTuple(x: Float64, y: Float64))
initialize(xy[:x], xy[:y])
end
def initialize(wh : NamedTuple(width: Int32, height: Int32))
initialize(wh[:width], wh[:height])
end
# swizzles
def xy
{x: @x, y: @y}
end
def yx
{x: @y, y: @x}
end
# int swizzles
def xy_i
{x: @x.to_i, y: @y.to_i}
end
def yx_i
{x: @y.to_i, y: @x.to_i}
end
def x_i
x.to_i
end
def y_i
y.to_i
end
# simpler swizzle
def values
{x, y}
end
def dot(other : Vec2)
x * other.x + y * other.y
end
def cross(other : Vec2)
Vec2.new(
self.x * other.y - self.y * other.x,
self.y * other.x - self.x * other.y
)
end
def angle
atan2(y, x)
end
def len
sqrt(x ** 2 + y ** 2)
end
def square_len
x ** 2 + y ** 2
end
def angle(other : Vec2)
self ** other / (self.length * other.length)
end
def +(other : Vec2)
Vec2.new(self.x + other.x, self.y + other.y)
end
def +(other : Number)
Vec2.new(self.x + other, self.y + other)
end
def -(other : Vec2)
Vec2.new(self.x - other.x, self.y - other.y)
end
def -(other : Number)
Vec2.new(self.x - other, self.y - other)
end
def -
Vec2.new(-self.x, -self.y)
end
def *(other : Vec2)
Vec2.new(self.x * other.x, self.y * other.y)
end
def *(other : Number)
Vec2.new(self.x * other, self.y * other)
end
def /(other : Vec2)
Vec2.new(self.x / other.x, self.y / other.y)
end
def /(other : Number)
Vec2.new(self.x / other, self.y / other)
end
def clone
Vec2.new(self.x, self.y)
end
def normalize!
m = length
unless m == 0
inverse = 1.0 / m
self.x *= inverse
self.y *= inverse
end
self
end
def normalize
clone.normalize!
end
def scale!(scale : Float64)
normalize!
self.x *= scale
self.y *= scale
end
def scale(scale : Float64)
clone.scale!(scale)
end
def dist(other : Vec2)
(self - other).len
end
def square_dist(other : Vec2)
(self - other).square_len
end
def ==(other : Vec2)
self.x == other.x && self.y == other.y
end
def !=(other : Vec2)
self.x != other.x || self.y != other.y
end
def to_s(io : IO)
io << "(#{x}, #{y})"
end
def inspect(io : IO)
io << "(x: #{x.inspect}, y: #{y.inspect})"
end
def self.zero
Vec2.new(0.0)
end
def self.additive_identity
Vec2.new(0.0)
end
def self.multiplicative_identity
Vec2.new(1.0)
end
def self.from_polar(angle : Float64, length : Float64)
Vec2.new(cos(angle) * length, sin(angle) * length)
end
def self.rand(length : Range = (0 .. 1))
from_polar((0..360).sample, length.sample)
end
end
end