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.
package org.opentripplanner.graph_builder.module.osm;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import org.opentripplanner.common.geometry.GeometryUtils;
import org.opentripplanner.openstreetmap.model.OSMNode;
import org.opentripplanner.openstreetmap.model.OSMWay;
import org.opentripplanner.openstreetmap.model.OSMWithTags;
import com.google.common.collect.ArrayListMultimap;
import org.locationtech.jts.geom.MultiPolygon;
import org.locationtech.jts.geom.Polygon;
/**
* Stores information about an OSM area needed for visibility graph construction. Algorithm based on
* http://wiki.openstreetmap.org/wiki/Relation:multipolygon/Algorithm but generally done in a
* quick/dirty way.
*/
class Area {
public static class AreaConstructionException extends RuntimeException {
private static final long serialVersionUID = 1L;
}
// This is the way or relation that has the relevant tags for the area
OSMWithTags parent;
List outermostRings = new ArrayList();
private MultiPolygon jtsMultiPolygon;
Area(OSMWithTags parent, List outerRingWays, List innerRingWays,
Map _nodes) {
this.parent = parent;
// ring assignment
List> innerRingNodes = constructRings(innerRingWays);
List> outerRingNodes = constructRings(outerRingWays);
if (innerRingNodes == null || outerRingNodes == null) {
throw new AreaConstructionException();
}
ArrayList> allRings = new ArrayList>(innerRingNodes);
allRings.addAll(outerRingNodes);
List innerRings = new ArrayList();
List outerRings = new ArrayList();
for (List ring : innerRingNodes) {
innerRings.add(new Ring(ring, _nodes));
}
for (List ring : outerRingNodes) {
outerRings.add(new Ring(ring, _nodes));
}
// now, ring grouping
// first, find outermost rings
OUTER: for (Ring outer : outerRings) {
for (Ring possibleContainer : outerRings) {
if (outer != possibleContainer
&& outer.geometry.hasPointInside(possibleContainer.geometry)) {
continue OUTER;
}
}
outermostRings.add(outer);
// find holes in this ring
for (Ring possibleHole : innerRings) {
if (possibleHole.geometry.hasPointInside(outer.geometry)) {
outer.holes.add(possibleHole);
}
}
}
// run this at end of ctor so that exception
// can be caught in the right place
toJTSMultiPolygon();
}
public MultiPolygon toJTSMultiPolygon() {
if (jtsMultiPolygon == null) {
List polygons = new ArrayList();
for (Ring ring : outermostRings) {
polygons.add(ring.toJtsPolygon());
}
jtsMultiPolygon = GeometryUtils.getGeometryFactory().createMultiPolygon(
polygons.toArray(new Polygon[0]));
if (!jtsMultiPolygon.isValid()) {
throw new AreaConstructionException();
}
}
return jtsMultiPolygon;
}
public List> constructRings(List ways) {
if (ways.size() == 0) {
// no rings is no rings
return Collections.emptyList();
}
List> closedRings = new ArrayList>();
ArrayListMultimap waysByEndpoint = ArrayListMultimap.create();
for (OSMWay way : ways) {
List refs = way.getNodeRefs();
long start = refs.get(0);
long end = refs.get(refs.size() - 1);
if (start == end) {
ArrayList ring = new ArrayList(refs);
closedRings.add(ring);
} else {
waysByEndpoint.put(start, way);
waysByEndpoint.put(end, way);
}
}
// precheck for impossible situations
List toRemove = new ArrayList();
for (Long endpoint : waysByEndpoint.keySet()) {
Collection list = waysByEndpoint.get(endpoint);
if (list.size() % 2 == 1) {
return null;
}
}
for (Long key : toRemove) {
waysByEndpoint.removeAll(key);
}
List partialRing = new ArrayList();
if (waysByEndpoint.size() == 0) {
return closedRings;
}
long firstEndpoint = 0, otherEndpoint = 0;
OSMWay firstWay = null;
for (Long endpoint : waysByEndpoint.keySet()) {
List list = waysByEndpoint.get(endpoint);
firstWay = list.get(0);
List nodeRefs = firstWay.getNodeRefs();
partialRing.addAll(nodeRefs);
firstEndpoint = nodeRefs.get(0);
otherEndpoint = nodeRefs.get(nodeRefs.size() - 1);
break;
}
waysByEndpoint.get(firstEndpoint).remove(firstWay);
waysByEndpoint.get(otherEndpoint).remove(firstWay);
if (constructRingsRecursive(waysByEndpoint, partialRing, closedRings, firstEndpoint)) {
return closedRings;
} else {
return null;
}
}
private boolean constructRingsRecursive(ArrayListMultimap waysByEndpoint,
List ring, List> closedRings, long endpoint) {
List ways = new ArrayList(waysByEndpoint.get(endpoint));
for (OSMWay way : ways) {
// remove this way from the map
List nodeRefs = way.getNodeRefs();
long firstEndpoint = nodeRefs.get(0);
long otherEndpoint = nodeRefs.get(nodeRefs.size() - 1);
waysByEndpoint.remove(firstEndpoint, way);
waysByEndpoint.remove(otherEndpoint, way);
ArrayList newRing = new ArrayList(ring.size() + nodeRefs.size());
long newFirstEndpoint;
if (firstEndpoint == endpoint) {
for (int j = nodeRefs.size() - 1; j >= 1; --j) {
newRing.add(nodeRefs.get(j));
}
newRing.addAll(ring);
newFirstEndpoint = otherEndpoint;
} else {
newRing.addAll(nodeRefs.subList(0, nodeRefs.size() - 1));
newRing.addAll(ring);
newFirstEndpoint = firstEndpoint;
}
if (newRing.get(newRing.size() - 1).equals(newRing.get(0))) {
// ring closure
closedRings.add(newRing);
// if we're out of endpoints, then we have succeeded
if (waysByEndpoint.size() == 0) {
return true; // success
}
// otherwise, we need to start a new partial ring
newRing = new ArrayList();
OSMWay firstWay = null;
for (Long entry : waysByEndpoint.keySet()) {
List list = waysByEndpoint.get(entry);
firstWay = list.get(0);
nodeRefs = firstWay.getNodeRefs();
newRing.addAll(nodeRefs);
firstEndpoint = nodeRefs.get(0);
otherEndpoint = nodeRefs.get(nodeRefs.size() - 1);
break;
}
waysByEndpoint.remove(firstEndpoint, firstWay);
waysByEndpoint.remove(otherEndpoint, firstWay);
if (constructRingsRecursive(waysByEndpoint, newRing, closedRings, firstEndpoint)) {
return true;
}
waysByEndpoint.remove(firstEndpoint, firstWay);
waysByEndpoint.remove(otherEndpoint, firstWay);
} else {
// continue with this ring
if (waysByEndpoint.get(newFirstEndpoint) != null) {
if (constructRingsRecursive(waysByEndpoint, newRing, closedRings,
newFirstEndpoint)) {
return true;
}
}
}
if (firstEndpoint == endpoint) {
waysByEndpoint.put(otherEndpoint, way);
} else {
waysByEndpoint.put(firstEndpoint, way);
}
}
return false;
}
}