I am trying to develop a "divide and conquer" algorithm to determine squares of latitude and longitude.
I wish to start with an 800 mile x 800 mile box around the UK. Then divide this into four squares, and then recursively repeating this process until the squares are 25 miles square. This will then be used to filter out unwanted results from a proximity search in a database of locations.
However, the algorithm I have which applies an offset to a lat/long (see below code), is giving me problems. I have tried other ones, too, but with much the same results. I think it may be my understanding of applying a coordinate system to a sphere.
I would expect that with a starting point, moving east 800 miles, then moving west 800 miles would result in being returned to (approx) the same location. However, this is not the case:
var coord =
{
lat : 60.678413562308236,
lng : -12.5
};
// Apply a distance and bearing to a set of coords.
var addOffset = function(coord, distance, angle)
{
// Earth Radius
//var radius = 6378.14; // KM
var radius = 3958.8; // Miles
// Degrees to Radians
var lat = coord.lat * (Math.PI/180);
var lng = coord.lng * (Math.PI/180);
var bearing = angle * (Math.PI/180);
var lat2 = Math.asin(Math.sin(lat)*Math.cos(distance/radius) + Math.cos(lat)*Math.sin(distance/radius)*Math.cos(bearing));
var lng2 = lng + Math.atan2(Math.sin(bearing)*Math.sin(distance/radius)*Math.cos(lat), Math.cos(distance/radius)-Math.sin(lat)*Math.sin(lat2));
// back to degrees
lat2 = lat2 * (180/Math.PI);
lng2 = lng2 * (180/Math.PI);
return { lat : lat2, lng : lng2};
}
console.log("start");
console.log(coord);
console.log("Move 800 miles east");
coord = addOffset(coord, 800, 90.0) // East
console.log(coord);
console.log("Move 800 miles west");
coord = addOffset(coord, 800, 270.0) // West
console.log(coord);
Further, when "walking" an 800 mile square around the UK, and plotting the points on a Google Map, I get big problems! The below is starting north-west, going south 800 miles, then going east 800 miles, then north 800 miles, then west 800 miles. As you can see, it's gone quite wrong:
Here's a fiddle (couldn't work out how to get the map working on a code snippet here):
https://jsfiddle.net/leetaylor/aoxnsqeu/6/
Could anyone explain where I'm going wrong? Is it possible to divide up geography into squares using lat/longs?
The problem is that your addOffset doesn't do what you think it does. Quoting the source site
Given a start point, initial bearing, and distance, this will
calculate the destination point and final bearing travelling along
a (shortest distance) great circle arc.
My emphasis. So when you say you want an initial bearing of East, you aren't calculating where you end up if you go east; instead, you're calculating where you end up if you follow the great circle that going east to start with puts you on. If you start from a point in the northern hemisphere and head east or west using this rule, you will curve south towards the equator, exactly as you can see happening in your map.
Note that the due-north and due-south lines are perfect, because lines of longitude are great circles.
Now, since you just want lat-long 'squares', you don't need trigonometry at all - just move along lines of latitude and longitude. This means that the top and bottom edge of each 'square' won't actually be the same length, but at temperate latitudes like the UK it shouldn't be too bad.
Related
I'm developing a Web GIS Application using arcgis javascript Api and I need to drawing line from point1 by distance and angle. first step calculate point2 by this formula
point2X = point1.x + distance * Math.cos(angle)
point2Y = point1.y + distance * Math.sin(angle)
Distance unit 'Meter' and angle in 'radians'
Second Step: Draw line with point1 and point2. If the input distance is 1000 meters, the drawn line shows the length as 866 meters, when measured with arcgis measurement tool. Is coordinate system in this formula an impact?
Function:
function GetNewPoint(x, y, distance, angle) {
var alpha = ToRadian(angle);
var cos = Math.cos(alpha);
var sin = Math.sin(alpha);
var x2 = (cos * distance)+x ;
var y2 = (sin * distance)+y ;
return esri.geometry.xyToLngLat(x2, y2);
}
function ToRadian(angle) {
return (Math.PI / 180) * angle;
}
The map projection (the thing that is defined by your coordinate system) will absolutely impact the result of the measure.
"Every map projection causes distortion of shapes, areas, directions, and/or distances. Some projections such as Robinson or Winkel Tripel attempt to minimize distortion across the world through some compromise of all those factors. Other projections (such as UTM and State Plane) are designed for focused areas of the globe in order to keep the distortion minimal."
source: https://blogs.esri.com/esri/arcgis/2010/03/05/measuring-distances-and-areas-when-your-map-uses-the-mercator-projection/
Fortunately, the Web API that you are using has some methods to re-project your data before you do any measurement.
If you are interested in re-project a specific feature of your map, you can use something like this:
var sr = new esri.SpatialReference({wkid:32610})
// assuming you already referenced geometryService
geometryService.project([graphic], sr, function(projectedGraphic){
geometryService.areasAndLengths(projectedGraphic, function(result){
var perimeter = result.lengths[0];
var area = result.areas[0];
});
});
The previous example assumes the usage of a geometry service (you can find this at ArcGIS Online or at your ArcGIS for Server Instance) and is remotely processed.
You can find more information about Geometry Service at this link.
Let me know if this information helps to solve your problem.
Check this website he put all the equation you need to work with coordiantes and HERE is my solution to get the coordiantes of the new point.
I am creating list of circles on my map using a loop. The circle radius may differ for each loop.
The logic should not overlap two circles. For this I need the following :-
Start with lat lng (circle center) and draw a circle.
Move radius*2 kilometer ahead and get the center point for second circle and so on.
Problem :
I am facing problem in the second step given above. How should I calculate the next point(Circle center) in row ? The input that I have is center point of first circle and radius.
Any suggestions?
The approximate conversions are:
Latitude: 1 deg = 110.574 km
Longitude: 1 deg = 111.320*cos(latitude) km
This doesn't fully correct for the Earth's polar flattening -- for that you'd probably want a more complicated formula using the WGS84 reference ellipsoid (the model used for GPS). But the error is probably negligible for your purposes.
Source: http://en.wikipedia.org/wiki/Latitude
So you can calculate the distance you need to move on the map and the latitude, Longitude for the next point on the map.
However there is a library (I have never used it, nut hope it helps)
http://www.jstott.me.uk/jcoord/
I use ol3 as a map service.
I have made a linestring with two points with coordinates : [[0,0],[0,1000]] and calculated the distance using the vincenty formula. This resulted in 1000 meter, what is accurate.
But when i made another linestring for example [[4052627,3971934],[4052627,3972934]] vincenty distance was around 850 meters.
I dont know what i forgot here. Any way to correct that? I want to calculate epgs:3857 meters (units) for a given real distance.
You can use ol.sphere.haversineDistance:
var c1 = [4052627, 3971934];
var c2 = [4052627,3972934];
var wgs84Sphere = new ol.Sphere(6378137);
var length = wgs84Sphere.haversineDistance(
ol.proj.transform(c1, 'EPSG:3857', 'EPSG:4326'),
ol.proj.transform(c2, 'EPSG:3857', 'EPSG:4326'));
// 833.12 m
Distances are tricky. The fact that the map units of a coordinate system are in meters (as epsg:3857) doesn't mean that you can measure distances in meters directly. See https://en.wikipedia.org/wiki/List_of_map_projections, and look how many of those have the "equidistant" property.
I suggest you use turf.js to calculate accurate geodetic distances: http://turfjs.org/static/docs/module-turf_distance.html
After alot of search I've found this PDF document:
Web Mercator:
Non-Conformal, Non-Mercator
There is something called Point Scale Factor - according to the way web Mercator is projected - which has tow values, not one like normal Mercator , North/South Scale Factor and East/West Scale Factor.
in my program I've ignored the East/West Scale Factors because it's to much small.
Once I've calculated the scale factor the real distance is almost equal to scale_factor * epgs_3857_distence
I was hoping someone out there could provide me with an equation to calculate a 1km square (X from a.aaa to b.bbb, Y from c.ccc to c.ccc) around a given point, say lat = 53.38292839 and lon = -6.1843984? I'll also need 2km, 5km and 10km squares around a point.
I've tried googling around to no avail... It's late at night and was hoping someone might have quick fix handy before I delve into the trigonometry...
I'll be running all this in Javascript, although any language is fine.
If the world were a perfect sphere, according to basic trigonometry...
Degrees of latitude have the same linear distance anywhere in the world, because all lines of latitude are the same size. So 1 degree of latitude is equal to 1/360th of the circumference of the Earth, which is 1/360th of 40,075 km.
The length of a lines of longitude depends on the latitude. The line of longitude at latitude l will be cos(l)*40,075 km. One degree of longitude will be 1/360th of that.
So you can work backwards from that. Assuming you want something very close to one square kilometre, you'll want 1 * (360/40075) = 0.008983 degrees of latitude.
At your example latitude of 53.38292839, the line of longitude will be cos(53.38292839)*40075 = [approx] 23903.297 km long. So 1 km is 1 * (360/23903.297) = 0.015060 degrees.
In reality the Earth isn't a perfect sphere, it's fatter at the equator. And the above gives a really good answer for most of the useful area of the world, but is prone to go a little odd near the poles (where rectangles in long/lat stop looking anything like rectangles on the globe). If you were on the equator, for example, the hypothetical line of longitude is 0 km long. So how you'd deal with a need to count degrees on that will depend on why you want the numbers.
Here is something from my notes to be used on Android with its decimal GPS.
Lat Long:
NY City 40N 47 73W 58 40.783333 73.966667
Wash DC 38N 53 77W 02 38.883333 77.033333
yields = 209 miles !! VERY CLOSE
Distance (miles) (x) = 69.1 (lat2-lat1)
Distance(miles) (y) = 53.0 (long2 - long1)
As crow flys sqrt (x2 + y2) ... duh!#
delta(LAT) / Mile = .014472
delta(LONG) / Mile = .018519
Using a box as approximation
To find someone within 100 miles (100 north / 100 south, 100 E / 100 W)
From 0,0
-14.472 / + 14.472 , -18.519 / 18.519
A simpler way of generating a gps square given the centre would be to use the indirect Vincenty algorithm.The Javascript code here shows how to do it http://www.movable-type.co.uk/scripts/latlong.html.
Creating a square using a circle isn't to hard. Squares are equal distance to each point. So given a centre point, distance from the centre, change the bearing from 0 or any number depending on rotation of the square and increment by 90 degrees or PI/2 radians. By incrementing by 90 degrees each time and you will up with a square in circular space.
I use this myself for generating GPS points around a centre point with a given distance
.---.
--/-
--0--
-/--
.---.
TL;DR
10 km = 0.08999 radius from a certain geopoint. This calculation is only based on latitude values and applies only to geopoints with WGS84 projection.
More details
If you want a more accurate answer you must have to calculate it by building a function of some sort. However it still don't guarantee because people even quarrel for the degrees of error. Taking altitude into account, mercator or not, etc.
Caution
The value above is just a rule of a thumb so don not use it for critical applications.
Reference
GIS StackExchange, How do I calculate the bounding box for given a distance and latitude/longitude, answer by David the Australian developer
I am working on a project in javascript involving google maps.
The goal is to figure out 16-20 coordinate points within n kilometers from a set of latitude longitude coordinates such that the 16 points if connected will form a circle around the original coordinates.
The end goal is to make it so I can figure out coordinates to plot and connect on google maps to make a circle around a given set of coordinates.
The code would go something like:
var coordinates = Array();
function findCoordinates(lat, long, range) {
}
coordinates = findCoordinates(-20, 40, 3);
Now to make the magic happen in the findCoordinates() function.
Basically what you're trying to do is find N points on the radius of a circle from a given point with a given radius. One simple way of doing it is splitting the 360 degrees of a circle in to N equal chunks, and finding the points at regular intervals.
The following should do roughly what you're after -
function findCoordinates(lat, long, range)
{
// How many points do we want? (should probably be function param..)
var numberOfPoints = 16;
var degreesPerPoint = 360 / numberOfPoints;
// Keep track of the angle from centre to radius
var currentAngle = 0;
// The points on the radius will be lat+x2, long+y2
var x2;
var y2;
// Track the points we generate to return at the end
var points = [];
for(var i=0; i < numberOfPoints; i++)
{
// X2 point will be cosine of angle * radius (range)
x2 = Math.cos(currentAngle) * range;
// Y2 point will be sin * range
y2 = Math.sin(currentAngle) * range;
// Assuming here you're using points for each x,y..
p = new Point(lat+x2, long+y2);
// save to our results array
points.push(p);
// Shift our angle around for the next point
currentAngle += degreesPerPoint;
}
// Return the points we've generated
return points;
}
The array of points you get back can then easily be used to draw the circle you wish on your google map.
If your overall goal however is just to draw a circle at a fixed radius around a point, then a far easier solution may be to use an overlay. I've found KMBox to be very easy to set up - you give it a central point, a radius and an image overlay (in your case, a transparent circle with a visible line around the edge) and it takes care of everything else, including resizing it on zoom in/out.
I had to find some code to calculate Great Circle distances a while back (just Google "Great Circle" if you don't know what I'm talking about) and I found this site:
http://williams.best.vwh.net/gccalc.htm
You might be able to build up your own JavaScript code to do your lat/lon range calculations using the JavaScript from that site as a reference. It sounds to me like you just need to divide up the 360 degrees of a circle into an equal number of pieces and draw a line out to an equal distance from the center at each "bearing". Once you know the lat/lon at the other end of each bearing/distance line, then connecting the dots to form a polygon is trivial.