package iamrescue.agent.firebrigade; import iamrescue.belief.IAMWorldModel; import iamrescue.belief.spatial.ISpatialIndex; import iamrescue.belief.spatial.SpatialIndex; import iamrescue.belief.spatial.SpatialQuery; import iamrescue.belief.spatial.SpatialQueryFactory; import iamrescue.util.PositionXY; import java.awt.geom.Rectangle2D; import java.util.ArrayList; import java.util.Collection; import java.util.List; import java.util.Set; import javolution.util.FastSet; import rescuecore2.misc.geometry.GeometryTools2D; import rescuecore2.misc.geometry.Line2D; import rescuecore2.misc.geometry.Point2D; import rescuecore2.standard.entities.Building; import rescuecore2.standard.entities.StandardEntity; import rescuecore2.worldmodel.EntityID; /** * This class represent a cluster of buildings on fire, that is a Fire Site, and contains all the properties, * that we use in order to represent it, extend it and finally maintain it * * @author fmdf08r * */ public class FireSite { private Building center; private Collection<Building> buildingsOnFire; private Set<FireDistanceArray> fireArrays; private int NUMBER_OF_ARRAYS = 8; // DEFAULT private IAMWorldModel model; private int FIRE_DISTANCE = 50000; // mm ??? private HeatTransferGraph graph; private int maxDistance = 0; private int MAX_ALLOWED_DISTANCE; /** * Constructor of the class it initialises the center of the firesite, the graph, the world model, and * some other useful parameters * * @param center building at the center of the FireSite * @param graph connection graph between buildings * @param model world model to consider * */ public FireSite(Building center, HeatTransferGraph graph, IAMWorldModel model, int numberOfFireArrays){ this.center = center; this.model = model; this.graph = graph; this.NUMBER_OF_ARRAYS = numberOfFireArrays; // bounds of the map Rectangle2D bounds = model.getBounds(); // all the buildings within the FireSite that are on fire this.buildingsOnFire = new FastSet<Building>(); this.buildingsOnFire.add(center); fireArrays = new FastSet<FireDistanceArray>(); double angle = 0.0; // angle of the fire array for(int i = 0; i < NUMBER_OF_ARRAYS; i++){ if(center.getX() == bounds.getMinX() && center.getY() == bounds.getMinY()) // bottom left corner if( angle < 0.0 || angle > 90.0 ) continue; if(center.getX() == bounds.getMinX() && center.getY() == bounds.getMaxY()) // top left corner if( angle > 270.0 ) continue; if(center.getX() == bounds.getMaxX() && center.getY() == bounds.getMaxY()) // top right corner if( angle < 180.0 || angle > 270.0) continue; if(center.getX() == bounds.getMaxX() && center.getY() == bounds.getMinY()) // bottom right corner if( angle < 90.0 || angle > 180.0 ) continue; FireDistanceArray fd_array = new FireDistanceArray(center, angle); fireArrays.add(fd_array); angle += (double) 360 / NUMBER_OF_ARRAYS; } } /** * Constructor with a default number of FireArrays * * @param center ~ same as other constructor * @param heatTransferGraph ~ same as other constructor * @param model ~ same as other constructor */ public FireSite(Building center, HeatTransferGraph graph, IAMWorldModel model) { this(center, graph, model, 8); } /** * this method updates the FireSite with the current information of the * buildings on fire * * @param time the current time step * @param buildingsOnFire2 new buildingsOnFire * */ public void update(int time) { // we first update the fireArray updateFireArrays(time); updateBuildingsOnFire(); } /** * update the buildingsOnFire vector * */ private void updateBuildingsOnFire() { Set<PositionXY> positionsSet = new FastSet<PositionXY>(); if(maxDistance > MAX_ALLOWED_DISTANCE) maxDistance = MAX_ALLOWED_DISTANCE; Collection<StandardEntity> buildingsToAdd = model.getObjectsInRange(center, maxDistance); for (StandardEntity standardEntity : buildingsToAdd) { if(standardEntity instanceof Building){ Building building = (Building) standardEntity; if(building.isFierynessDefined()){ if(building.getFieryness() <= 3 && building.getFieryness() >= 1) buildingsOnFire.add(building); else buildingsOnFire.remove(building); } } } } /** * update the fire arrays of the site, with the most up to date information * * @param time current time */ public void updateFireArrays(int time){ for (FireDistanceArray fireArray : fireArrays) updateFireArray(time, fireArray); } /** * update a single fireArray * * @param time current time * @param fireArray array to update * */ private void updateFireArray(int time, FireDistanceArray fireArray) { FastSet<Building> visitedBuildings = new FastSet<Building>(); boolean frontierHasChanged = true; Building currentFrontier = fireArray.getFrontierBuilding(); while(frontierHasChanged){ Line2D fireLine = new Line2D(new Point2D(currentFrontier.getX(), currentFrontier.getY()), new Point2D(currentFrontier.getX() + (int) FIRE_DISTANCE*Math.cos(Math.toRadians(fireArray.getAngle())), currentFrontier.getY() + (int) FIRE_DISTANCE*Math.sin(Math.toRadians(fireArray.getAngle())))); // we visited the frontier visitedBuildings.add(currentFrontier); // and the previous frontier visitedBuildings.add(fireArray.getPreviousFrontier()); Collection<Building> neighbours = graph.getNeighbouringBuildings(currentFrontier); //un-set the flag frontierHasChanged = false; for (Building building : neighbours) { double maxNeighbourDistance = 0.0; if(visitedBuildings.contains(building)) // if we already visited the building then we move on continue; if(building.isFierynessDefined()){ // the building is on fire if(building.getFieryness() <= 3 || building.getFieryness() >= 1){ // get current neighbours lines int[] apexes = ((Building) building).getApexList(); List<Point2D> points = GeometryTools2D.vertexArrayToPoints(apexes); List<Line2D> lines = GeometryTools2D.pointsToLines(points, true); boolean intersects = false; for (Line2D line : lines) { double d1 = line.getIntersection(fireLine); double d2 = fireLine.getIntersection(line); if (d2 >= 0 && d2 <= 1 && d1 >= 0 && d1 <= 1) { intersects = true; break; } } if(intersects){ double distanceToCurrentFrontier = Math.sqrt( ((double) building.getY() - currentFrontier.getY())*(building.getY() - currentFrontier.getY()) + ((double) building.getX() - currentFrontier.getX())*(building.getX() - currentFrontier.getX()) ); if(distanceToCurrentFrontier > maxNeighbourDistance){ maxNeighbourDistance = distanceToCurrentFrontier; currentFrontier = building; frontierHasChanged = true; } } } } // the building has now been visited visitedBuildings.add(building); } if(frontierHasChanged == true) { // update the current frontier fireArray.setPreviousFrontier(fireArray.getFrontierBuilding()); // update the fireSite fireArray.setFrontierBuilding(currentFrontier); // memorise the distance double distance = Math.sqrt( ( (double) currentFrontier.getY() - center.getY())*(currentFrontier.getY() - center.getY()) + ( (double) currentFrontier.getX() - center.getX())*(currentFrontier.getX() - center.getX()) ); if(distance > maxDistance) maxDistance = (int) (distance + 0.5); fireArray.addDistance(time, distance); } } } /** * This method predict the construct estimates the fireSite @param time * time steps in the future * * @param time the time at which we want the prediction * @return a predicted copy of the current fireSite * */ public FireSite predict(int time){ // we make a copy FireSite copy = null; try { copy = (FireSite) this.clone(); } catch (CloneNotSupportedException e) { // TODO Auto-generated catch block e.printStackTrace(); } copy.predictFireArrays(time); copy.predictBuildingsOnFire(); return copy; } /** * extend the fireArrays of the fireSite, considering the current prediction model * * @param time time for which the prediction must be considered * */ public void predictFireArrays(int time) { for (FireDistanceArray fireArray : fireArrays) { predictFireArray(time, fireArray); } } /** * this method extends the specified @param fireArray to the given @param time * * @param time time of prediction * @param fireArray fireArray to be predicted * */ private void predictFireArray(int time, FireDistanceArray fireArray) { FastSet<Building> visitedBuildings = new FastSet<Building>(); boolean frontierHasChanged = true; while(frontierHasChanged){ Building currentFrontier = fireArray.getFrontierBuilding(); // we visited the frontier visitedBuildings.add(currentFrontier); // and the previous frontier visitedBuildings.add(fireArray.getPreviousFrontier()); double predictedDistance = fireArray.getPredictedDistance(time); Line2D fireLine = new Line2D(new Point2D(currentFrontier.getX(), currentFrontier.getY()), new Point2D(currentFrontier.getX() + (int) predictedDistance*Math.cos(Math.toRadians(fireArray.getAngle())), currentFrontier.getY() + (int) predictedDistance*Math.sin(Math.toRadians(fireArray.getAngle())))); Collection<Building> neighbours = graph.getNeighbouringBuildings(currentFrontier); //un-set the flag frontierHasChanged = false; for (Building building : neighbours) { // TODO this portion of code might be BUGGED // for each neighbour we consider the FAREST ONE double maxNeighbourDistance = 0.0; // System.out.println("entering the NEIGHBOOURS loop"); if(visitedBuildings.contains(building)) // if we already visited the building then we move on continue; // get current neighbours lines int[] apexes = ((Building) building).getApexList(); List<Point2D> points = GeometryTools2D.vertexArrayToPoints(apexes); List<Line2D> lines = GeometryTools2D.pointsToLines(points, true); boolean intersects = false; for (Line2D line : lines) { double d1 = line.getIntersection(fireLine); double d2 = fireLine.getIntersection(line); if (d2 >= 0 && d2 <= 1 && d1 >= 0 && d1 <= 1) { intersects = true; break; } } if(intersects){ // building intersects the line and is on fire double distanceToCurrentFrontier = Math.sqrt( ((double) building.getY() - currentFrontier.getY())*(building.getY() - currentFrontier.getY()) + ((double) building.getX() - currentFrontier.getX())*(building.getX() - currentFrontier.getX()) ); if(distanceToCurrentFrontier > maxNeighbourDistance){ maxNeighbourDistance = distanceToCurrentFrontier; currentFrontier = building; frontierHasChanged = true; } } // the building has now been visited visitedBuildings.add(building); } if(frontierHasChanged) { // update the current frontier fireArray.setPreviousFrontier(fireArray.getFrontierBuilding()); // update the fireSite fireArray.setFrontierBuilding(currentFrontier); // memorize the distance double distance = Math.sqrt( ((double) currentFrontier.getY() - center.getY())*(currentFrontier.getY() - center.getY()) + ((double) currentFrontier.getX() - center.getX())*(currentFrontier.getX() - center.getX()) ); if(distance > maxDistance) maxDistance = (int) (distance + 0.5); } // System.out.println("exiting the WHILE LOOP"); } // System.out.println("ENDING THE PREDICTFIREARRAYMETHOD"); } /** * same as method updateBuildingsOnFire */ public void predictBuildingsOnFire(){ if(maxDistance > MAX_ALLOWED_DISTANCE) maxDistance = MAX_ALLOWED_DISTANCE; // System.out.println("maxDistance is: " + maxDistance); Collection<StandardEntity> buildingsToAdd = model.getObjectsInRange(center, maxDistance); // System.out.println("Buildings to add are: "); for (StandardEntity standardEntity : buildingsToAdd) { if(standardEntity instanceof Building){ Building building = (Building) standardEntity; // System.out.println(building); if(building.isFierynessDefined()){ if(building.getFieryness() == 8) buildingsOnFire.remove(building); } else buildingsOnFire.add(building); } } } /** * this method checks if the current fireSite has AT LEAST one building that is contained in * another fireSite * * @param otherSite * @return true if the 2 fireSites intersects */ public boolean intersects(FireSite otherSite) { for (Building building : buildingsOnFire) if(otherSite.containsBuilding(building)) return true; return false; } public boolean containsBuilding(Building building) { return buildingsOnFire.contains(building); } public Building getCenter() { return center; } public Set<FireDistanceArray> getFireArrays(){ return fireArrays; } /* (non-Javadoc) * @see java.lang.Object#clone() */ @Override protected Object clone() throws CloneNotSupportedException { FireSite copy = new FireSite(this.center, this.graph, this.model, this.NUMBER_OF_ARRAYS); copy.buildingsOnFire.addAll(this.buildingsOnFire); copy.maxDistance = this.maxDistance; copy.fireArrays = new FastSet<FireDistanceArray>(); for (FireDistanceArray fireArray : this.fireArrays) copy.fireArrays.add((FireDistanceArray) fireArray.clone()); return copy; } public List<Building> getListOfBuildingsOnFire(){ ArrayList<Building> list = new ArrayList<Building>(); list.addAll(buildingsOnFire); return list; } public Collection<Building> getBuildingsOnFire() { // TODO Auto-generated method stub return buildingsOnFire; } /* (non-Javadoc) * @see java.lang.Object#equals(java.lang.Object) */ @Override public boolean equals(Object obj) { // TODO Auto-generated method stub return super.equals(obj); } }