[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