Skip to content

Instantly share code, notes, and snippets.

@kaffepanna
Created September 2, 2016 13:06
Show Gist options
  • Save kaffepanna/948bb80ef7038a5fbda1a4171a07ccdf to your computer and use it in GitHub Desktop.
Save kaffepanna/948bb80ef7038a5fbda1a4171a07ccdf to your computer and use it in GitHub Desktop.
package se.randomserver.math
class DimensionError extends Error
trait VecFactory[V[_]] {
def apply[T](s: T*)(implicit num: VecIntegral[T]): V[T]
}
abstract sealed class Vec[T, V[T] <: Vec[T, V]](val elems: T*)(implicit num: VecIntegral[T], factory: VecFactory[V]) {
import num._
def +(v: V[T]): V[T] = factory(elems.zip(v.elems).map { case (a, b) => a + b }:_*)
def -(v: V[T]): V[T] = this + (-v)
def cross(v: V[T]): V[T]
def dot(v: V[T]): T = elems.zip(v.elems).map { case (a,b) => a * b }.sum
def unary_-(): V[T] = map(_.unary_-())
def *(scalar: T): V[T] = map(_ * scalar)
def abs: T = sqrt(elems.map(a => a * a).sum)
def *(v: V[T]): V[T] = cross(v)
def apply(n: Int): T = elems(n)
def map[C](f: T => C)(implicit n: VecIntegral[C], fa: VecFactory[V]): V[C] = fa(elems.map(f):_*)
override def toString: String = elems.mkString("[", ", ", "]")
}
class Vec2[T](x: T, y: T)(implicit num: VecIntegral[T]) extends Vec[T, Vec2](x,y) {
override def cross(v: Vec2[T]): Vec2[T] = throw new DimensionError
}
object Vec2 {
implicit val factory: VecFactory[Vec2] = new VecFactory[Vec2] {
override def apply[T](s: T*)(implicit num: VecIntegral[T]): Vec2[T] = s match {
case Seq(x,y) => new Vec2[T](x,y)
case _ => throw new DimensionError
}
}
def apply[T](elems: T*)(implicit num: VecIntegral[T]): Vec2[T] = factory(elems:_*)
}
class Vec3[T](x: T, y: T, z: T)(implicit num: VecIntegral[T]) extends Vec[T, Vec3](x,y, z) {
import num._
override def cross(v: Vec3[T]): Vec3[T] = v match {
case Vec(bx,by, bz) => new Vec3[T](y * bz - z * by,
z * bx - x * bz,
x * by - y * bx)
case _ => throw new DimensionError
}
}
object Vec3 {
implicit val factory: VecFactory[Vec3] = new VecFactory[Vec3] {
override def apply[T](s: T*)(implicit num: VecIntegral[T]): Vec3[T] = s match {
case Seq(x,y,z) => new Vec3[T](x,y,z)
case _ => throw new DimensionError
}
}
def apply[T](elems: T*)(implicit num: VecIntegral[T]): Vec3[T] = factory(elems:_*)
}
object Vec {
def unapplySeq[T, V[T] <: Vec[T, V]](v: Vec[T, V]): Option[Seq[T]] = Some(v.elems)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment