I'm trying to implement a simplified type of dasymetric mapping for census data. I've downloaded the Census's American Community Survey individual-level data and randomly assigned every household to a point within a block group. Now I want to move these random points to the nearest road. I've downloaded the OSM data and loaded it via osm2pgsql. So I have two tables:
dade_random_points: a point for each household. 'wkb_geometry' is the geo field.
dade_planet_osm_roads: a linestring for every road. 'way' is the geo field.
(By the way, I'm doing a proof-of-concept with just Miami-Dade County for right now.)
After reading How to get the nearest point on a linestring to a given point? and http://www.postgis.org/docs/ST_ClosestPoint.html
I wrote this enormous, multi-nested query. It's still churning on my laptop, but it seems to work when I put in 'limit' statements to do smaller pieces.
Surely there has to be a better way? (Or maybe there's a postgis dasymetric library out there somewhere that I haven't been able to find?)
drop table if exists dade_points_on_roads cascade;
create table dade_points_on_roads as
select
table4.id,
table4.osm_id,
table4.geoid10,
table4.name,
ST_ClosestPoint(
ST_Transform(table4.way, 4326),
ST_Transform(table4.wkb_geometry, 4326)
) as point_on_road
from
(
select
--table3.*,
points.*,
roads.*
from
(
select
table1.id,
min(table1.distance) as distance
from
(
select
p.id,
r.osm_id,
ST_Distance(
ST_Transform(r.way, 4326),
ST_Transform(p.wkb_geometry, 4326)
) as distance
from
dade_planet_osm_roads as r,
dade_random_points as p
where
ST_DWithin(
ST_Transform(r.way, 4326),
ST_Transform(p.wkb_geometry, 4326),
500
)
--limit 1000
) as table1
--order by distance asc
group by table1.id
--limit 10
) as table2,
(
select
p.id,
r.osm_id,
ST_Distance(
ST_Transform(r.way, 4326),
ST_Transform(p.wkb_geometry, 4326)
) as distance
from
dade_planet_osm_roads as r,
dade_random_points as p
where
ST_DWithin(
ST_Transform(r.way, 4326),
ST_Transform(p.wkb_geometry, 4326),
500
)
--limit 1000
) as table3,
dade_planet_osm_roads as roads,
dade_random_points as points
where
table2.id = table3.id
and table2.distance = table3.distance
and table2.id = points.id
and table3.osm_id = roads.osm_id
) as table4
;