OsmAnd/DataExtractionOSM/src/net/osmand/swing/MapRouterLayer.java
2011-07-03 14:56:03 +02:00

456 lines
15 KiB
Java

package net.osmand.swing;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Point;
import java.awt.event.ActionEvent;
import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.RandomAccessFile;
import java.io.StringReader;
import java.lang.reflect.InvocationTargetException;
import java.net.URL;
import java.net.URLConnection;
import java.util.ArrayList;
import java.util.List;
import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.JOptionPane;
import javax.swing.JPopupMenu;
import javax.swing.SwingUtilities;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import net.osmand.binary.BinaryMapDataObject;
import net.osmand.binary.BinaryMapIndexReader;
import net.osmand.binary.BinaryRouteDataReader;
import net.osmand.binary.BinaryMapIndexReader.TagValuePair;
import net.osmand.binary.BinaryRouteDataReader.RouteSegment;
import net.osmand.binary.BinaryRouteDataReader.RouteSegmentResult;
import net.osmand.binary.BinaryRouteDataReader.RouteSegmentVisitor;
import net.osmand.binary.BinaryRouteDataReader.RoutingContext;
import net.osmand.data.DataTileManager;
import net.osmand.osm.LatLon;
import net.osmand.osm.MapUtils;
import net.osmand.osm.Way;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
public class MapRouterLayer implements MapPanelLayer {
private MapPanel map;
private LatLon startRoute;
private LatLon endRoute;
@Override
public void destroyLayer() {
}
@Override
public void initLayer(MapPanel map) {
this.map = map;
fillPopupMenuWithActions(map.getPopupMenu());
}
public void fillPopupMenuWithActions(JPopupMenu menu) {
Action start = new AbstractAction("Mark start point") {
private static final long serialVersionUID = 507156107455281238L;
public void actionPerformed(ActionEvent e) {
Point popupMenuPoint = map.getPopupMenuPoint();
double fy = (popupMenuPoint.y - map.getCenterPointY()) / map.getTileSize();
double fx = (popupMenuPoint.x - map.getCenterPointX()) / map.getTileSize();
double latitude = MapUtils.getLatitudeFromTile(map.getZoom(), map.getYTile() + fy);
double longitude = MapUtils.getLongitudeFromTile(map.getZoom(), map.getXTile() + fx);
startRoute = new LatLon(latitude, longitude);
map.repaint();
}
};
menu.add(start);
Action end= new AbstractAction("Mark end point") {
private static final long serialVersionUID = 4446789424902471319L;
public void actionPerformed(ActionEvent e) {
Point popupMenuPoint = map.getPopupMenuPoint();
double fy = (popupMenuPoint.y - map.getCenterPointY()) / map.getTileSize();
double fx = (popupMenuPoint.x - map.getCenterPointX()) / map.getTileSize();
double latitude = MapUtils.getLatitudeFromTile(map.getZoom(), map.getYTile() + fy);
double longitude = MapUtils.getLongitudeFromTile(map.getZoom(), map.getXTile() + fx);
endRoute = new LatLon(latitude, longitude);
map.repaint();
}
};
menu.add(end);
Action route = new AbstractAction("Calculate YOURS route") {
private static final long serialVersionUID = 507156107455281238L;
public void actionPerformed(ActionEvent e) {
new Thread(){
@Override
public void run() {
List<Way> ways = route(startRoute, endRoute);
DataTileManager<Way> points = new DataTileManager<Way>();
points.setZoom(11);
for(Way w : ways){
LatLon n = w.getLatLon();
points.registerObject(n.getLatitude(), n.getLongitude(), w);
}
map.setPoints(points);
}
}.start();
}
};
menu.add(route);
Action altroute = new AbstractAction("Calculate CloudMade route") {
private static final long serialVersionUID = 507156107455281238L;
public void actionPerformed(ActionEvent e) {
new Thread() {
@Override
public void run() {
List<Way> ways = alternateRoute(startRoute, endRoute);
DataTileManager<Way> points = new DataTileManager<Way>();
points.setZoom(11);
for (Way w : ways) {
LatLon n = w.getLatLon();
points.registerObject(n.getLatitude(), n.getLongitude(), w);
}
map.setPoints(points);
}
}.start();
}
};
menu.add(altroute);
Action selfRoute = new AbstractAction("Calculate OsmAnd route") {
private static final long serialVersionUID = 507156107455281238L;
public void actionPerformed(ActionEvent e) {
new Thread() {
@Override
public void run() {
List<Way> ways = selfRoute(startRoute, endRoute);
if (ways != null) {
DataTileManager<Way> points = new DataTileManager<Way>();
points.setZoom(11);
for (Way w : ways) {
LatLon n = w.getLatLon();
points.registerObject(n.getLatitude(), n.getLongitude(), w);
}
map.setPoints(points);
}
}
}.start();
}
};
menu.add(selfRoute);
}
// for vector rendering we should extract from osm
// 1. Ways (different kinds) with tag highway= ?,highway=stop ...
// 2. Junction = roundabout
// 3. barrier, traffic_calming=bump
// 4. Save {name, ref} of way to unify it
// + for future routing we should extract from osm
// 1. oneway
// 2. max_speed
// 3. toll
// 4. traffic_signals
// 5. max_heigtht, max_width, min_speed, ...
// 6. incline ?
public static List<Way> route(LatLon start, LatLon end){
List<Way> res = new ArrayList<Way>();
long time = System.currentTimeMillis();
System.out.println("Route from " + start + " to " + end);
if (start != null && end != null) {
try {
StringBuilder uri = new StringBuilder();
uri.append("http://www.yournavigation.org/api/1.0/gosmore.php?format=kml");
uri.append("&flat=").append(start.getLatitude());
uri.append("&flon=").append(start.getLongitude());
uri.append("&tlat=").append(end.getLatitude());
uri.append("&tlon=").append(end.getLongitude());
uri.append("&v=motorcar").append("&fast=1").append("&layer=mapnik");
URL url = new URL(uri.toString());
URLConnection connection = url.openConnection();
StringBuilder content = new StringBuilder();
BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream()));
{
String s = null;
boolean fist = true;
while ((s = reader.readLine()) != null) {
if (fist) {
fist = false;
}
content.append(s).append("\n");
}
System.out.println(content);
}
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder dom = factory.newDocumentBuilder();
Document doc = dom.parse(new InputSource(new StringReader(content.toString())));
NodeList list = doc.getElementsByTagName("coordinates");
for(int i=0; i<list.getLength(); i++){
Node item = list.item(i);
String str = item.getTextContent();
int st = 0;
int next = 0;
Way w = new Way(-1);
while((next = str.indexOf('\n', st)) != -1){
String coordinate = str.substring(st, next + 1);
int s = coordinate.indexOf(',');
if (s != -1) {
try {
double lon = Double.parseDouble(coordinate.substring(0, s));
double lat = Double.parseDouble(coordinate.substring(s + 1));
w.addNode(new net.osmand.osm.Node(lat, lon, -1));
} catch (NumberFormatException e) {
}
}
st = next + 1;
}
if(!w.getNodes().isEmpty()){
res.add(w);
}
}
} catch (IOException e) {
ExceptionHandler.handle(e);
} catch (ParserConfigurationException e) {
ExceptionHandler.handle(e);
} catch (SAXException e) {
ExceptionHandler.handle(e);
}
System.out.println("Finding routes " + res.size() + " " + (System.currentTimeMillis() - time) + " ms");
}
return res;
}
public List<Way> alternateRoute(LatLon start, LatLon end) {
List<Way> res = new ArrayList<Way>();
long time = System.currentTimeMillis();
System.out.println("Cloud made route from " + start + " to " + end);
if (start != null && end != null) {
try {
StringBuilder uri = new StringBuilder();
// possibly hide that API key because it is privacy of osmand
uri.append("http://routes.cloudmade.com/A6421860EBB04234AB5EF2D049F2CD8F/api/0.3/");
uri.append(start.getLatitude()+"").append(",");
uri.append(start.getLongitude()+"").append(",");
uri.append(end.getLatitude()+"").append(",");
uri.append(end.getLongitude()+"").append("/");
uri.append("car.gpx").append("?lang=ru");
URL url = new URL(uri.toString());
URLConnection connection = url.openConnection();
StringBuilder content = new StringBuilder();
BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream()));
{
String s = null;
boolean fist = true;
while ((s = reader.readLine()) != null) {
if (fist) {
fist = false;
}
content.append(s).append("\n");
}
System.out.println(content);
}
DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
DocumentBuilder dom = factory.newDocumentBuilder();
Document doc = dom.parse(new InputSource(new StringReader(content.toString())));
NodeList list = doc.getElementsByTagName("wpt");
Way w = new Way(-1);
for (int i = 0; i < list.getLength(); i++) {
Element item = (Element) list.item(i);
try {
double lon = Double.parseDouble(item.getAttribute("lon"));
double lat = Double.parseDouble(item.getAttribute("lat"));
w.addNode(new net.osmand.osm.Node(lat, lon, -1));
} catch (NumberFormatException e) {
}
}
list = doc.getElementsByTagName("rtept");
for (int i = 0; i < list.getLength(); i++) {
Element item = (Element) list.item(i);
try {
double lon = Double.parseDouble(item.getAttribute("lon"));
double lat = Double.parseDouble(item.getAttribute("lat"));
System.out.println("Lat " + lat + " lon " + lon);
System.out.println("Distance : " + item.getElementsByTagName("distance").item(0).getTextContent());
System.out.println("Time : " + item.getElementsByTagName("time").item(0).getTextContent());
System.out.println("Offset : " + item.getElementsByTagName("offset").item(0).getTextContent());
System.out.println("Direction : " + item.getElementsByTagName("direction").item(0).getTextContent());
} catch (NumberFormatException e) {
}
}
if (!w.getNodes().isEmpty()) {
res.add(w);
}
} catch (IOException e) {
ExceptionHandler.handle(e);
} catch (ParserConfigurationException e) {
ExceptionHandler.handle(e);
} catch (SAXException e) {
ExceptionHandler.handle(e);
}
System.out.println("Finding cloudmade routes " + res.size() + " " + (System.currentTimeMillis() - time) + " ms");
}
return res;
}
public List<Way> selfRoute(LatLon start, LatLon end) {
List<Way> res = new ArrayList<Way>();
long time = System.currentTimeMillis();
File[] files = DataExtractionSettings.getSettings().getDefaultRoutingFile();
if(files == null){
JOptionPane.showMessageDialog(OsmExtractionUI.MAIN_APP.getFrame(), "Please specify obf file in settings", "Obf file not found",
JOptionPane.ERROR_MESSAGE);
return null;
}
System.out.println("Self made route from " + start + " to " + end);
if (start != null && end != null) {
try {
BinaryMapIndexReader[] rs = new BinaryMapIndexReader[files.length];
for(int i=0; i<files.length; i++){
RandomAccessFile raf = new RandomAccessFile(files[i], "r"); //$NON-NLS-1$ //$NON-NLS-2$
rs[i] = new BinaryMapIndexReader(raf);
}
BinaryRouteDataReader router = new BinaryRouteDataReader(rs);
RoutingContext ctx = new RoutingContext();
// find closest way
RouteSegment st = router.findRouteSegment(start.getLatitude(), start.getLongitude(), ctx);
if (st != null) {
BinaryMapDataObject road = st.getRoad();
TagValuePair pair = road.getTagValue(0);
System.out.println("ROAD TO START " + pair.tag + " " + pair.value + " " + road.getName() + " "
+ (road.getId() >> 3));
}
RouteSegment e = router.findRouteSegment(end.getLatitude(), end.getLongitude(), ctx);
if ( e != null) {
BinaryMapDataObject road = e.getRoad();
TagValuePair pair = road.getTagValue(0);
System.out.println("ROAD TO END " + pair.tag + " " + pair.value + " " + road.getName()+ " " +
+ (road.getId() >> 3));
}
final DataTileManager<Way> points = new DataTileManager<Way>();
points.setZoom(11);
map.setPoints(points);
ctx.visitor = new RouteSegmentVisitor() {
private final static int F_SIZE = 10;
private List<RouteSegment> cache = new ArrayList<RouteSegment>();
@Override
public void visitSegment(RouteSegment s) {
cache.add(s);
if(cache.size() < F_SIZE){
return;
}
for (RouteSegment segment : cache) {
Way way = new Way(-1);
for (int i = 0; i < segment.getRoad().getPointsLength(); i++) {
net.osmand.osm.Node n = new net.osmand.osm.Node(MapUtils.get31LatitudeY(segment.getRoad()
.getPoint31YTile(i)), MapUtils.get31LongitudeX(segment.getRoad().getPoint31XTile(i)), -1);
way.addNode(n);
}
LatLon n = way.getLatLon();
points.registerObject(n.getLatitude(), n.getLongitude(), way);
}
cache.clear();
try {
SwingUtilities.invokeAndWait(new Runnable() {
@Override
public void run() {
map.prepareImage();
}
});
} catch (InterruptedException e1) {
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
};
List<RouteSegmentResult> searchRoute = router.searchRoute(ctx, st, e);
try {
Thread.sleep(4000);
} catch (InterruptedException e1) {
}
for(RouteSegmentResult s : searchRoute){
// double dist = MapUtils.getDistance(s.startPoint, s.endPoint);
Way way = new Way(-1);
boolean plus = s.startPointIndex < s.endPointIndex;
int i=s.startPointIndex;
while (true) {
net.osmand.osm.Node n = new net.osmand.osm.Node(MapUtils.get31LatitudeY(s.object.getPoint31YTile(i)), MapUtils
.get31LongitudeX(s.object.getPoint31XTile(i)), -1);
way.addNode(n);
if (i == s.endPointIndex) {
break;
}
if (plus) {
i++;
} else {
i--;
}
}
res.add(way);
}
} catch (IOException e) {
ExceptionHandler.handle(e);
}
System.out.println("Finding self routes " + res.size() + " " + (System.currentTimeMillis() - time) + " ms");
}
return res;
}
@Override
public void prepareToDraw() {
}
@Override
public void paintLayer(Graphics g) {
g.setColor(Color.green);
if(startRoute != null){
int x = map.getMapXForPoint(startRoute.getLongitude());
int y = map.getMapYForPoint(startRoute.getLatitude());
g.drawOval(x, y, 12, 12);
g.fillOval(x, y, 12, 12);
}
g.setColor(Color.red);
if(endRoute != null){
int x = map.getMapXForPoint(endRoute.getLongitude());
int y = map.getMapYForPoint(endRoute.getLatitude());
g.drawOval(x, y, 12, 12);
g.fillOval(x, y, 12, 12);
}
}
}