All Downloads are FREE. Search and download functionalities are using the official Maven repository.
Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
org.opentripplanner.graph_builder.module.shapefile.ShapefileStreetModule Maven / Gradle / Ivy
package org.opentripplanner.graph_builder.module.shapefile;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import java.util.TreeSet;
import org.geotools.data.FeatureSource;
import org.geotools.data.Query;
import org.geotools.factory.Hints;
import org.geotools.feature.FeatureCollection;
import org.geotools.feature.FeatureIterator;
import org.geotools.geometry.jts.JTS;
import org.geotools.referencing.ReferencingFactoryFinder;
import org.opengis.feature.simple.SimpleFeature;
import org.opengis.feature.simple.SimpleFeatureType;
import org.opengis.referencing.crs.CRSAuthorityFactory;
import org.opengis.referencing.crs.CoordinateReferenceSystem;
import org.opentripplanner.common.geometry.GeometryUtils;
import org.opentripplanner.common.model.P2;
import org.opentripplanner.graph_builder.services.DefaultStreetEdgeFactory;
import org.opentripplanner.graph_builder.services.GraphBuilderModule;
import org.opentripplanner.graph_builder.services.StreetEdgeFactory;
import org.opentripplanner.graph_builder.services.shapefile.FeatureSourceFactory;
import org.opentripplanner.graph_builder.services.shapefile.SimpleFeatureConverter;
import org.opentripplanner.routing.alertpatch.Alert;
import org.opentripplanner.routing.edgetype.StreetEdge;
import org.opentripplanner.routing.edgetype.StreetTraversalPermission;
import org.opentripplanner.routing.graph.Graph;
import org.opentripplanner.routing.services.notes.StreetNotesService;
import org.opentripplanner.routing.vertextype.IntersectionVertex;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.locationtech.jts.geom.Coordinate;
import org.locationtech.jts.geom.Geometry;
import org.locationtech.jts.geom.LineString;
import org.locationtech.jts.geom.MultiLineString;
import org.opentripplanner.util.NonLocalizedString;
/**
* Loads a shapefile into an edge-based graph.
*
*/
public class ShapefileStreetModule implements GraphBuilderModule {
private static Logger log = LoggerFactory.getLogger(ShapefileStreetModule.class);
private FeatureSourceFactory featureSourceFactory;
private ShapefileStreetSchema schema;
public StreetEdgeFactory edgeFactory = new DefaultStreetEdgeFactory();
public List provides() {
return Arrays.asList("streets");
}
public List getPrerequisites() {
return Collections.emptyList();
}
public void setFeatureSourceFactory(FeatureSourceFactory factory) {
featureSourceFactory = factory;
}
public void setSchema(ShapefileStreetSchema schema) {
this.schema = schema;
}
@Override
public void buildGraph(Graph graph, HashMap, Object> extra) {
try {
FeatureSource featureSource = featureSourceFactory
.getFeatureSource();
CoordinateReferenceSystem sourceCRS = featureSource.getInfo().getCRS();
Hints hints = new Hints(Hints.FORCE_LONGITUDE_FIRST_AXIS_ORDER, Boolean.TRUE);
CRSAuthorityFactory factory = ReferencingFactoryFinder.getCRSAuthorityFactory("EPSG",
hints);
CoordinateReferenceSystem worldCRS = factory
.createCoordinateReferenceSystem("EPSG:4326");
Query query = new Query();
query.setCoordinateSystem(sourceCRS);
query.setCoordinateSystemReproject(worldCRS);
FeatureCollection features = featureSource
.getFeatures(query);
features = featureSource.getFeatures(query);
HashMap> intersectionNameToId = new HashMap>();
SimpleFeatureConverter streetIdConverter = schema.getIdConverter();
SimpleFeatureConverter streetNameConverter = schema.getNameConverter();
SimpleFeatureConverter> permissionConverter = schema
.getPermissionConverter();
SimpleFeatureConverter noteConverter = schema.getNoteConverter();
HashMap intersectionsByLocation =
new HashMap();
SimpleFeatureConverter> safetyConverter = schema.getBicycleSafetyConverter();
SimpleFeatureConverter slopeOverrideCoverter = schema.getSlopeOverrideConverter();
SimpleFeatureConverter featureSelector = schema.getFeatureSelector();
// Keep track of features that are duplicated so we don't have duplicate streets
Set seen = new HashSet();
List featureList = new ArrayList();
FeatureIterator it2 = features.features();
while (it2.hasNext()) {
SimpleFeature feature = it2.next();
if (featureSelector != null && ! featureSelector.convert(feature)) {
continue;
}
featureList.add(feature);
}
it2.close();
it2 = null;
HashMap> coordinateToStreetNames = getCoordinatesToStreetNames(featureList);
for (SimpleFeature feature : featureList) {
if (feature.getDefaultGeometry() == null) {
log.warn("feature has no geometry: " + feature.getIdentifier());
continue;
}
LineString geom = toLineString((Geometry) feature.getDefaultGeometry());
Object o = streetIdConverter.convert(feature);
String label = "" + o;
if (o != null && seen.contains(label)) {
continue;
}
seen.add(label);
String name = streetNameConverter.convert(feature);
Coordinate[] coordinates = geom.getCoordinates();
if (coordinates.length < 2) {
//not a real linestring
log.warn("Bad geometry for street with label " + label + " name " + name);
continue;
}
// this rounding is a total hack, to work around
// http://jira.codehaus.org/browse/GEOT-2811
Coordinate startCoordinate = new Coordinate(
Math.round(coordinates[0].x * 1048576) / 1048576.0, Math
.round(coordinates[0].y * 1048576) / 1048576.0);
Coordinate endCoordinate = new Coordinate(Math
.round(coordinates[coordinates.length - 1].x * 1048576) / 1048576.0, Math
.round(coordinates[coordinates.length - 1].y * 1048576) / 1048576.0);
String startIntersectionName = getIntersectionName(coordinateToStreetNames,
intersectionNameToId, startCoordinate);
if (startIntersectionName == "null") {
log.warn("No intersection name for " + name);
}
String endIntersectionName = getIntersectionName(coordinateToStreetNames,
intersectionNameToId, endCoordinate);
IntersectionVertex startIntersection = intersectionsByLocation.get(startCoordinate);
if (startIntersection == null) {
startIntersection = new IntersectionVertex(graph, startIntersectionName, startCoordinate.x,
startCoordinate.y, new NonLocalizedString(startIntersectionName));
intersectionsByLocation.put(startCoordinate, startIntersection);
}
IntersectionVertex endIntersection = intersectionsByLocation.get(endCoordinate);
if (endIntersection == null) {
endIntersection = new IntersectionVertex(graph, endIntersectionName, endCoordinate.x,
endCoordinate.y, new NonLocalizedString(endIntersectionName));
intersectionsByLocation.put(endCoordinate, endIntersection);
}
double length = 0;
for (int i = 0; i < coordinates.length - 1; ++i) {
length += JTS.orthodromicDistance(coordinates[i],
coordinates[i + 1], worldCRS);
}
P2 permissions = permissionConverter.convert(feature);
// TODO Set appropriate car speed from shapefile source.
StreetEdge street = edgeFactory.createEdge(startIntersection, endIntersection,
geom, new NonLocalizedString(name), length, permissions.first, false);
LineString reversed = (LineString) geom.reverse();
StreetEdge backStreet = edgeFactory.createEdge(endIntersection, startIntersection,
reversed, new NonLocalizedString(name), length, permissions.second, true);
backStreet.shareData(street);
if (noteConverter != null) {
String note = noteConverter.convert(feature);
if (note != null && note.length() > 0) {
Alert noteAlert = Alert.createSimpleAlerts(note);
graph.streetNotesService.addStaticNote(street, noteAlert, StreetNotesService.ALWAYS_MATCHER);
graph.streetNotesService.addStaticNote(backStreet, noteAlert, StreetNotesService.ALWAYS_MATCHER);
}
}
boolean slopeOverride = slopeOverrideCoverter.convert(feature);
street.setSlopeOverride(slopeOverride);
backStreet.setSlopeOverride(slopeOverride);
if (safetyConverter != null) {
P2 safetyFactors = safetyConverter.convert(feature);
if (safetyFactors != null) {
street.setBicycleSafetyFactor(safetyFactors.first.floatValue());
backStreet.setBicycleSafetyFactor(safetyFactors.second.floatValue());
}
}
}
} catch (Exception ex) {
throw new IllegalStateException("error loading shapefile street data", ex);
} finally {
featureSourceFactory.cleanup();
}
}
private HashMap> getCoordinatesToStreetNames(
List features) {
HashMap> coordinateToStreets = new HashMap>();
SimpleFeatureConverter streetNameConverter = schema.getNameConverter();
SimpleFeatureConverter featureSelector = schema.getFeatureSelector();
Iterator it = features.iterator();
while (it.hasNext()) {
SimpleFeature feature = it.next();
if (featureSelector != null && !featureSelector.convert(feature)) {
continue;
}
if (feature.getDefaultGeometry() == null) {
log.warn("feature has no geometry: " + feature.getIdentifier());
continue;
}
LineString geom = toLineString((Geometry) feature.getDefaultGeometry());
for (Coordinate coord : geom.getCoordinates()) {
// this rounding is a total hack, to work around
// http://jira.codehaus.org/browse/GEOT-2811
Coordinate rounded = new Coordinate(Math.round(coord.x * 1048576) / 1048576.0, Math
.round(coord.y * 1048576) / 1048576.0);
TreeSet streets = coordinateToStreets.get(rounded);
if (streets == null) {
streets = new TreeSet();
coordinateToStreets.put(rounded, streets);
}
String streetName = streetNameConverter.convert(feature);
if (streetName == null) {
throw new IllegalStateException("Unexpectedly got null for a street name for feature at " + coord);
}
streets.add(streetName);
}
}
return coordinateToStreets;
}
private String getIntersectionName(HashMap> coordinateToStreets,
HashMap> intersectionNameToId,
Coordinate coordinate) {
TreeSet streets = coordinateToStreets.get(coordinate);
if (streets == null) {
return "null";
}
//TODO: localize this and return localized string
String intersection = streets.first() + " at " + streets.last();
HashMap possibleIntersections = intersectionNameToId.get(intersection);
if (possibleIntersections == null) {
possibleIntersections = new HashMap();
possibleIntersections.put(coordinate, 1);
intersectionNameToId.put(intersection, possibleIntersections);
return intersection;
}
Integer index = possibleIntersections.get(coordinate);
if (index == null) {
int max = 0;
for (Integer value : possibleIntersections.values()) {
if (value > max)
max = value;
}
possibleIntersections.put(coordinate, max + 1);
index = max + 1;
}
if (index > 1) {
intersection += " #" + possibleIntersections.get(coordinate);
}
return intersection;
}
private LineString toLineString(Geometry g) {
if (g instanceof LineString) {
return (LineString) g;
} else if (g instanceof MultiLineString) {
MultiLineString ml = (MultiLineString) g;
Coordinate[] coords = ml.getCoordinates();
return GeometryUtils.getGeometryFactory().createLineString(coords);
} else {
throw new RuntimeException("found a geometry feature that's not a linestring: " + g);
}
}
@Override
public void checkInputs() {
featureSourceFactory.checkInputs();
}
}