/**
** PolySchellingWithUI.java
**
** Copyright 2011 by Sarah Wise, Mark Coletti, Andrew Crooks, and
** George Mason University.
**
** Licensed under the Academic Free License version 3.0
**
** See the file "LICENSE" for more information
**
** $Id$
**/
package sim.app.geo.schellingpolygon;
import java.awt.Color;
import java.awt.Graphics2D;
import javax.swing.JFrame;
import org.jfree.data.xy.XYSeries;
import sim.display.Console;
import sim.display.Controller;
import sim.display.Display2D;
import sim.display.GUIState;
import sim.engine.SimState;
import sim.engine.Steppable;
import sim.portrayal.DrawInfo2D;
import sim.portrayal.geo.GeomPortrayal;
import sim.portrayal.geo.GeomVectorFieldPortrayal;
import sim.util.media.chart.HistogramGenerator;
import sim.util.media.chart.TimeSeriesChartGenerator;
public class PolySchellingWithUI extends GUIState
{
Display2D display;
JFrame displayFrame;
// portrayal info
GeomVectorFieldPortrayal polyPortrayal = new GeomVectorFieldPortrayal();
// chart info
TimeSeriesChartGenerator happinessChart;
XYSeries happyReds;
XYSeries happyBlues;
// histogram info
HistogramGenerator numMovesHisto;
double[] peoplesMoves;
/** constructor function */
protected PolySchellingWithUI(SimState state)
{
super(state);
}
/** constructor function */
public PolySchellingWithUI()
{
super(new PolySchelling(System.currentTimeMillis()));
}
/** return the name of the simulation */
public static String getName()
{
return "PolySchelling";
}
/** initialize the simulation */
public void init(Controller controller)
{
super.init(controller);
display = new Display2D(800, 600, this);
display.attach(polyPortrayal, "Polys");
displayFrame = display.createFrame();
controller.registerFrame(displayFrame);
displayFrame.setVisible(true);
// the happiness chart setup
happinessChart = new TimeSeriesChartGenerator();
happinessChart.setTitle("Percent of Happy Persons in Simulation");
happinessChart.setRangeAxisLabel("Percent Happy");
happinessChart.setDomainAxisLabel("Opportunities to Move");
JFrame chartFrame = happinessChart.createFrame(this);
chartFrame.pack();
controller.registerFrame(chartFrame);
// the # moves histogram setup
numMovesHisto = new HistogramGenerator();
numMovesHisto.setTitle("Number of Moves People Have Made");
numMovesHisto.setDomainAxisLabel("Number of Moves");
numMovesHisto.setRangeAxisLabel("%");
JFrame histoFrame = numMovesHisto.createFrame(this);
histoFrame.pack();
controller.registerFrame(histoFrame);
}
/** quit the simulation, cleaning up after itself*/
public void quit()
{
super.quit();
if (displayFrame != null)
{
displayFrame.dispose();
}
displayFrame = null;
display = null;
}
/** start the simulation, setting up the portrayals and charts for a new run */
public void start()
{
super.start();
setupPortrayals();
}
/**
* Sets up the portrayals and charts for the simulation
*/
private void setupPortrayals()
{
PolySchelling world = (PolySchelling) state;
// reset the chart info
happyReds = new XYSeries("Happy Reds");
happyBlues = new XYSeries("Happy Blues");
happinessChart.removeAllSeries();
happinessChart.addSeries(happyReds, null);
happinessChart.addSeries(happyBlues, null);
// schedule the chart to take data
state.schedule.scheduleRepeating(new HappyTracker());
// reset the histogram info
peoplesMoves = new double[((PolySchelling) state).people.size()];
numMovesHisto.removeAllSeries();
numMovesHisto.addSeries(peoplesMoves, 10, "HistoMoves", null);
// schedule the histogram to take data
state.schedule.scheduleRepeating(new MoveTracker());
// the polygon portrayal
polyPortrayal.setField(world.world);
polyPortrayal.setPortrayalForAll(new PolyPortrayal());
display.reset();
display.repaint();
}
/** Keeps track of the rates of happy Reds and happy Blues in the simulation */
class HappyTracker implements Steppable
{
public void step(SimState state)
{
PolySchelling ps = (PolySchelling) state;
double hReds = 0, hBlues = 0;
// query all Persons whether their position is acceptable
for (Person p : ps.people)
{
if (p.acceptable(p.region))
{
if (p.color.equals("RED"))
{
hReds++;
} else
{
hBlues++;
}
}
}
// add this data to the chart
happyReds.add(state.schedule.getTime() / ps.people.size(),
hReds / ps.totalReds, true);
happyBlues.add(state.schedule.getTime() / ps.people.size(),
hBlues / ps.totalBlues, true);
}
}
/** Keeps track of the number of moves agents have made */
class MoveTracker implements Steppable
{
public void step(SimState state)
{
PolySchelling ps = (PolySchelling) state;
int numPeople = ps.people.size();
peoplesMoves = new double[numPeople];
for (int i = 0; i < numPeople; i++)
{
Person p = ps.people.get(i);
peoplesMoves[i] = p.numMoves;
}
numMovesHisto.updateSeries(0, peoplesMoves);
}
}
public static void main(String[] args)
{
PolySchellingWithUI worldGUI = new PolySchellingWithUI();
Console console = new Console(worldGUI);
console.setVisible(true);
}
/** The portrayal used to display Polygons with the appropriate color */
class PolyPortrayal extends GeomPortrayal
{
private static final long serialVersionUID = 1L;
@Override
public void draw(Object object, Graphics2D graphics, DrawInfo2D info)
{
Polygon poly = (Polygon) object;
if (poly.residents.isEmpty())
{
paint = Color.gray;
} else if (poly.getSoc().equals("RED"))
{
paint = Color.red;
} else if (poly.getSoc().equals("BLUE"))
{
paint = Color.blue;
} else
{
paint = Color.gray;
}
super.draw(object, graphics, info);
}
}
}