Water/ Not Water – Hacking the Google Maps API

This is the second post on mentorship at Iolani High School. Read part one if you’re interested in learning more about the mentorship.

The second page she was tasked with creating would allow users on the web to direct the catamaran to a specific GPS coordinate. In order to make sure users didn’t put in a GPS coordinate that was on land, she needed to determine if the input GPS coordinate was in the water.

She emailed me to ask for help:

I’m working on the control page now, and I am trying to figure out how to detect water on Google Maps. I have to make sure that the locations sent to the CAT are actually in the Ala Wai Canal. Since the Ala Wai Canal and other bodies of water show up as blue in Google Maps, I think that there should be a way to determine whether a location is in water or not. I’ve done some research on it and most pages suggest using reverse geocoding, however, I’m not sure it will work in this case. Here’s one website:
I clicked on the link to stackoverflow and read that the reverse geocoding wouldn’t work for this issue. So I dug into the second solution proposed. This seems absurd. Here’s the solution posted on stackoverflow:

These are steps your service must perform:

  1. Receive latitude,longitude and current zoom from client.
  2. Send http://maps.googleapis.com/maps/api/staticmap?center={latitude,longitude}&zoom={current zoom`}&size=1×1&maptype=roadmap&sensor=false request to Google Static Map service.
  3. Detect pixel’s color of 1×1 static image.
  4. Respond an information about detection.

You can’t detect pixel’s color in client side. Yes , you can load static image on client’s machine and draw image on canvas element. But you can’t use getImageData of canvas’s context for getting pixel’s color. This is restricted by cross domain policy.

Prons – Highly accurate detection

Cons – Use of own server resources for detection

Let’s go over how this works again to make sure you understand how hacky this solution is.

  1. Sign up for the Google Maps API
  2. Create a webpage in PHP
  3. Pass the GPS coordinates to the PHP page as GET parameters
  4. Send the GPS coordinates to Google
  5. Get back a 10 pixel by 10 pixel image of the map
  6. Process that image with PHP to determine what color it is
  7. If it’s blue it’s water
  8. If it’s any other color it is not water

I smiled all day after this project. It’s such a silly little solution. And it may break if Google changes the color of water in their map. But it works! I messaged back the student:

Thanks for the email. This was a really interesting problem! I ended up coding an API endpoint to determine if a latitude and longitude coordinate is WATER or is NOT WATER with the second option you linked to on stackoverflow.

Specifically this section:These are steps your service must perform:

Receive latitude,longitude and current zoom from client.

Send http://maps.googleapis.com/maps/api/staticmap?center={latitude,longitude}&zoom={current zoom`}&size=1×1&maptype=roadmap&sensor=false request to Google Static Map service.

Detect pixel’s color of 1×1 static image.

Respond an information about detection.

You can test the solution with the following calls:
 
Waikiki land: (returns NOT WATER) <link removed>
Pacific Ocean: (returns WATER) <link removed>
Ala Wai: (returns WATER) <link removed>
I am sharing the link with you to show that it works. I will be taking this code down at the end of the week so it is not possible to use this for your project. I would like to show you how to create this code for your project on your own machine. I’m free to meet in person or to help you via email or phone.
Here are the steps you need to take to set it up:
  1. Sign up for the Google Maps API
  2. Set up billing (this requires a credit card)
  3. Host the API code on a server with PHP
Let me know how you’d like to proceed
We’re meeting on Tuesday to get this set up and running on her webserver. This was such a fun project that I just had to post about it. Here is the code I created to solve this issue:

<?php

///////////////////// Gets the image from Google Maps API&lt;/code&gt;

// Set up the page to take in GET variables
$latitude = $_GET["latitude"];
$longitude = $_GET["longitude"];

// echo $latitude;
// echo "
";
// echo $longitude;

// Sets up parameters for call
$mapsApiKey = "";
$zoom = 20;

// Set up the API call
$apiCall = "https://maps.googleapis.com/maps/api/staticmap?center=" . $latitude . "%2c%20" . $longitude . "&amp;amp;zoom=" . $zoom . "&amp;amp;size=10x10&amp;amp;maptype=roadmap&amp;amp;sensor=false&amp;amp;key=" . $mapsApiKey;
// echo "
";
// echo $apiCall;

?>

document.addEventListener('DOMContentLoaded', function() {

// Gets the image from the API call
var apiCall = '';
// alert(apiCall);

// Set image source as constructed API call string
var img = new Image;
img.crossOrigin = "anonymous"; // To fix the security issue of reading images from other sources
var src = apiCall;

// Sets up the canvas
var canvas = document.getElementById("myCanvas");
var ctx = canvas.getContext("2d");

// Fill in the backgorund color with red so we can see it
// ctx.fillStyle = "#FF0000";
// ctx.fillRect(0, 0, 10, 10);

// // Download the image
img.onload = function() { // ...then set the onload handler...
ctx.drawImage(img, 0, 0);

// Get color of image
var imgData = ctx.getImageData(0, 0, 1, 1);
var red = imgData.data[0];
var green = imgData.data[1];
var blue = imgData.data[2];
var alpha = imgData.data[3];

// Hides the canvas as we are not interested in seeing it
canvas.style.display="none";

console.log("red: " + red + " green: " + green + " blue: " + blue + " alpha: " + alpha);

// Determine if this response is WATER or NOT WATER
if (red == 170 &amp;amp;&amp;amp; green == 218 &amp;amp;&amp;amp; blue == 255) {
document.getElementById("findings").innerHTML = "WATER";
} else {
document.getElementById("findings").innerHTML = "NOT WATER";
}
};
img.src = src; // because the internet says you should put your src after your load

}, false);

Advertisements

Author: David Neely

Professional Software Developer. Technology and Web Coordinator at the University of Hawaii's Manoa Career Center.