//:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: /** @author John Miller, Casey Bowman * @version 2.0 * @date Tue Feb 4 14:56:34 EST 2020 * @see LICENSE (MIT style license file). * * @note Variable Speed Transport is a Pathway between Components */ package scalation package simulation package process import scalation.animation.CommandType._ import scalation.mathstat._ //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: /** The `VTransport` class provides a variable-speed pathway between two other components. * The components in a `Model` conceptually form a 'graph' in which the edges * are `VTransport`s and the nodes are other `Component`s. * @see `animation.Dgraph.move2Boundary` that aligns edge with node boundaries. * @param name the name of the variable-speed transport * @param from the starting component * @param to the ending component * @param motion the dynamics model for the speed/trip-time for motion down the `VTransport` * @param isSpeed whether speed or trip-time is used for motion * @param bend the bend or curvature of the `VTransport` (0 => line) * @param shift1 the x-y shift for the transport's first end-point (from-side) * @param shift2 the x-y shift for the transport's second end-point (to-side) */ class VTransport (name: String, from_ : Component, to_ : Component, motion: Dynamics, isSpeed: Boolean = false, bend: Double = 0.0, shift1: VectorD = VectorD (0, 0), shift2: VectorD = VectorD (0, 0)) extends Transport (name, from_, to_, null, isSpeed, bend, shift1, shift2): private val debug = debugf ("VTransport", true) // debug function //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: /** Move the entity (SimActor) smoothly down this VTransport (e.g., road). * Repeatedely move it along the VTransport/Edge/QCurve. * Caveat: tokens coordinates are computed using a shadow QCurve (same coordinates * as the one that will be created by the animation engine). * @param x the currect displacement for the actor/vehicle (try 0.0) * @param fraction the fraction of the remaining transform to move along (try 1.0) */ def move (x: Double, fraction: Double): Unit = val actor = director.theActor.asInstanceOf [Vehicle] actor.disp = x tally (Vehicle.rt) var done = false while actor.disp < fraction * curve.length && ! done do director.log.trace (this, "moves for " + Vehicle.rt, actor, director.clock) motion.update (actor) debug ("move", s"${actor.name}, x = ${actor.disp}, VTransport = $name") director.animate (actor, MoveToken, null, null, calcPoint (actor.disp / fraction)) if actor.disp <= actor.t_disp then done = true val p = actor.pred val s = actor.succ if p != null && s != null then { p.succ = s; s.pred = p } else if p != null && s == null then p.succ = null else if p == null && s != null then s.pred = null actor.pred = null actor.succ = null actor.schedule (Vehicle.rt) actor.yieldToDirector () end while end move //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: /** Calculate the (x, y) point in the simulation space for the vehicle. * @param s the current displacement along the road of the vehicle. */ def calcPoint (s: Double): Array [Double] = val prop = s / curve.length val x = p1(0) + (p2(0) - p1(8)) * prop val y = p1(1) + (p2(1) - p1(1)) * prop Array (x - RAD, y - RAD) end calcPoint //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: /** Method to nudge the road over a little bit for use with multi-lane * highways. If nudge factor is zero then the road will not be nudged. * Uses the slope m; FIX angle might work better * @param λ the nudge factor * def nudgeAt (λ: Double): Unit = val a1 = p1.getX() val b1 = p1.getY() val a2 = p2.getX() val b2 = p2.getY() if m == Double.PositiveInfinity || m == Double.NegativeInfinity then p1.setLocation (a1 + λ, b1) p2.setLocation (a2 + λ, b2) else if m == 0.0 then p1.setLocation (a1, b1 + λ) p2.setLocation (a2, b2 + λ) else val α = λ * Math.sqrt (1.0 / (m * m + 1)) val c1 = a1 - m * α val d1 = b1 + α val c2 = a2 - m * α val d2 = b2 + α p1.setLocation (c1, d1) p2.setLocation (c2, d2) end nudgeAt import java.io._ var pw: PrintWriter = null def openPrint (path: String): Unit = pw = new PrintWriter (new FileWriter (new File (path))) } end openPrint def pw_println (s: String): Unit = if pw != null then { pw.println (s); pw.flush () } end pw_println def closePrint (): Unit = pw.close () */ end VTransport