Geographic Functions, any takers?
Ben Rubinstein
benr_mc at cogapp.com
Tue Sep 7 05:11:30 EDT 2010
On 30/08/2010 17:19, Ewan Richardson wrote:
> Has anyone written any libraries for Geographic functions within rev?
>
>
> Im thinking of a library for dealing with latitude and longitude, for
> example determining distance between points, bearings radian calculations
> ect.
Ewan,
Sorry for the delayed reply, just catching up with my mailing lists.
I did a project some years ago involving an embedded computer tracking GPS on
a moving vehicle. Looking at the code today, I see I started trying to do it
all by the book - and subsequently realised that since I was only going to be
interested in fine detail when the vehicle was close to any of the waypoints,
and the device was only going to used in Western Europe, I didn't actually
care about the true shape of the Earth etc!
However, for what it's worth, I find these two fragments of code; the first
looks jolly useful, but it appears that I don't actually use it in the final
system. The second is what's actually used, and produces a 'good enough'
result... if nothing else, the references in the comments might be useful.
Also a couple of utilities for working NMEA (the default 'language' of most
GPS units) - trivial but might save a few minutes.
I present these directly pasted from scripts, no checking, no warranty...
Ben
on initialiseGeoConstants
-- an array giving the approximage length in metres of one second of
longitude, at a given degree of latitude
-- source:
http://www.gis.unbc.ca/2003/courses/geog205/lectures/thegraticule/bottomframe.html
constant kSrcInfo = "0 111.32,10 109.64,20 104.65,30 96.49,40 85.39,50
71.70,60 55.80,70 38.19,80 19.39,90 0.00"
put empty into aTemp
put empty into bTemp
repeat for each item tDataPoint in kSrcInfo
put (((word 2 of tDataPoint) * 1000) / 3600) into aTemp[word 1 of
tDataPoint] -- km/degree to m/sec
put ((word 2 of tDataPoint) * 1000) into bTemp[word 1 of tDataPoint] --
km/degree to m/degree
end repeat
-- now try to fill in the degrees between, by crude linear interpolation
repeat with d = 1 to 89
get aTemp[d]
if it <> empty then next repeat
put trunc(d / 10) * 10 into d1
put d1 + 10 into d2
--
get (aTemp[d1] - aTemp[d2])
multiply it by (d2 - d)
put aTemp[d2] + (it / 10) into aTemp[d]
--
get (bTemp[d1] - bTemp[d2])
multiply it by (d2 - d)
put bTemp[d2] + (it / 10) into bTemp[d]
end repeat
set the customProperties["uLongSecLengthAtLatitude"] of this stack to aTemp
set the customProperties["uLongDegLengthAtLatitude"] of this stack to bTemp
end initialiseGeoConstants
--
-- %MACRO distance(lat1, lon1, lat2, lon2);
--
--%* calculates distance between two locations on earth; %* depends crucially
on the accurcy of the calculations!;
--
--%* input: latitude and longitude in radians; %* output: distance in meters,
as a data step expression; %* version: 26 June 1996, Willem Dekker;
--
--%Let Mile=1853.245; %* Nautical mile in meters; %Let
DegRad=180/3.141592653589793238; %* Degrees per Radian; %LET
MeterRad=60*&Mile*&DegRad; %* meters per radian;
--
--(&MeterRad * 2 * arsin(sqrt(2 - 2 * cos(&lat1) *cos(&lat2) * cos(&lon1 -
&lon2) - 2 * sin(&lat1) * sin(&lat2) ) / 2)); %mend;
-- source: http://www.census.gov/cgi-bin/geo/gisfaq?Q5.1
--
-- Presuming a spherical Earth with radius R (see below), and the locations of
the two points in spherical coordinates (longitude, latitude) are lon1, lat1
and lon2, lat2, then the Haversine Formula (Sinott 1984) will give
mathematically and computationally exact results. The intermediate result c is
the great circle distance in radians. The great circle distance d will be in
the same units as R. We provide the inverse tangent version of the Haversine
Formula:
--
-- dlon = lon2 - lon1
--
-- dlat = lat2 - lat1
--
-- a = (sin(dlat/2))^2 + cos(lat1) * cos(lat2) * (sin(dlon/2))^2
--
-- c = 2 * atan2( sqrt(a), sqrt(1-a) )
--
-- d = R * c
--
-- For R, use 3957 miles (6367 km), which is the radius of curvature at 30
latitude; the use of other possible values results in very small differences.
Most computers require the arguments of trigonometric functions to be
expressed in radians. To convert lon1, lat1 and lon2, lat2 from degrees,
minutes, and seconds to radians, first convert them to decimal degrees. To
convert decimal degrees to radians, multiply the number of degrees by: pi/180
= 0.017453293 radians/degree. Inverse trigonometric functions return results
expressed in radians. To express c in decimal degrees, multiply the number of
radians by 180/pi = 57.295780 degrees/radian. (But be sure to multiply the
number of radians by R to get d.)
--
function rangeBetweenPoints tLat1, tLon1, tLat2, tLon2
constant kRadius = 6367000 -- radius of curvature at 30 latitude; in metres
local kDegreesToRadians
put pi / 180 into kDegreesToRadians
local a, c, iDeltaLat, iDeltaLon
multiply tLat1 by kDegreesToRadians
multiply tLon1 by kDegreesToRadians
multiply tLat2 by kDegreesToRadians
multiply tLon2 by kDegreesToRadians
put tLat2 - tLat1 into iDeltaLat
put tLon2 - tLon1 into iDeltaLon
put (sin(iDeltaLat / 2) ^ 2) + cos(tLat1) * cos(tLat2) * (sin(iDeltaLon /
2) ^ 2) into a
put 2 * atan2(sqrt(a), sqrt(1 - a)) into c
-- put round(kRadius * c) & return & "lat1:" && tLat1 & return & "lon1:" &&
tLon1 & return & "lat2:" && tLat2 & return & "lon2:" && tLon2 & return &
"Dlat" && iDeltaLat & return & "Dlon" && iDeltaLon & return & "a" && a &
return & "c" && c
return round(kRadius * c)
end rangeBetweenPoints
function nmeaChecksum tString --> tSum
local iSum
put 0 into iSum
repeat for each char c in tString
put iSum bitXor chartonum(c) into iSum
end repeat
return format("*%02X", iSum)
end nmeaChecksum
function nmeaLatLongToDecimal tNMEAlatitude, tHemisphere --> tDecimalLat
get offset(".", tNMEAlatitude)
if it = 0 then
cancelNonRevMessages
breakpoint
return empty
end if
put char (it - 2) to -1 of tNMEAlatitude into tMinutes
put char 1 to (it - 3) of tNMEAlatitude into tDecimalLat
add (tMinutes / 60) to tDecimalLat
-- put (tDecimalLat * 60) + tMinutes into tDecimalLat -- express in minutes
-- multiply tDecimalLat by 60 -- actually, seconds
if tHemisphere is in "SW" then put "-" before tDecimalLat
return tDecimalLat
end nmeaLatLongToDecimal
More information about the use-livecode
mailing list