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);
}
}