//:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: /** @author John Miller * @version 2.0 * @date Sat Jan 25 19:44:16 EST 2014 * @see LICENSE (MIT style license file). * * @note Route for Modeling Multi-Stage, Multi-Lane Pathway */ package scalation package simulation package process import scalation.animation.CommandType._ import scalation.mathstat.VectorD import scalation.random.Variate //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: /** The `Route` class provides a multi-stage, multi-lane pathway between two other * components where the `Path`s are stitched together with `Junction`s. * @param name the name of the route * @param j the number of paths in the route * @param k the number of lanes/transports in the route * @param from the starting component * @param to the ending component * @param motion the variate or dynamics model for the speed/trip-time for motion down the `Route` * @param isSpeed whether speed or trip-time is used for motion * @param bend the bend or curvature of the `Route` (0 => line) */ class Route (name: String, j: Int, k: Int, val from: Component, val to: Component, motion: Variate | Dynamics, isSpeed: Boolean = false, bend: Double = 0.0) extends Component: initComponent (name, Array ()) private val debug = debugf ("Route", true) // debug function val path = Array.ofDim [Path] (j) // j paths/road segments (PUBLIC access required) val junc = Array.ofDim [Junction] (j-1) // j-1 junctions (PUBLIC access required) private val disp = calcDisp // displacement debug ("init", s"name = $name, from = ${from.name}, to = ${to.name} with j = $j paths, k = $k lanes") for i <- path.indices do val jPos = VectorD (from.at(0), from.at(1)) junc(i) = new Junction (s"${name}_j$i", xy = (jPos(0), jPos(1))) path(i) = if i == 0 then new Path (s"${name}_$i", k, from, junc(0), motion, isSpeed, bend) else if i == junc.size-1 then new Path (s"${name}_$i", k, junc.last, to, motion, isSpeed, bend) else new Path (s"${name}_$i", k, junc(i-1), junc(i), motion, isSpeed, bend) subpart += path(i) if i < junc.size then subpart += junc(i) jPos += disp end for //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: /** Get the first vehicle in alne i of `Route` (the first element in vtree). * @param i the i-th lane */ def getFirst (i: Int): Vehicle = path(0).lane(i).asInstanceOf [VTransport].vtree.getFirst //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: /** Return the number of segments/paths. */ def segments: Int = j //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: /** Return the number of lanes. */ def lanes: Int = k //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: /** Give the location of the curve to be its starting point. */ override def at: Array [Double] = path(0).lane(0).at //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: /** Calculate the amount of diplacement in the x and y directions between the * junctions assuming they are evenly spaced. */ private def calcDisp: VectorD = val xdist = from.at(0) - to.at(0) val ydist = from.at(1) - to.at(1) VectorD (xdist / k.toDouble, ydist / k.toDouble) end calcDisp //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: /** Tell the animation engine to display this `Route`. */ def display (): Unit = for p <- path do p.display () end display end Route //:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: /** The `routeTest` main function is used to test the `Route` class, which is a * composite class. It simulates a two-segment, two-lane road in one direction. * > runMain scalation.simulation.process.routeTest */ @main def routeTest (): Unit = import scalation.random.{Bernoulli, Uniform} class RouteModel (name: String, nArrivals: Int, iArrivalRV: Variate, moveRV: Variate) extends Model (name): val rng = Bernoulli () val onRamp = new Source ("onRamp", this, () => Car (), 0, nArrivals, iArrivalRV, (200.0, 200.0)) val offRamp = new Sink ("offRamp", (600.0, 200.0)) val road = new Route ("lane", 2, 2, onRamp, offRamp, moveRV, false, 0.25) addComponent (onRamp, offRamp, road) case class Car () extends SimActor ("c", this): override def act (): Unit = val i = rng.igen // choose a lane for the route val carAhead = road.getFirst (i) // find the car-ahead in lane i (the one to follow) SimActor.addToAlist (this, carAhead) // add this car after the car-ahead in alist for j <- 0 until road.segments do road.path(j).lane(i).move () // move along the j-th path in the i-th lane if j < road.segments - 1 then road.junc(j).jump () // enter the j-th junction SimActor.removeFromAlist (this) // remove this car from alist offRamp.leave () // exit end act end Car end RouteModel val rm = new RouteModel ("road", 10, Uniform (4000, 6000), Uniform (2900, 3100)) rm.simulate () rm.waitFinished () Model.shutdown () end routeTest