/*
* Simple Mechanics Simulator (SiMS)
* copyright (c) 2009 Jakob Odersky
* made available under the MIT License
*/
package sims.collision
import sims.dynamics._
import sims.geometry._
import scala.collection._
import scala.collection.mutable._
/**A conrete implementation of Detector
. GridDetector
divides the world into a grid
* for faster collision detection.*/
class GridDetector(override val world: World) extends Detector {
/**Array of collision detection methods. These methods return true
if two shapes are colliding.*/
val detectionMethods = new ArrayBuffer[PartialFunction[(Shape, Shape), Boolean]]
detectionMethods += {
case (c1: Circle, c2: Circle) => { //Kollision wenn Distanz <= Summe der Radien
val d = (c1.pos - c2.pos).length
val rSum = c1.radius + c2.radius
d - rSum <= 0
}
case (p1: ConvexPolygon, p2: ConvexPolygon) => { //SAT
val sides = p1.sides ++ p2.sides
val axes = sides map (_.n0)
axes.forall((a: Vector2D) => p1.project(a) overlaps p2.project(a))
}
case (p: ConvexPolygon, c: Circle) => { //Distanz von Zentrum zu Seiten oder Eckpunkten
val distances = for (s <- p.sides) yield (s distance c.pos)
distances.exists(_ - c.radius <= 0) || (p contains c.pos)
}
case (c: Circle, p: ConvexPolygon) => { //Distanz von Zentrum zu Seiten oder Eckpunkten
val distances = for (s <- p.sides) yield (s distance c.pos)
distances.exists(_ - c.radius <= 0) || (p contains c.pos)
}
}
/**Array of methods returning collisions. It is assumed that both shapes are colliding.*/
val collisionMethods = new ArrayBuffer[PartialFunction[(Shape, Shape), Collision]]
collisionMethods += {
case (c1: Circle, c2: Circle) => CircleCollision(c1, c2)
case (p1: ConvexPolygon, p2: ConvexPolygon) => PolyCollision(p1, p2)
case (p: ConvexPolygon, c: Circle) => PolyCircleCollision(p, c)
case (c: Circle, p: ConvexPolygon) => PolyCircleCollision(p, c)
}
/**Checks the pair of shapes p
for collision.
* @param p Pair of shapes.*/
def colliding(p: Pair) = {
if (detectionMethods.exists(_.isDefinedAt(p)))
detectionMethods.find(_.isDefinedAt(p)).get.apply(p)
else throw new IllegalArgumentException("No collision method for colliding pair!")
}
/**Returns the collision between both shapes of the pair p
.
* @param p Pair of shapes.*/
def collision(p: Pair): Collision = {
if (collisionMethods.exists(_.isDefinedAt(p)))
collisionMethods.find(_.isDefinedAt(p)).get.apply(p)
else throw new IllegalArgumentException("No collision found in colliding pair!")
}
/**Width and height of a grid cell.*/
var gridSide: Double = 2
/**Returns potential colliding pairs of shapes of the world world
.
*
* A potential colliding pair is a pair of two shapes that comply with the following criteria: *