Google Elevation API

A related piece to the new waterfall site (that I'm still actively working on) is geodata - that is, the coordinates of each waterfall and nearby features, paths, etc. The existing waterfall site had each coordinate saved inline with the fall record, a very sloppy and elementary implementation. Latitude/longitude pairs should be abstracted out in a separate area within the data structure. With this in mind I started to create a new data model, one that would handle the geodata and allow me to attach metadata to it, and connected each fall record to a coordinate record within the new model.

After all this setup was complete I had a starter set of 160 latitude/longitude pairs. I wanted more than that, though. I wanted to plug elevation information on a per coordinate level. I've done such work using a USGS web service in the past, though that code has now been lost to the elements. Instead of going back to USGS I decided to take a look at the Google's APIs. With all their geo-services it would only make sense for them to have some logic for elevations.

Google actually has a number of Map APIs, including Geocoding, Distance Matrix, and Elevation. Their 'free' usage limits seemed reasonable (and the business customer prices really, really high) so I began to dig through the Elevation API. I needed to define whether or not I had a sensor and at least one latitude/longitude pair per request. This smelled like a class waiting to happen.

The class would have three main functions. First, it would act like a bucket to accept coordinates. Since the Elevation API can accept a single point, an array of points (pipe-separated), or a path (something I wasn't terribly interested in at the moment), I wanted an instantiated class to hold onto all the coordinates until a request was made. Second, it would build a valid URL endpoint based on the parameters passed in. Third, the class would need to execute the request and return the appropriate response.

Some of the things that this class does not do includes validation of the request parameters or parsing of the return. While it does have three main functions the class should only have one main job - fetch information from the Googles. An invalid request would return an error message, so I wasn't terribly worried about handling things before-request, and I leave it up to the end user to format the response and handle any errors. The API is well-documented so I wasn't worried about client getting too confused.

Oh, and the class is on GitHub: jacobemerick/elevation.

Once the class was done I was able to easily create a script that would loop through my database records, fetch the elevation, and then update each coordinate. Here is that psuedocode…

  1. include_once 'elevation/GoogleElevationRequest.php';

  2. $mysqli = new mysqli(SERVER, USER, PASSWORD, DATABASE);

  3. $query = 'SELECT * FROM coordinate WHERE elevation = 0';

  4. $result = $mysqli->query($query);

  5. while ($row = $result->fetch_object()) {

  6. $request = new GoogleElevationRequest();

  7. $request->addCoordinate($row->latitude, $row->longitude);

  8. $response = $request->fetchJSON();

  9. $json = json_decode($response);

  10. if ($json->status != 'OK') {

  11. echo "We have a problem! {$json->status}\n\nStopped at {$row->id}.";

  12. exit;

  13. }

  14. $elevation = $json->results[0]->elevation;

  15. $query = 'UPDATE coordinate SET elevation = ? WHERE id = ?';

  16. $statement = $mysqli->prepare($query);

  17. $statement->bind_param('di', $elevation, $row->id);

  18. $statement->execute();

  19. }

One thing to note - yes, I could have fewer requests by plugging in multiple coordinates per run and then parsing through the return. However, the Elevation API does mention that their accuracy decreases with more individual coordinates in a request. In order to get the most accurate results you may want to limit to one coordinate per request.

And that's it! The next little class that I'm looking at (potentially) working on would fetch the nearest town for a given coordinate. I'm not entirely certain if Google's Geocoding would help out with that need, but if it does, than it may make sense to build a little Google Map API library and have easier access for all five of their main services.