package maps.gml.formats; import java.awt.Color; import java.io.File; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.UnsupportedEncodingException; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; import java.util.StringTokenizer; import javolution.util.FastMap; import maps.gml.GMLBuilding; import maps.gml.GMLCoordinates; import maps.gml.GMLDirectedEdge; import maps.gml.GMLMap; import maps.gml.GMLNode; import maps.gml.GMLRoad; import maps.gml.GMLShape; import maps.util.Polygon; import maps.util.PolygonSplitter; import maps.gml.GMLMapFormat; import org.dom4j.Document; import org.dom4j.DocumentHelper; import org.dom4j.Element; import org.dom4j.Namespace; import org.dom4j.QName; import org.dom4j.XPath; import org.dom4j.io.OutputFormat; import org.dom4j.io.XMLWriter; import rescuecore2.log.Logger; import rescuecore2.misc.Pair; import rescuecore2.misc.geometry.GeometryTools2D; import rescuecore2.misc.geometry.Line2D; import rescuecore2.misc.geometry.Point2D; import com.vividsolutions.jts.geom.Coordinate; import com.vividsolutions.jts.geom.Geometry; import com.vividsolutions.jts.geom.GeometryFactory; import com.vividsolutions.jts.io.ParseException; import com.vividsolutions.jts.io.WKTReader; // TO DO: Handle inner boundaries /** * A MapFormat that can handle maps from the UK Ordnance Survey. */ public final class OrdnanceSurveyFormat extends GMLMapFormat { /** Singleton instance. */ public static final OrdnanceSurveyFormat INSTANCE = new OrdnanceSurveyFormat(); private static final GeometryFactory factory = new GeometryFactory(); private static final String FEATURE_CODE_BUILDING = "10021"; private static final String FEATURE_CODE_ROAD = "10172"; private static final String FEATURE_CODE_FOOTPATH = "10183"; private static final String FEATURE_CODE_OPEN_SPACE = "10053"; private static final String FEATURE_CODE_GENERAL_SPACE = "10056"; private static final String OSGB_NAMESPACE_URI = "http://www.ordnancesurvey.co.uk/xml/namespaces/osgb"; private static final Namespace OSGB_NAMESPACE = DocumentHelper .createNamespace("osgb", OSGB_NAMESPACE_URI); private static final QName FEATURE_COLLECTION_QNAME = DocumentHelper .createQName("FeatureCollection", OSGB_NAMESPACE); private static final QName TOPOGRAPHIC_AREA_QNAME = DocumentHelper .createQName("TopographicArea", OSGB_NAMESPACE); private static final XPath BUILDING_XPATH = DocumentHelper .createXPath("//osgb:topographicMember/osgb:TopographicArea[osgb:featureCode[text()='" + FEATURE_CODE_BUILDING + "']]"); private static final XPath ROAD_XPATH = DocumentHelper .createXPath("//osgb:topographicMember/osgb:TopographicArea[osgb:featureCode[text()='" + FEATURE_CODE_ROAD + "']]"); private static final XPath SPACE_XPATH = DocumentHelper .createXPath("//osgb:topographicMember/osgb:TopographicArea[osgb:featureCode[text()='" + FEATURE_CODE_OPEN_SPACE + "' or text()='" + FEATURE_CODE_GENERAL_SPACE + "']]"); private static final XPath SHAPE_XPATH = DocumentHelper .createXPath("osgb:polygon/gml:Polygon/gml:outerBoundaryIs/gml:LinearRing/gml:coordinates"); private static final XPath INNER_RING_XPATH = DocumentHelper .createXPath("osgb:polygon/gml:Polygon/gml:innerBoundaryIs/gml:LinearRing/gml:coordinates"); // Map from uri prefix to uri for XPath expressions private static final Map<String, String> URIS = new HashMap<String, String>(); private static final Color NEW_BUILDING_COLOUR = new Color(255, 0, 0, 128); private static final Color NEW_ROAD_COLOUR = new Color(255, 0, 0, 128); private static final Color BUILDING_COLOUR = new Color(0, 128, 0, 128); private static final Color ROAD_COLOUR = new Color(128, 128, 128, 128); private static final int FID_PREFIX_LENGTH = 4; // private ShapeDebugFrame debug; // private List<GMLShapeInfo> background; private int maxRoadID; private double entrancewidth = 1.0; static { URIS.put("gml", Common.GML_NAMESPACE_URI); URIS.put("xlink", Common.XLINK_NAMESPACE_URI); URIS.put("osgb", OSGB_NAMESPACE_URI); BUILDING_XPATH.setNamespaceURIs(URIS); ROAD_XPATH.setNamespaceURIs(URIS); SPACE_XPATH.setNamespaceURIs(URIS); SHAPE_XPATH.setNamespaceURIs(URIS); INNER_RING_XPATH.setNamespaceURIs(URIS); } private OrdnanceSurveyFormat() { } @Override public String toString() { return "Ordnance survey"; } @Override public Map<String, String> getNamespaces() { return Collections.unmodifiableMap(URIS); } @Override public boolean isCorrectRootElement(String uri, String localName) { return OSGB_NAMESPACE_URI.equals(uri) && "FeatureCollection".equals(localName); } @Override public GMLMap read(Document doc) { GMLMap result = new GMLMap(); readBuildings(doc, result); readRoads(doc, result); readSpaces(doc, result); /* * make path between buildings and roads */ makeEntrances(result); /* * cut up roads into roughly convex sections */ cutRoads(result); /* * make road network connected after roads have been parsed */ // connectRoadNetwork(result); connectNetwork(result); /* * Output to a map file */ Document mydoc = RobocupFormat.INSTANCE.write(result); XMLWriter writer; try { String curDir = System.getProperty("user.dir"); String dirStr = curDir + "/../maps/gml/output/"; File outputdir = new File(dirStr); if (!outputdir.exists()) { outputdir.mkdir(); } File outfile = new File(dirStr + "map.gml"); if (!outfile.exists()) { outfile.createNewFile(); } writer = new XMLWriter(new FileOutputStream(outfile), OutputFormat .createPrettyPrint()); writer.write(mydoc); writer.flush(); writer.close(); } catch (UnsupportedEncodingException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (FileNotFoundException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } return result; } private void cutRoads(GMLMap result) { // TODO Auto-generated method stub /* * create new road segments */ Set<GMLRoad> roads = result.getRoads(); List<List<GMLDirectedEdge>> newRoads = new ArrayList<List<GMLDirectedEdge>>(); for (GMLRoad road : roads) { double[] xCoords = new double[road.getEdges().size()]; double[] yCoords = new double[road.getEdges().size()]; List<GMLDirectedEdge> edges = road.getEdges(); Map<Pair<Double, Double>, GMLNode> map = new FastMap<Pair<Double, Double>, GMLNode>(); int i = 0; for (GMLDirectedEdge edge : edges) { xCoords[i] = edge.getStartCoordinates().getX(); yCoords[i] = edge.getStartCoordinates().getY(); map.put(new Pair<Double, Double>(xCoords[i], yCoords[i]), edge .getStartNode()); i++; } Polygon polygon = new Polygon(xCoords, yCoords); Polygon[] splitPolygon = PolygonSplitter.splitPolygon(polygon, 25, 50); for (i = 0; i < splitPolygon.length; i++) { List<GMLDirectedEdge> e = new ArrayList<GMLDirectedEdge>(); for (int j = 0; j < splitPolygon[i].x.length; j++) { double x = splitPolygon[i].x[j]; double y = splitPolygon[i].y[j]; double nextX = splitPolygon[i].x[(j + 1) % splitPolygon[i].x.length]; double nextY = splitPolygon[i].y[(j + 1) % splitPolygon[i].x.length]; GMLDirectedEdge edge = new GMLDirectedEdge(result .createEdge( map.get(new Pair<Double, Double>(x, y)), map.get(new Pair<Double, Double>(nextX, nextY))), true); e.add(edge); } newRoads.add(e); } } // remove old roads result.removeAllRoads(); // add new roads for (List<GMLDirectedEdge> road : newRoads) { result.createRoad(road); maxRoadID++; } } private void makeEntrances(GMLMap result) { /* * draw an entrance to the nearest road; make it 2m wide? */ Set<GMLBuilding> buildings = result.getBuildings(); Iterator<GMLBuilding> bit = buildings.iterator(); int i = 0; while (bit.hasNext()) {// && i<4) { GMLBuilding building = (GMLBuilding) bit.next(); /* * for each building find the nearest road centre or point on edge? * * this is gonna be slow......... */ GMLRoad road = closestRoad(result, building, maxRoadID); GMLDirectedEdge[] edges = closestEdges(building, road, result); if (!shareEdge(edges)) { // System.out.println("building an edge"); // System.out.println(edges[0].getStartCoordinates() + // " "+edges[0].getEndCoordinates() + // " "+edges[1].getStartCoordinates() + // " "+edges[1].getEndCoordinates() + " "); // System.out.println(building.getCoordinates()); // System.out.println(edges[0]); double midx = (edges[0].getEndCoordinates().getX() + edges[0] .getStartCoordinates().getX()) / 2.0; double midy = (edges[0].getEndCoordinates().getY() + edges[0] .getStartCoordinates().getY()) / 2.0; // System.out.println(midx + ", " + midy); Point2D bPoint = new Point2D(midx, midy); Line2D bline = new Line2D(makePoint(edges[0] .getStartCoordinates()), makePoint(edges[0] .getEndCoordinates())); Line2D rline = new Line2D(makePoint(edges[1] .getStartCoordinates()), makePoint(edges[1] .getEndCoordinates())); // System.out.println(bline.toString()); Coordinate[] connection = new Coordinate[5]; Point2D rPoint = GeometryTools2D.getClosestPointOnSegment( rline, bPoint); double lengthB = GeometryTools2D.getDistance(makePoint(edges[0] .getStartCoordinates()), makePoint(edges[0] .getEndCoordinates())); // System.out.println(lengthB); // if(entrancewidth/lengthB<0.5){ // will fit on this edge of the building connection[0] = makeCoordinate(bline .getPoint(0.5 - (entrancewidth / lengthB))); connection[1] = makeCoordinate(bline .getPoint(0.5 + (entrancewidth / lengthB))); /* * } else { //wont so make it the limits of the edge * connection[0] = makeCoordinate(bline .getPoint(0.0)); * connection[1] = makeCoordinate(bline .getPoint(1.0)); } */ double distanceOnRoad = GeometryTools2D.getDistance( makePoint(edges[1].getStartCoordinates()), rPoint); double lengthRoad = GeometryTools2D.getDistance( makePoint(edges[1].getStartCoordinates()), makePoint(edges[1].getEndCoordinates())); if (distanceOnRoad / lengthRoad >= entrancewidth / lengthRoad) { connection[2] = makeCoordinate(rline .getPoint((distanceOnRoad / lengthRoad) - (entrancewidth / lengthRoad))); connection[3] = makeCoordinate(rline .getPoint((distanceOnRoad / lengthRoad) + (entrancewidth / lengthRoad))); } else { // wont fit here so move rPoint by 0.3 towards end connection[2] = makeCoordinate(rline .getPoint(distanceOnRoad / lengthRoad)); connection[3] = makeCoordinate(rline .getPoint((distanceOnRoad / lengthRoad) + (entrancewidth * 2 / lengthRoad))); } // check the path doesnt twist Line2D line1 = new Line2D(makePoint(connection[0]), makePoint(connection[3])); Line2D line2 = new Line2D(makePoint(connection[1]), makePoint(connection[2])); double int1 = line1.getIntersection(line2); double int2 = line2.getIntersection(line1); if (int1 < 1.0 && int1 > 0.0 && int2 < 1.0 && int2 > 0.0) { // System.out.println("twisty" + // line1.getIntersection(line2)); connection[4] = connection[2]; connection[2] = connection[3]; connection[3] = connection[4]; } connection[4] = connection[0]; Coordinate[] c = new Coordinate[4]; c[0] = connection[0];// new // Coordinate(bline.getOrigin().getX(),bline.getOrigin().getY());//connection[0]; c[1] = connection[1];// new // Coordinate(bline.getEndPoint().getX(),bline.getEndPoint().getY());//connection[1]; c[2] = new Coordinate(rPoint.getX(), rPoint.getY()); c[3] = c[0]; List<GMLDirectedEdge> e = readEdges(connection, result); if (noClash(connection, road, building, result)) { // System.out.println("no clash"); modifyRoad(road, connection[2], connection[3], edges[1], result); modifyBuilding(building, connection[0], connection[1], edges[0], result); GMLRoad newRoad = result.createRoad(e); // background.add(new GMLShapeInfo(newRoad, "Roads", // Color.BLACK, ROAD_COLOUR)); } else { bit.remove(); } i++; } } /* * while(bit.hasNext()){ GMLBuilding building = (GMLBuilding) * bit.next(); result.removeBuilding(building); } */ } private void modifyBuilding(GMLBuilding building, Coordinate c1, Coordinate c2, GMLDirectedEdge edge, GMLMap map) { /* * add these two points into the road edge so it can be connected * appropiatly */ List<GMLDirectedEdge> edges = building.getEdges(); Coordinate[] c = new Coordinate[edges.size() + 3]; if (GeometryTools2D.getDistance(makePoint(edge.getStartCoordinates()), makePoint(c1)) < GeometryTools2D.getDistance(makePoint(edge .getStartCoordinates()), makePoint(c2))) { // start c1 c2 end int i = 0; Iterator<GMLDirectedEdge> eit = edges.iterator(); while (eit.hasNext()) { GMLDirectedEdge e = (GMLDirectedEdge) eit.next(); if (e.getStartCoordinates() != edge.getStartCoordinates()) { c[i] = new Coordinate(e.getStartCoordinates().getX(), e .getStartCoordinates().getY()); c[i + 1] = new Coordinate(e.getEndCoordinates().getX(), e .getEndCoordinates().getY()); i++; } else { c[i] = new Coordinate(e.getStartCoordinates().getX(), e .getStartCoordinates().getY()); c[i + 1] = c1; c[i + 2] = c2; c[i + 3] = new Coordinate(e.getEndCoordinates().getX(), e .getEndCoordinates().getY()); i++; i++; i++; } } } else { // start c2 c1 end int i = 0; Iterator<GMLDirectedEdge> eit = edges.iterator(); while (eit.hasNext()) { GMLDirectedEdge e = (GMLDirectedEdge) eit.next(); if (e.getStartCoordinates() != edge.getStartCoordinates()) { c[i] = new Coordinate(e.getStartCoordinates().getX(), e .getStartCoordinates().getY()); c[i + 1] = new Coordinate(e.getEndCoordinates().getX(), e .getEndCoordinates().getY()); i++; } else { c[i] = new Coordinate(e.getStartCoordinates().getX(), e .getStartCoordinates().getY()); c[i + 1] = c2; c[i + 2] = c1; c[i + 3] = new Coordinate(e.getEndCoordinates().getX(), e .getEndCoordinates().getY()); i++; i++; i++; } } } map.removeBuilding(building); List<GMLDirectedEdge> e = readEdges(c, map); GMLBuilding newBuilding = new GMLBuilding(building.getID(), e); map.addBuilding(newBuilding); // GMLBuilding newBuilding = map.createBuilding(e); // background.add(new GMLShapeInfo(newBuilding, "Roads", Color.BLACK, // ROAD_COLOUR)); } private void modifyRoad(GMLRoad road, Coordinate c1, Coordinate c2, GMLDirectedEdge edge, GMLMap map) { /* * add these two points into the road edge so it can be connected * appropiatly */ List<GMLDirectedEdge> edges = road.getEdges(); Coordinate[] c = new Coordinate[edges.size() + 3]; if (GeometryTools2D.getDistance(makePoint(edge.getStartCoordinates()), makePoint(c1)) < GeometryTools2D.getDistance(makePoint(edge .getStartCoordinates()), makePoint(c2))) { // start c1 c2 end int i = 0; Iterator<GMLDirectedEdge> eit = edges.iterator(); while (eit.hasNext()) { GMLDirectedEdge e = (GMLDirectedEdge) eit.next(); if (e.getStartCoordinates() != edge.getStartCoordinates()) { c[i] = new Coordinate(e.getStartCoordinates().getX(), e .getStartCoordinates().getY()); c[i + 1] = new Coordinate(e.getEndCoordinates().getX(), e .getEndCoordinates().getY()); i++; } else { c[i] = new Coordinate(e.getStartCoordinates().getX(), e .getStartCoordinates().getY()); c[i + 1] = c1; c[i + 2] = c2; c[i + 3] = new Coordinate(e.getEndCoordinates().getX(), e .getEndCoordinates().getY()); i++; i++; i++; } } } else { // start c2 c1 end int i = 0; Iterator<GMLDirectedEdge> eit = edges.iterator(); while (eit.hasNext()) { GMLDirectedEdge e = (GMLDirectedEdge) eit.next(); if (e.getStartCoordinates() != edge.getStartCoordinates()) { c[i] = new Coordinate(e.getStartCoordinates().getX(), e .getStartCoordinates().getY()); c[i + 1] = new Coordinate(e.getEndCoordinates().getX(), e .getEndCoordinates().getY()); i++; } else { c[i] = new Coordinate(e.getStartCoordinates().getX(), e .getStartCoordinates().getY()); c[i + 1] = c2; c[i + 2] = c1; c[i + 3] = new Coordinate(e.getEndCoordinates().getX(), e .getEndCoordinates().getY()); i++; i++; i++; } } } map.removeRoad(road); List<GMLDirectedEdge> e = readEdges(c, map); // GMLRoad newRoad = map.createRoad(e); GMLRoad newRoad = new GMLRoad(road.getID(), e); map.addRoad(newRoad); // background.add(new GMLShapeInfo(newRoad, "Roads", Color.BLACK, // ROAD_COLOUR)); } private boolean noClash(Coordinate[] road, GMLRoad connectedRoad, GMLBuilding building, GMLMap result) { Geometry r = createGeometry(road); Iterator<GMLShape> it = result.getAllShapes().iterator(); while (it.hasNext()) { GMLShape shape = (GMLShape) it.next(); if (shape.getID() != building.getID() && shape.getID() != connectedRoad.getID()) { if (shapesIntersect(shape, road)) { return false; } } } return true; } private boolean shareEdge(GMLDirectedEdge[] edges) { double edge1startx = edges[0].getStartCoordinates().getX(); double edge1starty = edges[0].getStartCoordinates().getY(); double edge1endx = edges[0].getEndCoordinates().getX(); double edge1endy = edges[0].getEndCoordinates().getY(); double edge2startx = edges[1].getStartCoordinates().getX(); double edge2starty = edges[1].getStartCoordinates().getY(); double edge2endx = edges[1].getEndCoordinates().getX(); double edge2endy = edges[1].getEndCoordinates().getY(); if (edge1startx == edge2startx && edge1starty == edge2starty && edge1endx == edge2endx && edge1endy == edge2endy) { return true; } else if (edge1endx == edge2startx && edge1endy == edge2starty && edge1startx == edge2endx && edge1starty == edge2endy) { return true; } else { return false; } } private Coordinate makeCoordinate(Point2D point) { // TODO Auto-generated method stub return new Coordinate(point.getX(), point.getY()); } private Point2D makePoint(Coordinate point) { // TODO Auto-generated method stub return new Point2D(point.x, point.y); } private Point2D makePoint(GMLCoordinates gmlCoordinates) { return new Point2D(gmlCoordinates.getX(), gmlCoordinates.getY()); } /* * finds the closest edges between a building and road returns the 2 element * array with building edge first */ private GMLDirectedEdge[] closestEdges(GMLBuilding building, GMLRoad road, GMLMap result) { List<GMLDirectedEdge> bEdges = building.getEdges(); List<GMLDirectedEdge> rEdges = road.getEdges(); Iterator<GMLDirectedEdge> bit = bEdges.iterator(); GMLDirectedEdge[] closest = new GMLDirectedEdge[2]; double dist = Double.MAX_VALUE; while (bit.hasNext()) { GMLDirectedEdge bEdge = (GMLDirectedEdge) bit.next(); /* * get mid point of building edge */ double midx = (bEdge.getEndCoordinates().getX() + bEdge .getStartCoordinates().getX()) / 2.0; double midy = (bEdge.getEndCoordinates().getY() + bEdge .getStartCoordinates().getY()) / 2.0; Point2D bmid = new Point2D(midx, midy); Line2D bline = new Line2D(makePoint(bEdge.getStartCoordinates()), makePoint(bEdge.getEndCoordinates())); Iterator<GMLDirectedEdge> rit = rEdges.iterator(); while (rit.hasNext()) { GMLDirectedEdge rEdge = (GMLDirectedEdge) rit.next(); Line2D rline = new Line2D(new Point2D(rEdge .getStartCoordinates().getX(), rEdge .getStartCoordinates().getY()), new Point2D(rEdge .getEndCoordinates().getX(), rEdge.getEndCoordinates() .getY())); Point2D point = GeometryTools2D.getClosestPointOnSegment(rline, bmid); double temp = GeometryTools2D.getDistance(point, bmid); if (temp <= dist) {// && // GeometryTools2D.getAngleBetweenVectors(bline.getDirection(), // rline.getDirection())>140) { dist = temp; closest[0] = bEdge; closest[1] = rEdge; } } } return closest; } /* * find closest road using centroid of building and road edges would be more * accuate but this should do the job in most cases */ private GMLRoad closestRoad(GMLMap result, GMLBuilding building, int maxRoadID2) { List<GMLDirectedEdge> Bedges = building.getEdges(); List<Point2D> tempedges = new ArrayList<Point2D>(); Iterator<GMLDirectedEdge> eit = Bedges.iterator(); int i = 0; while (eit.hasNext()) { GMLDirectedEdge edge = (GMLDirectedEdge) eit.next(); if (GeometryTools2D.getDistance(makePoint(edge .getStartCoordinates()), makePoint(edge.getEndCoordinates())) <= entrancewidth * 2) { tempedges.add(new Point2D( (edge.getStartCoordinates().getX() + edge .getEndCoordinates().getX()) / 2, (edge .getStartCoordinates().getY() + edge .getEndCoordinates().getY()) / 2)); } } Point2D[] c = null; if (tempedges.size() == 0) { eit = Bedges.iterator(); c = new Point2D[Bedges.size()]; while (eit.hasNext()) { GMLDirectedEdge edge = (GMLDirectedEdge) eit.next(); c[i] = new Point2D((edge.getStartCoordinates().getX() + edge .getEndCoordinates().getX()) / 2, (edge .getStartCoordinates().getY() + edge .getEndCoordinates().getY()) / 2); i++; } } else { c = new Point2D[tempedges.size()]; Iterator<Point2D> tempit = tempedges.iterator(); while (tempit.hasNext()) { Point2D tempoint = (Point2D) tempit.next(); c[i] = tempoint; i++; } } Set<GMLRoad> roads = result.getRoads(); Iterator<GMLRoad> rit = roads.iterator(); GMLRoad closest = null; double dist = Double.MAX_VALUE; while (rit.hasNext()) { GMLRoad road = (GMLRoad) rit.next(); List<GMLDirectedEdge> Redges = road.getEdges(); double temp = distanceToClosestEdge(c, Redges); if (temp <= dist) {// && road.getID() <= maxRoadID2) { dist = temp; closest = road; } } return closest; } private double distanceToClosestEdge(Point2D[] c, List<GMLDirectedEdge> redges) { double dist = Double.MAX_VALUE; for (int i = 0; i < c.length; i++) { Iterator<GMLDirectedEdge> it = redges.iterator(); while (it.hasNext()) { GMLDirectedEdge edge = (GMLDirectedEdge) it.next(); Line2D eline = new Line2D( makePoint(edge.getStartCoordinates()), makePoint(edge .getEndCoordinates())); Point2D rPoint = GeometryTools2D.getClosestPointOnSegment( eline, c[i]); double temp = GeometryTools2D.getDistance(rPoint, c[i]); if (temp <= dist) { dist = temp; } } } return dist; } private void connectNetwork(GMLMap result) { /* * connect fully parsed road and building network could be slow - for * every shape find all the shapes it neighbours and make connected */ Set<GMLShape> shapes = result.getAllShapes(); Iterator<GMLShape> it = shapes.iterator(); while (it.hasNext()) { GMLShape shape = (GMLShape) it.next(); Iterator<GMLShape> secIt = result.getAllShapes().iterator(); while (secIt.hasNext()) { GMLShape shape2 = (GMLShape) secIt.next(); if (shape.getID() != shape2.getID()) { List<GMLDirectedEdge> connections = connected(shape, shape2); for (GMLDirectedEdge connection : connections) { shape.setNeighbour(connection, shape2.getID()); } } } } } private List<GMLDirectedEdge> connected(GMLShape road, GMLShape road2) { List<GMLDirectedEdge> list = new ArrayList<GMLDirectedEdge>(); /* * decides if two roads share an edge */ if (road instanceof GMLBuilding && road2 instanceof GMLBuilding) { return list; } List<GMLDirectedEdge> edges1 = road.getEdges(); List<GMLDirectedEdge> edges2 = road2.getEdges(); Iterator<GMLDirectedEdge> it1 = edges1.iterator(); while (it1.hasNext()) { GMLDirectedEdge edge1 = (GMLDirectedEdge) it1.next(); Iterator<GMLDirectedEdge> it2 = edges2.iterator(); double edge1StartX = edge1.getStartCoordinates().getX(); double edge1StartY = edge1.getStartCoordinates().getY(); double edge1EndX = edge1.getEndCoordinates().getX(); double edge1EndY = edge1.getEndCoordinates().getY(); while (it2.hasNext()) { GMLDirectedEdge edge2 = (GMLDirectedEdge) it2.next(); double edge2StartX = edge2.getStartCoordinates().getX(); double edge2StartY = edge2.getStartCoordinates().getY(); double edge2EndX = edge2.getEndCoordinates().getX(); double edge2EndY = edge2.getEndCoordinates().getY(); if (edge1StartX == edge2StartX && edge1StartY == edge2StartY && edge1EndX == edge2EndX && edge1EndY == edge2EndY) { list.add(edge1); } if (edge1EndX == edge2StartX && edge1EndY == edge2StartY && edge1StartX == edge2EndX && edge1StartY == edge2EndY) { list.add(edge1); } } } return list; } @Override public Document write(GMLMap map) { // Not implemented throw new RuntimeException("OrdnanceSurveyFormat.write not implemented"); } private void readBuildings(Document doc, GMLMap result) { for (Object next : BUILDING_XPATH.selectNodes(doc)) { Logger.debug("Found building element: " + next); Element e = (Element) next; // String fid = e.attributeValue("fid"); // long id = Long.parseLong(fid.substring(FID_PREFIX_LENGTH)); // // Strip off the 'osgb' prefix String coordinatesString = ((Element) SHAPE_XPATH.evaluate(e)) .getText(); // Geometry g = createGeometry(coordinatesString); // System.out.println(g.getArea()); // if(g.getArea()>0.0000000000001){ List<GMLDirectedEdge> edges = readEdges(coordinatesString, result); GMLBuilding b = result.createBuilding(edges); // double area = b.getBounds().getWidth()*b.getBounds().getHeight(); List<Point2D> vertices = coordinatesToVertices(b .getUnderlyingCoordinates()); double area = GeometryTools2D.computeArea(vertices); // 70 is ok if (area > 50) { // debug.show("New building", new GMLShapeInfo(b, // "New building", Color.BLACK, NEW_BUILDING_COLOUR)); // background.add(new GMLShapeInfo(b, "Buildings", Color.BLACK, // BUILDING_COLOUR)); // System.out.println("adding"); } else { result.removeBuilding(b); // System.out.println("removing"); } // } } } private List<Point2D> coordinatesToVertices(List<GMLCoordinates> coords) { List<Point2D> result = new ArrayList<Point2D>(coords.size()); for (GMLCoordinates c : coords) { result.add(new Point2D(c.getX(), c.getY())); } return result; } private void readRoads(Document doc, GMLMap result) { // debug.activate(); for (Object next : ROAD_XPATH.selectNodes(doc)) { Logger.debug("Found road element: " + next); Element e = (Element) next; // String fid = e.attributeValue("fid"); // long id = Long.parseLong(fid.substring(FID_PREFIX_LENGTH)); // // Strip off the 'osgb' prefix String coordinatesString = ((Element) SHAPE_XPATH.evaluate(e)) .getText(); Object inner = INNER_RING_XPATH.evaluate(e); if ((inner instanceof Collection) && ((Collection) inner).isEmpty()) { // no inner rings? List<GMLDirectedEdge> edges = readEdges(coordinatesString, result); GMLRoad road = result.createRoad(edges); maxRoadID = road.getID(); // debug.show("New road", new GMLShapeInfo(road, // "New road",Color.BLACK, NEW_ROAD_COLOUR)); // background.add(new GMLShapeInfo(road, "Roads", Color.BLACK, // ROAD_COLOUR)); } else { // 1 or more inner rings if (inner instanceof Collection) { // more than 1 inner ring so leave it just now } else { // must be just 1 so is an element Element innerE = (Element) inner; String innerCoordinatesString = innerE.getText(); Geometry outerG = createGeometry(coordinatesString); Geometry innerG = createGeometry(innerCoordinatesString); Geometry shape = outerG.difference(innerG); Coordinate[] coords = shape.getCoordinates(); List<GMLDirectedEdge> edges = readEdges(coords, result); GMLRoad road = result.createRoad(edges); maxRoadID = road.getID(); // debug.show("New road", new GMLShapeInfo(road, // "New road",Color.BLACK, NEW_ROAD_COLOUR)); // background.add(new GMLShapeInfo(road, "Roads", // Color.BLACK, ROAD_COLOUR)); } } } // debug.deactivate(); } private boolean sharesEdge(Geometry a, Geometry b) { /* * determines whether 2 geometries are touching in more than one point * used in triangulation merging */ Coordinate[] aC = a.getCoordinates(); Coordinate[] bC = b.getCoordinates(); boolean touch1 = true; boolean touch2 = false; boolean touch3 = false; for (int i = 0; i < aC.length; i++) { for (int j = 0; j < bC.length; j++) { if (aC[i].equals(bC[j]) && !touch1) { touch1 = true; } else if (aC[i].equals(bC[j]) && touch1 && !touch2) { touch2 = true; } else if (aC[i].equals(bC[j]) && touch2 && !touch3) { touch3 = true; } else if (aC[i].equals(bC[j]) && touch3) { return true; } } } return false; } private Collection<Line2D> getLines(Geometry a) { ArrayList<Line2D> lines = new ArrayList(); for (int i = 0; i < a.getCoordinates().length; i++) { Line2D line; if (i < a.getCoordinates().length - 1) { line = new Line2D(new Point2D(a.getCoordinates()[i].x, a .getCoordinates()[i].y), new Point2D( a.getCoordinates()[0].x, a.getCoordinates()[0].y)); } else { line = new Line2D(new Point2D(a.getCoordinates()[i].x, a .getCoordinates()[i].y), new Point2D( a.getCoordinates()[0].x, a.getCoordinates()[0].y)); } lines.add(line); } return lines; } private Coordinate pointOnEdge(Geometry g, Geometry edge) { Coordinate[] t = g.getCoordinates(); Coordinate[] o = edge.getCoordinates(); for (int i = 0; i < t.length; i++) { for (int j = 0; j < o.length; j++) { if (t[i].equals2D(o[j])) { return t[i]; } } } return null; } private boolean onEdge(Geometry g, Geometry outerG) { /* * determines if a geometry is on the outer segment or inner */ Coordinate[] t = g.getCoordinates(); Coordinate[] o = outerG.getCoordinates(); for (int i = 0; i < t.length; i++) { for (int j = 0; j < o.length; j++) { if (t[i].equals(o[j])) { return true; } } } return false; } private boolean shapesIntersect(GMLShape shape1, Coordinate[] shape2) { List<GMLDirectedEdge> edges1 = shape1.getEdges(); // List<GMLDirectedEdge> edges2 = shape2.getEdges(); for (GMLDirectedEdge edge1 : edges1) { Line2D edge1Line = new Line2D( makePoint(edge1.getStartCoordinates()), makePoint(edge1 .getEndCoordinates())); for (int i = 0; i < shape2.length; i++) { Line2D edge2Line = new Line2D(makePoint(shape2[i]), makePoint(shape2[(i + 1) % shape2.length])); double intersection1 = edge1Line.getIntersection(edge2Line); double intersection2 = edge2Line.getIntersection(edge1Line); if (intersection1 >= 0 && intersection1 <= 1 && intersection2 >= 0 && intersection2 <= 1) { return true; } } } return false; } private Geometry createGeometry(Coordinate[] coords) { return factory.createLinearRing(coords); /* * takes a string of coordinates and returns a jts geometry object */ // make the WKT string /* * String wktString = "LINESTRING ("; for (int i = 0; i < coords.length; * i++) { GMLCoordinates nextApex = new GMLCoordinates(coords[i].x, * coords[i].y); wktString = wktString + nextApex.getX() + " "; if (i + * 1 < coords.length) { wktString = wktString + nextApex.getY() + ", "; * } else { wktString = wktString + nextApex.getY(); } } wktString = * wktString + ")"; try { return new WKTReader().read(wktString); } * catch (ParseException e) { // TODO Auto-generated catch block * e.printStackTrace(); } return null; */ } private Geometry createGeometry(String coordinatesString) { /* * takes a string of coordinates and returns a jts geometry object */ // make the WKT string StringTokenizer tokens = new StringTokenizer(coordinatesString, " "); String wktString = "LINESTRING ("; while (tokens.hasMoreTokens()) { String token = tokens.nextToken(); GMLCoordinates nextApex = new GMLCoordinates(token); wktString = wktString + nextApex.getX() + " "; if (tokens.hasMoreTokens()) { wktString = wktString + nextApex.getY() + ", "; } else { wktString = wktString + nextApex.getY(); } } wktString = wktString + ")"; try { return new WKTReader().read(wktString); } catch (ParseException e) { // TODO Auto-generated catch block e.printStackTrace(); } return null; } private void readSpaces(Document doc, GMLMap result) { /* * for (Object next : SPACE_XPATH.selectNodes(doc)) { * Logger.debug("Found space element: " + next); Element e = * (Element)next; String fid = e.attributeValue("fid"); long id = * Long.parseLong(fid.substring(4)); // Strip off the 'osgb' prefix * String coordinatesString = * ((Element)SHAPE_XPATH.evaluate(e)).getText(); List<GMLEdge> edges = * readEdges(coordinatesString, result); result.createSpace(edges); } */ } private List<GMLDirectedEdge> readEdges(Coordinate[] coords, GMLMap map) { List<GMLDirectedEdge> edges = new ArrayList<GMLDirectedEdge>(); GMLCoordinates lastApex = null; GMLNode fromNode = null; GMLNode toNode = null; for (int i = 0; i < coords.length; i++) { GMLCoordinates nextApex = new GMLCoordinates(coords[i].x, coords[i].y); toNode = map.createNode(nextApex); if (lastApex != null) { edges.add(new GMLDirectedEdge(map.createEdge(fromNode, toNode), true)); } lastApex = nextApex; fromNode = toNode; } return edges; } private List<GMLDirectedEdge> readEdges(String coordinatesString, GMLMap map) { List<GMLDirectedEdge> edges = new ArrayList<GMLDirectedEdge>(); StringTokenizer tokens = new StringTokenizer(coordinatesString, " "); GMLCoordinates lastApex = null; GMLNode fromNode = null; GMLNode toNode = null; while (tokens.hasMoreTokens()) { String token = tokens.nextToken(); GMLCoordinates nextApex = new GMLCoordinates(token); toNode = map.createNode(nextApex); if (lastApex != null) { edges.add(new GMLDirectedEdge(map.createEdge(fromNode, toNode), true)); } lastApex = nextApex; fromNode = toNode; } return edges; } }