vtm-app: revive / update with latest VTM, closes #90
This commit is contained in:
112
vtm-app/src/org/osmdroid/utils/BonusPackHelper.java
Normal file
112
vtm-app/src/org/osmdroid/utils/BonusPackHelper.java
Normal file
@@ -0,0 +1,112 @@
|
||||
package org.osmdroid.utils;
|
||||
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.BitmapFactory;
|
||||
import android.os.Build;
|
||||
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FilterInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.net.URL;
|
||||
|
||||
/**
|
||||
* Useful functions and common constants.
|
||||
*
|
||||
* @author M.Kergall
|
||||
*/
|
||||
public class BonusPackHelper {
|
||||
|
||||
/**
|
||||
* Log tag.
|
||||
*/
|
||||
public static final String LOG_TAG = "BONUSPACK";
|
||||
|
||||
/**
|
||||
* User agent sent to services by default
|
||||
*/
|
||||
public static final String DEFAULT_USER_AGENT = "OsmBonusPack/1";
|
||||
|
||||
/**
|
||||
* @return true if the device is the emulator, false if actual device.
|
||||
*/
|
||||
public static boolean isEmulator() {
|
||||
//return Build.MANUFACTURER.equals("unknown");
|
||||
return ("google_sdk".equals(Build.PRODUCT) || "sdk".equals(Build.PRODUCT));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param connection ...
|
||||
* @return the whole content of the http request, as a string
|
||||
*/
|
||||
private static String readStream(HttpConnection connection) {
|
||||
String result = connection.getContentAsString();
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* sends an http request, and returns the whole content result in a String.
|
||||
*
|
||||
* @param url ...
|
||||
* @return the whole content, or null if any issue.
|
||||
*/
|
||||
public static String requestStringFromUrl(String url) {
|
||||
HttpConnection connection = new HttpConnection();
|
||||
connection.doGet(url);
|
||||
String result = readStream(connection);
|
||||
connection.close();
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads a bitmap from a url.
|
||||
*
|
||||
* @param url ...
|
||||
* @return the bitmap, or null if any issue.
|
||||
*/
|
||||
public static Bitmap loadBitmap(String url) {
|
||||
Bitmap bitmap = null;
|
||||
try {
|
||||
InputStream is = (InputStream) new URL(url).getContent();
|
||||
bitmap = BitmapFactory.decodeStream(new FlushedInputStream(is));
|
||||
//Alternative providing better handling on loading errors?
|
||||
/* Drawable d = Drawable.createFromStream(new
|
||||
* FlushedInputStream(is), null); if (is != null) is.close(); if (d
|
||||
* != null) bitmap = ((BitmapDrawable)d).getBitmap(); */
|
||||
} catch (FileNotFoundException e) {
|
||||
//log.debug("image not available: " + url);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
return bitmap;
|
||||
}
|
||||
|
||||
/**
|
||||
* Workaround on Android issue see
|
||||
* http://stackoverflow.com/questions/4601352
|
||||
* /createfromstream-in-android-returning-null-for-certain-url
|
||||
*/
|
||||
static class FlushedInputStream extends FilterInputStream {
|
||||
public FlushedInputStream(InputStream inputStream) {
|
||||
super(inputStream);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long skip(long n) throws IOException {
|
||||
long totalBytesSkipped = 0L;
|
||||
while (totalBytesSkipped < n) {
|
||||
long bytesSkipped = in.skip(n - totalBytesSkipped);
|
||||
if (bytesSkipped == 0L) {
|
||||
int byteValue = read();
|
||||
if (byteValue < 0)
|
||||
break; // we reached EOF
|
||||
|
||||
bytesSkipped = 1; // we read one byte
|
||||
}
|
||||
totalBytesSkipped += bytesSkipped;
|
||||
}
|
||||
return totalBytesSkipped;
|
||||
}
|
||||
}
|
||||
}
|
||||
141
vtm-app/src/org/osmdroid/utils/DouglasPeuckerReducer.java
Normal file
141
vtm-app/src/org/osmdroid/utils/DouglasPeuckerReducer.java
Normal file
@@ -0,0 +1,141 @@
|
||||
package org.osmdroid.utils;
|
||||
|
||||
import org.oscim.core.GeoPoint;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Reduces the number of points in a shape using the Douglas-Peucker algorithm. <br>
|
||||
* From:
|
||||
* http://www.phpriot.com/articles/reducing-map-path-douglas-peucker-algorithm/4<br>
|
||||
* Ported from PHP to Java. "marked" array added to optimize.
|
||||
*
|
||||
* @author M.Kergall
|
||||
*/
|
||||
public class DouglasPeuckerReducer {
|
||||
|
||||
/**
|
||||
* Reduce the number of points in a shape using the Douglas-Peucker
|
||||
* algorithm
|
||||
*
|
||||
* @param shape The shape to reduce
|
||||
* @param tolerance The tolerance to decide whether or not to keep a point, in the
|
||||
* coordinate system of the points (micro-degrees here)
|
||||
* @return the reduced shape
|
||||
*/
|
||||
public static List<GeoPoint> reduceWithTolerance(List<GeoPoint> shape,
|
||||
double tolerance) {
|
||||
int n = shape.size();
|
||||
// if a shape has 2 or less points it cannot be reduced
|
||||
if (tolerance <= 0 || n < 3) {
|
||||
return shape;
|
||||
}
|
||||
|
||||
boolean[] marked = new boolean[n]; //vertex indexes to keep will be marked as "true"
|
||||
for (int i = 1; i < n - 1; i++)
|
||||
marked[i] = false;
|
||||
// automatically add the first and last point to the returned shape
|
||||
marked[0] = marked[n - 1] = true;
|
||||
|
||||
// the first and last points in the original shape are
|
||||
// used as the entry point to the algorithm.
|
||||
douglasPeuckerReduction(
|
||||
shape, // original shape
|
||||
marked, // reduced shape
|
||||
tolerance, // tolerance
|
||||
0, // index of first point
|
||||
n - 1 // index of last point
|
||||
);
|
||||
|
||||
// all done, return the reduced shape
|
||||
ArrayList<GeoPoint> newShape = new ArrayList<GeoPoint>(n); // the new shape to return
|
||||
for (int i = 0; i < n; i++) {
|
||||
if (marked[i])
|
||||
newShape.add(shape.get(i));
|
||||
}
|
||||
return newShape;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reduce the points in shape between the specified first and last index.
|
||||
* Mark the points to keep in marked[]
|
||||
*
|
||||
* @param shape The original shape
|
||||
* @param marked The points to keep (marked as true)
|
||||
* @param tolerance The tolerance to determine if a point is kept
|
||||
* @param firstIdx The index in original shape's point of the starting point for
|
||||
* this line segment
|
||||
* @param lastIdx The index in original shape's point of the ending point for
|
||||
* this line segment
|
||||
*/
|
||||
private static void douglasPeuckerReduction(List<GeoPoint> shape, boolean[] marked,
|
||||
double tolerance, int firstIdx, int lastIdx) {
|
||||
if (lastIdx <= firstIdx + 1) {
|
||||
// overlapping indexes, just return
|
||||
return;
|
||||
}
|
||||
|
||||
// loop over the points between the first and last points
|
||||
// and find the point that is the farthest away
|
||||
|
||||
double maxDistance = 0.0;
|
||||
int indexFarthest = 0;
|
||||
|
||||
GeoPoint firstPoint = shape.get(firstIdx);
|
||||
GeoPoint lastPoint = shape.get(lastIdx);
|
||||
|
||||
for (int idx = firstIdx + 1; idx < lastIdx; idx++) {
|
||||
GeoPoint point = shape.get(idx);
|
||||
|
||||
double distance = orthogonalDistance(point, firstPoint, lastPoint);
|
||||
|
||||
// keep the point with the greatest distance
|
||||
if (distance > maxDistance) {
|
||||
maxDistance = distance;
|
||||
indexFarthest = idx;
|
||||
}
|
||||
}
|
||||
|
||||
if (maxDistance > tolerance) {
|
||||
//The farthest point is outside the tolerance: it is marked and the algorithm continues.
|
||||
marked[indexFarthest] = true;
|
||||
|
||||
// reduce the shape between the starting point to newly found point
|
||||
douglasPeuckerReduction(shape, marked, tolerance, firstIdx, indexFarthest);
|
||||
|
||||
// reduce the shape between the newly found point and the finishing point
|
||||
douglasPeuckerReduction(shape, marked, tolerance, indexFarthest, lastIdx);
|
||||
}
|
||||
//else: the farthest point is within the tolerance, the whole segment is discarded.
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate the orthogonal distance from the line joining the lineStart and
|
||||
* lineEnd points to point
|
||||
*
|
||||
* @param point The point the distance is being calculated for
|
||||
* @param lineStart The point that starts the line
|
||||
* @param lineEnd The point that ends the line
|
||||
* @return The distance in points coordinate system
|
||||
*/
|
||||
public static double orthogonalDistance(GeoPoint point, GeoPoint lineStart, GeoPoint lineEnd) {
|
||||
double area = Math.abs(
|
||||
(
|
||||
1.0 * lineStart.latitudeE6 * lineEnd.longitudeE6
|
||||
+ 1.0 * lineEnd.latitudeE6 * point.longitudeE6
|
||||
+ 1.0 * point.latitudeE6 * lineStart.longitudeE6
|
||||
- 1.0 * lineEnd.latitudeE6 * lineStart.longitudeE6
|
||||
- 1.0 * point.latitudeE6 * lineEnd.longitudeE6
|
||||
- 1.0 * lineStart.latitudeE6 * point.longitudeE6
|
||||
) / 2.0
|
||||
);
|
||||
|
||||
double bottom = Math.hypot(
|
||||
lineStart.latitudeE6 - lineEnd.latitudeE6,
|
||||
lineStart.longitudeE6 - lineEnd.longitudeE6
|
||||
);
|
||||
|
||||
return (area / bottom * 2.0);
|
||||
}
|
||||
}
|
||||
119
vtm-app/src/org/osmdroid/utils/HttpConnection.java
Normal file
119
vtm-app/src/org/osmdroid/utils/HttpConnection.java
Normal file
@@ -0,0 +1,119 @@
|
||||
package org.osmdroid.utils;
|
||||
|
||||
import android.util.Log;
|
||||
|
||||
import com.squareup.okhttp.OkHttpClient;
|
||||
import com.squareup.okhttp.Request;
|
||||
import com.squareup.okhttp.Response;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* A "very very simple to use" class for performing http get and post requests.
|
||||
* So many ways to do that, and potential subtle issues.
|
||||
* If complexity should be added to handle even more issues, complexity should be put here and only here.
|
||||
* <p/>
|
||||
* Typical usage:
|
||||
* <pre>HttpConnection connection = new HttpConnection();
|
||||
* connection.doGet("http://www.google.com");
|
||||
* InputStream stream = connection.getStream();
|
||||
* if (stream != null) {
|
||||
* //use this stream, for buffer reading, or XML SAX parsing, or whatever...
|
||||
* }
|
||||
* connection.close();</pre>
|
||||
*/
|
||||
public class HttpConnection {
|
||||
private final static int TIMEOUT_CONNECTION = 3000; //ms
|
||||
private final static int TIMEOUT_SOCKET = 10000; //ms
|
||||
|
||||
private static OkHttpClient client;
|
||||
private InputStream stream;
|
||||
private String mUserAgent;
|
||||
private Response response;
|
||||
|
||||
private static OkHttpClient getOkHttpClient() {
|
||||
if (client == null) {
|
||||
client = new OkHttpClient();
|
||||
client.setConnectTimeout(TIMEOUT_CONNECTION, TimeUnit.MILLISECONDS);
|
||||
client.setReadTimeout(TIMEOUT_SOCKET, TimeUnit.MILLISECONDS);
|
||||
}
|
||||
return client;
|
||||
}
|
||||
|
||||
public HttpConnection() {
|
||||
/*
|
||||
client = new OkHttpClient();
|
||||
client.setConnectTimeout(TIMEOUT_CONNECTION, TimeUnit.MILLISECONDS);
|
||||
client.setReadTimeout(TIMEOUT_SOCKET, TimeUnit.MILLISECONDS);
|
||||
*/
|
||||
}
|
||||
|
||||
public void setUserAgent(String userAgent) {
|
||||
mUserAgent = userAgent;
|
||||
}
|
||||
|
||||
public void doGet(final String url) {
|
||||
try {
|
||||
Request.Builder request = new Request.Builder().url(url);
|
||||
if (mUserAgent != null)
|
||||
request.addHeader("User-Agent", mUserAgent);
|
||||
response = getOkHttpClient().newCall(request.build()).execute();
|
||||
Integer status = response.code();
|
||||
if (status != 200) {
|
||||
Log.e(BonusPackHelper.LOG_TAG, "Invalid response from server: " + status.toString());
|
||||
}
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the opened InputStream, or null if creation failed for any reason.
|
||||
*/
|
||||
public InputStream getStream() {
|
||||
try {
|
||||
if (response == null)
|
||||
return null;
|
||||
stream = response.body().byteStream();
|
||||
return stream;
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the whole content as a String, or null if creation failed for any reason.
|
||||
*/
|
||||
public String getContentAsString() {
|
||||
try {
|
||||
if (response == null)
|
||||
return null;
|
||||
return response.body().string();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Calling close once is mandatory.
|
||||
*/
|
||||
public void close() {
|
||||
if (stream != null) {
|
||||
try {
|
||||
stream.close();
|
||||
stream = null;
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
/*
|
||||
if (client != null)
|
||||
client = null;
|
||||
*/
|
||||
}
|
||||
|
||||
}
|
||||
22
vtm-app/src/org/osmdroid/utils/MathConstants.java
Normal file
22
vtm-app/src/org/osmdroid/utils/MathConstants.java
Normal file
@@ -0,0 +1,22 @@
|
||||
/*
|
||||
* Copyright 2010, 2011, 2012 mapsforge.org
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify it under the
|
||||
* terms of the GNU Lesser General Public License as published by the Free Software
|
||||
* Foundation, either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
|
||||
* PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License along with
|
||||
* this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package org.osmdroid.utils;
|
||||
|
||||
public class MathConstants {
|
||||
|
||||
public static final double PI180E6 = (Math.PI / 180) / 1000000.0;
|
||||
public static final double PIx4 = Math.PI * 4;
|
||||
|
||||
}
|
||||
94
vtm-app/src/org/osmdroid/utils/PolylineEncoder.java
Normal file
94
vtm-app/src/org/osmdroid/utils/PolylineEncoder.java
Normal file
@@ -0,0 +1,94 @@
|
||||
package org.osmdroid.utils;
|
||||
|
||||
import org.oscim.core.GeoPoint;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
/**
|
||||
* Methods to encode and decode a polyline with Google polyline
|
||||
* encoding/decoding scheme. See
|
||||
* https://developers.google.com/maps/documentation/utilities/polylinealgorithm
|
||||
*/
|
||||
public class PolylineEncoder {
|
||||
|
||||
private static StringBuffer encodeSignedNumber(int num) {
|
||||
int sgn_num = num << 1;
|
||||
if (num < 0) {
|
||||
sgn_num = ~(sgn_num);
|
||||
}
|
||||
return (encodeNumber(sgn_num));
|
||||
}
|
||||
|
||||
private static StringBuffer encodeNumber(int num) {
|
||||
StringBuffer encodeString = new StringBuffer();
|
||||
while (num >= 0x20) {
|
||||
int nextValue = (0x20 | (num & 0x1f)) + 63;
|
||||
encodeString.append((char) (nextValue));
|
||||
num >>= 5;
|
||||
}
|
||||
num += 63;
|
||||
encodeString.append((char) (num));
|
||||
return encodeString;
|
||||
}
|
||||
|
||||
/**
|
||||
* Encode a polyline with Google polyline encoding method
|
||||
*
|
||||
* @param polyline the polyline
|
||||
* @param precision 1 for a 6 digits encoding, 10 for a 5 digits encoding.
|
||||
* @return the encoded polyline, as a String
|
||||
*/
|
||||
public static String encode(ArrayList<GeoPoint> polyline, int precision) {
|
||||
StringBuffer encodedPoints = new StringBuffer();
|
||||
int prev_lat = 0, prev_lng = 0;
|
||||
for (GeoPoint trackpoint : polyline) {
|
||||
int lat = trackpoint.latitudeE6 / precision;
|
||||
int lng = trackpoint.longitudeE6 / precision;
|
||||
encodedPoints.append(encodeSignedNumber(lat - prev_lat));
|
||||
encodedPoints.append(encodeSignedNumber(lng - prev_lng));
|
||||
prev_lat = lat;
|
||||
prev_lng = lng;
|
||||
}
|
||||
return encodedPoints.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Decode a "Google-encoded" polyline
|
||||
*
|
||||
* @param encodedString ...
|
||||
* @param precision 1 for a 6 digits encoding, 10 for a 5 digits encoding.
|
||||
* @return the polyline.
|
||||
*/
|
||||
public static ArrayList<GeoPoint> decode(String encodedString, int precision) {
|
||||
ArrayList<GeoPoint> polyline = new ArrayList<GeoPoint>();
|
||||
int index = 0;
|
||||
int len = encodedString.length();
|
||||
int lat = 0, lng = 0;
|
||||
|
||||
while (index < len) {
|
||||
int b, shift = 0, result = 0;
|
||||
do {
|
||||
b = encodedString.charAt(index++) - 63;
|
||||
result |= (b & 0x1f) << shift;
|
||||
shift += 5;
|
||||
} while (b >= 0x20);
|
||||
int dlat = ((result & 1) != 0 ? ~(result >> 1) : (result >> 1));
|
||||
lat += dlat;
|
||||
|
||||
shift = 0;
|
||||
result = 0;
|
||||
do {
|
||||
b = encodedString.charAt(index++) - 63;
|
||||
result |= (b & 0x1f) << shift;
|
||||
shift += 5;
|
||||
} while (b >= 0x20);
|
||||
int dlng = ((result & 1) != 0 ? ~(result >> 1) : (result >> 1));
|
||||
lng += dlng;
|
||||
|
||||
GeoPoint p = new GeoPoint(lat * precision, lng * precision);
|
||||
polyline.add(p);
|
||||
}
|
||||
|
||||
return polyline;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user