|
echo $fn ?>
|
|
/* ---------------------------------------------------------------- */
/* Two classes to facilitate Google maps interaction: */
/* */
/* GeoLoc - an immutable definition of a latitude/longitude pair */
/* GeoPath - a list of GeoLoc objects defining a route or path */
/* */
/* ---------------------------------------------------------------- */
/* */
/* Originally by Ruurd J. Idenburg */
/* */
/* No copyright, no licence, no guarantees or warrantees, be it */
/* explicit, implicit or whatever. Usage is totally and completely */
/* at the users own risk, the author shall not be liable for any */
/* damages whatsoever, for any reason whatsoever. */
/* */
/* Please keep this comment block intact when modifying this code */
/* and add a note with date and a description. */
/* */
/* ---------------------------------------------------------------- */
/* 2013/12/01 - Initial version approximately */
/* 2020/02/15 - Corrected comments above */
/* ---------------------------------------------------------------- */
::class geoloc public
-- GeoLoc class, for now consisting of an immutable latitude
-- and longitude specification in decimal degrees.
--
-- The precision for calculations is a settable attribute, initially
-- set to the highest precision supported by the 'rxmath' library.
--
::attribute latitude get
::attribute longitude get
::attribute precision
-- (equatorial) radius of the Earth in meters as used by Google
::constant earthRadius 6378137
::method init
expose latitude longitude precision
use strict arg lat,lon
-- set precision to the maximum supported number of digits in the rxmath library
precision = 16
-- create proper and valid latitude and longitude
latitude = .latitude~new(lat)
longitude = .longitude~new(lon)
::method distanceFrom
-- Calculates the distance between the receiving and the argument (geo)location
-- in thousands of Kilometers or Miles, as specified by the optional second argument.
-- Default is the the metric system, specify 'M' for the imperial system.
--
numeric digits (self~precision)
-- distance in Kilometers(K), is default, or Miles(M)
use strict arg fromGeoLoc, unit='K'
if fromGeoLoc~class<>.geoloc then raise syntax 88.914 array("1-(geoloc)",self~class~id)
unit = unit~subchar(1)~upper
-- distance will be calculated in thousands of the unit, be it metric or imperial
if ('KM')~pos(unit)==0 then raise syntax 88.916 array("2-(unit)",'"K(m)","M(ile)"',unit)
unit = '1000 1639'~word(('KM')~pos(unit))
-- I'm told that the best formula for short distances is:
-- d=R*2*asin(sqrt((sin((lat1-lat2)/2))^2 + cos(lat1)*cos(lat2)*(sin((lon1-lon2)/2)^2)))
lat1 = self~latitude
lat2 = fromGeoLoc~latitude
lon1 = self~longitude
lon2 = fromGeoLoc~longitude
R = self~earthRadius
dist = R*2*asin(sqrt((sin(lat1-lat2)/2)**2 + cos(lat1)*cos(lat2)*(sin((lon1-lon2)/2)**2)),,'R')
--for a possibly future method implementation
--R*2*(((lat1-lat2)/2)~sin**2 + lat1~cos*lat2~cos*(((lon1-lon2)/2)**2)~sqrt)~asin(,'R')
--
-- return distance in thousands of unit
return (dist/unit)~format(,3)
::method distanceTo
forward message('distanceFrom') to(self)
::class geoPath public subclass list
-- GeoPath class, defined as a list of GeoLocs.
-- Class method 'of' in the .list class uses insert instance methods, no need to override.
::method insert
use arg item
if item~class<>.geoloc then do
raise syntax 88.914 array(1,.geoloc~id)
end
-- 2nd argument is index if specified
if arg(2,'E') then do
return self~insert:super(item,arg(2))
end
-- no 2nd argument means append
else do
return self~insert:super(item)
end
exit
::method append
use strict arg item
self~insert(item)
exit
::method put
-- same as insert with 2nd argument
use strict arg item, index
self~insert(item,index)
::method distance
use strict arg unit='K'
items = self~items
distance = 0
do l=0 to items-2
distance += self[l]~distanceTo(self[l+1],unit)
end
return distance
::class number public subclass string
-- Number class, a subclass of the String class
-- Values can be any valid number
--
-- All arithmetic methods need to be defined here, because
-- the result of the operation should be another object of
-- the Number class, and the result of the String class operators
-- always is a String class object.
--
-- Note that subclasses of the Number class will yield results
-- that belong to that particular receiver subclass.
::method init
self~init:super
if (self)~datatype\='NUM' then do --if self is not a number
raise syntax 93.904 array(1,self) -- then raise an error and quit
end
::method '+'
--use strict arg num
--return self~class~new(self~'+':super(num))
-- or:
forward class(super) continue
return self~class~new(result)
::method '-'
use strict arg num
return self~class~new(self~'-':super(num))
::method '*'
use strict arg num
return self~class~new(self~'*':super(num))
::method '/'
use strict arg num
return self~class~new(self~'/':super(num))
::method '%'
use strict arg num
return self~class~new(self~'%':super(num))
::method '//'
use strict arg num
return self~class~new(self~'//':super(num))
::method '**'
use strict arg num
return self~class~new(self~'**':super(num))
::class latitude public subclass number
-- Latitude class, a subclass of the Number class
-- Values range from -90 thru +90
::method init
-- the number class will check if I'm a valid number
self~init:super
-- I check if I'm a valid latitude
if self<-90 | self>90 then do
raise syntax 88.907 array("1-(latitude)","-90","90",self)
end
::class longitude public subclass number
-- Longitude class, a subclass of the Number class
-- Values range from -180 thru +180
::method init
self~init:super
if self<-180 | self>180 then do
raise syntax 88.907 array("1-(longitude)","-180","180",self)
end
-- Simplify function names for the necessary 'RxMath' functions
::routine Sin EXTERNAL "LIBRARY rxmath RxCalcSin"
::routine Cos EXTERNAL "LIBRARY rxmath RxCalcCos"
::routine Asin EXTERNAL "LIBRARY rxmath RxCalcArcSin"
::routine Sqrt EXTERNAL "LIBRARY rxmath RxCalcSqrt"
-- number.cls added above
--::requires "number.cls"
If you feel inclined to make corrections, suggestions etc.,
please mail me any.
| |
All content © Ruurd Idenburg, 2007– echo date('Y');?>,
except where marked otherwise. All rights reserved. This page is primarily for non-commercial use only.
The Idenburg website records no personal information and sets no ‘cookies’.
This site is hosted on a VPS(Virtual Private System) rented from Transip.nl, a Dutch company, falling under Dutch (privacy) laws (I think).
This page updated on echo date("r", filemtime("./index.php"));?> by Ruurd Idenburg.
|
|