Height, slope and sun side for property listings
In hilly places, buyers ask how high a house stands, how steep the plot is and when it gets the sun. Five lookups give the answers when you save a listing: the height at the house and at four points around it.
How it works
The function asks for the height at the house and at four points 90 m to the north, south, east and west, the spacing of the data. North against south and east against west give the rise in each direction; together they give the slope in percent and the direction in which the ground falls away, which is the side a house there faces. Below a slope of 3 %, the ground counts as flat.
Run it on your server when an agent saves a listing, and store the three values with it. The key stays on the server, and the listing pages make no requests to us.
Python
import math, requests
API = "https://api.overpass.ch/v1/YOUR_API_KEY/elevation"
STEP = 90 # metres to the four neighbours, the grid of the data
SIDES = ["north", "north-east", "east", "south-east", "south", "south-west", "west", "north-west"]
def terrain(lat, lon):
"""Height, slope and the side the ground faces at lat, lon: 5 lookups."""
dlat = STEP / 111_320
dlon = STEP / (111_320 * math.cos(math.radians(lat)))
here = [[lat, lon], [lat + dlat, lon], [lat - dlat, lon], [lat, lon + dlon], [lat, lon - dlon]]
r = requests.post(API, json={"locations": here}, timeout=30)
r.raise_for_status()
h, n, s, e, w = (res["elevation"] for res in r.json()["results"])
east, north = (e - w) / (2 * STEP), (n - s) / (2 * STEP) # rise per metre
slope = math.hypot(east, north) * 100
downhill = math.degrees(math.atan2(-east, -north)) % 360 # 0 north, 90 east
return {
"height_m": round(h),
"slope_pct": round(slope),
"faces": SIDES[round(downhill / 45) % 8] if slope >= 3 else "flat",
}
if __name__ == "__main__":
print(terrain(47.2760, 8.6530)) # Meilen, above the lake
It prints {'height_m': 529, 'slope_pct': 10, 'faces': 'south-west'}.
PHP
<?php
const ELEVATION_API = 'https://api.overpass.ch/v1/YOUR_API_KEY/elevation';
// Height, slope and the side the ground faces at $lat, $lon: 5 lookups.
function terrain(float $lat, float $lon): array {
$step = 90; // metres to the four neighbours, the grid of the data
$dlat = $step / 111320;
$dlon = $step / (111320 * cos(deg2rad($lat)));
$here = [[$lat, $lon], [$lat + $dlat, $lon], [$lat - $dlat, $lon], [$lat, $lon + $dlon], [$lat, $lon - $dlon]];
$answer = file_get_contents(ELEVATION_API, false, stream_context_create(['http' => [
'method' => 'POST',
'header' => "Content-Type: application/json\r\n",
'content' => json_encode(['locations' => $here]),
'timeout' => 30,
]]));
if ($answer === false) {
throw new RuntimeException('The elevation API did not answer');
}
[$h, $n, $s, $e, $w] = array_column(json_decode($answer, true)['results'], 'elevation');
$east = ($e - $w) / (2 * $step); // rise per metre
$north = ($n - $s) / (2 * $step);
$slope = hypot($east, $north) * 100;
$downhill = fmod(rad2deg(atan2(-$east, -$north)) + 360, 360); // 0 north, 90 east
$sides = ['north', 'north-east', 'east', 'south-east', 'south', 'south-west', 'west', 'north-west'];
return [
'height_m' => (int) round($h),
'slope_pct' => (int) round($slope),
'faces' => $slope >= 3 ? $sides[(int) round($downhill / 45) % 8] : 'flat',
];
}
print_r(terrain(47.2760, 8.6530)); // Meilen, above the lake
It needs no extension; allow_url_fopen must be on, as it is by default. In WordPress, call it when a listing is saved (the save_post hook) and keep the values in custom fields.
In the listing
Show the values, for example “529 m above sea level, faces south-west”, or turn the side into words about the sun. For the northern half of the Earth:
| Faces | Sun |
|---|---|
| south | most of the day |
| south-east | in the morning and at midday |
| south-west | in the afternoon and evening |
| east | in the morning |
| west | in the evening |
| north-east, north, north-west | less direct sun, above all in winter |
In the southern half, swap north and south. Stored as numbers, the values also work in a search: height_m >= 1000 for holiday homes in the mountains, faces IN ('south', 'south-east', 'south-west') for the sunny side.
What it costs
Five lookups per listing, once. For the listings you already have, send the points of up to 2,000 listings in one request of 10,000 locations. The free plan includes 1 million lookups a month, for personal and non-commercial use. For an agency or a portal, the Elevation plan costs $7 a month plus tax and covers 50 million lookups: 10 million listings.
Good to know
- The slope is that of the hillside over about 200 m. A single garden can be steeper or flatter: a house on a flat terrace in a steep hillside gets the slope of the hillside.
- The data measures the surface: in a forest or between large buildings, part of their height is in it. In villages and towns, heights are typically within a few metres. See accuracy.
- Use the position of the building, for example from your address search or from the map of the listing. Five metres off makes no difference; a few hundred metres can.
- Where you show the values, credit the elevation data as described in the documentation, for example in the footer of the listing pages.