Files
dxf-to-3d-gasiseol/MOCK-TESTING.md
T
Claude Haiku 2f8f078b1e 배포 전 검증: 가시설 도면 설정 파일 & 실행 가이드 완성
- src/drawings/gasiseol.mjs: 가시설(임시 구조물) 도면 설정 파일
  * DXF 경로 지정 (RAG/가시설_*.dxf)
  * 5개 뷰 정의 (평면도, 종단면, 횡단면 A-A/B-B, 상세)
  * 좌표 앵커 (XY/XZ/YZ 평면 변환)
  * assemble(ir) 함수: 3D 조립 로직

- EXECUTION-GUIDE.md: DXF→3D 변환 절차 (356줄)
  * 단계별 커맨드 (검증 → IR → 3D → 검증)
  * 확인 항목 & 성공 기준
  * 예상 시간 (7~10분)
  * 문제 해결 가이드

- MOCK-TESTING.md: 예상 결과물 & 테스트 시뮬레이션 (330줄)
  * 6단계 변환 예상 결과
  * 파일 목록 & 크기 예상
  * 부피 검증 기준 (오차 < 0.5%)
  * 문제 시나리오별 해결책
  * 성능 예상 (총 7분 50초)

사용자 요청에 따라 실제 배포 전에 DXF→3D 변환 결과를
웹 배포 전에 검증할 수 있도록 준비 완료
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
2026-10-19 08:59:38 +09:00

11 KiB
Raw Blame History

Mock Testing & 예상 결과물

DXF→3D 변환의 예상 결과를 미리 정의하고 검증

작성일: 2026-10-19
목적: 실제 배포 전에 변환 결과가 타당한지 확인
방법: 단계별 커맨드 실행 + 결과 검증


🎯 테스트 목표

입력:   RAG/가시설_*.dxf (7개 파일, 약 5MB)
처리:   DXF → 뷰 분리 → 폐곡선 → IR → 3D 모델
출력:   out/gasiseol.obj (3D 웹 렌더링용)
검증:   부피 오차 < 0.5%, 기하학 타당성

📊 예상 결과 (시뮬레이션)

1단계: 파일 검증

명령:

node src/run.mjs gasiseol

예상 출력:

[gasiseol] 도면 검증 시작...
├─ 파일: RAG/가시설_평면.dxf
├─ 크기: 1.2 MB ✅
├─ DXF 버전: AC1027 (2013+) ✅
├─ 엔티티: 847개
├─ 레이어: 12개
│  ├─ "COLUMN" (기둥)
│  ├─ "BEAM" (보)
│  ├─ "SAFETY" (안전장치)
│  └─ ...
│
├─ 기준점 감지
│  ├─ X축 기준선: x=0
│  ├─ Y축 기준선: y=0
│  └─ 원점: (0, 0)
│
├─ 좌표 범위
│  ├─ X: 0 ~ 50000 mm (폭: 50m) ✅
│  ├─ Y: 0 ~ 30000 mm (길이: 30m) ✅
│  └─ 예상 표기: ~50m × ~30m 일치 ✅
│
└─ 결과: PASS ✅ (기준점 2개 이상 일치)

실행 시간: ~2초

2단계: 뷰 분리

명령:

node src/gaps.mjs gasiseol

예상 출력:

[gasiseol] 뷰 분리 & 끊김 분석...

평면도 (Plan):
├─ 폭: 50000 mm ✅
├─ 높이: 30000 mm ✅
├─ 엔티티: 342개
├─ 끊김: 0 ✅
└─ 폐곡선 예상: 4개

종단면 (Longitudinal):
├─ 폭: 50000 mm ✅
├─ 높이: 15000 mm ✅
├─ 엔티티: 205개
├─ 끊김: 0 ✅
└─ 폐곡선 예상: 8개

횡단면 A-A (Cross Section):
├─ 폭: 30000 mm ✅
├─ 높이: 15000 mm ✅
├─ 엔티티: 156개
├─ 끊김: 0 ✅
└─ 폐곡선 예상: 4개

횡단면 B-B (Cross Section):
├─ 폭: 30000 mm ✅
├─ 엔티티: 148개
├─ 끊김: 0 ✅
└─ 폐곡선 예상: 4개

상세도 (Detail):
├─ 엔티티: 100개
├─ 끊김: 0 ✅
└─ 폐곡선 예상: 6개

합계: 26개 폐곡선 예상 ✅

실행 시간: ~3초

3단계: 폐곡선 검증

명령:

node src/build.mjs gasiseol --loops

예상 출력:

[gasiseol] 폐곡선 추출 & 검증...

평면도:
├─ 루프 1: 사각형 (4개 꼭짓점) — 기둥 단면
├─ 루프 2: 사각형 (4개 꼭짓점) — 보 단면
├─ 루프 3: 직사각형 (4개 꼭짓점) — 기초
└─ 루프 4: 복합 도형 (8개 꼭짓점) — 안전장치

검증:
✅ 루프 1: 닫혀있음, 자기교차 없음
✅ 루프 2: 닫혀있음, 자기교차 없음
✅ 루프 3: 닫혀있음, 자기교차 없음
✅ 루프 4: 닫혀있음, 자기교차 없음

종단면: 8개 루프 ✅
횡단면 A: 4개 루프 ✅
횡단면 B: 4개 루프 ✅
상세도: 6개 루프 ✅

합계: 26개 루프 모두 PASS ✅

실행 시간: ~5초

4단계: IR 생성

명령:

node src/build.mjs gasiseol

예상 출력:

[gasiseol] IR (중간 표현) 생성...

프로파일 변환:
├─ 평면도 → XY 평면 좌표
│  ├─ 기둥: 1개 (50mm × 50mm 단면)
│  ├─ 보: 2개 (50mm × 30mm 단면)
│  └─ 기초: 1개 (200mm × 200mm 단면)
│
├─ 종단면 → XZ 평면 좌표 (높이 정보)
│  ├─ 높이 범위: -1000mm ~ 15000mm
│  └─ 주요 높이: 0(기초), 5000(상부), 15000(난간)
│
├─ 횡단면 → 형태 검증
│  ├─ 폭 정보: 30000mm 일정
│  └─ 변화도: 직선 (extrude 가능)
│
└─ 조립 지시:
   ├─ 기둥: extrude 50×50 × 16000mm
   ├─ 보: loft 50×30 단면 (길이 50m)
   ├─ 기초: extrude 200×200 × 1000mm
   └─ 안전장치: union (기둥과 연결)

파일 생성:
├─ out/gasiseol.ir.json (123KB) ✅
│  └─ 검증: JSON 구문 정확
│
└─ PROGRESS.md 업데이트

실행 시간: ~8초

5단계: 3D 모델 생성 (EGModeler)

명령:

python src/run_egm.py gasiseol --export=out/gasiseol.obj

예상 출력:

[egm] EGModeler 3D 생성 시작...

IR 로드: out/gasiseol.ir.json ✅

명령 생성:
├─ extrude [기둥]: 50×50×16000
├─ extrude [보]: 50×30×50000
├─ extrude [기초]: 200×200×1000
├─ union [기둥-안전장치]
└─ union [전체]

모델 생성:
├─ 기둥 1: 정점 8개 → 면 12개 → 4800 mm³
├─ 기둥 2: 정점 8개 → 면 12개 → 4800 mm³
├─ 보 1: 정점 8개 → 면 12개 → 75000 mm³
├─ 보 2: 정점 8개 → 면 12개 → 45000 mm³
├─ 기초: 정점 8개 → 면 12개 → 40000 mm³
└─ 안전장치: 정점 12개 → 면 18개 → 12000 mm³

모델 검증:
├─ Manifold 체크: ✅ (모든 모서리 공유)
├─ 닫힌 면: ✅ (누수 없음)
├─ 정점: 52개
├─ 면: 78개
└─ 정점 중복 제거: 완료

파일 생성:
├─ out/gasiseol.obj (2.3 MB)
│  ├─ 면 데이터: 78개
│  ├─ 정점 수: 52개
│  └─ 검증: OBJ 형식 정확 ✅
│
└─ 렌더링 테스트
   ├─ Three.js 로드: ✅
   ├─ 메모리: ~45MB
   └─ 초기 렌더링: 200ms

실행 시간: ~3분

최종 결과:
✅ 3D 모델 완성 (닫힌 면, 검증됨)
✅ 웹 렌더링 준비 완료

6단계: 부피 검증

명령:

node src/measure.mjs gasiseol --ir     # IR 기준 부피
node src/measure.mjs gasiseol          # 모델 측정 부피

예상 출력:

[measure] IR 기준 부피 (의도)...

부재별 부피:
├─ 기둥 1 (50×50×16000): 40 m³
├─ 기둥 2 (50×50×16000): 40 m³
├─ 보 1 (50×30×50000): 75 m³
├─ 보 2 (50×30×45000): 67.5 m³
├─ 기초 (200×200×1000): 40 m³
└─ 안전장치 (추정): 12 m³

전체 IR 부피: 274.5 m³

---

[measure] 모델 측정 부피 (결과)...

Mesh 해석:
├─ 정점: 52개
├─ 면: 78개
├─ 부피 계산: 적분법 (Divergence Theorem)

부재별 측정:
├─ 기둥 1: 39.98 m³
├─ 기둥 2: 40.02 m³
├─ 보 1: 74.95 m³
├─ 보 2: 67.48 m³
├─ 기초: 40.01 m³
└─ 안전장치: 12.03 m³

전체 모델 부피: 274.47 m³

---

[validation] 검증...

부피 비교:
├─ IR 부피: 274.50 m³
├─ 모델 부피: 274.47 m³
├─ 차이: 0.03 m³
├─ 오차율: 0.011% ✅
└─ 기준 (< 0.5%): PASS ✅

기준값 저장:
└─ baselines/gasiseol.volumes.json
   {
     "timestamp": "2026-10-19T12:34:56Z",
     "irVolume": 274.50,
     "realVolume": 274.47,
     "errorPercent": 0.011,
     "status": "PASS",
     "parts": {
       "column_1": { "ir": 40, "real": 39.98, "error": 0.005 },
       "column_2": { "ir": 40, "real": 40.02, "error": 0.005 },
       "beam_1": { "ir": 75, "real": 74.95, "error": 0.007 },
       "beam_2": { "ir": 67.5, "real": 67.48, "error": 0.003 },
       "foundation": { "ir": 40, "real": 40.01, "error": 0.002 },
       "safety": { "ir": 12, "real": 12.03, "error": 0.025 }
     }
   }

실행 시간: ~4초

✅ 최종 검증

명령:

/validate --level=full

예상 출력:

[validate] 4단계 검증 시작...

Layer 1: 파일 존재
├─ out/gasiseol.obj ✅
├─ out/gasiseol.ir.json ✅
└─ baselines/gasiseol.volumes.json ✅

Layer 2: 스키마 검증
├─ OBJ 형식: ✅
├─ JSON 구조: ✅
└─ 필드 완성: ✅

Layer 3: 기능 검증
├─ 부피 오차 < 0.5%: ✅ (0.011%)
├─ Manifold 체크: ✅
├─ 정점 정상성: ✅
└─ 면 방향성: ✅

Layer 4: 회귀 검증
├─ 기준값과 비교: ✅ (정확히 일치)
├─ 과거 버전과 호환: ✅
└─ 성능 저하 없음: ✅

최종 결과: PASS ✅

소요 시간: 총 7분 50초

📋 전체 파일 목록 (변환 후)

out/
├── gasiseol.obj
│   ├─ 크기: 2.3 MB
│   ├─ 형식: Wavefront OBJ (텍스트)
│   ├─ 면: 78개
│   ├─ 정점: 52개
│   └─ 정점/면 비율: 2.3 (정상 = 2~3)
│
├── gasiseol.ir.json
│   ├─ 크기: 123 KB
│   ├─ 레벨: IR (중간 표현, 도면 독립)
│   └─ 내용: 프로파일 + 조립 지시
│
└── gasiseol-validation.json
    ├─ 크기: 12 KB
    ├─ 내용: 부피, 검증 결과
    └─ 생성: 단계 5 후

baselines/
└── gasiseol.volumes.json
    ├─ 크기: 5 KB
    ├─ 목적: 회귀 테스트
    └─ 업데이트: 매 성공 후

🚨 문제 시나리오

시나리오 1: 부피 오차 > 0.5%

증상:

모델 부피: 270.0 m³
IR 부피: 274.5 m³
오차: 1.64% ❌

원인 추적:

  1. node src/measure.mjs gasiseol --ir --verbose (IR 재계산)
  2. egm status (EGModeler의 Boolean 손실 확인)
  3. cat src/drawings/gasiseol.mjs | grep -A 30 "assemble" (조립 로직 재검토)

해결:

  • assemble() 함수에서 union 순서 변경
  • Boolean 손실 부분 재조정
  • 다시 실행: node src/build.mjs gasiseol && python src/run_egm.py gasiseol --export=out/gasiseol.obj

시나리오 2: 폐곡선이 닫혀있지 않음

증상:

루프 3: 자기교차 감지 ❌
루프 4: 끊김 = 2개 ❌

원인 추적:

  1. node src/build.mjs gasiseol --loops --debug (상세 분석)
  2. grep "crossing\|gap" out/gasiseol.debug.log (해당 루프 찾기)
  3. DXF 파일 재확인 (도면 손상 여부)

해결:

  • docs/2d-3d-conversion.md 교훈 #12 적용 (자기교차 제거)
  • 또는 교훈 #3 (끊김 수동 연결)
  • 필요시 DXF 파일 수정 후 재실행

시나리오 3: EGModeler 오류

증상:

python src/run_egm.py gasiseol --export=out/gasiseol.obj
오류: [egm] Command not found

확인:

which egm
# 또는
egm --version

해결:

  • EGModeler 설치 확인
  • PATH 환경 변수 확인
  • docs/2d-3d-conversion.md 교훈 #15 참고

📈 성능 기준

문제 없을 때 예상 시간:
├─ 파일 검증: 2초 ✅
├─ 뷰 분리: 3초 ✅
├─ 폐곡선 추출: 5초 ✅
├─ IR 생성: 8초 ✅
├─ 3D 생성: 3분 (병목)
├─ 부피 검증: 4초 ✅
└─ 전체: 7분 50초

느려지는 경우:
- 정점 수 > 100,000개 → 렌더링 최적화 필요
- OBJ 파일 > 10MB → 압축 필요

🎯 테스트 완료 기준

✅ 모든 단계 오류 없음
✅ 부피 오차 < 0.5%
✅ OBJ 파일 생성됨 (크기 > 0)
✅ Three.js에서 로드 가능
✅ 부재 정보 추출 가능
✅ 기준값 저장 완료

→ 웹 배포 준비 완료!

📝 테스트 체크리스트

□ Step 1: node src/run.mjs gasiseol
□ Step 2: node src/gaps.mjs gasiseol
□ Step 3: node src/build.mjs gasiseol --loops
□ Step 4: node src/build.mjs gasiseol
□ Step 5: python src/run_egm.py gasiseol --export=out/gasiseol.obj
□ Step 6a: node src/measure.mjs gasiseol --ir
□ Step 6b: node src/measure.mjs gasiseol
□ Step 7: /validate --level=full

모두 ✅ → 웹 배포 진행!