Fix issue with MapViewDrawing and generalize ClickListener for all Drawings.

This commit is contained in:
Holt59 2018-02-23 23:21:21 +01:00
parent 24eeab7971
commit 9db2ee36dd
11 changed files with 1592 additions and 1689 deletions

View File

@ -53,17 +53,11 @@
<attribute name="javadoc_location" value="jar:platform:/resource/be-graphes-base/libs/mapsforge-poi-awt-0.9.1-javadoc.jar!/"/> <attribute name="javadoc_location" value="jar:platform:/resource/be-graphes-base/libs/mapsforge-poi-awt-0.9.1-javadoc.jar!/"/>
</attributes> </attributes>
</classpathentry> </classpathentry>
<classpathentry kind="lib" path="libs/mapsforge-themes-0.9.1.jar">
<attributes>
<attribute name="javadoc_location" value="jar:platform:/resource/be-graphes-base/libs/mapsforge-themes-0.9.1-javadoc.jar!/"/>
</attributes>
</classpathentry>
<classpathentry kind="lib" path="libs/kxml2-2.3.0.jar"/> <classpathentry kind="lib" path="libs/kxml2-2.3.0.jar"/>
<classpathentry kind="lib" path="libs/svg-salamander-1.0.jar"> <classpathentry kind="lib" path="libs/svg-salamander-1.0.jar">
<attributes> <attributes>
<attribute name="javadoc_location" value="jar:platform:/resource/be-graphes-base/libs/svg-salamander-1.0-javadoc.jar!/"/> <attribute name="javadoc_location" value="jar:platform:/resource/be-graphes-base/libs/svg-salamander-1.0-javadoc.jar!/"/>
</attributes> </attributes>
</classpathentry> </classpathentry>
<classpathentry kind="lib" path="libs/mapsforge-map-writer-0.9.1-jar-with-dependencies.jar"/>
<classpathentry kind="output" path="target/classes"/> <classpathentry kind="output" path="target/classes"/>
</classpath> </classpath>

View File

@ -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

View File

@ -0,0 +1,4 @@
activeProfiles=
eclipse.preferences.version=1
resolveWorkspaceProjects=true
version=1

View File

@ -8,32 +8,30 @@ import org.insa.graph.Node;
public class WeaklyConnectedComponentGraphicObserver implements WeaklyConnectedComponentObserver { public class WeaklyConnectedComponentGraphicObserver implements WeaklyConnectedComponentObserver {
private static final Color[] COLORS = { private static final Color[] COLORS = { Color.BLUE, Color.ORANGE, Color.GREEN, Color.YELLOW, Color.RED };
Color.BLUE, Color.ORANGE, Color.GREEN, Color.YELLOW, Color.RED
};
// Drawing + Graph drawing // Drawing + Graph drawing
private Drawing drawing; private Drawing drawing;
// Current index color // Current index color
private int cindex = -1; private int cindex = -1;
public WeaklyConnectedComponentGraphicObserver(Drawing drawing) { public WeaklyConnectedComponentGraphicObserver(Drawing drawing) {
this.drawing = drawing; this.drawing = drawing;
} }
@Override @Override
public void notifyStartComponent(Node curNode) { public void notifyStartComponent(Node curNode) {
cindex = (cindex + 1) % COLORS.length; cindex = (cindex + 1) % COLORS.length;
} }
@Override @Override
public void notifyNewNodeInComponent(Node node) { public void notifyNewNodeInComponent(Node node) {
this.drawing.drawMarker(node.getPoint(), COLORS[cindex]); this.drawing.drawPoint(node.getPoint(), 1, COLORS[cindex]);
} }
@Override @Override
public void notifyEndComponent(ArrayList<Node> nodes) { public void notifyEndComponent(ArrayList<Node> nodes) {
} }
} }

View File

@ -7,11 +7,8 @@ import java.awt.Dimension;
import java.awt.event.ActionEvent; import java.awt.event.ActionEvent;
import java.awt.event.ActionListener; import java.awt.event.ActionListener;
import java.awt.event.KeyEvent; import java.awt.event.KeyEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.WindowAdapter; import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent; import java.awt.event.WindowEvent;
import java.awt.geom.NoninvertibleTransformException;
import java.io.DataInputStream; import java.io.DataInputStream;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
@ -52,6 +49,7 @@ import org.insa.algo.weakconnectivity.WeaklyConnectedComponentsData;
import org.insa.drawing.BasicDrawing; import org.insa.drawing.BasicDrawing;
import org.insa.drawing.BlackAndWhiteGraphPalette; import org.insa.drawing.BlackAndWhiteGraphPalette;
import org.insa.drawing.Drawing; import org.insa.drawing.Drawing;
import org.insa.drawing.DrawingClickListener;
import org.insa.drawing.MapViewDrawing; import org.insa.drawing.MapViewDrawing;
import org.insa.graph.Graph; import org.insa.graph.Graph;
import org.insa.graph.Node; import org.insa.graph.Node;
@ -90,7 +88,7 @@ public class MainWindow extends JFrame {
}; };
protected class DrawingClickListener extends MouseAdapter { protected class MultiPointsClickListener implements DrawingClickListener {
// Enable/Disable. // Enable/Disable.
private boolean enabled = false; private boolean enabled = false;
@ -114,7 +112,8 @@ public class MainWindow extends JFrame {
/** /**
* Enable this listener. * Enable this listener.
* *
* @param nTargetPoints Number of point to found before calling the callable. * @param nTargetPoints
* Number of point to found before calling the callable.
*/ */
public void enable(int nTargetPoints, CallableWithNodes callable) { public void enable(int nTargetPoints, CallableWithNodes callable) {
this.enabled = true; this.enabled = true;
@ -130,25 +129,15 @@ public class MainWindow extends JFrame {
this.enabled = false; this.enabled = false;
} }
public void mouseClicked(MouseEvent evt) { @Override
public void mouseClicked(Point lonlat) {
if (!isEnabled()) { if (!isEnabled()) {
return; 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); Node node = graph.findClosestNode(lonlat);
drawing.drawMarker(node.getPoint(), Color.BLUE); drawing.drawMarker(node.getPoint(), Color.BLUE);
points.add(node); points.add(node);
System.out.println("Click at " + lonlat + ", " + points.size() + "/" + nTargetPoints + " in array.");
if (points.size() == nTargetPoints) { if (points.size() == nTargetPoints) {
callable.call(points); callable.call(points);
this.disable(); this.disable();
@ -179,7 +168,7 @@ public class MainWindow extends JFrame {
// Drawing and click adapter. // Drawing and click adapter.
private Drawing drawing; private Drawing drawing;
private DrawingClickListener clickAdapter; private MultiPointsClickListener clickAdapter;
// Main panel. // Main panel.
private JSplitPane mainPanel; private JSplitPane mainPanel;
@ -215,9 +204,8 @@ public class MainWindow extends JFrame {
addWindowListener(new WindowAdapter() { addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) { public void windowClosing(WindowEvent e) {
int confirmed = JOptionPane.showConfirmDialog(null, int confirmed = JOptionPane.showConfirmDialog(null, "Are you sure you want to close the application?",
"Are you sure you want to close the application?", "Exit Confirmation", "Exit Confirmation", JOptionPane.YES_NO_OPTION);
JOptionPane.YES_NO_OPTION);
if (confirmed == JOptionPane.YES_OPTION) { if (confirmed == JOptionPane.YES_OPTION) {
dispose(); dispose();
@ -229,19 +217,14 @@ public class MainWindow extends JFrame {
// Create graph area // Create graph area
mainPanel = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT); mainPanel = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT);
BasicDrawing drawing = new BasicDrawing(); this.drawing = new BasicDrawing();
// MapViewDrawing drawing = new MapViewDrawing();
Component drawingComponent = drawing;
this.drawing = drawing;
// Click adapter // Click adapter
this.clickAdapter = new DrawingClickListener(); this.clickAdapter = new MultiPointsClickListener();
// drawing.addMouseListener(this.clickAdapter); this.drawing.addDrawingClickListener(this.clickAdapter);
JTextArea infoPanel = new JTextArea(); JTextArea infoPanel = new JTextArea();
infoPanel.setMinimumSize(new Dimension(200, 50)); infoPanel.setMinimumSize(new Dimension(200, 50));
// infoPanel.setBorder(BorderFactory.createMatteBorder(0, 1, 0, 0, Color.GRAY));
infoPanel.setBackground(Color.WHITE); infoPanel.setBackground(Color.WHITE);
infoPanel.setLineWrap(true); infoPanel.setLineWrap(true);
infoPanel.setEditable(false); infoPanel.setEditable(false);
@ -253,8 +236,8 @@ public class MainWindow extends JFrame {
mainPanel.setDividerSize(5); mainPanel.setDividerSize(5);
mainPanel.setBackground(Color.WHITE); mainPanel.setBackground(Color.WHITE);
mainPanel.add(drawingComponent); mainPanel.setLeftComponent((Component) this.drawing);
mainPanel.add(new JScrollPane(infoPanel)); mainPanel.setRightComponent(new JScrollPane(infoPanel));
this.add(mainPanel, BorderLayout.CENTER); this.add(mainPanel, BorderLayout.CENTER);
// Top Panel // Top Panel
@ -317,6 +300,21 @@ public class MainWindow extends JFrame {
}); });
} }
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() { private JMenuBar createMenuBar() {
// Open Map item... // Open Map item...
@ -326,8 +324,8 @@ 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("Map & compressed map files", "map",
"Map & compressed map files", "map", "map2", "mapgr", "map.gz"); "map2", "mapgr", "map.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) {
@ -340,8 +338,7 @@ public class MainWindow extends JFrame {
stream = Openfile.open(path); stream = Openfile.open(path);
} }
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;
} }
AbstractGraphReader reader; AbstractGraphReader reader;
@ -366,8 +363,7 @@ public class MainWindow extends JFrame {
for (JMenuItem item: graphLockItems) { for (JMenuItem item: graphLockItems) {
item.setEnabled(true); item.setEnabled(true);
} }
mapIdPanel mapIdPanel.setText("Map ID: 0x" + Integer.toHexString(graph.getMapId()));
.setText("Map ID: 0x" + Integer.toHexString(graph.getMapId()));
} }
}, false); }, false);
} }
@ -381,19 +377,17 @@ 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( reader = new BinaryPathReader(Openfile.open(chooser.getSelectedFile().getAbsolutePath()));
Openfile.open(chooser.getSelectedFile().getAbsolutePath()));
} }
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 {
@ -405,8 +399,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;
} }
drawing.drawPath(currentPath); drawing.drawPath(currentPath);
@ -421,8 +414,7 @@ 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));
} }
}); });
@ -442,12 +434,7 @@ public class MainWindow extends JFrame {
launchThread(new Runnable() { launchThread(new Runnable() {
@Override @Override
public void run() { public void run() {
if (!(drawing instanceof BasicDrawing)) { updateDrawing(BasicDrawing.class);
BasicDrawing tmp = new BasicDrawing();
mainPanel.setLeftComponent(tmp);
drawing = tmp;
}
drawing.clear();
drawing.drawGraph(graph); drawing.drawGraph(graph);
} }
}); });
@ -462,12 +449,7 @@ public class MainWindow extends JFrame {
launchThread(new Runnable() { launchThread(new Runnable() {
@Override @Override
public void run() { public void run() {
if (!(drawing instanceof BasicDrawing)) { updateDrawing(BasicDrawing.class);
BasicDrawing tmp = new BasicDrawing();
mainPanel.setLeftComponent(tmp);
drawing = tmp;
}
drawing.clear();
drawing.drawGraph(graph, new BlackAndWhiteGraphPalette()); drawing.drawGraph(graph, new BlackAndWhiteGraphPalette());
} }
}); });
@ -475,21 +457,15 @@ 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(new ActionListener() { drawGraphMapsforgeItem.addActionListener(new ActionListener() {
@Override @Override
public void actionPerformed(ActionEvent e) { public void actionPerformed(ActionEvent e) {
launchThread(new Runnable() { launchThread(new Runnable() {
@Override @Override
public void run() { public void run() {
if (!(drawing instanceof MapViewDrawing)) { updateDrawing(MapViewDrawing.class);
MapViewDrawing tmp = new MapViewDrawing(); drawing.drawGraph(graph);
mainPanel.setLeftComponent(tmp);
drawing = tmp;
}
drawing.clear();
drawing.drawGraph(graph, new BlackAndWhiteGraphPalette());
} }
}); });
} }
@ -511,8 +487,7 @@ public class MainWindow extends JFrame {
@Override @Override
public void actionPerformed(ActionEvent e) { public void actionPerformed(ActionEvent e) {
WeaklyConnectedComponentsData instance = new WeaklyConnectedComponentsData(graph); WeaklyConnectedComponentsData instance = new WeaklyConnectedComponentsData(graph);
WeaklyConnectedComponentsAlgorithm algo = new WeaklyConnectedComponentsAlgorithm( WeaklyConnectedComponentsAlgorithm algo = new WeaklyConnectedComponentsAlgorithm(instance);
instance);
algo.addObserver(new WeaklyConnectedComponentGraphicObserver(drawing)); algo.addObserver(new WeaklyConnectedComponentGraphicObserver(drawing));
// algo.addObserver(new WeaklyConnectedComponentTextObserver(printStream)); // algo.addObserver(new WeaklyConnectedComponentTextObserver(printStream));
launchThread(new Runnable() { launchThread(new Runnable() {
@ -529,9 +504,8 @@ public class MainWindow extends JFrame {
bellmanItem.addActionListener(new ActionListener() { bellmanItem.addActionListener(new ActionListener() {
@Override @Override
public void actionPerformed(ActionEvent e) { public void actionPerformed(ActionEvent e) {
int idx = JOptionPane.showOptionDialog(MainWindow.this, "Which mode do you want?", int idx = JOptionPane.showOptionDialog(MainWindow.this, "Which mode do you want?", "Mode selection",
"Mode selection", JOptionPane.DEFAULT_OPTION, JOptionPane.QUESTION_MESSAGE, JOptionPane.DEFAULT_OPTION, JOptionPane.QUESTION_MESSAGE, null, Mode.values(), Mode.LENGTH);
null, Mode.values(), Mode.LENGTH);
if (idx != -1) { if (idx != -1) {
Mode mode = Mode.values()[idx]; Mode mode = Mode.values()[idx];
@ -596,8 +570,8 @@ public class MainWindow extends JFrame {
public void actionPerformed(ActionEvent e) { public void actionPerformed(ActionEvent e) {
if (currentThread != null && currentThread.isAlive()) { if (currentThread != null && currentThread.isAlive()) {
int confirmed = JOptionPane.showConfirmDialog(null, int confirmed = JOptionPane.showConfirmDialog(null,
"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) {
stopCurrentThread(); stopCurrentThread();
clearCurrentThread(); clearCurrentThread();
@ -612,8 +586,8 @@ public class MainWindow extends JFrame {
public void actionPerformed(ActionEvent e) { public void actionPerformed(ActionEvent e) {
Duration elapsed = Duration.between(threadStartTime, Instant.now()); Duration elapsed = Duration.between(threadStartTime, Instant.now());
long seconds = elapsed.getSeconds(); long seconds = elapsed.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

@ -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 <http://www.gnu.org/licenses/>.
*/
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<File> 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<org.insa.graph.Point> 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<File> 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: <mapFile>");
}
File demFolder = new File(args[0]);
if (demFolder.exists() && demFolder.isDirectory() && demFolder.canRead()) {
return demFolder;
}
return null;
}
private static List<File> getMapFiles(String[] args) {
if (args.length == 0) {
throw new IllegalArgumentException("missing argument: <mapFile>");
}
List<File> 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();
}
}

View File

@ -5,12 +5,16 @@ import java.awt.Color;
import java.awt.Graphics; import java.awt.Graphics;
import java.awt.Graphics2D; import java.awt.Graphics2D;
import java.awt.Image; import java.awt.Image;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent; import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.geom.NoninvertibleTransformException; import java.awt.geom.NoninvertibleTransformException;
import java.awt.geom.Point2D; import java.awt.geom.Point2D;
import java.awt.image.*; import java.awt.image.BufferedImage;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.IdentityHashMap;
import java.util.Iterator; import java.util.Iterator;
import java.util.Map;
import javax.swing.JPanel; import javax.swing.JPanel;
@ -21,294 +25,321 @@ import org.insa.graph.Path;
import org.insa.graph.Point; import org.insa.graph.Point;
/** /**
* Cette implementation de la classe Dessin produit vraiment un affichage * Cette implementation de la classe Dessin produit vraiment un affichage (au
* (au contraire de la classe DessinInvisible). * contraire de la classe DessinInvisible).
*/ */
public class BasicDrawing extends JPanel implements Drawing { public class BasicDrawing extends JPanel implements Drawing {
/** /**
* *
*/ */
private static final long serialVersionUID = 96779785877771827L; private static final long serialVersionUID = 96779785877771827L;
// Default path color. // Default path color.
public static final Color DEFAULT_PATH_COLOR = new Color(255, 0, 255); public static final Color DEFAULT_PATH_COLOR = new Color(255, 0, 255);
// Default palette. // Default palette.
public static final GraphPalette DEFAULT_PALETTE = new BasicGraphPalette(); public static final GraphPalette DEFAULT_PALETTE = new BasicGraphPalette();
// Default marker width // Default marker width
private static final int DEFAULT_MARKER_WIDTH = 10; private static final int DEFAULT_MARKER_WIDTH = 10;
// //
private final Graphics2D gr; private final Graphics2D gr;
private double long1, long2, lat1, lat2; private double long1, long2, lat1, lat2;
// Width and height of the image // Width and height of the image
private final int width, height; private final int width, height;
private Image image; //
private ZoomAndPanListener zoomAndPanListener; private Image image;
private ZoomAndPanListener zoomAndPanListener;
/** // Mapping DrawingClickListener -> MouseEventListener
* Create a new BasicDrawing. private Map<DrawingClickListener, MouseListener> listenerMapping = new IdentityHashMap<>();
*
*/
public BasicDrawing() {
this.zoomAndPanListener = new ZoomAndPanListener(this, ZoomAndPanListener.DEFAULT_MIN_ZOOM_LEVEL, 20, 1.2); /**
this.addMouseListener(zoomAndPanListener); * Create a new BasicDrawing.
this.addMouseMotionListener(zoomAndPanListener); *
this.addMouseWheelListener(zoomAndPanListener); */
public BasicDrawing() {
this.width = 2000; this.zoomAndPanListener = new ZoomAndPanListener(this, ZoomAndPanListener.DEFAULT_MIN_ZOOM_LEVEL, 20, 1.2);
this.height = 1600; this.addMouseListener(zoomAndPanListener);
this.addMouseMotionListener(zoomAndPanListener);
this.addMouseWheelListener(zoomAndPanListener);
BufferedImage img = new BufferedImage(this.width, this.height, BufferedImage.TYPE_3BYTE_BGR); this.width = 2000;
this.height = 1600;
this.image = img; BufferedImage img = new BufferedImage(this.width, this.height, BufferedImage.TYPE_3BYTE_BGR);
this.gr = img.createGraphics();
this.zoomAndPanListener.setCoordTransform(this.gr.getTransform()); this.image = img;
this.gr = img.createGraphics();
this.long1 = -180; this.zoomAndPanListener.setCoordTransform(this.gr.getTransform());
this.long2 = 180;
this.lat1 = -90;
this.lat2 = 90;
this.clear(); this.long1 = -180;
this.repaint(); this.long2 = 180;
this.lat1 = -90;
this.lat2 = 90;
} this.clear();
this.repaint();
@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);
}
protected void setBB(double long1, double long2, double lat1, double 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);
}
if (long1 > long2 || lat1 > lat2) { protected void setBB(double long1, double long2, double lat1, double lat2) {
throw new Error("DessinVisible.setBB : mauvaises coordonnees.");
}
this.long1 = long1; if (long1 > long2 || lat1 > lat2) {
this.long2 = long2; throw new Error("DessinVisible.setBB : mauvaises coordonnees.");
this.lat1= lat1; }
this.lat2 = lat2;
double scale = 1 / Math.max(this.width / (double)this.getWidth(), this.height / (double)this.getHeight()); this.long1 = long1;
this.long2 = long2;
this.lat1 = lat1;
this.lat2 = lat2;
this.zoomAndPanListener.getCoordTransform().setToIdentity(); double scale = 1 / Math.max(this.width / (double) this.getWidth(), this.height / (double) this.getHeight());
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();
} 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) { private int projx(double lon) {
return (int)(height * (1 - (lat - this.lat1) / (this.lat2 - this.lat1))) ; return (int) (width * (lon - this.long1) / (this.long2 - this.long1));
} }
/** private int projy(double lat) {
* Return the longitude and latitude corresponding to the given return (int) (height * (1 - (lat - this.lat1) / (this.lat2 - this.lat1)));
* 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(); * Return the longitude and latitude corresponding to the given position of the
double lat = ptDst.getY(); * MouseEvent.
lon = (lon / this.width) * (this.long2 - this.long1) + this.long1; *
lat = (1 - lat / this.height) * (this.lat2 - this.lat1) + this.lat1; * @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);
// Return a new point. // Inverse the "projection" on x/y to get longitude and latitude.
return new Point(lon, lat); 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;
protected void setWidth(int width) { // Return a new point.
this.gr.setStroke(new BasicStroke(width)); return new Point(lon, lat);
} }
protected void setColor(Color col) { @Override
this.gr.setColor(col); 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 @Override
public void clear() { public void removeDrawingClickListener(DrawingClickListener listener) {
this.gr.setColor(Color.WHITE); this.removeMouseListener(this.listenerMapping.get(listener));
this.gr.fillRect(0, 0, this.width, this.height); }
}
@Override protected void setWidth(int width) {
public void drawLine(Point from, Point to) { this.gr.setStroke(new BasicStroke(width));
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) ; protected void setColor(Color col) {
this.repaint(); this.gr.setColor(col);
} }
@Override @Override
public void drawLine(Point from, Point to, int width) { public void clear() {
setWidth(width); this.gr.setColor(Color.WHITE);
drawLine(from, to); this.gr.fillRect(0, 0, this.width, this.height);
} }
@Override @Override
public void drawLine(Point from, Point to, int width, Color color) { public void drawLine(Point from, Point to) {
setWidth(width); int x1 = this.projx(from.getLongitude());
setColor(color); int x2 = this.projx(to.getLongitude());
drawLine(from, to); int y1 = this.projy(from.getLatitude());
} int y2 = this.projy(to.getLatitude());
@Override gr.drawLine(x1, y1, x2, y2);
public void drawMarker(Point point) { this.repaint();
drawPoint(point, DEFAULT_MARKER_WIDTH, this.gr.getColor()); }
}
@Override
public void drawLine(Point from, Point to, int width) {
setWidth(width);
drawLine(from, to);
}
@Override @Override
public void drawMarker(Point point, Color color) { public void drawLine(Point from, Point to, int width, Color color) {
setColor(color); setWidth(width);
drawMarker(point); setColor(color);
} drawLine(from, to);
}
@Override @Override
public void drawPoint(Point point, int width, Color color) { public void drawMarker(Point point) {
setWidth(width); drawPoint(point, DEFAULT_MARKER_WIDTH, this.gr.getColor());
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();
}
/** @Override
* Draw the given arc. public void drawMarker(Point point, Color color) {
* setColor(color);
* @param arc Arc to draw. drawMarker(point);
* @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<Point> pts = arc.getPoints();
if (!pts.isEmpty()) {
if (palette != null) {
setColor(palette.getColorForType(arc.getInfo().getType()));
setWidth(palette.getWidthForType(arc.getInfo().getType()));
}
Iterator<Point> it1 = pts.iterator();
Point prev = it1.next();
while (it1.hasNext()) {
Point curr = it1.next();
drawLine(prev, curr);
prev = curr;
}
}
}
/** @Override
* Initialize the drawing for the given graph. public void drawPoint(Point point, int width, Color color) {
* setWidth(width);
* @param graph setColor(color);
*/ int x = this.projx(point.getLongitude()) - DEFAULT_MARKER_WIDTH / 2;
public void initialize(Graph graph) { int y = this.projy(point.getLatitude()) - DEFAULT_MARKER_WIDTH / 2;
double minLon = Double.POSITIVE_INFINITY, minLat = Double.POSITIVE_INFINITY, gr.fillOval(x, y, DEFAULT_MARKER_WIDTH, DEFAULT_MARKER_WIDTH);
maxLon = Double.NEGATIVE_INFINITY, maxLat = Double.NEGATIVE_INFINITY; this.repaint();
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); * 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<Point> pts = arc.getPoints();
if (!pts.isEmpty()) {
if (palette != null) {
setColor(palette.getColorForType(arc.getInfo().getType()));
setWidth(palette.getWidthForType(arc.getInfo().getType()));
}
Iterator<Point> it1 = pts.iterator();
Point prev = it1.next();
while (it1.hasNext()) {
Point curr = it1.next();
drawLine(prev, curr);
prev = curr;
}
}
}
setBB(minLon - deltaLon, maxLon + deltaLon, /**
minLat - deltaLat, maxLat + deltaLat); * 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();
}
}
@Override double deltaLon = 0.02 * (maxLon - minLon), deltaLat = 0.02 * (maxLat - minLat);
public void drawGraph(Graph graph, GraphPalette palette) {
clear();
initialize(graph);
for (Node node: graph.getNodes()) {
for (Arc arc: node.getSuccessors()) {
drawArc(arc, palette);
}
}
}
@Override setBB(minLon - deltaLon, maxLon + deltaLon, minLat - deltaLat, maxLat + deltaLat);
public void drawGraph(Graph graph) { }
drawGraph(graph, DEFAULT_PALETTE);
}
@Override @Override
public void drawPath(Path path, Color color, boolean markers) { public void drawGraph(Graph graph, GraphPalette palette) {
setColor(color); clear();
setWidth(2); initialize(graph);
for (Arc arc: path.getArcs()) { for (Node node: graph.getNodes()) {
drawArc(arc, null); for (Arc arc: node.getSuccessors()) {
} drawArc(arc, palette);
if (markers) { }
drawMarker(path.getOrigin().getPoint(), color); }
drawMarker(path.getDestination().getPoint(), color); }
}
}
@Override @Override
public void drawPath(Path path, Color color) { public void drawGraph(Graph graph) {
drawPath(path, color, true); drawGraph(graph, DEFAULT_PALETTE);
} }
@Override @Override
public void drawPath(Path path) { public void drawPath(Path path, Color color, boolean markers) {
drawPath(path, DEFAULT_PATH_COLOR); 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 @Override
public void drawPath(Path path, boolean markers) { public void drawPath(Path path, Color color) {
drawPath(path, DEFAULT_PATH_COLOR, markers); drawPath(path, color, true);
} }
@SuppressWarnings("unused") @Override
private void putText(Point point, String txt) { public void drawPath(Path path) {
int x = this.projx(point.getLongitude()); drawPath(path, DEFAULT_PATH_COLOR);
int y = this.projy(point.getLatitude()); }
gr.drawString(txt, x, y);
this.repaint(); @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();
}
} }

View File

@ -8,112 +8,127 @@ import org.insa.graph.Point;
public interface Drawing { public interface Drawing {
/** /**
* Clear the drawing. * Add a listener to click to this drawing.
*/ *
public void clear(); * @param listener
*/
public void addDrawingClickListener(DrawingClickListener listener);
/** /**
* Draw a line between the two given points with the default color * Remove the given listener from the drawing.
* and width. *
* * @param listener
* @param from */
* @param to public void removeDrawingClickListener(DrawingClickListener listener);
*/
public void drawLine(Point from, Point to);
/** /**
* Draw a line between the two given points with the default color * Clear the drawing.
* and the given width. */
* public void clear();
* @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 * Draw a line between the two given points with the default color and width.
* and the given width. *
* * @param from
* @param from * @param to
* @param to */
* @param width public void drawLine(Point from, Point to);
* @param color
*/
public void drawLine(Point from, Point to, int width, Color color);
/** /**
* Draw a marker at the given point with the default color. * Draw a line between the two given points with the default color and the given
* * width.
* @param point *
*/ * @param from
public void drawMarker(Point point); * @param to
* @param width
*/
public void drawLine(Point from, Point to, int width);
/** /**
* Draw the given point with the given color. * Draw a line between the two given points with the given color and the given
* * width.
* @param point *
*/ * @param from
public void drawMarker(Point point, Color color); * @param to
* @param width
* @param color
*/
public void drawLine(Point from, Point to, int width, Color color);
/** /**
* Draw a point width the given width and color. Do not use this to mark location, * Draw a marker at the given point with the default color.
* use drawMarker. *
* * @param point
* @param point */
* @param width public void drawMarker(Point point);
* @param color
*/
public void drawPoint(Point point, int width, Color color);
/** /**
* Draw the given graph using the given palette. * Draw the given point with the given color.
* *
* @param graph * @param point
* @param palette */
*/ public void drawMarker(Point point, Color color);
public void drawGraph(Graph graph, GraphPalette palette);
/** /**
* Draw the given graph using a default palette specific to the implementation. * Draw a point width the given width and color. Do not use this to mark
* * location, use drawMarker.
* @param graph *
*/ * @param point
public void drawGraph(Graph graph); * @param width
* @param color
*/
public void drawPoint(Point point, int width, Color color);
/** /**
* Draw a path using the given color. * Draw the given graph using the given palette.
* *
* @param path * @param graph
* @param color * @param palette
* @param markers Show origin and destination markers. */
*/ public void drawGraph(Graph graph, GraphPalette palette);
public void drawPath(Path path, Color color, boolean markers);
/** /**
* Draw a path using the given color with markers. * Draw the given graph using a default palette specific to the implementation.
* *
* @param path * @param graph
* @param color */
*/ public void drawGraph(Graph graph);
public void drawPath(Path path, Color color);
/** /**
* Draw a path using a default color specific to the implementation * Draw a path using the given color.
* *
* * @param path
* @param path * @param color
* @param markers Show origin and destination markers. * @param markers
*/ * Show origin and destination markers.
public void drawPath(Path path, boolean markers); */
public void drawPath(Path path, Color color, boolean markers);
/** /**
* Draw a path using a default color specific to the implementation * Draw a path using the given color with markers.
* *
* * @param path
* @param path * @param color
*/ */
public void drawPath(Path path); 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);
} }

View File

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

View File

@ -4,6 +4,7 @@ import java.awt.Color;
import java.awt.event.MouseAdapter; import java.awt.event.MouseAdapter;
import java.awt.event.MouseWheelEvent; import java.awt.event.MouseWheelEvent;
import java.io.File; import java.io.File;
import java.io.FileNotFoundException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
@ -12,10 +13,12 @@ import java.util.UUID;
import javax.swing.JFileChooser; import javax.swing.JFileChooser;
import javax.swing.filechooser.FileNameExtensionFilter; import javax.swing.filechooser.FileNameExtensionFilter;
import org.insa.drawing.utils.MarkerUtils;
import org.insa.graph.Arc; import org.insa.graph.Arc;
import org.insa.graph.Graph; import org.insa.graph.Graph;
import org.insa.graph.Path; import org.insa.graph.Path;
import org.insa.graph.Point; import org.insa.graph.Point;
import org.mapsforge.core.graphics.Bitmap;
import org.mapsforge.core.graphics.GraphicFactory; import org.mapsforge.core.graphics.GraphicFactory;
import org.mapsforge.core.graphics.Paint; import org.mapsforge.core.graphics.Paint;
import org.mapsforge.core.graphics.Style; import org.mapsforge.core.graphics.Style;
@ -37,7 +40,7 @@ import org.mapsforge.map.model.DisplayModel;
import org.mapsforge.map.model.MapViewPosition; import org.mapsforge.map.model.MapViewPosition;
import org.mapsforge.map.model.Model; import org.mapsforge.map.model.Model;
import org.mapsforge.map.reader.MapFile; import org.mapsforge.map.reader.MapFile;
import org.mapsforge.map.rendertheme.InternalRenderTheme; import org.mapsforge.map.rendertheme.ExternalRenderTheme;
import org.mapsforge.map.rendertheme.XmlRenderTheme; import org.mapsforge.map.rendertheme.XmlRenderTheme;
public class MapViewDrawing extends MapView implements Drawing { public class MapViewDrawing extends MapView implements Drawing {
@ -56,40 +59,73 @@ public class MapViewDrawing extends MapView implements Drawing {
// Default tile size. // Default tile size.
private static final int DEFAULT_TILE_SIZE = 512; private static final int DEFAULT_TILE_SIZE = 512;
// List of listeners.
private ArrayList<DrawingClickListener> drawingClickListeners = new ArrayList<>();
// Tile size. // Tile size.
int tileSize; int tileSize;
ArrayList<Paint> extraLayers; // 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<FixedStrokeWidthLayer> extraLayers = new ArrayList<>();
public MapViewDrawing() { public MapViewDrawing() {
getMapScaleBar().setVisible(true); getMapScaleBar().setVisible(true);
this.tileSize = DEFAULT_TILE_SIZE; this.tileSize = DEFAULT_TILE_SIZE;
DisplayModel model = getModel().displayModel; DisplayModel model = getModel().displayModel;
model.setFixedTileSize(tileSize); model.setFixedTileSize(tileSize);
// model.setBackgroundColor(convertColor(Color.WHITE));
extraLayers = new ArrayList<Paint>();
addMouseWheelListener(new MouseAdapter() { addMouseWheelListener(new MouseAdapter() {
@Override @Override
public void mouseWheelMoved(MouseWheelEvent e) { public void mouseWheelMoved(MouseWheelEvent e) {
byte zoomLevelDiff = (byte) -e.getWheelRotation(); for (FixedStrokeWidthLayer f: extraLayers) {
for (Paint p: extraLayers) { f.paint.setStrokeWidth(getStrokeWidth(f.width));
p.setStrokeWidth(p.getStrokeWidth() + zoomLevelDiff);
} }
} }
}); });
} }
/**
* @param color
* @return
*/
protected int convertColor(Color color) { protected int convertColor(Color color) {
return GRAPHIC_FACTORY.createColor(color.getAlpha(), color.getRed(), color.getGreen(), return GRAPHIC_FACTORY.createColor(color.getAlpha(), color.getRed(), color.getGreen(), color.getBlue());
color.getBlue());
} }
/**
* @param width
* @return
*/
private int getStrokeWidth(int width) { private int getStrokeWidth(int width) {
byte zoomLevel = getModel().mapViewPosition.getZoomLevel(); byte zoomLevel = getModel().mapViewPosition.getZoomLevel();
return width * (2 - (8 - zoomLevel)); 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) { private Paint createPaintStroke(int width, Color color) {
Paint paintStroke = AwtGraphicFactory.INSTANCE.createPaint(); Paint paintStroke = AwtGraphicFactory.INSTANCE.createPaint();
paintStroke.setStyle(Style.STROKE); paintStroke.setStyle(Style.STROKE);
@ -141,23 +177,42 @@ public class MapViewDrawing extends MapView implements Drawing {
return new LatLong(point.getLatitude(), point.getLongitude()); return new LatLong(point.getLatitude(), point.getLongitude());
} }
private static TileRendererLayer createTileRendererLayer(TileCache tileCache, private TileRendererLayer createTileRendererLayer(TileCache tileCache, MapDataStore mapDataStore,
MapDataStore mapDataStore, MapViewPosition mapViewPosition, MapViewPosition mapViewPosition, HillsRenderConfig hillsRenderConfig) {
HillsRenderConfig hillsRenderConfig) { TileRendererLayer tileRendererLayer = new TileRendererLayer(tileCache, mapDataStore, mapViewPosition, false,
TileRendererLayer tileRendererLayer = new TileRendererLayer(tileCache, mapDataStore, true, false, GRAPHIC_FACTORY, hillsRenderConfig) {
mapViewPosition, false, true, false, GRAPHIC_FACTORY, hillsRenderConfig) {
@Override @Override
public boolean onTap(LatLong tapLatLong, org.mapsforge.core.model.Point layerXY, public boolean onTap(LatLong tapLatLong, org.mapsforge.core.model.Point layerXY,
org.mapsforge.core.model.Point tapXY) { org.mapsforge.core.model.Point tapXY) {
System.out.println("Tap on: " + tapLatLong); 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; return true;
} }
}; };
XmlRenderTheme renderTheme = InternalRenderTheme.DEFAULT; XmlRenderTheme renderTheme = null;
try {
renderTheme = new ExternalRenderTheme("resources/assets/custom-theme.xml");
}
catch (FileNotFoundException e) {
e.printStackTrace();
}
tileRendererLayer.setXmlRenderTheme(renderTheme); tileRendererLayer.setXmlRenderTheme(renderTheme);
return tileRendererLayer; return tileRendererLayer;
} }
@Override
public void addDrawingClickListener(DrawingClickListener listener) {
this.drawingClickListeners.add(listener);
}
@Override
public void removeDrawingClickListener(DrawingClickListener listener) {
this.drawingClickListeners.remove(listener);
}
@Override @Override
public void clear() { public void clear() {
getLayerManager().getLayers().clear(); getLayerManager().getLayers().clear();
@ -186,18 +241,19 @@ public class MapViewDrawing extends MapView implements Drawing {
@Override @Override
public void drawMarker(Point point) { public void drawMarker(Point point) {
drawMarker(point, null); drawMarker(point, Color.GREEN);
} }
@Override @Override
public void drawMarker(Point point, Color color) { public void drawMarker(Point point, Color color) {
Marker marker = new Marker(convertPoint(point), GRAPHIC_FACTORY.createBitmap(10, 20), 1, 2); Bitmap bitmap = MarkerUtils.getMarkerForColor(color);
Marker marker = new Marker(convertPoint(point), bitmap, 0, -bitmap.getHeight() / 2);
getLayerManager().getLayers().add(marker); getLayerManager().getLayers().add(marker);
} }
@Override @Override
public void drawPoint(Point point, int width, Color color) { public void drawPoint(Point point, int width, Color color) {
// TODO: Maybe do something? // TODO:
} }
@Override @Override
@ -206,8 +262,7 @@ public class MapViewDrawing extends MapView implements Drawing {
File graphFile = getMapsforgeFileFromGraph(graph); File graphFile = getMapsforgeFileFromGraph(graph);
// Tile cache // Tile cache
TileCache tileCache = AwtUtil.createTileCache(tileSize, TileCache tileCache = AwtUtil.createTileCache(tileSize, getModel().frameBufferModel.getOverdrawFactor(), 1024,
getModel().frameBufferModel.getOverdrawFactor(), 1024,
new File(System.getProperty("java.io.tmpdir"), UUID.randomUUID().toString())); new File(System.getProperty("java.io.tmpdir"), UUID.randomUUID().toString()));
// Layers // Layers
@ -220,12 +275,10 @@ public class MapViewDrawing extends MapView implements Drawing {
BoundingBox boundingBox = mapDataStore.boundingBox(); BoundingBox boundingBox = mapDataStore.boundingBox();
final Model model = getModel(); final Model model = getModel();
if (model.mapViewPosition.getZoomLevel() == 0 if (model.mapViewPosition.getZoomLevel() == 0 || !boundingBox.contains(model.mapViewPosition.getCenter())) {
|| !boundingBox.contains(model.mapViewPosition.getCenter())) { byte zoomLevel = LatLongUtils.zoomForBounds(model.mapViewDimension.getDimension(), boundingBox,
byte zoomLevel = LatLongUtils.zoomForBounds(model.mapViewDimension.getDimension(), model.displayModel.getTileSize());
boundingBox, model.displayModel.getTileSize()); model.mapViewPosition.setMapPosition(new MapPosition(boundingBox.getCenterPoint(), zoomLevel));
model.mapViewPosition
.setMapPosition(new MapPosition(boundingBox.getCenterPoint(), zoomLevel));
model.mapViewPosition.setZoomLevelMin(zoomLevel); model.mapViewPosition.setZoomLevelMin(zoomLevel);
} }
} }
@ -242,15 +295,14 @@ public class MapViewDrawing extends MapView implements Drawing {
for (Arc arc: path.getArcs()) { for (Arc arc: path.getArcs()) {
ArrayList<Point> points = arc.getPoints(); ArrayList<Point> points = arc.getPoints();
for (int i = 0; i < points.size(); ++i) { for (int i = 0; i < points.size(); ++i) {
line.getLatLongs().add( line.getLatLongs().add(new LatLong(points.get(i).getLatitude(), points.get(i).getLongitude()));
new LatLong(points.get(i).getLatitude(), points.get(i).getLongitude()));
} }
} }
getLayerManager().getLayers().add(line); getLayerManager().getLayers().add(line);
extraLayers.add(paintStroke); extraLayers.add(new FixedStrokeWidthLayer(paintStroke, 1));
if (markers) { if (markers) {
drawMarker(path.getOrigin().getPoint()); drawMarker(path.getOrigin().getPoint(), DEFAULT_PATH_COLOR);
drawMarker(path.getDestination().getPoint()); drawMarker(path.getDestination().getPoint(), DEFAULT_PATH_COLOR);
} }
} }

View File

@ -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<Color, Bitmap> MARKER_BITMAPS = new HashMap<Color, Bitmap>();
/**
* 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}
};
}