Unverified Commit 342fea6f authored by Juon Kawakami's avatar Juon Kawakami 🥗
Browse files

init

parent 54f6cedf
package maps;
import java.io.File;
/**
Interface for different types of map format.
*/
public interface MapFormat {
/**
Read a File and return a Map.
@param file The file to read.
@return A new Map.
@throws MapException If there is a problem reading the map.
*/
Map read(File file) throws MapException;
/**
Write a map to a file.
@param map The map to write.
@param file The file to write to.
@throws MapException If there is a problem writing the map.
*/
void write(Map map, File file) throws MapException;
/**
Find out if a file looks valid to this format.
@param file The file to check.
@return True if this format can probably read the file, false otherwise.
@throws MapException If there is a problem reading the file.
*/
boolean canRead(File file) throws MapException;
}
package maps;
import maps.gml.formats.RobocupFormat;
import maps.gml.formats.OrdnanceSurveyFormat;
import maps.gml.formats.MeijoFormat;
import maps.gml.formats.GeospatialInformationAuthorityFormat;
import java.io.File;
import java.util.List;
import java.util.ArrayList;
import rescuecore2.log.Logger;
/**
A utility class for reading maps.
*/
public final class MapReader {
private static final List<MapFormat> ALL_FORMATS = new ArrayList<MapFormat>();
static {
ALL_FORMATS.add(RobocupFormat.INSTANCE);
ALL_FORMATS.add(MeijoFormat.INSTANCE);
ALL_FORMATS.add(OrdnanceSurveyFormat.INSTANCE);
ALL_FORMATS.add(GeospatialInformationAuthorityFormat.INSTANCE);
}
private MapReader() {
}
/**
Read a Map from a file and guess the format.
@param file The name of the file to read.
@return A Map.
@throws MapException If there is a problem reading the map.
*/
public static Map readMap(String file) throws MapException {
return readMap(file, null);
}
/**
Read a Map from a file using a particular format.
@param file The name of the file to read.
@param format The format to use. If this is null then the format will be guessed.
@return A Map.
@throws MapException If there is a problem reading the map.
*/
public static Map readMap(String file, MapFormat format) throws MapException {
return readMap(new File(file), format);
}
/**
Read a Map from a file and guess the format.
@param file The file to read.
@return A Map.
@throws MapException If there is a problem reading the map.
*/
public static Map readMap(File file) throws MapException {
return readMap(file, null);
}
/**
Read a Map from a file using a particular format.
@param file The file to read.
@param format The format to use. If this is null then the format will be guessed.
@return A Map.
@throws MapException If there is a problem reading the map.
*/
public static Map readMap(File file, MapFormat format) throws MapException {
if (format == null) {
format = guessFormat(file);
}
if (format == null) {
throw new MapException("Unrecognised format");
}
Logger.debug("Reading " + format.toString() + " format");
return format.read(file);
}
/**
Guess the format for a Map.
@param file The file to guess the format of.
@return The most likely format or null if the file type is unrecognised.
@throws MapException If there is a problem reading the file.
*/
public static MapFormat guessFormat(File file) throws MapException {
Logger.debug("Guessing format");
for (MapFormat next : ALL_FORMATS) {
if (next.canRead(file)) {
return next;
}
}
return null;
}
}
package maps;
import javax.measure.unit.NonSI;
import javax.measure.unit.SI;
import org.jscience.geography.coordinates.UTM;
import org.jscience.geography.coordinates.LatLong;
import org.jscience.geography.coordinates.crs.ReferenceEllipsoid;
/**
Utility class for dealing with maps.
*/
public final class MapTools {
private MapTools() {
}
/**
Compute the size of one metre in latitude/longitude relative to a reference point.
@param lat The latitude of the reference point.
@param lon The longitude of the reference point.
@return The size of one metre at the reference point.
*/
public static double sizeOf1Metre(double lat, double lon) {
UTM centre = UTM.latLongToUtm(LatLong.valueOf(lat, lon, NonSI.DEGREE_ANGLE), ReferenceEllipsoid.WGS84);
UTM offset = UTM.valueOf(centre.longitudeZone(), centre.latitudeZone(), centre.eastingValue(SI.METRE), centre.northingValue(SI.METRE) + 1, SI.METRE);
LatLong result = UTM.utmToLatLong(offset, ReferenceEllipsoid.WGS84);
return Math.abs(result.latitudeValue(NonSI.DEGREE_ANGLE) - lat);
}
}
package maps;
import java.io.File;
/**
A class for writing maps.
*/
public final class MapWriter {
private MapWriter() {
}
/**
Write a map to a file.
@param map The map to write.
@param file The name of the file to write to.
@param format The MapFormat to write.
@throws MapException If there is a problem writing the map.
*/
public static void writeMap(Map map, String file, MapFormat format) throws MapException {
writeMap(map, new File(file), format);
}
/**
Write a Map to a file.
@param map The map to write.
@param file The file to write to.
@param format The MapFormat to write.
@throws MapException If there is a problem writing the map.
*/
public static void writeMap(Map map, File file, MapFormat format) throws MapException {
format.write(map, file);
}
}
package maps;
/**
A coordinate conversion that scales and translates coordinates.
*/
public class ScaleConversion implements CoordinateConversion {
private double xOrigin;
private double yOrigin;
private double xScale;
private double yScale;
/**
Construct a ScaleConversion.
@param xOrigin The x coordinate of the new origin.
@param yOrigin The y coordinate of the new origin.
@param xScale The scale factor for x coordinates.
@param yScale The scale factor for y coordinates.
*/
public ScaleConversion(double xOrigin, double yOrigin, double xScale, double yScale) {
this.xOrigin = xOrigin;
this.yOrigin = yOrigin;
this.xScale = xScale;
this.yScale = yScale;
}
@Override
public double convertX(double x) {
return (x - xOrigin) * xScale;
}
@Override
public double convertY(double y) {
return (y - yOrigin) * yScale;
}
}
package maps.convert;
import maps.MapWriter;
import maps.osm.OSMMap;
import maps.osm.OSMMapViewer;
import maps.osm.OSMException;
import maps.gml.GMLMap;
import maps.gml.view.GMLMapViewer;
import maps.convert.osm2gml.Convertor;
import maps.gml.formats.RobocupFormat;
import org.dom4j.DocumentException;
import java.awt.GridLayout;
import java.awt.Dimension;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.BorderFactory;
import java.io.File;
import java.io.IOException;
/**
This class converts maps from one format to another.
*/
public final class Convert {
// Nodes that are close are deemed to be co-located.
private static final double NEARBY_NODE_THRESHOLD = 0.000001;
private static final int PROGRESS_WIDTH = 200;
private static final int PROGRESS_HEIGHT = 10;
private static final int VIEWER_SIZE = 500;
private static final int STATUS_WIDTH = 500;
private static final int STATUS_HEIGHT = 10;
private static final int MARGIN = 4;
// private ShapeDebugFrame debug;
// private List<ShapeDebugFrame.ShapeInfo> allOSMNodes;
// private List<ShapeDebugFrame.ShapeInfo> allGMLNodes;
private Convert() {
}
/**
Run the map convertor.
@param args Command line arguments: osm-mapname gml-mapname.
*/
public static void main(String[] args) {
if (args.length < 2) {
System.out.println("Usage: Convert <osm-mapname> <gml-mapname>");
return;
}
try {
OSMMap osmMap = readOSMMap(args[0]);
OSMMapViewer osmViewer = new OSMMapViewer(osmMap);
Convertor convert = new Convertor();
GMLMap gmlMap = convert.convert(osmMap);
MapWriter.writeMap(gmlMap, args[1], RobocupFormat.INSTANCE);
GMLMapViewer gmlViewer = new GMLMapViewer(gmlMap);
JFrame frame = new JFrame("Convertor");
JPanel main = new JPanel(new GridLayout(1, 2));
osmViewer.setPreferredSize(new Dimension(VIEWER_SIZE, VIEWER_SIZE));
gmlViewer.setPreferredSize(new Dimension(VIEWER_SIZE, VIEWER_SIZE));
osmViewer.setBorder(BorderFactory.createTitledBorder("OSM map"));
gmlViewer.setBorder(BorderFactory.createTitledBorder("GML map"));
main.add(osmViewer);
main.add(gmlViewer);
frame.setContentPane(main);
frame.pack();
frame.setVisible(true);
frame.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
}
// CHECKSTYLE:OFF:IllegalCatch
catch (Exception e) {
e.printStackTrace();
}
// CHECKSTYLE:ON:IllegalCatch
}
private static OSMMap readOSMMap(String file) throws OSMException, IOException, DocumentException {
File f = new File(file);
return new OSMMap(f);
}
}
package maps.convert;
import javax.swing.JProgressBar;
import javax.swing.JLabel;
import javax.swing.JComponent;
import javax.swing.SwingUtilities;
import rescuecore2.misc.gui.ShapeDebugFrame;
import rescuecore2.log.Logger;
/**
A step in the map conversion process.
*/
public abstract class ConvertStep {
/** A ShapeDebugFrame for use by subclasses. */
protected ShapeDebugFrame debug;
private JProgressBar progress;
private JLabel status;
/**
Construct a ConvertStep.
*/
protected ConvertStep() {
this.progress = new JProgressBar();
this.status = new JLabel();
progress.setString("");
progress.setStringPainted(true);
debug = new ShapeDebugFrame();
}
/**
Set the progress level.
@param amount The new progress.
*/
protected void setProgress(final int amount) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
progress.setValue(amount);
progress.setString(progress.getValue() + " / " + progress.getMaximum());
}
});
}
/**
Increase the progress level by one.
*/
protected void bumpProgress() {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
progress.setValue(progress.getValue() + 1);
progress.setString(progress.getValue() + " / " + progress.getMaximum());
}
});
}
/**
Increase the maximum progress level by one.
*/
protected void bumpMaxProgress() {
bumpMaxProgress(1);
}
/**
Increase the maximum progress level by some amount.
@param amount The amount to increase the maximum progress level.
*/
protected void bumpMaxProgress(final int amount) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
progress.setMaximum(progress.getMaximum() + amount);
progress.setString(progress.getValue() + " / " + progress.getMaximum());
}
});
}
/**
Set the progress maximum.
@param max The new progress maximum.
*/
protected void setProgressLimit(final int max) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
progress.setIndeterminate(false);
progress.setMaximum(max);
progress.setString(progress.getValue() + " / " + progress.getMaximum());
}
});
}
/**
Set the status label.
@param s The new status label.
*/
protected void setStatus(final String s) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
status.setText(s);
}
});
}
/**
Get the JProgressBar component for this step.
@return The progress bar component.
*/
public JProgressBar getProgressBar() {
return progress;
}
/**
Get the status component for this step.
@return The status component.
*/
public JComponent getStatusComponent() {
return status;
}
/**
Perform the conversion step.
*/
public final void doStep() {
try {
Logger.pushLogContext(getClass().getName());
SwingUtilities.invokeLater(new Runnable() {
public void run() {
progress.setIndeterminate(true);
}
});
step();
SwingUtilities.invokeLater(new Runnable() {
public void run() {
progress.setIndeterminate(false);
progress.setValue(progress.getMaximum());
}
});
debug.deactivate();
}
finally {
Logger.popLogContext();
}
}
/**
Get a user-friendly description of this step.
@return A description string.
*/
public abstract String getDescription();
/**
Perform the step.
*/
protected abstract void step();
}
package maps.convert.legacy2gml;
import maps.legacy.LegacyBuilding;
import maps.gml.GMLMap;
import maps.gml.GMLBuilding;
import maps.gml.GMLRoad;
import maps.gml.GMLNode;
import maps.gml.GMLDirectedEdge;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.util.Collection;
import java.util.HashSet;
import rescuecore2.misc.geometry.Point2D;
import rescuecore2.misc.geometry.Line2D;
import rescuecore2.misc.geometry.GeometryTools2D;
import rescuecore2.misc.geometry.Vector2D;
import rescuecore2.misc.Pair;
import rescuecore2.log.Logger;
/**
Container for building information during conversion.
*/
public class BuildingInfo {
/**
* Width of a generated entrance road.
*/
public static final int ENTRANCE_SIZE = 3000;
private Point2D roadLeft;
private Point2D roadRight;
private LegacyBuilding building;
private List<GMLNode> apexes;
/**
Construct a BuildingInfo object.
@param b The LegacyBuilding to store info about.
*/
public BuildingInfo(LegacyBuilding b) {
building = b;
}
/**
Set the left corner at the road end.
@param newRoadLeft The new head-left corner.
*/
public void setRoadLeft(Point2D newRoadLeft) {
roadLeft = newRoadLeft;
}
/**
Set the right corner at the road end.
@param newRoadRight The new head-right corner.
*/
public void setRoadRight(Point2D newRoadRight) {
roadRight = newRoadRight;
}
/**
Process the building and create a GMLBuilding.
@param gml The GML map.
@param nodeInfo Information about the legacy nodes.
@param roadInfo Information about the legacy roads.
*/
public void process(GMLMap gml, Map<Integer, NodeInfo> nodeInfo, Map<Integer, RoadInfo> roadInfo) {
apexes = new ArrayList<GMLNode>();
int[] coords = building.getApexes();
for (int i = 0; i < coords.length; i += 2) {
int x = coords[i];
int y = coords[i + 1];
GMLNode node = gml.createNode(x, y);
apexes.add(node);
}
GMLBuilding b = gml.createBuildingFromNodes(apexes);
b.setFloors(building.getFloors());
b.setCode(building.getCode());
// Create an entrance
// Logger.debug("Creating entrance for " + building);
if (building.getEntrances().length == 0) {
return;
}
Point2D entrancePoint = nodeInfo.get(building.getEntrances()[0]).getLocation();
Point2D centre = new Point2D(building.getX(), building.getY());
Line2D centreLine = new Line2D(centre, entrancePoint);
Vector2D centreVector = centreLine.getDirection();
Vector2D leftVector = centreVector.getNormal().normalised().scale(ENTRANCE_SIZE / 2.0);
Vector2D rightVector = leftVector.scale(-1);
Line2D left = new Line2D(centre.plus(leftVector), centreVector);
Line2D right = new Line2D(centre.plus(rightVector), centreVector);
// Logger.debug("Entrance point: " + entrancePoint);
// Logger.debug("Building centre: " + centre);
// Logger.debug("Left line: " + left);
// Logger.debug("Right line: " + right);
Pair<Line2D, GMLDirectedEdge> leftEntrance = getEntrancePoint(left, centreLine, b.getEdges(), true, true);
if (leftEntrance == null) {
Logger.warn(b + ": Left entrance line does not intersect any walls");
return;
}
GMLNode leftNode = gml.createNode(leftEntrance.first().getOrigin().getX(), leftEntrance.first().getOrigin().getY());
// Logger.debug("New left node: " + leftNode);
gml.splitEdge(leftEntrance.second().getEdge(), leftNode);
Pair<Line2D, GMLDirectedEdge> rightEntrance = getEntrancePoint(right, centreLine, b.getEdges(), false, true);
if (rightEntrance == null) {
Logger.warn(b + ": Right entrance line does not intersect any walls");
return;
}
GMLNode rightNode = gml.createNode(rightEntrance.first().getOrigin().getX(), rightEntrance.first().getOrigin().getY());
// Logger.debug("New right node: " + rightNode);
gml.splitEdge(rightEntrance.second().getEdge(), rightNode);
gml.removeEdge(leftEntrance.second().getEdge());
gml.removeEdge(rightEntrance.second().getEdge());
// Now create the new road segment
// Pair<Line2D, GMLDirectedEdge> leftRoad = getEntrancePoint(left, centreLine, getAllRoadEdges(nodeInfo.values(), roadInfo.values()), true, false);
// if (leftRoad == null) {
// Logger.warn(b + ": Left entrance line does not intersect any roads");
// return;
// }
GMLNode roadLeftNode = gml.createNode(roadLeft.getX(), roadLeft.getY());
// Logger.debug("New road left node: " + roadLeftNode);
// gml.splitEdge(leftRoad.second().getEdge(), roadLeftNode);
// Pair<Line2D, GMLDirectedEdge> rightRoad = getEntrancePoint(right, centreLine, getAllRoadEdges(nodeInfo.values(), roadInfo.values()), false, false);
// if (rightRoad == null) {
// Logger.warn(b + ": Right entrance line does not intersect any roads");
// return;
// }
GMLNode roadRightNode = gml.createNode(roadRight.getX(), roadRight.getY());
// Logger.debug("New road left node: " + roadRightNode);
// gml.splitEdge(rightRoad.second().getEdge(), roadRightNode);
// Create the road
gml.createRoad(gml.apexesToEdges(roadLeftNode, roadRightNode, rightNode, leftNode));
}
/**
Trim a line to a set of walls and return the trimmed line and intersecting wall. Returns null if the line does not intersect any walls.
@param line The line to trim.
@param walls The walls to trim to.
@param trimStart True to trim the start of the line, false to trim the end.
*/
private Pair<Line2D, GMLDirectedEdge> trim(Line2D line, Collection<GMLDirectedEdge> walls, boolean trimStart) {
GMLDirectedEdge wall = null;
for (GMLDirectedEdge next : walls) {
Point2D p = GeometryTools2D.getSegmentIntersectionPoint(line, Tools.gmlDirectedEdgeToLine(next));
if (p != null) {
if (trimStart) {
line = new Line2D(p, line.getEndPoint());
}
else {
line = new Line2D(line.getOrigin(), p);
}
wall = next;
}
}
if (wall == null) {
return null;
}
return new Pair<Line2D, GMLDirectedEdge>(line, wall);
}
private Pair<Line2D, GMLDirectedEdge> getEntrancePoint(Line2D line, Line2D centre, Collection<GMLDirectedEdge> walls, boolean left, boolean trimStart) {
Pair<Line2D, GMLDirectedEdge> trimmed = trim(line, walls, trimStart);
if (trimmed == null) {
// Entrance line does not intersect with the building outline. Snap it back to the endpoint of the wall the centre line intersects with.
trimmed = trim(centre, walls, trimStart);
if (trimmed == null) {
// Entrance does not intersect with any walls!
return null;
}
GMLDirectedEdge wall = trimmed.second();
Line2D wallLine = Tools.gmlDirectedEdgeToLine(wall);
Vector2D centreNormal = centre.getDirection().getNormal().normalised();
if (!left) {
centreNormal = centreNormal.scale(-1);
}
Vector2D wallDirection = wallLine.getDirection().normalised();
Point2D end;
if (wallDirection.dot(centreNormal) > 0) {
// Same direction: end point is the end of the wall
end = wallLine.getEndPoint();
}
else {
// Opposite directions: end point is the start of the wall
end = wallLine.getOrigin();
}
return new Pair<Line2D, GMLDirectedEdge>(new Line2D(end, line.getEndPoint()), wall);
}
else {
return trimmed;
}
}
private Collection<GMLDirectedEdge> getAllRoadEdges(Collection<NodeInfo> nodes, Collection<RoadInfo> roads) {
Collection<GMLDirectedEdge> all = new HashSet<GMLDirectedEdge>();
for (NodeInfo next : nodes) {
GMLRoad r = next.getRoad();
if (r != null) {
all.addAll(r.getEdges());
}
}
for (RoadInfo next : roads) {
all.addAll(next.getRoad().getEdges());
}
return all;
}
}
package maps.convert.legacy2gml;
import maps.legacy.LegacyMap;
import maps.legacy.LegacyMapFormat;
import maps.legacy.LegacyRoad;
import maps.legacy.LegacyNode;
import maps.legacy.LegacyBuilding;
import maps.gml.GMLMap;
import maps.gml.formats.RobocupFormat;
import maps.ScaleConversion;
import java.io.File;
import java.util.Map;
import java.util.HashMap;
import rescuecore2.log.Logger;
/**
This class converts maps from the legacy format to GML.
*/
public final class LegacyToGML {
private static final double MM_TO_M = 0.001;
private LegacyToGML() {}
/**
Run the map convertor.
@param args Command line arguments: legacy-mapdir gml-mapname.
*/
public static void main(String[] args) {
if (args.length < 2) {
System.out.println("Usage: LegacyToGML <legacy-mapdir> <gml-mapname>");
return;
}
try {
Logger.info("Reading legacy map");
LegacyMap legacy = LegacyMapFormat.INSTANCE.read(new File(args[0]));
GMLMap gml = new GMLMap();
Logger.info("Converting");
convert(legacy, gml);
Logger.info("Writing GML map");
RobocupFormat.INSTANCE.write(gml, new File(args[1]));
Logger.info("Done");
}
// CHECKSTYLE:OFF:IllegalCatch
catch (Exception e) {
e.printStackTrace();
}
// CHECKSTYLE:ON:IllegalCatch
System.exit(0);
}
private static void convert(LegacyMap legacy, GMLMap gml) {
Map<Integer, RoadInfo> roadInfo = new HashMap<Integer, RoadInfo>();
Map<Integer, NodeInfo> nodeInfo = new HashMap<Integer, NodeInfo>();
Map<Integer, BuildingInfo> buildingInfo = new HashMap<Integer, BuildingInfo>();
Logger.debug("Reading roads");
for (LegacyRoad r : legacy.getRoads()) {
roadInfo.put(r.getID(), new RoadInfo());
}
Logger.debug("Removing duplicate roads");
for (LegacyNode n : legacy.getNodes()) {
Map<Integer, LegacyRoad> roadToFarNode = new HashMap<Integer, LegacyRoad>();
for (int rid : n.getEdges()) {
LegacyRoad road = legacy.getRoad(rid);
if (road == null) {
continue;
}
int farNodeId = (n.getID() == road.getHead()) ? road.getTail() : road.getHead();
// Use the widest road
LegacyRoad existingRoad = roadToFarNode.get(farNodeId);
if (existingRoad != null && road.getWidth() <= existingRoad.getWidth()) {
roadInfo.remove(road.getID());
}
else if (existingRoad != null) {
roadInfo.remove(existingRoad.getID());
roadToFarNode.put(farNodeId, road);
}
else {
roadToFarNode.put(farNodeId, road);
}
}
}
Logger.debug("Reading nodes");
for (LegacyNode n : legacy.getNodes()) {
nodeInfo.put(n.getID(), new NodeInfo(n));
}
Logger.debug("Reading buildings");
for (LegacyBuilding b : legacy.getBuildings()) {
buildingInfo.put(b.getID(), new BuildingInfo(b));
}
Logger.debug("Creating intersections");
for (NodeInfo n : nodeInfo.values()) {
n.process(legacy, gml, roadInfo, buildingInfo);
}
Logger.debug("Creating roads");
for (RoadInfo r : roadInfo.values()) {
r.process(gml);
}
Logger.debug("Creating buildings");
for (BuildingInfo b : buildingInfo.values()) {
b.process(gml, nodeInfo, roadInfo);
}
// Rescale to m
gml.convertCoordinates(new ScaleConversion(gml.getMinX(), gml.getMinY(), MM_TO_M, MM_TO_M));
}
}
package maps.convert.legacy2gml;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import maps.gml.GMLMap;
import maps.gml.GMLNode;
import maps.gml.GMLRoad;
import maps.legacy.LegacyBuilding;
import maps.legacy.LegacyMap;
import maps.legacy.LegacyNode;
import maps.legacy.LegacyObject;
import maps.legacy.LegacyRoad;
import rescuecore2.misc.geometry.GeometryTools2D;
import rescuecore2.misc.geometry.Line2D;
import rescuecore2.misc.geometry.Point2D;
import rescuecore2.misc.geometry.Vector2D;
/**
Container for node information during conversion.
*/
public class NodeInfo {
private LegacyNode node;
private Point2D centre;
private List<GMLNode> apexes;
private GMLRoad road;
/**
Construct a NodeInfo object.
@param node The LegacyNode to store info about.
*/
public NodeInfo(LegacyNode node) {
this.node = node;
centre = new Point2D(node.getX(), node.getY());
}
/**
Get the LegacyNode.
@return The LegacyNode.
*/
public LegacyNode getNode() {
return node;
}
/**
Get the node location.
@return The node location.
*/
public Point2D getLocation() {
return centre;
}
/**
Get the generated GMLRoad.
@return The generated road or null if this node did not generate a road segment.
*/
public GMLRoad getRoad() {
return road;
}
/**
Process the node and create GMLRoad objects if required.
@param legacy The legacy map.
@param gml The GML map.
@param roadInfo A map from road ID to RoadInfo.
@param buildingInfo A map from building ID to BuildingInfo.
*/
public void process(LegacyMap legacy, GMLMap gml, Map<Integer, RoadInfo> roadInfo, Map<Integer, BuildingInfo> buildingInfo) {
apexes = new ArrayList<GMLNode>();
List<EdgeAspect> edges = new ArrayList<EdgeAspect>();
for (int id : node.getEdges()) {
LegacyRoad lRoad = legacy.getRoad(id);
if (lRoad != null && roadInfo.containsKey(id)) {
edges.add(new RoadAspect(lRoad, node, legacy, roadInfo.get(id)));
continue;
}
LegacyBuilding lBuilding = legacy.getBuilding(id);
if (lBuilding != null && buildingInfo.containsKey(id)) {
edges.add(new BuildingAspect(lBuilding, node, legacy, buildingInfo.get(id)));
}
}
if (edges.size() == 1) {
EdgeAspect aspect = edges.get(0);
findRoadEdges(aspect, centre);
}
else {
// Sort the roads
CounterClockwiseSort sort = new CounterClockwiseSort(centre);
Collections.sort(edges, sort);
// Now build the apex list
Iterator<EdgeAspect> it = edges.iterator();
EdgeAspect first = it.next();
EdgeAspect prev = first;
EdgeAspect next;
while (it.hasNext()) {
next = it.next();
Point2D[] newApexes = findIncomingEdgeIntersection(prev, next, centre);
for (Point2D apex : newApexes) {
apexes.add(gml.createNode(apex.getX(), apex.getY()));
}
prev = next;
}
Point2D[] newApexes = findIncomingEdgeIntersection(prev, first, centre);
for (Point2D apex : newApexes) {
apexes.add(gml.createNode(apex.getX(), apex.getY()));
}
}
if (apexes.size() > 2) {
road = gml.createRoadFromNodes(apexes);
}
}
/**
Process two incoming roads and find the intersection of the right edge of the first road and the left edge of the second road.
@param first The road endpoint to check the right edge of.
@param second The road endpoint to check the left edge of.
@param centrePoint The centre of the intersection.
@return The intersection of the two roads.
*/
private Point2D[] findIncomingEdgeIntersection(EdgeAspect first, EdgeAspect second, Point2D centrePoint) {
LegacyObject firstNode = first.getFarNode();
LegacyObject secondNode = second.getFarNode();
Point2D firstPoint = new Point2D(firstNode.getX(), firstNode.getY());
Point2D secondPoint = new Point2D(secondNode.getX(), secondNode.getY());
// Find the intersection of the incoming road edges
Vector2D firstVector = centrePoint.minus(firstPoint);
Vector2D secondVector = centrePoint.minus(secondPoint);
Vector2D firstNormal = firstVector.getNormal().normalised().scale(-first.getRoadWidth() / 2.0);
Vector2D secondNormal = secondVector.getNormal().normalised().scale(second.getRoadWidth() / 2.0);
Point2D start1Point = firstPoint.plus(firstNormal);
Point2D start2Point = secondPoint.plus(secondNormal);
Line2D line1 = new Line2D(start1Point, firstVector);
Line2D line2 = new Line2D(start2Point, secondVector);
Point2D intersection = GeometryTools2D.getIntersectionPoint(line1, line2);
if (intersection == null) {
// Lines are parallel
// This means the normals are parallel, so we can just add a normal to the centre point to generate an intersection point
intersection = centrePoint.plus(firstNormal);
}
double maxWidth = Math.max(first.getRoadWidth(), second.getRoadWidth());
double distance = GeometryTools2D.getDistance(centrePoint, intersection);
Vector2D intersectionVector = intersection.minus(centrePoint).normalised();
double dp1 = firstVector.normalised().dot(intersectionVector);
double dp2 = secondVector.normalised().dot(intersectionVector);
if (distance > maxWidth && dp1 > 0 && dp2 > 0) {
//Cap spikes on acute angles
Vector2D cutoffVector = intersectionVector.getNormal().scale(maxWidth);
Point2D cutoffStart = centrePoint.plus(intersectionVector.scale(maxWidth)).plus(cutoffVector);
// CHECKSTYLE:OFF:MagicNumber
Line2D cutoffLine = new Line2D(cutoffStart, cutoffVector.scale(-2.0));
// CHECKSTYLE:ON:MagicNumber
Point2D end1 = GeometryTools2D.getIntersectionPoint(line1, cutoffLine);
Point2D end2 = GeometryTools2D.getIntersectionPoint(line2, cutoffLine);
first.setRightEnd(end1);
second.setLeftEnd(end2);
return new Point2D[] {end1, end2};
}
else if (distance > maxWidth && (dp1 > 0 || dp2 > 0)) {
// Prevent too distant intersections on obtuse angles
// Those usually happen on intersections between roads with (very) different widths.
// For now, just use the intersection that would have occured between two roads
// of the averages width
double avgWidth = (first.getRoadWidth() + second.getRoadWidth()) / 2.0;
firstNormal = firstVector.getNormal().normalised().scale(-avgWidth / 2.0);
secondNormal = secondVector.getNormal().normalised().scale(avgWidth / 2.0);
start1Point = firstPoint.plus(firstNormal);
start2Point = secondPoint.plus(secondNormal);
line1 = new Line2D(start1Point, firstVector);
line2 = new Line2D(start2Point, secondVector);
intersection = GeometryTools2D.getIntersectionPoint(line1, line2);
first.setRightEnd(intersection);
second.setLeftEnd(intersection);
}
else if (distance > maxWidth) {
// Inner acute angle: just cut off at twice the max. road width.
intersection = centrePoint.plus(intersectionVector.scale(maxWidth * 2.0));
first.setRightEnd(intersection);
second.setLeftEnd(intersection);
}
else {
first.setRightEnd(intersection);
second.setLeftEnd(intersection);
}
return new Point2D[] {intersection};
}
private void findRoadEdges(EdgeAspect aspect, Point2D centrePoint) {
LegacyObject farNode = aspect.getFarNode();
Point2D roadPoint = new Point2D(farNode.getX(), farNode.getY());
Vector2D vector = centrePoint.minus(roadPoint);
Vector2D leftNormal = vector.getNormal().normalised().scale(aspect.getRoadWidth() / 2.0);
Vector2D rightNormal = leftNormal.scale(-1);
Point2D left = centrePoint.plus(leftNormal);
Point2D right = centrePoint.plus(rightNormal);
aspect.setLeftEnd(left);
aspect.setRightEnd(right);
}
private interface EdgeAspect {
int getRoadWidth();
LegacyObject getFarNode();
void setLeftEnd(Point2D p);
void setRightEnd(Point2D p);
}
private static class RoadAspect implements EdgeAspect {
private boolean forward;
private LegacyNode farNode;
private RoadInfo info;
private int width;
RoadAspect(LegacyRoad road, LegacyNode intersection, LegacyMap map, RoadInfo info) {
forward = intersection.getID() == road.getTail();
farNode = map.getNode(forward ? road.getHead() : road.getTail());
width = road.getWidth();
this.info = info;
}
public int getRoadWidth() {
return width;
}
public LegacyObject getFarNode() {
return farNode;
}
public void setLeftEnd(Point2D p) {
if (forward) {
info.setHeadLeft(p);
}
else {
info.setTailRight(p);
}
}
public void setRightEnd(Point2D p) {
if (forward) {
info.setHeadRight(p);
}
else {
info.setTailLeft(p);
}
}
}
private static class BuildingAspect implements EdgeAspect {
private LegacyBuilding building;
private BuildingInfo info;
BuildingAspect(LegacyBuilding building, LegacyNode intersection, LegacyMap map, BuildingInfo info) {
this.building = building;
this.info = info;
}
public int getRoadWidth() {
return BuildingInfo.ENTRANCE_SIZE;
}
public LegacyObject getFarNode() {
return building;
}
public void setLeftEnd(Point2D p) {
info.setRoadLeft(p);
}
public void setRightEnd(Point2D p) {
info.setRoadRight(p);
}
}
private static class CounterClockwiseSort implements Comparator<EdgeAspect> {
private Point2D centre;
/**
Construct a CounterClockwiseSort with a reference point.
@param centre The reference point.
*/
public CounterClockwiseSort(Point2D centre) {
this.centre = centre;
}
@Override
public int compare(EdgeAspect first, EdgeAspect second) {
double d1 = score(first);
double d2 = score(second);
if (d1 < d2) {
return 1;
}
else if (d1 > d2) {
return -1;
}
else {
return 0;
}
}
/**
Compute the score for a RoadAspect - the amount of clockwiseness from 12 o'clock.
@param aspect The RoadAspect.
@return The amount of clockwiseness. This will be in the range [0..4) with 0 representing 12 o'clock, 1 representing 3 o'clock and so on.
*/
public double score(EdgeAspect aspect) {
LegacyObject node = aspect.getFarNode();
Point2D point = new Point2D(node.getX(), node.getY());
Vector2D v = point.minus(centre);
double sin = v.getX() / v.getLength();
double cos = v.getY() / v.getLength();
if (Double.isNaN(sin) || Double.isNaN(cos)) {
System.out.println(v);
System.out.println(v.getLength());
}
return convert(sin, cos);
}
// CHECKSTYLE:OFF:MagicNumber
private double convert(double sin, double cos) {
if (sin >= 0 && cos >= 0) {
return sin;
}
if (sin >= 0 && cos < 0) {
return 2 - sin;
}
if (sin < 0 && cos < 0) {
return 2 - sin;
}
if (sin < 0 && cos >= 0) {
return 4 + sin;
}
throw new IllegalArgumentException("This should be impossible! What's going on? sin=" + sin + ", cos=" + cos);
}
// CHECKSTYLE:ON:MagicNumber
}
}
package maps.convert.legacy2gml;
import rescuecore2.misc.geometry.Point2D;
import maps.gml.GMLMap;
import maps.gml.GMLNode;
import maps.gml.GMLRoad;
import java.util.List;
import java.util.ArrayList;
/**
Container for road information during conversion.
*/
public class RoadInfo {
private Point2D headLeft;
private Point2D headRight;
private Point2D tailLeft;
private Point2D tailRight;
private GMLRoad road;
/**
Construct a RoadInfo.
*/
public RoadInfo() {
}
/**
Set the left corner at the head end.
@param newHeadLeft The new head-left corner.
*/
public void setHeadLeft(Point2D newHeadLeft) {
headLeft = newHeadLeft;
}
/**
Set the right corner at the head end.
@param newHeadRight The new head-right corner.
*/
public void setHeadRight(Point2D newHeadRight) {
headRight = newHeadRight;
}
/**
Set the left corner at the tail end.
@param newTailLeft The new tail-left corner.
*/
public void setTailLeft(Point2D newTailLeft) {
tailLeft = newTailLeft;
}
/**
Set the right corner at the tail end.
@param newTailRight The new tail-right corner.
*/
public void setTailRight(Point2D newTailRight) {
tailRight = newTailRight;
}
/**
Get the generated GMLRoad.
@return The generated road.
*/
public GMLRoad getRoad() {
return road;
}
/**
Process this RoadInfo and generate a GMLRoad object.
@param gml The GML map.
*/
public void process(GMLMap gml) {
List<GMLNode> apexes = new ArrayList<GMLNode>();
apexes.add(gml.createNode(headLeft.getX(), headLeft.getY()));
apexes.add(gml.createNode(tailLeft.getX(), tailLeft.getY()));
apexes.add(gml.createNode(tailRight.getX(), tailRight.getY()));
apexes.add(gml.createNode(headRight.getX(), headRight.getY()));
road = gml.createRoadFromNodes(apexes);
}
}
package maps.convert.legacy2gml;
import java.util.List;
import java.util.ArrayList;
import java.util.Iterator;
import rescuecore2.misc.geometry.Point2D;
import rescuecore2.misc.geometry.Line2D;
import maps.gml.GMLNode;
import maps.gml.GMLDirectedEdge;
/**
Utilities for the legacy2gml covertor.
*/
public final class Tools {
private Tools() {}
/**
Convert a list of GML nodes to Line2D objects.
@param nodes The node list.
@return A new Line2D list.
*/
public static List<Line2D> nodeListToLineList(List<GMLNode> nodes) {
List<Line2D> result = new ArrayList<Line2D>(nodes.size());
Iterator<GMLNode> it = nodes.iterator();
GMLNode first = it.next();
GMLNode prev = first;
while (it.hasNext()) {
GMLNode next = it.next();
result.add(new Line2D(new Point2D(prev.getX(), prev.getY()), new Point2D(next.getX(), next.getY())));
prev = next;
}
result.add(new Line2D(new Point2D(prev.getX(), prev.getY()), new Point2D(first.getX(), first.getY())));
return result;
}
/**
Convert a GMLDirectedEdge to a Line2D.
@param edge The edge to convert.
@return A new Line2D.
*/
public static Line2D gmlDirectedEdgeToLine(GMLDirectedEdge edge) {
GMLNode start = edge.getStartNode();
GMLNode end = edge.getEndNode();
Point2D origin = new Point2D(start.getX(), start.getY());
Point2D endPoint = new Point2D(end.getX(), end.getY());
return new Line2D(origin, endPoint);
}
}
\ No newline at end of file
package maps.convert.osm2gml;
import maps.osm.OSMMap;
import maps.osm.OSMNode;
import maps.osm.OSMRoad;
import maps.osm.OSMBuilding;
import maps.osm.OSMWay;
import maps.convert.ConvertStep;
import java.util.List;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.Set;
import java.util.HashSet;
import java.util.Collection;
import java.util.Collections;
import rescuecore2.misc.geometry.Line2D;
//import rescuecore2.log.Logger;
/**
This step cleans the OpenStreetMap data by removing duplicate nodes and way, fixing degenerate ways, and fixing building edge orderings.
*/
public class CleanOSMStep extends ConvertStep {
private TemporaryMap map;
/**
Construct a CleanOSMStep.
@param map The TemporaryMap to clean.
*/
public CleanOSMStep(TemporaryMap map) {
this.map = map;
}
@Override
public String getDescription() {
return "Cleaning OpenStreetMap data";
}
@Override
protected void step() {
OSMMap osm = map.getOSMMap();
setProgressLimit(osm.getNodes().size() + (osm.getRoads().size() + osm.getBuildings().size()) * 2 + osm.getBuildings().size());
setStatus("Looking for duplicate nodes");
int nodes = fixNodes();
setStatus("Fixing degenerate ways");
int fixed = fixDegenerateWays(osm.getRoads());
fixed += fixDegenerateWays(osm.getBuildings());
setStatus("Looking for duplicate ways");
int ways = fixDuplicateWays(osm.getRoads());
ways += fixDuplicateWays(osm.getBuildings());
setStatus("Fixing building direction");
int b = fixBuildingDirection(osm.getBuildings());
setStatus("Removed " + nodes + " duplicate nodes and " + ways + " duplicate ways, fixed " + fixed + " degenerate ways, fixed " + b + " clockwise buildings");
}
private int fixNodes() {
OSMMap osm = map.getOSMMap();
int count = 0;
double threshold = ConvertTools.nearbyThreshold(osm, map.getNearbyThreshold());
Set<OSMNode> removed = new HashSet<OSMNode>();
for (OSMNode next : osm.getNodes()) {
if (removed.contains(next)) {
bumpProgress();
continue;
}
for (OSMNode test : osm.getNodes()) {
if (next == test) {
continue;
}
if (removed.contains(test)) {
continue;
}
if (nearby(next, test, threshold)) {
// Remove the test node and replace all references to it with 'next'
osm.replaceNode(test, next);
removed.add(test);
// Logger.debug("Removed duplicate node " + test.getID());
++count;
}
}
bumpProgress();
}
return count;
}
private int fixDegenerateWays(Collection<? extends OSMWay> ways) {
int count = 0;
for (OSMWay way : ways) {
// Check that no nodes are listed multiple times in sequence
List<Long> ids = new ArrayList<Long>(way.getNodeIDs());
Iterator<Long> it = ids.iterator();
if (!it.hasNext()) {
// Empty way. Remove it.
remove(way);
++count;
continue;
}
long last = it.next();
boolean fixed = false;
while (it.hasNext()) {
long next = it.next();
if (next == last) {
// Duplicate node
it.remove();
// Logger.debug("Removed node " + next + " from way " + way.getID());
fixed = true;
}
last = next;
}
if (fixed) {
way.setNodeIDs(ids);
++count;
}
bumpProgress();
}
return count;
}
private int fixDuplicateWays(Collection<? extends OSMWay> ways) {
int count = 0;
Set<OSMWay> removed = new HashSet<OSMWay>();
for (OSMWay next : ways) {
if (removed.contains(next)) {
bumpProgress();
continue;
}
// Look at all other roads and see if any are subpaths of this road
for (OSMWay test : ways) {
if (next == test) {
continue;
}
if (removed.contains(test)) {
continue;
}
List<Long> testIDs = test.getNodeIDs();
if (isSubList(testIDs, next.getNodeIDs())) {
remove(test);
removed.add(test);
++count;
// Logger.debug("Removed way " + test.getID());
}
else {
Collections.reverse(testIDs);
if (isSubList(testIDs, next.getNodeIDs())) {
remove(test);
removed.add(test);
++count;
// Logger.debug("Removed way " + test.getID());
}
}
}
bumpProgress();
}
return count;
}
/**
Make sure all buildings have their nodes listed in clockwise order.
*/
private int fixBuildingDirection(Collection<OSMBuilding> buildings) {
OSMMap osm = map.getOSMMap();
// Sum the angles of all right-hand turns
// If the total is +360 then order is clockwise, -360 means counterclockwise.
int count = 0;
for (OSMBuilding building : buildings) {
// Logger.debug("Building " + building + " angle sum: " + ConvertTools.getAnglesSum(building, osm));
if (ConvertTools.isClockwise(building, osm)) {
// Reverse the order
List<Long> ids = building.getNodeIDs();
Collections.reverse(ids);
building.setNodeIDs(ids);
++count;
}
bumpProgress();
}
return count;
}
private boolean nearby(OSMNode first, OSMNode second, double threshold) {
double dx = first.getLongitude() - second.getLongitude();
double dy = first.getLatitude() - second.getLatitude();
return (dx >= -threshold
&& dx <= threshold
&& dy >= -threshold
&& dy <= threshold);
}
private boolean isSubList(List<Long> first, List<Long> second) {
return Collections.indexOfSubList(second, first) != -1;
}
private void remove(OSMWay way) {
OSMMap osm = map.getOSMMap();
if (way instanceof OSMRoad) {
osm.removeRoad((OSMRoad)way);
}
else if (way instanceof OSMBuilding) {
osm.removeBuilding((OSMBuilding)way);
}
else {
throw new IllegalArgumentException("Don't know how to handle this type of OSMWay: " + way.getClass().getName());
}
}
private Line2D makeLine(long first, long second) {
OSMMap osm = map.getOSMMap();
OSMNode n1 = osm.getNode(first);
OSMNode n2 = osm.getNode(second);
return new Line2D(n1.getLongitude(), n1.getLatitude(), n2.getLongitude() - n1.getLongitude(), n2.getLatitude() - n1.getLatitude());
}
}
package maps.convert.osm2gml;
import maps.convert.ConvertStep;
import java.util.Collection;
/**
This step computes which edges are passable and sets up neighbours accordingly.
*/
public class ComputePassableEdgesStep extends ConvertStep {
private TemporaryMap map;
/**
Construct a ComputePassableEdgesStep.
@param map The TemporaryMap to use.
*/
public ComputePassableEdgesStep(TemporaryMap map) {
this.map = map;
}
@Override
public String getDescription() {
return "Computing passable edges";
}
@Override
protected void step() {
setProgressLimit(map.getAllEdges().size());
// For each edge see if it is shared by two road faces
// If so, make it passable.
int count = 0;
for (Edge next : map.getAllEdges()) {
int roadCount = 0;
Collection<TemporaryObject> attached = map.getAttachedObjects(next);
for (TemporaryObject o : attached) {
if (o instanceof TemporaryRoad || o instanceof TemporaryIntersection) {
++roadCount;
}
}
if (roadCount > 1) {
// Edge is passable. Make the neighbours.
for (TemporaryObject o1 : attached) {
for (TemporaryObject o2 : attached) {
if (o1 == o2) {
continue;
}
o1.setNeighbour(next, o2);
}
}
++count;
}
bumpProgress();
}
setStatus("Made " + count + " edges passable");
}
}
package maps.convert.osm2gml;
import java.awt.Color;
/** Useful OSM to GML constants. */
public final class Constants {
/** The width of roads in m. */
public static final float ROAD_WIDTH = 7;
// CHECKSTYLE:OFF:JavadocVariable
public static final Color BLACK = new Color(0, 0, 0);
public static final Color WHITE = new Color(255, 255, 255);
public static final Color RED = new Color(255, 0, 0);
public static final Color MAROON = new Color(128, 0, 0);
public static final Color LIME = new Color(0, 255, 0);
public static final Color GREEN = new Color(0, 128, 0);
public static final Color BLUE = new Color(0, 0, 255);
public static final Color NAVY = new Color(0, 0, 128);
public static final Color FUSCHIA = new Color(255, 0, 255);
public static final Color GRAY = new Color(128, 128, 128);
public static final Color OLIVE = new Color(128, 128, 0);
public static final Color PURPLE = new Color(128, 0, 128);
public static final Color SILVER = new Color(192, 192, 192);
public static final Color TEAL = new Color(0, 128, 128);
public static final Color YELLOW = new Color(255, 255, 0);
public static final Color AQUA = new Color(0, 255, 255);
public static final Color ORANGE = new Color(255, 140, 0);
public static final Color TRANSPARENT_BLACK = new Color(0, 0, 0, 128);
public static final Color TRANSPARENT_WHITE = new Color(255, 255, 255, 128);
public static final Color TRANSPARENT_RED = new Color(255, 0, 0, 128);
public static final Color TRANSPARENT_MAROON = new Color(128, 0, 0, 128);
public static final Color TRANSPARENT_LIME = new Color(0, 255, 0, 128);
public static final Color TRANSPARENT_GREEN = new Color(0, 128, 0, 128);
public static final Color TRANSPARENT_BLUE = new Color(0, 0, 255, 128);
public static final Color TRANSPARENT_NAVY = new Color(0, 0, 128, 128);
public static final Color TRANSPARENT_FUSCHIA = new Color(255, 0, 255, 128);
public static final Color TRANSPARENT_GRAY = new Color(128, 128, 128, 128);
public static final Color TRANSPARENT_OLIVE = new Color(128, 128, 0, 128);
public static final Color TRANSPARENT_PURPLE = new Color(128, 0, 128, 128);
public static final Color TRANSPARENT_SILVER = new Color(192, 192, 192, 128);
public static final Color TRANSPARENT_TEAL = new Color(0, 128, 128, 128);
public static final Color TRANSPARENT_YELLOW = new Color(255, 255, 0, 128);
public static final Color TRANSPARENT_AQUA = new Color(0, 255, 255, 128);
public static final Color TRANSPARENT_ORANGE = new Color(255, 140, 0, 128);
public static final Color[] COLOURS = {RED,
GREEN,
BLUE,
MAROON,
LIME,
NAVY,
OLIVE,
PURPLE,
TEAL,
GRAY,
SILVER,
FUSCHIA,
YELLOW,
AQUA,
ORANGE,
BLACK,
WHITE
};
public static final Color[] TRANSPARENT_COLOURS = {TRANSPARENT_RED,
TRANSPARENT_GREEN,
TRANSPARENT_BLUE,
TRANSPARENT_MAROON,
TRANSPARENT_LIME,
TRANSPARENT_NAVY,
TRANSPARENT_OLIVE,
TRANSPARENT_PURPLE,
TRANSPARENT_TEAL,
TRANSPARENT_GRAY,
TRANSPARENT_SILVER,
TRANSPARENT_FUSCHIA,
TRANSPARENT_YELLOW,
TRANSPARENT_AQUA,
TRANSPARENT_ORANGE,
TRANSPARENT_BLACK,
TRANSPARENT_WHITE
};
// CHECKSTYLE:ON:JavadocVariable
private Constants() {
}
}
package maps.convert.osm2gml;
import rescuecore2.misc.geometry.Point2D;
import rescuecore2.misc.geometry.Line2D;
import rescuecore2.misc.geometry.Vector2D;
import rescuecore2.misc.geometry.GeometryTools2D;
import rescuecore2.misc.gui.ShapeDebugFrame;
//import rescuecore2.log.Logger;
import maps.gml.GMLMap;
import maps.gml.GMLNode;
import maps.gml.debug.GMLNodeShapeInfo;
import maps.gml.GMLEdge;
import maps.gml.debug.GMLEdgeShapeInfo;
//import maps.gml.GMLFace;
//import maps.gml.debug.GMLFaceShapeInfo;
import maps.gml.GMLDirectedEdge;
import maps.gml.GMLObject;
import maps.gml.GMLRoad;
import maps.gml.GMLBuilding;
import maps.gml.GMLSpace;
import maps.gml.GMLShape;
import maps.gml.debug.GMLShapeInfo;
import maps.osm.OSMMap;
import maps.osm.OSMNode;
import maps.osm.OSMBuilding;
import maps.MapTools;
import java.util.Set;
import java.util.List;
import java.util.Collection;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.awt.Color;
/**
Useful tools for converting OSM to GML.
*/
public final class ConvertTools {
private static final Color BACKGROUND_BUILDING_COLOUR = new Color(0, 255, 0, 32); // Transparent lime
private static final Color BACKGROUND_INTERSECTION_COLOUR = new Color(192, 192, 192, 32); // Transparent silver
private static final Color BACKGROUND_ROAD_COLOUR = new Color(128, 128, 128, 32); // Transparent gray
private static final Color BACKGROUND_SPACE_COLOUR = new Color(0, 128, 0, 32); // Transparent green
private static final double CLOCKWISE_SUM = -360;
private static final double THRESHOLD = 0.0001;
private ConvertTools() {}
/**
Compute the size of one metre in latitude/longitude for an OSMMap.
@param map The map to look up.
@return The size of one metre on the given map.
*/
public static double sizeOf1Metre(OSMMap map) {
return MapTools.sizeOf1Metre(map.getCentreLatitude(), map.getCentreLongitude());
}
/**
Compute the nearby-node threshold for an OSMMap in degrees.
@param map The map to look up.
@param thresholdM The desired threshold in meters.
@return The size of the nearby-node threshold for the map in degrees.
*/
public static double nearbyThreshold(OSMMap map, double thresholdM) {
return sizeOf1Metre(map) * thresholdM;
}
/**
Convert a GMLEdge to a Line2D.
@param edge The edge to convert.
@return A new Line2D.
*/
public static Line2D gmlEdgeToLine(GMLEdge edge) {
GMLNode start = edge.getStart();
GMLNode end = edge.getEnd();
Point2D origin = new Point2D(start.getX(), start.getY());
Point2D endPoint = new Point2D(end.getX(), end.getY());
return new Line2D(origin, endPoint);
}
/**
Convert a GMLEdge to a Line2D.
@param edge The edge to convert.
@param start The node to start from. This must be one of the endpoints of the edge.
@return A new Line2D.
*/
public static Line2D gmlEdgeToLine(GMLEdge edge, GMLNode start) {
if (!start.equals(edge.getStart()) && !start.equals(edge.getEnd())) {
throw new IllegalArgumentException("'start' must be one of the endpoints of 'edge'");
}
GMLNode end = start.equals(edge.getStart()) ? edge.getEnd() : edge.getStart();
Point2D origin = new Point2D(start.getX(), start.getY());
Point2D endPoint = new Point2D(end.getX(), end.getY());
return new Line2D(origin, endPoint);
}
/**
Convert a GMLDirectedEdge to a Line2D.
@param edge The edge to convert.
@return A new Line2D.
*/
public static Line2D gmlDirectedEdgeToLine(GMLDirectedEdge edge) {
GMLNode start = edge.getStartNode();
GMLNode end = edge.getEndNode();
Point2D origin = new Point2D(start.getX(), start.getY());
Point2D endPoint = new Point2D(end.getX(), end.getY());
return new Line2D(origin, endPoint);
}
/**
Find the "leftmost" turn in a particular direction, i.e. the one with the highest left angle, or the lowest right angle if there are no left turns possible.
@param from The edge we're turning from.
@param candidates The set of edges we could turn into.
@return The leftmost turn.
*/
public static Edge findLeftTurn(DirectedEdge from, Set<? extends Edge> candidates) {
return findBestTurn(from, candidates, true);
}
/**
Find the "rightmost" turn in a particular direction, i.e. the one with the highest right angle, or the lowest left angle if there are no right turns possible.
@param from The edge we're turning from.
@param candidates The set of edges we could turn into.
@return The rightmost turn.
*/
public static Edge findRightTurn(DirectedEdge from, Set<? extends Edge> candidates) {
return findBestTurn(from, candidates, false);
}
/**
Find the "best" turn in a particular direction. If left turns are preferred then the "best" turn is the one with the highest left angle, or the lowest right angle. For right turns, the "best" is the one with the highest right angle or the lowest left angle.
@param from The edge we're turning from.
@param candidates The set of edges we could turn into.
@param preferLeft Whether to prefer left turns or not.
@return The best turn.
*/
public static Edge findBestTurn(DirectedEdge from, Set<? extends Edge> candidates, boolean preferLeft) {
Edge mostRight = null;
Edge mostLeft = null;
Edge leastRight = null;
Edge leastLeft = null;
double mostRightAngle = 0;
double mostLeftAngle = 0;
double leastRightAngle = 0;
double leastLeftAngle = 0;
Line2D fromLine = from.getLine();
for (Edge next : candidates) {
if (next.equals(from.getEdge())) {
continue;
}
Line2D nextLine = next.getLine();
if (!next.getStart().equals(from.getEndNode())) {
nextLine = new Line2D(nextLine.getEndPoint(), nextLine.getOrigin());
}
if (GeometryTools2D.isRightTurn(fromLine, nextLine)) {
double angle = GeometryTools2D.getRightAngleBetweenLines(fromLine, nextLine);
if (mostRight == null || angle > mostRightAngle) {
mostRight = next;
mostRightAngle = angle;
}
if (leastRight == null || angle < leastRightAngle) {
leastRight = next;
leastRightAngle = angle;
}
}
else {
double angle = GeometryTools2D.getLeftAngleBetweenLines(fromLine, nextLine);
if (mostLeft == null || angle > mostLeftAngle) {
mostLeft = next;
mostLeftAngle = angle;
}
if (leastLeft == null || angle < leastLeftAngle) {
leastLeft = next;
leastLeftAngle = angle;
}
}
}
if (preferLeft) {
if (mostLeft != null) {
return mostLeft;
}
return leastRight;
}
else {
if (mostRight != null) {
return mostRight;
}
return leastLeft;
}
}
/**
Create ShapeInfo objects for all GMLShapes in a map.
@param map The map to debug.
@return A list of ShapeInfo objects.
*/
public static List<ShapeDebugFrame.ShapeInfo> getAllDebugShapes(GMLMap map) {
return createGMLShapeDebug(map.getAllShapes());
}
/**
Create ShapeInfo objects for all TemporaryObjects in a map.
@param map The map to debug.
@return A list of ShapeInfo objects.
*/
public static List<ShapeDebugFrame.ShapeInfo> getAllDebugShapes(TemporaryMap map) {
return createTemporaryObjectDebug(map.getAllObjects());
}
/**
Create ShapeInfo objects for a set of GMLShapes.
@param objects The objects to debug.
@return A list of ShapeInfo objects.
*/
public static List<ShapeDebugFrame.ShapeInfo> createGMLShapeDebug(GMLShape... objects) {
return createGMLShapeDebug(Arrays.asList(objects));
}
/**
Create ShapeInfo objects for a set of GMLShapes.
@param objects The objects to debug.
@return A list of ShapeInfo objects.
*/
public static List<ShapeDebugFrame.ShapeInfo> createGMLShapeDebug(Collection<? extends GMLShape> objects) {
List<ShapeDebugFrame.ShapeInfo> allShapes = new ArrayList<ShapeDebugFrame.ShapeInfo>();
for (GMLShape next : objects) {
Color c = Constants.TRANSPARENT_RED;
String name = "Unknown";
if (next instanceof GMLRoad) {
c = BACKGROUND_ROAD_COLOUR;
name = "Roads";
}
if (next instanceof GMLBuilding) {
c = BACKGROUND_BUILDING_COLOUR;
name = "Buildings";
}
if (next instanceof GMLSpace) {
c = BACKGROUND_SPACE_COLOUR;
name = "Spaces";
}
allShapes.add(new GMLShapeInfo(next, name, Color.BLACK, c));
}
return allShapes;
}
/**
Create ShapeInfo objects for a set of GMLObjects.
@param objects The objects to debug.
@return A list of ShapeInfo objects.
*/
public static List<ShapeDebugFrame.ShapeInfo> createGMLObjectDebug(GMLObject... objects) {
return createGMLObjectDebug(Arrays.asList(objects));
}
/**
Create ShapeInfo objects for a set of GMLObjects.
@param objects The objects to debug.
@return A list of ShapeInfo objects.
*/
public static List<ShapeDebugFrame.ShapeInfo> createGMLObjectDebug(Collection<? extends GMLObject> objects) {
List<ShapeDebugFrame.ShapeInfo> allShapes = new ArrayList<ShapeDebugFrame.ShapeInfo>();
for (GMLObject object : objects) {
if (object instanceof GMLNode) {
allShapes.add(new GMLNodeShapeInfo((GMLNode)object, "Nodes", Constants.BLACK, true));
}
if (object instanceof GMLEdge) {
allShapes.add(new GMLEdgeShapeInfo((GMLEdge)object, "Edges", Constants.BLACK, false));
}
/*
if (object instanceof GMLFace) {
GMLFace face = (GMLFace)object;
Color c = Constants.TRANSPARENT_RED;
String name = "Unknown";
allShapes.add(new GMLFaceShapeInfo(face, "Faces", Constants.BLACK, Constants.TRANSPARENT_AQUA, false));
}
*/
}
return allShapes;
}
/**
Create ShapeInfo objects for a set of TemporaryObjects.
@param objects The objects to debug.
@return A list of ShapeInfo objects.
*/
public static List<ShapeDebugFrame.ShapeInfo> createTemporaryObjectDebug(TemporaryObject... objects) {
return createTemporaryObjectDebug(Arrays.asList(objects));
}
/**
Create ShapeInfo objects for a set of TemporaryObjects.
@param objects The objects to debug.
@return A list of ShapeInfo objects.
*/
public static List<ShapeDebugFrame.ShapeInfo> createTemporaryObjectDebug(Collection<? extends TemporaryObject> objects) {
List<ShapeDebugFrame.ShapeInfo> allShapes = new ArrayList<ShapeDebugFrame.ShapeInfo>();
for (TemporaryObject next : objects) {
Color c = Constants.TRANSPARENT_RED;
String name = "Unknown";
if (next instanceof TemporaryRoad) {
c = BACKGROUND_ROAD_COLOUR;
name = "Roads";
}
if (next instanceof TemporaryBuilding) {
c = BACKGROUND_BUILDING_COLOUR;
name = "Buildings";
}
if (next instanceof TemporaryIntersection) {
c = BACKGROUND_INTERSECTION_COLOUR;
name = "Intersections";
}
allShapes.add(new TemporaryObjectInfo(next, name, Color.BLACK, c));
}
return allShapes;
}
/**
Is a number approximately equal to another number?
@param n The number to test.
@param expected The expected value.
@param threshold The threshold.
@return If n is within [expected - threshold, expected + threshold].
*/
public static boolean nearlyEqual(double n, double expected, double threshold) {
return (n >= expected - threshold
&& n <= expected + threshold);
}
/**
Find out if a set of GMLDirectedEdges is convex.
@param edges The set of edges to test.
@return True iff the face is convex.
*/
public static boolean isConvex(List<DirectedEdge> edges) {
Iterator<DirectedEdge> it = edges.iterator();
Line2D first = it.next().getLine();
Line2D a = first;
Line2D b = it.next().getLine();
boolean rightTurn = GeometryTools2D.isRightTurn(a, b);
while (it.hasNext()) {
a = b;
b = it.next().getLine();
if (rightTurn != GeometryTools2D.isRightTurn(a, b)) {
return false;
}
}
if (rightTurn != GeometryTools2D.isRightTurn(b, first)) {
return false;
}
return true;
}
/**
Sum the angles of all turns in a GMLFace.
@param face The face to check.
@return The sum of angles in the face.
*/
/*
public static double getAnglesSum(GMLFace face) {
double sum = 0;
Iterator<GMLDirectedEdge> it = face.getEdges().iterator();
GMLDirectedEdge first = it.next();
GMLDirectedEdge a = first;
while (it.hasNext()) {
GMLDirectedEdge b = it.next();
double d = getAngle(a, b);
if (!Double.isNaN(d)) {
sum += d;
}
a = b;
}
double d = getAngle(a, first);
if (!Double.isNaN(d)) {
sum += d;
}
return sum;
}
*/
/**
Sum the angles of all turns in an OSMBuilding.
@param building The building to check.
@param map The OSMMap the building is part of.
@return The sum of angles in the building.
*/
public static double getAnglesSum(OSMBuilding building, OSMMap map) {
double sum = 0;
Iterator<Long> it = building.getNodeIDs().iterator();
long first = it.next();
long second = it.next();
long a = first;
long b = second;
while (it.hasNext()) {
long c = it.next();
double d = getAngle(a, b, c, map);
// Logger.debug("Angle from " + a + ":" + b + ":" + c + " = " + d);
if (!Double.isNaN(d)) {
sum += d;
}
a = b;
b = c;
}
double d = getAngle(a, first, second, map);
// Logger.debug("Angle from " + a + ":" + first + ":" + second + " = " + d);
if (!Double.isNaN(d)) {
sum += d;
}
return sum;
}
/**
Find out if a GMLFace is defined clockwise or not.
@param face The GMLFace to check.
@return True if the face is defined clockwise, false if anti-clockwise.
*/
/*
public static boolean isClockwise(GMLFace face) {
return nearlyEqual(getAnglesSum(face), CLOCKWISE_SUM, THRESHOLD);
}
*/
/**
Find out if an OSMBuilding is defined clockwise or not.
@param building The OSMBuilding to check.
@param map The OSM map.
@return True if the building is defined clockwise, false if anti-clockwise.
*/
public static boolean isClockwise(OSMBuilding building, OSMMap map) {
return nearlyEqual(getAnglesSum(building, map), CLOCKWISE_SUM, THRESHOLD);
}
/*
private static double getAngle(GMLDirectedEdge a, GMLDirectedEdge b) {
Vector2D v1 = new Vector2D(a.getEndNode().getX() - a.getStartNode().getX(), a.getEndNode().getY() - a.getStartNode().getY());
Vector2D v2 = new Vector2D(b.getEndNode().getX() - b.getStartNode().getX(), b.getEndNode().getY() - b.getStartNode().getY());
double d = GeometryTools2D.getAngleBetweenVectors(v1, v2);
if (GeometryTools2D.isRightTurn(v1, v2)) {
return -d;
}
return d;
}
*/
private static double getAngle(long first, long second, long third, OSMMap map) {
OSMNode n1 = map.getNode(first);
OSMNode n2 = map.getNode(second);
OSMNode n3 = map.getNode(third);
Vector2D v1 = new Vector2D(n2.getLongitude() - n1.getLongitude(), n2.getLatitude() - n1.getLatitude());
Vector2D v2 = new Vector2D(n3.getLongitude() - n2.getLongitude(), n3.getLatitude() - n2.getLatitude());
double d = GeometryTools2D.getAngleBetweenVectors(v1, v2);
if (GeometryTools2D.isRightTurn(v1, v2)) {
return -d;
}
return d;
}
}
package maps.convert.osm2gml;
import maps.osm.OSMMap;
import maps.gml.GMLMap;
import maps.convert.ConvertStep;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JLabel;
import javax.swing.JComponent;
import javax.swing.JProgressBar;
import javax.swing.Box;
import java.awt.BorderLayout;
import java.awt.GridBagLayout;
import java.awt.GridBagConstraints;
import java.awt.Dimension;
import java.awt.Insets;
import java.util.List;
import java.util.ArrayList;
/**
This class converts OSMMaps to GMLMaps.
*/
public class Convertor {
private static final int PROGRESS_WIDTH = 200;
private static final int PROGRESS_HEIGHT = 10;
private static final int STATUS_WIDTH = 500;
private static final int STATUS_HEIGHT = 10;
private static final int MARGIN = 4;
/**
Convert an OSMMap to a GMLMap.
@param map The OSMMap to convert.
@return A new GMLMap.
*/
public GMLMap convert(OSMMap map) {
GMLMap gmlMap = new GMLMap();
JFrame frame = new JFrame("OSM to GML converter");
JPanel main = new JPanel(new BorderLayout());
JComponent top = Box.createVerticalBox();
top.add(new JLabel("Converting OSM map with " + map.getRoads().size() + " roads and " + map.getBuildings().size() + " buildings"));
top.add(new JLabel("Map size: " + (map.getMaxLongitude() - map.getMinLongitude()) + " x " + (map.getMaxLatitude() - map.getMinLatitude())));
GridBagLayout layout = new GridBagLayout();
GridBagConstraints c = new GridBagConstraints();
c.gridx = 0;
c.gridy = 0;
c.gridwidth = 1;
c.gridheight = 1;
c.weightx = 1;
c.weighty = 1;
c.fill = GridBagConstraints.BOTH;
c.anchor = GridBagConstraints.CENTER;
c.insets = new Insets(MARGIN, MARGIN, MARGIN, MARGIN);
JPanel progress = new JPanel(layout);
// Random random = new Random();
TemporaryMap temp = new TemporaryMap(map);
List<ConvertStep> steps = new ArrayList<ConvertStep>();
addStep(new CleanOSMStep(temp), steps, progress, layout, c);
addStep(new ScanOSMStep(temp), steps, progress, layout, c);
addStep(new MakeTempObjectsStep(temp), steps, progress, layout, c);
addStep(new SplitIntersectingEdgesStep(temp), steps, progress, layout, c);
addStep(new SplitShapesStep(temp), steps, progress, layout, c);
addStep(new RemoveShapesStep(temp), steps, progress, layout, c);
addStep(new MergeShapesStep(temp), steps, progress, layout, c);
addStep(new ComputePassableEdgesStep(temp), steps, progress, layout, c);
/*
addStep(new CreateBuildingsStep(temp, ConvertTools.sizeOf1Metre(osmMap), random), steps, progress, layout, c);
addStep(new CreateEntrancesStep(temp), steps, progress, layout, c);
addStep(new PruneStep(temp), steps, progress, layout, c);
*/
addStep(new MakeObjectsStep(temp, gmlMap), steps, progress, layout, c);
main.add(top);
main.add(progress);
frame.setContentPane(main);
frame.pack();
frame.setVisible(true);
for (ConvertStep next : steps) {
next.doStep();
}
return gmlMap;
}
private void addStep(ConvertStep step, List<ConvertStep> steps, JComponent panel, GridBagLayout layout, GridBagConstraints c) {
JLabel title = new JLabel(step.getDescription());
JProgressBar progress = step.getProgressBar();
JComponent status = step.getStatusComponent();
c.gridx = 0;
c.weightx = 1;
layout.setConstraints(title, c);
panel.add(title);
c.gridx = 1;
c.weightx = 0;
layout.setConstraints(progress, c);
panel.add(progress);
c.gridx = 2;
c.weightx = 1;
layout.setConstraints(status, c);
panel.add(status);
++c.gridy;
progress.setPreferredSize(new Dimension(PROGRESS_WIDTH, PROGRESS_HEIGHT));
status.setPreferredSize(new Dimension(STATUS_WIDTH, STATUS_HEIGHT));
steps.add(step);
}
}
package maps.convert.osm2gml;
import maps.gml.GMLMap;
import maps.convert.ConvertStep;
import java.util.Random;
/**
This class populates a GMLMap with random buildings.
*/
public class CreateBuildingsStep extends ConvertStep {
private static final double SIMILAR_LENGTH_THRESHOLD = 0.1;
private static final double NEARLY_PARALLEL_THRESHOLD = 0.0001;
// private GMLMap gmlMap;
// private double sizeOf1m;
// private Random random;
/**
Construct a CreateBuildingsStep.
@param gmlMap The GMLMap to use.
@param sizeOf1m The size of 1m in GMLMap units.
@param random The random number generator to use.
*/
public CreateBuildingsStep(GMLMap gmlMap, double sizeOf1m, Random random) {
// this.gmlMap = gmlMap;
// this.sizeOf1m = sizeOf1m;
// this.random = random;
}
@Override
public String getDescription() {
return "Creating buildings";
}
@Override
protected void step() {
/*
debug.setBackground(ConvertTools.getAllGMLShapes(gmlMap));
// Find open spaces with no buildings
setProgressLimit(gmlMap.getEdges().size());
Set<GMLEdge> seenLeft = new HashSet<GMLEdge>();
Set<GMLEdge> seenRight = new HashSet<GMLEdge>();
for (GMLEdge edge : gmlMap.getEdges()) {
if (seenLeft.contains(edge) && seenRight.contains(edge)) {
bumpProgress();
continue;
}
// Try walking from this edge looking for space on the left
if (!seenLeft.contains(edge)) {
List<GMLDirectedEdge> edges = walk(edge, true);
if (edges != null) {
processOpenSpace(edges);
for (GMLDirectedEdge dEdge : edges) {
seenLeft.add(dEdge.getEdge());
}
}
}
if (!seenRight.contains(edge)) {
List<GMLDirectedEdge> edges = walk(edge, false);
if (edges != null) {
processOpenSpace(reverseEdgeList(edges));
for (GMLDirectedEdge dEdge : edges) {
seenRight.add(dEdge.getEdge());
}
}
}
bumpProgress();
}
*/
}
/*
private List<GMLDirectedEdge> walk(GMLEdge edge, boolean left) {
if (hasConnectedFace(edge, left)) {
return null;
}
GMLNode start = edge.getStart();
GMLNode current = edge.getEnd();
GMLDirectedEdge dEdge = new GMLDirectedEdge(edge, start);
List<GMLDirectedEdge> result = new ArrayList<GMLDirectedEdge>();
result.add(dEdge);
GMLEdge last = edge;
while (current != start) {
GMLEdge next = ConvertTools.findBestTurn(dEdge, gmlMap.getAttachedEdges(current), left);
boolean forward = current == next.getStart();
boolean lookOnLeft = (left && forward) || (!left && !forward);
// debug.show("Walking outside " + (left ? "left" : "right"),
// new GMLEdgeShapeInfo(last, "From edge", Constants.RED, true),
// new GMLEdgeShapeInfo(next, "To edge", Constants.BLUE, true));
// See if any faces are connected on the side we care about
if (hasConnectedFace(next, lookOnLeft)) {
// There's a connected face so this walk isn't going to result in an open space.
return null;
}
dEdge = new GMLDirectedEdge(next, current);
current = dEdge.getEndNode();
last = next;
result.add(dEdge);
}
return result;
}
private boolean hasConnectedFace(GMLEdge edge, boolean left) {
Set<GMLFace> faces = gmlMap.getAttachedFaces(edge);
// List<ShapeDebugFrame.ShapeInfo> shapes = new ArrayList<ShapeDebugFrame.ShapeInfo>();
// shapes.add(new GMLEdgeShapeInfo(edge, "Test edge", Constants.BLUE, true));
// shapes.add(new GMLNodeShapeInfo(edge.getStart(), "Start node", Constants.RED, true));
// shapes.add(new GMLNodeShapeInfo(edge.getEnd(), "End node", Constants.NAVY, true));
// for (GMLFace face : faces) {
// shapes.add(new GMLFaceShapeInfo(face, "Attached face", Constants.BLACK, Constants.TRANSPARENT_ORANGE, true));
// }
// debug.show("Checking for connected faces", shapes);
for (GMLFace face : faces) {
if (FaceType.BUILDING.equals(face.getFaceType())) {
// Always exclude edges on buildings even if they're on the opposite side
return true;
}
if (left) {
if (face.isConnectedLeft(edge)) {
return true;
}
}
else {
if (face.isConnectedRight(edge)) {
return true;
}
}
}
return false;
}
private List<GMLDirectedEdge> reverseEdgeList(List<GMLDirectedEdge> edges) {
List<GMLDirectedEdge> result = new ArrayList<GMLDirectedEdge>(edges.size());
for (GMLDirectedEdge edge : edges) {
result.add(new GMLDirectedEdge(edge.getEdge(), !edge.isForward()));
}
Collections.reverse(result);
return result;
}
private void processOpenSpace(List<GMLDirectedEdge> edges) {
GMLFace face = gmlMap.createFace(edges, FaceType.BUILDING);
gmlMap.removeFace(face);
if (!ConvertTools.isClockwise(face)) {
List<GMLDirectedEdgeShapeInfo> e = new ArrayList<GMLDirectedEdgeShapeInfo>(edges.size());
for (GMLDirectedEdge next : edges) {
e.add(new GMLDirectedEdgeShapeInfo(next, "Open space edge", Constants.OLIVE, true, true));
}
// Split into "nice" shapes
// if (isNearlyRectangular(face)) {
debug.show("Open space", e);
RowHousingBuildingSpaceFiller filler = new RowHousingBuildingSpaceFiller(sizeOf1m, random, debug);
filler.createBuildings(face, gmlMap);
// }
}
}
private boolean isNearlyRectangular(GMLFace face) {
if (face.getEdges().size() != 4) {
return false;
}
// Check if the opposing faces are approximately parallel
Iterator<GMLDirectedEdge> it = face.getEdges().iterator();
GMLDirectedEdge e1 = it.next();
GMLDirectedEdge e2 = it.next();
GMLDirectedEdge e3 = it.next();
GMLDirectedEdge e4 = it.next();
if (nearlyParallel(e1, e3) && nearlyParallel(e2, e4) && similarLength(e1, e3) && similarLength(e2, e4)) {
return true;
}
return false;
}
private boolean nearlyParallel(GMLDirectedEdge e1, GMLDirectedEdge e2) {
Line2D l1 = ConvertTools.gmlDirectedEdgeToLine(e1);
Line2D l2 = ConvertTools.gmlDirectedEdgeToLine(e2);
double d = (l1.getDirection().getX() * l2.getDirection().getY()) - (l1.getDirection().getY() * l2.getDirection().getX());
return ConvertTools.nearlyEqual(d, 0, NEARLY_PARALLEL_THRESHOLD);
}
private boolean similarLength(GMLDirectedEdge e1, GMLDirectedEdge e2) {
double l1 = ConvertTools.gmlDirectedEdgeToLine(e1).getDirection().getLength();
double l2 = ConvertTools.gmlDirectedEdgeToLine(e1).getDirection().getLength();
return ConvertTools.nearlyEqual(l1 - l2, 0, SIMILAR_LENGTH_THRESHOLD);
}
*/
}
package maps.convert.osm2gml;
import maps.gml.GMLMap;
import maps.convert.ConvertStep;
/**
This class computes the entrances for buildings.
*/
public class CreateEntrancesStep extends ConvertStep {
// private GMLMap gmlMap;
/**
Construct a CreateEntrancesStep.
@param gmlMap The GMLMap to use.
*/
public CreateEntrancesStep(GMLMap gmlMap) {
super();
// this.gmlMap = gmlMap;
}
@Override
public String getDescription() {
return "Creating building entrances";
}
@Override
protected void step() {
/*
setProgressLimit(gmlMap.getFaces().size());
int sharedCount = 0;
int corridorCount = 0;
for (GMLFace face : gmlMap.getFaces()) {
if (FaceType.BUILDING.equals(face.getFaceType())) {
// Look to see if we have any edges shared with a road
boolean found = false;
for (GMLDirectedEdge directedEdge : face.getEdges()) {
GMLEdge edge = directedEdge.getEdge();
if (isSharedWithRoad(edge)) {
// Make the edge passable
// TO DO: Make part of the edge passable
// TO DO: Make more edges passable if this edge is too short
edge.setPassable(true);
found = true;
++sharedCount;
break;
}
}
// If we couldn't find a shared edge then we need to create a corridor that connects an edge to a road.
if (!found) {
makeCorrider(face);
++corridorCount;
}
}
bumpProgress();
}
setStatus("Made " + sharedCount + " shared edges passable and created " + corridorCount + " corridors");
*/
}
/*
private boolean isSharedWithRoad(GMLEdge edge) {
for (GMLFace face : gmlMap.getAttachedFaces(edge)) {
if (FaceType.ROAD.equals(face.getFaceType())) {
return true;
}
}
return false;
}
private void makeCorrider(GMLFace face) {
// Find an edge that is close to a road or intersection
GMLEdge bestBuildingEdge = null;
GMLEdge bestRoadEdge = null;
for (GMLDirectedEdge next : face.getEdges()) {
GMLEdge buildingEdge = next.getEdge();
// Look for the nearest road or intersection edge
}
}
*/
}
package maps.convert.osm2gml;
import rescuecore2.misc.geometry.Point2D;
import rescuecore2.misc.geometry.Line2D;
/**
A DirectedEdge is an edge with an orientation.
*/
public class DirectedEdge {
private Edge edge;
private boolean forward;
private Line2D line;
/**
Construct a directed edge.
@param edge The underlying edge.
@param forward True if this directed edge is aligned with the underlying edge direction, false otherwise.
*/
public DirectedEdge(Edge edge, boolean forward) {
this.edge = edge;
this.forward = forward;
this.line = edge.getLine();
if (!forward) {
line = new Line2D(line.getEndPoint(), line.getOrigin());
}
}
/**
Construct a directed edge.
@param edge The underlying edge.
@param start The start node.
*/
public DirectedEdge(Edge edge, Node start) {
this.edge = edge;
this.forward = start.equals(edge.getStart());
this.line = edge.getLine();
if (!forward) {
line = new Line2D(line.getEndPoint(), line.getOrigin());
}
}
/**
Get the underlying edge.
@return The underlying edge.
*/
public Edge getEdge() {
return edge;
}
/**
Get the line represented by this edge.
@return The line.
*/
public Line2D getLine() {
return line;
}
/**
Is this directed edge in the direction of the underlying edge?
@return True if this directed edge is aligned with the underlying edge direction, false otherwise.
*/
public boolean isForward() {
return forward;
}
/**
Get the node at the start of the underlying edge.
@return The start node.
*/
public Node getStartNode() {
return forward ? edge.getStart() : edge.getEnd();
}
/**
Get the node at the end of the underlying edge.
@return The end node.
*/
public Node getEndNode() {
return forward ? edge.getEnd() : edge.getStart();
}
/**
Get the coordinates of the start of this edge.
@return The coordinates of the start of this edge.
*/
public Point2D getStartCoordinates() {
if (forward) {
return edge.getStart().getCoordinates();
}
else {
return edge.getEnd().getCoordinates();
}
}
/**
Get the coordinates of the end of this edge.
@return The coordinates of the end of this edge.
*/
public Point2D getEndCoordinates() {
if (forward) {
return edge.getEnd().getCoordinates();
}
else {
return edge.getStart().getCoordinates();
}
}
@Override
public String toString() {
return "DirectedEdge" + (forward ? "" : " backwards") + " along " + edge;
}
@Override
public int hashCode() {
return edge.hashCode() ^ (forward ? 1 : 0);
}
@Override
public boolean equals(Object o) {
if (o instanceof DirectedEdge) {
DirectedEdge e = (DirectedEdge)o;
return this.forward == e.forward && this.edge.equals(e.edge);
}
return false;
}
}
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment