-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathcreate_gridlines.sql
More file actions
266 lines (252 loc) · 7.25 KB
/
create_gridlines.sql
File metadata and controls
266 lines (252 loc) · 7.25 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
--Purpose: to generate a grid of longitude and latitude lines that
--spand the SADC region and bend according to the projection in use.
--Output: Table containing rows, each row with geometry and data
--for a line of longitude or latitiude and each line separated at
--five-minute intervals.
--delete the old table if it's there
DROP TABLE IF EXISTS sadc.grid;
--create the grid line table
CREATE TABLE sadc.grid(
gid serial primary key,
the_geom geometry(LINESTRING,4326),
line_pos numeric(10,6),
line_name varchar(11),
line_res varchar(6),
line_type varchar(4),
line_num integer,
line_int_dd numeric (10,6),
line_int_min integer);
--create or replace the function that does the looping to ceate the lines
CREATE OR REPLACE FUNCTION sadc.draw_grid_lines(
x_min integer, --southern-most line of latitude in whole degrees
x_max integer, --northern-most line of latitude in whole degrees
y_int integer, --interval of latitude lines in whole minutes (60 = 1 degree)
y_min integer, --western-most line of longitude in whole degrees
y_max integer, --eastern-most line of longitude in whole degrees
x_int integer) --interval of longitude lines in whole minutes (60 = 1 degree)
RETURNS VOID AS
$BODY$
DECLARE
x_coord numeric(21,18); --the coordinates of the vertices on the lines
y_coord numeric(21,18); -- " " "
i integer; --counter
line_int numeric(24,21); --space between lines in decimal fractions of a degree
mant numeric(21,18); --fractional part of the line's definition
deg integer; --whole part (unsigned) of the line's defintion
min integer; --fractional part, (unsigned minutes) of the line's defintion
hemis varchar(2); --hemisphere (N, S, E, W) of the line's definition
line varchar(11); --description in degrees, minutes and hemisphere, of the line
unit varchar(6); --whether line represents a whole degree or a fraction (minute)
wkt_str varchar; --the WKT vesrion of each string
BEGIN
--Check the limits of the input parameters
--too far east
IF x_min < -179.99 THEN
--fix the limit to -179.99 long
x_min := -179.99;
END IF;
--too far west
IF x_max > 180 THEN
--fix the limit to 180.0 long
x_max := 180.0;
END IF;
--too far south
IF y_min < -85 THEN
--fix the limit to -85.0 lat
y_min := -85.0;
END IF;
--too far north
IF y_max > 85 THEN
--fix the limit to 85.0 lat
y_max := 85.0;
END IF;
--horizontal limits inverted
IF x_min > x_max THEN
--swap them
x_coord := x_max;
x_max := x_min;
x_min := x_coord;
END IF;
--vertical limits inverted
IF y_min > y_max THEN
--swap them
y_coord := y_max;
y_max := y_min;
y_min := y_coord;
END IF;
--start with the lines of latitude (horizontals)
y_coord := y_min;
--reset the counter
i := 1;
--Check the line interval isn't more that the bounds (y_min to y_max)
IF y_int > (y_max - y_min) * 60 THEN
y_int := (y_max - y_min) * 60;
END IF;
--get the interval between lines in decimal degrees
line_int := abs(y_int) / 60.0;
--loop to add new lines of latitude
<<hlines>>
LOOP
EXIT hlines WHEN (y_coord > y_max) OR (i > abs(60.0 * (y_max - y_min)));
--Reset the start of the lines to the left
x_coord := x_min;
--make a label for the line in degrees and minutes
deg := trunc(y_coord);
mant := abs(y_coord - deg);
hemis := to_char(sign(round(y_coord,6)),'SG9');
deg := abs(deg);
min := round(round(mant,5) * 60);
IF min >= 60 THEN
deg := deg + 1;
min := min - 60;
END IF;
CASE hemis
WHEN '-1' THEN
hemis := 'S';
WHEN '+1' THEN
hemis := 'N';
ELSE
hemis := ' ';
END CASE;
line := to_char(deg, '99') || chr(186) || to_char(min, '00') || chr(180) || ' ' || hemis;
--catagorise the line as a degree line or a minute line
CASE min
WHEN 0 THEN
unit := 'degree';
ELSE
unit := 'minute';
END CASE;
--set up the first point on the WKT string
wkt_str := 'SRID=4326;LINESTRING(' || x_coord || ' ' || y_coord;
--loop to add points to the line
<<hpoints>>
LOOP
--leave the loop after reaching the maximum width
EXIT hpoints WHEN x_coord > x_max;
--increment by 1 hundredth of a degree (line curvature)
x_coord := x_coord + 0.01;
--concatenate next coordinates
wkt_str := wkt_str || ', ' || x_coord || ' ' || y_coord;
END LOOP hpoints;
--close the WKT string with a ')'
wkt_str := wkt_str || ')';
--load the data,including the WKT as a geometry, into the table as a row
INSERT INTO sadc.grid(
the_geom,
line_pos,
line_name,
line_res,
line_type,
line_num,
line_int_dd,
line_int_min)
VALUES (
ST_GeomFromEWKT(wkt_str),
y_coord,
line,
unit,
'lat',
i,
line_int,
y_int);
--increment the longitude by the line interval to position the next line
y_coord := y_coord + line_int;
--increment the counter
i := i + 1;
END LOOP hlines;
--next, the lines of longitude (verticals)
x_coord := x_min;
--reset the counter
i := 1;
--Check the line interval isn't more that the bounds (x_min to x_max)
IF x_int > (x_max - x_min) * 60 THEN
x_int := (x_max - x_min) * 60;
END IF;
line_int := abs(x_int) / 60.0;
--loop to add new lines of longitude
<<vlines>>
LOOP
EXIT vlines WHEN (x_coord > x_max) OR (i > abs(60.0 * (x_max - x_min)));
y_coord := y_min;
--make a label for the line in degrees and minutes
deg := trunc(x_coord);
mant := abs(x_coord - deg);
hemis := to_char(sign(x_coord),'SG9');
deg := abs(deg);
min := round(round(mant,5) * 60.0);
IF min >= 60 THEN
deg := deg + 1;
min := min - 60;
END IF;
CASE hemis
WHEN '-1' THEN
hemis := 'W';
WHEN '+1' THEN
hemis := 'E';
ELSE
hemis := ' ';
END CASE;
line := to_char(deg, '999') || chr(186) || to_char(min, '00') || chr(180) || ' ' || hemis;
--catagorise the line as a degree line or a 10', 20', 30', 40' or 50' line
CASE min
WHEN 0 THEN
unit := 'degree';
ELSE
unit := 'minute';
END CASE;
--set up the first point on the WKT string
wkt_str := 'SRID=4326;LINESTRING(' || x_coord || ' ' || y_coord;
--loop to add points to the line
<<vpoints>>
LOOP
--leave the loop after reaching the maximum height
EXIT vpoints WHEN y_coord > y_max;
--increment by 1 hundredth of a degree (line curvature)
y_coord := y_coord + 0.01;
--concatenate next coordinates
wkt_str := wkt_str || ', ' || x_coord || ' ' || y_coord;
END LOOP vpoints;
--close the WKT string with a ')'
wkt_str := wkt_str || ')';
--load the data,including the WKT as a geometry, into the table as a row
INSERT INTO sadc.grid(
the_geom,
line_pos,
line_name,
line_res,
line_type,
line_num,
line_int_dd,
line_int_min)
VALUES (
ST_GeomFromEWKT(wkt_str),
x_coord,
line,
unit,
'long',
i,
line_int,
x_int);
--increment the longitude by the line interval to position the next line
x_coord := x_coord + line_int;
--increment the counter
i := i + 1;
END LOOP vlines;
-- RETURN wkt_str;
RETURN;
END;
$BODY$
LANGUAGE plpgsql;
--run the function, with the given parameters
SELECT * FROM sadc.draw_grid_lines(0, 75, 5, -50, 15, 5);
--view thw result
SELECT
ST_AsEWKT(the_geom),
line_pos,
line_name,
line_res,
line_type,
line_num,
line_int_dd,
line_int_min
FROM sadc.grid;