package org.opentrafficsim.demo.ntm;
import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collection;
import java.util.LinkedHashMap;
import java.util.Map;
import org.djunits.unit.FrequencyUnit;
import org.djunits.unit.LengthUnit;
import org.djunits.unit.SpeedUnit;
import org.djunits.value.vdouble.scalar.Frequency;
import org.djunits.value.vdouble.scalar.Length;
import org.djunits.value.vdouble.scalar.Speed;
import org.geotools.data.FileDataStoreFinder;
import org.geotools.data.shapefile.ShapefileDataStore;
import org.geotools.data.simple.SimpleFeatureCollection;
import org.geotools.data.simple.SimpleFeatureIterator;
import org.geotools.data.simple.SimpleFeatureSource;
import org.geotools.geometry.jts.JTSFactoryFinder;
import org.locationtech.jts.geom.Coordinate;
import org.locationtech.jts.geom.Geometry;
import org.locationtech.jts.geom.GeometryFactory;
import org.locationtech.jts.geom.LineString;
import org.locationtech.jts.geom.Point;
import org.opengis.feature.Property;
import org.opengis.feature.simple.SimpleFeature;
import org.opentrafficsim.core.geometry.OTSLine3D;
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 Sep 11, 2014
* @author Alexander Verbraeck
* @author Guus Tamminga
*/
public class ShapeFileReader
{
/**
* @param shapeFileName String; the areas shapefile to read
* @param centroids Map<String,NTMNode>; the map of centroids
* @return map of areas with areanr as the key
* @throws IOException on error
*/
public static Map readAreas(final String shapeFileName, final Map centroids,
double scalingFactorDemand) throws IOException
{
/*-
the_geom class com.vividsolutions.jts.geom.MultiPolygon MULTIPOLYGON (((81816.4228569232, ...
AREANR class java.lang.Long 15127
NAME class java.lang.String 70 Oostduinen
CENTROIDNR class java.lang.Long 1
NAMENR class java.lang.Long 175
GEMEENTE_N class java.lang.String S Gravenhage
GEMEENTEVM class java.lang.String sGravenhage
GEBIEDSNAA class java.lang.String Studiegebied
REGIO class java.lang.String Den_Haag
MATCOMPRES class java.lang.String Scheveningen
DHB class java.lang.Double 70.0
PARKEERTAR class java.lang.String
AREATAG class java.lang.String
*/
URL url;
if (new File(shapeFileName).canRead())
{
url = new File(shapeFileName).toURI().toURL();
}
else
{
url = ShapeFileReader.class.getResource(shapeFileName);
}
ShapefileDataStore storeAreas = (ShapefileDataStore) FileDataStoreFinder.getDataStore(url);
Map areas = new LinkedHashMap<>();
SimpleFeatureSource featureSourceAreas = storeAreas.getFeatureSource();
SimpleFeatureCollection featureCollectionAreas = featureSourceAreas.getFeatures();
SimpleFeatureIterator iterator = featureCollectionAreas.features();
Long newNr = 100000000L;
int numberOfAreasWithoutCentroid = 0;
int numberOfAreasWithCentroid = 0;
try
{
// loop through the areas
while (iterator.hasNext())
{
SimpleFeature feature = iterator.next();
Geometry geometry = (Geometry) feature.getAttribute("the_geom");
// String nr = String.valueOf(feature.getAttribute("AREANR"));
String centroidNr = "C" + String.valueOf(feature.getAttribute("CENTROIDNR"));
String name = (String) feature.getAttribute("NAME");
String gemeente = (String) feature.getAttribute("GEMEENTEVM");
String gebied = (String) feature.getAttribute("GEBIEDSNAA");
String regio = (String) feature.getAttribute("REGIO");
// double dhb = (double) feature.getAttribute("DHB");
/*
* String gemeente = "empty"; String gebied = "empty"; String regio = "empty";
*/
double dhb = (double) 0.0;
NTMNode centroidNode = null;
if (centroids != null)
{
// search for areas within the centroids (from the "points")
centroidNode = centroids.get(centroidNr);
}
if (centroidNode == null)
{
for (NTMNode node : centroids.values())
{
Geometry g = new GeometryFactory().createPoint(node.getPoint().getCoordinate());
if (geometry.contains(g))
{
centroidNode = node;
centroidNr = node.getId();
}
}
}
if (centroidNode == null)
{
// System.out.println("Centroid with number " + centroidNr + " not found for area " + nr + " (" +
// name
// + ")");
numberOfAreasWithoutCentroid++;
}
else
{
if (areas.containsKey(centroidNr))
{
System.out.println("Area number " + centroidNr + "(" + name + ") already exists. Number not unique!");
newNr++;
centroidNr = newNr.toString();
}
double accCritMaxCapStart = 25;
double accCritMaxCapEnd = 50;
double accCritJam = 100;
double increaseDemandByFactor = scalingFactorDemand;
ArrayList accCritical = new ArrayList();
accCritical.add(accCritMaxCapStart);
accCritical.add(accCritMaxCapEnd);
accCritical.add(accCritJam);
ParametersNTM parametersNTM = new ParametersNTM(accCritical);
Area area = new Area(geometry, centroidNr, name, gemeente, gebied, regio, dhb,
centroidNode.getPoint().getCoordinate(), TrafficBehaviourType.NTM, new Length(0, LengthUnit.METER),
new Speed(0, SpeedUnit.KM_PER_HOUR), increaseDemandByFactor, parametersNTM);
areas.put(centroidNr, area);
numberOfAreasWithCentroid++;
}
}
if (centroids != null)
{
System.out.println("Number of centroids " + centroids.size());
System.out.println("Number of areas with centroids " + numberOfAreasWithCentroid);
System.out.println("Number of areas without centroids " + numberOfAreasWithoutCentroid);
}
}
catch (Exception problem)
{
problem.printStackTrace();
}
finally
{
iterator.close();
storeAreas.dispose();
}
int teller = 0;
if (centroids != null)
{
for (NTMNode centroid : centroids.values())
{
boolean found = false;
if (areas.containsKey(centroid.getId()))
{
found = true;
teller++;
}
if (!found)
{
areas.put(centroid.getId(), BuildGraph.createMissingArea(centroid));
System.out.println("Centroid not found: create area for " + centroid.getId());
}
}
}
System.out.println("found : " + teller);
return areas;
}
/**
* @param shapeFileName String; the nodes shapefile to read
* @param numberType String;
* @param returnCentroid boolean; , if true only loop through the centroid/zones (in case of mixed nodes and centroids)
* @param allCentroids boolean; , if true: the file only contains centroids (a centroid file)
* @return map of (shape file) nodes with nodenr as the key
* @throws IOException on error
*/
public static Map ReadNodes(final NTMModel model, final String shapeFileName, final String numberType,
boolean returnCentroid, boolean allCentroids) throws IOException
{
/*-
* the_geom class com.vividsolutions.jts.geom.Point POINT (190599 325650)
* NODENR class java.lang.Long 18
* NAME class java.lang.String
* X class java.lang.Double 190599.0
* Y class java.lang.Double 325650.0
* ...
*/
URL url;
if (new File(shapeFileName).canRead())
{
url = new File(shapeFileName).toURI().toURL();
}
else
{
url = ShapeFileReader.class.getResource(shapeFileName);
}
ShapefileDataStore storeNodes = (ShapefileDataStore) FileDataStoreFinder.getDataStore(url);
Map nodes = new LinkedHashMap<>();
SimpleFeatureSource featureSourceNodes = storeNodes.getFeatureSource();
SimpleFeatureCollection featureCollectionNodes = featureSourceNodes.getFeatures();
SimpleFeatureIterator iterator = featureCollectionNodes.features();
try
{
while (iterator.hasNext())
{
SimpleFeature feature = iterator.next();
Point p = (Point) feature.getAttribute("the_geom");
Coordinate point = new Coordinate(p.getX(), p.getY());
String nr = CsvFileReader.removeQuotes(String.valueOf(feature.getAttribute(numberType)));
boolean addThisNode = false;
TrafficBehaviourType type = null;
if (returnCentroid)
{
if (nr.substring(0, 1).equals("C") || allCentroids)
{
addThisNode = true;
type = TrafficBehaviourType.NTM;
}
}
else
{
if (nr == null)
{
System.out.println("null found");
}
if (!nr.substring(0, 1).equals("C"))
{
addThisNode = true;
type = TrafficBehaviourType.ROAD;
}
}
if (addThisNode)
{
double x;
double y;
if (feature.getAttribute("X") != null)
{
x = (double) feature.getAttribute("X");
y = (double) feature.getAttribute("Y");
}
else
{
x = point.x;
y = point.y;
}
// initially, set the behaviour default to TrafficBehaviourType.ROAD
NTMNode node = new NTMNode(model.getNetwork(), nr, point, type);
nodes.put(nr, node);
}
}
}
catch (Exception problem)
{
problem.printStackTrace();
}
finally
{
iterator.close();
storeNodes.dispose();
}
System.out.println("aantal knopen (353): geteld " + nodes.size());
return nodes;
}
/* *//**
* @param number
* @return nr: the number of the Node without characters
*/
/*
* public static String NodeCentroidNumber(String number) { // String nr = null; number =
* CsvFileReader.removeQuotes(number); String[] names = number.split(":"); String name = names[0]; if (name.charAt(0) ==
* 'C') { name = name.substring(1); // nr = (long) Long.parseLong(name); } return name; }
*/
/**
* @param number String;
* @return nr: the number of the Node without characters
*/
public static boolean inspectNodeCentroid(String number)
{
boolean isCentroid = false;
number = CsvFileReader.removeQuotes(number);
String[] names = number.split(":");
String name = names[0];
if (name.charAt(0) == 'C')
{
isCentroid = true;
}
return isCentroid;
}
/**
* @param shapeFileName String; the nodes shapefile to read
* @param links Map<String,NTMLink>; : returns the file with real links
* @param connectors Map<String,NTMLink>; returns the file with artificial links to a centroid/zone
* @param nodes Map<String,NTMNode>; the map of nodes to retrieve start and end node
* @param centroids Map<String,NTMNode>; the centroids to check start and end Node
* @param lengthUnit String;
* @param linkCapacityNumberOfHours Double;
* @throws IOException on error
*/
public static void readLinks(final NTMModel model, final String shapeFileName, Map links,
Map connectors, Map nodes, Map centroids, String lengthUnit,
Double linkCapacityNumberOfHours) throws IOException
{
/*-
* the_geom class com.vividsolutions.jts.geom.MultiLineString MULTILINESTRING ((232250.38755446894 ...
* LINKNR class java.lang.Long 1
* NAME class java.lang.String
* DIRECTION class java.lang.Long 1
* LENGTH class java.lang.Double 1.80327678
* ANODE class java.lang.Long 684088
* BNODE class java.lang.Long 1090577263
* LINKTAG class java.lang.String 967536
* WEGTYPEAB class java.lang.String mvt
* TYPEWEGVAB class java.lang.String asw 2x2 (8600)
* TYPEWEG_AB class java.lang.String 12 Autosnelweg 2x2
* SPEEDAB class java.lang.Double 120.0
* CAPACITYAB class java.lang.Double 8600.0
* ...
*/
URL url;
if (new File(shapeFileName).canRead())
{
url = new File(shapeFileName).toURI().toURL();
}
else
{
url = ShapeFileReader.class.getResource(shapeFileName);
}
ShapefileDataStore storeLinks = (ShapefileDataStore) FileDataStoreFinder.getDataStore(url);
SimpleFeatureSource featureSourceLinks = storeLinks.getFeatureSource();
SimpleFeatureCollection featureCollectionLinks = featureSourceLinks.getFeatures();
SimpleFeatureIterator iterator = featureCollectionLinks.features();
try
{
while (iterator.hasNext())
{
SimpleFeature feature = iterator.next();
GeometryFactory geometryFactory = JTSFactoryFinder.getGeometryFactory();
Geometry geometry = (Geometry) feature.getAttribute("the_geom");
Coordinate[] coords = geometry.getCoordinates();
LineString line = geometryFactory.createLineString(coords);
String nr = String.valueOf(feature.getAttribute("LINKNR"));
String nrBA = nr + "_BA";
String name = String.valueOf(feature.getAttribute("NAME"));
// the reason to use String.valueOf(...) is that the .dbf files sometimes use double,
// but also represent LENGTH by a string ....
double lengthIn = Double.parseDouble(String.valueOf(feature.getAttribute("LENGTH")));
Length length = null;
if (lengthUnit.equals("kilometer"))
{
length = new Length(lengthIn, LengthUnit.KILOMETER);
}
else if (lengthUnit.equals("meter"))
{
length = new Length(lengthIn, LengthUnit.METER);
}
short direction = (short) Long.parseLong(String.valueOf(feature.getAttribute("DIRECTION")));
String lNodeA = String.valueOf(feature.getAttribute("ANODE"));
String lNodeB = String.valueOf(feature.getAttribute("BNODE"));
// long lNodeB = NodeCentroidNumber(String.valueOf(feature.getAttribute("BNODE")));
String linkTag = (String) feature.getAttribute("LINKTAG");
String wegtype = (String) feature.getAttribute("WEGTYPEAB");
String typeWegVak = (String) feature.getAttribute("TYPEWEGVAB");
String typeWeg = (String) feature.getAttribute("TYPEWEG_AB");
Double speedIn = Double.parseDouble(String.valueOf(feature.getAttribute("SPEEDAB")));
Speed speed = new Speed(speedIn, SpeedUnit.KM_PER_HOUR);
double capacityIn =
Double.parseDouble(String.valueOf(feature.getAttribute("CAPACITYAB"))) / linkCapacityNumberOfHours;
Frequency capacity = new Frequency(capacityIn, FrequencyUnit.PER_HOUR);
int hierarchy = 0;
// new DoubleScalar.Abs(shpLink.getLength(), LengthUnit.KILOMETER);
// create the link or connector to a centroid....
NTMNode centroidA = centroids.get(lNodeA);
NTMNode centroidB = centroids.get(lNodeB);
NTMNode nodeA = nodes.get(lNodeA);
NTMNode nodeB = nodes.get(lNodeB);
boolean nodeACentroid = false;
boolean nodeBCentroid = false;
if (centroidA == null && centroidB == null) // all normal links....
{
if (nodeA != null && nodeB != null)
{
NTMLink linkAB = null;
NTMLink linkBA = null;
LinkData linkData = new LinkData(name, linkTag, wegtype, typeWegVak, typeWeg);
linkAB = new NTMLink(model.getNetwork(), model.getSimulator(), new OTSLine3D(line), nr, length, nodeA,
nodeB, speed, null, capacity, TrafficBehaviourType.ROAD, linkData);
linkData = new LinkData(name + "_BA", linkTag, wegtype, typeWegVak, typeWeg);
linkBA = new NTMLink(model.getNetwork(), model.getSimulator(), new OTSLine3D(line), nrBA, length, nodeB,
nodeA, speed, null, capacity, TrafficBehaviourType.ROAD, linkData);
if (direction == 1)
{
links.put(nr, linkAB);
}
else if (direction == 2)
{
links.put(nrBA, linkBA);
}
else if (direction == 3)
{
links.put(nr, linkAB);
links.put(nrBA, linkBA);
}
}
else
{
System.out.println("Node lNodeA=" + lNodeA + " or lNodeB=" + lNodeB + " not found for linknr=" + nr
+ ", name=" + name);
}
}
else
{ // possibly a link that connects to a centroid
// but first test the geometry of the node/centroid: is it a node or is it a centroid?
if (centroidA != null)
{
if (testGeometry(geometry.getCoordinates()[0], centroidA.getPoint().getCoordinate()))
{
nodeACentroid = true;
}
}
if (centroidB != null)
{
if (testGeometry(geometry.getCoordinates()[geometry.getCoordinates().length - 1],
centroidA.getPoint().getCoordinate()))
{
nodeBCentroid = true;
}
}
if (nodeACentroid && nodeBCentroid) // should not happen
{
System.out.println("Strange connector!!!: both Centroids lNodeA= " + centroidA + " or lNodeB= "
+ centroidB + " connected to linknr=" + nr + ", name=" + name);
}
else if (nodeACentroid)
{
NTMLink linkAB = null;
NTMLink linkBA = null;
LinkData linkData = new LinkData(name, linkTag, wegtype, typeWegVak, typeWeg);
linkAB = new NTMLink(model.getNetwork(), model.getSimulator(), new OTSLine3D(line), nr, length,
centroidA, nodeB, speed, null, capacity, TrafficBehaviourType.NTM, linkData);
linkData = new LinkData(name + "_BA", linkTag, wegtype, typeWegVak, typeWeg);
linkBA = new NTMLink(model.getNetwork(), model.getSimulator(), new OTSLine3D(line), nrBA, length, nodeB,
centroidA, speed, null, capacity, TrafficBehaviourType.NTM, linkData);
if (direction == 1)
{
connectors.put(nr, linkAB);
}
else if (direction == 2)
{
connectors.put(nrBA, linkBA);
}
else if (direction == 3)
{
connectors.put(nr, linkAB);
connectors.put(nrBA, linkBA);
}
}
else if (nodeBCentroid)
{
NTMLink linkAB = null;
NTMLink linkBA = null;
LinkData linkData = new LinkData(name, linkTag, wegtype, typeWegVak, typeWeg);
linkAB = new NTMLink(model.getNetwork(), model.getSimulator(), new OTSLine3D(line), nr, length, nodeA,
centroidB, speed, null, capacity, TrafficBehaviourType.NTM, linkData);
linkData = new LinkData(name + "_BA", linkTag, wegtype, typeWegVak, typeWeg);
linkBA = new NTMLink(model.getNetwork(), model.getSimulator(), new OTSLine3D(line), nrBA, length,
centroidB, nodeA, speed, null, capacity, TrafficBehaviourType.NTM, linkData);
if (direction == 1)
{
connectors.put(nr, linkAB);
}
else if (direction == 2)
{
connectors.put(nrBA, linkBA);
}
else if (direction == 3)
{
connectors.put(nr, linkAB);
connectors.put(nrBA, linkBA);
}
}
else
// should not happen
{
LinkData linkData = new LinkData(name, linkTag, wegtype, typeWegVak, typeWeg);
NTMLink link = new NTMLink(model.getNetwork(), model.getSimulator(), new OTSLine3D(line), nr, length,
nodeA, nodeB, speed, null, capacity, TrafficBehaviourType.ROAD, linkData);
links.put(nr, link);
}
}
}
}
catch (Exception problem)
{
problem.printStackTrace();
}
finally
{
iterator.close();
storeLinks.dispose();
}
}
/**
* @param coordinate Coordinate;
* @param centroid Coordinate;
* @return if TRUE: the points match geographically
*/
public static boolean testGeometry(final Coordinate coordinate, final Coordinate centroid)
{
boolean geomEqual = false;
if (Math.abs(coordinate.x - centroid.x) < 1)
{
if (Math.abs(coordinate.y - centroid.y) < 1)
{
geomEqual = true;
}
}
return geomEqual;
}
/**
* @param shapeFileName String; the areas shapefile to read
* @throws IOException on error
*/
public static void shapeFileInfo(final String shapeFileName) throws IOException
{
URL url;
if (new File(shapeFileName).canRead())
{
url = new File(shapeFileName).toURI().toURL();
}
else
{
url = ShapeFileReader.class.getResource(shapeFileName);
}
ShapefileDataStore store = (ShapefileDataStore) FileDataStoreFinder.getDataStore(url);
SimpleFeatureSource featureSource = store.getFeatureSource();
SimpleFeatureCollection featureCollection = featureSource.getFeatures();
SimpleFeatureIterator iterator = featureCollection.features();
try
{
while (iterator.hasNext())
{
SimpleFeature feature = iterator.next();
Collection areaProperties = feature.getProperties();
for (Property p : areaProperties)
{
System.out.println(p.getName() + " " + p.getValue().getClass() + " " + p.getValue().toString());
}
return;
}
}
catch (Exception problem)
{
problem.printStackTrace();
}
finally
{
iterator.close();
store.dispose();
}
}
}