| /******************************************************************************* |
| * 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; |
| } |
| |
| } |