-
Notifications
You must be signed in to change notification settings - Fork 0
/
functions_def_02_content_based_balanced_grid.sql
247 lines (173 loc) · 7.24 KB
/
functions_def_02_content_based_balanced_grid.sql
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
--DROP FUNCTION cbg_content_based_balanced_grid(table_name_column_name_array VARCHAR[],
-- grid_geom_in geometry,
-- min_distance integer,
-- max_rows integer);
-- Create a content balanced grid based on number of rows in given cell.
-- Parameter 1 :
-- table_name_column_name_array a list of tables and collums to involve on the form
-- The table name must contain both schema and tablename
-- The geo column name must follow with one single space after the table name.
-- Does now handle tables with differentß srid
-- ARRAY['org_esri_union.table_1 geo_1', 'org_esri_union.table_2 geo_2']
-- Parameter 2 :
-- grid_geom_in if this is point it ises the boundry from the tables as a start
-- Parameter 3 :
-- min_distance this is the default min distance in meter (no box will be smaller that 5000 meter
-- Parameter 4 :
-- max_rows this is the max number rows that intersects with box before it's split into 4 new boxes
CREATE OR REPLACE FUNCTION cbg_content_based_balanced_grid (
table_name_column_name_array VARCHAR[],
grid_geom_in geometry,
min_distance integer,
max_rows integer
) RETURNS geometry AS
$body$
DECLARE
x_min float;
x_max float;
y_min float;
y_max float;
x_delta float;
y_delta float;
x_center float;
y_center float;
sectors geometry[];
grid_geom_meter geometry;
-- this may be adjusted to your case
metric_srid integer = 3035;
x_length_meter float;
y_length_meter float;
num_rows_table integer = 0;
num_rows_table_tmp integer = 0;
line VARCHAR;
line_values VARCHAR[];
geo_column_name VARCHAR;
table_name VARCHAR;
sql VARCHAR;
source_srid int;
grid_geom geometry;
tmp_geom geometry;
tmp_srid int;
tmp_schema_name VARCHAR;
tmp_table_name VARCHAR;
tmp_line_schema_table VARCHAR[];
BEGIN
-- if now extent is craeted for given table just do it.
IF ST_Area(grid_geom_in) = 0 THEN
grid_geom := cbg_get_table_extent(table_name_column_name_array);
--RAISE NOTICE 'Create new grid geom %', ST_AsText(grid_geom);
ELSE
grid_geom := grid_geom_in;
END IF;
source_srid = ST_Srid(grid_geom);
x_min := ST_XMin(grid_geom);
x_max := ST_XMax(grid_geom);
y_min := ST_YMin(grid_geom);
y_max := ST_YMax(grid_geom);
grid_geom_meter := ST_Transform(grid_geom, metric_srid);
x_length_meter := ST_XMax(grid_geom_meter) - ST_XMin(grid_geom_meter);
y_length_meter := ST_YMax(grid_geom_meter) - ST_YMin(grid_geom_meter);
FOR i IN ARRAY_LOWER(table_name_column_name_array,1)..ARRAY_UPPER(table_name_column_name_array,1) LOOP
line := table_name_column_name_array[i];
raise NOTICE '%',line;
SELECT string_to_array(line, ' ') INTO line_values;
table_name := line_values[1];
geo_column_name := line_values[2];
SELECT string_to_array(table_name, '.') INTO tmp_line_schema_table;
tmp_schema_name := tmp_line_schema_table[1];
tmp_table_name := tmp_line_schema_table[2];
tmp_geom = ST_MakeEnvelope( x_min, y_min, x_max, y_max, source_srid);
tmp_srid = Find_SRID(tmp_schema_name,tmp_table_name,geo_column_name);
tmp_geom = ST_Transform(tmp_geom,tmp_srid);
-- Use the && operator
-- We could here use any gis operation we vould like
EXECUTE Format('SELECT count(*) FROM %1$s WHERE %2$s && %3$L', table_name, geo_column_name, tmp_geom) INTO num_rows_table_tmp;
num_rows_table := num_rows_table + num_rows_table_tmp;
END LOOP;
IF x_length_meter < min_distance OR
y_length_meter < min_distance OR
num_rows_table < max_rows
THEN
sectors[0] := grid_geom;
RAISE NOTICE 'x_length_meter, y_length_meter %, % ', x_length_meter, y_length_meter ;
ELSE
x_delta := (x_max - x_min)/2;
y_delta := (y_max - y_min)/2;
x_center := x_min + x_delta;
y_center := y_min + y_delta;
-- sw
sectors[0] := cbg_content_based_balanced_grid(table_name_column_name_array,ST_MakeEnvelope(x_min,y_min,x_center,y_center, ST_SRID(grid_geom)), min_distance, max_rows);
-- se
sectors[1] := cbg_content_based_balanced_grid(table_name_column_name_array,ST_MakeEnvelope(x_center,y_min,x_max,y_center, ST_SRID(grid_geom)), min_distance, max_rows);
-- ne
sectors[2] := cbg_content_based_balanced_grid(table_name_column_name_array,ST_MakeEnvelope(x_min,y_center,x_center,y_max, ST_SRID(grid_geom)), min_distance, max_rows);
-- se
sectors[3] := cbg_content_based_balanced_grid(table_name_column_name_array,ST_MakeEnvelope(x_center,y_center,x_max,y_max, ST_SRID(grid_geom)), min_distance, max_rows);
END IF;
RETURN ST_Collect(sectors);
END;
$body$
LANGUAGE 'plpgsql';
-- Function with default values called with 2 parameters
-- Parameter 1 : An array of tables names and the name of geometry columns.
-- The table name must contain both schema and table name, The geometry column name must follow with one single space after the table name.
-- Parameter 2 : max_rows this is the max number rows that intersects with box before it's split into 4 new boxes
-- Parameter 3 : initial_bbox this is used when you need to limit the area you work on.
-- Using initial_bbox means not checking the table extent and then trust the initial_bbox
CREATE OR REPLACE FUNCTION cbg_content_based_balanced_grid (
table_name_column_name_array VARCHAR[],
max_rows integer,
initial_bbox geometry)
RETURNS geometry AS
$body$
DECLARE
-- sending in a point will cause the table to use table extent
grid_geom geometry := ST_GeomFromText('POINT(0 0)');
-- set default min distance to 1000 meter
min_distance integer := 1000;
BEGIN
-- use the area from the user as a bouding box
IF initial_bbox IS NOT NULL THEN
grid_geom := ST_Envelope(initial_bbox);
END IF;
return cbg_content_based_balanced_grid(
table_name_column_name_array,
grid_geom,
min_distance,
max_rows);
END;
$body$
LANGUAGE 'plpgsql';
-- Grant so all can use it
GRANT EXECUTE ON FUNCTION cbg_content_based_balanced_grid (table_name_column_name_array VARCHAR[],max_rows integer,initial_bbox geometry) to public;
-- Grant so all can use it
GRANT EXECUTE ON FUNCTION cbg_content_based_balanced_grid (
table_name_column_name_array VARCHAR[],
grid_geom_in geometry,
min_distance integer,
max_rows integer) to public;
-- Function with default values called with 2 parameters
-- Parameter 1 : An array of tables names and the name of geometry columns.
-- The table name must contain both schema and table name, The geometry column name must follow with one single space after the table name.
-- Parameter 2 : max_rows this is the max number rows that intersects with box before it's split into 4 new boxes
CREATE OR REPLACE FUNCTION cbg_content_based_balanced_grid (
table_name_column_name_array VARCHAR[],
max_rows integer)
RETURNS geometry AS
$body$
DECLARE
-- sending in a point will cause the table to use table extent
grid_geom geometry := ST_GeomFromText('POINT(0 0)');
-- set default min distance to 1000 meter
min_distance integer := 1000;
BEGIN
return cbg_content_based_balanced_grid(
table_name_column_name_array,
grid_geom,
min_distance,
max_rows);
END;
$body$
LANGUAGE 'plpgsql';
-- Grant so all can use it
GRANT EXECUTE ON FUNCTION cbg_content_based_balanced_grid (table_name_column_name_array VARCHAR[],max_rows integer) to public;