package gis2; import kernel.WorldModelCreator; import kernel.KernelException; import rescuecore2.config.Config; import rescuecore2.worldmodel.WorldModel; import rescuecore2.worldmodel.Entity; import rescuecore2.worldmodel.EntityID; import rescuecore2.misc.geometry.Point2D; import rescuecore2.misc.geometry.GeometryTools2D; import rescuecore2.log.Logger; import rescuecore2.standard.entities.StandardWorldModel; import rescuecore2.standard.entities.Building; import rescuecore2.standard.entities.Road; import rescuecore2.standard.entities.Edge; import maps.MapReader; import maps.MapException; import maps.gml.GMLMap; import maps.gml.GMLDirectedEdge; import maps.gml.GMLBuilding; import maps.gml.GMLRoad; import maps.gml.GMLShape; import maps.gml.GMLCoordinates; import maps.CoordinateConversion; import maps.ScaleConversion; import java.util.List; import java.util.ArrayList; import org.dom4j.Document; import org.dom4j.DocumentException; import org.dom4j.io.SAXReader; import java.io.File; //import rescuecore2.misc.gui.ShapeDebugFrame; /** A WorldModelCreator that reads a GML file and scenario descriptor. */ public class GMLWorldModelCreator implements WorldModelCreator { private static final String MAP_DIRECTORY_KEY = "gis.map.dir"; private static final String MAP_FILE_KEY = "gis.map.file"; private static final String DEFAULT_MAP_FILE = "map.gml"; private static final String SCENARIO_FILE_KEY = "gis.map.scenario"; private static final String DEFAULT_SCENARIO_FILE = "scenario.xml"; private static final double SQ_MM_TO_SQ_M = 0.000001; // CHECKSTYLE:OFF:MagicNumber // private static final double AREA_SCALE_FACTOR = 1.0 / 1000000.0; // CHECKSTYLE:ON:MagicNumber // private ShapeDebugFrame debug; private int nextID; @Override public String toString() { return "GML world model creator"; } @Override public WorldModel<? extends Entity> buildWorldModel(Config config) throws KernelException { try { StandardWorldModel result = new StandardWorldModel(); File dir = new File(config.getValue(MAP_DIRECTORY_KEY)); File mapFile = new File(dir, config.getValue(MAP_FILE_KEY, DEFAULT_MAP_FILE)); File scenarioFile = new File(dir, config.getValue(SCENARIO_FILE_KEY, DEFAULT_SCENARIO_FILE)); readMapData(mapFile, result); readScenarioData(scenarioFile, result, config); for (Entity e : result) { nextID = Math.max(nextID, e.getID().getValue()); } ++nextID; result.index(); return result; } catch (MapException e) { throw new KernelException("Couldn't read GML file", e); } catch (DocumentException e) { throw new KernelException("Couldn't read scenario file", e); } catch (ScenarioException e) { throw new KernelException("Invalid scenario file", e); } } @Override public EntityID generateID() { return new EntityID(nextID++); } private void readMapData(File mapFile, StandardWorldModel result) throws MapException { GMLMap map = (GMLMap)MapReader.readMap(mapFile); CoordinateConversion conversion = getCoordinateConversion(map); Logger.debug("Creating entities"); Logger.debug(map.getBuildings().size() + " buildings"); Logger.debug(map.getRoads().size() + " roads"); for (GMLBuilding next : map.getBuildings()) { // Create a new Building entity EntityID id = new EntityID(next.getID()); Building b = new Building(id); List<Point2D> vertices = convertShapeToPoints(next, conversion); double area = GeometryTools2D.computeArea(vertices) * SQ_MM_TO_SQ_M; Point2D centroid = GeometryTools2D.computeCentroid(vertices); // Logger.debug("Building vertices: " + vertices); // Logger.debug("Area: " + area); // Logger.debug("Centroid: " + centroid); // Building properties b.setFloors(next.getFloors()); b.setFieryness(0); b.setBrokenness(0); b.setBuildingCode(next.getCode()); b.setBuildingAttributes(0); b.setGroundArea((int)Math.abs(area)); b.setTotalArea(((int)Math.abs(area)) * b.getFloors()); b.setImportance(next.getImportance()); // Area properties b.setEdges(createEdges(next, conversion)); b.setX((int)centroid.getX()); b.setY((int)centroid.getY()); result.addEntity(b); // Logger.debug(b.getFullDescription()); } for (GMLRoad next : map.getRoads()) { // Create a new Road entity EntityID id = new EntityID(next.getID()); Road r = new Road(id); List<Point2D> vertices = convertShapeToPoints(next, conversion); Point2D centroid = GeometryTools2D.computeCentroid(vertices); // Logger.debug("Road vertices: " + vertices); // Logger.debug("Centroid: " + centroid); // Road properties: None // Area properties r.setX((int)centroid.getX()); r.setY((int)centroid.getY()); r.setEdges(createEdges(next, conversion)); result.addEntity(r); // Logger.debug(b.getFullDescription()); } } private void readScenarioData(File scenarioFile, StandardWorldModel result, Config config) throws DocumentException, ScenarioException { if (scenarioFile.exists()) { SAXReader reader = new SAXReader(); Logger.debug("Reading scenario"); Document doc = reader.read(scenarioFile); Scenario scenario = new Scenario(doc); Logger.debug("Applying scenario"); scenario.apply(result, config); } } private List<Edge> createEdges(GMLShape s, CoordinateConversion conversion) { // Logger.debug("Computing edges for " + s); List<Edge> result = new ArrayList<Edge>(); for (GMLDirectedEdge edge : s.getEdges()) { GMLCoordinates start = edge.getStartCoordinates(); GMLCoordinates end = edge.getEndCoordinates(); Integer neighbourID = s.getNeighbour(edge); EntityID id = neighbourID == null ? null : new EntityID(neighbourID); // Logger.debug("Edge: " + start + " -> " + end); double sx = conversion.convertX(start.getX()); double sy = conversion.convertY(start.getY()); double ex = conversion.convertX(end.getX()); double ey = conversion.convertY(end.getY()); // Logger.debug(edge.getEdge() + " : " + sx + "," + sy + " -> " + ex + "," + ey); result.add(new Edge((int)sx, (int)sy, (int)ex, (int)ey, id)); } return result; } private List<Point2D> convertShapeToPoints(GMLShape shape, CoordinateConversion conversion) { List<Point2D> points = new ArrayList<Point2D>(); for (GMLCoordinates next : shape.getCoordinates()) { points.add(new Point2D(conversion.convertX(next.getX()), conversion.convertY(next.getY()))); } return points; } private CoordinateConversion getCoordinateConversion(GMLMap map) { return new ScaleConversion(map.getMinX(), map.getMinY(), 1000, 1000); } }