package gps; // l'interface graphique import java.awt.BasicStroke; import java.awt.Color; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.Point; import java.awt.event.KeyEvent; import java.awt.event.KeyListener; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.awt.event.MouseWheelEvent; import java.util.List; import javax.swing.JFrame; import javax.swing.JPanel; // fenêtre graphique class GUI extends JFrame { private static final long serialVersionUID = 2465232426222345837L; GUI() { this.setTitle("navigateur GPS"); this.add(new Window()); this.setSize(800, 600); this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); this.setLocationRelativeTo(null); this.setResizable(false); } } // panneau graphique dans lequel on dessine class Window extends JPanel { private static final long serialVersionUID = -6904944047037109623L; // le centre de la carte et son échelle private double centerLat = 0.851; private double centerLon = 0.040; private double scale = 800 / 0.008; // 800 pixels = scale radians Vertex select1, select2; private Iterable<Edge> path = null; Window() { // gestion des événements clavier KeyListener kl = new KeyListener() { @Override public void keyPressed(KeyEvent e) { } @Override public void keyReleased(KeyEvent e) { } @Override public void keyTyped(KeyEvent e) { if (e.getKeyChar() == 'q') System.exit(0); if (select1 == null || select2 == null) { System.out.println("choisir deux points svp"); return; } switch (e.getKeyChar()) { case 'p': System.out.println("parcours en profondeur"); path = FindPath.runDFS(select1, select2); FindPath.printPath(path); break; case 'l': System.out.println("parcours en largeur"); path = FindPath.runBFS(select1, select2); FindPath.printPath(path); break; case 'd': System.out.println("algorithme de Dijkstra"); path = FindPath.runDijkstra(select1, select2); FindPath.printPath(path); break; default: path = null; break; } repaint(); } }; this.setFocusable(true); this.requestFocus(); this.addKeyListener(kl); // gestion des événements souris MouseAdapter ma = new MouseAdapter() { private Point lastMouse = null; @Override public void mousePressed(MouseEvent e) { //System.out.println("mouse pressed"); lastMouse = e.getPoint(); } @Override public void mouseReleased(MouseEvent e) { lastMouse = null; } @Override public void mouseWheelMoved(MouseWheelEvent e) { scale *= (e.getWheelRotation() < 0 ? 1.2 : 0.8); // System.out.println("new scale = " + scale); repaint(); } @Override public void mouseClicked(MouseEvent e) { //System.out.println("mouse clicked"); Point p = e.getPoint(); double lon = lon(p.x); System.out.print("x = " + p.x); System.out.println(" lon = " + lon); double lat = lat(p.y); System.out.print("y = " + p.y); System.out.println(" lat = " + lat); if (select1 == null || select2 != null) { select1 = Graph.closest(lat, lon); select2 = null; path = null; } else { select2 = Graph.closest(lat, lon); path = null; } repaint(); } @Override public void mouseDragged(MouseEvent e) { Point p = e.getPoint(); if (lastMouse != null) { double dLat = lat(p.y) - lat(lastMouse.y); double dLon = lon(p.x) - lon(lastMouse.x); centerLat -= dLat; centerLon -= dLon; repaint(); } lastMouse = p; } }; this.addMouseListener(ma); this.addMouseMotionListener(ma); this.addMouseWheelListener(ma); } // dessin private int width = 800, height = 600; /* les méthodes suivantes convertissent les coordonnées (lat,lon) * en points à l'écran (x,y) et vice versa */ private int x(double lon) { return (int) (width / 2 + (lon - centerLon) * scale); } private int x(Vertex v) { return x(v.lon); } private double lon(int x) { return centerLon + (x - width / 2) / scale; } private int y(double lat) { // une simple règle de trois return (int) (height / 2 - (lat - centerLat) * 2 * scale); // projection Mercator // double y0 = Math.log(Math.tan(Math.PI/4 + centerLat/2)); // double y = Math.log(Math.tan(Math.PI/4 + lat/2)); // return (int) (height / 2 - (y - y0) * scale); } private int y(Vertex v) { return y(v.lat); } private double lat(int y) { // avec la règle de trois return centerLat + (height / 2 - y) / scale / 2; // avec la projection Mercator // double y0 = Math.log(Math.tan(Math.PI/4 + centerLat/2)); // double my = y0 + (height / 2 - y) / scale; // return 2 * Math.atan(Math.exp(my)) - Math.PI/2; } // dessin des sommets private void drawVertex(Graphics2D g, Vertex p, Color c, int radius) { g.setColor(c); g.fillOval(x(p) - radius/2, y(p) - radius/2, radius, radius); } private void drawVertex(Graphics2D g, Vertex p) { drawVertex(g, p, Color.black, 3); } // dessin des arcs // à partir de scaleLimit, on dessine les routes avec une épaisseur private static final double scaleLimit = 1000000; private static final BasicStroke pen1 = new BasicStroke(1); private static final BasicStroke pen5 = new BasicStroke(5); private static final BasicStroke pen7 = new BasicStroke(7); private void drawEdge(Graphics2D g, Edge e, BasicStroke stroke, Color color) { g.setColor(color); g.setStroke(stroke); g.drawLine(x(e.src), y(e.src), x(e.dst), y(e.dst)); } private void drawEdge(Graphics2D g, Edge e, boolean firstStep) { if (!e.directed && e.src.id < e.dst.id) return; boolean road = scale >= scaleLimit; if (firstStep) { drawEdge(g, e, road ? pen7 : pen1, (e.directed ? Color.darkGray : Color.black)); } else if (road) { drawEdge(g, e, pen5, Color.white); } } @Override public void paintComponent(Graphics g) { super.paintComponent(g); Graphics2D g2d = (Graphics2D) g; width = this.getWidth(); height = this.getHeight(); for (Vertex p : Graph.vertices()) drawVertex(g2d, p); for (List<Edge> l : Graph.edges()) for (Edge e : l) drawEdge(g2d, e, true); for (List<Edge> l : Graph.edges()) for (Edge e : l) drawEdge(g2d, e, false); // s'il y a des points sélectionnés, les montrer if (select1 != null) drawVertex(g2d, select1, Color.red, 10); if (select2 != null) drawVertex(g2d, select2, Color.blue, 10); // s'il y a un chemin, le dessiner if (path != null) for (Edge e : path) drawEdge(g2d, e, pen5, Color.red); } }