1 package nl.tudelft.goal.unreal.floydwarshall;
2
3 import java.util.ArrayList;
4 import java.util.HashMap;
5 import java.util.List;
6 import java.util.Map;
7 import java.util.logging.Level;
8 import java.util.logging.Logger;
9
10 import javax.vecmath.Point3d;
11
12 import cz.cuni.amis.pogamut.base.agent.navigation.IPathFuture;
13 import cz.cuni.amis.pogamut.base.agent.navigation.IPathPlanner;
14 import cz.cuni.amis.pogamut.base.agent.navigation.impl.PrecomputedPathFuture;
15 import cz.cuni.amis.pogamut.unreal.communication.messages.UnrealId;
16 import cz.cuni.amis.pogamut.ut2004.agent.module.sensor.NavigationGraphBuilder;
17 import cz.cuni.amis.pogamut.ut2004.communication.messages.gbinfomessages.NavPoint;
18 import cz.cuni.amis.pogamut.ut2004.communication.messages.gbinfomessages.NavPointNeighbourLink;
19 import cz.cuni.amis.pogamut.ut2004.communication.translator.shared.events.MapPointListObtained;
20 import cz.cuni.amis.pogamut.ut2004.utils.LinkFlag;
21 import cz.cuni.amis.utils.collections.MyCollections;
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 public class FloydWarshallMap implements IPathPlanner<NavPoint> {
48
49 public static class PathMatrixNode {
50
51 private float distance = Float.POSITIVE_INFINITY;
52 private Integer viaNode = null;
53 private List<NavPoint> path = null;
54
55
56
57
58 public PathMatrixNode() {
59 }
60
61 public PathMatrixNode(float distance) {
62 this.distance = distance;
63 }
64
65 public float getDistance() {
66 return distance;
67 }
68
69 public void setDistance(float distance) {
70 this.distance = distance;
71 }
72
73
74
75
76
77
78 public Integer getViaNode() {
79 return viaNode;
80 }
81
82 public void setViaNode(Integer indice) {
83 this.viaNode = indice;
84 }
85
86 public List<NavPoint> getPath() {
87 return path;
88 }
89
90 public void setPath(List<NavPoint> path) {
91 this.path = path;
92 }
93 }
94
95
96
97 public static final int BAD_EDGE_FLAG = LinkFlag.FLY.get()
98 | LinkFlag.LADDER.get() | LinkFlag.PROSCRIBED.get()
99 | LinkFlag.SWIM.get() | LinkFlag.PLAYERONLY.get();
100
101 public static boolean isWalkable(int flag) {
102 return ((flag & BAD_EDGE_FLAG) == 0) && ((flag & LinkFlag.SPECIAL.get()) == 0);
103 }
104
105
106
107 protected int badEdgeFlag = 0;
108
109
110
111 protected Map<UnrealId, Integer> navPointIndices;
112
113
114
115
116
117
118
119 protected Map<Integer, NavPoint> indicesNavPoints;
120
121 protected PathMatrixNode[][] pathMatrix;
122
123
124
125
126 protected Object mutex = new Object();
127
128
129
130 private Logger log;
131
132 public FloydWarshallMap(Logger log) {
133 this(BAD_EDGE_FLAG, log);
134 }
135
136 public FloydWarshallMap(int badEdgeFlag, Logger log) {
137 this.badEdgeFlag = badEdgeFlag;
138 this.log = log;
139 }
140
141
142
143
144
145 public void refreshPathMatrix(List<NavPoint> navPoints) {
146 synchronized (mutex) {
147 if (log.isLoggable(Level.FINE)) {
148 log.fine(this + ": Refreshing path matrix...");
149 }
150 performFloydWarshall(navPoints);
151 if (log.isLoggable(Level.WARNING)) {
152 log.warning(this + ": Path matrix refreshed!");
153 }
154 }
155 }
156
157 protected void performFloydWarshall(MapPointListObtained map) {
158 List<NavPoint> navPoints = MyCollections.asList(map.getNavPoints().values());
159 performFloydWarshall(navPoints);
160 }
161
162 protected void performFloydWarshall(List<NavPoint> navPoints) {
163 if (log.isLoggable(Level.FINE)) {
164 log.fine(this + ": Beginning Floyd-Warshall algorithm...");
165 }
166 long start = System.currentTimeMillis();
167
168
169 int size = navPoints.size();
170 navPointIndices = new HashMap<UnrealId, Integer>(size);
171 indicesNavPoints = new HashMap<Integer, NavPoint>(size);
172 pathMatrix = new PathMatrixNode[size][size];
173
174
175 for (int i = 0; i < navPoints.size(); ++i) {
176 navPointIndices.put(navPoints.get(i).getId(), i);
177 indicesNavPoints.put(i, navPoints.get(i));
178 }
179
180
181 for (int i = 0; i < size; i++) {
182 for (int j = 0; j < size; j++) {
183 pathMatrix[i][j] = new PathMatrixNode((i == j) ? 0.0f
184 : Float.POSITIVE_INFINITY);
185 }
186 }
187
188
189 for (int i = 0; i < size; i++) {
190 Point3d location = navPoints.get(i).getLocation().getPoint3d();
191 for (NavPointNeighbourLink link : navPoints.get(i)
192 .getOutgoingEdges().values()) {
193 if (checkLink(link)) {
194 pathMatrix[i][navPointIndices.get(link.getToNavPoint()
195 .getId())].setDistance((float) location
196 .distance(link.getToNavPoint().getLocation()
197 .getPoint3d()));
198 }
199 }
200 }
201
202
203 for (int k = 0; k < size; k++) {
204 for (int i = 0; i < size; i++) {
205 for (int j = 0; j < size; j++) {
206 float newLen = pathMatrix[i][k].getDistance()
207 + pathMatrix[k][j].getDistance();
208 if (pathMatrix[i][j].getDistance() > newLen) {
209 pathMatrix[i][j].setDistance(newLen);
210 pathMatrix[i][j].setViaNode(k);
211 }
212 }
213 }
214 }
215
216
217 int count = 0;
218 for (int i = 0; i < size; i++) {
219 for (int j = 0; j < size; j++) {
220 if (pathMatrix[i][j].getDistance() == Float.POSITIVE_INFINITY) {
221 if (log.isLoggable(Level.FINER)) {
222 log.finer("Unreachable path from " + navPoints.get(i).getId().getStringId()
223 + " -> " + navPoints.get(j).getId().getStringId());
224 }
225 count++;
226 } else {
227
228 pathMatrix[i][j].setPath(retrievePath(i, j));
229 }
230 }
231 }
232
233 if (count > 0) {
234 if (log.isLoggable(Level.WARNING)) {
235 log.warning(this + ": There are " + count + " unreachable nav point pairs (if you wish to see more, set logging to Level.FINER).");
236 }
237 }
238
239 if (log.isLoggable(Level.INFO)) {
240 log.info(this + ": computation for " + size + " navpoints took " + (System.currentTimeMillis() - start) + " millis");
241 }
242
243
244 indicesNavPoints = null;
245 }
246
247
248
249
250
251
252
253
254 public boolean checkLink(NavPointNeighbourLink edge) {
255
256 if ((edge.getFlags() & badEdgeFlag) != 0) {
257 return false;
258 }
259
260
261 if (edge.isOnlyTranslocator()) {
262 return false;
263 }
264
265
266 if ((edge.getFlags() & LinkFlag.SPECIAL.get()) != 0) {
267 return true;
268 }
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290 if (edge.getNeededJump() != null && edge.getNeededJump().z > 680) {
291 return false;
292 }
293
294
295 if (edge.getToNavPoint().isLiftJumpExit()) {
296 return false;
297 }
298
299 return true;
300 }
301
302
303
304
305
306
307
308
309
310
311
312
313 private List<NavPoint> retrievePathInner(Integer from, Integer to) {
314 PathMatrixNode node = pathMatrix[from][to];
315 if (node.getDistance() == Float.POSITIVE_INFINITY) {
316 return null;
317 }
318 if (node.getViaNode() == null) {
319 return new ArrayList<NavPoint>(0);
320 }
321 if (node.getViaNode() == null) {
322 return new ArrayList<NavPoint>(0);
323 }
324
325 List<NavPoint> path = new ArrayList<NavPoint>();
326 path.addAll(retrievePathInner(from, node.getViaNode()));
327 path.add(indicesNavPoints.get(node.getViaNode()));
328 path.addAll(retrievePathInner(node.getViaNode(), to));
329
330 return path;
331 }
332
333
334
335
336
337
338
339
340
341
342
343
344 private List<NavPoint> retrievePath(Integer from, Integer to) {
345 List<NavPoint> path = new ArrayList<NavPoint>();
346 path.add(indicesNavPoints.get(from));
347 path.addAll(retrievePathInner(from, to));
348 path.add(indicesNavPoints.get(to));
349 return path;
350 }
351
352 protected PathMatrixNode getPathMatrixNode(NavPoint np1, NavPoint np2) {
353 return pathMatrix[navPointIndices.get(np1.getId())][navPointIndices
354 .get(np2.getId())];
355 }
356
357
358
359
360
361
362
363
364
365
366
367
368 public boolean reachable(NavPoint from, NavPoint to) {
369 if ((from == null) || (to == null)) {
370 return false;
371 }
372 return getPathMatrixNode(from, to).getDistance() != Float.POSITIVE_INFINITY;
373 }
374
375
376
377
378
379
380
381
382
383
384 public float getDistance(NavPoint from, NavPoint to) {
385 if ((from == null) || (to == null)) {
386 return Float.POSITIVE_INFINITY;
387 }
388 return getPathMatrixNode(from, to).getDistance();
389 }
390
391
392
393
394
395
396
397
398
399
400
401
402
403 public List<NavPoint> getPath(NavPoint from, NavPoint to) {
404 synchronized (mutex) {
405 if ((from == null) || (to == null)) {
406 return null;
407 }
408 if (log.isLoggable(Level.FINE)) {
409 log.fine("Retrieving path: " + from.getId().getStringId() + "[" + from.getLocation() + "] -> " + to.getId().getStringId() + "[" + to.getLocation() + "]");
410 }
411 List<NavPoint> path = getPathMatrixNode(from, to).getPath();
412 if (path == null) {
413 if (log.isLoggable(Level.WARNING)) {
414 log.warning("PATH NOT EXIST: " + from.getId().getStringId() + "[" + from.getLocation() + "] -> " + to.getId().getStringId() + "[" + to.getLocation() + "]");
415 }
416 } else {
417 if (log.isLoggable(Level.FINE)) {
418 log.fine("Path exists - " + path.size() + " navpoints.");
419 }
420 }
421 return path;
422 }
423 }
424
425 protected void cleanUp() {
426 pathMatrix = null;
427 navPointIndices = null;
428 }
429
430 @Override
431 public String toString() {
432 return "FloydWarshallMap";
433 }
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448 @Override
449 public IPathFuture<NavPoint> computePath(NavPoint from, NavPoint to) {
450 return new PrecomputedPathFuture<NavPoint>(from, to, getPath(from, to));
451 }
452 }