I am having trouble with overlays. I have drawn a polygon overlay on the map, however, when I zoom in or out, the edges no longer align with where I want them to. How can I fix this?
Here is what it looks like when I start the app (it covers the whole parking lot perfectly):
Correct
Here is what it looks like when I zoom out (edges no longer line up with parking lot. The overlay looks a bit bigger than the parking lot):
Zoomed out
Also, it doesn't align well when I zoom in. In this case the overlay is a bit smaller that the parking lot. (Sorry, stackoverflow won't let me post more that 2 links)
Any suggestions on how to fix this?
Here is the code:
private Projection projection;
private List<Overlay> mapOverlays;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
MapView mapView = (MapView) findViewById(R.id.mapView);
mapView.setBuiltInZoomControls(true);
MapController mc = mapView.getController();
mc.setZoom(17);
mc.animateTo(new GeoPoint((int)(32.734248*1E6), (int)(-97.113448*1E6)));
mapOverlays = mapView.getOverlays();
projection = mapView.getProjection();
mapOverlays.add(new MyOverlay());
mapView.postInvalidate();
}
#Override
protected boolean isRouteDisplayed() {
return false;
}
class MyOverlay extends Overlay{
public MyOverlay(){
}
public void draw(Canvas canvas, MapView mapv, boolean shadow){
super.draw(canvas, mapv, shadow);
Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mPaint.setColor(Color.RED);
mPaint.setStyle(Paint.Style.FILL);
mPaint.setAlpha(100);
GeoPoint gP1 = new GeoPoint(32733839,-97112976);
GeoPoint gP2 = new GeoPoint(32733875, -97113448);
GeoPoint gP3 = new GeoPoint(32734961,-97113455);
GeoPoint gP4 = new GeoPoint(32734953, -97112962);
Point p1 = new Point();
Point p2 = new Point();
Point p3 = new Point();
Point p4 = new Point();
Path path = new Path();
projection.toPixels(gP1, p1);
projection.toPixels(gP2, p2);
projection.toPixels(gP3, p3);
projection.toPixels(gP4, p4);
path.moveTo(p1.x, p1.y);
path.lineTo(p2.x,p2.y);
path.lineTo(p3.x,p3.y);
path.lineTo(p4.x,p4.y);
canvas.drawPath(path, mPaint);
}
}
}
Everytime the zoom changes, Projection also changes. Even when you make a large move in the map without changing zoom, projection may change.
To correct your code you need to add the line as bellow:
public void draw(Canvas canvas, MapView mapv, boolean shadow){
super.draw(canvas, mapv, shadow);
Projection projection = mapv.getProjection(); //Add this line
Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mPaint.setColor(Color.RED);
mPaint.setStyle(Paint.Style.FILL);
mPaint.setAlpha(100);
GeoPoint gP1 = new GeoPoint(32733839,-97112976);
GeoPoint gP2 = new GeoPoint(32733875, -97113448);
GeoPoint gP3 = new GeoPoint(32734961,-97113455);
GeoPoint gP4 = new GeoPoint(32734953, -97112962);
Point p1 = new Point();
Point p2 = new Point();
Point p3 = new Point();
Point p4 = new Point();
Path path = new Path();
projection.toPixels(gP1, p1);
projection.toPixels(gP2, p2);
projection.toPixels(gP3, p3);
projection.toPixels(gP4, p4);
path.moveTo(p1.x, p1.y);
path.lineTo(p2.x,p2.y);
path.lineTo(p3.x,p3.y);
path.lineTo(p4.x,p4.y);
canvas.drawPath(path, mPaint);
}
And you can remove the projection created in onCreate().
--EDITED--
Improvements - Quick wins
onDraw() is called twice eveytime you move the map or change zoom level, so it's important to make it as possible. Bellow you can find some suggestions:
private List<Overlay> mapOverlays;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
MapView mapView = (MapView) findViewById(R.id.mapView);
mapView.setBuiltInZoomControls(true);
MapController mc = mapView.getController();
mc.setZoom(17);
mc.animateTo(new GeoPoint((int)(32.734248*1E6), (int)(-97.113448*1E6)));
mapOverlays = mapView.getOverlays();
mapOverlays.add(new MyOverlay());
mapView.postInvalidate();
}
#Override
protected boolean isRouteDisplayed() {
return false;
}
class MyOverlay extends Overlay{
//Moved objects that need only one instance to the initialization, to avoid creating a new copy of each every time draw() runs
private Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
private GeoPoint gP1 = new GeoPoint(32733839,-97112976);
private GeoPoint gP2 = new GeoPoint(32733875, -97113448);
private GeoPoint gP3 = new GeoPoint(32734961,-97113455);
private GeoPoint gP4 = new GeoPoint(32734953, -97112962);
private Point p1 = new Point();
private Point p2 = new Point();
private Point p3 = new Point();
private Point p4 = new Point();
private Path path = new Path();
public MyOverlay(){
//mPaint settings done on class creation, to avoid repeating them on draw() call
mPaint.setColor(Color.RED);
mPaint.setStyle(Paint.Style.FILL);
mPaint.setAlpha(100);
}
public void draw(Canvas canvas, MapView mapv, boolean shadow){
super.draw(canvas, mapv, shadow);
//draw is always called twice, one with shadow equal to true and one to false.
//This can be used to draw the same image with shadow
//But you are not using shadows, so you can immediately return half of the calls, and reduce the draw() effort by half
if(shadow) return;
Projection projection = mapv.getProjection();
projection.toPixels(gP1, p1);
projection.toPixels(gP2, p2);
projection.toPixels(gP3, p3);
projection.toPixels(gP4, p4);
path.rewind();
path.moveTo(p1.x,p1.y);
path.lineTo(p2.x,p2.y);
path.lineTo(p3.x,p3.y);
path.lineTo(p4.x,p4.y);
canvas.drawPath(path, mPaint);
}
}
Improvements - a more complex one
The improvement I'm describing bellow is a overkill for you current overlay. It only makes sense when you have realy huge paths to draw.
When you move the map, without zomming it, with the code above the path will be recreated and redrawn in a different place to be aligned with the map. But the path you are creating is the same size, same shape as the previous one, just in a different position.
You can achive the same result using:
path.offset(dx, dy);
where dx, dy is the number of pixels you need to move the path to keep it aligned with the map. Of course, you need to keep track where was the map last time you offset the path, so you can offset the path to the new map position.
If you have a path with several thousands of points, offseting the path will be about 100 times faster then redrawing it.
You also need to keep track on zoom level, as you still need to recreate the path when zoom changes. You can't use getCurrentZoomLevel() to do it, as it´s not synchronized with zoom animation. You need to test longitudeSpan() value changes, to be able to have a synchronized path creation with zoom change animation.
I hope this will help.
Regards.
I need two overlay item in the map.I have used the following code to get the overlay
enter code here 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);
Paint paint = new Paint();
//---translate the GeoPoint to screen pixels---
Point screenPts = new Point();
mapView.getProjection().toPixels(p, screenPts);
// mapView.getProjection().toPixels(p1, screenPts);
paint.setStrokeWidth(1);
paint.setARGB(255, 255, 00, 00);
paint.setStyle(Paint.Style.STROKE);
//---add the marker---
Bitmap bmp = BitmapFactory.decodeResource(
getResources(), R.drawable.marker);
canvas.drawBitmap(bmp, screenPts.x, screenPts.y, paint);
canvas.drawText("Here I am...", screenPts.x, screenPts.y, paint);
return true;
}
MapOverlay mapOverlay = new MapOverlay();
List<Overlay> listOfOverlays = mapView.getOverlays();
listOfOverlays.clear();
listOfOverlays.add(mapOverlay);
mapView.invalidate();
the below code in in on create portion.from this code i could only get one overlay .how can I use it to get another overlay?I want two overlay,how could I get another one from this code?
You can use two/multiple overlay by adding MapOverlay on List<Overlay> as listOfOverlays.add(mapOverlay);. To know more information about adding Map overlay in android map, look at the answer Here
You just need to repeat the line:
listOfOverlays.add(mapOverlay);
everytime you want to add another overlay to mapview.
I'm working on a project to display a route in a MapView based on current location from GPS Provider. I'm able to draw the path between two points but the problem starts when the location changes to a new point causing the draw path to erase.
Basically my Location Listener saves the current GeoPoint and sets the new GeoPoint location and after that it starts the overlay to draw a path based on those two points.I think an option could be saving the coordinates to a database and then pulling the information from there to draw the path.
Here is my code so far:
private class MyLocationListener implements LocationListener {
public void onLocationChanged(Location location) {
Toast.makeText(getBaseContext(), "Tracking device..",
Toast.LENGTH_SHORT).show();
gp2 = new GeoPoint(
gp1.getLatitudeE6(),
gp1.getLongitudeE6());
gp1 = new GeoPoint(
(int) (location.getLatitude() * 1000000),
(int) (location.getLongitude() * 1000000));
myOverlay = new MapOverlay();
mapOverlays_route.add(myOverlay);
myMapView.invalidate();
}
}
class MapOverlay extends com.google.android.maps.Overlay{
public MapOverlay(){
}
public void draw(Canvas canvas, MapView mapv, boolean shadow){
super.draw(canvas, mapv, shadow);
//Configuring the paint brush
Paint mPaint = new Paint();
mPaint.setDither(true);
mPaint.setColor(Color.RED);
mPaint.setStyle(Paint.Style.FILL_AND_STROKE);
mPaint.setStrokeJoin(Paint.Join.ROUND);
mPaint.setStrokeCap(Paint.Cap.ROUND);
mPaint.setStrokeWidth(4);
Point p1 = new Point();
Point p2 = new Point();
Path path1 = new Path();
Path path2 = new Path();
projection.toPixels(gp1, p1);
projection.toPixels(gp2, p2);
path1.moveTo(p2.x, p2.y);//current location
path1.lineTo(p1.x,p1.y);//new location
canvas.drawPath(path1, mPaint);//drawing the path
}
}
Like you said, you need to have these coordinates stored somewhere. These can be stored in a database or a more temporary local list. The draw method must also iterate between all of the coordinates you store.
To show an specific location in android Map, I am using overlay class, and paint object which have reference of Geo point, drawing an balloon bitmap image.
But when I zoom (in/out) map, my balloon does not adjust according to the changed view of the map.
I'm using the following overlay pattern:
class MapOverlay extends com.google.android.maps.Overlay
{
#Override
public void draw(Canvas canvas, MapView mapView, boolean shadow) {
Point point = null, point1 = null;
if(p!=null)
{
point = new Point();
mapView.getProjection().toPixels(p, point);
Bitmap bmp = BitmapFactory.decodeResource(
getResources(), R.drawable.redbaloon);
canvas.drawBitmap(bmp, point.x-38, point.y+60, null);
}}
How can I draw balloon with zooming?
i want to mark with push pin image on more than one places on google map using overlayitem class..OR in simple how to add more than one overlay items on map..
as of now i can only mark a single place by overriding draw method of mapoverlay subclass...
here is my code
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(p, screenPts);
//---add the marker---
Bitmap bmp = BitmapFactory.decodeResource(getResources(), R.drawable.pushpin);
canvas.drawBitmap(bmp, screenPts.x, screenPts.y-24, null);
return true;
}
}
You can draw as many things as you like in the draw() method so just iterate over all the points you have in a loop and draw them one by one.