CONST current = 0
CONST work = -1
CONST origin = -2
CONST lastarray = 10
CONST TMscale! = .9996012717# 'was 0.9996
'the items work (-1) and origin (-2) in the following
arrays
'are for internal use within the subroutines only.
'Items 0 to 10 are for user data though this example
program
'only uses item 0.
DIM SHARED easting&(-2 TO lastarray), northing&(-2
TO lastarray) 'in metres
DIM SHARED longitude!(-2 TO lastarray), latitude!(-2
TO lastarray)
DIM SHARED gridletterx(26), gridlettery(26)
DIM SHARED majoraxis!, minoraxis!, rad#
DIM SHARED eccsq!, ecc2sq!, PA!, PB!, PC!
CALL setup
DO
bad = 0
CLS
PRINT
PRINT "Phil Brady's Long and Lat
<-> OSGB reference demo program."
PRINT
PRINT " 1 to input Latitude
and Longitude in decimal degrees"
PRINT " 2 to input Latitude
and Longitude in degrees, minutes, seconds"
PRINT " 3 to input OS grid
reference"
PRINT " 4 to input a Bartholomew
reference"
PRINT " 5 TO QUIT"
PRINT
INPUT "Which: ", choice
SELECT CASE choice
CASE 1
PRINT
"Give latitude and longitude:"
INPUT
"Latitude (eg 51.6) : ", latitude!(current)
INPUT
"Longitude (eg -4.0 for 4ø west): ", longitude!(current)
CALL LLtoCOORDS(current)
CASE 2
CLS
latitude!(current)
= getdms!("Latitude", "NS")
longitude!(current)
= getdms!("Longitude", "EW")
CALL LLtoCOORDS(current)
CASE 3
INPUT
"Give OS reference: ", os$
IF ReftoCOORDS(os$,
current) = 0 THEN
PRINT "Invalid reference - "
PRINT "needs 2 letters and an even number of digits"
BEEP
bad = 1
ELSE
CALL COORDStoLL(current)
END IF
CASE 4
INPUT
"Give Bartholomew eastings: ", easting&(current)
INPUT
"Give Bartholomew northings: ", northing&(current)
CALL COORDStoLL(current)
CASE 5: END
CASE ELSE: bad = 1
END SELECT
PRINT
IF bad = 0 THEN
PRINT
"OS ref= "; OSReference$(current)
CALL bartref(current)
PRINT
USING "Lat=###.####øN Long=###.####ø"; latitude!(current);
ABS(longitude!(current));
PRINT
MID$("W E", SGN(longitude!(current)) + 2, 1)
PRINT
"Lat= "; dms$(latitude!(current), 0);
PRINT
" Long= "; dms$(longitude!(current), 1)
PRINT
END IF
PRINT "Press any key to continue"
WHILE INKEY$ = ""
WEND
LOOP UNTIL 0
END
badosref:
PRINT
PRINT "Bad reference"
RESUME NEXT
SUB bartref (index)
'print Bartholomew reference.
'PRINT "Easting "; easting&(index)
'PRINT "Northing "; northing&(index)
PRINT "Bartholomew E:"; dig7$(easting&(index));
" N:"; dig7$(northing&(index))
END SUB
SUB COORDStoLL (index)
'compute lat & long from easting/northings
'correction constant is in degrees/metre
IF index < 0 THEN
PRINT "Bad index for COORDStoLL"
EXIT SUB
END IF
k! = 1 / (rad# * majoraxis!)
'initial wild guess
latitude!(work) = 52
longitude!(work) = -3
count = 0
DO
CALL LLtoCOORDS(work)
dx& = easting&(index)
- easting&(work)
dy& = northing&(index)
- northing&(work)
latitude!(work) = latitude!(work)
+ dy& * k!
longitude!(work) = longitude!(work)
+ dx& * k! / COS(rad# * latitude!(work))
count = count + 1
LOOP UNTIL (ABS(dx&) + ABS(dy&) < 1) OR
(count > 20)
latitude!(index) = latitude!(work)
longitude!(index) = longitude!(work)
END SUB
FUNCTION dig7$ (r&)
'return integer in 7 spaces
dig7$ = RIGHT$("
" + STR$(r&), 7)
END FUNCTION
FUNCTION dms$ (a!, eastwest)
' returns a! in degrees, seconds, minutes.
' eastwest=1 gives E/W rather than N/S
b& = INT(ABS(a!) * 3600 + .5)
d = b& \ 3600
b& = b& - 3600& * d
m = b& \ 60
b& = b& - 60 * m
out$ = RIGHT$(" " + STR$(d), 3) + "ø"
out$ = out$ + RIGHT$(STR$(m), 2) + "'"
out$ = out$ + RIGHT$(STR$(b&), 2) + CHR$(34)
s = SGN(a!)
out$ = out$ + MID$("SNNWEE", s + 2 + 3 * eastwest,
1)
dms$ = out$
END FUNCTION
FUNCTION getdms! (LorL$, compass$)
PRINT
PRINT "Please give "; LorL$
DO
INPUT "Degrees: ", d
LOOP UNTIL ABS(d) < 90
DO
INPUT "Minutes: ", m
LOOP UNTIL (m > -1) AND (m < 60)
DO
INPUT "Seconds: ", s
LOOP UNTIL (s > -1) AND (s < 60)
IF compass$ = "EW" THEN
DO
INPUT
"East or West? ", ew$
ew$ =
UCASE$(LEFT$(ew$ + " ", 1))
LOOP UNTIL INSTR("EW", ew$)
END IF
deg! = d + m / 60 + s / 3600
IF ew$ = "W" THEN deg! = -deg!
getdms! = deg!
END FUNCTION
SUB LLtoCOORDS (index)
longi! = rad# * (longitude!(index) - longitude!(origin))
lati! = rad# * latitude!(index)
t! = TAN(lati!)
tsq! = t! * t!
L! = longi! * COS(lati!)
Lsq! = L! * L!
etasq! = COS(lati!)
etasq! = etasq! * etasq! * ecc2sq!
nu! = SIN(lati!)
nu! = SQR(1 - eccsq! * nu! * nu!)
nu! = majoraxis! / nu!
'compute easting
A7! = (61 - tsq! * (479 - 179! * tsq! + tsq! * tsq!))
/ 5040!
A5! = (5 - tsq! * (18 - tsq!) + etasq! * (14 - 58
* tsq!)) / 120
A3! = (1 - tsq! + etasq!) / 6
A1! = TMscale! * nu!
easting&(index) = A1! * L! * (1 + Lsq! * (A3!
+ Lsq! * (A5! + A7! * Lsq!)))
easting&(index) = easting&(index)
'now do northings
m! = majoraxis! * (1 - eccsq!) * (PA! * lati! - .5
* PB! * SIN(2 * lati!) + .25 * PC! * SIN(4 * lati!))
a2! = .5 * A1! * t!
A4! = (5 - tsq! + etasq! * (9 + 4 * etasq!)) / 12
A6! = (61 - tsq! * (58 - tsq!) + etasq! * (270 -
330 * tsq!)) / 360
northing&(index) = TMscale! * m! + a2! * Lsq!
* (1 + Lsq! * (A4! + A6! * Lsq!))
IF index <> origin THEN
northing&(index) = northing&(index)
- northing&(origin)
easting&(index) = easting&(index)
- easting&(origin)
END IF
END SUB
FUNCTION OSReference$ (index)
'returns 10 digit reference for given easting and
northing in km.
' eg SO 12345 67890
ON ERROR GOTO badosref
e& = 1000000 + easting&(index)
N& = northing&(index) + 500000
i = e& \ 500000
j = N& \ 500000
L$ = MID$("VWXYZQRSTULMNOPFGHJKABCDE", i + 1 + j
* 5, 1)
e& = e& MOD 500000
N& = N& MOD 500000
i = e& \ 100000
j = N& \ 100000
L$ = L$ + MID$("VWXYZQRSTULMNOPFGHJKABCDE", j * 5
+ i + 1, 1)
e& = e& MOD 100000
N& = N& MOD 100000
L$ = L$ + " " + RIGHT$(STR$(INT(100000# + e&)), 5) + " " + RIGHT$(STR$(INT(100000# + N&)), 5)
OSReference$ = L$
END FUNCTION
FUNCTION ReftoCOORDS (in$, index)
'Calculate eastings and northings for a grid reference.
' eg SO 123 456
' Note our OS origin is at reference VV 0 0
ie 1000 km W and
' 500 km S of OS false origin.
' results in km!
' Return -1 if successful, 0 if faulty input.
t$ = UCASE$(in$)
FOR i = 1 TO LEN(in$)
c$ = MID$(t$, i, 1)
IF INSTR("1234567890", c$) THEN
numbers$
= numbers$ + c$
ELSEIF INSTR("ABCDEFGHJKLMNOPQRSTUVWXYZ",
c$) THEN
refLetters$
= refLetters$ + c$
END IF
NEXT
IF LEN(refLetters$) <> 2 THEN EXIT FUNCTION
L = LEN(numbers$)
IF (L = 0) OR (L AND 1) THEN EXIT FUNCTION
L = L / 2
refEasting$ = LEFT$(numbers$, L)
refEasting$ = LEFT$(refEasting$ + "00000", 5)
refNorthing$ = MID$(numbers$, L + 1)
refNorthing$ = LEFT$(refNorthing$ + "00000", 5)
ind = ASC(refLetters$) - 65
easting&(index) = 5000! * gridletterx(ind)
northing&(index) = 5000! * gridlettery(ind)
ind = ASC(MID$(refLetters$, 2, 1)) - 65
easting&(index) = easting&(index) + gridletterx(ind)
* 1000!
northing&(index) = northing&(index) + gridlettery(ind)
* 1000!
easting&(index) = easting&(index) + VAL(refEasting$)
- 1000000
northing&(index) = northing&(index) + VAL(refNorthing$)
- 500000
ReftoCOORDS = -1
END FUNCTION
SUB setup
CLS
'set up for 1st two letters of grid ref
char = ASC("A")
FOR v = 400 TO 0 STEP -100
FOR h = 0 TO 400 STEP 100
gridletterx(char
- 65) = h
gridlettery(char
- 65) = v
char =
char + 1
IF char
= ASC("I") THEN char = char + 1
NEXT
NEXT
'Airey 1849 global constants
majoraxis! = 6377563.396#
'minoraxis! = 6356256.9#
minoraxis! = 6356256.91# 'more
correct?
'define origin
longitude!(origin) = -2
latitude!(origin) = 49
rad# = ATN(1) / 45
majsq! = majoraxis! * majoraxis!
minsq! = minoraxis! * minoraxis!
eccsq! = (majsq! - minsq!) / majsq! 'eccentricity
^ 2
ecc4! = eccsq! * eccsq!
ecc6! = eccsq! * ecc4!
ecc2sq! = (majsq! - minsq!) / minsq! 'second eccentricity
^2
'
'meridinal distance parameters
PA! = 1 + .75 * eccsq! + .703125 * ecc4! + .068359375#
* ecc6!
PB! = .75 * eccsq! + .9375 * ecc4! + 1.025390625#
* ecc6!
PC! = .234375 * ecc4! + .41015625# * ecc6!
CALL LLtoCOORDS(origin)
easting&(origin) = -400000!
northing&(origin) = northing&(origin) + 100000
' replaced code 27 July 98
'easting&(origin) = -400000!
' was northing&(origin) = 5527056
now computed as 5527063
END SUB