
GIS 소프트웨어를 개발하다 보면 벡터 데이터를 어떻게 읽고, 어떻게 화면에 그리고, 어떻게 관리할지가 핵심 과제가 됩니다. SharkGeo는 WPF 기반 데스크탑 앱이라 웹 기반 GIS 라이브러리를 바로 가져다 쓸 수도 없고, ESRI ArcObjects 같은 상용 SDK는 과한 선택이죠. 결국 "필요한 부분만, 직접 만들자"는 방향으로 가게 됐습니다. 더군다나 포맷 파싱 관련부분들은 어느정도 널려 있기도 하고 AI 역시 이러한 파싱 부분에서는 뛰어납니다.
| 포맷 | 확장자 | 파서 |
| ESRI Shapefile | .shp | NetTopologySuite.IO.ShapeFile (NuGet) |
| GeoPackage | .gpkg | SQLite + 직접 GPKG 바이너리 파싱 |
| GeoJSON | .geojson | System.Text.Json 수동 파싱 |
| AutoCAD DXF | .dxf | 자체 스트리밍 파서 (DxfParserService) |
DXF는 텍스트 기반 포맷입니다. 그룹코드(int)와 값(string)이 2줄씩 반복되는 단순한 구조입니다. 이 구조를 StreamReader로 한 줄씩 읽는 스트리밍 방식으로 파싱합니다. 대용량 DXF 파일도 메모리에 전체를 올리지 않기 때문에 효율적입니다.
파싱 순서:
SECTION TABLES → 레이어명 / 색상 추출
SECTION BLOCKS → 블록 정의 파싱 (INSERT 참조용)
SECTION ENTITIES → LINE / LWPOLYLINE / CIRCLE / ARC / TEXT / INSERT
GPKG는 SQLite를 컨테이너로 쓰는 OGC 표준 포맷인데, geometry 컬럼의 바이너리 앞에 GPKG 전용 헤더가 붙어 있어서 WKB 오프셋을 직접 계산해야 했습니다. (표준 문서에도 이 부분이 모호하게 적혀 있습니다.)
// GPKG binary header
// magic(2) + version(1) + flags(1) + srsId(4) + envelope(가변)
byte flags = header[3];
int envType = (flags & 0x0E) >> 1;
int envBytes = envType switch
{
0 => 0, // 없음
1 => 32, // XY
2 => 48, // XYZ
3 => 64, // XYZM
4 => 48, // XYM
_ => 0
};
int wkbOffset = 8 + envBytes;
모든 벡터 데이터는 DxfDocument 하나로 표현됩니다. 처음에는 NTS(NetTopologySuite)의 Geometry를 그대로 쓸까도 했지만, WPF 렌더링에 최적화된 경량 모델이 필요해서 직접 설계했습니다. 제가 모든 모델을 가지고 QGIS와 같은 작업을 할껀 아니기에 필요한 객체들만 모델링하는 것이 맵상에서 상당히 빠름을 유지합니다. 제가 필요했던 모델은 "레이어 정보", "전체 엔티티 플랫 리스트", "블록 정의", "전체 바운딩 박스" 이정도 였고, 개발하면서 더 필요하면 모델을 늘려 나가야할 것 같네요.
WPF에서 벡터 데이터를 그리는 방법은 여러 가지입니다.
SharkGeo는 DrawingVisual 방식을 선택했습니다. UIElement 트리 없이 렌더링 명령만 기록하기 때문에 수십만 개의 폴리라인도 처리 가능합니다. 맵은 정상적으로 빠르게 올라왔지만, 그 이후가 문제였습니다. 패닝에서 상당한 부하가 걸리기에 이러 부하를 줄이기 위해서 쉬링크(너무 작아서 안보이면 스킵 하는 기술ㅋㅋ)라고 하는 것도 넣어보고, 레이어를 따로 관리하는 패널도 넣어보고, 움직이는 동안에는 블러처리도 해보고 현재는 스스로 빠르게 느꼈던 부분을 기준에 최적으로 맞춰놓은 상태입니다.
어차피 실제 맵작업을 할때는 '군'이나 '시'정도 사이즈의 벡터를 가지고 작업을 하지는 않고, 범위로 벡터를 잘라서 사용하게 되지만, 어떤 것을 맵컨트롤에 올리던지 빠르면 기분이 좋겠죠!!
마무리하며,
첫번째, Vworld 위성지도를 띄워 놓습니다.

두번째, 어떤 파일이든지 마우스 Drag & Drop으로 편하게 작업을 해야하기에 .shp 파일 맵 컨트롤에 던져봅니다.

세번째, 새롭게 추가되는 레이어의 좌표가 프로젝트 좌표와 맞지 않다면 프로젝트 좌표계 팝업이 바로 올라옵니다.

