/*-----------------------------------------------------------------------
* Copyright (C) 2001 Green Light District Team, Utrecht University
*
* This program (Green Light District) is free software.
* You may redistribute it and/or modify it under the terms
* of the GNU General Public License as published by
* the Free Software Foundation (version 2 or later).
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
* See the documentation of Green Light District for further information.
*------------------------------------------------------------------------*/
package gld.sim;
import gld.Model;
import gld.GLDException;
import gld.algo.dp.*;
import gld.algo.edit.ShortestPathCalculator;
import gld.algo.tlc.*;
import gld.edit.Validation;
import gld.infra.*;
import gld.sim.stats.StatisticsController;
import gld.sim.stats.TrackerFactory;
import gld.utils.Arrayutils;
import gld.utils.NumberDispenser;
import gld.xml.*;
import java.awt.Point;
import java.awt.Color;
import java.io.File;
import java.io.IOException;
import java.util.*;
import org.apache.xerces.parsers.DOMParser;
import org.w3c.dom.Attr;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
/**
*
* The heart of the simulation.
*
* @author Group Model
* @version 1.0
*/
public class SimModel extends Model implements XMLSerializable
{
private static final String statsCyclesKey = "gld.sim.stats.sender.cycles";
/** The pseudo-random-number-generator we need in this simulation */
protected Random generator;
/** The second thread that runs the actual simulation */
protected SimModelThread thread;
/** The current cycle we're in */
protected int curCycle;
/** The Driving Policy in this Simulation */
protected static DrivingPolicy dp;
/** The TrafficLightControlling Algorithm */
protected TLController tlc;
/** The Thing that makes all Trafficlights shudder */
protected SignController sgnctrl;
/** Name of the simulation */
protected String simName="untitled";
/** A boolean to keep track if this sim has already run (ivm initialization) */
protected boolean hasRun = false;
/** Indicates if roadusers cross nodes or jump over them. */
public static boolean CrossNodes = true;
/** Indicates wheter the StatisticsSender thread must run or not */
boolean active = false;
protected StatisticsSender statsSenderThread = null;
protected LinkedList spawnFreqsList = null;
protected Iterator iFreqs = null;
protected int nroFranja = 0;
protected String file_franjas_key = "gld.sim.timeInterval.source";
protected ResourceBundle rb = null;
/**
* Creates second thread
*/
public SimModel() {
thread = new SimModelThread();
thread.start();
// threadUpdate = new SimModelFreqsUpdate();
//System.out.println("va a arrancar el thread de configuracion de freqs");
// threadUpdate.start();
curCycle = 0;
generator = new Random();
sgnctrl = new SignController(tlc, infra);
//GASTON: getting resource bundle
rb = ResourceBundle.getBundle("simulation");
//GASTON: creting thread to send statistics
statsSenderThread = new StatisticsSender();
statsSenderThread.setModel(this);
statsSenderThread.start();
}
public void setInfrastructure(Infrastructure i) {
pause();
super.setInfrastructure(i);
if(tlc!=null)
tlc.setInfrastructure(i);
if(sgnctrl!=null)
sgnctrl.setInfrastructure(i);
}
/** Returns the current cycle */
public int getCurCycle() { return curCycle; }
/** Sets the current cycle */
public void setCurCycle(int c) { curCycle = c; }
/** Returns the current Driving Policy */
public static DrivingPolicy getDrivingPolicy() { return dp; }
/** Sets the current DrivTLController */
public void setDrivingPolicy(DrivingPolicy _dp) { dp = _dp; }
/** Returns the current TLController */
public TLController getTLController() { return tlc; }
/** Sets the current TLController */
public void setTLController(TLController _tlc) {
tlc = _tlc;
sgnctrl.setTLC(tlc);
}
/** Returns the random number generator */
public Random getRandom() { return generator; }
/** Sets the random number generator */
public void setRandom(Random r) { generator = r; }
/** Returns the name of the simulation */
public String getSimName() { return simName; }
/** Sets the name of the simulation */
public void setSimName(String s) { simName = s; }
/** Returns the pseudo-random-number generator of this Model */
public Random getRNGen() {return generator;}
/** Sets spawn frequency for given node and ru type. */
public void setSpawnFrequency(EdgeNode en, int rutype, float newspawn) {
en.setSpawnFrequency(rutype, newspawn);
setChanged();
notifyObservers();
}
/**
* Stops the simulation.
* This should only be called when the program exits.
* To start a new simulation, the simulation should be paused
* with a call to pause(), then followed by a call to reset(),
* and finally resumed with unpause().
*/
public void stop() {
thread.die();
}
/**
* Pauses the simulation
*/
public void pause() {
thread.pause();
}
/**
* Unpauses the simulation
*/
public void unpause() {
thread.unpause();
}
public boolean isRunning() {
return thread.isRunning();
}
/**
* Resets data
*/
public void reset() throws SimulationRunningException {
if (thread.isRunning()) throw new SimulationRunningException("Cannot reset data while simulation is running.");
infra.reset();
tlc.reset();
curCycle = 0;
generator = new Random();
TrackerFactory.resetTrackers();
setChanged();
notifyObservers();
}
public void disableTraffic(Drivelane lane){
try {
Road actual_road = lane.getRoad();
actual_road.setEnabled(false);
Node[] nodes = infra.getAllNodes();
for (int i=0;i<nodes.length;i++){
nodes[i].remAllPaths();
if (nodes[i] instanceof Junction){
((Junction)nodes[i]).updateAllAvailableRoads();
}
}
ShortestPathCalculator spcalculator = new ShortestPathCalculator();
spcalculator.calcAllShortestPaths(infra);
/*Validation validation = new Validation(infra);
validation.validate();*/
}catch(Exception e){
e.printStackTrace();
}
}
public void enableTraffic(Drivelane lane){
try {
Road actual_road = lane.getRoad();
actual_road.setEnabled(true);
Node[] nodes = infra.getAllNodes();
for (int i=0;i<nodes.length;i++){
nodes[i].remAllPaths();
if (nodes[i] instanceof Junction){
((Junction)nodes[i]).updateAllAvailableRoads();
}
}
ShortestPathCalculator spcalculator = new ShortestPathCalculator();
spcalculator.calcAllShortestPaths(infra);
}catch(Exception e){
e.printStackTrace();
}
}
/**
* Does 1 step in the simulation. All cars move, pedestrians get squashed etc...
*/
public void doStep( ) {
curCycle++;
int statisticsInterval = Integer.parseInt(rb.getString(statsCyclesKey));
if (curCycle% statisticsInterval == 0){
//GASTON:we try to export runtime information
sendStatistics();
}
//System.out.println("CurTLC:"+tlc.getXMLName());
if (! hasRun)
{ initialize();
hasRun=true;
}
try {
Enumeration specialNodes=Arrayutils.getEnumeration(infra.getSpecialNodes());
while (specialNodes.hasMoreElements())
((SpecialNode)(specialNodes.nextElement())).doStep(this);
moveAllRoadusers();
spawnNewRoadusers();
sgnctrl.switchSigns();
}
catch (Exception e) {
System.out.println("The simulator made a booboo:");
System.out.println(e.getMessage());
e.printStackTrace();
}
setChanged();
notifyObservers();
}
public void initialize ()
{ SAVE_STATS = true;
Enumeration e=Arrayutils.getEnumeration(infra.getSpecialNodes());
while (e.hasMoreElements())
((SpecialNode)(e.nextElement())).start();
//GASTON: we load the different spwan frequencies
spawnFreqsList = new LinkedList();
InputSource source = new InputSource(rb.getString(file_franjas_key));
DOMParser parser = new DOMParser();
try {
parser.parse(source);
} catch (SAXException e1) {
e1.printStackTrace();
} catch (IOException e1) {
e1.printStackTrace();
}
Document doc = parser.getDocument();
NodeList nodeList = doc.getElementsByTagName("franja");
for (int i=0;i<nodeList.getLength();i++){
System.out.println(nodeList.item(i).getNodeName());
NodeList edgeNodesList = nodeList.item(i).getChildNodes();
HashMap spawnFreqsHM = new HashMap();
for (int j=0;j<edgeNodesList.getLength() ;j++){
if (!edgeNodesList.item(j).getNodeName().equals("edgenode")) continue;
String nodeid = null;
NamedNodeMap nnm = edgeNodesList.item(j).getAttributes();
if(nnm != null )
{
int len = nnm.getLength() ;
Attr attr;
for ( int a = 0; a< len; a++ )
{
attr = (Attr)nnm.item(a);
System.out.print(' ' + attr.getNodeName() + "=\"" + attr.getNodeValue() + '"' );
if (attr.getNodeName().equals("id")) nodeid = attr.getNodeValue();
}
if (nodeid != null){
NodeList spawnFreqsList = edgeNodesList.item(j).getChildNodes();
String[] freqs = {"0.0","0.0","0.0"};
for (int k=0;k < spawnFreqsList.getLength();k++)
{
org.w3c.dom.Node nodo= spawnFreqsList.item(k);
int type = nodo.getNodeType();
//if (type == org.w3c.dom.Node.)
String nodeName = nodo.getNodeName();
//String nodeValue = nodo.getNodeValue();
//String nodeName = spawnFreqsList.item(k).getNodeName();
//String nodeValue = spawnFreqsList.item(k).getFirstChild().getNodeValue();
if (nodeName.equals("car")){
org.w3c.dom.Node child = nodo.getFirstChild();
freqs[0] = child.getNodeValue();
}
if (nodeName.equals("bus")){
org.w3c.dom.Node child = nodo.getFirstChild();
freqs[1] = child.getNodeValue();
}
if (nodeName.equals("bicycle")){
org.w3c.dom.Node child = nodo.getFirstChild();
freqs[2] = child.getNodeValue();
}
}
spawnFreqsHM.put(nodeid,freqs);
}
}
}
spawnFreqsList.add(spawnFreqsHM);
}
iFreqs = spawnFreqsList.iterator();
//updateSpawnFreqs();
}
/** Gets the speed of the simulation */
public int getSpeed() { return thread.getSleepTime(); }
/** Sets the speed of the simulation */
public void setSpeed(int s) { thread.setSleepTime(s); }
/** New road users are placed on the roads when necessary. When roads are full,
* new road users are queued.
*/
public void spawnNewRoadusers() throws InfraException,ClassNotFoundException
{
SpecialNode[] specialNodes = infra.getSpecialNodes();
EdgeNode edge;
Roaduser r;
int num_edges=specialNodes.length;
LinkedList wqueue;
ListIterator list;
for(int i=0;i<num_edges;i++) {
if ( ! (specialNodes[i] instanceof EdgeNode) )
break;
else
edge=(EdgeNode)(specialNodes[i]);
boolean placed = false;
wqueue = edge.getWaitingQueue();
list = wqueue.listIterator();
while(list.hasNext()) {
r = (Roaduser) list.next();
if(placeRoaduser(r, edge)) {
list.remove();
}
}
SpawnFrequency[] freqs = edge.getSpawnFrequencies();
DestFrequency[][] destfreqs = edge.getDestFrequencies();
int num_freqs = freqs.length;
int cur_index;
int[] freqIndexes = new int[num_freqs];
for (int nrs=0;nrs<num_freqs;nrs++)
freqIndexes[nrs] = nrs; //Shuffle the indexes
Arrayutils.randomizeIntArray(freqIndexes, generator);
for(int j=0;j<num_freqs;j++) {
//First try to place new road users on the road.
cur_index = freqIndexes[j];
if(freqs[cur_index].freq >= generator.nextFloat()) {
int ruType = freqs[cur_index].ruType;
/* Spawn road user of type freqs[i].ruType to a random destination.
* When all drivelanes are full the road users are queued.
*/
SpecialNode dest = getRandomDestination( specialNodes, edge, ruType, destfreqs );
r = RoaduserFactory.genRoaduser(ruType, edge, dest, 0);
r.setDrivelaneStartTime(curCycle);
//System.out.println("Origen: " + edge.getId()+ " - Destino: "+dest.getId());
// There might be space for r
if(!placeRoaduser(r, edge)) {
// There was no place on any possible lane.
list.add(r);
}
}//end if
}//end for
}
}
/** A road user is placed on the given edge node. When road is full the ru is queued */
private boolean placeRoaduser(Roaduser r, SpecialNode edge)
{
Drivelane found = findDrivelaneForRU(r,edge);
if(found==null)
return false;
else {
// There is room for me!
try {
//System.out.println("Adding RU with type:"+r.getType()+" to lane:"+found.getSign().getId()+" going to Node:"+found.getNodeLeadsTo().getId()+" at pos:"+found.getNodeLeadsTo().isConnectedAt(found.getRoad())+" with type:"+found.getType());
found.addRoaduserAtEnd(r, found.getLength()-r.getLength());
r.addDelay(curCycle - r.getDrivelaneStartTime());
r.setDrivelaneStartTime(curCycle);
return true;
}
catch(Exception e)
{ return false; }
}
}
private Drivelane findDrivelaneForRU(Roaduser r, SpecialNode e)
{
SpecialNode dest = (SpecialNode) r.getDestNode();
Drivelane[] lanes = (Drivelane[]) e.getShortestPaths(dest.getId(), r.getType()).clone();
Arrayutils.randomizeArray(lanes);
int num_lanes = lanes.length;
for(int i=0;i<num_lanes;i++) {
if(lanes[i].isLastPosFree(r.getLength()))
return lanes[i];
}
//System.out.println("Couldnt place RU");
return null;
}
/** Get a completely random destination, don't choose moi*/
public SpecialNode getRandomDestination(SpecialNode moi) throws InfraException
{ SpecialNode[] dests=infra.getSpecialNodes();
if (dests.length < 2 )
throw new InfraException
("Cannot choose random destination. Not enough special nodes.");
SpecialNode result;
while (moi==(result=dests[(int)(generator.nextFloat()*dests.length)]));
return result;
}
/*Choose a destination*/
private SpecialNode getRandomDestination( SpecialNode[] dests, SpecialNode here, int ruType, DestFrequency[][] destfreqs )
{
//GASTON: ESTA FUNCION DECIDE EL DESTINO. HABRÍA QUE CAMBIAR destfreqs para influir en la decisión
//destIds: va a tener los ids de los posibles nodos destino
/*destfreqs: es una matriz con las frecuencias(una fila por cada nodo de tipo EdgeNode, 1 columna por cada ruType (RoadUserType(ej: auto)) ).
Cada nodo tiene una matriz destfreqs indicando las frecuencias hacia cada nodo destino posible*/
int[] destIds = here.getShortestPathDestinations(ruType);
float choice = generator.nextFloat() ; //genero un nro al azar entre 0 y 1
float total = 0f ;
/*All frequencies are between 0 and 1, but their total can be greater than 1*/
for ( int i=0; i<destIds.length ; i++ ) {
//sumo todas las frecuencias (entre todos los nodos destino posible) para el ruType correspondiente
for ( int j=0; j<destfreqs[i].length ; j++ ) {
if ( destfreqs[destIds[i]][j].ruType == ruType ) {
total += destfreqs[destIds[i]][j].freq ;
}
}
}
float sumSoFar = 0f ;
int j = 0 ;
int index = 0 ;
boolean foundIndex = false ;
while ( j<destIds.length && !foundIndex ) {
//ac� se termina de decidir a qu� nodo destino se ir�
for ( int i=0; i<destfreqs[j].length ; i++ ) {
if ( destfreqs[destIds[j]][i].ruType == ruType ) {
float now = (destfreqs[destIds[j]][i].freq)/total ;
if (now+sumSoFar >= choice ) {
foundIndex = true ;
index = j;
}
else {
sumSoFar += now ;
}
}
}
j++;
}
return dests[destIds[index]] ;
}
/*Get a random index out of the lanes*/
private int getRandomLaneNr(Drivelane[] lanes) {
int ind = (int) Math.floor(generator.nextFloat()*(lanes.length));
while(ind!=lanes.length)
ind = (int) Math.floor(generator.nextFloat()*(lanes.length));
return ind ;
}
/**
*
* moving all Roadusers to their new places
*
* @author Blah... why put an author tag at every 10-line piece of code? -> Just because we can! MUHAHAahahahahah!
*/
public void moveAllRoadusers() throws InfraException
{ // Line below is faster than the obvious alternative
Enumeration lanes=Arrayutils.getEnumeration(infra.getAllInboundLanes().toArray());
Drivelane lane;
while (lanes.hasMoreElements()) {
lane=(Drivelane)(lanes.nextElement());
// First you should check wheter they are already moved ......
if(lane.getCycleMoved() != curCycle)
moveLane(lane, null);
}
}
/**
* moving all roadusers from one lane to their new places
*
* @author Jilles V, Arne K, Chaim Z and Siets el S
* @param lane The lane whose roadusers should be moved
* @param callingLanes Vector of drivelanes, for recursive internal use only, this parameter should have the value null, when called from the outside
* @version 1.0
*/
protected void moveLane(Drivelane lane, Vector callingLanes) throws InfraException
{
LinkedList queue;
ListIterator li;
Drivelane sourceLane, destLane;
Node node;
Sign sign;
Roaduser ru;
int ru_pos, ru_des, ru_speed, ru_type, ru_len;
//GASTON: we calculate the statistics for the lane, we will do it in every cycle.
lane.processStats();
//
sign = lane.getSign();
queue = lane.getQueue();
li = queue.listIterator();
while(li.hasNext()) {
try
{
ru = (Roaduser) li.next();
}
catch(Exception e)
{
// When this exception is thrown you removed the first element of the queue, therefore re-create the iterator.
System.out.println("CME");
li = queue.listIterator();
continue;
}
if(!ru.didMove(curCycle)) { // Only attempt to move this RU when it hasnt already
ru.setCycleAsked(curCycle);
ru_pos = ru.getPosition();
ru_speed = ru.getSpeed();
ru_len = ru.getLength();
//Calculating the ranges per drivelane in which this roaduser could get intro
node = sign.getNode();
ru_type = ru.getType();
ru_des = ru.getDestNode().getId();
Drivelane[] possiblelanes = node.getShortestPaths(ru_des, ru_type);
int lanes = possiblelanes.length;
Point[] ranges = new Point[lanes];
// Is our own lane free? If there is any ?????
if(lanes>=1)
{
int i=lane.getPosFree(li,ru_pos,ru_len,ru_speed,ru);
ranges[0] = new Point(i, ru_pos); //Range on own lane is [i, ru_pos]
lanes--;
//Is this lane clear, then figure out the other lanes
if(i==0 && ru_pos-ru_speed <= 0)
{
for(; lanes>0; lanes--) {
Drivelane test_lane = possiblelanes[lanes];
int range = test_lane.getLength()-1;
int max = range - (ru_speed-ru_pos);
while (test_lane.isLastPosFree(ru_len) && range > max ) {
range--;
}
ranges[lanes] = new Point(range, test_lane.getLength()-1); //The range is [range,test_lane]
}
}
else //Don't even bother, empty the ranges of the other lanes
{
for(; lanes>0; lanes--) {
ranges[lanes] = new Point(0, 0); //The range is [range,test_lane]
}
}
}
// =======================================
// The R stuff is now calculated
// Handle Roadusers that possibly can cross a Node
if(ru_pos-ru_speed < 0) {
// Handle Roadusers that get to Special Nodes
//System.out.println("Possibly can cross...");
if(node instanceof SpecialNode) {
//System.out.println("At a SpecialNode, will be removed");
if(ru_pos==0 || 0==lane.getPosFree(li, 0, ru_len, ru_speed, ru)) {
ru.setPosition(-1);
ru.setPrevSign(-1);
li.remove();
tlc.updateRoaduserMove(ru, lane, sign, ru_pos, null, null, 0, possiblelanes, ranges, null);
//Give RoadUser to Edgenode to unload stat information
node.processStats(ru, curCycle, sign);
((SpecialNode)(node)).enter(ru);
ru = null;
}
}
// Handle Roadusers that are (or nearly) at a Sign
else if(lane.getSign().getType()==Sign.NO_SIGN || lane.getSign().mayDrive()) {
//System.out.println("nearly at Sign");
// Can cross-check
if(ru_pos==0 || 0==lane.getPosFree(li, 0, ru_len, ru_speed, ru)) {
ru_type = ru.getType();
ru_des = ru.getDestNode().getId();
//Drivelane[] lanesleadingfrom = node.getLanesLeadingFrom(lane, ru_type);
Drivelane[] shortestpaths = node.getShortestPaths(ru_des, ru_type);
Drivelane[] lanesleadingfrom = node.getAvailableLanesLeadingFrom(lane, ru_type);
destLane = dp.getDirection(ru, lane, lanesleadingfrom, shortestpaths);
//GASTON: I added this lines to check wheter we could find a path or not
if (destLane==null){
//if I we could not find an alternative path for the road users, we erase them from the lane.
lane.getQueue().clear();
return;
}
//FIN DEL CHEQUEO
// Check if there is room on the node
if(destLane.isLastPosFree(ru_len)) {
// Let the RU touch the Sign to refresh/unload some statistical data
// Remove the RU from the present lane, and place it on the destination lane
try{
node.processStats(ru, curCycle, sign);
destLane.addRoaduserAtEnd(ru);
ru.setPrevSign(lane.getSign().getId());
li.remove();
tlc.updateRoaduserMove(ru, lane, sign, ru_pos, destLane, destLane.getSign(), ru.getPosition(), possiblelanes, ranges, destLane);
}
catch(Exception e) { System.out.println("Something screwd up in SimModel.moveLane where a Roaduser is about to cross:"+e); }
}
// Otherwise, check if the next lane should move, and then do just that
else {
// If the position is not free, then check if it already moved this turn, if not:
if (curCycle != destLane.getCycleAsked())
{
//System.out.println("DestLane hasnt been asked whether it has moved..");
if (curCycle != destLane.getCycleMoved())
{
//System.out.println("Waiting for another lane to move..");
Vector ln = callingLanes;
if (ln==null)
{
ln = new Vector();
}
// Detect when there is a cycle of waiting lanes
boolean cycle = false;
if (ln.size()>0) if (ln.firstElement()==lane) cycle = true;
if (cycle)
{
// If that's the case, they should all do one step
Vector rus = new Vector();
// first remove all first cars of all drivelanes and store them in a vector
for (Enumeration e=ln.elements();e.hasMoreElements();)
{
Drivelane dl = (Drivelane) e.nextElement();
Roaduser r = dl.getFirstRoaduser();
rus.addElement(r);
dl.remRoaduserAtStart();
r.setPrevSign(dl.getSign().getId());
node.processStats(r, curCycle, dl.getSign());
}
// Rotate all roadusers one position to the right
Roaduser r = (Roaduser) rus.elementAt(rus.size()-1);
rus.remove(r);
rus.insertElementAt(r,0);
// Now, all waiting drivelanes can move
for (Enumeration e=ln.elements();e.hasMoreElements();)
{
moveLane((Drivelane) e.nextElement(), null);
}
// Now place all stored Roadusers back at the end of another drivelane
for (int i=0; i<rus.size(); i++)
{
Drivelane dlFrom = (Drivelane) ln.elementAt(i==0?rus.size()-1:i-1);
Drivelane dlTo = (Drivelane) ln.elementAt(i);
Roaduser rub = (Roaduser) rus.elementAt(i);
dlTo.addRoaduserAtEnd(rub);
rub.setCycleMoved(curCycle);
Drivelane[] pblanes = dlFrom.getSign().getNode().getShortestPaths(ru_des, ru_type);
// TO DO: updateRUMove, including ranges
//tlc.updateRoaduserMove(ru, dlFrom, dlFrom.getSign(), 0, dlTo, dlTo.getSign(), rub.getPosition(), pbLanes, , destLane);
}
return;
}
else
{
ln.addElement(lane);
moveLane(destLane, ln);
if (lane.getCycleMoved()==curCycle) return;
}
}
}
// Let the RU touch the Sign to rerfesh/unload some statistical data
// Ok now the lane that should have moved, moved so try again .........
if(destLane.isLastPosFree(ru_len)) {
// If the position is free, then move
try{
node.processStats(ru, curCycle, sign);
destLane.addRoaduserAtEnd(ru);
ru.setPrevSign(lane.getSign().getId());
li.remove();
tlc.updateRoaduserMove(ru, lane, sign, ru_pos, destLane, destLane.getSign(), ru.getPosition(), possiblelanes, ranges, destLane);
}
catch(Exception e) {}
}
else {
// Apperently there was no space created on the lane
moveRoaduserOnLane(li, ru, ru_speed, lane);
if(ru.getPosition()==ru_pos) {
// Couldnt move
tlc.updateRoaduserMove(ru, lane, sign, ru_pos, lane, sign, ru_pos, possiblelanes, ranges, destLane);
}
else {
// Did move some
tlc.updateRoaduserMove(ru, lane, sign, ru_pos, lane, sign, ru.getPosition(), possiblelanes, ranges, destLane);
}
}
}
}
}
else {
if(moveRoaduserOnLane(li, ru, ru_speed, lane)!=ru_speed) {
// Light wasnt green, so just advanced some steps...
// Did move some on this lane.
tlc.updateRoaduserMove(ru, lane, sign, ru_pos, lane, sign, ru.getPosition(), possiblelanes, ranges, null);
}
// else Apparently I could overjump my neighbour orso :)
}
}
else {
/* This is when the roaduser doesn't go around the corner
The maximum amount of space per speed is travelled */
moveRoaduserOnLane(li, ru, ru_speed, lane);
if(ru_pos == ru.getPosition()) { // Couldnt move
tlc.updateRoaduserMove(ru, lane, sign, ru_pos, lane, sign, ru_pos, possiblelanes, ranges, null);
}
else { // Did move some
tlc.updateRoaduserMove(ru, lane, sign, ru_pos, lane, sign, ru.getPosition(), possiblelanes, ranges, null);
}
}
if (ru!=null) ru.setCycleMoved(curCycle);
}
}
lane.setCycleAsked(curCycle);
lane.setCycleMoved(curCycle);
}
protected int moveRoaduserOnLane(ListIterator li, Roaduser ru, int speed_left, Drivelane lane) {
int ru_pos = ru.getPosition();
int ru_len = ru.getLength();
int best_pos = ru_pos;
int max_pos = ru_pos;
int target_pos = (ru_pos - speed_left > 0) ? ru_pos-speed_left : 0;
//System.out.println("Targetpos:"+target_pos+" and hasPrev:"+li.hasPrevious());
// Previous should be 'ru'
Roaduser prv = (Roaduser) li.previous();
if(prv==ru && li.hasPrevious()) {
prv = (Roaduser) li.previous();
int prv_pos = prv.getPosition();
max_pos = prv_pos + prv.getLength();
if(target_pos < max_pos && ru instanceof PacCar && !(prv instanceof PacCar))
{
// eat it, car-cannibalism!
if (prv instanceof CustomRoaduser) CustomFactory.removeCustom((CustomRoaduser)prv);
best_pos = target_pos < prv_pos ? prv_pos : target_pos;
prv = null;
li.remove();
}
else
{
if(max_pos < target_pos)
best_pos = target_pos;
else
best_pos = max_pos;
li.next();
}
//System.out.println("RU had previous, now bestpos ="+best_pos);
}
else
best_pos = target_pos;
li.next();
if(best_pos != ru_pos) {
// The Roaduser can advance some positions
ru.setPosition(best_pos);
return (speed_left - (ru_pos-best_pos));
}
else
{
// check for aggressiveness
if (dp instanceof AggressiveDP) {
AggressiveDP adp = (AggressiveDP) dp;
Drivelane[] shortest = lane.getSign().getNode().getShortestPaths(ru.getDestNode().getId(), ru.getType());
try{
if (adp.checkNeighbourLanes(lane, ru, speed_left, shortest)) {
li.remove();
ru.setColor(Color.darkGray);
}
}
catch(InfraException e) { System.out.println("Something has become a little too aggressive."); }
}
return 0;
}
}
/* public class SimModelFreqsUpdate extends Thread
{
public SimModelFreqsUpdate(){
}
public void run( ) {
while (true) {
try {
sleep(1000);
synchronized(this) {
System.out.println("Se levanto el Thread!!");
XMLLoader loader=new XMLLoader(new File("../RedesEjemplo/miRedPrueb3.infra"));
loadAll(loader,getSimModel());
newInfrastructure(model.getInfrastructure());
loader.close();
Enumeration specialNodes = Arrayutils.getEnumeration(infra.getSpecialNodes());
while (specialNodes.hasMoreElements())
((SpecialNode)(specialNodes.nextElement())).;
EdgeNode specialNodes[] = infra.getSpecialNodes();
}
} catch (Exception e) { }
}
}
}
*/
/**
*
* The second thread that runs the simulation.
*
* @author Joep Moritz
* @version 1.0
*/
public class SimModelThread extends Thread
{
/** Is the thread suspended? */
private volatile boolean suspended;
/** Is the thread alive? If this is set to false, the thread will die gracefully */
private volatile boolean alive;
/** The time in milliseconds this thread sleeps after a call to doStep() */
private int sleepTime = 100;
/** Returns the current sleep time */
public int getSleepTime() { return sleepTime; }
/** Sets the sleep time */
public void setSleepTime(int s) { sleepTime = s; }
/**
* Starts the thread.
*/
public SimModelThread( ) {
alive = true;
suspended = true;
}
/**
* Suspends the thread.
*/
public synchronized void pause( ) {
suspended = true;
}
/**
* Resumes the thread.
*/
public synchronized void unpause( ) {
suspended = false;
notify();
}
/**
* Stops the thread. Invoked when the program exitst.
* This method cannot be named stop().
*/
public synchronized void die( ) {
alive = false;
interrupt();
}
/**
* Returns true if the thread is not suspended and not dead
*/
public boolean isRunning( ) {
return !suspended && alive;
}
/**
* Invokes Model.doStep() and sleeps for sleepTime milliseconds
*/
public void run( ) {
while (alive) {
try {
sleep(sleepTime);
synchronized(this) {
while (suspended && alive)
wait();
}
doStep();
} catch (InterruptedException e) { }
}
}
}
// Some XMLSerializable stuff
public void load (XMLElement myElement,XMLLoader loader) throws XMLTreeException,IOException,XMLInvalidInputException
{ super.load(myElement,loader);
setInfrastructure(infra);
Dictionary loadDictionary;
try
{ loadDictionary=infra.getMainDictionary();
}
catch (InfraException ohNo)
{ throw new XMLInvalidInputException
("This is weird. The infra can't make a dictionary for the second "+
"stage loader of the algorithms. Like : "+ohNo);
}
Dictionary infraDictionary=new Hashtable();
infraDictionary.put("infra",infra);
loadDictionary.put("infra",infraDictionary);
boolean savedBySim=("simulator").equals(myElement.getAttribute("saved-by").getValue());
if (savedBySim)
{ thread.setSleepTime(myElement.getAttribute("speed").getIntValue());
simName=myElement.getAttribute("sim-name").getValue();
curCycle=myElement.getAttribute("current-cycle").getIntValue();
TLCFactory factory=new TLCFactory(infra);
tlc = null;
try
{ tlc=factory.getInstanceForLoad
(factory.getNumberByXMLTagName
(loader.getNextElementName()));
loader.load(this,tlc);
System.out.println("Loaded TLC "+tlc.getXMLName());
}
catch (InfraException e2)
{ throw new XMLInvalidInputException
("Problem while TLC algorithm was processing infrastructure :"+e2);
}
tlc.loadSecondStage(loadDictionary);
DPFactory dpFactory=new DPFactory(this,tlc);
try
{ dp=dpFactory.getInstance
(dpFactory.getNumberByXMLTagName
(loader.getNextElementName()));
loader.load(this,dp);
System.out.println("Loaded DP "+dp.getXMLName());
}
catch (ClassNotFoundException e)
{ throw new XMLInvalidInputException
("Problem with creating DP in SimModel."+
"Could not generate instance of DP type :"+e);
}
dp.loadSecondStage(loadDictionary);
loader.load(this,sgnctrl);
sgnctrl.setTLC(tlc);
}
else {
curCycle = 0;
}
while (loader.getNextElementName().equals("dispenser"))
loader.load(this,new NumberDispenser());
}
public XMLElement saveSelf ()
{ XMLElement result=super.saveSelf();
result.addAttribute(new XMLAttribute("sim-name",simName));
result.addAttribute(new XMLAttribute("saved-by","simulator"));
result.addAttribute(new XMLAttribute("speed",thread.getSleepTime()));
result.addAttribute(new XMLAttribute("current-cycle",curCycle));
return result;
}
public void saveChilds (XMLSaver saver) throws IOException,XMLTreeException,XMLCannotSaveException
{ super.saveChilds(saver);
System.out.println("Saving TLC "+tlc.getXMLName());
saver.saveObject(tlc);
System.out.println("Saving DP "+dp.getXMLName());
saver.saveObject(dp);
saver.saveObject(sgnctrl);
}
protected void restartSpawnFreqs(){
if (! hasRun)
{
hasRun=true;
initialize();
}
iFreqs = spawnFreqsList.iterator();
nroFranja = 0;
}
protected void updateSpawnFreqs(){
if (! hasRun)
{
hasRun=true;
initialize();
}
HashMap spawnFreqs = null;
//while (true) {
try {
System.out.println("Se van a cambiar las frecuencias!!");
if (!iFreqs.hasNext()){
iFreqs = spawnFreqsList.iterator();
nroFranja = 0;
}
nroFranja ++;
System.out.println("Franja Horaria: " + nroFranja);
spawnFreqs = (HashMap)iFreqs.next();
Node[] nodos = infra.getAllNodes();
int k = 0;
for (int i=0;i<nodos.length;i++){
if (nodos[i] instanceof EdgeNode){
EdgeNode en = ((EdgeNode)nodos[i]);
String[] freqs = (String[])spawnFreqs.get(Integer.toString(en.getId()));
setSpawnFrequency(en,1,Float.parseFloat(freqs[0]));
setSpawnFrequency(en,2,Float.parseFloat(freqs[1]));
setSpawnFrequency(en,3,Float.parseFloat(freqs[2]));
}
//we could reinit the statistics, so they are not influenced by the old behaviour
/*anyway, we will not reinit them here, they will be reinitiated after we export the
* statistics of the current simulation
*/
/*
nodos[i].initStats();
Drivelane[] lanes = nodos[i].getAllLanes();
for (int j = 0; j < lanes.length; j++) {
Drivelane drivelane = lanes[j];
drivelane.initStats();
}*/
}
} catch (Exception e) {
System.out.println("Se lanzó una excepción");
e.printStackTrace();
}
infra.reset();
}
/**
* GASTON: Send the statistics to the DLC module.
*/
public void sendStatistics()
{
active = true;
//new StatisticsController(this);
}
public class StatisticsSender extends Thread{
SimModel model = null;
boolean alive = true;
public void run() {
while (alive) {
try {
synchronized(this){
while (!active)
sleep(500);
}
new StatisticsController(model,rb);
active = false;
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public SimModel getModel() {
return model;
}
/**
* @param b
*/
public void setAlive(boolean b) {
alive = b;
}
/**
* @param model
*/
public void setModel(SimModel model) {
this.model = model;
}
}
/**
* @return
*/
public ResourceBundle getResourceBundle() {
return rb;
}
/**
* @param bundle
*/
public void setResourceBundle(ResourceBundle bundle) {
rb = bundle;
}
}