1
0
mirror of https://frontier.innolan.net/rainlance/amiga-tz.git synced 2025-11-21 15:38:57 +00:00

tzselect: improve heuristic in Africa

Add the product of the longitude difference and the cosine of the
latitude farther from the equator to the distance measure.  This
works better for the Congolese test case noted by Alan Barrett in:
http://mm.icann.org/pipermail/tz/2014-July/021229.html
The new heuristic is not perfect, but no heuristic is.
* tzselect.ksh (abs, min): New functions
(convert_coord): Rename local to avoid name clash.
(gcdist): Rename from dist.
(pardist, dist): New functions.
* NEWS: Document this.
This commit is contained in:
Paul Eggert
2014-08-11 18:41:32 -07:00
parent 67d9b6ac6b
commit 62711791c3
2 changed files with 28 additions and 4 deletions

5
NEWS
View File

@ -19,6 +19,11 @@ Unreleased, experimental changes
Asia/Dakha ended DST on 2009-12-31 at 24:00, not 23:59. Asia/Dakha ended DST on 2009-12-31 at 24:00, not 23:59.
Changes affecting code
tzselect -c now uses a hybrid distance measure that works better
in Africa. (Thanks to Alana Barrett for noting the problem.)
Changes affecting distribution tarballs Changes affecting distribution tarballs
The files checktab.awk and zoneinfo2tdf.pl are now distributed in The files checktab.awk and zoneinfo2tdf.pl are now distributed in

View File

@ -192,7 +192,13 @@ output_distances='
country[$1] = $2 country[$1] = $2
country["US"] = "US" # Otherwise the strings get too long. country["US"] = "US" # Otherwise the strings get too long.
} }
function convert_coord(coord, deg, min, ilen, sign, sec) { function abs(x) {
return x < 0 ? -x : x;
}
function min(x, y) {
return x < y ? x : y;
}
function convert_coord(coord, deg, minute, ilen, sign, sec) {
if (coord ~ /^[-+]?[0-9]?[0-9][0-9][0-9][0-9][0-9][0-9]([^0-9]|$)/) { if (coord ~ /^[-+]?[0-9]?[0-9][0-9][0-9][0-9][0-9][0-9]([^0-9]|$)/) {
degminsec = coord degminsec = coord
intdeg = degminsec < 0 ? -int(-degminsec / 10000) : int(degminsec / 10000) intdeg = degminsec < 0 ? -int(-degminsec / 10000) : int(degminsec / 10000)
@ -203,8 +209,8 @@ output_distances='
} else if (coord ~ /^[-+]?[0-9]?[0-9][0-9][0-9][0-9]([^0-9]|$)/) { } else if (coord ~ /^[-+]?[0-9]?[0-9][0-9][0-9][0-9]([^0-9]|$)/) {
degmin = coord degmin = coord
intdeg = degmin < 0 ? -int(-degmin / 100) : int(degmin / 100) intdeg = degmin < 0 ? -int(-degmin / 100) : int(degmin / 100)
min = degmin - intdeg * 100 minute = degmin - intdeg * 100
deg = (intdeg * 60 + min) / 60 deg = (intdeg * 60 + minute) / 60
} else } else
deg = coord deg = coord
return deg * 0.017453292519943296 return deg * 0.017453292519943296
@ -220,7 +226,7 @@ output_distances='
# Great-circle distance between points with given latitude and longitude. # Great-circle distance between points with given latitude and longitude.
# Inputs and output are in radians. This uses the great-circle special # Inputs and output are in radians. This uses the great-circle special
# case of the Vicenty formula for distances on ellipsoids. # case of the Vicenty formula for distances on ellipsoids.
function dist(lat1, long1, lat2, long2, dlong, x, y, num, denom) { function gcdist(lat1, long1, lat2, long2, dlong, x, y, num, denom) {
dlong = long2 - long1 dlong = long2 - long1
x = cos (lat2) * sin (dlong) x = cos (lat2) * sin (dlong)
y = cos (lat1) * sin (lat2) - sin (lat1) * cos (lat2) * cos (dlong) y = cos (lat1) * sin (lat2) - sin (lat1) * cos (lat2) * cos (dlong)
@ -228,6 +234,19 @@ output_distances='
denom = sin (lat1) * sin (lat2) + cos (lat1) * cos (lat2) * cos (dlong) denom = sin (lat1) * sin (lat2) + cos (lat1) * cos (lat2) * cos (dlong)
return atan2(num, denom) return atan2(num, denom)
} }
# Parallel distance between points with given latitude and longitude.
# This is the product of the longitude difference and the cosine
# of the latitude of the point that is further from the equator.
# I.e., it considers longitudes to be further apart if they are
# nearer the equator.
function pardist(lat1, long1, lat2, long2) {
return abs (long1 - long2) * min (cos (lat1), cos (lat2))
}
# The distance function is the sum of the great-circle distance and
# the parallel distance. It could be weighted.
function dist(lat1, long1, lat2, long2) {
return gcdist (lat1, long1, lat2, long2) + pardist (lat1, long1, lat2, long2)
}
BEGIN { BEGIN {
coord_lat = convert_latitude(coord) coord_lat = convert_latitude(coord)
coord_long = convert_longitude(coord) coord_long = convert_longitude(coord)