I need some guidence in finding out how I can fire an alert when my location is located near a specified location.
I guess then would use google map and geolocation but I am not sure.
I would also like to be able to show some code but after doing countless google searches I can't find anything and I don't know what to look for.
I'll be using phonegap / cordova.
Can anyone guide me in the right direction?enter code here
It sounds like you are looking for a geofence plugin like this one: https://github.com/cowbell/cordova-plugin-geofence
This will let you monitor when your device transitions into and out of custom geofences / location zones you set up.
Add this to your project using cordova plugin add cordova-plugin-geofence and follow the usage guide in their readme.
//Convert Destination Address to lat lng values
var specificlocation = {
lat: -13.26589,
lng: 98.365297
}
function onDeviceReady() {
//onDeviceReaddy
navigator.geolocation.getCurrentPosition(displayAndWatch, locError);
}
// user Current Position
function displayAndWatch(position) {
setCurrentPosition(position);
watchCurrentPosition();
}
function setCurrentPosition(pos) {
var image = 'img/ic_CurrentLocationmap.png';
currentPositionMarker = new google.maps.Marker({
icon: image,
map: map,
position: new google.maps.LatLng(
pos.coords.latitude,
pos.coords.longitude
),
title: "Current Location"
});
map.panTo(new google.maps.LatLng(
pos.coords.latitude,
pos.coords.longitude
));
}
//Watch User/phone current location
function watchCurrentPosition() {
var positionTimer = navigator.geolocation.watchPosition(
function (position) {
setMarkerPosition(
currentPositionMarker,
position
);
});
}
function setMarkerPosition(marker, position) {
marker.setPosition(
new google.maps.LatLng(
position.coords.latitude,
position.coords.longitude)
);
var center = {
lat: position.coords.latitude,
lng: position.coords.longitude
}
map.setCenter(center);
//Check distance between specificlocation and user/phone current location
var distance = DistanceBetweenTwoPoints(center.lat, center.lng, specificlocation.lat,
specificlocation.lng, "K")
//with in 100 Meters
if (distance < 0.1) {
navigator.notification.confirm(
'You are Reached specificlocation Address', // message
onConfirmReached, //Callback
'AppName', // title
['No', 'Yes'] // buttonLabels
);
}
function locError(error) {
// the current position could not be located
}
function onConfirmReached(buttonIndex) {
if (buttonIndex == 2) {
//Alert result
}
}
//Find Distance between Two coordinations
function DistanceBetweenTwoPoints(lat1, lon1, lat2, lon2, unit) {
try {
unit = "K"
var radlat1 = Math.PI * lat1 / 180
var radlat2 = Math.PI * lat2 / 180
var radlon1 = Math.PI * lon1 / 180
var radlon2 = Math.PI * lon2 / 180
var theta = lon1 - lon2
var radtheta = Math.PI * theta / 180
var dist = Math.sin(radlat1) * Math.sin(radlat2) + Math.cos(radlat1) * Math.cos(radlat2) * Math.cos(
radtheta);
dist = Math.acos(dist)
dist = dist * 180 / Math.PI
dist = dist * 60 * 1.1515
//Calculate Kilometer
if (unit == "K") {
dist = dist * 1.609344
}
//Calculate Miles
if (unit == "N") {
dist = dist * 0.8684
}
return dist;
} catch (err) {
console.log(err);
}
}
Related
Background:
I'm trying to use a Google maps ground overlay but we are missing GPS positions.
We have a map to overlay that was drawn over a Google Maps screenshot. From this screenshot we recorded the Top Left and Center Center position.
We require the bottom right position to accurately overlay these images. See below:
The intial thinking is finding the difference between the two points and adding that onto the center point.
Attempted logic:
In JavaScript:
var topLeft = [-32.8830055, 151.686214];
var centerCenter = [-32.9293803, 151.756686];
var difference1 = centerCenter[0] - ( (topLeft[0] - centerCenter[0] ) ) ;
var difference2 = centerCenter[1] - ( (topLeft[1] - centerCenter[1] ) ) ;
// being bottom right this should be "bigger" than above values
// outputs [-32.97575509999999, 151.827158];
var bottomRight = [difference1 , difference2];
Problem:
However it appears this is where the curve of the earth throws that simple maths out the door. I'm guessing that what is happening below is why.
So given I have a rectangle overlay and I know the top left point and the center point can I work out the latitude and longitude of the bottom right point I.e X in the above diagram. Note I do not know the real world distances of this rectangle.
Note: I also know that I will have to change these to NW / SE to use ground overlays.
Approach(using the geometry-library):
calculate the heading from northwest to center
google.maps.geometry.spherical.computeHeading(northwest, center);
calculate the distance from northwest to center
google.maps.geometry.spherical.computeDistanceBetween(northwest, center);
calculate southeast by using
google.maps.geometry.spherical.computeOffset(center,
calculatedDistance,
calculatedHeading);
function initialize() {
var nw = new google.maps.LatLng(62.400471, -150.287132),
center = new google.maps.LatLng(62.341145, -150.14637),
map = new google.maps.Map(document.getElementById('map_canvas'), {
zoom: 9,
center: center
}),
heading, distance, se;
heading = google.maps.geometry.spherical.computeHeading(nw, center);
distance = google.maps.geometry.spherical.computeDistanceBetween(nw, center);
se = google.maps.geometry.spherical.computeOffset(center, distance, heading);
new google.maps.Marker({
map: map,
position: center
});
new google.maps.Marker({
map: map,
position: nw
});
new google.maps.Marker({
map: map,
position: se
});
new google.maps.GroundOverlay(
'https://developers.google.com/maps/documentation/' +
'javascript/examples/full/images/talkeetna.png', {
north: nw.lat(),
south: se.lat(),
west: nw.lng(),
east: se.lng()
}, {
map: map
});
}
google.maps.event.addDomListener(window, 'load', initialize);
html,
body,
#map_canvas {
height: 100%;
margin: 0;
padding: 0;
}
<div id="map_canvas"></div>
<script src="https://maps.googleapis.com/maps/api/js?v=3&libraries=geometry"></script>
Are you averse to using a library that already has support for Haversine calculation of center points? (With tests to boot)
Check out Geolib: https://github.com/manuelbieh/Geolib
var center = geolib.getCenter([
{latitude: 52.516272, longitude: 13.377722},
{latitude: 51.515, longitude: 7.453619},
{latitude: 51.503333, longitude: -0.119722}
]);
console.log(center);
// Output:
//
// {
// "latitude": "52.009802",
// "longitude": "6.629000",
// "distance": 932.209
// }
A codepen demo you can play with: http://codepen.io/anon/pen/grbGrz/?editors=1010
You can always pare it down to just the function you need.
You'll likely require the Haversine formula for such a calculation. The math involved is obviously at a higher level than is typical for SO answers though so your question might actually belong on gis or math stack exchanges where some more experienced SO users might be able to give you a more detailed answer / example.
lest start from beginning of your query. you have two latlng and now you want to get the latlng of the rectangle.
we will go with the calculation part first and then to the programming part. the assumptions are-
center point = e
top left = A
top right = B
bottom right = C
bottom left = D
mid point of AD=f
mid point of AB=g
Calculation Part
location g parameters- lat-A.lat, long-e.long
location f parameters- lat-e.lat, long-A.long
distance of A to g is = A.distanceTo(g)
distance of A to f is = A.distanceTo(f)
point B = 2Ag from A
point C = 2Af from B
point D = 2Af from A
Programming Part
LatLng A = null, B = null, C = null, D = null, e = null, f = null, g = null,temp=null;
e.latitude = your center latitude value;
e.longitude = your center longitude value;
A.latitude=your top left point latitude value;
A.longitude=your top left point longitude value;
f.latitude = e.latitude;
f.longitude = A.longitude;
g.latitude = A.latitude;
g.longitude = e.longitude;
double[] Ag = new double[1];
double[] Af = new double[1];
Location.distanceBetween(A.latitude, A.longitude, g.latitude, g.longitude, Ag);
Location.distanceBetween(A.latitude, A.longitude, f.latitude, f.longitude, Af);
temp=getDestinationPoint(A,90,(2*Ag));
B.latitude=temp.latitude;
B.longitude=temp.longitude;
temp=getDestinationPoint(B,180,(2*Af));
C.latitude=temp.latitude;
C.longitude=temp.longitude;
temp=getDestinationPoint(A,180,(2*Af));
D.latitude=temp.latitude;
D.longitude=temp.longitude;
private LatLng getDestinationPoint (LatLng source,double brng, double dist){
dist = dist / 6371;
brng = Math.toRadians(brng);
double lat1 = Math.toRadians(source.latitude), lon1 = Math.toRadians(source.longitude);
double lat2 = Math.asin(Math.sin(lat1) * Math.cos(dist) +
Math.cos(lat1) * Math.sin(dist) * Math.cos(brng));
double lon2 = lon1 + Math.atan2(Math.sin(brng) * Math.sin(dist) *
Math.cos(lat1),
Math.cos(dist) - Math.sin(lat1) *
Math.sin(lat2));
if (Double.isNaN(lat2) || Double.isNaN(lon2)) {
return null;
}
return new LatLng(Math.toDegrees(lat2), Math.toDegrees(lon2));
}
Explanation
the point f and g are the mid points of the line AD and AB respectively. we can get it by altering the lat and long value of A and e points. and by these two lengths (Af and Ag) we can get the four latlng points of the rectangle as you require.
thank you
Use the below javascript function for getting lat/long list of the rectangle based on center and distance.latLngArr is a list of rectangle points.
Number.prototype.degreeToRadius = function () {
return this * (Math.PI / 180);
};
Number.prototype.radiusToDegree = function () {
return (180 * this) / Math.PI;
};
function getBoundingBox(fsLatitude, fsLongitude, fiDistanceInKM) {
if (fiDistanceInKM == null || fiDistanceInKM == undefined || fiDistanceInKM == 0)
fiDistanceInKM = 1;
var MIN_LAT, MAX_LAT, MIN_LON, MAX_LON, ldEarthRadius, ldDistanceInRadius, lsLatitudeInDegree, lsLongitudeInDegree,
lsLatitudeInRadius, lsLongitudeInRadius, lsMinLatitude, lsMaxLatitude, lsMinLongitude, lsMaxLongitude, deltaLon;
// coordinate limits
MIN_LAT = (-90).degreeToRadius();
MAX_LAT = (90).degreeToRadius();
MIN_LON = (-180).degreeToRadius();
MAX_LON = (180).degreeToRadius();
// Earth's radius (km)
ldEarthRadius = 6378.1;
// angular distance in radians on a great circle
ldDistanceInRadius = fiDistanceInKM / ldEarthRadius;
// center point coordinates (deg)
lsLatitudeInDegree = fsLatitude;
lsLongitudeInDegree = fsLongitude;
// center point coordinates (rad)
lsLatitudeInRadius = lsLatitudeInDegree.degreeToRadius();
lsLongitudeInRadius = lsLongitudeInDegree.degreeToRadius();
// minimum and maximum latitudes for given distance
lsMinLatitude = lsLatitudeInRadius - ldDistanceInRadius;
lsMaxLatitude = lsLatitudeInRadius + ldDistanceInRadius;
// minimum and maximum longitudes for given distance
lsMinLongitude = void 0;
lsMaxLongitude = void 0;
// define deltaLon to help determine min and max longitudes
deltaLon = Math.asin(Math.sin(ldDistanceInRadius) / Math.cos(lsLatitudeInRadius));
if (lsMinLatitude > MIN_LAT && lsMaxLatitude < MAX_LAT) {
lsMinLongitude = lsLongitudeInRadius - deltaLon;
lsMaxLongitude = lsLongitudeInRadius + deltaLon;
if (lsMinLongitude < MIN_LON) {
lsMinLongitude = lsMinLongitude + 2 * Math.PI;
}
if (lsMaxLongitude > MAX_LON) {
lsMaxLongitude = lsMaxLongitude - 2 * Math.PI;
}
}
// a pole is within the given distance
else {
lsMinLatitude = Math.max(lsMinLatitude, MIN_LAT);
lsMaxLatitude = Math.min(lsMaxLatitude, MAX_LAT);
lsMinLongitude = MIN_LON;
lsMaxLongitude = MAX_LON;
}
return [
lsMinLatitude.radiusToDegree(),
lsMinLongitude.radiusToDegree(),
lsMaxLatitude.radiusToDegree(),
lsMaxLongitude.radiusToDegree()
];
};
use the below code to generate a lat/long array of rectanlge.
var lsRectangleLatLong = getBoundingBox(parseFloat(latitude), parseFloat(longitude), lsDistance);
if (lsRectangleLatLong != null && lsRectangleLatLong != undefined) {
latLngArr.push({ lat: lsRectangleLatLong[0], lng: lsRectangleLatLong[1] });
latLngArr.push({ lat: lsRectangleLatLong[0], lng: lsRectangleLatLong[3] });
latLngArr.push({ lat: lsRectangleLatLong[2], lng: lsRectangleLatLong[3] });
latLngArr.push({ lat: lsRectangleLatLong[2], lng: lsRectangleLatLong[1] });
}
I am using Bing maps to display markers on the map.
Now I am adding a functionality where I allow the user to draw a circle around any marker of his choice and let him specify the radius of the circle in kilometres.
I want the circle(polygon) to contain markers within the latitude/longitude bounds of that circle and the markers outside of the circle to disappear.
How do I achieve this?
You have provided no code.
However, I was involved in a similar project so I have an idea what you are talking about.
SInce you are looking for custom polygon you can have a look at this link.
Another way to do it would be to the x,y coordinates of the marker and using Javascript to draw a circle around the map.
THIS JAVASCRIPT SHOULD HELP
function drawCircle(radius, origin) {
var RadPerDeg = Math.PI / 180;
var earthRadius = 3959;
var lat = origin.latitude * RadPerDeg;
var lon = origin.longitude * RadPerDeg;
var locs = new Array();
var AngDist = parseFloat(radius) / earthRadius;
for (x = 0; x <= 360; x++) { //making a 360-sided polygon
var pLatitude, pLongitude;
// With a nice, flat earth we could just say p2.Longitude = lon * sin(brng) and p2.Latitude = lat * cos(brng)
// But it ain't, so we can't. See http://www.movable-type.co.uk/scripts/latlong.html
brng = x * RadPerDeg;
pLatitude = Math.asin(Math.sin(lat) * Math.cos(AngDist) + Math.cos(lat) * Math.sin(AngDist) * Math.cos(brng)); //still in radians
pLongitude = lon + Math.atan2(Math.sin(brng) * Math.sin(AngDist) * Math.cos(lat), Math.cos(AngDist) - Math.sin(lat) * Math.sin(pLatitude));
pLatitude = pLatitude / RadPerDeg;
pLongitude = pLongitude / RadPerDeg;
locs.push(new MM.Location(pLatitude, pLongitude));
};
circle = new MM.Polyline(locs, { visible: true, strokeThickness: 2, strokeDashArray: "1", strokeColor: new MM.Color(200, 0, 0, 200, 0) });
map.entities.push(circle);
};
Say I have a GPS coord say A (in longitude-latitude decimal form then I want to create a zone of 30 meters radius (a circle) so that I can trap any device(with GPS coord) which enters that zone, how to do it ? Thanks
Take a look at this javascript example, but it's easy to implement on any other language.
Main code:
var earthRadiusKm = 3437.74677 * 1.1508 * 1.6093470878864446;
function GeoArea(centerLat, centerLng, distanceKm, northPoint, southPoint, eastPoint, westPoint) {
this.northPoint = northPoint;
this.southPoint = southPoint;
this.eastPoint = eastPoint;
this.westPoint = westPoint;
this.inArea = function (lat, lng) {
var inBox = southPoint.lat <= lat && lat <= northPoint.lat && westPoint.lng <= lng && lng <= eastPoint.lng;
if (inBox) {
var distanceFromCenterKm = calcDistance(centerLat, centerLng, lat, lng);
return distanceFromCenterKm <= distanceKm;
} else {
return false;
}
}
}
function GeoPoint(lat, lng) {
this.lat = lat;
this.lng = lng;
}
function toDegrees(radians) {
return radians / (Math.PI / 180);
}
function toRadians(degrees) {
return Math.PI / 180 * degrees;
}
function calcDistance(latA, lngA, latB, lngB) {
var rLatA = toRadians(latA);
var rLatB = toRadians(latB);
var rHalfDeltaLat = toRadians((latB - latA) / 2);
var rHalfDeltaLng = toRadians((lngB - lngA) / 2);
return 2 * earthRadiusKm * Math.asin(Math.sqrt(Math.pow(Math.sin(rHalfDeltaLat), 2) + Math.cos(rLatA) * Math.cos(rLatB) * Math.pow(Math.sin(rHalfDeltaLng), 2)));
}
function findPoint(lat, lng, bearing, distance) {
var rLat = toRadians(lat);
var rLng = toRadians(lng);
var rBearing = toRadians(bearing);
var rAngDist = distance / earthRadiusKm;
var rLatB = Math.asin(Math.sin(rLat) * Math.cos(rAngDist) + Math.cos(rLat) * Math.sin(rAngDist) * Math.cos(rBearing));
var rLngB = rLng + Math.atan2(Math.sin(rBearing) * Math.sin(rAngDist) * Math.cos(rLat), Math.cos(rAngDist) - Math.sin(rLat) * Math.sin(rLatB));
var pLat = toDegrees(rLatB);
var pLng = toDegrees(rLngB);
return new GeoPoint(pLat, pLng);
}
function calcArea(lat, lng, distanceKm) {
var northPoint = findPoint(lat, lng, 0, distanceKm);
var eastPoint = findPoint(lat, lng, 90, distanceKm);
var southPoint = findPoint(lat, lng, 180, distanceKm);
var westPoint = findPoint(lat, lng, 270, distanceKm);
return new GeoArea(lat, lng, distanceKm, northPoint, southPoint, eastPoint, westPoint);
}
Usage example:
// calculate area with center in lat:55.742793 lng:37.615401
// and distance in 23 km
var area = calcArea(55.742793, 37.615401, 23);
//returns true
area.inArea(55.714735, 37.629547);
//returns false
area.inArea(55.693842, 38.015442);
I have a Google Maps Circle drawn on v3 api. When the user has plotted there circle (or polygon if they choose), they can save the data to the server. If the user has picked a radial search, the Centre coordinates and the radius in feet is stored to the database. This means when the user reloads his search, it can pull through the circle again (like below).
I'm having 1 problem, however, which is when the user selects what search they would like to use. It loads the polygon fine, if they drew a polygon, and if it's a circle it pulls through the marker on the center. However what I need is a function in static maps to draw a circle.
A bit late in the game, but nothing I found solved my issue (serverside php only, no javascript).
I ended up getting there in the end and have detailed my method here: http://jomacinc.com/map-radius/ and the short version is below.
This PHP function will return an encoded polyline string of lat/lng points in a circle around the specified point, and at the specified radius. The function requires Gabriel Svennerberg’s PHP polyline encoding class available here (http://www.svennerberg.com/examples/polylines/PolylineEncoder.php.txt).
function GMapCircle($Lat,$Lng,$Rad,$Detail=8){
$R = 6371;
$pi = pi();
$Lat = ($Lat * $pi) / 180;
$Lng = ($Lng * $pi) / 180;
$d = $Rad / $R;
$points = array();
$i = 0;
for($i = 0; $i <= 360; $i+=$Detail):
$brng = $i * $pi / 180;
$pLat = asin(sin($Lat)*cos($d) + cos($Lat)*sin($d)*cos($brng));
$pLng = (($Lng + atan2(sin($brng)*sin($d)*cos($Lat), cos($d)-sin($Lat)*sin($pLat))) * 180) / $pi;
$pLat = ($pLat * 180) /$pi;
$points[] = array($pLat,$pLng);
endfor;
require_once('PolylineEncoder.php');
$PolyEnc = new PolylineEncoder($points);
$EncString = $PolyEnc->dpEncode();
return $EncString['Points'];
}
You can now the use the above function to create a static map.
/* set some options */
$MapLat = '-42.88188'; // latitude for map and circle center
$MapLng = '147.32427'; // longitude as above
$MapRadius = 100; // the radius of our circle (in Kilometres)
$MapFill = 'E85F0E'; // fill colour of our circle
$MapBorder = '91A93A'; // border colour of our circle
$MapWidth = 640; // map image width (max 640px)
$MapHeight = 480; // map image height (max 640px)
/* create our encoded polyline string */
$EncString = GMapCircle($MapLat,$MapLng, $MapRadius);
/* put together the static map URL */
$MapAPI = 'http://maps.google.com.au/maps/api/staticmap?';
$MapURL = $MapAPI.'center='.$MapLat.','.$MapLng.'&size='.$MapWidth.'x'.$MapHeight.'&maptype=roadmap&path=fillcolor:0x'.$MapFill.'33%7Ccolor:0x'.$MapBorder.'00%7Cenc:'.$EncString.'&sensor=false';
/* output an image tag with our map as the source */
echo '<img src="'.$MapURL.'" />'
function GMapCircle(lat,lng,rad,detail=8){
var uri = 'https://maps.googleapis.com/maps/api/staticmap?';
var staticMapSrc = 'center=' + lat + ',' + lng;
staticMapSrc += '&size=100x100';
staticMapSrc += '&path=color:0xff0000ff:weight:1';
var r = 6371;
var pi = Math.PI;
var _lat = (lat * pi) / 180;
var _lng = (lng * pi) / 180;
var d = (rad/1000) / r;
var i = 0;
for(i = 0; i <= 360; i+=detail) {
var brng = i * pi / 180;
var pLat = Math.asin(Math.sin(_lat) * Math.cos(d) + Math.cos(_lat) * Math.sin(d) * Math.cos(brng));
var pLng = ((_lng + Math.atan2(Math.sin(brng) * Math.sin(d) * Math.cos(_lat), Math.cos(d) - Math.sin(_lat) * Math.sin(pLat))) * 180) / pi;
pLat = (pLat * 180) / pi;
staticMapSrc += "|" + pLat + "," + pLng;
}
return uri + encodeURI(staticMapSrc);}
Javascript version
Based on the answer from Jomac, Here is a Java/Android version of the same code.
It uses the PolyUtil class from Google Maps Android API Utility Library to encode the path.
import android.location.Location;
import com.google.android.gms.maps.model.LatLng;
import com.google.maps.android.PolyUtil;
import java.util.ArrayList;
public class GoogleStaticMapsAPIServices
{
private static final double EARTH_RADIUS_KM = 6371;
private static String GOOGLE_STATIC_MAPS_API_KEY = "XXXXXXXXXXXXX";
public static String getStaticMapURL(Location location, int radiusMeters)
{
String pathString = "";
if (radiusMeters > 0)
{
// Add radius path
ArrayList<LatLng> circlePoints = getCircleAsPolyline(location, radiusMeters);
if (circlePoints.size() > 0)
{
String encodedPathLocations = PolyUtil.encode(circlePoints);
pathString = "&path=color:0x0000ffff%7Cweight:1%7Cfillcolor:0x0000ff80%7Cenc:" + encodedPathLocations;
}
}
String staticMapURL = "https://maps.googleapis.com/maps/api/staticmap?size=640x320&markers=color:red%7C" +
location.getLatitude() + "," + location.getLongitude() +
pathString +
"&key=" + GOOGLE_STATIC_MAPS_API_KEY;
return staticMapURL;
}
private static ArrayList<LatLng> getCircleAsPolyline(Location center, int radiusMeters)
{
ArrayList<LatLng> path = new ArrayList<>();
double latitudeRadians = center.getLatitude() * Math.PI / 180.0;
double longitudeRadians = center.getLongitude() * Math.PI / 180.0;
double radiusRadians = radiusMeters / 1000.0 / EARTH_RADIUS_KM;
double calcLatPrefix = Math.sin(latitudeRadians) * Math.cos(radiusRadians);
double calcLatSuffix = Math.cos(latitudeRadians) * Math.sin(radiusRadians);
for (int angle = 0; angle < 361; angle += 10)
{
double angleRadians = angle * Math.PI / 180.0;
double latitude = Math.asin(calcLatPrefix + calcLatSuffix * Math.cos(angleRadians));
double longitude = ((longitudeRadians + Math.atan2(Math.sin(angleRadians) * Math.sin(radiusRadians) * Math.cos(latitudeRadians), Math.cos(radiusRadians) - Math.sin(latitudeRadians) * Math.sin(latitude))) * 180) / Math.PI;
latitude = latitude * 180.0 / Math.PI;
path.add(new LatLng(latitude, longitude));
}
return path;
}
}
I think it is not possible to draw a circle on a static Google map. You would need to approximate the circle by a polyline (best in encoded format). This has already been mentioned in Stackoverflow and it is demonstrated e.g. by Free Map Tools.
Sharing my C# version
private string GMapCircle(double lat, double lng, double rad, int detail = 8)
{
const string uri = "https://maps.googleapis.com/maps/api/staticmap?";
var staticMapSrc = "center=" + lat + "," + lng;
staticMapSrc += "&zoom=16";
staticMapSrc += "&maptype=satellite";
staticMapSrc += "&key=[YOURKEYHERE]";
staticMapSrc += "&size=640x426";
staticMapSrc += "&path=color:0xff0000ff:weight:1";
const int r = 6371;
const double pi = Math.PI;
var latAux = (lat * pi) / 180;
var longAux = (lng * pi) / 180;
var d = (rad / 1000) / r;
var i = 0;
if (rad > 0)
{
for (i = 0; i <= 360; i += detail)
{
var brng = i * pi / 180;
var pLat = Math.Asin(Math.Sin(latAux) * Math.Cos(d) + Math.Cos(latAux) * Math.Sin(d) * Math.Cos(brng));
var pLng = ((longAux + Math.Atan2(Math.Sin(brng) * Math.Sin(d) * Math.Cos(latAux), Math.Cos(d) - Math.Sin(latAux) * Math.Sin(pLat))) * 180) / pi;
pLat = (pLat * 180) / pi;
staticMapSrc += "|" + pLat + "," + pLng;
}
}
else
{
//TODO - Add marker
}
return uri + staticMapSrc;
}
This solution uses the significantly more versatile Canvas API to draw over the map image . All code is in Typescript, so simply remove type declarations if you're using Javascript.
ADVANGES OF USING CANVAS:
Its easier to draw shapes on.
Those shapes can also be revised without re-requesting the map image from Google.
The drawing 'layer' can be serialized independently of the underlying map image.
USAGE:
// DEFINE BASIC VARIABLES
const latitude: -34.3566871,
const longitude: 18.4967666
const mapZoom = 12;
const imageWidth: 100;
const imageHeight: 100;
// INVOKE UTILITY FUNCTION
savePlaceImage({
// SET BASIC PROPS
latitude,
longitude,
mapZoom,
imageWidth,
imageHeight,
fileName: 'Cape Point',
// DRAW IMAGE USING CANVAS API
draw: ctx => {
// draw location as dot
ctx.fillStyle = '#FF3366';
ctx.beginPath();
ctx.arc(imageWidth / 2, imageHeight / 2, 10, 0, 2 * Math.PI);
ctx.fill();
// draw circle around location with 1 kilometer radius
ctx.strokeStyle = '#0000FF';
ctx.beginPath();
ctx.arc(imageWidth / 2, imageHeight / 2, pixelsPerMeter(latitude) * 1000, 0, 2 * Math.PI);
ctx.stroke();
}
})
UTILITIES:
function savePlaceImage(
config: {
latitude: number,
longitude: number,
mapZoom: number,
imageWidth: number,
imageHeight: number,
fileName: string,
draw: (ctx: CanvasRenderingContext2D) => void,
},
) {
// DOWNLOAD MAP IMAGE FROM GOOGLE'S STATIC MAPS API AS A BLOB
return from(axios.get<Blob>(`https://maps.googleapis.com/maps/api/staticmap`, {
params: {
key: GOOGLE_MAPS_API_KEY,
size: `${config.imageWidth}x${config.imageHeight}`,
zoom: `${config.mapZoom}`,
center: `${config.latitude},${config.longitude}`,
style: 'feature:all|element:labels|visibility:off',
},
responseType: 'blob',
// CONVERT BLOB TO BASE64 ENCODED STRING
}).then(response => {
const reader = new FileReader();
reader.readAsDataURL(response.data);
return new Promise<string>(resolve => reader.onloadend = () => resolve(reader.result as string));
// CREATE HTML IMG ELEMENT, SET IT'S SRC TO MAP IMAGE, AND WAIT FOR IT TO LOAD
}).then(response => {
const image = document.createElement('img');
image.src = response;
return new Promise<HTMLImageElement>(resolve => image.onload = () => resolve(image));
// CREATE HTML CANVAS ELEMENT, THEN DRAW ON TOP OF CANVAS USING CANVAS API, THEN CONVERT TO BLOB
}).then(image => {
const canvas = document.createElement('canvas');
canvas.width = config.imageWidth;
canvas.height = config.imageHeight;
const ctx = canvas.getContext('2d');
ctx.drawImage(image, 0, 0);
config.draw(ctx);
return new Promise<Blob>(resolve => canvas.toBlob(blob => resolve(blob)));
// ATTACH BLOB TO HTML FORM WHICH CONVERTS IT TO A FILE TO BE POSTED, THEN SEND FILE TO SERVER
}).then(blob => {
const form = new FormData();
form.append('blob', blob, `${config.fileName}.png`);
const file = form.get('blob') as File;
return axios.post<{ file }>('https://www.my-api.com/save-image', form);
}));
}
function pixelsPerMeter(latitude: number) {
const radiusOfEarthInKilometers = 6371;
return Math.cos(latitude * Math.PI / 180) * 2 * Math.PI * radiusOfEarthInKilometers / (256 * Math.pow(2, 12));
}
python version, polyline library used for encoding the polygon
import math, polyline
def g_map_circle(lat,lng,radius,detail=8):
points = []
r = 6371
pi = math.pi
_lat = (lat * pi) /180
_lng = (lng * pi) /180
d = radius / r
i = 0
while i <= 360:
i = i + detail
brng = i * pi /180
p_lat = math.asin(math.sin(_lat) * math.cos(d) + math.cos(_lat) * math.sin(d) * math.cos(brng));
p_lng = (_lng + math.atan2(math.sin(brng) * math.sin(d) * math.cos(_lat), math.cos(d) - math.sin(_lat) * math.sin(p_lat))) * 180 / pi
p_lat = (p_lat * 180) /pi
points.append((p_lat,p_lng))
return polyline.encode(points)
I have a point (X,Y) and I want to create a square , Google maps LatLngBounds object so to make geocode requests bias only into this LatLngBound region.
How can I create such a LatLngBounds square with center the given point? I have to find the NE and SW point. But how can I find it given a distance d and a point (x,y)?
Thanks
You can also getBounds from a radius defined as a circle and leave the trig to google.
new google.maps.Circle({center: latLng, radius: radius}).getBounds();
well that's very complicated. for a rough box try this:
if (typeof(Number.prototype.toRad) === "undefined") {
Number.prototype.toRad = function() {
return this * Math.PI / 180;
}
}
if (typeof(Number.prototype.toDeg) === "undefined") {
Number.prototype.toDeg = function() {
return this * 180 / Math.PI;
}
}
var dest = function(lat,lng,brng, dist) {
this._radius = 6371;
dist = typeof(dist) == 'number' ? dist : typeof(dist) == 'string' && dist.trim() != '' ? +dist : NaN;
dist = dist / this._radius;
brng = brng.toRad();
var lat1 = lat.toRad(),
lon1 = lng.toRad();
var lat2 = Math.asin(Math.sin(lat1) * Math.cos(dist) + Math.cos(lat1) * Math.sin(dist) * Math.cos(brng));
var lon2 = lon1 + Math.atan2(Math.sin(brng) * Math.sin(dist) * Math.cos(lat1), Math.cos(dist) - Math.sin(lat1) * Math.sin(lat2));
lon2 = (lon2 + 3 * Math.PI) % (2 * Math.PI) - Math.PI;
return (lat2.toDeg() + ' ' + lon2.toDeg());
}
var northEastCorner = dest(centreLAT,centreLNG,45,10);
var southWestCorner = dest(centreLAT,centreLNG,225,10);
EDIT
The above was they way to do it way back in 2011 when I wrote it. These days the google maps api has come on a loooong way. The answer by #wprater is much neater and uses some of the newer api methods.
Wouldn't it work to simply add/subtract d/2 to your x/y locations?
Given x,y as the center point:
NW = x-(d/2),y-(d/2)
SE = x+(d/2),y+(d/2)
Don't trust me on this, though - I am terrible at math :)
This assumes d as a "diameter", rather than a radius. If "d" is the radius, don't bother with the divide-by-two part.