Filtering Searches by Location
- explicit – included in the request query parameters
Examples of explicit location contexts include providing a specific position, circle or bounding box based on user input by specifying a value for the query parameters
at
orin
. For more information on the available query parameters, see the API Reference. - implicit – included in the request header
Examples of implicit location contexts include providing the current location from a device GPS unit or the map view displayed in the request header in the headers
Geolocation
andX‑Map‑Viewport
. For more information on the available location context headers, see HTTP Request Headers.
All Places (Search) API entrypoints require at least one location context. We strongly recommend that you should always provide as much implicit location context information as possible and explicit location context information where relevant. For more information on best practices, see Best Practice.
Explicit Location Context
When the user explicitly indicates a location to your application, for example by clicking on a map position to trigger a discovery query at that location, your application should provide an explicit location context to the Places (Search) API using one of the following query string parameters:
Name | Availability | Format | Description |
---|---|---|---|
at | Always | Position | Specifies an explicit position as a point |
in | Selected request types | Circle or Bounding Box | Specifies an explicit area |
Implicit Location Context
Your application will often have location information available to it that is not explicitly provided by the user, such as the user's geolocation or a map area currently being displayed to the user. Sending at least one type of implicit location context information is required in the absence of an explicit location context, and you are strongly encouraged to send implicit location context information to ensure you get optimal results even when providing an explicit location.
Applications should always send the following implicit location context headers when the values are known:
Name | Format | Description |
---|---|---|
Geolocation | Position | Specifies the physical position of a user |
X‑Map‑Viewport | Bounding Box | Specifies the map area currently displayed to the user |
Best Practice
To get the best results, applications should always send implicit location context information when available, and only send an explicit location context parameter when the user has explicitly indicated (selected) a specific location. Therefore, applications should always send the X-Map-Viewport
header when displaying a map to user, and the Geolocation
header when the user's position is known. This is sufficient in many use cases, and an explicit location context (via a query string parameter) is often not required.
For example, if the application always displays a map to the user and provides a textbox for free-text search that makes use of the Places (Search) API search entrypoint
. When the user performs a search, the application should supply the X-Map-Viewport
header. If the user's position is also known, the application should include the Geolocation
header as well. In this scenario, the user does not indicate an explicit location related to the search (other than possibly positioning the map viewport), so there is no need to specify an explicit location context.
If, however, the application additionally allows the user to click on the map and find out what is at that location using the here entrypoint
and the user does select a location in this way, the application should provide that location as an explicit location context in the at
query string parameter. The application should still send the implicit context information via the X-Map-Viewport
header (and the Geolocation
if the user's location is available), but the explicit location takes precedence in determining the primary location for the request.
Distance Calculation
Places in results have a distance field indicating the distance from the user's location or from an explicit reference point to the place. An explicit location context in the request provides the location from which the distance is calculated. In the absence of an explicit location context, the position from the Geolocation header is used. If the only available location context is from the X-Map-Viewport, no distance calculation occurs and the distance is not set.
Position Format
The Geolocation header (implicit context) and at
parameter (explicit context) specify a position as a 'geo' URI. The position is given as comma-separated values for latitude and longitude (in the WGS 84 coordinate system), and optionally altitude (in meters above sea level), and a semicolon-separated list of position parameters.
Applications should specify the source for the position by passing one of the following values for the cgen
parameter:
-
map
for points on a map, for example,geo:53.12,10.15;cgen=map
. -
gps
for values from a GPS device, for example,geo:53.12,10.15;cgen=gps
. -
sgps
for shifted GPS coordinates from a device fulfilling the legal requirements in China, for example,geo:53.12,10.15;cgen=sgps
.
Uncertainty in the geo-coordinates should be given in the u parameter as the uncertainty in meters, for example, geo:53.12,10.15;cgen=gps;u=100
. This might be the uncertainty of a GPS coordinate fix, or uncertainty resulting from the resolution of a map. An absolutely accurate position should be specified with u=0
. If the u parameter is not provided, the uncertainty is unspecified rather than 0. For example, 39.91,116.40;cgen=gps;u=16
specifies a position derived from a GPS device with an uncertainty of 16 meters.
Circle Format
A circular area can be specified as a location context by providing a position (as described in Position) and an additional radius. The radius is given by setting the r parameter to the radius in meters. For example,53.12,10.15;r=10500
specifies an area with a 10.5km radius.
Bounding Box Format
A bounding box can be used to specify a geographic area as a location context. The rectangle spanning the area is specified in the WGS 84 coordinate system as four comma-separated values in the following order: west longitude, south latitude, east longitude, north latitude. For example, 13.125,52.362,13.661,52.693
specifies a bounding box for Berlin.
For maps applications using HERE map tiles, the zoom level should be sent as a fifth parameter. For example, if the zoom level is 4.3, the above example would become 13.125,52.362,13.661,52.693,4.3
.
HERE polyline encoding
compressedRoute
parameter. The polyline encoding is a compressed representation of a list of coordinate pairs. It achieves that by - reducing precision to 5 decimal places
- encoding only the offset from the previous point
- using variable length for each coordinate delta
- using 64 URL-safe characters to display the result
{ latitude: 52.0, longitude: 13.1 }
, iterate over this sequence and append the encoded latitude delta and then the longitude delta to the end result. For the first coordinate you have to encode the absolute value, for every other coordinate subtract the previous values from the current one to get the delta. Also, it may be desired to specify whether a route segment is located in a city or on a highway, this can be done by marking the starting point of the segment with .C
or .H
respectively. This will modify the search distance and possibly algorithm for every segment thereafter. The first segment affected is the one starting with the point preceding .C
or .H
. This is reflected by the following Javascript snippet:
function hereEncodePolyline(positions) {
var lastLat = 0, lastLon = 0;
var result = [];
var width = "D"
var newWidth;
for (var i = 0; i < positions.length; ++i) {
var position = positions[i];
if (i > 0) {
if (isCityRoad(lastLat, lastLon, position.latitude, position.longitude)) {
newWidth = "C";
} else if (isHighway(lastLat, lastLon, position.latitude, position.longitude)) {
newWidth = "H";
} else {
newWidth = "D"
}
if (newWidth != width) {
result.push("." + newWidth);
width = newWidth;
}
}
// it is an actual route point
result.push(hereEncodeFloat(position.latitude - lastLat));
result.push(hereEncodeFloat(position.longitude - lastLon));
lastLat = position.latitude;
lastLon = position.longitude;
}
return result.join('');
}
- Multiply with 1e5 and round to the nearest integer
- Shift left to make room on the lowest bit
- Invert negative numbers
- Divide the number into 5bit chunks and encode them starting from least significant part to most significant
- As it is a variable-length encoding, add
0x20
to signal that the another chuck follows
function hereEncodeFloat(value) {
var ENCODING_CHARS = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_';
var result = [];
// convert to fixed point
var fixedPoint = Math.round(value * 100000);
// make room on the lowest bit
fixedPoint = fixedPoint << 1;
// flip bits of negative numbers and ensure that the last bit is set
// (should actually always be the case, but for readability it is ok to do it explicitly)
if (fixedPoint > 0) {
fixedPoint = ~(fixedPoint) | 0x01
}
// var-length encode the number in chunks of 5 bits starting with the least significant
// to the most significant
while (fixedPoint > 0x1F) {
result.push(ENCODING_CHARS[(fixedPoint & 0x1F) | 0x20]);
fixedPoint >>= 5;
}
result.push(ENCODING_CHARS[fixedPoint]);
return result.join('');
}
input1 = "[50.1022829,8.6982122|50.1020076,8.6956695|50.1006313,8.6914960|50.0987800,8.6875156]"
encoded1 = "oz5xJ67i1B3B7PzIhaxL7Y"
input2 = "[52.5199356,13.3866272|52.5100899,13.2816896|52.4351807,13.1935196|" +
"52.4107285,13.1964502|52.38871,13.1557798|52.3727798,13.1491003|" +
"52.3737488,13.1154604|52.3875198,13.0872202|52.4029388,13.0706196|52.4105797,13.0755529]"
encoded2 = "05xgKuy2xCx9B7vUl0OhnR54EqSzpEl-HxjD3pBiGnyGi2CvwFsgD3nD4vB6e"
inputWithWidths = "[52.5160,13.3771|CW|52.5111,13.3712|52.5355,13.3634|52.5400,13.3704|" +
"52.56 26,13.3307|52.5665,13.3076|52.6007,13.2806|HW|52.6135,13.2484|52.6303,13.2406|" +
"52.6651,13.2410|52.7074,13.1926|52.7045,13.0661|52.7191,12.9621|52.76 36,12.8263|" +
"52.7861,12.8000|52.8335,12.7919|52.9002,12.7451|52.9708,12.6311|53.0526,12.5392|" +
"53.0867,12.5169|53.1146,12.4687|53.1334,12.4644|53.1415,12.4225|53.1666,12.3722|" +
"53.1785,12.3050|53.2570,12.1618|53.2893,12.0618|53.3000,11.9373|53.3316,11.8724|" +
"53.3463,11.8190|53.3669,11.7328|53.3725,11.6427|53.4154,11.5505|53.4309,11.4906|" +
"53.4342,11.4000|53.4655,11.3370|53.4873,11.2631|53.4860,11.2011|53.5110,10.9647|" +
"53.5128,10.8414|53.5495,10.6892|53.5692,10.5155|53.5596,10.4259|53.5682,10.2999|" +
"53.5571,10.2020|CW|53.5672,10.1279|53.5534,9.9924];w=1000"
encodedWithWidth = "ghxgK820xC.Cze7kBw4E3wBkc4rBotEj4HsYrwE41G3oF.H" +
"gwCnpGgpD3wBw5GwCsoIvuJjSz2Yo7C_pUk2I3wa0sErkFooJzyB8gNvkJo5NvoWo_Pr-Rk1GrrEsuFntJw1D7" +
"a0yB7lI88Er6JsqC_jN0qP_-b8pG_wT8iCjqYwlGz1M87C3tK4gE36QgjBjzRksIngS8gDr2L0Un2R0jG3pM" +
"ooE7tOjIvjMo8EvluBoLziYslHn3dk7Dz9hB_7B_vR41BvzYrlC7jT.Ck_BjvOn2C7ua;w=1000"
We also recommend to use a lossy compression on client side to e.g. combine segments into straight line if the deviation to the route geometry is small. There are several open source implementations available that can be used as a template for this.