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="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>
+9
View File
@@ -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);
}
}