diff --git a/.classpath b/.classpath
index a2f75d1..668b23b 100644
--- a/.classpath
+++ b/.classpath
@@ -1,69 +1,63 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/.settings/org.eclipse.jdt.core.prefs b/.settings/org.eclipse.jdt.core.prefs
new file mode 100644
index 0000000..d59e09c
--- /dev/null
+++ b/.settings/org.eclipse.jdt.core.prefs
@@ -0,0 +1,5 @@
+eclipse.preferences.version=1
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8
+org.eclipse.jdt.core.compiler.compliance=1.8
+org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning
+org.eclipse.jdt.core.compiler.source=1.8
diff --git a/.settings/org.eclipse.m2e.core.prefs b/.settings/org.eclipse.m2e.core.prefs
new file mode 100644
index 0000000..14b697b
--- /dev/null
+++ b/.settings/org.eclipse.m2e.core.prefs
@@ -0,0 +1,4 @@
+activeProfiles=
+eclipse.preferences.version=1
+resolveWorkspaceProjects=true
+version=1
diff --git a/src/main/org/insa/algo/weakconnectivity/WeaklyConnectedComponentGraphicObserver.java b/src/main/org/insa/algo/weakconnectivity/WeaklyConnectedComponentGraphicObserver.java
index c5cfa53..c2657ce 100644
--- a/src/main/org/insa/algo/weakconnectivity/WeaklyConnectedComponentGraphicObserver.java
+++ b/src/main/org/insa/algo/weakconnectivity/WeaklyConnectedComponentGraphicObserver.java
@@ -7,33 +7,31 @@ import org.insa.drawing.Drawing;
import org.insa.graph.Node;
public class WeaklyConnectedComponentGraphicObserver implements WeaklyConnectedComponentObserver {
-
- private static final Color[] COLORS = {
- Color.BLUE, Color.ORANGE, Color.GREEN, Color.YELLOW, Color.RED
- };
- // Drawing + Graph drawing
- private Drawing drawing;
-
- // Current index color
- private int cindex = -1;
-
- public WeaklyConnectedComponentGraphicObserver(Drawing drawing) {
- this.drawing = drawing;
- }
+ private static final Color[] COLORS = { Color.BLUE, Color.ORANGE, Color.GREEN, Color.YELLOW, Color.RED };
- @Override
- public void notifyStartComponent(Node curNode) {
- cindex = (cindex + 1) % COLORS.length;
- }
+ // Drawing + Graph drawing
+ private Drawing drawing;
- @Override
- public void notifyNewNodeInComponent(Node node) {
- this.drawing.drawMarker(node.getPoint(), COLORS[cindex]);
- }
+ // Current index color
+ private int cindex = -1;
- @Override
- public void notifyEndComponent(ArrayList nodes) {
- }
+ public WeaklyConnectedComponentGraphicObserver(Drawing drawing) {
+ this.drawing = drawing;
+ }
+
+ @Override
+ public void notifyStartComponent(Node curNode) {
+ cindex = (cindex + 1) % COLORS.length;
+ }
+
+ @Override
+ public void notifyNewNodeInComponent(Node node) {
+ this.drawing.drawPoint(node.getPoint(), 1, COLORS[cindex]);
+ }
+
+ @Override
+ public void notifyEndComponent(ArrayList nodes) {
+ }
}
diff --git a/src/main/org/insa/base/MainWindow.java b/src/main/org/insa/base/MainWindow.java
index 28b5c30..34da2b0 100644
--- a/src/main/org/insa/base/MainWindow.java
+++ b/src/main/org/insa/base/MainWindow.java
@@ -1,651 +1,625 @@
-package org.insa.base;
-
-import java.awt.BorderLayout;
-import java.awt.Color;
-import java.awt.Component;
-import java.awt.Dimension;
-import java.awt.event.ActionEvent;
-import java.awt.event.ActionListener;
-import java.awt.event.KeyEvent;
-import java.awt.event.MouseAdapter;
-import java.awt.event.MouseEvent;
-import java.awt.event.WindowAdapter;
-import java.awt.event.WindowEvent;
-import java.awt.geom.NoninvertibleTransformException;
-import java.io.DataInputStream;
-import java.io.File;
-import java.io.IOException;
-import java.io.OutputStream;
-import java.io.PrintStream;
-import java.time.Duration;
-import java.time.Instant;
-import java.util.ArrayList;
-
-import javax.swing.BorderFactory;
-import javax.swing.JButton;
-import javax.swing.JFileChooser;
-import javax.swing.JFrame;
-import javax.swing.JLabel;
-import javax.swing.JMenu;
-import javax.swing.JMenuBar;
-import javax.swing.JMenuItem;
-import javax.swing.JOptionPane;
-import javax.swing.JPanel;
-import javax.swing.JScrollPane;
-import javax.swing.JSplitPane;
-import javax.swing.JTextArea;
-import javax.swing.KeyStroke;
-import javax.swing.SwingConstants;
-import javax.swing.Timer;
-import javax.swing.UIManager;
-import javax.swing.filechooser.FileNameExtensionFilter;
-
-import org.insa.algo.shortestpath.BellmanFordAlgorithm;
-import org.insa.algo.shortestpath.ShortestPathAlgorithm;
-import org.insa.algo.shortestpath.ShortestPathData;
-import org.insa.algo.shortestpath.ShortestPathData.Mode;
-import org.insa.algo.shortestpath.ShortestPathGraphicObserver;
-import org.insa.algo.shortestpath.ShortestPathSolution;
-import org.insa.algo.weakconnectivity.WeaklyConnectedComponentGraphicObserver;
-import org.insa.algo.weakconnectivity.WeaklyConnectedComponentsAlgorithm;
-import org.insa.algo.weakconnectivity.WeaklyConnectedComponentsData;
-import org.insa.drawing.BasicDrawing;
-import org.insa.drawing.BlackAndWhiteGraphPalette;
-import org.insa.drawing.Drawing;
-import org.insa.drawing.MapViewDrawing;
-import org.insa.graph.Graph;
-import org.insa.graph.Node;
-import org.insa.graph.Path;
-import org.insa.graph.Point;
-import org.insa.graph.io.AbstractGraphReader;
-import org.insa.graph.io.BinaryGraphReader;
-import org.insa.graph.io.BinaryGraphReaderV2;
-import org.insa.graph.io.BinaryPathReader;
-import org.insa.graph.io.MapMismatchException;
-import org.insa.graph.io.Openfile;
-
-public class MainWindow extends JFrame {
-
- protected class JOutputStream extends OutputStream {
- private JTextArea textArea;
-
- public JOutputStream(JTextArea textArea) {
- this.textArea = textArea;
- }
-
- @Override
- public void write(int b) throws IOException {
- // redirects data to the text area
- textArea.setText(textArea.getText() + String.valueOf((char) b));
- // scrolls the text area to the end of data
- textArea.setCaretPosition(textArea.getDocument().getLength());
- // keeps the textArea up to date
- textArea.update(textArea.getGraphics());
- }
- }
-
- protected interface CallableWithNodes {
-
- void call(ArrayList nodes);
-
- };
-
- protected class DrawingClickListener extends MouseAdapter {
-
- // Enable/Disable.
- private boolean enabled = false;
-
- // List of points.
- private ArrayList points = new ArrayList();
-
- // Number of points to find before running.
- private int nTargetPoints = 0;
-
- // Callable to call when points are reached.
- CallableWithNodes callable = null;
-
- /**
- * @return true if this listener is enabled.
- */
- public boolean isEnabled() {
- return enabled;
- }
-
- /**
- * Enable this listener.
- *
- * @param nTargetPoints Number of point to found before calling the callable.
- */
- public void enable(int nTargetPoints, CallableWithNodes callable) {
- this.enabled = true;
- this.nTargetPoints = nTargetPoints;
- this.points.clear();
- this.callable = callable;
- }
-
- /**
- * Disable this listener.
- */
- public void disable() {
- this.enabled = false;
- }
-
- public void mouseClicked(MouseEvent evt) {
- if (!isEnabled()) {
- return;
- }
- Point lonlat;
- try {
- // TODO: Fix
- lonlat = ((BasicDrawing) drawing).getLongitudeLatitude(evt);
- }
- catch (NoninvertibleTransformException e) {
- // Should never happens in "normal" circumstances...
- e.printStackTrace();
- return;
- }
-
- Node node = graph.findClosestNode(lonlat);
-
- drawing.drawMarker(node.getPoint(), Color.BLUE);
- points.add(node);
- if (points.size() == nTargetPoints) {
- callable.call(points);
- this.disable();
- }
- }
- };
-
- /**
- *
- */
- private static final long serialVersionUID = -527660583705140687L;
-
- /**
- *
- */
- private static final String WINDOW_TITLE = "BE Graphes INSA";
-
- /**
- *
- */
- private static final int THREAD_TIMER_DELAY = 1000; // in milliseconds
-
- // Current graph.
- private Graph graph;
-
- // Current loaded path.
- private Path currentPath;
-
- // Drawing and click adapter.
- private Drawing drawing;
- private DrawingClickListener clickAdapter;
-
- // Main panel.
- private JSplitPane mainPanel;
-
- // List of item for the top menus.
- private JMenuItem openMapItem;
-
- // List of items that cannot be used without a graph
- private ArrayList graphLockItems = new ArrayList();
-
- // Label containing the map ID of the current graph.
- private JLabel mapIdPanel;
-
- // Thread information
- private Instant threadStartTime;
- private Timer threadTimer;
- private JPanel threadPanel;
-
- // Log stream and print stream
- private JOutputStream logStream;
-
- @SuppressWarnings("unused")
- private PrintStream printStream;
-
- // Current running thread
- private Thread currentThread;
-
- public MainWindow() {
- super(WINDOW_TITLE);
- setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
- setLayout(new BorderLayout());
- setJMenuBar(createMenuBar());
-
- addWindowListener(new WindowAdapter() {
- public void windowClosing(WindowEvent e) {
- int confirmed = JOptionPane.showConfirmDialog(null,
- "Are you sure you want to close the application?", "Exit Confirmation",
- JOptionPane.YES_NO_OPTION);
-
- if (confirmed == JOptionPane.YES_OPTION) {
- dispose();
- System.exit(0);
- }
- }
- });
-
- // Create graph area
- mainPanel = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT);
-
- BasicDrawing drawing = new BasicDrawing();
- // MapViewDrawing drawing = new MapViewDrawing();
-
- Component drawingComponent = drawing;
- this.drawing = drawing;
-
- // Click adapter
- this.clickAdapter = new DrawingClickListener();
- // drawing.addMouseListener(this.clickAdapter);
-
- JTextArea infoPanel = new JTextArea();
- infoPanel.setMinimumSize(new Dimension(200, 50));
- // infoPanel.setBorder(BorderFactory.createMatteBorder(0, 1, 0, 0, Color.GRAY));
- infoPanel.setBackground(Color.WHITE);
- infoPanel.setLineWrap(true);
- infoPanel.setEditable(false);
- this.logStream = new JOutputStream(infoPanel);
- this.printStream = new PrintStream(this.logStream);
-
- mainPanel.setResizeWeight(0.8);
- // sp.setEnabled(false);
- mainPanel.setDividerSize(5);
-
- mainPanel.setBackground(Color.WHITE);
- mainPanel.add(drawingComponent);
- mainPanel.add(new JScrollPane(infoPanel));
- this.add(mainPanel, BorderLayout.CENTER);
-
- // Top Panel
- this.add(createTopPanel(), BorderLayout.NORTH);
- this.add(createStatusBar(), BorderLayout.SOUTH);
- }
-
- private void restartThreadTimer() {
- threadStartTime = Instant.now();
- threadTimer.restart();
- }
-
- private void stopThreadTimer() {
- threadTimer.stop();
- }
-
- /**
- * @param runnable
- * @param canInterrupt
- */
- private void launchThread(Runnable runnable, boolean canInterrupt) {
- if (canInterrupt) {
- currentThread = new Thread(new Runnable() {
- @Override
- public void run() {
- restartThreadTimer();
- threadPanel.setVisible(true);
- runnable.run();
- clearCurrentThread();
- }
- });
- }
- else {
- currentThread = new Thread(runnable);
- }
- currentThread.start();
- }
-
- private void launchThread(Runnable runnable) {
- launchThread(runnable, true);
- }
-
- private void clearCurrentThread() {
- stopThreadTimer();
- threadPanel.setVisible(false);
- currentThread = null;
- }
-
- private void launchShortestPathThread(ShortestPathAlgorithm spAlgorithm) {
- spAlgorithm.addObserver(new ShortestPathGraphicObserver(drawing));
- // algo.addObserver(new ShortestPathTextObserver(printStream));
- launchThread(new Runnable() {
- @Override
- public void run() {
- ShortestPathSolution solution = spAlgorithm.run();
- if (solution != null && solution.isFeasible()) {
- drawing.drawPath(solution.getPath());
- }
- }
- });
- }
-
- private JMenuBar createMenuBar() {
-
- // Open Map item...
- openMapItem = new JMenuItem("Open Map... ", KeyEvent.VK_O);
- openMapItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_O, ActionEvent.ALT_MASK));
- openMapItem.addActionListener(new ActionListener() {
- @Override
- public void actionPerformed(ActionEvent e) {
- JFileChooser chooser = new JFileChooser();
- FileNameExtensionFilter filter = new FileNameExtensionFilter(
- "Map & compressed map files", "map", "map2", "mapgr", "map.gz");
- chooser.setCurrentDirectory(new File(System.getProperty("user.dir")));
- chooser.setFileFilter(filter);
- if (chooser.showOpenDialog(MainWindow.this) == JFileChooser.APPROVE_OPTION) {
- launchThread(new Runnable() {
- @Override
- public void run() {
- String path = chooser.getSelectedFile().getAbsolutePath();
- DataInputStream stream;
- try {
- stream = Openfile.open(path);
- }
- catch (IOException e1) {
- JOptionPane.showMessageDialog(MainWindow.this,
- "Cannot open the selected file.");
- return;
- }
- AbstractGraphReader reader;
- if (path.endsWith(".map2") || path.endsWith("mapgr")) {
- reader = new BinaryGraphReaderV2(stream);
- }
- else {
- reader = new BinaryGraphReader(stream);
- }
- try {
- graph = reader.read();
- }
- catch (Exception exception) {
- JOptionPane.showMessageDialog(MainWindow.this,
- "Unable to read graph from the selected file.");
- exception.printStackTrace(System.out);
- return;
- }
- drawing.clear();
- drawing.drawGraph(graph);
-
- for (JMenuItem item: graphLockItems) {
- item.setEnabled(true);
- }
- mapIdPanel
- .setText("Map ID: 0x" + Integer.toHexString(graph.getMapId()));
- }
- }, false);
- }
- }
- });
-
- // Open Path item...
- JMenuItem openPathItem = new JMenuItem("Open Path... ", KeyEvent.VK_P);
- openPathItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_P, ActionEvent.ALT_MASK));
- openPathItem.addActionListener(new ActionListener() {
- @Override
- public void actionPerformed(ActionEvent e) {
- JFileChooser chooser = new JFileChooser();
- FileNameExtensionFilter filter = new FileNameExtensionFilter(
- "Path & compressed path files", "path", "path.gz");
- chooser.setCurrentDirectory(new File(System.getProperty("user.dir")));
- chooser.setFileFilter(filter);
- if (chooser.showOpenDialog(MainWindow.this) == JFileChooser.APPROVE_OPTION) {
- BinaryPathReader reader;
- try {
- reader = new BinaryPathReader(
- Openfile.open(chooser.getSelectedFile().getAbsolutePath()));
- }
- catch (IOException e1) {
- JOptionPane.showMessageDialog(MainWindow.this,
- "Cannot open the selected file.");
- return;
- }
- try {
- currentPath = reader.readPath(graph);
- }
- catch (MapMismatchException exception) {
- JOptionPane.showMessageDialog(MainWindow.this,
- "The selected file does not contain a path for the current graph.");
- return;
- }
- catch (Exception exception) {
- JOptionPane.showMessageDialog(MainWindow.this,
- "Unable to read path from the selected file.");
- return;
- }
- drawing.drawPath(currentPath);
- }
- }
- });
- graphLockItems.add(openPathItem);
-
- // Close item
- JMenuItem closeItem = new JMenuItem("Quit", KeyEvent.VK_Q);
- closeItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_Q, ActionEvent.ALT_MASK));
- closeItem.addActionListener(new ActionListener() {
- @Override
- public void actionPerformed(ActionEvent e) {
- MainWindow.this.dispatchEvent(
- new WindowEvent(MainWindow.this, WindowEvent.WINDOW_CLOSING));
- }
- });
-
- // Build the first menu.
- JMenu fileMenu = new JMenu("File");
- fileMenu.add(openMapItem);
- fileMenu.add(openPathItem);
- fileMenu.addSeparator();
- fileMenu.add(closeItem);
-
- // Second menu
- JMenuItem drawGraphItem = new JMenuItem("Redraw", KeyEvent.VK_R);
- drawGraphItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_R, ActionEvent.ALT_MASK));
- drawGraphItem.addActionListener(new ActionListener() {
- @Override
- public void actionPerformed(ActionEvent e) {
- launchThread(new Runnable() {
- @Override
- public void run() {
- if (!(drawing instanceof BasicDrawing)) {
- BasicDrawing tmp = new BasicDrawing();
- mainPanel.setLeftComponent(tmp);
- drawing = tmp;
- }
- drawing.clear();
- drawing.drawGraph(graph);
- }
- });
- }
- });
- graphLockItems.add(drawGraphItem);
- JMenuItem drawGraphBWItem = new JMenuItem("Redraw (B&W)", KeyEvent.VK_B);
- drawGraphBWItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_B, ActionEvent.ALT_MASK));
- drawGraphBWItem.addActionListener(new ActionListener() {
- @Override
- public void actionPerformed(ActionEvent e) {
- launchThread(new Runnable() {
- @Override
- public void run() {
- if (!(drawing instanceof BasicDrawing)) {
- BasicDrawing tmp = new BasicDrawing();
- mainPanel.setLeftComponent(tmp);
- drawing = tmp;
- }
- drawing.clear();
- drawing.drawGraph(graph, new BlackAndWhiteGraphPalette());
- }
- });
- }
- });
- graphLockItems.add(drawGraphBWItem);
- JMenuItem drawGraphMapsforgeItem = new JMenuItem("Redraw (Map)", KeyEvent.VK_M);
- drawGraphMapsforgeItem
- .setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_M, ActionEvent.ALT_MASK));
- drawGraphMapsforgeItem.addActionListener(new ActionListener() {
- @Override
- public void actionPerformed(ActionEvent e) {
- launchThread(new Runnable() {
- @Override
- public void run() {
- if (!(drawing instanceof MapViewDrawing)) {
- MapViewDrawing tmp = new MapViewDrawing();
- mainPanel.setLeftComponent(tmp);
- drawing = tmp;
- }
- drawing.clear();
- drawing.drawGraph(graph, new BlackAndWhiteGraphPalette());
- }
- });
- }
- });
- graphLockItems.add(drawGraphMapsforgeItem);
-
- JMenu graphMenu = new JMenu("Graph");
- graphMenu.add(drawGraphItem);
- graphMenu.add(drawGraphBWItem);
- graphMenu.addSeparator();
- graphMenu.add(drawGraphMapsforgeItem);
-
- // Algo menu
- JMenu algoMenu = new JMenu("Algorithms");
-
- // Weakly connected components
- JMenuItem wccItem = new JMenuItem("Weakly Connected Components");
- wccItem.addActionListener(new ActionListener() {
- @Override
- public void actionPerformed(ActionEvent e) {
- WeaklyConnectedComponentsData instance = new WeaklyConnectedComponentsData(graph);
- WeaklyConnectedComponentsAlgorithm algo = new WeaklyConnectedComponentsAlgorithm(
- instance);
- algo.addObserver(new WeaklyConnectedComponentGraphicObserver(drawing));
- // algo.addObserver(new WeaklyConnectedComponentTextObserver(printStream));
- launchThread(new Runnable() {
- @Override
- public void run() {
- algo.run();
- }
- });
- }
- });
-
- // Shortest path
- JMenuItem bellmanItem = new JMenuItem("Shortest Path (Bellman-Ford)");
- bellmanItem.addActionListener(new ActionListener() {
- @Override
- public void actionPerformed(ActionEvent e) {
- int idx = JOptionPane.showOptionDialog(MainWindow.this, "Which mode do you want?",
- "Mode selection", JOptionPane.DEFAULT_OPTION, JOptionPane.QUESTION_MESSAGE,
- null, Mode.values(), Mode.LENGTH);
-
- if (idx != -1) {
- Mode mode = Mode.values()[idx];
- clickAdapter.enable(2, new CallableWithNodes() {
- @Override
- public void call(ArrayList nodes) {
- launchShortestPathThread(new BellmanFordAlgorithm(
- new ShortestPathData(graph, nodes.get(0), nodes.get(1), mode)));
- }
- });
- }
- }
- });
- graphLockItems.add(wccItem);
- graphLockItems.add(bellmanItem);
-
- algoMenu.add(wccItem);
- algoMenu.addSeparator();
- algoMenu.add(bellmanItem);
- // algoMenu.add(djikstraItem);
- // algoMenu.add(aStarItem);
-
- // Create the menu bar.
- JMenuBar menuBar = new JMenuBar();
-
- menuBar.add(fileMenu);
- menuBar.add(graphMenu);
- menuBar.add(algoMenu);
-
- for (JMenuItem item: graphLockItems) {
- item.setEnabled(false);
- }
-
- return menuBar;
- }
-
- @SuppressWarnings("deprecation")
- private void stopCurrentThread() {
- // Should not be used in production code, but here I have no idea how
- // to do this properly... Cannot use .interrupt() because it would requires
- // the algorithm to watch the ThreadInteruption exception.
- currentThread.stop();
- }
-
- private JPanel createStatusBar() {
- // create the status bar panel and shove it down the bottom of the frame
- JPanel statusPanel = new JPanel();
- statusPanel.setBorder(BorderFactory.createMatteBorder(1, 0, 0, 0, Color.GRAY));
- statusPanel.setPreferredSize(new Dimension(getWidth(), 38));
- statusPanel.setLayout(new BorderLayout());
-
- mapIdPanel = new JLabel();
- mapIdPanel.setHorizontalAlignment(SwingConstants.LEFT);
- statusPanel.add(mapIdPanel, BorderLayout.WEST);
-
- JLabel threadInfo = new JLabel("Thread running... ");
- JLabel threadTimerLabel = new JLabel("00:00:00");
- JButton threadButton = new JButton("Stop");
- threadButton.addActionListener(new ActionListener() {
-
- @Override
- public void actionPerformed(ActionEvent e) {
- if (currentThread != null && currentThread.isAlive()) {
- int confirmed = JOptionPane.showConfirmDialog(null,
- "Are you sure you want to kill the running thread?",
- "Kill Confirmation", JOptionPane.YES_NO_OPTION);
- if (confirmed == JOptionPane.YES_OPTION) {
- stopCurrentThread();
- clearCurrentThread();
- threadPanel.setVisible(false);
- }
- }
- }
- });
-
- threadTimer = new Timer(THREAD_TIMER_DELAY, new ActionListener() {
- @Override
- public void actionPerformed(ActionEvent e) {
- Duration elapsed = Duration.between(threadStartTime, Instant.now());
- long seconds = elapsed.getSeconds();
- threadTimerLabel.setText(String.format("%02d:%02d:%02d", seconds / 3600,
- seconds / 60 % 60, seconds % 60));
- }
- });
- threadTimer.setInitialDelay(0);
-
- threadPanel = new JPanel();
- threadPanel.add(threadInfo);
- threadPanel.add(threadTimerLabel);
- threadPanel.add(threadButton);
- threadPanel.setVisible(false);
- statusPanel.add(threadPanel, BorderLayout.EAST);
-
- return statusPanel;
- }
-
- protected JPanel createTopPanel() {
- JPanel topPanel = new JPanel();
-
- return topPanel;
- }
-
- public static void main(final String[] args) {
-
- // Try to set system look and feel.
- try {
- UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
- }
- catch (Exception e) {
- }
-
- MainWindow w = new MainWindow();
- w.setExtendedState(JFrame.MAXIMIZED_BOTH);
- w.setVisible(true);
- }
-
-}
+package org.insa.base;
+
+import java.awt.BorderLayout;
+import java.awt.Color;
+import java.awt.Component;
+import java.awt.Dimension;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.KeyEvent;
+import java.awt.event.WindowAdapter;
+import java.awt.event.WindowEvent;
+import java.io.DataInputStream;
+import java.io.File;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.PrintStream;
+import java.time.Duration;
+import java.time.Instant;
+import java.util.ArrayList;
+
+import javax.swing.BorderFactory;
+import javax.swing.JButton;
+import javax.swing.JFileChooser;
+import javax.swing.JFrame;
+import javax.swing.JLabel;
+import javax.swing.JMenu;
+import javax.swing.JMenuBar;
+import javax.swing.JMenuItem;
+import javax.swing.JOptionPane;
+import javax.swing.JPanel;
+import javax.swing.JScrollPane;
+import javax.swing.JSplitPane;
+import javax.swing.JTextArea;
+import javax.swing.KeyStroke;
+import javax.swing.SwingConstants;
+import javax.swing.Timer;
+import javax.swing.UIManager;
+import javax.swing.filechooser.FileNameExtensionFilter;
+
+import org.insa.algo.shortestpath.BellmanFordAlgorithm;
+import org.insa.algo.shortestpath.ShortestPathAlgorithm;
+import org.insa.algo.shortestpath.ShortestPathData;
+import org.insa.algo.shortestpath.ShortestPathData.Mode;
+import org.insa.algo.shortestpath.ShortestPathGraphicObserver;
+import org.insa.algo.shortestpath.ShortestPathSolution;
+import org.insa.algo.weakconnectivity.WeaklyConnectedComponentGraphicObserver;
+import org.insa.algo.weakconnectivity.WeaklyConnectedComponentsAlgorithm;
+import org.insa.algo.weakconnectivity.WeaklyConnectedComponentsData;
+import org.insa.drawing.BasicDrawing;
+import org.insa.drawing.BlackAndWhiteGraphPalette;
+import org.insa.drawing.Drawing;
+import org.insa.drawing.DrawingClickListener;
+import org.insa.drawing.MapViewDrawing;
+import org.insa.graph.Graph;
+import org.insa.graph.Node;
+import org.insa.graph.Path;
+import org.insa.graph.Point;
+import org.insa.graph.io.AbstractGraphReader;
+import org.insa.graph.io.BinaryGraphReader;
+import org.insa.graph.io.BinaryGraphReaderV2;
+import org.insa.graph.io.BinaryPathReader;
+import org.insa.graph.io.MapMismatchException;
+import org.insa.graph.io.Openfile;
+
+public class MainWindow extends JFrame {
+
+ protected class JOutputStream extends OutputStream {
+ private JTextArea textArea;
+
+ public JOutputStream(JTextArea textArea) {
+ this.textArea = textArea;
+ }
+
+ @Override
+ public void write(int b) throws IOException {
+ // redirects data to the text area
+ textArea.setText(textArea.getText() + String.valueOf((char) b));
+ // scrolls the text area to the end of data
+ textArea.setCaretPosition(textArea.getDocument().getLength());
+ // keeps the textArea up to date
+ textArea.update(textArea.getGraphics());
+ }
+ }
+
+ protected interface CallableWithNodes {
+
+ void call(ArrayList nodes);
+
+ };
+
+ protected class MultiPointsClickListener implements DrawingClickListener {
+
+ // Enable/Disable.
+ private boolean enabled = false;
+
+ // List of points.
+ private ArrayList points = new ArrayList();
+
+ // Number of points to find before running.
+ private int nTargetPoints = 0;
+
+ // Callable to call when points are reached.
+ CallableWithNodes callable = null;
+
+ /**
+ * @return true if this listener is enabled.
+ */
+ public boolean isEnabled() {
+ return enabled;
+ }
+
+ /**
+ * Enable this listener.
+ *
+ * @param nTargetPoints
+ * Number of point to found before calling the callable.
+ */
+ public void enable(int nTargetPoints, CallableWithNodes callable) {
+ this.enabled = true;
+ this.nTargetPoints = nTargetPoints;
+ this.points.clear();
+ this.callable = callable;
+ }
+
+ /**
+ * Disable this listener.
+ */
+ public void disable() {
+ this.enabled = false;
+ }
+
+ @Override
+ public void mouseClicked(Point lonlat) {
+ if (!isEnabled()) {
+ return;
+ }
+ Node node = graph.findClosestNode(lonlat);
+ drawing.drawMarker(node.getPoint(), Color.BLUE);
+ points.add(node);
+ System.out.println("Click at " + lonlat + ", " + points.size() + "/" + nTargetPoints + " in array.");
+ if (points.size() == nTargetPoints) {
+ callable.call(points);
+ this.disable();
+ }
+ }
+ };
+
+ /**
+ *
+ */
+ private static final long serialVersionUID = -527660583705140687L;
+
+ /**
+ *
+ */
+ private static final String WINDOW_TITLE = "BE Graphes INSA";
+
+ /**
+ *
+ */
+ private static final int THREAD_TIMER_DELAY = 1000; // in milliseconds
+
+ // Current graph.
+ private Graph graph;
+
+ // Current loaded path.
+ private Path currentPath;
+
+ // Drawing and click adapter.
+ private Drawing drawing;
+ private MultiPointsClickListener clickAdapter;
+
+ // Main panel.
+ private JSplitPane mainPanel;
+
+ // List of item for the top menus.
+ private JMenuItem openMapItem;
+
+ // List of items that cannot be used without a graph
+ private ArrayList graphLockItems = new ArrayList();
+
+ // Label containing the map ID of the current graph.
+ private JLabel mapIdPanel;
+
+ // Thread information
+ private Instant threadStartTime;
+ private Timer threadTimer;
+ private JPanel threadPanel;
+
+ // Log stream and print stream
+ private JOutputStream logStream;
+
+ @SuppressWarnings("unused")
+ private PrintStream printStream;
+
+ // Current running thread
+ private Thread currentThread;
+
+ public MainWindow() {
+ super(WINDOW_TITLE);
+ setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
+ setLayout(new BorderLayout());
+ setJMenuBar(createMenuBar());
+
+ addWindowListener(new WindowAdapter() {
+ public void windowClosing(WindowEvent e) {
+ int confirmed = JOptionPane.showConfirmDialog(null, "Are you sure you want to close the application?",
+ "Exit Confirmation", JOptionPane.YES_NO_OPTION);
+
+ if (confirmed == JOptionPane.YES_OPTION) {
+ dispose();
+ System.exit(0);
+ }
+ }
+ });
+
+ // Create graph area
+ mainPanel = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT);
+
+ this.drawing = new BasicDrawing();
+
+ // Click adapter
+ this.clickAdapter = new MultiPointsClickListener();
+ this.drawing.addDrawingClickListener(this.clickAdapter);
+
+ JTextArea infoPanel = new JTextArea();
+ infoPanel.setMinimumSize(new Dimension(200, 50));
+ infoPanel.setBackground(Color.WHITE);
+ infoPanel.setLineWrap(true);
+ infoPanel.setEditable(false);
+ this.logStream = new JOutputStream(infoPanel);
+ this.printStream = new PrintStream(this.logStream);
+
+ mainPanel.setResizeWeight(0.8);
+ // sp.setEnabled(false);
+ mainPanel.setDividerSize(5);
+
+ mainPanel.setBackground(Color.WHITE);
+ mainPanel.setLeftComponent((Component) this.drawing);
+ mainPanel.setRightComponent(new JScrollPane(infoPanel));
+ this.add(mainPanel, BorderLayout.CENTER);
+
+ // Top Panel
+ this.add(createTopPanel(), BorderLayout.NORTH);
+ this.add(createStatusBar(), BorderLayout.SOUTH);
+ }
+
+ private void restartThreadTimer() {
+ threadStartTime = Instant.now();
+ threadTimer.restart();
+ }
+
+ private void stopThreadTimer() {
+ threadTimer.stop();
+ }
+
+ /**
+ * @param runnable
+ * @param canInterrupt
+ */
+ private void launchThread(Runnable runnable, boolean canInterrupt) {
+ if (canInterrupt) {
+ currentThread = new Thread(new Runnable() {
+ @Override
+ public void run() {
+ restartThreadTimer();
+ threadPanel.setVisible(true);
+ runnable.run();
+ clearCurrentThread();
+ }
+ });
+ }
+ else {
+ currentThread = new Thread(runnable);
+ }
+ currentThread.start();
+ }
+
+ private void launchThread(Runnable runnable) {
+ launchThread(runnable, true);
+ }
+
+ private void clearCurrentThread() {
+ stopThreadTimer();
+ threadPanel.setVisible(false);
+ currentThread = null;
+ }
+
+ private void launchShortestPathThread(ShortestPathAlgorithm spAlgorithm) {
+ spAlgorithm.addObserver(new ShortestPathGraphicObserver(drawing));
+ // algo.addObserver(new ShortestPathTextObserver(printStream));
+ launchThread(new Runnable() {
+ @Override
+ public void run() {
+ ShortestPathSolution solution = spAlgorithm.run();
+ if (solution != null && solution.isFeasible()) {
+ drawing.drawPath(solution.getPath());
+ }
+ }
+ });
+ }
+
+ private void updateDrawing(Class extends Drawing> newClass) {
+
+ drawing.clear();
+ if (drawing == null || !newClass.isInstance(drawing)) {
+ try {
+ drawing = newClass.newInstance();
+ }
+ catch (InstantiationException | IllegalAccessException e) {
+ e.printStackTrace();
+ }
+ drawing.addDrawingClickListener(this.clickAdapter);
+ }
+ mainPanel.setLeftComponent((Component) drawing);
+ }
+
+ private JMenuBar createMenuBar() {
+
+ // Open Map item...
+ openMapItem = new JMenuItem("Open Map... ", KeyEvent.VK_O);
+ openMapItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_O, ActionEvent.ALT_MASK));
+ openMapItem.addActionListener(new ActionListener() {
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ JFileChooser chooser = new JFileChooser();
+ FileNameExtensionFilter filter = new FileNameExtensionFilter("Map & compressed map files", "map",
+ "map2", "mapgr", "map.gz");
+ chooser.setCurrentDirectory(new File(System.getProperty("user.dir")));
+ chooser.setFileFilter(filter);
+ if (chooser.showOpenDialog(MainWindow.this) == JFileChooser.APPROVE_OPTION) {
+ launchThread(new Runnable() {
+ @Override
+ public void run() {
+ String path = chooser.getSelectedFile().getAbsolutePath();
+ DataInputStream stream;
+ try {
+ stream = Openfile.open(path);
+ }
+ catch (IOException e1) {
+ JOptionPane.showMessageDialog(MainWindow.this, "Cannot open the selected file.");
+ return;
+ }
+ AbstractGraphReader reader;
+ if (path.endsWith(".map2") || path.endsWith("mapgr")) {
+ reader = new BinaryGraphReaderV2(stream);
+ }
+ else {
+ reader = new BinaryGraphReader(stream);
+ }
+ try {
+ graph = reader.read();
+ }
+ catch (Exception exception) {
+ JOptionPane.showMessageDialog(MainWindow.this,
+ "Unable to read graph from the selected file.");
+ exception.printStackTrace(System.out);
+ return;
+ }
+ drawing.clear();
+ drawing.drawGraph(graph);
+
+ for (JMenuItem item: graphLockItems) {
+ item.setEnabled(true);
+ }
+ mapIdPanel.setText("Map ID: 0x" + Integer.toHexString(graph.getMapId()));
+ }
+ }, false);
+ }
+ }
+ });
+
+ // Open Path item...
+ JMenuItem openPathItem = new JMenuItem("Open Path... ", KeyEvent.VK_P);
+ openPathItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_P, ActionEvent.ALT_MASK));
+ openPathItem.addActionListener(new ActionListener() {
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ JFileChooser chooser = new JFileChooser();
+ FileNameExtensionFilter filter = new FileNameExtensionFilter("Path & compressed path files", "path",
+ "path.gz");
+ chooser.setCurrentDirectory(new File(System.getProperty("user.dir")));
+ chooser.setFileFilter(filter);
+ if (chooser.showOpenDialog(MainWindow.this) == JFileChooser.APPROVE_OPTION) {
+ BinaryPathReader reader;
+ try {
+ reader = new BinaryPathReader(Openfile.open(chooser.getSelectedFile().getAbsolutePath()));
+ }
+ catch (IOException e1) {
+ JOptionPane.showMessageDialog(MainWindow.this, "Cannot open the selected file.");
+ return;
+ }
+ try {
+ currentPath = reader.readPath(graph);
+ }
+ catch (MapMismatchException exception) {
+ JOptionPane.showMessageDialog(MainWindow.this,
+ "The selected file does not contain a path for the current graph.");
+ return;
+ }
+ catch (Exception exception) {
+ JOptionPane.showMessageDialog(MainWindow.this, "Unable to read path from the selected file.");
+ return;
+ }
+ drawing.drawPath(currentPath);
+ }
+ }
+ });
+ graphLockItems.add(openPathItem);
+
+ // Close item
+ JMenuItem closeItem = new JMenuItem("Quit", KeyEvent.VK_Q);
+ closeItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_Q, ActionEvent.ALT_MASK));
+ closeItem.addActionListener(new ActionListener() {
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ MainWindow.this.dispatchEvent(new WindowEvent(MainWindow.this, WindowEvent.WINDOW_CLOSING));
+ }
+ });
+
+ // Build the first menu.
+ JMenu fileMenu = new JMenu("File");
+ fileMenu.add(openMapItem);
+ fileMenu.add(openPathItem);
+ fileMenu.addSeparator();
+ fileMenu.add(closeItem);
+
+ // Second menu
+ JMenuItem drawGraphItem = new JMenuItem("Redraw", KeyEvent.VK_R);
+ drawGraphItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_R, ActionEvent.ALT_MASK));
+ drawGraphItem.addActionListener(new ActionListener() {
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ launchThread(new Runnable() {
+ @Override
+ public void run() {
+ updateDrawing(BasicDrawing.class);
+ drawing.drawGraph(graph);
+ }
+ });
+ }
+ });
+ graphLockItems.add(drawGraphItem);
+ JMenuItem drawGraphBWItem = new JMenuItem("Redraw (B&W)", KeyEvent.VK_B);
+ drawGraphBWItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_B, ActionEvent.ALT_MASK));
+ drawGraphBWItem.addActionListener(new ActionListener() {
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ launchThread(new Runnable() {
+ @Override
+ public void run() {
+ updateDrawing(BasicDrawing.class);
+ drawing.drawGraph(graph, new BlackAndWhiteGraphPalette());
+ }
+ });
+ }
+ });
+ graphLockItems.add(drawGraphBWItem);
+ JMenuItem drawGraphMapsforgeItem = new JMenuItem("Redraw (Map)", KeyEvent.VK_M);
+ drawGraphMapsforgeItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_M, ActionEvent.ALT_MASK));
+ drawGraphMapsforgeItem.addActionListener(new ActionListener() {
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ launchThread(new Runnable() {
+ @Override
+ public void run() {
+ updateDrawing(MapViewDrawing.class);
+ drawing.drawGraph(graph);
+ }
+ });
+ }
+ });
+ graphLockItems.add(drawGraphMapsforgeItem);
+
+ JMenu graphMenu = new JMenu("Graph");
+ graphMenu.add(drawGraphItem);
+ graphMenu.add(drawGraphBWItem);
+ graphMenu.addSeparator();
+ graphMenu.add(drawGraphMapsforgeItem);
+
+ // Algo menu
+ JMenu algoMenu = new JMenu("Algorithms");
+
+ // Weakly connected components
+ JMenuItem wccItem = new JMenuItem("Weakly Connected Components");
+ wccItem.addActionListener(new ActionListener() {
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ WeaklyConnectedComponentsData instance = new WeaklyConnectedComponentsData(graph);
+ WeaklyConnectedComponentsAlgorithm algo = new WeaklyConnectedComponentsAlgorithm(instance);
+ algo.addObserver(new WeaklyConnectedComponentGraphicObserver(drawing));
+ // algo.addObserver(new WeaklyConnectedComponentTextObserver(printStream));
+ launchThread(new Runnable() {
+ @Override
+ public void run() {
+ algo.run();
+ }
+ });
+ }
+ });
+
+ // Shortest path
+ JMenuItem bellmanItem = new JMenuItem("Shortest Path (Bellman-Ford)");
+ bellmanItem.addActionListener(new ActionListener() {
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ int idx = JOptionPane.showOptionDialog(MainWindow.this, "Which mode do you want?", "Mode selection",
+ JOptionPane.DEFAULT_OPTION, JOptionPane.QUESTION_MESSAGE, null, Mode.values(), Mode.LENGTH);
+
+ if (idx != -1) {
+ Mode mode = Mode.values()[idx];
+ clickAdapter.enable(2, new CallableWithNodes() {
+ @Override
+ public void call(ArrayList nodes) {
+ launchShortestPathThread(new BellmanFordAlgorithm(
+ new ShortestPathData(graph, nodes.get(0), nodes.get(1), mode)));
+ }
+ });
+ }
+ }
+ });
+ graphLockItems.add(wccItem);
+ graphLockItems.add(bellmanItem);
+
+ algoMenu.add(wccItem);
+ algoMenu.addSeparator();
+ algoMenu.add(bellmanItem);
+ // algoMenu.add(djikstraItem);
+ // algoMenu.add(aStarItem);
+
+ // Create the menu bar.
+ JMenuBar menuBar = new JMenuBar();
+
+ menuBar.add(fileMenu);
+ menuBar.add(graphMenu);
+ menuBar.add(algoMenu);
+
+ for (JMenuItem item: graphLockItems) {
+ item.setEnabled(false);
+ }
+
+ return menuBar;
+ }
+
+ @SuppressWarnings("deprecation")
+ private void stopCurrentThread() {
+ // Should not be used in production code, but here I have no idea how
+ // to do this properly... Cannot use .interrupt() because it would requires
+ // the algorithm to watch the ThreadInteruption exception.
+ currentThread.stop();
+ }
+
+ private JPanel createStatusBar() {
+ // create the status bar panel and shove it down the bottom of the frame
+ JPanel statusPanel = new JPanel();
+ statusPanel.setBorder(BorderFactory.createMatteBorder(1, 0, 0, 0, Color.GRAY));
+ statusPanel.setPreferredSize(new Dimension(getWidth(), 38));
+ statusPanel.setLayout(new BorderLayout());
+
+ mapIdPanel = new JLabel();
+ mapIdPanel.setHorizontalAlignment(SwingConstants.LEFT);
+ statusPanel.add(mapIdPanel, BorderLayout.WEST);
+
+ JLabel threadInfo = new JLabel("Thread running... ");
+ JLabel threadTimerLabel = new JLabel("00:00:00");
+ JButton threadButton = new JButton("Stop");
+ threadButton.addActionListener(new ActionListener() {
+
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ if (currentThread != null && currentThread.isAlive()) {
+ int confirmed = JOptionPane.showConfirmDialog(null,
+ "Are you sure you want to kill the running thread?", "Kill Confirmation",
+ JOptionPane.YES_NO_OPTION);
+ if (confirmed == JOptionPane.YES_OPTION) {
+ stopCurrentThread();
+ clearCurrentThread();
+ threadPanel.setVisible(false);
+ }
+ }
+ }
+ });
+
+ threadTimer = new Timer(THREAD_TIMER_DELAY, new ActionListener() {
+ @Override
+ public void actionPerformed(ActionEvent e) {
+ Duration elapsed = Duration.between(threadStartTime, Instant.now());
+ long seconds = elapsed.getSeconds();
+ threadTimerLabel
+ .setText(String.format("%02d:%02d:%02d", seconds / 3600, seconds / 60 % 60, seconds % 60));
+ }
+ });
+ threadTimer.setInitialDelay(0);
+
+ threadPanel = new JPanel();
+ threadPanel.add(threadInfo);
+ threadPanel.add(threadTimerLabel);
+ threadPanel.add(threadButton);
+ threadPanel.setVisible(false);
+ statusPanel.add(threadPanel, BorderLayout.EAST);
+
+ return statusPanel;
+ }
+
+ protected JPanel createTopPanel() {
+ JPanel topPanel = new JPanel();
+
+ return topPanel;
+ }
+
+ public static void main(final String[] args) {
+
+ // Try to set system look and feel.
+ try {
+ UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
+ }
+ catch (Exception e) {
+ }
+
+ MainWindow w = new MainWindow();
+ w.setExtendedState(JFrame.MAXIMIZED_BOTH);
+ w.setVisible(true);
+ }
+
+}
diff --git a/src/main/org/insa/base/Samples.java b/src/main/org/insa/base/Samples.java
deleted file mode 100644
index 720eee8..0000000
--- a/src/main/org/insa/base/Samples.java
+++ /dev/null
@@ -1,302 +0,0 @@
-/*
- * Copyright 2010, 2011, 2012, 2013 mapsforge.org
- * Copyright 2014 Christian Pesch
- * Copyright 2014 Ludwig M Brinckmann
- * Copyright 2014-2018 devemux86
- * Copyright 2017 usrusr
- *
- * This program is free software: you can redistribute it and/or modify it under the
- * terms of the GNU Lesser General Public License as published by the Free Software
- * Foundation, either version 3 of the License, or (at your option) any later version.
- *
- * This program 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 Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License along with
- * this program. If not, see .
- */
-package org.insa.base;
-
-import java.awt.Dimension;
-import java.awt.event.WindowAdapter;
-import java.awt.event.WindowEvent;
-import java.io.File;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.List;
-import java.util.UUID;
-import java.util.prefs.Preferences;
-
-import javax.swing.JFrame;
-import javax.swing.JOptionPane;
-import javax.swing.WindowConstants;
-
-import org.insa.graph.Arc;
-import org.insa.graph.Graph;
-import org.insa.graph.Path;
-import org.insa.graph.io.BinaryGraphReader;
-import org.insa.graph.io.BinaryPathReader;
-import org.insa.graph.io.Openfile;
-import org.mapsforge.core.graphics.Color;
-import org.mapsforge.core.graphics.GraphicFactory;
-import org.mapsforge.core.graphics.Paint;
-import org.mapsforge.core.graphics.Style;
-import org.mapsforge.core.model.BoundingBox;
-import org.mapsforge.core.model.LatLong;
-import org.mapsforge.core.model.MapPosition;
-import org.mapsforge.core.model.Point;
-import org.mapsforge.core.util.LatLongUtils;
-import org.mapsforge.core.util.Parameters;
-import org.mapsforge.map.awt.graphics.AwtGraphicFactory;
-import org.mapsforge.map.awt.util.AwtUtil;
-import org.mapsforge.map.awt.util.JavaPreferences;
-import org.mapsforge.map.awt.view.MapView;
-import org.mapsforge.map.datastore.MapDataStore;
-import org.mapsforge.map.datastore.MultiMapDataStore;
-import org.mapsforge.map.layer.Layers;
-import org.mapsforge.map.layer.cache.TileCache;
-import org.mapsforge.map.layer.debug.TileCoordinatesLayer;
-import org.mapsforge.map.layer.debug.TileGridLayer;
-import org.mapsforge.map.layer.download.TileDownloadLayer;
-import org.mapsforge.map.layer.download.tilesource.OpenStreetMapMapnik;
-import org.mapsforge.map.layer.download.tilesource.TileSource;
-import org.mapsforge.map.layer.hills.DiffuseLightShadingAlgorithm;
-import org.mapsforge.map.layer.hills.HillsRenderConfig;
-import org.mapsforge.map.layer.hills.MemoryCachingHgtReaderTileSource;
-import org.mapsforge.map.layer.overlay.Polyline;
-import org.mapsforge.map.layer.renderer.TileRendererLayer;
-import org.mapsforge.map.model.MapViewPosition;
-import org.mapsforge.map.model.Model;
-import org.mapsforge.map.model.common.PreferencesFacade;
-import org.mapsforge.map.reader.MapFile;
-import org.mapsforge.map.rendertheme.InternalRenderTheme;
-
-public final class Samples {
- private static final GraphicFactory GRAPHIC_FACTORY = AwtGraphicFactory.INSTANCE;
- private static final boolean SHOW_DEBUG_LAYERS = false;
- private static final boolean SHOW_RASTER_MAP = false;
-
- private static final String MESSAGE = "Are you sure you want to exit the application?";
- private static final String TITLE = "Confirm close";
-
- /**
- * Starts the {@code Samples}.
- *
- * @param args
- * command line args: expects the map files as multiple parameters
- * with possible SRTM hgt folder as 1st argument.
- * @throws Exception
- */
- public static void main(String[] args) throws Exception {
-
- // Multithreaded map rendering
- Parameters.NUMBER_OF_THREADS = 2;
-
- // Square frame buffer
- Parameters.SQUARE_FRAME_BUFFER = false;
-
- HillsRenderConfig hillsCfg = null;
- File demFolder = getDemFolder(args);
- if (demFolder != null) {
- MemoryCachingHgtReaderTileSource tileSource = new MemoryCachingHgtReaderTileSource(
- demFolder, new DiffuseLightShadingAlgorithm(), AwtGraphicFactory.INSTANCE);
- tileSource.setEnableInterpolationOverlap(true);
- hillsCfg = new HillsRenderConfig(tileSource);
- hillsCfg.indexOnThread();
- args = Arrays.copyOfRange(args, 1, args.length);
- }
-
- List mapFiles = getMapFiles(args);
- final MapView mapView = createMapView();
- final BoundingBox boundingBox = addLayers(mapView, mapFiles, hillsCfg);
-
- // addAPath(mapView);
-
- final PreferencesFacade preferencesFacade = new JavaPreferences(
- Preferences.userNodeForPackage(Samples.class));
-
- final JFrame frame = new JFrame();
- frame.setTitle("Mapsforge Samples");
- frame.add(mapView);
- frame.pack();
- frame.setSize(new Dimension(800, 600));
- frame.setLocationRelativeTo(null);
- frame.setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE);
- frame.addWindowListener(new WindowAdapter() {
- @Override
- public void windowClosing(WindowEvent e) {
- int result = JOptionPane.showConfirmDialog(frame, MESSAGE, TITLE,
- JOptionPane.YES_NO_OPTION);
- if (result == JOptionPane.YES_OPTION) {
- mapView.getModel().save(preferencesFacade);
- mapView.destroyAll();
- AwtGraphicFactory.clearResourceMemoryCache();
- frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
- }
- }
-
- @Override
- public void windowOpened(WindowEvent e) {
- final Model model = mapView.getModel();
- model.init(preferencesFacade);
- if (model.mapViewPosition.getZoomLevel() == 0
- || !boundingBox.contains(model.mapViewPosition.getCenter())) {
- byte zoomLevel = LatLongUtils.zoomForBounds(
- model.mapViewDimension.getDimension(), boundingBox,
- model.displayModel.getTileSize());
- model.mapViewPosition.setMapPosition(
- new MapPosition(boundingBox.getCenterPoint(), zoomLevel));
- }
- }
- });
- frame.setVisible(true);
- }
-
- private static void addAPath(MapView mapView) throws Exception {
-
- Graph gr = (new BinaryGraphReader(Openfile.open("Maps/midip.map"))).read();
- Path path = (new BinaryPathReader(Openfile.open("Paths/chemin_0x400_119963_96676.path")))
- .readPath(gr);
-
- Paint paintStroke = AwtGraphicFactory.INSTANCE.createPaint();
- paintStroke.setColor(Color.GREEN);
- paintStroke.setStrokeWidth(3);
- paintStroke.setStyle(Style.STROKE);
-
- Polyline line = new Polyline(paintStroke, AwtGraphicFactory.INSTANCE);
-
- for (Arc arc : path.getArcs()) {
- ArrayList points = arc.getPoints();
- for (int i = 0; i < points.size(); ++i) {
- line.getLatLongs().add(
- new LatLong(points.get(i).getLatitude(), points.get(i).getLongitude()));
- }
- }
-
- mapView.getLayerManager().getLayers().add(line);
- }
-
- private static BoundingBox addLayers(MapView mapView, List mapFiles,
- HillsRenderConfig hillsRenderConfig) {
- Layers layers = mapView.getLayerManager().getLayers();
-
- int tileSize = SHOW_RASTER_MAP ? 256 : 512;
-
- // Tile cache
- TileCache tileCache = AwtUtil.createTileCache(tileSize,
- mapView.getModel().frameBufferModel.getOverdrawFactor(), 1024,
- new File(System.getProperty("java.io.tmpdir"), UUID.randomUUID().toString()));
-
- final BoundingBox boundingBox;
- if (SHOW_RASTER_MAP) {
- // Raster
- mapView.getModel().displayModel.setFixedTileSize(tileSize);
- TileSource tileSource = OpenStreetMapMapnik.INSTANCE;
- TileDownloadLayer tileDownloadLayer = createTileDownloadLayer(tileCache,
- mapView.getModel().mapViewPosition, tileSource);
- layers.add(tileDownloadLayer);
- tileDownloadLayer.start();
- mapView.setZoomLevelMin(tileSource.getZoomLevelMin());
- mapView.setZoomLevelMax(tileSource.getZoomLevelMax());
- boundingBox = new BoundingBox(LatLongUtils.LATITUDE_MIN, LatLongUtils.LONGITUDE_MIN,
- LatLongUtils.LATITUDE_MAX, LatLongUtils.LONGITUDE_MAX);
- }
- else {
- // Vector
- mapView.getModel().displayModel.setFixedTileSize(tileSize);
- MultiMapDataStore mapDataStore = new MultiMapDataStore(
- MultiMapDataStore.DataPolicy.RETURN_ALL);
- for (File file : mapFiles) {
- mapDataStore.addMapDataStore(new MapFile(file), false, false);
- }
- TileRendererLayer tileRendererLayer = createTileRendererLayer(tileCache, mapDataStore,
- mapView.getModel().mapViewPosition, hillsRenderConfig);
- layers.add(tileRendererLayer);
- boundingBox = mapDataStore.boundingBox();
- }
-
- // Debug
- if (SHOW_DEBUG_LAYERS) {
- layers.add(new TileGridLayer(GRAPHIC_FACTORY, mapView.getModel().displayModel));
- layers.add(new TileCoordinatesLayer(GRAPHIC_FACTORY, mapView.getModel().displayModel));
- }
-
- return boundingBox;
- }
-
- private static MapView createMapView() {
- MapView mapView = new MapView();
- mapView.getMapScaleBar().setVisible(true);
- if (SHOW_DEBUG_LAYERS) {
- mapView.getFpsCounter().setVisible(true);
- }
-
- return mapView;
- }
-
- @SuppressWarnings("unused")
- private static TileDownloadLayer createTileDownloadLayer(TileCache tileCache,
- MapViewPosition mapViewPosition, TileSource tileSource) {
- return new TileDownloadLayer(tileCache, mapViewPosition, tileSource, GRAPHIC_FACTORY) {
- @Override
- public boolean onTap(LatLong tapLatLong, Point layerXY, Point tapXY) {
- System.out.println("Tap on: " + tapLatLong);
- return true;
- }
- };
- }
-
- private static TileRendererLayer createTileRendererLayer(TileCache tileCache,
- MapDataStore mapDataStore, MapViewPosition mapViewPosition,
- HillsRenderConfig hillsRenderConfig) {
- TileRendererLayer tileRendererLayer = new TileRendererLayer(tileCache, mapDataStore,
- mapViewPosition, false, true, false, GRAPHIC_FACTORY, hillsRenderConfig) {
- @Override
- public boolean onTap(LatLong tapLatLong, Point layerXY, Point tapXY) {
- System.out.println("Tap on: " + tapLatLong);
- return true;
- }
- };
- tileRendererLayer.setXmlRenderTheme(InternalRenderTheme.DEFAULT);
- return tileRendererLayer;
- }
-
- private static File getDemFolder(String[] args) {
- if (args.length == 0) {
- throw new IllegalArgumentException("missing argument: ");
- }
-
- File demFolder = new File(args[0]);
- if (demFolder.exists() && demFolder.isDirectory() && demFolder.canRead()) {
- return demFolder;
- }
- return null;
- }
-
- private static List getMapFiles(String[] args) {
- if (args.length == 0) {
- throw new IllegalArgumentException("missing argument: ");
- }
-
- List result = new ArrayList<>();
- for (String arg : args) {
- File mapFile = new File(arg);
- if (!mapFile.exists()) {
- throw new IllegalArgumentException("file does not exist: " + mapFile);
- }
- else if (!mapFile.isFile()) {
- throw new IllegalArgumentException("not a file: " + mapFile);
- }
- else if (!mapFile.canRead()) {
- throw new IllegalArgumentException("cannot read file: " + mapFile);
- }
- result.add(mapFile);
- }
- return result;
- }
-
- private Samples() {
- throw new IllegalStateException();
- }
-}
\ No newline at end of file
diff --git a/src/main/org/insa/drawing/BasicDrawing.java b/src/main/org/insa/drawing/BasicDrawing.java
index 6b67e84..7320436 100644
--- a/src/main/org/insa/drawing/BasicDrawing.java
+++ b/src/main/org/insa/drawing/BasicDrawing.java
@@ -5,12 +5,16 @@ import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
+import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
+import java.awt.event.MouseListener;
import java.awt.geom.NoninvertibleTransformException;
import java.awt.geom.Point2D;
-import java.awt.image.*;
+import java.awt.image.BufferedImage;
import java.util.ArrayList;
+import java.util.IdentityHashMap;
import java.util.Iterator;
+import java.util.Map;
import javax.swing.JPanel;
@@ -21,294 +25,321 @@ import org.insa.graph.Path;
import org.insa.graph.Point;
/**
- * Cette implementation de la classe Dessin produit vraiment un affichage
- * (au contraire de la classe DessinInvisible).
+ * Cette implementation de la classe Dessin produit vraiment un affichage (au
+ * contraire de la classe DessinInvisible).
*/
public class BasicDrawing extends JPanel implements Drawing {
- /**
- *
- */
- private static final long serialVersionUID = 96779785877771827L;
-
- // Default path color.
- public static final Color DEFAULT_PATH_COLOR = new Color(255, 0, 255);
+ /**
+ *
+ */
+ private static final long serialVersionUID = 96779785877771827L;
- // Default palette.
- public static final GraphPalette DEFAULT_PALETTE = new BasicGraphPalette();
-
- // Default marker width
- private static final int DEFAULT_MARKER_WIDTH = 10;
-
- //
- private final Graphics2D gr;
+ // Default path color.
+ public static final Color DEFAULT_PATH_COLOR = new Color(255, 0, 255);
- private double long1, long2, lat1, lat2;
-
- // Width and height of the image
- private final int width, height;
-
- private Image image;
- private ZoomAndPanListener zoomAndPanListener;
-
- /**
- * Create a new BasicDrawing.
- *
- */
- public BasicDrawing() {
-
- this.zoomAndPanListener = new ZoomAndPanListener(this, ZoomAndPanListener.DEFAULT_MIN_ZOOM_LEVEL, 20, 1.2);
- this.addMouseListener(zoomAndPanListener);
- this.addMouseMotionListener(zoomAndPanListener);
- this.addMouseWheelListener(zoomAndPanListener);
-
- this.width = 2000;
- this.height = 1600;
-
- BufferedImage img = new BufferedImage(this.width, this.height, BufferedImage.TYPE_3BYTE_BGR);
-
- this.image = img;
- this.gr = img.createGraphics();
-
- this.zoomAndPanListener.setCoordTransform(this.gr.getTransform());
+ // Default palette.
+ public static final GraphPalette DEFAULT_PALETTE = new BasicGraphPalette();
- this.long1 = -180;
- this.long2 = 180;
- this.lat1 = -90;
- this.lat2 = 90;
+ // Default marker width
+ private static final int DEFAULT_MARKER_WIDTH = 10;
- this.clear();
- this.repaint();
+ //
+ private final Graphics2D gr;
- }
+ private double long1, long2, lat1, lat2;
- @Override
- public void paintComponent(Graphics g1) {
- Graphics2D g = (Graphics2D)g1;
- g.clearRect(0, 0, getWidth(), getHeight());
- g.setTransform(zoomAndPanListener.getCoordTransform());
- g.drawImage(image, 0, 0, this);
- }
+ // Width and height of the image
+ private final int width, height;
- protected void setBB(double long1, double long2, double lat1, double lat2) {
+ //
+ private Image image;
+ private ZoomAndPanListener zoomAndPanListener;
- if (long1 > long2 || lat1 > lat2) {
- throw new Error("DessinVisible.setBB : mauvaises coordonnees.");
- }
-
- this.long1 = long1;
- this.long2 = long2;
- this.lat1= lat1;
- this.lat2 = lat2;
-
- double scale = 1 / Math.max(this.width / (double)this.getWidth(), this.height / (double)this.getHeight());
-
- this.zoomAndPanListener.getCoordTransform().setToIdentity();
- this.zoomAndPanListener.getCoordTransform().translate((this.getWidth() - this.width * scale) / 2,
- (this.getHeight() - this.height * scale) / 2);
- this.zoomAndPanListener.getCoordTransform().scale(scale, scale);
- this.zoomAndPanListener.setZoomLevel(0);
- this.repaint();
-
- }
+ // Mapping DrawingClickListener -> MouseEventListener
+ private Map listenerMapping = new IdentityHashMap<>();
- private int projx(double lon) {
- return (int)(width * (lon - this.long1) / (this.long2 - this.long1)) ;
- }
+ /**
+ * Create a new BasicDrawing.
+ *
+ */
+ public BasicDrawing() {
- private int projy(double lat) {
- return (int)(height * (1 - (lat - this.lat1) / (this.lat2 - this.lat1))) ;
- }
-
- /**
- * Return the longitude and latitude corresponding to the given
- * position of the MouseEvent.
- *
- * @param event
- *
- * @return
- */
- public Point getLongitudeLatitude(MouseEvent event) throws NoninvertibleTransformException {
- // Get the point using the inverse transform of the Zoom/Pan object, this gives us
- // a point within the drawing box (between [0, 0] and [width, height]).
- Point2D ptDst = this.zoomAndPanListener.getCoordTransform().inverseTransform(event.getPoint(), null);
-
- // Inverse the "projection" on x/y to get longitude and latitude.
- double lon = ptDst.getX();
- double lat = ptDst.getY();
- lon = (lon / this.width) * (this.long2 - this.long1) + this.long1;
- lat = (1 - lat / this.height) * (this.lat2 - this.lat1) + this.lat1;
-
- // Return a new point.
- return new Point(lon, lat);
- }
-
- protected void setWidth(int width) {
- this.gr.setStroke(new BasicStroke(width));
- }
+ this.zoomAndPanListener = new ZoomAndPanListener(this, ZoomAndPanListener.DEFAULT_MIN_ZOOM_LEVEL, 20, 1.2);
+ this.addMouseListener(zoomAndPanListener);
+ this.addMouseMotionListener(zoomAndPanListener);
+ this.addMouseWheelListener(zoomAndPanListener);
- protected void setColor(Color col) {
- this.gr.setColor(col);
- }
-
- @Override
- public void clear() {
- this.gr.setColor(Color.WHITE);
- this.gr.fillRect(0, 0, this.width, this.height);
- }
+ this.width = 2000;
+ this.height = 1600;
- @Override
- public void drawLine(Point from, Point to) {
- int x1 = this.projx(from.getLongitude()) ;
- int x2 = this.projx(to.getLongitude()) ;
- int y1 = this.projy(from.getLatitude()) ;
- int y2 = this.projy(to.getLatitude()) ;
+ BufferedImage img = new BufferedImage(this.width, this.height, BufferedImage.TYPE_3BYTE_BGR);
- gr.drawLine(x1, y1, x2, y2) ;
- this.repaint();
- }
+ this.image = img;
+ this.gr = img.createGraphics();
- @Override
- public void drawLine(Point from, Point to, int width) {
- setWidth(width);
- drawLine(from, to);
- }
+ this.zoomAndPanListener.setCoordTransform(this.gr.getTransform());
- @Override
- public void drawLine(Point from, Point to, int width, Color color) {
- setWidth(width);
- setColor(color);
- drawLine(from, to);
- }
-
- @Override
- public void drawMarker(Point point) {
- drawPoint(point, DEFAULT_MARKER_WIDTH, this.gr.getColor());
- }
+ this.long1 = -180;
+ this.long2 = 180;
+ this.lat1 = -90;
+ this.lat2 = 90;
+ this.clear();
+ this.repaint();
- @Override
- public void drawMarker(Point point, Color color) {
- setColor(color);
- drawMarker(point);
- }
-
- @Override
- public void drawPoint(Point point, int width, Color color) {
- setWidth(width);
- setColor(color);
- int x = this.projx(point.getLongitude()) - DEFAULT_MARKER_WIDTH / 2;
- int y = this.projy(point.getLatitude()) - DEFAULT_MARKER_WIDTH / 2;
- gr.fillOval(x, y, DEFAULT_MARKER_WIDTH, DEFAULT_MARKER_WIDTH);
- this.repaint();
- }
-
- /**
- * Draw the given arc.
- *
- * @param arc Arc to draw.
- * @param palette Palette to use to retrieve color and width for arc,
- * or null to use current settings.
- */
- public void drawArc(Arc arc, GraphPalette palette) {
- ArrayList pts = arc.getPoints();
- if (!pts.isEmpty()) {
- if (palette != null) {
- setColor(palette.getColorForType(arc.getInfo().getType()));
- setWidth(palette.getWidthForType(arc.getInfo().getType()));
- }
- Iterator it1 = pts.iterator();
- Point prev = it1.next();
- while (it1.hasNext()) {
- Point curr = it1.next();
- drawLine(prev, curr);
- prev = curr;
- }
- }
- }
-
- /**
- * Initialize the drawing for the given graph.
- *
- * @param graph
- */
- public void initialize(Graph graph) {
- double minLon = Double.POSITIVE_INFINITY, minLat = Double.POSITIVE_INFINITY,
- maxLon = Double.NEGATIVE_INFINITY, maxLat = Double.NEGATIVE_INFINITY;
- for (Node node: graph.getNodes()) {
- Point pt = node.getPoint();
- if (pt.getLatitude() < minLat) {
- minLat = pt.getLatitude();
- }
- if (pt.getLatitude() > maxLat) {
- maxLat = pt.getLatitude();
- }
- if (pt.getLongitude() < minLon) {
- minLon = pt.getLongitude();
- }
- if (pt.getLongitude() > maxLon) {
- maxLon = pt.getLongitude();
- }
- }
-
- double deltaLon = 0.02 * (maxLon - minLon),
- deltaLat = 0.02 * (maxLat - minLat);
+ }
- setBB(minLon - deltaLon, maxLon + deltaLon,
- minLat - deltaLat, maxLat + deltaLat);
- }
+ @Override
+ public void paintComponent(Graphics g1) {
+ Graphics2D g = (Graphics2D) g1;
+ g.clearRect(0, 0, getWidth(), getHeight());
+ g.setTransform(zoomAndPanListener.getCoordTransform());
+ g.drawImage(image, 0, 0, this);
+ }
- @Override
- public void drawGraph(Graph graph, GraphPalette palette) {
- clear();
- initialize(graph);
- for (Node node: graph.getNodes()) {
- for (Arc arc: node.getSuccessors()) {
- drawArc(arc, palette);
- }
- }
- }
+ protected void setBB(double long1, double long2, double lat1, double lat2) {
- @Override
- public void drawGraph(Graph graph) {
- drawGraph(graph, DEFAULT_PALETTE);
- }
+ if (long1 > long2 || lat1 > lat2) {
+ throw new Error("DessinVisible.setBB : mauvaises coordonnees.");
+ }
- @Override
- public void drawPath(Path path, Color color, boolean markers) {
- setColor(color);
- setWidth(2);
- for (Arc arc: path.getArcs()) {
- drawArc(arc, null);
- }
- if (markers) {
- drawMarker(path.getOrigin().getPoint(), color);
- drawMarker(path.getDestination().getPoint(), color);
- }
- }
-
- @Override
- public void drawPath(Path path, Color color) {
- drawPath(path, color, true);
- }
+ this.long1 = long1;
+ this.long2 = long2;
+ this.lat1 = lat1;
+ this.lat2 = lat2;
- @Override
- public void drawPath(Path path) {
- drawPath(path, DEFAULT_PATH_COLOR);
- }
-
- @Override
- public void drawPath(Path path, boolean markers) {
- drawPath(path, DEFAULT_PATH_COLOR, markers);
- }
-
- @SuppressWarnings("unused")
- private void putText(Point point, String txt) {
- int x = this.projx(point.getLongitude());
- int y = this.projy(point.getLatitude());
- gr.drawString(txt, x, y);
- this.repaint();
- }
+ double scale = 1 / Math.max(this.width / (double) this.getWidth(), this.height / (double) this.getHeight());
+
+ this.zoomAndPanListener.getCoordTransform().setToIdentity();
+ this.zoomAndPanListener.getCoordTransform().translate((this.getWidth() - this.width * scale) / 2,
+ (this.getHeight() - this.height * scale) / 2);
+ this.zoomAndPanListener.getCoordTransform().scale(scale, scale);
+ this.zoomAndPanListener.setZoomLevel(0);
+ this.repaint();
+
+ }
+
+ private int projx(double lon) {
+ return (int) (width * (lon - this.long1) / (this.long2 - this.long1));
+ }
+
+ private int projy(double lat) {
+ return (int) (height * (1 - (lat - this.lat1) / (this.lat2 - this.lat1)));
+ }
+
+ /**
+ * Return the longitude and latitude corresponding to the given position of the
+ * MouseEvent.
+ *
+ * @param event
+ *
+ * @return
+ */
+ public Point getLongitudeLatitude(MouseEvent event) throws NoninvertibleTransformException {
+ // Get the point using the inverse transform of the Zoom/Pan object, this gives
+ // us
+ // a point within the drawing box (between [0, 0] and [width, height]).
+ Point2D ptDst = this.zoomAndPanListener.getCoordTransform().inverseTransform(event.getPoint(), null);
+
+ // Inverse the "projection" on x/y to get longitude and latitude.
+ double lon = ptDst.getX();
+ double lat = ptDst.getY();
+ lon = (lon / this.width) * (this.long2 - this.long1) + this.long1;
+ lat = (1 - lat / this.height) * (this.lat2 - this.lat1) + this.lat1;
+
+ // Return a new point.
+ return new Point(lon, lat);
+ }
+
+ @Override
+ public void addDrawingClickListener(DrawingClickListener listener) {
+ MouseListener mListener = new MouseAdapter() {
+ @Override
+ public void mouseClicked(MouseEvent evt) {
+ System.out.println(evt);
+ try {
+ listener.mouseClicked(getLongitudeLatitude(evt));
+ }
+ catch (NoninvertibleTransformException e) {
+ e.printStackTrace();
+ }
+ }
+ };
+ this.addMouseListener(mListener);
+ this.listenerMapping.put(listener, mListener);
+ }
+
+ @Override
+ public void removeDrawingClickListener(DrawingClickListener listener) {
+ this.removeMouseListener(this.listenerMapping.get(listener));
+ }
+
+ protected void setWidth(int width) {
+ this.gr.setStroke(new BasicStroke(width));
+ }
+
+ protected void setColor(Color col) {
+ this.gr.setColor(col);
+ }
+
+ @Override
+ public void clear() {
+ this.gr.setColor(Color.WHITE);
+ this.gr.fillRect(0, 0, this.width, this.height);
+ }
+
+ @Override
+ public void drawLine(Point from, Point to) {
+ int x1 = this.projx(from.getLongitude());
+ int x2 = this.projx(to.getLongitude());
+ int y1 = this.projy(from.getLatitude());
+ int y2 = this.projy(to.getLatitude());
+
+ gr.drawLine(x1, y1, x2, y2);
+ this.repaint();
+ }
+
+ @Override
+ public void drawLine(Point from, Point to, int width) {
+ setWidth(width);
+ drawLine(from, to);
+ }
+
+ @Override
+ public void drawLine(Point from, Point to, int width, Color color) {
+ setWidth(width);
+ setColor(color);
+ drawLine(from, to);
+ }
+
+ @Override
+ public void drawMarker(Point point) {
+ drawPoint(point, DEFAULT_MARKER_WIDTH, this.gr.getColor());
+ }
+
+ @Override
+ public void drawMarker(Point point, Color color) {
+ setColor(color);
+ drawMarker(point);
+ }
+
+ @Override
+ public void drawPoint(Point point, int width, Color color) {
+ setWidth(width);
+ setColor(color);
+ int x = this.projx(point.getLongitude()) - DEFAULT_MARKER_WIDTH / 2;
+ int y = this.projy(point.getLatitude()) - DEFAULT_MARKER_WIDTH / 2;
+ gr.fillOval(x, y, DEFAULT_MARKER_WIDTH, DEFAULT_MARKER_WIDTH);
+ this.repaint();
+ }
+
+ /**
+ * Draw the given arc.
+ *
+ * @param arc
+ * Arc to draw.
+ * @param palette
+ * Palette to use to retrieve color and width for arc, or null to use
+ * current settings.
+ */
+ public void drawArc(Arc arc, GraphPalette palette) {
+ ArrayList pts = arc.getPoints();
+ if (!pts.isEmpty()) {
+ if (palette != null) {
+ setColor(palette.getColorForType(arc.getInfo().getType()));
+ setWidth(palette.getWidthForType(arc.getInfo().getType()));
+ }
+ Iterator it1 = pts.iterator();
+ Point prev = it1.next();
+ while (it1.hasNext()) {
+ Point curr = it1.next();
+ drawLine(prev, curr);
+ prev = curr;
+ }
+ }
+ }
+
+ /**
+ * Initialize the drawing for the given graph.
+ *
+ * @param graph
+ */
+ public void initialize(Graph graph) {
+ double minLon = Double.POSITIVE_INFINITY, minLat = Double.POSITIVE_INFINITY, maxLon = Double.NEGATIVE_INFINITY,
+ maxLat = Double.NEGATIVE_INFINITY;
+ for (Node node: graph.getNodes()) {
+ Point pt = node.getPoint();
+ if (pt.getLatitude() < minLat) {
+ minLat = pt.getLatitude();
+ }
+ if (pt.getLatitude() > maxLat) {
+ maxLat = pt.getLatitude();
+ }
+ if (pt.getLongitude() < minLon) {
+ minLon = pt.getLongitude();
+ }
+ if (pt.getLongitude() > maxLon) {
+ maxLon = pt.getLongitude();
+ }
+ }
+
+ double deltaLon = 0.02 * (maxLon - minLon), deltaLat = 0.02 * (maxLat - minLat);
+
+ setBB(minLon - deltaLon, maxLon + deltaLon, minLat - deltaLat, maxLat + deltaLat);
+ }
+
+ @Override
+ public void drawGraph(Graph graph, GraphPalette palette) {
+ clear();
+ initialize(graph);
+ for (Node node: graph.getNodes()) {
+ for (Arc arc: node.getSuccessors()) {
+ drawArc(arc, palette);
+ }
+ }
+ }
+
+ @Override
+ public void drawGraph(Graph graph) {
+ drawGraph(graph, DEFAULT_PALETTE);
+ }
+
+ @Override
+ public void drawPath(Path path, Color color, boolean markers) {
+ setColor(color);
+ setWidth(2);
+ for (Arc arc: path.getArcs()) {
+ drawArc(arc, null);
+ }
+ if (markers) {
+ drawMarker(path.getOrigin().getPoint(), color);
+ drawMarker(path.getDestination().getPoint(), color);
+ }
+ }
+
+ @Override
+ public void drawPath(Path path, Color color) {
+ drawPath(path, color, true);
+ }
+
+ @Override
+ public void drawPath(Path path) {
+ drawPath(path, DEFAULT_PATH_COLOR);
+ }
+
+ @Override
+ public void drawPath(Path path, boolean markers) {
+ drawPath(path, DEFAULT_PATH_COLOR, markers);
+ }
+
+ @SuppressWarnings("unused")
+ private void putText(Point point, String txt) {
+ int x = this.projx(point.getLongitude());
+ int y = this.projy(point.getLatitude());
+ gr.drawString(txt, x, y);
+ this.repaint();
+ }
}
diff --git a/src/main/org/insa/drawing/Drawing.java b/src/main/org/insa/drawing/Drawing.java
index 0ab4927..79e222f 100644
--- a/src/main/org/insa/drawing/Drawing.java
+++ b/src/main/org/insa/drawing/Drawing.java
@@ -7,113 +7,128 @@ import org.insa.graph.Path;
import org.insa.graph.Point;
public interface Drawing {
-
- /**
- * Clear the drawing.
- */
- public void clear();
- /**
- * Draw a line between the two given points with the default color
- * and width.
- *
- * @param from
- * @param to
- */
- public void drawLine(Point from, Point to);
-
- /**
- * Draw a line between the two given points with the default color
- * and the given width.
- *
- * @param from
- * @param to
- * @param width
- */
- public void drawLine(Point from, Point to, int width);
-
- /**
- * Draw a line between the two given points with the given color
- * and the given width.
- *
- * @param from
- * @param to
- * @param width
- * @param color
- */
- public void drawLine(Point from, Point to, int width, Color color);
-
- /**
- * Draw a marker at the given point with the default color.
- *
- * @param point
- */
- public void drawMarker(Point point);
-
- /**
- * Draw the given point with the given color.
- *
- * @param point
- */
- public void drawMarker(Point point, Color color);
-
- /**
- * Draw a point width the given width and color. Do not use this to mark location,
- * use drawMarker.
- *
- * @param point
- * @param width
- * @param color
- */
- public void drawPoint(Point point, int width, Color color);
+ /**
+ * Add a listener to click to this drawing.
+ *
+ * @param listener
+ */
+ public void addDrawingClickListener(DrawingClickListener listener);
+
+ /**
+ * Remove the given listener from the drawing.
+ *
+ * @param listener
+ */
+ public void removeDrawingClickListener(DrawingClickListener listener);
+
+ /**
+ * Clear the drawing.
+ */
+ public void clear();
+
+ /**
+ * Draw a line between the two given points with the default color and width.
+ *
+ * @param from
+ * @param to
+ */
+ public void drawLine(Point from, Point to);
+
+ /**
+ * Draw a line between the two given points with the default color and the given
+ * width.
+ *
+ * @param from
+ * @param to
+ * @param width
+ */
+ public void drawLine(Point from, Point to, int width);
+
+ /**
+ * Draw a line between the two given points with the given color and the given
+ * width.
+ *
+ * @param from
+ * @param to
+ * @param width
+ * @param color
+ */
+ public void drawLine(Point from, Point to, int width, Color color);
+
+ /**
+ * Draw a marker at the given point with the default color.
+ *
+ * @param point
+ */
+ public void drawMarker(Point point);
+
+ /**
+ * Draw the given point with the given color.
+ *
+ * @param point
+ */
+ public void drawMarker(Point point, Color color);
+
+ /**
+ * Draw a point width the given width and color. Do not use this to mark
+ * location, use drawMarker.
+ *
+ * @param point
+ * @param width
+ * @param color
+ */
+ public void drawPoint(Point point, int width, Color color);
+
+ /**
+ * Draw the given graph using the given palette.
+ *
+ * @param graph
+ * @param palette
+ */
+ public void drawGraph(Graph graph, GraphPalette palette);
+
+ /**
+ * Draw the given graph using a default palette specific to the implementation.
+ *
+ * @param graph
+ */
+ public void drawGraph(Graph graph);
+
+ /**
+ * Draw a path using the given color.
+ *
+ * @param path
+ * @param color
+ * @param markers
+ * Show origin and destination markers.
+ */
+ public void drawPath(Path path, Color color, boolean markers);
+
+ /**
+ * Draw a path using the given color with markers.
+ *
+ * @param path
+ * @param color
+ */
+ public void drawPath(Path path, Color color);
+
+ /**
+ * Draw a path using a default color specific to the implementation
+ *
+ *
+ * @param path
+ * @param markers
+ * Show origin and destination markers.
+ */
+ public void drawPath(Path path, boolean markers);
+
+ /**
+ * Draw a path using a default color specific to the implementation
+ *
+ *
+ * @param path
+ */
+ public void drawPath(Path path);
- /**
- * Draw the given graph using the given palette.
- *
- * @param graph
- * @param palette
- */
- public void drawGraph(Graph graph, GraphPalette palette);
-
- /**
- * Draw the given graph using a default palette specific to the implementation.
- *
- * @param graph
- */
- public void drawGraph(Graph graph);
-
- /**
- * Draw a path using the given color.
- *
- * @param path
- * @param color
- * @param markers Show origin and destination markers.
- */
- public void drawPath(Path path, Color color, boolean markers);
-
- /**
- * Draw a path using the given color with markers.
- *
- * @param path
- * @param color
- */
- public void drawPath(Path path, Color color);
-
- /**
- * Draw a path using a default color specific to the implementation
- *
- *
- * @param path
- * @param markers Show origin and destination markers.
- */
- public void drawPath(Path path, boolean markers);
-
- /**
- * Draw a path using a default color specific to the implementation
- *
- *
- * @param path
- */
- public void drawPath(Path path);
-
}
diff --git a/src/main/org/insa/drawing/DrawingClickListener.java b/src/main/org/insa/drawing/DrawingClickListener.java
new file mode 100644
index 0000000..35ce18d
--- /dev/null
+++ b/src/main/org/insa/drawing/DrawingClickListener.java
@@ -0,0 +1,14 @@
+package org.insa.drawing;
+
+import org.insa.graph.Point;
+
+public interface DrawingClickListener {
+
+ /**
+ * Event triggered when a click is made on the map.
+ *
+ * @param point
+ */
+ public void mouseClicked(Point point);
+
+}
diff --git a/src/main/org/insa/drawing/MapViewDrawing.java b/src/main/org/insa/drawing/MapViewDrawing.java
index 5c08be5..a217a44 100644
--- a/src/main/org/insa/drawing/MapViewDrawing.java
+++ b/src/main/org/insa/drawing/MapViewDrawing.java
@@ -1,272 +1,324 @@
-package org.insa.drawing;
-
-import java.awt.Color;
-import java.awt.event.MouseAdapter;
-import java.awt.event.MouseWheelEvent;
-import java.io.File;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.UUID;
-
-import javax.swing.JFileChooser;
-import javax.swing.filechooser.FileNameExtensionFilter;
-
-import org.insa.graph.Arc;
-import org.insa.graph.Graph;
-import org.insa.graph.Path;
-import org.insa.graph.Point;
-import org.mapsforge.core.graphics.GraphicFactory;
-import org.mapsforge.core.graphics.Paint;
-import org.mapsforge.core.graphics.Style;
-import org.mapsforge.core.model.BoundingBox;
-import org.mapsforge.core.model.LatLong;
-import org.mapsforge.core.model.MapPosition;
-import org.mapsforge.core.util.LatLongUtils;
-import org.mapsforge.map.awt.graphics.AwtGraphicFactory;
-import org.mapsforge.map.awt.util.AwtUtil;
-import org.mapsforge.map.awt.view.MapView;
-import org.mapsforge.map.datastore.MapDataStore;
-import org.mapsforge.map.layer.Layers;
-import org.mapsforge.map.layer.cache.TileCache;
-import org.mapsforge.map.layer.hills.HillsRenderConfig;
-import org.mapsforge.map.layer.overlay.Marker;
-import org.mapsforge.map.layer.overlay.Polyline;
-import org.mapsforge.map.layer.renderer.TileRendererLayer;
-import org.mapsforge.map.model.DisplayModel;
-import org.mapsforge.map.model.MapViewPosition;
-import org.mapsforge.map.model.Model;
-import org.mapsforge.map.reader.MapFile;
-import org.mapsforge.map.rendertheme.InternalRenderTheme;
-import org.mapsforge.map.rendertheme.XmlRenderTheme;
-
-public class MapViewDrawing extends MapView implements Drawing {
-
- /**
- *
- */
- private static final long serialVersionUID = 8606967833704938092L;
-
- // Default path color.
- public static final Color DEFAULT_PATH_COLOR = new Color(66, 134, 244);
-
- // Graphic factory.
- private static final GraphicFactory GRAPHIC_FACTORY = AwtGraphicFactory.INSTANCE;
-
- // Default tile size.
- private static final int DEFAULT_TILE_SIZE = 512;
-
- // Tile size.
- int tileSize;
-
- ArrayList extraLayers;
-
- public MapViewDrawing() {
- getMapScaleBar().setVisible(true);
- this.tileSize = DEFAULT_TILE_SIZE;
- DisplayModel model = getModel().displayModel;
- model.setFixedTileSize(tileSize);
- // model.setBackgroundColor(convertColor(Color.WHITE));
-
- extraLayers = new ArrayList();
- addMouseWheelListener(new MouseAdapter() {
- @Override
- public void mouseWheelMoved(MouseWheelEvent e) {
- byte zoomLevelDiff = (byte) -e.getWheelRotation();
- for (Paint p: extraLayers) {
- p.setStrokeWidth(p.getStrokeWidth() + zoomLevelDiff);
- }
- }
- });
- }
-
- protected int convertColor(Color color) {
- return GRAPHIC_FACTORY.createColor(color.getAlpha(), color.getRed(), color.getGreen(),
- color.getBlue());
- }
-
- private int getStrokeWidth(int width) {
- byte zoomLevel = getModel().mapViewPosition.getZoomLevel();
- return width * (2 - (8 - zoomLevel));
- }
-
- private Paint createPaintStroke(int width, Color color) {
- Paint paintStroke = AwtGraphicFactory.INSTANCE.createPaint();
- paintStroke.setStyle(Style.STROKE);
- if (width != 0) {
- paintStroke.setStrokeWidth(getStrokeWidth(width));
- }
- if (color != null) {
- paintStroke.setColor(convertColor(color));
- }
- return paintStroke;
- }
-
- /**
- *
- * @param color
- * @return
- */
- private File getMapsforgeFileFromGraph(Graph graph) {
- // TODO: Find a way to change this...
- Map idToNames = new HashMap();
- idToNames.put(0x100, "insa");
- idToNames.put(0x110, "paris");
- idToNames.put(0x200, "mayotte");
- idToNames.put(0x250, "newzealand");
- idToNames.put(0x300, "reunion");
- idToNames.put(0x400, "midip");
- idToNames.put(0x410, "morbihan");
-
- File file = null;
- if (idToNames.containsKey(graph.getMapId())) {
- file = new File("Maps/" + idToNames.get(graph.getMapId()) + ".mapfg");
- if (!file.exists()) {
- file = new File("Maps/new/" + idToNames.get(graph.getMapId()) + ".mapfg");
- }
- }
-
- if (file == null || !file.exists()) {
- JFileChooser fileChooser = new JFileChooser("Maps/");
- fileChooser.setFileFilter(new FileNameExtensionFilter("mapsforge files", "" + "mapfg"));
- if (fileChooser.showOpenDialog(this.getParent()) == JFileChooser.APPROVE_OPTION) {
- file = fileChooser.getSelectedFile();
- }
- }
-
- return file;
- }
-
- protected LatLong convertPoint(Point point) {
- return new LatLong(point.getLatitude(), point.getLongitude());
- }
-
- private static TileRendererLayer createTileRendererLayer(TileCache tileCache,
- MapDataStore mapDataStore, MapViewPosition mapViewPosition,
- HillsRenderConfig hillsRenderConfig) {
- TileRendererLayer tileRendererLayer = new TileRendererLayer(tileCache, mapDataStore,
- mapViewPosition, false, true, false, GRAPHIC_FACTORY, hillsRenderConfig) {
- @Override
- public boolean onTap(LatLong tapLatLong, org.mapsforge.core.model.Point layerXY,
- org.mapsforge.core.model.Point tapXY) {
- System.out.println("Tap on: " + tapLatLong);
- return true;
- }
- };
- XmlRenderTheme renderTheme = InternalRenderTheme.DEFAULT;
- tileRendererLayer.setXmlRenderTheme(renderTheme);
- return tileRendererLayer;
- }
-
- @Override
- public void clear() {
- getLayerManager().getLayers().clear();
- extraLayers.clear();
- repaint();
- }
-
- @Override
- public void drawLine(Point from, Point to) {
- drawLine(from, to, 0, null);
- }
-
- @Override
- public void drawLine(Point from, Point to, int width) {
- drawLine(from, to, width, null);
- }
-
- @Override
- public void drawLine(Point from, Point to, int width, Color color) {
- Paint paintStroke = createPaintStroke(width, color);
- Polyline line = new Polyline(paintStroke, AwtGraphicFactory.INSTANCE);
- line.getLatLongs().add(convertPoint(from));
- line.getLatLongs().add(convertPoint(to));
- getLayerManager().getLayers().add(line);
- }
-
- @Override
- public void drawMarker(Point point) {
- drawMarker(point, null);
- }
-
- @Override
- public void drawMarker(Point point, Color color) {
- Marker marker = new Marker(convertPoint(point), GRAPHIC_FACTORY.createBitmap(10, 20), 1, 2);
- getLayerManager().getLayers().add(marker);
- }
-
- @Override
- public void drawPoint(Point point, int width, Color color) {
- // TODO: Maybe do something?
- }
-
- @Override
- public void drawGraph(Graph graph, GraphPalette palette) {
-
- File graphFile = getMapsforgeFileFromGraph(graph);
-
- // Tile cache
- TileCache tileCache = AwtUtil.createTileCache(tileSize,
- getModel().frameBufferModel.getOverdrawFactor(), 1024,
- new File(System.getProperty("java.io.tmpdir"), UUID.randomUUID().toString()));
-
- // Layers
- Layers layers = getLayerManager().getLayers();
-
- MapDataStore mapDataStore = new MapFile(graphFile);
- TileRendererLayer tileRendererLayer = createTileRendererLayer(tileCache, mapDataStore,
- getModel().mapViewPosition, null);
- layers.add(tileRendererLayer);
- BoundingBox boundingBox = mapDataStore.boundingBox();
-
- final Model model = getModel();
- if (model.mapViewPosition.getZoomLevel() == 0
- || !boundingBox.contains(model.mapViewPosition.getCenter())) {
- byte zoomLevel = LatLongUtils.zoomForBounds(model.mapViewDimension.getDimension(),
- boundingBox, model.displayModel.getTileSize());
- model.mapViewPosition
- .setMapPosition(new MapPosition(boundingBox.getCenterPoint(), zoomLevel));
- model.mapViewPosition.setZoomLevelMin(zoomLevel);
- }
- }
-
- @Override
- public void drawGraph(Graph graph) {
- drawGraph(graph, null);
- }
-
- @Override
- public void drawPath(Path path, Color color, boolean markers) {
- Paint paintStroke = createPaintStroke(1, DEFAULT_PATH_COLOR);
- Polyline line = new Polyline(paintStroke, AwtGraphicFactory.INSTANCE);
- for (Arc arc: path.getArcs()) {
- ArrayList points = arc.getPoints();
- for (int i = 0; i < points.size(); ++i) {
- line.getLatLongs().add(
- new LatLong(points.get(i).getLatitude(), points.get(i).getLongitude()));
- }
- }
- getLayerManager().getLayers().add(line);
- extraLayers.add(paintStroke);
- if (markers) {
- drawMarker(path.getOrigin().getPoint());
- drawMarker(path.getDestination().getPoint());
- }
- }
-
- @Override
- public void drawPath(Path path, Color color) {
- drawPath(path, color, true);
- }
-
- @Override
- public void drawPath(Path path) {
- drawPath(path, DEFAULT_PATH_COLOR, true);
- }
-
- @Override
- public void drawPath(Path path, boolean markers) {
- drawPath(path, DEFAULT_PATH_COLOR, markers);
- }
-
-}
+package org.insa.drawing;
+
+import java.awt.Color;
+import java.awt.event.MouseAdapter;
+import java.awt.event.MouseWheelEvent;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.UUID;
+
+import javax.swing.JFileChooser;
+import javax.swing.filechooser.FileNameExtensionFilter;
+
+import org.insa.drawing.utils.MarkerUtils;
+import org.insa.graph.Arc;
+import org.insa.graph.Graph;
+import org.insa.graph.Path;
+import org.insa.graph.Point;
+import org.mapsforge.core.graphics.Bitmap;
+import org.mapsforge.core.graphics.GraphicFactory;
+import org.mapsforge.core.graphics.Paint;
+import org.mapsforge.core.graphics.Style;
+import org.mapsforge.core.model.BoundingBox;
+import org.mapsforge.core.model.LatLong;
+import org.mapsforge.core.model.MapPosition;
+import org.mapsforge.core.util.LatLongUtils;
+import org.mapsforge.map.awt.graphics.AwtGraphicFactory;
+import org.mapsforge.map.awt.util.AwtUtil;
+import org.mapsforge.map.awt.view.MapView;
+import org.mapsforge.map.datastore.MapDataStore;
+import org.mapsforge.map.layer.Layers;
+import org.mapsforge.map.layer.cache.TileCache;
+import org.mapsforge.map.layer.hills.HillsRenderConfig;
+import org.mapsforge.map.layer.overlay.Marker;
+import org.mapsforge.map.layer.overlay.Polyline;
+import org.mapsforge.map.layer.renderer.TileRendererLayer;
+import org.mapsforge.map.model.DisplayModel;
+import org.mapsforge.map.model.MapViewPosition;
+import org.mapsforge.map.model.Model;
+import org.mapsforge.map.reader.MapFile;
+import org.mapsforge.map.rendertheme.ExternalRenderTheme;
+import org.mapsforge.map.rendertheme.XmlRenderTheme;
+
+public class MapViewDrawing extends MapView implements Drawing {
+
+ /**
+ *
+ */
+ private static final long serialVersionUID = 8606967833704938092L;
+
+ // Default path color.
+ public static final Color DEFAULT_PATH_COLOR = new Color(66, 134, 244);
+
+ // Graphic factory.
+ private static final GraphicFactory GRAPHIC_FACTORY = AwtGraphicFactory.INSTANCE;
+
+ // Default tile size.
+ private static final int DEFAULT_TILE_SIZE = 512;
+
+ // List of listeners.
+ private ArrayList drawingClickListeners = new ArrayList<>();
+
+ // Tile size.
+ int tileSize;
+
+ // Extra layers...
+ private static class FixedStrokeWidthLayer {
+ public Paint paint;
+ public int width;
+
+ public FixedStrokeWidthLayer(Paint paint, int width) {
+ this.paint = paint;
+ this.width = width;
+ }
+
+ };
+
+ ArrayList extraLayers = new ArrayList<>();
+
+ public MapViewDrawing() {
+ getMapScaleBar().setVisible(true);
+ this.tileSize = DEFAULT_TILE_SIZE;
+ DisplayModel model = getModel().displayModel;
+ model.setFixedTileSize(tileSize);
+
+ addMouseWheelListener(new MouseAdapter() {
+
+ @Override
+ public void mouseWheelMoved(MouseWheelEvent e) {
+ for (FixedStrokeWidthLayer f: extraLayers) {
+ f.paint.setStrokeWidth(getStrokeWidth(f.width));
+ }
+ }
+ });
+
+ }
+
+ /**
+ * @param color
+ * @return
+ */
+ protected int convertColor(Color color) {
+ return GRAPHIC_FACTORY.createColor(color.getAlpha(), color.getRed(), color.getGreen(), color.getBlue());
+ }
+
+ /**
+ * @param width
+ * @return
+ */
+ private int getStrokeWidth(int width) {
+ byte zoomLevel = getModel().mapViewPosition.getZoomLevel();
+ int mul = 2;
+ if (zoomLevel < 8) {
+ mul = 1;
+ }
+ else {
+ mul += 2 * (zoomLevel - 8) / 3;
+ }
+ return width * mul;
+ }
+
+ /**
+ * @param width
+ * @param color
+ * @return
+ */
+ private Paint createPaintStroke(int width, Color color) {
+ Paint paintStroke = AwtGraphicFactory.INSTANCE.createPaint();
+ paintStroke.setStyle(Style.STROKE);
+ if (width != 0) {
+ paintStroke.setStrokeWidth(getStrokeWidth(width));
+ }
+ if (color != null) {
+ paintStroke.setColor(convertColor(color));
+ }
+ return paintStroke;
+ }
+
+ /**
+ *
+ * @param color
+ * @return
+ */
+ private File getMapsforgeFileFromGraph(Graph graph) {
+ // TODO: Find a way to change this...
+ Map idToNames = new HashMap();
+ idToNames.put(0x100, "insa");
+ idToNames.put(0x110, "paris");
+ idToNames.put(0x200, "mayotte");
+ idToNames.put(0x250, "newzealand");
+ idToNames.put(0x300, "reunion");
+ idToNames.put(0x400, "midip");
+ idToNames.put(0x410, "morbihan");
+
+ File file = null;
+ if (idToNames.containsKey(graph.getMapId())) {
+ file = new File("Maps/" + idToNames.get(graph.getMapId()) + ".mapfg");
+ if (!file.exists()) {
+ file = new File("Maps/new/" + idToNames.get(graph.getMapId()) + ".mapfg");
+ }
+ }
+
+ if (file == null || !file.exists()) {
+ JFileChooser fileChooser = new JFileChooser("Maps/");
+ fileChooser.setFileFilter(new FileNameExtensionFilter("mapsforge files", "" + "mapfg"));
+ if (fileChooser.showOpenDialog(this.getParent()) == JFileChooser.APPROVE_OPTION) {
+ file = fileChooser.getSelectedFile();
+ }
+ }
+
+ return file;
+ }
+
+ protected LatLong convertPoint(Point point) {
+ return new LatLong(point.getLatitude(), point.getLongitude());
+ }
+
+ private TileRendererLayer createTileRendererLayer(TileCache tileCache, MapDataStore mapDataStore,
+ MapViewPosition mapViewPosition, HillsRenderConfig hillsRenderConfig) {
+ TileRendererLayer tileRendererLayer = new TileRendererLayer(tileCache, mapDataStore, mapViewPosition, false,
+ true, false, GRAPHIC_FACTORY, hillsRenderConfig) {
+ @Override
+ public boolean onTap(LatLong tapLatLong, org.mapsforge.core.model.Point layerXY,
+ org.mapsforge.core.model.Point tapXY) {
+ System.out.println("Tap on: " + tapLatLong);
+ Point pt = new Point(tapLatLong.getLongitude(), tapLatLong.getLatitude());
+ for (DrawingClickListener listener: MapViewDrawing.this.drawingClickListeners) {
+ listener.mouseClicked(pt);
+ }
+ return true;
+ }
+ };
+ XmlRenderTheme renderTheme = null;
+ try {
+ renderTheme = new ExternalRenderTheme("resources/assets/custom-theme.xml");
+ }
+ catch (FileNotFoundException e) {
+ e.printStackTrace();
+ }
+ tileRendererLayer.setXmlRenderTheme(renderTheme);
+ return tileRendererLayer;
+ }
+
+ @Override
+ public void addDrawingClickListener(DrawingClickListener listener) {
+ this.drawingClickListeners.add(listener);
+ }
+
+ @Override
+ public void removeDrawingClickListener(DrawingClickListener listener) {
+ this.drawingClickListeners.remove(listener);
+ }
+
+ @Override
+ public void clear() {
+ getLayerManager().getLayers().clear();
+ extraLayers.clear();
+ repaint();
+ }
+
+ @Override
+ public void drawLine(Point from, Point to) {
+ drawLine(from, to, 0, null);
+ }
+
+ @Override
+ public void drawLine(Point from, Point to, int width) {
+ drawLine(from, to, width, null);
+ }
+
+ @Override
+ public void drawLine(Point from, Point to, int width, Color color) {
+ Paint paintStroke = createPaintStroke(width, color);
+ Polyline line = new Polyline(paintStroke, AwtGraphicFactory.INSTANCE);
+ line.getLatLongs().add(convertPoint(from));
+ line.getLatLongs().add(convertPoint(to));
+ getLayerManager().getLayers().add(line);
+ }
+
+ @Override
+ public void drawMarker(Point point) {
+ drawMarker(point, Color.GREEN);
+ }
+
+ @Override
+ public void drawMarker(Point point, Color color) {
+ Bitmap bitmap = MarkerUtils.getMarkerForColor(color);
+ Marker marker = new Marker(convertPoint(point), bitmap, 0, -bitmap.getHeight() / 2);
+ getLayerManager().getLayers().add(marker);
+ }
+
+ @Override
+ public void drawPoint(Point point, int width, Color color) {
+ // TODO:
+ }
+
+ @Override
+ public void drawGraph(Graph graph, GraphPalette palette) {
+
+ File graphFile = getMapsforgeFileFromGraph(graph);
+
+ // Tile cache
+ TileCache tileCache = AwtUtil.createTileCache(tileSize, getModel().frameBufferModel.getOverdrawFactor(), 1024,
+ new File(System.getProperty("java.io.tmpdir"), UUID.randomUUID().toString()));
+
+ // Layers
+ Layers layers = getLayerManager().getLayers();
+
+ MapDataStore mapDataStore = new MapFile(graphFile);
+ TileRendererLayer tileRendererLayer = createTileRendererLayer(tileCache, mapDataStore,
+ getModel().mapViewPosition, null);
+ layers.add(tileRendererLayer);
+ BoundingBox boundingBox = mapDataStore.boundingBox();
+
+ final Model model = getModel();
+ if (model.mapViewPosition.getZoomLevel() == 0 || !boundingBox.contains(model.mapViewPosition.getCenter())) {
+ byte zoomLevel = LatLongUtils.zoomForBounds(model.mapViewDimension.getDimension(), boundingBox,
+ model.displayModel.getTileSize());
+ model.mapViewPosition.setMapPosition(new MapPosition(boundingBox.getCenterPoint(), zoomLevel));
+ model.mapViewPosition.setZoomLevelMin(zoomLevel);
+ }
+ }
+
+ @Override
+ public void drawGraph(Graph graph) {
+ drawGraph(graph, null);
+ }
+
+ @Override
+ public void drawPath(Path path, Color color, boolean markers) {
+ Paint paintStroke = createPaintStroke(1, DEFAULT_PATH_COLOR);
+ Polyline line = new Polyline(paintStroke, AwtGraphicFactory.INSTANCE);
+ for (Arc arc: path.getArcs()) {
+ ArrayList points = arc.getPoints();
+ for (int i = 0; i < points.size(); ++i) {
+ line.getLatLongs().add(new LatLong(points.get(i).getLatitude(), points.get(i).getLongitude()));
+ }
+ }
+ getLayerManager().getLayers().add(line);
+ extraLayers.add(new FixedStrokeWidthLayer(paintStroke, 1));
+ if (markers) {
+ drawMarker(path.getOrigin().getPoint(), DEFAULT_PATH_COLOR);
+ drawMarker(path.getDestination().getPoint(), DEFAULT_PATH_COLOR);
+ }
+ }
+
+ @Override
+ public void drawPath(Path path, Color color) {
+ drawPath(path, color, true);
+ }
+
+ @Override
+ public void drawPath(Path path) {
+ drawPath(path, DEFAULT_PATH_COLOR, true);
+ }
+
+ @Override
+ public void drawPath(Path path, boolean markers) {
+ drawPath(path, DEFAULT_PATH_COLOR, markers);
+ }
+
+}
diff --git a/src/main/org/insa/drawing/utils/MarkerUtils.java b/src/main/org/insa/drawing/utils/MarkerUtils.java
new file mode 100644
index 0000000..74f8fb2
--- /dev/null
+++ b/src/main/org/insa/drawing/utils/MarkerUtils.java
@@ -0,0 +1,118 @@
+package org.insa.drawing.utils;
+
+import java.awt.Color;
+import java.awt.image.BufferedImage;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.mapsforge.core.graphics.Bitmap;
+import org.mapsforge.map.awt.graphics.AwtBitmap;
+
+public class MarkerUtils {
+
+ // Marker
+ private static Map MARKER_BITMAPS = new HashMap();
+
+ /**
+ * Return a color mapping with the given color as the main color.
+ *
+ * @param color
+ * @return
+ */
+ protected static Color[] getColorMapping(Color color) {
+ return new Color[] { new Color(0, 0, 0, 0), color, Color.BLACK };
+ }
+
+ /**
+ * Create a Bitmap representing a marker of the given color.
+ *
+ * @param color
+ * @return
+ */
+ public static Bitmap getMarkerForColor(Color color) {
+ if (MARKER_BITMAPS.containsKey(color)) {
+ return MARKER_BITMAPS.get(color);
+ }
+
+ // create image
+ BufferedImage image = new BufferedImage(MARKER_MASK[0].length, MARKER_MASK.length, BufferedImage.TYPE_INT_ARGB);
+
+ Color[] map = getColorMapping(color);
+ for (int i = 0; i < image.getHeight(); ++i) {
+ for (int j = 0; j < image.getWidth(); ++j) {
+ image.setRGB(j, i, map[MARKER_MASK[i][j]].getRGB());
+ }
+ }
+
+ // Create Bitmap, add it to map and return it.
+ Bitmap bitmap = new AwtBitmap(image);
+ MARKER_BITMAPS.put(color, bitmap);
+ return bitmap;
+ }
+
+ // Mask
+ private static byte[][] MARKER_MASK = new byte[][] {
+ // @formatter:off
+ {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
+ {0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0},
+ {0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0},
+ {0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0},
+ {0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0},
+ {0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0},
+ {0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0},
+ {0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0},
+ {0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0},
+ {0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0},
+ {0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0},
+ {0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0},
+ {0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,2,2,2,2,2,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0},
+ {0,1,1,1,1,1,1,1,1,1,1,1,1,1,2,2,2,2,2,2,2,2,2,1,1,1,1,1,1,1,1,1,1,1,1,1,0},
+ {1,1,1,1,1,1,1,1,1,1,1,1,1,2,2,2,2,2,2,2,2,2,2,2,1,1,1,1,1,1,1,1,1,1,1,1,1},
+ {1,1,1,1,1,1,1,1,1,1,1,1,1,2,2,2,2,2,2,2,2,2,2,2,1,1,1,1,1,1,1,1,1,1,1,1,1},
+ {1,1,1,1,1,1,1,1,1,1,1,1,2,2,2,2,2,2,2,2,2,2,2,2,2,1,1,1,1,1,1,1,1,1,1,1,1},
+ {1,1,1,1,1,1,1,1,1,1,1,1,2,2,2,2,2,2,2,2,2,2,2,2,2,1,1,1,1,1,1,1,1,1,1,1,1},
+ {1,1,1,1,1,1,1,1,1,1,1,1,2,2,2,2,2,2,2,2,2,2,2,2,2,1,1,1,1,1,1,1,1,1,1,1,1},
+ {1,1,1,1,1,1,1,1,1,1,1,1,1,2,2,2,2,2,2,2,2,2,2,2,1,1,1,1,1,1,1,1,1,1,1,1,1},
+ {1,1,1,1,1,1,1,1,1,1,1,1,1,2,2,2,2,2,2,2,2,2,2,2,1,1,1,1,1,1,1,1,1,1,1,1,1},
+ {0,1,1,1,1,1,1,1,1,1,1,1,1,1,2,2,2,2,2,2,2,2,2,1,1,1,1,1,1,1,1,1,1,1,1,1,0},
+ {0,1,1,1,1,1,1,1,1,1,1,1,1,1,2,2,2,2,2,2,2,2,2,1,1,1,1,1,1,1,1,1,1,1,1,1,0},
+ {0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,2,2,2,2,2,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0},
+ {0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0},
+ {0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0},
+ {0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0},
+ {0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0},
+ {0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0},
+ {0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0},
+ {0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0},
+ {0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0},
+ {0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0},
+ {0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0},
+ {0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0},
+ {0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0},
+ {0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0},
+ {0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0},
+ {0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0},
+ {0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0},
+ {0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0},
+ {0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0},
+ {0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0},
+ {0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0},
+ {0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
+ {0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
+ {0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
+ {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
+ {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
+ {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
+ {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
+ {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
+ {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
+ {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
+ {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
+ {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
+ {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
+ {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
+ {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
+ {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0},
+ {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}
+ };
+}