android - كيف يمكنني رسم طريق ، على طول طريق حالي ، بين نقطتين؟




google-maps google-maps-android-api-2 (2)

تمكين واجهة برمجة تطبيقات Direction من Google Console. استبدال API_KEY في فئة GetPathFromLocation.java

import android.graphics.Color;
import android.os.AsyncTask;
import android.util.Log;

import com.google.android.gms.maps.model.LatLng;
import com.google.android.gms.maps.model.PolylineOptions;

import org.json.JSONObject;

import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

public class GetPathFromLocation extends AsyncTask<String, Void, PolylineOptions> {

    private String TAG = "GetPathFromLocation";
    private String API_KEY = "Place_Your_API_Key";
    private LatLng source, destination;
    private DirectionPointListener resultCallback;

    public GetPathFromLocation(LatLng source, LatLng destination, DirectionPointListener resultCallback) {
        this.source = source;
        this.destination = destination;
        this.resultCallback = resultCallback;
    }

    public String getUrl(LatLng origin, LatLng dest) {

        String str_origin = "origin=" + origin.latitude + "," + origin.longitude;
        String str_dest = "destination=" + dest.latitude + "," + dest.longitude;
        String sensor = "sensor=false";
        String parameters = str_origin + "&" + str_dest + "&" + sensor;
        String output = "json";
        String url = "https://maps.googleapis.com/maps/api/directions/" + output + "?" + parameters + "&key=" + API_KEY;

        return url;
    }

    @Override
    protected PolylineOptions doInBackground(String... url) {

        String data;

        try {
            InputStream inputStream = null;
            HttpURLConnection connection = null;
            try {
                URL directionUrl = new URL(getUrl(source, destination));
                connection = (HttpURLConnection) directionUrl.openConnection();
                connection.connect();
                inputStream = connection.getInputStream();

                BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
                StringBuffer stringBuffer = new StringBuffer();

                String line = "";
                while ((line = bufferedReader.readLine()) != null) {
                    stringBuffer.append(line);
                }

                data = stringBuffer.toString();
                bufferedReader.close();

            } catch (Exception e) {
                Log.e(TAG, "Exception : " + e.toString());
                return null;
            } finally {
                inputStream.close();
                connection.disconnect();
            }
            Log.e(TAG, "Background Task data : " + data);


            JSONObject jsonObject;
            List<List<HashMap<String, String>>> routes = null;

            try {
                jsonObject = new JSONObject(data);
                // Starts parsing data
                DirectionHelper helper = new DirectionHelper();
                routes = helper.parse(jsonObject);
                Log.e(TAG, "Executing Routes : "/*, routes.toString()*/);


                ArrayList<LatLng> points;
                PolylineOptions lineOptions = null;

                // Traversing through all the routes
                for (int i = 0; i < routes.size(); i++) {
                    points = new ArrayList<>();
                    lineOptions = new PolylineOptions();

                    // Fetching i-th route
                    List<HashMap<String, String>> path = routes.get(i);

                    // Fetching all the points in i-th route
                    for (int j = 0; j < path.size(); j++) {
                        HashMap<String, String> point = path.get(j);

                        double lat = Double.parseDouble(point.get("lat"));
                        double lng = Double.parseDouble(point.get("lng"));
                        LatLng position = new LatLng(lat, lng);

                        points.add(position);
                    }

                    // Adding all the points in the route to LineOptions
                    lineOptions.addAll(points);
                    lineOptions.width(10);
                    lineOptions.color(Color.BLUE);

                    Log.e(TAG, "PolylineOptions Decoded");
                }

                // Drawing polyline in the Google Map for the i-th route
                if (lineOptions != null) {
                    return lineOptions;
                } else {
                    return null;
                }

            } catch (Exception e) {
                Log.e(TAG, "Exception in Executing Routes : " + e.toString());
                return null;
            }

        } catch (Exception e) {
            Log.e(TAG, "Background Task Exception : " + e.toString());
            return null;
        }
    }

    @Override
    protected void onPostExecute(PolylineOptions polylineOptions) {
        super.onPostExecute(polylineOptions);
        if (resultCallback != null && polylineOptions != null)
            resultCallback.onPath(polylineOptions);
    }
}

DirectionHelper.java

import com.google.android.gms.maps.model.LatLng;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

public class DirectionHelper {

    public List<List<HashMap<String, String>>> parse(JSONObject jObject) {

        List<List<HashMap<String, String>>> routes = new ArrayList<>();
        JSONArray jRoutes;
        JSONArray jLegs;
        JSONArray jSteps;

        try {

            jRoutes = jObject.getJSONArray("routes");

            /** Traversing all routes */
            for (int i = 0; i < jRoutes.length(); i++) {
                jLegs = ((JSONObject) jRoutes.get(i)).getJSONArray("legs");
                List path = new ArrayList<>();

                /** Traversing all legs */
                for (int j = 0; j < jLegs.length(); j++) {
                    jSteps = ((JSONObject) jLegs.get(j)).getJSONArray("steps");

                    /** Traversing all steps */
                    for (int k = 0; k < jSteps.length(); k++) {
                        String polyline = "";
                        polyline = (String) ((JSONObject) ((JSONObject) jSteps.get(k)).get("polyline")).get("points");
                        List<LatLng> list = decodePoly(polyline);

                        /** Traversing all points */
                        for (int l = 0; l < list.size(); l++) {
                            HashMap<String, String> hm = new HashMap<>();
                            hm.put("lat", Double.toString((list.get(l)).latitude));
                            hm.put("lng", Double.toString((list.get(l)).longitude));
                            path.add(hm);
                        }
                    }
                    routes.add(path);
                }
            }

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


        return routes;
    }

    //Method to decode polyline points
    private List<LatLng> decodePoly(String encoded) {

        List<LatLng> poly = new ArrayList<>();
        int index = 0, len = encoded.length();
        int lat = 0, lng = 0;

        while (index < len) {
            int b, shift = 0, result = 0;
            do {
                b = encoded.charAt(index++) - 63;
                result |= (b & 0x1f) << shift;
                shift += 5;
            } while (b >= 0x20);
            int dlat = ((result & 1) != 0 ? ~(result >> 1) : (result >> 1));
            lat += dlat;

            shift = 0;
            result = 0;
            do {
                b = encoded.charAt(index++) - 63;
                result |= (b & 0x1f) << shift;
                shift += 5;
            } while (b >= 0x20);
            int dlng = ((result & 1) != 0 ? ~(result >> 1) : (result >> 1));
            lng += dlng;

            LatLng p = new LatLng((((double) lat / 1E5)),
                    (((double) lng / 1E5)));
            poly.add(p);
        }

        return poly;
    }
}

DirectionPointListener.java

import com.google.android.gms.maps.model.PolylineOptions;

public interface DirectionPointListener {
    public void onPath(PolylineOptions polyLine);
}

استخدام في النشاط أو شظية

LatLng source = new LatLng(xx.xxxx, yy.yyyy);
LatLng destination = new LatLng(xx.xxxx, yy.yyyy);

new GetPathFromLocation(source, destination, new DirectionPointListener() {
            @Override
            public void onPath(PolylineOptions polyLine) {
                yourMap.addPolyline(polyLine);
            }
        }).execute();

أرغب في عرض طريق القيادة بين موقعين في تطبيق Android الخاص بي. أريد رسم الطريق فقط أعلى قطاعات الطريق.

هناك العديد من الإجابات على تجاوز سعة المكدس نفسه ، وكلهم كانوا يستخدمون نفس الأسلوب. احصل على الاتجاهات من نقطة البداية إلى الوجهة باستخدام واجهة برمجة تطبيقات اتجاهات google ، وارسم خطًا متقاطعًا عبر النقاط التي تم إرجاعها. فيما يلي بعض الإجابات التي تستخدم هذه الطريقة.

https://stackoverflow.com/a/17007360/1015678

https://stackoverflow.com/a/40563930/1015678

ولكن ، المشكلة في الأسلوب أعلاه هي أنه عندما لا تكون الطرق مستقيمة ، فإن حبل الفجر لا يكون دائمًا في مقدمة الطرق ، لأن الاتجاهات API تُرجع فقط النقاط التي تحتاج إلى الانتقال من طريق إلى آخر (عند التقاطعات). لا يعطي تفاصيل النقطة في الانحناءات من نفس الطريق الطريق. لذلك ، عندما أستخدم الأسلوب أعلاه في منطقة بها الكثير من الانحناءات ، فإن المسار المرسوم دائمًا لا يكون دائمًا في قمة قطاعات الطريق.

لقد وجدت this الإجابة ، التي تفعل ما أحتاج إليه ، باستخدام جافا سكريبت API. في هذا الحل ، يتبع المسار المرسوم الطرق بشكل جيد ، على غرار تطبيق خرائط جوجل google. هل يعرف أحد ما إذا كان هذا ممكنًا في تطبيق Android؟

يمكن لتطبيق Android Maps في Google رسم مسار جيد من نقطة إلى أخرى ، مع الحفاظ على الطريق على الطرقات. هل يعرف أحد كيف تقوم خرائط Google بهذا؟ هل تستخدم أي واجهة برمجة تطبيقات أخرى غير مكشوفة بشكل عام؟


في الواقع ، يمكنك رسم مسار دقيق في Google Maps Android API باستخدام النتائج التي توفرها خدمة ويب الاتجاهات API. إذا قمت بقراءة الوثائق الخاصة بـ الاتجاهات API ، فسترى أن الاستجابة تحتوي على معلومات حول أرجل المسار وخطواته. تحتوي كل خطوة على حقل polyline المجالات موصوف في الوثائق كـ

يحتوي polyline على كائن نقطة مفردة يحتفظ بتمثيل متعدد الخطوط مشفر للخطوة. هذا الخط متعدد الطبقات هو مسار تقريبي (ناعم) للخطوة.

لذلك ، فإن الفكرة الأساسية لحل مشكلتك هي الحصول على استجابة من الاتجاهات API ، تنفيذ حلقة من خلال أرجل المسار والخطوات ، للحصول على كل خط متعدد الخطوط مشفر وفك تشفيره إلى قائمة الإحداثيات. بمجرد الانتهاء من ذلك ، سيكون لديك قائمة بجميع الإحداثيات التي تضاعف المسار ، وليس فقط بداية ونقطة نهاية كل خطوة.

للبساطة أوصي باستخدام مكتبة عملاء Java لخدمات Google Maps على الويب:

https://github.com/googlemaps/google-maps-services-java

باستخدام هذه المكتبة ، يمكنك تجنب تنفيذ مهامك غير المتزامنة ووظيفة فك التشفير للخطوط المتعددة. اقرأ الوثائق لمعرفة كيفية إضافة مكتبة العميل في مشروعك.

في Gradle يجب أن يكون شيء مشابه

compile 'com.google.maps:google-maps-services:(insert latest version)'
compile 'org.slf4j:slf4j-nop:1.7.25'

لقد قمت بإنشاء مثال بسيط لإظهار كيف يعمل. ألقِ نظرة على تعليقاتي في الكود

public class MapsActivity extends FragmentActivity implements OnMapReadyCallback {

    private GoogleMap mMap;
    private String TAG = "so47492459";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_maps);
        // Obtain the SupportMapFragment and get notified when the map is ready to be used.
        SupportMapFragment mapFragment = (SupportMapFragment) getSupportFragmentManager()
                .findFragmentById(R.id.map);
        mapFragment.getMapAsync(this);
    }

    @Override
    public void onMapReady(GoogleMap googleMap) {
        mMap = googleMap;

        LatLng barcelona = new LatLng(41.385064,2.173403);
        mMap.addMarker(new MarkerOptions().position(barcelona).title("Marker in Barcelona"));

        LatLng madrid = new LatLng(40.416775,-3.70379);
        mMap.addMarker(new MarkerOptions().position(madrid).title("Marker in Madrid"));

        LatLng zaragoza = new LatLng(41.648823,-0.889085);

        //Define list to get all latlng for the route
        List<LatLng> path = new ArrayList();


        //Execute Directions API request
        GeoApiContext context = new GeoApiContext.Builder()
                .apiKey("YOUR_API_KEY")
                .build();
        DirectionsApiRequest req = DirectionsApi.getDirections(context, "41.385064,2.173403", "40.416775,-3.70379");
        try {
            DirectionsResult res = req.await();

            //Loop through legs and steps to get encoded polylines of each step
            if (res.routes != null && res.routes.length > 0) {
                DirectionsRoute route = res.routes[0];

                if (route.legs !=null) {
                    for(int i=0; i<route.legs.length; i++) {
                        DirectionsLeg leg = route.legs[i];
                        if (leg.steps != null) {
                            for (int j=0; j<leg.steps.length;j++){
                                DirectionsStep step = leg.steps[j];
                                if (step.steps != null && step.steps.length >0) {
                                    for (int k=0; k<step.steps.length;k++){
                                        DirectionsStep step1 = step.steps[k];
                                        EncodedPolyline points1 = step1.polyline;
                                        if (points1 != null) {
                                            //Decode polyline and add points to list of route coordinates
                                            List<com.google.maps.model.LatLng> coords1 = points1.decodePath();
                                            for (com.google.maps.model.LatLng coord1 : coords1) {
                                                path.add(new LatLng(coord1.lat, coord1.lng));
                                            }
                                        }
                                    }
                                } else {
                                    EncodedPolyline points = step.polyline;
                                    if (points != null) {
                                        //Decode polyline and add points to list of route coordinates
                                        List<com.google.maps.model.LatLng> coords = points.decodePath();
                                        for (com.google.maps.model.LatLng coord : coords) {
                                            path.add(new LatLng(coord.lat, coord.lng));
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        } catch(Exception ex) {
            Log.e(TAG, ex.getLocalizedMessage());
        }

        //Draw the polyline
        if (path.size() > 0) {
            PolylineOptions opts = new PolylineOptions().addAll(path).color(Color.BLUE).width(5);
            mMap.addPolyline(opts);
        }

        mMap.getUiSettings().setZoomControlsEnabled(true);

        mMap.moveCamera(CameraUpdateFactory.newLatLngZoom(zaragoza, 6));
    }
}

يرجى ملاحظة أنه بالنسبة لخدمة الويب ، يجب عليك إنشاء مفتاح API منفصل ، فإن مفتاح API مع تقييد تطبيق Android لن يعمل مع خدمة الويب.

تظهر نتيجة مثالي في لقطة الشاشة

يمكنك أيضًا تنزيل مشروع نموذج كامل من

https://github.com/xomena-so/so47492459

لا تنس استبدال مفتاح API الخاص بك.

آمل أن يساعد هذا!





google-maps-android-api-2