package org.syzygy.gps.midp; import org.syzygy.gps.CoordinateMapper; import org.syzygy.gps.EventListener; import org.syzygy.gps.Location; import org.syzygy.gps.Util; import javax.microedition.lcdui.Canvas; import javax.microedition.lcdui.Font; import javax.microedition.lcdui.Graphics; import javax.microedition.lcdui.Image; import java.io.IOException; final class LocationCanvas extends Canvas { public LocationCanvas(CoordinateMapper mapper, EventListener listener) { this.listener = listener; this.mapper = mapper; } protected void keyPressed(int keyCode) { switch ((char) keyCode) { case '0': listener.exit(); return; case '1': painters[ZOOM] = new Zoomer("Zoom in from " + tile.getZoom()); listener.zoomIn(); return; case '2': painters[ZOOM] = new Zoomer("Zoom out from " + tile.getZoom()); listener.zoomOut(); return; case '4': listener.slowDown(); return; case '5': listener.speedUp(); return; } int action = getGameAction(keyCode); if (action != 0) { switch (action) { case FIRE: listener.pan(0, 0); break; case UP: listener.pan(0, -1); break; case DOWN: listener.pan(0, 1); break; case RIGHT: listener.pan(1, 0); break; case LEFT: listener.pan(-1, 0); break; } } } public void setTile(CoordinateMapper.Tile t) throws IOException { if (!t.equals(tile)) { tile = t; byte[] mapData = tile.getMap(); Image map = Image.createImage(mapData, 0, mapData.length); mw = map.getWidth(); mh = map.getHeight(); painters[MAP] = new ImagePainter(map, mapper.getLongitudinalDistance(tile)); updateXY(); repaint(); } } public void setLocation(Location l) { if (!l.samePosition(location)) { location = l; painters[POS] = new PositionPainter(l); painters[INFO] = new InfoPainter(l); updateXY(); repaint(); } } private void updateXY() { if (tile != null && location != null) { x = mapper.getScreenX(tile, location.getLongitude(), mw); y = mapper.getScreenY(tile, location.getLatitude(), mh); } } private int translateX() { int vw = getWidth(); return mw > vw && x > vw ? vw - mw : 0; } private int translateY(int fh) { int vh = getHeight() - fh; return mh > vh && y > vh ? vh - mh : 0; } private interface Painter { void paint(Graphics g); } private final class Zoomer implements Painter { private final String label; private final Painter map; public Zoomer(String label) { this.label = label; this.map = painters[MAP]; } public void paint(Graphics g) { Font f = Font.getDefaultFont(); int w = f.stringWidth(label); int h = f.getHeight(); int c = g.getColor(); g.setColor(0, 0, 0); g.fillRect(0, 0, w, h); g.setColor(c); g.drawString(label, 0, 0, Graphics.TOP | Graphics.LEFT); if (map != painters[MAP]) painters[ZOOM] = null; } } private final class ImagePainter implements Painter { private final Image map; private final double mapWidth; public ImagePainter(Image map, double mapWidth) { this.map = map; this.mapWidth = mapWidth; } public void paint(Graphics g) { int fontHeight = g.getFont().getHeight(); g.drawImage(map, translateX(), translateY(g.getFont().getHeight()), Graphics.TOP | Graphics.LEFT); double dx = mapWidth / 2; double d = round(dx); String u = d >= 1000 ? "km" : "m"; int v = (int) (d >= 1000 ? d / 1000 : d); int dd = (int) ((d / dx * (int) mw / 2)); g.setColor(0, 0, 255); int ox = fontHeight, ex = ox + dd, oy = fontHeight; g.drawLine(ox, oy, ex, oy); g.drawLine(ox, oy - fontHeight / 2, ox, oy + fontHeight / 2); g.drawLine(ex, oy - fontHeight / 2, ex, oy + fontHeight / 2); g.drawString(v + u, ex, oy, Graphics.BOTTOM | Graphics.HCENTER); } private double round(double x) { int e = 0; for (; x > 10; e++) x /= 10; x = Math.floor(x); while (e-- > 0) x *= 10; return x; } } private final class InfoPainter implements Painter { private final String time; private final boolean isError; private final String speed, altitude; public InfoPainter(Location location) { this.time = location.getGpsTime(); this.isError = location.getIsError(); this.speed = Util.formatDouble(location.getSpeedKmh(), 5, ""); this.altitude = Util.formatDouble(location.getAltitude(), 5, ""); } public void paint(Graphics g) { g.setColor(0, 0, 0); int fontHeight = g.getFont().getHeight(); int w = getWidth(), x = w / 2, h = getHeight(); g.fillRect(0, h - fontHeight, w, fontHeight); g.setColor(255, 255, 255); if (time != null) g.drawString(time + (isError ? "E" : " "), 0, h, Graphics.LEFT | Graphics.BOTTOM); if (speed != null) g.drawString(speed + "kmh", x, h, Graphics.HCENTER | Graphics.BOTTOM); if (altitude != null) g.drawString(altitude + "m", w, h, Graphics.RIGHT | Graphics.BOTTOM); } } private final class PositionPainter implements Painter { private final Location location; private final int DIA = 4, LEN = 10; public PositionPainter(Location location) { this.location = location; } public void paint(Graphics g) { g.setColor(255, 0, 0); int tx = translateX(); int ty = translateY(g.getFont().getHeight()); g.translate(tx, ty); double orientation = Math.toRadians(location.getCourse()); g.fillArc(x - DIA / 2, y - DIA / 2, DIA, DIA, 0, 360); int lx = (int) (LEN * Math.sin(orientation)), ly = (int) (LEN * Math.cos(orientation)); g.drawLine(x, y, x + lx, y - ly); } } protected void paint(Graphics g) { for (int i = 0; i < painters.length; i++) if (painters[i] != null) painters[i].paint(g); } private CoordinateMapper.Tile tile; private Location location; private int mw, mh; private int x, y; private final EventListener listener; private final CoordinateMapper mapper; private final Painter[] painters = new Painter[4]; private final int MAP = 0; private final int ZOOM = 1; private final int INFO = 2; private final int POS = 3; }