blob: cacd425426435082e17834f429a61e524b72577c [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2012 Bundesinstitut für Risikobewertung.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Bundesinstitut für Risikobewertung - initial API and implementation
*******************************************************************************/
package org.eclipse.stem.graphgenerators.impl;
import java.awt.Point;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import org.eclipse.emf.common.util.EList;
import org.eclipse.emf.common.util.URI;
import org.eclipse.emf.ecore.EClass;
import org.eclipse.emf.ecore.util.EDataTypeEList;
import org.eclipse.stem.core.STEMURI;
import org.eclipse.stem.core.common.DublinCore;
import org.eclipse.stem.core.graph.Edge;
import org.eclipse.stem.core.graph.Graph;
import org.eclipse.stem.core.graph.GraphFactory;
import org.eclipse.stem.core.graph.Node;
import org.eclipse.stem.definitions.adapters.spatial.geo.InlineLatLongDataProvider;
import org.eclipse.stem.definitions.adapters.spatial.geo.LatLong;
import org.eclipse.stem.definitions.adapters.spatial.geo.LatLong.SegmentBuilder;
import org.eclipse.stem.definitions.edges.EdgesFactory;
import org.eclipse.stem.definitions.edges.MigrationEdge;
import org.eclipse.stem.definitions.labels.impl.CommonBorderRelationshipLabelImpl;
import org.eclipse.stem.definitions.labels.impl.RoadTransportRelationshipLabelImpl;
import org.eclipse.stem.definitions.nodes.NodesFactory;
import org.eclipse.stem.definitions.nodes.Region;
import org.eclipse.stem.gis.shp.ShpPolyLine;
import org.eclipse.stem.gis.shp.ShpPolygon;
import org.eclipse.stem.gis.shp.ShpRecord;
import org.eclipse.stem.gis.shp.type.Box;
import org.eclipse.stem.gis.shp.type.Part;
import org.eclipse.stem.graphgenerators.GraphgeneratorsPackage;
import org.eclipse.stem.graphgenerators.ShapefileGraphGenerator;
import org.eclipse.stem.graphgenerators.ShapefileType;
/**
* <!-- begin-user-doc --> An implementation of the model object '
* <em><b>Shapefile Graph Generator</b></em>'. <!-- end-user-doc -->
* <p>
* The following features are implemented:
* <ul>
* <li>
* {@link org.eclipse.stem.graphgenerators.impl.ShapefileGraphGeneratorImpl#getShapefiles
* <em>Shapefiles</em>}</li>
* <li>
* {@link org.eclipse.stem.graphgenerators.impl.ShapefileGraphGeneratorImpl#getRegionIDs
* <em>Region IDs</em>}</li>
* <li>
* {@link org.eclipse.stem.graphgenerators.impl.ShapefileGraphGeneratorImpl#getRoadIDs
* <em>Road IDs</em>}</li>
* <li>
* {@link org.eclipse.stem.graphgenerators.impl.ShapefileGraphGeneratorImpl#getRoadClasses
* <em>Road Classes</em>}</li>
* <li>
* {@link org.eclipse.stem.graphgenerators.impl.ShapefileGraphGeneratorImpl#getShapefileTypes
* <em>Shapefile Types</em>}</li>
* <li>
* {@link org.eclipse.stem.graphgenerators.impl.ShapefileGraphGeneratorImpl#getMigrationIDs
* <em>Migration IDs</em>}</li>
* <li>
* {@link org.eclipse.stem.graphgenerators.impl.ShapefileGraphGeneratorImpl#getMigrationPopulations
* <em>Migration Populations</em>}</li>
* <li>
* {@link org.eclipse.stem.graphgenerators.impl.ShapefileGraphGeneratorImpl#getMigrationRates
* <em>Migration Rates</em>}</li>
* </ul>
* </p>
*
* @generated
*/
public class ShapefileGraphGeneratorImpl extends GraphGeneratorImpl implements
ShapefileGraphGenerator {
/**
* The cached value of the '{@link #getShapefiles() <em>Shapefiles</em>}'
* attribute list. <!-- begin-user-doc --> <!-- end-user-doc -->
*
* @see #getShapefiles()
* @generated
* @ordered
*/
protected EList<String> shapefiles;
/**
* The cached value of the '{@link #getRegionIDs() <em>Region IDs</em>}'
* attribute list. <!-- begin-user-doc --> <!-- end-user-doc -->
*
* @see #getRegionIDs()
* @generated
* @ordered
*/
protected EList<String> regionIDs;
/**
* The cached value of the '{@link #getRoadIDs() <em>Road IDs</em>}'
* attribute list. <!-- begin-user-doc --> <!-- end-user-doc -->
*
* @see #getRoadIDs()
* @generated
* @ordered
*/
protected EList<String> roadIDs;
/**
* The cached value of the '{@link #getRoadClasses() <em>Road Classes</em>}'
* attribute list. <!-- begin-user-doc --> <!-- end-user-doc -->
*
* @see #getRoadClasses()
* @generated
* @ordered
*/
protected EList<String> roadClasses;
/**
* The cached value of the '{@link #getShapefileTypes()
* <em>Shapefile Types</em>}' attribute list. <!-- begin-user-doc --> <!--
* end-user-doc -->
*
* @see #getShapefileTypes()
* @generated
* @ordered
*/
protected EList<ShapefileType> shapefileTypes;
/**
* The cached value of the '{@link #getMigrationIDs()
* <em>Migration IDs</em>}' attribute list. <!-- begin-user-doc --> <!--
* end-user-doc -->
*
* @see #getMigrationIDs()
* @generated
* @ordered
*/
protected EList<String> migrationIDs;
/**
* The cached value of the '{@link #getMigrationPopulations()
* <em>Migration Populations</em>}' attribute list. <!-- begin-user-doc -->
* <!-- end-user-doc -->
*
* @see #getMigrationPopulations()
* @generated
* @ordered
*/
protected EList<String> migrationPopulations;
/**
* The cached value of the '{@link #getMigrationRates()
* <em>Migration Rates</em>}' attribute list. <!-- begin-user-doc --> <!--
* end-user-doc -->
*
* @see #getMigrationRates()
* @generated
* @ordered
*/
protected EList<String> migrationRates;
/**
* <!-- begin-user-doc --> <!-- end-user-doc -->
*
* @generated NOT
*/
public ShapefileGraphGeneratorImpl() {
super();
}
/**
* <!-- begin-user-doc --> <!-- end-user-doc -->
*
* @generated
*/
@Override
protected EClass eStaticClass() {
return GraphgeneratorsPackage.Literals.SHAPEFILE_GRAPH_GENERATOR;
}
/**
* <!-- begin-user-doc --> <!-- end-user-doc -->
*
* @generated
*/
public EList<String> getShapefiles() {
if (shapefiles == null) {
shapefiles = new EDataTypeEList<String>(
String.class,
this,
GraphgeneratorsPackage.SHAPEFILE_GRAPH_GENERATOR__SHAPEFILES);
}
return shapefiles;
}
/**
* <!-- begin-user-doc --> <!-- end-user-doc -->
*
* @generated
*/
public EList<String> getRegionIDs() {
if (regionIDs == null) {
regionIDs = new EDataTypeEList<String>(
String.class,
this,
GraphgeneratorsPackage.SHAPEFILE_GRAPH_GENERATOR__REGION_IDS);
}
return regionIDs;
}
/**
* <!-- begin-user-doc --> <!-- end-user-doc -->
*
* @generated
*/
public EList<String> getRoadIDs() {
if (roadIDs == null) {
roadIDs = new EDataTypeEList<String>(String.class, this,
GraphgeneratorsPackage.SHAPEFILE_GRAPH_GENERATOR__ROAD_IDS);
}
return roadIDs;
}
/**
* <!-- begin-user-doc --> <!-- end-user-doc -->
*
* @generated
*/
public EList<String> getRoadClasses() {
if (roadClasses == null) {
roadClasses = new EDataTypeEList<String>(
String.class,
this,
GraphgeneratorsPackage.SHAPEFILE_GRAPH_GENERATOR__ROAD_CLASSES);
}
return roadClasses;
}
/**
* <!-- begin-user-doc --> <!-- end-user-doc -->
*
* @generated
*/
public EList<ShapefileType> getShapefileTypes() {
if (shapefileTypes == null) {
shapefileTypes = new EDataTypeEList<ShapefileType>(
ShapefileType.class,
this,
GraphgeneratorsPackage.SHAPEFILE_GRAPH_GENERATOR__SHAPEFILE_TYPES);
}
return shapefileTypes;
}
/**
* <!-- begin-user-doc --> <!-- end-user-doc -->
*
* @generated
*/
public EList<String> getMigrationIDs() {
if (migrationIDs == null) {
migrationIDs = new EDataTypeEList<String>(
String.class,
this,
GraphgeneratorsPackage.SHAPEFILE_GRAPH_GENERATOR__MIGRATION_IDS);
}
return migrationIDs;
}
/**
* <!-- begin-user-doc --> <!-- end-user-doc -->
*
* @generated
*/
public EList<String> getMigrationPopulations() {
if (migrationPopulations == null) {
migrationPopulations = new EDataTypeEList<String>(
String.class,
this,
GraphgeneratorsPackage.SHAPEFILE_GRAPH_GENERATOR__MIGRATION_POPULATIONS);
}
return migrationPopulations;
}
/**
* <!-- begin-user-doc --> <!-- end-user-doc -->
*
* @generated
*/
public EList<String> getMigrationRates() {
if (migrationRates == null) {
migrationRates = new EDataTypeEList<String>(
String.class,
this,
GraphgeneratorsPackage.SHAPEFILE_GRAPH_GENERATOR__MIGRATION_RATES);
}
return migrationRates;
}
/**
* <!-- begin-user-doc --> <!-- end-user-doc -->
*
* @generated
*/
@Override
public Object eGet(int featureID, boolean resolve, boolean coreType) {
switch (featureID) {
case GraphgeneratorsPackage.SHAPEFILE_GRAPH_GENERATOR__SHAPEFILES:
return getShapefiles();
case GraphgeneratorsPackage.SHAPEFILE_GRAPH_GENERATOR__REGION_IDS:
return getRegionIDs();
case GraphgeneratorsPackage.SHAPEFILE_GRAPH_GENERATOR__ROAD_IDS:
return getRoadIDs();
case GraphgeneratorsPackage.SHAPEFILE_GRAPH_GENERATOR__ROAD_CLASSES:
return getRoadClasses();
case GraphgeneratorsPackage.SHAPEFILE_GRAPH_GENERATOR__SHAPEFILE_TYPES:
return getShapefileTypes();
case GraphgeneratorsPackage.SHAPEFILE_GRAPH_GENERATOR__MIGRATION_IDS:
return getMigrationIDs();
case GraphgeneratorsPackage.SHAPEFILE_GRAPH_GENERATOR__MIGRATION_POPULATIONS:
return getMigrationPopulations();
case GraphgeneratorsPackage.SHAPEFILE_GRAPH_GENERATOR__MIGRATION_RATES:
return getMigrationRates();
}
return super.eGet(featureID, resolve, coreType);
}
/**
* <!-- begin-user-doc --> <!-- end-user-doc -->
*
* @generated
*/
@SuppressWarnings("unchecked")
@Override
public void eSet(int featureID, Object newValue) {
switch (featureID) {
case GraphgeneratorsPackage.SHAPEFILE_GRAPH_GENERATOR__SHAPEFILES:
getShapefiles().clear();
getShapefiles().addAll((Collection<? extends String>) newValue);
return;
case GraphgeneratorsPackage.SHAPEFILE_GRAPH_GENERATOR__REGION_IDS:
getRegionIDs().clear();
getRegionIDs().addAll((Collection<? extends String>) newValue);
return;
case GraphgeneratorsPackage.SHAPEFILE_GRAPH_GENERATOR__ROAD_IDS:
getRoadIDs().clear();
getRoadIDs().addAll((Collection<? extends String>) newValue);
return;
case GraphgeneratorsPackage.SHAPEFILE_GRAPH_GENERATOR__ROAD_CLASSES:
getRoadClasses().clear();
getRoadClasses().addAll((Collection<? extends String>) newValue);
return;
case GraphgeneratorsPackage.SHAPEFILE_GRAPH_GENERATOR__SHAPEFILE_TYPES:
getShapefileTypes().clear();
getShapefileTypes().addAll(
(Collection<? extends ShapefileType>) newValue);
return;
case GraphgeneratorsPackage.SHAPEFILE_GRAPH_GENERATOR__MIGRATION_IDS:
getMigrationIDs().clear();
getMigrationIDs().addAll((Collection<? extends String>) newValue);
return;
case GraphgeneratorsPackage.SHAPEFILE_GRAPH_GENERATOR__MIGRATION_POPULATIONS:
getMigrationPopulations().clear();
getMigrationPopulations().addAll(
(Collection<? extends String>) newValue);
return;
case GraphgeneratorsPackage.SHAPEFILE_GRAPH_GENERATOR__MIGRATION_RATES:
getMigrationRates().clear();
getMigrationRates().addAll((Collection<? extends String>) newValue);
return;
}
super.eSet(featureID, newValue);
}
/**
* <!-- begin-user-doc --> <!-- end-user-doc -->
*
* @generated
*/
@Override
public void eUnset(int featureID) {
switch (featureID) {
case GraphgeneratorsPackage.SHAPEFILE_GRAPH_GENERATOR__SHAPEFILES:
getShapefiles().clear();
return;
case GraphgeneratorsPackage.SHAPEFILE_GRAPH_GENERATOR__REGION_IDS:
getRegionIDs().clear();
return;
case GraphgeneratorsPackage.SHAPEFILE_GRAPH_GENERATOR__ROAD_IDS:
getRoadIDs().clear();
return;
case GraphgeneratorsPackage.SHAPEFILE_GRAPH_GENERATOR__ROAD_CLASSES:
getRoadClasses().clear();
return;
case GraphgeneratorsPackage.SHAPEFILE_GRAPH_GENERATOR__SHAPEFILE_TYPES:
getShapefileTypes().clear();
return;
case GraphgeneratorsPackage.SHAPEFILE_GRAPH_GENERATOR__MIGRATION_IDS:
getMigrationIDs().clear();
return;
case GraphgeneratorsPackage.SHAPEFILE_GRAPH_GENERATOR__MIGRATION_POPULATIONS:
getMigrationPopulations().clear();
return;
case GraphgeneratorsPackage.SHAPEFILE_GRAPH_GENERATOR__MIGRATION_RATES:
getMigrationRates().clear();
return;
}
super.eUnset(featureID);
}
/**
* <!-- begin-user-doc --> <!-- end-user-doc -->
*
* @generated
*/
@Override
public boolean eIsSet(int featureID) {
switch (featureID) {
case GraphgeneratorsPackage.SHAPEFILE_GRAPH_GENERATOR__SHAPEFILES:
return shapefiles != null && !shapefiles.isEmpty();
case GraphgeneratorsPackage.SHAPEFILE_GRAPH_GENERATOR__REGION_IDS:
return regionIDs != null && !regionIDs.isEmpty();
case GraphgeneratorsPackage.SHAPEFILE_GRAPH_GENERATOR__ROAD_IDS:
return roadIDs != null && !roadIDs.isEmpty();
case GraphgeneratorsPackage.SHAPEFILE_GRAPH_GENERATOR__ROAD_CLASSES:
return roadClasses != null && !roadClasses.isEmpty();
case GraphgeneratorsPackage.SHAPEFILE_GRAPH_GENERATOR__SHAPEFILE_TYPES:
return shapefileTypes != null && !shapefileTypes.isEmpty();
case GraphgeneratorsPackage.SHAPEFILE_GRAPH_GENERATOR__MIGRATION_IDS:
return migrationIDs != null && !migrationIDs.isEmpty();
case GraphgeneratorsPackage.SHAPEFILE_GRAPH_GENERATOR__MIGRATION_POPULATIONS:
return migrationPopulations != null
&& !migrationPopulations.isEmpty();
case GraphgeneratorsPackage.SHAPEFILE_GRAPH_GENERATOR__MIGRATION_RATES:
return migrationRates != null && !migrationRates.isEmpty();
}
return super.eIsSet(featureID);
}
/**
* <!-- begin-user-doc --> <!-- end-user-doc -->
*
* @generated
*/
@Override
public String toString() {
if (eIsProxy())
return super.toString();
StringBuffer result = new StringBuffer(super.toString());
result.append(" (shapefiles: ");
result.append(shapefiles);
result.append(", regionIDs: ");
result.append(regionIDs);
result.append(", roadIDs: ");
result.append(roadIDs);
result.append(", roadClasses: ");
result.append(roadClasses);
result.append(", shapefileTypes: ");
result.append(shapefileTypes);
result.append(", migrationIDs: ");
result.append(migrationIDs);
result.append(", migrationPopulations: ");
result.append(migrationPopulations);
result.append(", migrationRates: ");
result.append(migrationRates);
result.append(')');
return result.toString();
}
@Override
public Graph getGraph() {
Graph graph = GraphFactory.eINSTANCE.createGraph();
List<Node> nodeList = new ArrayList<Node>();
List<ShpPolygon> polygonList = new ArrayList<ShpPolygon>();
DublinCore dc = graph.getDublinCore();
Calendar c = Calendar.getInstance();
SimpleDateFormat formatter = new SimpleDateFormat(
"E yyyy.MM.dd 'at' hh:mm:ss a zzz");
dc.populate();
dc.setTitle("GIS Import");
dc.setSource(this.getClass().getSimpleName());
dc.setValid(formatter.format(c.getTime()));
processRegionShapefiles(graph, nodeList, polygonList);
processCommonBorderCreation(graph, nodeList, polygonList);
processRoadShapefiles(graph, nodeList, polygonList);
processMigrationShapefiles(graph, nodeList, polygonList);
assert graph.sane();
return graph;
}
/**
* This method iterates through all shapefiles that contain regions and
* creates a node for each region. These nodes are added to the graph.
* Additionally all polygons are added to polygonList, which is used by
* other methods.
*
* @param graph
* the graph to which the nodes are added
* @param nodeList
* created nodes are added to this list
* @param polygonList
* created polygons are added to this list
*/
private void processRegionShapefiles(Graph graph, List<Node> nodeList,
List<ShpPolygon> polygonList) {
for (int index = 0; index < shapefiles.size(); index++) {
if (shapefileTypes.get(index) != ShapefileType.REGION_FILE) {
continue;
}
List<ShpRecord> shapeList = null;
List<List<String>> data = null;
List<String> columnNames = null;
String regionID = regionIDs.get(index);
try {
Reader reader = new Reader(shapefiles.get(index));
shapeList = reader.getShapeList();
data = reader.getData();
columnNames = reader.getColumnNames();
} catch (Exception e) {
e.printStackTrace();
}
for (int i = 0; i < shapeList.size(); i++) {
ShpRecord shape = shapeList.get(i);
if (shape instanceof ShpPolygon) {
ShpPolygon polygon = (ShpPolygon) shape;
String currentID = data.get(i).get(
columnNames.indexOf(regionID.replaceFirst(
"column:", "")));
Region regionNode = createRegionNode(currentID);
LatLong nodeSegments = createSTEMPolygon(polygon);
String spatialURIString = InlineLatLongDataProvider
.createSpatialInlineURIString(nodeSegments);
regionNode.getDublinCore().setSpatial(spatialURIString);
nodeList.add(regionNode);
graph.putNode(regionNode);
polygonList.add(polygon);
} else {
System.err.println("Region Shapefile contains non-polygon");
}
}
}
}
/**
* This method iterates through all shapefiles that contain roads. For each
* polyline representing a road it is checked which polygons are connected
* by this polyline and RoadTransporationEdges are created between the
* connected polygons. These edges are added to the graph.
*
* @param graph
* the graph to which the edges are added
* @param nodeList
* list of all nodes created by processRegionShapefiles
* @param polygonList
* list of all polygons created by processRegionShapefiles
*/
private void processRoadShapefiles(Graph graph, List<Node> nodeList,
List<ShpPolygon> polygonList) {
for (int index = 0; index < shapefiles.size(); index++) {
if (shapefileTypes.get(index) != ShapefileType.ROAD_FILE) {
continue;
}
List<ShpRecord> shapeList = null;
List<List<String>> data = null;
List<String> columnNames = null;
String roadID = roadIDs.get(index);
String roadClass = roadClasses.get(index);
try {
Reader reader = new Reader(shapefiles.get(index));
shapeList = reader.getShapeList();
data = reader.getData();
columnNames = reader.getColumnNames();
} catch (Exception e) {
e.printStackTrace();
}
for (int i = 0; i < shapeList.size(); i++) {
ShpRecord shape = shapeList.get(i);
if (shape instanceof ShpPolyLine) {
ShpPolyLine polyline = (ShpPolyLine) shape;
Map<Point, Integer> crossings = getCrossings(polyline,
polygonList);
String currentID = data.get(i).get(
columnNames.indexOf(roadID.replaceFirst("column:",
"")));
String currentClass = null;
if (roadClass.startsWith("column:")) {
currentClass = data.get(i).get(
columnNames.indexOf(roadClass.replaceFirst(
"column:", "")));
} else {
currentClass = roadClass;
}
for (Entry<Point, Integer> entry : crossings.entrySet()) {
int loc1 = entry.getKey().x;
int loc2 = entry.getKey().y;
int numCrossings = entry.getValue();
graph.putEdge(createRoadTransportEdge(
nodeList.get(loc1), nodeList.get(loc2),
currentID, currentClass, numCrossings));
}
} else {
System.err.println("Road Shapefile contains non-polyline");
}
}
}
}
/**
* This method iterates through all shapefiles that contain polylines with
* migration data. For each of these polylines it is checked which polygons
* are connected by this polyline and MigrationEdges are created between the
* connected polygons. These edges are added to the graph.
*
* @param graph
* the graph to which the edges are added
* @param nodeList
* list of all nodes created by processRegionShapefiles
* @param polygonList
* list of all polygons created by processRegionShapefiles
*/
private void processMigrationShapefiles(Graph graph, List<Node> nodeList,
List<ShpPolygon> polygonList) {
for (int index = 0; index < shapefiles.size(); index++) {
if (shapefileTypes.get(index) != ShapefileType.MIGRATION_FILE) {
continue;
}
List<ShpRecord> shapeList = null;
List<List<String>> data = null;
List<String> columnNames = null;
String migrationID = migrationIDs.get(index);
String migrationPopulation = migrationPopulations.get(index);
String migrationRate = migrationRates.get(index);
try {
Reader reader = new Reader(shapefiles.get(index));
shapeList = reader.getShapeList();
data = reader.getData();
columnNames = reader.getColumnNames();
} catch (Exception e) {
e.printStackTrace();
}
for (int i = 0; i < shapeList.size(); i++) {
ShpRecord shape = shapeList.get(i);
if (shape instanceof ShpPolyLine) {
ShpPolyLine polyline = (ShpPolyLine) shape;
Map<Point, Integer> crossings = getCrossings(polyline,
polygonList);
String currentID = data.get(i).get(
columnNames.indexOf(migrationID.replaceFirst(
"column:", "")));
String currentPopulation = null;
double currentRate = 0.0;
if (migrationPopulation.startsWith("column:")) {
currentPopulation = data.get(i).get(
columnNames.indexOf(migrationPopulation
.replaceFirst("column:", "")));
} else {
currentPopulation = migrationPopulation;
}
if (migrationRate.startsWith("column:")) {
currentRate = Double.parseDouble(data.get(i).get(
columnNames.indexOf(migrationRate.replaceFirst(
"column:", ""))));
} else {
currentRate = Double.parseDouble(migrationRate);
}
for (Entry<Point, Integer> entry : crossings.entrySet()) {
int loc1 = entry.getKey().x;
int loc2 = entry.getKey().y;
int numCrossings = entry.getValue();
graph.putEdge(createMigrationEdge(nodeList.get(loc1),
nodeList.get(loc2), currentID,
currentPopulation, numCrossings * currentRate));
graph.putEdge(createMigrationEdge(nodeList.get(loc2),
nodeList.get(loc1), currentID,
currentPopulation, numCrossings * currentRate));
}
} else {
System.err
.println("Migration Shapefile contains non-polyline");
}
}
}
}
/**
* This method creates a CommonBorderEdge between each pair of nodes whose
* polygons have a common border. The edges are add to the graph.
*
* @param graph
* the graph to which the edges are added
* @param nodeList
* list of all nodes created by processRegionShapefiles
* @param polygonList
* list of all polygons created by processRegionShapefiles
*/
private void processCommonBorderCreation(Graph graph,
List<Node> nodeHolder, List<ShpPolygon> polygonList) {
int n = polygonList.size();
List<Rectangle2D> boundingBoxList = new ArrayList<Rectangle2D>(n);
for (ShpPolygon p : polygonList) {
Box b = p.getBoundingBox();
boundingBoxList.add(new Rectangle2D.Double(b.getXMin(),
b.getYMin(), b.getXMax() - b.getXMin(), b.getYMax()
- b.getYMin()));
}
for (int i = 0; i < n - 1; i++) {
for (int j = i + 1; j < n; j++) {
Rectangle2D intersection = boundingBoxList.get(i)
.createIntersection(boundingBoxList.get(j));
if (intersection.getWidth() >= 0.0
&& intersection.getHeight() >= 0.0) {
double borderLength = commonBorderLength(
polygonList.get(i), polygonList.get(j));
if (borderLength > 0) {
graph.putEdge(createCommonBorderEdge(nodeHolder.get(i),
nodeHolder.get(j), borderLength));
}
}
}
}
}
/**
* For each pair of polygons that are connected by the polyline, the number
* of crossing of the common border of the two polygons by the polyline is
* returned.
*
* @param polyline
* polyline for which the crossings are computed
* @param polygonList
* list of all polygons created by processRegionShapefiles
* @return Map with polygon index pair as key (lower index is first value)
* and number of crossing as value
*/
private Map<Point, Integer> getCrossings(ShpPolyLine polyline,
List<ShpPolygon> polygonList) {
Map<Point, Integer> crossings = new HashMap<Point, Integer>();
for (Part p : polyline.getParts()) {
double[] xs = p.getXs();
double[] ys = p.getYs();
int lastContainingPolygon = -1;
for (int i = 0; i < xs.length; i++) {
int containingPolygon = getContainingPolygon(xs[i], ys[i],
polygonList, lastContainingPolygon);
if (containingPolygon != lastContainingPolygon
&& containingPolygon != -1
&& lastContainingPolygon != -1) {
int loc1 = Math.min(lastContainingPolygon,
containingPolygon);
int loc2 = Math.max(lastContainingPolygon,
containingPolygon);
Integer n = crossings.get(new Point(loc1, loc2));
if (n != null) {
crossings.put(new Point(loc1, loc2), n + 1);
} else {
crossings.put(new Point(loc1, loc2), 1);
}
}
lastContainingPolygon = containingPolygon;
}
}
return crossings;
}
/**
* Returns the index of the polygons that contains the point (x/y). First
* the polygon with index guess is checked if guess != -1.
*
* @param x
* x-coordinate of the point
* @param y
* y-coordinate of the point
* @param esriPolygonLists
* list of all polygons created by processRegionShapefiles
* @param guess
* index of polygon that is checked first
* @return index of the polygon that contains the point
*/
private int getContainingPolygon(double x, double y,
List<ShpPolygon> esriPolygonLists, int guess) {
if (guess != -1) {
ShpPolygon list = esriPolygonLists.get(guess);
for (Part p : list.getParts()) {
if (isPointInPolygon(x, y, p)) {
return guess;
}
}
}
for (int i = 0; i < esriPolygonLists.size(); i++) {
ShpPolygon list = esriPolygonLists.get(i);
if (i == guess) {
continue;
}
for (Part p : list.getParts()) {
if (isPointInPolygon(x, y, p)) {
return i;
}
}
}
return -1;
}
/**
* Converts the polygon to a STEM-type polygon.
*
* @param polygon
* polygon to convert
* @return STEM-type polygon
*/
private LatLong createSTEMPolygon(ShpPolygon polygon) {
LatLong retValue = new LatLong();
for (Part p : polygon.getParts()) {
SegmentBuilder sb = new SegmentBuilder();
double[] xs = p.getXs();
double[] ys = p.getYs();
for (int i = 0; i < xs.length; i++) {
double latitude = ys[i];
double longitude = xs[i];
sb.add(latitude, longitude);
}
retValue.add(sb.toSegment());
}
return retValue;
}
/**
* Creates a node for a region with the specified name.
*
* @param regionName
* name of the region
* @return region node
*/
private Region createRegionNode(String regionName) {
Region node = NodesFactory.eINSTANCE.createRegion();
node.getDublinCore().setTitle(regionName);
node.setURI(STEMURI.createURI(Region.URI_TYPE_REGION_NODE_SEGMENT + "/"
+ makeURICompatible(regionName)));
return node;
}
/**
* Creates a RoadTransportEdge between the specified nodes.
*
* @param nodeA
* first node
* @param nodeB
* second node
* @param roadID
* ID of the RoadTransportEdge
* @param roadClass
* class of the RoadTransportEdge
* @param numCrossings
* number of crossings of the RoadTransportEdge
* @return RoadTransportEdge
*/
private Edge createRoadTransportEdge(Node nodeA, Node nodeB, String roadID,
String roadClass, int numCrossings) {
Edge edge = RoadTransportRelationshipLabelImpl
.createRoadTransportRelationship(nodeA, nodeB, roadID,
roadClass, numCrossings);
edge.setURI(STEMURI.createURI(Edge.URI_TYPE_EDGE_SEGMENT + "/"
+ nodeA.getURI().lastSegment() + "_"
+ nodeB.getURI().lastSegment() + "_"
+ makeURICompatible(roadID)));
edge.getDublinCore().setTitle(roadID);
return edge;
}
/**
* Creates a MigrationEdge between the specified nodes.
*
* @param nodeA
* source node
* @param nodeB
* destination node
* @param migrationID
* ID of the MigrationEdge
* @param migrationPopulation
* population identifier of the MigrationEdge
* @param migrationRate
* migration rate of the MigrationEdge
* @return MigrationEdge
*/
private MigrationEdge createMigrationEdge(Node nodeA, Node nodeB,
String migrationID, String migrationPopulation, double migrationRate) {
MigrationEdge mEdge = EdgesFactory.eINSTANCE.createMigrationEdge();
mEdge.setURI(STEMURI
.createURI(MigrationEdge.URI_TYPE_MIGRATION_EDGE_SEGMENT + "/"
+ nodeA.getURI().lastSegment() + "_"
+ nodeB.getURI().lastSegment() + "_"
+ makeURICompatible(migrationID)));
mEdge.setNodeAURI(nodeA.getURI());
mEdge.setNodeBURI(nodeB.getURI());
mEdge.getLabel().setURIOfIdentifiableToBeLabeled(mEdge.getURI());
mEdge.getLabel().getCurrentValue().setMigrationRate(migrationRate);
mEdge.getDublinCore().setTitle(migrationID);
mEdge.setPopulationIdentifier(migrationPopulation);
return mEdge;
}
/**
* Creates a CommonBorderEdge between the specified nodes.
*
* @param nodeA
* first node
* @param nodeB
* second node
* @param borderLength
* length of the common border
* @return CommonBorderEdge
*/
private Edge createCommonBorderEdge(Node nodeA, Node nodeB,
double borderLength) {
Edge edge = CommonBorderRelationshipLabelImpl
.createCommonBorderRelationship(nodeA, nodeB, borderLength);
String sEdge = edge.getURI().toString();
int last = sEdge.lastIndexOf("/");
String sEdge1 = sEdge.substring(0, last);
String sEdge2 = sEdge.substring(last, sEdge.length());
URI newURI = URI.createURI(sEdge1 + "/relationship/commonborder"
+ sEdge2);
edge.setURI(newURI);
edge.getDublinCore().setTitle(
"Edge[(" + nodeA.getDublinCore().getTitle() + ")<->("
+ nodeB.getDublinCore().getTitle() + ")]");
return edge;
}
/**
* Computes the length of the common border between the specified polygons.
*
* @param a
* first polygon
* @param b
* second polygon
* @return length of the common border
*/
private double commonBorderLength(ShpPolygon a, ShpPolygon b) {
double border_length = 0;
Set<Point2D.Double> bPoints = new HashSet<Point2D.Double>();
for (Part p : b.getParts()) {
double[] xs = p.getXs();
double[] ys = p.getYs();
for (int i = 0; i < xs.length; i++) {
bPoints.add(new Point2D.Double(xs[i], ys[i]));
}
}
for (Part p : a.getParts()) {
double[] xs = p.getXs();
double[] ys = p.getYs();
Point2D.Double p1 = null;
for (int i = 0; i < xs.length; i++) {
Point2D.Double p2 = new Point2D.Double(xs[i], ys[i]);
if (bPoints.contains(p2)) {
if (p1 != null) {
border_length += getDistanceInKM(p1.y, p1.x, p2.y,
p2.x, false);
}
p1 = p2;
} else {
p1 = null;
}
}
}
return border_length;
}
/**
* Computes the distance in km between two points in latitude/longitude
* coordinates.
*
* @param lat1
* latitude of first point in degrees
* @param lon1
* longitude of first point in degrees
* @param lat2
* latitude of second point in degrees
* @param lon2
* longitude of second point in degrees
* @param approx
* true if an approximative solution should be computed (faster),
* false otherwise
* @return distance between the point in km
*/
private double getDistanceInKM(double lat1, double lon1, double lat2,
double lon2, boolean approx) {
lat1 = Math.toRadians(lat1);
lon1 = Math.toRadians(lon1);
lat2 = Math.toRadians(lat2);
lon2 = Math.toRadians(lon2);
if (approx) {
double x = (lon2 - lon1) * Math.cos((lat1 + lat2) / 2);
double y = (lat2 - lat1);
return Math.sqrt(x * x + y * y) * 6731;
} else {
return Math.acos(Math.sin(lat1) * Math.sin(lat2) + Math.cos(lat1)
* Math.cos(lat2) * Math.cos(lon2 - lon1)) * 6731;
}
}
/**
* Returns true if the point (x/y) is in the polygon poly.
*
* @param x
* x-coordinate of the point
* @param y
* y-coordinate of the point
* @param poly
* polygon
* @return true if the point is in the polygon polygon, false otherwise
*/
private boolean isPointInPolygon(double x, double y, Part poly) {
double[] xs = poly.getXs();
double[] ys = poly.getYs();
int n = xs.length;
int hits = 0;
double x1 = xs[n - 1];
double y1 = ys[n - 1];
for (int i = 0; i < n; i++) {
double x2 = xs[i];
double y2 = ys[i];
if (y == y2) {
if (x < x2) {
double y3 = ys[(i + 1) % n];
if (y > Math.min(y1, y3) && y < Math.max(y1, y3)) {
hits++;
}
}
} else {
if (y > Math.min(y1, y2) && y < Math.max(y1, y2)) {
double xProjection = (x2 - x1) / (y2 - y1) * (y - y1) + x1;
if (x < xProjection) {
hits++;
}
}
}
x1 = x2;
y1 = y2;
}
return hits % 2 != 0;
}
/**
* Formats string so that it can be used in URI.
*
* @param s
* string to format
* @return formatted string
*/
private String makeURICompatible(String s) {
s = s.replaceAll("/", "");
s = s.replaceAll("-", "");
return s;
}
}