{"id":13,"date":"2011-12-22T13:56:28","date_gmt":"2011-12-22T13:56:28","guid":{"rendered":"http:\/\/www.tvarwebu.cz\/blog\/?p=13"},"modified":"2023-10-27T13:03:39","modified_gmt":"2023-10-27T13:03:39","slug":"android-drawing-route-on-mapview","status":"publish","type":"post","link":"https:\/\/www.tvarwebu.cz\/blog\/2011\/12\/android-drawing-route-on-mapview\/","title":{"rendered":"Android &#8211; Drawing route on MapView"},"content":{"rendered":"<p>Hi everyone,<\/p>\n<p>I had quite big problem with drawing route on MapView. Tutorials on the web which I found are quite confusing or with bugs. So I took several of them and did own program, which using some code from several tutorials . Here is source of my map activity:<\/p>\n<pre lang=\"java\" line=\"1\">package tvarwebu.projects.map;\r\n\r\nimport java.io.IOException;\r\nimport java.io.InputStream;\r\nimport java.net.MalformedURLException;\r\nimport java.net.URL;\r\nimport java.net.URLConnection;\r\nimport java.util.ArrayList;\r\nimport java.util.List;\r\n\r\nimport com.google.android.maps.GeoPoint;\r\nimport com.google.android.maps.MapActivity;\r\nimport com.google.android.maps.MapController;\r\nimport com.google.android.maps.MapView;\r\nimport com.google.android.maps.Overlay;\r\nimport com.google.android.maps.OverlayItem;\r\n\r\nimport android.graphics.Canvas;\r\nimport android.graphics.Color;\r\nimport android.graphics.Paint;\r\nimport android.graphics.Point;\r\nimport android.graphics.drawable.Drawable;\r\nimport android.location.Location;\r\nimport android.location.LocationManager;\r\nimport android.os.Bundle;\r\nimport android.os.Handler;\r\n\r\npublic class MapProjectActivity extends MapActivity {\r\n\r\nGeoPoint myPoint = null;\r\nGeoPoint nextPoint = null;\r\nMapView map;\r\nprivate Road mRoad;\r\nint latSpan = -1;\r\nboolean moving = false;\r\nlong lastTimestamp = 0;\r\nint pointCount = 0;\r\nint lat = 0;\r\nint lng = 0;\r\nLocation currLoc = null;\r\nOverlayItem currPoint;\r\nMyItemizedOverlay currItemizedOverlay;\r\nList&lt;Overlay&gt; mapOverlays;\r\nLocationManager lm;\r\n\r\n@Override\r\nprotected void onCreate(Bundle savedInstanceState) {\r\n\r\n  super.onCreate(savedInstanceState);\r\n  setContentView(R.layout.main);\r\n\r\n  map = (MapView) findViewById(R.id.mapView);\r\n  map.setBuiltInZoomControls(true);\r\n  map.setStreetView(true);\r\n  map.setSatellite(false);\r\n\r\n  \/\/ Your position initialize\r\n  lat = 53324388;\r\n  lng = -6263194;\r\n\r\n  myPoint = new GeoPoint(lat, lng);\r\n\r\n  Drawable drawable = this.getResources().getDrawable(\r\n  R.drawable.flag_green);\r\n\r\n  MyItemizedOverlay itemizedoverlay = new MyItemizedOverlay(drawable, this);\r\n\r\n  OverlayItem overlayitem = new OverlayItem(myPoint, \"Start Position\", \"Your start position\");\r\n\r\n  itemizedoverlay.addOverlay(overlayitem);\r\n\r\n  \/\/ Position of next point\r\n  int lat2 = 53348084;\r\n  int lng2 = -6292434;\r\n\r\n  nextPoint = new GeoPoint(lat2, lng2);\r\n\r\n  OverlayItem overlayitem2 = new OverlayItem(nextPoint, \"Position\", \"Position of next point\");\r\n\r\n  itemizedoverlay.addOverlay(overlayitem2);\r\n\r\n  mapOverlays = map.getOverlays();\r\n  mapOverlays.add(itemizedoverlay);\r\n\r\n  Drawable draw2 = this.getResources().getDrawable(R.drawable.flag_red);\r\n\r\n  MyItemizedOverlay over2 = new MyItemizedOverlay(draw2, this);\r\n  over2.addOverlay(overlayitem2);\r\n\r\n  mapOverlays.add(over2);\r\n\r\n  \/\/ zooming to both points\r\n  int maxLatitude = Math.max(lat, lat2);\r\n  int minLatitude = Math.min(lat, lat2);\r\n  int maxLongitude = Math.max(lng, lng2);\r\n  int minLongitude = Math.min(lng, lng2);\r\n\r\n  MapController mc = map.getController();\r\n  mc.zoomToSpan(maxLatitude - minLatitude, maxLongitude - minLongitude);\r\n  mc.animateTo(new GeoPoint((maxLatitude + minLatitude) \/ 2, (maxLongitude + minLongitude) \/ 2));\r\n\r\n  map.invalidate();\r\n\r\n  \/\/Drawing path in new Thread\r\n  new Thread() {\r\n\r\n  @Override\r\n  public void run() {\r\n    double fromLat = Double.valueOf(myPoint.getLatitudeE6()) \/ 1000000.0,\r\n    fromLon = Double.valueOf(myPoint.getLongitudeE6()) \/ 1000000.0;\r\n    double toLat = Double.valueOf(nextPoint.getLatitudeE6()) \/ 1000000.0,\r\n    toLon = Double.valueOf(nextPoint.getLongitudeE6()) \/ 1000000.0;\r\n\r\n    String url = RoadProvider.getUrl(fromLat, fromLon, toLat, toLon);\r\n    InputStream is = getConnection(url);\r\n    mRoad = RoadProvider.getRoute(is);\r\n    mHandler.sendEmptyMessage(0);\r\n  }\r\n}.start();\r\n\r\n}\r\n\r\nHandler mHandler = new Handler() {\r\n  public void handleMessage(android.os.Message msg) {\r\n    MapOverlay mapOverlay = new MapOverlay(mRoad, map);\r\n    List&lt;Overlay&gt; listOfOverlays = map.getOverlays();\r\n    \/\/ listOfOverlays.clear();\r\n    listOfOverlays.add(mapOverlay);\r\n    map.invalidate();\r\n  };\r\n};\r\n\r\nprivate InputStream getConnection(String url) {\r\n  InputStream is = null;\r\n  try {\r\n    URLConnection conn = new URL(url).openConnection();\r\n    is = conn.getInputStream();\r\n  } catch (MalformedURLException e) {\r\n    e.printStackTrace();\r\n  } catch (IOException e) {\r\n    e.printStackTrace();\r\n  }\r\n  return is;\r\n}\r\n\r\n@Override\r\nprotected boolean isRouteDisplayed() {\r\n  \/\/ TODO Auto-generated method stub\r\n  return false;\r\n}\r\n\/\/ Map extends overlay for drawing path\r\nclass MapOverlay extends com.google.android.maps.Overlay {\r\n  Road mRoad;\r\n  ArrayList&lt;GeoPoint&gt; mPoints;\r\n\r\n  public MapOverlay(Road road, MapView mv) {\r\n    mRoad = road;\r\n    \/\/ mRoute is field of route points getting from Google Maps\r\n    if (road.mRoute.length &gt; 0) {\r\n      mPoints = new ArrayList&lt;GeoPoint&gt;();\r\n      for (int i = 0; i &lt; road.mRoute.length; i++) {\r\n        mPoints.add(new GeoPoint(\r\n        (int) (road.mRoute[i][1] * 1000000),\r\n        (int) (road.mRoute[i][0] * 1000000)));\r\n      }\r\n    }\r\n  }\r\n\r\n  @Override\r\n  public void draw(Canvas canvas, MapView mv, boolean shadow) {\r\n    drawPath(mv, canvas);\r\n  }\r\n\r\n  public void drawPath(MapView mv, Canvas canvas) {\r\n    int x1 = -1, y1 = -1, x2 = -1, y2 = -1;\r\n    Paint paint = new Paint();\r\n    latSpan = mv.getLatitudeSpan();\r\n    paint.setColor(Color.parseColor(\"#998447cc\"));\r\n    paint.setStyle(Paint.Style.STROKE);\r\n    paint.setStrokeWidth(6);\r\n    if (mPoints != null) {\r\n      for (int i = 0; i &lt; mPoints.size(); i++) {\r\n        Point point = new Point();\r\n        mv.getProjection().toPixels(mPoints.get(i), point);\r\n        x2 = point.x;\r\n        y2 = point.y;\r\n        if (i &gt; 0) {\r\n          canvas.drawLine(x1, y1, x2, y2, paint);\r\n        }\r\n        x1 = x2;\r\n        y1 = y2;\r\n      }\r\n    }\r\n  }\r\n}\r\n}<\/pre>\n<p>In addition, you will need this files:<\/p>\n<p>1. Road.java<\/p>\n<pre lang=\"java\" line=\"1\">package tvarwebu.projects.map;\r\n\r\npublic class Road {\r\npublic String mName;\r\npublic String mDescription;\r\npublic int mColor;\r\npublic int mWidth;\r\npublic double[][] mRoute = new double[][] {};\r\npublic Point[] mPoints = new Point[] {};\r\n\r\n}<\/pre>\n<p>2. Point.java<\/p>\n<pre lang=\"java\" line=\"1\">package tvarwebu.projects.map;\r\n\r\npublic class Point {\r\n  String mName;\r\n  String mDescription;\r\n  String mIconUrl;\r\n  double mLatitude;\r\n  double mLongitude;\r\n}<\/pre>\n<p>3. RoadProvider.java<\/p>\n<pre lang=\"java\" line=\"1\">package tvarwebu.projects.map;\r\n\r\nimport java.io.IOException;\r\nimport java.io.InputStream;\r\nimport java.util.Stack;\r\n\r\nimport javax.xml.parsers.ParserConfigurationException;\r\nimport javax.xml.parsers.SAXParser;\r\nimport javax.xml.parsers.SAXParserFactory;\r\n\r\nimport org.xml.sax.Attributes;\r\nimport org.xml.sax.SAXException;\r\nimport org.xml.sax.helpers.DefaultHandler;\r\n\r\npublic class RoadProvider {\r\n\r\npublic static Road getRoute(InputStream is) {\r\n  KMLHandler handler = new KMLHandler();\r\n  try {\r\n    SAXParser parser = SAXParserFactory.newInstance().newSAXParser();\r\n    parser.parse(is, handler);\r\n  } catch (ParserConfigurationException e) {\r\n    e.printStackTrace();\r\n  } catch (SAXException e) {\r\n    e.printStackTrace();\r\n  } catch (IOException e) {\r\n    e.printStackTrace();\r\n  }\r\n  return handler.mRoad;\r\n}\r\n\r\npublic static String getUrl(double fromLat, double fromLon, double toLat, double toLon) {\/\/ connect to map web service\r\n  StringBuffer urlString = new StringBuffer();\r\n  urlString.append(\"http:\/\/maps.google.com\/maps?f=d&amp;hl=en\");\r\n  urlString.append(\"&amp;saddr=\");\/\/ from\r\n  urlString.append(Double.toString(fromLat));\r\n  urlString.append(\",\");\r\n  urlString.append(Double.toString(fromLon));\r\n  urlString.append(\"&amp;daddr=\");\/\/ to\r\n  urlString.append(Double.toString(toLat));\r\n  urlString.append(\",\");\r\n  urlString.append(Double.toString(toLon));\r\n  urlString.append(\"&amp;ie=UTF8&amp;0&amp;om=0&amp;output=kml\");\r\n\r\n  String ggg = urlString.toString();\r\n  return urlString.toString();\r\n}\r\n}\r\n\r\nclass KMLHandler extends DefaultHandler {\r\n  Road mRoad;\r\n  boolean isPlacemark;\r\n  boolean isRoute;\r\n  boolean isItemIcon;\r\n  private Stack mCurrentElement = new Stack();\r\n  private String mString;\r\n\r\n  public KMLHandler() {\r\n  mRoad = new Road();\r\n}\r\n\r\npublic void startElement(String uri, String localName, String name, Attributes attributes) throws SAXException {\r\n  mCurrentElement.push(localName);\r\n  if (localName.equalsIgnoreCase(\"Placemark\")) {\r\n    isPlacemark = true;\r\n    mRoad.mPoints = addPoint(mRoad.mPoints);\r\n  } else if (localName.equalsIgnoreCase(\"ItemIcon\")) {\r\n    if (isPlacemark)\r\n      isItemIcon = true;\r\n    }\r\n    mString = new String();\r\n  }\r\n\r\n  public void characters(char[] ch, int start, int length) throws SAXException {\r\n    String chars = new String(ch, start, length).trim();\r\n    mString = mString.concat(chars);\r\n  }\r\n\r\n  public void endElement(String uri, String localName, String name) throws SAXException {\r\n    if (mString.length() &gt; 0) {\r\n      if (localName.equalsIgnoreCase(\"name\")) {\r\n        if (isPlacemark) {\r\n          isRoute = mString.equalsIgnoreCase(\"Route\");\r\n          if (!isRoute) {\r\n            mRoad.mPoints[mRoad.mPoints.length - 1].mName = mString;\r\n          }\r\n        } else {\r\n          mRoad.mName = mString;\r\n        }\r\n      } else if (localName.equalsIgnoreCase(\"color\") &amp;&amp; !isPlacemark) {\r\n        mRoad.mColor = Integer.parseInt(mString, 16);\r\n      } else if (localName.equalsIgnoreCase(\"width\") &amp;&amp; !isPlacemark) {\r\n        mRoad.mWidth = Integer.parseInt(mString);\r\n      } else if (localName.equalsIgnoreCase(\"description\")) {\r\n        if (isPlacemark) {\r\n          String description = cleanup(mString);\r\n          if (!isRoute)\r\n            mRoad.mPoints[mRoad.mPoints.length - 1].mDescription = description;\r\n          else\r\n            mRoad.mDescription = description;\r\n        }\r\n      } else if (localName.equalsIgnoreCase(\"href\")) {\r\n        if (isItemIcon) {\r\n          mRoad.mPoints[mRoad.mPoints.length - 1].mIconUrl = mString;\r\n        }\r\n      } else if (localName.equalsIgnoreCase(\"coordinates\")) {\r\n        if (isPlacemark) {\r\n          if (!isRoute) {\r\n            String[] xyParsed = split(mString, \",\");\r\n            double lon = Double.parseDouble(xyParsed[0]);\r\n            double lat = Double.parseDouble(xyParsed[1]);\r\n            mRoad.mPoints[mRoad.mPoints.length - 1].mLatitude = lat;\r\n            mRoad.mPoints[mRoad.mPoints.length - 1].mLongitude = lon;\r\n          } else {\r\n            String[] coodrinatesParsed = split(mString, \" \");\r\n            int count = 0;\r\n            if(mRoad.mRoute.length &lt; 2)\r\n              mRoad.mRoute = new double[coodrinatesParsed.length][2];\r\n            else {\r\n              double[][] mRouteTmp = mRoad.mRoute;\r\n              mRoad.mRoute = new double[mRouteTmp.length + coodrinatesParsed.length][2];\r\n              \/\/for (int i = 0; i &lt; mRouteTmp.length; i++) {\r\n              \/\/mRoad.mRoute[i] = mRouteTmp[i];\r\n              \/\/mRoad.mRoute[i][i] = mRouteTmp[i][i];\r\n              \/\/}\r\n              System.arraycopy(mRouteTmp, 0, mRoad.mRoute, 0, mRouteTmp.length);\r\n\r\n              count = mRouteTmp.length;\r\n            }\r\n\r\n            for (int i = count; i &lt; (mRoad.mRoute.length); i++) {\r\n              String[] xyParsed = split(coodrinatesParsed[i - count], \",\");\r\n              for (int j = 0; j &lt; 2 &amp;&amp; j &lt; xyParsed.length; j++)\r\n                mRoad.mRoute[i][j] = Double.parseDouble(xyParsed[j]);\r\n            }\r\n          }\r\n        }\r\n      }\r\n    }\r\n    mCurrentElement.pop();\r\n    if (localName.equalsIgnoreCase(\"Placemark\")) {\r\n      isPlacemark = false;\r\n      if (isRoute)\r\n      isRoute = false;\r\n    } else if (localName.equalsIgnoreCase(\"ItemIcon\")) {\r\n      if (isItemIcon)\r\n        isItemIcon = false;\r\n    }\r\n  }\r\n\r\n  private String cleanup(String value) {\r\n    String remove = \"&lt;br\/&gt;\";\r\n    int index = value.indexOf(remove);\r\n    if (index != -1)\r\n    value = value.substring(0, index);\r\n    remove = \"\u00a0\";\r\n    index = value.indexOf(remove);\r\n    int len = remove.length();\r\n    while (index != -1) {\r\n      value = value.substring(0, index).concat(\r\n      value.substring(index + len, value.length()));\r\n      index = value.indexOf(remove);\r\n    }\r\n    return value;\r\n  }\r\n\r\n  public Point[] addPoint(Point[] mPoints) {\r\n    Point[] result = new Point[mPoints.length + 1];\r\n    for (int i = 0; i &lt; mPoints.length; i++)\r\n      result[i] = mPoints[i];\r\n    result[mPoints.length] = new Point();\r\n    return result;\r\n  }\r\n\r\n  private static String[] split(String strString, String strDelimiter) {\r\n    String[] strArray;\r\n    int iOccurrences = 0;\r\n    int iIndexOfInnerString = 0;\r\n    int iIndexOfDelimiter = 0;\r\n    int iCounter = 0;\r\n    if (strString == null) {\r\n      throw new IllegalArgumentException(\"Input string cannot be null.\");\r\n    }\r\n    if (strDelimiter.length() &lt;= 0 || strDelimiter == null) {\r\n      throw new IllegalArgumentException(\"Delimeter cannot be null or empty.\");\r\n    }\r\n    if (strString.startsWith(strDelimiter)) {\r\n      strString = strString.substring(strDelimiter.length());\r\n    }\r\n    if (!strString.endsWith(strDelimiter)) {\r\n      strString += strDelimiter;\r\n    }\r\n    while ((iIndexOfDelimiter = strString.indexOf(strDelimiter,\r\n      iIndexOfInnerString)) != -1) {\r\n      iOccurrences += 1;\r\n      iIndexOfInnerString = iIndexOfDelimiter + strDelimiter.length();\r\n    }\r\n\r\n    strArray = new String[iOccurrences];\r\n    iIndexOfInnerString = 0;\r\n    iIndexOfDelimiter = 0;\r\n    while ((iIndexOfDelimiter = strString.indexOf(strDelimiter,\r\n      iIndexOfInnerString)) != -1) {\r\n      strArray[iCounter] = strString.substring(iIndexOfInnerString,\r\n      iIndexOfDelimiter);\r\n      iIndexOfInnerString = iIndexOfDelimiter + strDelimiter.length();\r\n      iCounter += 1;\r\n    }\r\n\r\n    return strArray;\r\n  }\r\n}<\/pre>\n<p>4. MyItemizedOverlay.java :<\/p>\n<pre lang=\"java\" line=\"1\">package tvarwebu.projects.map;\r\n\r\nimport java.util.ArrayList;\r\nimport android.app.AlertDialog;\r\nimport android.content.Context;\r\nimport android.graphics.drawable.Drawable;\r\nimport com.google.android.maps.ItemizedOverlay;\r\nimport com.google.android.maps.OverlayItem;\r\n\r\npublic class MyItemizedOverlay extends ItemizedOverlay&lt;OverlayItem&gt; {\r\n  private ArrayList&lt;OverlayItem&gt; mOverlays = new ArrayList&lt;OverlayItem&gt;();\r\n  private Context mContext;\r\n\r\n  public MyItemizedOverlay(Drawable defaultMarker, Context context) {\r\n    super(boundCenterBottom(defaultMarker));\r\n    mContext = context;\r\n  }\r\n\r\n  public void addOverlay(OverlayItem overlay) {\r\n    mOverlays.add(overlay);\r\n    populate();\r\n  }\r\n\r\n  @Override\r\n  protected OverlayItem createItem(int i) {\r\n    return mOverlays.get(i);\r\n  }\r\n\r\n  @Override\r\n  public int size() {\r\n    return mOverlays.size();\r\n  }\r\n\r\n  public void removeLast(){\r\n    mOverlays.remove(mOverlays.size()-1);\r\n  }\r\n\r\n  @Override\r\n  protected boolean onTap(int index) {\r\n    OverlayItem item = mOverlays.get(index);\r\n    AlertDialog.Builder dialog = new AlertDialog.Builder(mContext);\r\n    dialog.setTitle(item.getTitle());\r\n    dialog.setMessage(item.getSnippet());\r\n    dialog.show();\r\n    return true;\r\n  }\r\n}<\/pre>\n<p>When you change names of package, you should get this screen after launch:<\/p>\n<p><a href=\"https:\/\/www.tvarwebu.cz\/blog\/wp-content\/uploads\/device-2011-12-22-130005.png\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone size-medium wp-image-15\" src=\"https:\/\/www.tvarwebu.cz\/blog\/wp-content\/uploads\/device-2011-12-22-130005-180x300.png\" alt=\"\" width=\"180\" height=\"300\" srcset=\"https:\/\/www.tvarwebu.cz\/blog\/wp-content\/uploads\/device-2011-12-22-130005-180x300.png 180w, https:\/\/www.tvarwebu.cz\/blog\/wp-content\/uploads\/device-2011-12-22-130005.png 480w\" sizes=\"auto, (max-width: 180px) 100vw, 180px\" \/><\/a><\/p>\n<p>Hope that this article helps you with this problem \ud83d\ude42 See the comple source code of Drawing route on MapView.<\/p>\n<p>by Roman Holomek, \u00a0Tv\u00e1\u0159Webu<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Hi everyone, I had quite big problem with drawing route on MapView. Tutorials on the web which I found are quite confusing or with bugs. So I took several of them and did own program, which using some code from several tutorials . Here is source of my map activity: package tvarwebu.projects.map; import java.io.IOException; import &hellip; <\/p>\n<p><a class=\"more-link btn\" href=\"https:\/\/www.tvarwebu.cz\/blog\/2011\/12\/android-drawing-route-on-mapview\/\">Continue reading<\/a><\/p>\n","protected":false},"author":3,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[4],"tags":[],"class_list":["post-13","post","type-post","status-publish","format-standard","hentry","category-android","item-wrap"],"aioseo_notices":[],"_links":{"self":[{"href":"https:\/\/www.tvarwebu.cz\/blog\/wp-json\/wp\/v2\/posts\/13","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.tvarwebu.cz\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.tvarwebu.cz\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.tvarwebu.cz\/blog\/wp-json\/wp\/v2\/users\/3"}],"replies":[{"embeddable":true,"href":"https:\/\/www.tvarwebu.cz\/blog\/wp-json\/wp\/v2\/comments?post=13"}],"version-history":[{"count":19,"href":"https:\/\/www.tvarwebu.cz\/blog\/wp-json\/wp\/v2\/posts\/13\/revisions"}],"predecessor-version":[{"id":119,"href":"https:\/\/www.tvarwebu.cz\/blog\/wp-json\/wp\/v2\/posts\/13\/revisions\/119"}],"wp:attachment":[{"href":"https:\/\/www.tvarwebu.cz\/blog\/wp-json\/wp\/v2\/media?parent=13"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.tvarwebu.cz\/blog\/wp-json\/wp\/v2\/categories?post=13"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.tvarwebu.cz\/blog\/wp-json\/wp\/v2\/tags?post=13"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}