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.graph.Graph;
import org.insa.graph.Path;
import org.insa.graph.io.BinaryGraphReaderInsa2016;
import org.insa.graph.io.BinaryGraphReaderInsa2018;
import org.insa.graph.io.BinaryPathReader;
import org.insa.graph.io.GraphReader;
@ -144,19 +143,17 @@ public class MainWindow extends JFrame {
@Override
public void actionPerformed(ActionEvent e) {
StartActionEvent evt = (StartActionEvent) e;
ShortestPathData data = new ShortestPathData(graph, evt.getOrigin(),
evt.getDestination(), evt.getMode());
ShortestPathData data = new ShortestPathData(graph, evt.getOrigin(), evt.getDestination(),
evt.getMode());
ShortestPathAlgorithm spAlgorithm = null;
try {
spAlgorithm = ShortestPathAlgorithmFactory
.createAlgorithm(evt.getAlgorithmClass(), data);
spAlgorithm = ShortestPathAlgorithmFactory.createAlgorithm(evt.getAlgorithmClass(), data);
}
catch (Exception e1) {
JOptionPane.showMessageDialog(MainWindow.this,
"An error occurred while creating the specified algorithm.",
"Internal error: Algorithm instantiation failure",
JOptionPane.ERROR_MESSAGE);
"Internal error: Algorithm instantiation failure", JOptionPane.ERROR_MESSAGE);
e1.printStackTrace();
return;
}
@ -341,14 +338,12 @@ public class MainWindow extends JFrame {
// We need to draw MapView, we have to check if the file exists.
File mfile = null;
if (isMapView) {
String mfpath = graphFilePath.substring(0, graphFilePath.lastIndexOf(".map"))
+ ".mapfg";
String mfpath = graphFilePath.substring(0, graphFilePath.lastIndexOf(".map")) + ".mapfg";
mfile = new File(mfpath);
if (!mfile.exists()) {
if (JOptionPane.showConfirmDialog(this,
"The associated mapsforge (.mapfg) file has not been found, do you want to specify it manually?",
"File not found",
JOptionPane.YES_NO_CANCEL_OPTION) == JOptionPane.YES_OPTION) {
"File not found", JOptionPane.YES_NO_CANCEL_OPTION) == JOptionPane.YES_OPTION) {
JFileChooser chooser = new JFileChooser(mfile.getParentFile());
if (chooser.showOpenDialog(this) == JFileChooser.APPROVE_OPTION) {
mfile = chooser.getSelectedFile();
@ -418,16 +413,15 @@ public class MainWindow extends JFrame {
reader.addObserver(progressBar);
try {
graph = reader.read();
System.out.flush();
}
catch (Exception exception) {
progressBar.setVisible(false);
progressBar = null;
JOptionPane.showMessageDialog(MainWindow.this,
"Unable to read graph from the selected file.");
JOptionPane.showMessageDialog(MainWindow.this, "Unable to read graph from the selected file.");
exception.printStackTrace(System.out);
return;
}
notifyNewGraphLoaded();
String info = graph.getMapId();
if (graph.getMapName() != null && !graph.getMapName().isEmpty()) {
@ -435,8 +429,11 @@ public class MainWindow extends JFrame {
}
info += ", " + graph.getNodes().size() + " nodes";
graphInfoPanel.setText(info);
drawGraph();
notifyNewGraphLoaded();
for (JMenuItem item: graphLockItems) {
item.setEnabled(true);
}
@ -453,8 +450,7 @@ public class MainWindow extends JFrame {
@Override
public void actionPerformed(ActionEvent e) {
JFileChooser chooser = new JFileChooser();
FileNameExtensionFilter filter = new FileNameExtensionFilter("Graph files",
"mapgr");
FileNameExtensionFilter filter = new FileNameExtensionFilter("Graph files", "mapgr");
chooser.setCurrentDirectory(new File(System.getProperty("user.dir")));
chooser.setFileFilter(filter);
if (chooser.showOpenDialog(MainWindow.this) == JFileChooser.APPROVE_OPTION) {
@ -462,12 +458,11 @@ public class MainWindow extends JFrame {
DataInputStream stream;
try {
stream = new DataInputStream(new BufferedInputStream(
new FileInputStream(chooser.getSelectedFile())));
stream = new DataInputStream(
new BufferedInputStream(new FileInputStream(chooser.getSelectedFile())));
}
catch (IOException e1) {
JOptionPane.showMessageDialog(MainWindow.this,
"Cannot open the selected file.");
JOptionPane.showMessageDialog(MainWindow.this, "Cannot open the selected file.");
return;
}
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...
JMenuItem openPathItem = new JMenuItem("Open Path... ", KeyEvent.VK_P);
openPathItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_P, ActionEvent.ALT_MASK));
@ -510,19 +478,18 @@ public class MainWindow extends JFrame {
@Override
public void actionPerformed(ActionEvent e) {
JFileChooser chooser = new JFileChooser();
FileNameExtensionFilter filter = new FileNameExtensionFilter(
"Path & compressed path files", "path", "path.gz");
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(new DataInputStream(new BufferedInputStream(
new FileInputStream(chooser.getSelectedFile()))));
reader = new BinaryPathReader(new DataInputStream(
new BufferedInputStream(new FileInputStream(chooser.getSelectedFile()))));
}
catch (IOException e1) {
JOptionPane.showMessageDialog(MainWindow.this,
"Cannot open the selected file.");
JOptionPane.showMessageDialog(MainWindow.this, "Cannot open the selected file.");
return;
}
try {
@ -535,8 +502,7 @@ public class MainWindow extends JFrame {
return;
}
catch (Exception exception) {
JOptionPane.showMessageDialog(MainWindow.this,
"Unable to read path from the selected file.");
JOptionPane.showMessageDialog(MainWindow.this, "Unable to read path from the selected file.");
return;
}
}
@ -550,15 +516,13 @@ public class MainWindow extends JFrame {
closeItem.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
MainWindow.this.dispatchEvent(
new WindowEvent(MainWindow.this, WindowEvent.WINDOW_CLOSING));
MainWindow.this.dispatchEvent(new WindowEvent(MainWindow.this, WindowEvent.WINDOW_CLOSING));
}
});
// Build the first menu.
JMenu fileMenu = new JMenu("File");
fileMenu.add(openMapItem);
fileMenu.add(openOldMapItem); // TODO: Remove this for Students.
fileMenu.add(openPathItem);
fileMenu.addSeparator();
fileMenu.add(closeItem);
@ -593,8 +557,7 @@ public class MainWindow extends JFrame {
}));
graphLockItems.add(drawGraphBWItem);
JMenuItem drawGraphMapsforgeItem = new JMenuItem("Redraw (Map)", KeyEvent.VK_M);
drawGraphMapsforgeItem
.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_M, ActionEvent.ALT_MASK));
drawGraphMapsforgeItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_M, ActionEvent.ALT_MASK));
drawGraphMapsforgeItem.addActionListener(baf.createBlockingAction(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
@ -669,8 +632,7 @@ public class MainWindow extends JFrame {
private JPanel createStatusBar() {
// create the status bar panel and shove it down the bottom of the frame
JPanel statusPanel = new JPanel();
statusPanel.setBorder(
new CompoundBorder(BorderFactory.createMatteBorder(1, 0, 0, 0, Color.GRAY),
statusPanel.setBorder(new CompoundBorder(BorderFactory.createMatteBorder(1, 0, 0, 0, Color.GRAY),
new EmptyBorder(0, 15, 0, 15)));
statusPanel.setPreferredSize(new Dimension(getWidth(), 38));
statusPanel.setLayout(new BorderLayout());
@ -688,8 +650,8 @@ public class MainWindow extends JFrame {
public void actionPerformed(ActionEvent e) {
if (currentThread.isRunning()) {
int confirmed = JOptionPane.showConfirmDialog(MainWindow.this,
"Are you sure you want to kill the running thread?",
"Kill Confirmation", JOptionPane.YES_NO_OPTION);
"Are you sure you want to kill the running thread?", "Kill Confirmation",
JOptionPane.YES_NO_OPTION);
if (confirmed == JOptionPane.YES_OPTION) {
currentThread.interrupt();
}
@ -701,8 +663,8 @@ public class MainWindow extends JFrame {
@Override
public void actionPerformed(ActionEvent e) {
long seconds = currentThread.getDuration().getSeconds();
threadTimerLabel.setText(String.format("%02d:%02d:%02d", seconds / 3600,
seconds / 60 % 60, seconds % 60));
threadTimerLabel
.setText(String.format("%02d:%02d:%02d", seconds / 3600, seconds / 60 % 60, seconds % 60));
}
});
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;
/**
* 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 {
/**
@ -77,6 +121,7 @@ public class NodesInputPanel extends JPanel
// Drawing and graph
private Drawing drawing;
private Graph graph;
private NodeFinder nodeFinder;
/**
* @param drawing Original drawing used (see {@link:newDrawingLoaded}).
@ -316,7 +361,7 @@ public class NodesInputPanel extends JPanel
public void mouseClicked(Point point) {
JTextField input = getInputToFill();
if (input != null) {
Node node = graph.findClosestNode(point);
Node node = nodeFinder.findClosestNode(point);
input.setText(String.valueOf(node.getId()));
nextInputToFill();
}
@ -328,6 +373,8 @@ public class NodesInputPanel extends JPanel
this.clear();
this.graph = graph;
nodeFinder = new NodeFinder(graph);
// Disable if previously disabled...
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.overlays.PathOverlay;
public class ShortestPathSolutionPanel extends JPanel
implements DrawingChangeListener, GraphChangeListener {
public class ShortestPathSolutionPanel extends JPanel implements DrawingChangeListener, GraphChangeListener {
/**
*
@ -98,12 +97,13 @@ public class ShortestPathSolutionPanel extends JPanel
/*
* (non-Javadoc)
*
* @see java.lang.Object#toString()
*/
public String toString() {
return "Shortest-path from #" + this.getData().getOrigin().getId() + " to #"
+ this.getData().getDestination().getId() + " ["
+ this.getData().getMode().toString().toLowerCase() + "]";
+ this.getData().getDestination().getId() + " [" + this.getData().getMode().toString().toLowerCase()
+ "]";
}
}
@ -167,10 +167,9 @@ public class ShortestPathSolutionPanel extends JPanel
@Override
public void actionPerformed(ActionEvent e) {
String filepath = System.getProperty("user.dir");
filepath += File.separator + String.format("path_%#x_%d_%d.path",
currentBundle.getData().getGraph().getMapId(),
currentBundle.getData().getOrigin().getId(),
currentBundle.getData().getDestination().getId());
filepath += File.separator + String.format("path_%s_%d_%d.path",
currentBundle.getData().getGraph().getMapId().toLowerCase().replaceAll("[^a-z0-9_]", "_"),
currentBundle.getData().getOrigin().getId(), currentBundle.getData().getDestination().getId());
JFileChooser fileChooser = new JFileChooser();
fileChooser.setSelectedFile(new File(filepath));
fileChooser.setApproveButtonText("Save");
@ -178,13 +177,12 @@ public class ShortestPathSolutionPanel extends JPanel
if (fileChooser.showOpenDialog(parent) == JFileChooser.APPROVE_OPTION) {
File file = fileChooser.getSelectedFile();
try {
BinaryPathWriter writer = new BinaryPathWriter(new DataOutputStream(
new BufferedOutputStream(new FileOutputStream(file))));
BinaryPathWriter writer = new BinaryPathWriter(
new DataOutputStream(new BufferedOutputStream(new FileOutputStream(file))));
writer.writePath(currentBundle.getSolution().getPath());
}
catch (IOException e1) {
JOptionPane.showMessageDialog(parent,
"Unable to write path to the selected file.");
JOptionPane.showMessageDialog(parent, "Unable to write path to the selected file.");
e1.printStackTrace();
}
}
@ -237,8 +235,8 @@ public class ShortestPathSolutionPanel extends JPanel
ShortestPathData data = bundle.getData();
String info = null;
if (!bundle.getSolution().isFeasible()) {
info = String.format("No path found from node #%d to node #%d.",
data.getOrigin().getId(), data.getDestination().getId());
info = String.format("No path found from node #%d to node #%d.", data.getOrigin().getId(),
data.getDestination().getId());
}
else {
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
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.currentBundle = null;
this.setVisible(false);

View File

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