# How to do small expansion into LINESTRING ends?

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 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).

## 1 Answer

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 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,array)) 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'
;
``````