Android - Google Maps, final overlay for cross hairs - android

I wonder if there is a chance to set a final Overlay in Google Maps. I wanna set my cross hairs this way, so that it isn't moving while zooming.
Code:
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.map_view);
initData();
mapView = (MapView) findViewById(R.id.mapView);
mapView.setSatellite(true);
mapView.setTraffic(true);
mapView.setBuiltInZoomControls(true);
controller = mapView.getController();
controller.animateTo(coordinate);
controller.setZoom(18);
// TODO:
CrossHairsOverlay chOverlay = new CrossHairsOverlay();
// Pin
MapOverlay mapOverlay = new MapOverlay();
mapOverlay.setPointToDraw(coordinate);
List<Overlay> listOfOverlays = mapView.getOverlays();
listOfOverlays.clear();
listOfOverlays.add(mapOverlay);
listOfOverlays.add(chOverlay);
}
Cross hairs:
public class CrossHairsOverlay extends Overlay {
public boolean draw(Canvas canvas, MapView mapView, boolean shadow, long when) {
super.draw(canvas, mapView, shadow);
Projection projection = mapView.getProjection();
Point centerPoint = projection.toPixels(mapView.getMapCenter(), null);
Bitmap crossHairs = BitmapFactory.decodeResource(getResources(), R.drawable.cross_hair);
canvas.drawBitmap(crossHairs, centerPoint.x - (int)(27 * dpi + 0.5f), centerPoint.y - (int)(27 * dpi + 0.5f), new Paint());
return true;
}
}
If I use it this way, it recenters after zooming is finished. Left/right draging works correct. I don't really wanna set a "ZoomListener" and redraw all the time. I hope there is a bether solution to do this.
Thanks

Forgive me for not fully understanding your question...
But, to draw to a simple point no need to use the projection, just draw your bitmap strictly to the center of the mapview.
ie...
// make the coordinated constant also.
canvas.drawBitam(bitmap, center.x-(imageWidth/2), center.y-(imageHeight/2),new Paint());
where center.x and center.y are just equal to
Point center = new Point(canvas.getWidth()/2,canvas.getHeight()/2);
Also dont reload your bitmap on every onDraw!, memory leak ftl ;).

Related

Strange behaviour with Osmdroid overlay at high zoom levels

I'm using the osmdroid 3.0.5 jar in my app to display a map view. I'm superimposing an overlay, consisting of horizontal and vertical lines. I've noticed that in certain locations only, at high zoom levels some of the lines disappear, then reappear as the map is dragged.
I've produced a minimal sample app which demonstrates the problem which exhibits itself both on a real device and an emulator (Gingerbread 2.3.3).
The complete code is shown below - (the 'transform' methods are necessary in the real app although they don't appear to be in this minimal sample) :
public class DemoMap extends Activity implements MapViewConstants {
private MapView mapView;
private MapController mapController;
private MapOverlay mmapOverlay = null;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.copymain);
mapView = (MapView) findViewById(R.id.mapview);
mapView.setTileSource(TileSourceFactory.MAPNIK);
mapView.setBuiltInZoomControls(true);
mapView.setMultiTouchControls(true);
mapController = mapView.getController();
mapController.setZoom(17);
// Only shows the bug at ceratin lat/lon positions, this is one
GeoPoint point2 = new GeoPoint(39191699, -120102561);
mapController.setCenter(point2);
mmapOverlay = new MapOverlay(this);
List<Overlay> listOfOverlays = mapView.getOverlays();
listOfOverlays.add(mmapOverlay);
mapView.invalidate();
}
public class MapOverlay extends org.osmdroid.views.overlay.Overlay {
public MapOverlay(Context ctx) {super(ctx); }
private int mVpl;// viewport left, top, right, bottom
private int mVpt;
private int mVpr;
private int mVpb;
private MapView mMv = null;
// Two routines to transform and scale between viewport and mapview
private float transformX(float in, MapView mv) {
float out;
out = ((mVpr - mVpl) * in) / (mv.getRight() - mv.getLeft())
+ mVpl;
return out;
}
private float transformY(float in, MapView mv) {
float out;
out = ((mVpb - mVpt) * in) / (mv.getBottom() - mv.getTop())
+ mVpt;
return out;
}
#Override
protected void draw(Canvas pC, MapView mapV, boolean shadow) {
if (shadow)
return;
Paint paint;
paint = new Paint();
paint.setColor(Color.RED);
paint.setAntiAlias(true);
paint.setStyle(Style.STROKE);
paint.setStrokeWidth(1);
paint.setTextAlign(Paint.Align.LEFT);
paint.setTextSize(12);
final Rect viewportRect = new Rect();
final Projection projection = mapV.getProjection();
viewportRect.set(projection.getScreenRect());
mVpl = viewportRect.left;
mVpt = viewportRect.top;
mVpr = viewportRect.right;
mVpb = viewportRect.bottom;
// draw two lines to split screen into 2x2 quarters
// drag the map left and right and the vertical line disappears,
// then reappears! It's OK at one less zoom level
pC.drawLine(transformX(mapV.getWidth()/2, mapV), transformY(0, mapV),
transformX(mapV.getWidth()/2, mapV),
transformY(mapV.getHeight(), mapV), paint);
pC.drawLine(transformX(0, mapV), transformY(mapV.getHeight()/2, mapV),
transformX(mapV.getWidth(), mapV),
transformY(mapV.getHeight()/2, mapV), paint);
}
}
}
Interestingly if, in my real app, if I do the drawing to an offscreen bitmap, then draw it all in one go at the end of the Overlay's draw, it's OK the lines don't disappear.
Any help will be much appreciated.
I know this is an old question, but I believe what you're experiencing is Issue 221. This has been fixed in version 3.0.9.
Also see: OSMDroid PathOverlay drawing is corrupted at high zoom levels
Sounds like it may be another manifestation of this bug:
Issue 207
Do you see the same behaviour with earlier API versions?

How to properly use drawMyLocation

I am trying to show the users current location with the default blue dot in android. In my maps page I also have a layout that shows different points of interest. Im having trouble figuring out what to put for some of the variables and was wondering if someone could help me out.
This is what I'm using so far to show my location.
Location location = locationManager
.getLastKnownLocation(bestProvider);
try {
GeoPoint myPoint2 = new GeoPoint(
(int) (location.getLatitude() * 1E6),
(int) (location.getLongitude() * 1E6));
newoverlay.drawMyLocation(null, mapView, location, myPoint2,
1000);
mapOverlays.add(newoverlay);
} catch (NullPointerException e) {
GeoPoint myPoint2 = new GeoPoint((int) (-1 * 1E6),
(int) (-1 * 1E6));
**newoverlay.drawMyLocation(null, mapView, location, myPoint2,
1000);**
mapOverlays.add(newoverlay);
}
I'm not sure what to put as the Canvas so I placed it with null so that it would compile. I'm using the location from a location Manager and I have my geopoint from the location variable. I'm also unsure what the "when" parameter is supposed to be.
I was also wondering how the blue bubble knows to move with the person, does the picture update every x milliseconds depending on the "when" parameter?
So far the app isn't crashing, but it is also not showing the blue dot at any location.
I'm sure I just need help with finding what the canvas parameter should be.
Thanks
try this way in your map activity
class CurOverlay extends Overlay {
private GeoPoint pointToDraw;
public void setPointToDraw(GeoPoint point) {
pointToDraw = point;
}
public GeoPoint getPointToDraw() {
return pointToDraw;
}
#Override
public boolean draw(Canvas canvas, MapView curmapView, boolean shadow,
long when) {
super.draw(canvas, curmapView, shadow);
// convert point to pixels
Point screenPts = new Point();
curmapView.getProjection().toPixels(pointToDraw, screenPts);
// add marker
Bitmap bmp = BitmapFactory.decodeResource(getResources(),
R.drawable.pinsource);
canvas.drawBitmap(bmp, screenPts.x - 28, screenPts.y - 48, null);
return true;
}
}
i hope this will work for you.

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!

Drawing transparent on a MapView

I am currently drawing lines on a MapView based on different GeoPoints to indicate sectors. With the following code (this is within an overlay):
#Override
public void draw(Canvas canvas, MapView mapView, boolean shadow)
{
for(Polygon polygonTemp : polygonList)
{
Path p = new Path();
Projection projection = mapView.getProjection();
boolean firstTime = true;
for(GeoPoint geoPoint : polygonTemp.getGeoPointList())
{
Point drawPoint = new Point();
projection.toPixels(geoPoint, drawPoint);
if(firstTime)
{
p.moveTo(drawPoint.x, drawPoint.y);
firstTime = false;
}
else
{
p.lineTo(drawPoint.x, drawPoint.y);
}
}
p.setFillType(Path.FillType.EVEN_ODD);
Paint polyPaint = new Paint();
polyPaint.setStrokeWidth(1);
polyPaint.setStyle(Paint.Style.FILL_AND_STROKE);
polyPaint.setAntiAlias(true);
polyPaint.setColor(Color.parseColor(polygonTemp.getColor()));
canvas.drawPath(p, polyPaint);
firstTime = true;
}
super.draw(canvas, mapView, shadow);
}
The problem is, I want them to be filled with some degree of transparency, so I can still see the map under the filled sectors. I tried to set polyPaint.setAlpha(), even to 255 (which should be completely transparent) and it doesn't do anything, it's completely opague.
Anyone knows what I'm doing wrong?
I don't see where you are setting the alpha. Regardless 255 is not transparent, it is opaque.
FYI, I am doing identical things (drawing paths on map overlays) and this works fine for drawing a 50% opaque, red line:
mPaint.setColor(Color.parseColor ("#88ff0000"));

Efficient Map Overlays in Android Google Map

I want to do the following and am kind of stuck on these for a few days:
I was trying to draw polylines (I have encoded polylines, but have managed to decode those) that move when I move the map.
The only solution that I found was for Geopoints to be transformed into screen coordinates... which won't move if I move the map.
I used HelloItemizedOverlay to add about 150 markers and it gets very very slow.
Any idea what to do? I was thinking about threads (handler).
I was looking for some sort of a timer function that executes a given function periodically, say, every 1 minute or so.
I was also looking for ways to clear the Google map from all the markers/lines, etc.
Answers given below :
1) Here's a solution that I used :
/** Called when the activity is first created. */
private List<Overlay> mapOverlays;
private Projection projection;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
linearLayout = (LinearLayout) findViewById(R.id.zoomview);
mapView = (MapView) findViewById(R.id.mapview);
mapView.setBuiltInZoomControls(true);
mapOverlays = mapView.getOverlays();
projection = mapView.getProjection();
mapOverlays.add(new MyOverlay());
}
#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();
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(2);
GeoPoint gP1 = new GeoPoint(19240000,-99120000);
GeoPoint gP2 = new GeoPoint(37423157, -122085008);
Point p1 = new Point();
Point p2 = new Point();
Path path = new Path();
Projection projection.toPixels(gP1, p1);
projection.toPixels(gP2, p2);
path.moveTo(p2.x, p2.y);
path.lineTo(p1.x,p1.y);
canvas.drawPath(path, mPaint);
}
courtesy: Drawing a line/path on Google Maps
2) Here's what worked for me :
createMarkers()
{
for(elem:bigList)
{
GeoPoint geoPoint = new GeoPoint((int)(elem.getLat()*1000000), (int) (elem.getLon()*1000000));
OverlayItem overlayItem = new OverlayItem(geoPoint, elem.getName(), elem.getData());
itemizedOverlay.addOverlay(overlayItem);
}
itemizedOverlay.populateNow();
mapOverlays.add(itemizedOverlay); //outside of for loop
}
and in MyOverlay:
public void addOverlay(OverlayItem overlay)
{
m_overlays.add(overlay);
}
public void populateNow()
{
populate();
}
courtesy: stackoverflow.com unknown link
3) The best way is to use a timer class. A very detailed description of the timer class and how to use it is given at this link :
http://life.csu.edu.au/java-tut/essential/threads/timer.html
4) I used this code :
if(!mapOverlays.isEmpty())
{
mapOverlays.clear();
mapView.invalidate();
}
Hope these answers help atleast one other person. Thanks.
I have the same problem. We are developing an iphone app and an android app at the same time. I have 2500 + map overlays. No problem on iphone; a huge performance hit on android when calling populate() after adding all overlays. (Of course, my first try was to call populate() every time after adding an overlay; a typical mistake due to google's tutorial. Now I am calling populate() just once, after all 2500+ overlays have been added to the ItemizedOverlay.)
So the single populate() call takes over 40 seconds to complete on an htc hero device. I had to put in a busy indicator; no progress bar is possible because we cannot get any information about the progress of populate().
I tried another solution: not use ItemizedOverlay but add overlays by hand, subclassing Overlay. Result: indeed it is much faster to add all those overlays to the map; however, the map becomes unusable due to constant calling of the draw() method on each overlay. In my draw method, I tried to optimize as much as possible; I do not create a bitmap every time. My draw() method looks like this:
public void draw(android.graphics.Canvas canvas, MapView mapView, boolean shadow) {
// our marker bitmap already includes shadow.
// centerPoint is the geopoint where we need to put the marker.
if (!shadow) {
Point point = new Point();
mapView.getProjection().toPixels(centerPoint, point);
canvas.drawBitmap(markerBitmap, point.x, point.y, null);
}
}
Here markerBitmap is precomputed. I don't know what else I could optimize. Is there some kind of populate() call required if we are not using ItemizedOverlay??? I could not find any good answers for that.
Right now I resort to caching the ItemizedOverlay once it has been created in a background thread. This way at least the user does not have to wait every time.
For #2, I don't think you solved anything there. Your hard-to-read code is showing how to put markers on overlay and then, how to add that overlay to the map. That's exactly how I do it. I have map with around 300 hotels and it takes around 5 seconds for Android on my Nexus One to create markers. The whole thing is running inside thread and I guess I will have to do some sort of progress bar to let user know what's going on.
I am working on app that already exists on iPhone and it seems iPhone doesn't have any issues to almost instantaneously draw these 300+ markers. I'll have hard time to explain existence of progress bar to my bosses.
If anybody have idea how to optimize this process... I will be grateful.
Here is my code:
...
for (int m = 0; m < ArrList.size(); m++) {
tName = ArrList.get(m).get("name").toString();
tId = ArrList.get(m).get("id").toString();
tLat = ArrList.get(m).get("lat").toString();;
tLng = ArrList.get(m).get("lng").toString();;
try {
lat = Double.parseDouble(tLat);
lng = Double.parseDouble(tLng);
p1 = new GeoPoint(
(int) (lat * 1E6),
(int) (lng * 1E6));
OverlayItem overlayitem = new OverlayItem(p1, tName, tId);
itemizedoverlay.addOverlay(overlayitem);
} catch (NumberFormatException e) {
Log.d(TAG, "NumberFormatException" + e);
}
}
I know I could save some time by avoiding this String > Double conversion, but I don't feel that would give me significant saving.. or it would?
For your 4th question.... simply use the mapOverlays.clear(); method and all the previous markers will be vanished.
code:
if(!mapOverlays.isEmpty()) {
mapOverlays.clear();
mapView.invalidate();
}
Multiple number of drawable objects can be added to a single Overlay which can then be added to the map. Hence, drawing x number of overlay's for x number of objects wouldnt be necessary unless the objects are of different types. Code snippet..
..
Here, CustomPinPoint is my class which extends ItemizedOverlay<OverlayItem>
CustomPinPoint customPinPoint = new CustomPinPoint(drawable, Main.this);
OverlayItem tempOverLayItem = new OverlayItem(
touchedPoint, "PinPoint", "PintPoint 2"); //Point One
customPinPoint.insertPinPoint(tempOverLayItem);
tempOverLayItem = new OverlayItem(new GeoPoint(
(int)(-27.34498 * 1E6), (int)(153.00724 * 1E6)), "PinPoint",
"PintPoint 2"); //Point Two
customPinPoint.insertPinPoint(tempOverLayItem);
overlayList.add(customPinPoint); //Overlay added only once

Categories

Resources