package com.roboclub.robobuggy.ui;
import com.roboclub.robobuggy.main.RobobuggyLogicNotification;
import com.roboclub.robobuggy.main.RobobuggyMessageLevel;
import com.roboclub.robobuggy.messages.GPSPoseMessage;
import com.roboclub.robobuggy.nodes.localizers.LocTuple;
import com.roboclub.robobuggy.ros.Message;
import com.roboclub.robobuggy.ros.MessageListener;
import com.roboclub.robobuggy.ros.NodeChannel;
import com.roboclub.robobuggy.ros.Subscriber;
import org.openstreetmap.gui.jmapviewer.Coordinate;
import org.openstreetmap.gui.jmapviewer.JMapViewerTree;
import org.openstreetmap.gui.jmapviewer.MapMarkerDot;
import org.openstreetmap.gui.jmapviewer.MapPolygonImpl;
import org.openstreetmap.gui.jmapviewer.MemoryTileCache;
import org.openstreetmap.gui.jmapviewer.OsmTileLoader;
import org.openstreetmap.gui.jmapviewer.Tile;
import org.openstreetmap.gui.jmapviewer.interfaces.MapMarker;
import org.openstreetmap.gui.jmapviewer.interfaces.MapPolygon;
import org.openstreetmap.gui.jmapviewer.interfaces.TileCache;
import org.openstreetmap.gui.jmapviewer.tilesources.BingAerialTileSource;
import javax.imageio.ImageIO;
import javax.swing.JPanel;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FilenameFilter;
import java.io.IOException;
import java.util.List;
/**
* the map, it plots points where we are based on gps
*/
public class Map extends JPanel {
private JMapViewerTree mapTree;
private double mapViewerLat = 40.440138;
private double mapViewerLon = -79.945306;
private int zoomLevel = 20;
private double mapDragX = -1;
private double mapDragY = -1;
private static final int MAX_POINT_BUF_SIZE = 3000;
/**
* initializes a new Map with cache loaded
*/
public Map() {
initMapTree();
addCacheToTree();
this.add(getMapTree());
//adds track buggy
new Subscriber("Map", NodeChannel.POSE.getMsgPath(), new MessageListener() {
//TODO make this optional
@Override
public void actionPerformed(String topicName, Message m) {
GPSPoseMessage gpsM = (GPSPoseMessage) m;
zoomLevel = getMapTree().getViewer().getZoom();
getMapTree().getViewer().setDisplayPosition(new Coordinate(gpsM.getLatitude(),
gpsM.getLongitude()), zoomLevel);
}
});
}
private void initMapTree() {
setMapTree(new JMapViewerTree("Buggy"));
getMapTree().getViewer().setTileSource(new BingAerialTileSource());
getMapTree().setSize(getWidth(), getHeight());
getMapTree().getViewer().setSize(getWidth(), getHeight());
getMapTree().getViewer().setTileLoader(new OsmTileLoader(getMapTree().getViewer()));
getMapTree().getViewer().setDisplayPosition(new Coordinate(mapViewerLat, mapViewerLon), zoomLevel);
getMapTree().getViewer().addMouseListener(new MouseListener() {
@Override
public void mouseReleased(MouseEvent e) {
// TODO Auto-generated method stub
}
@Override
public void mousePressed(MouseEvent e) {
// TODO Auto-generated method stub
mapDragX = e.getX();
mapDragY = e.getY();
}
@Override
public void mouseExited(MouseEvent e) {
// TODO Auto-generated method stub
}
@Override
public void mouseEntered(MouseEvent e) {
// TODO Auto-generated method stub
}
@Override
public void mouseClicked(MouseEvent e) {
// TODO Auto-generated method stub
}
});
getMapTree().getViewer().addMouseMotionListener(new MouseMotionListener() {
@Override
public void mouseMoved(MouseEvent e) {
// TODO Auto-generated method stub
}
@Override
public void mouseDragged(MouseEvent e) {
// TODO Auto-generated method stub
zoomLevel = getMapTree().getViewer().getZoom();
mapViewerLat -= ((mapDragY - e.getY()) * 0.001) / (zoomLevel * 1000);
mapViewerLon -= ((e.getX() - mapDragX) * 0.001) / (zoomLevel * 1000);
getMapTree().getViewer().setDisplayPosition(new Coordinate(mapViewerLat, mapViewerLon), zoomLevel);
}
});
}
private void addCacheToTree() {
try {
TileCache courseCache = new MemoryTileCache();
String mapCacheFolderDiskPath = "images/cachedCourseMap";
File mapCacheDir = new File(mapCacheFolderDiskPath);
if (!mapCacheDir.isDirectory() || !mapCacheDir.exists()) {
throw new IOException("cache dir isn't properly structured or doesn't exist");
}
FilenameFilter filter = (dir, name) -> {
// TODO Auto-generated method stub
if (name.contains("png")) {
return true;
}
return false;
};
String[] cachedImages = mapCacheDir.list(filter);
if (cachedImages == null) {
return;
}
for (String imageName : cachedImages) {
BufferedImage tileImageSource = ImageIO.read(new File(mapCacheDir.getAbsolutePath() + "/" + imageName));
String[] tileCoords = imageName.substring(0, imageName.indexOf(".")).split("_");
int xCoord = Integer.parseInt(tileCoords[0]);
int yCoord = Integer.parseInt(tileCoords[1]);
zoomLevel = Integer.parseInt(tileCoords[2]);
Tile cacheInsert = new Tile(getMapTree().getViewer().getTileController().getTileSource(),
xCoord, yCoord, zoomLevel, tileImageSource);
cacheInsert.setLoaded(true);
courseCache.addTile(cacheInsert);
}
getMapTree().getViewer().getTileController().setTileCache(courseCache);
} catch (IOException e) {
new RobobuggyLogicNotification("Something is wrong with the map cache: " + e.getMessage(), RobobuggyMessageLevel.EXCEPTION);
}
}
/**
* updates the current arrow displaying on the GUI - shows orientation based on GPS
*/
public void updateArrow() {
List<MapPolygon> polygons = getMapTree().getViewer().getMapPolygonList();
List<MapMarker> markers = getMapTree().getViewer().getMapMarkerList();
if (markers.size() >= 2) {
MapMarker backMarker = markers.get(markers.size() - 2);
MapMarker frontMarker = markers.get(markers.size() - 1);
double endpointLat = 50 * (frontMarker.getLat() - backMarker.getLat()) + frontMarker.getLat();
double endpointLon = 50 * (frontMarker.getLon() - backMarker.getLon()) + frontMarker.getLon();
polygons.clear();
addLineToMap(new LocTuple(frontMarker.getLat(), frontMarker.getLon()), new LocTuple(endpointLat, endpointLon), Color.RED);
}
}
/**
* @param points points to add to the map
* @param thisColor color of the point
*/
public void addPointsToMapTree(Color thisColor, LocTuple... points) {
List<MapMarker> markers = getMapTree().getViewer().getMapMarkerList();
while (markers.size() > MAX_POINT_BUF_SIZE - points.length) {
markers.remove(0);
}
for (LocTuple point : points) {
getMapTree().getViewer().addMapMarker(new MapMarkerDot(thisColor, point.getLatitude(), point.getLongitude()));
}
}
/**
* @param point1 1st endpoint of line to add
* @param point2 2nd endpoint of line to add
* @param lineColor color of the line
*/
public void addLineToMap(LocTuple point1, LocTuple point2, Color lineColor) {
MapPolygonImpl polygon = new MapPolygonImpl(
new Coordinate(point1.getLatitude(), point1.getLongitude()),
new Coordinate(point1.getLatitude(), point1.getLongitude()),
new Coordinate(point2.getLatitude(), point2.getLongitude())
);
polygon.setColor(lineColor);
getMapTree().getViewer().addMapPolygon(polygon);
}
/**
* @param originPoint the origin point of the ray
* @param angle the heading of the ray in radians
* @param lineColor the color of the line
* @param clearPrevLine update the line or add a new one
*/
public void addLineToMap(LocTuple originPoint, double angle, Color lineColor, boolean clearPrevLine) {
if (clearPrevLine) {
getMapTree().getViewer().getMapPolygonList().clear();
}
double scalingFactor = 0.0005;
double dx = Math.cos(angle) * scalingFactor;
double dy = Math.sin(angle) * scalingFactor;
LocTuple endpoint = new LocTuple(originPoint.getLatitude() + dy, originPoint.getLongitude() + dx);
addLineToMap(originPoint, endpoint, lineColor);
}
@Override
public void paintComponent(Graphics g) {
getMapTree().setBounds(0, 0, getWidth(), getHeight());
getMapTree().getViewer().setSize(getWidth(), getHeight());
}
/**
* @return the mapTree
*/
public JMapViewerTree getMapTree() {
return mapTree;
}
/**
* @param mapTree the mapTree to set
*/
public void setMapTree(JMapViewerTree mapTree) {
this.mapTree = mapTree;
}
}