Geocoding and Geosearch
These examples are for the current version of geocoding service (V2). Examples for earlier versions are located here.
Simple Query¶
Throughout this series of examples, we will demonstrate usage of CloudMade standalone geocoding service using a typical travel advice application workflow.
First of all you need to sign up for a CloudMade API key, by following this link, if you have not done it before.
Let's get started with our application. At the very least, we want users to be able to type in an address and view it on the map. To be able to do it, we need to retrieve the coordinates of that address. This is as easy as sending a GET request to the geocoder:
For debugging purposes, substitute .js for .html and view matching objects on a map in your browser (not for use in production environment):
The response from the geocoder is encoded in GeoJSON format:
{
"found": 1,
"type": "FeatureCollection",
"features": [
{
"centroid": {"type": "POINT", "coordinates": [52.48708, 13.42482]},
"bounds": [[52.48621, 13.42404], [52.48795, 13.42556]],
"geometry": {"type": "MULTILINESTRING", "coordinates": [
[[52.48781, 13.42513], [52.48764, 13.42555]],
[[52.48795, 13.42512], [52.48781, 13.42513]],
[[52.48622, 13.42433], [52.48634, 13.42447]],
[[52.48633, 13.42404], [52.48622, 13.42433]],
[[52.48634, 13.42447], [52.4865, 13.42411]],
[[52.48776, 13.42556], [52.48783, 13.42541]],
[[52.48639, 13.42446], [52.48639, 13.42446]],
[[52.48634, 13.42447], [52.48764, 13.42555]],
[[52.48783, 13.42541], [52.48795, 13.42512]],
[[52.48764, 13.42555], [52.48776, 13.42556]],
[[52.48781, 13.42513], [52.4865, 13.42411]],
[[52.4865, 13.42411], [52.48633, 13.42404]]
]},
"type": "Feature",
"properties": {"name": "Hermannplatz"}
}
],
"bounds": [[52.48621, 13.42404], [52.48795, 13.42556]],
"crs": {"type": "EPSG", "properties": {"code": 4326, "coordinate_order": [1, 0]}}
}
Let's take a closer look at the structure of the response.
"found": 1,
"type": "FeatureCollection",
The first two lines indicate that only one object was found (an object is called feature in GeoJSON), and that search result(s) are passed as a collection, or array, of objects. In this case only one object matched the search criteria:
{
"type": "Feature",
"bounds": [[52.48621, 13.42404], [52.48795, 13.42556]],
"centroid": {"type": "POINT", "coordinates": [52.48708, 13.42482]},
"geometry": {"type": "MULTILINESTRING", "coordinates": [
[[52.48781, 13.42513], [52.48764, 13.42555]],
[[52.48795, 13.42512], [52.48781, 13.42513]],
[[52.48622, 13.42433], [52.48634, 13.42447]],
[[52.48633, 13.42404], [52.48622, 13.42433]],
[[52.48634, 13.42447], [52.4865, 13.42411]],
[[52.48776, 13.42556], [52.48783, 13.42541]],
[[52.48639, 13.42446], [52.48639, 13.42446]],
[[52.48634, 13.42447], [52.48764, 13.42555]],
[[52.48783, 13.42541], [52.48795, 13.42512]],
[[52.48764, 13.42555], [52.48776, 13.42556]],
[[52.48781, 13.42513], [52.4865, 13.42411]],
[[52.4865, 13.42411], [52.48633, 13.42404]]
]},
"properties": {"name": "Hermannplatz"}
}
- bounds property defines the minimal bounding box that fully encloses the object, in this order: southern_latitude, western_longitude, northern_latitude, eastern_longitude
- centroid is, informally, the center of the object. Possible usages include displaying a marker or an icon for this object. More information on centroid can be found here
- geometry defines the shape of the object. In this example, it is a polyline (called MULTISTRING in GeoJSON), but for many object types this will be a point. Tip: if you don't need this information, omit return_geometry parameter:
- properties is a set of key/value pairs that provide additional information about the object. In this case, only the name of the object was returned.
The next part of the response object contains bounding box for all objects contained in the response (in our example we only have one object, so this value is equal to "bounds" property of Hermannplatz square). Should there be more results in the response, we would most likely use these coordinates to calculate appropriate zoom level for our map so that all results could be displayed at once.
"bounds": [[52.48621, 13.42404], [52.48795, 13.42556]],
And finally, response object indicates the coordinate reference system used to represent coordinates. You don't have to worry about this one for now.
"crs": {"type": "EPSG", "properties": {"code": 4326, "coordinate_order": [1, 0]}}
When used this way, geolocation service provides enough information for a lot of applications. But sometimes applications could use a lot more data about the objects. For instance, our application could need to know which country Hermannplatz is located in to keep track of most visited countries. No problem, simply append {{return_location=true}} to the URL to request location info:
This time, the service returns full address inside the "location" property of the object:
{
"found": 1,
"type": "FeatureCollection",
"features": [
{
"type": "Feature",
"bounds": [[52.48621, 13.42404], [52.48795, 13.42556]],
"centroid": {"type": "POINT", "coordinates": [52.48708, 13.42482]},
"geometry": {"type": "MULTILINESTRING", "coordinates": [
[[52.48781, 13.42513], [52.48764, 13.42555]],
[[52.48795, 13.42512], [52.48781, 13.42513]],
[[52.48622, 13.42433], [52.48634, 13.42447]],
[[52.48633, 13.42404], [52.48622, 13.42433]],
[[52.48634, 13.42447], [52.4865, 13.42411]],
[[52.48776, 13.42556], [52.48783, 13.42541]],
[[52.48639, 13.42446], [52.48639, 13.42446]],
[[52.48634, 13.42447], [52.48764, 13.42555]],
[[52.48783, 13.42541], [52.48795, 13.42512]],
[[52.48764, 13.42555], [52.48776, 13.42556]],
[[52.48781, 13.42513], [52.4865, 13.42411]],
[[52.4865, 13.42411], [52.48633, 13.42404]]
]},
"properties": {"name": "Hermannplatz"},
"location": {"county": "BRANDENBURG", "country": "Germany", "city": "Berlin"}
}
],
"bounds": [[52.48621, 13.42404], [52.48795, 13.42556]],
"crs": {"type": "EPSG", "properties": {"code": 4326, "coordinate_order": [1, 0]}}
}
This was easy. Now that users of our app have been able to locate Hermannplatz, it's time to suggest them a couple of restaurants in the area.
Searching for points of interest¶
This example demonstrates using geocoding service to find restaurants, monuments and dozens of other POI types. Don't forget to sign up for a CloudMade API key, by following this link, if you have not done it before.
In our previous example above, we retrieved coordinates of Hermannplatz, Berlin (52.4870, 13.4248). Let's search for hotels in the nearby area. Let's assume our map is 400px tall by 600px wide, therefore we can limit our search to an area of 4km by 6km, or 2km to the north and to the south, and 3km to the west and to the east. One degree of latitude is approximately equal to 110km, therefore 2km is 0.01818 degrees of latitude. It's slightly more complicated with longitude, as one degree of longitude is approximately equal to 111 km at the equator and gradually shrinks to zero at the poles. In this example we will use a simple formula (don't forget to translate degrees to radians where your programming language expects radians):1 degree of longitude = 60 * 1.852 km * cos (latitude) Therefore, at 52.48 degrees latitude, 1 degree of longitude equals 67.6654km, and 3km equals 1 / 67.6654 * 3 = 0.04434 degrees. We are now able to calculate the target bounding box: [52.4870-0.01818, 13.4248-0.04434, 52.4870+0.01818, 13.4248+0.04434] = [52.46882, 13.38046, 52.50518, 13.46914], and send a request to the geocoding service:
To visualize these hotels on a map, substitute .js extension with .html:
Note object_type parameter that we use to specify exactly what objects we are searching for. The full list of object types can be found here. Let's try other types:
cafe
http://geocoding.cloudmade.com/8ee2a50541944fb9bcedded5165f09d9/geocoding/v2/find.js?bbox=52.46882,13.38046,52.50518,13.46914&object_type=cafe http://geocoding.cloudmade.com/8ee2a50541944fb9bcedded5165f09d9/geocoding/v2/find.html?bbox=52.46882,13.38046,52.50518,13.46914&object_type=cafe
bank
http://geocoding.cloudmade.com/8ee2a50541944fb9bcedded5165f09d9/geocoding/v2/find.js?bbox=52.46882,13.38046,52.50518,13.46914&object_type=bank http://geocoding.cloudmade.com/8ee2a50541944fb9bcedded5165f09d9/geocoding/v2/find.html?bbox=52.46882,13.38046,52.50518,13.46914&object_type=bank
parking
http://geocoding.cloudmade.com/8ee2a50541944fb9bcedded5165f09d9/geocoding/v2/find.js?bbox=52.46882,13.38046,52.50518,13.46914&object_type=parking http://geocoding.cloudmade.com/8ee2a50541944fb9bcedded5165f09d9/geocoding/v2/find.html?bbox=52.46882,13.38046,52.50518,13.46914&object_type=parking
If we needed more or fewer results for each call, we would use results parameter to specify their number. Try this:
http://geocoding.cloudmade.com/8ee2a50541944fb9bcedded5165f09d9/geocoding/v2/find.js?bbox=52.46882,13.38046,52.50518,13.46914&object_type=cafe&results=5 http://geocoding.cloudmade.com/8ee2a50541944fb9bcedded5165f09d9/geocoding/v2/find.html?bbox=52.46882,13.38046,52.50518,13.46914&object_type=cafe&results=5
In order to display the next page of results, we would use skip parameter:
http://geocoding.cloudmade.com/8ee2a50541944fb9bcedded5165f09d9/geocoding/v2/find.js?bbox=52.46882,13.38046,52.50518,13.46914&object_type=bank&results=5&skip=5 http://geocoding.cloudmade.com/8ee2a50541944fb9bcedded5165f09d9/geocoding/v2/find.html?bbox=52.46882,13.38046,52.50518,13.46914&object_type=bank&results=5&skip=5
Limiting the search area by bounding box is applicable in most situations, since maps tend to be rectangular. However, there is also another method to limit the search area - by passing around and distance parameters:
Compare these two requests:
http://geocoding.cloudmade.com/8ee2a50541944fb9bcedded5165f09d9/geocoding/v2/find.html?around=52.4870,13.4248&distance=2000&object_type=cafe&results=100 http://geocoding.cloudmade.com/8ee2a50541944fb9bcedded5165f09d9/geocoding/v2/find.html?bbox=52.46882,13.38046,52.50518,13.46914&object_type=cafe&results=100
You can see that there are quite a few cafes outside of a 2km radius, but still within the limits of our map. We could have chosen a 3km radius, but then we would be likely to get objects that are outside the map.
And finally, if we wanted to let the users of our application search for specific points of interest by typing a keyword, we would form the request similarly to simple geocoding query:
http://geocoding.cloudmade.com/8ee2a50541944fb9bcedded5165f09d9/geocoding/v2/find.js?bbox=52.46882,13.38046,52.50518,13.46914&object_type=cafe&query=Isabel http://geocoding.cloudmade.com/8ee2a50541944fb9bcedded5165f09d9/geocoding/v2/find.html?bbox=52.46882,13.38046,52.50518,13.46914&object_type=cafe&query=Isabel
http://geocoding.cloudmade.com/8ee2a50541944fb9bcedded5165f09d9/geocoding/v2/find.js?bbox=52.46882,13.38046,52.50518,13.46914&object_type=bank&query=GE http://geocoding.cloudmade.com/8ee2a50541944fb9bcedded5165f09d9/geocoding/v2/find.html?bbox=52.46882,13.38046,52.50518,13.46914&object_type=bank&query=GE
Now, let's see how an application can present the user's current location in a nice and human-readable form.
Reverse geocoding¶
This example illustrates use of CloudMade geocoding service to find an address from a coordinate (often called reverse geocoding). Easy:
http://geocoding.cloudmade.com/8ee2a50541944fb9bcedded5165f09d9/geocoding/v2/find.html?around=52.4870,13.4248&distance=closest&object_type=address&return_location=true http://geocoding.cloudmade.com/8ee2a50541944fb9bcedded5165f09d9/geocoding/v2/find.js?around=52.4870,13.4248&distance=closest&object_type=address&return_location=true
Using structured search¶
This example demonstrates using structured search to improve user experience by providing better search results. Don't forget to sign up for a CloudMade API key, by following this link, if you have not done it before.
Often, the users of an application will not be willing to enter well-formed address, and this can reduce the quality of search results. For example, consider a user who is using a cellphone app to locate an address. Instead of typing "Bunker Hill Street, Boston", they will likely type in "bunker hill st boston". The geocoding service may be unable to geocode such addresses.
In order to improve the quality of search results, we could provide two entry fields, one for the street name, and the other for city name. In this case, the user would type "bunker hill st" for the street name, and "boston" for the city name. This is how, then, the request would be formed:
Or, to see the results on the map, use .html extension instead of .js:
That's a lot better, isn't it? The following qualifiers can be used:
- house
- street
- city
- postcode/zipcode
- county
- country
Try this:
http://geocoding.cloudmade.com/8ee2a50541944fb9bcedded5165f09d9/geocoding/v2/find.html?query=postcode:BS9 http://geocoding.cloudmade.com/8ee2a50541944fb9bcedded5165f09d9/geocoding/v2/find.html?query=zipcode:90210
Notice for iPhone developers
Find out how to prepare your iPhone app for iOS 4.0 Detailed instructions
Start Here
Get an API KeyWiki
Start page
Index by title
Index by date