Java tutorial
/* * This file is part of ViDESO. * ViDESO is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * ViDESO is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with ViDESO. If not, see <http://www.gnu.org/licenses/>. */ package fr.crnan.videso3d.databases.aip; import java.awt.Color; import java.awt.Point; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.HashSet; import java.util.List; import org.jdom2.Element; import fr.crnan.videso3d.Couple; import fr.crnan.videso3d.DatasManager; import fr.crnan.videso3d.DatasManager.Type; import fr.crnan.videso3d.MultiValueMap; import fr.crnan.videso3d.Pallet; import fr.crnan.videso3d.ProgressSupport; import fr.crnan.videso3d.VidesoController; import fr.crnan.videso3d.VidesoGLCanvas; import fr.crnan.videso3d.databases.DatabaseManager; import fr.crnan.videso3d.databases.aip.AIP.Altitude; import fr.crnan.videso3d.databases.aip.RoutesSegments.Segment; import fr.crnan.videso3d.graphics.Aerodrome; import fr.crnan.videso3d.graphics.Balise2D; import fr.crnan.videso3d.graphics.Balise3D; import fr.crnan.videso3d.graphics.DatabaseBalise2D; import fr.crnan.videso3d.graphics.DatabaseBalise3D; import fr.crnan.videso3d.graphics.DatabasePisteAerodrome; import fr.crnan.videso3d.graphics.DatabaseRoute2D; import fr.crnan.videso3d.graphics.DatabaseRoute3D; import fr.crnan.videso3d.graphics.DatabaseVidesoObject; import fr.crnan.videso3d.graphics.Route; import fr.crnan.videso3d.graphics.Route.Parity; import fr.crnan.videso3d.graphics.MarqueurAerodrome; import fr.crnan.videso3d.graphics.Route2D; import fr.crnan.videso3d.graphics.Route3D; import fr.crnan.videso3d.graphics.Secteur3D; import fr.crnan.videso3d.graphics.VPolygon; import fr.crnan.videso3d.graphics.VidesoAnnotation; import fr.crnan.videso3d.graphics.VidesoObject; import fr.crnan.videso3d.layers.AirportLayer; import fr.crnan.videso3d.layers.Balise2DLayer; import fr.crnan.videso3d.layers.Balise3DLayer; import fr.crnan.videso3d.layers.FilterableAirspaceLayer; import fr.crnan.videso3d.layers.Routes2DLayer; import fr.crnan.videso3d.layers.Routes3DLayer; import fr.crnan.videso3d.layers.TextLayer; import gov.nasa.worldwind.Restorable; import gov.nasa.worldwind.avlist.AVKey; import gov.nasa.worldwind.geom.LatLon; import gov.nasa.worldwind.geom.Position; import gov.nasa.worldwind.layers.Layer; import gov.nasa.worldwind.render.Annotation; import gov.nasa.worldwind.render.GlobeAnnotation; import gov.nasa.worldwind.render.Material; import gov.nasa.worldwind.render.airspaces.BasicAirspaceAttributes; import gov.nasa.worldwind.view.orbit.BasicOrbitView; /** * Contrle l'affichage et la construction des lments AIP * @author A. Vidal * @author Bruno Spyckerelle * @version 0.4.2 */ public class AIPController extends ProgressSupport implements VidesoController { private VidesoGLCanvas wwd; private AIP aip; private FilterableAirspaceLayer zonesLayer = new FilterableAirspaceLayer(); { zonesLayer.setName("Zones"); zonesLayer.setEnableAntialiasing(true); } private TextLayer textLayer = new TextLayer("Coord. volumes AIP"); /** * Layer contenant les routes */ private Routes2DLayer routes2D; private Routes3DLayer routes3D; private Balise2DLayer navFixLayer; private Balise3DLayer navFixLayer3D; private AirportLayer arptLayer; private HashMap<String, Secteur3D> zones; private MultiValueMap<String, String> volumesSecteursCTL = new MultiValueMap<String, String>(); private HashSet<String> balises; private HashMap<String, GlobeAnnotation> routesAnnotations; private RoutesSegments routesSegments = new RoutesSegments(); private Annotation lastSegmentAnnotation; private Balise2D lastHighlighted; private Annotation lastNavFixAnnotation; private String routeEnCreation = ""; public AIPController(VidesoGLCanvas wwd) { aip = new AIP(); this.wwd = wwd; this.buildAIP(); } private void buildAIP() { this.wwd.firePropertyChange("step", "", "Cration des volumes AIP"); if (zonesLayer != null) { zonesLayer.removeAllAirspaces(); this.toggleLayer(zonesLayer, true); this.toggleLayer(textLayer, true); } else { zonesLayer = new FilterableAirspaceLayer(); zonesLayer.setName("Zones"); zonesLayer.setEnableAntialiasing(true); this.toggleLayer(zonesLayer, true); this.toggleLayer(textLayer, true); } try { if (DatabaseManager.getCurrentAIP() != null) { //cration des nouveaux objets zones = new HashMap<String, Secteur3D>(); balises = new HashSet<String>(); } } catch (SQLException e) { e.printStackTrace(); } this.wwd.firePropertyChange("step", "", "Cration des routes AIP"); //Layers pour les routes if (routes3D != null) { routes3D.removeAllAirspaces(); } else { routes3D = new Routes3DLayer("Routes AIP 3D"); this.toggleLayer(routes3D, false); //affichage en 2D par dfaut } if (routes2D != null) { routes2D.removeAllRenderables(); } else { routes2D = new Routes2DLayer("Routes AIP 2D"); this.toggleLayer(routes2D, true); } routesAnnotations = new HashMap<String, GlobeAnnotation>(); this.wwd.firePropertyChange("step", "", "Cration des balises AIP"); if (navFixLayer != null) { navFixLayer.removeAllBalises(); } else { navFixLayer = new Balise2DLayer("NavFix AIP"); this.toggleLayer(navFixLayer, true); } if (navFixLayer3D != null) { navFixLayer3D.removeAllBalises(); } else { navFixLayer3D = new Balise3DLayer("NavFix AIP"); this.toggleLayer(navFixLayer3D, false); } this.wwd.firePropertyChange("step", "", "Cration des aroports AIP"); if (arptLayer != null) { arptLayer.removeAllAirports(); this.toggleLayer(arptLayer, true); } else { arptLayer = new AirportLayer("Arodromes AIP"); this.toggleLayer(arptLayer, true); } this.wwd.redraw(); } @Override public void unHighlight(int type, String name) { } @Override public void addLayer(String name, Layer layer) { } @Override public void removeLayer(String name, Layer layer) { } @Override public void removeAllLayers() { this.wwd.removeLayer(routes2D); this.wwd.removeLayer(routes3D); this.wwd.removeLayer(navFixLayer); this.wwd.removeLayer(navFixLayer3D); this.wwd.removeLayer(zonesLayer); this.wwd.removeLayer(arptLayer); this.wwd.removeLayer(textLayer); } public FilterableAirspaceLayer getZonesLayer() { return zonesLayer; } public Routes2DLayer getRoutes2DLayer() { return routes2D; } public Routes3DLayer getRoutes3DLayer() { return routes3D; } public RoutesSegments.Route getSegmentsOfRoute(int pkRoute) { return routesSegments.getSegmentOfRoute(pkRoute); } @Override public void toggleLayer(Layer layer, Boolean state) { this.wwd.toggleLayer(layer, state); } @Override public void showObject(int type, String name) { if (type >= AIP.AWY && type < AIP.DMEATT) { this.showRoute(name, type); } else if (type == AIP.CTL) { // si c'est de type CTL, il se peut qu'il y ait plusieurs volumes correspondant un seul secteur // donc on va chercher les diffrents morceaux avec getCTLSecteurs et on les ajoute tous. name = name.split(" ")[0].trim(); List<String> volumesSecteur = volumesSecteursCTL.get(name); if (volumesSecteur == null) { ArrayList<String> volumesSect = getCTLSecteurs(name); volumesSecteursCTL.put(name, volumesSect); for (String nomVolumeSecteur : volumesSect) { this.addZone(type, nomVolumeSecteur); } } else { for (String nomVolumeSecteur : volumesSecteur) { this.addZone(type, nomVolumeSecteur); } } } else if (type >= AIP.DMEATT && type < AIP.AERODROME) { this.showNavFix(type, name); } else if (type >= AIP.AERODROME) { this.showAerodrome(type, name); } else { this.addZone(type, name); } //synchroniser la vue si l'appel n'a pas t fait par la vue DatasManager.getView(DatasManager.Type.AIP).showObject(type, name); } @Override public void hideObject(int type, String name) { this.wwd.getView().stopMovement(); if (type >= AIP.AWY && type < AIP.DMEATT) { this.removeRoute(type, name); } else if (type >= AIP.DMEATT && type < AIP.AERODROME) { this.removeNavFix(type, name); } else if (type >= AIP.AERODROME) { this.removeAerodrome(type, name); } else if (type == AIP.CTL) { // si c'est de type CTL, il se peut qu'il y ait plusieurs volumes correspondant un seul secteur // donc on va chercher les diffrents morceaux avec getCTLSecteurs et on les enlve tous. name = name.split(" ")[0].trim(); List<String> volumesSecteur = volumesSecteursCTL.get(name); if (volumesSecteur != null) { for (String nomVolumeSecteur : volumesSecteur) { this.hideZone(type, nomVolumeSecteur); } } } else { this.hideZone(type, name); } //synchroniser la vue si l'appel n'a pas t fait par la vue DatasManager.getView(DatasManager.Type.AIP).hideObject(type, name); } public int string2type(String type) { return AIP.string2type(type); } private void addZone(int type, String name) { Secteur3D zone = this.zones.get(type + " " + name); if (zone == null) { this.createZone(type, name); zone = this.zones.get(type + " " + name); } if (zone != null) { zone.setVisible(true); this.zonesLayer.firePropertyChange(AVKey.LAYER, null, this.zonesLayer); } } private void createZone(int type, String name) { if (!this.zones.containsKey(type + " " + name)) { Color couleurZone = null; switch (type) { case AIP.TSA: couleurZone = Color.orange; break; case AIP.SIV: couleurZone = Pallet.SIVColor; break; case AIP.CTR: couleurZone = Pallet.CTRColor; break; case AIP.TMA: couleurZone = Pallet.TMAColor; break; case AIP.P: couleurZone = Color.red; break; case AIP.R: couleurZone = Color.red; break; case AIP.D: couleurZone = Color.red; break; case AIP.FIR: couleurZone = Pallet.FIRColor; break; case AIP.UIR: couleurZone = Pallet.UIRColor; break; case AIP.LTA: couleurZone = Pallet.LTAColor; break; case AIP.UTA: couleurZone = Pallet.UTAColor; break; case AIP.CTA: couleurZone = Pallet.CTAColor; break; case AIP.CTL: couleurZone = Pallet.CTLColor; break; case AIP.Pje: couleurZone = Pallet.defaultColor; break; case AIP.Aer: couleurZone = Pallet.defaultColor; break; case AIP.Vol: couleurZone = Pallet.defaultColor; break; case AIP.Bal: couleurZone = Pallet.defaultColor; break; case AIP.TrPla: couleurZone = Pallet.defaultColor; break; case AIP.OCA: couleurZone = Pallet.OCAColor; break; case AIP.PRN: couleurZone = Pallet.PRNColor; break; default: break; } Element maZone = aip.findElementByName(type, name); Couple<Altitude, Altitude> niveaux = aip.getLevels(maZone); Secteur3D zone = new Secteur3D(name, niveaux.getFirst().getFL(), niveaux.getSecond().getFL(), type, DatasManager.Type.AIP, textLayer); BasicAirspaceAttributes attrs = new BasicAirspaceAttributes(); attrs.setDrawOutline(true); attrs.setMaterial(new Material(couleurZone)); attrs.setOutlineMaterial(new Material(Pallet.makeBrighter(couleurZone))); attrs.setOpacity(0.2); attrs.setOutlineOpacity(0.9); attrs.setOutlineWidth(1.5); zone.setNormalAttributes(attrs); zone.setAnnotation("<p><b>" + name + "</b></p>" + "<p>Plafond : " + niveaux.getSecond().getFullText() + "<br />Plancher : " + niveaux.getFirst().getFullText() + "</p>"); Geometrie contour = new Geometrie(aip.findElement(aip.getDocumentRoot().getChild("PartieS"), maZone.getChild("Partie").getAttributeValue("pk"))); if (contour.getLocations().isEmpty()) return; zone.setLocations(contour.getLocations()); String upperAltitudeRef, lowerAltitudeRef = null; if (niveaux.getFirst().getRef() == Altitude.asfc) { lowerAltitudeRef = AVKey.ABOVE_GROUND_LEVEL; } else { //Si le plancher est SFC, on met comme rfrence AMSL pour viter que //les zones au-dessus de la mer ne descendent sous la surface de l'eau. lowerAltitudeRef = AVKey.ABOVE_MEAN_SEA_LEVEL; } if (niveaux.getSecond().getRef() == Altitude.asfc || niveaux.getSecond().getRef() == Altitude.refSFC) { upperAltitudeRef = AVKey.ABOVE_GROUND_LEVEL; } else { upperAltitudeRef = AVKey.ABOVE_MEAN_SEA_LEVEL; } zone.setAltitudeDatum(lowerAltitudeRef, upperAltitudeRef); zone.setVisible(false); this.zonesLayer.addAirspace(zone); zones.put(type + " " + name, zone); } } private void hideZone(int type, String name) { Secteur3D zone = zones.get(type + " " + name); if (zone != null) { zone.setVisible(false); zone.getAnnotation(Position.ZERO).getAttributes().setVisible(false); zone.setLocationsVisible(false); this.zonesLayer.firePropertyChange(AVKey.LAYER, null, this.zonesLayer); } } public void showRoute(String routeName, int type) { if (!routeEnCreation.equals(routeName)) { routeEnCreation = routeName; RoutesSegments.Route route = routesSegments.getSegmentOfRoute(routeName); if (route == null) { addRouteToLayer(routeName, type, true); } else { if (!route.isVisible()) { route.setVisible(true); for (Segment s : route) { routes2D.displayRoute(s.getName()); routes3D.displayRoute(s.getName()); } } } routeEnCreation = ""; } } /** * Ajoute une route identifie par son nom et son type la vue 3D. Si les points d'une route ne sont pas dfinis dans le fichier SIA, * on reprsente la route seulement par un point situ 48N, 0E . * @param routeName Le nom de la route afficher. * @param type */ public void addRouteToLayer(String routeName, int type, boolean display) { String routeID = AIP.getID(type, routeName); Route.Space routeType; if (type == AIP.PDR) { routeType = Route.Space.UIR; } else { routeType = Route.Space.FIR; } try { String previousNavFix = null; PreparedStatement st = DatabaseManager.prepareStatement(DatasManager.Type.AIP, "select NavFix.nom from NavFix, routes where routes.pk = ? AND routes.navFixExtremite = NavFix.pk"); st.setString(1, routeID); ResultSet rs = st.executeQuery(); if (rs.next()) { previousNavFix = rs.getString(1); } st = DatabaseManager.prepareStatement(DatasManager.Type.AIP, "select segments.pk, NavFix.nom from segments, NavFix where pkRoute = ? AND NavFix.pk = segments.navFixExtremite ORDER BY sequence"); st.setString(1, routeID); ResultSet segments = st.executeQuery(); while (segments.next()) { Element segment = aip.findElement(aip.getDocumentRoot().getChild("SegmentS"), segments.getString(1)); String navFixExtremite = segments.getString(2); String segmentName = buildSegmentName(routeName, segment.getChildText("Sequence")); if (routes2D.getRoute(segmentName) == null) { if (!segment.getChildText("Circulation").equals("(XxX)")) { routesSegments.addSegment(segmentName, previousNavFix, navFixExtremite, routeName, type, Integer.parseInt(routeID), display); previousNavFix = navFixExtremite; Couple<Altitude, Altitude> altis = aip.getLevels(segment); ArrayList<LatLon> loc = new ArrayList<LatLon>(); Geometrie geometrieSegment = new Geometrie(segment); loc.addAll(geometrieSegment.getLocations()); if (loc.get(0) == null) { loc.clear(); loc.add(LatLon.fromDegrees(48, 0)); } DatabaseRoute2D segment2D = new DatabaseRoute2D(segmentName, routeType, DatasManager.Type.AIP, type); List<Integer> directions = new ArrayList<Integer>(); Parity sens = null; String sensString = segment.getChildText("Circulation"); if (sensString.equals("(2=1)") || sensString.equals("(1=2)") || sensString.equals("(0=0)")) { sens = Parity.RED; for (int i = 0; i < loc.size() - 1; i++) { directions.add(Route2D.LEG_AUTHORIZED); } } else if (sensString.equals("(X-1)") || sensString.equals("(1-X)")) { sens = Parity.GREEN; for (int i = 0; i < loc.size() - 1; i++) { if (i == loc.size() / 2) directions.add(Route2D.LEG_DIRECT); else directions.add(Route2D.LEG_AUTHORIZED); } } else if (sensString.equals("(X-2)") || sensString.equals("(2-X)") || sensString.equals("(X-0)")) { sens = Parity.BLUE; for (int i = 0; i < loc.size() - 1; i++) { if (i == loc.size() / 2) directions.add(Route2D.LEG_DIRECT); else directions.add(Route2D.LEG_AUTHORIZED); } } segment2D.setParity(sens); segment2D.setLocations(loc, directions); segment2D.setAnnotation("<html>Route " + segmentName + "<br/><b>Plancher :</b>" + altis.getFirst().getFullText() + "<br/><b>Plafond :</b>" + altis.getSecond().getFullText() + "</html>"); routes2D.addRoute(segment2D, segmentName); //TODO prendre en compte le sens de circulation pour les routes 3D... DatabaseRoute3D segment3D = new DatabaseRoute3D(segmentName, routeType, DatasManager.Type.AIP, type); segment3D.setLocations(loc); boolean lowerTerrainConformant = false, upperTerrainConformant = false; if (altis.getFirst().isTerrainConforming()) { lowerTerrainConformant = true; } if (altis.getSecond().isTerrainConforming()) { upperTerrainConformant = true; } segment3D.setParity(sens); segment3D.setTerrainConforming(lowerTerrainConformant, upperTerrainConformant); segment3D.setAltitudes(altis.getFirst().getMeters(), altis.getSecond().getMeters()); segment3D.setAnnotation("<html>Route " + segmentName + "<br/><b>Plancher :</b>" + altis.getFirst().getFullText() + "<br/><b>Plafond :</b>" + altis.getSecond().getFullText() + "</html>"); routes3D.addRoute(segment3D, segmentName); if (display) { routes3D.displayRoute(segmentName); routes2D.displayRoute(segmentName); } } } } } catch (SQLException e) { e.printStackTrace(); } } private void removeRoute(int type, String routeName) { //TODO problme avec les routes qui ont le mme nom (J 22 et J 22 Polynsie...) : quand on met l'annotation dans le hashmap //on ne connat pas le territoire, donc quand on affiche les deux J 22 en mme temps, on ne garde qu'une seule des deux annotations //dans le hashmap. Du coup on ne peut plus enlever l'autre. String routeID = AIP.getID(type, routeName); GlobeAnnotation routeAnnotation = routesAnnotations.get(routeName.split("-")[0].trim()); if (routeAnnotation != null) routeAnnotation.getAttributes().setVisible(false); RoutesSegments.Route route = routesSegments.getSegmentOfRoute(routeName); if (route != null) { if (route.isVisible()) { route.setVisible(false); for (Segment s : route) { routes2D.hideRoute(s.getName()); routes3D.hideRoute(s.getName()); } } if (route.areNavFixsVisible()) { displayRouteNavFixs(routeID, false, false); } } } /** * * @param pkRoute l'identifiant de la route * @param display true si on veut afficher les balises, false si on veut les cacher * @param withLocations true si on veut afficher les coordonnes des balises, false sinon */ public void displayRouteNavFixs(String pkRoute, boolean display, boolean withLocations) { List<Couple<String, String>> navFixExtremites = new ArrayList<Couple<String, String>>(); try { PreparedStatement st = DatabaseManager.prepareStatement(DatasManager.Type.AIP, "select nom, type from NavFix, segments where segments.pkRoute = ? AND segments.navFixExtremite = NavFix.pk"); st.setString(1, pkRoute); ResultSet rs = st.executeQuery(); while (rs.next()) { navFixExtremites.add(new Couple<String, String>(rs.getString(1), rs.getString(2))); } st = DatabaseManager.prepareStatement(DatasManager.Type.AIP, "select NavFix.nom, NavFix.type from NavFix, routes where routes.pk = ? AND routes.navFixExtremite = NavFix.pk"); st.setString(1, pkRoute); rs = st.executeQuery(); if (rs.next()) { navFixExtremites.add(new Couple<String, String>(rs.getString(1), rs.getString(2))); } } catch (SQLException e) { e.printStackTrace(); } fr.crnan.videso3d.databases.aip.RoutesSegments.Route routeAIP = routesSegments .getSegmentOfRoute(Integer.parseInt(pkRoute)); if (display) { for (Couple<String, String> navFix : navFixExtremites) { showObject(AIP.string2type(navFix.getSecond()), navFix.getFirst()); if (withLocations) { setLocationsVisible(AIP.string2type(navFix.getSecond()), navFix.getFirst(), true); } } if (routeAIP != null) routesSegments.getSegmentOfRoute(Integer.parseInt(pkRoute)).setNavFixsVisible(true); } else { for (Couple<String, String> navFix : navFixExtremites) { hideObject(AIP.string2type(navFix.getSecond()), navFix.getFirst()); setLocationsVisible(AIP.string2type(navFix.getSecond()), navFix.getFirst(), false); } if (routeAIP != null) routesSegments.getSegmentOfRoute(Integer.parseInt(pkRoute)).setNavFixsVisible(false); } } private void showNavFix(int type, String name) { if (!balises.contains(type + " " + name)) { double latitude = 0; double longitude = 0; String typeString = ""; double freq = 0; PreparedStatement ps; try { ps = DatabaseManager.prepareStatement(DatasManager.Type.AIP, "select lat, lon, type, frequence from NavFix where nom = ? and type = ?"); ps.setString(1, name); ps.setString(2, AIP.type2String(type)); ResultSet rs = ps.executeQuery(); while (rs.next()) { latitude = rs.getDouble(1); longitude = rs.getDouble(2); typeString = rs.getString(3); freq = rs.getDouble(4); } } catch (SQLException e) { e.printStackTrace(); } Balise2D navFix = new DatabaseBalise2D(name, Position.fromDegrees(latitude, longitude), DatasManager.Type.AIP, type, navFixLayer.getTextLayer()); String annotation = "<html><b>" + name + "</b><br/><i>Type : </i>" + typeString; if (freq != 0) { annotation += "<br/><i>Frq. : </i>" + freq; } annotation += "</html>"; navFix.setAnnotation(annotation); navFixLayer.addBalise(navFix); navFixLayer.showBalise(navFix); Balise3D navFix3D = new DatabaseBalise3D(name, Position.fromDegrees(latitude, longitude, 665 * 30.47), DatasManager.Type.AIP, type); navFix3D.setAnnotation(annotation); navFixLayer3D.addBalise(navFix3D); navFixLayer3D.showBalise(navFix3D); balises.add(type + " " + name); } else { navFixLayer.showBalise(name, type); navFixLayer3D.showBalise(name, type); } } private void removeNavFix(int type, String name) { if (balises.contains(type + " " + name)) { Balise2D navFix = navFixLayer.getBalise(name, type); navFixLayer.hideBalise(navFix); navFixLayer3D.hideBalise(name, type); this.wwd.getAnnotationLayer().removeAnnotation(navFix.getAnnotation(null)); } } private void showAerodrome(int type, String nom) { if (arptLayer.containsAirport(nom)) { ArrayList<Aerodrome> aerodromes = arptLayer.getAirport(nom); for (Aerodrome ad : aerodromes) { arptLayer.addAirport(ad); } } else { int pk = -1; double latRef = 0, lonRef = 0; ResultSet rs; PreparedStatement ps; try { if (type == AIP.AERODROME) { ps = DatabaseManager.prepareStatement(DatasManager.Type.AIP, "select pk, latRef, lonRef from aerodromes where upper(code) = ?"); ps.setString(1, nom.split("--")[0].trim()); rs = ps.executeQuery(); } else { ps = DatabaseManager.prepareStatement(DatasManager.Type.AIP, "select pk, latRef, lonRef from aerodromes where nom = ?"); ps.setString(1, nom); rs = ps.executeQuery(); } if (rs.next()) { pk = rs.getInt(1); latRef = rs.getDouble(2); lonRef = rs.getDouble(3); } ps = DatabaseManager.prepareStatement(DatasManager.Type.AIP, "select * from runways where pk_ad=?"); ps.setInt(1, pk); ResultSet rs2 = ps.executeQuery(); boolean runwayExists = false; while (rs2.next()) { runwayExists = true; String nomPiste = rs2.getString("nom"); if (rs2.getInt("largeur") > 0 && rs2.getDouble("lat1") != 0) { double lat1 = rs2.getDouble("lat1"); double lon1 = rs2.getDouble("lon1"); double lat2 = rs2.getDouble("lat2"); double lon2 = rs2.getDouble("lon2"); double largeur = rs2.getDouble("largeur"); DatabasePisteAerodrome piste = new DatabasePisteAerodrome(type, nom, nomPiste, lat1, lon1, lat2, lon2, largeur, Position.fromDegrees(latRef, lonRef), DatasManager.Type.AIP, arptLayer.getTextLayer()); arptLayer.addAirport(piste); } else { MarqueurAerodrome airportBalise = new MarqueurAerodrome(type, nom, Position.fromDegrees(latRef, lonRef), nomPiste, DatasManager.Type.AIP, arptLayer.getTextLayer()); arptLayer.addAirport(airportBalise); } } if (!runwayExists) { MarqueurAerodrome airportBalise = new MarqueurAerodrome(type, nom, Position.fromDegrees(latRef, lonRef), "Pistes inconnues", DatasManager.Type.AIP, arptLayer.getTextLayer()); arptLayer.addAirport(airportBalise); } } catch (SQLException e) { e.printStackTrace(); } } } private void removeAerodrome(int type, String nom) { arptLayer.hideAirport(nom); } @Override public void set2D(Boolean flat) { } @Override public void reset() { for (Secteur3D s : zones.values()) { s.setVisible(false); } this.routes2D.hideAllRoutes(); this.routes3D.hideAllRoutes(); this.navFixLayer.removeAllBalises(); this.navFixLayer3D.removeAllBalises(); this.arptLayer.removeAllAirports(); } public AIP getAIP() { return aip; } /** * Centre la vue sur la zone identifie par name et affiche l'annotation associe * (ou les annotations si c'est un secteur en plusieurs morceaux) * @param name */ @Override public void highlight(int type, String name) { this.showObject(type, name); if (type == AIP.CTL) { highlightCTL(name); //Si le type est suprieur 20 et infrieur 30, c'est une route } else if (type >= 20 && type < 30) { highlightRoute(type, name); //Si le type est suprieur ou gal 30 et infrieur 40, c'est une balise } else if (type >= 30 && type < 40) { highlightNavFix(type, name); //Si le type est suprieur ou gal 40, c'est un arodrome } else if (type >= 40) { highlightAirport(type, name); //Sinon c'est un volume } else { this.addZone(type, name); Secteur3D zone = zones.get(type + " " + name); this.centerView(zone); } } /** * Centre la vue sur une route ou un secteur3D, avec le niveau de zoom appropri, et affiche l'annotation associe. * @param zone * @return La position sur laquelle la vue est centre. */ public Position centerView(Object object) { Position centerPosition = this.wwd.centerView(object); if (centerPosition != null) showAnnotation(object, centerPosition); return centerPosition; } /** * Affiche une annotation pour l'objet obj la position pos * (pour l'instant, seuls les secteurs3D et les routes2D sont pris en charge). * @param obj * @param pos */ @SuppressWarnings("unchecked") public void showAnnotation(Object obj, Position pos) { if (obj instanceof VidesoObject) { this.wwd.getAnnotationLayer().addAnnotation(((VidesoObject) obj).getAnnotation(pos)); } else if (obj instanceof List) { if (((List<?>) obj).get(0) instanceof Route) { String routeName = ((List<? extends Route>) obj).get(0).getName().split("-")[0].trim(); GlobeAnnotation routeAnnotation = new VidesoAnnotation(routeName, pos); routeAnnotation.getAttributes().setLeaderGapWidth(10); routeAnnotation.getAttributes().setDrawOffset(new Point(20, 20)); routesAnnotations.put(routeName, routeAnnotation); this.wwd.getAnnotationLayer().addAnnotation(routeAnnotation); } } } /** * Centre la vue sur le premier morceau du secteur de contrle, et affiche les annotations de tous les morceaux. * @param names les noms des diffrents morceaux correspondant un secteur. */ private void highlightCTL(String name) { String nomSecteur = name.split(" ")[0].trim(); List<String> names = volumesSecteursCTL.get(nomSecteur); //on construit le secteur s'il n'existe pas encore // for(String n : names){ // this.addZone(AIP.CTL, n); // } //puis on le centre dans la vue Position center = centerView(zones.get(AIP.CTL + " " + names.get(0))); if (names.size() > 1) { for (int i = 1; i < names.size(); i++) { Position otherPosition = new Position(center.latitude.addDegrees(i * 0.2), center.longitude.addDegrees(-i * 0.2), center.elevation); this.wwd.getAnnotationLayer() .addAnnotation(zones.get(AIP.CTL + " " + names.get(i)).getAnnotation(otherPosition)); } } } /** * Renvoie les noms des morceaux de secteur correspondant au secteur name. * @param name * @return */ private ArrayList<String> getCTLSecteurs(String name) { ArrayList<String> names = new ArrayList<String>(); try { Statement st = DatabaseManager.getCurrentAIP(); ResultSet rs = st.executeQuery("select nom from volumes where type ='CTL' and (nom LIKE '" + name + " %' OR nom ='" + name + "')"); while (rs.next()) { names.add(rs.getString(1)); } st.close(); } catch (SQLException e) { e.printStackTrace(); } return names; } private void highlightAirport(int type, String name) { centerView(arptLayer.getAirport(name).get(0)); } private void highlightNavFix(int type, String name) { Balise2D navFix = navFixLayer.getBalise(name, type); navFix.setHighlighted(true); if (lastHighlighted != null) { lastHighlighted.setHighlighted(false); } if (lastNavFixAnnotation != null) { lastNavFixAnnotation.getAttributes().setVisible(false); } lastHighlighted = navFix; lastNavFixAnnotation = navFix.getAnnotation(null); centerView(navFix); } /** * Centre la vue sur la route dfinie par les segments passs en paramtre. * @param segmentsNames Les noms des segments de la route */ private void highlightRoute(int type, String name) { RoutesSegments.Route route = routesSegments.getSegmentOfRoute(name); if (route != null) { ArrayList<Route2D> segments2D = new ArrayList<Route2D>(); ArrayList<Route3D> segments3D = new ArrayList<Route3D>(); for (Segment s : route) { segments2D.add((Route2D) routes2D.getRoute(s.getName())); segments3D.add((Route3D) routes3D.getRoute(s.getName())); } centerView(segments2D); } } private String buildSegmentName(String routeName, String sequence) { return routeName.concat(" - ").concat(sequence); } public String getRouteIDFromSegmentName(String segmentName, String typeRoute) throws SQLException { String[] splittedRouteName = segmentName.split("-"); String route = splittedRouteName[0].trim(); String pkRoute = null; PreparedStatement st; ResultSet rs; if (splittedRouteName.length < 3) { st = DatabaseManager.prepareStatement(DatasManager.Type.AIP, "select pk from routes where nom = ? AND type = ?"); st.setString(1, route); st.setString(2, typeRoute); rs = st.executeQuery(); if (rs.next()) { pkRoute = rs.getString(1); } } else { st = DatabaseManager.prepareStatement(DatasManager.Type.AIP, "select pk from routes where nom LIKE ? AND type = ?"); st.setString(1, route + " -%"); st.setString(2, typeRoute); rs = st.executeQuery(); if (rs.next()) pkRoute = rs.getString(1); } return pkRoute; } /** * Renvoie le segment prcdent (par le numro de squence) ou null s'il n'y en a pas. * @param routeName Le nom de la route (et pas le nom du segment) * @param segmentSequenceString le numro de squence du segment * @param type le type de route (AWY, PDR ou TAC) * @return null si le segment */ public Route getPrevious(String routeName, String segmentSequenceString, String type, boolean route3D) { Route previousSegment = null; String pkRoute = null; int segmentSequence = Integer.parseInt(segmentSequenceString); try { pkRoute = getRouteIDFromSegmentName(routeName, type); int previousSeq = getNearSequence(pkRoute, segmentSequence, -1); if (previousSeq != 0) { if (route3D) { previousSegment = (Route3D) routes3D.getRoute(routeName.concat(" - " + previousSeq)); } else { previousSegment = (Route2D) routes2D.getRoute(routeName.concat(" - " + previousSeq)); } } } catch (SQLException e) { e.printStackTrace(); } return previousSegment; } /** * Renvoie le segment suivant (par le numro de squence) ou null s'il n'y en a pas. * @param routeName Le nom de la route (et pas le nom du segment) * @param segmentSequenceString le numro de squence du segment * @param type le type de route (AWY, PDR ou TAC) * @return The next segment if it exists, null if not */ public Route getNext(String routeName, String segmentSequenceString, String type, boolean route3D) { Route nextSegment = null; String pkRoute = null; int segmentSequence = Integer.parseInt(segmentSequenceString); try { pkRoute = getRouteIDFromSegmentName(routeName, type); int nextSeq = getNearSequence(pkRoute, segmentSequence, 1); if (nextSeq != 0) { if (route3D) { nextSegment = (Route3D) routes3D.getRoute(routeName.concat(" - " + nextSeq)); } else { nextSegment = (Route2D) routes2D.getRoute(routeName.concat(" - " + nextSeq)); } } } catch (SQLException e) { e.printStackTrace(); } return nextSegment; } /** * Renvoie le numro de squence prcdent ou suivant (selon nextOrPrevious) pour la mme route, * ou 0 s'il n'y a pas de segment prcdent ou suivant. * @param pkRoute l'identifiant de la route * @param originalSequence le numro de squence de dpart * @param nextOrPrevious doit tre >0 si on cherche la squence suivante, <=0 si on cherche la prcdente. * @return Le numro de squence recherch ou 0. * @throws SQLException */ private int getNearSequence(String pkRoute, int originalSequence, int nextOrPrevious) throws SQLException { PreparedStatement ps = null; if (nextOrPrevious > 0) { ps = DatabaseManager.prepareStatement(DatasManager.Type.AIP, "select sequence from segments where pkRoute = ? ORDER BY sequence DESC"); } else { ps = DatabaseManager.prepareStatement(DatasManager.Type.AIP, "select sequence from segments where pkRoute = ? ORDER BY sequence ASC"); } ps.setString(1, pkRoute); ResultSet rs = ps.executeQuery(); int nearSeq = 0; if (nextOrPrevious > 0) { while (rs.next()) { int seq = rs.getInt(1); if (seq > originalSequence) { nearSeq = seq; } else { break; } } } else { while (rs.next()) { int seq = rs.getInt(1); if (seq < originalSequence) { nearSeq = seq; } else { break; } } } return nearSeq; } public void displayAnnotationAndGoTo(Route segment) { Position annotationPosition = new Position(segment.getLocations().iterator().next(), 0); Annotation annotation = ((VidesoObject) segment).getAnnotation(annotationPosition); if (lastSegmentAnnotation != null) lastSegmentAnnotation.getAttributes().setVisible(false); lastSegmentAnnotation = annotation; annotation.getAttributes().setVisible(true); wwd.getAnnotationLayer().addAnnotation(annotation); BasicOrbitView bov = (BasicOrbitView) wwd.getView(); bov.addPanToAnimator(annotationPosition, bov.getHeading(), bov.getPitch(), bov.getEyePosition().elevation, 2000, true); bov.firePropertyChange(AVKey.VIEW, null, bov); wwd.redraw(); } public void setBalisesLayer3D(boolean threeD) { this.toggleLayer(this.navFixLayer, !threeD); this.toggleLayer(this.navFixLayer3D, threeD); } @Override public String type2string(int type) { return AIP.type2String(type); } @Override public String toString() { return "AIP"; } public static int getNumberInitSteps() { return 3; } /** * * @param name * @return Tous les {@link VPolygon} qui forment une zone ou un secteur */ public List<VPolygon> getPolygons(int type, String name) { List<VPolygon> polygons = new ArrayList<VPolygon>(); if (type == AIP.CTL) { for (String n : this.getCTLSecteurs(name.split(" ")[0])) { polygons.add(this.zones.get(type + " " + n)); } } else { polygons.add(this.zones.get(type + " " + name)); } return polygons; } @Override public Collection<Object> getObjects(int type) { if (type == AIP.CTL) { try { Statement st = DatabaseManager.getCurrentAIP(); ResultSet rs = st.executeQuery("select count(*) from volumes where type = 'CTL'"); this.fireTaskStarts(rs.getInt(1)); rs = st.executeQuery("select nom from volumes where type = 'CTL' order by nom"); int i = 1; while (rs.next()) { this.createZone(AIP.CTL, rs.getString(1)); this.fireTaskProgress(i++); } st.close(); } catch (SQLException e) { e.printStackTrace(); } Collection<Object> secteurs = new HashSet<Object>(); for (Secteur3D s : this.zones.values()) { if (s.getType() == AIP.CTL) secteurs.add(s); } return secteurs; } else if (type == AIP.TMA) { try { Statement st = DatabaseManager.getCurrentAIP(); ResultSet rs = st.executeQuery("select count(*) from volumes where type = 'TMA'"); this.fireTaskStarts(rs.getInt(1)); rs = st.executeQuery("select nom from volumes where type = 'TMA' order by nom"); int i = 1; while (rs.next()) { this.createZone(AIP.TMA, rs.getString(1)); this.fireTaskProgress(i++); } st.close(); } catch (SQLException e) { e.printStackTrace(); } Collection<Object> secteurs = new HashSet<Object>(); for (Secteur3D s : this.zones.values()) { if (s.getType() == AIP.TMA) secteurs.add(s); } return secteurs; } else if (type == AIP.CTR) { try { Statement st = DatabaseManager.getCurrentAIP(); ResultSet rs = st.executeQuery("select count(*) from volumes where type = 'CTR'"); this.fireTaskStarts(rs.getInt(1)); rs = st.executeQuery("select nom from volumes where type = 'CTR' order by nom"); int i = 1; while (rs.next()) { this.createZone(AIP.CTR, rs.getString(1)); this.fireTaskProgress(i++); } st.close(); } catch (SQLException e) { e.printStackTrace(); } Collection<Object> secteurs = new HashSet<Object>(); for (Secteur3D s : this.zones.values()) { if (s.getType() == AIP.CTR) secteurs.add(s); } return secteurs; } return null; } @Override public void setColor(Color color, int type, String name) { throw new UnsupportedOperationException("Not implemented"); } @Override public boolean isColorEditable(int type) { return false; } @Override public HashMap<Integer, List<String>> getSelectedObjectsReference() { HashMap<Integer, List<String>> objects = new HashMap<Integer, List<String>>(); //routes for (RoutesSegments.Route r : this.routesSegments.getRoutes()) { if (r.isVisible()) { if (!objects.containsKey(r.getType())) { objects.put(r.getType(), new ArrayList<String>()); } objects.get(r.getType()).add(r.getName()); } } //navfix for (Balise2D b : this.navFixLayer.getVisibleBalises()) { Integer type = ((DatabaseBalise2D) b).getType(); String name = ((DatabaseBalise2D) b).getName(); if (!objects.containsKey(type)) { objects.put(type, new ArrayList<String>()); } objects.get(type).add(name); } //zones for (Secteur3D s : this.zones.values()) { if (s.isVisible()) { Integer type = s.getType(); String name = s.getName(); if (!objects.containsKey(type)) { objects.put(type, new ArrayList<String>()); } objects.get(type).add(name); } } //airports for (Aerodrome a : this.arptLayer.getVisiblePistes()) { Integer type = ((DatabaseVidesoObject) a).getType(); String name = ((DatabaseVidesoObject) a).getName(); if (!objects.containsKey(type)) { objects.put(type, new ArrayList<String>()); } if (!objects.get(type).contains(name)) { objects.get(type).add(name); } } return objects; } @Override public Iterable<Restorable> getSelectedObjects() { ArrayList<Restorable> restorables = new ArrayList<Restorable>(); if (this.routes2D.isEnabled()) { for (String r : this.routes2D.getVisibleRoutes()) { restorables.add(this.routes2D.getRoute(r)); } } else { for (String r : this.routes3D.getVisibleRoutes()) { restorables.add(this.routes3D.getRoute(r)); } } if (this.navFixLayer.isEnabled()) { restorables.addAll(this.navFixLayer.getVisibleBalises()); } else { restorables.addAll(this.navFixLayer3D.getVisibleBalises()); } for (Secteur3D s : this.zones.values()) { if (s.isVisible()) restorables.add(s); } restorables.addAll(this.arptLayer.getVisibleRestorables()); return restorables; } @Override public boolean areLocationsVisible(int type, String name) { if (type >= AIP.AWY && type < AIP.DMEATT) { return routes2D.getRoute(name).areLocationsVisible(); } else if (type >= AIP.DMEATT && type < AIP.AERODROME) { Balise2D b = navFixLayer.getBalise(name, type); return (b != null ? b.isLocationVisible() : false); } else if (type >= AIP.AERODROME) { List<Aerodrome> aerodromes = arptLayer.getAirport(name); Aerodrome aerodrome = aerodromes.get(0); if (aerodrome instanceof MarqueurAerodrome) return ((MarqueurAerodrome) aerodrome).isLocationVisible(); else return ((DatabasePisteAerodrome) aerodrome).areLocationsVisible(); } else { return zones.get(type + " " + name).areLocationsVisible(); } } @Override public void setLocationsVisible(int type, String name, boolean visible) { if (type >= AIP.AWY && type < AIP.DMEATT) { String pkRoute = null; try { pkRoute = getRouteIDFromSegmentName(name, AIP.type2String(type)); } catch (SQLException e) { e.printStackTrace(); } displayRouteNavFixs(pkRoute, visible, visible); RoutesSegments.Route route = routesSegments.getSegmentOfRoute(Integer.parseInt(pkRoute)); if (route != null) { for (Segment s : route) { routes2D.getRoute(s.getName()).setLocationsVisible(visible); } } } else if (type >= AIP.DMEATT && type < AIP.AERODROME) { navFixLayer.getBalise(name, type).setLocationVisible(visible); navFixLayer3D.getBalise(name, type).setLocationVisible(visible); } else if (type >= AIP.AERODROME) { List<Aerodrome> aerodromes = arptLayer.getAirport(name); for (Aerodrome aero : aerodromes) { if (aero instanceof MarqueurAerodrome) ((MarqueurAerodrome) aero).setLocationVisible(visible); else { ((DatabasePisteAerodrome) aero).setLocationsVisible(visible); } } } else { List<VPolygon> polygons = getPolygons(type, name); for (VPolygon p : polygons) { ((Secteur3D) p).setLocationsVisible(visible); } } } }