ooRexx logo
../code/geoloc.cls/var/www/html/ooRexx/wip /* ---------------------------------------------------------------- */ /* 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–, 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 by Ruurd Idenburg.