aboutsummaryrefslogtreecommitdiff
path: root/src/main/scala/sims/dynamics/Body.scala
blob: 52624680de89f841542be2a3cccf688b9a19a4c2 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
/*    _____ _ __  ________    ___                                      *\
**   / ___/(_)  |/  / ___/   |__ \  Simple Mechanics Simulator 2       **
**   \__ \/ / /|_/ /\__ \    __/ /  copyright (c) 2011 Jakob Odersky   **
**  ___/ / / /  / /___/ /   / __/                                      **
** /____/_/_/  /_//____/   /____/                                      **
\*                                                                     */

package sims.dynamics

import sims.math._

class Body(shapes0: Shape*) {
	
	val shapes: List[Shape] = shapes0.toList
	
	var force: Vector2D = Vector2D.Null
	
	var torque: Double = 0.0
	
	var linearVelocity: Vector2D = Vector2D.Null
	
	var angularVelocity: Double = 0.0 
	
	private var _position: Vector2D = 
		(Vector2D.Null /: shapes)((v: Vector2D, s: Shape) => v + s.position * s.mass) / shapes.map(_.mass).sum
	
	def position = _position
	
	def position_=(pos: Vector2D) = {
		val delta = pos - _position
		_position = pos
		for (s <- shapes) s.position += delta
	}
	
	private var _rotation: Double = 0.0
	
	def rotation = _rotation
	
	def rotation_=(r: Double) = {
		val delta = _rotation - r
		_rotation = r
		for (s <- shapes) {
			s.rotation += delta
			s.position = position + (s.local.get rotate r)
		} 
	}
	
	var fixed = false
	
	/**Returns the mass of this body. If the body is free, its mass is the sum of the masses of its shapes.
 	* If the body is fixed, its mass is infinite (`Double.PositiveInfinity`).
 	* @return this body's mass*/
 	lazy val mass: Double = if (!fixed) shapes.map(_.mass).sum else Double.PositiveInfinity
 	
 	/**Returns the moment of inertia for rotations about the COM of this body.
 	* It is calculated using the moments of inertia of this body's shapes and the parallel axis theorem.
 	* If the body is fixed, its moment of inertia is infinite (`Double.PositiveInfinity`).
 	* @return moment of inertia for rotations about the center of mass of this body*/
 	lazy val inertia: Double = if (!fixed) shapes.map((s: Shape) => s.inertia + s.mass * (s.local.get dot s.local.get)).sum else Double.PositiveInfinity
 	
 	/**Applies a force to the center of mass of this body.
   * @param force applied force*/
  def applyForce(force: Vector2D) = if (!fixed) this.force += force
  
  /**Applies a force to a point on this body. The point is considered to be contained within this body.
   * @param force applied force
   * @param point position vector of the point (in world coordinates)*/
  def applyForce(force: Vector2D, point: Vector2D) = if (!fixed) {this.force += force; torque += (point - position) cross force}
	
	/**Applies a torque to the center of mass.*/
	def applyTorque(torque: Double) = if (!fixed) this.torque += torque
	
	/**Applies an impulse to the center of mass of this body.
   * @param impulse applied impulse*/  
  def applyImpulse(impulse: Vector2D) = if (!fixed) linearVelocity += impulse / mass
  
  /**Applies an impulse to a point on this body. The point is considered to be contained within this body.
   * @param impulse applied impulse
   * @param point position vector of the point (in world coordinates)*/
  def applyImpulse(impulse: Vector2D, point: Vector2D) = if (!fixed) {linearVelocity += impulse / mass; angularVelocity += ((point - position) cross impulse) / inertia}
  
  /**Applies an angular impulse to the center of mass.*/
  def applyAngularImpulse(impulse: Double) = if (!fixed) angularVelocity += impulse / inertia
  
  /**Linear velocity of the given point on this body (in world coordinates).*/
  def velocityOfPoint(point: Vector2D) = linearVelocity + (angularVelocity cross (point - position))
  
  /**Linear momentum.*/
  def linearMomentum = linearVelocity * mass  
  
 	for (s0 <- shapes0) {
 		s0.local = Some(s0.position - _position)
 		s0.body = this
 	}
  
  def contains(point: Vector2D) = shapes.exists(_.contains(point))
  
  def info = {
  	"Body@" + hashCode + "(" + this.getClass() + ")\n" +  
  			"\tPosition: " + position + "\n" + 
  			"\tRotation: " + rotation + "\n" + 
  			"\tLinear velocity: " + linearVelocity + "\n" + 
  			"\tAngular velocity: " + angularVelocity + "\n" +
  			"\tForce: " + force + "\n" +
  			"\tTorque: " + torque + "\n" +
  			"\tMass: " + mass + "\n" +
  			"\tInertia: " + inertia + "\n" +
  			"\tFixed: " + fixed + "\n" +
  			"\tShape count" + shapes.length
  			
  }
 	
}