문서 / 코어 / 지구 위의 계산

지구 위의 계산(Spherical)

거리・방위・면적・보간 같은 지리 계산을, 3개 플랫폼에서 같은 이름・같은 결과로 제공합니다. 지도 SDK마다의 유틸리티에 기대지 않기 때문에, 프로바이더를 교체해도 수치가 달라지지 않습니다. SDK 내부의 탭 판정이나 대권 코스 렌더링도, 모두 이 계산을 쓰고 있습니다.

ELLIPSOID
WGS84
SEMI-MAJOR
6,378,137 m
FLATTENING
1 / 298.257…
UNIT
미터 / 도
플랫폼

01 · 기본의 계산

자주 쓰는 함수는 Spherical에 모여 있습니다. 거리는 미터, 방위는 진북을 0으로 한 도, 면적은 제곱미터로 반환됩니다. 인수는 좌표 그 자체이고, 투영이나 줌에는 의존하지 않습니다.

함수
설명
computeDistanceBetween
2점 사이의 거리(미터).
computeHeading
시작점에서 끝점을 봤을 때의 방위(−180〜180도).
computeOffset
시작점에서 거리와 방위를 지정한 앞의 좌표. 원이나 링의 생성에 씁니다.
computeOffsetOrigin
끝점・거리・방위에서 시작점을 역산합니다.
computeLength
좌표열을 따른 전체 길이(미터). 경로의 거리 표시에.
computeArea / computeSignedArea
닫힌 좌표열이 둘러싸는 면적(제곱미터). 부호가 붙은 것은 회전 방향의 판정에 쓸 수 있습니다.
interpolate
2점 사이를 대권 코스 위에서 비율 보간합니다.
Planar.interpolate
2점 사이를 위경도의 직선으로 비율 보간합니다(직선 모델 Planar의 메서드). 날짜변경선을 넘는 경우에도 최단 쪽을 지나갑니다.
com.mapconductor.core.spherical
val meters = Spherical.computeDistanceBetween(from, to)
val heading = Spherical.computeHeading(from, to)

// 원의 외곽 마커를 8방향에 놓는다
val ring = (0 until 8).map { i ->
    Spherical.computeOffset(center, 3_000.0, i * 45.0)
}

val routeMeters = Spherical.computeLength(routePoints)
val areaSqMeters = Spherical.computeArea(polygonPoints)

02 · 구체 모델과 타원체 모델

지리 계산에는 2가지 정밀도 수준을 마련하고 있습니다. 지구를 완전한 구로 다루는 구체 모델과, WGS84 타원체로 다루는 측지선 모델입니다. 용도에 따라 나눠 씁니다.

상수는 양쪽 모두 WGS84에 기반합니다(적도 반경 6,378,137 m, 편평률 1/298.257223563). 3개 플랫폼에서 같은 상수・같은 식을 쓰기 때문에, 같은 입력이라면 같은 값이 반환됩니다.

Spherical

구체 모델(충분히 빠르고, 충분히 정확)

용도: 거리 표시 · 방위 · 링 생성 · 면적 · 탭 판정

반정시(haversine)에 의한 거리, 구면삼각법에 의한 방위・보간입니다. 수백km 정도까지라면 오차는 실용상 무시할 수 있고, 계산 비용이 작은 것이 장점입니다.

WGS84Geodesic

타원체 모델(측지선)

용도: 장거리 비행 경로 · 정밀한 거리・방위・면적

WGS84 타원체 위의 측지선(Vincenty 계열의 반복 해)으로 계산합니다. Spherical과 같은 메서드 구성이므로, 구체라면 Spherical, WGS84라면 WGS84Geodesic처럼 호출을 바꾸지 않고 교체할 수 있습니다. 면적은 타원체(authalic)로 구합니다.

FALLBACK

수렴하지 않을 때는 구체로 폴백

타원체의 반복 해는, 거의 대척점에 있는 2점 등에서 수렴하지 않는 경우가 있습니다. 그 경우에는 구체 모델의 결과로 자동으로 전환하기 때문에, 0이나 NaN이 반환되는 일은 없습니다. 호출하는 쪽에서 예외 처리를 쓸 필요는 없습니다.

03 · 화면과의 다리 놓기

지도 위의 「손가락 하나 분」이나 「16px의 여백」 같은 화면 기준의 양을, 지리적인 거리로 환산하는 함수군입니다. 줌과 위도에 따른 환산이 들어 있기 때문에, 배율이나 장소가 바뀌어도 체감이 변하지 않습니다.

calculateMetersPerPixel
지정 줌・위도에서의 1픽셀당 미터 수.
expandBounds
사각형 범위를 미터 단위로 바깥쪽으로 넓힙니다. 표시 범위보다 조금 넓게 데이터를 가져올 때에.

그림 · 탭 판정에 쓰이는 흐름

01

설정값의 「손가락의 크기」(논리 단위)를 화면 픽셀로 변환합니다.

02

calculateMetersPerPixel로, 현재의 줌과 위도에서의 허용 거리(미터)로 환산합니다.

03

그 허용 거리를 써서, 선이나 도형과의 거리를 지리 좌표인 채로 판정합니다.

이 흐름 덕분에, 줌을 바꿔도 선의 누르기 쉬운 정도가 변하지 않고, 어느 프로바이더에서도 같은 판정이 됩니다.

04 · 선과 형태를 위한 계산

폴리라인이나 폴리곤의 렌더링・판정을, 어느 프로바이더에서도 같은 결과로 만들기 위한 함수군입니다. SDK 내부에서 쓰고 있는 것과 같은 것이 공개되어 있습니다.

함수
설명
WGS84Geodesic.createInterpolatePoints
측지선을 따라, 구간마다 좌표를 보완합니다. 곡선을 직접 그릴 수 없는 엔진용 좌표열을 만듭니다.
Planar.createInterpolatePoints
위경도의 직선을 따라 좌표를 보완합니다. 이름은 같고, 네임스페이스만 다릅니다.
WGS84Geodesic.pointOnLineOrNull
측지선 위의 선분에 대해, 지정 거리 이내의 최근점을 반환합니다. 곡선의 탭 판정에 씁니다.
Planar.pointOnLineOrNull
직선의 선분에 대해, 지정 거리 이내인지를 판정합니다.
splitByMeridian
경도 180도를 넘는 좌표열을, 경계에서 분할합니다. 네임스페이스에 속하지 않는 톱레벨 함수입니다.
closestPointOnSegment
선분 위에서 가장 가까운 점을 구합니다. 이쪽도 톱레벨 함수입니다.

createInterpolatePoints와 pointOnLineOrNull은, WGS84Geodesic과 Planar 양쪽에 같은 이름으로 마련되어 있습니다. 호출하는 쪽은 네임스페이스를 교체하기만 하면, 측지선 모델과 직선 모델을 전환할 수 있습니다.

CONSISTENCY

같은 입력이라면 같은 결과

Kotlin・Swift・TypeScript의 구현은 같은 식으로 쓰여 있고, 같은 상수를 씁니다. 플랫폼 간에 표시되는 거리나 면적이 어긋나는 일은 없습니다.

PUBLIC API

앱에서도 쓸 수 있다

코어의 계산 함수는 내부 전용이 아니라 공개 API입니다. 경로 거리의 표시, 반지름의 계산, 독자적인 히트 판정 등, 앱 쪽의 로직에 그대로 쓸 수 있습니다. 이 페이지에 든 함수는 모두 3개 플랫폼에 갖춰져 있습니다.

관련 페이지