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
37
38
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 }