-----------------------------------------------------------------------------------------------------
-- PL/SQL function: get_csq --
-- Written by: Tony Rees, CSIRO Australia (Tony.Rees@csiro.au) --
-- Date Created: January, 2003 --
-- Description: gets c-squares code for a supplied lat/long coordinate pair; rewritten as a --
-- recursive function (cf original "get_csquare"), to cope with any supplied resolution --
-- Inputs: nlat: latitude in decimal degrees (number) --
-- nlong: longitude in decimal degrees (number) --
-- resolution: square size in decimal degrees (number) --
-- Output: code as varchar2 --
-- Remarks: resolution expected as one of the following: 10, 5, 1, 0.5, 0.1 etc. [degrees], --
-- **now extensible (cf original "get_csquare" code)** --
-- 0 deg latitude/longitude is treated as positive --
-- 90 deg latitude is treated as 89.99999, -90 deg latitude is treated as -89.99999 --
-- 180 deg longitude is treated as 179.99999, -180 deg longitude is treated as -179.99999 --
-----------------------------------------------------------------------------------------------------
function get_csq(nlat number :=null, nlong number :=null, resolution number) return varchar2
is
code_char1 varchar2 (1) :=null;
code_char2 varchar2 (1) :=null;
code_chars34 varchar2 (2) :=null;
csq_str varchar2 (20000) :=null;
next_triplet varchar2 (3) :=null;
lat_remainder number :=null;
long_remainder number :=null;
cycles_required number :=null;
proc_start integer; -- process timer in seconds
proc_end integer; -- process timer in seconds
function get_triplet (xLat number :=null, xLong number :=null) return varchar2 is
digit1 number :=null;
digit2 number :=null;
digit3 number :=null;
begin
--get the second digit
digit2 := trunc(xLat);
--get the third digit
digit3 := trunc(xLong);
--get the first digit
if digit2 between 0 and 4 and digit3 between 0 and 4 then
digit1 := 1;
elsif digit2 between 0 and 4 and digit3 between 5 and 9 then
digit1 := 2;
elsif digit2 between 5 and 9 and digit3 between 0 and 4 then
digit1 := 3;
elsif digit2 between 5 and 9 and digit3 between 5 and 9 then
digit1 := 4;
end if;
return to_char(digit1)||to_char(digit2)||to_char(digit3);
end get_triplet;
begin
-------------------------------
if global_debug then proc_start := to_number(to_char(sysdate,'SSSSS'));end if;
-------------------------------
--get the global quadrant
if nlat>=0 then
if nlong>=0 then
code_char1 :='1';
elsif nlong<0 then
code_char1 :='7';
end if;
elsif nlat<0 then
if nlong>=0 then
code_char1 :='3';
elsif nlong<0 then
code_char1 :='5';
end if;
end if;
--get the next digit (tens of degrees latitude)
if abs(nlat) >=90 then
--special case for +90, -90 degrees
code_char2 := '8';
lat_remainder := 9.99999;
else
code_char2 := to_char(trunc(abs(nlat/10)));
lat_remainder := abs(nlat) - (to_number(code_char2)*10);
end if;
--get the next 2 digits (tens of degrees longitude)
if abs(nlong) >=180 then
--special case for +180, -180 degrees
code_chars34 := '17';
long_remainder := 9.99999;
else
code_chars34 := substr('00'||to_char(trunc(abs(nlong/10))), -2);
long_remainder := abs(nlong) - (to_number(code_chars34)*10);
end if;
csq_str := code_char1||code_char2||code_chars34;
-- convert resolution to a number of times to process remainder
if resolution = 10 then
cycles_required := 0;
else
-- assign cycles_required to value 1 for resolution >=1, 2 for resolution >=0.1,
-- 3 for resolution >=0.01, etc.
cycles_required := length(to_char(resolution - trunc(resolution)));
end if;
while cycles_required >0 loop
next_triplet := get_triplet(lat_remainder, long_remainder);
csq_str := csq_str||':'||next_triplet;
lat_remainder := (lat_remainder - (to_number(substr(next_triplet,2,1))))*10;
long_remainder := (long_remainder - (to_number(substr(next_triplet,3,1))))*10;
cycles_required := cycles_required - 1;
end loop;
-- remove last two characters for a resolution whose last digit is a five, according to c-squares spec
if substr(to_char(resolution),-1)='5' then
csq_str := substr(csq_str,1,length(csq_str)-2);
end if;
return csq_str;
-------------------------------
if global_debug then proc_end := to_number(to_char(sysdate,'SSSSS'));htp.print('function get_csq : '||' Start sec: '||proc_start||' Finish sec: '||proc_end||' Total time: '|| to_char(proc_end -proc_start));htp.br;end if;
-------------------------------
end get_csq;