Маршруты на картах Google в вашем Android-приложении

    Не так давно мне понадобилось написать приложение, которое бы показывало на карте маршрут между двумя заданными точками. В качестве инструмента были выбраны карты от Google. После непродолжительных поисков были найдены статьи про интеграцию карт в приложение, про фильтрацию пинов, про маршруты. Однако статьи, в которой бы описывалось как делать подобные маршруты в Android-приложении, не было и я решил исправить данное упущение (для новоиспечённых разработчиков под Android пригодится). Добро пожаловать под хабракат.

    Предположим, что мы уже прочитали статью про интеграцию, получили API-Key и написали приложение с картой, на которой отмечены две точки. Поэтому нам осталось только проложить маршрут между двумя данными точками.

    Получение маршрута



    Прежде всего необходимо отправить запрос и получить файл с данными о маршруте. Для этого нам потребуется открыть соединение по указанной ссылке (широта и долгота в ссылке задаются через запятую) и получить данные в виде XML. Вытаскивать точки маршрута из файла мы будем DOM парсером, для чего создаем объект Document.

    String urlString = "http://maps.google.com/maps?f=d&hl=en&saddr=" + startGeoPoint + "&daddr=" + stopGeoPoint + "&ie=UTF8&0&om=0&output=kml";
    Document document = null;
    HttpURLConnection urlConnection = null;
    URL url = null;
    try {
    url = new URL(urlString);
    urlConnection = (HttpURLConnection) url.openConnection();
    urlConnection.connect();
    DocumentBuilderFactory documentBuildFactory = DocumentBuilderFactory.newInstance();
    DocumentBuilder documentBuilder = documentBuildFactory.newDocumentBuilder();
    document = documentBuilder.parse(urlConnection.getInputStream());
    } catch (Exception e) { }


    Следуя документации по KML маршрут состоит из более мелких отрезков, поэтому нам предстоит создать массив из точек, через которые будет проходить наш маршрут. Подробности о разборе XML файла можно найти в этой статье. Стоит отметить, что точки находятся в теле тега «coordinates», который, в свою очередь, находится внутри «LineString».

    String points = null;
    NodeList nodeList = document.getElementsByTagName("LineString");
    points = nodeList.item(0).getFirstChild().getFirstChild().getNodeValue();
    String[] finalArray = points.split(" ");


    На этом получение координат, по которым будет строиться маршрут закончено. Переходим к рисованию самой линии.

    Overlay линии маршрута



    Данный класс наследует Overlay и представляет из себя (грубо говоря) графический уровень, который будет отображаться на карте. В данном классе мы создадим конструктор, через который будем задавать точки начала и конца линии, и допишем метод draw, который будет рисовать данную линию.

    private GeoPoint start;
    private GeoPoint stop;
    public MapOverlay(GeoPoint start, GeoPoint stop) {
    this.start = start;
    this.stop = stop;
    }

    @Override
    public boolean draw(Canvas canvas, MapView mapView, boolean shadow, long when) {
    // TODO Auto-generated method stub
    Projection projection = mapView.getProjection();
    if (shadow == false) {
    Paint paint = new Paint();
    paint.setAntiAlias(true);
    Point point = new Point();
    projection.toPixels(start, point);
    paint.setColor(Color.BLUE);
    Point point2 = new Point();
    projection.toPixels(stop, point2);
    paint.setStrokeWidth(2);
    canvas.drawLine((float) point.x, (float) point.y, (float) point2.x, (float) point2.y, paint);
    }
    return super.draw(canvas, mapView, shadow, when);
    }


    А теперь нам необходимо написать метод, который будет добавлять точки на этот уровень, создавая наш маршрут.

    Создание маршрута



    Если вы дошли до этого момента, то, скорее всего, знаете, что в GeoPoint сначала указывается широта, потом долгота.

    String coords = finalArray[0].split(",");
    GeoPoint start = new GeoPoint((int) (Double.parseDouble(coords[1]) * 1E6), (int) (Double.parseDouble(coords[0]) * 1E6));
    //Первую и последнюю точку маршрута добавляю отдельно потому, что мне проще написать так, однако вы можете написать свой цикл, в который данные точки будут включены
    mapView.getOverlays().add(new MapOverlay(start, start));
    GeoPoint geoPoint1;
    GeoPoint geoPoint2 = start;
    for (int i = 1; i < finalArray.length; i++) {
    coords = finalArray[i].split(",");
    geoPoint1 = geoPoint2;
    geoPoint2 = new GeoPoint((int) (Double.parseDouble(coords[1]) * 1E6), (int) (Double.parseDouble(coords[0]) * 1E6));
    mapView.getOverlays().add(new MapOverlay(geoPoint1, geoPoint2));
    }
    mapView.getOverlays().add(new MapOverlay(geoPoint2, geoPoint2));


    На этом создание маршрута завершено. Спасибо за внимание. В качестве примера приведу скриншот того, что получилось у меня.



    P.S. Это моя первая статья, поэтому не судите, пожалуйста, строго, так как большого опыта написания статей не имею, а код объяснял только словами и на пальцах.
    Ads
    AdBlock has stolen the banner, but banners are not teeth — they will be back

    More

    Comments 4

      0
      >сначала указывается широта, потом долгота, однако называются координаты наоборот

      0_однако
        0
        Половина шестого было — переклинило, видимо. Пардоньте ^_^
        0
        А нельзя указатели погуманнее выбрать?

        Гигантский человекоподобный робот накрывает весьма большую площадь (что, при его весе — не его проблема, конечно).

        Перевёрнутый треугольник имхо было бы самое оно.
          0
          указатель — картинка, которая лежит в drawable. Мы создаем класс, который наследует ItemizedOverlay, и в его конструкторе задаем маркер (ту самую картинку). Выглядит это примерно так:

          public class MyItemizedOverlay extends ItemizedOverlay {

          private ArrayList myOverlays = new ArrayList();

          public MyItemizedOverlay(Drawable defaultMarker) {
          super(boundCenterBottom(defaultMarker));
          // TODO Auto-generated constructor stub
          }

          @Override
          protected OverlayItem createItem(int i) {
          // TODO Auto-generated method stub
          return myOverlays.get(i);
          }

          public void addOverlay(OverlayItem overlay) {
          myOverlays.add(overlay);
          populate();
          }

          @Override
          public int size() {
          // TODO Auto-generated method stub
          return myOverlays.size();
          }

          }


          А в коде нашего активити мы уже указываем и путь к картинке и класс с этим маркером:

          drawable = this.getResources().getDrawable(R.drawable.androidmarker);
          itemizedOverlay = new MyItemizedOverlay(drawable);


          При большом желании можно создать много таких уровней с разными маркерами.

        Only users with full accounts can post comments. Log in, please.