Google Maps Roads API 返回重复的坐标和 placeIds

Posted

技术标签:

【中文标题】Google Maps Roads API 返回重复的坐标和 placeIds【英文标题】:Google Maps Roads API returns duplicate coordinates and placeIds 【发布时间】:2015-11-12 15:59:21 【问题描述】:

我正在实施谷歌地图道路 API 来获取我点击道路的坐标。但它返回的坐标和位置标识超出了预期。假设我使用方向 API 设置从地点 A 到地点 B 的方向,然后我单击道路上的一些点(比如说 10 个点)来绘制路线。作为响应,Roads API 返回了 10 多个 placeId 和坐标,而我只需要 10 个。这是代码。

<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
<script src="https://maps.googleapis.com/maps/api/js?libraries=drawing,places"></script>

        <script>

            //GOOGLE_API_KEY
           var apiKey = '';

            if(!apiKey)
                    alert("Please provide API Key");

            var map;
            var elevator;
            var directionsDisplay;
            var directionsService;
            var placeDetailsService;

            var drawingManager;
            var placeIdArray = [];
            var polylines = [];
            var snappedCoordinates = [];

            var initialLocation;
            var siberia = new google.maps.LatLng(60, 105);
            var newyork = new google.maps.LatLng(40.69847032728747, -73.9514422416687);
            var browserSupportFlag = new Boolean();

            function initialize()
            
                document.getElementById("save").style.display="none";
                var mapOptions = 
                    zoom: 17,
                    center: lat: 40.69847032728747, lng: -73.9514422416687
                ;


                directionsService = new google.maps.DirectionsService();
                var polylineOptionsActual = new google.maps.Polyline(
                    strokeColor: '#FF0000',
                    strokeOpacity: 0.6,
                    strokeWeight: 2
                );
                directionsDisplay = new google.maps.DirectionsRenderer(polylineOptions: polylineOptionsActual);
                map = new google.maps.Map(document.getElementById('map'), mapOptions);
                directionsDisplay.setMap(map);

                //Place Details 
                placeDetailsService= new google.maps.places.PlacesService(map);
                // Create an ElevationService
                elevator = new google.maps.ElevationService();

                // Adds a Places search box. Searching for a place will center the map on that location

                map.controls[google.maps.ControlPosition.RIGHT_TOP].push(
                        document.getElementById('bar'));

                //Start Location Searchbox
                var autocomplete = new google.maps.places.Autocomplete(document.getElementById('autocStart'));
                autocomplete.bindTo('bounds', map);
                autocomplete.addListener('place_changed', function () 
                    var placeStart = autocomplete.getPlace();
                    //alert(placeStart.place_id);

                    placeDetailsService.getDetails(
                      placeId: placeStart.place_id
                    , function(place, status) 
                      if (status === google.maps.places.PlacesServiceStatus.OK) 

                          console.log(place.geometry.location);
                        //alert("Start Location: "+place.geometry.location.G);
                        document.getElementById("startPlaceLat").value=place.geometry.location.G;
                        document.getElementById("startPlaceLng").value=place.geometry.location.K;

                      
                    );


                );

                //End Location Searchbox
                var autocomplete1 = new google.maps.places.Autocomplete(document.getElementById('autocEnd'));
                autocomplete1.bindTo('bounds', map);
                autocomplete1.addListener('place_changed', function () 

                    var placeEnd = autocomplete1.getPlace();
                    //alert(placeEnd.place_id);
                    placeDetailsService.getDetails(
                      placeId: placeEnd.place_id
                    , function(place, status) 
                      if (status === google.maps.places.PlacesServiceStatus.OK) 
                          console.log(place.geometry.location);
                        //alert("End Location: "+place.geometry.location.G);
                        document.getElementById("endPlaceLat").value=place.geometry.location.G;
                        document.getElementById("endPlaceLng").value=place.geometry.location.K;

                      
                    );

                );


                // Enables the polyline drawing control. Click on the map to start drawing a
                // polyline. Each click will add a new vertice. Double-click to stop drawing.
                drawingManager = new google.maps.drawing.DrawingManager(
                    drawingMode: google.maps.drawing.OverlayType.POLYLINE,
                    drawingControl: true,
                    drawingControlOptions: 
                        position: google.maps.ControlPosition.TOP_CENTER,
                        drawingModes: [
                            google.maps.drawing.OverlayType.POLYLINE
                        ]
                    ,
                    polylineOptions: 
                        strokeColor: '#696969',
                        strokeWeight: 2
                    
                );
                drawingManager.setMap(map);

                // Snap-to-road when the polyline is completed.
                drawingManager.addListener('polylinecomplete', function (poly) 
                    var path = poly.getPath();
                    polylines.push(poly);
                    placeIdArray = [];
                    runSnapToRoad(path);
                );

                // Clear button. Click to remove all polylines.
                $('#clear').click(function (ev) 
                    for (var i = 0; i < polylines.length; ++i) 
                        polylines[i].setMap(null);
                    
                    polylines = [];
                    ev.preventDefault();
                    document.getElementById("snappedCoordinatesArray").value = "";
                    document.getElementById("snappedPaceIdArray").value = "";
                    document.getElementById("altitudeArray").value = "";
                    document.getElementById("dataDisplay").style.display = "none";
                    document.getElementById("autocStart").value = "";
                    document.getElementById("autocEnd").value = "";
                    document.getElementById("startPlaceLat").value = "";
                    document.getElementById("startPlaceLng").value = "";
                    document.getElementById("endPlaceLat").value = "";
                    document.getElementById("endPlaceLng").value = "";
                    document.getElementById("save").style.display="none";
                    directionsDisplay.set('directions', null);
                    return false;
                );

                _init();
            

            // Snap a user-created polyline to roads and draw the snapped path
            function runSnapToRoad(path) 
                var pathValues = [];
                for (var i = 0; i < path.getLength(); i++) 
                    pathValues.push(path.getAt(i).toUrlValue());
                

                $.get('https://roads.googleapis.com/v1/snapToRoads', 
                    interpolate: true,
                    key: apiKey,
                    path: pathValues.join('|')
                , function (data) 
                    processSnapToRoadResponse(data);
                    drawSnappedPolyline();
                    //getAndDrawSpeedLimits();
                );
            

            // Store snapped polyline returned by the snap-to-road method.
            function processSnapToRoadResponse(data)
            
                snappedCoordinates = [];
                placeIdArray = [];


                for (var i = 0; i < data.snappedPoints.length; i++)
                
                    var latlng = new google.maps.LatLng(
                            data.snappedPoints[i].location.latitude,
                            data.snappedPoints[i].location.longitude);
                    //getElevation(latlng);
                    snappedCoordinates.push(latlng);
                    placeIdArray.push(data.snappedPoints[i].placeId);

                

                //get Altitude in meters
                getElevation(snappedCoordinates);
                document.getElementById("snappedCoordinatesArray").value = snappedCoordinates;
                document.getElementById("snappedPaceIdArray").value = placeIdArray;


            

            // Draws the snapped polyline (after processing snap-to-road response).
            function drawSnappedPolyline() 
                var snappedPolyline = new google.maps.Polyline(
                    path: snappedCoordinates,
                    strokeColor: 'black',
                    strokeWeight: 3
                );

                snappedPolyline.setMap(map);
                polylines.push(snappedPolyline);
            

            // Gets speed limits (for 100 segments at a time) and draws a polyline
            // color-coded by speed limit. Must be called after processing snap-to-road
            // response.
            function getAndDrawSpeedLimits() 
                for (var i = 0; i <= placeIdArray.length / 100; i++) 
                    // Ensure that no query exceeds the max 100 placeID limit.
                    var start = i * 100;
                    var end = Math.min((i + 1) * 100 - 1, placeIdArray.length);

                    drawSpeedLimits(start, end);
                
            

            // Gets speed limits for a 100-segment path and draws a polyline color-coded by
            // speed limit. Must be called after processing snap-to-road response.
            function drawSpeedLimits(start, end) 
                var placeIdQuery = '';
                for (var i = start; i < end; i++) 
                    placeIdQuery += '&placeId=' + placeIdArray[i];
                

                $.get('https://roads.googleapis.com/v1/speedLimits',
                        'key=' + apiKey + placeIdQuery,
                        function (speedData) 
                            processSpeedLimitResponse(speedData, start);
                        
                );
            

            // Draw a polyline segment (up to 100 road segments) color-coded by speed limit.
            function processSpeedLimitResponse(speedData, start) 
                var end = start + speedData.speedLimits.length;
                for (var i = 0; i < speedData.speedLimits.length - 1; i++) 
                    var speedLimit = speedData.speedLimits[i].speedLimit;
                    var color = getColorForSpeed(speedLimit);

                    // Take two points for a single-segment polyline.
                    var coords = snappedCoordinates.slice(start + i, start + i + 2);

                    var snappedPolyline = new google.maps.Polyline(
                        path: coords,
                        strokeColor: color,
                        strokeWeight: 6
                    );
                    snappedPolyline.setMap(map);
                    polylines.push(snappedPolyline);


                    //passDataToObjC();

                
            

            //Color of the roads depends upon speed limit
            function getColorForSpeed(speed_kph) 
                if (speed_kph <= 40) 
                    return 'purple';
                
                if (speed_kph <= 50) 
                    return 'blue';
                
                if (speed_kph <= 60) 
                    return 'green';
                
                if (speed_kph <= 80) 
                    return 'yellow';
                
                if (speed_kph <= 100) 
                    return 'orange';
                
                return 'red';
            

            //Call Elevation API to get Altitude
            function getElevation(snappedCoordinatesArr)
            
                var locations = [];

                // Retrieve the latlng and push it on the array
                for (var i = 0; i < snappedCoordinatesArr.length; i++)
                
                    locations.push(snappedCoordinatesArr[i]);
                



                // Create a LocationElevationRequest object using the array's one value
                var positionalRequest =
                        
                            'locations': locations
                        
                //alert(positionalRequest);

                // Initiate the location request
                elevator.getElevationForLocations(positionalRequest, function (results, status)
                
                    if (status == google.maps.ElevationStatus.OK)
                    

                        // Retrieve the first result
                        if (results)
                        
                            var altitudeArr = [];

                            for (var j = 0; j < results.length; j++)
                            
                                altitudeArr.push(results[j].elevation);

                            
                            document.getElementById("altitudeArray").value = altitudeArr;
                            document.getElementById("dataDisplay").style.display = "block";
                            document.getElementById("save").style.display="block";
                            //alert(altitudeArr);
                        
                        else
                        
                            alert('No results found');
                        
                    
                    else
                    
                        alert('Elevation service failed due to: ' + status);
                    
                );
            

            //Call Directions API to draw route
            function calcRoute()
            
                var start = document.getElementById("autocStart").value;
                var end = document.getElementById('autocEnd').value;
                var selectedMode = document.getElementById("travelType").value;

                //alert(start);
                var request = 
                    origin: start,
                    destination: end,
                    travelMode: google.maps.TravelMode[selectedMode]
                ;
                directionsService.route(request, function (response, status) 
                    if (status == google.maps.DirectionsStatus.OK) 
                        directionsDisplay.setDirections(response);

                    
                );
            

            //Save Details into Database
            function _init() 
            

                document.getElementById("geodata-form").onsubmit = function (e) 

                    e.preventDefault();

                    var f = e.target,
                            formData = new FormData(f),
                            xhr = new XMLHttpRequest();

                    xhr.onreadystatechange = function () 
                        if (xhr.readyState == 4) 
                            if (xhr.responseText) 
                                alert('Geodata successfully saved.');
                                document.getElementById("save").style.display="none";
                                // location.reload();
                             else 
                                alert('Error occured !');
                            
                        
                    

                    xhr.open("POST", f.action);
                    xhr.send(formData);
                
            

            $(window).load(initialize);

        </script>

我创建了一个 JSfiddle here。只需提供一个 google API 密钥,然后告诉我这段代码有什么问题吗?

【问题讨论】:

【参考方案1】:

您正在使用 interpolate: true 调用 Roads API。根据the documentation 的说法,这会导致它按照您所说的方式行事。

from the documentation:

interpolate - 是否插入路径以包括形成完整道路几何图形的所有点。当为 true 时,还将返回额外的插值点,从而形成一条平滑地遵循道路几何形状的路径,即使在拐角处和通过隧道也是如此。 插值路径很可能包含比原始路径更多的点。默认为 false。

【讨论】:

以上是关于Google Maps Roads API 返回重复的坐标和 placeIds的主要内容,如果未能解决你的问题,请参考以下文章

Google Maps Roads API:让“快速上路”更加宽容

如何使用带有 Google Maps Roads API 的坐标列表计算距离

有没有一种好方法可以最大限度地减少 Google Maps Roads API 的负载?

Google Roads API 的 Nearest Roads 函数返回的点数多于给定点,包含重复项

Google Maps API - 意外重定向

如何在 Google Maps API 上强制重绘?