/*
* 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.nearbyworld;
import com.vividsolutions.jts.geom.*;
import com.vividsolutions.jts.util.GeometricShapeFactory;
import sim.engine.SimState;
import sim.field.geo.GeomVectorField;
import sim.util.geo.MasonGeometry;
/**
* The NearbyWorld GeoMASON example show how to add Geometries to a field, and also how to query
* the field for the closest objects. In this simulation, we create severals points, two lines, and
* a polygon. An agent then randomly wanders around, reporting the closest objects.
*
* <p> The agent wanders in a GeomVectorField so that we can use the spatial indexing feature to
* determine the closest objects.
*/
public class NearbyWorld extends SimState
{
private static final long serialVersionUID = 752764560336956655L;
// Contains the objects in which the agent will be wandering
public GeomVectorField objects = new GeomVectorField(WIDTH, HEIGHT);
// Field for just the agent
public GeomVectorField agentField = new GeomVectorField(WIDTH, HEIGHT);
// Field that's used to highlight nearby objects
public GeomVectorField nearbyField = new GeomVectorField(WIDTH, HEIGHT);
// Agent that moves around the objects
Agent agent;
// size of the display
public static final int WIDTH = 300;
public static final int HEIGHT = 300;
private static final int NUM_POINTS = 40;
private static final int NUM_RECTANGLES = 35;
public static final int NUM_LINES = 35;
/** Average number of line segments in randomly generated lines
*/
private static final int NUM_LINE_SEGMENTS = 6;
public NearbyWorld(long seed)
{
super(seed);
createWorld();
}
/** set up the static geometry in the objects
*
*/
private void createWorld()
{
for (int i = 0; i < NUM_LINES; i++)
{
addRandomLine(WIDTH, HEIGHT);
}
for (int i = 0; i < NUM_RECTANGLES; i++)
{
addRandomRectangle(WIDTH, HEIGHT);
}
for (int i = 0; i < NUM_POINTS; i++)
{
addRandomPoint(WIDTH, HEIGHT);
}
agentField.setMBR(objects.getMBR());
nearbyField.setMBR(objects.getMBR());
}
@Override
public void start()
{
super.start();
// position the agent at a random starting location
agent = new Agent(random.nextInt(WIDTH), random.nextInt(HEIGHT));
// Add the agent
agentField.addGeometry(agent.getGeometry());
schedule.scheduleRepeating(agent);
schedule.scheduleRepeating(agentField.scheduleSpatialIndexUpdater(), 1, 1.0);
}
/** Used to create JTS geometries
*
* @see addRandomPoint
* @see addRandomRectangle
* @see addRandomLine
*/
private GeometryFactory geometryFactory = new GeometryFactory();
/** Add a random point to the objects layer
*
* @param width of the MBR
* @param height of the MBR
*/
private void addRandomPoint(final int width, final int height)
{
Point location = geometryFactory.createPoint(new Coordinate(random.nextInt(width), random.nextInt(height)));
objects.addGeometry(new MasonGeometry(location));
}
/** Add a rectangle to within the given dimensions
*
* @param width of the MBR
* @param height of the MBR
*/
private void addRandomRectangle(final int width, final int height)
{
GeometricShapeFactory factory = new GeometricShapeFactory();
// Randomly establish the lower left corner of the rectangle while
// ensuring that the upper right corner doesn't go outside the area.
Coordinate lowerLeft = new Coordinate(random.nextDouble() * (width - 5),
random.nextDouble() * (height - 5));
factory.setBase(lowerLeft);
factory.setWidth(random.nextDouble() * 15);
factory.setHeight(random.nextDouble() * 15);
Polygon rectangle = factory.createRectangle();
objects.addGeometry(new MasonGeometry(rectangle));
}
/** Add a line to within the given dimensions
*
* @param width of the MBR
* @param height of the MBR
*/
private void addRandomLine(final int width, final int height)
{
// We may have up to five line segments
int numSegments = random.nextInt(NUM_LINE_SEGMENTS - 1) + 2;
Coordinate coordinates[] = new Coordinate[numSegments];
// Pick location of line start
coordinates[0] = new Coordinate();
coordinates[0].x = random.nextDouble() * WIDTH;
coordinates[0].y = random.nextDouble() * HEIGHT;
for (int i = 1; i < coordinates.length; i++)
{
// regenerate points until we get a point that's inside the boundary
do
{
int goLeftOrRight = random.nextBoolean() ? -1 : 1;
int goUpOrDown = random.nextBoolean() ? -1 : 1;
coordinates[i] = new Coordinate();
coordinates[i].x = coordinates[i - 1].x + random.nextDouble() * 10 * goLeftOrRight;
coordinates[i].y = coordinates[i - 1].y + random.nextDouble() * 10 * goUpOrDown;
} while (coordinates[i].x > WIDTH - 1 || coordinates[i].y > HEIGHT - 1 ||
coordinates[i].x < 0.0 || coordinates[i].y < 0.0);
}
LineString line = null;
try
{
line = geometryFactory.createLineString(coordinates);
} catch (Exception e)
{
System.err.println(e);
}
objects.addGeometry(new MasonGeometry(line));
}
public static void main(String[] args)
{
doLoop(NearbyWorld.class, args);
System.exit(0);
}
}