blob: d5b2a0edc57ca6822041858fb5888398ea7b121f (
plain) (
tree)
|
|
/*
* Simple Mechanics Simulator (SiMS)
* copyright (c) 2009 Jakob Odersky
* made available under the MIT License
*/
package sims.dynamics
import sims.geometry._
import sims.dynamics.joints._
/**Ein 2-Dimensionaler Koerper besteht aus mehreren Formen. Im gegensatz zu letzteren, enthaelt ein Koerper dynamische Informationen (v, F, etc...).
* @param shps zu dem Koerper gehoerende Formen.*/
class Body(shps: Shape*){
/**Einzigartige Identifikationsnummer dieses Koerpers.*/
val uid = Body.nextUid
/**Formen aus denen dieser Koerper besteht.*/
val shapes: List[Shape] = shps.toList
//Formen werden bei Initialisierung eingefuegt
for (s <- shapes) {
s.body = this
s.refLocalPos = s.pos - pos
s.rotation0 = s.rotation
}
private var isFixed: Boolean = false
/**Gibt an ob dieser Koerper fixiert ist.*/
def fixed = isFixed
/**Fixiert oder unfixiert diesen Koerper.*/
def fixed_=(value: Boolean) = {
if (value) {linearVelocity = Vector2D.Null; angularVelocity = 0.0}
isFixed = value
}
/**Gibt an ob die Eigenschaften dieses Koerpers ueberwacht werden sollen.
* @see World#monitors*/
var monitor: Boolean = false
/**Ermittelt die Position dieses Koerpers. Die Position entspricht dem Schwerpunkt.
* @return Position dieses Koerpers*/
def pos: Vector2D = // Shwerpunkt = sum(pos*mass)/M
(Vector2D.Null /: shapes)((v: Vector2D, s: Shape) => v + s.pos * s.mass) /
(0.0 /: shapes)((i: Double, s: Shape) => i + s.mass)
/**Setzt die Position dieses Koerpers und verschiebt dadurch die Positionen seiner Formen.
* @param newPos neue Position*/
def pos_=(newPos: Vector2D) = {
val stepPos = pos
shapes.foreach((s: Shape) => s.pos = s.pos - stepPos + newPos)
}
/**Enthaelt die aktuelle Rotation dieses Koerpers.*/
private var _rotation: Double = 0.0 //shapes(0).rotation
/**Ergibt die aktuelle Rotation dieses Koerpers.
* @return aktuelle Rotation dieses Koerpers*/
def rotation: Double = _rotation
/**Setzt die Rotation dieses Koerpers. Dazu werden auch die Positionen und Rotationen seiner Formen entsprechend veraendert.
* @param r neue Rotation*/
def rotation_=(newRotation: Double) = {
_rotation = newRotation
val stepPos = pos
for (s <- shapes) {
s.rotation = newRotation + s.rotation0
s.pos = stepPos + (s.refLocalPos rotate (newRotation))
}
}
/**Lineargeschwindigkeit dieses Koerpers.*/
var linearVelocity: Vector2D = Vector2D.Null
/**Winkelgeschwindigkeit dieses Koerpers.*/
var angularVelocity: Double = 0
/**Lineargeschwindigkeit des gegebenen Punktes auf diesem Koerper. In Weltkoordinaten.*/
def velocityOfPoint(point: Vector2D) = linearVelocity + ((point - pos).leftNormal * angularVelocity)
/**Resultierende Kraft auf den Schwerpunkt dieses Koerpers.*/
var force: Vector2D = Vector2D.Null
/**Resultierender Drehmoment zu dem Schwerpunkt dieses Koerpers.*/
var torque: Double = 0
/**Ergibt die Masse dieses Koerpers. Die Masse ist gleich die Summe aller Massen seiner Formen.
* @return Masse des Koerpers*/
def mass: Double = if (fixed) Double.PositiveInfinity else (0.0 /: shapes)((i: Double, s: Shape) => i + s.mass)
/**Ergibt den Traegheitsmoment zu dem Schwerpunkt dieses Koerpers. Der Traegheitsmoment wird mit Hilfe des Steinerschen Satzes errechnet.
* @return Traegheitsmoment relativ zu dem Schwerpunkt dieses Koerpers*/
def I: Double = if (fixed) Double.PositiveInfinity else
(0.0 /: (for (s <- shapes) yield (s.I + s.mass * ((s.pos - pos) dot (s.pos - pos)))))(_+_)
/**Wendet eine Kraft auf den Schwerpunkt dieses Koerpers an.
* @param force anzuwendender Kraftvektor*/
def applyForce(force: Vector2D) = if (!fixed) this.force += force
/**Wendet eine Kraft auf einen Punkt dieses Koerpers an. Achtung: der gegebene Punkt wird nicht auf angehoerigkeit dieses
* Koerpers ueberprueft.
* @param force anzuwendender Kraftvektor
* @param point Ortsvektor des Punktes auf den die Kraft wirken soll (gegeben in Weltkoordinaten).*/
def applyForce(force: Vector2D, point: Vector2D) = if (!fixed) {this.force += force; torque += (point - pos) cross force}
/**Wendet einen Impuls auf den Schwerpunkt dieses Koerpers an.
* @param impulse anzuwendender Impulsvektor*/
def applyImpulse(impulse: Vector2D) = if (!fixed) linearVelocity += impulse / mass
/**Wendet einen Impuls auf einen Punkt dieses Koerpers an. Achtung: der gegebene Punkt wird nicht auf angehoerigkeit dieses
* Koerpers ueberprueft.
* @param impulse anzuwendender Impulsvektor
* @param point Ortsvektor des Punktes auf den der Impuls wirken soll (gegeben in Weltkoordinaten).*/
def applyImpulse(impulse: Vector2D, point: Vector2D) = if (!fixed) {linearVelocity += impulse / mass; angularVelocity += ((point - pos) cross impulse) / I}
/**Ueberprueft ob der gegebene Punkt <code>point</code> sich in diesem Koerper befindet.*/
def contains(point: Vector2D) = shapes.exists(_.contains(point))
override def toString: String = {
"Body" + uid + " " + shapes + " fixed=" + fixed + " m=" + mass + " I=" + I + " pos=" + pos + " rot=" + rotation + " v=" + linearVelocity + " w=" + angularVelocity + " F=" + force + " tau=" + torque
}
/**Erstellt einen neuen Koerper der zusaetzlich die Form <code>s</code> enthaelt.
* @param s zusaetzliche Form
* @return neuer Koerper*/
def ^(s: Shape) = new Body((s :: shapes): _*)
/**Erstellt einen neuen Koerper der zusaetzlich die Formen von dem Koerper <code>b</code> enthaelt.
* @param b Koerper mit zusaetzlichen Formen
* @return neuer Koerper*/
def ^(b: Body) = {
val shapes = this.shapes ::: b.shapes
new Body(shapes: _*)
}
}
object Body {
private var uidCounter = -1
private def nextUid = {uidCounter += 1; uidCounter}
}
|