1 package Steerings;
2
3 import SteeringStuff.SteeringManager;
4 import SteeringStuff.SteeringTools;
5 import SteeringStuff.RefBoolean;
6 import SteeringProperties.SteeringProperties;
7 import SteeringProperties.WallFollowingProperties;
8 import SteeringStuff.IRaysFlagChanged;
9 import cz.cuni.amis.pogamut.base3d.worldview.object.Location;
10 import javax.vecmath.Vector3d;
11 import cz.cuni.amis.pogamut.ut2004.bot.impl.UT2004Bot;
12 import cz.cuni.amis.pogamut.ut2004.communication.messages.gbinfomessages.AutoTraceRay;
13 import SteeringStuff.ISteering;
14 import SteeringStuff.RaycastingManager;
15 import SteeringStuff.SteeringRay;
16 import SteeringStuff.SteeringType;
17 import cz.cuni.amis.pogamut.ut2004.utils.UnrealUtils;
18 import java.util.HashMap;
19 import java.util.LinkedList;
20 import java.util.Random;
21 import java.util.concurrent.ExecutionException;
22 import java.util.concurrent.Future;
23 import java.util.logging.Level;
24 import java.util.logging.Logger;
25 import javax.vecmath.Tuple3d;
26
27
28
29
30
31
32
33 public class WallFollowingSteer implements ISteering, IRaysFlagChanged {
34
35 private UT2004Bot botself;
36 private RaycastingManager rayManager;
37
38 private int wallForce;
39
40 private int orderOfTheForce;
41
42 private double attractiveForceWeight;
43
44 private double repulsiveForceWeight;
45
46 private double convexEdgesForceWeight;
47
48 private double concaveEdgesForceWeight;
49
50 private boolean justMySide;
51
52 private boolean specialDetection;
53
54 private boolean frontCollisions;
55
56
57
58 int DISTANCE_FROM_THE_WALL = 166;
59
60 private static final int DEFAULTCOUNTER = 10;
61
62 private boolean goFast = false;
63
64
65 enum State { NOTHING, LEFT, RIGHT };
66
67
68
69 State state;
70
71
72 int counter;
73
74
75 boolean convexTurning;
76
77 private boolean raysReady;
78 private HashMap<String, Future<AutoTraceRay>> myFutureRays;
79
80
81 protected static final String NLEFTFRONT = "wleftfront";
82 protected static final String NLEFT = "wleft";
83 protected static final String NRIGHTFRONT = "wrightfront";
84 protected static final String NRIGHT = "wright";
85 protected static final String NFRONT = "wfront";
86
87 Random random = new Random();
88
89
90
91
92 AutoTraceRay nleft, nright, nleftfront, nrightfront, nfront;
93
94
95
96
97 int shortSideRayLength;
98 int shortSideFrontRayLength;
99 int longSideRayLength;
100 int longSideFrontRayLength;
101 int shortFrontRayLength;
102 int longFrontRayLength;
103
104
105
106
107
108
109
110
111 public WallFollowingSteer(UT2004Bot bot, RaycastingManager rayManager, SteeringProperties newProperties) {
112 botself = bot;
113 this.rayManager = rayManager;
114 setProperties(newProperties);
115 state = State.NOTHING;
116 counter = 0;
117 convexTurning = false;
118 prepareRays();
119 }
120
121
122
123
124
125
126 public WallFollowingSteer(UT2004Bot bot, RaycastingManager rayManager) {
127 botself = bot;
128 this.rayManager = rayManager;
129 setProperties(new WallFollowingProperties());
130 state = State.NOTHING;
131 counter = 0;
132 convexTurning = false;
133 prepareRays();
134 }
135
136
137
138
139 private void prepareRays() {
140
141
142 int shortLength = 8;
143 int longLength = 12;
144
145 shortSideRayLength = (int) (UnrealUtils.CHARACTER_COLLISION_RADIUS * shortLength * DISTANCE_FROM_THE_WALL / 166f);
146 longSideRayLength = (int) (UnrealUtils.CHARACTER_COLLISION_RADIUS * longLength * DISTANCE_FROM_THE_WALL / 166f);
147 shortSideFrontRayLength = (int) (UnrealUtils.CHARACTER_COLLISION_RADIUS * shortLength * 2 * DISTANCE_FROM_THE_WALL / 166f);
148 longSideFrontRayLength = (int) (UnrealUtils.CHARACTER_COLLISION_RADIUS * longLength * 2 * DISTANCE_FROM_THE_WALL / 166f);
149 shortFrontRayLength = (int) (UnrealUtils.CHARACTER_COLLISION_RADIUS * shortLength * Math.sqrt(3) * DISTANCE_FROM_THE_WALL / 166f);
150 longFrontRayLength = (int) (UnrealUtils.CHARACTER_COLLISION_RADIUS * longLength * Math.sqrt(3) * DISTANCE_FROM_THE_WALL / 166f);
151
152
153 LinkedList<SteeringRay> rayList = new LinkedList<SteeringRay>();
154 rayList.add(new SteeringRay(NLEFT, new Vector3d(0, -1, 0), longSideRayLength));
155 rayList.add(new SteeringRay(NLEFTFRONT, new Vector3d(Math.sqrt(3), -1, 0), longSideFrontRayLength));
156 rayList.add(new SteeringRay(NRIGHTFRONT, new Vector3d(Math.sqrt(3), 1, 0), longSideFrontRayLength));
157 rayList.add(new SteeringRay(NRIGHT, new Vector3d(0, 1, 0), longSideRayLength));
158 rayList.add(new SteeringRay(NFRONT, new Vector3d(1, 0, 0), longFrontRayLength));
159 rayManager.addRays(SteeringType.WALL_FOLLOWING, rayList, this);
160 raysReady = false;
161
162 }
163
164
165 public void flagRaysChanged() {
166 myFutureRays = rayManager.getMyFutureRays(SteeringType.WALL_FOLLOWING);
167 raysReady = false;
168 listenToRays();
169 }
170
171 private void listenToRays() {
172 for(String rayId : myFutureRays.keySet()) {
173 Future<AutoTraceRay> fr = myFutureRays.get(rayId);
174 if (fr.isDone()) {
175
176 try {
177 if (rayId.equals(NLEFTFRONT)) {
178 nleftfront = fr.get();
179 } else if (rayId.equals(NRIGHTFRONT)) {
180 nrightfront = fr.get();
181 } else if (rayId.equals(NLEFT)) {
182 nleft = fr.get();
183 } else if (rayId.equals(NRIGHT)) {
184 nright = fr.get();
185 } else if (rayId.equals(NFRONT)) {
186 nfront = fr.get();
187 }
188 raysReady = true;
189 } catch (InterruptedException ex) {
190 Logger.getLogger(ObstacleAvoidanceSteer.class.getName()).log(Level.SEVERE, null, ex);
191 } catch (ExecutionException ex) {
192 Logger.getLogger(ObstacleAvoidanceSteer.class.getName()).log(Level.SEVERE, null, ex);
193 }
194 } else {
195
196 }
197 }
198 }
199
200
201
202
203
204
205 public Vector3d run(Vector3d scaledActualVelocity, RefBoolean wantsToGoFaster, RefBoolean wantsToStop, Location focus) {
206
207
208
209 wantsToGoFaster.setValue(false);
210
211 Vector3d nextVelocity = new Vector3d(0,0,0);
212
213 if (!raysReady) {
214 listenToRays();
215 return nextVelocity;
216 }
217
218
219 Vector3d botToHitLocation;
220
221
222 Vector3d normal;
223
224
225 double multiplier;
226
227
228 Vector3d actualVelocity = botself.getVelocity().getVector3d();
229
230
231 boolean shortrays = false;
232
233
234 boolean sensornLeft = false;
235 boolean sensornRight = false;
236 boolean sensornLeftFront = false;
237 boolean sensornRightFront = false;
238 boolean sensornFront = false;
239
240
241 if (nleftfront != null)
242 sensornLeftFront = nleftfront.isResult();
243 if (nrightfront != null)
244 sensornRightFront = nrightfront.isResult();
245 if (nleft != null)
246 sensornLeft = nleft.isResult();
247 if (nright != null)
248 sensornRight = nright.isResult();
249 if (nfront != null)
250 sensornFront = nfront.isResult();
251
252
253
254
255
256
257 if (state == State.NOTHING) {
258
259
260 if (sensornLeft && sensornLeftFront) {
261 state = State.LEFT;
262 counter = DEFAULTCOUNTER;
263 } else if (sensornRight && sensornRightFront) {
264 state = State.RIGHT;
265 counter = DEFAULTCOUNTER;
266 } else if (sensornFront) {
267 if (frontCollisions) {
268 botToHitLocation = new Vector3d(nfront.getHitLocation().x - botself.getLocation().x, nfront.getHitLocation().y - botself.getLocation().y, 0);
269 normal = nfront.getHitNormal();
270 if (Math.PI - normal.angle(actualVelocity) < Math.PI/5) {
271 boolean turnLeft;
272 if (normal.angle(actualVelocity) == 180) {
273 turnLeft = random.nextBoolean();
274 if (SteeringManager.DEBUG) {
275 System.out.println("Wall exactly front collision.");
276 }
277 } else {
278 turnLeft = SteeringTools.pointIsLeftFromTheVector(actualVelocity, normal);
279 if (SteeringManager.DEBUG) {
280 System.out.println("Wall nearly front collision.");
281 }
282 }
283 if (SteeringManager.DEBUG) {
284 System.out.println("We turn left " + turnLeft);
285 }
286 Vector3d turn = SteeringTools.getTurningVector(actualVelocity, turnLeft);
287 turn.normalize();
288 turn.scale(0.5);
289 normal.add(turn);
290 normal.normalize();
291 multiplier = Math.pow(((longFrontRayLength - botToHitLocation.length()) * 2f / longFrontRayLength), orderOfTheForce);
292 normal.scale(multiplier * wallForce);
293 nextVelocity.add((Tuple3d) normal);
294 return nextVelocity;
295 }
296 }
297 }
298 } else if (state == State.LEFT) {
299 if (sensornLeft && sensornLeftFront) {
300 counter = DEFAULTCOUNTER;
301 }
302 } else if (state == State.RIGHT) {
303 if (sensornRight && sensornRightFront) {
304 counter = DEFAULTCOUNTER;
305 }
306 }
307
308
309
310
311 if (justMySide) {
312 if (state.equals(State.LEFT)) {
313 sensornRight = false;
314 sensornRightFront = false;
315 } else if (state.equals(State.RIGHT)) {
316 sensornLeft = false;
317 sensornLeftFront = false;
318 }
319 }
320
321
322
323
324 if (goFast) {
325 if (sensornFront) {
326 wantsToGoFaster.setValue(false);
327 } else {
328 wantsToGoFaster.setValue(true);
329 }
330 } else {
331 if (!shortrays) {
332 wantsToGoFaster.setValue(true);
333 } else {
334 wantsToGoFaster.setValue(false);
335 }
336 }
337
338
339
340
341
342
343
344
345
346 if (sensornLeft) {
347
348 botToHitLocation = new Vector3d(nleft.getHitLocation().x - botself.getLocation().x, nleft.getHitLocation().y - botself.getLocation().y, 0);
349 normal = nleft.getHitNormal();
350 multiplier = Math.pow(1 - (longSideRayLength - botToHitLocation.length()) / longSideRayLength, orderOfTheForce);
351 normal.scale(attractiveForceWeight * multiplier * wallForce);
352 nextVelocity.sub((Tuple3d) normal);
353
354
355
356 if (botToHitLocation.length() < shortSideRayLength) {
357 shortrays = true;
358 multiplier = Math.pow(((shortSideRayLength - botToHitLocation.length()) * 2f / shortSideRayLength), orderOfTheForce);
359 normal.normalize();
360 normal.scale(repulsiveForceWeight * multiplier * wallForce);
361 nextVelocity.add((Tuple3d) normal);
362
363 }
364 }
365
366 if (sensornRight) {
367
368 botToHitLocation = new Vector3d(nright.getHitLocation().x - botself.getLocation().x, nright.getHitLocation().y - botself.getLocation().y, 0);
369 normal = nright.getHitNormal();
370 multiplier = Math.pow(1 - (longSideRayLength - botToHitLocation.length()) / longSideRayLength, orderOfTheForce);
371 normal.scale(attractiveForceWeight * multiplier * wallForce);
372 nextVelocity.sub((Tuple3d) normal);
373
374
375
376 if (botToHitLocation.length() < shortSideRayLength) {
377 shortrays = true;
378 multiplier = Math.pow(((shortSideRayLength - botToHitLocation.length()) * 2f / shortSideRayLength), orderOfTheForce);
379 normal.normalize();
380 normal.scale(repulsiveForceWeight * multiplier * wallForce);
381 nextVelocity.add((Tuple3d) normal);
382
383 }
384 }
385 if (sensornLeftFront) {
386
387 botToHitLocation = new Vector3d(nleftfront.getHitLocation().x - botself.getLocation().x, nleftfront.getHitLocation().y - botself.getLocation().y, 0);
388 normal = nleftfront.getHitNormal();
389 multiplier = Math.pow(1 - (longSideFrontRayLength - botToHitLocation.length()) / longSideFrontRayLength, orderOfTheForce);
390 normal.scale(attractiveForceWeight * multiplier * wallForce);
391 nextVelocity.sub((Tuple3d) normal);
392
393
394
395 if (botToHitLocation.length() < shortSideFrontRayLength) {
396 shortrays = true;
397 multiplier = Math.pow(((shortSideFrontRayLength - botToHitLocation.length()) * 2f / shortSideFrontRayLength), orderOfTheForce);
398 normal.normalize();
399 normal.scale(repulsiveForceWeight * multiplier * wallForce);
400 nextVelocity.add((Tuple3d) normal);
401
402 }
403
404 }
405 if (sensornRightFront) {
406
407 botToHitLocation = new Vector3d(nrightfront.getHitLocation().x - botself.getLocation().x, nrightfront.getHitLocation().y - botself.getLocation().y, 0);
408 normal = nrightfront.getHitNormal();
409 multiplier = Math.pow(1 - (longSideFrontRayLength - botToHitLocation.length()) / longSideFrontRayLength, orderOfTheForce);
410 normal.scale(attractiveForceWeight * multiplier * wallForce);
411 nextVelocity.sub((Tuple3d) normal);
412
413
414
415 if (botToHitLocation.length() < shortSideFrontRayLength) {
416 shortrays = true;
417 multiplier = Math.pow(((shortSideFrontRayLength - botToHitLocation.length()) * 2f / shortSideFrontRayLength), orderOfTheForce);
418 normal.normalize();
419 normal.scale(repulsiveForceWeight * multiplier * wallForce);
420 nextVelocity.add((Tuple3d) normal);
421
422 }
423 }
424 if (sensornFront) {
425
426 botToHitLocation = new Vector3d(nfront.getHitLocation().x - botself.getLocation().x, nfront.getHitLocation().y - botself.getLocation().y, 0);
427 normal = nfront.getHitNormal();
428
429
430
431
432
433 if (botToHitLocation.length() < shortFrontRayLength) {
434 shortrays = true;
435 multiplier = Math.pow(((shortFrontRayLength - botToHitLocation.length()) * 2f / shortFrontRayLength), orderOfTheForce);
436 normal.normalize();
437 normal.scale(repulsiveForceWeight * 3 * multiplier * wallForce);
438
439 nextVelocity.add((Tuple3d) normal);
440 }
441 }
442
443
444 boolean nextTurning = false;
445
446
447
448 if (specialDetection) {
449 if (state.equals(State.LEFT)) {
450 if ( (sensornFront && (convexTurning || (Math.abs(nfront.getHitNormal().angle(actualVelocity) - Math.PI) < Math.PI/4)) ) ||
451 ( (sensornLeftFront && (Math.abs(nleftfront.getHitNormal().angle(actualVelocity) - Math.PI) < Math.PI/2) && convexTurning) ||
452 (sensornLeftFront && (Math.abs(nleftfront.getHitNormal().angle(actualVelocity) - Math.PI) < Math.PI/4)) ||
453 (sensornLeft && (Math.abs(nleft.getHitNormal().angle(actualVelocity) - Math.PI) < Math.PI/2) && convexTurning) ) ) {
454 if (SteeringManager.DEBUG) System.out.println("Left convex edge. " + SteeringTools.radiansToDegrees(nleftfront.getHitNormal().angle(actualVelocity)));
455 if (SteeringManager.DEBUG) {
456 if (sensornFront) System.out.println("Left convex edge front collision. " + SteeringTools.radiansToDegrees(nfront.getHitNormal().angle(actualVelocity)));
457 else if (sensornLeftFront) System.out.println("Left convex edge side front. " + SteeringTools.radiansToDegrees(nleftfront.getHitNormal().angle(actualVelocity)));
458 else System.out.println("Left convex edge side. " + SteeringTools.radiansToDegrees(nleft.getHitNormal().angle(actualVelocity)));
459 }
460
461 nextTurning = true;
462 double k = 1;
463 if (sensornFront) {
464 k = nfront.getHitNormal().angle(actualVelocity) / Math.PI;
465 }
466 else if (sensornLeftFront) {
467 k = 0.6*nleftfront.getHitNormal().angle(actualVelocity) / Math.PI;
468 }
469 else {
470 k = 0.3*nleft.getHitNormal().angle(actualVelocity) / Math.PI;
471 }
472 if (SteeringManager.DEBUG) {
473 System.out.println("Turning vector. " + k*SteeringTools.getTurningVector2(actualVelocity, false).length());
474 }
475 Vector3d turningVector = SteeringTools.getTurningVector2(actualVelocity, false);
476 turningVector.scale(k*convexEdgesForceWeight);
477
478
479 counter = DEFAULTCOUNTER;
480 convexTurning = nextTurning;
481 return turningVector;
482
483 }
484 } else if (state.equals(State.RIGHT)) {
485 if ( (sensornFront && (convexTurning || (Math.abs(nfront.getHitNormal().angle(actualVelocity) - Math.PI) < Math.PI/4)) ) ||
486 ( (sensornRightFront && (Math.abs(nrightfront.getHitNormal().angle(actualVelocity) - Math.PI) < Math.PI/2) && convexTurning) ||
487 (sensornRightFront && (Math.abs(nrightfront.getHitNormal().angle(actualVelocity) - Math.PI) < Math.PI/4)) ||
488 (sensornRight && (Math.abs(nright.getHitNormal().angle(actualVelocity) - Math.PI) < Math.PI/2) && convexTurning) ) ) {
489 if (SteeringManager.DEBUG) {
490 if (sensornFront) System.out.println("Right convex edge front collision. " + SteeringTools.radiansToDegrees(nfront.getHitNormal().angle(actualVelocity)));
491 else if (sensornRightFront) System.out.println("Right convex edge side front. " + SteeringTools.radiansToDegrees(nrightfront.getHitNormal().angle(actualVelocity)));
492 else System.out.println("Right convex edge side. " + SteeringTools.radiansToDegrees(nright.getHitNormal().angle(actualVelocity)));
493 }
494 nextTurning = true;
495 double k = 1;
496 if (sensornFront) {
497 k = nfront.getHitNormal().angle(actualVelocity) / Math.PI;
498 }
499 else if (sensornRightFront) {
500 k = 0.6*nrightfront.getHitNormal().angle(actualVelocity) / Math.PI;
501 }
502 else {
503 k = 0.3*nright.getHitNormal().angle(actualVelocity) / Math.PI;
504 }
505 if (SteeringManager.DEBUG) {
506 System.out.println("Turning vector. " + k*SteeringTools.getTurningVector2(actualVelocity, true).length());
507 }
508 Vector3d turningVector = SteeringTools.getTurningVector2(actualVelocity, true);
509 turningVector.scale(k*convexEdgesForceWeight);
510
511
512 counter = DEFAULTCOUNTER;
513 convexTurning = nextTurning;
514 return turningVector;
515
516 }
517 }
518 } else {
519
520 if (state == State.LEFT) {
521 if (sensornLeftFront && sensornFront) {
522
523
524 Vector3d turningVector = SteeringTools.getTurningVector2(actualVelocity, false);
525 turningVector.scale(convexEdgesForceWeight*0.8);
526 return turningVector;
527
528
529
530 }
531 } else if (state == State.RIGHT) {
532 if (sensornRightFront && sensornFront) {
533
534
535 Vector3d turningVector = SteeringTools.getTurningVector2(actualVelocity, true);
536 turningVector.scale(convexEdgesForceWeight*0.8);
537 return turningVector;
538
539
540
541 }
542 }
543 }
544
545
546
547
548
549
550
551
552 if (state == State.LEFT) {
553 if (!sensornLeft && !sensornLeftFront) {
554 if (SteeringManager.DEBUG) System.out.println("counter "+counter);
555 if (counter > 0) {
556 counter--;
557 if (SteeringManager.DEBUG) System.out.println("Left concave edge. ");
558 Vector3d turningVector = SteeringTools.getTurningVector2(actualVelocity, true);
559 if (convexTurning) turningVector.scale(0.5);
560 turningVector.scale(concaveEdgesForceWeight*0.8);
561 return turningVector;
562 } else {
563 state = State.NOTHING;
564 }
565 }
566 } else if (state == State.RIGHT) {
567 if (!sensornRight && !sensornRightFront) {
568 if (SteeringManager.DEBUG) System.out.println("counter "+counter);
569 if (counter > 0) {
570 counter--;
571 if (SteeringManager.DEBUG) System.out.println("Right concave edge. ");
572 Vector3d turningVector = SteeringTools.getTurningVector2(actualVelocity, false);
573 if (convexTurning) turningVector.scale(0.5);
574 turningVector.scale(concaveEdgesForceWeight*0.8);
575 return turningVector;
576
577
578 } else {
579 state = State.NOTHING;
580 }
581 }
582 }
583
584
585 convexTurning = nextTurning;
586 return nextVelocity;
587 }
588
589 @Override
590 public void setProperties(SteeringProperties newProperties) {
591 this.wallForce = ((WallFollowingProperties)newProperties).getWallForce();
592 this.orderOfTheForce = ((WallFollowingProperties)newProperties).getOrderOfTheForce();
593 this.attractiveForceWeight = ((WallFollowingProperties)newProperties).getAttractiveForceWeight();
594 this.repulsiveForceWeight = ((WallFollowingProperties)newProperties).getRepulsiveForceWeight();
595 this.concaveEdgesForceWeight = ((WallFollowingProperties)newProperties).getConcaveEdgesForceWeight();
596 this.convexEdgesForceWeight = ((WallFollowingProperties)newProperties).getConvexEdgesForceWeight();
597 this.justMySide = ((WallFollowingProperties)newProperties).isJustMySide();
598 this.specialDetection = ((WallFollowingProperties)newProperties).isSpecialDetection();
599 this.frontCollisions = ((WallFollowingProperties)newProperties).isFrontCollisions();
600 }
601
602 public WallFollowingProperties getProperties() {
603 WallFollowingProperties properties = new WallFollowingProperties();
604 properties.setWallForce(wallForce);
605 properties.setOrderOfTheForce(orderOfTheForce);
606 properties.setAttractiveForceWeight(attractiveForceWeight);
607 properties.setRepulsiveForceWeight(repulsiveForceWeight);
608 properties.setConcaveEdgesForceWeight(concaveEdgesForceWeight);
609 properties.setConvexEdgesForceWeight(convexEdgesForceWeight);
610 properties.setJustMySide(justMySide);
611 properties.setSpecialDetection(specialDetection);
612 properties.setFrontCollisions(frontCollisions);
613 return properties;
614 }
615 }