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

init

parent 54f6cedf
package clear;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import rescuecore2.log.Logger;
import rescuecore2.messages.Command;
import rescuecore2.messages.control.KSCommands;
import rescuecore2.misc.geometry.GeometryTools2D;
import rescuecore2.misc.geometry.Line2D;
import rescuecore2.misc.geometry.Point2D;
import rescuecore2.standard.components.StandardSimulator;
import rescuecore2.standard.entities.Area;
import rescuecore2.standard.entities.Blockade;
import rescuecore2.standard.entities.PoliceForce;
import rescuecore2.standard.entities.Road;
import rescuecore2.standard.entities.StandardEntity;
import rescuecore2.standard.messages.AKClear;
import rescuecore2.standard.messages.AKClearArea;
import rescuecore2.worldmodel.ChangeSet;
import rescuecore2.worldmodel.EntityID;
/**
* The area model clear simulator. This simulator processes AKClear messages.
*/
public class ClearSimulator extends StandardSimulator {
private static final String SIMULATOR_NAME = "Area Model Clear Simulator";
private static final String REPAIR_RATE_KEY = "clear.repair.rate";
private static final String REPAIR_RAD_KEY = "clear.repair.rad";
private static final String REPAIR_DISTANCE_KEY = "clear.repair.distance";
// Converts square mm to square m.
private static final double REPAIR_COST_FACTOR = 0.000001;
private int repairRate;
private int repairRadius;
private int repairDistance;
@Override
public String getName() {
return SIMULATOR_NAME;
}
@Override
protected void postConnect() {
this.repairRate = config.getIntValue(REPAIR_RATE_KEY);
this.repairRadius = config.getIntValue(REPAIR_RAD_KEY);
this.repairDistance = config.getIntValue(REPAIR_DISTANCE_KEY);
}
@Override
protected void processCommands(KSCommands c, ChangeSet changes) {
long start = System.currentTimeMillis();
int time = c.getTime();
Logger.info("Timestep " + time);
Map<Blockade, Integer> partiallyCleared = new HashMap<>();
Set<EntityID> cleared = new HashSet<>();
for (Command command : c.getCommands()) {
if ((command instanceof AKClear clear) && isValid(clear, cleared)) {
Logger.debug("Processing " + clear);
EntityID blockadeID = clear.getTarget();
Blockade blockade = (Blockade) model.getEntity(blockadeID);
Area area = (Area) model.getEntity(blockade.getPosition());
int cost = blockade.getRepairCost();
Logger.debug("Blockade repair cost: " + cost);
Logger.debug("Blockade repair rate: " + this.repairRate);
if (this.repairRate >= cost) {
// Remove the blockade entirely
List<EntityID> ids = new ArrayList<>(area.getBlockades());
ids.remove(blockadeID);
area.setBlockades(ids);
model.removeEntity(blockadeID);
changes.addChange(area, area.getBlockadesProperty());
changes.entityDeleted(blockadeID);
partiallyCleared.remove(blockade);
cleared.add(blockadeID);
Logger.debug("Cleared " + blockade);
} else {
// Update the repair cost
if (!partiallyCleared.containsKey(blockade)) {
partiallyCleared.put(blockade, cost);
}
cost -= this.repairRate;
blockade.setRepairCost(cost);
changes.addChange(blockade, blockade.getRepairCostProperty());
}
} else if ((command instanceof AKClearArea clearArea)
&& (isValid(clearArea))) {
processClearArea(clearArea, changes);
Logger.debug("Processing " + clearArea);
}
}
// Shrink partially cleared blockades
for (Map.Entry<Blockade, Integer> next : partiallyCleared.entrySet()) {
Blockade b = next.getKey();
double original = next.getValue();
double current = b.getRepairCost();
// d is the new size relative to the old size
double d = current / original;
Logger.debug("Partially cleared " + b);
Logger.debug("Original repair cost: " + original);
Logger.debug("New repair cost: " + current);
Logger.debug("Proportion left: " + d);
int[] apexes = b.getApexes();
double cx = b.getX();
double cy = b.getY();
// Move each apex towards the centre
for (int i = 0; i < apexes.length; i += 2) {
double x = apexes[i];
double y = apexes[i + 1];
double dx = x - cx;
double dy = y - cy;
// Shift both x and y so they are now d * dx from the centre
double newX = cx + (dx * d);
double newY = cy + (dy * d);
apexes[i] = (int) newX;
apexes[i + 1] = (int) newY;
}
b.setApexes(apexes);
changes.addChange(b, b.getApexesProperty());
}
long end = System.currentTimeMillis();
Logger.info("Timestep " + time + " took " + (end - start) + " ms");
}
private void processClearArea(AKClearArea clear, ChangeSet changes) {
PoliceForce agent = (PoliceForce) model.getEntity(clear.getAgentID());
int targetX = clear.getDestinationX();
int targetY = clear.getDestinationY();
int length = this.repairDistance;
Map<Blockade, java.awt.geom.Area> blockades = new HashMap<>();
for (StandardEntity entity : model.getObjectsInRange(agent.getX(),
agent.getY(), length)) {
if ((entity instanceof Area area) && (area.isBlockadesDefined())) {
for (EntityID blockadeID : area.getBlockades()) {
Blockade blockade = (Blockade) model.getEntity(blockadeID);
if (blockade != null) {
if (blockade.getShape() == null) {
Logger.debug("Blockade Shape is null");
}
blockades.put(blockade,
new java.awt.geom.Area(blockade.getShape()));
}
}
}
}
int counter = 0;
int min = 0;
int max = 2 * length;
while (true) {
counter++;
length = (min + max) / 2;
java.awt.geom.Area area = Geometry.getClearArea(agent, targetX, targetY,
length, this.repairRadius);
double firstSurface = Geometry.surface(area);
for (java.awt.geom.Area blockade : blockades.values())
area.subtract(blockade);
double surface = Geometry.surface(area);
double clearedSurface = firstSurface - surface;
if ((clearedSurface * REPAIR_COST_FACTOR) > this.repairRate) {
max = length;
} else if ((counter != 1) && (counter < 15) && ((max - min) > 5)) {
min = length;
} else {
break;
}
}
java.awt.geom.Area area = Geometry.getClearArea(agent, targetX, targetY,
length, this.repairRadius);
for (Map.Entry<Blockade, java.awt.geom.Area> entry : blockades.entrySet()) {
Blockade blockade = entry.getKey();
java.awt.geom.Area blockadeArea = entry.getValue();
Road road = (Road) model.getEntity(blockade.getPosition());
double firstSurface = Geometry.surface(blockadeArea);
blockadeArea.subtract(area);
double surface = Geometry.surface(blockadeArea);
if (surface < firstSurface) {
changes.addChange(blockade, blockade.getApexesProperty());
List<int[]> areas = Geometry.getAreas(blockadeArea);
if (areas.size() == 1) {
Blockade backupBlockade = blockade;
blockade = updateBlockadeApexes(blockade, areas.get(0));
if (blockade == null) {
blockade = backupBlockade;
areas.clear();
} else {
changes.addChange(blockade, blockade.getApexesProperty());
changes.addChange(blockade, blockade.getXProperty());
changes.addChange(blockade, blockade.getYProperty());
changes.addChange(blockade, blockade.getRepairCostProperty());
}
}
if (areas.size() != 1) {
try {
List<EntityID> newIDs = requestNewEntityIDs(areas.size());
Iterator<EntityID> it = newIDs.iterator();
List<Blockade> newBlockades = new ArrayList<>();
if (!areas.isEmpty())
Logger.debug("Creating new blockade objects for "
+ blockade.getID().getValue() + " " + areas.size());
for (int[] apexes : areas) {
EntityID id = it.next();
Blockade b = makeBlockade(id, apexes, road.getID());
if (b != null)
newBlockades.add(b);
}
List<EntityID> existing = road.getBlockades();
List<EntityID> ids = new ArrayList<>();
if (existing != null)
ids.addAll(existing);
for (Blockade b : newBlockades) {
ids.add(b.getID());
}
ids.remove(blockade.getID());
road.setBlockades(ids);
changes.addAll(newBlockades);
model.removeEntity(blockade.getID());
changes.addChange(road, road.getBlockadesProperty());
changes.entityDeleted(blockade.getID());
} catch (InterruptedException e) {
Logger.error("Interrupted while requesting IDs");
}
}
}
}
}
private Blockade updateBlockadeApexes(Blockade blockade, int[] apexes) {
List<Point2D> points = GeometryTools2D.vertexArrayToPoints(apexes);
if (points.size() >= 2) {
Point2D centroid = GeometryTools2D.computeCentroid(points);
blockade.setApexes(apexes);
blockade.setX((int) centroid.getX());
blockade.setY((int) centroid.getY());
int cost = (int) (GeometryTools2D.computeArea(points)
* REPAIR_COST_FACTOR);
if (cost != 0) {
blockade.setRepairCost(cost);
return blockade;
}
}
return null;
}
private Blockade makeBlockade(EntityID id, int[] apexes, EntityID roadID) {
Blockade blockade = new Blockade(id);
blockade.setPosition(roadID);
return updateBlockadeApexes(blockade, apexes);
}
private boolean isValid(AKClear clear, Set<EntityID> cleared) {
// Check Target
StandardEntity target = model.getEntity(clear.getTarget());
if (target == null) {
Logger
.info("Rejecting clear command " + clear + ": target does not exist");
return false;
} else if (cleared.contains(clear.getTarget())) {
Logger.info("Ignoring clear command " + clear
+ ": target already cleared in this timestep");
return false;
} else if (!(target instanceof Blockade)) {
Logger.info(
"Rejecting clear command " + clear + ": target is not a blockade");
return false;
}
// Check Agent
StandardEntity agent = model.getEntity(clear.getAgentID());
if (agent == null) {
Logger
.info("Rejecting clear command " + clear + ": agent does not exist");
return false;
} else if (!(agent instanceof PoliceForce)) {
Logger.info(
"Rejecting clear command " + clear + ": agent is not a PoliceForce");
return false;
}
// Check PoliceForce
PoliceForce police = (PoliceForce) agent;
StandardEntity agentPosition = police.getPosition(model);
if (agentPosition == null) {
Logger.info(
"Rejecting clear command " + clear + ": could not locate the agent");
return false;
} else if (!police.isHPDefined() || police.getHP() <= 0) {
Logger.info("Rejecting clear command " + clear + ": agent is dead");
return false;
} else if (police.isBuriednessDefined() && police.getBuriedness() > 0) {
Logger.info("Rejecting clear command " + clear + ": agent is buried");
return false;
}
// Check Blockade
Blockade targetBlockade = (Blockade) target;
if (!targetBlockade.isPositionDefined()) {
Logger.info(
"Rejecting clear command " + clear + ": blockade position undefined");
return false;
} else if (!targetBlockade.isRepairCostDefined()) {
Logger.info(
"Rejecting clear command " + clear + ": blockade has no repair cost");
return false;
}
// Check Any Blockade to Clear
Point2D agentLocation = new Point2D(police.getX(), police.getY());
double bestDistance = Double.MAX_VALUE;
for (Line2D line : GeometryTools2D.pointsToLines(
GeometryTools2D.vertexArrayToPoints(targetBlockade.getApexes()),
true)) {
Point2D closest = GeometryTools2D.getClosestPointOnSegment(line,
agentLocation);
double distance = GeometryTools2D.getDistance(agentLocation, closest);
if (distance < this.repairDistance) {
return true;
} else if (bestDistance > distance) {
bestDistance = distance;
}
}
Logger.info("Rejecting clear command " + clear
+ ": agent is not adjacent to a target: closest blockade is "
+ bestDistance);
return false;
}
private boolean isValid(AKClearArea clear) {
StandardEntity agent = model.getEntity(clear.getAgentID());
if (agent == null) {
Logger
.info("Rejecting clear command " + clear + ": agent does not exist");
return false;
} else if (!(agent instanceof PoliceForce)) {
Logger.info("Rejecting clear command " + clear
+ ": agent is not a police officer");
return false;
}
// Check PoliceForce
PoliceForce police = (PoliceForce) agent;
StandardEntity agentPosition = police.getPosition(model);
if (!(agentPosition instanceof Area)) {
Logger.info(
"Rejecting clear command " + clear + " : could not locate agent");
return false;
} else if (!police.isHPDefined() || police.getHP() <= 0) {
Logger.info("Rejecting clear command " + clear + " : agent is dead");
return false;
} else if (police.isBuriednessDefined() && police.getBuriedness() > 0) {
Logger.info("Rejecting clear command " + clear + " : agent is buried");
return false;
}
return true;
}
}
\ No newline at end of file
package clear;
import java.awt.Polygon;
import java.awt.geom.Area;
import java.awt.geom.PathIterator;
import java.util.ArrayList;
import java.util.List;
import rescuecore2.misc.geometry.Line2D;
import rescuecore2.misc.geometry.Vector2D;
import rescuecore2.standard.entities.Human;
public class Geometry {
public static Area getClearArea(Human agent, int targetX, int targetY,
int clearLength, int clearRad) {
Vector2D agentToTarget = new Vector2D(targetX - agent.getX(),
targetY - agent.getY());
if (agentToTarget.getLength() > clearLength)
agentToTarget = agentToTarget.normalised().scale(clearLength);
agentToTarget = agentToTarget.normalised()
.scale(agentToTarget.getLength() + 510);
Vector2D backAgent = (new Vector2D(agent.getX(), agent.getY()))
.add(agentToTarget.normalised().scale(-510));
Line2D line = new Line2D(backAgent.getX(), backAgent.getY(),
agentToTarget.getX(), agentToTarget.getY());
Vector2D dir = agentToTarget.normalised().scale(clearRad);
Vector2D perpend1 = new Vector2D(-dir.getY(), dir.getX());
Vector2D perpend2 = new Vector2D(dir.getY(), -dir.getX());
rescuecore2.misc.geometry.Point2D points[] = new rescuecore2.misc.geometry.Point2D[] {
line.getOrigin().plus(perpend1), line.getEndPoint().plus(perpend1),
line.getEndPoint().plus(perpend2), line.getOrigin().plus(perpend2)};
int[] xPoints = new int[points.length];
int[] yPoints = new int[points.length];
for (int i = 0; i < points.length; i++) {
xPoints[i] = (int) points[i].getX();
yPoints[i] = (int) points[i].getY();
}
return new Area(new Polygon(xPoints, yPoints, points.length));
}
public static double surface(Area area) {
PathIterator iter = area.getPathIterator(null);
double sum_all = 0;
while (!iter.isDone()) {
List<double[]> points = new ArrayList<double[]>();
while (!iter.isDone()) {
double point[] = new double[2];
int type = iter.currentSegment(point);
iter.next();
if (type == PathIterator.SEG_CLOSE) {
if (points.size() > 0)
points.add(points.get(0));
break;
}
points.add(point);
}
double sum = 0;
for (int i = 0; i < points.size() - 1; i++)
sum += points.get(i)[0] * points.get(i + 1)[1]
- points.get(i)[1] * points.get(i + 1)[0];
sum_all += Math.abs(sum) / 2;
}
return sum_all;
}
public static List<int[]> getAreas(Area area) {
PathIterator iter = area.getPathIterator(null);
List<int[]> areas = new ArrayList<int[]>();
ArrayList<Integer> list = new ArrayList<Integer>();
while (!iter.isDone()) {
double point[] = new double[2]; // x, y
int type = iter.currentSegment(point);
if (type == PathIterator.SEG_CLOSE) {
if (list.size() > 0) {
int[] newArea = new int[list.size()];
for (int i = 0; i < list.size(); i++)
newArea[i] = list.get(i);
areas.add(newArea);
list = new ArrayList<Integer>();
}
} else {
list.add((int) point[0]);
list.add((int) point[1]);
}
iter.next();
}
return areas;
}
}
\ No newline at end of file
package collapse;
import rescuecore2.standard.entities.Building;
/**
* Collapse Simulator Building (CSBuilding) is a wrapper for the Standard
* Building class that contains extra variables created, updated and used by the
* Collapse Simulator only. This class is created in order to prevented
* unnecessary changes to the Standard Building class.
*
* @author Salim
*
*/
public class CSBuilding {
/**
* The reference to the real building class
*/
private final Building real;
/**
* Collapse Ratio shows the percent that the building has been collapsed so
* far.
*/
private float collapsedRatio = 0;
/**
* This shows whether the building has fire damage in the last cycle or not
*/
private boolean hasFireDamage = false;
public CSBuilding(Building building) {
real = building;
}
/**
* Returns the building's collapse ratio
*
* @return
*/
public float getCollapsedRatio() {
return collapsedRatio;
}
/**
* Changes the collapse ratio of the building to the input ratio
*
* @param collapsedRatio
* is a float
*/
public void setCollapsedRatio(float collapsedRatio) {
this.collapsedRatio = collapsedRatio;
}
/**
* Adds the input ratio to the building's collapse ratio
*
* @param ratio
* is a float that represents the increased value of the collapse
* ratio
*/
public void increaseCollapseRatio(float ratio) {
setCollapsedRatio(getCollapsedRatio() + ratio);
}
public Building getReal() {
return real;
}
/**
* Returns the extent that is still possible to collapse.
*
* @return a float representing the extent
*/
public double getRemainingToCollapse(double floorHeight) {
return floorHeight * real.getFloors() * (1 - getCollapsedRatio());
}
public boolean hasFireDamage() {
return false;
}
public void setHasFireDamage(boolean hasFireDamage) {
this.hasFireDamage = hasFireDamage;
}
public double getTotalCollapse(double floorHeight){
return floorHeight*real.getFloors();
}
}
This diff is collapsed.
package collapse;
import javax.swing.JPanel;
import javax.swing.JProgressBar;
import javax.swing.JLabel;
import javax.swing.SwingUtilities;
import java.awt.GridLayout;
/**
GUI for the collapse simulator.
*/
public class CollapseSimulatorGUI extends JPanel {
private JLabel timeLabel;
private JLabel statusLabel;
private JProgressBar collapseProgress;
private JProgressBar fireProgress;
private JProgressBar blockadeProgress;
private int collapse;
private int fire;
private int block;
/**
Construct a collapse simulator GUI.
*/
public CollapseSimulatorGUI() {
super(new GridLayout(0, 2));
timeLabel = new JLabel("Not started");
statusLabel = new JLabel("Not started");
collapseProgress = new JProgressBar(0, 1);
fireProgress = new JProgressBar(0, 1);
blockadeProgress = new JProgressBar(0, 1);
collapseProgress.setStringPainted(true);
fireProgress.setStringPainted(true);
blockadeProgress.setStringPainted(true);
add(new JLabel("Timestep"));
add(timeLabel);
add(new JLabel("Status"));
add(statusLabel);
add(new JLabel("Collapsing buildings"));
add(collapseProgress);
add(new JLabel("Fire damage"));
add(fireProgress);
add(new JLabel("Creating blockades"));
add(blockadeProgress);
}
/**
Notify the gui that a new timestep has started.
@param time The timestep.
*/
void timestep(final int time) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
timeLabel.setText(String.valueOf(time));
collapseProgress.setValue(0);
fireProgress.setValue(0);
blockadeProgress.setValue(0);
collapse = 0;
fire = 0;
block = 0;
}
});
}
/**
Notify the gui that collapse computation has begun.
@param buildingCount The number of buildings to process.
*/
void startCollapse(final int buildingCount) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
statusLabel.setText("Collapsing buildings");
collapseProgress.setMaximum(buildingCount);
collapseProgress.setValue(0);
collapse = 0;
}
});
}
/**
Notify the gui that a building collapse has been processed.
*/
void bumpCollapse() {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
collapseProgress.setValue(++collapse);
}
});
}
/**
Notify the gui that building collapse computation is complete.
*/
void endCollapse() {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
collapseProgress.setValue(collapseProgress.getMaximum());
}
});
}
/**
Notify the gui that fire collapse computation has begun.
@param buildingCount The number of buildings to process.
*/
void startFire(final int buildingCount) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
statusLabel.setText("Fire damage");
fireProgress.setMaximum(buildingCount);
fireProgress.setValue(0);
fire = 0;
}
});
}
/**
Notify the gui that a fire collapse has been processed.
*/
void bumpFire() {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
fireProgress.setValue(++fire);
}
});
}
/**
Notify the gui that fire collapse computation is complete.
*/
void endFire() {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
fireProgress.setValue(fireProgress.getMaximum());
}
});
}
/**
Notify the gui that blockade generation has begun.
@param buildingCount The number of buildings to process.
*/
void startBlock(final int buildingCount) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
statusLabel.setText("Computing blockades");
if (buildingCount == 0) {
blockadeProgress.setMaximum(1);
blockadeProgress.setValue(1);
}
else {
blockadeProgress.setMaximum(buildingCount);
blockadeProgress.setValue(0);
block = 0;
}
}
});
}
/**
Notify the gui that blockade generation for a building has been processed.
*/
void bumpBlock() {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
blockadeProgress.setValue(++block);
}
});
}
/**
Notify the gui that blockade generation is complete.
*/
void endBlock() {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
blockadeProgress.setValue(blockadeProgress.getMaximum());
statusLabel.setText("Done");
}
});
}
}
\ No newline at end of file
package collapse;
import java.util.HashMap;
import rescuecore2.messages.control.KSAfterShocksInfo;
import rescuecore2.standard.entities.Building;
import rescuecore2.standard.entities.StandardEntity;
import rescuecore2.standard.entities.StandardEntityURN;
import rescuecore2.standard.entities.StandardWorldModel;
import rescuecore2.worldmodel.ChangeSet;
import rescuecore2.worldmodel.EntityID;
/**
*
* Collapse simulator's world model contains aftershocks' information that other
* simulators don't need.
*
* @author Salim
*
*/
public class CollapseWorldModel extends StandardWorldModel {
private HashMap<Integer, Float> aftershocks;
private HashMap<Building, CSBuilding> collapseBuildings;
public CollapseWorldModel() {
this.aftershocks = new HashMap<Integer, Float>();
collapseBuildings = new HashMap<Building, CSBuilding>();
}
@Override
public void merge(ChangeSet changes) {
super.merge(changes);
}
/**
* Changes the list in the world model with the new input aftershock list
*
* @param msg
* instance of KSAfterShocksInfo
*/
public void updateAftershocks(KSAfterShocksInfo msg) {
aftershocks = msg.getAftershocks();
}
public boolean aftershockHappens(int time) {
return aftershocks.get(time) != null;
}
public float aftershockIntensity(int time) {
return aftershocks.get(time);
}
public HashMap<Building, CSBuilding> getCollapseBuildings() {
if (collapseBuildings.size() == 0)
createCollapseBuildings();
return collapseBuildings;
}
/**
* Creates Collapse Simulator Buildings using the Standard Buildings
*/
private void createCollapseBuildings() {
for (StandardEntity entity : this) {
if(entity instanceof Building)
collapseBuildings.put((Building) entity, new CSBuilding((Building) entity));
}
}
/**
* Returns a specific CSBuilding by its EntityID
*
* @param id
* is an EntityID
* @return the corresponding CSBuilding to id
*/
public CSBuilding getCSBuiding(EntityID id) {
return getCollapseBuildings().get((Building) getEntity(id));
}
/**
* Returns a specific CSBuilding by its Building
*
* @param building
* is an Building
* @return the corresponding CSBuilding to building
*/
public CSBuilding getCSBuiding(Building building) {
return getCollapseBuildings().get(building);
}
}
package gis2;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import org.apache.log4j.Logger;
import rescuecore2.Constants;
import rescuecore2.config.Config;
import rescuecore2.connection.Connection;
import rescuecore2.connection.ConnectionException;
import rescuecore2.connection.ConnectionListener;
import rescuecore2.connection.TCPConnection;
import rescuecore2.messages.Message;
import rescuecore2.messages.control.GKConnectOK;
import rescuecore2.messages.control.KGConnect;
import rescuecore2.messages.control.Shutdown;
import rescuecore2.misc.CommandLineOptions;
import rescuecore2.misc.java.LoadableTypeProcessor;
import rescuecore2.registry.Registry;
import rescuecore2.worldmodel.Entity;
import rescuecore2.worldmodel.WorldModel;
/**
* This class is used for starting a remote GIS server.
*/
public final class GISServer {
private static final long WAIT_TIME = 1000;
private ServerSocket server;
private WorldModel<? extends Entity> world;
private volatile boolean running;
private static final Logger LOG = Logger.getLogger(GISServer.class);
private GISServer(int port, WorldModel<? extends Entity> world) throws IOException {
server = new ServerSocket(port);
this.world = world;
running = true;
}
/**
* Start the GIS server.
*
* @param args Command line arguments: <-c config file>
*/
public static void main(String[] args) {
Config config = new Config();
try {
CommandLineOptions.processArgs(args, config);
int port = config.getIntValue(Constants.GIS_PORT_NUMBER_KEY, Constants.DEFAULT_GIS_PORT_NUMBER);
processJarFiles(config);
GMLWorldModelCreator creator = new GMLWorldModelCreator();
new GISServer(port, creator.buildWorldModel(config)).run();
LOG.info("GIS server listening on port " + port);
} catch (Exception e) {
LOG.fatal("Error starting GIS server", e);
}
}
private static void processJarFiles(Config config) throws IOException {
LoadableTypeProcessor processor = new LoadableTypeProcessor(config);
processor.addFactoryRegisterCallbacks(Registry.SYSTEM_REGISTRY);
processor.process();
}
/**
* Run the GIS server.
*/
public void run() {
while (running) {
try {
Socket socket = server.accept();
new ServerThread(socket).start();
} catch (IOException e) {
LOG.error("Error accepting connection", e);
running = false;
}
}
}
private class ServerThread extends Thread implements ConnectionListener {
private Socket socket;
private boolean dead;
public ServerThread(Socket socket) {
this.socket = socket;
dead = false;
}
@Override
public void run() {
TCPConnection c = null;
try {
c = new TCPConnection(socket);
} catch (IOException e) {
LOG.error("Error starting TCPConnection", e);
return;
}
c.startup();
c.addConnectionListener(this);
synchronized (this) {
while (!dead) {
try {
this.wait(WAIT_TIME);
} catch (InterruptedException e) {
dead = true;
}
}
}
c.shutdown();
}
@Override
public void messageReceived(Connection c, Message msg) {
if (msg instanceof KGConnect) {
// Send a GKConnectOK
try {
c.sendMessage(new GKConnectOK(world.getAllEntities()));
} catch (ConnectionException e) {
LOG.fatal("Error sending message", e);
die();
}
}
if (msg instanceof Shutdown) {
die();
}
}
private void die() {
synchronized (this) {
dead = true;
notifyAll();
}
running = false;
}
}
}
\ No newline at end of file
package gis2;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
import kernel.KernelException;
import kernel.WorldModelCreator;
import maps.CoordinateConversion;
import maps.MapException;
import maps.MapReader;
import maps.ScaleConversion;
import maps.gml.GMLBuilding;
import maps.gml.GMLCoordinates;
import maps.gml.GMLDirectedEdge;
import maps.gml.GMLMap;
import maps.gml.GMLRoad;
import maps.gml.GMLShape;
import org.apache.log4j.Logger;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.io.SAXReader;
import rescuecore2.config.Config;
import rescuecore2.misc.geometry.GeometryTools2D;
import rescuecore2.misc.geometry.Point2D;
import rescuecore2.scenario.exceptions.ScenarioException;
import rescuecore2.standard.entities.Building;
import rescuecore2.standard.entities.Edge;
import rescuecore2.standard.entities.Road;
import rescuecore2.standard.entities.StandardWorldModel;
import rescuecore2.worldmodel.Entity;
import rescuecore2.worldmodel.EntityID;
import rescuecore2.worldmodel.WorldModel;
/**
* 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 String MAX_FLOOR = "gis.map.max-floor";
private static final String FLOOR_PLACEMENT_TYPE = "gis.map.floor-placement.random";
private static final String RANDOM_FLOOR_RATE = "gis.map.floor-placement.random.floor-rate.";
private static final String BUILDING_CODE_PLACEMENT_TYPE = "gis.map.building-code-placement.random";
private static final String RANDOM_BUILDING_CODE_RATE = "gis.map.building-code-placement.random.code-rate.";
private static final String MAX_BUILDING_CODE = "gis.map.max-building-code";
private static final double SQ_MM_TO_SQ_M = 0.000001;
private GisScenario scenario;
private static final Logger LOG = Logger
.getLogger(GMLWorldModelCreator.class);
// 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, config);
readScenarioAndApply(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,
Config config) throws MapException {
int maxFloor = config.getIntValue(MAX_FLOOR, 3);
boolean randomfloorPlacement = config.getBooleanValue(FLOOR_PLACEMENT_TYPE,
false);
int[] floorRates = null;
int[] floorRatesCumulative = null;
if (randomfloorPlacement) {
floorRates = new int[maxFloor + 1];
floorRatesCumulative = new int[maxFloor + 1];
for (int i = 1; i <= maxFloor; i++) {
floorRates[i] = config.getIntValue(RANDOM_FLOOR_RATE + i);
floorRatesCumulative[i] = floorRatesCumulative[i - 1] + floorRates[i];
}
}
int maxBuildingCode = config.getIntValue(MAX_BUILDING_CODE, 2);
boolean randomBuildingCodePlacement = config
.getBooleanValue(BUILDING_CODE_PLACEMENT_TYPE, false);
int[] buildingCodeRates = null;
int[] buildingCodesCumulative = null;
if (randomBuildingCodePlacement) {
buildingCodeRates = new int[maxBuildingCode + 1];
buildingCodesCumulative = new int[maxBuildingCode + 1];
for (int i = 0; i <= maxBuildingCode; i++) {
buildingCodeRates[i] = config
.getIntValue(RANDOM_BUILDING_CODE_RATE + i);
buildingCodesCumulative[i] = (i > 0 ? buildingCodesCumulative[i - 1]
: 0) + buildingCodeRates[i];
}
}
GMLMap map = (GMLMap) MapReader.readMap(mapFile);
CoordinateConversion conversion = getCoordinateConversion(map);
LOG.debug("Creating entities");
LOG.debug(map.getBuildings().size() + " buildings");
LOG.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);
// Building properties
int floors = Math.min(maxFloor, next.getFloors());
if (randomfloorPlacement) {
int rnd = config.getRandom().nextInt(floorRatesCumulative[maxFloor])
+ 1;
for (int i = 1; i <= maxFloor; i++) {
if (rnd <= floorRatesCumulative[i]) {
floors = i;
break;
}
}
}
int code = Math.min(maxBuildingCode, next.getCode());
if (randomBuildingCodePlacement) {
int rnd = config.getRandom()
.nextInt(buildingCodesCumulative[maxBuildingCode]) + 1;
for (int i = 0; i <= maxBuildingCode; i++) {
if (rnd <= buildingCodesCumulative[i]) {
code = i;
break;
}
}
}
b.setFloors(floors);
b.setFieryness(0);
b.setBrokenness(0);
b.setBuildingCode(code);
b.setBuildingAttributes(0);
b.setGroundArea((int) Math.abs(area));
b.setTotalArea(((int) Math.abs(area)) * b.getFloors());
b.setImportance(next.getImportance());
b.setCapacity(0);
// Area properties
b.setEdges(createEdges(next, conversion));
b.setX((int) centroid.getX());
b.setY((int) centroid.getY());
result.addEntity(b);
}
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);
// Road properties: None
// Area properties
r.setX((int) centroid.getX());
r.setY((int) centroid.getY());
r.setEdges(createEdges(next, conversion));
result.addEntity(r);
}
}
private void readScenarioAndApply(File scenarioFile,
StandardWorldModel result, Config config)
throws DocumentException, ScenarioException {
if (scenarioFile.exists()) {
readScenario(scenarioFile, config);
LOG.debug("Applying scenario");
scenario.apply(result, config);
}
}
private void readScenario(File scenarioFile, Config config)
throws DocumentException, ScenarioException {
if (scenarioFile.exists()) {
SAXReader reader = new SAXReader();
LOG.debug("Reading scenario");
Document doc = reader.read(scenarioFile);
scenario = new GisScenario(doc, config);
}
}
private List<Edge> createEdges(GMLShape s, CoordinateConversion conversion) {
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);
double sx = conversion.convertX(start.getX());
double sy = conversion.convertY(start.getY());
double ex = conversion.convertX(end.getX());
double ey = conversion.convertY(end.getY());
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);
}
public GisScenario getScenario(Config config) throws DocumentException {
if (scenario == null) {
File dir = new File(config.getValue(MAP_DIRECTORY_KEY));
File scenarioFile = new File(dir,
config.getValue(SCENARIO_FILE_KEY, DEFAULT_SCENARIO_FILE));
try {
readScenario(scenarioFile, config);
} catch (ScenarioException e) {
e.printStackTrace();
}
}
return scenario;
}
}
\ No newline at end of file
This diff is collapsed.
package gis2;
/**
* Exception class for problems with scenarios.
*/
public class ScenarioException extends Exception {
/**
* Construct a scenario exception with no information.
*/
public ScenarioException() {
super();
}
/**
* Construct a scenario exception with an error message.
*
* @param msg The error message.
*/
public ScenarioException(String msg) {
super(msg);
}
/**
* Construct a scenario exception that was caused by another exception.
*
* @param cause The cause of this exception.
*/
public ScenarioException(Throwable cause) {
super(cause);
}
/**
* Construct a scenario exception with an error message and an underlying cause.
*
* @param msg The error message.
* @param cause The cause of this exception.
*/
public ScenarioException(String msg, Throwable cause) {
super(msg, cause);
}
}
\ No newline at end of file
package gis2.scenario;
/**
* Abstract base class for scenario editing functions.
*/
public abstract class AbstractFunction implements Function {
/** The editor instance. */
protected ScenarioEditor editor;
/**
* Construct an AbstractFunction.
*
* @param editor The editor instance.
*/
protected AbstractFunction(ScenarioEditor editor) {
this.editor = editor;
}
}
\ No newline at end of file
package gis2.scenario;
/**
* Abstract base class for scenario editing tools.
*/
public abstract class AbstractTool implements Tool {
/** The scenario editor instance. */
protected ScenarioEditor editor;
/**
* Construct an AbstractTool.
*
* @param editor The scenario editor instance.
*/
protected AbstractTool(ScenarioEditor editor) {
this.editor = editor;
}
}
\ No newline at end of file
package gis2.scenario;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics2D;
import java.awt.Shape;
import java.awt.geom.Ellipse2D;
import java.util.Map;
import maps.gml.GMLShape;
import maps.gml.view.Overlay;
import rescuecore2.misc.collections.LazyMap;
import rescuecore2.misc.gui.ScreenTransform;
/**
* Overlay for viewing agents in a scenario.
*/
public class AgentOverlay implements Overlay {
private static final int SIZE = 11;
private static final Color CIVILIAN_COLOUR = Color.GREEN;
private static final Color FIRE_BRIGADE_COLOUR = Color.RED;
private static final Color POLICE_FORCE_COLOUR = Color.BLUE;
private static final Color AMBULANCE_TEAM_COLOUR = Color.WHITE;
private static final int OFFSET = 7;
private ScenarioEditor editor;
/**
* Construct an AgentOverlay.
*
* @param editor The scenario editor.
*/
public AgentOverlay(ScenarioEditor editor) {
this.editor = editor;
}
@Override
public void render(Graphics2D g, ScreenTransform transform) {
// Count agents in each location
g.setFont(new Font(g.getFont().getName(), Font.BOLD, g.getFont().getSize()));
Map<Integer, Integer> civs = new LazyMap<Integer, Integer>() {
@Override
public Integer createValue() {
return 0;
}
};
Map<Integer, Integer> fbs = new LazyMap<Integer, Integer>() {
@Override
public Integer createValue() {
return 0;
}
};
Map<Integer, Integer> pfs = new LazyMap<Integer, Integer>() {
@Override
public Integer createValue() {
return 0;
}
};
Map<Integer, Integer> ats = new LazyMap<Integer, Integer>() {
@Override
public Integer createValue() {
return 0;
}
};
for (int next : editor.getScenario().getCivilians()) {
civs.put(next, civs.get(next) + 1);
}
for (int next : editor.getScenario().getFireBrigades()) {
fbs.put(next, fbs.get(next) + 1);
}
for (int next : editor.getScenario().getPoliceForces()) {
pfs.put(next, pfs.get(next) + 1);
}
for (int next : editor.getScenario().getAmbulanceTeams()) {
ats.put(next, ats.get(next) + 1);
}
// Now draw them
for (Map.Entry<Integer, Integer> next : civs.entrySet()) {
GMLShape shape = editor.getMap().getShape(next.getKey());
int count = next.getValue();
// int x = transform.xToScreen(shape.getCentreX());
// int y = transform.yToScreen(shape.getCentreY()) + CIV_OFFSET;
int x = transform.xToScreen(shape.getCentreX()) + OFFSET;
int y = transform.yToScreen(shape.getCentreY());
// g.drawString(count + " civs", x, y);
paint(g, x, y, CIVILIAN_COLOUR);
g.drawString(count + "", x, y);
}
for (Map.Entry<Integer, Integer> next : fbs.entrySet()) {
GMLShape shape = editor.getMap().getShape(next.getKey());
int count = next.getValue();
// int x = transform.xToScreen(shape.getCentreX());
// int y = transform.yToScreen(shape.getCentreY()) + FB_OFFSET;
int x = transform.xToScreen(shape.getCentreX());
int y = transform.yToScreen(shape.getCentreY()) - OFFSET;
// g.drawString(count + " fbs", x, y);
paint(g, x, y, FIRE_BRIGADE_COLOUR);
g.drawString(count + "", x, y);
}
for (Map.Entry<Integer, Integer> next : pfs.entrySet()) {
GMLShape shape = editor.getMap().getShape(next.getKey());
int count = next.getValue();
// int x = transform.xToScreen(shape.getCentreX());
// int y = transform.yToScreen(shape.getCentreY()) + PF_OFFSET;
int x = transform.xToScreen(shape.getCentreX());
int y = transform.yToScreen(shape.getCentreY()) + OFFSET;
// g.drawString(count + " pfs", x, y);
paint(g, x, y, POLICE_FORCE_COLOUR);
g.drawString(count + "", x, y);
}
for (Map.Entry<Integer, Integer> next : ats.entrySet()) {
GMLShape shape = editor.getMap().getShape(next.getKey());
int count = next.getValue();
// int x = transform.xToScreen(shape.getCentreX());
// int y = transform.yToScreen(shape.getCentreY()) + AT_OFFSET;
int x = transform.xToScreen(shape.getCentreX()) - OFFSET;
int y = transform.yToScreen(shape.getCentreY());
// g.drawString(count + " ats", x, y);
paint(g, x, y, AMBULANCE_TEAM_COLOUR);
g.drawString(count + "", x, y);
}
}
public void paint(Graphics2D g, int x, int y, Color color) {
Shape shape = new Ellipse2D.Double(x - SIZE / 4, y - SIZE, SIZE, SIZE);
g.setColor(color);
g.fill(shape);
g.draw(shape);
g.setColor(Color.black);
}
}
\ No newline at end of file
package gis2.scenario;
/**
* Exception for indicating the the user has cancelled an operation.
*/
public class CancelledByUserException extends Exception {
/**
* Constructor.
*/
public CancelledByUserException() {
}
}
\ No newline at end of file
package gis2.scenario;
import gis2.GisScenario;
import java.util.HashSet;
/**
* Function for removing all agents.
*/
public class ClearAgentsFunction extends AbstractFunction {
/**
* Construct a clear agents function.
*
* @param editor The editor instance.
*/
public ClearAgentsFunction(ScenarioEditor editor) {
super(editor);
}
@Override
public String getName() {
return "Remove agents";
}
@Override
public void execute() {
GisScenario s = editor.getScenario();
s.setFireBrigades(new HashSet<Integer>());
s.setFireStations(new HashSet<Integer>());
s.setPoliceForces(new HashSet<Integer>());
s.setPoliceOffices(new HashSet<Integer>());
s.setAmbulanceTeams(new HashSet<Integer>());
s.setAmbulanceCentres(new HashSet<Integer>());
editor.setChanged();
editor.updateOverlays();
}
}
\ No newline at end of file
package gis2.scenario;
import gis2.GisScenario;
import java.util.HashSet;
/**
* Function for removing all agents, fires, civilians and refuges.
*/
public class ClearAllFunction extends AbstractFunction {
/**
* Construct a clear all function.
*
* @param editor The editor instance.
*/
public ClearAllFunction(ScenarioEditor editor) {
super(editor);
}
@Override
public String getName() {
return "Remove all";
}
@Override
public void execute() {
GisScenario s = editor.getScenario();
s.setFireBrigades(new HashSet<Integer>());
s.setFireStations(new HashSet<Integer>());
s.setPoliceForces(new HashSet<Integer>());
s.setPoliceOffices(new HashSet<Integer>());
s.setAmbulanceTeams(new HashSet<Integer>());
s.setAmbulanceCentres(new HashSet<Integer>());
s.setCivilians(new HashSet<Integer>());
s.setFires(new HashSet<Integer>());
s.setRefuges(new HashSet<Integer>());
s.setGasStations(new HashSet<Integer>());
s.setHydrants(new HashSet<Integer>());
editor.setChanged();
editor.updateOverlays();
}
}
\ No newline at end of file
package gis2.scenario;
import gis2.GisScenario;
import java.util.HashSet;
/**
* Function for removing all fires.
*/
public class ClearFiresFunction extends AbstractFunction {
/**
* Construct a clear fires function.
*
* @param editor The editor instance.
*/
public ClearFiresFunction(ScenarioEditor editor) {
super(editor);
}
@Override
public String getName() {
return "Remove fires";
}
@Override
public void execute() {
GisScenario s = editor.getScenario();
s.setFires(new HashSet<Integer>());
editor.setChanged();
editor.updateOverlays();
}
}
\ No newline at end of file
package gis2.scenario;
/**
* Interface for a scenario editing function.
*/
public interface Function {
/**
* Get the name of this function.
*
* @return The name of the function.
*/
String getName();
/**
* Execute this function.
*/
void execute();
}
\ No newline at end of file
package gis2.scenario;
import java.awt.Component;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Insets;
/**
* A modified version of FlowLayout that allows containers using this Layout to
* behave in a reasonable manner when placed inside a JScrollPane
*
* @author Babu Kalakrishnan Modifications by greearb and jzd
*/
public class ModifiedFlowLayout extends FlowLayout {
public ModifiedFlowLayout() {
super(FlowLayout.LEFT);
}
public ModifiedFlowLayout(int align) {
super(align);
}
public ModifiedFlowLayout(int align, int hgap, int vgap) {
super(align, hgap, vgap);
}
public Dimension minimumLayoutSize(Container target) {
// Size of largest component, so we can resize it in
// either direction with something like a split-pane.
return computeMinSize(target);
}
public Dimension preferredLayoutSize(Container target) {
return computeSize(target);
}
private Dimension computeSize(Container target) {
synchronized (target.getTreeLock()) {
int hgap = getHgap();
int vgap = getVgap();
int w = target.getWidth();
// Let this behave like a regular FlowLayout (single row)
// if the container hasn't been assigned any size yet
if (w == 0) {
w = Integer.MAX_VALUE;
}
Insets insets = target.getInsets();
if (insets == null) {
insets = new Insets(0, 0, 0, 0);
}
int reqdWidth = 0;
int maxwidth = w - (insets.left + insets.right + hgap * 2);
int n = target.getComponentCount();
int x = 0;
int y = insets.top + vgap; // FlowLayout starts by adding vgap, so
// do that here too.
int rowHeight = 0;
for (int i = 0; i < n; i++) {
Component c = target.getComponent(i);
if (c.isVisible()) {
Dimension d = c.getPreferredSize();
if ((x == 0) || ((x + d.width) <= maxwidth)) {
// fits in current row.
if (x > 0) {
x += hgap;
}
x += d.width;
rowHeight = Math.max(rowHeight, d.height);
} else {
// Start of new row
x = d.width;
y += vgap + rowHeight;
rowHeight = d.height;
}
reqdWidth = Math.max(reqdWidth, x);
}
}
y += rowHeight;
y += insets.bottom;
return new Dimension(reqdWidth + insets.left + insets.right, y);
}
}
private Dimension computeMinSize(Container target) {
synchronized (target.getTreeLock()) {
int minx = Integer.MAX_VALUE;
int miny = Integer.MIN_VALUE;
boolean found_one = false;
int n = target.getComponentCount();
for (int i = 0; i < n; i++) {
Component c = target.getComponent(i);
if (c.isVisible()) {
found_one = true;
Dimension d = c.getPreferredSize();
minx = Math.min(minx, d.width);
miny = Math.min(miny, d.height);
}
}
if (found_one) {
return new Dimension(minx, miny);
}
return new Dimension(0, 0);
}
}
}
\ No newline at end of file
package gis2.scenario;
import gis2.GisScenario;
import java.awt.GridLayout;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import javax.swing.JCheckBox;
import javax.swing.JComboBox;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JTextField;
import maps.gml.GMLShape;
/**
* Function for placing agents.
*/
public class PlaceAgentsFunction extends AbstractFunction {
private static final int TYPE_FIRE = 0;
private static final int TYPE_POLICE = 1;
private static final int TYPE_AMBULANCE = 2;
private static final int TYPE_CIVILIAN = 3;
private Random random;
/**
* Construct a place agents function.
*
* @param editor The editor instance.
*/
public PlaceAgentsFunction(ScenarioEditor editor) {
super(editor);
random = new Random();
}
@Override
public String getName() {
return "Place agents";
}
@Override
public void execute() {
JPanel panel = new JPanel(new GridLayout(3, 2));
JTextField numberField = new JTextField("1");
JComboBox<String> typeCombo = new JComboBox<String>(new String[] { "Fire", "Police", "Ambulance", "Civilian" });
JCheckBox buildingBox = new JCheckBox("In buildings?", false);
JCheckBox roadBox = new JCheckBox("In Roads?", true);
JPanel jp = new JPanel();
jp.add(buildingBox);
jp.add(roadBox);
panel.add(new JLabel("Type"));
panel.add(typeCombo);
panel.add(new JLabel("Number"));
panel.add(numberField);
panel.add(jp);
List<Integer> ids = new ArrayList<Integer>();
int type = -1;
List<GMLShape> all = new ArrayList<GMLShape>();
if (JOptionPane.showConfirmDialog(null, panel, "Add agents",
JOptionPane.OK_CANCEL_OPTION) == JOptionPane.OK_OPTION) {
try {
int number = Integer.parseInt(numberField.getText());
type = typeCombo.getSelectedIndex();
if (roadBox.isSelected())
all.addAll(editor.getMap().getRoads());
if (buildingBox.isSelected())
all.addAll(editor.getMap().getBuildings());
if (all.size() == 0) {
JOptionPane.showMessageDialog(null, "No Area to Place... Please choose In Road or Building...", "Error",
JOptionPane.ERROR_MESSAGE);
return;
}
for (int i = 0; i < number; ++i) {
ids.add(all.get(random.nextInt(all.size())).getID());
}
} catch (NumberFormatException e) {
e.printStackTrace();
}
}
GisScenario s = editor.getScenario();
switch (type) {
case TYPE_FIRE:
for (int id : ids) {
s.addFireBrigade(id);
}
break;
case TYPE_POLICE:
for (int id : ids) {
s.addPoliceForce(id);
}
break;
case TYPE_AMBULANCE:
for (int id : ids) {
s.addAmbulanceTeam(id);
}
break;
case TYPE_CIVILIAN:
for (int id : ids) {
s.addCivilian(id);
}
break;
default:
throw new IllegalArgumentException("Unexpected type: " + type);
}
editor.setChanged();
editor.updateOverlays();
}
}
\ No newline at end of file
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