In order to do aggregation/dissolving, you can try using st_buffer
on grouped (clustered) geometries.
Something like this:
st_buffer(st_buffer(your_clustered_aggregated_geometry, 1000), -1000)
Depending on details you can add an option to use quad_segs=1 to
avoid having round corners when doing positive buffer.
Something like this:
st_buffer(st_buffer(you_clustered_aggregated_geometry, 1000,
'quad_segs=1'), -1000, 'quad_segs=1')
--
Tomas
Have not tested your statement, but besides missing comma between
1000 and 'quad_segs=1' looks fine.
I use such buffering for landuse (forest, water) aggregation for
different scales.
There are other options like doing +50 -100 +50, or -50 +100 -50
buffer. Depending on which works better. One way is better at
eradicating small inner gaps, other method is better at removing small
external details.
P.S. There is also convex function, but in my experience buffers give
better result.
--
Tomas
Yes (just not buildings, but landuses).
ST_ClusterWithin(way, 500)) <- this combines all polygons which are
less than 500 meters apart.
For landuses 10 meters for ST_Buffer not enough. Try increasing 10
to say a 400(m) or even more (especially given you're clustering
polygons with a distance of 500 meters). If a distance between
different parts (polygons) of a geometry is 500 meters, you need a
buffer of at least 250 meters for them to "touch", if different parts
of geometries will not "touch" with positive buffer - they will not
combine - will not form one aggregated geometry out of a lot of small
ones.
> But I don't understand what "res" means...
In my case the same table holds information for different scales of
a map (multi-sclae). res=10 are values for 10 scale, then there are
values for 40, 120 etc. You can ignore them.
P.S. Hint: do one step at a time and then use QGIS to see how those
intermediate geometries look like. It will make it easier to
understand what this code does.
--
Tomas
This statement has problems.
You're adding a buffer of 10 then removing a buffer of 500 (so
basically leaving only very large polygons and they are eroded by
500meters). Then you're simplifying the result with a 500m value (a
lot).
Try this:
UPDATE city_boundaries
SET way = ST_Makevalid(ST_Multi(ST_Buffer(ST_Buffer(way, 400,
'quad_segs=1'), -400, 'quad_segs=1')));
Hi
> This statement has problems.
> You're adding a buffer of 10 then removing a buffer of 500 (so
> basically leaving only very large polygons and they are eroded by
> 500meters). Then you're simplifying the result with a 500m value (a
> lot).
>
> Try this:
>
> UPDATE city_boundaries
> SET way = ST_Makevalid(ST_Multi(ST_Buffer(ST_Buffer(way, 400,
> 'quad_segs=1'), -400, 'quad_segs=1')));
I tried this:
CREATE TABLE city_boundaries AS
SELECT NEXTVAL('city_boundaries_seq') AS id
,0::bigint AS way_area
,10 AS res
,ST_CollectionExtract(unnest(ST_ClusterWithin(way, 400)),
3)::geometry(MultiPolygon, 3857) as way
FROM planet_osm_polygon
WHERE landuse IN ('residential', 'retail', 'retail;residential',
'commercial', 'school', 'university');
ALTER TABLE city_boundaries OWNER TO _renderd;
DELETE FROM city_boundaries WHERE ST_Area(ST_Buffer(way, -400)) < 400
and res = 10;
UPDATE city_boundaries SET way =
ST_Makevalid(ST_Multi(ST_Buffer(ST_Buffer(way, 400, 'quad_segs=1'),
-400, 'quad_segs=1')));
UPDATE city_boundaries SET way_area = st_area(way) WHERE res = 10;
This will be better, but:
1) I have always many little areas
2) I miss some "medium areas"
3) the displayed areas have many "holes"
A possible solution to 2) could be to reduce the distance (let's say 200
meter instead of 400?) but so I'll increase the number of little areas.
I think a right way could be to reduce the distance (see previous) and
generate an area grouping all near little areas, filling the "inclosed"
holes in the areas. Then I can search for areas greater than for example
20 Km².
But I don't know to do that...
Thanks
Luca Bertoncello
(luca...@lucabert.de)
Hi Hugues
> The attached function could help you to solve your issues and test
> several thresholds when adapted to your own database. I'm sorry it's
> written in a weird French-English style but the queries should help
> you to understand the variable names meaning. Of course, feel free to
> ask any question.
>
> The hole issue is directly adressed line 55 to line 85. It uses
> st_dumprings along with st_exterrioring and st_buildarea and compares
> hole surface to the "surf_trou" threshold.
Thank you very much. I'll try to adapt your functions to the
OpenStreetMaps' data.
Now I'm trying to reduce the "little spots" on the map joining the table
with the "city's building boundaries" with a table with the "city's
administrative boundaries" and select only the building in a city, but
it does not work...
My query:
SELECT
city_boundaries.way
FROM city_boundaries, city_admin_boundaries
WHERE ST_Within(city_boundaries.way,
city_admin_boundaries.way) AND
(city_admin_boundaries.population >= 18000 OR
city_admin_boundaries.km2 >= 50);
Unfortunately I get many little spots outsides the cities and inside the
cities I have few spots with buildings.
If I just use:
SELECT
city_boundaries.way
FROM city_boundaries
WHERE (ST_Area(ST_Transform(way, 4326)::geography) / 1000000)
> 3.5;
I get many spots outside the city and great building's spots inside the
cities.
city_admin_boundaries was created as:
CREATE TABLE city_admin_boundaries AS
SELECT
planet_osm_polygon.way,
planet_osm_polygon.admin_level,
planet_osm_point.name,
planet_osm_point.place,
CASE
WHEN (planet_osm_point.tags->'population' ~ '^[0-9]{1,8}$') THEN
(planet_osm_point.tags->'population')::INTEGER ELSE 0
END as population,
(ST_Area(ST_Transform(planet_osm_polygon.way, 4326)::geography) /
1000000) AS km2
FROM planet_osm_polygon
JOIN (
SELECT name, MAX(admin_level) AS al
FROM planet_osm_polygon
WHERE boundary = 'administrative' AND admin_level IN ('4', '6', '8')
AND osm_id < 0 GROUP BY name
) size USING(name)
JOIN planet_osm_point USING (name)
WHERE planet_osm_polygon.boundary = 'administrative' AND
planet_osm_polygon.admin_level = size.al AND
(
(
planet_osm_polygon.admin_level IN ('6', '8') AND
planet_osm_point.place IN ('city', 'town')
) OR
(
planet_osm_polygon.admin_level = '4' AND
planet_osm_point.place = 'city'
)
) AND
planet_osm_polygon.osm_id < 0;
and contains correct data, since I display the administrative boundaries
on the map, too and they are correct.
Could someone explain me where is my error?
Thanks
Luca Bertoncello
(luca...@lucabert.de)
If 300m buffer +- is good for your scale, then you can reduce the
number of vertexes thus speeding up buffer operations considerably.
For example you could dp simplify geometries beforehand.
Something like:
UPDATE city_boundaries SET way = ST_SimplifyPreserveTopology(way, 100);
before running running buffer +- update.
(or you could put simplify inside your current update statement as a
first action then you will only have one update instead of two for
each geometry)
--
Tomas
Add ST_Multi like this:
UPDATE city_boundaries SET way =
ST_Multi(ST_SimplifyPreserveTopology(way, 100));
OK, thank you!
A test looks like very good, pretty the same of the previous version, so
I'll use it.
Regards
Luca Bertoncello
(luca...@lucabert.de)
UPDATE city_boundaries SET way =ST_Multi(
ST_SimplifyPreserveTopology(way, 100));
>