View Javadoc

1   package SocialSteeringsBeta;
2   
3   import SteeringProperties.SteeringProperties;
4   import SteeringStuff.RefBoolean;
5   import SteeringStuff.SteeringTools;
6   import cz.cuni.amis.pogamut.base3d.worldview.object.Location;
7   import cz.cuni.amis.pogamut.ut2004.bot.impl.UT2004Bot;
8   import java.util.ArrayList;
9   import javax.vecmath.Tuple3d;
10  import javax.vecmath.Vector3d;
11  
12  /**
13   *
14   * @author Petr
15   */
16  public class TriangleSteer implements ISocialSteering {
17  
18      protected UT2004Bot botself;
19      protected TriangleSteeringProperties properties;
20      private static final int KDefaultAttraction = 600;
21      private static final double K90deg = 90;
22      private static final double K360deg = 360;
23      private static final double K180deg = 180;
24      private static final double KMinimalDistance = 40;
25      private static final String KTowards = "towards";
26  
27      public TriangleSteer(UT2004Bot botself) {
28          this.botself = botself;
29  
30      }
31  
32      @Override
33      public Vector3d run(Vector3d scaledActualVelocity, RefBoolean wantsToGoFaster, RefBoolean wantsToStop, RefLocation focus) {
34          // <editor-fold defaultstate="collapsed" desc="debug">
35          if (properties == null) {
36              if (SOC_STEER_LOG.DEBUG) {
37                  SOC_STEER_LOG.AddLogLineWithDate("no properties", "triangleError");
38  
39              }
40          }// </editor-fold>
41  
42          Location newFocus = getFocus();
43          if (newFocus != null) {
44              focus.data = newFocus;
45          }
46  
47  
48          //returns ideal place where steered agent wants to stay...
49          Location targetLocation = WhereToGo(botself, properties);
50  
51          // Supposed velocity in the next tick of logic, after applying various steering forces to the bot.
52          SteeringResult nextVelocity = new SteeringResult(new Vector3d(0, 0, 0), 1);
53  
54          //we are able to compute ideal place...
55          if (targetLocation != null) {
56  
57  
58              // A vector from the bot to the target location.
59              targetLocation = new Location(targetLocation.x,targetLocation.y, botself.getLocation().z);
60              Vector3d vectorToTarget = targetLocation.sub(botself.getLocation()).asVector3d();
61  
62              double distFromTarget = vectorToTarget.length();
63              nextVelocity.setMult(distFromTarget / 100);
64              if (distFromTarget < KMinimalDistance) {
65                  wantsToStop.setValue(true);
66                  return new SteeringResult(new Vector3d(0, 0, 0), 1);
67              }
68  
69              double attractiveForce = KDefaultAttraction;//* (distFromTarget / KDefaultAttractionDistance);
70  
71              vectorToTarget.normalize();
72              vectorToTarget.scale(attractiveForce);
73              nextVelocity.add((Tuple3d) vectorToTarget);
74          }else
75          {
76              nextVelocity.setMult(1);
77          }
78          
79          //no need to scale, scaling is done within method attraction(...)
80          int botAttractiveForce = KDefaultAttraction / 6;
81  
82          Vector3d attractionFromFst = attraction(botself, properties.getFstBot(), 1.3);
83          Vector3d attractionFromSnd = attraction(botself, properties.getSndBot(), 1.3);
84          
85          attractionFromFst.scale(botAttractiveForce);
86          nextVelocity.add((Tuple3d) attractionFromFst);
87  
88          attractionFromSnd.scale(botAttractiveForce);
89          nextVelocity.add((Tuple3d) attractionFromSnd);
90  
91  
92  
93          wantsToGoFaster.setValue(false);
94          return nextVelocity;
95      }
96  
97      @Override
98      public void setProperties(SteeringProperties newProperties) {
99          properties = (TriangleSteeringProperties) newProperties;
100     }
101 
102     /**
103      *
104      * @param me
105      * @param propers
106      * @return Location which is suitable for all coditions described in parameter propers
107      */
108     
109     private Location WhereToGo(UT2004Bot me, TriangleSteeringProperties propers) {
110         UT2004Bot first = propers.getFstBot();
111         UT2004Bot second = propers.getSndBot();
112 
113 
114 
115         // <editor-fold defaultstate="collapsed" desc="debug">
116         if (SOC_STEER_LOG.DEBUG) {
117             SOC_STEER_LOG.AddLogLineWithDate(me.getName() + " " + me.getLocation().toString() + " --------------------------------------------", "triangle");
118             if (propers == null) {
119                 SOC_STEER_LOG.AddLogLineWithDate(me.getName() + "I have no properties!!!", "triangleError");
120             }
121         }
122 // </editor-fold>
123 
124         ArrayList<Location> edgePoints = new ArrayList<Location>();
125         Location S1 = first.getLocation();
126         Location S2 = second.getLocation();
127         int r1min = propers.getFstDistance().getMin();
128         int r1max = propers.getFstDistance().getMax();
129         int r2min = propers.getSndDistance().getMin();
130         int r2max = propers.getSndDistance().getMax();
131 
132 
133 
134         if (isSuitable(me.getLocation(), S1, S2, propers, 0)) {
135             SOC_STEER_LOG.AddLogLineWithDate(me.getName() + "is in suitable place.", "triangle");
136             return me.getLocation();
137         }
138         // <editor-fold defaultstate="collapsed" desc="heuristics">
139         double othersDistance = S1.getDistance2D(S2);
140         if (r1max + r2max < othersDistance) {
141             SOC_STEER_LOG.AddLogLineWithDate(me.getName() + "see: " + first.getName() + "to far from: " + second.getName(), "triangle");
142             float factor = (float) r1max / (float) (r1max + r2max); // rika jak daleko ma byt od 1
143             return S1.add((S2.sub(S1)).scale(factor));//bod na usecce S1 S2
144         }
145         // </editor-fold>
146 
147         // <editor-fold defaultstate="collapsed" desc="polomery uhlovych kruznic">
148         //vstup je uhel vystup jsou polomery opsanych kruznic
149         double r3min = 0;
150         double r3max = 0;
151         for (int i = 0; i < 2; i++) {
152             // <editor-fold defaultstate="collapsed" desc="debug">
153             if (SOC_STEER_LOG.DEBUG) {
154                 if (propers == null) {
155                     SOC_STEER_LOG.AddLogLine("nemam TP pro TS", SOC_STEER_LOG.KError);
156                 }
157                 if (propers.getAngle() == null) {
158                     SOC_STEER_LOG.AddLogLine("nemam uhel v TP", SOC_STEER_LOG.KError);
159                 }
160             }// </editor-fold>
161             double angle = i == 0 ? propers.getAngle().getMin() : propers.getAngle().getMax();
162             double gamma = angle < K90deg ? 2 * angle : K360deg - 2 * angle;
163             double alpha = (K180deg - gamma) / 2;
164             double s = S1.getDistance2D(S2);
165             double alphaRad = SteeringTools.degreesToRadians(alpha);
166             double cosAlpha = Math.cos(alphaRad);
167             double b = s / (2 * cosAlpha);
168             if (i == 0) {
169                 r3min = b;
170             } else {
171                 r3max = b;
172             }
173         }// </editor-fold>
174 
175         // <editor-fold defaultstate="collapsed" desc="stredy uhlovych kruznic">
176 //stredy kruznic co definuji spravny uhel;
177         Location S3max1 = null;
178         Location S3min1 = null;
179         Location S3max2 = null;
180         Location S3min2 = null;
181         Location[] tmp; // zapisuju do ni vystupy z commonPoints;
182 
183         tmp = SteeringTools.commonPoints(S2, r3max, S1, r3max);
184         if (tmp[0] != null) {
185             S3max1 = tmp[0];
186         }
187         if (tmp[1] != null) {
188             S3max2 = tmp[1];
189         }
190         tmp = SteeringTools.commonPoints(S2, r3min, S1, r3min);
191         if (tmp[0] != null) {
192             S3min1 = tmp[0];
193         }
194         if (tmp[1] != null) {
195             S3min2 = tmp[1];// </editor-fold>
196         }
197         // <editor-fold defaultstate="collapsed" desc="pruniky okrajovych kruznic ">
198         // <editor-fold defaultstate="collapsed" desc="S1 a S2 spolu">
199         // <editor-fold defaultstate="collapsed" desc="debug">
200         int edgeSize = edgePoints.size();
201         // </editor-fold>
202         tmp = SteeringTools.commonPoints(S1, r1min, S2, r2min);
203         if (tmp[0] != null) {
204             edgePoints.add(tmp[0]);
205         }
206         if (tmp[1] != null) {
207             edgePoints.add(tmp[1]);
208         }
209 
210         tmp = SteeringTools.commonPoints(S1, r1max, S2, r2min);
211         if (tmp[0] != null) {
212             edgePoints.add(tmp[0]);
213         }
214         if (tmp[1] != null) {
215             edgePoints.add(tmp[1]);
216         }
217 
218         tmp = SteeringTools.commonPoints(S1, r1max, S2, r2max);
219         if (tmp[0] != null) {
220             edgePoints.add(tmp[0]);
221         }
222         if (tmp[1] != null) {
223             edgePoints.add(tmp[1]);
224         }
225 
226         tmp = SteeringTools.commonPoints(S1, r1min, S2, r2max);
227         if (tmp[0] != null) {
228             edgePoints.add(tmp[0]);
229         }
230         if (tmp[1] != null) {
231             edgePoints.add(tmp[1]);
232         }
233         // <editor-fold defaultstate="collapsed" desc="debug">
234         if (SOC_STEER_LOG.DEBUG) {
235             if (edgeSize == edgePoints.size()) {
236                 SOC_STEER_LOG.AddLogLine(me.getName() + " no distance-circles cross", "triangle");
237                 SOC_STEER_LOG.AddLogLine("-  S1: " + S1 + " S2: " + S2 + " r1: " + r1min + "-" + r1max + " r2: " + r2min + "-" + r2max, "triangle");
238             }
239         }
240         edgeSize = edgePoints.size();
241         // </editor-fold>
242         // </editor-fold>
243 
244         // <editor-fold defaultstate="collapsed" desc="S3min1">
245 
246         if (S3min1 != null) {
247             tmp = SteeringTools.commonPoints(S3min1, r3min, S2, r2max);
248             if (tmp[0] != null) {
249                 edgePoints.add(tmp[0]);
250             }
251             if (tmp[1] != null) {
252                 edgePoints.add(tmp[1]);
253             }
254 
255             tmp = SteeringTools.commonPoints(S3min1, r3min, S2, r2min);
256             if (tmp[0] != null) {
257                 edgePoints.add(tmp[0]);
258             }
259             if (tmp[1] != null) {
260                 edgePoints.add(tmp[1]);
261             }
262 
263             tmp = SteeringTools.commonPoints(S3min1, r3min, S1, r1min);
264             if (tmp[0] != null) {
265                 edgePoints.add(tmp[0]);
266             }
267             if (tmp[1] != null) {
268                 edgePoints.add(tmp[1]);
269             }
270 
271             tmp = SteeringTools.commonPoints(S3min1, r3min, S1, r1max);
272             if (tmp[0] != null) {
273                 edgePoints.add(tmp[0]);
274             }
275             if (tmp[1] != null) {
276                 edgePoints.add(tmp[1]);
277             }
278             // <editor-fold defaultstate="collapsed" desc="debug">
279             if (SOC_STEER_LOG.DEBUG) {
280                 if (edgeSize == edgePoints.size()) {
281                     SOC_STEER_LOG.AddLogLine(me.getName() + " no S3min1 cross", "triangle");
282                     SOC_STEER_LOG.AddLogLine("-  S3min1: " + S3min1 + " r3min: " + r3min + " r1: " + r1min + "-" + r1max + " r2: " + r2min + "-" + r2max, "triangle");
283                 }
284             }
285             edgeSize = edgePoints.size();
286             // </editor-fold>
287         } else {
288             // <editor-fold defaultstate="collapsed" desc="debug">
289             if (SOC_STEER_LOG.DEBUG) {
290                 SOC_STEER_LOG.AddLogLine(me.getName() + " no S3min1", "triangle");
291             }// </editor-fold>
292         }
293 
294 // </editor-fold>
295 
296         // <editor-fold defaultstate="collapsed" desc="S3max1">
297         if (S3max1 != null) {
298             tmp = SteeringTools.commonPoints(S3max1, r3max, S2, r2max);
299             if (tmp[0] != null) {
300                 edgePoints.add(tmp[0]);
301             }
302             if (tmp[1] != null) {
303                 edgePoints.add(tmp[1]);
304             }
305 
306             tmp = SteeringTools.commonPoints(S3max1, r3max, S2, r2min);
307             if (tmp[0] != null) {
308                 edgePoints.add(tmp[0]);
309             }
310             if (tmp[1] != null) {
311                 edgePoints.add(tmp[1]);
312             }
313 
314             tmp = SteeringTools.commonPoints(S3max1, r3max, S1, r1min);
315             if (tmp[0] != null) {
316                 edgePoints.add(tmp[0]);
317             }
318             if (tmp[1] != null) {
319                 edgePoints.add(tmp[1]);
320             }
321 
322             tmp = SteeringTools.commonPoints(S3max1, r3max, S1, r1max);
323             if (tmp[0] != null) {
324                 edgePoints.add(tmp[0]);
325             }
326             if (tmp[1] != null) {
327                 edgePoints.add(tmp[1]);
328             }
329             // <editor-fold defaultstate="collapsed" desc="debug">
330             if (SOC_STEER_LOG.DEBUG) {
331                 if (edgeSize == edgePoints.size()) {
332                     SOC_STEER_LOG.AddLogLine(me.getName() + " no S3max1 cross", "triangle");
333                     SOC_STEER_LOG.AddLogLine("-  S3max1: " + S3max1 + " r3max: " + r3max + " r1: " + r1min + "-" + r1max + " r2: " + r2min + "-" + r2max, "triangle");
334                 }
335             }
336             edgeSize = edgePoints.size();
337             // </editor-fold>
338         } else {
339             // <editor-fold defaultstate="collapsed" desc="debug">
340             if (SOC_STEER_LOG.DEBUG) {
341                 SOC_STEER_LOG.AddLogLine(me.getName() + " no S3max1", "triangle");
342             }// </editor-fold>
343         }
344 
345         // </editor-fold>
346 
347         // <editor-fold defaultstate="collapsed" desc="S3min2">
348         if (S3min2 != null) {
349             tmp = SteeringTools.commonPoints(S3min2, r3min, S2, r2max);
350             if (tmp[0] != null) {
351                 edgePoints.add(tmp[0]);
352             }
353             if (tmp[1] != null) {
354                 edgePoints.add(tmp[1]);
355             }
356 
357             tmp = SteeringTools.commonPoints(S3min2, r3min, S2, r2min);
358             if (tmp[0] != null) {
359                 edgePoints.add(tmp[0]);
360             }
361             if (tmp[1] != null) {
362                 edgePoints.add(tmp[1]);
363             }
364 
365             tmp = SteeringTools.commonPoints(S3min2, r3min, S1, r1min);
366             if (tmp[0] != null) {
367                 edgePoints.add(tmp[0]);
368             }
369             if (tmp[1] != null) {
370                 edgePoints.add(tmp[1]);
371             }
372 
373             tmp = SteeringTools.commonPoints(S3min2, r3min, S1, r1max);
374             if (tmp[0] != null) {
375                 edgePoints.add(tmp[0]);
376             }
377             if (tmp[1] != null) {
378                 edgePoints.add(tmp[1]);
379             }
380             // <editor-fold defaultstate="collapsed" desc="debug">
381             if (SOC_STEER_LOG.DEBUG) {
382                 if (edgeSize == edgePoints.size()) {
383                     SOC_STEER_LOG.AddLogLine(me.getName() + " no S3min2 cross", "triangle");
384                     SOC_STEER_LOG.AddLogLine("-  S3min2: " + S3min2 + " r3min: " + r3min + " r1: " + r1min + "-" + r1max + " r2: " + r2min + "-" + r2max, "triangle");
385                 }
386             }
387             edgeSize = edgePoints.size();
388             // </editor-fold>
389         } else {
390             // <editor-fold defaultstate="collapsed" desc="debug">
391             if (SOC_STEER_LOG.DEBUG) {
392                 SOC_STEER_LOG.AddLogLine(me.getName() + " no S3min2", "triangle");
393             }// </editor-fold>
394         }
395 
396         // </editor-fold>
397 
398         // <editor-fold defaultstate="collapsed" desc="S3max2">
399         if (S3max2 != null) {
400             tmp = SteeringTools.commonPoints(S3max2, r3max, S2, r2max);
401             if (tmp[0] != null) {
402                 edgePoints.add(tmp[0]);
403             }
404             if (tmp[1] != null) {
405                 edgePoints.add(tmp[1]);
406             }
407 
408             tmp = SteeringTools.commonPoints(S3max2, r3max, S2, r2min);
409             if (tmp[0] != null) {
410                 edgePoints.add(tmp[0]);
411             }
412             if (tmp[1] != null) {
413                 edgePoints.add(tmp[1]);
414             }
415 
416             tmp = SteeringTools.commonPoints(S3max2, r3max, S1, r1min);
417             if (tmp[0] != null) {
418                 edgePoints.add(tmp[0]);
419             }
420             if (tmp[1] != null) {
421                 edgePoints.add(tmp[1]);
422             }
423 
424             tmp = SteeringTools.commonPoints(S3max2, r3max, S1, r1max);
425             if (tmp[0] != null) {
426                 edgePoints.add(tmp[0]);
427             }
428             if (tmp[1] != null) {
429                 edgePoints.add(tmp[1]);
430             }
431             // <editor-fold defaultstate="collapsed" desc="debug">
432             if (SOC_STEER_LOG.DEBUG) {
433                 if (edgeSize == edgePoints.size()) {
434                     SOC_STEER_LOG.AddLogLine(me.getName() + " no S3max2 cross", "triangle");
435                     SOC_STEER_LOG.AddLogLine("-  S3max2: " + S3max2 + " r3max: " + r3max + " r1: " + r1min + "-" + r1max + " r2: " + r2min + "-" + r2max, "triangle");
436                 }
437             }
438             // </editor-fold>
439         } else {
440             // <editor-fold defaultstate="collapsed" desc="debug">
441             if (SOC_STEER_LOG.DEBUG) {
442                 SOC_STEER_LOG.AddLogLine(me.getName() + " no S3max2", "triangle");
443             }// </editor-fold>
444         }
445 
446         // </editor-fold>
447         // </editor-fold>
448 
449         for (int i = 0; i < edgePoints.size(); i++) {
450             if (!isSuitable(edgePoints.get(i), S1, S2, propers, 8)) {
451                 edgePoints.set(i, null);
452             }
453         }
454 
455         Location result = calculateBest(edgePoints, me.getLocation(), propers);
456         // <editor-fold defaultstate="collapsed" desc="debug">
457         if (SOC_STEER_LOG.DEBUG && result == null) {
458             SOC_STEER_LOG.AddLogLineWithDate(me.getName() + ": no suitable edge points from total of:" + String.valueOf(edgePoints.size()), "triangleError");
459         }
460         if (SOC_STEER_LOG.DEBUG && result != null) {
461             SOC_STEER_LOG.AddLogLine(me.getName() + ": has best suitable edge point:" + result.toString()
462                     + "distance: " + String.valueOf(me.getLocation().getDistance2D(result)), "triangle");
463         }// </editor-fold>
464         if (result == null) {
465             if (Math.min(r1min, r2min) > Math.max(me.getLocation().getDistance2D(S2), me.getLocation().getDistance2D(S1))) {
466                 SOC_STEER_LOG.AddLogLineWithDate(me.getName() + " is to close to, going away from both", "triangle");
467                 Location mine = me.getLocation();
468                 Location middle = S1.add((S2.sub(S1)).scale(1 / 2));//stred usecky S1 S2
469                 return mine.add(middle.sub(mine).scale(-1));
470             }
471         }
472         // <editor-fold defaultstate="collapsed" desc="debug">
473         if (SOC_STEER_LOG.DEBUG) {
474             SOC_STEER_LOG.AddLogLine("--------------------------------------------", "triangle");
475         }
476 // </editor-fold>
477         return result;
478 
479     }
480 
481     /**
482      * @return true if point is suitable for steering conditions
483      */
484     private static boolean isSuitable(Location point, Location fst, Location snd, TriangleSteeringProperties props, double tolerance) {
485         if (props.getFstDistance().in((int) point.getDistance2D(fst), tolerance)
486                 && props.getSndDistance().in((int) point.getDistance2D(snd), tolerance)) {
487             double a = point.getDistance2D(fst);
488             double b = point.getDistance2D(snd);
489             double c = fst.getDistance2D(snd);
490             double gamma = Math.acos((c * c - a * a - b * b) / (-2 * a * b)) * (180 / Math.PI);
491             if (props.getAngle().in((int) gamma, tolerance / 5)) {
492                 // <editor-fold defaultstate="collapsed" desc="debug">
493                 if (SOC_STEER_LOG.DEBUG) {
494                     //SOC_STEER_LOG.AddLogLine("suitable: " + point.toString(), "triangle");
495                 }
496                 // </editor-fold>
497                 return true;
498 
499             } else {
500                 return false;
501             }
502         } else {
503             return false;
504         }
505     }
506 
507     /**
508      * @return best point in area of suitable points, usually the center of gravity
509      */
510     private static Location calculateBest(ArrayList<Location> edgePoints, Location me, TriangleSteeringProperties props) {
511 
512         Location avgL = new Location(0, 0, 0);
513         Location avgR = new Location(0, 0, 0);
514         int countL = 0;
515         int countR = 0;
516         Vector3d divider = new Vector3d(props.getFstBot().getLocation().x - props.getSndBot().getLocation().x,
517                 props.getFstBot().getLocation().y - props.getSndBot().getLocation().y, 0);
518         for (Location ll : edgePoints) {
519             if (ll == null) {
520                 continue;
521             }
522             Vector3d point = (ll.sub(props.getSndBot().getLocation())).asVector3d();
523             if (SteeringTools.pointIsLeftFromTheVector(point, divider)) {
524                 avgL = avgL.add(ll);
525                 countL++;
526             } else {
527                 avgR = avgR.add(ll);
528                 countR++;
529             }
530 
531         }
532         boolean Lsuit = false;
533         if (countL != 0) {
534             avgL = avgL.scale(1 / (double) countL);
535             if (isSuitable(avgL, props.getFstBot().getLocation(), props.getSndBot().getLocation(), props, 1)) {
536                 // <editor-fold defaultstate="collapsed" desc="debug">
537                 if (SOC_STEER_LOG.DEBUG) {
538                     SOC_STEER_LOG.AddLogLine("suitable těžiště L: " + avgL.toString(), "triangle");
539                 }
540                 // </editor-fold>
541                 Lsuit = true;
542             }
543         }
544         boolean Rsuit = false;
545         if (countR != 0) {
546             avgR = avgR.scale(1 / (double) countR);
547             if (isSuitable(avgR, props.getFstBot().getLocation(), props.getSndBot().getLocation(), props, 1)) {
548                 // <editor-fold defaultstate="collapsed" desc="debug">
549                 if (SOC_STEER_LOG.DEBUG) {
550                     SOC_STEER_LOG.AddLogLine("suitable těžiště R: " + avgR.toString(), "triangle");
551                 }
552                 // </editor-fold>
553                 Rsuit = true;
554             }
555 
556         }
557 
558         if ((Lsuit && avgL.getDistance2D(me) < avgR.getDistance2D(me) && Rsuit) || (Lsuit && !Rsuit)) {
559             return avgL;
560         } else if ((Rsuit && !Lsuit) || (Rsuit && avgL.getDistance2D(me) >= avgR.getDistance2D(me) && Lsuit)) {
561             return avgR;
562         }
563 
564 
565         Location best = null;
566         double min = Integer.MAX_VALUE;
567         for (Location p : edgePoints) {
568             if (p == null) {
569                 continue;
570             }
571             double next = me.getDistance2D(p);
572             if (next < min) {
573                 best = p;
574                 min = next;
575             }
576         }
577         if (best == null) {
578             // <editor-fold defaultstate="collapsed" desc="debug">
579             if (SOC_STEER_LOG.DEBUG) {
580                 SOC_STEER_LOG.AddLogLine("nenasli jsme vhodny bod, tzn s nami hybou uz jen pritazlivo odpudive sily vuci dalsim postavam ", "triangleError");
581             }
582             // </editor-fold>
583         }
584         return best;
585     }
586 
587     /**
588      * returns attractive or distractive force between agents
589      *
590      * @param treshhold ideally bigger then 1... like 1.3 1.6
591      */
592     private Vector3d attraction(UT2004Bot botself, UT2004Bot other, double trashhold) {
593         trashhold = trashhold < 1 ? 1 : trashhold;
594         double max = properties.getFstDistance().getMax();
595         double min = properties.getFstDistance().getMin();
596         double actual = botself.getLocation().getDistance2D(other.getLocation());
597         Vector3d result = new Vector3d(0, 0, 0);
598         if (actual > max * trashhold) {
599             result = new Vector3d(other.getLocation().x - botself.getLocation().x,
600                     other.getLocation().y - botself.getLocation().y, 0);
601             result.normalize();
602             result.scale(actual / max);
603             // <editor-fold defaultstate="collapsed" desc="debug">
604             if (SOC_STEER_LOG.DEBUG) {
605                 SOC_STEER_LOG.AddLogLine("!! " + botself.getName() + ": too far from " + other.getName() + " --strength " + result.length(), "triangle");
606             }
607             // </editor-fold>
608         }
609         if (actual < min * trashhold) {
610             result = new Vector3d(botself.getLocation().x - other.getLocation().x,
611                     botself.getLocation().y - other.getLocation().y, 0);
612             result.normalize();
613             result.scale(min / actual);
614             // <editor-fold defaultstate="collapsed" desc="debug">
615             if (SOC_STEER_LOG.DEBUG) {
616                 SOC_STEER_LOG.AddLogLine("!! " + botself.getName() + ": too close to " + other.getName() + " --strength " + result.length(), "triangle");
617             }
618             // </editor-fold>
619         }
620         return result;
621     }
622     
623     private Location getFocus() {
624 
625 
626         if (properties.getHeadingType() == null) {
627             return null; //impicit behaviour;
628         }
629         String headingType = properties.getHeadingType();
630         UT2004Bot fst = properties.getFstBot();
631         UT2004Bot snd = properties.getSndBot();
632         Interval headingValue = properties.getHeadingValue();
633         int fromFst = 0;
634         boolean headingToAgents = false;
635 
636         if (headingType.compareTo(fst.getName().substring(0, 1)) == 0) {
637             fromFst = 100 - headingValue.avg();
638             headingToAgents = true;
639         } else if (headingType.compareTo(snd.getName().substring(0, 1)) == 0) {
640             fromFst = headingValue.avg();
641             headingToAgents = true;
642         }
643         if (headingToAgents) {
644             Location fstL = fst.getLocation();
645             Location sndL = snd.getLocation();
646 
647             Location shift = (fstL.sub(sndL)).scale(((double) fromFst) / 100);
648             Location result = sndL.add(shift);
649             return result;
650         } else if (headingType.compareTo(KTowards) == 0) {
651             return null;
652         } else {
653             return null;
654         }
655 
656 
657     }
658 
659     @Override
660     public SteeringResult runSocial(Vector3d scaledActualVelocity, RefBoolean wantsToGoFaster, RefBoolean wantsToStop, RefLocation focus) {
661         return (SteeringResult) this.run(scaledActualVelocity, wantsToGoFaster, wantsToStop, focus);
662     }
663 }