osmdroid ile android harita uygulamaları – 2

Merhaba bir önceki yazımızda bahsettiğimiz OSMDroid’in rota çıkarma gibi güzel ve işe yarar özelliklerine de bu yazıda bakacağız. Ancak rota verisini Google Directions API’dan alacağız. Projenin tümüne https://github.com/berkanuslu/osmdroiddirections adresinden erişebilirsiniz.

Bunun için öncelikle daha önceki uygulamamıza ek olarak AndroidManifest.xml dosyasına aşağıdaki internet erişim iznini eklememiz gerekiyor. <uses-sdk> etiketinden önce aşağıdaki izni ekliyoruz.

<uses-permission android:name="android.permission.INTERNET" />

Bu iznin ardından arayüz (layout) dosyamızın içerisini aşağıdaki gibi güncelleyelim ve rota çıkarmak için gerekli olan Seyahat Modu (Travel Mode) seçeneğini aktif edelim. Ayrıca rotayı almak için de bir buton ekleyelim. Kısacası arayüz dosyamızın tamamı … linkteki gibi olacaktır.

Daha sonra MainActivity.java dosyamız içerisinde RadioGroup ve Button tanımlamalarını yapıyoruz.

final RadioGroup group = (RadioGroup) findViewById(R.id.travelModes);

Button btnGetDirections = (Button) findViewById(R.id.buttonGetDirections);
btnGetDirections.setOnClickListener(new OnClickListener() {

	@Override
	public void onClick(View v) {
		RadioButton selectedRadioButton = (RadioButton) findViewById(group.getCheckedRadioButtonId());
		String mode = selectedRadioButton.getText().toString().toLowerCase();

		String urlForDirections = makeURL(
				startPoint.getLatitude(),
				startPoint.getLongitude(),
				endPoint.getLatitude(),
				endPoint.getLongitude(), mode);
	        new connectAsyncTask(urlForDirections).execute();
	}
});

Burada az önce arayüz dosyasına eklediğimiz kontrolleri tanımladık ve işlevselliklerini verdik. Butona tıklandığında RadioGroup içerisinde seçili olan RadioButton nesnesinin ID’sini .getCheckedRadioButtonId() metodu ile alıp seçili olan modu belirliyor ve Google Directions API için gerekli URL’yi oluşturmak için makeURL() metodunu çağırıyoruz.

public String makeURL(double sourcelat, double sourcelog, double destlat, double destlog, String travelMode) {
        StringBuilder urlString = new StringBuilder();
        urlString.append("http://maps.googleapis.com/maps/api/directions/json");
        urlString.append("?origin=");// from
        urlString.append(Double.toString(sourcelat));
        urlString.append(",");
        urlString.append(Double.toString(sourcelog));
        urlString.append("&destination=");// to
        urlString.append(Double.toString(destlat));
        urlString.append(",");
        urlString.append(Double.toString(destlog));
        urlString.append("&sensor=false&mode="+travelMode+"&alternatives=true");
        return urlString.toString();
}

Yukarıdaki metoda göre Google Directions API’ın belirlemiş olduğu formatta bir istekle rotamızı cevap olarak alacağız. Burada dikkat etmemiz gereken origin parametresiyle başlangıç noktasını destination parametresiyle de varış noktasını Double tipinde (tabiiki bir URL oluşturduğumuz için String’e çevirerek)  ekliyoruz. Burada bir de mode parametresi ile seyahat modunu belirliyoruz.

Şimdi elimizde artık verdiğimiz başlangıç ve bitiş konumlarına göre belirlediğimiz seyahat modunda Google Directions API’dan gerekli bilgiyi isteyeceğimiz bir URL’miz var. Bu URL’yi kullanarak gerekli JSON verisini almak için bir AsyncTask oluşturmamız gerekiyor.

private class connectAsyncTask extends AsyncTask {
        private ProgressDialog progressDialog;
        String url;

        connectAsyncTask(String urlPass) {
            url = urlPass;
        }

        @Override
        protected void onPreExecute() {
            super.onPreExecute();
            progressDialog = new ProgressDialog(context);
            progressDialog.setMessage("Fetching route, Please wait...");
            progressDialog.setIndeterminate(true);
            progressDialog.show();
        }

        @Override
        protected String doInBackground(Void... params) {
            JSONParser jParser = new JSONParser();
            String json = jParser.getJSONFromUrl(url);
            return json;
        }

        @Override
        protected void onPostExecute(String result) {
            super.onPostExecute(result);
            progressDialog.hide();
            if (result != null) {
                drawPath(result);
            }
        }
}

Burada dönen JSON sorgusunun içerisinden bazı verileri ayıklamamız gerekiyor ki aldığımız GeoPoint noktaları ile birlikte rotamızı çizebilelim. Onun için gelen veriyi drawPath() metodu ile ayıklıyoruz.

public void drawPath(String result) {
    	map.getOverlays().clear();

    	addStartEndMarkers();

    	ArrayList waypoints = new ArrayList();
    	waypoints.add(startPoint);

        try {
            final JSONObject json = new JSONObject(result);
            JSONArray routeArray = json.getJSONArray("routes");
            JSONObject routes = routeArray.getJSONObject(0);
            JSONObject overviewPolylines = routes
                    .getJSONObject("overview_polyline");

            String duration = routes.getJSONArray("legs").getJSONObject(0)
            		.getJSONObject("duration").getString("text");

            String distance = routes.getJSONArray("legs").getJSONObject(0)
            		.getJSONObject("distance").getString("text");

            Toast.makeText(context, ("Total Road Duration: " + duration + "  / Total Distance: " + distance), Toast.LENGTH_LONG).show();
            String encodedString = overviewPolylines.getString("points");
            List list = decodePoly(encodedString);

            for (int z = 0; z < list.size() - 1; z++) {
                GeoPoint src = list.get(z);
                waypoints.add(src);
            }

        } catch (Exception e) {
            e.printStackTrace();
        }

        waypoints.add(endPoint);

        RoadManager roadManager = new OSRMRoadManager();
        Road road = roadManager.getRoad(waypoints);
        Polyline roadOverlay = RoadManager.buildRoadOverlay(road, this);

        map.getOverlays().add(roadOverlay);
        map.invalidate();
    }

Dönen JSON verisi içerisinde toplam rota zamanını (duration) ve rotanın uzunluğunu (distance) alabileceğimiz veriler mevcuttur. Bunun yanında her bir adımda mevcut konumu açıklayan bir veri de gelen JSON verisi içerisinde var, bunu arzu edenler dönen verinin olduğu kısma Breakpoint koyup Debug modda çalıştırarak gelen veriyi inceleyebilirler.

Burada dikkat etmemiz gereken bazı noktalar mevcut, onlardan ilki çizeceğimiz rotanın dönen tüm noktalarını bir ArrayList içerisinde tutmamız gerekiyor. Bunu da decodePoly() metodu içerisinde ayrıştıracak GeoPoint nesnesi tipinde bir dizi gönderiyoruz. Bu dizinin başına başlangıç ve bitiş noktalarını da ekledikten sonra geriye bu noktaları harita üzerinde çizdirmek kalıyor.

RoadManager roadManager = new OSRMRoadManager();
Road road = roadManager.getRoad(waypoints);
Polyline roadOverlay = RoadManager.buildRoadOverlay(road, this);

Yukarıdaki kodda OSMDroid BonusPack içerisinde yer alan RoadManager sınıfından faydalanıyoruz. Bu sınıfın getRoad() metodu sayesinde parametre olarak verdiğimiz GeoPoint dizisini Road isimli bir nesneye çeviriyoruz. Road nesnemizi de RoadManager sınıfının buildRoalOverlay() metodunu kullanarak bir Polyline’a dönüştürüyoruz.

Artık elimizde haritamız üzerine ekleyebildiğimiz bir Polyline sınıfı türünden nesnemiz var. Bunu tıpkı Marker ekler gibi Overlay olarak ekledikten sonra MapView nesnemizin invalidate() metodu ile haritamızı yeni çizilen rotamızla birlikte güncelliyoruz.

İşlem sonunda ise aşağıdaki gibi bir görüntü oluşacak ve belirlediğimiz başlangıç ve bitiş noktaları arasındaki rota belirlediğimiz seyahat moduna göre harita üzerinde çizdirilecektir.

Herkese iyi çalışmalar…