2016-11-25 10 views
0

stackoverflowでJavaで解決されるポイントオンライン問題に関する興味深い質問が見つかりました。明らかに誰かが他人に宿題をしたがっているので、ポストは大幅にダウン投票され、削除されています(正当な理由!)。とにかく、私はそれが本当に素晴らしいPostGISの例になると思った。目的はplpgsql/control構造体を使用しないことです。多くの例がすでにあります。クエリを書きたいと思います。だから、 "パラメータ"は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
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;