package org.opentrafficsim.demo.ntm;
import java.util.ArrayList;
import java.util.Collection;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import org.djunits.unit.DurationUnit;
import org.djunits.unit.FrequencyUnit;
import org.djunits.unit.LengthUnit;
import org.djunits.unit.SpeedUnit;
import org.djunits.value.vdouble.scalar.Duration;
import org.djunits.value.vdouble.scalar.Frequency;
import org.djunits.value.vdouble.scalar.Length;
import org.djunits.value.vdouble.scalar.Speed;
import org.jgrapht.GraphPath;
import org.jgrapht.alg.shortestpath.DijkstraShortestPath;
import org.jgrapht.graph.SimpleDirectedWeightedGraph;
import org.locationtech.jts.geom.Coordinate;
import org.locationtech.jts.geom.Envelope;
import org.locationtech.jts.geom.Geometry;
import org.locationtech.jts.geom.GeometryFactory;
import org.locationtech.jts.geom.TopologyException;
import org.locationtech.jts.index.SpatialIndex;
import org.locationtech.jts.index.strtree.STRtree;
import org.opentrafficsim.core.network.LinkEdge;
import org.opentrafficsim.core.network.NetworkException;
import org.opentrafficsim.demo.ntm.NTMNode.TrafficBehaviourType;
/**
*
* Copyright (c) 2013-2017 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved.
* BSD-style license. See OpenTrafficSim License.
*
* $LastChangedDate$, @version $Revision$, by $Author$,
* initial version 29 Oct 2014
* @author Alexander Verbraeck
* @author Hans van Lint
* @author Peter Knoppers
* @author Guus Tamminga
* @author Yufei Yuan
*/
public class BuildGraph
{
/**
* Build the graph using roads between touching areas, flowLinks and Cordon areas (artificially created).
*/
static void buildGraph(NTMModel model, Map areasToUse, Map centroidsToUse,
Map shpConnectorsToUse)
{
/** Debug information?. */
final boolean DEBUG = false;
// temporary storage for nodes and edges mapped from the number to the node
Map nodeMap = new LinkedHashMap<>();
// Map nodeAreaGraphMap = new LinkedHashMap<>();
Map areaNodeCentroidMap = new LinkedHashMap<>();
Map> linkMap = new LinkedHashMap<>();
ArrayList allLinks = new ArrayList();
allLinks.addAll(model.getShpLinks().values());
allLinks.addAll(model.getFlowLinks().values());
allLinks.addAll(shpConnectorsToUse.values());
/*
* //generate the incoming and outgoing links from nodes for (Link link: allLinks) {
* link.getStartNode().getIncomingLinks().add(link); link.getEndNode().getIncomingLinks().add(link); }
*/// make a directed graph of the entire network
// FIRST CREATE the LinkGraph
for (NTMLink shpLink : allLinks)
{
// area node: copies a node from a link and connects the area
// the nodeMap connects the shpNodes to these new AreaNode
BoundedNode nodeA = (BoundedNode) nodeMap.get(shpLink.getStartNode().getId());
if (nodeA == null)
{
nodeA = addNodeToLinkGraph(shpLink, (NTMNode) shpLink.getStartNode(), nodeMap, areasToUse.values(), model);
}
BoundedNode nodeB = (BoundedNode) nodeMap.get(shpLink.getEndNode().getId());
if (nodeB == null)
{
nodeB = addNodeToLinkGraph(shpLink, (NTMNode) shpLink.getEndNode(), nodeMap, areasToUse.values(), model);
}
try
{
LinkEdge linkEdge = new LinkEdge<>(shpLink);
model.getLinkGraph().addEdge(nodeA, nodeB, linkEdge);
double speed = shpLink.getFreeSpeed().getInUnit(SpeedUnit.METER_PER_SECOND);
double length = shpLink.getLength().getInUnit(LengthUnit.METER);
double travelTime = length / speed;
model.getLinkGraph().setEdgeWeight(linkEdge, travelTime);
linkMap.put(shpLink.getId(), linkEdge);
}
catch (Exception e)
{
e.printStackTrace();
}
// The flow links are included in the AREA graph: here the vertices are already added
if (shpLink.getBehaviourType() == TrafficBehaviourType.FLOW)
{
nodeA = (BoundedNode) model.getNodeAreaGraphMap().get(shpLink.getStartNode().getId());
if (nodeA == null)
{
nodeA = addNodeToAreaGraph(shpLink, (NTMNode) shpLink.getStartNode(), model.getNodeAreaGraphMap(),
areaNodeCentroidMap, areasToUse.values(), model);
}
nodeB = (BoundedNode) model.getNodeAreaGraphMap().get(shpLink.getEndNode().getId());
if (nodeB == null)
{
nodeB = addNodeToAreaGraph(shpLink, (NTMNode) shpLink.getEndNode(), model.getNodeAreaGraphMap(),
areaNodeCentroidMap, areasToUse.values(), model);
}
}
}
// and finally put all centroids in the Graph as vertices
for (Area area : areasToUse.values())
{
// find the new centroids in the big areas
BoundedNode node = findCentroidInArea(model, area, centroidsToUse.values());
// BoundedNode node = nodeMap.get(area.getCentroidNr());
if (node != null)
{
// put centroid back in links
if (node.getArea().getRoadLength().doubleValue() == Double.POSITIVE_INFINITY)
{
node.setBehaviourType(TrafficBehaviourType.CORDON);
}
areaNodeCentroidMap.put(area, node);
model.getNodeAreaGraphMap().put(node.getId(), node);
model.getAreaGraph().addVertex(node);
// model.getLinkGraph().addVertex(node);
}
else
{
System.out.println("Build graph line 133: look out, no area connected!!!");
}
}
// ///////////////////////////////////////
// SECOND part: the AREA graph creation:
// The next section creates the EDGES
// First, add all GIS-like objects in an array
ArrayList gisObjects = new ArrayList();
gisObjects.addAll(areasToUse.values());
// gisObjects.addAll(this.flowLinks.values());
findTouching(gisObjects);
// Secondly, find the Areas that do not touch any other area and connect them with the nearest areas!!
connectIsolatedAreas(model, model.getNodeAreaGraphMap(), areaNodeCentroidMap, areasToUse.values());
if (DEBUG)
{
// test: from node 314071 (Scheveningen) to node 78816 (Voorburg)
NTMNode nSch = nodeMap.get("314071");
NTMNode nVb = nodeMap.get("78816");
DijkstraShortestPath> dijkstra = new DijkstraShortestPath<>(model.getLinkGraph());
GraphPath> sp = dijkstra.getPath(nSch, nVb);
System.out.println("\nScheveningen -> Voorburg");
System.out.println("Length=" + sp.getLength());
List> spList = sp.getEdgeList();
if (spList != null)
{
for (LinkEdge le : spList)
{
System.out.println(le.getLink().getLinkData().getName());
}
}
}
// iterate over the roads and create the areaGraph
// this connects the areas and highways
// map them on the area centroids
// The LinkEdges already have a travel time (allLinks not)
for (LinkEdge le : linkMap.values())
{
Area aA;
Area aB;
/*
* if (le.getLink().getStartNode().getId().equals("65800") && le.getLink().getEndNode().getId().equals("78816")) {
* System.out.println("no"); }
*/
aA = findArea(le.getLink().getStartNode().getPoint().getCoordinate(), areasToUse.values());
aB = findArea(le.getLink().getEndNode().getPoint().getCoordinate(), areasToUse.values());
// When this is a flow link, inspect if they connect to urban roads
// if so, create a GraphEdge that connects flow roads with urban roads / areas (in/out going)
if (le.getLink().getBehaviourType() == TrafficBehaviourType.FLOW)
{
// make FLOW connectors (in the areaGraph!!)
// create cellTransmissionLinks for the edges of the real FLOW connectors
// every CTM link receives a set of FlowCells that will be simulated as a nested process within the
// Network Transmission Model
createFlowConnectors(aA, aB, le, linkMap, areaNodeCentroidMap, model.getNodeAreaGraphMap(), model, areasToUse);
}
// for all other links, inspect if they connect areas (startNode in areaA and endNode in area B (or vice
// versa))
else if (aA != null && aB != null && aA.getTouchingAreas().contains(aB))
{
BoundedNode cA = null;
BoundedNode cB = null;
cA = (BoundedNode) areaNodeCentroidMap.get(aA);
cB = (BoundedNode) areaNodeCentroidMap.get(aB);
// first, test if these links connect two different areas (not within one area)
if (cA.getId() != cB.getId())
{
if (model.getAreaGraph().containsEdge(cA, cB))
{
if (le.getLink().getCapacity() != null && model.getAreaGraph().getEdge(cA, cB).getLink() != null)
{
if (model.getAreaGraph().getEdge(cA, cB).getLink().getCorridorCapacity() != null)
{
model.getAreaGraph().getEdge(cA, cB).getLink().addCorridorCapacity(le.getLink().getCapacity());
}
else
{
System.out.println("no corridorCapacity computed for this link/edge: node " + cA + " , " + cB);
}
}
else
{
System.out.println("no capacity computed for this link/edge: node " + cA + " , " + cB);
}
}
else
{
// Create the edge that connects two areas and find the time to travel between centroids
if (cA != null && cB != null)
{
// Node cAVertex = model.getLinkGraph().vertexSet().contains(cA)?cA:null;
NTMNode cAVertex = null;
NTMNode cBVertex = null;
for (NTMNode node : model.getLinkGraph().vertexSet())
{
if (node.getId().equals(cA.getId()))
{
cAVertex = node;
}
if (node.getId().equals(cB.getId()))
{
cBVertex = node;
}
}
if (cAVertex == null || cBVertex == null)
{
throw new RuntimeException("cAVertex == null || cBVertex == null");
}
Speed speedA = null;
Speed speedB = null;
// TODO: checken
if (cA.getBehaviourType() == TrafficBehaviourType.NTM)
{
CellBehaviourNTM cellBehaviourNTMA = (CellBehaviourNTM) cA.getCellBehaviour();
speedA = cellBehaviourNTMA.getParametersNTM().getFreeSpeed();
}
else if (cA.getBehaviourType() == TrafficBehaviourType.CORDON)
{
speedA = new Speed(70, SpeedUnit.KM_PER_HOUR);
}
if (cB.getBehaviourType() == TrafficBehaviourType.NTM)
{
CellBehaviourNTM cellBehaviourNTMB = (CellBehaviourNTM) cB.getCellBehaviour();
speedB = cellBehaviourNTMB.getParametersNTM().getFreeSpeed();
}
else if (cB.getBehaviourType() == TrafficBehaviourType.CORDON)
{
speedB = new Speed(70, SpeedUnit.KM_PER_HOUR);
}
addGraphConnector(model, cAVertex, cBVertex, speedA, speedB, le, TrafficBehaviourType.NTM);
}
// TODO is the distance between two points in Amersfoort Rijksdriehoeksmeting Nieuw in m or in
// km?
else if (cA == null || cB == null)
{
System.out.println("cA == null || cB == null");
}
}
}
}
// else
// {
// System.out.println("test: cA == cB??");
// }
}
// add the flowLinks and their A and B nodes as special types of areaNodes and edges
// add the unconnected cordon feeders
// create the connections between the cordon connectors and their nearest areas or roads
if (DEBUG)
{
// test: from node 314071 (Scheveningen) to node 78816 (Voorburg)
System.out.println("\nScheveningen -> Voorburg via centroids");
Coordinate pSch = nodeMap.get("314071").getPoint().getCoordinate();
Coordinate pVb = nodeMap.get("78816").getPoint().getCoordinate();
Area aSch;
Area aVb;
aSch = findArea(pSch, areasToUse.values());
aVb = findArea(pVb, areasToUse.values());
if (aSch == null || aVb == null)
{
System.out.println("Could not find areas");
}
else
{
BoundedNode cSch = (BoundedNode) areaNodeCentroidMap.get(aSch);
BoundedNode cVb = (BoundedNode) areaNodeCentroidMap.get(aVb);
DijkstraShortestPath> dijkstra = new DijkstraShortestPath<>(model.getAreaGraph());
GraphPath> sp = dijkstra.getPath(cSch, cVb);
System.out.println("Length=" + sp.getLength());
List> spList = sp.getEdgeList();
if (spList != null)
{
for (LinkEdge le : spList)
{
System.out.println(le.getLink().getId());
}
}
System.out.println("Length = " + System.currentTimeMillis());
}
}
}
/**
* @param model NTMModel;
* @param cAVertex NTMNode;
* @param cBVertex NTMNode;
*/
private static void addGraphConnector(NTMModel model, NTMNode cAVertex, NTMNode cBVertex, Speed speedA, Speed speedB,
LinkEdge le, TrafficBehaviourType trafficBehaviourType)
{
DijkstraShortestPath> sp = new DijkstraShortestPath<>(model.getLinkGraph());
// if (model.getLinkGraph().containsVertex(cAVertex) && model.getLinkGraph().containsVertex(cBVertex))
// {
// sp = new DijkstraShortestPath>(model.getLinkGraph(), cAVertex, cBVertex);
// }
/*
* else { System.out.println("no grapph for this node " + cAVertex + " or , " + cBVertex); }
*/
Duration time = null;
if (sp != null)
{
if (sp.getPath(cAVertex, cBVertex) != null)
{
time = new Duration(sp.getPath(cAVertex, cBVertex).getWeight(), DurationUnit.HOUR);
double xA = cAVertex.getPoint().getCoordinate().x;
double yA = cAVertex.getPoint().getCoordinate().y;
double xB = cBVertex.getPoint().getCoordinate().x;
double yB = cBVertex.getPoint().getCoordinate().y;
// TODO check distance by coordinates!!!!
double distance = 1.3 * Math.sqrt(Math.pow(xB - xA, 2) + Math.pow(yB - yA, 2));
double timeDouble = 0.5 * distance / speedA.getSI() + 0.5 * distance / speedB.getSI();
time = new Duration(timeDouble, DurationUnit.SECOND);
double speedDouble =
0.5 * speedA.getInUnit(SpeedUnit.KM_PER_HOUR) + 0.5 * speedB.getInUnit(SpeedUnit.KM_PER_HOUR);
Speed speed = new Speed(speedDouble, SpeedUnit.KM_PER_HOUR);
NTMLink newLink = NTMLink.createLink(model.getNetwork(), model.getSimulator(), cAVertex, cBVertex, null, speed,
time, trafficBehaviourType);
if (((NTMLink) le.getLink()).getCapacity() != null)
{
newLink.setCorridorCapacity(((NTMLink) le.getLink()).getCapacity());
}
else
{
System.out.println("no capacity computed for this link/edge: node " + cAVertex + " , " + cBVertex);
}
LinkEdge newLinkEdge = new LinkEdge<>(newLink);
addLinkEdge(cAVertex, cBVertex, newLinkEdge, trafficBehaviourType, model.getAreaGraph());
}
else
{
System.out.println("No path between these nodes, while trying to connect areas" + cAVertex + ", " + cBVertex);
}
}
}
/**
* @param flowNodeA NTMNode;
* @param flowNodeB NTMNode;
* @param centroidA
* @param centroidB
* @param le
* @param type TrafficBehaviourType;
*/
private static void addLinkEdge(NTMNode flowNodeA, NTMNode flowNodeB, LinkEdge linkEdge, TrafficBehaviourType type,
SimpleDirectedWeightedGraph> graph)
{
if (!graph.containsEdge(flowNodeA, flowNodeB))
{
try
{
if (graph.containsVertex(flowNodeA) && graph.containsVertex(flowNodeB))
{
if (flowNodeA != flowNodeB)
{
graph.addEdge(flowNodeA, flowNodeB, linkEdge);
if (linkEdge.getLink().getDuration() != null)
{
graph.setEdgeWeight(linkEdge, linkEdge.getLink().getDuration().getInUnit(DurationUnit.HOUR));
}
else
{
java.lang.Double timeDouble = linkEdge.getLink().getLength().getInUnit(LengthUnit.KILOMETER)
/ linkEdge.getLink().getFreeSpeed().getInUnit(SpeedUnit.KM_PER_HOUR);
Duration time = new Duration(timeDouble, DurationUnit.HOUR);
linkEdge.getLink().setDuration(time);
graph.setEdgeWeight(linkEdge, linkEdge.getLink().getDuration().getInUnit(DurationUnit.HOUR));
}
}
else
{
System.out.println("same nodes????");
}
}
else
{
System.out.println("missing");
}
}
catch (Exception exception1)
{
exception1.printStackTrace();
}
}
/*
* else { System.out.println("Already found"); }
*/
// TODO average length? straight distance? straight distance + 20%?
}
/**
* @param shpLink NTMLink; link
* @param node node
* @param map Map<String,NTMNode>; receives node
*/
private static BoundedNode addNodeToLinkGraph(NTMLink shpLink, NTMNode shpLinkNode, Map map,
Collection areas, NTMModel model)
{
Area area = findArea(shpLinkNode.getPoint().getCoordinate(), areas);
/*
* if (area == null) { System.out.println("Could not find area for NodeA of shapeLink " + shpLinkNode); }
*/
// BoundedNode node1 = (BoundedNode) shpLinkNode;
// node1.setArea(area);
BoundedNode node;
try
{
node = new BoundedNode(model.getNetwork(), shpLinkNode.getPoint().getCoordinate(), shpLinkNode.getId(), area,
shpLink.getBehaviourType());
}
catch (NetworkException exception)
{
exception.printStackTrace();
node = null;
}
map.put(shpLinkNode.getId(), node);
if (!model.getLinkGraph().containsVertex(node))
{
model.getLinkGraph().addVertex(node);
}
else
{
throw new RuntimeException("Node added to network: already existed " + node.getId());
}
return node;
}
/**
* @param shpLink NTMLink; link
* @param node node
* @param nodeGraphMap Map<String,NTMNode>; receives node
*/
private static BoundedNode addNodeToAreaGraph(NTMLink shpLink, NTMNode shpLinkNode, Map nodeGraphMap,
Map areaNodeCentroidMap, Collection areas, NTMModel model)
{
Area area = findArea(shpLinkNode.getPoint().getCoordinate(), areas);
/*
* if (area == null) { System.err.println("Could not find area for NodeA of shapeLink " + shpLinkNode); }
*/
// BoundedNode node1 = (BoundedNode) shpLinkNode;
// node1.setArea(area);
BoundedNode node;
try
{
node = new BoundedNode(model.getNetwork(), shpLinkNode.getPoint().getCoordinate(), shpLinkNode.getId(), area,
shpLink.getBehaviourType());
}
catch (NetworkException exception)
{
exception.printStackTrace();
node = null;
}
nodeGraphMap.put(shpLinkNode.getId(), node);
areaNodeCentroidMap.put(area, node);
shpLinkNode = node;
if (!model.getAreaGraph().containsVertex(node))
{
model.getAreaGraph().addVertex(node);
}
return node;
}
/**
* @param area Area; the point to search.
* @return the area that contains point p, or null if not found.
*/
private static BoundedNode findCentroidInArea(NTMModel model, final Area area, Collection collection)
{
BoundedNode centroid = null;
for (NTMNode node : collection)
{
Geometry g = new GeometryFactory().createPoint(node.getPoint().getCoordinate());
if (area.getGeometry().contains(g))
{
// TODO later: why multiple areas
/*
* if (area != null) { System.out.println("findArea: point " + p.toText() + " is in multiple areas: " +
* a.getCentroidNr() + " and " + area.getCentroidNr()); }
*/
try
{
if (node.getId().equals(area.getName()))
{
centroid = new BoundedNode(model.getNetwork(), node.getPoint().getCoordinate(), node.getId(), area,
node.getBehaviourType());
}
else if (centroid == null)
{
centroid = new BoundedNode(model.getNetwork(), node.getPoint().getCoordinate(), node.getId(), area,
node.getBehaviourType());
}
}
catch (NetworkException exception)
{
exception.printStackTrace();
}
}
}
return centroid;
}
/**
* @param c Coordinate; the point to search.
* @return the area that contains point p, or null if not found.
*/
private static Area findArea(final Coordinate c, Collection areas)
{
Geometry g = new GeometryFactory().createPoint(c);
Area area = null;
for (Area a : areas)
{
if (a.getGeometry().contains(g))
{
// TODO later: why multiple areas
/*
* if (area != null) { System.out.println("findArea: point " + p.toText() + " is in multiple areas: " +
* a.getCentroidNr() + " and " + area.getCentroidNr()); }
*/
area = a;
}
}
return area;
}
/**
* @param geom1 Geometry;
* @param geom2 Geometry;
* @return
*/
private static boolean findBoundaryAreas(Geometry geom1, Geometry geom2)
{
boolean touch = false;
Envelope e1 = geom1.getEnvelopeInternal();
try
{
// if (area != area2 && (area.getDesignLine().touches(area2.getDesignLine())
// || area.getDesignLine().intersects(area2.getDesignLine())))
// first see if envelopes overlap
if (geom1 != geom2 && e1.intersects(geom2.getEnvelopeInternal()))
{
// 1 meter distance
// if (area1.getDesignLine().isWithinDistance(area2.getDesignLine(), 1.0d))
if (geom1.touches(geom2) || geom1.intersects(geom2))
{
touch = true;
}
else if (geom1.isWithinDistance(geom2, 50.0d))
{
touch = true;
}
}
}
catch (TopologyException te)
{
System.out.println("TopologyException " + te.getMessage() + " when checking border of " + geom1 + " and " + geom2);
}
return touch;
}
/**
* finds the Areas that do not touch any other area and connects them with the nearest areas!!
* @param areaNodeCentroidMap Map<Area,NTMNode>;
* @param areaGraph2
* @param linkGraph2
* @param areas2
*/
private static void connectIsolatedAreas(final NTMModel model, final Map nodeGraphMap,
final Map areaNodeCentroidMap, final Collection areas)
{
final SpatialIndex index = new STRtree();
for (Area areaIndex : areas)
{
Geometry geom = areaIndex.getGeometry();
if (geom != null)
{
Envelope env = geom.getEnvelopeInternal();
if (!env.isNull())
{
index.insert(env, areaIndex);
}
}
}
// try and find
final double MAX_SEARCH_DISTANCE = 8000.0; // meters?
final int NUMBER_OF_AREAS = 6;
for (Area isolatedArea : areas)
{
if (isolatedArea.getTouchingAreas().size() == 0)
{
System.out.println("no touching area for number " + isolatedArea.getCentroidNr() + ", Area type: "
+ isolatedArea.getTrafficBehaviourType());
if (isolatedArea.getCentroidNr().equals("3794"))
{
System.out.println("no ");
}
// Get point and create search envelope
Geometry geom = isolatedArea.getGeometry();
Envelope search = geom.getEnvelopeInternal();
double searchDistance = MAX_SEARCH_DISTANCE;
search.expandBy(searchDistance);
/*
* Query the spatial index for objects within the search envelope. Note that this just compares the point
* envelope to the line envelopes so it is possible that the point is actually more distant than
* MAX_SEARCH_DISTANCE from a line.
*/
@SuppressWarnings("unchecked")
List nearestAreas = index.query(search);
while (nearestAreas.size() > NUMBER_OF_AREAS && searchDistance > 0.1)
{
double decreaseBy = -0.2 * searchDistance;
searchDistance += decreaseBy;
search.expandBy(decreaseBy);
nearestAreas = index.query(search);
}
// now find the nearest Areas that are connected by a road
// / TODO the next part contains errors!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
NTMNode nodeIsolated = areaNodeCentroidMap.get(isolatedArea);
for (Area nearArea : nearestAreas)
{
NTMNode nodeNear = areaNodeCentroidMap.get(nearArea);
try
{
if (!model.getLinkGraph().containsVertex(nodeNear))
{
System.out.println("No nodeNear");
}
else if (!model.getLinkGraph().containsVertex(nodeIsolated))
{
System.out.println("No nodeNear");
}
else
{
DijkstraShortestPath> dijkstra =
new DijkstraShortestPath<>(model.getLinkGraph());
GraphPath> sp = dijkstra.getPath(nodeIsolated, nodeNear);
List> spList = sp.getEdgeList();
if (spList != null)
{
double cumulativeTime = 0;
double cumulativeLength = 0;
for (LinkEdge le : spList)
{
double speed = le.getLink().getFreeSpeed().getInUnit(SpeedUnit.KM_PER_HOUR);
double length = le.getLink().getLength().getInUnit(LengthUnit.KILOMETER);
cumulativeTime += length / speed;
cumulativeLength += length;
Area enteredArea = findArea(le.getLink().getEndNode().getPoint().getCoordinate(), areas);
if (enteredArea != null && enteredArea != isolatedArea
&& le.getLink().getBehaviourType() != TrafficBehaviourType.FLOW)
{
isolatedArea.getTouchingAreas().add(enteredArea);
NTMNode centroidEntered = areaNodeCentroidMap.get(enteredArea);
if (centroidEntered == null)
{
System.out.println("No node in this area");
}
Speed speedA = new Speed(cumulativeLength / cumulativeTime, SpeedUnit.KM_PER_HOUR);
addGraphConnector(model, nodeIsolated, centroidEntered, speedA, speedA, le,
nodeIsolated.getBehaviourType());
break;
}
else if (le.getLink().getBehaviourType() == TrafficBehaviourType.FLOW)
{
NTMNode bN = nodeGraphMap.get(le.getLink().getStartNode().getId());
Speed speedA = new Speed(cumulativeLength / cumulativeTime, SpeedUnit.KM_PER_HOUR);
addGraphConnector(model, nodeIsolated, bN, speedA, speedA, le,
nodeIsolated.getBehaviourType());
break;
}
}
}
dijkstra = new DijkstraShortestPath<>(model.getLinkGraph());
sp = dijkstra.getPath(nodeNear, nodeIsolated);
spList = sp.getEdgeList();
if (spList != null)
{
double cumulativeTime = 0;
double cumulativeLength = 0;
for (LinkEdge le : spList)
{
double speed = le.getLink().getFreeSpeed().getInUnit(SpeedUnit.KM_PER_HOUR);
double length = le.getLink().getLength().getInUnit(LengthUnit.KILOMETER);
cumulativeTime += length / speed;
cumulativeLength += length;
Area enteredArea = findArea(le.getLink().getEndNode().getPoint().getCoordinate(), areas);
if (enteredArea != null && enteredArea != isolatedArea
&& le.getLink().getBehaviourType() != TrafficBehaviourType.FLOW)
{
isolatedArea.getTouchingAreas().add(enteredArea);
NTMNode centroidEntered = areaNodeCentroidMap.get(enteredArea);
if (centroidEntered == null)
{
System.out.println("No node in this area");
}
Speed speedA = new Speed(cumulativeLength / cumulativeTime, SpeedUnit.KM_PER_HOUR);
addGraphConnector(model, centroidEntered, nodeIsolated, speedA, speedA, le,
nodeIsolated.getBehaviourType());
break;
}
else if (le.getLink().getBehaviourType() == TrafficBehaviourType.FLOW)
{
NTMNode bN = nodeGraphMap.get(le.getLink().getStartNode().getId());
Speed speedA = new Speed(cumulativeLength / cumulativeTime, SpeedUnit.KM_PER_HOUR);
addGraphConnector(model, bN, nodeIsolated, speedA, speedA, le,
nodeIsolated.getBehaviourType());
break;
}
}
}
}
}
catch (Exception e)
{
e.printStackTrace();
}
}
// find the nearest areas and connect them (HERE? of further down this Class...)
// TODO make the code
}
}
}
/**
* @param areaStart Area;
* @param areaEnd Area;
* @param le LinkEdge<NTMLink>;
* @param linkMap Map<String,LinkEdge<NTMLink>>;
* @param areaNodeCentroidMap Map<Area,NTMNode>;
*/
private static void createFlowConnectors(final Area areaStart, final Area areaEnd, final LinkEdge le,
final Map> linkMap, final Map areaNodeCentroidMap,
final Map nodeGraphMap, NTMModel model, Map areasToUse)
{
NTMNode node = (NTMNode) le.getLink().getStartNode();
BoundedNode flowNodeStart = (BoundedNode) nodeGraphMap.get(node.getId());
if (flowNodeStart.getArea() == null)
{
flowNodeStart.setArea(areaStart);
}
// BoundedNode flowNodeStart = new BoundedNode(node.getPoint().getCoordinate(), node.getId(), areaStart,
// node.getBehaviourType());
node = (NTMNode) le.getLink().getEndNode();
BoundedNode flowNodeEnd = (BoundedNode) nodeGraphMap.get(node.getId());
if (flowNodeEnd.getArea() == null)
{
flowNodeEnd.setArea(areaStart);
}
NTMLink link = le.getLink();
ArrayList cells =
LinkCellTransmission.createCells(link, model.getSettingsNTM().getTimeStepDurationCellTransmissionModel());
LinkCellTransmission linkCTM;
try
{
linkCTM = new LinkCellTransmission(link, flowNodeStart, flowNodeEnd, cells);
}
catch (NetworkException exception)
{
exception.printStackTrace();
linkCTM = null;
}
@SuppressWarnings({"unchecked", "rawtypes"})
LinkEdge leNew = new LinkEdge(linkCTM);
addLinkEdge(flowNodeStart, flowNodeEnd, leNew, TrafficBehaviourType.FLOW, model.getAreaGraph());
// loop through the other links to find the links that connect
BoundedNode cA = null;
BoundedNode cB = null;
// cA = areaNodeCentroidMap.get(areaStart);
// cB = areaNodeCentroidMap.get(areaEnd);
for (LinkEdge urbanLink : linkMap.values())
{
if (urbanLink.getLink().getBehaviourType() == TrafficBehaviourType.ROAD
|| urbanLink.getLink().getBehaviourType() == TrafficBehaviourType.NTM)
{
if (urbanLink.getLink().getEndNode().getId().equals(flowNodeStart.getId()))
{
// from urban (Area) to Highway (flow)
Area aStart = findArea(urbanLink.getLink().getStartNode().getPoint().getCoordinate(), areasToUse.values());
cA = (BoundedNode) areaNodeCentroidMap.get(aStart);
if (aStart != null)
{
if (cA == null || flowNodeStart == null)
{
System.out.println("No connection of flow Link to Area for this one...");
}
Speed speed = new Speed(70, SpeedUnit.KM_PER_HOUR);
Frequency capacity =
new Frequency(4000.0, FrequencyUnit.PER_HOUR);
NTMLink newLink = NTMLink.createLink(model.getNetwork(), model.getSimulator(), cA, flowNodeStart,
capacity, speed, null, TrafficBehaviourType.NTM);
LinkEdge newLinkEdge = new LinkEdge<>(newLink);
addLinkEdge(cA, flowNodeStart, newLinkEdge, TrafficBehaviourType.NTM, model.getAreaGraph());
}
else
{
System.out.println("BuildGraph line 785: this Node is outside any area: "
+ urbanLink.getLink().getStartNode().getId());
}
}
if (urbanLink.getLink().getStartNode().getId().equals(flowNodeEnd.getId()))
{
// from Highway (flow) to urban (Area)
Area aEnd = findArea(urbanLink.getLink().getEndNode().getPoint().getCoordinate(), areasToUse.values());
cB = (BoundedNode) areaNodeCentroidMap.get(aEnd);
if (aEnd != null)
{
if (cB == null || flowNodeStart == null)
{
System.out.println("No connection of flow Link to Area for this one...");
}
Speed speed = new Speed(70, SpeedUnit.KM_PER_HOUR);
Frequency capacity = new Frequency(4000.0, FrequencyUnit.PER_HOUR);
NTMLink newLink = NTMLink.createLink(model.getNetwork(), model.getSimulator(), flowNodeEnd, cB,
capacity, speed, null, TrafficBehaviourType.NTM);
LinkEdge newLinkEdge = new LinkEdge<>(newLink);
addLinkEdge(flowNodeEnd, cB, newLinkEdge, TrafficBehaviourType.NTM, model.getAreaGraph());
}
else
{
System.out.println("BuildGraph line 812 this Node is outside any area: "
+ urbanLink.getLink().getEndNode().getId());
}
}
}
else if (urbanLink.getLink().getBehaviourType() == TrafficBehaviourType.CORDON)
{
if (urbanLink.getLink().getEndNode().getId().equals(flowNodeStart.getId()))
{
// from urban (Area) to Highway (flow)
node = (NTMNode) urbanLink.getLink().getStartNode();
cA = (BoundedNode) nodeGraphMap.get(node.getId());
// cA = new BoundedNode(node.getPoint().getCoordinate(), node.getId(), areaStart, node.getBehaviourType());
// cA = (BoundedNode) urbanLink.getLink().getStartNode();
if (cA != null)
{
if (flowNodeStart.getArea() == null)
{
cA.setArea(areaStart);
}
Speed speed = new Speed(70, SpeedUnit.KM_PER_HOUR);
Frequency capacity = new Frequency(4000.0, FrequencyUnit.PER_HOUR);
NTMLink newLink = NTMLink.createLink(model.getNetwork(), model.getSimulator(), cA, flowNodeStart,
capacity, speed, null, TrafficBehaviourType.CORDON);
LinkEdge newLinkEdge = new LinkEdge<>(newLink);
addLinkEdge(cA, flowNodeStart, newLinkEdge, TrafficBehaviourType.CORDON, model.getAreaGraph());
}
}
else if (urbanLink.getLink().getStartNode().getId().equals(flowNodeEnd.getId()))
{
// from Highway (flow) to urban (Area)
node = (NTMNode) urbanLink.getLink().getEndNode();
cB = (BoundedNode) nodeGraphMap.get(node.getId());
// cB = new BoundedNode(node.getPoint().getCoordinate(), node.getId(), areaEnd, node.getBehaviourType());
// cB = (BoundedNode) urbanLink.getLink().getStartNode();
if (cB != null)
{
if (flowNodeStart.getArea() == null)
{
cB.setArea(areaStart);
}
Speed speed = new Speed(70, SpeedUnit.KM_PER_HOUR);
Frequency capacity = new Frequency(4000.0, FrequencyUnit.PER_HOUR);
NTMLink newLink = NTMLink.createLink(model.getNetwork(), model.getSimulator(), flowNodeEnd, cB,
capacity, speed, null, TrafficBehaviourType.CORDON);
LinkEdge newLinkEdge = new LinkEdge<>(newLink);
addLinkEdge(flowNodeEnd, cB, newLinkEdge, TrafficBehaviourType.CORDON, model.getAreaGraph());
}
}
}
}
}
// Create new Areas where they are lacking
/**
* @param centroid NTMNode;
* @return the additional areas
*/
public static Area createMissingArea(final NTMNode centroid)
{
Geometry cg = new GeometryFactory().createPoint(centroid.getPoint().getCoordinate());
Geometry buffer = cg.buffer(30);
String nr = centroid.getId();
String name = centroid.getId();
String gemeente = "Area is missing for: " + centroid.getId();
String gebied = "Area is missing for: " + centroid.getId();
String regio = "Missing";
double dhb = 0.0;
Double increaseDemandByFactor = 1.0;
ParametersNTM parametersNTM = new ParametersNTM();
Area area = new Area(buffer, nr, name, gemeente, gebied, regio, dhb, centroid.getPoint().getCoordinate(),
TrafficBehaviourType.NTM, new Length(0, LengthUnit.METER), new Speed(0, SpeedUnit.KM_PER_HOUR),
increaseDemandByFactor, parametersNTM);
return area;
}
/*
* // Create new Areas where they are lacking
*//**
* @param centroid
* @return the additional areas
*/
public SimpleDirectedWeightedGraph copySimpleDirectedWeightedGraph(final SimpleDirectedWeightedGraph graph)
{
SimpleDirectedWeightedGraph copyOfGraph = null;
return copyOfGraph;
}
/**
* For every area, find the touching areas
* @param gisObjects ArrayList<GeoObject>;
*/
private static void findTouching(ArrayList gisObjects)
{
// then find out if they touch
for (GeoObject gis1 : gisObjects)
{
Geometry geom1 = gis1.getGeometry();
for (GeoObject gis2 : gisObjects)
{
Geometry geom2 = gis2.getGeometry();
// if the areas geometrically touch or intersect:
if (findBoundaryAreas(geom1, geom2))
{
gis1.getTouchingAreas().add(gis2);
}
}
}
// inspect, if there are objects without neighbours
for (GeoObject gis1 : gisObjects)
{
if (gis1.getTouchingAreas() == null)
{
Area noTouch = (Area) gis1;
System.out.println("no touching area for this one" + noTouch.getCentroidNr());
}
}
}
}