Reorganize code.
This commit is contained in:
599
src/main/org/insa/graphics/drawing/components/BasicDrawing.java
Normal file
599
src/main/org/insa/graphics/drawing/components/BasicDrawing.java
Normal file
@@ -0,0 +1,599 @@
|
||||
package org.insa.graphics.drawing.components;
|
||||
|
||||
import java.awt.BasicStroke;
|
||||
import java.awt.Color;
|
||||
import java.awt.Graphics;
|
||||
import java.awt.Graphics2D;
|
||||
import java.awt.Image;
|
||||
import java.awt.event.MouseAdapter;
|
||||
import java.awt.event.MouseEvent;
|
||||
import java.awt.event.MouseListener;
|
||||
import java.awt.geom.NoninvertibleTransformException;
|
||||
import java.awt.geom.Point2D;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.IdentityHashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.swing.JPanel;
|
||||
|
||||
import org.insa.graph.Arc;
|
||||
import org.insa.graph.Graph;
|
||||
import org.insa.graph.Node;
|
||||
import org.insa.graph.Path;
|
||||
import org.insa.graph.Point;
|
||||
import org.insa.graphics.drawing.BasicGraphPalette;
|
||||
import org.insa.graphics.drawing.Drawing;
|
||||
import org.insa.graphics.drawing.DrawingClickListener;
|
||||
import org.insa.graphics.drawing.GraphPalette;
|
||||
import org.insa.graphics.drawing.overlays.MarkerOverlay;
|
||||
import org.insa.graphics.drawing.overlays.MarkerUtils;
|
||||
import org.insa.graphics.drawing.overlays.Overlay;
|
||||
import org.insa.graphics.drawing.overlays.PathOverlay;
|
||||
import org.insa.graphics.drawing.overlays.PointSetOverlay;
|
||||
|
||||
/**
|
||||
* Cette implementation de la classe Dessin produit vraiment un affichage (au
|
||||
* contraire de la classe DessinInvisible).
|
||||
*/
|
||||
|
||||
public class BasicDrawing extends JPanel implements Drawing {
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private static final long serialVersionUID = 96779785877771827L;
|
||||
|
||||
private abstract class BasicOverlay implements Overlay {
|
||||
|
||||
// Visible?
|
||||
protected boolean visible;
|
||||
|
||||
public BasicOverlay() {
|
||||
this.visible = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setVisible(boolean visible) {
|
||||
this.visible = visible;
|
||||
BasicDrawing.this.repaint();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isVisible() {
|
||||
return this.visible;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void delete() {
|
||||
synchronized (overlays) {
|
||||
BasicDrawing.this.overlays.remove(this);
|
||||
}
|
||||
BasicDrawing.this.repaint();
|
||||
}
|
||||
|
||||
/**
|
||||
* Draw the given overlay.
|
||||
*/
|
||||
public void draw(Graphics2D g) {
|
||||
if (this.visible) {
|
||||
drawImpl(g);
|
||||
}
|
||||
}
|
||||
|
||||
public abstract void drawImpl(Graphics2D g);
|
||||
|
||||
};
|
||||
|
||||
private class BasicMarkerOverlay extends BasicOverlay implements MarkerOverlay {
|
||||
|
||||
// Default marker width
|
||||
private static final int DEFAULT_MARKER_WIDTH = 20;
|
||||
|
||||
// Point of the marker.
|
||||
private Point point;
|
||||
|
||||
// Color of the marker.
|
||||
private final Color color;
|
||||
|
||||
public BasicMarkerOverlay(Point point, Color color) {
|
||||
super();
|
||||
this.point = point;
|
||||
this.color = color;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Point getPoint() {
|
||||
return point;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Color getColor() {
|
||||
return color;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void moveTo(Point point) {
|
||||
this.point = point;
|
||||
BasicDrawing.this.repaint();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void drawImpl(Graphics2D graphics) {
|
||||
|
||||
int px = BasicDrawing.this.projx(getPoint().getLongitude());
|
||||
int py = BasicDrawing.this.projy(getPoint().getLatitude());
|
||||
|
||||
BufferedImage img = MarkerUtils.getMarkerForColor(color);
|
||||
Graphics2D gr = img.createGraphics();
|
||||
double scale = DEFAULT_MARKER_WIDTH / (double) img.getHeight();
|
||||
gr.scale(scale, scale);
|
||||
|
||||
graphics.drawImage(img, px - img.getWidth() / 2, py - img.getHeight(), BasicDrawing.this);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
private class BasicPathOverlay extends BasicOverlay implements PathOverlay {
|
||||
|
||||
// List of points
|
||||
private final List<Point> points;
|
||||
|
||||
// Color for the path
|
||||
private Color color;
|
||||
|
||||
// Origin / Destination markers.
|
||||
private BasicMarkerOverlay origin, destination;
|
||||
|
||||
public BasicPathOverlay(List<Point> points, Color color, BasicMarkerOverlay origin,
|
||||
BasicMarkerOverlay destination) {
|
||||
this.points = points;
|
||||
this.origin = origin;
|
||||
this.destination = destination;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void drawImpl(Graphics2D graphics) {
|
||||
|
||||
if (!points.isEmpty()) {
|
||||
|
||||
graphics.setStroke(new BasicStroke(2));
|
||||
graphics.setColor(color);
|
||||
|
||||
Iterator<Point> itPoint = points.iterator();
|
||||
Point prev = itPoint.next();
|
||||
|
||||
while (itPoint.hasNext()) {
|
||||
Point curr = itPoint.next();
|
||||
|
||||
int x1 = BasicDrawing.this.projx(prev.getLongitude());
|
||||
int x2 = BasicDrawing.this.projx(curr.getLongitude());
|
||||
int y1 = BasicDrawing.this.projy(prev.getLatitude());
|
||||
int y2 = BasicDrawing.this.projy(curr.getLatitude());
|
||||
|
||||
graphics.drawLine(x1, y1, x2, y2);
|
||||
|
||||
prev = curr;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (this.origin != null) {
|
||||
this.origin.draw(graphics);
|
||||
}
|
||||
if (this.destination != null) {
|
||||
this.destination.draw(graphics);
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
private class BasicPointSetOverlay extends BasicOverlay implements PointSetOverlay {
|
||||
|
||||
// Default point width
|
||||
private static final int DEFAULT_POINT_WIDTH = 5;
|
||||
|
||||
// Image for path / points
|
||||
private final BufferedImage image;
|
||||
private final Graphics2D graphics;
|
||||
|
||||
private int width = DEFAULT_POINT_WIDTH;
|
||||
|
||||
public BasicPointSetOverlay() {
|
||||
this.image = new BufferedImage(BasicDrawing.this.width, BasicDrawing.this.height,
|
||||
BufferedImage.TYPE_4BYTE_ABGR);
|
||||
this.graphics = image.createGraphics();
|
||||
this.graphics.setBackground(new Color(0, 0, 0, 0));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setColor(Color color) {
|
||||
this.graphics.setColor(color);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setWidth(int width) {
|
||||
this.width = width;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setWidthAndColor(int width, Color color) {
|
||||
setWidth(width);
|
||||
setColor(color);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addPoint(Point point) {
|
||||
this.width = 5;
|
||||
int x = BasicDrawing.this.projx(point.getLongitude()) - this.width / 2;
|
||||
int y = BasicDrawing.this.projy(point.getLatitude()) - this.width / 2;
|
||||
this.graphics.fillOval(x, y, this.width, this.width);
|
||||
BasicDrawing.this.repaint();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addPoint(Point point, int width) {
|
||||
setWidth(width);
|
||||
addPoint(point);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addPoint(Point point, Color color) {
|
||||
setColor(color);
|
||||
addPoint(point);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addPoint(Point point, int width, Color color) {
|
||||
setWidth(width);
|
||||
setColor(color);
|
||||
addPoint(point);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void drawImpl(Graphics2D g) {
|
||||
g.drawImage(this.image, 0, 0, BasicDrawing.this);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Default path color.
|
||||
public static final Color DEFAULT_PATH_COLOR = new Color(255, 0, 255);
|
||||
|
||||
// Default palette.
|
||||
public static final GraphPalette DEFAULT_PALETTE = new BasicGraphPalette();
|
||||
|
||||
// Maximum width for the drawing (in pixels).
|
||||
private static final int MAXIMUM_DRAWING_WIDTH = 2000;
|
||||
|
||||
private double long1, long2, lat1, lat2;
|
||||
|
||||
// Width and height of the image
|
||||
private int width, height;
|
||||
|
||||
private ZoomAndPanListener zoomAndPanListener;
|
||||
|
||||
//
|
||||
private Image graphImage = null;
|
||||
private Graphics2D graphGraphics = null;
|
||||
|
||||
// List of image for markers
|
||||
private List<BasicOverlay> overlays = Collections.synchronizedList(new ArrayList<BasicOverlay>());
|
||||
|
||||
// Mapping DrawingClickListener -> MouseEventListener
|
||||
private Map<DrawingClickListener, MouseListener> listenerMapping = new IdentityHashMap<>();
|
||||
|
||||
/**
|
||||
* Create a new BasicDrawing.
|
||||
*
|
||||
*/
|
||||
public BasicDrawing() {
|
||||
this.zoomAndPanListener = new ZoomAndPanListener(this, ZoomAndPanListener.DEFAULT_MIN_ZOOM_LEVEL, 20, 1.2);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void paintComponent(Graphics g1) {
|
||||
Graphics2D g = (Graphics2D) g1;
|
||||
g.clearRect(0, 0, getWidth(), getHeight());
|
||||
g.setTransform(zoomAndPanListener.getCoordTransform());
|
||||
|
||||
if (graphImage != null) {
|
||||
// Draw graph
|
||||
g.drawImage(graphImage, 0, 0, this);
|
||||
}
|
||||
|
||||
// Draw markers
|
||||
synchronized (overlays) {
|
||||
for (BasicOverlay overlay: overlays) {
|
||||
overlay.draw(g);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param lon
|
||||
* @return
|
||||
*/
|
||||
private int projx(double lon) {
|
||||
return (int) (width * (lon - this.long1) / (this.long2 - this.long1));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param lat
|
||||
* @return
|
||||
*/
|
||||
private int projy(double lat) {
|
||||
return (int) (height * (1 - (lat - this.lat1) / (this.lat2 - this.lat1)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the longitude and latitude corresponding to the given position of the
|
||||
* MouseEvent.
|
||||
*
|
||||
* @param event
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public Point getLongitudeLatitude(MouseEvent event) throws NoninvertibleTransformException {
|
||||
// Get the point using the inverse transform of the Zoom/Pan object, this gives
|
||||
// us
|
||||
// a point within the drawing box (between [0, 0] and [width, height]).
|
||||
Point2D ptDst = this.zoomAndPanListener.getCoordTransform().inverseTransform(event.getPoint(), null);
|
||||
|
||||
// Inverse the "projection" on x/y to get longitude and latitude.
|
||||
double lon = ptDst.getX();
|
||||
double lat = ptDst.getY();
|
||||
lon = (lon / this.width) * (this.long2 - this.long1) + this.long1;
|
||||
lat = (1 - lat / this.height) * (this.lat2 - this.lat1) + this.lat1;
|
||||
|
||||
// Return a new point.
|
||||
return new Point(lon, lat);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addDrawingClickListener(DrawingClickListener listener) {
|
||||
MouseListener mListener = new MouseAdapter() {
|
||||
@Override
|
||||
public void mouseClicked(MouseEvent evt) {
|
||||
try {
|
||||
listener.mouseClicked(getLongitudeLatitude(evt));
|
||||
}
|
||||
catch (NoninvertibleTransformException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
};
|
||||
this.addMouseListener(mListener);
|
||||
this.listenerMapping.put(listener, mListener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeDrawingClickListener(DrawingClickListener listener) {
|
||||
this.removeMouseListener(this.listenerMapping.get(listener));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear() {
|
||||
if (this.graphGraphics != null) {
|
||||
this.graphGraphics.clearRect(0, 0, this.width, this.height);
|
||||
}
|
||||
synchronized (overlays) {
|
||||
this.overlays.clear();
|
||||
}
|
||||
}
|
||||
|
||||
public BasicMarkerOverlay createMarker(Point point, Color color) {
|
||||
return new BasicMarkerOverlay(point, color);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MarkerOverlay drawMarker(Point point, Color color) {
|
||||
BasicMarkerOverlay marker = createMarker(point, color);
|
||||
synchronized (overlays) {
|
||||
this.overlays.add(marker);
|
||||
}
|
||||
this.repaint();
|
||||
return marker;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PointSetOverlay createPointSetOverlay() {
|
||||
BasicPointSetOverlay ps = new BasicPointSetOverlay();
|
||||
synchronized (overlays) {
|
||||
this.overlays.add(ps);
|
||||
}
|
||||
return ps;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PointSetOverlay createPointSetOverlay(int width, Color color) {
|
||||
PointSetOverlay ps = createPointSetOverlay();
|
||||
ps.setWidthAndColor(width, color);
|
||||
return ps;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
protected void drawArc(Arc arc, GraphPalette palette, boolean repaint) {
|
||||
List<Point> pts = arc.getPoints();
|
||||
if (!pts.isEmpty()) {
|
||||
if (palette != null) {
|
||||
this.graphGraphics.setColor(palette.getColorForArc(arc));
|
||||
this.graphGraphics.setStroke(new BasicStroke(palette.getWidthForArc(arc)));
|
||||
}
|
||||
Iterator<Point> it1 = pts.iterator();
|
||||
Point prev = it1.next();
|
||||
while (it1.hasNext()) {
|
||||
Point curr = it1.next();
|
||||
|
||||
int x1 = this.projx(prev.getLongitude());
|
||||
int x2 = this.projx(curr.getLongitude());
|
||||
int y1 = this.projy(prev.getLatitude());
|
||||
int y2 = this.projy(curr.getLatitude());
|
||||
|
||||
graphGraphics.drawLine(x1, y1, x2, y2);
|
||||
prev = curr;
|
||||
}
|
||||
}
|
||||
if (repaint) {
|
||||
this.repaint();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize the drawing for the given graph.
|
||||
*
|
||||
* @param graph
|
||||
*/
|
||||
protected void initialize(Graph graph) {
|
||||
|
||||
// Clear everything.
|
||||
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;
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
// Add a little delta to avoid drawing on the edge...
|
||||
double diffLon = maxLon - minLon, diffLat = maxLat - minLat;
|
||||
double deltaLon = 0.01 * diffLon, deltaLat = 0.01 * diffLat;
|
||||
|
||||
this.long1 = minLon - deltaLon;
|
||||
this.long2 = maxLon + deltaLon;
|
||||
this.lat1 = minLat - deltaLat;
|
||||
this.lat2 = maxLat + deltaLat;
|
||||
|
||||
// Compute width/height for the image
|
||||
|
||||
if (diffLat < diffLon) {
|
||||
this.width = MAXIMUM_DRAWING_WIDTH;
|
||||
this.height = (int) (this.width * diffLat / diffLon);
|
||||
}
|
||||
else {
|
||||
this.height = MAXIMUM_DRAWING_WIDTH;
|
||||
this.width = (int) (this.height * diffLon / diffLat);
|
||||
}
|
||||
|
||||
// Create the image
|
||||
BufferedImage img = new BufferedImage(this.width, this.height, BufferedImage.TYPE_3BYTE_BGR);
|
||||
this.graphImage = img;
|
||||
this.graphGraphics = img.createGraphics();
|
||||
this.graphGraphics.setBackground(Color.WHITE);
|
||||
this.graphGraphics.clearRect(0, 0, this.width, this.height);
|
||||
|
||||
// Set the zoom and pan listener
|
||||
|
||||
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.getHeight() - this.height * scale) / 2);
|
||||
this.zoomAndPanListener.getCoordTransform().scale(scale, scale);
|
||||
this.zoomAndPanListener.setZoomLevel(0);
|
||||
|
||||
// Repaint
|
||||
this.repaint();
|
||||
}
|
||||
|
||||
@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, 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) {
|
||||
drawGraph(graph, DEFAULT_PALETTE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PathOverlay drawPath(Path path, Color color, boolean markers) {
|
||||
List<Point> points = new ArrayList<Point>();
|
||||
if (!path.isEmpty()) {
|
||||
points.add(path.getOrigin().getPoint());
|
||||
for (Arc arc: path.getArcs()) {
|
||||
Iterator<Point> itPoint = arc.getPoints().iterator();
|
||||
// Discard origin each time
|
||||
itPoint.next();
|
||||
while (itPoint.hasNext()) {
|
||||
points.add(itPoint.next());
|
||||
}
|
||||
}
|
||||
}
|
||||
BasicMarkerOverlay origin = null, destination = null;
|
||||
if (markers && !path.isEmpty()) {
|
||||
origin = createMarker(path.getOrigin().getPoint(), color);
|
||||
destination = createMarker(path.getDestination().getPoint(), color);
|
||||
}
|
||||
BasicPathOverlay overlay = new BasicPathOverlay(points, color, origin, destination);
|
||||
synchronized (overlays) {
|
||||
this.overlays.add(overlay);
|
||||
}
|
||||
this.repaint();
|
||||
return overlay;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PathOverlay drawPath(Path path, Color color) {
|
||||
return drawPath(path, color, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PathOverlay drawPath(Path path) {
|
||||
return drawPath(path, DEFAULT_PATH_COLOR);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PathOverlay drawPath(Path path, boolean markers) {
|
||||
return drawPath(path, DEFAULT_PATH_COLOR, markers);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,350 @@
|
||||
package org.insa.graphics.drawing.components;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.UUID;
|
||||
|
||||
import org.insa.graph.Arc;
|
||||
import org.insa.graph.Graph;
|
||||
import org.insa.graph.Path;
|
||||
import org.insa.graph.Point;
|
||||
import org.insa.graphics.drawing.Drawing;
|
||||
import org.insa.graphics.drawing.DrawingClickListener;
|
||||
import org.insa.graphics.drawing.GraphPalette;
|
||||
import org.insa.graphics.drawing.overlays.MarkerOverlay;
|
||||
import org.insa.graphics.drawing.overlays.MarkerUtils;
|
||||
import org.insa.graphics.drawing.overlays.Overlay;
|
||||
import org.insa.graphics.drawing.overlays.PathOverlay;
|
||||
import org.insa.graphics.drawing.overlays.PointSetOverlay;
|
||||
import org.insa.graphics.drawing.overlays.PolylineAutoScaling;
|
||||
import org.mapsforge.core.graphics.Bitmap;
|
||||
import org.mapsforge.core.graphics.GraphicFactory;
|
||||
import org.mapsforge.core.model.BoundingBox;
|
||||
import org.mapsforge.core.model.LatLong;
|
||||
import org.mapsforge.core.model.MapPosition;
|
||||
import org.mapsforge.core.util.LatLongUtils;
|
||||
import org.mapsforge.core.util.Parameters;
|
||||
import org.mapsforge.map.awt.graphics.AwtBitmap;
|
||||
import org.mapsforge.map.awt.graphics.AwtGraphicFactory;
|
||||
import org.mapsforge.map.awt.util.AwtUtil;
|
||||
import org.mapsforge.map.awt.view.MapView;
|
||||
import org.mapsforge.map.datastore.MapDataStore;
|
||||
import org.mapsforge.map.layer.Layer;
|
||||
import org.mapsforge.map.layer.Layers;
|
||||
import org.mapsforge.map.layer.cache.TileCache;
|
||||
import org.mapsforge.map.layer.hills.HillsRenderConfig;
|
||||
import org.mapsforge.map.layer.overlay.Marker;
|
||||
import org.mapsforge.map.layer.renderer.TileRendererLayer;
|
||||
import org.mapsforge.map.model.DisplayModel;
|
||||
import org.mapsforge.map.model.MapViewPosition;
|
||||
import org.mapsforge.map.model.Model;
|
||||
import org.mapsforge.map.reader.MapFile;
|
||||
import org.mapsforge.map.rendertheme.InternalRenderTheme;
|
||||
|
||||
public class MapViewDrawing extends MapView implements Drawing {
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private static final long serialVersionUID = 8606967833704938092L;
|
||||
|
||||
/**
|
||||
* Base Overlay for MapViewDrawing overlays.
|
||||
*
|
||||
*/
|
||||
private abstract class MapViewOverlay implements Overlay {
|
||||
|
||||
// Marker associated.
|
||||
protected Layer[] layers;
|
||||
|
||||
public MapViewOverlay(Layer[] layers) {
|
||||
this.layers = layers;
|
||||
for (Layer layer: this.layers) {
|
||||
MapViewDrawing.this.getLayerManager().getLayers().add(layer);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setVisible(boolean visible) {
|
||||
for (Layer layer: layers) {
|
||||
layer.setVisible(visible);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isVisible() {
|
||||
if (this.layers.length == 0) {
|
||||
return true;
|
||||
}
|
||||
return this.layers[0].isVisible();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void delete() {
|
||||
Layers mlayers = MapViewDrawing.this.getLayerManager().getLayers();
|
||||
for (Layer layer: layers) {
|
||||
mlayers.remove(layer);
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* MarkerOverlay for MapViewDrawing.
|
||||
*
|
||||
*/
|
||||
private class MapViewMarkerOverlay extends MapViewOverlay implements MarkerOverlay {
|
||||
|
||||
// Color of this marker
|
||||
Color color;
|
||||
|
||||
public MapViewMarkerOverlay(Marker marker, Color color) {
|
||||
super(new Layer[] { marker });
|
||||
this.color = color;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Point getPoint() {
|
||||
Marker marker = (Marker) super.layers[0];
|
||||
return new Point(marker.getLatLong().getLongitude(), marker.getLatLong().getLatitude());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Color getColor() {
|
||||
return color;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void moveTo(Point point) {
|
||||
Marker marker = (Marker) this.layers[0];
|
||||
this.delete();
|
||||
marker = new Marker(convertPoint(point), marker.getBitmap(), marker.getHorizontalOffset(),
|
||||
marker.getVerticalOffset());
|
||||
this.layers[0] = marker;
|
||||
MapViewDrawing.this.getLayerManager().getLayers().add(marker);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* PathOverlay for MapViewDrawing.
|
||||
*
|
||||
*/
|
||||
private class MapViewPathOverlay extends MapViewOverlay implements PathOverlay {
|
||||
|
||||
public MapViewPathOverlay(PolylineAutoScaling path, Marker origin, Marker destination) {
|
||||
super(new Layer[] { path, origin, destination });
|
||||
}
|
||||
|
||||
public MapViewPathOverlay(PolylineAutoScaling path) {
|
||||
super(new Layer[] { path });
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* PointSetOverlay for MapViewDrawing - Not currently implemented.
|
||||
*
|
||||
*/
|
||||
private class MapViewPointSetOverlay extends MapViewOverlay implements PointSetOverlay {
|
||||
|
||||
public MapViewPointSetOverlay() {
|
||||
super(new Layer[0]);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setColor(Color color) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setWidth(int width) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setWidthAndColor(int width, Color color) {
|
||||
setWidth(width);
|
||||
setColor(color);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addPoint(Point point) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addPoint(Point point, int width) {
|
||||
setWidth(width);
|
||||
addPoint(point);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addPoint(Point point, Color color) {
|
||||
setColor(color);
|
||||
addPoint(point);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addPoint(Point point, int width, Color color) {
|
||||
setWidth(width);
|
||||
setColor(color);
|
||||
addPoint(point);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
// Default path color.
|
||||
public static final Color DEFAULT_PATH_COLOR = new Color(66, 134, 244);
|
||||
|
||||
// Graphic factory.
|
||||
private static final GraphicFactory GRAPHIC_FACTORY = AwtGraphicFactory.INSTANCE;
|
||||
|
||||
// Default tile size.
|
||||
private static final int DEFAULT_TILE_SIZE = 512;
|
||||
|
||||
// List of listeners.
|
||||
private ArrayList<DrawingClickListener> drawingClickListeners = new ArrayList<>();
|
||||
|
||||
// Tile size
|
||||
private int tileSize;
|
||||
|
||||
public MapViewDrawing() {
|
||||
super();
|
||||
Parameters.NUMBER_OF_THREADS = 2;
|
||||
Parameters.SQUARE_FRAME_BUFFER = false;
|
||||
|
||||
getMapScaleBar().setVisible(true);
|
||||
DisplayModel model = getModel().displayModel;
|
||||
this.tileSize = DEFAULT_TILE_SIZE;
|
||||
model.setFixedTileSize(this.tileSize);
|
||||
|
||||
this.setZoomLevelMin((byte) 0);
|
||||
this.setZoomLevelMax((byte) 20);
|
||||
}
|
||||
|
||||
protected LatLong convertPoint(Point point) {
|
||||
return new LatLong(point.getLatitude(), point.getLongitude());
|
||||
}
|
||||
|
||||
private TileRendererLayer createTileRendererLayer(TileCache tileCache, MapDataStore mapDataStore,
|
||||
MapViewPosition mapViewPosition, HillsRenderConfig hillsRenderConfig) {
|
||||
TileRendererLayer tileRendererLayer = new TileRendererLayer(tileCache, mapDataStore, mapViewPosition, false,
|
||||
true, false, GRAPHIC_FACTORY, hillsRenderConfig) {
|
||||
@Override
|
||||
public boolean onTap(LatLong tapLatLong, org.mapsforge.core.model.Point layerXY,
|
||||
org.mapsforge.core.model.Point tapXY) {
|
||||
Point pt = new Point(tapLatLong.getLongitude(), tapLatLong.getLatitude());
|
||||
for (DrawingClickListener listener: MapViewDrawing.this.drawingClickListeners) {
|
||||
listener.mouseClicked(pt);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
tileRendererLayer.setXmlRenderTheme(InternalRenderTheme.DEFAULT);
|
||||
return tileRendererLayer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addDrawingClickListener(DrawingClickListener listener) {
|
||||
this.drawingClickListeners.add(listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeDrawingClickListener(DrawingClickListener listener) {
|
||||
this.drawingClickListeners.remove(listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear() {
|
||||
getLayerManager().getLayers().clear();
|
||||
repaint();
|
||||
}
|
||||
|
||||
protected Marker createMarker(Point point, Color color) {
|
||||
Bitmap bitmap = new AwtBitmap(MarkerUtils.getMarkerForColor(color));
|
||||
return new Marker(convertPoint(point), bitmap, 0, -bitmap.getHeight() / 2);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MarkerOverlay drawMarker(Point point, Color color) {
|
||||
return new MapViewMarkerOverlay(createMarker(point, color), color);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PointSetOverlay createPointSetOverlay() {
|
||||
return new MapViewPointSetOverlay();
|
||||
}
|
||||
|
||||
@Override
|
||||
public PointSetOverlay createPointSetOverlay(int width, Color color) {
|
||||
PointSetOverlay ps = new MapViewPointSetOverlay();
|
||||
ps.setWidthAndColor(width, color);
|
||||
return ps;
|
||||
}
|
||||
|
||||
public void drawGraph(File file) {
|
||||
|
||||
// Tile cache
|
||||
TileCache tileCache = AwtUtil.createTileCache(tileSize, getModel().frameBufferModel.getOverdrawFactor(), 1024,
|
||||
new File(System.getProperty("java.io.tmpdir"), UUID.randomUUID().toString()));
|
||||
|
||||
// Layers
|
||||
Layers layers = getLayerManager().getLayers();
|
||||
|
||||
MapDataStore mapDataStore = new MapFile(file);
|
||||
TileRendererLayer tileRendererLayer = createTileRendererLayer(tileCache, mapDataStore,
|
||||
getModel().mapViewPosition, null);
|
||||
layers.add(tileRendererLayer);
|
||||
BoundingBox boundingBox = mapDataStore.boundingBox();
|
||||
|
||||
final Model model = getModel();
|
||||
if (model.mapViewPosition.getZoomLevel() == 0 || !boundingBox.contains(model.mapViewPosition.getCenter())) {
|
||||
byte zoomLevel = LatLongUtils.zoomForBounds(model.mapViewDimension.getDimension(), boundingBox,
|
||||
model.displayModel.getTileSize());
|
||||
model.mapViewPosition.setMapPosition(new MapPosition(boundingBox.getCenterPoint(), zoomLevel));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void drawGraph(Graph graph, GraphPalette palette) {
|
||||
// drawGraph(graph, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void drawGraph(Graph graph) {
|
||||
// drawGraph(graph, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PathOverlay drawPath(Path path, Color color, boolean markers) {
|
||||
PolylineAutoScaling line = new PolylineAutoScaling(1, DEFAULT_PATH_COLOR);
|
||||
for (Arc arc: path.getArcs()) {
|
||||
line.add(arc.getPoints());
|
||||
}
|
||||
PathOverlay overlay = null;
|
||||
if (markers) {
|
||||
Marker origin = createMarker(path.getOrigin().getPoint(), DEFAULT_PATH_COLOR),
|
||||
destination = createMarker(path.getDestination().getPoint(), DEFAULT_PATH_COLOR);
|
||||
overlay = new MapViewPathOverlay(line, origin, destination);
|
||||
}
|
||||
else {
|
||||
overlay = new MapViewPathOverlay(line);
|
||||
}
|
||||
return overlay;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PathOverlay drawPath(Path path, Color color) {
|
||||
return drawPath(path, color, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PathOverlay drawPath(Path path) {
|
||||
return drawPath(path, DEFAULT_PATH_COLOR, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PathOverlay drawPath(Path path, boolean markers) {
|
||||
return drawPath(path, DEFAULT_PATH_COLOR, markers);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,141 @@
|
||||
package org.insa.graphics.drawing.components;
|
||||
|
||||
import java.awt.*;
|
||||
import java.awt.event.*;
|
||||
import java.awt.geom.AffineTransform;
|
||||
import java.awt.geom.NoninvertibleTransformException;
|
||||
import java.awt.geom.Point2D;
|
||||
|
||||
public class ZoomAndPanListener implements MouseListener, MouseMotionListener, MouseWheelListener {
|
||||
public static final int DEFAULT_MIN_ZOOM_LEVEL = -20;
|
||||
public static final int DEFAULT_MAX_ZOOM_LEVEL = 10;
|
||||
public static final double DEFAULT_ZOOM_MULTIPLICATION_FACTOR = 1.2;
|
||||
|
||||
private Component targetComponent;
|
||||
|
||||
private int zoomLevel = 0;
|
||||
private int minZoomLevel = DEFAULT_MIN_ZOOM_LEVEL;
|
||||
private int maxZoomLevel = DEFAULT_MAX_ZOOM_LEVEL;
|
||||
private double zoomMultiplicationFactor = DEFAULT_ZOOM_MULTIPLICATION_FACTOR;
|
||||
|
||||
private Point dragStartScreen;
|
||||
private Point dragEndScreen;
|
||||
private AffineTransform coordTransform = new AffineTransform();
|
||||
|
||||
public ZoomAndPanListener(Component targetComponent) {
|
||||
this.targetComponent = targetComponent;
|
||||
}
|
||||
|
||||
public ZoomAndPanListener(Component targetComponent, int minZoomLevel, int maxZoomLevel, double zoomMultiplicationFactor) {
|
||||
this.targetComponent = targetComponent;
|
||||
this.minZoomLevel = minZoomLevel;
|
||||
this.maxZoomLevel = maxZoomLevel;
|
||||
this.zoomMultiplicationFactor = zoomMultiplicationFactor;
|
||||
}
|
||||
|
||||
public void translate(double dx, double dy) {
|
||||
coordTransform.translate(dx, dy);
|
||||
targetComponent.repaint();
|
||||
}
|
||||
|
||||
|
||||
public void mouseClicked(MouseEvent e) {
|
||||
}
|
||||
|
||||
public void mousePressed(MouseEvent e) {
|
||||
dragStartScreen = e.getPoint();
|
||||
dragEndScreen = null;
|
||||
}
|
||||
|
||||
public void mouseReleased(MouseEvent e) {
|
||||
// moveCamera(e);
|
||||
}
|
||||
|
||||
public void mouseEntered(MouseEvent e) {
|
||||
}
|
||||
|
||||
public void mouseExited(MouseEvent e) {
|
||||
}
|
||||
|
||||
public void mouseMoved(MouseEvent e) {
|
||||
}
|
||||
|
||||
public void mouseDragged(MouseEvent e) {
|
||||
moveCamera(e);
|
||||
}
|
||||
|
||||
public void mouseWheelMoved(MouseWheelEvent e) {
|
||||
zoomCamera(e);
|
||||
}
|
||||
|
||||
private void moveCamera(MouseEvent e) {
|
||||
try {
|
||||
dragEndScreen = e.getPoint();
|
||||
Point2D.Float dragStart = transformPoint(dragStartScreen);
|
||||
Point2D.Float dragEnd = transformPoint(dragEndScreen);
|
||||
double dx = dragEnd.getX() - dragStart.getX();
|
||||
double dy = dragEnd.getY() - dragStart.getY();
|
||||
coordTransform.translate(dx, dy);
|
||||
dragStartScreen = dragEndScreen;
|
||||
dragEndScreen = null;
|
||||
targetComponent.repaint();
|
||||
} catch (NoninvertibleTransformException ex) {
|
||||
ex.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
private void zoomCamera(MouseWheelEvent e) {
|
||||
try {
|
||||
int wheelRotation = e.getWheelRotation();
|
||||
Point p = e.getPoint();
|
||||
if (wheelRotation > 0) {
|
||||
if (zoomLevel < maxZoomLevel) {
|
||||
zoomLevel++;
|
||||
Point2D p1 = transformPoint(p);
|
||||
coordTransform.scale(1 / zoomMultiplicationFactor, 1 / zoomMultiplicationFactor);
|
||||
Point2D p2 = transformPoint(p);
|
||||
coordTransform.translate(p2.getX() - p1.getX(), p2.getY() - p1.getY());
|
||||
targetComponent.repaint();
|
||||
}
|
||||
} else {
|
||||
if (zoomLevel > minZoomLevel) {
|
||||
zoomLevel--;
|
||||
Point2D p1 = transformPoint(p);
|
||||
coordTransform.scale(zoomMultiplicationFactor, zoomMultiplicationFactor);
|
||||
Point2D p2 = transformPoint(p);
|
||||
coordTransform.translate(p2.getX() - p1.getX(), p2.getY() - p1.getY());
|
||||
targetComponent.repaint();
|
||||
}
|
||||
}
|
||||
} catch (NoninvertibleTransformException ex) {
|
||||
ex.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
private Point2D.Float transformPoint(Point p1) throws NoninvertibleTransformException {
|
||||
|
||||
AffineTransform inverse = coordTransform.createInverse();
|
||||
|
||||
Point2D.Float p2 = new Point2D.Float();
|
||||
inverse.transform(p1, p2);
|
||||
return p2;
|
||||
}
|
||||
|
||||
public int getZoomLevel() {
|
||||
return zoomLevel;
|
||||
}
|
||||
|
||||
|
||||
public void setZoomLevel(int zoomLevel) {
|
||||
this.zoomLevel = zoomLevel;
|
||||
}
|
||||
|
||||
|
||||
public AffineTransform getCoordTransform() {
|
||||
return coordTransform;
|
||||
}
|
||||
|
||||
public void setCoordTransform(AffineTransform coordTransform) {
|
||||
this.coordTransform = coordTransform;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user