Android map performance with > 800 overlays of KML data - android

I have some a shape file which I have converted to a KML file that I wish to read coordinates from and then draw paths between the coordinates on a MapView. With the help of this great post: How to draw a path on a map using kml file? I have been able to read the the KML into an ArrayList of "Placemarks". This great blog post then showed how to take a list of GeoPoints and draw a path: http://djsolid.net/blog/android---draw-a-path-array-of-points-in-mapview
The example in the above post only draws one path between some points however and since I have many more paths than that I am running into some performance problems. I'm currently adding a new RouteOverlay for each of the separate paths. This results in me having over 800 overlays when they have all been added. This has a performance hit and I would love some input on what I can do to improve it.
Here are some options I have considered:
Try to add all the points to a List which then can be passed into a class that will extend Overlay. In that new class perhaps it would be possible to add and draw the paths in a single Overlay layer? I'm not sure on how to implement this though since the paths are not always intersecting and they have different start and end points. At the moment I'm adding each path which has several points to it's own list and then I add that to an Overlay. That results in over 700 overlays...
Simplify the KML or SHP. Instead of having over 700 different paths, perhaps there is someway to merge them into perhaps 100 paths or less? Since alot of paths are intersected at some point it should be possible to modify the original SHP file so that it merges all intersections. Since I have never worked with these kinds of files before I have not been able to find a way to do this in GQIS. If someone knows how to do this I would love for some input on that. Here is a link to the group of shape files if you are interested:
http://danielkvist.net/cprg_bef_cbana_polyline.shp
http://danielkvist.net/cprg_bef_cbana_polyline.shx
http://danielkvist.net/cprg_bef_cbana_polyline.dbf
http://danielkvist.net/cprg_bef_cbana_polyline.prj
Anyway, here is the code I'm using to add the Overlays. Many thanks in advance.
RoutePathOverlay.java
package net.danielkvist;
import java.util.List;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.Point;
import android.graphics.RectF;
import com.google.android.maps.GeoPoint;
import com.google.android.maps.MapView;
import com.google.android.maps.Overlay;
import com.google.android.maps.Projection;
public class RoutePathOverlay extends Overlay
{
private int _pathColor;
private final List<GeoPoint> _points;
private boolean _drawStartEnd;
public RoutePathOverlay(List<GeoPoint> points)
{
this(points, Color.RED, false);
}
public RoutePathOverlay(List<GeoPoint> points, int pathColor, boolean drawStartEnd)
{
_points = points;
_pathColor = pathColor;
_drawStartEnd = drawStartEnd;
}
private void drawOval(Canvas canvas, Paint paint, Point point)
{
Paint ovalPaint = new Paint(paint);
ovalPaint.setStyle(Paint.Style.FILL_AND_STROKE);
ovalPaint.setStrokeWidth(2);
int _radius = 6;
RectF oval = new RectF(point.x - _radius, point.y - _radius, point.x + _radius, point.y + _radius);
canvas.drawOval(oval, ovalPaint);
}
public boolean draw(Canvas canvas, MapView mapView, boolean shadow, long when)
{
Projection projection = mapView.getProjection();
if (shadow == false && _points != null)
{
Point startPoint = null, endPoint = null;
Path path = new Path();
// We are creating the path
for (int i = 0; i < _points.size(); i++)
{
GeoPoint gPointA = _points.get(i);
Point pointA = new Point();
projection.toPixels(gPointA, pointA);
if (i == 0)
{ // This is the start point
startPoint = pointA;
path.moveTo(pointA.x, pointA.y);
}
else
{
if (i == _points.size() - 1)// This is the end point
endPoint = pointA;
path.lineTo(pointA.x, pointA.y);
}
}
Paint paint = new Paint();
paint.setAntiAlias(true);
paint.setColor(_pathColor);
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeWidth(3);
paint.setAlpha(90);
if (getDrawStartEnd())
{
if (startPoint != null)
{
drawOval(canvas, paint, startPoint);
}
if (endPoint != null)
{
drawOval(canvas, paint, endPoint);
}
}
if (!path.isEmpty())
canvas.drawPath(path, paint);
}
return super.draw(canvas, mapView, shadow, when);
}
public boolean getDrawStartEnd()
{
return _drawStartEnd;
}
public void setDrawStartEnd(boolean markStartEnd)
{
_drawStartEnd = markStartEnd;
}
}
MyMapActivity
package net.danielkvist;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import android.graphics.Color;
import android.os.Bundle;
import android.util.Log;
import com.google.android.maps.GeoPoint;
import com.google.android.maps.MapActivity;
import com.google.android.maps.MapView;
public class MyMapActivity extends MapActivity
{
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
MapView mapView = (MapView) findViewById(R.id.mapview);
mapView.setBuiltInZoomControls(true);
String url = "http://danielkvist.net/cprg_bef_cbana_polyline_simp1600.kml";
NavigationDataSet set = MapService.getNavigationDataSet(url);
drawPath(set, Color.parseColor("#6C8715"), mapView);
}
/**
* Does the actual drawing of the route, based on the geo points provided in
* the nav set
*
* #param navSet
* Navigation set bean that holds the route information, incl.
* geo pos
* #param color
* Color in which to draw the lines
* #param mMapView01
* Map view to draw onto
*/
public void drawPath(NavigationDataSet navSet, int color, MapView mMapView01)
{
ArrayList<GeoPoint> geoPoints = new ArrayList<GeoPoint>();
Collection overlaysToAddAgain = new ArrayList();
for (Iterator iter = mMapView01.getOverlays().iterator(); iter.hasNext();)
{
Object o = iter.next();
Log.d(BikeApp.APP, "overlay type: " + o.getClass().getName());
if (!RouteOverlay.class.getName().equals(o.getClass().getName()))
{
overlaysToAddAgain.add(o);
}
}
mMapView01.getOverlays().clear();
mMapView01.getOverlays().addAll(overlaysToAddAgain);
int totalNumberOfOverlaysAdded = 0;
for(Placemark placemark : navSet.getPlacemarks())
{
String path = placemark.getCoordinates();
if (path != null && path.trim().length() > 0)
{
String[] pairs = path.trim().split(" ");
String[] lngLat = pairs[0].split(","); // lngLat[0]=longitude
// lngLat[1]=latitude
// lngLat[2]=height
try
{
if(lngLat.length > 1 && !lngLat[0].equals("") && !lngLat[1].equals(""))
{
GeoPoint startGP = new GeoPoint(
(int) (Double.parseDouble(lngLat[1]) * 1E6),
(int) (Double.parseDouble(lngLat[0]) * 1E6));
GeoPoint gp1;
GeoPoint gp2 = startGP;
geoPoints = new ArrayList<GeoPoint>();
geoPoints.add(startGP);
for (int i = 1; i < pairs.length; i++)
{
lngLat = pairs[i].split(",");
gp1 = gp2;
if (lngLat.length >= 2 && gp1.getLatitudeE6() > 0
&& gp1.getLongitudeE6() > 0
&& gp2.getLatitudeE6() > 0
&& gp2.getLongitudeE6() > 0)
{
// for GeoPoint, first:latitude, second:longitude
gp2 = new GeoPoint(
(int) (Double.parseDouble(lngLat[1]) * 1E6),
(int) (Double.parseDouble(lngLat[0]) * 1E6));
if (gp2.getLatitudeE6() != 22200000)
{
geoPoints.add(gp2);
}
}
}
totalNumberOfOverlaysAdded++;
mMapView01.getOverlays().add(new RoutePathOverlay(geoPoints));
}
}
catch (NumberFormatException e)
{
Log.e(BikeApp.APP, "Cannot draw route.", e);
}
}
}
Log.d(BikeApp.APP, "Total overlays: " + totalNumberOfOverlaysAdded);
mMapView01.setEnabled(true);
}
#Override
protected boolean isRouteDisplayed()
{
// TODO Auto-generated method stub
return false;
}
}
Edit: There are of course some more files I'm using but that I have not posted. You can download the complete Eclipse project here: http://danielkvist.net/se.zip

Have you considered rendering all the paths to a bitmap and then use that as a overlay, and of-course you would need to render it again if the user zooms in or out or moves the map alot. Making the bitmap 2 or 4 times as large as the screen (be care-full not to use up all memory here) you should be able to get some zooming in and out a-swell as allow for a bit of panning until you need to render it again.
Rendering it like a quad-tree (with week references to the bitmaps in the tree) would allow for some caching and possibly big performance improvements.
Going with a quad-tree is not an easy approach but might be worth the effort if you have the time and knowledge for it. I believe this roughly is how the google maps handles its map tiles.

Related

Incorrect localization of markers on map. Strange behaviour of markers on the map

I works with OSMdroid. I extended the Overlay class and I overridden the draw method to my needs. And I have a problem with placing of markers. When I display them for the first time they have wrong location. But when I start zooming they move and after couple of zooms they have correct localization.
Here is my code:
protected final Rect mRect = new Rect();
protected Point mScreenPts = new Point();
#Override
protected void draw(Canvas c, MapView osmv, boolean shadow) {
Projection pj = osmv.getProjection();
synchronized (mInternalItemList) {
if (shadow && !mInternalItemList.isEmpty()) {
for(int i = 0; i < mInternalItemList.size(); i++) {
CustomizedItem customized = mInternalItemList.get(i);
pj.toMapPixels(new GeoPoint(customized.getLatitude(),
customized.getLongitude()), mScreenPts);
boundToHotspot(customized.getDrawable(), HotspotPlace.LOWER_LEFT_CORNER);
Drawable draw = customized.getDrawable();
draw.copyBounds(mRect);
draw.setBounds(mRect.left + mScreenPts.x, mRect.top + mScreenPts.y,
mRect.right + mScreenPts.x, mRect.bottom + mScreenPts.y);
draw.draw(c);
draw.setBounds(mRect);
}
}
}
}

How to cache android.graphics.path or Bitmap when using Overlays?

I'm using an Overlay to mark areas on Google Maps by drawing a shape of ten thousands of GeoPoints I get from any source. This works and looks like this:
#Override
public void draw(android.graphics.Canvas canvas, MapView mapView, boolean shadow) {
super.draw(canvas, mapView, false);
Projection projection = mapView.getProjection();
List<Zone> zones = ApplicationContext.getZones();
path.rewind();
for (Zone zone : zones) {
paint.setDither(true);
paint.setStyle(Style.FILL);
paint.setAlpha(40);
MultiPolygon multiPolygon = zone.getMultiPolygon();
List<Polygon> polygons = multiPolygon.getPolygons();
for (Polygon polygon : polygons) {
for (List<Coordinate> coordinates : polygon.getCoordinates()) {
for (int i = 0; i < coordinates.size(); i++) {
Point p = new Point();
projection.toPixels(new GeoPoint((int)(coordinates.get(i).getLatitude() * 1E6), (int)(coordinates.get(i).getLongitude() * 1E6)), p);
if (i == 0) {
path.moveTo(p.x, p.y);
}
else {
path.lineTo(p.x, p.y);
}
}
}
}
}
canvas.drawPath(path, paint);
}
The problem is that this is very resource consuming. Every time one scrolls or moves the map on MapView, the path has to be calculated over and over again, because the pixel coordinates have been changed. The drawn area could become so big that the scrolling on the MapView is so slow that it is functional unusable.
My ideas are
to somehow cache the "shape" the path generates and just redraw it
when the zoom level changes on the MapView.
to somehow draw the painting on an "on the fly"-Bitmap to use it as Overlay (maybe as ItemizedOverlay), listen for MapView scrolling and move the bitmap by the scrolled distance.
I'm not sure if there are better methods.
Any ideas how I could solve this problem?
(I'm using Google Maps API 1 and can't change).
Before resorting to trying to figure out how to match the map's movement, there are some optimizations to your current code that will probably yield significant savings. In particular, these two lines inside your inner loop is executed the most times, but fairly expensive to execute (two memory allocations, floating point multiplies, and four method calls).
Point p = new Point();
projection.toPixels(new GeoPoint((int)(coordinates.get(i).getLatitude() * 1E6), (int)(coordinates.get(i).getLongitude() * 1E6)), p);
First, you only ever need one Point object, so avoid allocating it in your loop. Move it to just below your path.rewind();
Second, if you pre-computed your coordinates as GeoPoints instead of computing them each time, you would save a lot of processing in your draw routine. You can also get rid of that if statement with a little work. Assuming you preconvert your list of coordinate to a list of GeoPoint, and make it available through polygon.getGeoCoordinates(), you could end up with your inner loops looking like -
for (List<GeoPoint> geoCoordinates : polygon.getGeoCoordinates()) {
projection.toPixels(geoCoordinates.get(0),p);
path.moveTo(p.x, p.y); // move to first spot
final List<GeoPoint> lineToList = geoCoordinates.sublist(1,geoCoordinates.size()); // A list of all the other points
for(GeoPoint gp : lineToList) {
projection.toPixels(gp, p);
path.lineTo(p.x, p.y);
}
}
And that will run a lot faster than what you were doing before.
After tinkering around in the last days I found a possible solution (and I don't think there is a better one) to not draw the path over and over again but move it to the current position.
The difficult part was to figure out how to cache the drawn shape to not calculate it over and over again. This can be done by using a Matrix. With this Matrix (I imagine this as some kind of "template") you can manipulate the points coordinates inside the path. The first time (when someone starts moving the Map) I draw the area as usual. When it tries to calculate it the second time or more, I don't redraw the shape but I manipulate the path by calculating the "delta" from the current point to the last point. I know what the current point is, because I always map the original GeoPoint (which always stays the same) to the point which results from the current projection. The "delta" needs to be set as Matrix. After that I transform the path by using this new Matrix. The result is really very fast. The scrolling of the Map is as fast as without using an Overlay.
This looks like this (this is no production code, and it cannot deal with zooming yet, but it shows the principle I use as basis for my optimizations):
public class DistrictOverlay extends Overlay {
// private final static String TAG = DistrictOverlay.class.getSimpleName();
private Paint paint = new Paint();
private Path path = new Path();
private boolean alreadyDrawn = false;
private GeoPoint origGeoPoint;
Point p = new Point();
Point lastPoint = new Point();
#Override
public void draw(android.graphics.Canvas canvas, MapView mapView, boolean shadow) {
super.draw(canvas, mapView, false);
Projection projection = mapView.getProjection();
List<Zone> zones = ApplicationContext.getZones();
if (!alreadyDrawn) {
path.rewind();
for (Zone zone : zones) {
if (!zone.getZoneId().equals(MenuContext.getChosenZoneId())) {
continue;
}
String dateString = zone.getEffectiveFrom().trim().replace("CEST", "").replace("GMT", "").replace("CET", "").replace("MESZ", "");
if (DateUtil.isBeforeCurrentDate(dateString)) {
paint.setColor(Color.RED);
} else {
paint.setColor(Color.GREEN);
}
paint.setDither(true);
paint.setStyle(Style.FILL);
paint.setAlpha(40);
MultiPolygon multiPolygon = zone.getMultiPolygon();
List<Polygon> polygons = multiPolygon.getPolygons();
for (Polygon polygon : polygons) {
for (List<GeoPoint> geoPoints : polygon.getGeoPoints()) {
projection.toPixels(geoPoints.get(0), p);
path.moveTo(p.x, p.y);
origGeoPoint = new GeoPoint(geoPoints.get(0).getLatitudeE6(), geoPoints.get(0).getLongitudeE6());
lastPoint = new Point(p.x, p.y);
final List<GeoPoint> pathAsList = geoPoints.subList(1, geoPoints.size());
for (GeoPoint geoPoint : pathAsList) {
projection.toPixels(geoPoint, p);
path.lineTo(p.x, p.y);
}
}
}
}
}
else {
projection.toPixels(origGeoPoint, p);
Matrix translateMatrix = new Matrix();
translateMatrix.setTranslate(p.x - lastPoint.x, p.y - lastPoint.y);
path.transform(translateMatrix);
lastPoint = new Point(p.x, p.y);
}
canvas.drawPath(path, paint);
if (!path.isEmpty()) {
alreadyDrawn = true;
}
}
#Override
public boolean onTap(GeoPoint p, MapView mapView) {
return true;
}
}

Android: Draw Polygon on OSM MapView (OSMDroid)

Is it possible to draw a polygon on the mapview of OSMDroid? It should scale easy with the Mapview so I didn't want to use the canvas. Any advice?
I have my own MapOverlay (extends org.osmdroid.views.overlay.Overlay), but can't get my Polygon on it.
If your class is extending org.osmdroid.views.overlay.Overlay you have to modify the draw method so it looks somehow like in the code below:
#Override
protected void draw(final Canvas canvas, final MapView mapView, final boolean shadow) {
if (shadow) {
return;
}
if (this.mPoints.size() < 2) {
//Do nothing
return;
}
final Projection pj = mapView.getProjection();
// precompute new points to the intermediate projection.
final int size = this.mPoints.size();
while (this.mPointsPrecomputed < size) {
final Point pt = this.mPoints.get(this.mPointsPrecomputed);
pj.toMapPixelsProjected(pt.x, pt.y, pt);
this.mPointsPrecomputed++;
}
Point screenPoint0 = null; // points on screen
Point screenPoint1 = null;
Point projectedPoint0; // points from the points list
Point projectedPoint1;
// clipping rectangle in the intermediate projection, to avoid performing projection.
final Rect clipBounds = pj.fromPixelsToProjected(pj.getScreenRect());
mPath.rewind();
mPath.setFillType(Path.FillType.EVEN_ODD);
projectedPoint0 = this.mPoints.get(size - 1);
mLineBounds.set(projectedPoint0.x, projectedPoint0.y, projectedPoint0.x, projectedPoint0.y);
for (int i = size - 2; i >= 0; i--) {
// compute next points
projectedPoint1 = this.mPoints.get(i);
mLineBounds.union(projectedPoint1.x, projectedPoint1.y);
if (!Rect.intersects(clipBounds, mLineBounds)) {
// skip this line, move to next point
projectedPoint0 = projectedPoint1;
screenPoint0 = null;
continue;
}
// the starting point may be not calculated, because previous segment was out of clip
// bounds
if (screenPoint0 == null) {
screenPoint0 = pj.toMapPixelsTranslated(projectedPoint0, this.mTempPoint1);
mPath.moveTo(screenPoint0.x, screenPoint0.y);
}
screenPoint1 = pj.toMapPixelsTranslated(projectedPoint1, this.mTempPoint2);
// skip this point, too close to previous point
if (Math.abs(screenPoint1.x - screenPoint0.x) + Math.abs(screenPoint1.y - screenPoint0.y) <= 1) {
continue;
}
mPath.lineTo(screenPoint1.x, screenPoint1.y);
// update starting point to next position
projectedPoint0 = projectedPoint1;
screenPoint0.x = screenPoint1.x;
screenPoint0.y = screenPoint1.y;
mLineBounds.set(projectedPoint0.x, projectedPoint0.y, projectedPoint0.x, projectedPoint0.y);
}
mPath.close();
canvas.drawPath(mPath, this.mPaint);
}

Android- Draw Path from KML File in MapView

I've been working on this for a while now, but I still have not gotten the result I'm looking for. I'm trying to create an app to display our mountain bike trails so you can see where you are when you're on them. I started by manually copying coordinates from my kml file and pasting them as Geopoints with this code which worked until I got to point 80. Then the LogCat gave an error rejecting large method, and I still have hundreds more to go:
import java.util.List;
import com.google.android.maps.GeoPoint;
import com.google.android.maps.MapActivity;
import com.google.android.maps.MapController;
import com.google.android.maps.MapView;
import com.google.android.maps.Overlay;
import com.google.android.maps.Projection;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.Point;
import android.os.Bundle;
public class TrailMaps extends MapActivity {
private List mapOverlays;
private Projection projection;
private MapController mc;
private MapView mapView;
private GeoPoint gP;
private MyOverlay myoverlay;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
mapView = (MapView) findViewById(R.id.mapview);//Creating an instance of MapView
mapView.setBuiltInZoomControls(true);//Enabling the built-in Zoom Controls
gP = new GeoPoint(43311836,-91777756);//Creating a GeoPoint
mc = mapView.getController();
mc.setCenter(gP);
mc.setZoom(15);//Initializing the MapController and setting the map to center at the
mapOverlays = mapView.getOverlays();
projection = mapView.getProjection();
myoverlay = new MyOverlay();
mapOverlays.add(myoverlay);
}
class MyOverlay extends Overlay{
public MyOverlay(){
}
public void draw(Canvas canvas, MapView mapView, boolean shadow) {
super.draw(canvas, mapView, shadow);
Paint paint;
paint = new Paint();
paint.setDither(true);
paint.setColor(Color.RED);
paint.setStyle(Paint.Style.FILL_AND_STROKE);
paint.setStrokeJoin(Paint.Join.ROUND);
paint.setStrokeWidth(2);
GeoPoint gp1 = new GeoPoint(43311836,-91777756);
GeoPoint gp2 = new GeoPoint(43311718,-91777699);
GeoPoint gp3 = new GeoPoint(43311718,-91777699);
GeoPoint gp4 = new GeoPoint(43311666,-91777627);
GeoPoint gp5 = new GeoPoint(43311624,-91777541);
Point pt1 = new Point();
Point pt2 = new Point();
Point pt3 = new Point();
Point pt4 = new Point();
Point pt5 = new Point();
Path path1 = new Path();
Path path2 = new Path();
Path path3 = new Path();
projection.toPixels(gp1,pt1);
projection.toPixels(gp2, pt2);
projection.toPixels(gp3, pt3);
projection.toPixels(gp4, pt4);
projection.toPixels(gp5, pt5);
path1.moveTo(pt1.x, pt1.y);
path1.lineTo(pt2.x, pt2.y);
path2.moveTo(pt3.x,pt3.y);
path2.lineTo(pt4.x, pt4.y);
path3.moveTo(pt4.x,pt4.y);
path3.lineTo(pt5.x,pt5.y);
canvas.drawPath(path1, paint);
canvas.drawPath(path2, paint);
canvas.drawPath(path3, paint);
}
}
#Override
protected boolean isRouteDisplayed() {
return false;
}
}
Then I tried to parse the kml file as in this example: How to draw a path on a map using kml file?
But this is taking my coordinates and finding the nearest streets and overlaying a route. My coordinates are not along the street they are in a park off road, so how else should I do it?
Right now I'm open to any suggestions. Is there a better way to parse the kml file, do it locally vs going to http://maps.google.com/maps?, overlaying it as an image, or a whole new direction completely... Any suggestions would be much appreciated.
Thanks

Google Maps overlay image not visible

I want to overlay a map image (.jpg) over the Google Maps mapview.
The problem is: The overlay image is not showing, who knows what's the
problem?
There is no error in logcat and the MapView is working.
The code:
package nl.ultimo.android.skikaart;
import java.util.List;
import com.google.android.maps.GeoPoint;
import com.google.android.maps.MapActivity;
import com.google.android.maps.MapController;
import com.google.android.maps.MapView;
import com.google.android.maps.Overlay;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Point;
import android.graphics.Rect;
import android.os.Bundle;
public class MapsActivity extends MapActivity
{
Bitmap bmp; //Loaded bitmap in memory
GeoPoint min; //Top left corner (lat/long)
GeoPoint max; //Right bottom corner (lat/long)
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
float lat1 = 45.19775f;
float lng1 = 6.28418333f;
float lat2 = 45.2636667f;
float lng2 = 6.17431667f;
min = new GeoPoint((int)(lat1 * 1E6), (int)(lng1 * 1E6)); // bounding rectangle
max = new GeoPoint((int)(lat2 * 1E6), (int)(lng2 * 1E6));
MapView mapView = (MapView) findViewById(R.id.mapView);
MapController ctrl = mapView.getController();
int x = (min.getLongitudeE6() + max.getLongitudeE6())/ 2; //Select map center
int y = (min.getLatitudeE6() + max.getLatitudeE6())/ 2;
ctrl.setCenter(new GeoPoint(y,x));
ctrl.setZoom(12); //Set scale
mapView.setBuiltInZoomControls(true); //Enable zoom controls
//Add overlay
MapOverlay mapOverlay = new MapOverlay();
List<Overlay> listOfOverlays = mapView.getOverlays();
listOfOverlays.clear();
listOfOverlays.add(mapOverlay);
mapView.invalidate();
}
class MapOverlay extends com.google.android.maps.Overlay
{
#Override
public boolean draw(Canvas canvas, MapView mapView, boolean shadow, long when)
{
super.draw(canvas, mapView, shadow);
//Translate the GeoPoint to screen pixels
Point screenPts = new Point();
mapView.getProjection().toPixels(min, screenPts);
//The overlay image
Bitmap bmp = BitmapFactory.decodeResource(getResources(),R.drawable.skikaart);
//Prepare two rectangles (pixels)
Point top_left = new Point();
mapView.getProjection().toPixels(min, top_left);
Point bottom_right = new Point();
mapView.getProjection().toPixels(max, bottom_right);
Rect src = new Rect( 0,0,bmp.getWidth() - 1, bmp.getHeight() - 1 );
Rect dst = new Rect( top_left.x, bottom_right.y,bottom_right.x,top_left.y );
canvas.drawBitmap(bmp, src, dst, null);
return true;
}
}
#Override
protected boolean isRouteDisplayed() {
return false;
}
}
to see marker you need to do next
Drawable drawable = ...set your marker drawable
drawable.setBounds(-drawable.getIntrinsicWidth() / 2, -drawable.getIntrinsicHeight(), drawable.getIntrinsicWidth() / 2, 0);
overlayitem.setMarker(drawable);
Just to make things clear here is a quote from reference
"The setBounds(Rect) method must be called to tell the Drawable where it is drawn and how large it should be."
Your code has one minor mistake.
Change
Rect dst = new Rect( top_left.x, bottom_right.y,bottom_right.x,top_left.y );
to
Rect dst = new Rect( top_left.x, top_left.y,bottom_right.x,bottom_right.y );
and you should be good.
Remember that draw() is called each time the overlay needs to be rendered. When the map is being moved by the user, this could happen multiple times per second!!
You need to load the resource only ONCE, then only draw the bitmap onto the canvas during the draw invocation.
Also, your current implementation is highly coupled with the actual Activity.
in your activity
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
...
map.getOverlays().add(new PNGMapOverlay(getResources(), R.drawable.bitmap_id));
}
// allows re-factoring into separate class/file
class MapOverlay extends com.google.android.maps.Overlay
{
private Bitmap bitmap;
public MapOverlay(Resources resources, int resourceId) {
bitmap = BitmapFactory.decodeResource(resources, resourceId);
}
#Override
public void draw(Canvas canvas, MapView mapView, boolean shadow) {
...
canvas.drawBitmap(bmp, src, dst, null);
}
}
Change this code
min = new GeoPoint((int)(lat1 * 1E6), (int)(lng2 * 1E6)); // bounding rectangle
max = new GeoPoint((int)(lat2 * 1E6), (int)(lng1 * 1E6));
instead of
min = new GeoPoint((int)(lat1 * 1E6), (int)(lng1 * 1E6)); // bounding rectangle
max = new GeoPoint((int)(lat2 * 1E6), (int)(lng2 * 1E6));
and try its working.
You have to add overlays into your listOfOverlays. Then only it will be shown on the map. For that you have to create an overlayitem using ur geopoint and then add it to the list of overlays.
For eg:
GeoPoint point = new GeoPoint((int) (latitude * 1E6), (int) (longitude * 1E6));
OverlayItem overlayItem = new OverlayItem(point, "", "");
listOfOverlays.addOverlay(overlayItem);
mapView.invalidate();
Try and see. If you face any issue, please add as comments.
I just spent ages pulling my hair out with the same problem as you. Turned out removing android:layout_weight="1" from my MapView declaration resolved the problem. Don't ask me why!

Categories

Resources