[postgis-users] Obtaining nearest points between two linestrings
Arnaud Lesauvage
thewild at freesurf.fr
Fri Dec 8 02:14:08 PST 2006
Rodrigo Martín LÓPEZ GREGORIO a écrit :
> Hi, first of all, sorry my english.
>
> I was trying to find a way to obtain the coordinates of the nearest points
> between two linestring. I play some time with the distance, line_locate_point,
> line_interpolate_point and other functions but I didn't find a way to get
> the information I want. I think that what I'm trying to find is a function
> like line_locate_point that obtain the point on one linestring nearest to
> another linestring.
Yes, I think that's the way to go. In fact, I think you should find which segments of the two linestrings are closest, and then you can easily guess the nearest point between them.
I wrote a simple function (sorry if it is poorly written, but this question was intriguing me so I gave it a try).
Could you test it on some of your linestrings ?
CREATE OR REPLACE FUNCTION tmp.nearest_point(linestring1 linestring, linestring2 linestring) RETURNS POINT AS
$BODY$
DECLARE
i integer;
mindistance float8;
segment1 line;
segment2 line;
point1a point;
point1b point;
point2a point;
point2b point;
closestpoint1 point;
closestpoint2 point;
BEGIN
mindistance := 2*Distance(linestring1, linestring2);
FOR i IN 0..(NumPoints(linestring1) - 1) LOOP
IF Distance(MakeLine(PointN(linestring1, i), PointN(linestring1, i+1)), linestring2) < mindistance THEN
point1a := PointN(linestring1, i);
point1b := PointN(linestring1, i+1);
segment1 := MakeLine(point1a, point1b);
mindistance := Distance(segment1, linestring2);
END IF;
END LOOP;
mindistance := 2*Distance(linestring1, linestring2);
FOR i IN 0..(NumPoints(linestring2) - 1) LOOP
IF Distance(MakeLine(PointN(linestring2, i), PointN(linestring2, i+1)), linestring1) < mindistance THEN
point2a := PointN(linestring2, i);
point2b := PointN(linestring2, i+1);
segment2 := MakeLine(point2a, point2b);
mindistance := Distance(segment2, linestring1);
END IF;
END LOOP;
IF Distance(point1a, segment2) <= Distance(point1b, segment2)
AND Distance(point1a, segment2) <= Distance(point2a, segment1)
AND Distance(point1a, segment2) <= Distance(point2b, segment1) THEN
closestpoint1 := point1a;
closestpoint2 := line_interpolate_point(segment2, line_locate_point(segment2, point1a));
ELSEIF Distance(point1b, segment2) <= Distance(point1a, segment2)
AND Distance(point1b, segment2) <= Distance(point2a, segment1)
AND Distance(point1b, segment2) <= Distance(point2b, segment1) THEN
closestpoint1 := point1b;
closestpoint2 := line_interpolate_point(segment2, line_locate_point(segment2, point1b));
ELSEIF Distance(point2a, segment1) <= Distance(point2b, segment1)
AND Distance(point2a, segment1) <= Distance(point1a, segment2)
AND Distance(point2a, segment1) <= Distance(point1b, segment2) THEN
closestpoint1 := point2a;
closestpoint2 := line_interpolate_point(segment1, line_locate_point(segment1, point2a));
ELSE
closestpoint1 := point2b;
closestpoint2 := line_interpolate_point(segment1, line_locate_point(segment1, point2b));
END IF;
RETURN line_interpolate_point(MakeLine(closestpoint1,closestpoint2), 0.5);
END;
$BODY$
LANGUAGE 'plpgsql' VOLATILE;
--
Arnaud
More information about the postgis-users
mailing list