116 lines
3.5 KiB
PL/PgSQL
116 lines
3.5 KiB
PL/PgSQL
CREATE OR REPLACE FUNCTION CDB_Gravity(
|
|
IN target_query text,
|
|
IN weight_column text,
|
|
IN source_query text,
|
|
IN pop_column text,
|
|
IN target bigint,
|
|
IN radius integer,
|
|
IN minval numeric DEFAULT -10e307
|
|
)
|
|
RETURNS TABLE(
|
|
the_geom geometry,
|
|
source_id bigint,
|
|
target_id bigint,
|
|
dist numeric,
|
|
h numeric,
|
|
hpop numeric) AS $$
|
|
DECLARE
|
|
t_id bigint[];
|
|
t_geom geometry[];
|
|
t_weight numeric[];
|
|
s_id bigint[];
|
|
s_geom geometry[];
|
|
s_pop numeric[];
|
|
BEGIN
|
|
EXECUTE 'WITH foo as('+target_query+') SELECT array_agg(cartodb_id), array_agg(the_geom), array_agg(' || weight_column || ') FROM foo' INTO t_id, t_geom, t_weight;
|
|
EXECUTE 'WITH foo as('+source_query+') SELECT array_agg(cartodb_id), array_agg(the_geom), array_agg(' || pop_column || ') FROM foo' INTO s_id, s_geom, s_pop;
|
|
RETURN QUERY
|
|
SELECT g.* FROM t, s, CDB_Gravity(t_id, t_geom, t_weight, s_id, s_geom, s_pop, target, radius, minval) g;
|
|
END;
|
|
$$ language plpgsql VOLATILE PARALLEL UNSAFE;
|
|
|
|
CREATE OR REPLACE FUNCTION CDB_Gravity(
|
|
IN t_id bigint[],
|
|
IN t_geom geometry[],
|
|
IN t_weight numeric[],
|
|
IN s_id bigint[],
|
|
IN s_geom geometry[],
|
|
IN s_pop numeric[],
|
|
IN target bigint,
|
|
IN radius integer,
|
|
IN minval numeric DEFAULT -10e307
|
|
)
|
|
RETURNS TABLE(
|
|
the_geom geometry,
|
|
source_id bigint,
|
|
target_id bigint,
|
|
dist numeric,
|
|
h numeric,
|
|
hpop numeric) AS $$
|
|
DECLARE
|
|
t_type text;
|
|
s_type text;
|
|
t_center geometry[];
|
|
s_center geometry[];
|
|
BEGIN
|
|
t_type := GeometryType(t_geom[1]);
|
|
s_type := GeometryType(s_geom[1]);
|
|
IF t_type = 'POINT' THEN
|
|
t_center := t_geom;
|
|
ELSE
|
|
WITH tmp as (SELECT unnest(t_geom) as g) SELECT array_agg(ST_Centroid(g)) INTO t_center FROM tmp;
|
|
END IF;
|
|
IF s_type = 'POINT' THEN
|
|
s_center := s_geom;
|
|
ELSE
|
|
WITH tmp as (SELECT unnest(s_geom) as g) SELECT array_agg(ST_Centroid(g)) INTO s_center FROM tmp;
|
|
END IF;
|
|
RETURN QUERY
|
|
with target0 as(
|
|
SELECT unnest(t_center) as tc, unnest(t_weight) as tw, unnest(t_id) as td
|
|
),
|
|
source0 as(
|
|
SELECT unnest(s_center) as sc, unnest(s_id) as sd, unnest (s_geom) as sg, unnest(s_pop) as sp
|
|
),
|
|
prev0 as(
|
|
SELECT
|
|
source0.sg,
|
|
source0.sd as sourc_id,
|
|
coalesce(source0.sp,0) as sp,
|
|
target.td as targ_id,
|
|
coalesce(target.tw,0) as tw,
|
|
GREATEST(1.0,ST_Distance(geography(target.tc), geography(source0.sc)))::numeric as distance
|
|
FROM source0
|
|
CROSS JOIN LATERAL
|
|
(
|
|
SELECT
|
|
*
|
|
FROM target0
|
|
WHERE tw > minval
|
|
AND ST_DWithin(geography(source0.sc), geography(tc), radius)
|
|
) AS target
|
|
),
|
|
deno as(
|
|
SELECT
|
|
sourc_id,
|
|
sum(tw/distance) as h_deno
|
|
FROM
|
|
prev0
|
|
GROUP BY sourc_id
|
|
)
|
|
SELECT
|
|
p.sg as the_geom,
|
|
p.sourc_id as source_id,
|
|
p.targ_id as target_id,
|
|
case when p.distance > 1 then p.distance else 0.0 end as dist,
|
|
100*(p.tw/p.distance)/d.h_deno as h,
|
|
p.sp*(p.tw/p.distance)/d.h_deno as hpop
|
|
FROM
|
|
prev0 p,
|
|
deno d
|
|
WHERE
|
|
p.targ_id = target AND
|
|
p.sourc_id = d.sourc_id;
|
|
END;
|
|
$$ language plpgsql IMMUTABLE PARALLEL SAFE;
|