forked from upstream-mirrors/OpenTracks
Further improving/fixing drawing, and adding a bounding box for debugging.
This commit is contained in:
@@ -37,6 +37,7 @@ limitations under the License.
|
||||
<string name="share_url_only_key">shareUrlOnly</string>
|
||||
<string name="signal_sampling_frequency_key">signalSamplingFrequency</string>
|
||||
<string name="split_frequency_key">splitFrequency</string>
|
||||
<string name="debug_draw_bounds_key">debugDrawBounds</string>
|
||||
|
||||
<!-- Preference keys which keep transient state (not user preferences) - DO NOT TRANSLATE -->
|
||||
<string name="recording_track_key">recordingTrack</string>
|
||||
|
||||
@@ -125,4 +125,13 @@ limitations under the License.
|
||||
android:persistent="false" />
|
||||
</PreferenceCategory>
|
||||
</PreferenceScreen>
|
||||
|
||||
<!-- Debug settings - uncomment this while debugging only -->
|
||||
<!--
|
||||
<PreferenceScreen android:title="Debug">
|
||||
<CheckBoxPreference android:key="@string/debug_draw_bounds_key"
|
||||
android:title="Draw bounding box"
|
||||
android:defaultValue="false" />
|
||||
</PreferenceScreen>
|
||||
-->
|
||||
</PreferenceScreen>
|
||||
|
||||
@@ -372,6 +372,8 @@ public class MyTracksMap extends MapActivity
|
||||
setSelectedTrack(selectedTrackId);
|
||||
}
|
||||
updateOptionsButton();
|
||||
mapOverlay.setDrawBounds(preferences.getBoolean(
|
||||
getString(R.string.debug_draw_bounds_key), false));
|
||||
preferences.registerOnSharedPreferenceChangeListener(this);
|
||||
}
|
||||
}
|
||||
@@ -916,6 +918,10 @@ public class MyTracksMap extends MapActivity
|
||||
mapOverlay.setShowEndMarker(!isRecordingSelected());
|
||||
mapView.postInvalidate();
|
||||
}
|
||||
} else if (key.equals(getString(R.string.debug_draw_bounds_key))) {
|
||||
mapOverlay.setDrawBounds(
|
||||
sharedPreferences.getBoolean(
|
||||
getString(R.string.debug_draw_bounds_key), false));
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@@ -29,6 +29,7 @@ import android.graphics.Paint;
|
||||
import android.graphics.Path;
|
||||
import android.graphics.Point;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.Region;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.location.Location;
|
||||
|
||||
@@ -59,6 +60,7 @@ public class MyTracksOverlay extends Overlay {
|
||||
private int lastHeading = 0;
|
||||
private Location myLocation;
|
||||
private boolean showEndMarker = true;
|
||||
private boolean drawBounds;
|
||||
|
||||
public MyTracksOverlay(Context context) {
|
||||
this.context = context;
|
||||
@@ -127,7 +129,11 @@ public class MyTracksOverlay extends Overlay {
|
||||
* @param l the location to add
|
||||
*/
|
||||
public void addLocation(Location l) {
|
||||
points.add(l);
|
||||
if (l != null) {
|
||||
synchronized (points) {
|
||||
points.add(l);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void addWaypoint(Waypoint wpt) {
|
||||
@@ -135,7 +141,9 @@ public class MyTracksOverlay extends Overlay {
|
||||
}
|
||||
|
||||
public int getNumLocations() {
|
||||
return points.size();
|
||||
synchronized (points) {
|
||||
return points.size();
|
||||
}
|
||||
}
|
||||
|
||||
public void clearWaypoints() {
|
||||
@@ -143,7 +151,9 @@ public class MyTracksOverlay extends Overlay {
|
||||
}
|
||||
|
||||
public void clearPoints() {
|
||||
points.clear();
|
||||
synchronized (points) {
|
||||
points.clear();
|
||||
}
|
||||
}
|
||||
|
||||
public void setTrackDrawingEnabled(boolean trackDrawingEnabled) {
|
||||
@@ -220,73 +230,118 @@ public class MyTracksOverlay extends Overlay {
|
||||
}
|
||||
|
||||
private void drawTrack(Canvas canvas, MapView mapView) {
|
||||
if (points.size() < 2) {
|
||||
return;
|
||||
}
|
||||
Path path;
|
||||
Point pt = new Point();
|
||||
Location lastValidLocation;
|
||||
int locLon = 0, locLat = 0;
|
||||
GeoPoint firstGeoPoint = null;
|
||||
boolean lastLocValid;
|
||||
|
||||
// Get the current viewing window:
|
||||
int w = mapView.getLongitudeSpan();
|
||||
int h = mapView.getLatitudeSpan();
|
||||
int cx = mapView.getMapCenter().getLongitudeE6();
|
||||
int cy = mapView.getMapCenter().getLatitudeE6();
|
||||
Rect rect = new Rect(cx - w, cy - h, cx + w, cy + h);
|
||||
Rect viewRect = new Rect(cx - w, cy - h, cx + w, cy + h);
|
||||
|
||||
Point pt = new Point();
|
||||
GeoPoint geoPoint;
|
||||
Location loc;
|
||||
Location lastValidLocation = null;
|
||||
Path path;
|
||||
boolean wasInside;
|
||||
|
||||
// Do as much allocation and preparation outside the loop over track
|
||||
// points:
|
||||
wasInside = false;
|
||||
int locLon = 0, locLat = 0, minLon, maxLon, minLat, maxLat;
|
||||
int lastLocLon = (int) (points.get(0).getLongitude() * 1E6);
|
||||
int lastLocLat = (int) (points.get(0).getLatitude() * 1E6);
|
||||
|
||||
// Loop over track points:
|
||||
path = new Path();
|
||||
for (int i = 1; i < points.size(); i++) {
|
||||
|
||||
loc = points.get(i);
|
||||
if (loc == null) {
|
||||
continue;
|
||||
// Global bounding box, including points not visible
|
||||
int allMinLat, allMinLon, allMaxLat, allMaxLon;
|
||||
|
||||
synchronized (points) {
|
||||
int numPoints = points.size();
|
||||
if (numPoints < 2) {
|
||||
return;
|
||||
}
|
||||
locLon = (int) (loc.getLongitude() * 1E6);
|
||||
locLat = (int) (loc.getLatitude() * 1E6);
|
||||
|
||||
// Draw a line segment if it's inside the viewing window:
|
||||
if (locLat < 90E6 && lastLocLat < 90E6) {
|
||||
lastValidLocation = loc;
|
||||
minLon = Math.min(locLon, lastLocLon);
|
||||
maxLon = Math.max(locLon, lastLocLon);
|
||||
minLat = Math.min(locLat, lastLocLat);
|
||||
maxLat = Math.max(locLat, lastLocLat);
|
||||
if (rect.intersects(minLon, minLat, maxLon, maxLat)) {
|
||||
if (!wasInside) {
|
||||
geoPoint = new GeoPoint(lastLocLat, lastLocLon);
|
||||
mapView.getProjection().toPixels(geoPoint, pt);
|
||||
path.moveTo(pt.x, pt.y);
|
||||
GeoPoint geoPoint;
|
||||
Location loc;
|
||||
int minLon, maxLon, minLat, maxLat;
|
||||
lastValidLocation = points.get(0);
|
||||
int lastLocLon = allMinLon = allMaxLon = (int) (lastValidLocation.getLongitude() * 1E6);
|
||||
int lastLocLat = allMinLat = allMaxLat = (int) (lastValidLocation.getLatitude() * 1E6);
|
||||
lastLocValid = MyTracksUtils.isValidLocation(lastValidLocation);
|
||||
boolean lastLocVisible = false;
|
||||
path = new Path();
|
||||
|
||||
// Loop over track points:
|
||||
path.incReserve(numPoints);
|
||||
for (int i = 1; i < numPoints; i++) {
|
||||
loc = points.get(i);
|
||||
|
||||
boolean locValid = MyTracksUtils.isValidLocation(loc);
|
||||
boolean locVisible = false;
|
||||
if (locValid) {
|
||||
locLon = (int) (loc.getLongitude() * 1E6);
|
||||
locLat = (int) (loc.getLatitude() * 1E6);
|
||||
|
||||
if (firstGeoPoint == null) {
|
||||
// Found the starting point
|
||||
firstGeoPoint = new GeoPoint(locLat, locLon);
|
||||
}
|
||||
|
||||
// If both the current and previous locations were valid
|
||||
if (lastLocValid) {
|
||||
lastValidLocation = loc;
|
||||
|
||||
// Get the bounding box of the segment about to be drawn
|
||||
if (locLon > lastLocLon) {
|
||||
minLon = lastLocLon;
|
||||
maxLon = locLon;
|
||||
} else {
|
||||
minLon = locLon;
|
||||
maxLon = lastLocLon;
|
||||
}
|
||||
if (locLat > lastLocLat) {
|
||||
minLat = lastLocLat;
|
||||
maxLat = locLat;
|
||||
} else {
|
||||
minLat = locLat;
|
||||
maxLat = lastLocLat;
|
||||
}
|
||||
|
||||
if (drawBounds) {
|
||||
allMaxLat = Math.max(allMaxLat, maxLat);
|
||||
allMinLat = Math.min(allMinLat, minLat);
|
||||
allMaxLon = Math.max(allMaxLon, maxLon);
|
||||
allMinLon = Math.min(allMinLon, minLon);
|
||||
}
|
||||
|
||||
// See if that bounding box intersects the viewable bounding box
|
||||
// Assume that if it does, the location is visible
|
||||
locVisible = viewRect.intersects(minLon, minLat, maxLon, maxLat);
|
||||
if (locVisible) {
|
||||
// If the previous point wasn't drawn, start at its position
|
||||
if (!lastLocVisible) {
|
||||
geoPoint = new GeoPoint(lastLocLat, lastLocLon);
|
||||
mapView.getProjection().toPixels(geoPoint, pt);
|
||||
path.moveTo(pt.x, pt.y);
|
||||
}
|
||||
|
||||
// Draw a line to the new point
|
||||
geoPoint = new GeoPoint(locLat, locLon);
|
||||
mapView.getProjection().toPixels(geoPoint, pt);
|
||||
path.lineTo(pt.x, pt.y);
|
||||
}
|
||||
}
|
||||
geoPoint = new GeoPoint(locLat, locLon);
|
||||
mapView.getProjection().toPixels(geoPoint, pt);
|
||||
path.lineTo(pt.x, pt.y);
|
||||
wasInside = rect.contains(locLon, locLat);
|
||||
}
|
||||
} else {
|
||||
wasInside = false;
|
||||
lastLocLon = locLon;
|
||||
lastLocLat = locLat;
|
||||
lastLocValid = locValid;
|
||||
lastLocVisible = locVisible;
|
||||
}
|
||||
lastLocLon = locLon;
|
||||
lastLocLat = locLat;
|
||||
}
|
||||
|
||||
canvas.drawPath(path, selectedTrackPaint);
|
||||
|
||||
if (drawBounds) {
|
||||
drawBoundingBox(canvas, mapView,
|
||||
allMinLat, allMinLon, allMaxLat, allMaxLon);
|
||||
}
|
||||
|
||||
// Draw the "End" marker:
|
||||
Location currentLastValidLocation = lastValidLocation;
|
||||
if (showEndMarker && currentLastValidLocation != null) {
|
||||
if (showEndMarker && lastValidLocation != null) {
|
||||
canvas.save();
|
||||
geoPoint = MyTracksUtils.getGeoPoint(currentLastValidLocation);
|
||||
GeoPoint geoPoint = MyTracksUtils.getGeoPoint(lastValidLocation);
|
||||
mapView.getProjection().toPixels(geoPoint, pt);
|
||||
canvas.translate(pt.x - (markerWidth / 2), pt.y - markerHeight);
|
||||
endMarker.draw(canvas);
|
||||
@@ -294,22 +349,46 @@ public class MyTracksOverlay extends Overlay {
|
||||
}
|
||||
|
||||
// Draw the "Start" marker:
|
||||
for (int i = 0; i < points.size(); i++) {
|
||||
loc = points.get(i);
|
||||
if (loc.getLatitude() < 90) {
|
||||
locLon = (int) (loc.getLongitude() * 1E6);
|
||||
locLat = (int) (loc.getLatitude() * 1E6);
|
||||
geoPoint = new GeoPoint(locLat, locLon);
|
||||
mapView.getProjection().toPixels(geoPoint, pt);
|
||||
canvas.save();
|
||||
canvas.translate(pt.x - (markerWidth / 2), pt.y - markerHeight);
|
||||
startMarker.draw(canvas);
|
||||
canvas.restore();
|
||||
break;
|
||||
}
|
||||
if (firstGeoPoint != null) {
|
||||
mapView.getProjection().toPixels(firstGeoPoint, pt);
|
||||
canvas.save();
|
||||
canvas.translate(pt.x - (markerWidth / 2), pt.y - markerHeight);
|
||||
startMarker.draw(canvas);
|
||||
canvas.restore();
|
||||
}
|
||||
}
|
||||
|
||||
private void drawBoundingBox(Canvas canvas, MapView mapView, int allMinLat,
|
||||
int allMinLon, int allMaxLat, int allMaxLon) {
|
||||
// Transform coordinates
|
||||
GeoPoint maxPoint = new GeoPoint(allMaxLat, allMaxLon);
|
||||
GeoPoint minPoint = new GeoPoint(allMinLat, allMinLon);
|
||||
Point minPt = new Point();
|
||||
Point maxPt = new Point();
|
||||
mapView.getProjection().toPixels(minPoint, minPt);
|
||||
mapView.getProjection().toPixels(maxPoint, maxPt);
|
||||
Rect allBounds = new Rect(minPt.x, minPt.y, maxPt.x, maxPt.y);
|
||||
|
||||
// Prepare a green paint
|
||||
Paint boundingBoxPaint = new Paint();
|
||||
boundingBoxPaint.setColor(context.getResources().getColor(R.color.green));
|
||||
boundingBoxPaint.setStrokeWidth(2);
|
||||
boundingBoxPaint.setStyle(Paint.Style.STROKE);
|
||||
boundingBoxPaint.setAntiAlias(true);
|
||||
|
||||
// Disable clipping
|
||||
canvas.save();
|
||||
canvas.clipRect(Float.NEGATIVE_INFINITY, Float.NEGATIVE_INFINITY,
|
||||
Float.POSITIVE_INFINITY, Float.POSITIVE_INFINITY,
|
||||
Region.Op.REPLACE);
|
||||
|
||||
// Draw the bounding box
|
||||
canvas.drawRect(allBounds, boundingBoxPaint);
|
||||
|
||||
// Re-enable clipping
|
||||
canvas.restore();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean draw(Canvas canvas, MapView mapView, boolean shadow,
|
||||
long when) {
|
||||
@@ -378,4 +457,8 @@ public class MyTracksOverlay extends Overlay {
|
||||
}
|
||||
return super.onTap(p, mapView);
|
||||
}
|
||||
|
||||
public void setDrawBounds(boolean drawBounds) {
|
||||
this.drawBounds = drawBounds;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -49,14 +49,12 @@ import android.widget.Toast;
|
||||
* @author Sandor Dornbush
|
||||
*/
|
||||
public class StatsActivity extends Activity
|
||||
implements OnSharedPreferenceChangeListener, LocationListener {
|
||||
|
||||
implements OnSharedPreferenceChangeListener {
|
||||
|
||||
private final StatsUtilities utils;
|
||||
private UIUpdateThread thread;
|
||||
|
||||
private ContentObserver observer;
|
||||
private LocationManager locationManager;
|
||||
|
||||
/**
|
||||
* The id of the currently selected track.
|
||||
@@ -96,7 +94,6 @@ public class StatsActivity extends Activity
|
||||
private boolean showCurrentSegment = false;
|
||||
|
||||
private final MyTracksProviderUtils providerUtils;
|
||||
private Track track = null;
|
||||
|
||||
/**
|
||||
* A runnable for posting to the UI thread. Will update the total time field.
|
||||
@@ -179,11 +176,9 @@ public class StatsActivity extends Activity
|
||||
preferences.getBoolean(getString(R.string.report_speed_key), true);
|
||||
checkLiveTrack();
|
||||
restoreStats();
|
||||
updateLocation(null);
|
||||
showUnknownLocation();
|
||||
preferences.registerOnSharedPreferenceChangeListener(this);
|
||||
}
|
||||
locationManager =
|
||||
(LocationManager) getSystemService(Context.LOCATION_SERVICE);
|
||||
utils.setMetricUnits(metricUnits);
|
||||
utils.setReportSpeed(displaySpeed);
|
||||
utils.updateUnits();
|
||||
@@ -214,7 +209,7 @@ public class StatsActivity extends Activity
|
||||
activityOnTop = true;
|
||||
checkLiveTrack();
|
||||
restoreStats();
|
||||
updateLocation(null);
|
||||
showUnknownLocation();
|
||||
super.onResume();
|
||||
}
|
||||
|
||||
@@ -234,7 +229,7 @@ public class StatsActivity extends Activity
|
||||
-1);
|
||||
checkLiveTrack();
|
||||
restoreStats();
|
||||
updateLocation(null);
|
||||
showUnknownLocation();
|
||||
} else if (key.equals(getString(R.string.recording_track_key))) {
|
||||
recordingTrackId =
|
||||
sharedPreferences.getLong(
|
||||
@@ -242,7 +237,7 @@ public class StatsActivity extends Activity
|
||||
-1);
|
||||
checkLiveTrack();
|
||||
restoreStats();
|
||||
updateLocation(null);
|
||||
showUnknownLocation();
|
||||
} else if (key.equals(getString(R.string.metric_units_key))) {
|
||||
metricUnits =
|
||||
sharedPreferences.getBoolean(
|
||||
@@ -299,29 +294,36 @@ public class StatsActivity extends Activity
|
||||
return super.onOptionsItemSelected(item);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLocationChanged(Location l) {
|
||||
if (selectedTrackIsRecording()) {
|
||||
updateLocation(l);
|
||||
private final LocationListener locationListener = new LocationListener() {
|
||||
@Override
|
||||
public void onLocationChanged(Location l) {
|
||||
if (selectedTrackIsRecording()) {
|
||||
showLocation(l);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onProviderDisabled(String provider) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onProviderEnabled(String provider) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStatusChanged(String provider, int status, Bundle extras) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onProviderDisabled(String provider) {
|
||||
// Do nothing
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onProviderEnabled(String provider) {
|
||||
// Do nothing
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStatusChanged(String provider, int status, Bundle extras) {
|
||||
// Do nothing
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Registers to receive location updates from the GPS location provider.
|
||||
*/
|
||||
private void registerLocationListener() {
|
||||
LocationManager locationManager =
|
||||
(LocationManager) getSystemService(Context.LOCATION_SERVICE);
|
||||
if (locationManager != null) {
|
||||
LocationProvider gpsProvider =
|
||||
locationManager.getProvider(MyTracksConstants.GPS_PROVIDER);
|
||||
@@ -334,7 +336,7 @@ public class StatsActivity extends Activity
|
||||
+ gpsProvider.getName());
|
||||
}
|
||||
locationManager.requestLocationUpdates(gpsProvider.getName(),
|
||||
0/*minTime*/, 0/*minDist*/, this);
|
||||
0/*minTime*/, 0/*minDist*/, locationListener);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -342,8 +344,10 @@ public class StatsActivity extends Activity
|
||||
* Unregisters all location listener.
|
||||
*/
|
||||
private void unregisterLocationListener() {
|
||||
LocationManager locationManager =
|
||||
(LocationManager) getSystemService(Context.LOCATION_SERVICE);
|
||||
if (locationManager != null) {
|
||||
locationManager.removeUpdates(this);
|
||||
locationManager.removeUpdates(locationListener);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -364,7 +368,7 @@ public class StatsActivity extends Activity
|
||||
return;
|
||||
}
|
||||
|
||||
track = providerUtils.getTrack(selectedTrackId);
|
||||
Track track = providerUtils.getTrack(selectedTrackId);
|
||||
if (track == null || track.getStatistics() == null) {
|
||||
utils.setAllToUnknown();
|
||||
return;
|
||||
@@ -421,17 +425,17 @@ public class StatsActivity extends Activity
|
||||
*
|
||||
* @param l may be null (will set location fields to unknown)
|
||||
*/
|
||||
private void updateLocation(Location l) {
|
||||
if (l == null) {
|
||||
utils.setUnknown(R.id.elevation_register);
|
||||
utils.setUnknown(R.id.latitude_register);
|
||||
utils.setUnknown(R.id.longitude_register);
|
||||
utils.setUnknown(R.id.speed_register);
|
||||
} else {
|
||||
utils.setAltitude(R.id.elevation_register, l.getAltitude());
|
||||
utils.setLatLong(R.id.latitude_register, l.getLatitude());
|
||||
utils.setLatLong(R.id.longitude_register, l.getLongitude());
|
||||
utils.setSpeed(R.id.speed_register, l.getSpeed() * 3.6);
|
||||
}
|
||||
private void showLocation(Location l) {
|
||||
utils.setAltitude(R.id.elevation_register, l.getAltitude());
|
||||
utils.setLatLong(R.id.latitude_register, l.getLatitude());
|
||||
utils.setLatLong(R.id.longitude_register, l.getLongitude());
|
||||
utils.setSpeed(R.id.speed_register, l.getSpeed() * 3.6);
|
||||
}
|
||||
|
||||
private void showUnknownLocation() {
|
||||
utils.setUnknown(R.id.elevation_register);
|
||||
utils.setUnknown(R.id.latitude_register);
|
||||
utils.setUnknown(R.id.longitude_register);
|
||||
utils.setUnknown(R.id.speed_register);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user