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