diff --git a/src/main/org/insa/graphics/BlockingActionListener.java b/src/main/org/insa/graphics/BlockingActionListener.java new file mode 100644 index 0000000..8539d78 --- /dev/null +++ b/src/main/org/insa/graphics/BlockingActionListener.java @@ -0,0 +1,14 @@ +package org.insa.graphics; + +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; + +public abstract class BlockingActionListener implements ActionListener { + + @Override + public void actionPerformed(ActionEvent e) { + this.actionAccepted(e); + } + + public abstract void actionAccepted(ActionEvent e); +} diff --git a/src/main/org/insa/graphics/MainWindow.java b/src/main/org/insa/graphics/MainWindow.java index b668efb..5678bfe 100644 --- a/src/main/org/insa/graphics/MainWindow.java +++ b/src/main/org/insa/graphics/MainWindow.java @@ -49,7 +49,6 @@ import org.insa.algo.weakconnectivity.WeaklyConnectedComponentsData; 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; @@ -59,7 +58,6 @@ import org.insa.graph.io.Openfile; import org.insa.graphics.drawing.BasicDrawing; import org.insa.graphics.drawing.BlackAndWhiteGraphPalette; import org.insa.graphics.drawing.Drawing; -import org.insa.graphics.drawing.DrawingClickListener; import org.insa.graphics.drawing.MapViewDrawing; public class MainWindow extends JFrame { @@ -88,63 +86,6 @@ public class MainWindow extends JFrame { }; - 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(); - } - } - }; - /** * */ @@ -168,7 +109,7 @@ public class MainWindow extends JFrame { // Drawing and click adapter. private Drawing drawing; - private MultiPointsClickListener clickAdapter; + private MultiPointsClickListener clickAdapter = null; // Main panel. private JSplitPane mainPanel; @@ -220,8 +161,7 @@ public class MainWindow extends JFrame { this.drawing = new BasicDrawing(); // Click adapter - this.clickAdapter = new MultiPointsClickListener(); - this.drawing.addDrawingClickListener(this.clickAdapter); + addDrawingClickListeners(); JTextArea infoPanel = new JTextArea(); infoPanel.setMinimumSize(new Dimension(200, 50)); @@ -300,6 +240,11 @@ public class MainWindow extends JFrame { }); } + private void addDrawingClickListeners() { + this.clickAdapter = new MultiPointsClickListener(graph, drawing); + drawing.addDrawingClickListener(this.clickAdapter); + } + private void updateDrawing(Class newClass) { drawing.clear(); @@ -310,7 +255,7 @@ public class MainWindow extends JFrame { catch (InstantiationException | IllegalAccessException e) { e.printStackTrace(); } - drawing.addDrawingClickListener(this.clickAdapter); + addDrawingClickListeners(); } mainPanel.setLeftComponent((Component) drawing); } @@ -320,9 +265,9 @@ public class MainWindow extends JFrame { // 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() { + openMapItem.addActionListener(new BlockingActionListener() { @Override - public void actionPerformed(ActionEvent e) { + public void actionAccepted(ActionEvent e) { JFileChooser chooser = new JFileChooser(); FileNameExtensionFilter filter = new FileNameExtensionFilter("Map & compressed map files", "map", "map2", "mapgr", "map.gz"); @@ -373,9 +318,9 @@ public class MainWindow extends JFrame { // 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() { + openPathItem.addActionListener(new BlockingActionListener() { @Override - public void actionPerformed(ActionEvent e) { + public void actionAccepted(ActionEvent e) { JFileChooser chooser = new JFileChooser(); FileNameExtensionFilter filter = new FileNameExtensionFilter("Path & compressed path files", "path", "path.gz"); @@ -411,9 +356,9 @@ public class MainWindow extends JFrame { // Close item JMenuItem closeItem = new JMenuItem("Quit", KeyEvent.VK_Q); closeItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_Q, ActionEvent.ALT_MASK)); - closeItem.addActionListener(new ActionListener() { + closeItem.addActionListener(new BlockingActionListener() { @Override - public void actionPerformed(ActionEvent e) { + public void actionAccepted(ActionEvent e) { MainWindow.this.dispatchEvent(new WindowEvent(MainWindow.this, WindowEvent.WINDOW_CLOSING)); } }); @@ -428,9 +373,9 @@ public class MainWindow extends JFrame { // Second menu JMenuItem drawGraphItem = new JMenuItem("Redraw", KeyEvent.VK_R); drawGraphItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_R, ActionEvent.ALT_MASK)); - drawGraphItem.addActionListener(new ActionListener() { + drawGraphItem.addActionListener(new BlockingActionListener() { @Override - public void actionPerformed(ActionEvent e) { + public void actionAccepted(ActionEvent e) { launchThread(new Runnable() { @Override public void run() { @@ -443,9 +388,9 @@ public class MainWindow extends JFrame { 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() { + drawGraphBWItem.addActionListener(new BlockingActionListener() { @Override - public void actionPerformed(ActionEvent e) { + public void actionAccepted(ActionEvent e) { launchThread(new Runnable() { @Override public void run() { @@ -458,9 +403,9 @@ 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.addActionListener(new ActionListener() { + drawGraphMapsforgeItem.addActionListener(new BlockingActionListener() { @Override - public void actionPerformed(ActionEvent e) { + public void actionAccepted(ActionEvent e) { launchThread(new Runnable() { @Override public void run() { @@ -483,9 +428,9 @@ public class MainWindow extends JFrame { // Weakly connected components JMenuItem wccItem = new JMenuItem("Weakly Connected Components"); - wccItem.addActionListener(new ActionListener() { + wccItem.addActionListener(new BlockingActionListener() { @Override - public void actionPerformed(ActionEvent e) { + public void actionAccepted(ActionEvent e) { WeaklyConnectedComponentsData instance = new WeaklyConnectedComponentsData(graph); WeaklyConnectedComponentsAlgorithm algo = new WeaklyConnectedComponentsAlgorithm(instance); algo.addObserver(new WeaklyConnectedComponentGraphicObserver(drawing)); @@ -501,9 +446,9 @@ public class MainWindow extends JFrame { // Shortest path JMenuItem bellmanItem = new JMenuItem("Shortest Path (Bellman-Ford)"); - bellmanItem.addActionListener(new ActionListener() { + bellmanItem.addActionListener(new BlockingActionListener() { @Override - public void actionPerformed(ActionEvent e) { + public void actionAccepted(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); diff --git a/src/main/org/insa/graphics/MultiPointsClickListener.java b/src/main/org/insa/graphics/MultiPointsClickListener.java new file mode 100644 index 0000000..7656768 --- /dev/null +++ b/src/main/org/insa/graphics/MultiPointsClickListener.java @@ -0,0 +1,79 @@ +package org.insa.graphics; + +import java.awt.Color; +import java.util.ArrayList; + +import org.insa.graph.Graph; +import org.insa.graph.Node; +import org.insa.graph.Point; +import org.insa.graphics.MainWindow.CallableWithNodes; +import org.insa.graphics.drawing.Drawing; +import org.insa.graphics.drawing.DrawingClickListener; + +public 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; + + // Graph + private final Graph graph; + + // Drawing + private final Drawing drawing; + + public MultiPointsClickListener(Graph graph, Drawing drawing) { + this.graph = graph; + this.drawing = drawing; + } + + /** + * @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); + if (points.size() == nTargetPoints) { + callable.call(points); + this.disable(); + } + } + +} diff --git a/src/main/org/insa/graphics/drawing/MapViewDrawing.java b/src/main/org/insa/graphics/drawing/MapViewDrawing.java index 72d54d0..f714d17 100644 --- a/src/main/org/insa/graphics/drawing/MapViewDrawing.java +++ b/src/main/org/insa/graphics/drawing/MapViewDrawing.java @@ -1,8 +1,6 @@ package org.insa.graphics.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; @@ -17,10 +15,9 @@ import org.insa.graph.Graph; import org.insa.graph.Path; import org.insa.graph.Point; import org.insa.graphics.drawing.utils.MarkerUtils; +import org.insa.graphics.drawing.utils.PolylineAutoScaling; 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; @@ -60,80 +57,14 @@ public class MapViewDrawing extends MapView implements Drawing { // 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<>(); + // Tile size + private int tileSize; 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; + this.tileSize = DEFAULT_TILE_SIZE; + model.setFixedTileSize(this.tileSize); } /** @@ -207,7 +138,6 @@ public class MapViewDrawing extends MapView implements Drawing { @Override public void clear() { getLayerManager().getLayers().clear(); - extraLayers.clear(); repaint(); } @@ -223,8 +153,7 @@ public class MapViewDrawing extends MapView implements Drawing { @Override public void drawLine(Point from, Point to, int width, Color color) { - Paint paintStroke = createPaintStroke(width, color); - Polyline line = new Polyline(paintStroke, AwtGraphicFactory.INSTANCE); + Polyline line = new PolylineAutoScaling(width, color); line.getLatLongs().add(convertPoint(from)); line.getLatLongs().add(convertPoint(to)); getLayerManager().getLayers().add(line); @@ -281,16 +210,11 @@ public class MapViewDrawing extends MapView implements Drawing { @Override public void drawPath(Path path, Color color, boolean markers) { - Paint paintStroke = createPaintStroke(1, DEFAULT_PATH_COLOR); - Polyline line = new Polyline(paintStroke, AwtGraphicFactory.INSTANCE); + PolylineAutoScaling line = new PolylineAutoScaling(1, DEFAULT_PATH_COLOR); 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())); - } + line.add(arc.getPoints()); } 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); diff --git a/src/main/org/insa/graphics/drawing/utils/PaintUtils.java b/src/main/org/insa/graphics/drawing/utils/PaintUtils.java new file mode 100644 index 0000000..8c024cf --- /dev/null +++ b/src/main/org/insa/graphics/drawing/utils/PaintUtils.java @@ -0,0 +1,35 @@ +package org.insa.graphics.drawing.utils; + +import java.awt.Color; + +import org.mapsforge.core.graphics.GraphicFactory; +import org.mapsforge.map.awt.graphics.AwtGraphicFactory; + +public class PaintUtils { + + // Graphic factory. + private static final GraphicFactory GRAPHIC_FACTORY = AwtGraphicFactory.INSTANCE; + + /** + * @param color + * @return + */ + public static int convertColor(Color color) { + return GRAPHIC_FACTORY.createColor(color.getAlpha(), color.getRed(), color.getGreen(), color.getBlue()); + } + + /** + * @param width + * @return + */ + public static int getStrokeWidth(int width, byte zoomLevel) { + int mul = 2; + if (zoomLevel < 8) { + mul = 1; + } + else { + mul += 2 * (zoomLevel - 8) / 3; + } + return width * mul; + } +} diff --git a/src/main/org/insa/graphics/drawing/utils/PolylineAutoScaling.java b/src/main/org/insa/graphics/drawing/utils/PolylineAutoScaling.java new file mode 100644 index 0000000..ed6992f --- /dev/null +++ b/src/main/org/insa/graphics/drawing/utils/PolylineAutoScaling.java @@ -0,0 +1,58 @@ +package org.insa.graphics.drawing.utils; + +import java.awt.Color; +import java.util.ArrayList; + +import org.insa.graph.Point; +import org.mapsforge.core.graphics.Canvas; +import org.mapsforge.core.graphics.GraphicFactory; +import org.mapsforge.core.model.BoundingBox; +import org.mapsforge.core.model.LatLong; +import org.mapsforge.map.awt.graphics.AwtGraphicFactory; +import org.mapsforge.map.layer.overlay.Polyline; + +public class PolylineAutoScaling extends Polyline { + + // Graphic factory. + private static final GraphicFactory GRAPHIC_FACTORY = AwtGraphicFactory.INSTANCE; + + // Original width of the polyline. + private final int width; + + /** + * @param width + * @param color + */ + public PolylineAutoScaling(int width, Color color) { + super(GRAPHIC_FACTORY.createPaint(), GRAPHIC_FACTORY); + getPaintStroke().setColor(PaintUtils.convertColor(color)); + this.width = width; + } + + /** + * @param point + */ + public void add(Point point) { + getLatLongs().add(new LatLong(point.getLatitude(), point.getLongitude())); + } + + /** + * @param points + */ + public void add(ArrayList points) { + for (Point point: points) { + add(point); + } + } + + @Override + public synchronized void draw(BoundingBox boundingBox, byte zoomLevel, Canvas canvas, + org.mapsforge.core.model.Point topLeftPoint) { + + // Update paint stroke with width for level + this.getPaintStroke().setStrokeWidth(PaintUtils.getStrokeWidth(width, zoomLevel)); + + super.draw(boundingBox, zoomLevel, canvas, topLeftPoint); + } + +}