-
Notifications
You must be signed in to change notification settings - Fork 0
/
AgentCopy.java
executable file
·344 lines (280 loc) · 10.3 KB
/
AgentCopy.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
/**
** Agent.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: Agent.java 842 2012-12-18 01:09:18Z mcoletti $
**
**/
package sim.app.geo.gridlock_norfolk_TEST;
import com.vividsolutions.jts.geom.*;
import com.vividsolutions.jts.linearref.LengthIndexedLine;
import com.vividsolutions.jts.planargraph.Node;
import java.util.ArrayList;
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;
/**
* Our simple agent for the CampusWorld GeoMASON example. The agent randomly wanders
* around the campus walkways. When
* the agent reaches an intersection, it chooses a random direction and continues on.
*
*/
@SuppressWarnings("restriction")
public final class AgentCopy implements Steppable
{
private static final long serialVersionUID = -1113018274619047013L;
Gridlock_NorfolkTEST world;
// Residence/Work Attributes
String homeTract = "";
String workTract = "";
Node homeNode = null;
Node workNode = null;
// point that denotes agent's position
// private Point location;
private MasonGeometry location;
// How much to move the agent by in each step()
private double moveRate = .001;
// Used by agent to walk along line segment
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
GeomPlanarGraphEdge currentEdge = null;
int linkDirection = 1;
double speed = 0; // useful for graph
ArrayList<GeomPlanarGraphDirectedEdge> pathFromHomeToWork =
new ArrayList<GeomPlanarGraphDirectedEdge>();
int indexOnPath = 0;
int pathDirection = 1;
boolean reachedDestination = false;
PointMoveTo pointMoveTo = new PointMoveTo();
/** This is the wrapper object in the agents layer. We need a handle on
* it so that we can update our location with each step().
*/
// private MasonGeometry renderedGeometry;
//
//
//
// public MasonGeometry getRenderedGeometry()
// {
// return renderedGeometry;
// }
//
//
//
// public void setRenderedGeometry(MasonGeometry renderedGeometry)
// {
// this.renderedGeometry = renderedGeometry;
// }
/** Constructor Function */
public AgentCopy(Gridlock_NorfolkTEST g, String home, String work,
GeomPlanarGraphEdge startingEdge, GeomPlanarGraphEdge goalEdge)
{
world = g;
// set up information about where the node is and where it's going
homeNode = startingEdge.getDirEdge(0).getFromNode();
workNode = goalEdge.getDirEdge(0).getToNode();
homeTract = home;
workTract = work;
// set the location to be displayed
GeometryFactory fact = new GeometryFactory();
location = new MasonGeometry(fact.createPoint(new Coordinate(10, 10))) ;
Coordinate startCoord = null;
startCoord = homeNode.getCoordinate();
updatePosition(startCoord);
}
/** Initialization of an Agent: find an A* path to work!
*
* @param state
* @return whether or not the agent successfully found a path to work
*/
public boolean start(Gridlock_NorfolkTEST state)
{
findNewAStarPath(state);
if (pathFromHomeToWork.isEmpty())
{
System.out.println("Initialization of agent failed: it is located in a part "
+ "of the network that cannot access the given goal node");
return false;
} else
{
return true;
}
}
/** Plots a path between the Agent's home Node and its work Node */
private void findNewAStarPath(Gridlock_NorfolkTEST geoTest)
{
// get the home and work Nodes with which this Agent is associated
Node currentJunction = geoTest.network.findNode(location.geometry.getCoordinate());
Node destinationJunction = workNode;
if (currentJunction == null)
{
return; // just a check
}
// find the appropriate A* path between them
AStar pathfinder = new AStar();
ArrayList<GeomPlanarGraphDirectedEdge> path =
pathfinder.astarPath(currentJunction, destinationJunction);
// if the path works, lay it in
if (path != null && path.size() > 0)
{
// save it
pathFromHomeToWork = path;
// set up how to traverse this first link
GeomPlanarGraphEdge edge =
(GeomPlanarGraphEdge) path.get(0).getEdge();
setupEdge(edge);
// update the current position for this link
updatePosition(segment.extractPoint(currentIndex));
}
}
double progress(double val)
{
double edgeLength = currentEdge.getLine().getLength();
double traffic = world.edgeTraffic.get(currentEdge).size();
double factor = 1000 * edgeLength / (traffic * 5);
factor = Math.min(1, factor);
return val * linkDirection * factor;
}
/** Called every tick by the scheduler */
/** moves the agent along the path */
public void step(SimState state)
{
// check that we've been placed on an Edge
if (segment == null)
{
return;
} // check that we haven't already reached our destination
else if (reachedDestination)
{
return;
}
// make sure that we're heading in the right direction
boolean toWork = ((Gridlock_NorfolkTEST) state).goToWork;
if ((toWork && pathDirection < 0) || (!toWork && pathDirection > 0))
{
flipPath();
}
// move along the current segment
speed = progress(moveRate);
currentIndex += speed;
// check to see if the progress has taken the current index beyond its goal
// given the direction of movement. If so, proceed to the next edge
if (linkDirection == 1 && currentIndex > endIndex)
{
Coordinate currentPos = segment.extractPoint(endIndex);
updatePosition(currentPos);
transitionToNextEdge(currentIndex - endIndex);
} else if (linkDirection == -1 && currentIndex < startIndex)
{
Coordinate currentPos = segment.extractPoint(startIndex);
updatePosition(currentPos);
transitionToNextEdge(startIndex - currentIndex);
} else
{ // just update the position!
Coordinate currentPos = segment.extractPoint(currentIndex);
updatePosition(currentPos);
}
}
/** Flip the agent's path around */
void flipPath()
{
reachedDestination = false;
pathDirection = -pathDirection;
linkDirection = -linkDirection;
}
/**
* Transition to the next edge in the path
* @param residualMove the amount of distance the agent can still travel
* this turn
*/
void transitionToNextEdge(double residualMove)
{
// update the counter for where the index on the path is
indexOnPath += pathDirection;
// check to make sure the Agent has not reached the end
// of the path already
if ((pathDirection > 0 && indexOnPath >= pathFromHomeToWork.size())
|| (pathDirection < 0 && indexOnPath < 0))// depends on where you're going!
{
System.out.println(this + " has reached its destination");
reachedDestination = true;
indexOnPath -= pathDirection; // make sure index is correct
return;
}
// move to the next edge in the path
GeomPlanarGraphEdge edge =
(GeomPlanarGraphEdge) pathFromHomeToWork.get(indexOnPath).getEdge();
setupEdge(edge);
speed = progress(residualMove);
currentIndex += speed;
// check to see if the progress has taken the current index beyond its goal
// given the direction of movement. If so, proceed to the next edge
if (linkDirection == 1 && currentIndex > endIndex)
{
transitionToNextEdge(currentIndex - endIndex);
} else if (linkDirection == -1 && currentIndex < startIndex)
{
transitionToNextEdge(startIndex - currentIndex);
}
}
///////////// HELPER FUNCTIONS ////////////////////////////
/** Sets the Agent up to proceed along an Edge
* @param edge the GeomPlanarGraphEdge to traverse next
* */
void setupEdge(GeomPlanarGraphEdge edge)
{
// clean up on old edge
if (currentEdge != null)
{
ArrayList<AgentCopy> traffic = world.edgeTraffic.get(currentEdge);
traffic.remove(this);
}
currentEdge = edge;
// update new edge traffic
if (world.edgeTraffic.get(currentEdge) == null)
{
world.edgeTraffic.put(currentEdge, new ArrayList<AgentCopy>());
}
world.edgeTraffic.get(currentEdge).add(this);
// set up the new segment and index info
LineString line = edge.getLine();
segment = new LengthIndexedLine(line);
startIndex = segment.getStartIndex();
endIndex = segment.getEndIndex();
linkDirection = 1;
// check to ensure that Agent is moving in the right direction
double distanceToStart = line.getStartPoint().distance(location.geometry),
distanceToEnd = line.getEndPoint().distance(location.geometry);
if (distanceToStart <= distanceToEnd)
{ // closer to start
currentIndex = startIndex;
linkDirection = 1;
} else if (distanceToEnd < distanceToStart)
{ // closer to end
currentIndex = endIndex;
linkDirection = -1;
}
}
/** move the agent to the given coordinates */
public void updatePosition(Coordinate c)
{
pointMoveTo.setCoordinate(c);
// location.geometry.apply(pointMoveTo);
world.agents.setGeometryLocation(location, pointMoveTo);
}
/** return geometry representing agent location */
public MasonGeometry getGeometry()
{
return location;
}
}