contest algorithms january 2016 a little bit of spherical trigonometry: great circles, the haversine...
TRANSCRIPT
1
Contest AlgorithmsJanuary 2016
A little bit of spherical trigonometry: great circles, the Haversine Law, Rhumb lines
and Mercator maps
16. Latitude and Longitude
Contest Algorithms: 16. Lat & Long
Latitude and Longitude
latitude
longitude
Contest Algorithms:16. Lat & Long 3
Great Circles
The largest circle that can be drawn on the surface of the earth.
Equator Meridian/ Longitude line Another Great Circle
Small Circles
Parallel/ Latitude line Another Small Circle
All latitude lines (parallels) are small circles except for the equator
Nautical Miles
A nautical mile (NM) is the distance travelled on a great circle when moving through 1 minute of arc.
Contest Algorithms:16. Lat & Long 8
There are 360o in a circle and 60' (minutes) in a degree. No. of minutes in a circle: 360 x 60 = 21600'
NM length of the equator: 21600 NM 1 NM == 1.852 km (by int. agreement) km length of the equator = 21600 * 1.852 = 40,003 km
actual is 40,075 km
Length of the Equator
From Angle to NM Calculate the shortest distance
from 60o W to 10o E along the equator.
Smallest angle along the equator between the two positions is 60 + 10 =70o
Shortest distance = 70 x 60 = 4200 NM
convert degrees to minutes
Latitude Distance As you travel around a line of latitude
(small circle) the distance travelled is shorter than the distance covered on the equator (great circle).
Radius of the small circle: rRadius of the Equator: RLatitude angle:
Then r = R cos So the small circle is smaller than the
great circle by a factor of cos .
Equator
Latitude 41o N
N
S
41o
R
r
r
Nr
R
Calculate a Latitude Distance Calculate the distance along the line
of latitude from (41o N, 36o W) to (41o N, 155o E) .
Smallest angle is not 191o, but 169o
Converting this angle into minutes: = 169 x 60 = 10140'.
Since the measurement is along a small circle the distance is reduced by a factor of cos 41o.
Distance in nautical miles = 10140 x cos 41o = 7653
NM
0o
N
36o W
155o
E
144 + 25
12
Review of Plane Trigonometry
A
B C
a
bc
Angles A, B and C; Sides a, b and c
Cosine Law:
Sine Law:
c2 =a
2 +b2 - 2abcosC
a
sinA= b
sinB= c
sinC
Contest Algorithms:16. Lat & Long 13
Great circles arcs / sides / angles: a, b, c
this assumes a unit sphere; otherwise multiple by radius R to get lengths
0 < a + b + c < 3π
Face/surface angles / bearings: A, B, C
π < A + B + C < 3π
Spherical Trigonometry
A B C are angles
a b c are sides
Sine Law
sina
sinA= sinb
sinB= sinc
sinC
Cosine Law for sides Cosine Law for angles
cosa= cosb cosc + sinb sinc cosAcosb= cosc cosa + sinc sina cosBcosc= cosb cosa + sina sinb cosC
cosA= - cosB cosC + sinB sinC cosacosB= - cosA cosC + sinA sinC cosbcosC= - cosA cosB + sinA sinB cosc
Spherical Trig. Laws
B
AC
a
b
c
Contest Algorithms:16. Lat & Long 15
Calculate the air distance from New York to Moscow
We know their coordinates. New York: Latitude = 40o47'N,
Longitude = 73o58'W Moscow: Latitude = 55o45'N,
Longitude = 37o42'E
The air distance = great circle arc from N to M == p
Calculating DistanceP
N M
m n
p
Contest Algorithms:16. Lat & Long 16
Views of the Triangle
N
P
earth'scenter
New York'slatitude
equator
m
mM
earth'scenter
Moscow'slatitude
n
P
n
40o47'N55o45'N
MN
earth'scenter
View from above
primemeridian
Moscow'slongitude
New York'slongitude
73o58'W 37o42'E
P
Contest Algorithms:16. Lat & Long 17
Calculate cos p = cos m cos n + sin m sin n cos P Sides m and n:
m = 90o – lat of New York = 49o13' = 49.2167 cos m = 0.6532; sin m = 0.7572
n = 90o - lat of Moscow = 34o15' = 34.25 cos n = 0.8266; sin n = 0.5628
Face/surface angle P P = long NY + long MO = 73o58'W + 37o42'E = 111o40' =
111.6667 cos P = -0.3692
Contest Algorithms:16. Lat & Long 18
cos p = cos m cos n + sin m sin n cos P Substitute:
cos p = 0.6532 * 0.8266 + 0.7572 * 0.5628 * -0.3692 = 0.3826 p = cos-1 0.3826 = 67.51o == 66.51*60 minutes = 405.3' = 4050.3 NM == 4050.3 * 1.852 = 7501 km
Google reports:
Contest Algorithms:16. Lat & Long 19
cos a = cos b cos c + sin b sin c cos A Inaccurate when a is small Instead substitute:
cos θ = 1 − 2 hav θ cos(a − b) = cos a cos b + sin a sin b
Produces: hav a = hav(c-b) + sin c sin b hav A
The Haversine Law
Contest Algorithms:16. Lat & Long 20
Considers the special case when A is the north pole, and B and C are the two points whose separation d is to be determined.
In that case, c and b are 90° − their latitudes, A is the longitude separation Δlon, and a is the desired d/R.
Note that sin(π/2 − φ) = cos(φ)
The Haversine Formula
Contest Algorithms:16. Lat & Long 21
hav(a/R) = hav(lat2 - lat1) + cos(lat1) cos(lat2) hav(lon2 – lon1)
lati and lon i are the lattitide of the two points R is the Earth's radius
hav(angle) = sin2(angle/2) [ = (1 – cos(angle))/2 ] Let rhs of 1st equation be h, then
hav(a/R) =h, so sin2(a/2R)= h a = 2R arcsin( √h)
Contest Algorithms:16. Lat & Long 22
public static double haversine(double lat1, double lon1, double lat2, double lon2) { double dLat = Math.toRadians(lat2 - lat1); double dLon = Math.toRadians(lon2 - lon1); lat1 = Math.toRadians(lat1); lat2 = Math.toRadians(lat2); double a = Math.pow(Math.sin(dLat/2), 2) + Math.pow(Math.sin(dLon/2), 2) * Math.cos(lat1) * Math.cos(lat2); double c = 2 * Math.asin(Math.sqrt(a));
return EARTH_RADIUS_KM * c; } // end of haversine()
Code see LatLongTests.java
Contest Algorithms:16. Lat & Long 23
public static double fromDMS(String dmsStr) /* Obtain an angle from a degrees, minute and secs character string. see http://kb.tableau.com/articles/knowledgebase/convert-latitude-longitude e.g. 45 12 30 S -45 12 30.25 W */ { if (dmsStr == null) { System.out.println("String is null"); return 0; }
String[] dms = dmsStr.split("\\s+"); if (dms.length != 4) { System.out.println("Incorrect DMS format in \"" + dmsStr +"\""); return 0; } :
Contest Algorithms:16. Lat & Long 24
int sign = 1; int degrees = parseInt(dms[0]); if (degrees < 0) { sign = -1; degrees *= -1; }
int mins = parseInt(dms[1]); double secs = parseInt(dms[2]);
char suffix = dms[3].toUpperCase().charAt(0); if (suffix == 'S' || suffix == 'W') sign *= -1;
if (mins < 0 || mins >= 60) { System.out.println("Minutes out of range; using 0"); mins = 0; } if (secs < 0 || secs >= 60) { System.out.println("Seconds out of range; using 0"); secs = 0; }
return ( sign*(Math.abs(degrees) + mins/60d + secs/3600d)); } // end of fromDMS()
Contest Algorithms:16. Lat & Long 25
public static void main(String[] args) { // New York coordinates (from http://www.latlong.net/) double nyLat = fromDMS("40 43 50 N"); double nyLong = fromDMS("73 56 7 W"); System.out.printf("New York lat,long: %.3f, %.3f\n", nyLat, nyLong); // 40.731, -73.935 // Moscow coordinates double mLat = fromDMS("55 45 4 N"); double mLong = fromDMS("37 37 6 E"); System.out.printf("Moscow lat,long: %.3f, %.3f\n", mLat, + mLong); // 55.751, 37.618
System.out.printf("Great circle distance: %.1f\n", haversine(nyLat, nyLong, mLat, mLong) ); : // more examples }
Usage> java LatLongTestsGreat circle distance: 7507.8
Contest Algorithms:16. Lat & Long 26
Coordinates: New York: Latitude = 40o47'N, Longitude = 73o58'W Moscow: Latitude = 55o45'N, Longitude = 37o42'E
Calculation: diffLat = 55.75 - 40.7833 = 14.9667 diffLon = 37.7 + 73.9667 = 111.6667 h = sin²(diffLat/2) + cos(lat1) * cos(lat2) * sin²(diffLon/2); // in
radians h = 0.017 + (0.7572 * 0.5628 * 0.6846) = 0.017 + 0.2917 = 0.3087
a = 2*6371*arcsin(√h) a = 12742 * 0.5891 = 7506, which agrees with Google's result
Distance from NY to Moscow (2)
Navigational Terminology Azimuth / bearing / true course: the angle a line
makes with a meridian, taken clockwise from north North=0°, East=90°, South=180°, West=270° the A, B, C angles
Geodesic: The smaller great circle arc through two given points
the shortest distance between the two points the a, b, c "lines”
Contest Algorithms:16. Lat & Long 28
Use the sine law:
Bearing for New York (N) in terms of the polar data:
N = sin-1( sin(111.6667) / sin(67.51) * 0.5628) = sin-1(0.9293/0.9239 * 0.5628) = sin-1(0.5660) = 34.48o
Bearing from NY to Moscow
Contest Algorithms:16. Lat & Long 29
Confirmation using earthdirections.org
Contest Algorithms:16. Lat & Long 30
public static double bearing(double lat1, double lon1, double lat2, double lon2) { double dLon = Math.toRadians(lon2 - lon1); lat1 = Math.toRadians(lat1); lat2 = Math.toRadians(lat2);
double y = Math.sin(dLon) * Math.cos(lat2);
double x = (Math.cos(lat1) * Math.sin(lat2)) - (Math.sin(lat1) * Math.cos(lat2) * Math.cos(dLon));
return (Math.toDegrees(Math.atan2(y, x))+360)%360; } // end of bearing()
Code see LatLongTests.java
Contest Algorithms:16. Lat & Long 31
// in main()System.out.printf("Bearing from NYC to Moscow: %.3f degrees\n", bearing(nyLat, nyLong, mLat, mLong) );
Usage
> java LatLongTestsGreat circle distance: 7507.8Bearing from NYC to Moscow: 34.511 degrees
Contest Algorithms:16. Lat & Long 32
The two points are located on a Mercator map, and a straight line (the rhumb line) is drawn between them.
The Rhumb Line
Mercator vs. From Space
View fromSpace
Mercator map
meridians
latitudelines
Contest Algorithms:16. Lat & Long 34
Let the globe be a spherical balloon that is blown up inside a cylinder, and sticks to the cylinder when it comes into contact with it.
unroll the cylinder to get the map
Two properties: circles of latitude become horizontal lines on the map meridians become vertical lines
Result: latitudes and longitude lines form a grid pattern
The Mercator Projection
A constant course always make the same angle with the meridians(longitude line) that it passes through.
constant course == a rhumb line on a Mercator map
Also called a loxodrome
Contest Algorithms 36
Derive the equations to calculate the Rhumb line course C and its distance d between two points A and B.
d can be calculated in terms of a sum of small distances dx between A and B:
Calculating Rhumb Line Info
lattitudelines
meridians
ddivide d intolots of small triangles
A
C
dx
CdLat
dLon * cos Lat
Contest Algorithms:16. Lat & Long 37
dx is composed of a north-south component, dLat, and a west-east component, dLon ∙ cos Lat.
The factor (cos Lat) is the relative circumference of the respective parallel of latitude.
Rearrange:
Contest Algorithms:16. Lat & Long 38
Sum all the dx triangles by integrating the equations between (Lat A, Lat B) and (Lon A, Lon B):
1/cos θ = sec θ ln( | sec + tan |) + K = tan(/2 + π/4) + K
Contest Algorithms:16. Lat & Long 39
Integrate both sides:
Rearrange:
Contest Algorithms:16. Lat & Long 40
Solve for C, and use atan2(y,x) rather than arctan()
C = Math.atan2( , )
Contest Algorithms:16. Lat & Long 41
Result:
To find d, sum the dx lengths, by integrating the dx equation:
𝐷=𝐿𝑎𝑡𝐵−𝐿𝑎𝑡 𝐴cos𝐶
Contest Algorithms:16. Lat & Long 42
Coordinates: New York: Latitude = 40o47'N, Longitude = 73o58'W Moscow: Latitude = 55o45'N, Longitude = 37o42'E
Calculation: diffLat = 55.75 - 40.7833 = 14.9667o
diffLon = 37.7 + 73.9667 = 111.6667o = 1.949 radians tan(LatMO/2 + π/4) = 3.2455 ; tan(LatNY/2 + π/4) = 2.1833 ln( 3.2455 / 2.1833) = 0.3964 C = atan2(1.949, 0.3964) = 1.37 radians = 78.5o
Rhumb Line from NY to Moscow
Contest Algorithms:16. Lat & Long 43
D = 14.9667 / cos(1.37) = 14.9667 / 0.1994 = 75.06 NM distance == 75.06 * 60 = 4503.6 NM km distance = 4503.6 * 1.852 = 8341 km
Contest Algorithms:16. Lat & Long 44
http://www.madinstro.net/sundry/navigation/rhumb_line.html
Online Rhumb Line Calculator
Contest Algorithms:16. Lat & Long 45
public static double rhumbDistance(double lat1d, double lon1d, double lat2d, double lon2d) // return distance in km { double lat1 = Math.toRadians(lat1d); double lon1 = Math.toRadians(lon1d); double lat2 = Math.toRadians(lat2d); double lon2 = Math.toRadians(lon2d); if ((Math.abs(lat1 - lat2) < EPS) && (Math.abs(lon1 - lon2) < EPS)){ System.out.println("Too points are the same"); return 0; } double dPhi = Math.log(Math.tan(lat2/2.0 + Math.PI/4.0) / Math.tan(lat1/2.0 + Math.PI/4.0)); double course = Math.atan2((lon2 - lon1), dPhi); System.out.printf("Rhumb line course (in degrees): %.4f\n", Math.toDegrees(course)); double distNM = ((lat2d - lat1d) / Math.cos(course) * 60); // in Nautical miles return (distNM * NAUTICAL_MILES_TO_KM); } // end of rhumbDistance()
Code
Contest Algorithms:16. Lat & Long 46
// in main()System.out.printf("Rhumb line distance (in km): %.1f\n", rhumbDistance(nyLat, nyLong, mLat, mLong) );
Usage