How to access MyLocationOverlay's canvas? - android

I override the drawMyLocation of MyLocationOverlay to display an arrow as marker instead of the normal blue dot. However, I also need to change the direction to which the pointer is pointing depending on the sensor of the phone. I decided to call drawMyLocation inside onSensorChanged. But one of the parameters required to call drawMyLocation is a Canvas. How can I access the Canvas of the MyLocationOverlay? Or do I need to create a new Canvas and pass the new Canvas everytime I call drawMyLocation inside onSensorChanged?
Below is my code when I tried to override draw method. However, even though I can see that it was continuously being executed, it takes a while for the rotated bitmap to display.
**UPDATE: If I try to touch my map, I can see my arrow rotating as I touch the map. However, if I don't touch it, it takes a while for the arrow to update its direction.
public boolean draw(android.graphics.Canvas canvas, MapView mapView, boolean shadow, long when)
{
Log.v("Message", "Executing draw method...");
boolean result;
result = super.draw(canvas, mapView, shadow, when);
if(geoLastFix != null) //geoLastFix contains the GeoPoint of my Location.
{
Point screenPts = mapView.getProjection().toPixels(geoLastFix, null);
//rotate bitmap
Bitmap arrowBitmap = marker;
Matrix matrix = new Matrix();
matrix.postRotate(orientation);
Bitmap rotatedBmp = Bitmap.createBitmap(
arrowBitmap,
0, 0,
arrowBitmap.getWidth(),
arrowBitmap.getHeight(),
matrix,
true
);
//print bitmap to canvas
canvas.drawBitmap(
rotatedBmp,
screenPts.x - (rotatedBmp.getWidth() / 2),
screenPts.y - (rotatedBmp.getHeight() / 2),
null
);
}
return result;
}

You should not be accessing the canvas outside of the draw() method. If you find yourself needing to do drawing or use the canvas, you should override the draw() method.
Use the onSensonrChanged method to save the current orientation or sensor information into your classes state and then override the draw() method and use the saved state to augment your drawing routine.

Related

Calibrated PNG over google map

I have a google map activity with trails, pois, proximity alerts, etc. and I would like to put a new PNG map (new layer) over the current google map at the same position (calibrated by latitude and longitude). How could I do that?
Best regards
Use the Google Maps Overlay functionality. Here is a rough outline for what needs to be done.
public class PNGOverlay extends Overlay {
Bitmap mImage;
// Allocate once and reuse
private final Paint mPaint = new Paint();
PNGOverlay(Bitmap image) {
mImage=image;
// Configure paint so image is transparent
}
/**
* Draw the overlay over the map.
*
* #see com.google.android.maps.Overlay#draw(Canvas, MapView, boolean)
*/
#Override
public void draw(Canvas canvas, MapView mapv, boolean shadow) {
// Use projection to figure out where to draw
Point center = new Point();
Projection projection = mapv.getProjection();
projection.toPixels(new GeoPoint(lat,lon), p);
// Transform image to fill the correct area
Matrix matrix = new Matrix;
// Do stuff
// Draw the image
canvas.drawBitmap(mImage, matrix, mPaint);
}
}
Have you tried adding both views to a FrameLayout? I would recommend that you make the top one transparent, however.
Using Surface View for camera and others for overlay image

How to use a custom compass image android

Let me start by saying that I have seen this thread: How can I replace the Compass image of MyLocationOverlay?
According to that thread, it tells me that I can't override the icon.
Not a big deal. That said, I'm trying to figure out a way to implement this.
Would I be correct in saying that I would need to create my own custom canvas that would simply draw the icon and rotate it and override the drawcompass method in another custom class that extends MyLocationOverlay?
If that is correct, how do I create this custom canvas of the icon/rotate it? (I have no experience with drawing in the android os).
Didn't need to make my own custom canvas, only had to override the drawCompass method, so it appears that the information in the initial question I linked was incorrect:
#Override
protected void drawCompass(Canvas canvas, float bearing) {
Bitmap arrowBitmap = BitmapFactory.decodeResource( mContext.getResources(), R.drawable.compass);
Matrix matrix = new Matrix();
matrix.postRotate(bearing);
Bitmap rotatedBmp = Bitmap.createBitmap(
arrowBitmap,
0, 0,
arrowBitmap.getWidth(),
arrowBitmap.getHeight(),
matrix,
true
);
canvas.drawBitmap(rotatedBmp, 20, 20, null );
}

Map overlay for osmdroid never appears

I am trying to implement my own map overlay for osmdroid (but I assume it is fairly similar to Google map overlays).
What I am trying to do is draw a plane, rotate it according to bearing and draw a speed vector (line ahead of the plane in the flight direction that shows where it will soon be).
The idea is that I draw the plane (et all) on a canvas "facing North", then rotate it according to flight direction and "merge" it with the overlay canvas (I tried drawing directly to the overlay canvas, but on rotate, it was rotating the map as well).
I have created a subclass of Overlay and overiden the onDraw method as follows:
#Override
protected void draw(Canvas c, MapView mapView, boolean shadow) {
if (location != null) {
Point locPoint = new Point();
GeoPoint locGeoPoint = new GeoPoint(location);
final Projection pj = mapView.getProjection();
pj.toMapPixels(locGeoPoint, locPoint);
this.drawPlane(c, locPoint, location.getBearing());
}
}
private void drawPlane(Canvas cs, Point ctr, float bearing) {
Paint paint = new Paint();
paint.setColor(Color.RED);
paint.setAntiAlias(true);
Bitmap planeBM = Bitmap.createBitmap(cs.getWidth(), cs.getHeight(), Bitmap.Config.ARGB_8888);
planeBM.setDensity(cs.getDensity());
Canvas c = new Canvas(planeBM);
Rect r = new Rect();
//Point center = new Point(cs.getWidth() / 2, cs.getHeight() /2);
Point center = new Point(0, 0);
// Draw fuselage
r.left = center.x - PLANE_WIDTH / 2;
r.right = r.left + PLANE_WIDTH;
r.top = center.y - PLANE_SIZE / 3;
r.bottom = r.top + PLANE_SIZE;
c.drawRect(r, paint);
// Draw wing (REMOVED)
// Draw stabilizer (REMOVED)
// TODO Draw Speed vector
// "Merging" canvas
Matrix merge = new Matrix(cs.getMatrix());
//merge.setTranslate(0, 0);
//merge.setRotate(bearing, center.x, center.y);
cs.drawBitmap(planeBM, merge, paint);
cs.save();
}
Basically my plane never shows.
I assume this has to do with the matrix in the initial canvas which has large values (I assume these are sort of geographical coordinates).
It all seems to be consistent though (the plane location has large values as well consistent with the matrix).
I have tried a number of things :
drawing from the actual plane location (large values) : did not help;
setting the matrix of my new canvas with the overlay canvas matrix : did not help;
merging with a new "empty" matrix : did not help;
-...
I know that my image contains the plane (at least if I draw from 0,0 or the new canvas center as I saved it to the SD to check...
In case this is usefull to someone, I finally found a solution.
Basicaly I was trying to do too much at the same time.
Using setPostRotate instead of setRotate on the merge matrix did solve the issue (that and goig bac to the drawing board for the correct translation parameters).
Using the below as a merge matrix worked:
// "Merging" canvas
Matrix merge = new Matrix();
merge.setTranslate(loc.x - pCenter.x, loc.y - pCenter.y);
merge.postRotate(bearing, loc.x, loc.y);

How to make Overlay to show above canvas.drawLine in Android map API

I have used the draw() method of my SitesOverlay class that is extending the ItemizedOverlay<OverlayItem> to draw some lines. Now, I am also putting in multiple images to the map as overlay by adding this one image to the List<OverlayItem> at many different points.
What happens now is that wherever the line (drawn using the draw() method) and the image icon overlap, the line is drawn over the overlayed image.
How do I make the overlay image come on top of the line?
Edit: I am using populate() to put all my overlays on the map, as soon as i add them to the list. IS there any way I can call populate after I have used my draw() method? I tried putting populate into the draw() method but the application stopped working...any other way?
Here I am sharing my source
public void draw(Canvas canvas, MapView mapView, boolean shadow) {
super.draw(canvas, mapView, shadow);
try {
for (int i = 0; i < size(); i++) {
OverlayItem item = getItem(i);
String driverName = item.getSnippet();
Data.activlyShownDrivers.add(driverName);
Point screenPts = new Point();
mapView.getProjection().toPixels(item.getPoint(), screenPts);
Bitmap bmp = null;
Context ctx = ShowAll.getContext();
long angle = (long) Double.parseDouble(item.getTitle());
// ---add the marker---
bmp = BitmapFactory.decodeResource(ctx.getResources(),
R.drawable.img1);
Paint paint = new Paint();
paint.setColor(Color.BLACK);
paint.setStyle(Style.FILL_AND_STROKE);
canvas.drawBitmap(bmp, screenPts.x, screenPts.y, null);
canvas.drawText(driverName, screenPts.x, screenPts.y, paint);
}
// }
} catch (Exception e) {
try {
Log.e(Data.LOG, e.getMessage());
} catch (Exception e1) {
e1.printStackTrace();
}
}
}
well, it figures that if you are using the draw method, then whatever you draw using it, will be drawn over your overlays. This is because draw() is called every time you drag/zoom or do anything with the map and overlays are populated only at the beginning...so drawn lines using draw() will always come over the overlays..

How can I draw an Arrow showing the driving direction in MapView?

I use that Google Maps component MapView in an Android application. I can use the GPS location to show my location with a dot. But I would like to show an arrow instead, that points out the driving direction (bearing). I think that I can use the bearing value to get the angle of the arrow.
How can I do that?
Assuming you've got the Location then obtain the bearing by doing:
float myBearing = location.getBearing();
To implement the overlay you'll be using ItemizedOverlay and OverlayItem. You'll need to subclass OverlayItem to add the functionality to rotate the Drawable. Something like:
public BitmapDrawable rotateDrawable(float angle)
{
Bitmap arrowBitmap = BitmapFactory.decodeResource(context.getResources(),
R.drawable.map_pin);
// Create blank bitmap of equal size
Bitmap canvasBitmap = arrowBitmap.copy(Bitmap.Config.ARGB_8888, true);
canvasBitmap.eraseColor(0x00000000);
// Create canvas
Canvas canvas = new Canvas(canvasBitmap);
// Create rotation matrix
Matrix rotateMatrix = new Matrix();
rotateMatrix.setRotate(angle, canvas.getWidth()/2, canvas.getHeight()/2);
// Draw bitmap onto canvas using matrix
canvas.drawBitmap(arrowBitmap, rotateMatrix, null);
return new BitmapDrawable(canvasBitmap);
}
Then all that remains to be done is to apply this new Drawable to the OverlayItem. This is done using the setMarker() method.

Categories

Resources