1 package cz.cuni.amis.pogamut.ut2004.agent.navigation.floydwarshall;
2
3 import cz.cuni.amis.pogamut.base.agent.IGhostAgent;
4 import cz.cuni.amis.pogamut.base.agent.module.SensorModule;
5 import cz.cuni.amis.pogamut.base.agent.navigation.IPathFuture;
6 import cz.cuni.amis.pogamut.base.agent.navigation.IPathPlanner;
7 import cz.cuni.amis.pogamut.base.agent.navigation.impl.PrecomputedPathFuture;
8 import cz.cuni.amis.pogamut.base.communication.worldview.event.IWorldEventListener;
9 import cz.cuni.amis.pogamut.unreal.communication.messages.UnrealId;
10 import cz.cuni.amis.pogamut.ut2004.agent.module.sensor.NavigationGraphBuilder;
11 import cz.cuni.amis.pogamut.ut2004.agent.navigation.UT2004EdgeChecker;
12 import cz.cuni.amis.pogamut.ut2004.communication.messages.gbinfomessages.Item;
13 import cz.cuni.amis.pogamut.ut2004.communication.messages.gbinfomessages.NavPoint;
14 import cz.cuni.amis.pogamut.ut2004.communication.messages.gbinfomessages.NavPointNeighbourLink;
15 import cz.cuni.amis.pogamut.ut2004.communication.translator.shared.events.MapPointListObtained;
16 import cz.cuni.amis.pogamut.ut2004.utils.LinkFlag;
17 import cz.cuni.amis.utils.IFilter;
18 import cz.cuni.amis.utils.collections.MyCollections;
19 import cz.cuni.amis.utils.exception.PogamutException;
20 import java.util.ArrayList;
21 import java.util.Collection;
22 import java.util.HashMap;
23 import java.util.List;
24 import java.util.Map;
25 import java.util.logging.Level;
26 import java.util.logging.Logger;
27 import javax.vecmath.Point3d;
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 public class FloydWarshallMap extends SensorModule<IGhostAgent> implements IPathPlanner<NavPoint> {
61
62 public static class PathMatrixNode {
63
64 private float distance = Float.POSITIVE_INFINITY;
65 private Integer viaNode = null;
66 private List<NavPoint> path = null;
67
68
69
70
71 public PathMatrixNode() {
72 }
73
74 public PathMatrixNode(float distance) {
75 this.distance = distance;
76 }
77
78 public float getDistance() {
79 return distance;
80 }
81
82 public void setDistance(float distance) {
83 this.distance = distance;
84 }
85
86
87
88
89
90
91 public Integer getViaNode() {
92 return viaNode;
93 }
94
95 public void setViaNode(Integer indice) {
96 this.viaNode = indice;
97 }
98
99 public List<NavPoint> getPath() {
100 return path;
101 }
102
103 public void setPath(List<NavPoint> path) {
104 this.path = path;
105 }
106
107 }
108
109 private IWorldEventListener<MapPointListObtained> mapListener = new IWorldEventListener<MapPointListObtained>() {
110
111 @Override
112 public void notify(MapPointListObtained event) {
113 if (log.isLoggable(Level.INFO)) {
114 log.info("Map point list obtained.");
115 }
116 performFloydWarshall(event);
117 }
118 };
119
120
121
122
123 public static final int BAD_EDGE_FLAG = LinkFlag.FLY.get()
124 | LinkFlag.LADDER.get() | LinkFlag.PROSCRIBED.get()
125 | LinkFlag.SWIM.get() | LinkFlag.PLAYERONLY.get();
126
127 public static boolean isWalkable(int flag) {
128 return ((flag & BAD_EDGE_FLAG) == 0) && ((flag & LinkFlag.SPECIAL.get()) == 0);
129 }
130
131
132
133
134 protected int badEdgeFlag = 0;
135
136
137
138
139 protected Map<UnrealId, Integer> navPointIndices;
140
141
142
143
144
145
146
147
148 protected Map<Integer, NavPoint> indicesNavPoints;
149
150
151 protected PathMatrixNode[][] pathMatrix;
152
153
154
155
156
157
158
159
160 private boolean enabled = true;
161
162
163
164
165
166 protected Object mutex = new Object();
167
168 public FloydWarshallMap(IGhostAgent bot) {
169 this(bot, BAD_EDGE_FLAG, null);
170 }
171
172 public FloydWarshallMap(IGhostAgent bot, Logger log) {
173 this(bot, BAD_EDGE_FLAG, log);
174 }
175
176 public FloydWarshallMap(IGhostAgent bot, int badEdgeFlag, Logger log) {
177 super(bot, log);
178 this.badEdgeFlag = badEdgeFlag;
179 worldView.addEventListener(MapPointListObtained.class, mapListener);
180 }
181
182
183
184
185
186
187
188
189
190
191 public boolean isEnabled() {
192 return enabled;
193 }
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214 public void setEnabled(boolean enabled) {
215 synchronized (mutex) {
216 this.enabled = enabled;
217 if (!enabled) {
218 cleanUp();
219 }
220 }
221 }
222
223
224
225
226
227 public void refreshPathMatrix() {
228 synchronized (mutex) {
229 if (!enabled) {
230 if (log.isLoggable(Level.WARNING)) {
231 log.fine(this + ": Won't refresh path matrix, object is disabled.");
232 }
233 return;
234 }
235 if (log.isLoggable(Level.FINE)) {
236 log.fine(this + ": Refreshing path matrix...");
237 }
238 List<NavPoint> navPoints = MyCollections.asList(agent.getWorldView().getAll(NavPoint.class).values());
239 performFloydWarshall(navPoints);
240 if (log.isLoggable(Level.WARNING)) {
241 log.warning(this + ": Path matrix refreshed!");
242 }
243 }
244 }
245
246 protected void performFloydWarshall(MapPointListObtained map) {
247 List<NavPoint> navPoints = MyCollections.asList(map.getNavPoints().values());
248 performFloydWarshall(navPoints);
249 }
250
251 protected void performFloydWarshall(List<NavPoint> navPoints) {
252 if (!enabled) {
253 if (log.isLoggable(Level.WARNING)) {
254 log.fine(this + ": Should not be running Floyd-Warshall, object disabled.");
255 }
256 return;
257 }
258 if (log.isLoggable(Level.FINE)) {
259 log.fine(this + ": Beginning Floyd-Warshall algorithm...");
260 }
261 long start = System.currentTimeMillis();
262
263
264 int size = navPoints.size();
265 navPointIndices = new HashMap<UnrealId, Integer>(size);
266 indicesNavPoints = new HashMap<Integer, NavPoint>(size);
267 pathMatrix = new PathMatrixNode[size][size];
268
269
270 for (int i = 0; i < navPoints.size(); ++i) {
271 navPointIndices.put(navPoints.get(i).getId(), i);
272 indicesNavPoints.put(i, navPoints.get(i));
273 }
274
275
276 for (int i = 0; i < size; i++) {
277 for (int j = 0; j < size; j++) {
278 pathMatrix[i][j] = new PathMatrixNode((i == j) ? 0.0f
279 : Float.POSITIVE_INFINITY);
280 }
281 }
282
283
284 for (int i = 0; i < size; i++) {
285 Point3d location = navPoints.get(i).getLocation().getPoint3d();
286 for (NavPointNeighbourLink link : navPoints.get(i)
287 .getOutgoingEdges().values()) {
288 if (UT2004EdgeChecker.checkLink(link)) {
289
290
291 if (link.getFromNavPoint().isTeleporter() && link.getToNavPoint().isTeleporter()) {
292 pathMatrix[i][navPointIndices.get(link.getToNavPoint()
293 .getId())].setDistance(0);
294 } else {
295
296 pathMatrix[i][navPointIndices.get(link.getToNavPoint()
297 .getId())].setDistance((float) location
298 .distance(link.getToNavPoint().getLocation()
299 .getPoint3d()));
300 }
301 }
302 }
303 }
304
305
306 for (int k = 0; k < size; k++) {
307 for (int i = 0; i < size; i++) {
308 for (int j = 0; j < size; j++) {
309 float newLen = pathMatrix[i][k].getDistance()
310 + pathMatrix[k][j].getDistance();
311 if (pathMatrix[i][j].getDistance() > newLen) {
312 pathMatrix[i][j].setDistance(newLen);
313 pathMatrix[i][j].setViaNode(k);
314 }
315 }
316 }
317 }
318
319
320 int count = 0;
321 for (int i = 0; i < size; i++) {
322 for (int j = 0; j < size; j++) {
323 if (pathMatrix[i][j].getDistance() == Float.POSITIVE_INFINITY) {
324 if (log.isLoggable(Level.FINER)) {
325 log.finer("Unreachable path from " + navPoints.get(i).getId().getStringId()
326 + " -> " + navPoints.get(j).getId().getStringId());
327 }
328 count++;
329 } else {
330
331 pathMatrix[i][j].setPath(retrievePath(i, j));
332 }
333 }
334 }
335
336 if (count > 0) {
337 if (log.isLoggable(Level.WARNING)) {
338 log.warning(this + ": There are " + count + " unreachable nav point pairs (if you wish to see more, set logging to Level.FINER).");
339 }
340 }
341
342 if (log.isLoggable(Level.INFO)) {
343 log.info(this + ": computation for " + size + " navpoints took " + (System.currentTimeMillis() - start) + " millis");
344 }
345
346
347 indicesNavPoints = null;
348 }
349
350
351
352
353
354
355
356
357 public boolean checkLink(NavPointNeighbourLink edge) {
358
359 if ((edge.getFlags() & badEdgeFlag) != 0) {
360 return false;
361 }
362
363
364 if ((edge.getFlags() & LinkFlag.SPECIAL.get()) != 0) {
365 return true;
366 }
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387 if (edge.getNeededJump() != null && edge.getNeededJump().z > 680) {
388 return false;
389 }
390
391
392 if (edge.getToNavPoint().isLiftJumpExit()) {
393 return false;
394 }
395
396 return true;
397 }
398
399
400
401
402
403
404
405
406
407
408
409
410 private List<NavPoint> retrievePathInner(Integer from, Integer to) {
411 PathMatrixNode node = pathMatrix[from][to];
412 if (node.getDistance() == Float.POSITIVE_INFINITY) {
413 return null;
414 }
415 if (node.getViaNode() == null) {
416 return new ArrayList<NavPoint>(0);
417 }
418 if (node.getViaNode() == null) {
419 return new ArrayList<NavPoint>(0);
420 }
421
422 List<NavPoint> path = new ArrayList<NavPoint>();
423 path.addAll(retrievePathInner(from, node.getViaNode()));
424 path.add(indicesNavPoints.get(node.getViaNode()));
425 path.addAll(retrievePathInner(node.getViaNode(), to));
426
427 return path;
428 }
429
430
431
432
433
434
435
436
437
438
439
440
441 private List<NavPoint> retrievePath(Integer from, Integer to) {
442 List<NavPoint> path = new ArrayList<NavPoint>();
443 path.add(indicesNavPoints.get(from));
444 path.addAll(retrievePathInner(from, to));
445 path.add(indicesNavPoints.get(to));
446 return path;
447 }
448
449 protected PathMatrixNode getPathMatrixNode(NavPoint np1, NavPoint np2) {
450 return pathMatrix[navPointIndices.get(np1.getId())][navPointIndices
451 .get(np2.getId())];
452 }
453
454
455
456
457
458
459
460
461
462
463
464
465
466 public boolean reachable(NavPoint from, NavPoint to) {
467 if ((from == null) || (to == null)) {
468 return false;
469 }
470 return getPathMatrixNode(from, to).getDistance() != Float.POSITIVE_INFINITY;
471 }
472
473
474
475
476
477
478
479
480
481
482
483 @Override
484 public double getDistance(NavPoint from, NavPoint to) {
485 if ((from == null) || (to == null)) {
486 return Double.POSITIVE_INFINITY;
487 }
488 return getPathMatrixNode(from, to).getDistance();
489 }
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504 public List<NavPoint> getPath(NavPoint from, NavPoint to) {
505 synchronized (mutex) {
506 if (!enabled) {
507 throw new PogamutException("Can't return path as the object is disabled, call .setEnabled(true) & .refreshPathMatrix() first!", log, this);
508 }
509 if ((from == null) || (to == null)) {
510 return null;
511 }
512 if (log.isLoggable(Level.FINE)) {
513 log.fine("Retrieving path: " + from.getId().getStringId() + "[" + from.getLocation() + "] -> " + to.getId().getStringId() + "[" + to.getLocation() + "]");
514 }
515 List<NavPoint> path = getPathMatrixNode(from, to).getPath();
516 if (path == null) {
517 if (log.isLoggable(Level.WARNING)) {
518 log.warning("PATH NOT EXIST: " + from.getId().getStringId() + "[" + from.getLocation() + "] -> " + to.getId().getStringId() + "[" + to.getLocation() + "]");
519 }
520 } else {
521 if (log.isLoggable(Level.FINE)) {
522 log.fine("Path exists - " + path.size() + " navpoints.");
523 }
524 }
525 return path;
526 }
527 }
528
529 @Override
530 protected void cleanUp() {
531 super.cleanUp();
532 pathMatrix = null;
533 navPointIndices = null;
534 }
535
536 @Override
537 public String toString() {
538 return "FloydWarshallMap";
539 }
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555 @Override
556 public IPathFuture<NavPoint> computePath(NavPoint from, NavPoint to) {
557 return new PrecomputedPathFuture<NavPoint>(from, to, getPath(from, to));
558 }
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575 public <T extends NavPoint> T getNearestNavPoint(Collection<T> locations, T target) {
576 if (locations == null) {
577 return null;
578 }
579 if (target == null) {
580 return null;
581 }
582 T nearest = null;
583 double minDistance = Double.MAX_VALUE;
584 double d;
585 for (T l : locations) {
586 if (l.getLocation() == null) {
587 continue;
588 }
589 d = getDistance(target, l);
590 if (d < minDistance) {
591 minDistance = d;
592 nearest = l;
593 }
594 }
595 return nearest;
596 }
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612 public <T extends NavPoint> T getNearestNavPoint(Collection<T> locations, NavPoint target, double maxDistance) {
613 if (locations == null) {
614 return null;
615 }
616 if (target == null) {
617 return null;
618 }
619 T nearest = null;
620 double minDistance = Double.MAX_VALUE;
621 double d;
622 for (T l : locations) {
623 d = getDistance(target, l);
624 if (d > maxDistance) {
625 continue;
626 }
627 if (d < minDistance) {
628 minDistance = d;
629 nearest = l;
630 }
631 }
632 return nearest;
633 }
634
635
636
637
638
639
640
641
642
643
644
645
646
647 public <T extends NavPoint> T getNearestFilteredNavPoint(Collection<T> locations, NavPoint target, IFilter<T> filter) {
648 if (locations == null) {
649 return null;
650 }
651 if (target == null) {
652 return null;
653 }
654 T nearest = null;
655 double minDistance = Double.MAX_VALUE;
656 double d;
657 for (T l : locations) {
658 if (!filter.isAccepted(l)) {
659 continue;
660 }
661 d = getDistance(target, l);
662 if (d < minDistance) {
663 minDistance = d;
664 nearest = l;
665 }
666 }
667 return nearest;
668 }
669
670
671
672
673
674
675
676
677
678
679
680
681
682 public <T extends NavPoint> T getSecondNearestNavPoint(Collection<T> locations, NavPoint target) {
683 if (locations == null) {
684 return null;
685 }
686 if (target == null) {
687 return null;
688 }
689 T secondNearest = null;
690 T nearest = null;
691 double closestDistance = Double.MAX_VALUE;
692 double secondClosestDistance = Double.MAX_VALUE;
693
694 for (T l : locations) {
695 double distance = getDistance(target, l);
696 if (distance < closestDistance) {
697 secondClosestDistance = closestDistance;
698 secondNearest = nearest;
699
700 closestDistance = distance;
701 nearest = l;
702 } else {
703 if (distance < secondClosestDistance) {
704 secondClosestDistance = distance;
705 secondNearest = l;
706 }
707 }
708 }
709 return secondNearest;
710 }
711
712
713
714
715
716
717
718
719
720
721
722
723
724 public <T extends Item> T getNearestItem(Collection<T> locations, NavPoint target) {
725 if (locations == null) {
726 return null;
727 }
728 if (target == null) {
729 return null;
730 }
731 T nearest = null;
732 double minDistance = Double.MAX_VALUE;
733 double d;
734 for (T l : locations) {
735 if (l.getLocation() == null) {
736 continue;
737 }
738 d = getDistance(target, l.getNavPoint());
739 if (d < minDistance) {
740 minDistance = d;
741 nearest = l;
742 }
743 }
744 return nearest;
745 }
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761 public <T extends Item> T getNearestItem(Collection<T> locations, NavPoint target, double maxDistance) {
762 if (locations == null) {
763 return null;
764 }
765 if (target == null) {
766 return null;
767 }
768 T nearest = null;
769 double minDistance = Double.MAX_VALUE;
770 double d;
771 for (T l : locations) {
772 d = getDistance(target, l.getNavPoint());
773 if (d > maxDistance) {
774 continue;
775 }
776 if (d < minDistance) {
777 minDistance = d;
778 nearest = l;
779 }
780 }
781 return nearest;
782 }
783
784
785
786
787
788
789
790
791
792
793
794
795
796 public <T extends Item> T getNearestFilteredItem(Collection<T> locations, NavPoint target, IFilter<T> filter) {
797 if (locations == null) {
798 return null;
799 }
800 if (target == null) {
801 return null;
802 }
803 T nearest = null;
804 double minDistance = Double.MAX_VALUE;
805 double d;
806 for (T l : locations) {
807 if (!filter.isAccepted(l)) {
808 continue;
809 }
810 d = getDistance(target, l.getNavPoint());
811 if (d < minDistance) {
812 minDistance = d;
813 nearest = l;
814 }
815 }
816 return nearest;
817 }
818
819
820
821
822
823
824
825
826
827
828
829
830
831 public <T extends Item> T getSecondNearestItem(Collection<T> targets, NavPoint from) {
832 if (targets == null) {
833 return null;
834 }
835 if (from == null) {
836 return null;
837 }
838 T secondNearest = null;
839 T nearest = null;
840 double closestDistance = Double.MAX_VALUE;
841 double secondClosestDistance = Double.MAX_VALUE;
842
843 for (T l : targets) {
844 double distance = getDistance(from, l.getNavPoint());
845 if (distance < closestDistance) {
846 secondClosestDistance = closestDistance;
847 secondNearest = nearest;
848
849 closestDistance = distance;
850 nearest = l;
851 } else {
852 if (distance < secondClosestDistance) {
853 secondClosestDistance = distance;
854 secondNearest = l;
855 }
856 }
857 }
858 return secondNearest;
859 }
860
861 }