View Javadoc
1   package au.gov.amsa.animator;
2   
3   import java.awt.Color;
4   import java.awt.Graphics2D;
5   import java.awt.geom.AffineTransform;
6   import java.awt.geom.Point2D;
7   import java.text.DecimalFormat;
8   import java.util.Collection;
9   import java.util.Map;
10  import java.util.Set;
11  import java.util.concurrent.TimeUnit;
12  
13  import com.github.davidmoten.grumpy.core.Position;
14  import com.google.common.collect.Sets;
15  
16  import au.gov.amsa.risky.format.Fix;
17  
18  public class ViewRecentTracks implements View {
19  
20      final Set<ViewRecentTracksOption> options;
21  
22      public ViewRecentTracks(ViewRecentTracksOption... options) {
23          this.options = Sets.newHashSet(options);
24      }
25  
26      @Override
27      public void draw(Model model, Graphics2D g, AffineTransform worldToScreen) {
28          if (worldToScreen == null)
29              return;
30          long n = model.stepNumber();
31          int size = 20;
32          long r = n % size;
33          if (r > size / 2)
34              r = size - r;
35          g.setColor(Color.red);
36          // g.drawString("Hello", 100 + r, 100 + r);
37          // g.drawString("there", 200 + r, 150 - r);
38          // g.drawString("how", 130 + r, 180 - r);
39          Point2D.Float p = toScreen(worldToScreen, -35.25f, 149.0f);
40          g.drawString("Canberra", p.x - size / 4 + r, p.y - size / 4 + r);
41          g.setColor(Color.BLUE);
42          g.setFont(g.getFont().deriveFont(8f));
43          Map<Integer, Collection<Fix>> fixGroups = model.recent();
44  
45          DecimalFormat df = new DecimalFormat("0");
46  
47          for (Collection<Fix> fixes : fixGroups.values()) {
48              Long lastTime = null;
49              for (Fix fix : fixes) {
50                  lastTime = fix.time();
51              }
52              Point2D.Float previous = null;
53              Fix previousFix = null;
54              int i = 1;
55              for (Fix fix : fixes) {
56                  if (lastTime == null || fixes.size() == 1
57                          || fix.time() + TimeUnit.HOURS.toMillis(1) > lastTime) {
58                      double speedKnots = -1;
59                      if (previousFix != null) {
60                          double distanceKm = Position.create(previousFix.lat(), previousFix.lon())
61                                  .getDistanceToKm(Position.create(fix.lat(), fix.lon()));
62                          long timeDiffMs = fix.time() - previousFix.time();
63                          if (timeDiffMs > TimeUnit.MINUTES.toMillis(3)) {
64                              speedKnots = distanceKm / 1.852 * TimeUnit.HOURS.toMillis(1)
65                                      / timeDiffMs;
66                          }
67                      }
68                      g.setColor(Color.getHSBColor(0.7833f,
69                              (float) Math.pow(i / (double) fixes.size(), 2), 1f));
70                      Point2D.Float position = toScreen(worldToScreen, fix.lat(), fix.lon());
71                      if (previous != null) {
72                          g.drawLine(Math.round(previous.x), Math.round(previous.y),
73                                  Math.round(position.x), Math.round(position.y));
74                      }
75                      previous = position;
76                      previousFix = fix;
77                      if (i == fixes.size()) {
78                          final int sz = 2;
79                          g.drawArc(Math.round(position.x - sz / 2), Math.round(position.y - sz / 2),
80                                  sz, sz, 0, 360);
81                          if (speedKnots > 0) {
82                              if (options.contains(ViewRecentTracksOption.SHOW_SPEED))
83                                  g.drawString(df.format(speedKnots), position.x, position.y);
84                          }
85                      }
86                  }
87                  i++;
88              }
89          }
90      }
91  
92      static Point2D.Float toScreen(AffineTransform worldToScreen, float lat, float lon) {
93          Point2D.Float a = new Point2D.Float(lon, lat);
94          Point2D.Float b = new Point2D.Float();
95          worldToScreen.transform(a, b);
96          return b;
97      }
98  }