Update graphics.

This commit is contained in:
Holt59 2018-03-02 23:48:57 +01:00
parent ae082d0b8a
commit be94c670b7
4 changed files with 131 additions and 112 deletions

View File

@ -53,7 +53,6 @@ import org.insa.algo.weakconnectivity.WeaklyConnectedComponentsAlgorithm;
import org.insa.algo.weakconnectivity.WeaklyConnectedComponentsData; import org.insa.algo.weakconnectivity.WeaklyConnectedComponentsData;
import org.insa.graph.Graph; import org.insa.graph.Graph;
import org.insa.graph.Path; import org.insa.graph.Path;
import org.insa.graph.io.BinaryGraphReaderInsa2016;
import org.insa.graph.io.BinaryGraphReaderInsa2018; import org.insa.graph.io.BinaryGraphReaderInsa2018;
import org.insa.graph.io.BinaryPathReader; import org.insa.graph.io.BinaryPathReader;
import org.insa.graph.io.GraphReader; import org.insa.graph.io.GraphReader;
@ -144,19 +143,17 @@ public class MainWindow extends JFrame {
@Override @Override
public void actionPerformed(ActionEvent e) { public void actionPerformed(ActionEvent e) {
StartActionEvent evt = (StartActionEvent) e; StartActionEvent evt = (StartActionEvent) e;
ShortestPathData data = new ShortestPathData(graph, evt.getOrigin(), ShortestPathData data = new ShortestPathData(graph, evt.getOrigin(), evt.getDestination(),
evt.getDestination(), evt.getMode()); evt.getMode());
ShortestPathAlgorithm spAlgorithm = null; ShortestPathAlgorithm spAlgorithm = null;
try { try {
spAlgorithm = ShortestPathAlgorithmFactory spAlgorithm = ShortestPathAlgorithmFactory.createAlgorithm(evt.getAlgorithmClass(), data);
.createAlgorithm(evt.getAlgorithmClass(), data);
} }
catch (Exception e1) { catch (Exception e1) {
JOptionPane.showMessageDialog(MainWindow.this, JOptionPane.showMessageDialog(MainWindow.this,
"An error occurred while creating the specified algorithm.", "An error occurred while creating the specified algorithm.",
"Internal error: Algorithm instantiation failure", "Internal error: Algorithm instantiation failure", JOptionPane.ERROR_MESSAGE);
JOptionPane.ERROR_MESSAGE);
e1.printStackTrace(); e1.printStackTrace();
return; return;
} }
@ -341,14 +338,12 @@ public class MainWindow extends JFrame {
// We need to draw MapView, we have to check if the file exists. // We need to draw MapView, we have to check if the file exists.
File mfile = null; File mfile = null;
if (isMapView) { if (isMapView) {
String mfpath = graphFilePath.substring(0, graphFilePath.lastIndexOf(".map")) String mfpath = graphFilePath.substring(0, graphFilePath.lastIndexOf(".map")) + ".mapfg";
+ ".mapfg";
mfile = new File(mfpath); mfile = new File(mfpath);
if (!mfile.exists()) { if (!mfile.exists()) {
if (JOptionPane.showConfirmDialog(this, if (JOptionPane.showConfirmDialog(this,
"The associated mapsforge (.mapfg) file has not been found, do you want to specify it manually?", "The associated mapsforge (.mapfg) file has not been found, do you want to specify it manually?",
"File not found", "File not found", JOptionPane.YES_NO_CANCEL_OPTION) == JOptionPane.YES_OPTION) {
JOptionPane.YES_NO_CANCEL_OPTION) == JOptionPane.YES_OPTION) {
JFileChooser chooser = new JFileChooser(mfile.getParentFile()); JFileChooser chooser = new JFileChooser(mfile.getParentFile());
if (chooser.showOpenDialog(this) == JFileChooser.APPROVE_OPTION) { if (chooser.showOpenDialog(this) == JFileChooser.APPROVE_OPTION) {
mfile = chooser.getSelectedFile(); mfile = chooser.getSelectedFile();
@ -418,16 +413,15 @@ public class MainWindow extends JFrame {
reader.addObserver(progressBar); reader.addObserver(progressBar);
try { try {
graph = reader.read(); graph = reader.read();
System.out.flush();
} }
catch (Exception exception) { catch (Exception exception) {
progressBar.setVisible(false); progressBar.setVisible(false);
progressBar = null; progressBar = null;
JOptionPane.showMessageDialog(MainWindow.this, JOptionPane.showMessageDialog(MainWindow.this, "Unable to read graph from the selected file.");
"Unable to read graph from the selected file.");
exception.printStackTrace(System.out); exception.printStackTrace(System.out);
return; return;
} }
notifyNewGraphLoaded();
String info = graph.getMapId(); String info = graph.getMapId();
if (graph.getMapName() != null && !graph.getMapName().isEmpty()) { if (graph.getMapName() != null && !graph.getMapName().isEmpty()) {
@ -435,8 +429,11 @@ public class MainWindow extends JFrame {
} }
info += ", " + graph.getNodes().size() + " nodes"; info += ", " + graph.getNodes().size() + " nodes";
graphInfoPanel.setText(info); graphInfoPanel.setText(info);
drawGraph(); drawGraph();
notifyNewGraphLoaded();
for (JMenuItem item: graphLockItems) { for (JMenuItem item: graphLockItems) {
item.setEnabled(true); item.setEnabled(true);
} }
@ -453,8 +450,7 @@ public class MainWindow extends JFrame {
@Override @Override
public void actionPerformed(ActionEvent e) { public void actionPerformed(ActionEvent e) {
JFileChooser chooser = new JFileChooser(); JFileChooser chooser = new JFileChooser();
FileNameExtensionFilter filter = new FileNameExtensionFilter("Graph files", FileNameExtensionFilter filter = new FileNameExtensionFilter("Graph files", "mapgr");
"mapgr");
chooser.setCurrentDirectory(new File(System.getProperty("user.dir"))); chooser.setCurrentDirectory(new File(System.getProperty("user.dir")));
chooser.setFileFilter(filter); chooser.setFileFilter(filter);
if (chooser.showOpenDialog(MainWindow.this) == JFileChooser.APPROVE_OPTION) { if (chooser.showOpenDialog(MainWindow.this) == JFileChooser.APPROVE_OPTION) {
@ -462,12 +458,11 @@ public class MainWindow extends JFrame {
DataInputStream stream; DataInputStream stream;
try { try {
stream = new DataInputStream(new BufferedInputStream( stream = new DataInputStream(
new FileInputStream(chooser.getSelectedFile()))); new BufferedInputStream(new FileInputStream(chooser.getSelectedFile())));
} }
catch (IOException e1) { catch (IOException e1) {
JOptionPane.showMessageDialog(MainWindow.this, JOptionPane.showMessageDialog(MainWindow.this, "Cannot open the selected file.");
"Cannot open the selected file.");
return; return;
} }
loadGraph(new BinaryGraphReaderInsa2018(stream)); loadGraph(new BinaryGraphReaderInsa2018(stream));
@ -475,33 +470,6 @@ public class MainWindow extends JFrame {
} }
})); }));
JMenuItem openOldMapItem = new JMenuItem("Open Map (Old version)... ");
openOldMapItem.addActionListener(baf.createBlockingAction(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
JFileChooser chooser = new JFileChooser();
FileNameExtensionFilter filter = new FileNameExtensionFilter(
"Map & compressed map files", "map");
chooser.setCurrentDirectory(new File(System.getProperty("user.dir")));
chooser.setFileFilter(filter);
if (chooser.showOpenDialog(MainWindow.this) == JFileChooser.APPROVE_OPTION) {
graphFilePath = chooser.getSelectedFile().getAbsolutePath();
DataInputStream stream;
try {
stream = new DataInputStream(new BufferedInputStream(
new FileInputStream(chooser.getSelectedFile())));
}
catch (IOException e1) {
JOptionPane.showMessageDialog(MainWindow.this,
"Cannot open the selected file.");
return;
}
loadGraph(new BinaryGraphReaderInsa2016(stream));
}
}
}));
// Open Path item... // Open Path item...
JMenuItem openPathItem = new JMenuItem("Open Path... ", KeyEvent.VK_P); JMenuItem openPathItem = new JMenuItem("Open Path... ", KeyEvent.VK_P);
openPathItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_P, ActionEvent.ALT_MASK)); openPathItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_P, ActionEvent.ALT_MASK));
@ -510,19 +478,18 @@ public class MainWindow extends JFrame {
@Override @Override
public void actionPerformed(ActionEvent e) { public void actionPerformed(ActionEvent e) {
JFileChooser chooser = new JFileChooser(); JFileChooser chooser = new JFileChooser();
FileNameExtensionFilter filter = new FileNameExtensionFilter( FileNameExtensionFilter filter = new FileNameExtensionFilter("Path & compressed path files", "path",
"Path & compressed path files", "path", "path.gz"); "path.gz");
chooser.setCurrentDirectory(new File(System.getProperty("user.dir"))); chooser.setCurrentDirectory(new File(System.getProperty("user.dir")));
chooser.setFileFilter(filter); chooser.setFileFilter(filter);
if (chooser.showOpenDialog(MainWindow.this) == JFileChooser.APPROVE_OPTION) { if (chooser.showOpenDialog(MainWindow.this) == JFileChooser.APPROVE_OPTION) {
BinaryPathReader reader; BinaryPathReader reader;
try { try {
reader = new BinaryPathReader(new DataInputStream(new BufferedInputStream( reader = new BinaryPathReader(new DataInputStream(
new FileInputStream(chooser.getSelectedFile())))); new BufferedInputStream(new FileInputStream(chooser.getSelectedFile()))));
} }
catch (IOException e1) { catch (IOException e1) {
JOptionPane.showMessageDialog(MainWindow.this, JOptionPane.showMessageDialog(MainWindow.this, "Cannot open the selected file.");
"Cannot open the selected file.");
return; return;
} }
try { try {
@ -535,8 +502,7 @@ public class MainWindow extends JFrame {
return; return;
} }
catch (Exception exception) { catch (Exception exception) {
JOptionPane.showMessageDialog(MainWindow.this, JOptionPane.showMessageDialog(MainWindow.this, "Unable to read path from the selected file.");
"Unable to read path from the selected file.");
return; return;
} }
} }
@ -550,15 +516,13 @@ public class MainWindow extends JFrame {
closeItem.addActionListener(new ActionListener() { closeItem.addActionListener(new ActionListener() {
@Override @Override
public void actionPerformed(ActionEvent e) { public void actionPerformed(ActionEvent e) {
MainWindow.this.dispatchEvent( MainWindow.this.dispatchEvent(new WindowEvent(MainWindow.this, WindowEvent.WINDOW_CLOSING));
new WindowEvent(MainWindow.this, WindowEvent.WINDOW_CLOSING));
} }
}); });
// Build the first menu. // Build the first menu.
JMenu fileMenu = new JMenu("File"); JMenu fileMenu = new JMenu("File");
fileMenu.add(openMapItem); fileMenu.add(openMapItem);
fileMenu.add(openOldMapItem); // TODO: Remove this for Students.
fileMenu.add(openPathItem); fileMenu.add(openPathItem);
fileMenu.addSeparator(); fileMenu.addSeparator();
fileMenu.add(closeItem); fileMenu.add(closeItem);
@ -593,8 +557,7 @@ public class MainWindow extends JFrame {
})); }));
graphLockItems.add(drawGraphBWItem); graphLockItems.add(drawGraphBWItem);
JMenuItem drawGraphMapsforgeItem = new JMenuItem("Redraw (Map)", KeyEvent.VK_M); JMenuItem drawGraphMapsforgeItem = new JMenuItem("Redraw (Map)", KeyEvent.VK_M);
drawGraphMapsforgeItem drawGraphMapsforgeItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_M, ActionEvent.ALT_MASK));
.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_M, ActionEvent.ALT_MASK));
drawGraphMapsforgeItem.addActionListener(baf.createBlockingAction(new ActionListener() { drawGraphMapsforgeItem.addActionListener(baf.createBlockingAction(new ActionListener() {
@Override @Override
public void actionPerformed(ActionEvent e) { public void actionPerformed(ActionEvent e) {
@ -669,9 +632,8 @@ public class MainWindow extends JFrame {
private JPanel createStatusBar() { private JPanel createStatusBar() {
// create the status bar panel and shove it down the bottom of the frame // create the status bar panel and shove it down the bottom of the frame
JPanel statusPanel = new JPanel(); JPanel statusPanel = new JPanel();
statusPanel.setBorder( statusPanel.setBorder(new CompoundBorder(BorderFactory.createMatteBorder(1, 0, 0, 0, Color.GRAY),
new CompoundBorder(BorderFactory.createMatteBorder(1, 0, 0, 0, Color.GRAY), new EmptyBorder(0, 15, 0, 15)));
new EmptyBorder(0, 15, 0, 15)));
statusPanel.setPreferredSize(new Dimension(getWidth(), 38)); statusPanel.setPreferredSize(new Dimension(getWidth(), 38));
statusPanel.setLayout(new BorderLayout()); statusPanel.setLayout(new BorderLayout());
@ -688,8 +650,8 @@ public class MainWindow extends JFrame {
public void actionPerformed(ActionEvent e) { public void actionPerformed(ActionEvent e) {
if (currentThread.isRunning()) { if (currentThread.isRunning()) {
int confirmed = JOptionPane.showConfirmDialog(MainWindow.this, int confirmed = JOptionPane.showConfirmDialog(MainWindow.this,
"Are you sure you want to kill the running thread?", "Are you sure you want to kill the running thread?", "Kill Confirmation",
"Kill Confirmation", JOptionPane.YES_NO_OPTION); JOptionPane.YES_NO_OPTION);
if (confirmed == JOptionPane.YES_OPTION) { if (confirmed == JOptionPane.YES_OPTION) {
currentThread.interrupt(); currentThread.interrupt();
} }
@ -701,8 +663,8 @@ public class MainWindow extends JFrame {
@Override @Override
public void actionPerformed(ActionEvent e) { public void actionPerformed(ActionEvent e) {
long seconds = currentThread.getDuration().getSeconds(); long seconds = currentThread.getDuration().getSeconds();
threadTimerLabel.setText(String.format("%02d:%02d:%02d", seconds / 3600, threadTimerLabel
seconds / 60 % 60, seconds % 60)); .setText(String.format("%02d:%02d:%02d", seconds / 3600, seconds / 60 % 60, seconds % 60));
} }
}); });
threadTimer.setInitialDelay(0); threadTimer.setInitialDelay(0);

View File

@ -34,10 +34,54 @@ public class NodesInputPanel extends JPanel
/** /**
* *
*/ */
private static final long serialVersionUID = -1638302070013027690L; private static final long serialVersionUID = 1L;
private static final Color DEFAULT_MARKER_COLOR = Color.BLUE; private static final Color DEFAULT_MARKER_COLOR = Color.BLUE;
/**
* Utility class that can be used to find a node from coordinates in a "fast"
* way.
*
*/
private static class NodeFinder {
// Graph associated with this node finder.
private Graph graph;
/**
* @param graph
*/
public NodeFinder(Graph graph) {
this.graph = graph;
}
/**
* @param point
*
* @return the closest node to the given point, or null if no node is "close
* enough".
*/
public Node findClosestNode(Point point) {
Node minNode = null;
double minDis = Double.POSITIVE_INFINITY;
for (Node node: graph.getNodes()) {
double dlon = point.getLongitude() - node.getPoint().getLongitude();
double dlat = point.getLatitude() - node.getPoint().getLatitude();
double dis = dlon * dlon + dlat * dlat; // No need to square
if (dis < minDis) {
minNode = node;
minDis = dis;
}
}
return minNode;
}
}
/**
* Event data send when a node input has changed.
*
*/
public class InputChangedEvent extends ActionEvent { public class InputChangedEvent extends ActionEvent {
/** /**
@ -77,6 +121,7 @@ public class NodesInputPanel extends JPanel
// Drawing and graph // Drawing and graph
private Drawing drawing; private Drawing drawing;
private Graph graph; private Graph graph;
private NodeFinder nodeFinder;
/** /**
* @param drawing Original drawing used (see {@link:newDrawingLoaded}). * @param drawing Original drawing used (see {@link:newDrawingLoaded}).
@ -316,7 +361,7 @@ public class NodesInputPanel extends JPanel
public void mouseClicked(Point point) { public void mouseClicked(Point point) {
JTextField input = getInputToFill(); JTextField input = getInputToFill();
if (input != null) { if (input != null) {
Node node = graph.findClosestNode(point); Node node = nodeFinder.findClosestNode(point);
input.setText(String.valueOf(node.getId())); input.setText(String.valueOf(node.getId()));
nextInputToFill(); nextInputToFill();
} }
@ -328,6 +373,8 @@ public class NodesInputPanel extends JPanel
this.clear(); this.clear();
this.graph = graph; this.graph = graph;
nodeFinder = new NodeFinder(graph);
// Disable if previously disabled... // Disable if previously disabled...
setEnabled(this.isEnabled()); setEnabled(this.isEnabled());
} }

View File

@ -32,8 +32,7 @@ import org.insa.graph.io.BinaryPathWriter;
import org.insa.graphics.drawing.Drawing; import org.insa.graphics.drawing.Drawing;
import org.insa.graphics.drawing.overlays.PathOverlay; import org.insa.graphics.drawing.overlays.PathOverlay;
public class ShortestPathSolutionPanel extends JPanel public class ShortestPathSolutionPanel extends JPanel implements DrawingChangeListener, GraphChangeListener {
implements DrawingChangeListener, GraphChangeListener {
/** /**
* *
@ -98,12 +97,13 @@ public class ShortestPathSolutionPanel extends JPanel
/* /*
* (non-Javadoc) * (non-Javadoc)
*
* @see java.lang.Object#toString() * @see java.lang.Object#toString()
*/ */
public String toString() { public String toString() {
return "Shortest-path from #" + this.getData().getOrigin().getId() + " to #" return "Shortest-path from #" + this.getData().getOrigin().getId() + " to #"
+ this.getData().getDestination().getId() + " [" + this.getData().getDestination().getId() + " [" + this.getData().getMode().toString().toLowerCase()
+ this.getData().getMode().toString().toLowerCase() + "]"; + "]";
} }
} }
@ -167,10 +167,9 @@ public class ShortestPathSolutionPanel extends JPanel
@Override @Override
public void actionPerformed(ActionEvent e) { public void actionPerformed(ActionEvent e) {
String filepath = System.getProperty("user.dir"); String filepath = System.getProperty("user.dir");
filepath += File.separator + String.format("path_%#x_%d_%d.path", filepath += File.separator + String.format("path_%s_%d_%d.path",
currentBundle.getData().getGraph().getMapId(), currentBundle.getData().getGraph().getMapId().toLowerCase().replaceAll("[^a-z0-9_]", "_"),
currentBundle.getData().getOrigin().getId(), currentBundle.getData().getOrigin().getId(), currentBundle.getData().getDestination().getId());
currentBundle.getData().getDestination().getId());
JFileChooser fileChooser = new JFileChooser(); JFileChooser fileChooser = new JFileChooser();
fileChooser.setSelectedFile(new File(filepath)); fileChooser.setSelectedFile(new File(filepath));
fileChooser.setApproveButtonText("Save"); fileChooser.setApproveButtonText("Save");
@ -178,13 +177,12 @@ public class ShortestPathSolutionPanel extends JPanel
if (fileChooser.showOpenDialog(parent) == JFileChooser.APPROVE_OPTION) { if (fileChooser.showOpenDialog(parent) == JFileChooser.APPROVE_OPTION) {
File file = fileChooser.getSelectedFile(); File file = fileChooser.getSelectedFile();
try { try {
BinaryPathWriter writer = new BinaryPathWriter(new DataOutputStream( BinaryPathWriter writer = new BinaryPathWriter(
new BufferedOutputStream(new FileOutputStream(file)))); new DataOutputStream(new BufferedOutputStream(new FileOutputStream(file))));
writer.writePath(currentBundle.getSolution().getPath()); writer.writePath(currentBundle.getSolution().getPath());
} }
catch (IOException e1) { catch (IOException e1) {
JOptionPane.showMessageDialog(parent, JOptionPane.showMessageDialog(parent, "Unable to write path to the selected file.");
"Unable to write path to the selected file.");
e1.printStackTrace(); e1.printStackTrace();
} }
} }
@ -237,8 +235,8 @@ public class ShortestPathSolutionPanel extends JPanel
ShortestPathData data = bundle.getData(); ShortestPathData data = bundle.getData();
String info = null; String info = null;
if (!bundle.getSolution().isFeasible()) { if (!bundle.getSolution().isFeasible()) {
info = String.format("No path found from node #%d to node #%d.", info = String.format("No path found from node #%d to node #%d.", data.getOrigin().getId(),
data.getOrigin().getId(), data.getDestination().getId()); data.getDestination().getId());
} }
else { else {
info = String.format("Found a path from node #%d to node #%d", data.getOrigin().getId(), info = String.format("Found a path from node #%d to node #%d", data.getOrigin().getId(),
@ -275,6 +273,12 @@ public class ShortestPathSolutionPanel extends JPanel
@Override @Override
public void newGraphLoaded(Graph graph) { public void newGraphLoaded(Graph graph) {
for (int i = 0; i < this.solutionSelect.getItemCount(); ++i) {
PathOverlay overlay = this.solutionSelect.getItemAt(i).getOverlay();
if (overlay != null) {
overlay.delete();
}
}
this.solutionSelect.removeAllItems(); this.solutionSelect.removeAllItems();
this.currentBundle = null; this.currentBundle = null;
this.setVisible(false); this.setVisible(false);

View File

@ -8,7 +8,6 @@ import java.awt.Image;
import java.awt.event.MouseAdapter; import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent; import java.awt.event.MouseEvent;
import java.awt.event.MouseListener; import java.awt.event.MouseListener;
import java.awt.geom.AffineTransform;
import java.awt.geom.NoninvertibleTransformException; import java.awt.geom.NoninvertibleTransformException;
import java.awt.geom.Point2D; import java.awt.geom.Point2D;
import java.awt.image.BufferedImage; import java.awt.image.BufferedImage;
@ -129,8 +128,7 @@ public class BasicDrawing extends JPanel implements Drawing {
double scale = DEFAULT_MARKER_WIDTH / (double) img.getHeight(); double scale = DEFAULT_MARKER_WIDTH / (double) img.getHeight();
gr.scale(scale, scale); gr.scale(scale, scale);
graphics.drawImage(img, px - img.getWidth() / 2, py - img.getHeight(), graphics.drawImage(img, px - img.getWidth() / 2, py - img.getHeight(), BasicDrawing.this);
BasicDrawing.this);
} }
}; };
@ -279,8 +277,7 @@ public class BasicDrawing extends JPanel implements Drawing {
private Graphics2D graphGraphics = null; private Graphics2D graphGraphics = null;
// List of image for markers // List of image for markers
private List<BasicOverlay> overlays = Collections private List<BasicOverlay> overlays = Collections.synchronizedList(new ArrayList<BasicOverlay>());
.synchronizedList(new ArrayList<BasicOverlay>());
// Mapping DrawingClickListener -> MouseEventListener // Mapping DrawingClickListener -> MouseEventListener
private Map<DrawingClickListener, MouseListener> listenerMapping = new IdentityHashMap<>(); private Map<DrawingClickListener, MouseListener> listenerMapping = new IdentityHashMap<>();
@ -290,14 +287,7 @@ public class BasicDrawing extends JPanel implements Drawing {
* *
*/ */
public BasicDrawing() { public BasicDrawing() {
this.zoomAndPanListener = new ZoomAndPanListener(this, this.zoomAndPanListener = new ZoomAndPanListener(this, ZoomAndPanListener.DEFAULT_MIN_ZOOM_LEVEL, 20, 1.2);
ZoomAndPanListener.DEFAULT_MIN_ZOOM_LEVEL, 20, 1.2);
this.addMouseListener(zoomAndPanListener);
this.addMouseMotionListener(zoomAndPanListener);
this.addMouseWheelListener(zoomAndPanListener);
// Avoid bunch of NullPointerException
this.zoomAndPanListener.setCoordTransform(new AffineTransform());
} }
@Override @Override
@ -347,8 +337,7 @@ public class BasicDrawing extends JPanel implements Drawing {
// Get the point using the inverse transform of the Zoom/Pan object, this gives // Get the point using the inverse transform of the Zoom/Pan object, this gives
// us // us
// a point within the drawing box (between [0, 0] and [width, height]). // a point within the drawing box (between [0, 0] and [width, height]).
Point2D ptDst = this.zoomAndPanListener.getCoordTransform() Point2D ptDst = this.zoomAndPanListener.getCoordTransform().inverseTransform(event.getPoint(), null);
.inverseTransform(event.getPoint(), null);
// Inverse the "projection" on x/y to get longitude and latitude. // Inverse the "projection" on x/y to get longitude and latitude.
double lon = ptDst.getX(); double lon = ptDst.getX();
@ -427,9 +416,9 @@ public class BasicDrawing extends JPanel implements Drawing {
* *
* @param arc Arc to draw. * @param arc Arc to draw.
* @param palette Palette to use to retrieve color and width for arc, or null to * @param palette Palette to use to retrieve color and width for arc, or null to
* use current settings. * use current settings.
*/ */
protected void drawArc(Arc arc, GraphPalette palette) { protected void drawArc(Arc arc, GraphPalette palette, boolean repaint) {
List<Point> pts = arc.getPoints(); List<Point> pts = arc.getPoints();
if (!pts.isEmpty()) { if (!pts.isEmpty()) {
if (palette != null) { if (palette != null) {
@ -450,7 +439,9 @@ public class BasicDrawing extends JPanel implements Drawing {
prev = curr; prev = curr;
} }
} }
this.repaint(); if (repaint) {
this.repaint();
}
} }
/** /**
@ -464,8 +455,8 @@ public class BasicDrawing extends JPanel implements Drawing {
this.clear(); this.clear();
// Find minimum/maximum longitude and latitude. // Find minimum/maximum longitude and latitude.
double minLon = Double.POSITIVE_INFINITY, minLat = Double.POSITIVE_INFINITY, double minLon = Double.POSITIVE_INFINITY, minLat = Double.POSITIVE_INFINITY, maxLon = Double.NEGATIVE_INFINITY,
maxLon = Double.NEGATIVE_INFINITY, maxLat = Double.NEGATIVE_INFINITY; maxLat = Double.NEGATIVE_INFINITY;
for (Node node: graph.getNodes()) { for (Node node: graph.getNodes()) {
Point pt = node.getPoint(); Point pt = node.getPoint();
if (pt.getLatitude() < minLat) { if (pt.getLatitude() < minLat) {
@ -503,8 +494,7 @@ public class BasicDrawing extends JPanel implements Drawing {
} }
// Create the image // Create the image
BufferedImage img = new BufferedImage(this.width, this.height, BufferedImage img = new BufferedImage(this.width, this.height, BufferedImage.TYPE_3BYTE_BGR);
BufferedImage.TYPE_3BYTE_BGR);
this.graphImage = img; this.graphImage = img;
this.graphGraphics = img.createGraphics(); this.graphGraphics = img.createGraphics();
this.graphGraphics.setBackground(Color.WHITE); this.graphGraphics.setBackground(Color.WHITE);
@ -512,12 +502,10 @@ public class BasicDrawing extends JPanel implements Drawing {
// Set the zoom and pan listener // Set the zoom and pan listener
double scale = 1 / Math.max(this.width / (double) this.getWidth(), double scale = 1 / Math.max(this.width / (double) this.getWidth(), this.height / (double) this.getHeight());
this.height / (double) this.getHeight());
this.zoomAndPanListener.setCoordTransform(this.graphGraphics.getTransform()); this.zoomAndPanListener.setCoordTransform(this.graphGraphics.getTransform());
this.zoomAndPanListener.getCoordTransform().translate( this.zoomAndPanListener.getCoordTransform().translate((this.getWidth() - this.width * scale) / 2,
(this.getWidth() - this.width * scale) / 2,
(this.getHeight() - this.height * scale) / 2); (this.getHeight() - this.height * scale) / 2);
this.zoomAndPanListener.getCoordTransform().scale(scale, scale); this.zoomAndPanListener.getCoordTransform().scale(scale, scale);
this.zoomAndPanListener.setZoomLevel(0); this.zoomAndPanListener.setZoomLevel(0);
@ -528,15 +516,33 @@ public class BasicDrawing extends JPanel implements Drawing {
@Override @Override
public void drawGraph(Graph graph, GraphPalette palette) { public void drawGraph(Graph graph, GraphPalette palette) {
int repaintModulo = graph.getNodes().size() / 100;
// Initialize the buffered image
this.initialize(graph); this.initialize(graph);
// Remove zoom and pan listener
this.removeMouseListener(zoomAndPanListener);
this.removeMouseMotionListener(zoomAndPanListener);
this.removeMouseWheelListener(zoomAndPanListener);
for (Node node: graph.getNodes()) { for (Node node: graph.getNodes()) {
for (Arc arc: node.getSuccessors()) { for (Arc arc: node.getSuccessors()) {
if (arc.getRoadInformation().isOneWay() if (arc.getRoadInformation().isOneWay() || arc.getOrigin().compareTo(arc.getDestination()) < 0) {
|| arc.getOrigin().compareTo(arc.getDestination()) < 0) { drawArc(arc, palette, false);
drawArc(arc, palette);
} }
} }
if (node.getId() % repaintModulo == 0) {
this.repaint();
}
} }
this.repaint();
// Re-add zoom and pan listener
this.addMouseListener(zoomAndPanListener);
this.addMouseMotionListener(zoomAndPanListener);
this.addMouseWheelListener(zoomAndPanListener);
} }
@Override @Override