Creating one-sided buffers or parallel lines in PostGIS?
Proper one-sided buffers were supposed to have landed in 1.5, but it looks to me that while the styles did land, sidedness didn't make it in. There is however a current patchset which exposes GEOSSingleSidedBuffer
and performs the one-sided buffer as expected, under the name ST_OffsetCurve
; see further background in ticket #413. In use:
select ST_AsText(ST_OffsetCurve(
ST_GeomFromText('LINESTRING(10 10,10 20, 20 20 )'),
1,'right', 'join=mitre mitre_limit=5.0'));
--------------
LINESTRING(20 19,11 19,11 10)
This sample creates two polygons on either side of a linestring. It requires PostGIS 1.5 or greater. I'm not sure how well it will cope with lines that cross themselves.
SELECT ST_AsText(geom)
FROM ST_Dump ((
SELECT
ST_Polygonize(GEOMUNION(ST_Boundary(ST_Buffer(the_geom, 0.5, 'endcap=flat join=round')), the_geom)) AS buffer_sides
FROM
(SELECT ST_GeomFromText('LINESTRING(1 1, 1 5, 5 5)') AS the_geom) AS table1
));
It outputs:
st_astext
------------------------------------------------------------------------------------------------------------------------
------------------------------------------------------------------------------------------------------------------------
----------------------------------------------------------
POLYGON((0.5 5,0.509607359798385 5.09754516100806,0.538060233744357 5.19134171618254,0.584265193848727 5.2777851165098,
0.646446609406726 5.35355339059327,0.722214883490199 5.41573480615127,0.808658283817455 5.46193976625564,0.9024548389919
36 5.49039264020162,1 5.5,5 5.5,5 5,1 5,1 1,0.5 1,0.5 5))
POLYGON((5 5,5 4.5,1.5 4.5,1.5 1,1 1,1 5,5 5))
(2 rows)
The code works the following way:
- Buffer the linestring using ST_Buffer. We take advantage of the PostGIS 1.5 feature supporting custom endcaps in order to specify no end cap at all. See example below.
- Split the buffered polygon in two, using the original line, using the method documented in the wiki.
This could be improved to cope with self-crossing lines in future.
This modification creates two parallel linestring. It requires PostGIS 1.5 or greater.
required geometry or wkt, and distance in the buffer
SELECT astext(
st_removepoint(
st_removepoint( st_linemerge(ST_Difference(st_boundary(geom),ST_GeomFromText('LINESTRING(1 1, 1 5, 5 5)'))) ,0),
st_npoints(st_linemerge(ST_Difference(st_boundary(geom),ST_GeomFromText('LINESTRING(1 1, 1 5, 5 5)'))))-2)
) as parallel
FROM ST_Dump ((
SELECT
ST_Polygonize(st_union(ST_Boundary(ST_Buffer(geometria, 0.5, 'endcap=flat join=mitre mitre_limit=5.0')), geometria)) AS buffer_sides
FROM
(SELECT ST_GeomFromText('LINESTRING(1 1, 1 5, 5 5)')
AS geometria) AS tabla))
-------------- RESULTS
"LINESTRING(0.5 1,0.5 5.5,5 5.5)"
"LINESTRING(5 4.5,1.5 4.5,1.5 1)"