지리공간 데이터 - GeoJSON 객체 이해하기

지리 공간 데이터를 다루는 회사에서 일하다 보니, GeoJSON 포맷의 데이터를 늘 접하곤 한다. 이 글에서는 GeoJSON의 개념과 구성 요소, 특징 등에 대해 간단히 정리해보려 한다.

GeoJSON이란?

GeoJSON은 점, 선, 다각형과 같은 지리적 데이터를 표현하기 위한 개방형 표준 포맷으로, JavaScript 객체 표기법(JSON)을 기반으로 한다. 웹에서 지리공간 데이터를 다룰 때 가장 인기 있는 포맷 중 하나이며, 지리적 좌표 참조 시스템인 WGS 1984를 사용한다. 십진수로 된 경도와 위도를 사용한다. (e.g. [125.6, 10.1])

JSON 기반이라 JavaScript와 쉽게 호환되고 프론트엔드 개발자 입장에서 직관적으로 느껴지는 구조를 갖고 있다.

GeoJSON 기본 구조

GeoJSON 객체는 Geometry(기하 객체), Feature(공간 데이터), 또는 Feature들의 컬렉션을 나타낸다.

  • Type : FeatureFeatureCollection
    • Feature 객체는 하나의 Geometry 객체와 추가적인 속성(properties)을 포함한다.
    • FeatureCollection 객체는 여러 Feature 객체를 포함하는 배열이다.
  • Properties : 위치와 관련된 추가 정보를 담고 있다.
  • Geometry 객체: 지리적 위치를 나타내는 객체로, type과 coordinates로 구성되어 있다.
    • Type : "Point", "MultiPoint", "LineString", "MultiLineString", "Polygon", "MultiPolygon", "GeometryCollection"
    • coordinates : 위치 값을 나타내며 Geometry의 기본 요소다.
      • 배열의 첫 두 요소는 경도(longitude)와 위도(latitude)이며, 세 번째 요소로 고도가 들어갈 수 있으나 이는 optional이다.
      • 추가적인 요소는 파서가 제대로 해석할 수 없는 경우가 많기 때문에, 세 개 이상의 요소를 확장하는 것은 권장되지 않는다고 한다.
      • 단일 Point를 표현하는 경우 [102.0, 0.5] 이런 식으로 한 쌍의 좌표를 담게 되며, 선을 표현하는 경우 [[102.0, 0.0],[103.0, 1.0],[104.0, 0.0], [105.0, 1.0]] 이렇게 여러 좌표를 담은 배열의 형태를 띄게 된다.
      • Polygon의 경우 4개 이상의 좌표값으로 이루어진 닫힌 LineString이다. 그러므로 첫 번째와 마지막 위치는 동일해야 하며, 그 값도 같아야 한다.
 "geometry": {
    "type": "Point",
    "coordinates": [102.0, 0.5]
  }

geometry 객체 예시

    • GeometryCollection 타입은 여러 Geometry 객체를 묶음으로써 이질적인 기하 객체동시에 가질 수 있다. (e.g. 알파벳 i와 같은 모양을 지도상에 표현할 때 점 부분은 Point로, 아래 선 부분은 LineString으로 표현)
{
  "type": "GeometryCollection",
  "geometries": [
    {
      "type": "Point",
      "coordinates": [102.0, 0.5]
    },
    {
      "type": "LineString",
      "coordinates": [
        [102.0, 0.0],
        [103.0, 1.0]
      ]
    }
  ]
}

geometryCollection 객체 예시

  • FeatureCollection과 GeometryCollection의 차이 : FeatureCollection다양한 Feature들을 포함하객체의 배열이고, GeometryCollection다양한 Geometry객체들을 묶은 하나의 Geometry 객체다.
{
  "type": "FeatureCollection",
  "features": [
    {
      "type": "Feature",
      "geometry": {
        "type": "Point",
        "coordinates": [102.0, 0.5]
      },
      "properties": {
        "name": "Point",
        "status": "enabled"
      }
    },
    {
      "type": "Feature",
      "geometry": {
        "type": "Polygon",
        "coordinates": [
          [
            [100.0, 0.0],
            [101.0, 0.0],
            [101.0, 1.0],
            [100.0, 0.0]
          ]
        ]
      },
      "properties": {
        "name": "Triangle",
        "status" : "disabled"
      }
    }
  ]
}

FeatureCollection과 Feature 예시

  • bbox : GeoJSON 객체는 type, geometry 외에도 optional한 요소로 bbox를 가질 수 있다. 이는 Bounding Box의 약자로, 어떤 GeoJSON 객체가 차지하는 공간을 간략히 나타내는 직사각형 영역을 정의하는 메타데이터라고 보면 된다. Bounding Box는 두 점을 정의하는 좌표로 구성된다.
    • 남서쪽 (southwest): 가장 작은 좌표 (최저 경도/위도/고도)
    • 북동쪽 (northeast): 가장 큰 좌표 (최고 경도/위도/고도)
{
    "type": "Feature",
    "bbox": [-10.0, -10.0, 10.0, 10.0],
    "geometry": {
        "type": "Polygon",
        "coordinates": [
            [ 
                [-10.0, -10.0], // 가장 작은 좌표 - bbox의 첫 두 숫자
                [10.0, -10.0],
                [10.0, 10.0], // 가장 큰 좌표 - bbox의 마지막 두 숫자
                [-10.0, 10.0],
                [-10.0, -10.0]
            ]
        ]
    }
}

2D Bounding Box 예시

  • bbox는 필수 요소는 아니나, 객체의 전체 좌표를 계산하거나 확인하지 않고 그 객체가 포함된 공간 범위를 빠르게 파악할 수 있게 해주어 성능 최적화에 도움이 된다. 예를 들어, 여러 개의 GeoJSON 객체가 있을 때, 각 객체의 bbox만 확인하면 해당 객체가 특정 영역에 포함되는지 여부를 빠르게 확인할 수 있다. 그래서 특히 공간 검색에서 유용하게 쓰일 수 있다.

Antimeridian 처리

Antimeridian은 지구의 경도 180도를 기준으로 하는 반대편의 경선이다. (동경 180도, 서경 180도) 이는 지구를 동서로 나누는 기준선 중 하나다. 국제 날짜 변경선이 이 안티메리디안을 따라 설정되어 있다고 한다.

이미지 출처 : https://www.pacioos.hawaii.edu/metadata/world_antimeridian.html?format=fgdc

GeoJSON과 같은 좌표 시스템에서는 경도의 범위가 -180도에서 +180도 사이로 정의되기 때문에, 180도를 넘거나 넘어서는 객체를 처리할 때 문제가 발생할 수 있다. 그래서 해당 객체를 두 개로 나누어 각각 별개의 범위로 처리해야 한다.

예를 들어 아래 이미지와 같이 하나의 선이 안티메리디안을 가로지르는 경우 두 개의 MultiLineString으로 쪼개어 표현하고, 마찬가지로 하나의 다각형이 경선을 가로지르는 경우 MultiPolygon으로 표현한다. (다각형에서 경계선으로 표현된 부분이 안티메리디안)

주의사항

  • GeoJSON 타입은 확장 불가능하다. 즉 FeatureCollection, Feature, Point, LineString, MultiPoint, Polygon, MultiLineString, MultiPolygon, GeometryCollection과 같은 고정된 타입만 사용할 수 있다.
  • GeoJSON 타입은 변경할 수도 없으며, 새로운 타입을 추가하거나 수정하는 것은 허용되지 않는다. 예를 들어, FeatureCollection이나 Feature 객체에는 반드시 다음과 같이 정해진 요소들만 있어야 한다:
    • FeatureCollectionfeatures만 포함하고, coordinatesgeometry는 포함할 수 없다.
    • Featuregeometryproperties만 포함할 수 있으며, coordinatesgeometries는 포함할 수 없다.
    • Geometry 객체는 coordinates만 포함해야 하며, propertiesfeatures는 포함할 수 없다.

다음 사이트에서 geojson객체를 만들어보고 지도상에 어떻게 보여지는지 쉽게 확인할 수 있다.

geojson.io | powered by Mapbox
A quick, simple tool for creating, viewing, and sharing spatial data.

출처 : https://datatracker.ietf.org/doc/html/rfc7946