diff options
author | Jakob Odersky <jodersky@gmail.com> | 2011-08-26 20:29:25 +0200 |
---|---|---|
committer | Jakob Odersky <jodersky@gmail.com> | 2011-08-26 20:29:25 +0200 |
commit | 2750bc0277c3d929603daceee2e8a1e88368a306 (patch) | |
tree | 2db8bdecf84971e550bacb7737a1c19ababb87df /src/test/scala/sims/test/gui | |
download | sims2-2750bc0277c3d929603daceee2e8a1e88368a306.tar.gz sims2-2750bc0277c3d929603daceee2e8a1e88368a306.tar.bz2 sims2-2750bc0277c3d929603daceee2e8a1e88368a306.zip |
import from local directory
Diffstat (limited to 'src/test/scala/sims/test/gui')
18 files changed, 876 insertions, 0 deletions
diff --git a/src/test/scala/sims/test/gui/DebugWorld.scala b/src/test/scala/sims/test/gui/DebugWorld.scala new file mode 100644 index 0000000..937bd77 --- /dev/null +++ b/src/test/scala/sims/test/gui/DebugWorld.scala @@ -0,0 +1,29 @@ +package sims.test.gui + +class DebugWorld extends sims.dynamics.World with Publisher { + + override def +=(b: sims.dynamics.Body) = { + super.+=(b) + publish(BodyAdded(this, b)) + } + + override def -=(b: sims.dynamics.Body) = { + super.-=(b) + publish(BodyRemoved(this, b)) + } + + override def +=(j: sims.dynamics.Joint) = { + super.+=(j) + publish(JointAdded(this, j)) + } + + override def -=(j: sims.dynamics.Joint) = { + super.-=(j) + publish(JointRemoved(this, j)) + } + + override def step() = { + super.step() + publish(Stepped(this)) + } +}
\ No newline at end of file diff --git a/src/test/scala/sims/test/gui/KeyManager.scala b/src/test/scala/sims/test/gui/KeyManager.scala new file mode 100644 index 0000000..f7cc199 --- /dev/null +++ b/src/test/scala/sims/test/gui/KeyManager.scala @@ -0,0 +1,53 @@ +package sims.test.gui + +import processing.core.PApplet + +class KeyManager(implicit top: Main) { + + def keyPressed(keyCode: Int) = keyCode match { + // ENTER + case 10 => top.SceneManager.currentScene.world.step() + + // SPACE + case 32 => top.paused = !top.paused + + // PAGE UP + case 33 => top.viewScale += top.viewScale * 0.02f + + // PAGE DOWN + case 34 => top.viewScale -= top.viewScale * 0.02f + + // 0 + case 36 => {top.offsetX = 0; top.offsetY = 0} + + // LEFT + case 37 => top.offsetX += 50 + + // UP + case 38 => top.offsetY -= 50 + + // RIGHT + case 39 => top.offsetX -= 50 + + // DOWN + case 40 => top.offsetY += 50 + + // , (<) + case 44 => top.SceneManager.previousScene() + + // . (>) + case 46 => top.SceneManager.nextScene() + + // b + case 66 => top.SceneManager.currentScene.world.errorReduction += 0.1 + + //v + case 86 => top.SceneManager.currentScene.world.errorReduction -= 0.1 + + case 45 => top.SceneManager.currentScene.world.iterations -= 1 + case 61 => top.SceneManager.currentScene.world.iterations += 1 + + case x: Any => println("unknown key: " + x) + } + +}
\ No newline at end of file diff --git a/src/test/scala/sims/test/gui/Main.scala b/src/test/scala/sims/test/gui/Main.scala new file mode 100644 index 0000000..745d793 --- /dev/null +++ b/src/test/scala/sims/test/gui/Main.scala @@ -0,0 +1,143 @@ +package sims.test.gui + +import processing.core.PApplet +import processing.core.PConstants._ +import scala.collection.mutable.ArrayBuffer + +import sims.math._ +import sims.test.gui.RichShape._ +import sims.test.gui.scenes._ +import sims.dynamics.Shape + +class Main extends PApplet { + implicit val top = this + + val SceneManager = new SceneManager + import SceneManager._ + + val KeyManager = new KeyManager + import KeyManager._ + + var (offsetX, offsetY) = (200.0f, 100.0f) + val PPM = 39.37f * 96 + var viewScale: Float = 1.0f / 80 + + private val fontSize = 16 + private val f = createFont("Monospaced.plain", fontSize) + private def displayText(lines: String*) = { + val size = 16 + val indent = 10 + + fill(0, 0, 0) + textMode(SCREEN) + textFont(f) + + for (i <- 0 until lines.length) text(lines(i), indent, (i + 1) * size) + } + + + override def setup() = { + size(screenWidth * 2 / 3, screenHeight * 2 / 3, P2D) + background(255,255,255) + frameRate(60) + //frame.setResizable(true) + currentScene = scenes(0) + } + + var paused = true + override def draw() = { + smooth() + background(255,255,255) + + translate(offsetX, height - offsetY) + scale(viewScale * PPM, -viewScale * PPM) + + val t0 = System.nanoTime() + if (!paused) currentScene.world.step() + val collisions = if (currentScene.world.collisionDetection) SceneManager.currentScene.world.detector.collisions() else Seq() + val dStep = System.nanoTime() - t0 + + for (g <- graphicals) g.render() + fill(255, 0, 0) + stroke(20, 0, 0) + for (c <- collisions; p <- c.points) { + ellipse(p.x.toFloat, p.y.toFloat, 0.1f, 0.1f) + stroke(0, 255, 0) + val s = p + val e = p + c.normal + line(s.x.toFloat, s.y.toFloat, e.x.toFloat, e.y.toFloat) + } + + //_.points.foreach((v) => ellipse(v.x.toFloat, v.y.toFloat, 0.1f, 0.1f))) + + val dRender = System.nanoTime() - t0 - dStep + + displayText( + "status : " + (if (paused) "paused" else "running"), + "------------", + "fps [Hz]: " + frameRate, + "------------", + "step [ms]: " + (dStep / 1E6f), + " [%] : " + (dStep.toFloat / (dStep + dRender) * 100), + "render [ms]: " + (dRender / 1E6f), + " [%] : " + (dRender.toFloat / (dStep + dRender) * 100), + "------------", + "memory [MB]: " + java.lang.Runtime.getRuntime.totalMemory / 1E6, + "load : " + java.lang.management.ManagementFactory.getOperatingSystemMXBean.getSystemLoadAverage(), + "------------", + "bodies : " + currentScene.world.bodies.length, + "shapes : " + currentScene.world.shapes.length, + "joints : " + currentScene.world.joints.length, + "constraints: " + currentScene.world.joints.map(_.constraints.length).sum, + "collisions : " + collisions.length, + "it [1] : " + currentScene.world.iterations, + "dt [ms]: " + currentScene.world.h.toFloat, + "erp [ms]: " + currentScene.world.errorReduction.toFloat, + "------------", + "(" + scaledMouseX + ", " + scaledMouseY + ")" + ) + } + + def drawGrid() = { + + } + + override def keyPressed() = KeyManager.keyPressed(keyCode) + + def scaledMouseX = (mouseX - offsetX) / viewScale / PPM + def scaledMouseY = (height - mouseY - offsetY) / viewScale / PPM + + var mouseJoint: Option[MouseJoint] = None + override def mousePressed(): Unit = { + import Vector2D._ + val body = currentScene.world.bodies.find(_.contains((scaledMouseX, scaledMouseY))) + if (body.isEmpty) return () + val mj = new MouseJoint(body.get, (scaledMouseX, scaledMouseY)) + currentScene.world += mj + mouseJoint = Some(mj) + } + + override def mouseReleased(): Unit = { + if (mouseJoint.isEmpty) return () + currentScene.world -= mouseJoint.get + mouseJoint = None + } + + override def mouseDragged(): Unit = { + import Vector2D._ + + if (mouseJoint.isEmpty) return () + + mouseJoint.get.anchor = (scaledMouseX, scaledMouseY) + + } + + + +} + +object Main { + def main(args : Array[String]) : Unit = { + PApplet.main(args ++ Array("sims.test.gui.Main")) + } +}
\ No newline at end of file diff --git a/src/test/scala/sims/test/gui/MouseJoint.scala b/src/test/scala/sims/test/gui/MouseJoint.scala new file mode 100644 index 0000000..0d74dd5 --- /dev/null +++ b/src/test/scala/sims/test/gui/MouseJoint.scala @@ -0,0 +1,38 @@ +package sims.test.gui + +import sims.dynamics._ +import sims.dynamics.constraints._ +import sims.math._ + +class MouseJoint(val body1: Body, var anchor: Vector2D) extends Joint { + val body2 = new Body() {fixed = true} + + private val self = this + + private val local1 = anchor - body1.position + + private val rotation01 = body1.rotation + + def r1 = (local1 rotate (body1.rotation - rotation01)) + + def x1 = body1.position + r1 + def x2 = anchor + + def x = x2 - x1 + + val constraints = List( + new Constraint { + val body1 = self.body1 + val body2 = self.body2 + def value = x.x + def jacobian = new Jacobian(-Vector2D(1, 0), r1.y, Vector2D.i, 0) + }, + new Constraint { + val body1 = self.body1 + val body2 = self.body2 + def value = x.y + def jacobian = new Jacobian(-Vector2D(0, 1), -r1.x, Vector2D.j, 0) + } + ) + +}
\ No newline at end of file diff --git a/src/test/scala/sims/test/gui/RichJoint.scala b/src/test/scala/sims/test/gui/RichJoint.scala new file mode 100644 index 0000000..2c3d5fd --- /dev/null +++ b/src/test/scala/sims/test/gui/RichJoint.scala @@ -0,0 +1,51 @@ +package sims.test.gui + +import processing.core.PApplet +import processing.core.PConstants._ +import sims.dynamics._ + +class RichJoint(joint: Joint) { +private implicit def double2Float(x: Double): Float = x.toFloat + + def toGraphical(implicit parent: PApplet) = new GraphicalJoint(joint) { + + val top = parent + + val render = joint match { + + case j: DistanceJoint => () => { + top.pushMatrix() + top.stroke(0, 0, 0) + top.fill(0, 0, 0) + top.line(j.x1.x, j.x1.y, j.x2.x, j.x2.y) + top.stroke(100, 100, 100) + top.line(j.body1.position.x, j.body1.position.y, j.x1.x, j.x1.y) + top.line(j.body2.position.x, j.body2.position.y, j.x2.x, j.x2.y) + top.popMatrix() + } + + case j: RevoluteJoint => () => { + top.pushMatrix() + top.stroke(0, 0, 0) + top.fill(0, 0, 0) + top.line(j.x1.x, j.x1.y, j.x2.x, j.x2.y) + top.stroke(100, 100, 100) + top.line(j.body1.position.x, j.body1.position.y, j.x1.x, j.x1.y) + top.line(j.body2.position.x, j.body2.position.y, j.x2.x, j.x2.y) + top.popMatrix() + } + + case j: MouseJoint => () => () + + case _ => throw new IllegalArgumentException("Cannot create graphical joint: unknown joint.") + } + + } + +} + +object RichJoint { + + implicit def jointToRichShape(j: Joint) = new RichJoint(j) + +}
\ No newline at end of file diff --git a/src/test/scala/sims/test/gui/RichShape.scala b/src/test/scala/sims/test/gui/RichShape.scala new file mode 100644 index 0000000..6817ebe --- /dev/null +++ b/src/test/scala/sims/test/gui/RichShape.scala @@ -0,0 +1,49 @@ +package sims.test.gui + +import processing.core.PApplet +import processing.core.PConstants._ +import sims.dynamics._ + +class RichShape(shape: Shape) { + private implicit def double2Float(x: Double): Float = x.toFloat + + def toGraphical(implicit parent: PApplet) = new GraphicalShape(shape) { + + val top = parent + + val render = shape match { + + case c: Circle => () => { + top.pushMatrix() + top.stroke(0, 0, 0) + top.fill(0, 0, 255, 200) + top.translate(c.position.x, c.position.y) + top.rotate(-c.rotation) + top.ellipseMode(CENTER) + top.ellipse(0, 0, c.radius * 2, c.radius * 2) + top.line(0,0, c.radius, 0) + top.popMatrix() + } + + case r: Rectangle => () => { + top.pushMatrix() + top.translate(r.position.x, r.position.y) + top.rotate(-r.rotation) + top.fill(255, 0, 0, 200) + top.rectMode(CENTER) + top.rect(0, 0, r.halfWidth * 2, r.halfHeight * 2) + top.popMatrix() + } + + case _ => throw new IllegalArgumentException("Cannot create graphical shape: unknown shape.") + } + + } + +} + +object RichShape { + + implicit def shapeToRichShape(s: Shape) = new RichShape(s) + +}
\ No newline at end of file diff --git a/src/test/scala/sims/test/gui/Scene.scala b/src/test/scala/sims/test/gui/Scene.scala new file mode 100644 index 0000000..6e1664e --- /dev/null +++ b/src/test/scala/sims/test/gui/Scene.scala @@ -0,0 +1,13 @@ +package sims.test.gui + +trait Scene extends Reactor { + def name: String = this.getClass().getName() + def description: String = "" + + val world = new DebugWorld + + def init(): Unit + + def exit(): Unit = {} + +}
\ No newline at end of file diff --git a/src/test/scala/sims/test/gui/SceneManager.scala b/src/test/scala/sims/test/gui/SceneManager.scala new file mode 100644 index 0000000..39da308 --- /dev/null +++ b/src/test/scala/sims/test/gui/SceneManager.scala @@ -0,0 +1,95 @@ +package sims.test.gui + +import processing.core.PApplet +import scala.collection.mutable.ArrayBuffer +import sims.math._ +import sims.test.gui.scenes._ +import sims.test.gui.RichShape._ +import sims.test.gui.RichJoint._ + +class SceneManager(implicit top: PApplet) { + + /* Contains objects that will be rendered on `draw()`. */ + private var _graphicals = new ArrayBuffer[Graphical[_]] + def graphicals: Seq[Graphical[_]] = _graphicals + + /* Current scene. */ + private var _currentScene: Scene = EmptyScene + + /* Get current scene. */ + def currentScene = _currentScene + + /* Set current scene. */ + def currentScene_=(newScene: Scene) = { + + // remove reactions + currentScene.deafTo(currentScene.world) + currentScene.reactions.clear() + + // empty world + currentScene.world.clear() + + // clear graphical objects + _graphicals.clear() + + // custom exit behavior + currentScene.exit() + + // add new reactions to create / remove graphical objects + newScene.listenTo(newScene.world) + newScene.reactions += { + case BodyAdded(newScene.world, body) => for (s <- body.shapes) _graphicals += s.toGraphical + case BodyRemoved(newScene.world, body) => for (s <- body.shapes) { + val index = _graphicals.findIndexOf((g: Graphical[_]) => g match { + case gs: GraphicalShape => gs.physical == s + case _ => false + }) + _graphicals.remove(index) + } + + case JointAdded(newScene.world, joint) => _graphicals += joint.toGraphical + case JointRemoved(newScene.world, joint) => { + val index = _graphicals.findIndexOf((g: Graphical[_]) => g match { + case gj: GraphicalJoint => gj.physical == joint + case _ => false + }) + _graphicals.remove(index) + } + + } + + // custom initialization + newScene.init() + + // set current scene + _currentScene = newScene + + println("set scene to '" + currentScene.name + "'") + } + + private var currentSceneIndex = 0 + val scenes = List( + BasicScene, + CollisionScene, + LongCollisionScene, + CloudScene, + PyramidScene, + ShiftedStackScene, + JointScene + ) + + def nextScene() = { + currentSceneIndex += 1 + currentScene = scenes(mod(currentSceneIndex, scenes.length)) + } + + def previousScene() = { + currentSceneIndex -= 1 + currentScene = scenes(mod(currentSceneIndex, scenes.length)) + } + + def restartScene() = { + currentScene = currentScene + } + +}
\ No newline at end of file diff --git a/src/test/scala/sims/test/gui/events.scala b/src/test/scala/sims/test/gui/events.scala new file mode 100644 index 0000000..22015ce --- /dev/null +++ b/src/test/scala/sims/test/gui/events.scala @@ -0,0 +1,49 @@ +package sims.test.gui + +import scala.collection.mutable.ListBuffer +import sims.dynamics._ + +trait Event +case class BodyAdded(world: World, body: Body) extends Event +case class BodyRemoved(world: World, body: Body) extends Event +case class Stepped(wordl: World) extends Event +case class JointAdded(world: World, joint: Joint) extends Event +case class JointRemoved(world: World, joint: Joint) extends Event + +object Reactions { + class Impl extends Reactions { + private val parts = new ListBuffer[Reaction] + def isDefinedAt(e: Event) = parts exists (_ isDefinedAt e) + def +=(r: Reaction) = parts += r + def -=(r: Reaction) = parts -= r + def clear() = parts.clear() + def apply(e: Event) { + for (p <- parts; if p isDefinedAt e) p(e) + } + } + type Reaction = PartialFunction[Event, Unit] +} + +abstract class Reactions extends Reactions.Reaction { + def +=(r: Reactions.Reaction): Unit + def -=(r: Reactions.Reaction): Unit + def clear(): Unit +} + +trait Reactor { + val reactions: Reactions = new Reactions.Impl + + def listenTo(ps: Publisher*) = for (p <- ps) p.subscribe(reactions) + def deafTo(ps: Publisher*) = for (p <- ps) p.unsubscribe(reactions) +} + +trait Publisher { + import Reactions._ + + private val listeners = new ListBuffer[Reaction] + + def subscribe(listener: Reaction) = listeners += listener + def unsubscribe(listener: Reaction) = listeners -= listener + + def publish(e: Event) { for (l <- listeners) l(e) } +}
\ No newline at end of file diff --git a/src/test/scala/sims/test/gui/graphicals.scala b/src/test/scala/sims/test/gui/graphicals.scala new file mode 100644 index 0000000..39b2ea0 --- /dev/null +++ b/src/test/scala/sims/test/gui/graphicals.scala @@ -0,0 +1,13 @@ +package sims.test.gui + +import processing.core.PApplet +import sims.dynamics.Shape +import sims.dynamics.Joint + +abstract class Graphical[+A](val physical: A) { + val top: PApplet + val render: () => Unit +} + +abstract class GraphicalShape(val shape: Shape) extends Graphical[Shape](shape) +abstract class GraphicalJoint(val joint: Joint) extends Graphical[Joint](joint)
\ No newline at end of file diff --git a/src/test/scala/sims/test/gui/scenes/BasicScene.scala b/src/test/scala/sims/test/gui/scenes/BasicScene.scala new file mode 100644 index 0000000..9598ab1 --- /dev/null +++ b/src/test/scala/sims/test/gui/scenes/BasicScene.scala @@ -0,0 +1,18 @@ +package sims.test.gui +package scenes + +import sims.math._ +import sims.dynamics._ +import sims.dynamics._ + +object BasicScene extends Scene { + + def init() = { + world.gravity = Vector2D.Null + val s = new Circle(1) + world += new Body(s) {linearVelocity = Vector2D(0.1, 0.01); angularVelocity = 1} + world += new Body(new Rectangle(2,1)) {linearVelocity = Vector2D(0.1, 0.01); angularVelocity = 1} + } + + +}
\ No newline at end of file diff --git a/src/test/scala/sims/test/gui/scenes/CloudScene.scala b/src/test/scala/sims/test/gui/scenes/CloudScene.scala new file mode 100644 index 0000000..660e309 --- /dev/null +++ b/src/test/scala/sims/test/gui/scenes/CloudScene.scala @@ -0,0 +1,47 @@ +package sims.test.gui +package scenes + +import sims.math._ +import sims.dynamics._ + +object CloudScene extends Scene { + override def description = "A cloud of circles." + + val MaxItems = 1000 + val MaxItemSize = 0.2 + val Width = 10 + val Height = 10 + + val random = new scala.util.Random(1234567890) + def randomCircles(): Seq[Body] = for (i <- 0 until MaxItems) yield { + val rX = random.nextDouble * Width + val rY = random.nextDouble * Height + val c = new Circle(random.nextDouble * MaxItemSize) { + position = Vector2D(rX, rY) + } + new Body(c) { + linearVelocity = Vector2D(random.nextDouble * (if (random.nextBoolean) 1 else -1), random.nextDouble * (if (random.nextBoolean) 1 else -1)) + angularVelocity = random.nextDouble * (if (random.nextBoolean) 1 else -1) * 10 + } + } + + def frame() = { + val points = List(Vector2D(-1, -1), Vector2D(11, -1), Vector2D(11, 11), Vector2D(-1, 11)) + for (i <- 0 until points.length) yield { + val sp = points(i) + val ep = points((i + 1) % points.length) + val center = (sp + ep) / 2 + val r = new Rectangle((center - ep).length, 0.2) { + position = center + rotation = math.Pi / 2 * i + } + new Body(r) {fixed = true} + } + } + + override def init() = { + world.gravity = Vector2D.Null + for (r <- randomCircles()) world += r + //for (r <- frame()) world += r + } +}
\ No newline at end of file diff --git a/src/test/scala/sims/test/gui/scenes/CollisionScene.scala b/src/test/scala/sims/test/gui/scenes/CollisionScene.scala new file mode 100644 index 0000000..cf2ea61 --- /dev/null +++ b/src/test/scala/sims/test/gui/scenes/CollisionScene.scala @@ -0,0 +1,41 @@ +package sims.test.gui +package scenes + +import sims.dynamics._ +import sims.math._ +import sims.dynamics._ + +object CollisionScene extends Scene { + override def description = "A basic collision detection test." + + var c1 = (new Circle(1) {restitution = 1.0}).asBody + var c2 = (new Circle(1) {position = Vector2D(3, 0)}).asBody + var r1 = (new Rectangle(0.5, 0.5) {position = Vector2D(6,0)}).asBody + + def init() = { + c1 = (new Circle(1) {restitution = 1.0}).asBody + c2 = (new Circle(1) {position = Vector2D(3, 0); restitution = 1.0}).asBody + r1 = (new Rectangle(0.5, 0.5) {position = Vector2D(6,0)}).asBody + + c1.linearVelocity = Vector2D(1, 0) + + world.gravity = Vector2D(0, 0) + world += c1 + world += c2 + world += r1 + + reactions += { + case Stepped(`world`) => + println( + "p: " + (c1.linearMomentum.length + c2.linearMomentum.length + r1.linearMomentum.length).toFloat + + "\tE: " + (E(c1) + E(c2) + E(r1)).toFloat + ) + } + } + + + def E(b: Body) = { + (b.linearVelocity dot b.linearVelocity) * b.mass / 2 + } + +}
\ No newline at end of file diff --git a/src/test/scala/sims/test/gui/scenes/EmptyScene.scala b/src/test/scala/sims/test/gui/scenes/EmptyScene.scala new file mode 100644 index 0000000..a88679a --- /dev/null +++ b/src/test/scala/sims/test/gui/scenes/EmptyScene.scala @@ -0,0 +1,6 @@ +package sims.test.gui +package scenes + +object EmptyScene extends Scene { + def init() = () +}
\ No newline at end of file diff --git a/src/test/scala/sims/test/gui/scenes/JointScene.scala b/src/test/scala/sims/test/gui/scenes/JointScene.scala new file mode 100644 index 0000000..4a0726f --- /dev/null +++ b/src/test/scala/sims/test/gui/scenes/JointScene.scala @@ -0,0 +1,107 @@ +package sims.test.gui +package scenes + +import sims.dynamics._ +import sims.math._ +import sims.dynamics._ + +object JointScene extends Scene { + + override def init() = { + val b1 = new Body(new Circle(0.1)) {fixed = true} + val b2 = new Body(new Rectangle(0.1, 0.5)) {position = Vector2D(2,2)} + val j = new DistanceJoint(b1, b1.position, b2, b2.position + Vector2D(0, -0.5)) + world += b1 + world += b2 + world += j + + val chainBodies = for (i <- 0 until 10) yield new Body(new Rectangle(0.5, 0.1)){fixed = i == 0 || i == 9; position = Vector2D(i, 5)} + val chainHinges = for (i <- 0 until chainBodies.length - 1) yield + new RevoluteJoint(chainBodies(i), chainBodies(i + 1), Vector2D(i + 0.5, 5)) + for (b <- chainBodies) world += b + for (j <- chainHinges) world += j + + import sims.dsl._ + val c = new Body(new Circle(0.1)) {position = Vector2D(4, 0)} + world += c + world += c distance chainBodies(4) + + val r = new Body(new Rectangle(2, 0.1)) {position = Vector2D(4, 0)} + world += r + world += c revolute r + + val c2 = new Body(new Circle(0.2)) {position = Vector2D(2, 2)} + world += c2 + world += r :@@ (-2, 0) distance c2 + + val r2 = new Body(new Rectangle(0.1, 0.2)) {position = Vector2D(6, 2)} + world += r2 + world += r :@@ (2, 0) distance (0, -0.2) @@: r2 + + val r3 = new Body(new Rectangle(0.3, 0.1)) {position = Vector2D(6.3, 2.2)} + world += r3 + world += r2 :@ (6, 2.2) revolute r3 + + // chaos pendulum + { + val c1 = new Body(new Circle(0.1)) {fixed = true; position = Vector2D(12, 2)} + world += c1 + val r1 = new Body(new Rectangle(1, 0.1)) {position = Vector2D(13, 2)} + world += r1 + val r2 = new Body(new Rectangle(1, 0.1)) {position = Vector2D(15, 2)} + world += r2 + + world += c1 revolute r1 + world += r1 :@@ (1, 0) revolute r2 + + } + + // net + { + val w = 10 + val h = 10 + val d = 0.2 + + val nodes = + for (i <- (0 until w).toArray) yield + for (j <- (0 until h).toArray) yield + new Body(new Circle(0.05)) {fixed = i == 0 && j == h - 1 ; position = Vector2D(i * d, j * d) + Vector2D(-3, 2)} + + for (n <- nodes.flatten) world += n + + val joints = { + var r: List[DistanceJoint] = Nil + for(i <- 0 to nodes.length - 1; j <- 0 to nodes(i).length - 1) { + if (i > 0) + r = (nodes(i-1)(j) distance nodes(i)(j)) :: r + if (j > 0) + r = (nodes(i)(j-1) distance nodes(i)(j)) :: r + } + r + } + + for (j <- joints) world += j + + } + + + world.collisionDetection = false + world.iterations = 10 + world.errorReduction = 1 + + + /* + val r1 = new Body(new Rectangle(0.5, 0.1)) {fixed = true; position = Vector2D(5, 5)} + val r2 = new Body(new Rectangle(0.5, 0.1)) {position = Vector2D(6, 5)} + val r3 = new Body(new Rectangle(0.5, 0.1)) {position = Vector2D(7, 5)} + val j12 = new RevoluteJoint(r1, r2, Vector2D(5.5, 5)) + val j23 = new RevoluteJoint(r2, r3, Vector2D(6.5, 5)) + world += r1 + world += r2 + world += r3 + world += j12 + world += j23 + */ + } + +}
\ No newline at end of file diff --git a/src/test/scala/sims/test/gui/scenes/LongCollisionScene.scala b/src/test/scala/sims/test/gui/scenes/LongCollisionScene.scala new file mode 100644 index 0000000..d153f1b --- /dev/null +++ b/src/test/scala/sims/test/gui/scenes/LongCollisionScene.scala @@ -0,0 +1,54 @@ +package sims.test.gui +package scenes + +import sims.dynamics._ +import sims.math._ +import sims.dynamics._ + +object LongCollisionScene extends Scene { + override def description = "A test to verify conservation in a collision." + + def makeBodies() = (for (i <- 0 until 10) yield { + new Circle(0.2) { + position = Vector2D(0 + 2.01 * radius * i, 0) + restitution = 0.8 + } + }.asBody) ++ (for (i <- 0 until 10) yield { + new Circle(0.2) { + position = Vector2D(6 + 2.01 * radius * i, 0) + restitution = 0.8 + } + }.asBody) + + override def init() = { + val bodies = makeBodies() + bodies(0).fixed = true + bodies(19).fixed = true + for (b <- bodies) world += b + world.gravity = Vector2D.Null + + val bullet = new Body(new Circle(0.2) { + position = Vector2D(5, 0) + restitution = 0.8}) { + linearVelocity = Vector2D(3, 0) + } + world += bullet + + world.iterations = 10 + + registerListeners() + } + + def registerListeners() = { + reactions += { + case Stepped(`world`) => println( + "P: " + world.bodies.map(P(_)).sum.toFloat + + "\tE: " + world.bodies.map(E(_)).sum.toFloat + ) + } + } + + def P(b: Body) = if (b.fixed) 0 else b.linearMomentum.length + def E(b: Body) = if (b.fixed) 0 else (b.linearVelocity dot b.linearVelocity) * b.mass * 0.5 + +}
\ No newline at end of file diff --git a/src/test/scala/sims/test/gui/scenes/PyramidScene.scala b/src/test/scala/sims/test/gui/scenes/PyramidScene.scala new file mode 100644 index 0000000..19438de --- /dev/null +++ b/src/test/scala/sims/test/gui/scenes/PyramidScene.scala @@ -0,0 +1,40 @@ +package sims.test.gui +package scenes + +import sims.math._ +import sims.dynamics._ +import sims.dynamics._ + +object PyramidScene extends Scene { + override def description = "A pyramid made out of circles." + + val Base = 40 + var Radius = 0.2 + + val s = math.sqrt(3) + + def pyramid: Seq[Body] = (for (i <- 0 until Base) yield { + for (j <- 0 until Base - i) yield new Body( + new Circle(Radius) { + position = Vector2D(2 * j * Radius + i * Radius, s * i * Radius) + restitution = 0.5 + } + ) {fixed = (i == 0)} + }).flatten + + override def init() = { + //world.gravity = Vector2D.Null + for (b <- pyramid) world += b + + val b = new Circle(0.3) { + override val density = 10.0 + position = Vector2D(4,15) + } + val bd = new Body(b){ + linearVelocity = Vector2D(0, -2.5) + } + + world += bd + } + +}
\ No newline at end of file diff --git a/src/test/scala/sims/test/gui/scenes/ShiftedStackScene.scala b/src/test/scala/sims/test/gui/scenes/ShiftedStackScene.scala new file mode 100644 index 0000000..c8a7af6 --- /dev/null +++ b/src/test/scala/sims/test/gui/scenes/ShiftedStackScene.scala @@ -0,0 +1,30 @@ +package sims.test.gui +package scenes + +import sims.math._ +import sims.dynamics._ + +object ShiftedStackScene extends Scene { + override def description = "A stack of shifted rectangles." + /*override val world = new DebugWorld{ + import sims.collision._ + import sims.collision.narrowphase._ + import sims.collision.broadphase._ + override val detector = SAP[Shape] narrowedBy new sims.test.gjk.GJK[Shape] + }*/ + + val width = 1.0 + val height = 0.2 + + def stack() = for (i <- 0 until 2) yield + new Body(new Rectangle(width / 2, height / 2) { + position = Vector2D(0.25 * (i % 2) , i * height) + restitution = 0.0 + }) {fixed = i == 0} + + override def init() = { + for (s <- stack()) world += s + world.iterations = 100 + } + +}
\ No newline at end of file |