Hands On

How to Get the Shape of an Area Using the HERE Geocoder API

By Richard Süselbeck | 17 May 2019

We recently walked you through the HERE Geocoder API and how it can be used to discover interesting details about any given place, for example the local time or which side of the road people drive on. However, there are even more neat features hidden in the API. Today we will be looking at the IncludeShapeLevel feature, which returns the shape of an area such as a district, city or even a whole country! This can be very useful for a variety of use cases, such as visualizing postal codes or generating geofences.

First, let’s fire up the Geocoder API! As we learned last time, we can customize the response of the API using special parameters. This allows us to request additional information about a place. Last time we asked for data like the local time and currency, this time are going to ask for the shape of the areas around our location.

Once again, we are using the parameter additionaldata to request, well, additional data.


https://reverse.geocoder.api.here.com/6.2/reversegeocode.json
?app_id={{app_id}}
&app_code={{app_code}}
&prox=52.52087,13.40891
&mode=retrieveAddresses
&additionaldata=IncludeShapeLevel,district
&maxresults=1

As you can see we are providing a value pair of IncludeShapeLevel,<level> for this parameter. Valid choices for <level> are country, state, county, city, district, postalCode and default. In the example above, we’ve reverse geocoded a latitude and longitude (the location of the TV tower in Berlin) and requested the shape of the city district around it (called “Mitte”).

Similarly, we could forward geocode a postal code.


https://geocoder.api.here.com/6.2/geocode.json
?app_id={{app_id}}
&app_code={{app_code}}
&searchtext=10115+DE
&additionaldata=IncludeShapeLevel,postalCode

Note that we’ve used default as the shape level. When using default, the returned shape will correspond to the match level of the geocoder response. Since we’ve only provided a postal and country information, the best match the Geocoder will be able to provide is at the postal code level. This means that the returned shape will be that of the postal code area. Note that you can only request one shape per Geocoder request.

In both cases, our response will include a Shape element, which contains the requested outline in WKT (well-known text) format. Depending on whether the requested area is contiguous or not, this will either be a POLYGON or MULTIPOLYGON geometry.


"Shape": {
   "_type": "WKTShapeType",
   "Value": "POLYGON ((13.36566 52.53586, 13.36575 52.53579, 13.36582 52.53574, 13.36599 52.53564, ..., 13.36566 52.53586))"
}

Like last time, let’s use the HERE JavaScript API to visualize this information. We want to build a simple web map which highlights the shape of a country when you click on it. Below we will look at the most relevant elements of the code, but you can always explore the complete project in GitHub. The end result should look something like this.

 

geocoder-shapes-screenshot1

We can grab most of the elements for this app from the examples section of our JavaScript documentation. First, we’ll need to set up a basic interactive map. Next, we need to be able to calculate a geographic location from a mouse click. We also need to display a polygon on the map.

The Geocoder call is where it gets interesting. The JavaScript API provides convenient wrappers for the various HERE REST APIs, which means we can simply create a GeocodingService object, pass it the parameters from our REST call above and then initiate a reverse geocode. We also need to provide OnSuccess and OnError callback functions to handle the response. First, let's look at how to initiate the geocoding request.


function reverseGeocode(platform) {
    // set up Geocoder API    
    var geocoder = platform.getGeocodingService();  
    var prox = coord.lat + ',' + coord.lng;
    
    var reverseGeocodingParameters = {
        prox: prox,
        mode: 'retrieveAddresses',
        maxresults: '1',            
        additionaldata: 'IncludeShapeLevel,country'      
    };

    geocoder.reverseGeocode(
        reverseGeocodingParameters,
        onSuccess,
        onError
    );
}

We can then parse the results in the OnSuccess function. Since the JavaScript API uses its own internal format for Geometries, we need to convert our WKT data in this format. Fortunately, there’s a convenient helper function in H.util.wkt available to do this.

As mentioned above, the shape returned might either be a single polygon (in case of a contiguous area) or multiple polygons. While postal codes will usually be contiguous areas, most countries will not. Even a single island or exclave will result in a MULTIPOLYGON response. I mean, just check out Finland.

geocoder-shapes-screenshot2

After using H.util.wkt.toGeometry() we can check for the type of Geometry returned and handle it appropriately. In either case we will create at least one H.map.Polygon object, style it, and add it to the map. Voila!


function onSuccess(result) {
    // parse results from Geocoder API and retrieve shape information
    locations = result.Response.View[0].Result;
    shape = locations[0].Location.Shape.Value;                 
    addCountryOutline(map);
}

function onError(error) {
    alert('Ooops!');
}

function addCountryOutline(map) {

    // clear map
    markerGroup.removeAll();

    // set up polygon style
    var customStyle = {
        strokeColor: 'black', 
        fillColor: 'rgba(0,175,170,0.5)', 
        lineWidth: 2,            
        lineJoin: 'bevel'
    };
    
    // the shape is returned as WKT and we need to convert it a Geometry
    var geometry = H.util.wkt.toGeometry(shape); 

    // geometry is either a single or multi-polygon     
    if (geometry instanceof H.geo.MultiGeometry) {
        var geometryArray = geometry.getGeometries(); 
        for (var i = 0; i < geometryArray.length; i++) {
            markerGroup.addObject(new H.map.Polygon(geometryArray[i].getExterior(), 
            	{ style: customStyle }));            
        }
    } else { // instanceof H.geo.Polygon            
        markerGroup.addObject(new H.map.Polygon(geometry.getExterior(), 
        	{ style: customStyle }));            
    }        
}

Stay tuned for more Geocoder secrets in the near future!