From 70d15df43ea0d57c3fe237211098645733048c45 Mon Sep 17 00:00:00 2001 From: Ben Burwell Date: Sat, 19 Nov 2016 22:14:13 -0500 Subject: Add airports --- .../java/com/benburwell/planes/data/Airport.java | 198 +++++++++++++++++++++ .../com/benburwell/planes/data/AirportStore.java | 30 ++++ .../benburwell/planes/data/NavigationAidStore.java | 4 + .../java/com/benburwell/planes/gui/Main1090.java | 20 ++- .../planes/gui/NavigationAidComponent.java | 26 +++ .../planes/gui/NavigationAidsTableModel.java | 57 ++++++ .../planes/gui/aircraftmap/AircraftMap.java | 72 +++++++- .../gui/aircraftmap/AircraftMapComponent.java | 31 ++-- .../planes/gui/aircraftmap/GeoPoint.java | 6 + .../benburwell/planes/gui/aircraftmap/Plane.java | 126 ------------- .../gui/aircraftmap/symbols/AirportSymbol.java | 48 +++++ .../planes/gui/aircraftmap/symbols/NDBSymbol.java | 42 +++++ .../gui/aircraftmap/symbols/PlaneSymbol.java | 129 ++++++++++++++ .../gui/aircraftmap/symbols/VORDMESymbol.java | 29 +++ .../planes/gui/aircraftmap/symbols/VORSymbol.java | 49 +++++ .../gui/aircraftmap/symbols/VORTACSymbol.java | 32 ++++ 16 files changed, 751 insertions(+), 148 deletions(-) create mode 100644 src/main/java/com/benburwell/planes/data/Airport.java create mode 100644 src/main/java/com/benburwell/planes/data/AirportStore.java create mode 100644 src/main/java/com/benburwell/planes/gui/NavigationAidComponent.java create mode 100644 src/main/java/com/benburwell/planes/gui/NavigationAidsTableModel.java delete mode 100644 src/main/java/com/benburwell/planes/gui/aircraftmap/Plane.java create mode 100644 src/main/java/com/benburwell/planes/gui/aircraftmap/symbols/AirportSymbol.java create mode 100644 src/main/java/com/benburwell/planes/gui/aircraftmap/symbols/NDBSymbol.java create mode 100644 src/main/java/com/benburwell/planes/gui/aircraftmap/symbols/PlaneSymbol.java create mode 100644 src/main/java/com/benburwell/planes/gui/aircraftmap/symbols/VORDMESymbol.java create mode 100644 src/main/java/com/benburwell/planes/gui/aircraftmap/symbols/VORSymbol.java create mode 100644 src/main/java/com/benburwell/planes/gui/aircraftmap/symbols/VORTACSymbol.java diff --git a/src/main/java/com/benburwell/planes/data/Airport.java b/src/main/java/com/benburwell/planes/data/Airport.java new file mode 100644 index 0000000..92e43bc --- /dev/null +++ b/src/main/java/com/benburwell/planes/data/Airport.java @@ -0,0 +1,198 @@ +package com.benburwell.planes.data; + +import org.apache.commons.csv.CSVRecord; + +/** + * Created by ben on 11/19/16. + */ +public class Airport { + private int id; + private String ident; + private String type; + private String name; + private double latitude; + private double longitude; + private int elevation; + private String continent; + private String isoCountry; + private String isoRegion; + private String municipality; + private boolean scheduledService; + private String gpsCode; + private String iataCode; + private String localCode; + private String homeLink; + private String wikipediaLink; + private String keywords; + + public Airport(CSVRecord record) { + this.setId(Integer.valueOf(record.get("id"))); + this.setIdent(record.get("ident")); + this.setType(record.get("type")); + this.setName(record.get("name")); + try { + this.setLatitude(Double.valueOf(record.get("latitude_deg"))); + } catch (NumberFormatException ignored) {} + try { + this.setLongitude(Double.valueOf(record.get("longitude_deg"))); + } catch (NumberFormatException ignored) {} + try { + this.setElevation(Integer.valueOf(record.get("elevation_ft"))); + } catch (NumberFormatException ignored) {} + this.setContinent(record.get("continent")); + this.setIsoCountry(record.get("iso_country")); + this.setIsoRegion(record.get("iso_region")); + this.setMunicipality(record.get("municipality")); + this.setScheduledService(record.get("scheduled_service").equals("yes")); + this.setGpsCode(record.get("gps_code")); + this.setIataCode(record.get("iata_code")); + this.setLocalCode(record.get("local_code")); + this.setHomeLink(record.get("home_link")); + this.setWikipediaLink(record.get("wikipedia_link")); + this.setKeywords(record.get("keywords")); + } + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public String getIdent() { + return ident; + } + + public void setIdent(String ident) { + this.ident = ident; + } + + public String getType() { + return type; + } + + public void setType(String type) { + this.type = type; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public double getLatitude() { + return latitude; + } + + public void setLatitude(double latitude) { + this.latitude = latitude; + } + + public double getLongitude() { + return longitude; + } + + public void setLongitude(double longitude) { + this.longitude = longitude; + } + + public int getElevation() { + return elevation; + } + + public void setElevation(int elevation) { + this.elevation = elevation; + } + + public String getContinent() { + return continent; + } + + public void setContinent(String continent) { + this.continent = continent; + } + + public String getIsoCountry() { + return isoCountry; + } + + public void setIsoCountry(String isoCountry) { + this.isoCountry = isoCountry; + } + + public String getIsoRegion() { + return isoRegion; + } + + public void setIsoRegion(String isoRegion) { + this.isoRegion = isoRegion; + } + + public String getMunicipality() { + return municipality; + } + + public void setMunicipality(String municipality) { + this.municipality = municipality; + } + + public boolean isScheduledService() { + return scheduledService; + } + + public void setScheduledService(boolean scheduledService) { + this.scheduledService = scheduledService; + } + + public String getGpsCode() { + return gpsCode; + } + + public void setGpsCode(String gpsCode) { + this.gpsCode = gpsCode; + } + + public String getIataCode() { + return iataCode; + } + + public void setIataCode(String iataCode) { + this.iataCode = iataCode; + } + + public String getLocalCode() { + return localCode; + } + + public void setLocalCode(String localCode) { + this.localCode = localCode; + } + + public String getHomeLink() { + return homeLink; + } + + public void setHomeLink(String homeLink) { + this.homeLink = homeLink; + } + + public String getWikipediaLink() { + return wikipediaLink; + } + + public void setWikipediaLink(String wikipediaLink) { + this.wikipediaLink = wikipediaLink; + } + + public String getKeywords() { + return keywords; + } + + public void setKeywords(String keywords) { + this.keywords = keywords; + } +} diff --git a/src/main/java/com/benburwell/planes/data/AirportStore.java b/src/main/java/com/benburwell/planes/data/AirportStore.java new file mode 100644 index 0000000..93f1ccc --- /dev/null +++ b/src/main/java/com/benburwell/planes/data/AirportStore.java @@ -0,0 +1,30 @@ +package com.benburwell.planes.data; + +import org.apache.commons.csv.CSVFormat; +import org.apache.commons.csv.CSVParser; +import org.apache.commons.csv.CSVRecord; + +import java.io.File; +import java.io.IOException; +import java.nio.charset.Charset; +import java.util.ArrayList; +import java.util.List; + +/** + * Created by ben on 11/19/16. + */ +public class AirportStore { + private List airports = new ArrayList<>(); + + public void readFromFile(String filename) throws IOException { + File csvData = new File(filename); + CSVParser parser = CSVParser.parse(csvData, Charset.defaultCharset(), CSVFormat.RFC4180.withFirstRecordAsHeader()); + for (CSVRecord record : parser) { + this.airports.add(new Airport(record)); + } + } + + public List getAirports() { + return this.airports; + } +} diff --git a/src/main/java/com/benburwell/planes/data/NavigationAidStore.java b/src/main/java/com/benburwell/planes/data/NavigationAidStore.java index 3bc06d9..6f0ce9c 100644 --- a/src/main/java/com/benburwell/planes/data/NavigationAidStore.java +++ b/src/main/java/com/benburwell/planes/data/NavigationAidStore.java @@ -23,4 +23,8 @@ public class NavigationAidStore { this.aids.add(new NavigationAid(record)); } } + + public List getNavigationAids() { + return this.aids; + } } diff --git a/src/main/java/com/benburwell/planes/gui/Main1090.java b/src/main/java/com/benburwell/planes/gui/Main1090.java index d7fc830..962e428 100644 --- a/src/main/java/com/benburwell/planes/gui/Main1090.java +++ b/src/main/java/com/benburwell/planes/gui/Main1090.java @@ -11,10 +11,13 @@ import com.benburwell.planes.gui.aircraftmap.*; import java.awt.*; import javax.swing.*; import java.awt.event.ActionEvent; +import java.io.IOException; public class Main1090 extends JFrame { private AggregateDataSource sbsDataSource = new AggregateDataSource(); private AircraftStore aircraft = new AircraftStore(); + private NavigationAidStore navaids = new NavigationAidStore(); + private AirportStore airports = new AirportStore(); private int currentTcpConnection = 0; private JTabbedPane tabbedPane = new JTabbedPane(); @@ -32,6 +35,18 @@ public class Main1090 extends JFrame { this.openDataSource(); + try { + this.navaids.readFromFile("/home/ben/.airdata/navaids.csv"); + } catch (IOException e) { + System.out.println("Could not read navaid file: " + e.getMessage()); + } + + try { + this.airports.readFromFile("/home/ben/.airdata/airports.csv"); + } catch (IOException e) { + System.out.println("Could not read airport file: " + e.getMessage()); + } + this.createTabs(); } @@ -39,9 +54,12 @@ public class Main1090 extends JFrame { AircraftTableComponent aircraftData = new AircraftTableComponent(this.aircraft); this.tabbedPane.addTab("Aircraft Data", aircraftData.getComponent()); - AircraftMapComponent aircraftMap = new AircraftMapComponent(this.aircraft); + AircraftMapComponent aircraftMap = new AircraftMapComponent(this.aircraft, this.navaids, this.airports); this.tabbedPane.addTab("Live Map", aircraftMap.getComponent()); + NavigationAidComponent navaids = new NavigationAidComponent(this.navaids); + this.tabbedPane.addTab("Navigation Aids", navaids.getComponent()); + this.add(this.tabbedPane); this.tabbedPane.setTabLayoutPolicy(JTabbedPane.SCROLL_TAB_LAYOUT); diff --git a/src/main/java/com/benburwell/planes/gui/NavigationAidComponent.java b/src/main/java/com/benburwell/planes/gui/NavigationAidComponent.java new file mode 100644 index 0000000..a1f97cf --- /dev/null +++ b/src/main/java/com/benburwell/planes/gui/NavigationAidComponent.java @@ -0,0 +1,26 @@ +package com.benburwell.planes.gui; + +import com.benburwell.planes.data.NavigationAidStore; + +import javax.swing.*; + +/** + * Created by ben on 11/19/16. + */ +public class NavigationAidComponent implements ViewComponent { + private JTable table; + private NavigationAidsTableModel tableModel; + private JScrollPane scrollPane; + + public NavigationAidComponent(NavigationAidStore store) { + this.tableModel = new NavigationAidsTableModel(store); + this.table = new JTable(this.tableModel); + this.table.setFillsViewportHeight(true); + this.scrollPane = new JScrollPane(table); + } + + @Override + public JComponent getComponent() { + return this.scrollPane; + } +} diff --git a/src/main/java/com/benburwell/planes/gui/NavigationAidsTableModel.java b/src/main/java/com/benburwell/planes/gui/NavigationAidsTableModel.java new file mode 100644 index 0000000..064ca25 --- /dev/null +++ b/src/main/java/com/benburwell/planes/gui/NavigationAidsTableModel.java @@ -0,0 +1,57 @@ +package com.benburwell.planes.gui; + +import com.benburwell.planes.data.NavigationAid; +import com.benburwell.planes.data.NavigationAidStore; + +import javax.swing.table.AbstractTableModel; + +/** + * Created by ben on 11/19/16. + */ +public class NavigationAidsTableModel extends AbstractTableModel { + private final String[] COLUMN_NAMES = { "Ident", "Type", "Frequency", "DME Frequency", "DME Channel", "Usage Type", "Power", "Airport" }; + private NavigationAidStore store; + + public NavigationAidsTableModel(NavigationAidStore store) { + this.store = store; + } + + @Override + public int getRowCount() { + return this.store.getNavigationAids().size(); + } + + @Override + public String getColumnName(int col) { + return COLUMN_NAMES[col]; + } + + @Override + public int getColumnCount() { + return this.COLUMN_NAMES.length; + } + + @Override + public Object getValueAt(int rowIndex, int columnIndex) { + NavigationAid aid = this.store.getNavigationAids().get(rowIndex); + switch (columnIndex) { + case 0: + return aid.getIdent(); + case 1: + return aid.getType(); + case 2: + return aid.getFrequency(); + case 3: + return aid.getDmeFrequency(); + case 4: + return aid.getDmeChannel(); + case 5: + return aid.getUsageType(); + case 6: + return aid.getPower(); + case 7: + return aid.getAssociatedAirport(); + } + return null; + } +} diff --git a/src/main/java/com/benburwell/planes/gui/aircraftmap/AircraftMap.java b/src/main/java/com/benburwell/planes/gui/aircraftmap/AircraftMap.java index fad1082..64d86e9 100644 --- a/src/main/java/com/benburwell/planes/gui/aircraftmap/AircraftMap.java +++ b/src/main/java/com/benburwell/planes/gui/aircraftmap/AircraftMap.java @@ -1,6 +1,10 @@ package com.benburwell.planes.gui.aircraftmap; +import com.benburwell.planes.data.Airport; +import com.benburwell.planes.data.NavigationAid; +import com.benburwell.planes.data.Position; import com.benburwell.planes.gui.GraphicsTheme; +import com.benburwell.planes.gui.aircraftmap.symbols.*; import javax.swing.*; import java.awt.*; @@ -30,9 +34,13 @@ public class AircraftMap extends JPanel { // instance fields private List planes = new ArrayList<>(); + private List navaids = new ArrayList<>(); + private List airports = new ArrayList<>(); private double centerLatitude; private double centerLongitude; private int pixelsPerNauticalMile = 10; + private boolean showNavAids = true; + private boolean showAirports = true; /** * Construct a map @@ -44,6 +52,45 @@ public class AircraftMap extends JPanel { this.setCenter(0, 0); } + public void addNavAids(List aids) { + for (NavigationAid aid : aids) { + if (aid.getType().equals("VOR")) { + Position pos = new Position(); + pos.setLatitude(aid.getLatitude()); + pos.setLongitude(aid.getLongitude()); + pos.setAltitude(aid.getElevation()); + this.navaids.add(new VORSymbol(aid.getIdent(), pos, aid.getFrequency())); + } + if (aid.getType().equals("VOR-DME")) { + Position pos = new Position(); + pos.setLatitude(aid.getLatitude()); + pos.setLongitude(aid.getLongitude()); + pos.setAltitude(aid.getElevation()); + this.navaids.add(new VORDMESymbol(aid.getIdent(), pos, aid.getFrequency())); + } + if (aid.getType().equals("VORTAC")) { + Position pos = new Position(); + pos.setLatitude(aid.getLatitude()); + pos.setLongitude(aid.getLongitude()); + pos.setAltitude(aid.getElevation()); + this.navaids.add(new VORTACSymbol(aid.getIdent(), pos, aid.getFrequency())); + } + if (aid.getType().equals("NDB")) { + Position pos = new Position(); + pos.setLatitude(aid.getLatitude()); + pos.setLongitude(aid.getLongitude()); + pos.setAltitude(aid.getElevation()); + this.navaids.add(new NDBSymbol(aid.getIdent(), pos, aid.getFrequency())); + } + } + } + + public void addAirports(List airports) { + for (Airport airport : airports) { + this.airports.add(new AirportSymbol(airport)); + } + } + /** * Paint the ViewComponent on a Graphics instance * @@ -52,9 +99,28 @@ public class AircraftMap extends JPanel { @Override public void paintComponent(Graphics g) { super.paintComponent(g); - this.drawPositionAndScale(g); - this.drawRange(g); - this.planes.forEach(item -> item.drawOn(g, this)); + Graphics2D g2d = (Graphics2D)g.create(); + g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); + this.drawPositionAndScale(g2d); + this.drawRange(g2d); + if (this.showNavAids) { + this.navaids.forEach(aid -> aid.drawOn(g2d, this)); + } + if (this.showAirports) { + this.airports.forEach(airport -> airport.drawOn(g2d, this)); + } + this.planes.forEach(item -> item.drawOn(g2d, this)); + g2d.dispose(); + } + + public void toggleNavAids() { + this.showNavAids = !this.showNavAids; + this.redraw(); + } + + public void toggleAirports() { + this.showAirports = !this.showAirports; + this.redraw(); } public void drawPositionAndScale(Graphics g) { diff --git a/src/main/java/com/benburwell/planes/gui/aircraftmap/AircraftMapComponent.java b/src/main/java/com/benburwell/planes/gui/aircraftmap/AircraftMapComponent.java index f45071b..24dfc94 100644 --- a/src/main/java/com/benburwell/planes/gui/aircraftmap/AircraftMapComponent.java +++ b/src/main/java/com/benburwell/planes/gui/aircraftmap/AircraftMapComponent.java @@ -1,18 +1,14 @@ package com.benburwell.planes.gui.aircraftmap; -import com.benburwell.planes.data.AircraftStore; -import com.benburwell.planes.data.AircraftStoreListener; -import com.benburwell.planes.data.NavigationAidStore; -import com.benburwell.planes.data.Position; +import com.benburwell.planes.data.*; import com.benburwell.planes.gui.ViewComponent; +import com.benburwell.planes.gui.aircraftmap.symbols.PlaneSymbol; import javax.swing.*; import java.awt.*; import java.awt.event.KeyEvent; -import java.io.IOException; import java.util.List; import java.util.ArrayList; -import java.util.Collections; /** * Created by ben on 11/18/16. @@ -20,25 +16,20 @@ import java.util.Collections; public class AircraftMapComponent implements ViewComponent { private AircraftStore store; private NavigationAidStore navaids; + private AirportStore airportStore; private AircraftMap mapPanel; private String focusedAircraftIdentifier = null; - public AircraftMapComponent(AircraftStore store) { + public AircraftMapComponent(AircraftStore store, NavigationAidStore navaids, AirportStore airportStore) { this.store = store; - this.navaids = new NavigationAidStore(); + this.navaids = navaids; + this.airportStore = airportStore; this.setupMap(); this.bindKeys(); this.subscribeToChanges(); - this.readNavAids(); - } - - public void readNavAids() { - try { - this.navaids.readFromFile("/home/ben/.airdata/navaids.csv"); - } catch (IOException e) { - System.out.println("Could not read navaid file: " + e.getMessage()); - } + this.mapPanel.addNavAids(this.navaids.getNavigationAids()); + this.mapPanel.addAirports(this.airportStore.getAirports()); } public void focusNextAircraft() { @@ -82,6 +73,10 @@ public class AircraftMapComponent implements ViewComponent { } else if (e.getKeyCode() == KeyEvent.VK_TAB && e.getID() == KeyEvent.KEY_PRESSED) { this.focusNextAircraft(); this.centerMapOnPlane(this.focusedAircraftIdentifier); + } else if (e.getKeyCode() == KeyEvent.VK_N && e.getID() == KeyEvent.KEY_PRESSED) { + this.mapPanel.toggleNavAids(); + } else if (e.getKeyCode() == KeyEvent.VK_A && e.getID() == KeyEvent.KEY_PRESSED) { + this.mapPanel.toggleAirports(); } return false; }); @@ -99,7 +94,7 @@ public class AircraftMapComponent implements ViewComponent { @Override public void aircraftStoreChanged() { List planes = new ArrayList<>(); - store.getAircraft().values().forEach(aircraft -> planes.add(new Plane(aircraft))); + store.getAircraft().values().forEach(aircraft -> planes.add(new PlaneSymbol(aircraft))); mapPanel.setPlanes(planes); mapPanel.validate(); mapPanel.repaint(); diff --git a/src/main/java/com/benburwell/planes/gui/aircraftmap/GeoPoint.java b/src/main/java/com/benburwell/planes/gui/aircraftmap/GeoPoint.java index d3eda40..80c6204 100644 --- a/src/main/java/com/benburwell/planes/gui/aircraftmap/GeoPoint.java +++ b/src/main/java/com/benburwell/planes/gui/aircraftmap/GeoPoint.java @@ -30,6 +30,12 @@ public class GeoPoint { return yPosition; } + public boolean shouldDrawOn(AircraftMap map) { + int x = this.getX(map); + int y = this.getY(map); + return (x >= 0 && x <= map.getWidth() && y >= 0 && y <= map.getHeight()); + } + public double getAltitude() { return this.altitude; } diff --git a/src/main/java/com/benburwell/planes/gui/aircraftmap/Plane.java b/src/main/java/com/benburwell/planes/gui/aircraftmap/Plane.java deleted file mode 100644 index 2f98bab..0000000 --- a/src/main/java/com/benburwell/planes/gui/aircraftmap/Plane.java +++ /dev/null @@ -1,126 +0,0 @@ -package com.benburwell.planes.gui.aircraftmap; - -import com.benburwell.planes.data.Aircraft; -import com.benburwell.planes.data.Position; -import com.benburwell.planes.gui.GraphicsTheme; - -import java.awt.*; -import java.awt.geom.AffineTransform; - -/** - * Created by ben on 11/19/16. - */ -public class Plane extends GeoPoint implements Drawable { - public final int TRIANGLE_HEIGHT = 6; - public final int TRIANGLE_WIDTH = 4; - public final int TEXT_OFFSET_X = 10; - public final int TEXT_OFFSET_Y = 15; - public final int MIN_COLOR_HEIGHT = 0; - public final int MAX_COLOR_HEIGHT = 50000; - private String name; - private double heading; - private double speed; - private double verticalRate; - - public Plane(Aircraft ac) { - this(ac.getCallsign(), ac.getCurrentPosition(), ac.getTrack(), ac.getGroundSpeed(), ac.getVerticalRate()); - } - - public Plane(String name, Position position, double heading, double speed, double verticalRate) { - this(name, position.getLatitude(), position.getLongitude(), position.getAltitude(), heading, speed, verticalRate); - } - - public Plane(String name, double latitude, double longitude, double altitude, double heading, double speed, double verticalRate) { - super(latitude, longitude, altitude); - this.name = name; - this.heading = heading; - this.speed = speed; - this.verticalRate = verticalRate; - } - - public int getFlightLevel() { - return (int) this.getAltitude() / 100; - } - - public Color getPlaneColor() { - Color minColor = GraphicsTheme.Colors.RED; - Color maxColor = GraphicsTheme.Colors.GREEN; - - float[] minHsb = Color.RGBtoHSB(minColor.getRed(), minColor.getGreen(), minColor.getBlue(), null); - float[] maxHsb = Color.RGBtoHSB(maxColor.getRed(), maxColor.getGreen(), maxColor.getBlue(), null); - - float minHue = minHsb[0]; - float maxHue = maxHsb[0]; - float minSat = minHsb[1]; - float maxSat = maxHsb[1]; - float minBright = minHsb[2]; - float maxBright = maxHsb[2]; - - double planePosition = (this.getAltitude() / (MAX_COLOR_HEIGHT - MIN_COLOR_HEIGHT)) + MIN_COLOR_HEIGHT; - float huePosition = (float) (planePosition * (maxHue - minHue) + minHue); - float satPosition = (float) (planePosition * (maxSat - minSat) + minSat); - float brightPosition = (float) (planePosition * (maxBright - minBright) + minBright); - - Color c = Color.getHSBColor(huePosition, satPosition, brightPosition); - return c; - } - - public double getAngle() { - return Math.toRadians(this.heading); - } - - public double getSpeed() { - return this.speed; - } - - public void drawTriangle(Graphics2D ctx, int x, int y, int predictionLength) { - AffineTransform at = new AffineTransform(); - at.setToRotation(this.getAngle(), x, y); - ctx.setTransform(at); - int[] xs = new int[]{ x - TRIANGLE_WIDTH, x, x + TRIANGLE_WIDTH, x - TRIANGLE_WIDTH }; - int[] ys = new int[]{ y + TRIANGLE_HEIGHT, y - TRIANGLE_HEIGHT, y + TRIANGLE_HEIGHT, y + TRIANGLE_HEIGHT }; - ctx.fillPolygon(xs, ys, 4); - ctx.drawLine(x, y, x, y - predictionLength); - } - - public String getVerticalRateIndicator() { - if (this.verticalRate > 0) { - return "\u2191"; // ↑ - } else if (this.verticalRate < 0) { - return "\u2193"; // ↓ - } - return ""; - } - - public String getDisplayName() { - if (this.name == null || this.name.isEmpty()) { - return "-----"; - } - return this.name; - } - - public int getPredictionLength(double pixelsPerNauticalMile) { - return (int) (this.speed / 60.0 * pixelsPerNauticalMile); - } - - public void drawOn(Graphics g, AircraftMap map) { - int x = this.getX(map); - int y = this.getY(map); - - if (x >= 0 && x <= map.getSize().getWidth() && y >= 0 && y <= map.getSize().getHeight()) { - // draw the plane dot - Graphics2D g2d = (Graphics2D) g.create(); - g2d.setColor(this.getPlaneColor()); - int predictedTrack = this.getPredictionLength(map.getPixelsPerNauticalMile()); - this.drawTriangle(g2d, x, y, predictedTrack); - g2d.dispose(); - - - // draw the name of the plane - g.setColor(GraphicsTheme.Colors.BASE_5); - g.drawString(this.getDisplayName(), x + TEXT_OFFSET_X, y + TEXT_OFFSET_Y); - String infoString = String.format("%d%s %.1f", this.getFlightLevel(), this.getVerticalRateIndicator(), this.getSpeed()); - g.drawString(infoString, x + TEXT_OFFSET_X, y + TEXT_OFFSET_Y + g.getFontMetrics().getHeight()); - } - } -} diff --git a/src/main/java/com/benburwell/planes/gui/aircraftmap/symbols/AirportSymbol.java b/src/main/java/com/benburwell/planes/gui/aircraftmap/symbols/AirportSymbol.java new file mode 100644 index 0000000..5286f6f --- /dev/null +++ b/src/main/java/com/benburwell/planes/gui/aircraftmap/symbols/AirportSymbol.java @@ -0,0 +1,48 @@ +package com.benburwell.planes.gui.aircraftmap.symbols; + +import com.benburwell.planes.data.Airport; +import com.benburwell.planes.gui.GraphicsTheme; +import com.benburwell.planes.gui.aircraftmap.AircraftMap; +import com.benburwell.planes.gui.aircraftmap.Drawable; +import com.benburwell.planes.gui.aircraftmap.GeoPoint; + +import java.awt.*; + +/** + * Created by ben on 11/19/16. + */ +public class AirportSymbol extends GeoPoint implements Drawable { + private String name; + private String iataCode; + private String localCode; + + public AirportSymbol(Airport airport) { + super(airport.getLatitude(), airport.getLongitude(), airport.getElevation()); + this.name = airport.getName(); + this.iataCode = airport.getIataCode(); + this.localCode = airport.getLocalCode(); + } + + public String getDisplayName() { + if (this.iataCode != null && !this.iataCode.isEmpty()) { + return this.iataCode; + } + if (this.localCode != null && !this.localCode.isEmpty()) { + return this.localCode; + } + return this.name; + } + + @Override + public void drawOn(Graphics g, AircraftMap map) { + if (this.shouldDrawOn(map)) { + int x = this.getX(map); + int y = this.getY(map); + + g.setColor(GraphicsTheme.Colors.MAGENTA); + + g.drawRect(x - 2, y - 2, 4, 4); + g.drawString(this.getDisplayName(), x + 6, y); + } + } +} diff --git a/src/main/java/com/benburwell/planes/gui/aircraftmap/symbols/NDBSymbol.java b/src/main/java/com/benburwell/planes/gui/aircraftmap/symbols/NDBSymbol.java new file mode 100644 index 0000000..08793ec --- /dev/null +++ b/src/main/java/com/benburwell/planes/gui/aircraftmap/symbols/NDBSymbol.java @@ -0,0 +1,42 @@ +package com.benburwell.planes.gui.aircraftmap.symbols; + +import com.benburwell.planes.data.Position; +import com.benburwell.planes.gui.GraphicsTheme; +import com.benburwell.planes.gui.aircraftmap.AircraftMap; +import com.benburwell.planes.gui.aircraftmap.Drawable; +import com.benburwell.planes.gui.aircraftmap.GeoPoint; + +import java.awt.*; + +/** + * Created by ben on 11/19/16. + */ +public class NDBSymbol extends GeoPoint implements Drawable { + public static final int INNER_RADIUS = 3; + public static final int OUTER_RADIUS = 9; + public static final int TEXT_OFFSET = 4; + + private String name; + private int frequency; + + public NDBSymbol(String name, Position pos, int frequency) { + super(pos.getLatitude(), pos.getLongitude(), pos.getAltitude()); + this.name = name; + this.frequency = frequency; + } + + @Override + public void drawOn(Graphics g, AircraftMap map) { + if (this.shouldDrawOn(map)) { + g.setColor(GraphicsTheme.Colors.VIOLET); + + int x = this.getX(map); + int y = this.getY(map); + g.fillOval(x - INNER_RADIUS, y - INNER_RADIUS, INNER_RADIUS * 2, INNER_RADIUS * 2); + g.drawOval(x - OUTER_RADIUS, y - OUTER_RADIUS, OUTER_RADIUS * 2, OUTER_RADIUS * 2); + + g.drawString(this.name, x + OUTER_RADIUS + TEXT_OFFSET, y); + g.drawString("" + this.frequency, x + OUTER_RADIUS + TEXT_OFFSET, y + g.getFontMetrics().getHeight()); + } + } +} diff --git a/src/main/java/com/benburwell/planes/gui/aircraftmap/symbols/PlaneSymbol.java b/src/main/java/com/benburwell/planes/gui/aircraftmap/symbols/PlaneSymbol.java new file mode 100644 index 0000000..4e8ebc0 --- /dev/null +++ b/src/main/java/com/benburwell/planes/gui/aircraftmap/symbols/PlaneSymbol.java @@ -0,0 +1,129 @@ +package com.benburwell.planes.gui.aircraftmap.symbols; + +import com.benburwell.planes.data.Aircraft; +import com.benburwell.planes.data.Position; +import com.benburwell.planes.gui.GraphicsTheme; +import com.benburwell.planes.gui.aircraftmap.AircraftMap; +import com.benburwell.planes.gui.aircraftmap.Drawable; +import com.benburwell.planes.gui.aircraftmap.GeoPoint; + +import java.awt.*; +import java.awt.geom.AffineTransform; + +/** + * Created by ben on 11/19/16. + */ +public class PlaneSymbol extends GeoPoint implements Drawable { + public final int TRIANGLE_HEIGHT = 6; + public final int TRIANGLE_WIDTH = 4; + public final int TEXT_OFFSET_X = 10; + public final int TEXT_OFFSET_Y = 15; + public final int MIN_COLOR_HEIGHT = 0; + public final int MAX_COLOR_HEIGHT = 50000; + private String name; + private double heading; + private double speed; + private double verticalRate; + + public PlaneSymbol(Aircraft ac) { + this(ac.getCallsign(), ac.getCurrentPosition(), ac.getTrack(), ac.getGroundSpeed(), ac.getVerticalRate()); + } + + public PlaneSymbol(String name, Position position, double heading, double speed, double verticalRate) { + this(name, position.getLatitude(), position.getLongitude(), position.getAltitude(), heading, speed, verticalRate); + } + + public PlaneSymbol(String name, double latitude, double longitude, double altitude, double heading, double speed, double verticalRate) { + super(latitude, longitude, altitude); + this.name = name; + this.heading = heading; + this.speed = speed; + this.verticalRate = verticalRate; + } + + public int getFlightLevel() { + return (int) this.getAltitude() / 100; + } + + public Color getPlaneColor() { + Color minColor = GraphicsTheme.Colors.RED; + Color maxColor = GraphicsTheme.Colors.GREEN; + + float[] minHsb = Color.RGBtoHSB(minColor.getRed(), minColor.getGreen(), minColor.getBlue(), null); + float[] maxHsb = Color.RGBtoHSB(maxColor.getRed(), maxColor.getGreen(), maxColor.getBlue(), null); + + float minHue = minHsb[0]; + float maxHue = maxHsb[0]; + float minSat = minHsb[1]; + float maxSat = maxHsb[1]; + float minBright = minHsb[2]; + float maxBright = maxHsb[2]; + + double planePosition = (this.getAltitude() / (MAX_COLOR_HEIGHT - MIN_COLOR_HEIGHT)) + MIN_COLOR_HEIGHT; + float huePosition = (float) (planePosition * (maxHue - minHue) + minHue); + float satPosition = (float) (planePosition * (maxSat - minSat) + minSat); + float brightPosition = (float) (planePosition * (maxBright - minBright) + minBright); + + Color c = Color.getHSBColor(huePosition, satPosition, brightPosition); + return c; + } + + public double getAngle() { + return Math.toRadians(this.heading); + } + + public double getSpeed() { + return this.speed; + } + + public void drawTriangle(Graphics2D ctx, int x, int y, int predictionLength) { + AffineTransform at = new AffineTransform(); + at.setToRotation(this.getAngle(), x, y); + ctx.setTransform(at); + int[] xs = new int[]{ x - TRIANGLE_WIDTH, x, x + TRIANGLE_WIDTH, x - TRIANGLE_WIDTH }; + int[] ys = new int[]{ y + TRIANGLE_HEIGHT, y - TRIANGLE_HEIGHT, y + TRIANGLE_HEIGHT, y + TRIANGLE_HEIGHT }; + ctx.fillPolygon(xs, ys, 4); + ctx.drawLine(x, y, x, y - predictionLength); + } + + public String getVerticalRateIndicator() { + if (this.verticalRate > 0) { + return "\u2191"; // ↑ + } else if (this.verticalRate < 0) { + return "\u2193"; // ↓ + } + return ""; + } + + public String getDisplayName() { + if (this.name == null || this.name.isEmpty()) { + return "-----"; + } + return this.name; + } + + public int getPredictionLength(double pixelsPerNauticalMile) { + return (int) (this.speed / 60.0 * pixelsPerNauticalMile); + } + + public void drawOn(Graphics g, AircraftMap map) { + if (this.shouldDrawOn(map)) { + int x = this.getX(map); + int y = this.getY(map); + + // draw the plane dot + Graphics2D g2d = (Graphics2D) g.create(); + g2d.setColor(this.getPlaneColor()); + int predictedTrack = this.getPredictionLength(map.getPixelsPerNauticalMile()); + this.drawTriangle(g2d, x, y, predictedTrack); + g2d.dispose(); + + + // draw the name of the plane + g.setColor(GraphicsTheme.Colors.BASE_5); + g.drawString(this.getDisplayName(), x + TEXT_OFFSET_X, y + TEXT_OFFSET_Y); + String infoString = String.format("%d%s %.1f", this.getFlightLevel(), this.getVerticalRateIndicator(), this.getSpeed()); + g.drawString(infoString, x + TEXT_OFFSET_X, y + TEXT_OFFSET_Y + g.getFontMetrics().getHeight()); + } + } +} diff --git a/src/main/java/com/benburwell/planes/gui/aircraftmap/symbols/VORDMESymbol.java b/src/main/java/com/benburwell/planes/gui/aircraftmap/symbols/VORDMESymbol.java new file mode 100644 index 0000000..0b67989 --- /dev/null +++ b/src/main/java/com/benburwell/planes/gui/aircraftmap/symbols/VORDMESymbol.java @@ -0,0 +1,29 @@ +package com.benburwell.planes.gui.aircraftmap.symbols; + +import com.benburwell.planes.data.Position; +import com.benburwell.planes.gui.GraphicsTheme; +import com.benburwell.planes.gui.aircraftmap.AircraftMap; +import com.benburwell.planes.gui.aircraftmap.Drawable; +import com.benburwell.planes.gui.aircraftmap.symbols.VORSymbol; + +import java.awt.Graphics; + +/** + * Created by ben on 11/19/16. + */ +public class VORDMESymbol extends VORSymbol implements Drawable { + public VORDMESymbol(String name, Position pos, int frequency) { + super(name, pos, frequency); + } + + @Override + public void drawOn(Graphics graphicsContext, AircraftMap map) { + super.drawOn(graphicsContext, map); + if (this.shouldDrawOn(map)) { + int x = this.getX(map); + int y = this.getY(map); + graphicsContext.setColor(GraphicsTheme.Colors.VIOLET); + graphicsContext.drawRect(x - VORSymbol.RADIUS, y - VORSymbol.HEIGHT, VORSymbol.RADIUS * 2, VORSymbol.HEIGHT * 2); + } + } +} diff --git a/src/main/java/com/benburwell/planes/gui/aircraftmap/symbols/VORSymbol.java b/src/main/java/com/benburwell/planes/gui/aircraftmap/symbols/VORSymbol.java new file mode 100644 index 0000000..e854c2b --- /dev/null +++ b/src/main/java/com/benburwell/planes/gui/aircraftmap/symbols/VORSymbol.java @@ -0,0 +1,49 @@ +package com.benburwell.planes.gui.aircraftmap.symbols; + +import com.benburwell.planes.data.Position; +import com.benburwell.planes.gui.GraphicsTheme; +import com.benburwell.planes.gui.aircraftmap.AircraftMap; +import com.benburwell.planes.gui.aircraftmap.Drawable; +import com.benburwell.planes.gui.aircraftmap.GeoPoint; + +import java.awt.*; + +/** + * Created by ben on 11/19/16. + */ +public class VORSymbol extends GeoPoint implements Drawable { + public static final int RADIUS = 11; + public static final int HEIGHT = (int) (Math.sin(Math.toRadians(60)) * RADIUS); + public static final int X_OFFSET = (int) (Math.cos(Math.toRadians(60)) * RADIUS); + public static final int DOT_RADIUS = 3; + public static final int TEXT_OFFSET = 4; + + private String name; + private int frequency; + + public VORSymbol(String name, Position pos, int frequency) { + super(pos.getLatitude(), pos.getLongitude(), pos.getAltitude()); + this.name = name; + this.frequency = frequency; + } + + @Override + public void drawOn(Graphics graphicsContext, AircraftMap map) { + if (this.shouldDrawOn(map)) { + int x = this.getX(map); + int y = this.getY(map); + graphicsContext.setColor(GraphicsTheme.Colors.VIOLET); + + // center dot + graphicsContext.fillOval(x - DOT_RADIUS, y - DOT_RADIUS, DOT_RADIUS * 2, DOT_RADIUS * 2); + + // hexagon + int[] xs = { x - RADIUS, x - X_OFFSET, x + X_OFFSET, x + RADIUS, x + X_OFFSET, x - X_OFFSET, x - RADIUS }; + int[] ys = { y, y - HEIGHT, y - HEIGHT, y, y + HEIGHT, y + HEIGHT, y }; + graphicsContext.drawPolygon(xs, ys, 7); + + graphicsContext.drawString(this.name, x + RADIUS + TEXT_OFFSET, y); + graphicsContext.drawString(String.format("%.3f", this.frequency / 1000.0), x + RADIUS + TEXT_OFFSET, y + graphicsContext.getFontMetrics().getHeight()); + } + } +} diff --git a/src/main/java/com/benburwell/planes/gui/aircraftmap/symbols/VORTACSymbol.java b/src/main/java/com/benburwell/planes/gui/aircraftmap/symbols/VORTACSymbol.java new file mode 100644 index 0000000..3b0043f --- /dev/null +++ b/src/main/java/com/benburwell/planes/gui/aircraftmap/symbols/VORTACSymbol.java @@ -0,0 +1,32 @@ +package com.benburwell.planes.gui.aircraftmap.symbols; + +import com.benburwell.planes.data.Position; +import com.benburwell.planes.gui.GraphicsTheme; +import com.benburwell.planes.gui.aircraftmap.AircraftMap; +import com.benburwell.planes.gui.aircraftmap.Drawable; +import com.benburwell.planes.gui.aircraftmap.symbols.VORSymbol; + +import java.awt.*; + +/** + * Created by ben on 11/19/16. + */ +public class VORTACSymbol extends VORSymbol implements Drawable { + public VORTACSymbol(String name, Position pos, int frequency) { + super(name, pos, frequency); + } + + @Override + public void drawOn(Graphics graphicsContext, AircraftMap map) { + super.drawOn(graphicsContext, map); + if (this.shouldDrawOn(map)) { + int x = this.getX(map); + int y = this.getY(map); + graphicsContext.setColor(GraphicsTheme.Colors.VIOLET); + + int[] xs = { x - VORSymbol.X_OFFSET, x + VORSymbol.X_OFFSET, x + VORSymbol.X_OFFSET, x - VORSymbol.X_OFFSET, x - VORSymbol.X_OFFSET }; + int[] ys = { y + VORSymbol.RADIUS, y + VORSymbol.RADIUS, y + VORSymbol.RADIUS * 2, y + VORSymbol.RADIUS * 2, y + VORSymbol.RADIUS }; + graphicsContext.fillPolygon(xs, ys, 5); + } + } +} -- cgit v1.2.3