I imported ~1000 paths from somewhere into my postgis database to a linestring field.

(EDIT) My table is like this

+---------+---------------+------------------+
| id(int) | name(varchar) | path(LINESTRING) |
+---------+---------------+------------------+
| 123     | foo           | 000002...        |
| 124     | bar           | 000002...        |

I had the problem that each of the paths were divided into chunks, and those chunks were mixed up in some cases.

Suppose a linestring that was divided at point number 50 and 70:

  1. Chunk A: points 1-50
  2. Chunk B: points 51-70
  3. Chunk C: points 71-100

When I migrated that into my database, they got mixed, so the resulted linestring could end up like this:

  1. Chunk A: points 1-50
  2. Chunk C: points 71-100
  3. Chunk B: points 51-70

So that produces a jump from 50 to 71 and another one from 100 to 51

(EDIT) When I imported those paths divided in chunks I supposed that they were ordered, but the fact was that some were mixed, and that made some of my linestrings to be with their points ordered like the second example.

I want to be able to reorder those chunks (of points) so I would like to construct a SQL query to detect which paths have mixed points, then I could manually (with a tool made using openlayers) rearrange them.

It would be desirable to have a SQL update query to solve this problem, but I think that detection is easier (I presume there are ~5% or less of paths with errors)

EDIT3: I think the script for detection could check if a path contains a pair of consecutive points too far away. Maybe a SQL that orders paths from the path that contains the longest segment, would be good.

How could I make a function to get the length of the max segment in a linestring?

Here I show an example: This is how it is in the database a bad way

This is how I want it to be fixed a good (fixed) way

EDIT4: Like I planned on EDIT3, a function could be written to find the longest distance between two consecutive points in a linestring iterating through the points of a linestring using ST_NPoints() and ST_PointN(), then a query could be made to order paths with that longest distance. It's highly probable that the linestrings that have this distance too long present the problem described. That way I would be able to detect them, and fix them manually.

The result from the detection SQL would be something like this:

                                             |ordered by this|
+---------+---------------+------------------+---------------+
| id(int) | name(varchar) | path(LINESTRING) |  msbtcp(int)  |
+---------+---------------+------------------+---------------+
| 123     | foo           | 000002...        | 1000          |
| 124     | bar           | 000002...        | 800           |

*msbtcp would be the result of the function: max_separation_between_two_consecutive_points(path)

有帮助吗?

解决方案

This sounds a bit convoluted, however if you're just after the max distance between two consecutive points in a linestring:

CREATE OR REPLACE FUNCTION max_distance_in_linestring(line geometry) RETURNS float as $BODY$
DECLARE
    i integer;
    n integer;
    d float;
    m float;
BEGIN
    d := 0;
    n := ST_NPoints(line);
    i := 2;
    LOOP
        EXIT WHEN i >= n;
        m := ST_Distance(ST_PointN(line,i-1),ST_PointN(line,i));
        -- use for lon,lats:
        -- m := ST_Distance(ST_PointN(line,i-1)::geography,ST_PointN(line,i)::geography);
        IF m > d THEN
            d := m;
        END IF;
        i := i + 1;
    END LOOP;
    RETURN d;
END;
$BODY$
LANGUAGE plpgsql;

SELECT max_distance_in_linestring('LINESTRING(0 0, 1 1, 2 2)'::geometry);
SELECT max_distance_in_linestring('LINESTRING(0 0, 4 3, 2 2)'::geometry);

you may want to re-cast the ST_PointN calls to ::geography for getting distance in meters.

The SQL would be like this:

SELECT
  name, path 
FROM
  paths
ORDER BY
  max_distance_in_linestring(path) DESC

其他提示

Well what you want to know is how the segments are linked, so you need to compare the first and last point of each segment with all the other segments:

SELECT foo.gid as segment_a, bar.gid as segment_b
    FROM 
        segments AS foo, 
        (SELECT the_geom, gid FROM segments) AS bar
    WHERE 
        bar.gid != foo.gid AND ( -- avoid same segments  
        ST_DWithin( 
                ST_GeometryN(foo.the_geom,  ST_NumGeometries(foo.the_geom)) , -- last from foo
                ST_GeometryN(bar.the_geom,  ST_NumGeometries(bar.the_geom)) , -- last from bar
                0.00005 ) OR -- precision, depends of your SRID
        ST_DWithin( 
                ST_GeometryN(foo.the_geom,  1) , -- first from foo (start = 1 index)
                ST_GeometryN(bar.the_geom,  ST_NumGeometries(bar.the_geom)) , -- last from bar
                0.00005 ) OR -- precision, depends of your SRID
        ST_DWithin( 
                ST_GeometryN(foo.the_geom,  ST_NumGeometries(foo.the_geom)) , -- last from foo
                ST_GeometryN(bar.the_geom,  1) , -- first from bar
                0.00005 ) OR -- precision, depends of your SRID
        ST_DWithin( 
                ST_GeometryN(foo.the_geom,  1) , -- first from foo 
                ST_GeometryN(bar.the_geom,  1) , -- first from bar
                0.00005 ) ) -- precision, depends of your SRID

voilà ... ! you can save this links in a new table and join the linked segments with ST_Union.

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top