/* * Copyright 2011 by Mark Coletti, Keith Sullivan, Sean Luke, and * George Mason University Mason University Licensed under the Academic * Free License version 3.0 * * See the file "LICENSE" for more information * * $Id$ */ package sim.app.geo.colorworld; import java.io.FileNotFoundException; import java.net.URL; import java.util.logging.Level; import java.util.logging.Logger; import sim.engine.SimState; import sim.field.geo.GeomVectorField; import sim.io.geo.ShapeFileImporter; import sim.util.Bag; import sim.util.geo.MasonGeometry; /** * The ColorWorld example shows how to change the portrayal of individual geometries based on * simulation information. To do this, we create our own portrayal and MasonGeometry. The portrayal * accesses the simulation core via the extended MasonGeometry class. * * This simulation has agents wandering randomly around Fairfax County, VA, voting districts. There are * 12 districts total. The color of the district changes shade based on the number of agents currently * inside the district. If no agents are inside the district, then the district is not shown (actually, its * drawn as white, on a white background). * * There are two special things about this simulation: First, we subclass MasonGeometry to count the * number of agents inside each district, and use this subclass as a replacement for the standard MasonGeometry. The * replacement *MUST* be done prior to ingesting the files to ensure that the GeomField uses our subclass rather than * the standard MasonGeometry. Second, we use the global Union of the voting districts to determine if the agents are * wandering out of the county. Doing this instead of looping through all the districts provides at least an order of * magnitude speedup. We also compute the ConvexHull, mainly to show how its done. * */ public class ColorWorld extends SimState { private static final long serialVersionUID = -2568637684893865458L; public static final int WIDTH = 300; public static final int HEIGHT = 300; // number of agents in the simulation public static int NUM_AGENTS = 20; // where all the county geometry lives public GeomVectorField county = new GeomVectorField(WIDTH, HEIGHT); // where all the agents live. We use a GeomVectorField since we want to determine how // many agents are inside each district. The most efficient way to do this is via // the GeomVectorField's spatial indexing. public static GeomVectorField agents = new GeomVectorField(WIDTH, HEIGHT); // getters and setters for inspectors public int getNumAgents() { return NUM_AGENTS; } public void setNumAgents(int a) { if (a > 0) NUM_AGENTS = a; } public ColorWorld(long seed) { super(seed); // this line allows us to replace the standard MasonGeometry with our // own subclass of MasonGeometry; see CountingGeomWrapper.java for more info. // Note: this line MUST occur prior to ingesting the data URL politicalBoundaries = ColorWorld.class.getResource("data/pol.shp"); Bag empty = new Bag(); try { ShapeFileImporter.read(politicalBoundaries, county, empty, CountingGeomWrapper.class); } catch (Exception ex) { Logger.getLogger(ColorWorld.class.getName()).log(Level.SEVERE, null, ex); } // we use either the ConvexHull or Union to determine if the agents are within // Fairfax county or not county.computeConvexHull(); county.computeUnion(); } private void addAgents() { //Agent a = null; for (int i = 0; i < NUM_AGENTS; i++) { // pick a random political region to plop the agent in Bag allRegions = county.getGeometries(); if (allRegions.isEmpty()) { // Something went wrong. We *should* have regions. throw new RuntimeException("No regions found."); } MasonGeometry region = ((MasonGeometry)allRegions.objs[random.nextInt(allRegions.numObjs)]); // give each agent a random direction to initially move in Agent a = new Agent(random.nextInt(8)); // set each agent in the center of corresponding region a.setLocation(region.getGeometry().getCentroid()); // place the agents in the GeomVectorField agents.addGeometry(new MasonGeometry(a.getGeometry())); // add the new agent the schedule schedule.scheduleRepeating(a); } } @Override public void start() { super.start(); agents.clear(); // remove any agents from previous runs // add agents to the simulation addAgents(); // ensure both GeomFields Color same area agents.setMBR(county.getMBR()); } public static void main(String[] args) { doLoop(ColorWorld.class, args); System.exit(0); } }