"자세히 보아야 예쁘다. 오래 보아야 사랑스럽다. 너도그렇다" 나태주님의 "풀꽃"입니다. 

제게는 PostGIS가 그런 존재입니다. 사용하면 할수록 대견스럽고 사랑스럽습니다. 데이터 시각화라는 부분만 제외하면 대부분의 공간정보 처리가 가능합니다. 한동안 바쁘다는 핑계로 포스트 작성에 소홀했습니다. 하지만 사랑이 변할 수 있나요. PostGIS가 제공하는 함수(ST_Translate)를 이용하여 격자 데이터를 만들겠습니다. 응용하면 "Hexagonal Grid"등 반복되는 도형을 가지는 격자 데이터를 생성할 수 있습니다. 모양은 아래 그림을 참조하십시오.

격자의 쓰임은 다음과 같습니다.
첫째, 격자 단위로 다른 객체(POI 등)를 위상관계(Topology)에 따라 집계해서, 개별 격자 별 밀집도가 높은 지역을 식별하기 용이합니다.
둘째, 불변하는 집계(Sub Total) 데이터를 생성하는 기준 도형이 될 수 있습니다. 변하지 않는 격자를 기준으로 데이터 생산 시점 별 집계를 수행하여 일관된 비교가 가능한 시계열 데이터를 생성할 수 있습니다. 
이러한 기준은 행정경계도 가능하겠지만 인구의 가감 등으로 향후 변경이 발생할 여지가 있기 때문에 격자가 기준으로 적합할 수 있습니다.

이러한 격자는 육각형의 벌집 모양으로도 반복할 수 있지만 가장 쉬운 바둑판 형식의 격자를 제작하겠습니다. 인터넷에서 "Fishnet Grid"를 검색하면 다양한 제작 방법을 찾을 수 있습니다. 저는 PostGIS의 공간함수를 이용하여 SQL Function을 제작합니다. 제작된 Grid는 Qgis에서 형상을 확인합니다.

1. 함수 원형 및 설명



CREATE OR REPLACE FUNCTION __progworks_rect_grid_on_linearUnit_M(
grid_count_x integer, grid_count_y integer,
grid_size_x integer, grid_size_y integer,
start_x double precision, start_y double precision,
target_srid integer) RETURNS varchar AS
$$
DECLARE
target_table_name text;
BEGIN
EXECUTE format('SELECT ___progworks_new_table_name(''%s'')', 'temp' ) INTO target_table_name;
EXECUTE format('CREATE TABLE IF NOT EXISTS %I AS
               SELECT i+1 AS col, j+1 AS row, ST_Translate(cell, i * %s + %s, j * %s + %s) AS geom
   FROM 
   generate_series(0, %s - 1) AS i,
   generate_series(0, %s - 1) AS j,
   (SELECT ST_GeomFromText(''POLYGON((0 0, 0 %s, %s %s, %s 0,0 0))'')  AS cell) AS ORIGIN;',
                target_table_name,
    grid_size_x, start_x,
    grid_size_y, start_y,
    grid_count_x, grid_count_y,
    grid_size_y, grid_size_x, grid_size_y, grid_size_x
  );
EXECUTE format('SELECT UpdateGeometrySRID(''%I'', ''geom'', %s);', target_table_name, target_srid );
return target_table_name;
END
$$
LANGUAGE plpgsql;

 

2. 함수 설명

위 함수의 입력 파라미터를 간단히 설명하면
입력된 좌표(start_x, start_y)를 바둑판의 시작점(우리나라에서 사각형의 좌하단 지점)으로,
가로길이(grid_size_x)와 세로길이(grid_size_y)의 격자가,
가로축 방향으로 지정된 갯수(grid_count_x), 세로축으로 지정된 갯수(grid_count_y)만큼 가지는 격자를 생성하라는 것입니다.

이 때, 생성되는 격자는 지정된 좌표계(target_srid)를 가지도록 정의합니다.
굳이 SQL 함수 이름 끝에  LinearUnit_M을 붙여준 이유는 meter로 거리를 나타내는 좌표계를 사용하라는 뜻입니다.
4326으로 표시되는 경위도 좌표계는 AngularUnit의 degree를 사용하는 구면좌표계로 위경도에 따라 정확한 거리 지정이 불가능합니다. 물론 좁은 지역이라면 상관없습니다. 하지만 정확한 격자크기의 보장을 위해 평면으로 투영된 좌표계 사용을 권장합니다.

함수 내부를 보면 미리 정의된 격자 폴리곤이 WKT 형식으로 존재합니다. 기준 폴리곤은 가로, 세로 각각 0을 기준으로 사용자가 지정한 크기(grid_size)로 이루어지도록 정의 됩니다.
이후 질의 실행에 따라 generate_series 함수가 호출될 때 마다 ST_Translate 함수가 기준 폴리곤을 지정된 위치로 옮기며 새로운 개별 격자를 생성하는 형식입니다.

실제 함수를 실행하여 등록한 후 아래와 같이 함수를 호출합니다. 만들어진 격자는 Qgis를 통해 확인하겠습니다.



 SELECT __progworks_rect_grid_on_linearUnit_M(30, 30, 1000, 1000, 955000, 1937000, 5179);

 

 

3. 맺으며

격자 만들기는 어떤 목적을 이루기 위해 데이터를 준비하는 중간 과정 입니다.

격자를 왜 만들었을까요? 앞에서 설명한대로 격자에 의미있는 무언가를 담기 위해서 입니다. 다음 글에서 만들어진 격자를 이용해 다른 테이블과 위상관계를 분석하여 집계 하는 것을 설명하겠습니다.

자주 하는 말이지만 수학문제 눈으로 풀지 않듯이 개발자는 손이 부지런해야 합니다. 즐코딩~~~

+ Recent posts