2

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:

CREATE VIEW v AS
  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).

Peter Krauss
  • 2,292
  • 23
  • 43

2 Answers2

2

In PostGIS 3.4 this can be done using ST_LineExtend.

dr_jts
  • 5,038
  • 18
  • 15
0

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

CREATE FUNCTION ST_ExtendLine_ToPoly(
  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
) RETURNS TABLE (
  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$
  SELECT
   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,
   boundary,
   (
    SELECT ST_MakeLine(geom)
    FROM (
      (SELECT array[0] AS path, geom
       FROM ST_Dump(ST_Intersection(
             boundary, 
             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
      )
      UNION ALL
      SELECT * FROM ST_Dump(p_line)
      UNION ALL
      (SELECT array [ST_NumPoints(p_line)+1] as path, geom
       FROM ST_Dump(ST_Intersection(
              boundary, 
              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 (
    SELECT
      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'
;
Peter Krauss
  • 2,292
  • 23
  • 43