Addressed Rodrigo's comments.

This commit is contained in:
Bartlomiej Niechwiej
2010-10-13 21:58:26 -07:00
parent 09203ffb95
commit b70e001206
2 changed files with 104 additions and 75 deletions
@@ -68,19 +68,17 @@ public class MyTracksOverlay extends Overlay {
// TODO: Remove it completely after completing performance tests. // TODO: Remove it completely after completing performance tests.
private boolean alwaysVisible = true; private boolean alwaysVisible = true;
private GeoPoint lastReferencePoint;
private Rect lastViewRect; private Rect lastViewRect;
private Path lastPath; private Path lastPath;
/** /**
* Represents a pre-processed {@code Location} to speed up drawing. * Represents a pre-processed {@code Location} to speed up drawing.
* This class is more like a data object and doesn't provide getters/setters. * This class is more like a data object and doesn't provide accessors.
*/ */
private static class CachedLocation { private static class CachedLocation {
public final boolean valid; public final boolean valid;
public final GeoPoint geoPoint; public final GeoPoint geoPoint;
// Cached point in the screen's coordinate system.
// TODO: Use it in drawTrack.
public Point point;
public CachedLocation(Location location) { public CachedLocation(Location location) {
this.valid = MyTracksUtils.isValidLocation(location); this.valid = MyTracksUtils.isValidLocation(location);
@@ -285,29 +283,67 @@ public class MyTracksOverlay extends Overlay {
private void drawTrack(Canvas canvas, Projection projection, Rect viewRect) { private void drawTrack(Canvas canvas, Projection projection, Rect viewRect) {
Path path; Path path;
final Point pt = new Point();
GeoPoint firstGeoPoint = null;
GeoPoint lastGeoPoint = null;
synchronized (points) { synchronized (points) {
// Merge the pending points with the list of cached locations. // Merge the pending points with the list of cached locations.
if (pendingPoints.drainTo(points) == 0 && lastPath != null && final GeoPoint referencePoint = projection.fromPixels(0, 0);
viewRect.equals(lastViewRect)) { int newPoints = pendingPoints.drainTo(points);
boolean newProjection = !viewRect.equals(lastViewRect) ||
!referencePoint.equals(lastReferencePoint);
if (newPoints == 0 && lastPath != null && !newProjection) {
// No need to recreate path (same points and viewing area). // No need to recreate path (same points and viewing area).
path = lastPath; path = lastPath;
} else { } else {
// Regenerate the whole path.
int numPoints = points.size(); int numPoints = points.size();
if (numPoints < 2) { if (numPoints < 2) {
return; path = null;
} } else if (lastPath != null && !newProjection) {
path = lastPath;
updatePath(projection, viewRect, path, numPoints - newPoints);
} else {
path = newPath(); path = newPath();
path.incReserve(numPoints); path.incReserve(numPoints);
updatePath(projection, viewRect, path, 0);
}
lastPath = path;
}
lastReferencePoint = referencePoint;
lastViewRect = viewRect;
}
if (path != null) {
canvas.drawPath(path, selectedTrackPaint);
}
// Draw the "End" marker.
if (showEndMarker) {
for (int i = points.size() - 1; i >= 0; --i) {
if (points.get(i).valid) {
drawElement(canvas, projection, points.get(i).geoPoint, endMarker,
-markerWidth / 2, -markerHeight);
break;
}
}
}
// Draw the "Start" marker.
for (int i = 0; i < points.size(); ++i) {
if (points.get(i).valid) {
drawElement(canvas, projection, points.get(i).geoPoint, startMarker,
-markerWidth / 2, -markerHeight);
break;
}
}
}
private void updatePath(Projection projection, Rect viewRect, Path path,
int startLocationIdx) {
// Whether to start a new segment on new valid and visible point. // Whether to start a new segment on new valid and visible point.
boolean newSegment = true; boolean newSegment =
boolean lastVisible = false; startLocationIdx > 0 ? !points.get(startLocationIdx - 1).valid : true;
// Loop over track points: boolean lastVisible = !newSegment;
for (CachedLocation loc : points) { final Point pt = new Point();
// Loop over track points.
for (int i = startLocationIdx; i < points.size(); ++i) {
CachedLocation loc = points.get(i);
// Check if valid, if not then indicate a new segment. // Check if valid, if not then indicate a new segment.
if (!loc.valid) { if (!loc.valid) {
newSegment = true; newSegment = true;
@@ -315,12 +351,6 @@ public class MyTracksOverlay extends Overlay {
} }
final GeoPoint geoPoint = loc.geoPoint; final GeoPoint geoPoint = loc.geoPoint;
if (firstGeoPoint == null) {
// Found the starting point.
firstGeoPoint = geoPoint;
}
lastGeoPoint = geoPoint;
// Check if this breaks the existing segment. // Check if this breaks the existing segment.
boolean visible = alwaysVisible || viewRect.contains( boolean visible = alwaysVisible || viewRect.contains(
geoPoint.getLongitudeE6(), geoPoint.getLatitudeE6()); geoPoint.getLongitudeE6(), geoPoint.getLatitudeE6());
@@ -339,23 +369,6 @@ public class MyTracksOverlay extends Overlay {
path.lineTo(pt.x, pt.y); path.lineTo(pt.x, pt.y);
} }
} }
lastPath = path;
lastViewRect = viewRect;
}
}
canvas.drawPath(path, selectedTrackPaint);
// Draw the "End" marker.
if (showEndMarker && lastGeoPoint != null) {
drawElement(canvas, projection, lastGeoPoint, endMarker, -markerWidth / 2,
-markerHeight);
}
// Draw the "Start" marker:
if (firstGeoPoint != null) {
drawElement(canvas, projection, firstGeoPoint,
startMarker, -markerWidth / 2, -markerHeight);
}
} }
// Visible for testing. // Visible for testing.
@@ -45,6 +45,10 @@ public class MyTracksOverlayTest extends AndroidTestCase {
private MapView mockView; private MapView mockView;
private Projection mockProjection; private Projection mockProjection;
/**
* A mock version of {@code MyTracksOverlay} that does not use
* {@class MapView}.
*/
private class MockMyTracksOverlay extends MyTracksOverlay { private class MockMyTracksOverlay extends MyTracksOverlay {
public MockMyTracksOverlay(Context context) { public MockMyTracksOverlay(Context context) {
super(context); super(context);
@@ -63,9 +67,16 @@ public class MyTracksOverlayTest extends AndroidTestCase {
} }
} }
/**
* A mock class that intercepts {@code Path}'s and records calls to
* {@code #moveTo()} and {@code #lineTo()}.
*/
private static class MockPath extends Path { private static class MockPath extends Path {
/** A list of disjoined path segments. */
public final List<List<PointF>> segments = new LinkedList<List<PointF>>(); public final List<List<PointF>> segments = new LinkedList<List<PointF>>();
/** The total number of points in this path. */
public int totalPoints; public int totalPoints;
private List<PointF> currentSegment; private List<PointF> currentSegment;
@Override @Override
@@ -84,15 +95,10 @@ public class MyTracksOverlayTest extends AndroidTestCase {
} }
} }
@Override /**
protected void setUp() throws Exception { * A mock {@code Projection} that acts as the identity matrix.
super.setUp(); */
canvas = new Canvas(); private static class MockProjection implements Projection {
myTracksOverlay = new MockMyTracksOverlay(getContext());
// Enable drawing.
myTracksOverlay.setTrackDrawingEnabled(true);
mockView = null;
mockProjection = new Projection() {
@Override @Override
public Point toPixels(GeoPoint in, Point out) { public Point toPixels(GeoPoint in, Point out) {
return out; return out;
@@ -105,7 +111,17 @@ public class MyTracksOverlayTest extends AndroidTestCase {
public GeoPoint fromPixels(int x, int y) { public GeoPoint fromPixels(int x, int y) {
return new GeoPoint(y, x); return new GeoPoint(y, x);
} }
}; }
@Override
protected void setUp() throws Exception {
super.setUp();
canvas = new Canvas();
myTracksOverlay = new MockMyTracksOverlay(getContext());
// Enable drawing.
myTracksOverlay.setTrackDrawingEnabled(true);
mockView = null;
mockProjection = new MockProjection();
} }
public void testAddLocation() throws Exception { public void testAddLocation() throws Exception {