В Google Maps Roads API собирается до 100 GPS-точек вдоль маршрута следования и возвращается сходный набор данных с точками, привязанными к наиболее вероятным дорогам, по которым проехал автомобиль. Дополнительно можно запросить интерполяцию точек для получения пути, максимально соответствующего геометрии дороги.
Запросы
Запрос на привязку к дороге отправляется по протоколу HTTPS и выглядит следующим образом:
https://roads.googleapis.com/v1/snapToRoads?parameters&key=YOUR_API_KEY
Использование параметров
Обязательные параметры
-
path– путь, который требуется привязать к дорогам. Параметрpathдопускает использование списка, состоящего из парных значений координат широты/долготы. Значения широты и долготы должны быть разделены запятыми. Отдельные пары координат должны разделяться вертикальной чертой: "|". Например:path=60.170880,24.942795|60.170879,24.942796|60.170877,24.942796.Примечание. Алгоритм привязки наиболее эффективно работает с близко расположенными точками. Если в ходе привязки возникают проблемы, попробуйте создать пути с более близко расположенными точками. Для наилучшего качества привязки к дороге нужно постараться указать пути, на которых последовательные пары точек находятся на расстоянии не более 300 м друг от друга. Это также поможет в обработке любых изолированных длинных скачков между последовательными точками из-за потери сигнала GPS или помех.
-
key– ключ API вашего приложения. Приложение должно выполнять автоматическую аутентификацию при каждой отправке запроса в Google Maps Roads API, указывая ключ API в каждом запросе. См. дополнительную информацию о получении ключа.
Дополнительные параметры
interpolate– интерполяция пути с целью включения всех точек, образующих полную геометрию дороги. Если для параметра установлено значениеtrue, будут возвращены дополнительные интерполированные точки для получения пути, который точно соответствует геометрии дороги, даже за поворотами и в туннелях. Интерполированные пути, скорее всего, будут содержать больше точек, чем исходный путь. По умолчанию установлено значениеfalse.
Ответы
Для каждого допустимого запроса Google Maps Roads API возвращает данные в формате, указанном в URL-адресе запроса. В ответе службы привязки к дорогам могут содержаться следующие элементы.
snappedPoints– массив привязанных точек. Каждая точка состоит из следующих полей.location– содержит значениеlatitudeиlongitude.originalIndex– целое число, обозначающее соответствующее значение в исходном запросе. Каждое значение в запросе должно быть сопоставлено с привязанным значением в ответе. Однако при использовании режимаinterpolate=trueответ может содержать больше координат, чем указано в запросе. Интерполированные значения не будут иметьoriginalIndex. Данные значения индексируются от0, поэтому точка сoriginalIndexравным4будет привязана к 5-му значению координат ширины/долготы, переданному в параметрpath.placeId– уникальный идентификатор места. Все идентификаторы мест, возвращенные Google Maps Roads API, будут соответствовать участкам дороги. [Идентификаторы мест] можно использовать и с другими API-интерфейсами Google, включая Google Places API и Google Maps JavaScript API. Например, чтобы получить названия дорог для привязанных точек, возвращенных Google Maps Roads API, следует передатьplaceIdв Google Places API или Google Maps Geocoding API. В Google Maps Roads API можно передаватьplaceIdв запросе для определения ограничений скорости на указанном участке дороги.
Пример запроса
В следующем запросе будет выполнена привязка указанных точек к геометрии дороги. Этот
набор данных связан с кольцевой дорогой; установка interpolate=true
обеспечивает точное соответствие полученной геометрии с кривизной дороги. При использовании
interpolate=false привязанный путь также будет соответствовать дороге, но результирующая ломаная
линия не будет такой плавной.
Запрос
https://roads.googleapis.com/v1/snapToRoads?path=-35.27801,149.12958|-35.28032,149.12907|-35.28099,149.12929|-35.28144,149.12984|-35.28194,149.13003|-35.28282,149.12956|-35.28302,149.12881|-35.28473,149.12836&interpolate=true&key=YOUR_API_KEY
Ответ
{
"snappedPoints": [
{
"location": {
"latitude": -35.2784167,
"longitude": 149.1294692
},
"originalIndex": 0,
"placeId": "ChIJoR7CemhNFmsRQB9QbW7qABM"
},
{
"location": {
"latitude": -35.280321693840129,
"longitude": 149.12908274880189
},
"originalIndex": 1,
"placeId": "ChIJiy6YT2hNFmsRkHZAbW7qABM"
},
{
"location": {
"latitude": -35.2803415,
"longitude": 149.1290788
},
"placeId": "ChIJiy6YT2hNFmsRkHZAbW7qABM"
},
{
"location": {
"latitude": -35.2803415,
"longitude": 149.1290788
},
"placeId": "ChIJI2FUTGhNFmsRcHpAbW7qABM"
},
{
"location": {
"latitude": -35.280451499999991,
"longitude": 149.1290784
},
"placeId": "ChIJI2FUTGhNFmsRcHpAbW7qABM"
},
{
"location": {
"latitude": -35.2805167,
"longitude": 149.1290879
},
"placeId": "ChIJI2FUTGhNFmsRcHpAbW7qABM"
},
{
"location": {
"latitude": -35.2805901,
"longitude": 149.1291104
},
"placeId": "ChIJI2FUTGhNFmsRcHpAbW7qABM"
},
{
"location": {
"latitude": -35.2805901,
"longitude": 149.1291104
},
"placeId": "ChIJW9R7smlNFmsRMH1AbW7qABM"
},
{
"location": {
"latitude": -35.280734599999995,
"longitude": 149.1291517
},
"placeId": "ChIJW9R7smlNFmsRMH1AbW7qABM"
},
{
"location": {
"latitude": -35.2807852,
"longitude": 149.1291716
},
"placeId": "ChIJW9R7smlNFmsRMH1AbW7qABM"
},
{
"location": {
"latitude": -35.2808499,
"longitude": 149.1292099
},
"placeId": "ChIJW9R7smlNFmsRMH1AbW7qABM"
},
{
"location": {
"latitude": -35.280923099999995,
"longitude": 149.129278
},
"placeId": "ChIJW9R7smlNFmsRMH1AbW7qABM"
},
{
"location": {
"latitude": -35.280960897210818,
"longitude": 149.1293250692261
},
"originalIndex": 2,
"placeId": "ChIJW9R7smlNFmsRMH1AbW7qABM"
},
... results truncated ...
{
"location": {
"latitude": -35.284728724835304,
"longitude": 149.12835061713685
},
"originalIndex": 7,
"placeId": "ChIJW5JAZmpNFmsRegG0-Jc80sM"
}
]
}
Демонстрация
- Получение ключа API.
- Скопируйте приведенный ниже код и замените ключ API собственным ключом. Демонстрация будет недоступна без ключа API.
- Загрузите демонстрацию в браузер.
Отобразится карта г. Сидней, Австралия. - Нажмите на карту для создания пути транспортного средства. Обратите внимание, что если точки расположены слишком далеко друг от друга, привязка может быть выполнена неверно.
- Дважды щелкните для привязки пути к дороге и выполнения кодирования ломаной линии цветом
с учетом установленных ограничений скорости.
- фиолетовый <= 40 км/ч
- синий = 40-50 км/ч
- зеленый = 50-60 км/ч
- желтый = 70-80 км/ч
- оранжевый = 90-100 км/ч
- красный = >100 км/ч
Примечание. Алгоритм привязки наиболее эффективно работает с близкорасположенными точками. Если в ходе привязки возникают проблемы, попробуйте создать пути с более близко расположенными точками. Например, для повышения качества привязки к дороге в городе точки должны отстоять на несколько кварталов друг от друга.
Просмотреть пример в полноэкранном режиме.
var apiKey = 'YOUR_API_KEY';
var map;
var drawingManager;
var placeIdArray = [];
var polylines = [];
var snappedCoordinates = [];
function initialize() {
var mapOptions = {
zoom: 17,
center: {lat: -33.8667, lng: 151.1955}
};
map = new google.maps.Map(document.getElementById('map'), mapOptions);
// 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'));
var autocomplete = new google.maps.places.Autocomplete(
document.getElementById('autoc'));
autocomplete.bindTo('bounds', map);
autocomplete.addListener('place_changed', function() {
var place = autocomplete.getPlace();
if (place.geometry.viewport) {
map.fitBounds(place.geometry.viewport);
} else {
map.setCenter(place.geometry.location);
map.setZoom(17);
}
});
// 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();
return false;
});
}
// 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 service.
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);
snappedCoordinates.push(latlng);
placeIdArray.push(data.snappedPoints[i].placeId);
}
}
// 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);
}
}
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';
}
$(window).load(initialize);
<!DOCTYPE html> <html>
<head>
<meta name="viewport" content="initial-scale=1.0, user-scalable=no">
<meta charset="utf-8">
<title>Демонстрация Roads API</title>
<style>
html, body, #map {
height: 100%;
margin: 0px;
padding: 0px
}
#panel {
position: absolute;
top: 5px;
left: 50%;
margin-left: -180px;
z-index: 5;
background-color: #fff;
padding: 5px;
border: 1px solid #999;
}
#bar {
width: 240px;
background-color: rgba(255, 255, 255, 0.75);
margin: 8px;
padding: 4px;
border-radius: 4px;
}
#autoc {
width: 100%;
box-sizing: border-box;
}
</style>
<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>
var apiKey = 'YOUR_API_KEY';
var map;
var drawingManager;
var placeIdArray = [];
var polylines = [];
var snappedCoordinates = [];
function initialize() {
var mapOptions = {
zoom: 17,
center: {lat: -33.8667, lng: 151.1955}
};
map = new google.maps.Map(document.getElementById('map'), mapOptions);
// 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'));
var autocomplete = new google.maps.places.Autocomplete(
document.getElementById('autoc'));
autocomplete.bindTo('bounds', map);
autocomplete.addListener('place_changed', function() {
var place = autocomplete.getPlace();
if (place.geometry.viewport) {
map.fitBounds(place.geometry.viewport);
} else {
map.setCenter(place.geometry.location);
map.setZoom(17);
}
});
// 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();
return false;
});
}
// 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 service.
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);
snappedCoordinates.push(latlng);
placeIdArray.push(data.snappedPoints[i].placeId);
}
}
// 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);
}
}
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';
}
$(window).load(initialize);
</script>
</head>
<body>
<div id="map"></div>
<div id="bar">
<p class="auto"><input type="text" id="autoc"/></p>
<p><a id="clear" href="#">Нажмите здесь</a>, чтобы очистить карту.</p>
</div>
</body>
</html>
