The geometric problem is similar to this other one, that can be described as "small extrapolation of the line ends".

The correct solution must to expand/extrapolate d meters (ex. 2 meters) of line ends, of lines of any length.

Illustrating by a real life example

Here we need a small expansion into line ends to glue lines of a road network. The magic function not exists, but in some cases we can use ST_Scale to illustrate in the context.

I am testing this algorithm with no changes, except to include ST_Scale:

  SELECT city_id, (st_dump).path[1] as poly_id, (st_dump).geom 
  FROM (
    SELECT city_id, ST_Dump(ST_Polygonize(geom))
    FROM (
       SELECT city_id,
              -- this works only for some straight lines
              ST_Union( ST_Scale(geom,1.01,1.01) ) as geom
       FROM road_network -- suppose all LINESTRINGs
       GROUP BY city_id
    ) mergedlines
    GROUP BY city_id
  ) polys

This wrong use of ST_Scale() funciton expanded in 1% the length (average ~2m) of the lines... Seems that works with straight lines, but, of course, curved lines will be distorted. And also I not need "proportional expansion" but only "constant line ends expansion" (the small 2 meters extrapolation of line ends).

I not see how to use the @SzieberthAdam's function of his solution, replacing ST_Scale of the example. The @Jayden and @EoghanM solutions must be transformed into a generic function to be applied into LINESTRINGs.

PS: on this problem the ST_SnapToGrid is valid but only for very small correction. Not a good solution, because cause geometric distortions, and the ST_SnapToGrid(geom,w) not solves all cases with w=2m (need bigger), and it not shows convergence with w (destroys/collapses the network).


This is a Wiki, and I am testing the function, it is not 100% checked.

  p_line geometry('LINESTRING'),  -- line to be extended
  p_area geometry,                -- POLYGON or MULTIPOLIGON as context or boundary limits
  P_maxGrow float DEFAULT NULL    -- not null is a limit
  p_gflag boolean DEFAULT false   -- for SRID=4326, etc. to be metric on true
  dist float,  -- dist from line to boundary-diagonal
  first_segment geometry('LINESTRING'),
  last_segment geometry('LINESTRING'),
  boundary geometry, -- expecting POLYGON
  points geometry('LINESTRING')
) AS $f$
   dist,  -- * = <dist, first_segment, last_segment, boundary>
   CASE WHEN P_maxGrow IS NOT NULL AND ST_Length(first_segment,p_gflag)>P_maxGrow THEN NULL ELSE first_segment END,
   CASE WHEN P_maxGrow IS NOT NULL AND ST_Length(last_segment,p_gflag)>P_maxGrow THEN NULL ELSE last_segment END,
    SELECT ST_MakeLine(geom)
    FROM (
      (SELECT array[0] AS path, geom
       FROM ST_Dump(ST_Intersection(
             ST_Scale(first_segment, ST_MakePoint(dist/ST_length(first_segment), dist/ST_length(first_segment)), ST_EndPoint(first_segment))
       ORDER BY ST_Distance(geom, ST_StartPoint(first_segment))
       LIMIT 1
      SELECT * FROM ST_Dump(p_line)
      (SELECT array [ST_NumPoints(p_line)+1] as path, geom
       FROM ST_Dump(ST_Intersection(
              ST_Scale(last_segment, ST_MakePoint(dist/ST_length(last_segment), dist/ST_length(last_segment)), ST_StartPoint(last_segment))
       ORDER BY ST_Distance(geom, ST_StartPoint(last_segment))
       LIMIT 1
    ) pts -- table
   ) AS points -- last attribute after t1.*
  FROM (
      ST_Length(ST_BoundingDiagonal(p_area)) AS dist,
      (SELECT ST_MakeLine(geom) FROM ST_DumpPoints(p_line) WHERE path in (array[1],array[2])) AS first_segment,
      (  SELECT ST_MakeLine(geom) 
         FROM ST_DumpPoints(p_line) 
         WHERE path in (array[ST_NPoints(p_line)],array[ST_NPoints(p_line)-1])
      ) AS last_segment,
      ST_Boundary(p_area) AS boundary
  ) t1
$f$ language SQL IMMUTABLE;
COMMENT ON FUNCTION ST_ExtendLine_ToPoly(geometry,geometry)
  IS 'Extends a linestring to the edge of an enclosing polygon, see https://gis.stackexchange.com/a/345484/7505'

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.