- CLAUDE.md: 프로젝트 전체 가이드 및 워크플로우 정의 - CONSIDERATIONS.md: 8개 영역 고려사항 분석 (기술, 품질, 배포, UX) - PROGRESS.md: 진행 상황 추적 및 체크리스트 - PLAN.md: 단계 5~9 상세 계획 및 에이전트 역할 정의 - 메모리: 프로젝트 정보 저장 다음: 단계 5 (에이전트/커맨드/스킬/훅 아이디어 제안)
517 lines
23 KiB
Markdown
517 lines
23 KiB
Markdown
# 파라메트릭 설계 층 — 설계 노트
|
||
|
||
2026-08-06 토론 정리 → **구현 완료.** 12절에 실제로 만든 것과 확인된 것을 적었다.
|
||
결정 근거는 11절(순서) · 8절 (b)(대조 등급) · 8.5절(UI).
|
||
|
||
- 절차는 [`2d-3d-process.md`](2d-3d-process.md), 노하우는 [`2d-3d-conversion.md`](2d-3d-conversion.md)
|
||
- 남은 일 전체는 [`roadmap.md`](roadmap.md)
|
||
|
||
---
|
||
|
||
## 0. 대전제 — 목표는 바뀌지 않았다
|
||
|
||
**이 저장소의 목표는 여전히 `2D DWG → 3D 모델 · IFC` 다.**
|
||
파라메트릭은 그 위에 얹는 층이지 대체가 아니다. 맨홀 도면 모델링은 **파이프라인을
|
||
검증하는 과정**이지 그 자체가 목적이 아니다.
|
||
|
||
순서를 헷갈리면 안 된다.
|
||
|
||
```
|
||
DWG 를 읽어 3D 를 세운다 ← 본체. 지금 여기
|
||
그 위에
|
||
치수를 파라미터로 뽑아 바꾼다 ← 이 문서
|
||
그 위에
|
||
바꾼 결과가 맞는지 평가한다 ← 설계 도구가 되는 지점
|
||
```
|
||
|
||
---
|
||
|
||
## 1. 사용자가 원하는 것
|
||
|
||
> 설계란, 비슷한 도면을 가져와 **새 환경에 맞게 치수를 바꿔보고**, 맞는지 검토하고,
|
||
> 다시 바꾸는 **반복 작업**이다.
|
||
|
||
그래서 필요한 것은 이것뿐이다.
|
||
|
||
```
|
||
값을 바꾼다 → 모델이 다시 만들어진다
|
||
```
|
||
|
||
**속도는 요구사항이 아니다.** 전체 재생성으로 충분하다(현재 28파트 1~2분).
|
||
실시간 프리뷰·부분 재생성은 있으면 좋은 것이지 필수가 아니다 — 우선순위 뒤로.
|
||
|
||
### 모델러에 패밀리 개념이 없다는 것
|
||
|
||
EGModeler 는 Revit 패밀리 같은 것이 없다. 매번 새로 만들어야 한다.
|
||
**그래도 된다 — 패밀리를 모델러가 아니라 우리가 들고 있으면 된다.**
|
||
|
||
| Revit | 우리 |
|
||
|---|---|
|
||
| 패밀리 `.rfa` | `assemble()` 조립 로직 |
|
||
| 타입 파라미터 | `params.json` |
|
||
| 인스턴스 배치 | egm 재생성 |
|
||
|
||
모델러는 **덤 렌더러**다. 형상 지능은 전부 IR 위쪽에 둔다. 지금 계층 구조가
|
||
이미 그렇게 생겼다 — `core/*` 는 3D 를 모르고 `emit/*` 만 모델러 사정을 안다.
|
||
|
||
---
|
||
|
||
## 2. D-Cubed 검토 결과 — 쓰지 않는다
|
||
|
||
Siemens PLM 의 CAD 부품 라이브러리. 원래 영국 D-Cubed Ltd, 2004년 UGS 인수.
|
||
|
||
| 컴포넌트 | 하는 일 |
|
||
|---|---|
|
||
| **2D DCM** | 2D 스케치 구속 솔버 (치수·평행·접선·동심) |
|
||
| **3D DCM** | 3D 어셈블리 구속 솔버 |
|
||
| AEM / CDM / PGM | 기구학 · 간섭검사 · 2D 프로파일 연산 |
|
||
|
||
SolidWorks · Solid Edge · NX 가 쓴다.
|
||
|
||
**쓰지 않기로 한 이유**
|
||
|
||
- CAD 벤더용 **상용 C++ SDK**. Siemens 와 개별 계약해야 하고 공개 가격이 없다
|
||
- 우리는 Node 다. FFI/N-API 바인딩을 직접 짜야 한다
|
||
- **무엇보다, 우리 문제에 구속 솔버가 거의 필요 없다** (아래 3절)
|
||
|
||
오픈소스 대안 (필요해질 때 검토)
|
||
|
||
| | 라이선스 | 비고 |
|
||
|---|---|---|
|
||
| **planegcs** (FreeCAD 스케처 솔버) | LGPL | Eigen 기반. WASM 포팅본이 있다고 알고 있으나 **미확인** |
|
||
| **SolveSpace `slvs`** | GPL-3 | C 라이브러리 + Python 바인딩. 2D·3D |
|
||
|
||
GPL 배포 조건 확인 필요. `vendor/acadrust-dwg` MPL-2.0 을 이미 다루고 있으니 낯선 문제는 아니다.
|
||
|
||
---
|
||
|
||
## 3. 구속 솔버가 필요 없는 이유
|
||
|
||
파라메트릭에는 성격이 다른 두 가지가 있다.
|
||
|
||
```
|
||
① 명시적 (history-based) 치수 = 프로그램의 입력. 값 → 계산 → 형상
|
||
OpenSCAD · Grasshopper · 그리고 지금 우리 파이프라인
|
||
② 변분/구속 (variational) 엔티티 + 구속을 선언하고 솔버가 위치를 찾는다
|
||
SolidWorks 스케치 · D-Cubed
|
||
```
|
||
|
||
요구사항은 **①로 거의 다 된다.** 증거가 이미 코드에 있다 —
|
||
`drawings/manhole1-trans.mjs` 의 외곽 챔퍼 중간 단면은 상수가 아니라 **식**이다.
|
||
|
||
```js
|
||
const t = (CH1 - CH0) / (CH2 - CH0);
|
||
const oY = Math.round(1350 + (1650 - 1350) * t); // 1550
|
||
const oZ = Math.round(-4907 + (-4608 + 4907) * t); // -4708
|
||
```
|
||
|
||
②가 필요한 것은 **관계가 순환할 때**다. "헌치가 두 면에 접하면서 벽 두께는
|
||
유지" 같은 것. 우리 형상은 거의 직각·45° 라 순환이 잘 안 생긴다.
|
||
|
||
**결론: 파라미터 + 식 + 위상 정렬로 시작한다. 솔버는 필요한 자리를 실제로
|
||
세어본 뒤에 결정한다.**
|
||
|
||
---
|
||
|
||
## 4. 핵심 구조 변경 — `params.json` 을 파이프라인 한가운데 끼운다
|
||
|
||
이 하나가 나머지를 거의 다 푼다.
|
||
|
||
```
|
||
지금 DWG ──build.mjs──→ IR ──→ 3D 치수가 코드 안에 박혀 있다
|
||
|
||
바꿀 것 DWG ──fit──→ params.json ──build──→ IR ──→ 3D
|
||
↑ 사람이 여기만 만진다 도면을 다시 안 본다
|
||
```
|
||
|
||
**빌드가 도면을 안 보는 것이 핵심이다.**
|
||
|
||
지금 `assemble()` 은 `loop('단 면 B-B', 2700, 2750)` 로 **치수를 도면 조회 키로**
|
||
쓴다. 사용자가 2700 을 3000 으로 바꾸면 그런 폐곡선이 없어 예외가 난다.
|
||
도면에 묶여 있는 한 파라메트릭이 성립하지 않는다.
|
||
|
||
```
|
||
① fit 도면에서 값을 뽑아 params.json 을 쓴다. 출처까지 기록
|
||
② build params.json 만 읽어 IR 을 만든다. 도면 없이도 돈다
|
||
```
|
||
|
||
부수 효과가 크다.
|
||
|
||
- `git diff params.json` 이 곧 "무엇을 바꿨나"
|
||
- 설계안 A/B/C 를 파일 셋으로 두고 나란히 비교
|
||
- **새 도면 설정 비용이 첫 도면 한 번으로 끝난다** — 변형은 도면을 안 읽는다
|
||
|
||
---
|
||
|
||
## 5. 파일을 셋으로 가른다
|
||
|
||
지금 `drawings/manhole1.mjs` 한 파일이 세 가지를 섞고 있다.
|
||
|
||
```
|
||
types/전력구_박스.mjs 조립 로직. 파라미터를 받는다 ← 패밀리
|
||
params/맨홀1.json 그 도면에서 뽑은 값 ← 타입 파라미터
|
||
drawings/manhole1.mjs DWG 읽기 설정 (레이어·앵커·기준점) ← 추출 규칙
|
||
```
|
||
|
||
**"비슷한 도면 가져와 치수만 바꾼다" = 같은 type + 다른 params.json.**
|
||
|
||
```sh
|
||
cp params/맨홀1.json params/신규현장.json
|
||
# 구체_외폭 3800 → 4200, 토피 2957 → 3500 수정
|
||
node src/build.mjs --params 신규현장 # 도면 안 읽는다
|
||
```
|
||
|
||
`src/core/*` 와 `src/ir.mjs` 에 도면 고유값이 들어가면 안 된다는 기존 경계는
|
||
그대로 유지된다. `types/*` 는 도면 고유값이 아니라 **부재 종류**다.
|
||
|
||
---
|
||
|
||
## 6. 파라미터 스키마 — 값만으로는 부족하다
|
||
|
||
```jsonc
|
||
{
|
||
"구체_외폭": { "v": 3800, "src": "measured", "from": "단면 C-C #1 폭" },
|
||
"벽두께": { "v": 400, "src": "design", "min": 300, "max": 600, "step": 50 },
|
||
"구체_내폭": { "expr": "구체_외폭 - 2*벽두께" },
|
||
"헌치": { "v": 150, "src": "design" },
|
||
"샤프트": [
|
||
{ "x": 2550, "저부Z": -3157, "정상Z": 0 },
|
||
{ "x": 13250, "저부Z": -3157, "정상Z": -39 }
|
||
]
|
||
}
|
||
```
|
||
|
||
넷이 필요하다.
|
||
|
||
| 항목 | 왜 |
|
||
|---|---|
|
||
| `expr` 식 | 파생값. 위상 정렬해 평가. 솔버 불필요 |
|
||
| `src` 출처 | `measured` 는 도면과 묶여 있다. 바꾸면 "도면과 다름" 경고 |
|
||
| `min`/`max`/`step` | 유효 범위. 검증이자 나중에 UI |
|
||
| **배열** | 치수만이 아니라 **개수**가 바뀐다. 샤프트 2→3, 환기구 없음 |
|
||
|
||
배열이 특히 중요하다. `manhole1-trans.mjs` 의 샤프트를 이미
|
||
`for (const s of shafts)` 로 짜놨다 — 그대로 파라미터로 올라간다.
|
||
|
||
### `src` 3분류가 도면과의 계약이다
|
||
|
||
```
|
||
measured 도면에서 뽑았다. 바꾸면 도면과 어긋난다 → 경고하되 막지는 않는다
|
||
design 사람이 정한다. 자유롭게 바꾼다
|
||
derived 식으로 나온다. 직접 못 바꾼다
|
||
```
|
||
|
||
기존 `datum.checks` 가 이미 이 자리를 갖고 있다. 확장하면 된다.
|
||
|
||
---
|
||
|
||
## 7. 설계 도구가 되는 지점 — 규칙과 물량
|
||
|
||
치수를 바꾸는 것보다 **바꾼 결과를 즉시 평가하는 것**이 설계다.
|
||
지금 파이프라인에 없는 층이 이것이고, 실제 가치는 여기서 나온다.
|
||
|
||
```
|
||
rules.mjs 벽두께 ≥ 최소, 내공 높이 ≥ 2,100, 피복 ≥ 기준,
|
||
헌치가 부재보다 크지 않은가, 샤프트 보어가 벽 안에 있는가,
|
||
개구부 최소 치수, 케이블랙 이격
|
||
quantity.mjs 콘크리트 m³ · 굴착 m³ · 거푸집 m² · 되메움
|
||
```
|
||
|
||
**물량은 이미 공짜로 나온다.** 오늘 OBJ 를 발산 정리로 재서 0.0003% 오차로
|
||
검증했다. 그 코드가 그대로 물량 산출이다.
|
||
|
||
```
|
||
안 A 구체 3,800×4,600 콘크리트 100.5 m³ ✓ 전 규칙 통과
|
||
안 B 구체 4,200×4,600 콘크리트 108.2 m³ ✓
|
||
안 C 구체 4,200×4,600 · 벽 300 — ✗ 최소 벽두께 미달
|
||
```
|
||
|
||
이 표가 나오는 순간 도구가 쓸모를 얻는다.
|
||
|
||
---
|
||
|
||
## 8. 위험한 곳
|
||
|
||
**(a) 파라미터가 형상 위상(topology)을 바꾼다.**
|
||
벽두께를 키우다 헌치보다 커지면 꼭짓점 수가 달라져 loft 대응이 깨진다.
|
||
`validateIR` 의 꼭짓점 수 검사가 여기서 걸린다(교훈 #16). `min`/`max` 로
|
||
미리 막고, 걸리면 명확한 메시지를 낸다.
|
||
|
||
**(b) 프로파일을 파라미터로 "생성"하면 도면의 실제 형상을 잃는다.**
|
||
|
||
```
|
||
지금 loop('단 면 B-B', 2700, 2750).ring 도면이 준 실제 링
|
||
이후 box(p.스터브_외폭, p.스터브_외고, p.헌치) 파라미터로 만든 링
|
||
```
|
||
|
||
B-B 내부 링에 있는 **50mm 보도 단차** 같은 자잘한 것이 생성기로 재현이 안 되면
|
||
조용히 빠진다. **fit 단계에서 "이 링이 생성기로 재현되는가"를 대조**해야 한다.
|
||
그게 도면과의 마지막 끈이다.
|
||
|
||
#### 결정 (2026-08-06) — 3등급으로 기록한다
|
||
|
||
완전일치를 요구하지 않는다. `fit` 이 링마다 등급을 매겨 `params.json` 에 남긴다.
|
||
|
||
```
|
||
exact 꼭짓점 집합이 mm 단위로 일치 → 파라미터로 완전 대체
|
||
tolerant bbox · 면적 · 꼭짓점 수 일치 → 경고를 남기고 파라미터 사용
|
||
개별 점은 ±ε
|
||
opaque 생성기로 재현 불가 → 파라미터화하지 않는다.
|
||
도면 링을 **리터럴로 얼려** params 에 박는다
|
||
```
|
||
|
||
`opaque` 가 핵심이다. "재현 못 하면 파라미터화 안 한다"가 아니라 **"재현 못 하는
|
||
링은 값으로 얼려 넣는다"** (`src: "measured"` + `ring` 배열). 그러면
|
||
|
||
- 4절 불변식(build 가 도면을 안 본다)이 안 깨진다
|
||
- 50mm 보도 단차 같은 것이 조용히 빠지지 않는다
|
||
- 그 링은 **못 바꾸는 것**일 뿐이고, 그게 정직하다
|
||
|
||
등급 분포가 곧 "이 도면이 얼마나 파라메트릭한가" 의 척도가 된다. `opaque` 가
|
||
많으면 생성기가 부족한 것이지 도면이 이상한 게 아니다.
|
||
|
||
**(c) 재생성하면 모델러의 UID 가 전부 바뀐다.**
|
||
이름·색은 우리가 다시 붙이니 괜찮지만 사용자가 모델러에서 직접 손댄 것은 날아간다.
|
||
**"모델러에서 편집하지 않는다"를 규칙으로 못 박아야 한다.** 편집은 params 에서만.
|
||
|
||
**(d) 추출 설정은 여전히 도면당 반나절이다.**
|
||
4절의 fit/build 분리가 이 비용을 **첫 도면 한 번**으로 묶어준다. 그래서 구조
|
||
변경이 이 위험까지 같이 없앤다.
|
||
|
||
---
|
||
|
||
## 8.5. 모델러 밖 UI — 값을 바꾸고 "갱신"
|
||
|
||
요구사항으로 확정(2026-08-06). 파이프가 이미 CLI 단계 사슬이라 **새 아키텍처가
|
||
아니라 얇은 껍데기**다.
|
||
|
||
### 1단계는 이미 있다 — 읽기 전용 뷰어 (`report.mjs`)
|
||
|
||
`node src/report.mjs <도면>` → `out/<도면>.html`. 의존성 없는 한 장짜리다.
|
||
뷰별 링을 SVG 로 그리고 자기교차·꼭짓점 수·원·IR·부피를 같이 보여준다.
|
||
|
||
**만든 날 바로 값을 했다** — 맨홀 #2 의 부피가 2배로 나온 원인(`mh.outer`
|
||
자기교차)을 숫자로 찾는 데 반나절 걸렸는데, 그림에서는 빨간 X 두 개로 즉시
|
||
보인다(교훈 #18).
|
||
|
||
`build.mjs` 와 **같은 `projectViews()`** 를 쓴다. 뷰어가 자기 변환을 따로 갖고
|
||
있으면 보여주는 것과 조립되는 것이 갈라진다 — **거짓말하는 뷰어는 없는 것보다
|
||
나쁘다.**
|
||
|
||
편집은 아직 안 된다. `params.json` 이 없어서 편집할 대상이 없다.
|
||
|
||
```
|
||
UI(로컬 웹앱) → params.json → build(도면 안 봄) → IR → emit/egm → run_egm.py → 모델러
|
||
↘ three.js 프리뷰 (9절·나중)
|
||
```
|
||
|
||
- **입력 위젯이 공짜로 나온다.** 6절의 `min`/`max`/`step`/`src` 가 그대로
|
||
슬라이더·범위·경고다. 그러라고 스키마를 그렇게 잡았다.
|
||
- **갱신 버튼이 검증을 태워야 도구가 된다.** 단순 실행이면 폼이고,
|
||
`validateIR` → `rules.mjs`(7절) → `measure.mjs` 기준선까지 통과 못 하면
|
||
거부하면 설계 도구다. 여기가 값이 나오는 지점이다.
|
||
- 재생성 1~2분. 버튼 누르고 기다리는 UX 로 견딘다(1절).
|
||
|
||
못 박을 것 둘.
|
||
|
||
```
|
||
갱신 = 씬 초기화 포함. Esc → SelAll → Delete → Esc. `!Cancel` 은 쓰지 않는다
|
||
모델러에서 직접 편집 금지. 8절 (c) — 갱신하면 UID 가 전부 바뀐다. 편집은 params 에서만
|
||
```
|
||
|
||
**순서상 위치: 10절 1~4 뒤.** 지금 만들면 편집할 `params.json` 이 없다.
|
||
|
||
---
|
||
|
||
## 9. 나중에 (필수 아님)
|
||
|
||
- **브라우저 프리뷰** — IR 은 이미 도구 중립이다. three.js + CSG(`manifold-3d` WASM 이
|
||
빠르다고 알고 있으나 **미확인**)로 모델러 없이 확인. 속도가 요구사항이 아니므로 뒤로.
|
||
- **선택 재생성** — 파라미터 → 파트 의존 그래프로 바뀐 파트만 다시. 마찬가지로 뒤로.
|
||
- **구속 솔버** — 1~5 를 하고 나서 정말 필요한 자리를 세어본 뒤 결정.
|
||
- **모델 → 도면 역방향** — DWG writer 가 필요하다. 현재 범위 밖.
|
||
|
||
---
|
||
|
||
## 10. 1차 목표 — **전부 됐다**
|
||
|
||
```
|
||
✔ 1. params.json 스키마 확정 v / expr / src / grade / min·max·step / 배열
|
||
✔ 2. build.mjs 를 fit / build 로 분리 --params 면 도면을 아예 안 읽는다
|
||
✔ 3. manhole1 을 params 로 전환 egm 명령 목록이 **바이트 단위로 동일**했다
|
||
✔ 4. 파라미터 바꿔 재생성 시연 본체_외폭 3800→4200, 종헌치 150→200
|
||
✔ 5. 물량 measure.mjs 가 재질별로 낸다
|
||
```
|
||
|
||
3번이 좋은 시험대다. `manhole1-trans.mjs` 에 이미 이름이 뚜렷한 값들이 있다 —
|
||
**챔퍼 200×200, 헌치 150×150, 벽두께 200, 보어 Ø900, 칼라 900, 토피 2,957.**
|
||
|
||
5번은 [`../src/measure.mjs`](../src/measure.mjs) 로 **먼저 끝났다.** 실측·기준선
|
||
대조·재질별 물량이 돈다. 남은 것은 굴착·거푸집·되메움 같은 파생 물량이다.
|
||
|
||
---
|
||
|
||
## 11. 순서 결정 (2026-08-06)
|
||
|
||
**본체(A)를 좁혀서 먼저, 그 다음 파라메트릭(B).** 근거 셋.
|
||
|
||
**① 인스턴스 1개로 추상화를 얼리게 된다.**
|
||
5절의 가치 명제는 "같은 type + 다른 params" 인데 도면이 하나뿐이라 type/params
|
||
경계를 **검증할 두 번째 인스턴스가 없다.** 맨홀 #2(격실·환기구·침사조)가 스키마에
|
||
요구할 것 — 배열이 아니라 *선택적 존재*("환기구 없음"), 중첩 격실, 구간별 단면
|
||
배정표 — 은 지금 `manhole1-trans` 3파트에 안 보인다.
|
||
|
||
재작업이 대칭이 아니다. A 먼저 → `assemble()` 본문이 늘어 변환 비용이 커지지만
|
||
그 변환은 10절 3번 그 자체다(어차피 한 번은 한다). B 먼저 → 스키마를 **두 번** 짠다.
|
||
|
||
**② 8절 (b) 결정이 A 에 의존한다.**
|
||
"어디까지 엄격하게 대조하나"는 *불규칙한 링이 몇 개냐*에 달렸다. 지금 아는
|
||
사례(B-B 내부 50mm 보도 단차, C-C 외곽 샤프트 융합, 개구 기호로 정점 8,
|
||
케이블랙 정점 114)는 전부 `manhole1-trans` 밖에서 나왔다. 등급 기준은 정했지만
|
||
`ε` 와 등급 분포는 표본을 세어본 뒤에 확정한다.
|
||
|
||
**③ CIRCLE 파서가 B 의 전제다.**
|
||
`manhole1-trans.mjs` 의 `BORE_R = 450` 은 원본 엔티티에서 눈으로 읽어 손으로 적은
|
||
값이다. 8절 (b) 가 말하는 "도면과의 마지막 끈"이 보어에는 **아예 없다.**
|
||
|
||
```
|
||
✔ 0. measure.mjs B 에서 유일하게 당겨온 항목(10절 5번).
|
||
앞으로 만드는 모든 파트의 회귀 검사가 된다
|
||
1. CIRCLE 파서 → circle() 헬퍼 손으로 적은 R450 을 대조로. Φ100 ×5 도 풀린다
|
||
2. manhole1-trans 를 본편으로 통합 기초·잡석 이관. 지금 반쪽 모델이 둘이다
|
||
3. 맨홀 #2 + 출구 스터브 파라미터 표본을 대표성 있게
|
||
4. → 10절 1~4
|
||
5. → 8.5절 UI
|
||
```
|
||
|
||
---
|
||
|
||
## 부록 — 2026-08-06 기준 현재 상태
|
||
|
||
**되는 것**
|
||
|
||
| | |
|
||
|---|---|
|
||
| `manhole1` | 11파트. 전이부는 X=250 계단 근사, **지붕 개구 없음**(결함) |
|
||
| `manhole1-trans` | 3파트. 스터브 + 챔퍼 전이 + 본체 + 종방향 헌치 + 샤프트 2기(Ø900 원형 보어) |
|
||
| 새 IR 연산 | `loft` (2단면, `Loft C=True`), `cylinder` (Z축 한정, `Cylinder S=True`) |
|
||
| 새 유틸 | `normalizeRing` — loft 꼭짓점 대응용. `addProfile` 이 자동 적용 |
|
||
| 검증 | 부피 대조 107.1425 실측 / 107.1422 기대 (0.0003%) |
|
||
| `measure.mjs` | OBJ 실측 · 기준선 회귀 · 재질별 물량. 기준선 `baselines/manhole1-trans.volumes.json` |
|
||
| CIRCLE | `circles(뷰, 지름, 레이어)`. 보어 R450 이 손으로 적은 수에서 도면 대조로 바뀌었다 |
|
||
|
||
**안 되는 것 / 남은 것**
|
||
|
||
```
|
||
맨홀 #2 (X 15,400~18,200) 챔버·격실·환기구·침사조. 제일 크다
|
||
출구 스터브 (X 18,200~19,200) 맨홀 #2 뒤라 그전에 맨홀을 해야 자리를 얻는다
|
||
기초·잡석 manhole1.mjs 에 있다. trans 로 옮기면 됨
|
||
Ø100 관통 5개 환기구 4 · 배수관 1. 평면도의 1개는 X=17,690 으로
|
||
맨홀 #2 영역이라 그 형상을 세운 뒤에 뚫는다
|
||
이음매 T 정점 열린 변 49개. 기하는 닫힘. IFC 갈 때 재검토
|
||
IFC 출력 emit/ifc.mjs 미구현
|
||
```
|
||
|
||
---
|
||
|
||
## 12. 구현 결과 (2026-08-06)
|
||
|
||
### 만든 것
|
||
|
||
| 파일 | 하는 일 |
|
||
|---|---|
|
||
| [`../src/params.mjs`](../src/params.mjs) | 스키마 · 식 평가(위상 정렬) · 검증 · 도면 이탈 감지 |
|
||
| [`../src/fit.mjs`](../src/fit.mjs) | 도면 → `params/<이름>.json`. 출처(`from`)와 원값(`fitted`)까지 |
|
||
| [`../src/rules.mjs`](../src/rules.mjs) | 규칙 13개. 위상 8(막는다) · 설계 5(경고) |
|
||
| [`../src/volume.mjs`](../src/volume.mjs) | IR 을 격자로 평가 — **모델러 없이** "의도" 부피 |
|
||
| [`../src/ui.mjs`](../src/ui.mjs) | 편집 + 갱신. `node src/ui.mjs manhole1` → `localhost:7331` |
|
||
| [`../src/core/pick.mjs`](../src/core/pick.mjs) | 도면 조회 도우미. **`fit()` 만 쓴다** |
|
||
|
||
### 확인된 것
|
||
|
||
```
|
||
파라미터 스칼라 49 (measured 38 · design 3 · derived 8) + 배열 1(샤프트)
|
||
링 11 (opaque 8 · exact 2 · tolerant 1)
|
||
규칙 13개 중 위반 0
|
||
기하 불변 전환 전후 egm.json **바이트 동일**
|
||
도면 없이 views.json 을 치운 채 --params 로 빌드 → 역시 바이트 동일
|
||
```
|
||
|
||
### 8절 (b) 결정이 실제로 어떻게 쓰였나
|
||
|
||
`opaque` 8개가 결정의 값을 증명한다. B-B 내부(50mm 보도 단차), C-C 내부(헌치),
|
||
E-E 외곽(23꼭짓점 오목 윤곽) 같은 것은 파라미터로 재현이 안 된다. 좌표째 얼려
|
||
넣으니 **도면 없이도 형상이 그대로** 나오고, 자잘한 형상이 조용히 빠지지도 않는다.
|
||
그 링들은 못 바꿀 뿐이고, 그게 정직하다.
|
||
|
||
`exact` 2개는 개구부다 — 개구 기호의 네 모서리라 직사각형으로 완전히 재현된다.
|
||
|
||
### 규칙이 폼과 도구를 가른다
|
||
|
||
```
|
||
✗ 맨홀 내벽이 뒤집혔다: 16900 ≥ 16700 (벽두께 1500)
|
||
(맨홀 벽두께가 절반을 넘으면 내부가 사라진다)
|
||
```
|
||
|
||
벽두께를 1,500 으로 바꾸면 **빌드가 거부한다**(exit 1). 모델러까지 가서 비틀린
|
||
면으로 만나는 것보다 훨씬 싸다. 설계 규칙(내공 높이·토피·최소 벽두께)은 경고만
|
||
하고 사람이 판단한다.
|
||
|
||
### 도면 이탈은 막지 않고 남긴다
|
||
|
||
```
|
||
⚠ 도면에서 뽑은 값이 바뀌어 있다 — 이 모델은 원 도면과 다르다
|
||
본체_외폭 도면 3800 → 지금 4200 C-C 구체 외폭
|
||
```
|
||
|
||
설계를 바꾸는 게 이 층의 목적이니 막지 않는다. 다만 "도면대로 만든 모델"인 척하게
|
||
두면 안 된다.
|
||
|
||
### 그림 위에서 치수를 고친다
|
||
|
||
`render.mjs --dims` 가 **파라미터를 가리키는 치수선**을 렌더에 얹는다. 2D 도면이
|
||
치수를 적어 형상을 증명하듯이, 우리 렌더도 "이 길이가 이 파라미터다" 를 그림에서
|
||
바로 보이게 한다.
|
||
|
||
```
|
||
span 두 점 사이 **길이** 연장선 + 치수선 + 이름 상자
|
||
level 한 좌표의 **위치** 그 자리를 가로지르는 선 + 이름 상자
|
||
```
|
||
|
||
둘로 나눈 이유가 있다. 파라미터의 절반은 길이가 아니라 **좌표**다(`본체_상단Z`
|
||
같은 표고). 그런 것을 억지로 길이로 그리면 거짓말이 된다 — 표고선으로 그린다.
|
||
|
||
같이 나오는 `model-<축>.dims.json` 이 각 라벨의 자리를 **캔버스 비율**로 담는다.
|
||
UI 가 그 자리에 `<input>` 을 얹으므로 **그림에서 값을 고칠 수 있다**. 비율이라
|
||
창 크기가 바뀌어도 따라간다. 표와 그림의 입력칸은 서로 동기화된다.
|
||
|
||
라벨이 많으면 겹치므로 위에서부터 훑으며 겹치는 것을 아래로 민다. 치수선 자체는
|
||
안 움직인다 — 라벨만.
|
||
|
||
**47개**가 그림에 올라간다. 빠진 둘(`커터여유`·`면겹침_여유`)은 형상이 아니라
|
||
수치 여유값이라 패널에만 둔다.
|
||
|
||
### UI 는 정말로 얇았다
|
||
|
||
파이프가 이미 CLI 단계 사슬이라, UI 가 한 일은 `params.json` 편집 + 그 사슬을
|
||
순서대로 돌리는 것뿐이다. 갱신 사슬:
|
||
|
||
```
|
||
build --params → emit → run_egm --reset --export → measure --ir → render --dims
|
||
```
|
||
|
||
`--reset` 이 필수다. 안 비우면 갱신할 때마다 객체가 쌓여 `modelCount` 대조가
|
||
무의미해진다. 다만 **연달아 여러 번 하면 안 된다** — 초기화를 10번쯤 반복했더니
|
||
모델러 파이프가 죽었다. 갱신 1회당 1번이면 문제없다.
|
||
|
||
`min`/`max`/`step` 이 그대로 입력 위젯이 됐고, `src` 는 태그, `fitted` 는 변경
|
||
표시가 됐다. **그러라고 6절에서 그렇게 설계했던 것이 그대로 맞았다.**
|
||
|
||
### 남은 것
|
||
|
||
- **맨홀 #2 부피 9.32 손실** — 우리 IR 은 맞고(74.68) 모델러가 흘린다(65.36).
|
||
원인은 면으로만 맞닿은 union (교훈 #19). 제대로 된 해법은 맨홀을 **수평 단면에서
|
||
Z 로 쌓는 것** — 조각이 Z 로 진짜 겹치고 평면 헌치도 같이 따라온다
|
||
- 외부 헌치 5개 (평면 좌표 확정, Z 구간 미확정)
|
||
- `quantity.mjs` — 굴착·거푸집·되메움 같은 파생 물량
|