/************************************************************************************ * Copyright (C) 2008 by Politehnica University of Bucharest and Rutgers University * All rights reserved. * Refer to LICENSE for terms and conditions of use. ***********************************************************************************/ package vnsim.vehicular.simulator.intersections; import java.util.ArrayList; import java.util.Collections; import java.util.LinkedList; import java.util.ListIterator; import vnsim.applications.adaptiveTL.*; import vnsim.applications.trafficview.SimulatedCarInfo; import vnsim.map.object.*; import vnsim.vehicular.simulator.RouteSegment; public class DirectedRoadSegment implements java.io.Serializable { // represents a road segment of road "roadIndex", starting // from point "pointIndex" going either towards point "0" (if // "direction"=false) or towards the last point on the road // (if "direction"=true); private static final long serialVersionUID = -5883719321862303634L; public int roadIndex; public int pointIndex; public boolean direction; public int segmentIndex; public Intersection intersection = null; public double angle; // degrees ( 0 - 360) public SortedIntersectionRecordList cars = null; public ArrayList paths = new ArrayList(); public IntersectionCarRecord[] endOfQueue = null; public double[] queueDischargeRate; public double leftProc; public double pedestrianCrossingTime = 0; // seconds public double noOfStops = 0; public int totalLaneNo; public Road road; public int demand = 0; public int totalVolume = 0; public int carryOver = 0; TrafficLightInfo lightInfo = null; TrafficLightInfo newLightInfo = null; public WirelessTrafficLight nextwtl = null; public int nextwtlPointIndex = -1; public DirectedRoadSegment left = null, right = null, front = null, pair = null; // queue sizes measured for a speciffic analysis period public LinkedList queueSizes = new LinkedList(); public int crossedLeft = 0; public DirectedRoadSegment(int roadIndex, int pointIndex, boolean direction) { this.roadIndex=roadIndex; this.pointIndex=pointIndex; this.direction=direction; // set the angle Road r1 = Globals.map.roads.get(roadIndex); this.road = r1; Point p1 = r1.points.get(pointIndex); Point p2; if (direction) { p2 = Globals.map.roads.get(roadIndex).points.get(pointIndex + 1); } else { p2 = Globals.map.roads.get(roadIndex).points.get(pointIndex - 1); } double dy = p2.getLatitude() - p1.getLatitude(); double dx = p2.getLongitude() - p1.getLongitude(); if (dx == 0) { if (dy > 0) angle = 90.0; else angle = 270.0; return; } double rads = Math.atan(dy / dx); if (rads > 0) { if (dx > 0) { // dx and dy both positive angle = Math.toDegrees(rads); } else { // both negative angle = Math.toDegrees(rads + Math.PI); } } else { if (dx < 0) { // dx negative, dy positive angle = Math.toDegrees(Math.PI + rads); } else { // dy negative, dx positive angle = Math.toDegrees(2 * Math.PI + rads); } } // compute crossing time and maximum intergreen time Road r = Globals.map.roads.get(roadIndex); if (r.oneWay == 0) { totalLaneNo = 2 * r.laneNo; } else { totalLaneNo = r.laneNo; } pedestrianCrossingTime = Math.ceil((double) (totalLaneNo * Globals.LANE_WIDTH) / Globals.PEDESTRIAN_SPEED); } public boolean equals(Object o) { try { DirectedRoadSegment drs = (DirectedRoadSegment) o; if (drs.roadIndex == roadIndex && drs.pointIndex == pointIndex && drs.direction == direction) return true; return false; } catch (Exception ex) { return false; } } public boolean isSameSegment(RouteSegment s1) { // should be on the same road if (s1.roadIndex != this.roadIndex) return false; // should have a point in common if (s1.pt1 == this.pointIndex) { if (s1.pt2 < s1.pt1 && this.direction == false) return true; if (s1.pt2 > s1.pt1 && this.direction == true) return true; } if (s1.pt2 == this.pointIndex) { if (s1.pt1 < s1.pt2 && this.direction == false) return true; if (s1.pt1 > s1.pt2 && this.direction == true) return true; } return false; } public boolean isExitOnly() { Road r = Globals.map.roads.get(roadIndex); if (r.oneWay == 0) return false; if (r.oneWay == 1) { if (direction) return true; else return false; } if (r.oneWay == 2) { if (direction) return false; else return true; } System.out.println("ERROR! isExitOnly found an unexpected value for oneWay!"); return false; } public boolean isEntryOnly() { Road r = Globals.map.roads.get(roadIndex); if (r.oneWay == 0) return false; if (r.oneWay == 1) { if (direction) return false; else return true; } if (r.oneWay == 2) { if (direction) return true; else return false; } System.out.println("ERROR! isEntryOnly found an unexpected value for oneWay!"); return false; } public boolean carEntersIntersection(IntersectionCarRecord icr) { SimulatedCarInfo sc = icr.getCar(); if (roadIndex == sc.getRoadIdx() && sc.getPointIdx() == pointIndex && (sc.getDirection() == 1) == !direction) return true; return false; } public boolean carExitsIntersection(IntersectionCarRecord icr) { SimulatedCarInfo sc = icr.getCar(); if (roadIndex == sc.getRoadIdx() && sc.getPointIdx() == pointIndex && (sc.getDirection() == 1) == direction) return true; return false; } public boolean containsCar(IntersectionCarRecord icr) { SimulatedCarInfo sc = icr.getCar(); if (roadIndex == sc.getRoadIdx() && ((sc.getPointIdx() > pointIndex && direction == true) || (sc.getPointIdx() < pointIndex && direction == false))) { // || (sc.getPointIdx() == pointIndex) && (sc.getDirection() == 1) // == direction)) if (nextwtl != null) { if (direction == true && sc.getPointIdx() >= nextwtlPointIndex) return false; if (direction == false && sc.getPointIdx() <= nextwtlPointIndex) return false; } return true; } return false; } public boolean isCarApproaching(IntersectionCarRecord icr) { SimulatedCarInfo sc = icr.getCar(); if (this.roadIndex == sc.getRoadIdx()) { if (sc.getPointIdx() >= this.pointIndex && this.direction == true) { if (sc.getDirection() == 1) { return false; } else { return true; } } if (sc.getPointIdx() <= this.pointIndex && this.direction == false) { if (sc.getDirection() == 1) { return true; } else { return false; } } } return false; } public void computeEndOfQueue(IntersectionCarRecord icr) { SimulatedCarInfo car = icr.getCar(); endOfQueue[car.getLane()] = null; ListIterator it = cars.listIterator(); Point px = Globals.map.roads.get(roadIndex).points.get(pointIndex); IntersectionCarRecord end = new IntersectionCarRecord(null); while (it.hasNext()) { IntersectionCarRecord crt = it.next(); SimulatedCarInfo crtcar = crt.getCar(); if (cars.getComparator().compare(crt, icr) > 0 && crtcar.getPointIdx() != car.getPointIdx()) break; if (crtcar.getLane() != car.getLane()) continue; Point p = Globals.map.roads.get(roadIndex).points.get(crtcar.getPointIdx()); double dist = p.getDistance() - px.getDistance(); if (dist < 0) dist = -dist; if (dist < WirelessTrafficLight.MAX_QUEUE_GAP) { end = crt; } px = p; } endOfQueue[car.getLane()] = end; } public boolean isCarQueuing(IntersectionCarRecord icr) { SimulatedCarInfo car = icr.getCar(); if (car.getSpeed() < WirelessTrafficLight.LOW_SPEED) { int lane = car.getLane(); Point p = Globals.map.roads.get(roadIndex).points.get(car.getPointIdx()); Point px = null; if (endOfQueue[lane].getCar() == null) { // intersection point px = Globals.map.roads.get(roadIndex).points.get(pointIndex); } else { if (cars.getComparator().compare(endOfQueue[lane], icr) > 0) return true; if (endOfQueue[lane].equals(icr)) { // endOfQueue[lane] = icr; // return true; int idx = Collections.binarySearch(cars, icr, cars.getComparator()); ListIterator it = cars.listIterator(idx); boolean first = true; while (it.hasPrevious()) { SimulatedCarInfo carInFront = it.previous().getCar(); if (carInFront.getLane() != car.getLane()) continue; first = false; int pi = endOfQueue[lane].getCar().getPointIdx(); px = Globals.map.roads.get(roadIndex).points.get(pi); double dist = p.getDistance() - px.getDistance(); if (dist < 0) dist = -dist; if (dist < WirelessTrafficLight.MAX_QUEUE_GAP * 2) { endOfQueue[lane] = icr; return true; } else { computeEndOfQueue(endOfQueue[lane]); return false; } } if (first) { endOfQueue[lane] = new IntersectionCarRecord(null); return isCarQueuing(icr); } } else { int pi = endOfQueue[lane].getCar().getPointIdx(); px = Globals.map.roads.get(roadIndex).points.get(pi); } } double dist = p.getDistance() - px.getDistance(); if (dist < 0) dist = -dist; if (dist < WirelessTrafficLight.MAX_QUEUE_GAP) { endOfQueue[lane] = icr; return true; } } return false; } // the number of seconds to extend the green phase, for protected left public int leftSignalExtension() { int leftLane = road.laneNo; if (endOfQueue[leftLane].getCar() == null || this.front == null) { return 0; } ListIterator it = cars.listIterator(); int leftRq = 0; while (it.hasNext()) { IntersectionCarRecord crt = it.next(); SimulatedCarInfo crtcar = crt.getCar(); if (crtcar.getLane() != leftLane) { continue; } if (cars.getComparator().compare(crt, endOfQueue[leftLane]) > 0) break; if (crtcar.getSignal() == (byte) 1) { leftRq++; } } if (leftRq == 0) return 0; int i = paths.indexOf(new IntersectionPath(this, this.front)); double stops = paths.get(i).computeAvgNoOfStops(Globals.ANALYSIS_PERIOD); if (stops == 0) stops = 0.5; if (crossedLeft != 0 && (double) (crossedLeft + leftRq) / crossedLeft < 2 * stops) return 0; int shouldPass = (int) (2 * stops * (leftRq + crossedLeft)) - crossedLeft; if (shouldPass == 0) return 0; leftRq = 0; int k = 0; it = cars.listIterator(); while (it.hasNext()) { IntersectionCarRecord crt = it.next(); SimulatedCarInfo crtcar = crt.getCar(); if (crtcar.getLane() != leftLane) { continue; } if (cars.getComparator().compare(crt, endOfQueue[leftLane]) > 0) break; k++; if (crtcar.getSignal() == (byte) 1) { leftRq++; } if (leftRq == shouldPass) { break; } } // 0.5 veh/s return k * 2; } public int computeDemand(int period) { if (paths.size() == 0) return 0; IntersectionPath ip = paths.get(0); demand = ip.computeDemand(period); int left = ip.computeLeftDemand(period); leftProc = (double) left * 100.0 / demand; // if (Globals.engine.crtTime < period ) // demand = (int)((double) (Globals.HOUR * demand) / // Globals.engine.crtTime ); // else // demand = (int)((double) (Globals.HOUR * demand) / period); demand = (int) ((double) (Globals.HOUR * demand) / ip.analysisPeriod); return demand; } public int computeVolume(int period) { totalVolume = 0; noOfStops = 0; int analysisPeriod = 0; for (int i = 0; i < paths.size(); i++) { IntersectionPath ip = paths.get(i); int vol = ip.computeVolume(period); analysisPeriod += ip.analysisPeriod; totalVolume += vol; double stops = ip.computeAvgNoOfStops(period); noOfStops += (double) vol * stops; } try { analysisPeriod /= paths.size(); noOfStops /= totalVolume; totalVolume = (int) ((double) (Globals.HOUR * totalVolume) / analysisPeriod); } catch (Exception e) { totalVolume = 0; noOfStops = 0; } return totalVolume; } // public double computeLastCycleQueueSize(){ // if (paths.size() == 0) // return 0; // IntersectionPath ip = paths.get(0); // return ip.computeLastCycleQueueSize(); // } public void changePhase(DirectedRoadSegment connection, int crtTime, int color) { if (color == Globals.GREEN) { crossedLeft = 0; } if (connection == null) { // one single color for all directions int n = 0; for (int i = 0; i < paths.size(); i++) { IntersectionPath ip = paths.get(i); n += ip.lastHourHistory.getLast().getCarsNo(); ip.changePhase(crtTime, color); } } else { int i = paths.indexOf(connection); assert (i != -1); IntersectionPath ip = paths.get(i); ip.changePhase(crtTime, color); } } public void recordCar(IntersectionCarRecord icr, DirectedRoadSegment newseg) { int i = paths.indexOf(new IntersectionPath(this, newseg)); if (this.left != null && this.left.equals(newseg)) { crossedLeft++; } if (i == -1) return; IntersectionPath ip = paths.get(i); ip.recordCar(icr); } public void recordQueueSize() { double avg = 0; Point px = road.points.get(pointIndex); for (int i = 1; i < endOfQueue.length; i++) { if (endOfQueue[i].getCar() != null) { Point p = road.points.get(endOfQueue[i].getCar().getPointIdx()); avg += Math.abs(p.getDistance() - px.getDistance()); } } try { avg /= endOfQueue.length - 1; } catch (Exception e) { avg = 0; } queueSizes.add(new Double(avg)); while (queueSizes.size() > Globals.ANALYSIS_PERIOD / (10 * Globals.SECOND)) { queueSizes.removeFirst(); } } public double get95thQueueSize() { if (queueSizes.size() == 0) { return 0; } ArrayList array = new ArrayList(); array.addAll(queueSizes); Collections.sort(array); int idx = (int) (array.size() * 0.95); return array.get(idx).doubleValue(); } public String toString() { return "(Rd=" + roadIndex + ";Pt=" + pointIndex + ";Dir=" + direction + " + ANGLE=" + angle + ") "; } public TrafficLightInfo getLightInfo() { return lightInfo; } public void setLightInfo(TrafficLightInfo lightInfo) { this.lightInfo = lightInfo; } public TrafficLightInfo getNewLightInfo() { return newLightInfo; } public void setNewLightInfo(TrafficLightInfo newLightInfo) { this.newLightInfo = newLightInfo; } }