2016-11-25 80 views
0

我發現了一個有趣的問題,關於在stackoverflow上用Java解決的點問題。這篇文章被嚴重低估並被刪除(理所當然!),因爲顯然有人只是想讓別人做他的功課。無論如何,我認爲這會成爲一個非常好的PostGIS示例。目的是不使用plpgsql /控制結構,因爲已經有很多例子 - 我想寫查詢。因此,「參數」在CTE中(繼續前進,讓我感受它:D ...或將代碼放入函數並共享)。開始了。如何解決PostGIS的在線問題

問題陳述
您給出的座標爲(0,0)(0,1)(0,2)(0,3)(1,5)(1,4)(3,5)作爲輸入。

  1. 檢查給定的點是否位於同一行。
  2. 給定2分找到它們之間的點。輸入:(0,0)(0,3),輸出:(0,1)(0,2)
  3. 給定一個點,找到最大線上的點 - 根據它包含的點 - 通過那一點。輸入:(0,1),輸出:(0,0)(0,1)(0,2)(0,3)

回答

0

1.

WITH param AS (
    SELECT 
     ARRAY[ST_MakePoint(0,0), ST_MakePoint(0,1), ST_MakePoint(0,2), ST_MakePoint(0,3), ST_MakePoint(1,5), ST_MakePoint(1,4), ST_MakePoint(3,5)] AS points 
), ps AS (
    SELECT ROW_NUMBER() OVER() AS id, tmp.p 
    FROM (
     SELECT UNNEST(points) AS p 
     FROM param 
    ) AS tmp 
) 
-- if every point triple forms a straight line, all points form a straight line 
SELECT bool_and(ST_Area(ST_MakePolygon(ST_MakeLine(ARRAY[ps1.p, ps2.p, ps3.p, ps1.p]))) = 0) 
FROM ps AS ps1, ps AS ps2, ps AS ps3 
WHERE ps1.id < ps2.id 
    AND ps2.id < ps3.id; 

2。

WITH param AS (
    SELECT 
     ARRAY[ST_MakePoint(0,0), ST_MakePoint(0,1), ST_MakePoint(0,2), ST_MakePoint(0,3), ST_MakePoint(1,5), ST_MakePoint(1,4), ST_MakePoint(3,5)] AS points, 
     1 AS p1_index, 
     4 AS p2_index 
), ps AS (
    SELECT ROW_NUMBER() OVER() AS id, tmp.p 
    FROM (
     SELECT UNNEST(points) AS p 
     FROM param 
    ) AS tmp 
) 
SELECT ST_AsText(ps.p) 
FROM ps, param 
WHERE ST_Intersects(ps.p, ST_MakeLine(points[p1_index], points[p2_index])) 
    AND ps.id NOT IN (p1_index, p2_index); 

3.

WITH param AS (
    SELECT 
    ARRAY[ST_MakePoint(0,0), ST_MakePoint(0,1), ST_MakePoint(0,2), ST_MakePoint(0,3), ST_MakePoint(1,5), ST_MakePoint(1,4), ST_MakePoint(3,5)] AS points, 
    2 AS p_index 
), ps AS (
    SELECT (ROW_NUMBER() OVER())::INTEGER AS id, tmp.p 
    FROM (
     SELECT UNNEST(points) AS p 
     FROM param 
    ) AS tmp 
), straight_triple AS (
    SELECT ps1.id AS p1, ps2.id AS p2, ps3.id AS p3 
    FROM ps AS ps1, ps AS ps2, ps AS ps3 
    WHERE ST_Area(ST_MakePolygon(ST_MakeLine(ARRAY[ps1.p, ps2.p, ps3.p, ps1.p]))) = 0 
     AND ps1.id < ps2.id 
     AND ps2.id < ps3.id 
    ORDER BY ps1.id 
), candidate_line AS (
    -- the point could be on more than one line 
    SELECT p1s || p2 || p3 AS p_indexes, ROW_NUMBER() OVER(ORDER BY cardinality(p1s || p2 || p3) DESC) AS n_points_rank 
    FROM (
     -- group up points by point pairs they form a straight line with 
     SELECT array_agg(p1) AS p1s, p2, p3, ROW_NUMBER() OVER(PARTITION BY (array_agg(p1))[1] ORDER BY cardinality(array_agg(p1)) DESC) AS length_rank 
     FROM straight_triple 
     GROUP BY p2, p3 
    ) AS pair_intersection, param 
    WHERE length_rank = 1 AND (p1s || p2 || p3) @> ARRAY[p_index] 
) 
-- pick the longest line, or any from multiple longest lines 
SELECT ST_AsText(points[i]) 
FROM (
    SELECT UNNEST(p_indexes) AS i 
    FROM candidate_line 
    WHERE n_points_rank = 1 
) AS indexes, param;