I'm looking for a way to create so-called one-sided buffers or parallel lines in PostGIS. Example: 1. buffer, 2. one-side, 3. both-sides

alt text

I've found some discussion on the mailing list from 2009 and information that it has been implemented in GEOS, but nothing about the current PostGIS status.

In case the function is not implemented yet, do you know any workarounds? Is it possible to cut off one side of a normal buffer?

  • So you're looking for an equivalent to "offset" in AutoCAD? – dassouki Aug 15 '10 at 23:06
  • @dassouki: Sorry, I don't know AutoCAD. But I think UMN Mapserver has an "offset" option that would do what I'm looking for. – underdark Aug 17 '10 at 10:11
  • How to create one-sided buffers or parallel lines, from a table that have 600 lines? – user3230 Jun 10 '11 at 0:35
  • Welcome to the site. If the current set of answers doesn't solve your problem you should open this as a new question (and state why this question does not answer your problem). Within the format of the site this is not an appropriate place to make this statement, as it is not an answer to the question. – Andy W Jun 10 '11 at 1:26
  • How can I create a parallel lines in a MULTILINESTRING table? – Felipe Costa Jun 23 '11 at 13:35

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)
| improve this answer | |
  • Hi I'm trying to use this solution but don't use postgis often - I have tested this query and get some ouput values, but how do i translate those into features? I just want the lines in the end, either as part of the original table, or a new one.This is my query: select ST_AsText(ST_OffsetCurve( test_data_.geom, test_data_.buffer_dis,'join=mitre mitre_limit=5.0')) from test_data_; – kflaw Apr 18 '16 at 21:07
  • @kflaw - you've probably already figured this out, but you just need to add to the beginning of the query: "create newtable as" or for a view, "create or replace view newview as" followed by the select statement. – jbalk Mar 10 '17 at 2:03

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 ((

  ST_Polygonize(GEOMUNION(ST_Boundary(ST_Buffer(the_geom, 0.5, 'endcap=flat join=round')), the_geom)) AS buffer_sides 
  (SELECT ST_GeomFromText('LINESTRING(1 1, 1 5, 5 5)') AS the_geom) AS table1


It outputs:


 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:

  1. 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.
  2. 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.

A buffered linestring with a flat endcap

| improve this answer | |

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_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 ((
    ST_Polygonize(st_union(ST_Boundary(ST_Buffer(geometria, 0.5, 'endcap=flat join=mitre mitre_limit=5.0')), geometria)) AS buffer_sides 
    (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)"


Because i still can't comment here, i add this answer

SCW give the best answer,

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)

But looks like the function change

Now the 'right' parameter isn't necessary. Using positive distance will create left side and negative distance will create the right side

Also no patch needed with my postgis

SELECT PostGIS_full_version();
"POSTGIS="2.0.3 r11132" GEOS="3.3.8-CAPI-1.7.8" 
PROJ="Rel. 4.8.0, 6 March 2012" GDAL="GDAL 1.9.2, 
released 2012/10/08" LIBXML="2.7.8" LIBJSON="UNKNOWN" RASTER"
| improve this answer | |

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.