Further improving/fixing drawing, and adding a bounding box for debugging.

This commit is contained in:
Rodrigo Damazio
2010-09-27 16:14:04 -03:00
parent cd9c17f9b3
commit 44a6f2d448
5 changed files with 211 additions and 108 deletions
+1
View File
@@ -37,6 +37,7 @@ limitations under the License.
<string name="share_url_only_key">shareUrlOnly</string> <string name="share_url_only_key">shareUrlOnly</string>
<string name="signal_sampling_frequency_key">signalSamplingFrequency</string> <string name="signal_sampling_frequency_key">signalSamplingFrequency</string>
<string name="split_frequency_key">splitFrequency</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 --> <!-- Preference keys which keep transient state (not user preferences) - DO NOT TRANSLATE -->
<string name="recording_track_key">recordingTrack</string> <string name="recording_track_key">recordingTrack</string>
+9
View File
@@ -125,4 +125,13 @@ limitations under the License.
android:persistent="false" /> android:persistent="false" />
</PreferenceCategory> </PreferenceCategory>
</PreferenceScreen> </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> </PreferenceScreen>
@@ -372,6 +372,8 @@ public class MyTracksMap extends MapActivity
setSelectedTrack(selectedTrackId); setSelectedTrack(selectedTrackId);
} }
updateOptionsButton(); updateOptionsButton();
mapOverlay.setDrawBounds(preferences.getBoolean(
getString(R.string.debug_draw_bounds_key), false));
preferences.registerOnSharedPreferenceChangeListener(this); preferences.registerOnSharedPreferenceChangeListener(this);
} }
} }
@@ -916,6 +918,10 @@ public class MyTracksMap extends MapActivity
mapOverlay.setShowEndMarker(!isRecordingSelected()); mapOverlay.setShowEndMarker(!isRecordingSelected());
mapView.postInvalidate(); 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.Path;
import android.graphics.Point; import android.graphics.Point;
import android.graphics.Rect; import android.graphics.Rect;
import android.graphics.Region;
import android.graphics.drawable.Drawable; import android.graphics.drawable.Drawable;
import android.location.Location; import android.location.Location;
@@ -59,6 +60,7 @@ public class MyTracksOverlay extends Overlay {
private int lastHeading = 0; private int lastHeading = 0;
private Location myLocation; private Location myLocation;
private boolean showEndMarker = true; private boolean showEndMarker = true;
private boolean drawBounds;
public MyTracksOverlay(Context context) { public MyTracksOverlay(Context context) {
this.context = context; this.context = context;
@@ -127,7 +129,11 @@ public class MyTracksOverlay extends Overlay {
* @param l the location to add * @param l the location to add
*/ */
public void addLocation(Location l) { public void addLocation(Location l) {
points.add(l); if (l != null) {
synchronized (points) {
points.add(l);
}
}
} }
public void addWaypoint(Waypoint wpt) { public void addWaypoint(Waypoint wpt) {
@@ -135,7 +141,9 @@ public class MyTracksOverlay extends Overlay {
} }
public int getNumLocations() { public int getNumLocations() {
return points.size(); synchronized (points) {
return points.size();
}
} }
public void clearWaypoints() { public void clearWaypoints() {
@@ -143,7 +151,9 @@ public class MyTracksOverlay extends Overlay {
} }
public void clearPoints() { public void clearPoints() {
points.clear(); synchronized (points) {
points.clear();
}
} }
public void setTrackDrawingEnabled(boolean trackDrawingEnabled) { public void setTrackDrawingEnabled(boolean trackDrawingEnabled) {
@@ -220,73 +230,118 @@ public class MyTracksOverlay extends Overlay {
} }
private void drawTrack(Canvas canvas, MapView mapView) { private void drawTrack(Canvas canvas, MapView mapView) {
if (points.size() < 2) { Path path;
return; Point pt = new Point();
} Location lastValidLocation;
int locLon = 0, locLat = 0;
GeoPoint firstGeoPoint = null;
boolean lastLocValid;
// Get the current viewing window: // Get the current viewing window:
int w = mapView.getLongitudeSpan(); int w = mapView.getLongitudeSpan();
int h = mapView.getLatitudeSpan(); int h = mapView.getLatitudeSpan();
int cx = mapView.getMapCenter().getLongitudeE6(); int cx = mapView.getMapCenter().getLongitudeE6();
int cy = mapView.getMapCenter().getLatitudeE6(); 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(); // Global bounding box, including points not visible
GeoPoint geoPoint; int allMinLat, allMinLon, allMaxLat, allMaxLon;
Location loc;
Location lastValidLocation = null; synchronized (points) {
Path path; int numPoints = points.size();
boolean wasInside; if (numPoints < 2) {
return;
// 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;
} }
locLon = (int) (loc.getLongitude() * 1E6);
locLat = (int) (loc.getLatitude() * 1E6);
// Draw a line segment if it's inside the viewing window: GeoPoint geoPoint;
if (locLat < 90E6 && lastLocLat < 90E6) { Location loc;
lastValidLocation = loc; int minLon, maxLon, minLat, maxLat;
minLon = Math.min(locLon, lastLocLon); lastValidLocation = points.get(0);
maxLon = Math.max(locLon, lastLocLon); int lastLocLon = allMinLon = allMaxLon = (int) (lastValidLocation.getLongitude() * 1E6);
minLat = Math.min(locLat, lastLocLat); int lastLocLat = allMinLat = allMaxLat = (int) (lastValidLocation.getLatitude() * 1E6);
maxLat = Math.max(locLat, lastLocLat); lastLocValid = MyTracksUtils.isValidLocation(lastValidLocation);
if (rect.intersects(minLon, minLat, maxLon, maxLat)) { boolean lastLocVisible = false;
if (!wasInside) { path = new Path();
geoPoint = new GeoPoint(lastLocLat, lastLocLon);
mapView.getProjection().toPixels(geoPoint, pt); // Loop over track points:
path.moveTo(pt.x, pt.y); 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 { lastLocLon = locLon;
wasInside = false; lastLocLat = locLat;
lastLocValid = locValid;
lastLocVisible = locVisible;
} }
lastLocLon = locLon;
lastLocLat = locLat;
} }
canvas.drawPath(path, selectedTrackPaint); canvas.drawPath(path, selectedTrackPaint);
if (drawBounds) {
drawBoundingBox(canvas, mapView,
allMinLat, allMinLon, allMaxLat, allMaxLon);
}
// Draw the "End" marker: // Draw the "End" marker:
Location currentLastValidLocation = lastValidLocation; if (showEndMarker && lastValidLocation != null) {
if (showEndMarker && currentLastValidLocation != null) {
canvas.save(); canvas.save();
geoPoint = MyTracksUtils.getGeoPoint(currentLastValidLocation); GeoPoint geoPoint = MyTracksUtils.getGeoPoint(lastValidLocation);
mapView.getProjection().toPixels(geoPoint, pt); mapView.getProjection().toPixels(geoPoint, pt);
canvas.translate(pt.x - (markerWidth / 2), pt.y - markerHeight); canvas.translate(pt.x - (markerWidth / 2), pt.y - markerHeight);
endMarker.draw(canvas); endMarker.draw(canvas);
@@ -294,22 +349,46 @@ public class MyTracksOverlay extends Overlay {
} }
// Draw the "Start" marker: // Draw the "Start" marker:
for (int i = 0; i < points.size(); i++) { if (firstGeoPoint != null) {
loc = points.get(i); mapView.getProjection().toPixels(firstGeoPoint, pt);
if (loc.getLatitude() < 90) { canvas.save();
locLon = (int) (loc.getLongitude() * 1E6); canvas.translate(pt.x - (markerWidth / 2), pt.y - markerHeight);
locLat = (int) (loc.getLatitude() * 1E6); startMarker.draw(canvas);
geoPoint = new GeoPoint(locLat, locLon); canvas.restore();
mapView.getProjection().toPixels(geoPoint, pt);
canvas.save();
canvas.translate(pt.x - (markerWidth / 2), pt.y - markerHeight);
startMarker.draw(canvas);
canvas.restore();
break;
}
} }
} }
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 @Override
public boolean draw(Canvas canvas, MapView mapView, boolean shadow, public boolean draw(Canvas canvas, MapView mapView, boolean shadow,
long when) { long when) {
@@ -378,4 +457,8 @@ public class MyTracksOverlay extends Overlay {
} }
return super.onTap(p, mapView); return super.onTap(p, mapView);
} }
public void setDrawBounds(boolean drawBounds) {
this.drawBounds = drawBounds;
}
} }
@@ -49,14 +49,12 @@ import android.widget.Toast;
* @author Sandor Dornbush * @author Sandor Dornbush
*/ */
public class StatsActivity extends Activity public class StatsActivity extends Activity
implements OnSharedPreferenceChangeListener, LocationListener { implements OnSharedPreferenceChangeListener {
private final StatsUtilities utils; private final StatsUtilities utils;
private UIUpdateThread thread; private UIUpdateThread thread;
private ContentObserver observer; private ContentObserver observer;
private LocationManager locationManager;
/** /**
* The id of the currently selected track. * The id of the currently selected track.
@@ -96,7 +94,6 @@ public class StatsActivity extends Activity
private boolean showCurrentSegment = false; private boolean showCurrentSegment = false;
private final MyTracksProviderUtils providerUtils; private final MyTracksProviderUtils providerUtils;
private Track track = null;
/** /**
* A runnable for posting to the UI thread. Will update the total time field. * 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); preferences.getBoolean(getString(R.string.report_speed_key), true);
checkLiveTrack(); checkLiveTrack();
restoreStats(); restoreStats();
updateLocation(null); showUnknownLocation();
preferences.registerOnSharedPreferenceChangeListener(this); preferences.registerOnSharedPreferenceChangeListener(this);
} }
locationManager =
(LocationManager) getSystemService(Context.LOCATION_SERVICE);
utils.setMetricUnits(metricUnits); utils.setMetricUnits(metricUnits);
utils.setReportSpeed(displaySpeed); utils.setReportSpeed(displaySpeed);
utils.updateUnits(); utils.updateUnits();
@@ -214,7 +209,7 @@ public class StatsActivity extends Activity
activityOnTop = true; activityOnTop = true;
checkLiveTrack(); checkLiveTrack();
restoreStats(); restoreStats();
updateLocation(null); showUnknownLocation();
super.onResume(); super.onResume();
} }
@@ -234,7 +229,7 @@ public class StatsActivity extends Activity
-1); -1);
checkLiveTrack(); checkLiveTrack();
restoreStats(); restoreStats();
updateLocation(null); showUnknownLocation();
} else if (key.equals(getString(R.string.recording_track_key))) { } else if (key.equals(getString(R.string.recording_track_key))) {
recordingTrackId = recordingTrackId =
sharedPreferences.getLong( sharedPreferences.getLong(
@@ -242,7 +237,7 @@ public class StatsActivity extends Activity
-1); -1);
checkLiveTrack(); checkLiveTrack();
restoreStats(); restoreStats();
updateLocation(null); showUnknownLocation();
} else if (key.equals(getString(R.string.metric_units_key))) { } else if (key.equals(getString(R.string.metric_units_key))) {
metricUnits = metricUnits =
sharedPreferences.getBoolean( sharedPreferences.getBoolean(
@@ -299,29 +294,36 @@ public class StatsActivity extends Activity
return super.onOptionsItemSelected(item); return super.onOptionsItemSelected(item);
} }
@Override private final LocationListener locationListener = new LocationListener() {
public void onLocationChanged(Location l) { @Override
if (selectedTrackIsRecording()) { public void onLocationChanged(Location l) {
updateLocation(l); if (selectedTrackIsRecording()) {
showLocation(l);
}
} }
}
@Override
@Override public void onProviderDisabled(String provider) {
public void onProviderDisabled(String provider) { // Do nothing
} }
@Override @Override
public void onProviderEnabled(String provider) { public void onProviderEnabled(String provider) {
} // Do nothing
}
@Override
public void onStatusChanged(String provider, int status, Bundle extras) { @Override
} public void onStatusChanged(String provider, int status, Bundle extras) {
// Do nothing
}
};
/** /**
* Registers to receive location updates from the GPS location provider. * Registers to receive location updates from the GPS location provider.
*/ */
private void registerLocationListener() { private void registerLocationListener() {
LocationManager locationManager =
(LocationManager) getSystemService(Context.LOCATION_SERVICE);
if (locationManager != null) { if (locationManager != null) {
LocationProvider gpsProvider = LocationProvider gpsProvider =
locationManager.getProvider(MyTracksConstants.GPS_PROVIDER); locationManager.getProvider(MyTracksConstants.GPS_PROVIDER);
@@ -334,7 +336,7 @@ public class StatsActivity extends Activity
+ gpsProvider.getName()); + gpsProvider.getName());
} }
locationManager.requestLocationUpdates(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. * Unregisters all location listener.
*/ */
private void unregisterLocationListener() { private void unregisterLocationListener() {
LocationManager locationManager =
(LocationManager) getSystemService(Context.LOCATION_SERVICE);
if (locationManager != null) { if (locationManager != null) {
locationManager.removeUpdates(this); locationManager.removeUpdates(locationListener);
} }
} }
@@ -364,7 +368,7 @@ public class StatsActivity extends Activity
return; return;
} }
track = providerUtils.getTrack(selectedTrackId); Track track = providerUtils.getTrack(selectedTrackId);
if (track == null || track.getStatistics() == null) { if (track == null || track.getStatistics() == null) {
utils.setAllToUnknown(); utils.setAllToUnknown();
return; return;
@@ -421,17 +425,17 @@ public class StatsActivity extends Activity
* *
* @param l may be null (will set location fields to unknown) * @param l may be null (will set location fields to unknown)
*/ */
private void updateLocation(Location l) { private void showLocation(Location l) {
if (l == null) { utils.setAltitude(R.id.elevation_register, l.getAltitude());
utils.setUnknown(R.id.elevation_register); utils.setLatLong(R.id.latitude_register, l.getLatitude());
utils.setUnknown(R.id.latitude_register); utils.setLatLong(R.id.longitude_register, l.getLongitude());
utils.setUnknown(R.id.longitude_register); utils.setSpeed(R.id.speed_register, l.getSpeed() * 3.6);
utils.setUnknown(R.id.speed_register); }
} else {
utils.setAltitude(R.id.elevation_register, l.getAltitude()); private void showUnknownLocation() {
utils.setLatLong(R.id.latitude_register, l.getLatitude()); utils.setUnknown(R.id.elevation_register);
utils.setLatLong(R.id.longitude_register, l.getLongitude()); utils.setUnknown(R.id.latitude_register);
utils.setSpeed(R.id.speed_register, l.getSpeed() * 3.6); utils.setUnknown(R.id.longitude_register);
} utils.setUnknown(R.id.speed_register);
} }
} }