implement layers for map panel, investigate loading process

git-svn-id: https://osmand.googlecode.com/svn/trunk@149 e29c36b1-1cfa-d876-8d93-3434fc2bb7b8
This commit is contained in:
Victor Shcherb 2010-06-10 19:36:21 +00:00
parent 3e536eb61c
commit a50b00c7e7
14 changed files with 603 additions and 267 deletions

View file

@ -19,6 +19,8 @@ public interface IProgress {
public void remaining(int remainingWork);
public void setGeneralProgress(String genProgress);
public void finishTask();
public boolean isIndeterminate();

View file

@ -16,16 +16,6 @@ public class ToDoConstants {
// }
// }
// PREPARE RELEASE OPTIONS LIST :
// 1. Revise UI (icons/layouts). Support different devices. Add inactive/focus(!) icon versions.
// 2. Translation (support russian) +
// 3. POI Search ( 1) predefined filters, 2) choose subtype's, 3) filter by name, 4) opening hours (filter)) +
// 4. Support old-versionned resources (1) odb indexes, 2) favourites table, 3) atomic settings (?))
// 5. Swing refactoring MapPanel (support layers) +
// 6. Support vector road rendering (new index file) !
// 7. Suppport navigation for calculated route. !
// 8. Editing POI on map +
/**
@ -35,33 +25,31 @@ public class ToDoConstants {
// TODO ANDROID
// 8. Enable change POI directly on map (requires OSM login)
// 30. Performance issue with map drawing :
// 31. Translation.
// 32. Introduce POI predefined filters (car filter(other-fuel, transportation-car_wash, show-car) and others)
// 33. Build transport locations (investigate)
// 34. Investigate routing (bicycle, car)
// ( 1) predefined filters, 2) choose subtype's, 3) filter by name, 4) opening hours (filter))
// 33. Build transport locations. Create transport index (transport-stops) (investigate)
// 34. Suppport navigation for calculated route (example of get route from internet is in swing app).
// 36. Postcode search
// 37. Get rid of exit button (!). Think about when notification should go & how clear resources if it is necessary
// 38. Add button in search "navigate to".
// 39. Support old-versionned resources (1) odb indexes, 2) favourites table, 3) atomic settings (?))
// 20. Implement save track/route to gpx (?)
// 26. Show the whole street on map (when it is chosen in search activity). Possibly extend that story to show layer with streets.
// 40. Support simple vector road rendering (require new index file)
// 41. POI layer over map (shows poi by selected filter)
// 42. Revise UI (icons/layouts). Support different devices. Add inactive/focus(!) icon versions.
// BUGS Android
// 1. Fix bug with navigation layout (less zoom controls) [fixed].
// 4. Fix layout problems with add comment [fixed]
// 7. Fix set location (clear sync with gps) [fixed]
// 3. Implement clear existing area with tiles (update map) [fixed]
// 6. Implement context menu for long press & trackball press [fixed - trackball todo]
// 2. Include to amenity index : historic, sport, ....
// 5. Improvement : Implement caching files existing on FS, implement specific method in RM
// Introducing cache of file names that are on disk (creating new File() consumes a lot of memory)
// TODO swing
// 2. Internal (Simplify MapPanel - introduce layers for it)ю
// 3. Implement clear progress.
// 4. Fix issues with big files (such as netherlands)
// 1. Download tiles without using dir tiles
// 1. Download tiles without using dir tiles (?)
@ -74,4 +62,5 @@ public class ToDoConstants {
// 35. Enable trackball navigation in android
// DONE SWING
// 2. Internal (Simplify MapPanel - introduce layers for it)
}

View file

@ -14,6 +14,8 @@ import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.Map;
import javax.xml.parsers.ParserConfigurationException;
import net.sf.junidecode.Junidecode;
import org.apache.commons.logging.Log;
@ -31,6 +33,7 @@ import com.osmand.data.MapObject;
import com.osmand.data.Region;
import com.osmand.data.Street;
import com.osmand.data.City.CityType;
import com.osmand.impl.ConsoleProgressImplementation;
import com.osmand.osm.Entity;
import com.osmand.osm.LatLon;
import com.osmand.osm.MapUtils;
@ -231,6 +234,23 @@ public class DataExtraction {
}
// Information about progress for belarus.osm [165 seconds]
// FINE: Loading file E:\Information\OSM maps\belarus_2010_06_02.osm started - 61%
// FINE: Correlating data... started after 101921 ms - 10%
// FINE: Indexing poi... started after 17062 ms - 0 %
// FINE: Indexing cities... started after 47 ms - 0%
// FINE: Indexing streets... started after 94 ms - 10%
// FINE: Indexing buildings... started after 16531 ms - 20 %
// FINE: Normalizing name streets... started after 30890 ms - 0%
// minsk.bz2 [36]
// FINE: Loading file E:\Information\OSM maps\minsk_extr.bz2 started - 63%
// FINE: Correlating data... started after 23829 ms - 27%
// FINE: Indexing poi... started after 10547 ms - 0%
// FINE: Indexing cities... started after 31 ms - 0%
// FINE: Indexing streets... started after 94 ms - 0%
// FINE: Indexing buildings... started after 672 ms - 1%
// FINE: Normalizing name streets... started after 2421 ms - 7%
public Region readCountry(String path, IProgress progress, IOsmStorageFilter addFilter) throws IOException, SAXException, SQLException{
// data to load & index
@ -268,12 +288,14 @@ public class DataExtraction {
filter.initDatabase();
// 0.2 parsing osm itself
progress.setGeneralProgress("[40 of 100]");
storage.parseOSM(stream, progress, streamFile, parseEntityInfo);
if (log.isInfoEnabled()) {
log.info("File parsed : " + (System.currentTimeMillis() - st));
}
progress.finishTask();
progress.setGeneralProgress("[55 of 100]");
// 0.3 Correlating data (linking way & node)
filter.correlateData(storage, progress);
@ -291,25 +313,33 @@ public class DataExtraction {
country.setStorage(storage);
// 2. Reading amenities
progress.setGeneralProgress("[60 of 100]");
progress.startTask("Indexing poi...", -1);
if (indexPOI) {
readingAmenities(amenities, country);
}
// 3. Reading cities
progress.setGeneralProgress("[65 of 100]");
progress.startTask("Indexing cities...", -1);
readingCities(places, country);
if (indexAddress) {
// 4. Reading streets
progress.setGeneralProgress("[80 of 100]");
readingStreets(progress, ways, country);
// 5. reading buildings
progress.setGeneralProgress("[95 of 100]");
readingBuildings(progress, buildings, country);
}
progress.setGeneralProgress("[100 of 100]");
if(normalizeStreets){
// 6. normalizing streets
normalizingStreets(progress, country);
}
// 7. Call data preparation to sort cities, calculate center location, assign id to objects
country.doDataPreparation();
// 8. Transliterate names to english
@ -498,4 +528,59 @@ public class DataExtraction {
}
}
// Performance testing methods
public static void main(String[] args) throws IOException, SAXException, SQLException, ParserConfigurationException {
ArrayList<Entity> amenities = new ArrayList<Entity>();
ArrayList<Entity> buildings = new ArrayList<Entity>();
ArrayList<Node> places = new ArrayList<Node>();
ArrayList<Way> ways = new ArrayList<Way>();
long time = System.currentTimeMillis();
OsmBaseStorage storage = new OsmBaseStorage();
String path = "E:\\Information\\OSM maps\\belarus_2010_06_02.osm";
// String path = "E:\\Information\\OSM maps\\minsk_extr.bz2";
// String path = "E:\\Information\\OSM maps\\netherlands.osm.bz2";
String wDir = "E:\\Information\\OSM maps\\osmand\\";
File f = new File(path);
InputStream stream = new FileInputStream(f);
InputStream streamFile = stream;
if (path.endsWith(".bz2")) {
if (stream.read() != 'B' || stream.read() != 'Z') {
throw new RuntimeException("The source stream must start with the characters BZ if it is to be read as a BZip2 stream.");
} else {
stream = new CBZip2InputStream(stream);
}
}
// only sax parser
// if(true){
// SAXParser parser = SAXParserFactory.newInstance().newSAXParser();
// parser.parse(f, new DefaultHandler());
// System.out.println("All time " + (System.currentTimeMillis() - time) + " ms"); //
// }
storage.getFilters().add(new IOsmStorageFilter(){
@Override
public boolean acceptEntityToLoad(OsmBaseStorage storage, Entity entity) {
return false;
}
});
DataExtraction e = new DataExtraction(true, true, true, false, true, new File(wDir));
DataExtractionOsmFilter filter = e.new DataExtractionOsmFilter(amenities, buildings, places, ways);
filter.initDatabase();
storage.getFilters().add(filter);
// belarus.osm - 22 843 (only sax), 33 344 (wo filter), 82 829 (filter)
// storage.parseOSM(stream, null, streamFile, false);
// belarus.osm - 46 938 (wo filter), 98 188 (filter)
// netherlands.osm - 1743 511 (wo filter)
storage.parseOSM(stream, new ConsoleProgressImplementation(), streamFile, true);
System.out.println("Total mem: " + Runtime.getRuntime().totalMemory() + " free : " + Runtime.getRuntime().freeMemory());
System.out.println("All time " + (System.currentTimeMillis() - time) + " ms"); //
System.out.println(amenities.size() + " " + buildings.size() + " " + places.size() + " " + ways.size());
}
}

View file

@ -74,4 +74,8 @@ public class ConsoleProgressImplementation implements IProgress {
return false;
}
@Override
public void setGeneralProgress(String genProgress) {
}
}

View file

@ -60,6 +60,7 @@ public class OsmBaseStorage extends DefaultHandler {
protected Map<Long, EntityInfo> entityInfo = new LinkedHashMap<Long, EntityInfo>();
// this is used to show feedback to user
protected int progressEntity = 0;
protected IProgress progress;
protected InputStream inputStream;
protected InputStream streamForProgress;
@ -164,6 +165,8 @@ public class OsmBaseStorage extends DefaultHandler {
parseStarted = true;
}
private static final int moduleProgress = 1 << 10;
@Override
public void startElement(String uri, String localName, String name, Attributes attributes) throws SAXException {
name = saxParser.isNamespaceAware() ? localName : name;
@ -171,7 +174,9 @@ public class OsmBaseStorage extends DefaultHandler {
initRootElement(uri, localName, name, attributes);
}
if (currentParsedEntity == null) {
if(progress != null && !progress.isIndeterminate() && streamForProgress != null){
progressEntity ++;
if(progress != null && ((progressEntity & moduleProgress) == 0) &&
!progress.isIndeterminate() && streamForProgress != null){
try {
progress.remaining(streamForProgress.available());
} catch (IOException e) {

View file

@ -13,8 +13,10 @@ import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
@ -67,7 +69,7 @@ public class MinskTransReader {
public static final String pathToRoutes = "E:/routes.txt";
public static final String pathToStops = "E:/stops.txt";
public static final String pathToMinsk = "E:\\Information\\OSM maps\\data.osm";
public static final String pathToMinsk = "E:\\Information\\OSM maps\\minsk_streets.osm";
public static final String pathToSave = "E:\\Information\\OSM maps\\data_edit.osm";
public static void main(String[] args) throws IOException, SAXException, XMLStreamException {
@ -202,7 +204,6 @@ public class MinskTransReader {
}
}
}
for(Node stop : busStops.getAllObjects()){
if(!usedNodes.contains(stop) && "yes".equals(stop.getTag("generated"))){
EntityInfo info = storage.getRegisteredEntityInfo().get(stop.getId());
@ -226,9 +227,12 @@ public class MinskTransReader {
@Override
public boolean acceptEntityToLoad(OsmBaseStorage storage, Entity entity) {
if(entity.getTag("route") != null){
String route = entity.getTag("route");
if(route.equals("bus") || route.equals("tram") || route.equals("trolleybus") || route.equals("subway")){
definedRoutes.put(entity.getTag("route") + "_" + entity.getTag("ref"), (Relation) entity);
return true;
}
}
if(entity.getTag(OSMTagKey.HIGHWAY) != null && entity.getTag(OSMTagKey.HIGHWAY).equals("bus_stop")){
LatLon e = entity.getLatLon();
busStops.registerObject(e.getLatitude(), e.getLongitude(), (Node) entity);
@ -249,6 +253,58 @@ public class MinskTransReader {
return storage;
}
protected static boolean validateRoute(String routeStr, Map<String, TransportStop> trStops, Map<String, Node> correlated, Relation relation, TransportRoute route, boolean direct){
Collection<Entity> stops = relation.getMembers("stop");
routeStr += direct ? "_forward" : "_backward";
if(stops.size() != 2){
System.out.println("[INVALID ] " + routeStr + " : doesn't contain start/final stop.");
return false;
}
List<Entity> list = new ArrayList<Entity>(relation.getMembers(direct?"forward:stop" : "backward:stop"));
if((list.size() + 2) != route.routeStops.size()){
System.out.println("[INVALID ] " + routeStr + " number of stops isn't equal (" +
((list.size() + 2)) + " relation != " + route.routeStops.size() + " route) ");
return false;
}
Iterator<Entity> it = stops.iterator();
Entity start = it.next();
Entity end = it.next();
if(direct){
list.add(0, start);
list.add(end);
} else {
list.add(0, end);
list.add(start);
}
for(int i=0; i<list.size(); i++){
String st = route.routeStops.get(i);
Node correlatedNode = correlated.get(st);
TransportStop trStop = trStops.get(st);
String stStr = trStop.stopId + " " + trStop.name;
Entity e = list.get(i);
if(correlatedNode == null){
double dist = MapUtils.getDistance(e.getLatLon(), trStop.latitude, trStop.longitude);
if(dist > 20){
System.out.println("[INVALID ]" + routeStr + " stop " + (i+1) + " was not correlated " + stStr + " distance = " + dist);
return false;
}
} else if(correlatedNode.getId() != e.getId()){
double dist = MapUtils.getDistance(correlatedNode, e.getLatLon());
if(i==list.size() - 1 && !direct && dist < 150){
continue;
}
String eStop = e.getId() + " " + e.getTag(OSMTagKey.NAME);
System.out.println("[INVALID ] " + routeStr + " stop " + (i+1) + " wrong : " + stStr + " != " + eStop + " dist = " + dist +
" current correlated to " + correlatedNode.getId());
return false;
}
}
return true;
}
protected static long id = -55000;
protected static void registerNewRoutesAndEditExisting(Map<String, TransportStop> stopsMap, List<TransportRoute> routes,
OsmBaseStorage storage, final Map<String, Relation> definedRoutes, Map<String, Node> correlated) {
@ -276,6 +332,10 @@ public class MinskTransReader {
if (definedRoutes.containsKey(s)) {
checkedRoutes.put(s, definedRoutes.get(s));
boolean valid = validateRoute(s, stopsMap, correlated, definedRoutes.get(s), r, direct);
if(valid){
System.err.println("VALID " + s + " " + direct);
}
// System.out.println("Already registered " + s);
} else {
if (!checkedRoutes.containsKey(s)) {

View file

@ -0,0 +1,109 @@
package com.osmand.swing;
import java.awt.Color;
import java.awt.Component;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.text.MessageFormat;
import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.BorderFactory;
import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JLabel;
public class MapInformationLayer implements MapPanelLayer {
private MapPanel map;
private JLabel gpsLocation;
private JButton areaButton;
@Override
public void destroyLayer() {
}
@Override
public void initLayer(final MapPanel map) {
this.map = map;
BoxLayout layout = new BoxLayout(map, BoxLayout.LINE_AXIS);
map.setLayout(layout);
map.setBorder(BorderFactory.createEmptyBorder(2, 10, 10, 10));
gpsLocation = new JLabel();
gpsLocation.setOpaque(false);
updateLocationLabel();
JButton zoomIn = new JButton("+");
JButton zoomOut = new JButton("-");
areaButton = new JButton();
areaButton.setAction(new AbstractAction("Preload area"){
private static final long serialVersionUID = -5512220294374994021L;
@Override
public void actionPerformed(ActionEvent e) {
new TileBundleDownloadDialog(map, map).showDialog();
}
});
zoomIn.addActionListener(new ActionListener(){
@Override
public void actionPerformed(ActionEvent e) {
map.setZoom(map.getZoom() + 1);
}
});
zoomOut.addActionListener(new ActionListener(){
@Override
public void actionPerformed(ActionEvent e) {
map.setZoom(map.getZoom() - 1);
}
});
map.add(gpsLocation);
map.add(Box.createHorizontalGlue());
map.add(areaButton);
map.add(zoomIn);
map.add(zoomOut);
gpsLocation.setAlignmentY(Component.TOP_ALIGNMENT);
areaButton.setVisible(false);
areaButton.setAlignmentY(Component.TOP_ALIGNMENT);
zoomOut.setAlignmentY(Component.TOP_ALIGNMENT);
zoomIn.setAlignmentY(Component.TOP_ALIGNMENT);
}
public void setAreaButtonVisible(boolean b){
areaButton.setVisible(b);
}
public void setAreaActionHandler(Action a){
areaButton.setAction(a);
}
private void updateLocationLabel(){
double latitude = map.getLatitude();
double longitude = map.getLongitude();
int zoom = map.getZoom();
gpsLocation.setText(MessageFormat.format("Lat : {0,number,#.####}, lon : {1,number,#.####}, zoom : {2}", latitude, longitude, zoom));
}
@Override
public void prepareToDraw() {
updateLocationLabel();
}
@Override
public void paintLayer(Graphics g) {
g.setColor(Color.black);
g.fillOval((int)map.getCenterPointX() - 2,(int) map.getCenterPointY() - 2, 4, 4);
g.drawOval((int)map.getCenterPointX() - 2,(int) map.getCenterPointY() - 2, 4, 4);
g.drawOval((int)map.getCenterPointX() - 5,(int) map.getCenterPointY()- 5, 10, 10);
}
}

View file

@ -2,7 +2,6 @@ package com.osmand.swing;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Container;
import java.awt.Graphics;
import java.awt.Image;
@ -18,13 +17,9 @@ import java.awt.event.MouseEvent;
import java.awt.event.MouseWheelEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.geom.AffineTransform;
import java.awt.geom.Line2D;
import java.awt.geom.Point2D;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
@ -32,15 +27,8 @@ import java.util.Map;
import javax.imageio.IIOException;
import javax.imageio.ImageIO;
import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.BorderFactory;
import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JCheckBoxMenuItem;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JPanel;
@ -61,8 +49,6 @@ import com.osmand.map.TileSourceManager.TileSourceTemplate;
import com.osmand.osm.Entity;
import com.osmand.osm.LatLon;
import com.osmand.osm.MapUtils;
import com.osmand.osm.Node;
import com.osmand.osm.Way;
public class MapPanel extends JPanel implements IMapDownloaderCallback {
@ -135,17 +121,11 @@ public class MapPanel extends JPanel implements IMapDownloaderCallback {
// name of source map
private ITileSource map;
// special points to draw
private DataTileManager<? extends Entity> points;
// zoom level
private int zoom = 1;
// degree measurements (-180, 180)
// долгота
private double longitude;
// широта
// degree measurements (90, -90)
private double latitude;
@ -153,27 +133,18 @@ public class MapPanel extends JPanel implements IMapDownloaderCallback {
private MapSelectionArea selectionArea = new MapSelectionArea();
private LatLon startRoute;
private LatLon endRoute;
private List<MapPanelLayer> layers = new ArrayList<MapPanelLayer>();
// cached data to draw image
private Image[][] images;
private int xStartingImage = 0;
private int yStartingImage = 0;
private List<Point> pointsToDraw = new ArrayList<Point>();
private List<Line2D> linesToDraw = new ArrayList<Line2D>();
private MapTileDownloader downloader = MapTileDownloader.getInstance();
Map<String, Image> cache = new HashMap<String, Image>();
private JLabel gpsLocation;
private JButton areaButton;
private JPopupMenu popupMenu;
private Point popupMenuPoint;
private boolean willBePopupShown = false;
@ -187,9 +158,7 @@ public class MapPanel extends JPanel implements IMapDownloaderCallback {
longitude = defaultLocation.getLongitude();
zoom = DataExtractionSettings.getSettings().getDefaultZoom();
addControls();
popupMenu = new JPopupMenu();
downloader.addDownloaderCallback(this);
setFocusable(true);
addComponentListener(new ComponentAdapter(){
@ -203,9 +172,10 @@ public class MapPanel extends JPanel implements IMapDownloaderCallback {
addMouseMotionListener(mouse);
addMouseWheelListener(mouse);
initDefaultLayers();
}
@Override
public void setVisible(boolean flag) {
super.setVisible(flag);
@ -235,7 +205,8 @@ public class MapPanel extends JPanel implements IMapDownloaderCallback {
double tileX = MapUtils.getTileNumberX(zoom, longitude);
return (int) ((tileX - getXTile()) * getTileSize() + getCenterPointX());
}
private double getCenterPointX() {
public double getCenterPointX() {
return getWidth() / 2;
}
@ -245,7 +216,7 @@ public class MapPanel extends JPanel implements IMapDownloaderCallback {
return (int) ((tileY - getYTile()) * getTileSize() + getCenterPointY());
}
private double getCenterPointY() {
public double getCenterPointY() {
return getHeight() / 2;
}
@ -276,46 +247,8 @@ public class MapPanel extends JPanel implements IMapDownloaderCallback {
}
}
}
g.setColor(Color.black);
// draw user points
for (Point p : pointsToDraw) {
g.drawOval(p.x, p.y, 3, 3);
g.fillOval(p.x, p.y, 3, 3);
}
g.setColor(Color.green);
if(startRoute != null){
int x = getMapXForPoint(startRoute.getLongitude());
int y = getMapYForPoint(startRoute.getLatitude());
g.drawOval(x, y, 12, 12);
g.fillOval(x, y, 12, 12);
}
g.setColor(Color.red);
if(endRoute != null){
int x = getMapXForPoint(endRoute.getLongitude());
int y = getMapYForPoint(endRoute.getLatitude());
g.drawOval(x, y, 12, 12);
g.fillOval(x, y, 12, 12);
}
g.setColor(Color.black);
// draw user points
int[] xPoints = new int[4];
int[] yPoints = new int[4];
for (Line2D p : linesToDraw) {
AffineTransform transform = new AffineTransform();
transform.translate(p.getX1(), p.getY1());
transform.rotate(p.getX2() - p.getX1(), p.getY2() - p.getY1());
xPoints[1] = xPoints[0] = 0;
xPoints[2] = xPoints[3] = (int) Math.sqrt((p.getX2() - p.getX1())*(p.getX2() - p.getX1()) +
(p.getY2() - p.getY1())*(p.getY2() - p.getY1())) +1;
yPoints[3] = yPoints[0] = 0;
yPoints[2] = yPoints[1] = 2;
for(int i=0; i< 4; i++){
Point2D po = transform.transform(new Point(xPoints[i], yPoints[i]), null);
xPoints[i] = (int) po.getX();
yPoints[i] = (int) po.getY();
}
g.drawPolygon(xPoints, yPoints, 4);
g.fillPolygon(xPoints, yPoints, 4);
for(MapPanelLayer l : layers){
l.paintLayer(g);
}
if(selectionArea.isVisible()){
@ -323,19 +256,9 @@ public class MapPanel extends JPanel implements IMapDownloaderCallback {
Rectangle r = selectionArea.getSelectedArea();
g.fillRect(r.x, r.y, r.width, r.height);
}
g.setColor(Color.black);
g.fillOval(getWidth() / 2 - 2, getHeight() / 2 - 2, 4, 4);
g.drawOval(getWidth() / 2 - 2, getHeight() / 2 - 2, 4, 4);
g.drawOval(getWidth() / 2 - 5, getHeight() / 2 - 5, 10, 10);
super.paintComponent(g);
}
public File getTilesLocation() {
return tilesLocation;
}
@ -346,7 +269,6 @@ public class MapPanel extends JPanel implements IMapDownloaderCallback {
prepareImage();
}
public String getFileForImage (int x, int y, int zoom, String ext){
return map.getName() +"/"+zoom+"/"+(x) +"/"+y+ext+".tile";
}
@ -398,10 +320,6 @@ public class MapPanel extends JPanel implements IMapDownloaderCallback {
return cache.get(file);
}
public void setAreaActionHandler(Action a){
areaButton.setAction(a);
}
@Override
public void tileDownloaded(DownloadRequest request) {
if(request == null){
@ -415,7 +333,6 @@ public class MapPanel extends JPanel implements IMapDownloaderCallback {
int j = request.yTile - (int)yTileUp;
if (request.zoom == this.zoom && (i >= 0 && i < images.length) && (j >= 0 && j < images[i].length)) {
try {
System.out.println();
images[i][j] = getImageFor(request.xTile, request.yTile, zoom, false);
repaint();
} catch (IOException e) {
@ -439,11 +356,10 @@ public class MapPanel extends JPanel implements IMapDownloaderCallback {
}
}
}
double xTileLeft = getXTile() - getSize().width / (2d * tileSize);
double xTileRight = getXTile() + getSize().width / (2d * tileSize);
double yTileUp = getYTile() - getSize().height / (2d * tileSize);
double yTileDown = getYTile() + getSize().height / (2d * tileSize);
double xTileLeft = getXTile() - getCenterPointX() / tileSize;
double xTileRight = getXTile() + getCenterPointX() / tileSize;
double yTileUp = getYTile() - getCenterPointY() / tileSize;
double yTileDown = getYTile() + getCenterPointY() / tileSize;
xStartingImage = -(int) ((xTileLeft - Math.floor(xTileLeft)) * tileSize);
yStartingImage = -(int) ((yTileUp - Math.floor(yTileUp)) * tileSize);
@ -462,44 +378,9 @@ public class MapPanel extends JPanel implements IMapDownloaderCallback {
}
}
if (points != null) {
double latDown = MapUtils.getLatitudeFromTile(zoom, yTileDown);
double longDown = MapUtils.getLongitudeFromTile(zoom, xTileRight);
double latUp = MapUtils.getLatitudeFromTile(zoom, yTileUp);
double longUp = MapUtils.getLongitudeFromTile(zoom, xTileLeft);
List<? extends Entity> objects = points.getObjects(latUp, longUp, latDown, longDown);
pointsToDraw.clear();
linesToDraw.clear();
for (Entity e : objects) {
if(e instanceof Way){
List<Node> nodes = ((Way)e).getNodes();
if (nodes.size() > 1) {
int prevPixX = 0;
int prevPixY = 0;
for (int i = 0; i < nodes.size(); i++) {
Node n = nodes.get(i);
int pixX = MapUtils.getPixelShiftX(zoom, n.getLongitude(), this.longitude, tileSize) + getWidth() / 2;
int pixY = MapUtils.getPixelShiftY(zoom, n.getLatitude(), this.latitude, tileSize) + getHeight() / 2;
if (i > 0) {
linesToDraw.add(new Line2D.Float(pixX, pixY, prevPixX, prevPixY));
for(MapPanelLayer l : layers){
l.prepareToDraw();
}
prevPixX = pixX;
prevPixY = pixY;
}
}
} else if(e instanceof Node){
Node n = (Node) e;
int pixX = MapUtils.getPixelShiftX(zoom, n.getLongitude(), this.longitude, tileSize) + getWidth() / 2;
int pixY = MapUtils.getPixelShiftY(zoom, n.getLatitude(), this.latitude, tileSize) + getHeight() / 2;
if (pixX >= 0 && pixY >= 0) {
pointsToDraw.add(new Point(pixX, pixY));
}
} else {
}
}
}
repaint();
} catch (IOException e) {
log.error("Eror reading png preparing images");
@ -513,7 +394,6 @@ public class MapPanel extends JPanel implements IMapDownloaderCallback {
return;
}
this.zoom = zoom;
updateLocationLabel();
prepareImage();
}
@ -563,17 +443,46 @@ public class MapPanel extends JPanel implements IMapDownloaderCallback {
listeners.remove(l);
}
private void updateLocationLabel(){
gpsLocation.setText(MessageFormat.format("Lat : {0,number,#.####}, lon : {1,number,#.####}, zoom : {2}", latitude, longitude, zoom));
}
protected void fireMapLocationListeners(){
updateLocationLabel();
for(IMapLocationListener l : listeners){
l.locationChanged(latitude, longitude, null);
}
}
public List<MapPanelLayer> getLayers() {
return layers;
}
protected void initDefaultLayers() {
addLayer(new MapInformationLayer());
addLayer(new MapRouterLayer());
addLayer(new MapPointsLayer());
}
public void addLayer(MapPanelLayer l){
l.initLayer(this);
layers.add(l);
}
public void addLayer(int ind, MapPanelLayer l){
l.initLayer(this);
layers.add(ind, l);
}
public boolean removeLayer(MapPanelLayer l){
return layers.remove(l);
}
@SuppressWarnings("unchecked")
public <T extends MapPanelLayer> T getLayer(Class<T> cl){
for(MapPanelLayer l : layers){
if(cl.isInstance(l)){
return (T) l;
}
}
return null;
}
@Override
protected void processKeyEvent(KeyEvent e) {
@ -620,116 +529,29 @@ public class MapPanel extends JPanel implements IMapDownloaderCallback {
}
public DataTileManager<? extends Entity> getPoints() {
return points;
return getLayer(MapPointsLayer.class).getPoints();
}
public void setPoints(DataTileManager<? extends Entity> points) {
this.points = points;
getLayer(MapPointsLayer.class).setPoints(points);
prepareImage();
}
public void addControls(){
BoxLayout layout = new BoxLayout(this, BoxLayout.LINE_AXIS);
setLayout(layout);
setBorder(BorderFactory.createEmptyBorder(2, 10, 10, 10));
gpsLocation = new JLabel();
gpsLocation.setOpaque(false);
updateLocationLabel();
JButton zoomIn = new JButton("+");
JButton zoomOut = new JButton("-");
areaButton = new JButton();
areaButton.setAction(new AbstractAction("Preload area"){
private static final long serialVersionUID = -5512220294374994021L;
@Override
public void actionPerformed(ActionEvent e) {
new TileBundleDownloadDialog(MapPanel.this, MapPanel.this).showDialog();
public Point getPopupMenuPoint(){
return popupMenuPoint;
}
});
zoomIn.addActionListener(new ActionListener(){
@Override
public void actionPerformed(ActionEvent e) {
setZoom(getZoom() + 1);
}
});
zoomOut.addActionListener(new ActionListener(){
@Override
public void actionPerformed(ActionEvent e) {
setZoom(getZoom() - 1);
}
});
add(gpsLocation);
add(Box.createHorizontalGlue());
add(areaButton);
add(zoomIn);
add(zoomOut);
gpsLocation.setAlignmentY(Component.TOP_ALIGNMENT);
areaButton.setVisible(false);
areaButton.setAlignmentY(Component.TOP_ALIGNMENT);
zoomOut.setAlignmentY(Component.TOP_ALIGNMENT);
zoomIn.setAlignmentY(Component.TOP_ALIGNMENT);
popupMenu = new JPopupMenu();
fillPopupMenuWithActions(popupMenu);
public JPopupMenu getPopupMenu() {
return popupMenu;
}
public void fillPopupMenuWithActions(JPopupMenu menu) {
Action start = new AbstractAction("Mark start point") {
private static final long serialVersionUID = 507156107455281238L;
public void actionPerformed(ActionEvent e) {
double fy = (popupMenuPoint.y - getCenterPointY()) / getTileSize();
double fx = (popupMenuPoint.x - getCenterPointX()) / getTileSize();
double latitude = MapUtils.getLatitudeFromTile(zoom, getYTile() + fy);
double longitude = MapUtils.getLongitudeFromTile(zoom, getXTile() + fx);
startRoute = new LatLon(latitude, longitude);
repaint();
}
};
menu.add(start);
Action end= new AbstractAction("Mark end point") {
private static final long serialVersionUID = 4446789424902471319L;
public void actionPerformed(ActionEvent e) {
double fy = (popupMenuPoint.y - getCenterPointY()) / getTileSize();
double fx = (popupMenuPoint.x - getCenterPointX()) / getTileSize();
double latitude = MapUtils.getLatitudeFromTile(zoom, getYTile() + fy);
double longitude = MapUtils.getLongitudeFromTile(zoom, getXTile() + fx);
endRoute = new LatLon(latitude, longitude);
repaint();
}
};
menu.add(end);
Action route = new AbstractAction("Calculate route") {
private static final long serialVersionUID = 507156107455281238L;
public void actionPerformed(ActionEvent e) {
List<Way> ways = RoutingHelper.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);
}
MapPanel.this.points = points;
prepareImage();
}
};
menu.add(route);
}
public class MapSelectionArea {
private double lat1;
private double lon1;
private double lat2;
private double lon2;
public double getLat1() {
return lat1;
}
@ -784,7 +606,7 @@ public class MapPanel extends JPanel implements IMapDownloaderCallback {
lat2 = MapUtils.getLatitudeFromTile(zoom, yTile2);
lon1 = MapUtils.getLongitudeFromTile(zoom, xTile1);
lon2 = MapUtils.getLongitudeFromTile(zoom, xTile2);
areaButton.setVisible(isVisible());
getLayer(MapInformationLayer.class).setAreaButtonVisible(isVisible());
}
}
@ -862,7 +684,6 @@ public class MapPanel extends JPanel implements IMapDownloaderCallback {
if(willBePopupShown && e.isPopupTrigger()){
popupMenuPoint = new Point(e.getX(), e.getY());
popupMenu.show(MapPanel.this, e.getX(), e.getY());
willBePopupShown = false;
}
super.mouseReleased(e);

View file

@ -0,0 +1,15 @@
package com.osmand.swing;
import java.awt.Graphics;
public interface MapPanelLayer {
public void initLayer(MapPanel map);
public void destroyLayer();
public void prepareToDraw();
public void paintLayer(Graphics g);
}

View file

@ -0,0 +1,123 @@
package com.osmand.swing;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Point;
import java.awt.geom.AffineTransform;
import java.awt.geom.Line2D;
import java.awt.geom.Point2D;
import java.util.ArrayList;
import java.util.List;
import com.osmand.data.DataTileManager;
import com.osmand.osm.Entity;
import com.osmand.osm.MapUtils;
import com.osmand.osm.Node;
import com.osmand.osm.Way;
public class MapPointsLayer implements MapPanelLayer {
private MapPanel map;
// special points to draw
private DataTileManager<? extends Entity> points;
private List<Point> pointsToDraw = new ArrayList<Point>();
private List<Line2D> linesToDraw = new ArrayList<Line2D>();
@Override
public void destroyLayer() {
}
@Override
public void initLayer(MapPanel map) {
this.map = map;
}
@Override
public void paintLayer(Graphics g) {
g.setColor(Color.black);
// draw user points
for (Point p : pointsToDraw) {
g.drawOval(p.x, p.y, 3, 3);
g.fillOval(p.x, p.y, 3, 3);
}
g.setColor(Color.black);
// draw user points
int[] xPoints = new int[4];
int[] yPoints = new int[4];
for (Line2D p : linesToDraw) {
AffineTransform transform = new AffineTransform();
transform.translate(p.getX1(), p.getY1());
transform.rotate(p.getX2() - p.getX1(), p.getY2() - p.getY1());
xPoints[1] = xPoints[0] = 0;
xPoints[2] = xPoints[3] = (int) Math.sqrt((p.getX2() - p.getX1())*(p.getX2() - p.getX1()) +
(p.getY2() - p.getY1())*(p.getY2() - p.getY1())) +1;
yPoints[3] = yPoints[0] = 0;
yPoints[2] = yPoints[1] = 2;
for(int i=0; i< 4; i++){
Point2D po = transform.transform(new Point(xPoints[i], yPoints[i]), null);
xPoints[i] = (int) po.getX();
yPoints[i] = (int) po.getY();
}
g.drawPolygon(xPoints, yPoints, 4);
g.fillPolygon(xPoints, yPoints, 4);
}
}
@Override
public void prepareToDraw() {
if (points != null) {
double xTileLeft = map.getXTile() - map.getCenterPointX() / map.getTileSize();
double xTileRight = map.getXTile() + map.getCenterPointX() / map.getTileSize();
double yTileUp = map.getYTile() - map.getCenterPointY() / map.getTileSize();
double yTileDown = map.getYTile() + map.getCenterPointY() / map.getTileSize();
double latDown = MapUtils.getLatitudeFromTile(map.getZoom(), yTileDown);
double longDown = MapUtils.getLongitudeFromTile(map.getZoom(), xTileRight);
double latUp = MapUtils.getLatitudeFromTile(map.getZoom(), yTileUp);
double longUp = MapUtils.getLongitudeFromTile(map.getZoom(), xTileLeft);
List<? extends Entity> objects = points.getObjects(latUp, longUp, latDown, longDown);
pointsToDraw.clear();
linesToDraw.clear();
for (Entity e : objects) {
if(e instanceof Way){
List<Node> nodes = ((Way)e).getNodes();
if (nodes.size() > 1) {
int prevPixX = 0;
int prevPixY = 0;
for (int i = 0; i < nodes.size(); i++) {
Node n = nodes.get(i);
int pixX = (int) (MapUtils.getPixelShiftX(map.getZoom(), n.getLongitude(), map.getLongitude(), map.getTileSize()) + map.getCenterPointX());
int pixY = (int) (MapUtils.getPixelShiftY(map.getZoom(), n.getLatitude(), map.getLatitude(), map.getTileSize()) + map.getCenterPointY());
if (i > 0) {
linesToDraw.add(new Line2D.Float(pixX, pixY, prevPixX, prevPixY));
}
prevPixX = pixX;
prevPixY = pixY;
}
}
} else if(e instanceof Node){
Node n = (Node) e;
int pixX = (int) (MapUtils.getPixelShiftX(map.getZoom(), n.getLongitude(), map.getLongitude(), map.getTileSize()) + map.getCenterPointX());
int pixY = (int) (MapUtils.getPixelShiftY(map.getZoom(), n.getLatitude(), map.getLatitude(), map.getTileSize()) + map.getCenterPointY());
if (pixX >= 0 && pixY >= 0) {
pointsToDraw.add(new Point(pixX, pixY));
}
} else {
}
}
}
}
public DataTileManager<? extends Entity> getPoints() {
return points;
}
public void setPoints(DataTileManager<? extends Entity> points) {
this.points = points;
}
}

View file

@ -1,5 +1,9 @@
package com.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.IOException;
import java.io.InputStreamReader;
@ -9,6 +13,9 @@ import java.net.URLConnection;
import java.util.ArrayList;
import java.util.List;
import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.JPopupMenu;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
@ -20,17 +27,81 @@ import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import com.osmand.ExceptionHandler;
import com.osmand.data.DataTileManager;
import com.osmand.osm.LatLon;
import com.osmand.osm.MapUtils;
import com.osmand.osm.Way;
public class RoutingHelper {
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 route") {
private static final long serialVersionUID = 507156107455281238L;
public void actionPerformed(ActionEvent e) {
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);
}
};
menu.add(route);
}
// 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
@ -39,8 +110,6 @@ public class RoutingHelper {
// 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();
@ -110,4 +179,28 @@ public class RoutingHelper {
}
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);
}
}
}

View file

@ -655,7 +655,7 @@ public class OsmExtractionUI implements IMapLocationListener {
panel.setLatLon(mapPanel.getLatitude(), mapPanel.getLongitude());
panel.setZoom(mapPanel.getZoom());
final StringBuilder res = new StringBuilder();
panel.setAreaActionHandler(new AbstractAction("Select area"){
panel.getLayer(MapInformationLayer.class).setAreaActionHandler(new AbstractAction("Select area"){
private static final long serialVersionUID = -3452957517341961969L;
@Override
public void actionPerformed(ActionEvent e) {

View file

@ -12,17 +12,22 @@ import javax.swing.JPanel;
import javax.swing.JProgressBar;
import javax.swing.SwingUtilities;
import org.apache.commons.logging.Log;
import com.osmand.IProgress;
import com.osmand.LogUtil;
public class ProgressDialog extends JDialog implements IProgress {
private static final long serialVersionUID = -3915486672514402269L;
private final static Log log = LogUtil.getLog(ProgressDialog.class);
private JProgressBar progressBar;
private JLabel label;
private Runnable run;
private InvocationTargetException exception = null;
private Object result;
@ -32,6 +37,9 @@ public class ProgressDialog extends JDialog implements IProgress {
private String taskName;
private int deltaWork;
private WorkerThread workerThread;
private String genProgress;
private long previousTaskStarted = 0;
public ProgressDialog(Component parent, String name){
@ -132,7 +140,8 @@ public class ProgressDialog extends JDialog implements IProgress {
private void updateMessage() {
if(!progressBar.isIndeterminate()){
label.setText(taskName + String.format("\t %.1f %%", progressBar.getValue() * 100f / ((float) progressBar.getMaximum())));
String format = String.format("\t %.1f %%", progressBar.getValue() * 100f / ((float) progressBar.getMaximum()));
label.setText(taskName + format + (genProgress == null ? "" : (" " + genProgress)));
}
}
@ -158,12 +167,27 @@ public class ProgressDialog extends JDialog implements IProgress {
return progressBar.isIndeterminate();
}
@Override
public void setGeneralProgress(String genProgress) {
this.genProgress = genProgress;
}
@Override
public void startTask(String taskName, int work) {
if (log.isDebugEnabled()) {
if (previousTaskStarted == 0) {
log.debug(taskName + " started");
} else {
log.debug(taskName + " started after " + (System.currentTimeMillis() - previousTaskStarted) + " ms");
}
log.debug("Total mem: " + Runtime.getRuntime().totalMemory() + " free : " + Runtime.getRuntime().freeMemory());
}
previousTaskStarted = System.currentTimeMillis();
if(taskName == null){
taskName = "";
}
label.setText(taskName);
label.setText(taskName + (genProgress == null ? "" : (" "+genProgress)));
this.taskName = taskName;
startWork(work);
}

View file

@ -110,4 +110,10 @@ public class ProgressDialogImplementation implements IProgress {
deltaWork = 0;
}
@Override
public void setGeneralProgress(String genProgress) {
// not implemented yet
}
}