/*
* 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: Agent.java,v 1.7 2010-08-25 20:06:51 mcoletti Exp $
*/
package sim.app.geo.networkworld;
import com.vividsolutions.jts.geom.*;
import com.vividsolutions.jts.linearref.LengthIndexedLine;
import com.vividsolutions.jts.planargraph.DirectedEdgeStar;
import com.vividsolutions.jts.planargraph.Node;
import sim.engine.SimState;
import sim.engine.Steppable;
import sim.util.geo.GeomPlanarGraphDirectedEdge;
import sim.util.geo.GeomPlanarGraphEdge;
import sim.util.geo.MasonGeometry;
import sim.util.geo.PointMoveTo;
/**
* A simple agent for the NetworkWorld GeoMASON example. The agent moves
* randomly along the network, choosing a random direction at each intersection.
*/
public class Agent implements Steppable
{
private static final long serialVersionUID = -7060584745540577823L;
// point that denotes agent's position
private Point location;
// How much to move the agent by in each step(); may become negative if
// agent is moving from the end to the start of current line.
private double moveRate = 0.01;
// Used by agent to walk along line segment; assigned in setNewRoute()
private LengthIndexedLine segment = null;
double startIndex = 0.0; // start position of current line
double endIndex = 0.0; // end position of current line
double currentIndex = 0.0; // current location along line
// used to update location
private PointMoveTo pointMoveTo = new PointMoveTo();
public Agent()
{
GeometryFactory fact = new GeometryFactory();
location = fact.createPoint(new Coordinate(10, 10)); // magic numbers
}
// return geometry representing agent location
public Geometry getGeometry()
{
return location;
}
// true if the agent has arrived at the target intersection
private boolean arrived()
{
// If we have a negative move rate the agent is moving from the end to
// the start, else the agent is moving in the opposite direction.
if ((moveRate > 0 && currentIndex >= endIndex)
|| (moveRate < 0 && currentIndex <= startIndex))
{
return true;
}
return false;
}
public void start(NetworkWorld state)
{
// Find the first line segment and set our position over the start coordinate.
MasonGeometry line = (MasonGeometry) state.world.getGeometries().objs[0];
setNewRoute((LineString) line.geometry, true);
}
// randomly selects an adjacent route to traverse
private void findNewPath(NetworkWorld NetworkWorld)
{
// find all the adjacent junctions
Node currentJunction = NetworkWorld.network.findNode(location.getCoordinate());
if (currentJunction != null)
{
DirectedEdgeStar directedEdgeStar = currentJunction.getOutEdges();
Object[] edges = directedEdgeStar.getEdges().toArray();
if (edges.length > 0)
{
// pick one randomly
int i = NetworkWorld.random.nextInt(edges.length);
GeomPlanarGraphDirectedEdge directedEdge = (GeomPlanarGraphDirectedEdge) edges[i];
GeomPlanarGraphEdge edge = (GeomPlanarGraphEdge) directedEdge.getEdge();
// and start moving along it
LineString newRoute = edge.getLine();
Point startPoint = newRoute.getStartPoint();
Point endPoint = newRoute.getEndPoint();
if (startPoint.equals(location))
{
setNewRoute(newRoute, true);
} else
{
if (endPoint.equals(location))
{
setNewRoute(newRoute, false);
} else // some how the agent is neither at the beginning or
{ // the end of the selected line segment
System.err.println("Where the hell am I?");
}
}
}
} else
{
System.err.println("Cannot find node nearest to " + location);
}
}
/**
* have the agent move along new route
*
* @param line defining new route
* @param start true if agent at start of line else agent placed at end
*/
private void setNewRoute(LineString line, boolean start)
{
segment = new LengthIndexedLine(line);
startIndex = segment.getStartIndex();
endIndex = segment.getEndIndex();
Coordinate startCoord = null;
if (start)
{
startCoord = segment.extractPoint(startIndex);
currentIndex = startIndex;
moveRate = Math.abs(moveRate); // ensure we move forward along segment
} // by using a positive value
else
{
startCoord = segment.extractPoint(endIndex);
currentIndex = endIndex;
moveRate = -Math.abs(moveRate); // ensure we move backward along segment
} // by using a negative value
moveTo(startCoord);
}
// move the agent to the given coordinates
public void moveTo(Coordinate c)
{
pointMoveTo.setCoordinate(c);
location.apply(pointMoveTo);
}
public void step(SimState state)
{
// if we're not at a junction move along the current segment
if (!arrived())
{
moveAlongPath((NetworkWorld) state);
} else
{
findNewPath((NetworkWorld) state);
}
}
/**
* Ensure the current position in clipped to the line
*
* @param currentIndex that's guaranteed to be on the current line
*/
private double clipCurrentIndex(double currentIndex)
{
// If move rate is positive ensure we're not off the end of the line.
if (moveRate > 0)
{
return Math.min(currentIndex, endIndex);
} else // else we're moving backwards from the other end, so ensure
{ // we're not going to fall off the front
return Math.max(currentIndex, startIndex);
}
}
// move agent along current line segment
private void moveAlongPath(NetworkWorld world)
{
currentIndex += moveRate;
currentIndex = clipCurrentIndex(currentIndex);
Coordinate currentPos = segment.extractPoint(currentIndex);
moveTo(currentPos);
world.agents.clear();
world.agents.addGeometry(new MasonGeometry(this.location));
}
}