Google Maps API points in polygons

By David Marland
· 286 words ( )

Reading speed

Don't know your reading speed?
Start a timer while reading this post. When finished, stop the timer to find your reading speed.

UPDATE 27th March 2012: The Google Maps Geometry library now contains a containsLocation method which will achieve the same thing as detailed below. I’d recommend you use that instead.

Discovering whether a point on a map is inside a polygon can be very useful, especially now that modern browsers and phones are location aware. If you can tell if your user is within a specific boundary then you can present them with immediately relevant information. An example I have used is telling the user they are in the coverage area of a local business (Gascall).

Assuming you’ve already set up your map, the Google maps API allows you to create polygons using simple code.

var path = [
    new google.maps.LatLng(51.73383267274113, -1.03271484375),
    new google.maps.LatLng(51.45400691005984, -1.4501953125),
    new google.maps.LatLng(51.83577752045251, -0.8843994140625)];
    var polygon = new google.maps.Polygon({path:path, clickable:false});
    polygon.setMap(map);

You can create a Google maps point from latitude/longitude values or the users location:

if (navigator.geolocation) {
    navigator.geolocation.getCurrentPosition(function(position) {
        var point = new google.maps.LatLng(position.coords.latitude, position.coords.longitude);
    });
}

Determining if the point is inside the polygon

The google maps api does not already provide a method for checking points in polygons. Some research has already been done on this, but I couldn’t find a complete solution in Google maps api v3 that also catered for crossing 180 degrees longitude. I would have done a straight translation into Google maps api v3, but decided to actually try to understand what was going on.

After researching a bit I stumbled across the Ray-casting algorithm which will determine if an X-Y coordinate is inside a plotted shape. This will translate to latitude and longitude. The following extends the google.maps.polygon.prototype to use this algorithm. Simply include this code at a point in the code after google.maps has loaded:

google.maps.Polygon.prototype.Contains = function(point) {
        // ray casting alogrithm http://rosettacode.org/wiki/Ray-casting_algorithm
        var crossings = 0,
            path = this.getPath();
 
        // for each edge
        for (var i=0; i < path.getLength(); i++) {
            var a = path.getAt(i),
                j = i + 1;
            if (j >= path.getLength()) {
                j = 0;
            }
            var b = path.getAt(j);
            if (rayCrossesSegment(point, a, b)) {
                crossings++;
            }
        }
 
        // odd number of crossings?
        return (crossings % 2 == 1);
 
        function rayCrossesSegment(point, a, b) {
            var px = point.lng(),
                py = point.lat(),
                ax = a.lng(),
                ay = a.lat(),
                bx = b.lng(),
                by = b.lat();
            if (ay > by) {
                ax = b.lng();
                ay = b.lat();
                bx = a.lng();
                by = a.lat();
            }
            // alter longitude to cater for 180 degree crossings
            if (px < 0) { px += 360 };
            if (ax < 0) { ax += 360 };
            if (bx < 0) { bx += 360 };
 
            if (py == ay || py == by) py += 0.00000001;
            if ((py > by || py < ay) || (px > Math.max(ax, bx))) return false;
            if (px < Math.min(ax, bx)) return true;
 
            var red = (ax != bx) ? ((by - ay) / (bx - ax)) : Infinity;
            var blue = (ax != px) ? ((py - ay) / (px - ax)) : Infinity;
            return (blue >= red);
 
        }
 
     };

Then to check a point:

var point = new google.maps.LatLng(52.05249047600099, -0.6097412109375);
var polygon = new google.maps.Polygon({path:[INSERT_PATH_ARRAY_HERE]});
if (polygon.Contains(point)) {
    // point is inside polygon
}

I hope this proves useful. Let me know if you have any suggestions/comments.

Stop reading timer

Elapsed time: 00:00:00

© 2011 - 2026 hammerspace.co.uk / Piko design system / Admin

The opinions expressed on this site are my own and do not necessarily reflect the views of my employers, past or present.

Look Ma, no cookie banner. Anything stored in your browser is purely functional. No information is stored about you or shared with anyone. Your IP address may be used to estimate your location to see which regions generate the most traffic, but is not stored after that estimation. A cookie may be set to prevent double counting of page views, but is not used for tracking (which is acceptable without a cookie banner under the UK's DUAA and EU Digital Omnibus Package).
This site is proxied via Cloudflare, which may collect some information about your visit. See Cloudflare's privacy policy.