Re-test of every sample in the browser viewer and headless Node, the history of 13 handled errors with before/after/current captures for the 8 that could be reproduced, newly found issues (Fit cropping, %%% control codes, symbol-only CP949 strings, broken e2e) and the library packaging assessment. scripts/parse-dwg.mjs is the headless parser used for it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
419 lines
26 KiB
Markdown
419 lines
26 KiB
Markdown
# 샘플 테스트·오류 처리 현황 보고서 (2026-10-19)
|
||
|
||
> 대상: `dwg-dxf-viewer-sample` (HEAD `1f80442` + 미커밋 작업 트리)
|
||
> 근거: 이번 재테스트 실측, git 이력 20커밋, `docs/*.md` 10건, `hmwebviewer/PROGRESS.md`
|
||
> 상태 표기: `원인 확정` · `수정 완료·검증됨` · `수정 완료·미검증`
|
||
> 이 보고서에는 검증된 결과만 싣는다. 검증하지 못한 항목은 §8 목록에만 적는다.
|
||
|
||
---
|
||
|
||
## 1. 핵심
|
||
|
||
- **고유 샘플 20개(DWG 19 + DXF 1)가 모두 브라우저 뷰어에서 로드에 성공했다.** 콘솔 에러는 404 리소스 1건뿐이다. Node 헤드리스 파싱도 19/19 성공했다.
|
||
- **기존 e2e(`e2e_lin_test.cjs`)는 지금 상태 그대로는 실패한다** (`ERR_MODULE_NOT_FOUND`). 끝까지 돌려도 assert 가 없어서 결과를 판정하지 못한다.
|
||
- **과거에 처리한 오류 13건 중 8건을 검증했다** (§4.1). 해당 커밋의 수정 전 버전과 수정 후 버전을 실제로 띄워서, 현재 버전까지 3단으로 캡처하고 측정했다.
|
||
- 대용량 로드: 213.8초 → 3.6초
|
||
- Slug 글자 높이: 150px → 202px (비율 0.743, 커밋 주장 0.744)
|
||
- 레이어 토글: 454~622ms → 13~35ms
|
||
- 그 외 회색 원 제거, 메쉬 표시, 선가중치 적용, Model/Paper 분리, 한글 복원
|
||
- **이번에 새로 찾은 문제는 4건이다.**
|
||
- Fit 이 도면 가장자리를 잘라냄
|
||
- `%%%` 제어코드가 변환되지 않음
|
||
- 기호만 있는 CP949 문자열이 깨진 채 남음
|
||
- e2e 스크립트가 고장 나 있음
|
||
- **라이선스 2건 (`원인 확정`)**
|
||
- 공개한 MPL 패치를 원본 acadrust 0.4.1 에 적용하면 실패한다. 실제 wasm 의 소스를 재현할 수 없다는 뜻이다.
|
||
- Visio 저작권("All rights reserved") 라인타입 데이터가 번들에 들어 있다.
|
||
- Gitea 와 dist2 는 사내 전용이다. **외부 반출(고객 납품·외부 웹 공개·npm) 전에 해결해야 한다.** 라이선스 고지 버튼 자체는 형식이 맞다. 그 버튼이 가리키는 패치 내용이 틀렸다.
|
||
- **라이브러리 배포는 조건부로 가능하다** (§6). 위 라이선스 2건, Vite 전용 코드, Viewer2D 에 `dispose()` 가 없는 문제를 먼저 해결해야 한다.
|
||
|
||
## 2. 권장 액션
|
||
|
||
1. **라이선스.**
|
||
- MPL 패치를 다시 만든다. 원본 0.4.1 과 실제 vendored 트리의 전체 diff 로 만들고, 원본에 적용해서 성공하는지 확인한다.
|
||
- 고지 문서 4곳의 "한 파일만 수정", "unmodified" 문구를 고친다.
|
||
- `ICAD_LIN` 은 IntelliCAD(ITC) 계약 범위를 확인한다. 외부 배포가 허용되지 않으면 제거한다.
|
||
2. **미커밋 작업 정리.**
|
||
- 2.5D 보기, VIEWPORT 채움 변환, Z 붕괴 수정을 커밋하거나 분리한다.
|
||
- 루트의 untracked 대용량 파일(`C0060202.json` 31.7MB, `SAN01.json` 16.6MB, `C0060202.zip`)은 `.gitignore` 에 넣거나 삭제한다.
|
||
3. **e2e 를 실제 테스트로.**
|
||
- `linParser.ts` 의 확장자 없는 import 를 고친다.
|
||
- 샘플 경로를 `dist/` 에서 `public/samples/` 로 바꾼다.
|
||
- assert 를 추가한다.
|
||
- 이번에 쓴 브라우저 e2e 와 3단 비교 스크립트를 레포에 넣는다.
|
||
4. **Fit 잘림 수정** (§3.4-①).
|
||
5. **텍스트 후처리 2건 수정.**
|
||
- `stripMText` 에 `%%%`, `%%nnn`, `%%o`, `%%u` 처리를 추가한다.
|
||
- `fixCp949Mojibake` 가 한글이 없는 CP949 기호도 복원하게 한다.
|
||
|
||
---
|
||
|
||
## 3. 이번 재테스트 결과
|
||
|
||
### 3.1 환경
|
||
|
||
| 항목 | 값 |
|
||
|---|---|
|
||
| 코드 | HEAD `1f80442` + 미커밋 변경(2.5D 보기, `_bakeFillXf`, `_trimmedContentBox` Z 수정) |
|
||
| Node | v24.11.1 |
|
||
| 브라우저 | 시스템 Chrome headless, `playwright-core@1.56.1` |
|
||
| GPU | ANGLE D3D11 / NVIDIA RTX 3060 (실제 GPU) |
|
||
| 타입체크 | `npm run typecheck` 통과 (컴파일 통과일 뿐, 동작 검증은 아님) |
|
||
|
||
### 3.2 샘플별 결과
|
||
|
||
열 설명:
|
||
- **Node 파싱**: `parse_dwg_json` + `fixDwgKoreanText` 실행 시간.
|
||
- **RSS**: 프로세스 전체 메모리.
|
||
- **브라우저 로드**: 파일을 선택한 뒤 상태바에 `✓ <파일명>` 이 뜨기까지의 시간.
|
||
- **JS heap**: `performance.memory`.
|
||
- **notif**: acadrust notification 개수.
|
||
|
||
| 파일 | MB | 버전 | 엔티티 | Node 파싱 ms | RSS MB | 브라우저 로드 ms | JS heap MB | 콘솔 에러 | notif | 결과 |
|
||
|---|---|---|---|---|---|---|---|---|---|---|
|
||
| BasicSample.dwg | 0.4 | R2018 | 7,309 | 142 | 147 | 553 | 47 | 1¹ | 4 | 통과 |
|
||
| civil.dwg² | 5.4 | R2000 | 17,810 | 389 | 264 | 799 | 98 | 0 | 2 | 통과 |
|
||
| C0060203-001-표준단면도(…).dwg | 0.4 | R2007 | 2,068 | 93 | 126 | 567 | 57 | 0 | **78** | 통과 |
|
||
| bb.dwg | 0.7 | R2018 | 438 | 75 | 109 | 579 | 46 | 0 | 4 | 통과 |
|
||
| simple.dxf | 0.0 | DXF | 6 | — | — | 74 | 34 | 0 | — | 통과 |
|
||
| 04manhole1-simplify.dwg | 0.4 | R2018 | 7,035 | 118 | 138 | 575 | 54 | 0 | 4 | 통과 |
|
||
| dwg_18.3mb.dwg | 18.4 | R2018 | 82,393 | 1,988 | 1,087 | **4,232** | 372 | 0 | 4 | 통과 |
|
||
| test.dwg³ | 18.4 | R2018 | 82,393 | 2,156 | 1,088 | 3,914 | 371 | 0 | 4 | 통과 |
|
||
| 대산당진 2공구_노면_….dwg | 37.1 | R2018 | 65,495 | 3,017 | **1,373** | **5,454** | **782** | 0 | 4 | 통과 |
|
||
| a. 거더배치 삽도 | 0.2 | R2018 | 1,433 | 118 | 134 | 568 | 139 | 0 | 5 | 통과 |
|
||
| a. 교대배치 삽도 | 0.4 | R2018 | 2,138 | 58 | 102 | 565 | 59 | 0 | 4 | 통과 |
|
||
| a. 교량시종점 삽도 | 0.4 | R2018 | 4,432 | 84 | 105 | 542 | 56 | 0 | 4 | 통과 |
|
||
| a. 교량폭원 삽도 | 0.5 | R2018 | 2,824 | 64 | 106 | 575 | 45 | 0 | 4 | 통과 |
|
||
| a. 교면포장 삽도 | 0.2 | R2018 | 1,304 | 54 | 104 | 570 | 44 | 0 | 4 | 통과 |
|
||
| a. 중앙분리대 삽도 | 0.4 | R2018 | 2,159 | 63 | 103 | 537 | 44 | 0 | 4 | 통과 |
|
||
| a. 횡단경사 삽도 | 0.5 | R2018 | 5,635 | 126 | 138 | 569 | 44 | 0 | 4 | 통과 |
|
||
| 산외교- ELEVATION 산출근거도 | 0.6 | R2007 | 11,262 | 162 | 181 | 937 | 111 | 0 | **44** | 통과 |
|
||
| 산외교-받침배치도 | 0.4 | R2018 | 6,240 | 106 | 144 | 635 | 63 | 0 | 4 | 통과 |
|
||
| 산외교_파이형_교각일반도(울산P11-꺾임) | 1.0 | R2018 | 25,927 | 371 | 219 | 810 | 56 | 0 | 4 | 통과 |
|
||
| 산외교_파이형_교각일반도(울산P9) | 1.0 | R2018 | 26,207 | 397 | 220 | 744 | 57 | 0 | 4 | 통과 |
|
||
|
||
¹ 404 리소스 1건, 첫 페이지에서만 발생. `/favicon.ico` 가 404 를 반환하는 것은 확인했다.
|
||
² `civil.dwg` 와 `C0060202-001-평면및종단면도(…).dwg` 는 md5 가 같다. 같은 파일이다.
|
||
³ `test.dwg` 는 `dwg_18.3mb.dwg` 와 바이트는 다르지만, 파싱 결과의 엔티티 수와 텍스트 통계가 같다.
|
||
|
||
"통과" 의 기준: 상태바에 `✓ <그 파일명> · … entities` 가 표시되고, `.err` 가 없고, 페이지 crash 가 없을 것.
|
||
|
||
### 3.3 기존 e2e (`e2e_lin_test.cjs`)
|
||
|
||
| 실행 방식 | 결과 |
|
||
|---|---|
|
||
| `node e2e_lin_test.cjs` (그대로) | **실패, exit 1**. 4단계에서 `ERR_MODULE_NOT_FOUND: …/src/viewer2d/linData` |
|
||
| resolve hook 추가 | 끝까지 실행, exit 0. H-DICHL06/06R/02R/01R/05 패턴 5개 출력 |
|
||
|
||
`원인 확정`: `linParser.ts` 가 `./linData` 를 확장자 없이 import 한다. Vite 는 이것을 해석하지만 Node ESM 은 해석하지 못한다.
|
||
|
||
그 밖의 문제:
|
||
- **assert 가 없다.** 패턴을 못 찾아도 `console.error` 만 찍고, 마지막에 항상 `COMPLETED SUCCESSFULLY` 를 출력한다.
|
||
- 샘플 경로가 gitignore 된 `./dist/samples/…` 다. clean checkout 에서는 실패한다.
|
||
- 느린 경로인 `parse_dwg` 를 쓰고 `fixDwgKoreanText` 를 적용하지 않는다. 그래서 출력되는 라인타입 설명이 `LÇüÃø±¸` 처럼 깨진다.
|
||
- `Found 0 text styles` 가 출력된다. `tables.styles` 가 비어 있다는 문서상 과제가 C0060202 에서도 재현된다.
|
||
|
||
### 3.4 이번에 새로 확인한 문제
|
||
|
||
**① Fit 이 도면 가장자리를 잘라냄.** 재현 확인.
|
||
- ELEVATION 도면에서 Fit 을 하면 도곽 왼쪽이 화면 밖으로 나가고, 오른쪽에는 약 470px 가 비어 있다 (§4.1 캡처).
|
||
- 자동 Fit, Fit 버튼, 창 크기 변경 후 Fit 모두 같은 결과다.
|
||
- HEAD(미커밋 변경 제외)에서도 똑같다. WIP 회귀가 아니다.
|
||
|
||
**② AutoCAD 제어코드 `%%%` 등이 변환되지 않음.** `원인 확정`.
|
||
- C0060203 에 `-2 %%%`, civil Layout 에 `S=0.0000%%%` 가 그대로 표시된다.
|
||
- [`Viewer2D.js:64`](../src/viewer2d/Viewer2D.js) 의 `stripMText` 는 `%%d`, `%%p`, `%%c` 만 처리한다.
|
||
|
||
**③ 기호만 있는 CP949 문자열이 깨진 채 남음.** `원인 확정`.
|
||
- civil 에 `500¡¿350` 이 표시된다. CP949 로 디코딩하면 `500×350` 이다.
|
||
- [`fixDwgKoreanText.ts:64-67`](../src/viewer2d/fixDwgKoreanText.ts) 는 디코딩 결과에 한글이 생길 때만 변환을 받아들인다.
|
||
|
||
**④ e2e 스크립트 고장.** §3.3 참고.
|
||
|
||
**기타 (경미)**
|
||
- Layout 탭 이름이 `Layout (Paper_Space0)` 처럼 내부 블록명으로 나온다. dwg2model 삽도 7개 전부가 그렇다.
|
||
- Layout 탭이 많으면 툴바가 줄바꿈되면서 상태바가 속성 패널과 겹친다.
|
||
- `parse_dwg_json` 은 acadrust notification 의 개수만 돌려주고 내용은 돌려주지 않는다 (C0060203 78건, ELEVATION 44건).
|
||
|
||
---
|
||
|
||
## 4. 처리된 오류 이력
|
||
|
||
표기: [M] 커밋 메시지 · [D] diff 로 확인 · [Doc] 문서 기록.
|
||
Rust 쪽 수정(dwg-wasm, acadrust)은 `hmwebviewer/rust/dwg-wasm` 에 있다.
|
||
|
||
| # | 시기 | 증상 | 재현 샘플 | 원인 | 조치 | 커밋 | 이번 검증 |
|
||
|---|---|---|---|---|---|---|---|
|
||
| 1 | 07-30 | 구형 한글 TEXT/MTEXT 깨짐 | civil 외 | CP949 바이트가 Latin-1 로 올라옴 [Doc] | `fixDwgKoreanText.ts` (뷰어) | be8d52f | **`수정 완료·검증됨`** (§4.1-①) |
|
||
| 2 | 07-30 | Model 과 Paper 동시 렌더, Layout 비어 보임, Fit/좌표, 글자 거대, VP 순서 (6건) | C0060202 | VIEWPORT 미투영, minTextH 등 [Doc] | `cadSpaces.ts`, Viewer2D (뷰어) | be8d52f | **`수정 완료·검증됨`** (§4.1-②) |
|
||
| 3 | 07-30 | Brave/Firefox 에서 OLE BMP 미표시 | — | `<img>` 가 data:image/bmp 미지원 [M] | 순수 JS BMP 디코더 [D] | 963a903 | §8 |
|
||
| 4 | 07-30 | OLE2FRAME 이 하드코딩된 좌표에 고정됨 | — | 정답 좌표 하드코딩 [D] | 파서가 준 ul/lr 사용 | 76f3e20 | §8 |
|
||
| 5 | 08-03 | Slug 텍스트 cap-height 약 26% 작음 | BasicSample | 3d3e052 의 회귀 [D] | 되돌림 | fb8f7ca | **`수정 완료·검증됨`** (§4.1-④) |
|
||
| 6 | 08-03 | 19MB DWG 로딩 시 탭 프리즈 | dwg_18.3mb | wasm 힙 O(n²) [M] | `parse_dwg_json` 스트리밍 | b047dc4 | **`수정 완료·검증됨`** (§4.1-③) |
|
||
| 7 | 08-03 | 도면 위아래 거대 회색 원 | dwg_18.3mb | `sample_arc` 각도 swap 등 [Doc] | 손상 호 감지 후 생략 (파서) | b047dc4 | **`수정 완료·검증됨`** (§4.1-③) |
|
||
| 8 | 08-04 | 레이어 토글 지연 | dwg_18.3mb | 토글마다 `load()` 재빌드 [M] | setDrawRange, `.visible` 토글 | 3480945 | **`수정 완료·검증됨`** (§4.1-⑦) |
|
||
| 9 | 08-04 | 노면/부체도로면(MESH) 미표시 | 대산당진 노면 | MESH 직렬화 누락, read_mesh 100k 상한 [M] | acadrust 패치 + 직렬화 + `_meshSegs` | eec3382, c67a803 | **`수정 완료·검증됨`** (§4.1-⑤) |
|
||
| 10 | 08-04 | 모든 선이 1px | 대산당진 노면 | lineWeight 누락, WebGL linewidth 무시 [M] | LineSegments2 버킷 | c67a803 | **`수정 완료·검증됨`** (§4.1-⑥) |
|
||
| 11 | 08-04~05 | 선가중치 배율 (8 → 20 → 11 px/mm) | 대산당진 노면 | 배율 [M] | 기본값 11, 옵션 패널 | cf12987, a924b1e, 1f80442 | 굵기 적용 확인 (§4.1-⑥). 배율 일치는 §8 |
|
||
| 12 | 08-04 | MPL-2.0 고지 누락 | — | 고지/원문/소스 경로 없음 [M] | NOTICES, `public/licenses/` | ce3859c | **조치 불충분**: 패치가 원본에 적용되지 않음 (§5 A-1) |
|
||
| 13 | 08-04 | `vite build` 가 dist2 테스트 파일을 삭제 | — | `emptyOutDir` 기본값 [M] | `--emptyOutDir false` 절차 문서화 | 6f200ef | — |
|
||
|
||
분리 전 hmwebviewer 에서 처리한 것 (07-10~14, `PROGRESS.md`):
|
||
- solid HATCH 구멍, HIDDEN/CENTER 파선 무시
|
||
- MAX_TEXTS 3000 상한
|
||
- 회전 도곽 viewTwist, 로고 해치, 폴리라인 폭, MTEXT 배경
|
||
|
||
**미커밋 수정 2건** (`수정 완료·미검증`):
|
||
- VIEWPORT 안 SOLID/HATCH 채움에 model→paper 변환 추가 (`_fillXf`/`_bakeFillXf`)
|
||
- `_trimmedContentBox` 의 Z 붕괴 수정
|
||
|
||
### 4.1 수정 전 / 수정 후 / 현재 비교 캡처
|
||
|
||
**방법**
|
||
- 각 버전은 `git archive <커밋>` 으로 풀어서 실행했다. wasm 이 커밋마다 함께 커밋돼 있어서, 그 시점의 파서와 뷰어가 같이 재현된다.
|
||
- 계측용으로 두 가지만 덧붙였다. 둘 다 동작에는 영향이 없다.
|
||
- `main.ts` 에 `window.__viewer = viewer` 1줄
|
||
- vite 캐시 경로 분리
|
||
- "현재" 는 오늘의 작업 트리다.
|
||
- 로드 판정은 상태바가 `✓ <그 파일명> ·` 으로 바뀌었는지로 했다.
|
||
- 확대 화면은 모든 버전에서 같은 WCS 좌표와 화면 폭으로 카메라를 고정했다. 파일럿 캡처로 목표 객체가 화면 중앙에 오는 것을 먼저 확인했다.
|
||
- UI 패널은 숨기고 캔버스만 찍었다. 해상도 1280×800, RTX 3060.
|
||
- 24회 실행 모두 로드 성공, 콘솔 에러 0건.
|
||
|
||
**① 한글 깨짐** (`civil.dwg`)
|
||
|
||
수정 전 버전의 wasm 이 실제로 내보낸 문자열과, 수정 후 화면을 함께 비교했다:
|
||
|
||
| handle | 수정 전 `95fa6a4` wasm 출력 | 수정 후 `be8d52f` |
|
||
|---|---|---|
|
||
| 3232403 | `Ãø Á¡` | `측 점` |
|
||
| 3232405 | `°èȹ°í` | `계획고` |
|
||
| 3232408 | `Áö¹Ý°í` | `지반고` |
|
||
| 3240601 | `õÀÇ1Áö±¸ °èȹ¼±` | `천의1지구 계획선` |
|
||
| 3241973 | `(»ç¾÷ ÁøÇà ¿¹Á¤)` | `(사업 진행 예정)` |
|
||
| 1009 | `°Ç¼³´Ü°è` | `건설단계` |
|
||
|
||
| 수정 후 `be8d52f` | 현재 |
|
||
|---|---|
|
||
|  |  |
|
||
|
||
**② Model/Paper 겹침, Layout 비어 보임** (`civil.dwg`, 로드 직후 기본 화면)
|
||
|
||
| 수정 전 `95fa6a4` | 수정 후 `be8d52f` | 현재 |
|
||
|---|---|---|
|
||
|  |  |  |
|
||
| 점 3개만 보임. Model(x≈600k·162k)과 Paper(원점)를 한꺼번에 Fit 함 | Layout 이 열리고 VIEWPORT 내용이 투영됨 | 같음 (밝은 종이 배경) |
|
||
|
||
**③ 대용량 로딩 + 거대 회색 원** (`dwg_18.3mb.dwg`, 로드 직후 기본 화면)
|
||
|
||
| 수정 전 `7a6edd4` | 수정 후 `b047dc4` | 현재 |
|
||
|---|---|---|
|
||
|  |  |  |
|
||
| 로드 **213.8초**. 회색 SOLID HATCH 가 도면 아래쪽 절반을 덮음 | **3.6초**, 회색 채움 없음 | **3.7초** |
|
||
|
||
**④ Slug 텍스트 크기** (`BasicSample.dwg`, "정면도" h=140 주변 고정 화면)
|
||
|
||
| 수정 전 `b047dc4` | 수정 후 `fb8f7ca` | 현재 |
|
||
|---|---|---|
|
||
|  |  |  |
|
||
| 글자 높이 **150px** | **202px** | **202px** |
|
||
|
||
- 자홍색 픽셀 bbox 높이를 쟀다. 비율 150/202 = **0.743** 으로, 커밋 메시지 "3.6 → 2.68 (0.744)" 와 일치한다.
|
||
- 주변 선과 치수의 위치는 세 장 모두 같다.
|
||
|
||
**⑤ SubDMesh(MESH) 미표시** (노면 도면, 연결부 (156542, 479804), 폭 160)
|
||
|
||
| 수정 전 `6f200ef` | 수정 후 `c67a803` | 현재 |
|
||
|---|---|---|
|
||
|  |  |  |
|
||
| 삼각망 없음 | 도로면·부체도로면 삼각망 표시 | 같음 |
|
||
|
||
c67a803 에는 선가중치 수정도 함께 들어 있다.
|
||
|
||
**⑥ 선가중치** (⑤와 같은 화면)
|
||
|
||
| 수정 전 `eec3382` | 수정 후 `1f80442` (11 px/mm) | 현재 |
|
||
|---|---|---|
|
||
|  |  |  |
|
||
| 0.50mm 도로마킹 포함 모든 선 1px (메쉬 렌더러 이전 버전) | 굵게 표시 | 같음 |
|
||
|
||
**⑦ 레이어 토글 속도** (`dwg_18.3mb.dwg`, `setHiddenLayers(CF-PATT)` 숨김→표시 3회, 동기 실행 시간)
|
||
|
||
| | 수정 전 `fb8f7ca` | 수정 후 `3480945` | 현재 |
|
||
|---|---|---|---|
|
||
| 숨김 ms | 565 / 454 / 512 | 18 / 17 / 13 | 21 / 18 / 13 |
|
||
| 표시 ms | 501 / 622 / 609 | 26 / 5 / 6 | 35 / 5 / 5 |
|
||
|
||
**새로 확인한 문제 (현재 버전)**
|
||
|
||
| `%%%` 미변환 (C0060203) | CP949 기호 잔존 (civil) | Fit 잘림 (ELEVATION) |
|
||
|---|---|---|
|
||
|  |  |  |
|
||
| `-2 %%%` (정답 `-2 %`) | `500¡¿350` (정답 `500×350`) | 왼쪽 잘림, 오른쪽 약 470px 공백 |
|
||
|
||
---
|
||
|
||
## 5. 남은 과제
|
||
|
||
### A. 우선 처리
|
||
|
||
| # | 과제 | 근거 |
|
||
|---|---|---|
|
||
| A-1 | **MPL 패치가 실제 소스를 재현하지 못함** (`원인 확정`)<br>- `public/licenses/acadrust-0.4.1-read_mesh.patch` 를 원본 acadrust 0.4.1 crate 에 `git apply --check` 하면 `entities.rs:2350`(read_ole2frame)에서 실패한다.<br>- 고지의 "One file differs", "exact Source Code Form" 문구와 `acadrust-dwg/package.json` 의 "used unmodified" 가 사실과 다르다. | 이번 실행, `THIRD-PARTY-NOTICES.md` |
|
||
| A-2 | **Visio 저작권 데이터가 번들됨**<br>- `linData.ts` 의 `ICAD_LIN` 헤더가 "Copyright (c) 1998 by Visio Corporation. All rights reserved" 다.<br>- `linParser.ts:228` 이 import 될 때 등록하므로 배포본에 반드시 들어간다.<br>- IntelliCAD(ITC) 계약이 자사 웹 뷰어로의 외부 배포를 허용하는지 확인이 필요하다. | 이번 확인 |
|
||
| A-3 | 자체 `LICENSE` 파일 없음, NanumGothic OFL 원문 미동봉 | §6 |
|
||
| A-4 | 자동 판정 테스트 없음, e2e 고장 | §3.3 |
|
||
| A-5 | Fit 이 가장자리를 잘라냄 | §3.4-① |
|
||
| A-6 | 미커밋 WIP 정리, `src/topProgress.ts` 어디서도 import 되지 않음, 루트 대용량 untracked 파일 | `git status` |
|
||
| A-7 | 원본 hmwebviewer 에 Model/Paper 수정 미이식 (`cadSpaces.ts` 없음) | `model-paper-space.md` §9 |
|
||
|
||
### B. 기능·품질
|
||
|
||
| # | 과제 | 근거 |
|
||
|---|---|---|
|
||
| B-1 | 해치 손상 호의 근본 원인 미확인. 현재 수정은 감지 후 생략. `spurious_r` 5배 임계값은 경험값 | `hatch-boundary-arc-artifact.md` §7 |
|
||
| B-2 | 파싱 중 메인 스레드 블로킹. 37MB 도면 로드 5.5초 동안 UI 정지. Web Worker 미적용 | 이번 측정 |
|
||
| B-3 | 메쉬 레이어에 굵기가 지정되면 fat 버킷 상한(40만) 124.5% 초과 → 버킷 전체 헤어라인 폴백 | `improvement-results` §5-3 |
|
||
| B-4 | `%%%` 등 제어코드, CP949 기호 | §3.4-②③ |
|
||
| B-5 | `tables.styles` 비어 있음 → 폰트 매핑 불가 | 한글 문서 §8, 이번 e2e |
|
||
| B-6 | 한글 처리가 JS 휴리스틱. 932/936/950 미지원 | 한글 문서 §8 |
|
||
| B-7 | Layout 탭 캡션이 내부명 | 이번 실행 |
|
||
| B-8 | acadrust notification 내용 비노출 | 이번 실행 |
|
||
| B-9 | 40만 상한 초과 시 사용자 알림 없음 (`console.warn` 만) | `lineweight-rendering.md` §6 |
|
||
| B-10 | wasm32 4GB 한계. 37MB 도면에서 Node RSS 1.37GB, 브라우저 JS heap 782MB | 이번 측정 |
|
||
|
||
### C. 나중에
|
||
|
||
- 선가중치: 중첩 ByBlock 미추적, DXF LAYER 코드 370 무시, `celweight` 가 DWG 인덱스 그대로 나감
|
||
- MESH: Catmull-Clark(`subdivisionLevel > 0`), POLYFACE/POLYGON MESH, shaded 패스
|
||
- VIEWPORT: 솔리드 HATCH 근사, 비직교 VP, TILEMODE/CTAB 휴리스틱
|
||
- OLE BMP 가 24/32bpp 만 지원
|
||
- `parse_dwg` export 미정리
|
||
- CXGLOGO-EX흑백.dwg 의 얇은 원 (hmwebviewer 시절부터)
|
||
|
||
### D. 배포·문서 정리
|
||
|
||
- `build:dist2` 스크립트 없음, `dist2/assets` 에 예전 해시 번들 누적, 테스트 도면이 `dist2/samples` 에 섞여 있음
|
||
- 문서 상태 표기가 낡음:
|
||
- `subdmesh-rendering.md`: "렌더러 미커밋"
|
||
- `lineweight-rendering.md`, `improvement-results`: "미푸시"
|
||
- 여러 문서: "acadrust 미수정"
|
||
- `Viewer2D.d.ts:24`, `Viewer2D.js:1389` 주석은 "Default 20" 인데 실제 기본값은 11
|
||
- README 이슈 표에 hatch, large-dwg 문서 누락
|
||
|
||
---
|
||
|
||
## 6. 라이브러리 배포 가능성
|
||
|
||
### 6.1 결론: 조건부 가능
|
||
|
||
- 파서는 DOM 없이 동작한다. Node 24 에서 `initSync` 로 19개 도면을 파싱해 실측했다.
|
||
- Viewer2D 가 DOM 에 닿는 곳은 생성자로 받는 `container` 하나뿐이다.
|
||
- 다만 아래 차단 요소를 먼저 풀어야 한다.
|
||
|
||
### 6.2 차단 요소
|
||
|
||
| # | 문제 | 위치 | 영향 |
|
||
|---|---|---|---|
|
||
| L1 | MPL 패치로 소스 재현 불가 | §5 A-1 | 법적 의무 미충족 |
|
||
| L2 | Visio 저작권 lin 데이터 | `linData.ts:2` | 재배포 권리 확인 필요 |
|
||
| L3 | 자체 `LICENSE`, `package.json` `license` 필드 없음. `Viewer2D.js:3` 에 "Ported from webviewer/…" | 루트 | 사용 권리 불명확 |
|
||
| L4 | NanumGothic OFL 원문 미동봉 | `public/licenses/` | 폰트 동봉 시 위반 |
|
||
| B1 | `?url` import 가 Vite 전용 | `acadrustParser.ts:6` | Node·webpack·SSR 에서 실패. Vite lib 모드로 빌드하면 wasm 이 base64 로 두 번 인라인됨 (실측 2.37MB) |
|
||
| B2 | 확장자 없는 상대 import | `dwgParser.ts:16`, `parseDxf.ts:7`, `Viewer2D.js:16-18` 외 | Node ESM 에서 `ERR_MODULE_NOT_FOUND` (§3.3 과 같은 원인) |
|
||
| B3 | 폰트 경로 `/fonts/…` 하드코딩, 전역 싱글톤 | `slugText.ts:32-49`, `Viewer2D.js:127` | 호스트에 그 경로가 없으면 404 |
|
||
| B4 | `dispose()` 없음 | `Viewer2D.js:159,164,4527` | 익명 window 리스너와 rAF 루프를 해제할 수 없음. F 키 리스너는 입력란에서도 Fit 실행 |
|
||
| B5 | 타입 불완전 | `Viewer2D.d.ts` | `load(result: unknown)`, 일부 메서드 누락, 기본값 주석 20 ≠ 실제 11 |
|
||
| B6 | 패키지 설정 없음 | `package.json` | `private: true`, `exports`/`files`/`peerDependencies` 없음 |
|
||
| B7 | 소스 정본이 여러 곳 | 이 레포 / `hmwebviewer/src/viewer2d` / `hmwebviewer/packages/dwg-dxf-viewer` | wasm 바이너리 3개가 모두 다름. `Viewer2D.js` 는 hmwebviewer 와 1,217줄 차이 |
|
||
|
||
### 6.3 권장 구조: 패키지 2개
|
||
|
||
```
|
||
@scope/cad-parser (headless, three 없음) license: "MIT AND MPL-2.0"
|
||
initDwgParser({ wasm?: URL | bytes | Module })
|
||
parseDwg(bytes) / parseDxf(buf) / parseCad(buf, nameHint?)
|
||
listCadSpaces, pickDefaultSpace, isDwg/isDxf, CadParseResult 타입
|
||
./worker (선택: 메인 스레드 비블로킹)
|
||
|
||
@scope/viewer2d (Viewer2D, slugText, linParser) license: "MIT"
|
||
peerDependencies: three ^0.185.0 ← peer + external
|
||
dependencies: @scope/cad-parser, opentype.js
|
||
```
|
||
|
||
파서 패키지 `package.json` 핵심:
|
||
|
||
```json
|
||
{
|
||
"type": "module",
|
||
"license": "MIT AND MPL-2.0",
|
||
"exports": {
|
||
".": { "types": "./dist/index.d.ts", "node": "./dist/node.js", "default": "./dist/browser.js" },
|
||
"./worker": "./dist/worker.js",
|
||
"./acadrust_dwg_bg.wasm": "./dist/acadrust_dwg_bg.wasm"
|
||
},
|
||
"files": ["dist", "licenses", "THIRD-PARTY-NOTICES.md", "LICENSE"],
|
||
"sideEffects": false
|
||
}
|
||
```
|
||
|
||
wasm 로딩:
|
||
1. **기본**: glue 의 `new URL('./acadrust_dwg_bg.wasm', import.meta.url)` 패턴을 유지한다.
|
||
2. **탈출구**: `init({ wasm })` 로 URL, bytes, Module 을 직접 넘길 수 있게 한다.
|
||
3. **Node**: `initSync({ module: readFileSync(...) })`. `scripts/parse-dwg.mjs` 에서 동작을 확인했다.
|
||
|
||
### 6.4 작업 순서
|
||
|
||
1. 라이선스 L1~L4 해결
|
||
2. 정본 레포 통일, `rust/dwg-wasm` 과 vendored acadrust 이전, `rust-toolchain.toml` 로 툴체인 고정
|
||
3. 파서 분리: `?url` 제거, `init({ wasm })` 추가, Node 진입점, `parseCad()`, 상대 import 에 `.js`
|
||
4. Viewer2D: 생성자 옵션(`fontUrl`, `keyboard` 등), `dispose()`, `ResizeObserver`, `localStorage` 잔재 제거, 콜백 해제 함수
|
||
5. 타입: 수기 `Viewer2D.d.ts` 보완, `CadParseResult` 구체화
|
||
6. 빌드: tsup/rollup/tsc 로 ESM, wasm 은 파일로 복사, `opentype.js` 는 default import (Node ESM 에서 named import 실패 실측)
|
||
7. 검증: 소비 예제(Vite, webpack 5, Node)를 CI 로 돌리고, §3 의 샘플 20개 e2e 를 회귀 테스트로
|
||
|
||
### 6.5 유의할 점
|
||
|
||
- **크기**
|
||
|
||
| 파일 | raw | brotli |
|
||
|---|---|---|
|
||
| wasm | 884KB | 301KB |
|
||
| 폰트 | 2.05MB | 432KB |
|
||
|
||
폰트는 번들하지 말고 `fontUrl` 옵션으로 받는다.
|
||
- **메모리**: 37MB 도면에서 Node RSS 1.37GB, 브라우저 JS heap 782MB. wasm32 상한은 4GB 다.
|
||
- **런타임**: CSP 에 `'wasm-unsafe-eval'` 이 필요하다. `application/wasm` MIME 이 아니면 느린 폴백으로 떨어진다.
|
||
- **한글**: `cp949`/`euc-kr` TextDecoder 가 없는 런타임에서는 `fixDwgKoreanText` 가 아무 표시 없이 보정을 건너뛴다.
|
||
- **버전 정책**: 두 패키지는 lockstep 으로 올린다. `CadParseResult` 필드 추가는 minor, 삭제나 변경은 major.
|
||
- **upstream drift**: README 의 "본가에서 다시 복사" 절차를 따르면 이 레포의 기능(lineweight, 2.5D, Model/Layout)이 지워진다.
|
||
- **acadrust 버전**: 상류는 0.6.x 다. 0.4.1 fork 유지 여부를 결정해야 한다.
|
||
- **릴리스**: 깨끗한 태그에서만 배포한다.
|
||
|
||
---
|
||
|
||
## 7. 재현 방법
|
||
|
||
```powershell
|
||
# 헤드리스 파싱 (1개 파일)
|
||
node scripts/parse-dwg.mjs "<file.dwg>" [out.json]
|
||
|
||
# 기존 e2e (현재는 실패, §3.3)
|
||
node e2e_lin_test.cjs
|
||
```
|
||
|
||
배치 파서, 브라우저 e2e, 3단 비교 캡처 스크립트는 세션 임시 폴더에 있다. 레포 반영은 §2-3. 측정 원본은 `images/sample-test-2026-10-19/results.json` 에 있다.
|
||
|
||
## 8. 검증 불가 목록
|
||
|
||
| 항목 | 이유 |
|
||
|---|---|
|
||
| OLE BMP(#3), OLE2FRAME(#4) | OLE2FRAME 엔티티가 있는 샘플이 없음 |
|
||
| 선가중치 배율(#11)이 AutoCAD 와 일치하는지 | 같은 위치의 AutoCAD 정답 캡처가 없음 |
|
||
| 한글 깨짐(#1) 수정 전 화면 | 같은 커밋에서 고친 '글자 거대' 버그 때문에 판독 불가. 문자열 비교로 대신 검증함 |
|
||
| 수정 전 수치와 문서 기록의 차이 (로드 213.8s vs 문서 354s, 토글 약 0.5s vs 커밋 "5초 이상") | 당시 측정 환경과 방법을 알 수 없음 |
|
||
| Fit 잘림의 원인 | 재현만 확인, 원인 미확정 |
|
||
| H-DICHL06 의 `patternLen`(1) 과 요소 합(1.588) 중 어느 쪽이 AutoCAD 기준인지 | AutoCAD 대조 수단 없음 |
|
||
| 문서상 한글 재현 도면 `C0060203-002-굴착및시공순서도.dwg` | 레포에 없음 |
|
||
| 7~8월 테스트 당시의 증상 원문 | 세션 기록이 남아 있지 않음 (가장 오래된 기록이 09-16) |
|