Calculating the diameter of a google map - google-maps

I want to display a google map on my site along with a caption of how large of an area is covered in miles. I will use the area between the left and right borders for this.
For example under the map it will say "3 miles" and then when the user zooms in, it will change to "1 mile" and so on
Thanks

The API has a distance method which returns the distance in meters. So you can do it like this:
var bounds = myMap.getBounds();
google.maps.geometry.spherical.computeDistanceBetween(bounds.getNorthEast(), bounds.getSouthWest());

Start by calling the getBounds() method on the Map object. This will return a LatLngBounds object from which you'll know the latitude and longitude of the bounding box the map defines.
Now that you're armed with the latitude and longitudes you'll simply need to apply the Haversine formula to computer the distance. For a good overview of this equation, and an example in Javascript see this page. An excerpt of which is:
var R = 6371; // km
var dLat = (lat2-lat1).toRad();
var dLon = (lon2-lon1).toRad();
var lat1 = lat1.toRad();
var lat2 = lat2.toRad();
var a = Math.sin(dLat/2) * Math.sin(dLat/2) +
Math.sin(dLon/2) * Math.sin(dLon/2) * Math.cos(lat1) * Math.cos(lat2);
var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));
var d = R * c;
Since the above equation operates in kilometers, and you asked for miles, one additional modification you could perform would be to convert the output (d) to miles. Converting kilometers to miles is simply a matter of dividing by 1.609344. So, you could simply:
d /= 1.609344;
Expanding upon this, you could then even allow the user to choose between miles/kilometers, and wrap the whole thing up in an if statement:
if(miles)
d /= 1.609344;

Related

Get center in Cesium Map

I need to know what is the current center of the Cesium Map.
I tried to use viewer.camera.position but it always gives the same z value (x: 16921255.101297915, y: 5578093.302269477, z: 12756274) and I'm not sure about the x and y values. Are they in meters?
Thanks a lot!
EDIT: Solution
With all the help I got (thanks!) I put this together:
getPosition(){
if (viewer.scene.mode == 3) {
var windowPosition = new Cesium.Cartesian2(viewer.container.clientWidth / 2, viewer.container.clientHeight / 2);
var pickRay = viewer.scene.camera.getPickRay(windowPosition);
var pickPosition = viewer.scene.globe.pick(pickRay, viewer.scene);
var pickPositionCartographic = viewer.scene.globe.ellipsoid.cartesianToCartographic(pickPosition);
console.log(pickPositionCartographic.longitude * (180 / Math.PI));
console.log(pickPositionCartographic.latitude * (180 / Math.PI));
} else if (viewer.scene.mode == 2) {
var camPos = viewer.camera.positionCartographic;
console.log(camPos.longitude * (180 / Math.PI));
console.log(camPos.latitude * (180 / Math.PI));
}
};
This function gives longitude/latitude coordinates in degrees.
viewer.camera.position gives you the position at which camera is located in X,Y,Z coordinates in meters in relation to earth center.
Depending on which scene mode you are using approach is different:
SCENE3D:
In order to see at what is the camera looking at you need to get the intersect point of camera's pick ray and map.
function getMapCenter() {
var windowPosition = new Cesium.Cartesian2(viewer.container.clientWidth / 2, viewer.container.clientHeight / 2);
var pickRay = viewer.scene.camera.getPickRay(windowPosition);
var pickPosition = viewer.scene.globe.pick(pickRay, viewer.scene);
var pickPositionCartographic = viewer.scene.globe.ellipsoid.cartesianToCartographic(pickPosition);
console.log(pickPositionCartographic.longitude * (180/Math.PI));
console.log(pickPositionCartographic.latitude * (180/Math.PI));
}
Based on this thread.
Also try to check if camera is looking at the map, and not a the sky.
SCENE2D:
This is a simple 2D view with camera pointing directly down.
From docs:
2D mode. The map is viewed top-down with an orthographic projection
var camPos = viewer.camera.positionCartographic;
console.log(camPos.longitude * (180/Math.PI));
console.log(camPos.latitude * (180/Math.PI));
Remaining case is 2.5D or COLUMBUS_VIEW

Google maps v3 - Draw a polygon to show photo take angle

I am displaying in google maps (v3) markers with the position where the photograph was taken and position of the subject and tracing a line to show direction in which photo was taken. I have also calculated the distance and the angle from camera position.
What I am trying now is to show the view from camera with a triangle that opens, lets say 30 degrees toward the subject. Seem to me is a third grade math, but can't figure out after 25 years, I know how to draw the polygon/triangle but not really how to calculate the points at subject's distance about 30 degrees in both directions, of course taking in mind the heading angle.
Almost there...
Used the formula Red answered below to create a function (found I needed to convert: lat1, lon1 and bearing to radians before the math.
I call this function each time a marker changes to calculate again pos1 and pos2 of the triangle and change the paths to redraw it.
Thing now is that triangle shows up but facing all kind of directions but the proper one.
Question now is:
Google return the heading in degrees negative to West and positive to East (-180/180) and seems that the formula need the bearing (heading) in 360 degress? Right now function CameraView(75) display correctly but I am passing the angle as 75 degrees instead of 15 degrees (to have 15 degrees view left, and 15 to right).
function getVertex(brng) {
var R = 6366.707;
var d = parseFloat( getObj('GPSDestDistance').value ) * 1.5 //distance on form field
//position of Camera
var lat1 = deg2rad( markerCam.getPosition().lat() )
var lon1 = deg2rad( markerCam.getPosition().lng() )
var lat2 = Math.asin( Math.sin(lat1) * Math.cos(d/R) + Math.cos(lat1) * Math.sin(d/R) * Math.cos(brng) );
var lon2 = lon1 + Math.atan2( Math.sin(brng) * Math.sin(d/R) * Math.cos(lat1), Math.cos(d/R) - Math.sin(lat1) * Math.sin(lat2) );
lat2 = rad2deg( lat2 )
lon2 = rad2deg( lon2 )
var pos = new google.maps.LatLng(lat2, lon2)
return pos;
}
function CameraView(angle) {
var brng = deg2rad( parseFloat( getObj('GPSDestBearing').value ) ); //get heading from form
if(brng<0){
//brng = Math.round(-brng / 360 + 180)
}
var pos1 = markerCam.getPosition();
var pos2 = getVertex(brng - angle);
var pos3 = getVertex(brng + angle);
var paths = [ pos1, pos2, pos3 ];
poly.setPath(paths);
}
function deg2rad(x) { return x * (Math.PI / 180); }
function rad2deg(x) { return x * (180 / Math.PI); }
A simpler way: use google maps geometry library
calculateAngle: function(subjectMarker, cameraMarker, angle) {
var distance, heading, left, right;
// Get the heading between two markers
heading = google.maps.geometry.spherical.computeHeading(subjectMarker.getPosition(), cameraMarker.getPosition());
// convert heading range from [-180,180] to [0,360]
heading = ((heading - -180) * 360) / 360;
// Get the distance between two markers
distance = google.maps.geometry.spherical.computeDistanceBetween(cameraMarker.getPosition(), subjectMarker.getPosition());
// Calculate angle
left = new google.maps.geometry.spherical.computeOffset(cameraMarker.getPosition(), distance / Math.cos(Math.PI * (angle / 2) / 180), heading - (angle / 2));
right = new google.maps.geometry.spherical.computeOffset(cameraMarker.getPosition(), distance / Math.cos(Math.PI * (angle / 2) / 180), heading + (angle / 2));
// Return an array of `google.maps.LatLng` objects for use when drawing a polygon.
return [cameraMarker.getPosition(), left, right];
}
The formula to get an endpoint latitude and longitude (lat 2,lon2) (in radians) from a starting location (lat1,lon1) (also in radians), range (d), radius of the Earth (R) and bearing (brng) is:
var lat2 = Math.asin( Math.sin(lat1)*Math.cos(d/R) + Math.cos(lat1)*Math.sin(d/R)*Math.cos(brng) );
var lon2 = lon1 + Math.atan2(Math.sin(brng)*Math.sin(d/R)*Math.cos(lat1), Math.cos(d/R)-Math.sin(lat1)*Math.sin(lat2));
Your start point will be one of the points of the triangle polygon. The other two can be found using this code snippet, putting in your bearing +/- 15 degrees (for the 30 degree triangle example) and a range that depends entirely on how big you want the triangle.

Translating LAT, LONG to actual Screen X,Y coordinates on a Equirectangular Map Projection in AS3

I am doing a little project on Geo Locations. I need to highlight certain cities on an a map that is in equirectangular projection. I have got the LON LAT values for those cities, I need to find a way to translate those values to actual x,y coordinates on screen that will work with any size of map (with equirectangular projection). I have found a code but that does it for Mercator projection. Any Clue ?Thanks
That is quite simpler than doing Mercator projection, try this function:
public function getXY(lat:Number, lng:Number):Point
{
var screenX:Number = ((lng + 180) * (mapWidth / 360));
var screenY:Number = (((lat * -1) + 90) * (mapHeight/ 180));
return new Point(screenX,screenY);
}
mapWidth and mapHeight should be the width and height of your Map's Image that you are using. This function will return you the translated coordinates from LAT LON to X, Y of your screen with respect to your map size.

finding closer points to create markers on google map

I have a multidimensional array of latitudes and longitudes, and one other single marker "m". I need to get the two most closest points to "m" from the array for creating two other markers. Any help would be highly appreciated.
this is the array of lats and lons
var locations= [
['loc1', 54.1121824,-1.3983992],
['loc2', 54.2121824,-1.4323992],
['loc3', 54.4121824,-1.5993992],
['loc4', 54.3871874,-1.6773992],
['loc5', 54.1963824,-1.5983992]
];
I want to get the most two closest points to m=54.1143824,-1.4963992 for creating two markers from them
One of the components is using the geometry library function computeDistanceBetween(from:LatLng, to:LatLng, radius?:number) where radius is optional (Earth's radius).
You must include geometry with the JS API using the libraries parameter:
<script type="text/javascript" src="http://maps.googleapis.com/maps/api/js?libraries=geometry&sensor=false"></script>
Now you can loop through your data, saving the computed distance between each coordinate and the special marker m. The result will be in meters by default (changing the radius optionally will give different units)
For each row in the coordinates data, make a rowLatLng = new google.maps.LatLng(row[1], row[2])
google.maps.geometry.spherical.computeDistanceBetween(rowLatLng, m.getPosition())
Then, the best way I can think of extracting the two closest points is using an object { locationname: "loc1", distance: 20 } to save which point is being compared to marker "m", and what the computed distance is. Even better, could be to save the "row" index from the locations variable so you can pull the coordinate easily.
An array of these objects can then be sorted by distance. I found a post here: Sorting an array of JavaScript objects with the following answer for sorting homes by their price:
homes.sort(function(a,b) { return parseFloat(a.price) - parseFloat(b.price) } );
I have some code for that on my main computer but basically here's what you have to do:
Loop through the coordinates and calculate the distance between each one and m (Haversine Formula)
Store each distance with the position's name in an array
Sort the array
Bingo.
EDIT:
Some code to calculate Haversine:
Number.prototype.toRad=function() {
return this * (Math.PI / 180);
}
function Haversine=function(lat1, lon1, lat2, lon2) {
var R = 6371; // km
var dLat = (lat2-lat1).toRad();
var dLon = (lon2-lon1).toRad();
var lat1 = lat1.toRad();
var lat2 = lat2.toRad();
var a = Math.sin(dLat/2) * Math.sin(dLat/2) + Math.sin(dLon/2) * Math.sin(dLon/2) * Math.cos(lat1) * Math.cos(lat2);
var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));
var d = R * c;
return d;
}

google maps. how to create a LatLngBounds rectangle (square) given coords of a central point

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.