Circle overlay on Google Map
This is my first "Zoom around Town"-related technical post. This first post looks at the use of GGroundOverlay for rendering circles on Google Maps.
To represent the current search areas in Zoom around Town, I decided to overlay two radar-style circles, on the start point map and on the end point map. These circles have to increase and decrease in diameter depending on the user's range selections. See this page in Zoom around Town for a demonstration. When you change the values of the +/- distance dropdowns, and update the maps, you should see the two circles change in size. The radius of the circle corresponds to the selected +/- value.
While the Google Map API (v2) provides GPolyline and GPolygon for drawing lines and polygons on Google Map, it does not provide an overlay class for drawing circles.
One solution is to create a multi-point GPolygon to approximate a circle. Check out this article for an explanation on how this can be done.
A better (in my opinion) solution is to instead use a GGroundOverlay. GGroundOverlay provides a means to overlay an image on top of the map. The image will be scaled automatically as the user zooms the map, so that the image will always cover the same geography area on the map. So, to create a radar-style circle, one only has to find a transparent circle png file, locate the point on the map where the circle should be centred upon, and specify the southwest corner coordinate and the northeast corner coordinate of the imaginery square that bounds this circle (i.e. the GLatLngBounds). Sounds simple, does'nt it? Well almost, to work out the GLatLngBounds coordinates, we need a bit of good old trigonometry.
Pythagoras told us that, for a 2km-radius circle, the four corners of this bounding square will be sqrt(2*2^2) km from the centre of the circle. So, to draw a 2km-radius circle centred upon a specific point, we need the southwest corner coordinate, which is sqrt(2*2^2) at 225 degrees from the original point and the northeast corner coordinate, which is the same distance at 45 degrees from the original point.
Coordinate of a destination point given distance and bearing from a start point
Unfortunately, as the globe is a sphere, working out a destination point coordinate given the distance and the bearing from a start point is no straightforward maths. Fortunately, the good people at Movable Type Ltd. (not to be confused with http://www.movabletype.org) published this informative page. So based on the formula and the Javascript given on the page, I created the Javascript function:
Now, the rest is easy:
To represent the current search areas in Zoom around Town, I decided to overlay two radar-style circles, on the start point map and on the end point map. These circles have to increase and decrease in diameter depending on the user's range selections. See this page in Zoom around Town for a demonstration. When you change the values of the +/- distance dropdowns, and update the maps, you should see the two circles change in size. The radius of the circle corresponds to the selected +/- value.
While the Google Map API (v2) provides GPolyline and GPolygon for drawing lines and polygons on Google Map, it does not provide an overlay class for drawing circles.
One solution is to create a multi-point GPolygon to approximate a circle. Check out this article for an explanation on how this can be done.
A better (in my opinion) solution is to instead use a GGroundOverlay. GGroundOverlay provides a means to overlay an image on top of the map. The image will be scaled automatically as the user zooms the map, so that the image will always cover the same geography area on the map. So, to create a radar-style circle, one only has to find a transparent circle png file, locate the point on the map where the circle should be centred upon, and specify the southwest corner coordinate and the northeast corner coordinate of the imaginery square that bounds this circle (i.e. the GLatLngBounds). Sounds simple, does'nt it? Well almost, to work out the GLatLngBounds coordinates, we need a bit of good old trigonometry.
Pythagoras told us that, for a 2km-radius circle, the four corners of this bounding square will be sqrt(2*2^2) km from the centre of the circle. So, to draw a 2km-radius circle centred upon a specific point, we need the southwest corner coordinate, which is sqrt(2*2^2) at 225 degrees from the original point and the northeast corner coordinate, which is the same distance at 45 degrees from the original point.
Coordinate of a destination point given distance and bearing from a start point
Unfortunately, as the globe is a sphere, working out a destination point coordinate given the distance and the bearing from a start point is no straightforward maths. Fortunately, the good people at Movable Type Ltd. (not to be confused with http://www.movabletype.org) published this informative page. So based on the formula and the Javascript given on the page, I created the Javascript function:
function getDestLatLng(latLng, bearing, distance) {
var lat1 = latLng.latRadians();
var lng1 = latLng.lngRadians();
var brng = bearing*Math.PI/180;
var dDivR = distance/EARTH_RADIUS;
var lat2 = Math.asin( Math.sin(lat1)*Math.cos(dDivR) + Math.cos(lat1)*Math.sin(dDivR)*Math.cos(brng) );
var lng2 = lng1 + Math.atan2(Math.sin(brng)*Math.sin(dDivR)*Math.cos(lat1), Math.cos(dDivR)-Math.sin(lat1)*Math.sin(lat2));
return new GLatLng(lat2/ Math.PI * 180, lng2/ Math.PI * 180);
}
Now, the rest is easy:
var EARTH_RADIUS = 6378.137; //in kilometres
function drawCircle(map, centrePt, rangeValue) {
var boundaries = getBoundaries(centrePt, rangeValue);
var circle = new GGroundOverlay("/images/map_overlays/circle.png", boundaries);
map.addOverlay(circle);
}
function getBoundaries(centrePt, radius) {
var hypotenuse = Math.sqrt(2 * radius * radius);
var sw = getDestLatLng(centrePt, 225, hypotenuse);
var ne = getDestLatLng(centrePt, 45, hypotenuse);
return new GLatLngBounds(sw, ne);
}
Comments
Otherwise just go for the multi-point GPolygon approach, but then I have not done any performance testing with GPolygon. Not sure about the performance implications of creating 200 GPolygon though...
http://smokesignalsgrill.com/groundoverlay-test2.html
Now I have to figure out how to shoehorn that into his wordpress blog. Wish me luck!
I try to do it as generic and parametrable as i could.
Cheers!
ps: JavaDoc and comments are in French =P i'll try to translate it if someone ever uses it =P