Merge remote-tracking branch 'origin/master'

This commit is contained in:
Weblate 2017-05-17 18:40:32 +02:00
commit 1461870885
7 changed files with 339 additions and 42 deletions

View file

@ -41,13 +41,15 @@ public class TileSourceManager {
private static final TileSourceTemplate CYCLE_MAP_SOURCE =
new TileSourceTemplate("CycleMap", "http://b.tile.opencyclemap.org/cycle/{0}/{1}/{2}.png", ".png", 16, 1, 256, 32, 18000); //$NON-NLS-1$//$NON-NLS-2$ //$NON-NLS-3$
private static final TileSourceTemplate MAPILLARY_RASTER_SOURCE =
new TileSourceTemplate("Mapillary (raster tiles)", "https://d6a1v2w10ny40.cloudfront.net/v0.1/{0}/{1}/{2}.png", ".png", 14, 0, 256, 16, 32000);
new TileSourceTemplate("Mapillary (raster tiles)", "https://d6a1v2w10ny40.cloudfront.net/v0.1/{0}/{1}/{2}.png", ".png", 13, 0, 256, 16, 32000);
private static final TileSourceTemplate MAPILLARY_VECTOR_SOURCE =
new TileSourceTemplate("Mapillary (vector tiles)", "https://d25uarhxywzl1j.cloudfront.net/v0.1/{0}/{1}/{2}.mvt", ".mvt", 21, 15, 256, 16, 3200);
new TileSourceTemplate("Mapillary (vector tiles)", "https://d25uarhxywzl1j.cloudfront.net/v0.1/{0}/{1}/{2}.mvt", ".mvt", 21, 14, 256, 16, 3200);
static {
MAPILLARY_RASTER_SOURCE.setExpirationTimeMinutes(60 * 24);
MAPILLARY_RASTER_SOURCE.setHidden(true);
MAPILLARY_VECTOR_SOURCE.setExpirationTimeMinutes(60 * 24);
MAPILLARY_VECTOR_SOURCE.setHidden(true);
}
public static class TileSourceTemplate implements ITileSource, Cloneable {
@ -63,7 +65,8 @@ public class TileSourceManager {
private int expirationTimeMillis = -1;
private boolean ellipticYTile;
private String rule;
private boolean hidden; // if hidden in configure map settings, for example mapillary sources
private boolean isRuleAcceptable = true;
public TileSourceTemplate(String name, String urlToLoad, String ext, int maxZoom, int minZoom, int tileSize, int bitDensity,
@ -93,8 +96,15 @@ public class TileSourceManager {
public void setMaxZoom(int maxZoom) {
this.maxZoom = maxZoom;
}
public boolean isHidden() {
return hidden;
}
public void setHidden(boolean hidden) {
this.hidden = hidden;
}
public void setName(String name) {
this.name = name;
}
@ -430,7 +440,6 @@ public class TileSourceManager {
list.add(getMapillaryRasterSource());
list.add(getMapillaryVectorSource());
return list;
}
public static TileSourceTemplate getMapnikSource(){

View file

@ -9,6 +9,7 @@
3. All your modified/created strings are in the top of the file (to make easier find what\'s translated).
PLEASE: Have a look at http://code.google.com/p/osmand/wiki/UIConsistency, it may really improve your and our work :-) Thx - Hardy
-->
<string name="mapillary_image">Mapillary image</string>
<string name="open_mapillary">Open Mapillary</string>
<string name="shared_string_install">Install</string>
<string name="improve_coverage_mapillary">Improve coverage with Mapillary</string>

View file

@ -44,6 +44,7 @@ public class PointDescription {
public static final String POINT_TYPE_BLOCKED_ROAD = "blocked_road";
public static final String POINT_TYPE_TRANSPORT_ROUTE = "transport_route";
public static final String POINT_TYPE_TRANSPORT_STOP = "transport_stop";
public static final String POINT_TYPE_MAPILLARY_IMAGE = "mapillary_image";
public static final PointDescription LOCATION_POINT = new PointDescription(POINT_TYPE_LOCATION, "");

View file

@ -1407,7 +1407,11 @@ public class OsmandSettings {
}
}
for (TileSourceTemplate l : TileSourceManager.getKnownSourceTemplates()) {
map.put(l.getName(), l.getName());
if (!l.isHidden()) {
map.put(l.getName(), l.getName());
} else {
map.remove(l.getName());
}
}
return map;

View file

@ -1,15 +1,88 @@
package net.osmand.plus.mapillary;
import net.osmand.util.Algorithms;
import java.util.Map;
public class MapillaryImage {
/*
* ca number Camera heading. -1 if not found.
* captured_at number When the image was captured, expressed as UTC epoch time in milliseconds. Must be non-negative integer; 0 if not found.
* key Key Image key.
* pano number Whether the image is panorama ( 1 ), or not ( 0 ).
* skey Key Sequence key.
* userkey Key User key. Empty if not found.
*/
// Image location
private double latitude;
private double longitude;
// Camera heading. -1 if not found.
private double ca = -1;
// When the image was captured, expressed as UTC epoch time in milliseconds. Must be non-negative integer; 0 if not found.
private long capturedAt;
// Image key.
private String key;
// Whether the image is panorama ( 1 ), or not ( 0 ).
private boolean pano;
// Sequence key.
private String sKey;
// User key. Empty if not found.
private String userKey;
private double ca = Double.NaN;
public MapillaryImage(double latitude, double longitude, double ca, long capturedAt, String key, boolean pano, String sKey, String userKey) {
this.latitude = latitude;
this.longitude = longitude;
this.ca = ca;
this.capturedAt = capturedAt;
this.key = key;
this.pano = pano;
this.sKey = sKey;
this.userKey = userKey;
}
public MapillaryImage(double latitude, double longitude) {
this.latitude = latitude;
this.longitude = longitude;
}
public boolean setData(Map userData) {
boolean res = true;
try {
this.ca = (Double) userData.get("ca");
this.capturedAt = (Long) userData.get("captured_at");
this.key = (String) userData.get("key");
this.pano = ((Long) userData.get("pano")) == 1;
this.sKey = (String) userData.get("skey");
this.userKey = (String) userData.get("userkey");
} catch (Exception e) {
res = false;
}
return res && this.key != null;
}
public double getLatitude() {
return latitude;
}
public double getLongitude() {
return longitude;
}
public double getCa() {
return ca;
}
public long getCapturedAt() {
return capturedAt;
}
public String getKey() {
return key;
}
public boolean isPano() {
return pano;
}
public String getsKey() {
return sKey;
}
public String getUserKey() {
return userKey;
}
}

View file

@ -28,8 +28,8 @@ class MapillaryRasterLayer extends MapTileLayer implements MapillaryLayer {
public void initLayer(OsmandMapTileView view) {
super.initLayer(view);
paintIcon = new Paint();
selectedImage = BitmapFactory.decodeResource(view.getResources(), R.drawable.map_default_location);
headingImage = BitmapFactory.decodeResource(view.getResources(), R.drawable.map_pedestrian_location_view_angle);
selectedImage = BitmapFactory.decodeResource(view.getResources(), R.drawable.map_mapillary_location);
headingImage = BitmapFactory.decodeResource(view.getResources(), R.drawable.map_mapillary_location_view_angle);
}
@Override

View file

@ -4,12 +4,20 @@ import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.PointF;
import android.support.v4.content.ContextCompat;
import com.vividsolutions.jts.geom.Coordinate;
import com.vividsolutions.jts.geom.CoordinateSequence;
import com.vividsolutions.jts.geom.Geometry;
import com.vividsolutions.jts.geom.LineString;
import com.vividsolutions.jts.geom.Point;
import net.osmand.AndroidUtils;
import net.osmand.data.GeometryTile;
import net.osmand.data.LatLon;
import net.osmand.data.PointDescription;
import net.osmand.data.QuadPointDouble;
import net.osmand.data.QuadRect;
import net.osmand.data.RotatedTileBox;
import net.osmand.map.ITileSource;
@ -17,23 +25,31 @@ import net.osmand.plus.OsmandPlugin;
import net.osmand.plus.R;
import net.osmand.plus.rastermaps.OsmandRasterMapsPlugin;
import net.osmand.plus.resources.ResourceManager;
import net.osmand.plus.views.ContextMenuLayer.IContextMenuProvider;
import net.osmand.plus.views.MapTileLayer;
import net.osmand.plus.views.OsmandMapTileView;
import net.osmand.util.Algorithms;
import net.osmand.util.MapUtils;
import java.util.LinkedHashMap;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
class MapillaryVectorLayer extends MapTileLayer implements MapillaryLayer {
class MapillaryVectorLayer extends MapTileLayer implements MapillaryLayer, IContextMenuProvider {
private static final int TILE_ZOOM = 14;
private static final double EXTENT = 4096.0;
private LatLon selectedImageLocation;
private Float selectedImageCameraAngle;
private Bitmap selectedImage;
private Bitmap headingImage;
private Paint paintIcon;
private Paint paintPoint;
private Paint paintLine;
private Bitmap point;
private Map<QuadPointDouble, Map> visiblePoints = new HashMap<>();
MapillaryVectorLayer() {
super(false);
@ -42,9 +58,18 @@ class MapillaryVectorLayer extends MapTileLayer implements MapillaryLayer {
@Override
public void initLayer(OsmandMapTileView view) {
super.initLayer(view);
paintIcon = new Paint();
selectedImage = BitmapFactory.decodeResource(view.getResources(), R.drawable.map_default_location);
headingImage = BitmapFactory.decodeResource(view.getResources(), R.drawable.map_pedestrian_location_view_angle);
paintPoint = new Paint();
paintLine = new Paint();
paintLine.setStyle(Paint.Style.STROKE);
paintLine.setAntiAlias(true);
paintLine.setColor(ContextCompat.getColor(view.getContext(), R.color.mapillary_color));
paintLine.setStrokeWidth(AndroidUtils.dpToPx(view.getContext(), 4f));
//paintLine.setStrokeJoin(Paint.Join.ROUND);
paintLine.setStrokeCap(Paint.Cap.ROUND);
selectedImage = BitmapFactory.decodeResource(view.getResources(), R.drawable.map_mapillary_location);
headingImage = BitmapFactory.decodeResource(view.getResources(), R.drawable.map_mapillary_location_view_angle);
point = BitmapFactory.decodeResource(view.getResources(), R.drawable.map_note_small);
}
@ -68,10 +93,10 @@ class MapillaryVectorLayer extends MapTileLayer implements MapillaryLayer {
canvas.save();
canvas.rotate(selectedImageCameraAngle - 180, x, y);
canvas.drawBitmap(headingImage, x - headingImage.getWidth() / 2,
y - headingImage.getHeight() / 2, paintIcon);
y - headingImage.getHeight() / 2, paintPoint);
canvas.restore();
}
canvas.drawBitmap(selectedImage, x - selectedImage.getWidth() / 2, y - selectedImage.getHeight() / 2, paintIcon);
canvas.drawBitmap(selectedImage, x - selectedImage.getWidth() / 2, y - selectedImage.getHeight() / 2, paintPoint);
}
}
@ -102,7 +127,8 @@ class MapillaryVectorLayer extends MapTileLayer implements MapillaryLayer {
boolean useInternet = (OsmandPlugin.getEnabledPlugin(OsmandRasterMapsPlugin.class) != null || OsmandPlugin.getEnabledPlugin(MapillaryPlugin.class) != null) &&
settings.USE_INTERNET_TO_DOWNLOAD_TILES.get() && settings.isInternetConnectionAvailable() && map.couldBeDownloadedFromInternet();
Map<String, GeometryTile> tiles = new LinkedHashMap<>();
Map<String, GeometryTile> tiles = new HashMap<>();
Map<QuadPointDouble, Map> visiblePoints = new HashMap<>();
for (int i = 0; i < width; i++) {
for (int j = 0; j < height; j++) {
int leftPlusI = left + i;
@ -118,7 +144,6 @@ class MapillaryVectorLayer extends MapTileLayer implements MapillaryLayer {
int tileX = leftPlusI;
int tileY = topPlusJ;
//String tileId = mgr.calculateTileId(map, tileX, tileY, nzoom);
int dzoom = nzoom - TILE_ZOOM;
int div = (int) Math.pow(2.0, dzoom);
tileX /= div;
@ -134,27 +159,211 @@ class MapillaryVectorLayer extends MapTileLayer implements MapillaryLayer {
if (tile != null) {
tiles.put(tileId, tile);
if (tile.getData() != null) {
drawPoints(canvas, tileBox, tileX, tileY, tile);
drawLines(canvas, tileBox, tileX, tileY, tile);
if (nzoom > 15) {
drawPoints(canvas, tileBox, tileX, tileY, tile, visiblePoints);
}
}
}
}
}
}
this.visiblePoints = visiblePoints;
}
protected void drawPoints(Canvas canvas, RotatedTileBox tileBox, int tileX, int tileY,
GeometryTile tile, Map<QuadPointDouble, Map> visiblePoints) {
Map<String, List<Point>> seqMap = new HashMap<>();
for (Geometry g : tile.getData()) {
if (g instanceof Point && !g.isEmpty() && g.getUserData() != null && g.getUserData() instanceof HashMap) {
HashMap userData = (HashMap) g.getUserData();
String seq = (String) userData.get("skey");
if (!Algorithms.isEmpty(seq)) {
List<Point> pointList = seqMap.get(seq);
if (pointList == null) {
pointList = new ArrayList<>();
seqMap.put(seq, pointList);
}
pointList.add((Point) g);
}
}
}
int dzoom = tileBox.getZoom() - TILE_ZOOM;
int mult = (int) Math.pow(2.0, dzoom);
QuadRect tileBounds = tileBox.getTileBounds();
double px, py, tx, ty;
float x, y;
float lx = -1000f;
float ly = -1000f;
float pw = point.getWidth();
float ph = point.getHeight();
float pwd = pw / 2;
float phd = ph / 2;
float pwm = pw * 2;
float phm = ph * 2;
canvas.rotate(-tileBox.getRotate(), tileBox.getCenterPixelX(), tileBox.getCenterPixelY());
for (List<Point> points : seqMap.values()) {
for (int i = 0; i < points.size(); i++) {
Point p = points.get(i);
px = p.getCoordinate().x / EXTENT;
py = p.getCoordinate().y / EXTENT;
tx = (tileX + px) * mult;
ty = (tileY + py) * mult;
if (tileBounds.contains(tx, ty, tx, ty)) {
x = tileBox.getPixXFromTile(tileX + px, tileY + py, TILE_ZOOM);
y = tileBox.getPixYFromTile(tileX + px, tileY + py, TILE_ZOOM);
//QuadRect rNow = calculateRect(x, y, pwm, phm);
//QuadRect rLast = calculateRect(lx, ly, pw, ph);
//if (!QuadRect.intersects(rLast, rNow) || i == points.size() - 1) {
canvas.drawBitmap(point, x - pwd, y - phd, paintPoint);
visiblePoints.put(new QuadPointDouble(tileX + px, tileY + py), (Map) p.getUserData());
lx = x;
ly = y;
//}
}
}
}
canvas.rotate(tileBox.getRotate(), tileBox.getCenterPixelX(), tileBox.getCenterPixelY());
}
protected void drawLines(Canvas canvas, RotatedTileBox tileBox, int tileX, int tileY, GeometryTile tile) {
for (Geometry g : tile.getData()) {
if (g instanceof LineString && !g.isEmpty()) {
LineString l = (LineString) g;
if (l.getCoordinateSequence() != null && !l.isEmpty()) {
draw(l.getCoordinateSequence(), canvas, tileBox, tileX, tileY);
}
}
}
}
protected void draw(CoordinateSequence points, Canvas canvas, RotatedTileBox tileBox, int tileX, int tileY) {
if (points.size() > 1) {
int dzoom = tileBox.getZoom() - TILE_ZOOM;
int mult = (int) Math.pow(2.0, dzoom);
QuadRect tileBounds = tileBox.getTileBounds();
canvas.rotate(-tileBox.getRotate(), tileBox.getCenterPixelX(), tileBox.getCenterPixelY());
Coordinate lastPt = points.getCoordinate(0);
float x;
float y;
float lastx = 0;
float lasty = 0;
double px, py, tpx, tpy, tlx, tly;
double lx = lastPt.x / EXTENT;
double ly = lastPt.y / EXTENT;
boolean reCalculateLastXY = true;
int size = points.size();
for (int i = 1; i < size; i++) {
Coordinate pt = points.getCoordinate(i);
px = pt.x / EXTENT;
py = pt.y / EXTENT;
tpx = (tileX + px) * mult;
tpy = (tileY + py) * mult;
tlx = (tileX + lx) * mult;
tly = (tileY + ly) * mult;
if (tileBounds.contains(tpx, tpy, tpx, tpy) || tileBounds.contains(tlx, tly, tlx, tly)) {
if (reCalculateLastXY) {
lastx = tileBox.getPixXFromTile(tileX + lx, tileY + ly, TILE_ZOOM);
lasty = tileBox.getPixYFromTile(tileX + lx, tileY + ly, TILE_ZOOM);
reCalculateLastXY = false;
}
x = tileBox.getPixXFromTile(tileX + px, tileY + py, TILE_ZOOM);
y = tileBox.getPixYFromTile(tileX + px, tileY + py, TILE_ZOOM);
canvas.drawLine(lastx, lasty, x, y, paintLine);
lastx = x;
lasty = y;
} else {
reCalculateLastXY = true;
}
lx = px;
ly = py;
}
canvas.rotate(tileBox.getRotate(), tileBox.getCenterPixelX(), tileBox.getCenterPixelY());
}
}
@Override
public PointDescription getObjectName(Object o) {
if (o instanceof MapillaryImage) {
return new PointDescription(PointDescription.POINT_TYPE_MAPILLARY_IMAGE, view.getContext().getString(R.string.mapillary_image));
}
return null;
}
@Override
public boolean disableSingleTap() {
return false;
}
@Override
public boolean disableLongPressOnMap() {
return false;
}
@Override
public void collectObjectsFromPoint(PointF point, RotatedTileBox tileBox, List<Object> objects) {
if (map != null && tileBox.getZoom() >= map.getMinimumZoomSupported()) {
getImagesFromPoint(tileBox, point, objects);
}
}
@Override
public LatLon getObjectLocation(Object o) {
if (o instanceof MapillaryImage) {
MapillaryImage image = (MapillaryImage) o;
return new LatLon(image.getLatitude(), image.getLongitude());
}
return null;
}
@Override
public boolean isObjectClickable(Object o) {
return o instanceof MapillaryImage;
}
private void getImagesFromPoint(RotatedTileBox tb, PointF point, List<? super MapillaryImage> images) {
Map<QuadPointDouble, Map> points = this.visiblePoints;
if (points != null) {
int ex = (int) point.x;
int ey = (int) point.y;
final int rp = getRadius(tb);
int radius = rp * 3 / 2;
float x, y;
for (Entry<QuadPointDouble, Map> entry : points.entrySet()) {
x = tb.getPixXFromTile(entry.getKey().x, entry.getKey().y, TILE_ZOOM);
y = tb.getPixYFromTile(entry.getKey().x, entry.getKey().y, TILE_ZOOM);
if (Math.abs(x - ex) <= radius && Math.abs(y - ey) <= radius) {
MapillaryImage img = new MapillaryImage(MapUtils.getLatitudeFromTile(TILE_ZOOM, entry.getKey().y),
MapUtils.getLongitudeFromTile(TILE_ZOOM, entry.getKey().x));
if (img.setData(entry.getValue())) {
images.add(img);
}
}
}
}
}
private void drawPoints(Canvas canvas, RotatedTileBox tileBox, int tileX, int tileY, GeometryTile tile) {
for (Geometry g : tile.getData()) {
if (g instanceof Point && g.getCoordinate() != null) {
int x = (int) g.getCoordinate().x;
int y = (int) g.getCoordinate().y;
double lat = MapUtils.getLatitudeFromTile(TILE_ZOOM, tileY + y / 4096f);
double lon = MapUtils.getLongitudeFromTile(TILE_ZOOM, tileX + x / 4096f);
if (tileBox.containsLatLon(lat, lon)) {
float px = tileBox.getPixXFromLatLon(lat, lon);
float py = tileBox.getPixYFromLatLon(lat, lon);
canvas.drawBitmap(point, px - point.getWidth() / 2, py - point.getHeight() / 2, paintIcon);
}
}
public int getRadius(RotatedTileBox tb) {
int r;
final double zoom = tb.getZoom();
if (zoom < TILE_ZOOM) {
r = 0;
} else if (zoom <= 15) {
r = 10;
} else if (zoom <= 16) {
r = 14;
} else if (zoom <= 17) {
r = 16;
} else {
r = 18;
}
return (int) (r * view.getScaleCoefficient());
}
}