도구스개발

모턴 코드(Z-order) 변환기

2차원·3차원 좌표를 비트 인터리브로 하나의 정수로 접고 되풉니다. 매직 넘버 비트 트릭을 소박한 반복문과 나란히 대조하고, 지도 타일 쿼드키와 붙어 있는 칸의 코드 차이(Z자 점프)까지 함께 보여 줍니다.

비트

한 변 16칸 · 코드는 8비트 (0 ~ 255)

모턴 코드

109

0x6D · 2진수 01101101 · 쿼드키 1231

0y1x1y0x1y1x0y1x

오른쪽 끝이 0번 자리입니다. 축마다 한 칸씩 걸러 들어갑니다

x = 111011
y = 60110
모턴 코드 (10진)109
16진0x6D
2진01101101
지도 쿼드키 (4진)1231
격자 칸 수256
매직 넘버 없이 구한 값109 — 같음
다시 풀어 본 좌표(11, 6) — 제자리
방향좌표코드차이
왼쪽 (x−1)(10, 6)1081
오른쪽 (x+1)(12, 6)12011
아래 (y−1)(11, 5)1036
위 (y+1)(11, 7)1112

한 칸 옆인데 코드가 얼마나 떨어지는지 — 이것이 Z-order의 약점입니다

계산 근거코드 = … y₁x₁y₀x₀ — x는 짝수 자리, y는 홀수 자리x = (x ^ (x<<8)) & 0x00ff00ff → … → & 0x55555555비트를 하나씩 옮기는 반복문 대신 자리를 절반씩 갈라 옮기는 다섯 줄을 씁니다. 마스크 0x55555555는 0101…, 0x09249249는 001001001…이라 마스크 자체가 남길 자리의 그림입니다. 위의 «매직 넘버 없이 구한 값»은 소박한 반복문으로 따로 구한 것이고, 두 값이 같아야 합니다.
붙어 있는데 코드가 86만큼 떨어지는 자리가 있습니다. 이 격자에서 (7, 7)와 (7, 8)는 맞닿아 있지만 코드는 그만큼 벌어집니다. 격자를 위아래로 가르는 선을 넘으면서 y의 최상위 비트가 바뀌기 때문이고, y가 각 비트 쌍의 «높은» 자리를 차지해 좌우로 가르는 선을 넘을 때보다 두 배 넘게 벌어집니다. 지나는 길이 Z자를 반복하는 모양이라 «Z자 점프»라 부르며, 모턴 코드로 공간 인덱스를 만들 때 이 자리들이 캐시 미스와 범위 질의의 조각남을 만듭니다.
지도 타일의 쿼드키가 바로 이 코드입니다. 모턴 코드를 4진수로 적으면 자릿수 하나가 확대 단계 하나가 되고, 각 자리는 «위·아래»와 «왼쪽·오른쪽»을 뜻하는 두 비트입니다. 그래서 쿼드키의 앞자리를 잘라내면 곧바로 상위 타일이 되고, 문자열 접두사가 겹치는지만 봐도 어느 타일이 어느 타일 안에 있는지 알 수 있습니다. 지오해시도 위도·경도를 번갈아 엮는다는 점에서 같은 발상입니다.
힐베르트 곡선은 이런 점프가 없지만 변환이 훨씬 비쌉니다. 모턴 코드는 시프트와 마스크 몇 번이면 끝나 GPU·자료구조에서 널리 쓰이고, 힐베르트 곡선은 이웃이 언제나 번호도 이웃이라 지역성이 좋은 대신 단계마다 방향을 따져야 합니다. 두 곡선의 도약 거리를 실제로 세어 견주는 것은 힐베르트 곡선 계산기 쪽에 있습니다.
한 축의 값을 키우면 코드도 반드시 커집니다. 다른 축을 그대로 둔 채 x만 늘리면 x가 차지한 자리들의 값만 커지므로 코드도 커집니다. 그래서 모턴 코드로 정렬한 목록에서 «x가 a 이상 b 이하»인 범위를 찾으면 반드시 이어진 구간 안에 들어 있습니다. 다만 그 구간에 조건 밖의 칸이 섞여 들어오므로, 실제 공간 데이터베이스는 구간을 잘게 쪼개는 계산을 따로 합니다.

사용 방법

  1. 1차원(2D·3D)과 축마다 쓸 비트 수를 고릅니다. 비트 수 b면 한 변이 2ᵇ칸입니다.
  2. 2«좌표 → 코드»에서 x·y(·z)를 넣으면 엮인 코드가 10진·16진·2진으로 나옵니다.
  3. 3«코드 → 좌표»로 바꾸면 코드를 넣어 원래 좌표를 되풉니다.
  4. 4«엮인 비트»에서 각 자리가 어느 축에서 왔는지 색으로 확인합니다.
  5. 5아래 이웃 표에서 한 칸 옆인데 코드가 얼마나 떨어지는지 봅니다.

자주 묻는 질문

좌표의 비트를 번갈아 끼워 넣어 하나의 정수로 만든 값입니다. x = 0b1011, y = 0b0110이면 y와 x의 비트를 한 칸씩 걸러 엮어 0b01101101 = 109가 됩니다. 이렇게 접은 수로 정렬하면 가까운 좌표끼리 대체로 가까운 번호를 받으므로, 2차원·3차원 자료를 1차원 인덱스(B-트리·디스크·캐시)에 얹을 수 있습니다. 지나는 길이 Z자를 반복해 Z-order 곡선이라고도 부릅니다.

비트를 벌리는 다섯 줄짜리 트릭에서 남길 자리를 고르는 마스크입니다. 0x55555555는 2진수로 0101…이라 «한 칸 걸러 하나»를, 0x33333333은 00110011…이라 «둘씩 묶어 걸러»를 뜻해서, 마스크 자체가 그 단계에서 만들려는 모양입니다. 비트마다 반복문을 도는 대신 자리를 절반씩 갈라 옮겨 다섯 번 만에 끝냅니다. 3차원은 한 칸 걸러 둘씩 벌려야 해서 0x09249249(001001001…)를 씁니다.

같습니다. 쿼드키는 모턴 코드를 4진수로 적은 것이고, 자릿수 하나가 확대 단계 하나입니다. 각 자리의 두 비트가 «위·아래»와 «왼쪽·오른쪽»을 뜻하므로 앞자리를 잘라내면 곧바로 상위 타일이 되고, 문자열 접두사만 봐도 포함 관계를 알 수 있습니다.

모턴 코드는 변환이 시프트와 마스크 몇 번으로 끝나 훨씬 싸지만, 격자에서 붙어 있는데 번호는 멀리 떨어지는 자리가 생깁니다. 힐베르트 곡선은 그런 자리가 없어 지역성이 좋은 대신 단계마다 방향을 따져야 해 변환이 비쌉니다. 두 곡선의 도약 거리를 실제로 세어 견주는 것은 힐베르트 곡선 계산기 쪽에 있습니다.

격자를 반으로 가르는 선을 넘을 때입니다. 한 칸 옆으로 갔을 뿐인데 상위 비트가 바뀌면 코드가 통째로 건너뜁니다. 특히 위아래로 가르는 선이 가장 심한데, y가 각 비트 쌍의 높은 자리를 차지해 좌우로 가르는 선을 넘을 때보다 두 배 넘게 벌어지기 때문입니다. 8×8 격자에서 (3,3)과 (3,4)는 맞닿아 있지만 코드는 15와 37로 22만큼 떨어집니다.

2차원은 축마다 16비트(코드 32비트), 3차원은 축마다 10비트(코드 30비트)까지 다룹니다. 널리 쓰이는 32비트 구현의 한계와 같으며, 자바스크립트의 비트 연산이 32비트에서 부호를 뒤집는 것도 이 범위로 맞춘 이유입니다.

그대로 쓰면 조건 밖의 칸이 섞여 들어옵니다. 한 축만 늘리면 코드도 반드시 커지므로 «x가 a 이상 b 이하»인 칸들이 이어진 구간 안에 들어 있기는 하지만, 그 구간에는 조건을 벗어난 칸도 함께 들어갑니다. 실제 공간 데이터베이스는 구간을 조건에 맞게 잘게 쪼개는 계산을 따로 합니다.

전송되지 않습니다. 계산은 모두 브라우저 안에서 이루어지며 입력한 좌표는 이 기기에만 남습니다.

알아두면 좋은 점

  • 축의 순서는 x가 가장 낮은 자리입니다. 2차원은 y가 홀수 자리, 3차원은 y·z가 차례로 위 자리를 차지합니다. 구현마다 순서를 반대로 두기도 하므로 다른 코드와 값을 맞출 때 확인해야 합니다.
  • 좌표는 0 이상의 정수만 다룹니다. 음수 좌표는 미리 더해 옮겨 넣으십시오.
  • 범위를 벗어난 좌표는 격자 안으로 잘라 냅니다.
  • 두 곡선의 지역성을 수치로 견주려면 힐베르트 곡선 계산기를 쓰십시오. 여기서는 붙어 있는 네 칸의 코드 차이만 보여 줍니다.

함께 보면 좋은 도구

마지막 검증: 2026년 9월 2일 · 결과는 참고용 추정치입니다.