Skip to content

Commit d8913f0

Browse files
committed
More Great Circle calculations for future use.
1 parent b7ee6dc commit d8913f0

File tree

1 file changed

+147
-0
lines changed

1 file changed

+147
-0
lines changed

Diff for: latlong.c

+147
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,17 @@
5959
*
6060
* Returns: None
6161
*
62+
* Idea for future:
63+
* Non zero ambiguity removes least significant digits without rounding.
64+
* Maybe we could use -1 and -2 to add extra digits using !DAO! as
65+
* documented in http://www.aprs.org/datum.txt
66+
*
67+
* For example, -1 adds one more human readable digit.
68+
* lat minutes 12.345 would produce "12.34" and !W5 !
69+
*
70+
* -2 would encode almost 2 digits in base 91.
71+
* lat minutes 10.0027 would produce "10.00" and !w: !
72+
*
6273
*----------------------------------------------------------------*/
6374

6475
void latitude_to_str (double dlat, int ambiguity, char *slat)
@@ -555,6 +566,92 @@ double ll_distance_km (double lat1, double lon1, double lat2, double lon2)
555566
}
556567

557568

569+
/*------------------------------------------------------------------
570+
*
571+
* Function: ll_bearing_deg
572+
*
573+
* Purpose: Calculate bearing between two locations.
574+
*
575+
* Inputs: lat1, lon1 - starting location, in degrees.
576+
* lat2, lon2 - destination location
577+
*
578+
* Returns: Initial Bearing, in degrees.
579+
* The calculation produces Range +- 180 degrees.
580+
* But I think that 0 - 360 would be more customary?
581+
*
582+
*------------------------------------------------------------------*/
583+
584+
double ll_bearing_deg (double lat1, double lon1, double lat2, double lon2)
585+
{
586+
double b;
587+
588+
lat1 *= M_PI / 180;
589+
lon1 *= M_PI / 180;
590+
lat2 *= M_PI / 180;
591+
lon2 *= M_PI / 180;
592+
593+
b = atan2 (sin(lon2-lon1) * cos(lat2),
594+
cos(lat1) * sin(lat2) - sin(lat1) * cos(lat2) * cos(lon2-lon1));
595+
596+
b *= 180 / M_PI;
597+
if (b < 0) b += 360;
598+
599+
return (b);
600+
}
601+
602+
603+
/*------------------------------------------------------------------
604+
*
605+
* Function: ll_dest_lat
606+
* ll_dest_lon
607+
*
608+
* Purpose: Calculate the destination location given a starting point,
609+
* distance, and bearing,
610+
*
611+
* Inputs: lat1, lon1 - starting location, in degrees.
612+
* dist - distance in km.
613+
* bearing - direction in degrees. Shouldn't matter
614+
* if it is in +- 180 or 0 to 360 range.
615+
*
616+
* Returns: New latitude or longitude.
617+
*
618+
*------------------------------------------------------------------*/
619+
620+
double ll_dest_lat (double lat1, double lon1, double dist, double bearing)
621+
{
622+
double lat2;
623+
624+
lat1 *= M_PI / 180; // Everything to radians.
625+
lon1 *= M_PI / 180;
626+
bearing *= M_PI / 180;
627+
628+
lat2 = asin(sin(lat1) * cos(dist/R) + cos(lat1) * sin(dist/R) * cos(bearing));
629+
630+
lat2 *= 180 / M_PI; // Back to degrees.
631+
632+
return (lat2);
633+
}
634+
635+
double ll_dest_lon (double lat1, double lon1, double dist, double bearing)
636+
{
637+
double lon2;
638+
double lat2;
639+
640+
lat1 *= M_PI / 180; // Everything to radians.
641+
lon1 *= M_PI / 180;
642+
bearing *= M_PI / 180;
643+
644+
lat2 = asin(sin(lat1) * cos(dist/R) + cos(lat1) * sin(dist/R) * cos(bearing));
645+
646+
lon2 = lon1 + atan2(sin(bearing) * sin(dist/R) * cos(lat1), cos(dist/R) - sin(lat1) * sin(lat2));
647+
648+
lon2 *= 180 / M_PI; // Back to degrees.
649+
650+
return (lon2);
651+
}
652+
653+
654+
558655
/*------------------------------------------------------------------
559656
*
560657
* Function: ll_from_grid_square
@@ -776,6 +873,7 @@ int main (int argc, char *argv[])
776873
int errors = 0;
777874
int ok;
778875
double dlat, dlon;
876+
double d, b;
779877

780878
/* Latitude to APRS format. */
781879

@@ -860,6 +958,55 @@ int main (int argc, char *argv[])
860958
// to be continued for others... NMEA...
861959

862960

961+
/* Distance & bearing - Take a couple examples from other places and see if we get similar results. */
962+
963+
// http://www.movable-type.co.uk/scripts/latlong.html
964+
965+
d = ll_distance_km (35., 45., 35., 135.);
966+
b = ll_bearing_deg (35., 45., 35., 135.);
967+
968+
if (d < 7862 || d > 7882) { errors++; dw_printf ("Error 5.1: Did not expect distance %.1f\n", d); }
969+
970+
if (b < 59.7 || b > 60.3) { errors++; dw_printf ("Error 5.2: Did not expect bearing %.1f\n", b); }
971+
972+
// Sydney to Kinsale. https://woodshole.er.usgs.gov/staffpages/cpolloni/manitou/ccal.htm
973+
974+
d = ll_distance_km (-33.8688, 151.2093, 51.7059, -8.5222);
975+
b = ll_bearing_deg (-33.8688, 151.2093, 51.7059, -8.5222);
976+
977+
if (d < 17435 || d > 17455) { errors++; dw_printf ("Error 5.3: Did not expect distance %.1f\n", d); }
978+
979+
if (b < 327-1 || b > 327+1) { errors++; dw_printf ("Error 5.4: Did not expect bearing %.1f\n", b); }
980+
981+
982+
/*
983+
* More distance and bearing.
984+
* Here we will start at some location1 (lat1,lon1) and go some distance (d1) at some bearing (b1).
985+
* This results in a new location2 (lat2, lon2).
986+
* We then calculate the distance and bearing from location1 to location2 and compare with the intention.
987+
*/
988+
int lat1, lon1, d1 = 10, b1;
989+
double lat2, lon2, d2, b2;
990+
991+
for (lat1 = -60; lat1 <= 60; lat1 += 30) {
992+
for (lon1 = -180; lon1 <= 180; lon1 +=30) {
993+
for (b1 = 0; b1 < 360; b1 += 15) {
994+
995+
lat2 = ll_dest_lat ((double)lat1, (double)lon1, (double)d1, (double)b1);
996+
lon2 = ll_dest_lon ((double)lat1, (double)lon1, (double)d1, (double)b1);
997+
998+
d2 = ll_distance_km ((double)lat1, (double)lon1, lat2, lon2);
999+
b2 = ll_bearing_deg ((double)lat1, (double)lon1, lat2, lon2);
1000+
if (b2 > 359.9 && b2 < 360.1) b2 = 0;
1001+
1002+
// must be within 0.1% of distance and 0.1 degree.
1003+
if (d2 < 0.999 * d1 || d2 > 1.001 * d1) { errors++; dw_printf ("Error 5.8: lat1=%d, lon2=%d, d1=%d, b1=%d, d2=%.2f\n", lat1, lon1, d1, b1, d2); }
1004+
if (b2 < b1 - 0.1 || b2 > b1 + 0.1) { errors++; dw_printf ("Error 5.9: lat1=%d, lon2=%d, d1=%d, b1=%d, b2=%.2f\n", lat1, lon1, d1, b1, b2); }
1005+
}
1006+
}
1007+
}
1008+
1009+
8631010
/* Maidenhead locator to lat/long. */
8641011

8651012

0 commit comments

Comments
 (0)