1 package cz.cuni.amis.pogamut.udk.agent.navigation.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.module.SensorModule;
13 import cz.cuni.amis.pogamut.base.communication.worldview.event.IWorldEventListener;
14 import cz.cuni.amis.pogamut.udk.bot.impl.UDKBot;
15 import cz.cuni.amis.pogamut.udk.communication.messages.gbinfomessages.NavPoint;
16 import cz.cuni.amis.pogamut.udk.communication.messages.gbinfomessages.NavPointNeighbourLink;
17 import cz.cuni.amis.pogamut.udk.communication.translator.shared.events.MapPointListObtained;
18 import cz.cuni.amis.pogamut.unreal.communication.messages.UnrealId;
19 import cz.cuni.amis.utils.collections.MyCollections;
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43 public class FloydWarshallMap extends SensorModule<UDKBot> {
44
45 public static class PathMatrixNode {
46
47 private float distance = Float.POSITIVE_INFINITY;
48 private Integer viaNode = null;
49 private List<NavPoint> path = null;
50
51
52
53
54 public PathMatrixNode() {
55 }
56
57 public PathMatrixNode(float distance) {
58 this.distance = distance;
59 }
60
61 public float getDistance() {
62 return distance;
63 }
64
65 public void setDistance(float distance) {
66 this.distance = distance;
67 }
68
69
70
71
72
73
74 public Integer getViaNode() {
75 return viaNode;
76 }
77
78 public void setViaNode(Integer indice) {
79 this.viaNode = indice;
80 }
81
82 public List<NavPoint> getPath() {
83 return path;
84 }
85
86 public void setPath(List<NavPoint> path) {
87 this.path = path;
88 }
89
90 }
91
92 private IWorldEventListener<MapPointListObtained> mapListener = new IWorldEventListener<MapPointListObtained>() {
93
94 @Override
95 public void notify(MapPointListObtained event) {
96 if (log.isLoggable(Level.INFO)) log.info("Map point list obtained.");
97 performFloydWarshall(event);
98 }
99 };
100
101
102
103
104 public static final int BAD_EDGE_FLAG = LinkFlag.FLY.get()
105 | LinkFlag.LADDER.get() | LinkFlag.PROSCRIBED.get()
106 | LinkFlag.SWIM.get() | LinkFlag.PLAYERONLY.get()
107 | LinkFlag.FORCED.get();
108
109
110
111
112 protected int badEdgeFlag = 0;
113
114
115
116
117 protected Map<UnrealId, Integer> navPointIndices;
118
119
120
121
122
123
124
125
126 protected Map<Integer, NavPoint> indicesNavPoints;
127
128
129 protected PathMatrixNode[][] pathMatrix;
130
131 public FloydWarshallMap(UDKBot bot) {
132 this(bot, BAD_EDGE_FLAG, null);
133 }
134
135 public FloydWarshallMap(UDKBot bot, Logger log) {
136 this(bot, BAD_EDGE_FLAG, log);
137 }
138
139 public FloydWarshallMap(UDKBot bot, int badEdgeFlag, Logger log) {
140 super(bot, log);
141 this.badEdgeFlag = badEdgeFlag;
142 worldView.addEventListener(MapPointListObtained.class, mapListener);
143 }
144
145 protected void performFloydWarshall(MapPointListObtained map) {
146 List<NavPoint> navPoints = MyCollections.asList(map.getNavPoints().values());
147 performFloydWarshall(navPoints);
148 }
149
150 protected void performFloydWarshall(List<NavPoint> navPoints) {
151 if (log.isLoggable(Level.FINE)) log.fine(this + ": Beginning Floyd-Warshall algorithm...");
152 long start = System.currentTimeMillis();
153
154
155 int size = navPoints.size();
156 navPointIndices = new HashMap<UnrealId, Integer>(size);
157 indicesNavPoints = new HashMap<Integer, NavPoint>(size);
158 pathMatrix = new PathMatrixNode[size][size];
159
160
161 for (int i = 0; i < navPoints.size(); ++i) {
162 navPointIndices.put(navPoints.get(i).getId(), i);
163 indicesNavPoints.put(i, navPoints.get(i));
164 }
165
166
167 for (int i = 0; i < size; i++) {
168 for (int j = 0; j < size; j++) {
169 pathMatrix[i][j] = new PathMatrixNode((i == j) ? 0.0f
170 : Float.POSITIVE_INFINITY);
171 }
172 }
173
174
175 for (int i = 0; i < size; i++) {
176 Point3d location = navPoints.get(i).getLocation().getPoint3d();
177 for (NavPointNeighbourLink link : navPoints.get(i)
178 .getOutgoingEdges().values()) {
179 if (checkLink(link)) {
180 pathMatrix[i][navPointIndices.get(link.getToNavPoint()
181 .getId())].setDistance((float) location
182 .distance(link.getToNavPoint().getLocation()
183 .getPoint3d()));
184 }
185 }
186 }
187
188
189 for (int k = 0; k < size; k++) {
190 for (int i = 0; i < size; i++) {
191 for (int j = 0; j < size; j++) {
192 float newLen = pathMatrix[i][k].getDistance()
193 + pathMatrix[k][j].getDistance();
194 if (pathMatrix[i][j].getDistance() > newLen) {
195 pathMatrix[i][j].setDistance(newLen);
196 pathMatrix[i][j].setViaNode(k);
197 }
198 }
199 }
200 }
201
202
203 int count = 0;
204 for (int i = 0; i < size; i++) {
205 for (int j = 0; j < size; j++) {
206 if (pathMatrix[i][j].getDistance() == Float.POSITIVE_INFINITY) {
207 if (log.isLoggable(Level.WARNING)) log.warning("Unreachable path from " + navPoints.get(i).getId().getStringId()
208 + " -> " + navPoints.get(j).getId().getStringId());
209 count++;
210 } else {
211
212 pathMatrix[i][j].setPath(retrievePath(i, j));
213 }
214 }
215 }
216
217 if (count > 0) {
218 if (log.isLoggable(Level.WARNING)) log.warning(this + ": There are " + count + " unreachable nav point pairs.");
219 }
220
221 if (log.isLoggable(Level.INFO)) log.info(this + ": computation for " + size + " navpoints took " + (System.currentTimeMillis() - start) + " millis");
222
223
224 indicesNavPoints = null;
225 }
226
227
228
229
230
231
232
233
234
235
236 public boolean checkLink(NavPointNeighbourLink edge) {
237
238 if ((edge.getFlags() & badEdgeFlag) != 0)
239 return false;
240
241
242 if ((edge.getFlags() & LinkFlag.SPECIAL.get()) != 0)
243 return true;
244
245
246 if ((edge.getFromNavPoint().getLocation().getPoint3d().distance(
247 edge.getToNavPoint().getLocation().getPoint3d()) < (edge
248 .getToNavPoint().getLocation().z - edge.getFromNavPoint()
249 .getLocation().z))
250 && (edge.getFromNavPoint().getLocation().getPoint3d().distance(
251 edge.getToNavPoint().getLocation().getPoint3d()) > 100)) {
252 return false;
253 }
254
255
256 if (((edge.getFlags() & LinkFlag.JUMP.get()) != 0)
257 && (edge.getToNavPoint().getLocation().z
258 - edge.getFromNavPoint().getLocation().z > 80)) {
259 return false;
260 }
261
262 return true;
263 }
264
265
266
267
268
269
270
271
272
273
274
275
276 private List<NavPoint> retrievePathInner(Integer from, Integer to) {
277 PathMatrixNode node = pathMatrix[from][to];
278 if (node.getDistance() == Float.POSITIVE_INFINITY)
279 return null;
280 if (node.getViaNode() == null) {
281 return new ArrayList<NavPoint>(0);
282 }
283 if (node.getViaNode() == null)
284 return new ArrayList<NavPoint>(0);
285
286 List<NavPoint> path = new ArrayList<NavPoint>();
287 path.addAll(retrievePathInner(from, node.getViaNode()));
288 path.add(indicesNavPoints.get(node.getViaNode()));
289 path.addAll(retrievePathInner(node.getViaNode(), to));
290
291 return path;
292 }
293
294
295
296
297
298
299
300
301
302
303
304
305 private List<NavPoint> retrievePath(Integer from, Integer to) {
306 List<NavPoint> path = new ArrayList<NavPoint>();
307 path.add(indicesNavPoints.get(from));
308 path.addAll(retrievePathInner(from, to));
309 path.add(indicesNavPoints.get(to));
310 return path;
311 }
312
313 protected PathMatrixNode getPathMatrixNode(NavPoint np1, NavPoint np2) {
314 return pathMatrix[navPointIndices.get(np1.getId())][navPointIndices
315 .get(np2.getId())];
316 }
317
318
319
320
321
322
323
324
325 public boolean reachable(NavPoint from, NavPoint to) {
326 if ((from == null) || (to == null))
327 return false;
328 return getPathMatrixNode(from, to).getDistance() != Float.POSITIVE_INFINITY;
329 }
330
331
332
333
334
335
336 public float getDistance(NavPoint from, NavPoint to) {
337 if ((from == null) || (to == null))
338 return Float.POSITIVE_INFINITY;
339 return getPathMatrixNode(from, to).getDistance();
340 }
341
342
343
344
345
346
347
348
349
350 public List<NavPoint> getPath(NavPoint from, NavPoint to) {
351 if ((from == null) || (to == null))
352 return null;
353 return getPathMatrixNode(from, to).getPath();
354 }
355
356 @Override
357 public String toString() {
358 return "FloydWarshallMap";
359 }
360
361 }