I'm using the below code to put an overlay on my MapView. For some reason after itterating through the location data it draws the point in the same place.
It seems to be happening on conversion from Location to GeoPoint to Projection:
Location (lat : lon) 51.2651789188385 : -0.5398589372634888
Projection (x : y) 239 : 361
Location (lat : lon) 51.26375198364258 : -0.5417096614837646
Projection (x : y) 239 : 361
Locations are Doubles
GeoPoints are Integers
Projections are screen coordinates.
Could someone please look over the below code and find if i am doing something wrong?
thanks
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Point;
import android.graphics.RectF;
import android.location.Location;
import android.util.Log;
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 ROverlay extends Overlay {
private Context context;
private HashMap<String, Location> friendLocations;
private ArrayList<LocationData> locD;
private Location location;
private GeoPoint locationPoint;
private Paint paint;
private Paint backPaint;
private static int markerRadius = 7;
/** Get your current location */
public Location getLocation() {
return location;
}
/** Set your current location */
public void setLocation(Location location) {
this.location = location;
Double latitude = location.getLatitude()*1E6;
Double longitude = location.getLongitude()*1E6;
locationPoint = new GeoPoint(latitude.intValue(),longitude.intValue());
}
/** Refresh the locations of each of the contacts */
public void refreshLocation() {
locD = RMapView.getARR();
}
/**
* Create a new FriendLocationOverlay to show your contact's locations on a map
* #param _context Parent application context
*/
public ROverlay(Context _context) {
super();
context = _context;
friendLocations = new HashMap<String, Location>();
locD = new ArrayList<LocationData>();
//refreshFriendLocations();
// Create the paint objects
backPaint = new Paint();
backPaint.setARGB(200, 200, 200, 200);
backPaint.setAntiAlias(true);
paint = new Paint();
paint.setDither(true);
paint.setColor(Color.RED);
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeJoin(Paint.Join.ROUND);
paint.setStrokeCap(Paint.Cap.ROUND);
paint.setStrokeWidth(5);
}
#Override
public void draw(Canvas canvas, MapView mapView, boolean shadow) {
// Get the map projection to convert lat/long to screen coordinates
Projection projection = mapView.getProjection();
for (int q = 1; q < locD.size(); q++){
Double latitude = locD.get(q-1).mLocation.getLatitude()*1e6;
Double longitude = locD.get(q-1).mLocation.getLongitude()*1e6;
GeoPoint geopoint = new GeoPoint(latitude.intValue(),longitude.intValue());
//Log.d("Double", ""+latitude+" : "+longitude);
//Log.d("Geopoint", ""+geopoint.getLatitudeE6()+" : "+geopoint.getLongitudeE6());
Point point = new Point();
projection.toPixels(geopoint, point);
Double latitude2 = locD.get(q).mLocation.getLatitude()*1e6;
Double longitude2 = locD.get(q).mLocation.getLongitude()*1e6;
GeoPoint geopoint2 = new GeoPoint(latitude2.intValue(),longitude2.intValue());
Point point2 = new Point();
projection.toPixels(geopoint2, point2);
canvas.drawLine(point.x, point.y, point2.x, point2.y, paint);
canvas.drawPoint(point.x, point.y, paint);
Log.d("Point", ""+point.x+" : "+point.y);
}
super.draw(canvas, mapView, shadow);
}
#Override
public boolean onTap(GeoPoint point, MapView mapView) {
// Do not react to screen taps.
return false;
}
}
</code>
I don't know what the problem is with this one. I couldn't get it working and the debug was showing no errors so in the end i used code from the Google Mytracks project to enable the map view and projection problems
http://code.google.com/p/mytracks/
You should look at this The projection value to pixel may vary.
as http://code.google.com/android/add-ons/google-apis/reference/com/google/android/maps/MapView.html#getProjection%28%29 says that "The Projection of the map in its current state. You should not hold on to this object for more than one draw, since the projection of the map could change."
Instead of writing
projection.toPixels(geopoint2, point2);
you must code as
mapView.getProjection().toPixels(geopoint2, point2);
Related
I am a newbie in android field. I have written a android App1 that will retrieve latitude and longitude values from Network Provider and stores it in my local server(LAMP).
I have also created a MYSQL DB table that has 3 columns(lat,lon,id) that has the values (lat and lon) which are retrieved using the Network Provider. Currently there are more than 10 values in my table.
I have created JSON object for getting those values from MYSQL DB using PHP script in my Android App2. All these things works fine. I have also done creating MapActivity which will plot those lat and lon values on map using Marker.
What I have to do now is to join those markers to draw path on google map. How to do it. Please help
Try this.
String uri = "http://maps.google.com/maps?saddr=" + currentLatitude+","+currentLongitude+"&daddr="+fixedLatitude+","+fixedLongitude;
Intent intent = new Intent(android.content.Intent.ACTION_VIEW, Uri.parse(uri));
intent.setClassName("com.google.android.apps.maps", "com.google.android.maps.MapsActivity");
startActivity(intent);
may this help you
Try this this to draw path in google map
public class Location extends MapActivity {
MapView mapView;
public static ArrayList<String> paramLat = new ArrayList<String>();
public static ArrayList<String> paramLong = new ArrayList<String>();
private List<Overlay> mapOverlays;
public List<GeoPoint> geopoints = new ArrayList<GeoPoint>();
public void onCreate(Bundle savedInstanceState) {
//your code to display location
for(int i=0;i<paramLat.size();i++)
{
lat = Double.parseDouble(paramLat.get(i));
lon = Double.parseDouble(paramLong.get(i));
geoPoint = new GeoPoint((int)(lat * 1E6), (int)(lon *1E6));
geopoints.add(geoPoint);
}
mapOverlays = mapView.getOverlays();
mapOverlays.add(new MyOverlay());
}
class MyOverlay extends Overlay{
public MyOverlay(){
}
public void draw(Canvas canvas, MapView mapv, boolean shadow){
super.draw(canvas, mapv, shadow);
int loopcount = geopoints.size() - 1;
Paint mPaint = new Paint();
mPaint.setDither(true);
mPaint.setColor(Color.BLUE);
mPaint.setStyle(Paint.Style.FILL_AND_STROKE);
mPaint.setStrokeJoin(Paint.Join.ROUND);
mPaint.setStrokeCap(Paint.Cap.ROUND);
mPaint.setStrokeWidth(2);
for (int i = 0; i < loopcount; i++)
{
GeoPoint pp1 = (GeoPoint) geopoints.get(i);
GeoPoint pp2 = (GeoPoint) geopoints.get(i + 1);
Point p1 = new Point();
Point p2 = new Point();
Path path = new Path();
projection.toPixels(pp1, p1);
projection.toPixels(pp2, p2);
path.moveTo(p2.x, p2.y);
path.lineTo(p1.x,p1.y);
canvas.drawPath(path, mPaint);
}
}
} //end of MyOverlay class
} //end of Location class
I copied a pushpin.gif to the appropriate folder: project/res/drawable-mdpi/pushpin.gif
I am not able to display the marker on the map, here is the code i used:
import android.os.Bundle;
import android.app.Activity;
import android.view.Menu;
import android.view.MenuItem;
import android.support.v4.app.NavUtils;
import com.google.android.maps.MapActivity;
import com.google.android.maps.MapView;
import com.google.android.maps.GeoPoint;
import android.view.KeyEvent;
import com.google.android.maps.MapController;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Point;
import com.google.android.maps.Overlay;
import java.util.List;
import android.view.MotionEvent;
import android.widget.Toast;
import android.location.Address;
import android.location.Geocoder;
import java.util.Locale;
import java.io.IOException;
public class MainActivity extends MapActivity {
MapView mapView;
MapController mc;
GeoPoint p;
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-50, null);
return true;
}
#Override
public boolean onTouchEvent(MotionEvent event, MapView mapView)
{
//---when user lifts his finger---
if (event.getAction() == 1) {
GeoPoint p = mapView.getProjection().fromPixels(
(int) event.getX(),
(int) event.getY());
/* --To display the lat & long on the screen--
Toast.makeText(getBaseContext(), "Location: "+ p.getLatitudeE6() / 1E6 + "," + p.getLongitudeE6() /1E6 ,Toast.LENGTH_SHORT).show();*/
/*Geo Locating the empire state
Geocoder geoCoder = new Geocoder(this, Locale.getDefault());
try {
List<Address> addresses = geoCoder.getFromLocationName("empire state building", 5);
String add = "";
if (addresses.size() > 0) {
p = new GeoPoint(
(int) (addresses.get(0).getLatitude() * 1E6),
(int) (addresses.get(0).getLongitude() * 1E6));
mc.animateTo(p);
mapView.invalidate();
}
} catch (IOException e) {
e.printStackTrace();
}*/
Geocoder geoCoder = new Geocoder(
getBaseContext(), Locale.getDefault());
try {
List<Address> addresses = geoCoder.getFromLocation(
p.getLatitudeE6() / 1E6,
p.getLongitudeE6() / 1E6, 1);
String add = "";
if (addresses.size() > 0)
{
for (int i=0; i<addresses.get(0).getMaxAddressLineIndex(); i++)
add += addresses.get(0).getAddressLine(i) + "\n";
}
Toast.makeText(getBaseContext(), add, Toast.LENGTH_SHORT).show();
}
catch (IOException e) {
e.printStackTrace();
}
return true;
}
return false;
}
}
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
//To display the built-in zoom controls
mapView = (MapView) findViewById(R.id.mapView);
mapView.setBuiltInZoomControls(true);
/*
//To change the view to Satellite
mapView.setSatellite(true);
*/
/*
//To change the view to Street
mapView.setStreetView(true);
*/
//assign the mapview to MapController object"oc"
mc = mapView.getController();
//the coordinates in micro degrees
String coordinates[] = {"33.717261","-117.763589"};
double lat = Double.parseDouble(coordinates[0]);
double lng = Double.parseDouble(coordinates[1]);
//Gep point to represent geographical location
p = new GeoPoint(
//the coordinates in micro degrees
(int) (lat * 1E6),
(int) (lng * 1E6));
//To navigate the map to a particular location
mc.animateTo(p);
//To Specify the zoom level
mc.setZoom(13);
//Add a location marker
MapOverlay mapOverlay = new MapOverlay();
List<Overlay> listOfOverlays = mapView.getOverlays();
listOfOverlays.clear();
listOfOverlays.add(mapOverlay);
//Method to force the MapView to be redrawn
mapView.invalidate();
//To display traffic conditions on the Map
// mapView.setTraffic(true);
}
public boolean onKeyDown(int keyCode, KeyEvent event)
{
MapController mc = mapView.getController();
switch (keyCode)
{
case KeyEvent.KEYCODE_3:
mc.zoomIn();
break;
case KeyEvent.KEYCODE_1:
mc.zoomOut();
break;
}
return super.onKeyDown(keyCode, event);
}
#Override
protected boolean isRouteDisplayed() {
// TODO Auto-generated method stub
return false;
}
}
I was able to find a sample project that explains all the issues I faced.
https://github.com/commonsguy/cw-android/tree/master/Maps/NooYawk/
class MyMapOverlays extends com.google.android.maps.Overlay
{
GeoPoint location = null;
public MyMapOverlays(GeoPoint location)
{
super();
this.location = location;
}
#Override
public void draw(Canvas canvas, MapView mapView, boolean shadow)
{
super.draw(canvas, mapView, shadow);
//translate the screen pixels
Point screenPoint = new Point();
mapView.getProjection().toPixels(this.location, screenPoint);
//add the image
canvas.drawBitmap(BitmapFactory.decodeResource(getResources(), R.drawable.our_cross_image),
screenPoint.x, screenPoint.y , null); //Setting the image location on the screen (x,y).
}
}
I need to draw shapes just like those you would create with custom maps on Google Maps, using Android's MapView.
In other words, if I draw a shape on the map, when I zoom out it should shrink, covering the same area of the map regardless of the zoom level.
Example following the Android Reference:
#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);
Paint boxPaint = new Paint();
boxPaint.setColor(android.graphics.Color.WHITE);
boxPaint.setStyle(Paint.Style.FILL);
boxPaint.setAlpha(140);
canvas.drawCircle(screenPts.x, screenPts.y, 20, boxPaint);
return true;
}
This shows a white circle on the map, but if you zoom out, the circle is the same size. Perhaps using canvas is not right approach?
I need something like how Google Maps highlights neighborhoods or cities:
Any ideas? Thanks in advance!
I had the same problem myself, here's a full solution with demo locations:
import java.util.*;
import android.graphics.*;
import android.graphics.Paint.Style;
import android.graphics.Region.Op;
import android.os.Bundle;
import com.google.android.maps.*;
public class ShapeOverlayTest extends MapActivity {
private MapView m_map;
#Override
public void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
m_map = (MapView) findViewById(R.id.mapview);
m_map.displayZoomControls(true);
m_map.setBuiltInZoomControls(true);
}
#Override
protected void onStart() {
super.onStart();
Loc[][] areas = {
{
new Loc(51.51695436113811, -0.28686325139653757),
new Loc(51.5268179962453, -0.28118722558738923),
new Loc(51.526498459594215, -0.27779666308279755),
new Loc(51.52521530775356, -0.26943974607777654),
new Loc(51.52292555645698, -0.25813738590178786),
new Loc(51.52054465991048, -0.2498381618983569),
new Loc(51.51012230470141, -0.24509233633017083),
new Loc(51.50884762913046, -0.24465130560570497),
new Loc(51.50732063336974, -0.2441767643132881),
new Loc(51.50431624597833, -0.24473900326760137),
new Loc(51.49756328092904, -0.2714528238165076),
new Loc(51.50092541797557, -0.28360267232347336),
new Loc(51.50205958485736, -0.28490018935582045),
new Loc(51.50488447379555, -0.28681164237730944)
},
{
new Loc(51.50368617913765, -0.25313579464343156),
new Loc(51.51978611305675, -0.24842567405905958),
new Loc(51.51039382684418, -0.24460628015366626),
new Loc(51.508792552597576, -0.24397604687682156),
new Loc(51.50713008309719, -0.24346350415674722),
new Loc(51.502411013302684, -0.2508501075008919),
new Loc(51.502377240039664, -0.25160073203846817),
new Loc(51.50274364303565, -0.25204783703705536)
},
{
new Loc(51.49924084955314, -0.2858705706471945),
new Loc(51.50212820259818, -0.2791479893522646),
new Loc(51.49724510427319, -0.27427453152961206),
new Loc(51.49429724502515, -0.2799184038304611),
new Loc(51.494270969987404, -0.28180678948730314)
}
};
String[] areaNames = { "W3 Ealing", "W3 Hammersmith & Fulham", "W3 Hounslow" };
// for (Map.Entry<String, List<Loc>> area : m_areas.entrySet()) {
// // to have much less points and make sure they are in order
// // the demo data already has these properties
// // http://en.wikipedia.org/wiki/Gift_wrapping_algorithm#Pseudocode
// area.setValue(Algo.convexHull(area.getValue()));
// }
Map<String, List<GeoPoint>> areaMap = new HashMap<String, List<GeoPoint>>();
for (int i = 0; i < areaNames.length; i++) {
List<GeoPoint> points = new ArrayList<GeoPoint>();
for (int j = 0; j < areas[i].length; j++) {
points.add(areas[i][j].toGeoPoint());
}
areaMap.put(areaNames[i], points);
}
m_map.getOverlays().add(new AreasOverlay(areaMap));
// TODO determine location better, e.g. averaging area points
GeoPoint center = new GeoPoint(51509704, -270710);
m_map.getController().setCenter(center);
m_map.getController().setZoom(15);
}
#Override
protected boolean isRouteDisplayed() {
return false;
}
static class Loc {
private double m_lat;
private double m_lon;
public Loc(final double lat, final double lon) {
m_lat = lat;
m_lon = lon;
}
public GeoPoint toGeoPoint() {
return new GeoPoint((int) (m_lat * 1e6), (int) (m_lon * 1e6));
}
};
static class AreasOverlay extends Overlay {
private final Map<String, List<GeoPoint>> m_areas;
private final Paint m_paintFill;
private final Paint m_paintStroke;
private static final int ALPHA = 0x30ffffff; // 48 out of 255 transparent
private static final int[] COLORS =
{ Color.YELLOW, Color.MAGENTA, Color.CYAN, Color.RED, Color.GREEN, Color.BLUE };
static {
for (int i = 0; i < AreasOverlay.COLORS.length; i++) {
AreasOverlay.COLORS[i] &= AreasOverlay.ALPHA;
}
}
public AreasOverlay(final Map<String, List<GeoPoint>> areaMap) {
m_areas = areaMap;
// prepare paints
m_paintFill = new Paint();
m_paintFill.setStyle(Paint.Style.FILL);
m_paintStroke = new Paint(Paint.ANTI_ALIAS_FLAG);
m_paintStroke.setStyle(Style.STROKE);
m_paintStroke.setAntiAlias(true);
m_paintStroke.setStrokeWidth(3);
}
#Override
public void draw(final Canvas canvas, final MapView mapView, final boolean shadow) {
super.draw(canvas, mapView, shadow);
if (shadow) {
return;
}
Projection projection = mapView.getProjection();
List<Path> areaPaths = getPaths(projection, m_areas);
drawPaths(canvas, areaPaths);
}
private List<Path> getPaths(final Projection projection, final Map<String, List<GeoPoint>> areas) {
List<Path> areaPaths = new ArrayList<Path>(areas.size());
for (Map.Entry<String, List<GeoPoint>> entry : areas.entrySet()) {
List<GeoPoint> sourceList = entry.getValue();
Path path = new Path();
path.setFillType(Path.FillType.EVEN_ODD);
Iterator<GeoPoint> it = sourceList.iterator();
Point point = nextDrawPoint(projection, it);
path.moveTo(point.x, point.y);
while (it.hasNext()) {
point = nextDrawPoint(projection, it);
path.lineTo(point.x, point.y);
}
path.close();
areaPaths.add(path);
}
return areaPaths;
}
/**
* <ul>
* <li>Draw with different colors.
* <li>Draw strokes first for them to be always visible.
* <li>Draw fills next with each removing from the drawable area.
* </ul>
*/
private void drawPaths(final Canvas canvas, final List<Path> areaPaths) {
int currentColorIndex;
currentColorIndex = 0;
for (Path path : areaPaths) {
int currentColor = AreasOverlay.COLORS[currentColorIndex++];
currentColorIndex %= AreasOverlay.COLORS.length;
m_paintStroke.setColor(currentColor & 0xff7f7f7f); // make it darker by clearing the high bit
canvas.drawPath(path, m_paintStroke);
}
currentColorIndex = 0;
for (Path path : areaPaths) {
int currentColor = AreasOverlay.COLORS[currentColorIndex++];
currentColorIndex %= AreasOverlay.COLORS.length;
m_paintFill.setColor(currentColor);
canvas.drawPath(path, m_paintFill);
canvas.clipPath(path, Op.DIFFERENCE); // don't allow to draw over each other
}
}
private Point nextDrawPoint(final Projection projection, final Iterator<GeoPoint> it) {
GeoPoint geo = it.next();
Point p = new Point();
projection.toPixels(geo, p);
return p;
}
}
}
The radius for drawCircle is in pixels so it make sense that the circle is always the same size. You have to scale the radius based on the zoom level. The example below will graph a geometry from the JTS Topology Suite that will scale.
public class MapOverlay extends Overlay {
private static final String TAG = MapOverlay.class.getName();
// Allocate once and reuse
private final Paint mPaint = new Paint();
private final Path mPath = new Path();
// Region to highlight
private Geometry mGeometry;
/**
* #param geometry Region to highlight on map
*/
public MapOverlay(Geometry geometry) {
// Set region
mGeometry = geometry;
// Edit paint style
mPaint.setDither(true);
mPaint.setColor(Color.rgb(128, 136, 231));
mPaint.setAlpha(100);
mPaint.setStyle(Paint.Style.FILL_AND_STROKE);
mPaint.setStrokeJoin(Paint.Join.ROUND);
mPaint.setStrokeCap(Paint.Cap.ROUND);
mPaint.setStrokeWidth(6);
}
/**
* 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) {
super.draw(canvas, mapv, shadow);
if (mGeometry != null) {
// TODO There could be more than one geometries
Geometry g = mGeometry.getGeometryN(0);
final Point p = new Point();
boolean first = true;
mPath.reset();
for (Coordinate c : g.getCoordinates()) {
// Convert lat/lon to pixels on screen
// GeoPoint is immutable so allocation is unavoidable
Projection projection = mapv.getProjection();
projection.toPixels(new GeoPoint((int) (c.y * 1E6), (int) (c.x * 1E6)), p);
// Set path starting point to first coordinate
// otherwise default start is (0,0)
if (first) {
mPath.moveTo(p.x, p.y);
first = false;
}
// Add new point to path
mPath.lineTo(p.x, p.y);
}
}
// Draw the path with give paint
canvas.drawPath(mPath, mPaint);
}
Adapted from here: MapSelectionOverlay.java
This maybe what you are looking for: Can "overlay" size be zoomed together with the google map on android?
public class ImpactOverlay extends Overlay {
private static int CIRCLERADIUS = 0;
private GeoPoint geopoint;
public ImpactOverlay(GeoPoint point, int myRadius) {
geopoint = point;
CIRCLERADIUS = myRadius;
}
#Override
public void draw(Canvas canvas, MapView mapView, boolean shadow) {
// Transfrom geoposition to Point on canvas
Projection projection = mapView.getProjection();
Point point = new Point();
projection.toPixels(geopoint, point);
// the circle to mark the spot
Paint circle = new Paint();
circle.setColor(Color.BLACK);
int myCircleRadius = metersToRadius(CIRCLERADIUS, mapView, (double)geopoint.getLatitudeE6()/1000000);
canvas.drawCircle(point.x, point.y, myCircleRadius, circle);
}
public static int metersToRadius(float meters, MapView map, double latitude) {
return (int) (map.getProjection().metersToEquatorPixels(meters) * (1/ Math.cos(Math.toRadians(latitude))));
}
}
What you need is a list of lat/lon points for each shape you want to draw on the map. In the onDraw method, you need to iterate over that list (for each shape you want to draw), and do this:
//---translate the GeoPoint to screen pixels---
Point screenPts = new Point();
mapView.getProjection().toPixels(p, screenPts);
then draw the shape on the canvas. IIRC that works correctly regardless of zoom, because the mapView is aware of the zoom level, and gives you the appropriate pixel location for the lat/long pair at that zoom level.
I'm trying to validate a clickable route functionality using google map API.
I established route display between two coordinates using the map API.
To realize this, I used the following tutorial http://csie-tw.blogspot.com/2009/06/android-driving-direction-route-path.html ,
which basically parse a KML file (the response of a google map direction request) and use a custom map overlay to draw a route.
Custom Overlay :
package com.test.route;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Point;
import android.graphics.RectF;
import android.util.Log;
import android.view.MotionEvent;
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 MyOverLay extends Overlay
{
private GeoPoint gp1;
private GeoPoint gp2;
private int mRadius=6;
private int mode=0;
private int defaultColor;
private String text="";
private Bitmap img = null;
public MyOverLay(GeoPoint gp1,GeoPoint gp2,int mode) // GeoPoint is a int. (6E)
{
this.gp1 = gp1;
this.gp2 = gp2;
this.mode = mode;
defaultColor = 999; // no defaultColor
}
public MyOverLay(GeoPoint gp1,GeoPoint gp2,int mode, int defaultColor)
{
this.gp1 = gp1;
this.gp2 = gp2;
this.mode = mode;
this.defaultColor = defaultColor;
}
public void setText(String t)
{
this.text = t;
}
public void setBitmap(Bitmap bitmap)
{
this.img = bitmap;
}
public int getMode()
{
return mode;
}
#Override
public boolean draw
(Canvas canvas, MapView mapView, boolean shadow, long when)
{
Projection projection = mapView.getProjection();
if (shadow == false)
{
Paint paint = new Paint();
paint.setAntiAlias(true);
Point point = new Point();
projection.toPixels(gp1, point);
// mode=1¡Gstart
if(mode==1)
{
if(defaultColor==999)
paint.setColor(Color.BLUE);
else
paint.setColor(defaultColor);
RectF oval=new RectF(point.x - mRadius, point.y - mRadius,
point.x + mRadius, point.y + mRadius);
// start point
canvas.drawOval(oval, paint);
}
// mode=2¡Gpath
else if(mode==2)
{
if(defaultColor==999)
paint.setColor(Color.RED);
else
paint.setColor(defaultColor);
Point point2 = new Point();
projection.toPixels(gp2, point2);
paint.setStrokeWidth(5);
paint.setAlpha(120);
canvas.drawLine(point.x, point.y, point2.x,point2.y, paint);
}
/* mode=3¡Gend */
else if(mode==3)
{
/* the last path */
if(defaultColor==999)
paint.setColor(Color.GREEN);
else
paint.setColor(defaultColor);
Point point2 = new Point();
projection.toPixels(gp2, point2);
paint.setStrokeWidth(5);
paint.setAlpha(120);
canvas.drawLine(point.x, point.y, point2.x,point2.y, paint);
RectF oval=new RectF(point2.x - mRadius,point2.y - mRadius,
point2.x + mRadius,point2.y + mRadius);
/* end point */
paint.setAlpha(255);
canvas.drawOval(oval, paint);
}
/* mode=4¡Gcar */
else if(mode==4)
{
if(defaultColor==999)
paint.setColor(Color.GREEN);
else
paint.setColor(defaultColor);
Point point2 = new Point();
projection.toPixels(gp2, point2);
paint.setTextSize(20);
paint.setAntiAlias(true);
canvas.drawBitmap(img, point2.x, point2.y,paint);
canvas.drawText(this.text, point2.x, point2.y, paint);
}
else if(mode==5)
{
if(defaultColor==999)
paint.setColor(Color.GREEN);
else
paint.setColor(defaultColor);
Point point2 = new Point();
projection.toPixels(gp2, point2);
paint.setTextSize(20);
paint.setAntiAlias(true);
canvas.drawBitmap(img, point2.x, point2.y,paint);
}
}
return super.draw(canvas, mapView, shadow, when);
}
#Override
public boolean onTouchEvent(MotionEvent event, MapView mapView)
{
Log.i("Map", "Clicked");
return false;
}
}
Test Map Activity :
package com.test.route;
import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import org.w3c.dom.Document;
import org.xml.sax.SAXException;
import android.content.Intent;
import android.graphics.Color;
import android.net.Uri;
import android.os.Bundle;
import android.util.Log;
import com.dailymates.carmate.utils.MyOverLay;
import com.google.android.maps.GeoPoint;
import com.google.android.maps.MapActivity;
import com.google.android.maps.MapView;
public class TestMap extends MapActivity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.map);
MapView mapView = (MapView) findViewById(R.id.mapview);
/*
* Defining the starting and end point of the route (latitude / longitude)
* Oh Paris
*
*/
final double src_lat = 48.847378;
final double src_long = 2.340417;
final double dest_lat = 48.931466;
final double dest_long = 2.504525;
GeoPoint srcGeoPoint = new GeoPoint((int) (src_lat * 1E6),
(int) (src_long * 1E6));
GeoPoint destGeoPoint = new GeoPoint((int) (dest_lat * 1E6),
(int) (dest_long * 1E6));
DrawPath(srcGeoPoint, destGeoPoint, Color.GREEN, mapView);
mapView.getController().animateTo(srcGeoPoint);
mapView.getController().setZoom(12);
}
protected boolean isRouteDisplayed() {
return false;
}
private void DrawPath(GeoPoint src, GeoPoint dest, int color, MapView mMapView01) {
StringBuilder urlString = new StringBuilder();
urlString.append("http://maps.google.com/maps?f=d&hl=en");
urlString.append("&saddr=");
urlString.append(Double.toString((double) src.getLatitudeE6() / 1.0E6));
urlString.append(",");
urlString.append(Double.toString((double) src.getLongitudeE6() / 1.0E6));
urlString.append("&daddr=");// to
urlString.append(Double.toString((double) dest.getLatitudeE6() / 1.0E6));
urlString.append(",");
urlString.append(Double.toString((double) dest.getLongitudeE6() / 1.0E6));
urlString.append("&ie=UTF8&0&om=0&output=kml");
Log.d("xxx", "URL=" + urlString.toString());
Document doc = null;
HttpURLConnection urlConnection = null;
URL url = null;
try {
url = new URL(urlString.toString());
urlConnection = (HttpURLConnection) url.openConnection();
urlConnection.setRequestMethod("GET");
urlConnection.setDoOutput(true);
urlConnection.setDoInput(true);
urlConnection.connect();
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
DocumentBuilder db = dbf.newDocumentBuilder();
doc = db.parse(urlConnection.getInputStream());
if (doc.getElementsByTagName("GeometryCollection").getLength() > 0) {
String path = doc.getElementsByTagName("GeometryCollection")
.item(0).getFirstChild().getFirstChild()
.getFirstChild().getNodeValue();
Log.d("xxx", "path=" + path);
String[] pairs = path.split(" ");
String[] lngLat = pairs[0].split(",");
// lngLat[0]=longitude
// lngLat[1]=latitude
// lngLat[2]=height
GeoPoint startGP = new GeoPoint((int) (Double.parseDouble(lngLat[1]) * 1E6),
(int) (Double.parseDouble(lngLat[0]) * 1E6));
mMapView01.getOverlays().add(new MyOverLay(startGP, startGP, 1));
GeoPoint gp1;
GeoPoint gp2 = startGP;
for (int i = 1; i < pairs.length; i++)
{
lngLat = pairs[i].split(",");
gp1 = gp2;
gp2 = new GeoPoint(
(int) (Double.parseDouble(lngLat[1]) * 1E6),
(int) (Double.parseDouble(lngLat[0]) * 1E6));
mMapView01.getOverlays().add(
new MyOverLay(gp1, gp2, 2, color));
Log.d("xxx", "pair:" + pairs[i]);
}
mMapView01.getOverlays().add(new MyOverLay(dest, dest, 3));
}
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (ParserConfigurationException e) {
e.printStackTrace();
} catch (SAXException e) {
e.printStackTrace();
}
}
}
So, as I said, I correctly get a route drawing.
But how could I handle click events on those drawn routes ?
For information, I was thinking about something which would probably be inefficient, but I'll tell it, we never knows :)
Since the route establishement is basicaly a succession of drawings beetween two geopoints (segments), we could prehaps handle route clicking this way :
Using the onTouchEvent method of the map overlay, we can get the geopoint associated to a click.
Then we try to establish if the clicked geopoint is part of a route segment.
One last information : Several routes will be drawn on the map at the same instant, so the click must be associated to a unique route and not all of them.
Thanks.
10 month later, I'm giving the work around I used (10 month ago), who knows, perhaps it will helps someone :).
In order to handle clicks/touch on map routes, one method can be to estimate if the clicked point is located near a displayed route.
Using the OnTouchEvent method, you should calculate if the clicked point is near a segment (a route part).
A route can be represented as a list of segments.
The following method let you calculate the distance between a point and a segment (from Java java.awt.geom.Line2D) :
/**
* Get the closest distance between a point and a segment
*
* #param x1 , x coordinate of the 1st segment point
* #param y1 , y coordinate of the 1st segment point
* #param x2 , x coordinate of the 2st segment point
* #param y2 , y coordinate of the 2st segment point
* #param x , x coordinate of the point from which distance will be calculated
* #param y , y coordinate of the point from which distance will be calculated
*
* #return the distance
*
*/
public static float ptSegDistSq(float x1, float y1, float x2, float y2, float px, float py){
// Adjust vectors relative to x1,y1
// x2,y2 becomes relative vector from x1,y1 to end of segment
x2 -= x1;
y2 -= y1;
// px,py becomes relative vector from x1,y1 to test point
px -= x1;
py -= y1;
float dotprod = px * x2 + py * y2;
float projlenSq;
if (dotprod <= 0.0) {
// px,py is on the side of x1,y1 away from x2,y2
// distance to segment is length of px,py vector
// "length of its (clipped) projection" is now 0.0
projlenSq = (float) 0.0;
} else {
// switch to backwards vectors relative to x2,y2
// x2,y2 are already the negative of x1,y1=>x2,y2
// to get px,py to be the negative of px,py=>x2,y2
// the dot product of two negated vectors is the same
// as the dot product of the two normal vectors
px = x2 - px;
py = y2 - py;
dotprod = px * x2 + py * y2;
if (dotprod <= 0.0) {
// px,py is on the side of x2,y2 away from x1,y1
// distance to segment is length of (backwards) px,py vector
// "length of its (clipped) projection" is now 0.0
projlenSq = (float) 0.0;
} else {
// px,py is between x1,y1 and x2,y2
// dotprod is the length of the px,py vector
// projected on the x2,y2=>x1,y1 vector times the
// length of the x2,y2=>x1,y1 vector
projlenSq = dotprod * dotprod / (x2 * x2 + y2 * y2);
}
}
// Distance to line is now the length of the relative point
// vector minus the length of its projection onto the line
// (which is zero if the projection falls outside the range
// of the line segment).
float lenSq = px * px + py * py - projlenSq;
if (lenSq < 0) {
lenSq = 0;
}
return lenSq;
}
Having this distance, you can establish fixed rules to estimate if the point is near a route, taking in count the map zoom level (at each zoom level correspond a maximum distance tolerance).
Here I create one project that will track our current location.
But I have a problem coding it... I don't know exactly how to use the OVERLAY class and when it is called.
I have posted my code.. Please help me
package com.techno.gps;
import java.io.IOException;
import java.util.List;
import java.util.Locale;
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.app.Activity;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Point;
import android.graphics.RectF;
import android.location.Address;
import android.location.Criteria;
import android.location.Geocoder;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.os.Bundle;
import android.widget.TextView;
public class gps extends MapActivity{
MapController mapController;
Location location;
MyPositionOverlay positionOverlay;
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
// Get a reference to the MapView
MapView myMapView = (MapView)findViewById(R.id.mapView);
// Get the Map View’s controller
mapController = myMapView.getController();
// Configure the map display options
myMapView.setSatellite(true);
myMapView.setStreetView(true);
myMapView.displayZoomControls(false);
// Zoom in
mapController.setZoom(17);
//add postionoverlay
positionOverlay = new MyPositionOverlay();
List<Overlay> overlays = myMapView.getOverlays();
overlays.add(positionOverlay);
LocationManager locationManager;
String context = Context.LOCATION_SERVICE;
locationManager = (LocationManager)getSystemService(context);
Criteria criteria = new Criteria();
criteria.setAccuracy(Criteria.ACCURACY_FINE);
criteria.setAltitudeRequired(false);
criteria.setBearingRequired(false);
criteria.setCostAllowed(true);
criteria.setPowerRequirement(Criteria.POWER_LOW);
String provider = locationManager.getBestProvider(criteria, true);
location = locationManager.getLastKnownLocation(provider);
updateWithNewLocation(location);
locationManager.requestLocationUpdates(provider, 2000, 10,locationListener);
}
#Override
protected boolean isRouteDisplayed() {
// TODO Auto-generated method stub
return false;
}
private void updateWithNewLocation(Location location)
{
String latLongString;
TextView myLocationText;
myLocationText = (TextView)findViewById(R.id.myLocationText);
String addressString = "No address found";
if (location != null) {
// Update the map location.
positionOverlay.setLocation(location);
Double geoLat = location.getLatitude()*1E6;
Double geoLng = location.getLongitude()*1E6;
GeoPoint point = new GeoPoint(geoLat.intValue(),
geoLng.intValue());
mapController.animateTo(point);
double lat = location.getLatitude();
double lng = location.getLongitude();
latLongString = "Lat: "+ lat + " Long:" + lng;
double latitude = location.getLatitude();
double longitude = location.getLongitude();
Geocoder gc = new Geocoder(this, Locale.getDefault());
try
{
List<Address> addresses = gc.getFromLocation(latitude, longitude, 1);
StringBuilder sb = new StringBuilder();
if (addresses.size() > 0)
{
Address address = addresses.get(0);
for (int i = 0; i < address.getMaxAddressLineIndex(); i++)
{
sb.append(address.getAddressLine(i)).append("\n");
}
sb.append(address.getLocality()).append("\n");
sb.append(address.getPostalCode()).append("\n");
sb.append(address.getCountryName());
}
addressString = sb.toString();
}
catch (IOException e)
{
}
}
else
{
latLongString = "No location found";
}
myLocationText.setText("Your Current Position is:\n" +latLongString + "\n" + addressString);
}
private final LocationListener locationListener = new LocationListener()
{
public void onLocationChanged(Location location) {
updateWithNewLocation(location);
}
public void onProviderDisabled(String provider)
{
updateWithNewLocation(null);
}
public void onProviderEnabled(String provider)
{
}
public void onStatusChanged(String provider, int status,Bundle extras)
{
}
};
public class MyPositionOverlay extends Overlay
{
Location location;
#Override
public void draw(Canvas canvas, MapView mapView, boolean shadow)
{
Projection projection = mapView.getProjection();
if (shadow == false) {
// Get the current location
Double latitude = location.getLatitude()*1E6;
Double longitude = location.getLongitude()*1E6;
GeoPoint geoPoint;
geoPoint = new GeoPoint(latitude.intValue(),longitude.intValue());
// Convert the location to screen pixels
int mRadius=5;
Point point = new Point();
projection.toPixels(geoPoint, point);
RectF oval = new RectF(point.x - mRadius, point.y - mRadius,
point.x + mRadius, point.y + mRadius);
// Setup the paint
Paint paint = new Paint();
paint.setARGB(250, 255, 0, 0);
paint.setAntiAlias(true);
paint.setFakeBoldText(true);
Paint backPaint = new Paint();
backPaint.setARGB(175, 50, 50, 50);
backPaint.setAntiAlias(true);
RectF backRect = new RectF(point.x + 2 + mRadius,
point.y - 3*mRadius,
point.x + 65, point.y + mRadius);
// Draw the marker
canvas.drawOval(oval, paint);
canvas.drawRoundRect(backRect, 5, 5, backPaint);
canvas.drawText("Here I Am", point.x + 2*mRadius, point.y, paint);
}
super.draw(canvas, mapView, shadow);
}
#Override
public boolean onTap(GeoPoint point, MapView mapView)
{
// Return true if screen tap is handled by this overlay
return false;
}
public Location getLocation() {
return location;
}
public void setLocation(Location location) {
this.location = location;
}
}
}
thanks...
Strange that you don't know your own code. You should try writing it by yourself. Copy-pasting does not work always.
To answer your question. An Overlay is drawable object that can be shown on top of the map on a different layer above the MapView.
This is the part of the code where you add that drawing to the MapView.
positionOverlay = new MyPositionOverlay();
List<Overlay> overlays = myMapView.getOverlays();
overlays.add(positionOverlay);
You are doing this in OnCreate(). Which does not makes sense, because you have no position fix yet.
Add the overlay when you get a pos-fix in updateWithNewLocation()
To call draw forcefully use MapView.invalidate()
i have the same example code, with 2.2 android, works, but don't drow the overlay, with my position, otherwise, with debuggin you can see code working properltly. Really strange.
I think code is correct, because, in onCreate, code is initializated, then in updateWithNewLocation, the overlay is updated with positionOverlay.setLocation(location);