package edu.colorado.phet.movingman.ladybug import scala.collection.mutable.ArrayBuffer import LadybugUtil._ class LadybugModel extends Observable[LadybugModel] { val ladybug = new Ladybug val history = new ArrayBuffer[DataPoint] private val ladybugMotionModel = new LadybugMotionModel def getLadybugMotionModel() = ladybugMotionModel private var time: Double = 0; def getTime() = time def setUpdateModePosition = updateMode = positionMode def setUpdateModeVelocity = updateMode = velocityMode def setUpdateModeAcceleration = updateMode = accelerationMode var playbackIndexFloat = 0.0 //floor this to get playbackIndex def getPlaybackIndex(): Int = java.lang.Math.floor(playbackIndexFloat).toInt def getPlaybackIndexFloat(): Double = playbackIndexFloat def positionMode(dt: Double) = { if (estimateVelocity(history.length - 1).magnitude > 1E-6) ladybug.setAngle(estimateAngle()) var velocityEstimate = average(history.length - 3, history.length - 1, estimateVelocity) ladybug.setVelocity(velocityEstimate) var accelEstimate = average(history.length - 15, history.length - 1, estimateAcceleration) ladybug.setAcceleration(accelEstimate) } def velocityMode(dt: Double) = { ladybug.translate(ladybug.getVelocity * dt) var accelEstimate = average(history.length - 15, history.length - 1, estimateAcceleration) ladybug.setAcceleration(accelEstimate) } def accelerationMode(dt: Double) = { ladybug.translate(ladybug.getVelocity * dt) ladybug.setVelocity(ladybug.getVelocity + ladybug.getAcceleration * dt) } private var updateMode: (Double) => Unit = positionMode def setStateToPlaybackIndex() = ladybug.setState(history(getPlaybackIndex()).state) def update(dt: Double) = { if (!paused) { if (isRecord()) { time += dt; ladybugMotionModel.update(dt, this) history += new DataPoint(time, ladybug.getState) if (history.length > 20) { updateMode(dt) } notifyListeners(this) } else if (isPlayback()) { if (getPlaybackIndex() < history.length) { setStateToPlaybackIndex() time = history(getPlaybackIndex()).time playbackIndexFloat = playbackIndexFloat + playbackSpeed notifyListeners(this) } } } } def estimateAngle(): Double = estimateVelocity(history.length - 1).getAngle def getPosition(index: Int): Vector2D = { history(index).state.position } def estimateVelocity(index: Int): Vector2D = { val dx = getPosition(index) - getPosition(index - 1) val dt = history(index).time - history(index - 1).time dx / dt } def estimateAcceleration(index: Int): Vector2D = { val dv = estimateVelocity(index) - estimateVelocity(index - 1) val dt = history(index).time - history(index - 1).time dv / dt } def average(start: Int, end: Int, function: Int => Vector2D): Vector2D = { var sum = new Vector2D for (i <- start until end) { sum = sum + function(i) } sum / (end - start) } var record = true var paused = false var playbackSpeed = 1.0 def isPlayback() = !record def isRecord() = record def setRecord(rec: Boolean) = { record = rec notifyListeners(this) } def setPlayback(speed: Double) = { playbackSpeed = speed record = false notifyListeners(this) } def setPaused(p: Boolean) = { paused = p notifyListeners(this) } def isPaused() = paused def rewind = { setPlaybackIndexFloat(0.0) } def setPlaybackIndexFloat(index: Double) = { playbackIndexFloat = index setStateToPlaybackIndex() notifyListeners(this) } def startRecording() = { getLadybugMotionModel.motion = LadybugMotionModel.MANUAL setRecord(true) setPaused(false) } def resetAll() = { record = true paused = false playbackSpeed = 1.0 history.clear ladybugMotionModel.resetAll() playbackIndexFloat = 0.0 time = 0 ladybug.resetAll() notifyListeners(this) } }