กำลังสร้างตารางหลายเหลี่ยมปกติใน PostGIS หรือไม่


61

วิธีการสร้างรูปหลายเหลี่ยมตารางปกติของรูปหลายเหลี่ยม / สี่เหลี่ยมขนาดที่กำหนดในโพสกิส?

ฉันคิดเกี่ยวกับฟังก์ชั่นอย่างเช่นสร้างตารางจุดปกติภายในรูปหลายเหลี่ยมใน Postgis ได้อย่างไร สำหรับสี่เหลี่ยมเท่านั้นเพื่อให้สี่เหลี่ยมสามารถมีขนาด 5 ม. x 5 ม. หรือแม้แต่ 10 ม. x 10 ม. แต่ไม่มีความคิดที่จะเปลี่ยนแปลงสิ่งนี้ในวิธีที่ถูกต้อง


2
ลักษณะทั่วไปที่คุณค้นหาไม่ชัดเจน คุณกำลังบอกว่าคุณเริ่มต้นด้วยรูปหลายเหลี่ยม (ตามอำเภอใจ) และต้องการจัดเรียงระนาบด้วยสำเนาที่สอดคล้องกันหรือไม่? โดยทั่วไปแล้วนี่เป็นไปไม่ได้ แต่บางทีรูปหลายเหลี่ยมนี้อาจมีคุณสมบัติเฉพาะ (เช่นกันอาจเป็นรูปสี่เหลี่ยมด้านขนานรูปสามเหลี่ยมหรือรูปหกเหลี่ยมเป็นต้น)
whuber

คำตอบ:


60

นี่คือฟังก์ชั่นส่งคืนST_CreateFishnetที่สร้างกริดรูปหลายเหลี่ยม 2 มิติ

CREATE OR REPLACE FUNCTION ST_CreateFishnet(
        nrow integer, ncol integer,
        xsize float8, ysize float8,
        x0 float8 DEFAULT 0, y0 float8 DEFAULT 0,
        OUT "row" integer, OUT col integer,
        OUT geom geometry)
    RETURNS SETOF record AS
$$
SELECT i + 1 AS row, j + 1 AS col, ST_Translate(cell, j * $3 + $5, i * $4 + $6) AS geom
FROM generate_series(0, $1 - 1) AS i,
     generate_series(0, $2 - 1) AS j,
(
SELECT ('POLYGON((0 0, 0 '||$4||', '||$3||' '||$4||', '||$3||' 0,0 0))')::geometry AS cell
) AS foo;
$$ LANGUAGE sql IMMUTABLE STRICT;

โดยที่nrowและncolเป็นจำนวนแถวและคอลัมน์xsizeและysizeเป็นความยาวของขนาดเซลล์และเป็นทางเลือกx0และy0เป็นพิกัดสำหรับมุมซ้ายล่าง

ผลลัพธ์คือrowและcolตัวเลขเริ่มต้นจาก 1 ที่มุมซ้ายล่างและgeomรูปหลายเหลี่ยมรูปสี่เหลี่ยมผืนผ้าสำหรับแต่ละเซลล์ ตัวอย่างเช่น:

SELECT *
FROM ST_CreateFishnet(4, 6, 10, 10) AS cells;
 row | col |         geom
-----+-----+--------------------------------
   1 |   1 | 0103000000010000000500000000...
   2 |   1 | 0103000000010000000500000000...
   3 |   1 | 0103000000010000000500000000...
   4 |   1 | 0103000000010000000500000000...
   1 |   2 | 0103000000010000000500000000...
   2 |   2 | 0103000000010000000500000000...
   ...
   3 |   6 | 0103000000010000000500000000...
   4 |   6 | 0103000000010000000500000000...
(24 rows)

หรือสร้างคอลเล็กชั่นรูปทรงเรขาคณิตสำหรับตารางแบบเต็ม:

SELECT ST_Collect(cells.geom)
FROM ST_CreateFishnet(4, 6, 10, 10) AS cells;

ตาราง 4x6

คุณสามารถเพิ่มx0/ y0กำเนิดชดเชย (ค่าเริ่มต้นเหล่านี้เป็นศูนย์)


1
ขอบคุณ! ตอนนี้ฉันต้องผูกแหอวนกับ BBox ของรูปหลายเหลี่ยม
mk.archaeo

สิ่งนี้มีประโยชน์มาก .. ฉันมีหนึ่งข้อความค้นหา ฉันจะสร้างกริดภายในรูปหลายเหลี่ยม / bbox ได้อย่างไร
Mohammed shafeek

Nice Work ไมค์มันมีประโยชน์มาก
Mounaim

56

นี่คือตัวแปรเฉพาะของการสร้างสำหรับสถานการณ์เมื่อคุณต้องการสร้างตารางสำหรับแผนที่ทางภูมิศาสตร์ด้วยขั้นตอนการวัดค่าคงที่ (เซลล์อาจใช้สำหรับการจัดกลุ่มค่าเช่นความหนาแน่นของฟ้าผ่าในภูมิภาค)

ฟังก์ชั่นไม่หรูหรามาก แต่ฉันไม่พบวิธีแก้ปัญหาที่ดีกว่าสำหรับงานนั้น (รวมถึงฟังก์ชั่นของ Mike Toews ด้านบน) ดังนั้นคุณมีรูปหลายเหลี่ยมที่ถูกผูกไว้ (เช่นมาจากอินเทอร์เฟซของ Google Maps) มีค่าขั้นตอนเป็นเมตร:

CREATE OR REPLACE FUNCTION public.makegrid_2d (
  bound_polygon public.geometry,
  grid_step integer,
  metric_srid integer = 28408 --metric SRID (this particular is optimal for the Western Russia)
)
RETURNS public.geometry AS
$body$
DECLARE
  BoundM public.geometry; --Bound polygon transformed to the metric projection (with metric_srid SRID)
  Xmin DOUBLE PRECISION;
  Xmax DOUBLE PRECISION;
  Ymax DOUBLE PRECISION;
  X DOUBLE PRECISION;
  Y DOUBLE PRECISION;
  sectors public.geometry[];
  i INTEGER;
BEGIN
  BoundM := ST_Transform($1, $3); --From WGS84 (SRID 4326) to the metric projection, to operate with step in meters
  Xmin := ST_XMin(BoundM);
  Xmax := ST_XMax(BoundM);
  Ymax := ST_YMax(BoundM);

  Y := ST_YMin(BoundM); --current sector's corner coordinate
  i := -1;
  <<yloop>>
  LOOP
    IF (Y > Ymax) THEN  --Better if generating polygons exceeds the bound for one step. You always can crop the result. But if not you may get not quite correct data for outbound polygons (e.g. if you calculate frequency per sector)
        EXIT;
    END IF;

    X := Xmin;
    <<xloop>>
    LOOP
      IF (X > Xmax) THEN
          EXIT;
      END IF;

      i := i + 1;
      sectors[i] := ST_GeomFromText('POLYGON(('||X||' '||Y||', '||(X+$2)||' '||Y||', '||(X+$2)||' '||(Y+$2)||', '||X||' '||(Y+$2)||', '||X||' '||Y||'))', $3);

      X := X + $2;
    END LOOP xloop;
    Y := Y + $2;
  END LOOP yloop;

  RETURN ST_Transform(ST_Collect(sectors), ST_SRID($1));
END;
$body$
LANGUAGE 'plpgsql';

วิธีใช้งาน:

SELECT cell FROM 
(SELECT (
ST_Dump(makegrid_2d(ST_GeomFromText('Polygon((35.099577 45.183417,47.283415 45.183417,47.283415 49.640445,35.099577 49.640445,35.099577 45.183417))',
 4326), -- WGS84 SRID
 10000) -- cell step in meters
)).geom AS cell) AS q_grid

ดังนั้นคุณจะเห็นว่าเส้นที่จัดรูปแบบโดยรูปหลายเหลี่ยมที่สร้างขึ้นนั้นอยู่ในแนวขนานทางภูมิศาสตร์และเส้นเมอริเดียนซึ่งสะดวกมาก

ตัวอย่างของกริดที่มีขั้นตอน 50 กม

คำแนะนำ: หากคุณคำนวณความหนาแน่น (เช่นแผนที่ของฟ้าผ่าโดยเซลล์) และตารางถูกสร้างแบบไดนามิกเพื่อเพิ่มประสิทธิภาพฉันขอแนะนำให้ใช้ตารางชั่วคราวสำหรับการจัดเก็บเซลล์เป็นรูปหลายเหลี่ยมเรขาคณิตกับดัชนีเชิงพื้นที่ในคอลัมน์แสดง เซลล์


ฉันหวังว่าฉันจะสามารถโหวตสิ่งนี้ได้อีกครั้ง ... นี่เป็นโซลูชั่นที่สมบูรณ์แบบ! และความสามารถในการปรับแต่งระบบพิกัดนั้นยอดเยี่ยมมาก ~!
DPSSpatial

เพียงแค่ข้อเสนอแนะเล็ก ๆ น้อย ๆ แทนที่จะใช้ST_GeomFromTextเมื่อสร้างกล่องเพื่อเพิ่มsectorsคุณสามารถใช้ST_MakeEnvelopeและเพียงระบุพิกัดด้านล่างซ้ายและขวาบนของกล่อง
แมตต์

สิ่งนี้ทำให้เกิดศักยภาพ
nickves

11

คุณสามารถสร้างกริดปกติเพียงแค่ทำให้ภาพแรสเตอร์ว่างเปล่า:

SELECT (ST_PixelAsPolygons(ST_AddBand(ST_MakeEmptyRaster(100, 100, 1.1, 1.1, 1.0), '8BSI'::text, 1, 0), 1, false)).geom

1
นั่นเป็นวิธีแก้ปัญหาง่ายๆที่ทำเวกเตอร์ไปหลายครั้ง
John Powell

6

ฉันได้สร้างฟังก์ชันของ @ Alexander ขึ้นมาหลายแบบซึ่งไม่ต้องการให้เราเปลี่ยนเป็น SRID อื่น นี่เป็นการหลีกเลี่ยงปัญหาที่จะต้องหาเส้นโครงที่ใช้เมตรเป็นหน่วยสำหรับพื้นที่เฉพาะ มันใช้ST_Projectเพื่อก้าวย่างอย่างถูกต้องโดยใช้การฉายที่กำหนด ฉันยังได้เพิ่มwidth_stepและheight_stepอนุญาตสำหรับกระเบื้องสี่เหลี่ยมแทนที่จะกำหนดให้มันเป็นสี่เหลี่ยม

CREATE OR REPLACE FUNCTION public.makegrid_2d (
  bound_polygon public.geometry,
  width_step integer,
  height_step integer
)
RETURNS public.geometry AS
$body$
DECLARE
  Xmin DOUBLE PRECISION;
  Xmax DOUBLE PRECISION;
  Ymax DOUBLE PRECISION;
  X DOUBLE PRECISION;
  Y DOUBLE PRECISION;
  NextX DOUBLE PRECISION;
  NextY DOUBLE PRECISION;
  CPoint public.geometry;
  sectors public.geometry[];
  i INTEGER;
  SRID INTEGER;
BEGIN
  Xmin := ST_XMin(bound_polygon);
  Xmax := ST_XMax(bound_polygon);
  Ymax := ST_YMax(bound_polygon);
  SRID := ST_SRID(bound_polygon);

  Y := ST_YMin(bound_polygon); --current sector's corner coordinate
  i := -1;
  <<yloop>>
  LOOP
    IF (Y > Ymax) THEN  
        EXIT;
    END IF;

    X := Xmin;
    <<xloop>>
    LOOP
      IF (X > Xmax) THEN
          EXIT;
      END IF;

      CPoint := ST_SetSRID(ST_MakePoint(X, Y), SRID);
      NextX := ST_X(ST_Project(CPoint, $2, radians(90))::geometry);
      NextY := ST_Y(ST_Project(CPoint, $3, radians(0))::geometry);

      i := i + 1;
      sectors[i] := ST_MakeEnvelope(X, Y, NextX, NextY, SRID);

      X := NextX;
    END LOOP xloop;
    CPoint := ST_SetSRID(ST_MakePoint(X, Y), SRID);
    NextY := ST_Y(ST_Project(CPoint, $3, radians(0))::geometry);
    Y := NextY;
  END LOOP yloop;

  RETURN ST_Collect(sectors);
END;
$body$
LANGUAGE 'plpgsql';

คุณสามารถใช้มันได้เช่น:

SELECT ST_AsGeoJSON(cell) FROM (
  SELECT (
    ST_Dump(
      makegrid_2d(
        ST_GeomFromText(
          'Polygon((35.099577 45.183417,47.283415 45.183417,47.283415 49.640445,35.099577 49.640445,35.099577 45.183417))',
          4326
        ),
         10000, -- width step in meters
         10000  -- height step in meters
       ) 
    )
  ) .geom AS cell
)q;

5

นี่คืออัลกอริธึมที่เหมาะสมและมีประสิทธิภาพในการสร้างแหอวนกริดปกติกริดรูปหลายเหลี่ยมกริดสี่เหลี่ยมภายในซองจดหมายโพลิกอนหรือ Multipolygons ใด ๆ เกือบจัดการกับ SRID ใด ๆ ;

ลิงค์ Repo GitHub

ป้อนคำอธิบายรูปภาพที่นี่

DROP FUNCTION IF EXISTS PUBLIC.I_Grid_Regular(geometry, float8, float8);
CREATE OR REPLACE FUNCTION PUBLIC.I_Grid_Regular
( geom geometry, x_side float8, y_side float8, OUT geometry )
RETURNS SETOF geometry AS $BODY$ DECLARE
x_max DECIMAL;
y_max DECIMAL;
x_min DECIMAL;
y_min DECIMAL;
srid INTEGER := 4326;
input_srid INTEGER;
x_series DECIMAL;
y_series DECIMAL;
geom_cell geometry := ST_GeomFromText(FORMAT('POLYGON((0 0, 0 %s, %s %s, %s 0,0 0))',
                                        $3, $2, $3, $2), srid);
BEGIN
CASE ST_SRID (geom) WHEN 0 THEN
    geom := ST_SetSRID (geom, srid);
    RAISE NOTICE'SRID Not Found.';
ELSE
    RAISE NOTICE'SRID Found.';
END CASE;
input_srid := ST_srid ( geom );
geom := ST_Transform ( geom, srid );
x_max := ST_XMax ( geom );
y_max := ST_YMax ( geom );
x_min := ST_XMin ( geom );
y_min := ST_YMin ( geom );
x_series := CEIL ( @( x_max - x_min ) / x_side );
y_series := CEIL ( @( y_max - y_min ) / y_side );

RETURN QUERY With foo AS (
    SELECT
    ST_Translate( geom_cell, j * $2 + x_min, i * $3 + y_min ) AS cell
    FROM
        generate_series ( 0, x_series ) AS j,
        generate_series ( 0, y_series ) AS i
    ) SELECT ST_CollectionExtract(ST_Collect(ST_Transform ( ST_Intersection(cell, geom), input_srid)), 3)
    FROM foo where ST_intersects (cell, geom);
END;
$BODY$ LANGUAGE plpgsql IMMUTABLE STRICT;

ใช้มันกับแบบสอบถามง่ายๆ อินพุตควรเป็นรูปหลายเหลี่ยมที่ถูกต้อง Multipolygon หรือซองจดหมาย

select I_Grid_Regular(st_setsrid(g.geom, 4326), .0001, .0001 ), geom from polygons limit 1
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.