package maps.convert.osm2gml;
import java.util.Set;
import java.util.Map;
import java.util.HashSet;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.ArrayList;
import maps.osm.OSMMap;
import rescuecore2.misc.geometry.Point2D;
import rescuecore2.misc.collections.LazyMap;
//import rescuecore2.log.Logger;
/**
This class holds all temporary information during map conversion.
*/
public class TemporaryMap {
/**
The threshold for determining if nodes are co-located in metres.
*/
private static final double NEARBY_THRESHOLD_M = 1;
private double threshold;
private Set<Node> nodes;
private Set<Edge> edges;
private Map<Node, Set<Edge>> edgesAtNode;
private Map<Edge, Set<TemporaryObject>> objectsAtEdge;
private Set<TemporaryRoad> tempRoads;
private Set<TemporaryIntersection> tempIntersections;
private Set<TemporaryBuilding> tempBuildings;
private Set<TemporaryObject> allObjects;
private OSMMap osmMap;
private Collection<OSMIntersectionInfo> osmIntersections;
private Collection<OSMRoadInfo> osmRoads;
private Collection<OSMBuildingInfo> osmBuildings;
private int nextID;
/**
Construct a TemporaryMap.
@param osmMap The OpenStreetMap data this map is generated from.
*/
public TemporaryMap(OSMMap osmMap) {
this.osmMap = osmMap;
nextID = 0;
nodes = new HashSet<Node>();
edges = new HashSet<Edge>();
threshold = ConvertTools.nearbyThreshold(osmMap, NEARBY_THRESHOLD_M);
tempRoads = new HashSet<TemporaryRoad>();
tempIntersections = new HashSet<TemporaryIntersection>();
tempBuildings = new HashSet<TemporaryBuilding>();
allObjects = new HashSet<TemporaryObject>();
edgesAtNode = new LazyMap<Node, Set<Edge>>() {
@Override
public Set<Edge> createValue() {
return new HashSet<Edge>();
}
};
objectsAtEdge = new LazyMap<Edge, Set<TemporaryObject>>() {
@Override
public Set<TemporaryObject> createValue() {
return new HashSet<TemporaryObject>();
}
};
}
/**
Get the OSMMap.
@return The OSMMap.
*/
public OSMMap getOSMMap() {
return osmMap;
}
/**
Set the OSMMap information.
@param intersections The set of intersections.
@param roads The set of roads.
@param buildings The set of buildings.
*/
public void setOSMInfo(Collection<OSMIntersectionInfo> intersections, Collection<OSMRoadInfo> roads, Collection<OSMBuildingInfo> buildings) {
osmIntersections = new HashSet<OSMIntersectionInfo>(intersections);
osmRoads = new HashSet<OSMRoadInfo>(roads);
osmBuildings = new HashSet<OSMBuildingInfo>(buildings);
}
/**
Get the OSM intersection info.
@return The OSM intersection info.
*/
public Collection<OSMIntersectionInfo> getOSMIntersectionInfo() {
return Collections.unmodifiableCollection(osmIntersections);
}
/**
Get the OSM road info.
@return The OSM road info.
*/
public Collection<OSMRoadInfo> getOSMRoadInfo() {
return Collections.unmodifiableCollection(osmRoads);
}
/**
Get the OSM building info.
@return The OSM building info.
*/
public Collection<OSMBuildingInfo> getOSMBuildingInfo() {
return Collections.unmodifiableCollection(osmBuildings);
}
/**
Add a road.
@param road The road to add.
*/
public void addRoad(TemporaryRoad road) {
tempRoads.add(road);
addObject(road);
}
/**
Remove a road.
@param road The road to remove.
*/
public void removeRoad(TemporaryRoad road) {
tempRoads.remove(road);
removeObject(road);
}
/**
Add an intersection.
@param intersection The intersection to add.
*/
public void addIntersection(TemporaryIntersection intersection) {
tempIntersections.add(intersection);
addObject(intersection);
}
/**
Remove an intersection.
@param intersection The intersection to remove.
*/
public void removeIntersection(TemporaryIntersection intersection) {
tempIntersections.remove(intersection);
removeObject(intersection);
}
/**
Add a building.
@param building The building to add.
*/
public void addBuilding(TemporaryBuilding building) {
tempBuildings.add(building);
addObject(building);
}
/**
Remove a building.
@param building The building to remove.
*/
public void removeBuilding(TemporaryBuilding building) {
tempBuildings.remove(building);
removeObject(building);
}
/**
Add an object.
@param object The object to add.
*/
public void addTemporaryObject(TemporaryObject object) {
if (object instanceof TemporaryRoad) {
addRoad((TemporaryRoad)object);
}
if (object instanceof TemporaryIntersection) {
addIntersection((TemporaryIntersection)object);
}
if (object instanceof TemporaryBuilding) {
addBuilding((TemporaryBuilding)object);
}
}
/**
Remove an object.
@param object The object to remove.
*/
public void removeTemporaryObject(TemporaryObject object) {
if (object instanceof TemporaryRoad) {
removeRoad((TemporaryRoad)object);
}
if (object instanceof TemporaryIntersection) {
removeIntersection((TemporaryIntersection)object);
}
if (object instanceof TemporaryBuilding) {
removeBuilding((TemporaryBuilding)object);
}
}
/**
Get all roads in the map.
@return All roads.
*/
public Collection<TemporaryRoad> getRoads() {
return new HashSet<TemporaryRoad>(tempRoads);
}
/**
Get all intersections in the map.
@return All intersections.
*/
public Collection<TemporaryIntersection> getIntersections() {
return new HashSet<TemporaryIntersection>(tempIntersections);
}
/**
Get all buildings in the map.
@return All buildings.
*/
public Collection<TemporaryBuilding> getBuildings() {
return new HashSet<TemporaryBuilding>(tempBuildings);
}
/**
Get all objects in the map.
@return All objects.
*/
public Collection<TemporaryObject> getAllObjects() {
return new HashSet<TemporaryObject>(allObjects);
}
/**
Get all nodes in the map.
@return All nodes.
*/
public Collection<Node> getAllNodes() {
return new HashSet<Node>(nodes);
}
/**
Get all edges in the map.
@return All edges.
*/
public Collection<Edge> getAllEdges() {
return new HashSet<Edge>(edges);
}
/**
Get all objects attached to an Edge.
@param e The Edge.
@return All attached TemporaryObjects.
*/
public Set<TemporaryObject> getAttachedObjects(Edge e) {
return new HashSet<TemporaryObject>(objectsAtEdge.get(e));
}
/**
Get all edges attached to a Node.
@param n The Node.
@return All attached edges.
*/
public Set<Edge> getAttachedEdges(Node n) {
return new HashSet<Edge>(edgesAtNode.get(n));
}
/**
Set the threshold for deciding if two points are the same. The {@link #isNear(Point2D, Point2D)} method uses this value to check if a new point needs to be registered.
@param t The new threshold.
*/
public void setNearbyThreshold(double t) {
threshold = t;
}
/**
Get the threshold for deciding if two points are the same. The {@link #isNear(Point2D, Point2D)} method uses this value to check if a new point needs to be registered.
@return The nearby threshold.
*/
public double getNearbyThreshold() {
return threshold;
}
/**
Find out if two points are nearby.
@param point1 The first point.
@param point2 The second point.
@return True iff the two points are within the nearby threshold.
*/
public boolean isNear(Point2D point1, Point2D point2) {
return isNear(point1.getX(), point1.getY(), point2.getX(), point2.getY());
}
/**
Find out if two points are nearby.
@param x1 The x coordinate of the first point.
@param y1 The y coordinate of the first point.
@param x2 The x coordinate of the second point.
@param y2 The y coordinate of the second point.
@return True iff the two points are within the nearby threshold.
*/
public boolean isNear(double x1, double y1, double x2, double y2) {
double dx = x2 - x1;
double dy = y2 - y1;
return (dx >= -threshold
&& dx <= threshold
&& dy >= -threshold
&& dy <= threshold);
}
/**
Get a Node near a point. If a Node already exists nearby then it will be returned, otherwise a new Node will be created.
@param p The node coordinates.
@return A Node.
*/
public Node getNode(Point2D p) {
return getNode(p.getX(), p.getY());
}
/**
Get a Node near a point. If a Node already exists nearby then it will be returned, otherwise a new Node will be created.
@param x The X coordinate.
@param y The Y coordinate.
@return A Node.
*/
public Node getNode(double x, double y) {
for (Node next : nodes) {
if (isNear(x, y, next.getX(), next.getY())) {
return next;
}
}
return createNode(x, y);
}
/**
Get an Edge between two nodes. This will return either a new Edge or a shared instance if one already exists.
@param from The from node.
@param to The to node.
@return An Edge.
*/
public Edge getEdge(Node from, Node to) {
for (Edge next : edges) {
if (next.getStart().equals(from) && next.getEnd().equals(to)
|| next.getStart().equals(to) && next.getEnd().equals(from)) {
return next;
}
}
return createEdge(from, to);
}
/**
Get a DirectedEdge between two nodes.
@param from The from node.
@param to The to node.
@return A new DirectedEdge.
*/
public DirectedEdge getDirectedEdge(Node from, Node to) {
Edge e = getEdge(from, to);
return new DirectedEdge(e, from);
}
/**
Replace an existing edge with a set of new edges.
@param edge The old edge.
@param newEdges The new edges.
*/
public void replaceEdge(Edge edge, Collection<Edge> newEdges) {
for (TemporaryObject next : getAttachedObjects(edge)) {
next.replaceEdge(edge, newEdges);
for (Edge nextEdge : newEdges) {
objectsAtEdge.get(nextEdge).add(next);
}
}
removeEdge(edge);
}
/**
Split an edge into chunks.
@param edge The edge to split.
@param splitPoints The points to split the line. These must be in order along the line.
@return The replacement edges.
*/
public List<Edge> splitEdge(Edge edge, Node... splitPoints) {
List<Edge> replacements = new ArrayList<Edge>();
Edge current = edge;
for (Node n : splitPoints) {
if (n.equals(current.getStart()) || n.equals(current.getEnd())) {
// Don't bother if the split point is at the origin or endpoint
continue;
}
replacements.add(getEdge(current.getStart(), n));
current = getEdge(n, current.getEnd());
}
if (!edge.equals(current)) {
replacements.add(current);
}
if (!replacements.isEmpty()) {
replaceEdge(edge, replacements);
}
return replacements;
}
private Node createNode(double x, double y) {
Node result = new Node(nextID++, x, y);
nodes.add(result);
return result;
}
private Edge createEdge(Node from, Node to) {
Edge result = new Edge(nextID++, from, to);
edges.add(result);
edgesAtNode.get(from).add(result);
edgesAtNode.get(to).add(result);
// Logger.debug("Created edge " + result);
return result;
}
private void addObject(TemporaryObject object) {
allObjects.add(object);
for (DirectedEdge next : object.getEdges()) {
objectsAtEdge.get(next.getEdge()).add(object);
}
}
private void removeNode(Node n) {
nodes.remove(n);
edgesAtNode.remove(n);
}
private void removeEdge(Edge e) {
edges.remove(e);
edgesAtNode.get(e.getStart()).remove(e);
edgesAtNode.get(e.getEnd()).remove(e);
objectsAtEdge.remove(e);
// Logger.debug("Removed edge " + e);
}
private void removeObject(TemporaryObject object) {
allObjects.remove(object);
for (DirectedEdge next : object.getEdges()) {
objectsAtEdge.get(next.getEdge()).remove(object);
}
}
}