Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
38854cbe4c | ||
|
|
7d36c4b64a | ||
|
|
ef596650cc | ||
|
|
fc520ec03d | ||
|
|
b2bebe47eb | ||
|
|
d740406a8c | ||
|
|
f51865c57b | ||
|
|
c9e1cc6eaa | ||
|
|
7182b6cbb4 | ||
|
|
bff1502ecf | ||
|
|
1fda705b75 | ||
|
|
c7acfccd51 | ||
|
|
7c5f129712 | ||
|
|
3bd2340609 | ||
|
|
d22c5008f0 | ||
|
|
54c855ab1a | ||
|
|
2668f17bf2 | ||
|
|
9d357de4d1 | ||
|
|
364b329c54 | ||
|
|
87b445965b | ||
|
|
a0b0929e13 | ||
|
|
5fec2743cb | ||
|
|
3d0d484524 | ||
|
|
2b26b7c095 | ||
|
|
fb7b4b021b | ||
|
|
370bd3d7cd | ||
|
|
42316104df | ||
|
|
da7b13a568 | ||
|
|
2e0bfb6fc8 | ||
|
|
3922b330d5 | ||
|
|
0c23173a1a | ||
|
|
a0ec74b09b | ||
|
|
7efe9097ce | ||
|
|
91c4a4ad63 | ||
|
|
bc91a8166f | ||
|
|
a68e4a0366 | ||
|
|
5856cfb423 | ||
|
|
a2d0d6057f | ||
|
|
b75f3d4855 | ||
|
|
a282618d90 | ||
|
|
e9d79957c8 | ||
|
|
9ae6cf0945 | ||
|
|
fa7d0032c3 | ||
|
|
bb2af4bdf5 | ||
|
|
7b9de649e5 | ||
|
|
89ebf852a9 | ||
|
|
81fe1f1549 | ||
|
|
e3c9ad0953 | ||
|
|
bac087ce63 | ||
|
|
d15b237100 | ||
|
|
e6869d17be | ||
|
|
06220fa312 | ||
|
|
3800a75b78 | ||
|
|
5e64a4f2ed | ||
|
|
51a36669a8 | ||
|
|
9f152fef90 | ||
|
|
914e3dbda8 | ||
|
|
ba71911edc | ||
|
|
25a4a84138 | ||
|
|
74de932eb9 | ||
|
|
34959f5b4e | ||
|
|
a4c7bcabcf | ||
|
|
a17c9ebbb4 | ||
|
|
079748e5e7 | ||
|
|
66e7d4d90d | ||
|
|
1da8dd74e2 | ||
|
|
8361487b6b | ||
|
|
d7714f7ef2 | ||
|
|
f4311d7f95 | ||
|
|
603066f370 | ||
|
|
a5cc458252 | ||
|
|
b06bf368b6 | ||
|
|
e00e43ca61 | ||
|
|
59c2607418 | ||
|
|
9835fb42b3 | ||
|
|
4b8b80ae97 | ||
|
|
fc0370883f | ||
|
|
41b3165543 | ||
|
|
886347471e | ||
|
|
4ef3650454 | ||
|
|
80e5302192 | ||
|
|
a025a61209 | ||
|
|
4eb92d381d | ||
|
|
372d759eb7 | ||
|
|
55b679932e | ||
|
|
796a267205 | ||
|
|
6b969f4a7c | ||
|
|
4b02dde153 | ||
|
|
4e3950eb67 | ||
|
|
7e3ba306f3 | ||
|
|
5bdd360235 | ||
|
|
e1f85e5d86 | ||
|
|
842d372312 | ||
|
|
a14497a771 | ||
|
|
08b1138c96 | ||
|
|
a756fd11ce | ||
|
|
d3440e9158 | ||
|
|
686d87bad9 | ||
|
|
804bd5c8f8 | ||
|
|
d2d679a8e6 | ||
|
|
aaa9f57908 | ||
|
|
61ef001034 | ||
|
|
4b51ef186f | ||
|
|
786c4a73dd | ||
|
|
e5134cdb68 | ||
|
|
ea36df58cc | ||
|
|
3aa7cc06b6 | ||
|
|
7fab9b6685 | ||
|
|
b425a6010b | ||
|
|
43edcdc3c5 | ||
|
|
986418024a | ||
|
|
67bebe5ec2 | ||
|
|
fbc315fdba | ||
|
|
8f75c6dc9f | ||
|
|
5c2b23211e | ||
|
|
789f62adf0 | ||
|
|
18524460e8 | ||
|
|
929f8eb4a2 | ||
|
|
5af88a511e | ||
|
|
1d31d2f3a9 | ||
|
|
ad73ddec2b | ||
|
|
b1b2ad1ddb | ||
|
|
6cbda0e126 | ||
|
|
36b26209df |
No files matched your search
@@ -12,3 +12,6 @@ __pycache__/
|
||||
*.zip
|
||||
pierzainer_ground/data/cache/
|
||||
pierzainer_ground/data/output/**/cache/
|
||||
backup/
|
||||
verify/
|
||||
도면추출/output/
|
||||
@@ -1,6 +1,14 @@
|
||||
# PIERZAINER · PIER & ABUT
|
||||
|
||||
교각 Excel을 읽어 형상을 생성하고 원도면 기반 지반면·위성사진·2D 지도를 함께 표시하는 프로젝트입니다.
|
||||
교각·교대 Excel을 읽어 형상과 철근배근을 생성하고 원도면 기반 지반면·위성사진·2D 지도를 함께 표시하는 프로젝트입니다.
|
||||
|
||||
## 현재 작업 상태 (2026-11-05 확인)
|
||||
|
||||
- 현재 로컬 작업 브랜치는 `master`이며 제품 코드 기준 커밋은 `91c4a4a`입니다. 아래 11월 2일 복구 기록은 당시 이력입니다.
|
||||
- 교대 ② 형상계획 카드 6개와 ③ 철근배근 6개 부재(받침블럭·벽체·흉벽/브라켓·확대기초·날개벽·접속슬래브)가 구현되어 있습니다.
|
||||
- A1 표본으로 ③ 입력 재계산·삽도/3D 표시·철근 선택·파일 다운로드·새 페이지 저장 복원을 검증했습니다. 설계 미결 사항과 다른 입력의 동작은 별도 확인 대상입니다.
|
||||
- 최신 진행 기록은 `../../context-migration/컨텍스트_2026-11-03_교각_교대_진행상황.md`, 남은 항목은 `../../context-migration/OPEN_미해결목록.md`에서 관리합니다.
|
||||
- 로컬 `origin/master` 추적 정보 대비 89커밋 앞선 상태였습니다. 실제 원격은 조회하지 않았습니다. 브랜치 전환이나 이력 변경 전에 현재 상태를 확인하세요.
|
||||
|
||||
## 실행
|
||||
|
||||
@@ -11,19 +19,45 @@ npm run dev -- --host 127.0.0.1 --port 5173
|
||||
|
||||
브라우저에서 http://127.0.0.1:5173/ 을 엽니다. 랜딩페이지의 Excel 가져오기와 실제 교량 샘플 선택을 사용합니다.
|
||||
|
||||
랜딩페이지의 **도면 불러오기**를 누르면 프로그램 내부의 도면추출 팝업이 열립니다. DWG 폴더를 선택하고 자동 추출을 시작하면 진행 로그와 결과가 팝업에 표시됩니다. 결과의 **교각 불러오기**로 바로 Excel 인식·형상 생성 단계에 연결하거나 **Excel 저장**으로 파일을 받을 수 있습니다. 원래 추출 엔진은 화면 없이 실행하며 미확정 값은 검토 대상으로 유지합니다.
|
||||
|
||||
결과는 프로젝트의 `도면추출/output/작업ID/`에 저장합니다. 선택한 원본 도면 폴더는 수정하지 않습니다. 팝업을 닫아도 추출은 계속되며 다시 열어 결과를 확인할 수 있습니다.
|
||||
|
||||
배포 빌드를 로컬에서 실행하려면 `npm run build` 후 `npm run preview -- --host 127.0.0.1`을 사용합니다. 도면추출은 이 PC의 Windows 로컬 서버와 포함된 `도면추출/app` 엔진을 사용하므로, `dist`만 올린 정적 웹사이트에서는 추출을 실행할 수 없습니다.
|
||||
|
||||
## 유지하는 폴더
|
||||
|
||||
- `src/`, `index.html`: 실제 교각 프로그램
|
||||
- `랜딩페이지/`: 랜딩 화면과 지도 포함 통합 샘플 12개
|
||||
- `pierzainer_ground/`: 지반 생성 프로그램, 원본 자료, 최종 지반 JSON 및 재현에 필요한 데이터
|
||||
- `도면추출_연동패키지_20261102/`: 도면 추출 프로그램과 교각 샘플 Excel
|
||||
- `public/`: 프로그램 리소스 및 기본 Excel 샘플
|
||||
- `tests/`, `scripts/`, `verify/`: 자동 검사와 유지보수 스크립트
|
||||
- `도면추출/`: 도면 추출 프로그램과 교각 샘플 Excel (기본 P1 샘플 포함)
|
||||
- `tests/`, `scripts/`, `verify/`: 현재 교각·Excel·지도 기능의 자동 검사와 유지보수 도구
|
||||
|
||||
`node_modules/`, `dist/`, `.verify/`, 지반 `cache/`는 실행·검증 중 재생성되는 파일이며 Git에 추가하지 않습니다.
|
||||
|
||||
## 2026-11-02 혼합 파일 복구
|
||||
## 검증
|
||||
|
||||
```bash
|
||||
npm test -- --maxWorkers=2
|
||||
npm run build
|
||||
```
|
||||
|
||||
A1 화면 검증 스크립트는 `scripts/verify-abut-workflow.cjs`입니다. 개발 서버와 별도 프로필 Chrome의 로컬 CDP 포트(기본 9444)가 필요합니다.
|
||||
|
||||
현장타설 실배근의 현행 UI 검증은 `node scripts/verify-cast-rebar.cjs`를 사용합니다. Windows Chrome 사용 시 Windows Node로 실행합니다. 샘플 Excel에서 9개 교각·기초 조합을 생성하고 실제 주철근/횡철근/커플러 행·삽도·입력 재생성·불일치 경고·재료표·파일 저장/새 페이지 복원·헤더 3개 폭을 검사합니다. 결과는 `.verify/cast-rebar-20261106/`에 저장합니다. `verify-unified-input.cjs`는 실배근 연결 전 통합 입력 단계의 검증이고, `verify-cast-input.cjs`와 `verify-cast-detail.cjs`는 통합 전 분리 카드 선택자를 사용한 과거 검증 스크립트입니다.
|
||||
|
||||
```text
|
||||
node scripts/verify-abut-workflow.cjs <input.xlsx> <output-directory> <download-directory>
|
||||
```
|
||||
|
||||
Windows Chrome을 쓰면 Windows Node로 실행하고 입력·출력 경로도 Windows 경로 또는 WSL UNC 경로로 전달합니다. 결과 JSON·화면 캡처·SVG·프로젝트 표본은 `.verify/abut-workflow-20261105/`에 보관했습니다. `report.json`의 실행 결과와 범위를 확인하세요. 단순 재열기 검사는 같은 인자 뒤에 `--resume`을 붙일 수 있습니다.
|
||||
|
||||
## 2026-11-02 혼합 파일 복구 (당시 기록)
|
||||
|
||||
혼합 전 Pierzainer 커밋 `d6735a6`에서 로컬 브랜치 `recovery/pierzainer-20261102`를 만들었습니다. π형 Excel 인식, 전·후열 받침 수 불일치 허용, 랜딩페이지 샘플 연결을 포함합니다. 기존 ITAM 브랜치와 원격 기록은 변경하지 않았습니다.
|
||||
|
||||
복구본과 분리한 파일은 상위 `_recovery/20261102_mixed_projects/`에 보관했습니다. 기존 `master`는 ITAM 코드이므로 그 브랜치로 전환하면 화면과 파일이 다시 바뀝니다. 현재 복구 브랜치에서 작업하세요. 이 작업에서는 원격 push를 수행하지 않았습니다.
|
||||
당시 복구 기록에는 분리 파일을 상위 `_recovery/20261102_mixed_projects/`에 보관하고, 당시 `master`가 ITAM 코드였다고 적혀 있습니다. 2026-11-05 현재 로컬 `master`는 Pierzainer 코드(`91c4a4a`)이므로 과거 안내에 따라 복구 브랜치로 전환하지 마세요. 당시 복구 보관 경로의 현존 여부는 이번 작업에서 재확인하지 않았습니다. 이번 검증·기록 정리에서도 원격 push와 브랜치 전환은 수행하지 않았습니다.
|
||||
|
||||
## 정리 기준
|
||||
|
||||
실행에 필요한 코드·원본 도면·샘플 Excel·최종 지반 JSON은 유지합니다. 과거 개발용 도구와 옛 좌표 기준의 검증 파일은 정리했으며 백업 목록은 상위 `_recovery/20261103_cleanup/`에 있습니다.
|
||||
+110
-28
@@ -11,22 +11,27 @@
|
||||
<header class="top">
|
||||
<div class="brand">
|
||||
<strong>Pierzainer</strong>
|
||||
<span>교각 설계</span>
|
||||
<span id="project-line" class="proj">프로젝트 미지정</span>
|
||||
</div>
|
||||
<nav class="steps" aria-label="단계">
|
||||
<button id="nav-shape" class="step current" type="button" aria-current="step">① 형상 생성 <em id="step1-status">미생성</em></button>
|
||||
<button id="nav-plan" class="step" type="button">② 형상계획 <em id="step2-status">예정</em></button>
|
||||
<button id="nav-rebar" class="step" type="button">③ 철근배근 <em id="step3-status">예정</em></button>
|
||||
<button id="nav-quantity" class="step" type="button">④ 재료표 <em id="step4-status">예정</em></button>
|
||||
<button id="nav-shape" class="step current" data-label="① 형상 생성" aria-label="① 형상 생성" type="button" aria-current="step">① 형상 <em id="step1-status"></em></button>
|
||||
<button id="nav-plan" class="step" data-label="② 형상계획" aria-label="② 형상계획" type="button">② 계획 <em id="step2-status"></em></button>
|
||||
<button id="nav-rebar" class="step" data-label="③ 철근배근" aria-label="③ 철근배근" type="button">③ 배근 <em id="step3-status"></em></button>
|
||||
<button id="nav-drawing" class="step" data-label="④ 도면작성" aria-label="④ 도면작성" type="button">④ 도면 <em id="step-drawing-status"></em></button>
|
||||
<button id="nav-quantity" class="step" aria-label="⑤ 재료표·수량산출" type="button">⑤ 재료표·수량</button>
|
||||
</nav>
|
||||
<div class="actions">
|
||||
<span id="save-status" class="savest">저장 전</span>
|
||||
<button id="home-from-app" class="btn-s" type="button" hidden>홈으로</button>
|
||||
<button id="home-from-app" class="btn-s" type="button" hidden>홈</button>
|
||||
<button id="save-project" class="btn-s" type="button" disabled title="프로젝트 파일 저장 (Ctrl+S)">저장</button>
|
||||
<button id="open-import" class="btn-s" type="button">엑셀 불러오기</button>
|
||||
<button id="open-project" class="btn-s" type="button">프로젝트 열기</button>
|
||||
<button id="regen" class="btn-p" type="button" disabled>선택 교각 형상 생성</button>
|
||||
<details id="file-menu" class="file-menu">
|
||||
<summary class="btn-s">불러오기</summary>
|
||||
<div class="file-menu-items">
|
||||
<button id="open-import" class="btn small" type="button">엑셀 불러오기</button>
|
||||
<button id="open-project" class="btn small" type="button">프로젝트 열기</button>
|
||||
</div>
|
||||
</details>
|
||||
<button id="regen" class="btn-p" type="button" disabled>생성</button>
|
||||
<input id="project-file" type="file" accept=".json" hidden />
|
||||
</div>
|
||||
</header>
|
||||
@@ -43,7 +48,9 @@
|
||||
|
||||
<main class="grid" id="view-shape">
|
||||
<aside class="panel piers" aria-labelledby="pier-title">
|
||||
<p id="pier-title" class="lbl">교각 목록</p>
|
||||
<button id="project-ground-open" class="btn-o" type="button">프로젝트 지반모델</button>
|
||||
<p id="project-ground-status" class="pnote">모델 없음</p>
|
||||
<p id="pier-title" class="lbl">교각·교대 목록</p>
|
||||
<div class="pier-tools">
|
||||
<label>형식
|
||||
<select id="type-filter"></select>
|
||||
@@ -54,7 +61,7 @@
|
||||
<p id="pier-empty" class="muted">불러온 교각이 없습니다.</p>
|
||||
<p class="pnote">시트 1장 = 교각 1기입니다. 오류가 난 교각만 건너뛰고 나머지는 생성합니다.</p>
|
||||
|
||||
<section class="pier-input" aria-labelledby="input-title">
|
||||
<section id="pier-info" class="pier-input" aria-labelledby="input-title">
|
||||
<p id="input-title" class="lbl">입력값</p>
|
||||
<div class="pier-table-wrap">
|
||||
<table id="inputs-all" class="grid-table compact">
|
||||
@@ -71,6 +78,27 @@
|
||||
<button id="edit-regen" class="btn primary" type="button" disabled>다시 생성 · 변경 0</button>
|
||||
</section>
|
||||
</section>
|
||||
<section id="abut-panel" class="pier-input" hidden aria-labelledby="abut-panel-title">
|
||||
<p id="abut-panel-title" class="lbl"><span id="abut-panel-name"></span> 입력값 <span class="badge">입력</span>
|
||||
<button id="abut-panel-edit-toggle" class="btn small" type="button" aria-expanded="false">편집</button></p>
|
||||
<dl id="abut-panel-input" class="kv wide"></dl>
|
||||
<div id="abut-panel-editor" hidden>
|
||||
<div id="abut-panel-basic" class="edit-row"></div>
|
||||
<details class="abut-group">
|
||||
<summary>받침 값</summary>
|
||||
<div id="abut-panel-bearings" class="edit-row"></div>
|
||||
</details>
|
||||
<details class="abut-group">
|
||||
<summary>형상 (벽체·흉벽, 저판, 말뚝)</summary>
|
||||
<div id="abut-panel-shape" class="edit-row"></div>
|
||||
</details>
|
||||
<p id="abut-panel-msg" class="muted" aria-live="polite"></p>
|
||||
</div>
|
||||
<details class="abut-group">
|
||||
<summary>상세 (계산값)</summary>
|
||||
<dl id="abut-panel-summary" class="kv wide"></dl>
|
||||
</details>
|
||||
</section>
|
||||
</aside>
|
||||
|
||||
<section class="panel viewer" id="viewer-block" aria-labelledby="viewer-title">
|
||||
@@ -159,15 +187,44 @@
|
||||
|
||||
<main class="grid plan" id="view-plan" hidden>
|
||||
<aside class="panel piers" aria-labelledby="plan-pier-title">
|
||||
<p id="plan-pier-title" class="lbl">교각 목록</p>
|
||||
<p id="plan-pier-title" class="lbl">교각·교대 목록</p>
|
||||
<div class="phead" aria-hidden="true"><span>교각</span><span>변경</span></div>
|
||||
<ul id="plan-pier-items" class="pier-items"></ul>
|
||||
<p class="lbl abut-members-title">부재 · 교대</p>
|
||||
<ul id="abut-members" class="members abut-members" aria-label="교대 부재"></ul>
|
||||
<p class="lbl members-title">부재 · 5개</p>
|
||||
<ul id="members" class="members"></ul>
|
||||
</aside>
|
||||
|
||||
<div class="center-col">
|
||||
<div class="center-col workspace" id="plan-workspace" data-stage="plan">
|
||||
<div class="workspace-tools" aria-label="계획 화면 배치 조절">
|
||||
<div class="layout-switch" role="group" aria-label="모델과 입력창 배치">
|
||||
<button type="button" class="btn small" data-layout="stack" aria-pressed="true">상하</button>
|
||||
<button type="button" class="btn small" data-layout="side" aria-pressed="false">좌우</button>
|
||||
</div>
|
||||
<label class="model-height-control" for="plan-model-height"><span data-size-label>모델 높이</span>
|
||||
<input id="plan-model-height" type="range" min="180" max="560" step="20" value="400" />
|
||||
<output id="plan-model-height-value" for="plan-model-height">400 px</output>
|
||||
</label>
|
||||
<button id="plan-model-toggle" class="btn small" type="button" aria-expanded="true" aria-controls="slot-plan">모델 접기</button>
|
||||
<span class="layout-note muted small" aria-live="polite"></span>
|
||||
</div>
|
||||
<div class="viewer-slot" id="slot-plan"></div>
|
||||
<div class="workspace-splitter" role="separator" tabindex="0" aria-controls="slot-plan" aria-label="모델 크기 조절"></div>
|
||||
<div class="workspace-pane">
|
||||
<!-- ② 교대 부재 카드 (시안, 2026-11-03): the card of the row picked in 부재 · 교대, under the 3D view. -->
|
||||
<section id="abut-panel-plan" class="panel viewer abut-card" hidden aria-labelledby="abut-panel-plan-title">
|
||||
<div class="viewer-head">
|
||||
<h2 id="abut-panel-plan-title"><span id="abut-panel-plan-member">교량받침 · 받침블럭 · 솔플레이트</span> <span class="muted small" id="abut-panel-plan-name"></span></h2>
|
||||
</div>
|
||||
<div id="abut-panel-plan-bearings" class="edit-row"></div>
|
||||
<div id="abut-panel-plan-wing" class="edit-row"></div>
|
||||
<div id="abut-panel-plan-slab" class="edit-row"></div>
|
||||
<div id="abut-panel-plan-ground" class="edit-row"></div>
|
||||
<div id="abut-panel-plan-shape" class="edit-row abut-shape-view"></div>
|
||||
<div id="abut-panel-plan-footing" class="edit-row abut-shape-view"></div>
|
||||
<p id="abut-panel-plan-msg" class="muted" aria-live="polite"></p>
|
||||
</section>
|
||||
<section class="panel viewer" aria-labelledby="member-title">
|
||||
<div class="viewer-head">
|
||||
<h2 id="member-title">코핑</h2>
|
||||
@@ -218,6 +275,7 @@
|
||||
</section>
|
||||
</section>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<aside class="panel results" aria-labelledby="changes-title">
|
||||
<h2 id="changes-title">기본값 대비 변경</h2>
|
||||
@@ -227,6 +285,8 @@
|
||||
</aside>
|
||||
</main>
|
||||
|
||||
<main id="view-drawing" hidden aria-label="교각 일반도 작성"></main>
|
||||
|
||||
<main class="grid quantity" id="view-quantity" hidden>
|
||||
<aside class="panel piers" aria-labelledby="quantity-pier-title">
|
||||
<p id="quantity-pier-title" class="lbl">교각 목록</p>
|
||||
@@ -236,6 +296,7 @@
|
||||
</aside>
|
||||
<section class="panel viewer" aria-labelledby="quantity-title">
|
||||
<div class="viewer-head">
|
||||
<button id="quantity-back" class="btn-o" type="button">← ③ 철근배근</button>
|
||||
<h2 id="quantity-title">철근재료표</h2>
|
||||
<button id="quantity-export" class="btn-o" type="button">엑셀로 내보내기</button>
|
||||
<button id="quantity-print" class="btn-o" type="button">인쇄</button>
|
||||
@@ -252,35 +313,54 @@
|
||||
<ul id="rebar-tabs" class="members"></ul>
|
||||
<p class="pnote">형상은 ② 형상계획 기준입니다. 형상이 바뀌면 "형상 바뀜"으로 표시합니다.</p>
|
||||
</aside>
|
||||
<div class="center-col">
|
||||
<div class="center-col workspace review-workspace" id="review-workspace" data-stage="rebar">
|
||||
<div class="workspace-tools" aria-label="검토 공간 조절">
|
||||
<div class="layout-switch" role="group" aria-label="모델과 철근표 배치">
|
||||
<button type="button" class="btn small" data-layout="stack" aria-pressed="true">상하</button>
|
||||
<button type="button" class="btn small" data-layout="side" aria-pressed="false">좌우</button>
|
||||
</div>
|
||||
<label class="model-height-control" for="review-model-height"><span data-size-label>모델 높이</span>
|
||||
<input id="review-model-height" type="range" min="180" max="560" step="20" value="240" />
|
||||
<output id="review-model-height-value" for="review-model-height">240 px</output>
|
||||
</label>
|
||||
<button id="review-model-toggle" class="btn small" type="button" aria-expanded="true" aria-controls="slot-rebar">모델 접기</button>
|
||||
<button id="review-inputs" class="btn small" type="button">입력 보기</button>
|
||||
<button id="review-table" class="btn small" type="button">철근표 보기</button>
|
||||
<span class="layout-note muted small" aria-live="polite"></span>
|
||||
</div>
|
||||
<div class="viewer-slot" id="slot-rebar"></div>
|
||||
<div class="workspace-splitter" role="separator" tabindex="0" aria-controls="slot-rebar" aria-label="모델 크기 조절"></div>
|
||||
<div class="workspace-pane">
|
||||
<section class="panel viewer" aria-labelledby="rebar-title">
|
||||
<div class="viewer-head"><h2 id="rebar-title">철근표</h2></div>
|
||||
<div class="viewer-head"><h2 id="rebar-title">철근표</h2><button id="rebar-materials" class="btn-o" type="button">재료표·수량산출 보기</button></div>
|
||||
<p id="rebar-note" class="num"></p>
|
||||
<div id="rebar-table"></div>
|
||||
</section>
|
||||
</div>
|
||||
</div>
|
||||
<aside class="panel results" aria-labelledby="rebar-issues-title">
|
||||
<h2 id="rebar-issues-title">알림</h2>
|
||||
<ul id="rebar-issues" class="issues"></ul>
|
||||
<h2>검토 필요 (결정 대기)</h2>
|
||||
<ul class="issues">
|
||||
<li>Q-B5 B1·B3·B5·B7 다리 길이 (제안값 사용)</li>
|
||||
<li>Q-B6 B2·B6 이음 위치와 길이</li>
|
||||
<li>Q-C9 P4–B11 간섭: 무시로 결정, 문서 반영 필요</li>
|
||||
</ul>
|
||||
<h2>부재 검토</h2>
|
||||
<p id="review-summary" class="muted small" aria-live="polite"></p>
|
||||
<ul id="review-tasks" class="issues review-tasks"></ul>
|
||||
<section class="common" aria-labelledby="common-title">
|
||||
<p id="common-title" class="lbl">공통 설정</p>
|
||||
<h3 id="common-title">공통 설정</h3>
|
||||
<fieldset class="material-fields">
|
||||
<legend>재료</legend>
|
||||
<label class="mat">fck (MPa) <input id="mat-fck" type="number" step="any" /></label>
|
||||
<label class="mat">D 규격 강도 <select id="mat-grade-d"><option value="300" selected>SD300</option><option value="400">SD400</option><option value="500">SD500</option></select></label>
|
||||
<label class="mat">H 규격 강도 <select id="mat-grade-h"><option value="300">SD300</option><option value="400" selected>SD400</option><option value="500">SD500</option></select></label>
|
||||
<label class="mat">S 규격 강도 <select id="mat-grade-s"><option value="300">SD300</option><option value="400">SD400</option><option value="500" selected>SD500</option></select></label>
|
||||
<label class="mat">재료표 할증 (%) · 기본 0 가정 <input id="mat-waste" type="number" step="0.5" min="0" /></label>
|
||||
<p class="lbl">굽힘 내면반경 (× 철근 지름)</p>
|
||||
</fieldset>
|
||||
<fieldset class="material-fields">
|
||||
<legend>굽힘 내면반경 (× 철근 지름)</legend>
|
||||
<label class="mat">D16 이하 <input id="bend-small16" type="number" step="0.5" min="0.5" /></label>
|
||||
<label class="mat">D19–D25 <input id="bend-main25" type="number" step="0.5" min="0.5" /></label>
|
||||
<label class="mat">D29–D35 <input id="bend-main35" type="number" step="0.5" min="0.5" /></label>
|
||||
<label class="mat">D38 이상 <input id="bend-main51" type="number" step="0.5" min="0.5" /></label>
|
||||
</fieldset>
|
||||
<p id="mat-note" class="muted small"></p>
|
||||
</section>
|
||||
</aside>
|
||||
@@ -353,20 +433,22 @@
|
||||
<div class="dlg-col">
|
||||
<section>
|
||||
<h3>미리보기</h3>
|
||||
<p id="preview-title" class="muted"></p>
|
||||
<p id="preview-title" class="muted" aria-live="polite"></p>
|
||||
<h4>교각 정보</h4>
|
||||
<div class="pv-scroll"><table id="pv-pier" class="grid-table"></table></div>
|
||||
<h4>교대 정보</h4>
|
||||
<div class="pv-scroll"><table id="pv-abuts" class="grid-table"></table></div>
|
||||
<h4>받침</h4>
|
||||
<div class="pv-scroll">
|
||||
<table id="pv-bearings" class="grid-table">
|
||||
<thead><tr><th>교각</th><th>번호</th><th>x (m)</th><th>y (m)</th><th>z (m)</th><th>방위각</th><th>위치</th></tr></thead>
|
||||
<thead><tr><th>구조물</th><th>번호</th><th>x (m)</th><th>y (m)</th><th>z (m)</th><th>방위각</th><th>위치</th></tr></thead>
|
||||
<tbody></tbody>
|
||||
</table>
|
||||
</div>
|
||||
<h4>IP</h4>
|
||||
<div class="pv-scroll">
|
||||
<table id="pv-ips" class="grid-table">
|
||||
<thead><tr><th>교각</th><th>점</th><th>x (m)</th><th>y (m)</th><th>꺾임각</th></tr></thead>
|
||||
<thead><tr><th>구조물</th><th>점</th><th>x (m)</th><th>y (m)</th><th>꺾임각</th></tr></thead>
|
||||
<tbody></tbody>
|
||||
</table>
|
||||
</div>
|
||||
@@ -375,9 +457,9 @@
|
||||
</div>
|
||||
|
||||
<footer class="dlg-foot">
|
||||
<span id="dlg-selected" class="muted"></span>
|
||||
<span id="dlg-selected" class="muted" aria-live="polite"></span>
|
||||
<button id="dlg-cancel" class="btn" type="button">취소</button>
|
||||
<button id="dlg-apply" class="btn primary" type="button" disabled>선택한 교각 0기 형상 생성</button>
|
||||
<button id="dlg-apply" class="btn primary" type="button" disabled>불러올 구조물을 선택하세요</button>
|
||||
</footer>
|
||||
</dialog>
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
"description": "교각 3D 형상 생성 웹앱 (1단계: 형상 생성)",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
"preview": "vite preview",
|
||||
"build": "tsc --noEmit && vite build",
|
||||
"typecheck": "tsc --noEmit",
|
||||
"test": "vitest run"
|
||||
|
||||
@@ -16,7 +16,7 @@ import traceback
|
||||
|
||||
ROOT = Path(__file__).resolve().parent
|
||||
OUTPUT = ROOT / 'data/output/samples_20261102'
|
||||
PACKAGE = ROOT.parent / '도면추출_연동패키지_20261102'
|
||||
PACKAGE = ROOT.parent / '도면추출'
|
||||
|
||||
|
||||
def save(path, value):
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
"terrain_crs": "EPSG:5183",
|
||||
"cad_axes": "YX",
|
||||
"terrain_block": "CSSAA14",
|
||||
"piers": "C:\\Users\\User\\Desktop\\Pier_v1-main\\Pier_v1\\도면추출_연동패키지_20261102\\samples\\샘플01_산외교_교각입력데이터.xlsx",
|
||||
"piers": "C:\\Users\\User\\Desktop\\Pier_v1-main\\Pier_v1\\도면추출\\samples\\샘플01_산외교_교각입력데이터.xlsx",
|
||||
"boreholes": "",
|
||||
"layers": "",
|
||||
"margin": 100.0,
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"sample": 1,
|
||||
"bridge": "산외교",
|
||||
"workbook": "C:\\Users\\User\\Desktop\\Pier_v1-main\\Pier_v1\\도면추출_연동패키지_20261102\\samples\\샘플01_산외교_교각입력데이터.xlsx",
|
||||
"workbook": "C:\\Users\\User\\Desktop\\Pier_v1-main\\Pier_v1\\도면추출\\samples\\샘플01_산외교_교각입력데이터.xlsx",
|
||||
"drawing": "C:\\Users\\User\\Desktop\\도면추출\\엔지니어(sample1)_π형교각_산외교\\02.종평면도(울산)_2017.0619-수정.dwg",
|
||||
"candidates": [
|
||||
"C:\\Users\\User\\Desktop\\도면추출\\엔지니어(sample1)_π형교각_산외교\\02.종평면도(울산)_2017.0619-수정.dwg"
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
"terrain_crs": "EPSG:5186",
|
||||
"cad_axes": "YX",
|
||||
"terrain_block": "",
|
||||
"piers": "C:\\Users\\User\\Desktop\\Pier_v1-main\\Pier_v1\\도면추출_연동패키지_20261102\\samples\\샘플02_운곡교_교각입력데이터.xlsx",
|
||||
"piers": "C:\\Users\\User\\Desktop\\Pier_v1-main\\Pier_v1\\도면추출\\samples\\샘플02_운곡교_교각입력데이터.xlsx",
|
||||
"boreholes": "",
|
||||
"layers": "CA002,CA0021,CAA001,CAA002",
|
||||
"margin": 100.0,
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"sample": 2,
|
||||
"bridge": "운곡교",
|
||||
"workbook": "C:\\Users\\User\\Desktop\\Pier_v1-main\\Pier_v1\\도면추출_연동패키지_20261102\\samples\\샘플02_운곡교_교각입력데이터.xlsx",
|
||||
"workbook": "C:\\Users\\User\\Desktop\\Pier_v1-main\\Pier_v1\\도면추출\\samples\\샘플02_운곡교_교각입력데이터.xlsx",
|
||||
"drawing": "C:\\Users\\User\\Desktop\\도면추출\\엔지니어(sample2)_T형교각_운곡교\\C0050202-001-운곡교 종평면도(완도방향).dwg",
|
||||
"candidates": [
|
||||
"C:\\Users\\User\\Desktop\\도면추출\\엔지니어(sample2)_T형교각_운곡교\\C0050202-001-운곡교 종평면도(완도방향).dwg"
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
"terrain_crs": "EPSG:5186",
|
||||
"cad_axes": "YX",
|
||||
"terrain_block": "*Model_Space",
|
||||
"piers": "C:\\Users\\User\\Desktop\\Pier_v1-main\\Pier_v1\\도면추출_연동패키지_20261102\\samples\\샘플03_대호지교_교각입력데이터.xlsx",
|
||||
"piers": "C:\\Users\\User\\Desktop\\Pier_v1-main\\Pier_v1\\도면추출\\samples\\샘플03_대호지교_교각입력데이터.xlsx",
|
||||
"boreholes": "",
|
||||
"layers": "PDF_SOUNDING",
|
||||
"margin": 100.0,
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"sample": 3,
|
||||
"bridge": "대호지교",
|
||||
"workbook": "C:\\Users\\User\\Desktop\\Pier_v1-main\\Pier_v1\\도면추출_연동패키지_20261102\\samples\\샘플03_대호지교_교각입력데이터.xlsx",
|
||||
"workbook": "C:\\Users\\User\\Desktop\\Pier_v1-main\\Pier_v1\\도면추출\\samples\\샘플03_대호지교_교각입력데이터.xlsx",
|
||||
"drawing": "C:\\Users\\User\\Desktop\\Pier_v1-main\\Pier_v1\\pierzainer_ground\\data\\input\\samples_20261102\\recovered\\03_original_pdf_soundings.dxf",
|
||||
"candidates": [],
|
||||
"output": "C:\\Users\\User\\Desktop\\Pier_v1-main\\Pier_v1\\pierzainer_ground\\data\\output\\samples_20261102\\03_대호지교",
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
"terrain_crs": "EPSG:5186",
|
||||
"cad_axes": "YX",
|
||||
"terrain_block": "",
|
||||
"piers": "C:\\Users\\User\\Desktop\\Pier_v1-main\\Pier_v1\\도면추출_연동패키지_20261102\\samples\\샘플04_목동교_교각입력데이터.xlsx",
|
||||
"piers": "C:\\Users\\User\\Desktop\\Pier_v1-main\\Pier_v1\\도면추출\\samples\\샘플04_목동교_교각입력데이터.xlsx",
|
||||
"boreholes": "",
|
||||
"layers": "CA002,CA0021,CAA001,CAA002",
|
||||
"margin": 100.0,
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"sample": 4,
|
||||
"bridge": "목동교",
|
||||
"workbook": "C:\\Users\\User\\Desktop\\Pier_v1-main\\Pier_v1\\도면추출_연동패키지_20261102\\samples\\샘플04_목동교_교각입력데이터.xlsx",
|
||||
"workbook": "C:\\Users\\User\\Desktop\\Pier_v1-main\\Pier_v1\\도면추출\\samples\\샘플04_목동교_교각입력데이터.xlsx",
|
||||
"drawing": "C:\\Users\\User\\Desktop\\Pier_v1-main\\Pier_v1\\pierzainer_ground\\data\\input\\samples_20261102\\recovered\\04_@서울-세종 9공구 1000현황.dwg",
|
||||
"candidates": [
|
||||
"C:\\Users\\User\\Desktop\\도면추출\\엔지니어(sample4)_π형교각_목동교\\01 공통사항(목동교 종평면도).dwg"
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
"terrain_crs": "EPSG:5186",
|
||||
"cad_axes": "YX",
|
||||
"terrain_block": "",
|
||||
"piers": "C:\\Users\\User\\Desktop\\Pier_v1-main\\Pier_v1\\도면추출_연동패키지_20261102\\samples\\샘플05_승천천교_교각입력데이터.xlsx",
|
||||
"piers": "C:\\Users\\User\\Desktop\\Pier_v1-main\\Pier_v1\\도면추출\\samples\\샘플05_승천천교_교각입력데이터.xlsx",
|
||||
"boreholes": "",
|
||||
"layers": "F0017111,F0017114,F0027217,F0027132",
|
||||
"margin": 100.0,
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"sample": 5,
|
||||
"bridge": "승천천교",
|
||||
"workbook": "C:\\Users\\User\\Desktop\\Pier_v1-main\\Pier_v1\\도면추출_연동패키지_20261102\\samples\\샘플05_승천천교_교각입력데이터.xlsx",
|
||||
"workbook": "C:\\Users\\User\\Desktop\\Pier_v1-main\\Pier_v1\\도면추출\\samples\\샘플05_승천천교_교각입력데이터.xlsx",
|
||||
"drawing": "C:\\Users\\User\\Desktop\\Pier_v1-main\\Pier_v1\\pierzainer_ground\\data\\input\\samples_20261102\\recovered\\05_project_topography_original.dwg",
|
||||
"candidates": [
|
||||
"C:\\Users\\User\\Desktop\\도면추출\\엔지니어(sample5)_π형교각_승천천교\\01 승천천교(DR) 종평면도.dwg"
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
"terrain_crs": "EPSG:5186",
|
||||
"cad_axes": "YX",
|
||||
"terrain_block": "xref-현황(191219)",
|
||||
"piers": "C:\\Users\\User\\Desktop\\Pier_v1-main\\Pier_v1\\도면추출_연동패키지_20261102\\samples\\샘플06_계문철교_교각입력데이터.xlsx",
|
||||
"piers": "C:\\Users\\User\\Desktop\\Pier_v1-main\\Pier_v1\\도면추출\\samples\\샘플06_계문철교_교각입력데이터.xlsx",
|
||||
"boreholes": "",
|
||||
"layers": "",
|
||||
"margin": 100.0,
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"sample": 6,
|
||||
"bridge": "계문철교",
|
||||
"workbook": "C:\\Users\\User\\Desktop\\Pier_v1-main\\Pier_v1\\도면추출_연동패키지_20261102\\samples\\샘플06_계문철교_교각입력데이터.xlsx",
|
||||
"workbook": "C:\\Users\\User\\Desktop\\Pier_v1-main\\Pier_v1\\도면추출\\samples\\샘플06_계문철교_교각입력데이터.xlsx",
|
||||
"drawing": "C:\\Users\\User\\Desktop\\Pier_v1-main\\Pier_v1\\pierzainer_ground\\data\\input\\samples_20261102\\recovered\\06_서수평장1-현황+선형+노리-20200410.dwg",
|
||||
"candidates": [
|
||||
"C:\\Users\\User\\Desktop\\도면추출\\엔지니어(sample6)_π형교각_계문철교\\01 계문철교 종평면도.dwg"
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
"terrain_crs": "EPSG:5186",
|
||||
"cad_axes": "YX",
|
||||
"terrain_block": "xref-현황(191219)",
|
||||
"piers": "C:\\Users\\User\\Desktop\\Pier_v1-main\\Pier_v1\\도면추출_연동패키지_20261102\\samples\\샘플07_기양천교_교각입력데이터.xlsx",
|
||||
"piers": "C:\\Users\\User\\Desktop\\Pier_v1-main\\Pier_v1\\도면추출\\samples\\샘플07_기양천교_교각입력데이터.xlsx",
|
||||
"boreholes": "",
|
||||
"layers": "",
|
||||
"margin": 100.0,
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"sample": 7,
|
||||
"bridge": "기양천교",
|
||||
"workbook": "C:\\Users\\User\\Desktop\\Pier_v1-main\\Pier_v1\\도면추출_연동패키지_20261102\\samples\\샘플07_기양천교_교각입력데이터.xlsx",
|
||||
"workbook": "C:\\Users\\User\\Desktop\\Pier_v1-main\\Pier_v1\\도면추출\\samples\\샘플07_기양천교_교각입력데이터.xlsx",
|
||||
"drawing": "C:\\Users\\User\\Desktop\\Pier_v1-main\\Pier_v1\\pierzainer_ground\\data\\input\\samples_20261102\\recovered\\06_서수평장1-현황+선형+노리-20200410.dwg",
|
||||
"candidates": [
|
||||
"C:\\Users\\User\\Desktop\\도면추출\\엔지니어(sample7)_π형교각_기양천교\\01 기양천교종평면도.dwg"
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
"terrain_crs": "EPSG:5186",
|
||||
"cad_axes": "YX",
|
||||
"terrain_block": "XR_현황",
|
||||
"piers": "C:\\Users\\User\\Desktop\\Pier_v1-main\\Pier_v1\\도면추출_연동패키지_20261102\\samples\\샘플08_옥성교_교각입력데이터.xlsx",
|
||||
"piers": "C:\\Users\\User\\Desktop\\Pier_v1-main\\Pier_v1\\도면추출\\samples\\샘플08_옥성교_교각입력데이터.xlsx",
|
||||
"boreholes": "",
|
||||
"layers": "",
|
||||
"margin": 100.0,
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"sample": 8,
|
||||
"bridge": "옥성교",
|
||||
"workbook": "C:\\Users\\User\\Desktop\\Pier_v1-main\\Pier_v1\\도면추출_연동패키지_20261102\\samples\\샘플08_옥성교_교각입력데이터.xlsx",
|
||||
"workbook": "C:\\Users\\User\\Desktop\\Pier_v1-main\\Pier_v1\\도면추출\\samples\\샘플08_옥성교_교각입력데이터.xlsx",
|
||||
"drawing": "C:\\Users\\User\\Desktop\\도면추출\\엔지니어(sample8)_T형교각_옥성교\\01 옥성교 종평면도.dwg",
|
||||
"candidates": [
|
||||
"C:\\Users\\User\\Desktop\\도면추출\\엔지니어(sample8)_T형교각_옥성교\\01 옥성교 종평면도.dwg"
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
"terrain_crs": "EPSG:5186",
|
||||
"cad_axes": "YX",
|
||||
"terrain_block": "*Model_Space",
|
||||
"piers": "C:\\Users\\User\\Desktop\\Pier_v1-main\\Pier_v1\\도면추출_연동패키지_20261102\\samples\\샘플09_새재1교_교각입력데이터.xlsx",
|
||||
"piers": "C:\\Users\\User\\Desktop\\Pier_v1-main\\Pier_v1\\도면추출\\samples\\샘플09_새재1교_교각입력데이터.xlsx",
|
||||
"boreholes": "",
|
||||
"layers": "XR_현황-수정$0$Point",
|
||||
"margin": 100.0,
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"sample": 9,
|
||||
"bridge": "새재1교",
|
||||
"workbook": "C:\\Users\\User\\Desktop\\Pier_v1-main\\Pier_v1\\도면추출_연동패키지_20261102\\samples\\샘플09_새재1교_교각입력데이터.xlsx",
|
||||
"workbook": "C:\\Users\\User\\Desktop\\Pier_v1-main\\Pier_v1\\도면추출\\samples\\샘플09_새재1교_교각입력데이터.xlsx",
|
||||
"drawing": "C:\\Users\\User\\Desktop\\도면추출\\엔지니어(sample9)_T형교각_새재1교\\01 새재1교 종평면도.dwg",
|
||||
"candidates": [
|
||||
"C:\\Users\\User\\Desktop\\도면추출\\엔지니어(sample9)_T형교각_새재1교\\01 새재1교 종평면도.dwg"
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
"terrain_crs": "EPSG:5186",
|
||||
"cad_axes": "YX",
|
||||
"terrain_block": "*Model_Space",
|
||||
"piers": "C:\\Users\\User\\Desktop\\Pier_v1-main\\Pier_v1\\도면추출_연동패키지_20261102\\samples\\샘플10_도하4교_교각입력데이터.xlsx",
|
||||
"piers": "C:\\Users\\User\\Desktop\\Pier_v1-main\\Pier_v1\\도면추출\\samples\\샘플10_도하4교_교각입력데이터.xlsx",
|
||||
"boreholes": "",
|
||||
"layers": "CA002,CA0021,CAA001,CAA002",
|
||||
"margin": 100.0,
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"sample": 10,
|
||||
"bridge": "도하4교",
|
||||
"workbook": "C:\\Users\\User\\Desktop\\Pier_v1-main\\Pier_v1\\도면추출_연동패키지_20261102\\samples\\샘플10_도하4교_교각입력데이터.xlsx",
|
||||
"workbook": "C:\\Users\\User\\Desktop\\Pier_v1-main\\Pier_v1\\도면추출\\samples\\샘플10_도하4교_교각입력데이터.xlsx",
|
||||
"drawing": "C:\\Users\\User\\Desktop\\도면추출\\엔지니어(sample10)_T형교각_도하4교\\01.종평면도.dwg",
|
||||
"candidates": [
|
||||
"C:\\Users\\User\\Desktop\\도면추출\\엔지니어(sample10)_T형교각_도하4교\\01.종평면도.dwg"
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
"terrain_crs": "EPSG:5186",
|
||||
"cad_axes": "YX",
|
||||
"terrain_block": "*Model_Space",
|
||||
"piers": "C:\\Users\\User\\Desktop\\Pier_v1-main\\Pier_v1\\도면추출_연동패키지_20261102\\samples\\샘플11_곡천교_교각입력데이터.xlsx",
|
||||
"piers": "C:\\Users\\User\\Desktop\\Pier_v1-main\\Pier_v1\\도면추출\\samples\\샘플11_곡천교_교각입력데이터.xlsx",
|
||||
"boreholes": "",
|
||||
"layers": "CA002,CA0021,CAA001,CAA002",
|
||||
"margin": 100.0,
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"sample": 11,
|
||||
"bridge": "곡천교",
|
||||
"workbook": "C:\\Users\\User\\Desktop\\Pier_v1-main\\Pier_v1\\도면추출_연동패키지_20261102\\samples\\샘플11_곡천교_교각입력데이터.xlsx",
|
||||
"workbook": "C:\\Users\\User\\Desktop\\Pier_v1-main\\Pier_v1\\도면추출\\samples\\샘플11_곡천교_교각입력데이터.xlsx",
|
||||
"drawing": "C:\\Users\\User\\Desktop\\도면추출\\엔지니어(sample11)_π형교각_곡천교\\01 종평면도_곡천교.dwg",
|
||||
"candidates": [
|
||||
"C:\\Users\\User\\Desktop\\도면추출\\엔지니어(sample11)_π형교각_곡천교\\01 종평면도_곡천교.dwg"
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
"terrain_crs": "EPSG:5181",
|
||||
"cad_axes": "YX",
|
||||
"terrain_block": "",
|
||||
"piers": "C:\\Users\\User\\Desktop\\Pier_v1-main\\Pier_v1\\도면추출_연동패키지_20261102\\samples\\샘플12_감북교_교각입력데이터.xlsx",
|
||||
"piers": "C:\\Users\\User\\Desktop\\Pier_v1-main\\Pier_v1\\도면추출\\samples\\샘플12_감북교_교각입력데이터.xlsx",
|
||||
"boreholes": "",
|
||||
"layers": "CAA001,CAA002",
|
||||
"margin": 100.0,
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"sample": 12,
|
||||
"bridge": "감북교",
|
||||
"workbook": "C:\\Users\\User\\Desktop\\Pier_v1-main\\Pier_v1\\도면추출_연동패키지_20261102\\samples\\샘플12_감북교_교각입력데이터.xlsx",
|
||||
"workbook": "C:\\Users\\User\\Desktop\\Pier_v1-main\\Pier_v1\\도면추출\\samples\\샘플12_감북교_교각입력데이터.xlsx",
|
||||
"drawing": "C:\\Users\\User\\Desktop\\도면추출\\엔지니어(sample12)_π형교각_감북교\\01 감북교 종평면도.dwg",
|
||||
"candidates": [
|
||||
"C:\\Users\\User\\Desktop\\도면추출\\엔지니어(sample12)_π형교각_감북교\\01 감북교 종평면도.dwg"
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
{
|
||||
"sample": 1,
|
||||
"bridge": "산외교",
|
||||
"workbook": "C:\\Users\\User\\Desktop\\Pier_v1-main\\Pier_v1\\도면추출_연동패키지_20261102\\samples\\샘플01_산외교_교각입력데이터.xlsx",
|
||||
"workbook": "C:\\Users\\User\\Desktop\\Pier_v1-main\\Pier_v1\\도면추출\\samples\\샘플01_산외교_교각입력데이터.xlsx",
|
||||
"drawing": "C:\\Users\\User\\Desktop\\도면추출\\엔지니어(sample1)_π형교각_산외교\\02.종평면도(울산)_2017.0619-수정.dwg",
|
||||
"candidates": [
|
||||
"C:\\Users\\User\\Desktop\\도면추출\\엔지니어(sample1)_π형교각_산외교\\02.종평면도(울산)_2017.0619-수정.dwg"
|
||||
@@ -12,7 +12,7 @@
|
||||
{
|
||||
"sample": 2,
|
||||
"bridge": "운곡교",
|
||||
"workbook": "C:\\Users\\User\\Desktop\\Pier_v1-main\\Pier_v1\\도면추출_연동패키지_20261102\\samples\\샘플02_운곡교_교각입력데이터.xlsx",
|
||||
"workbook": "C:\\Users\\User\\Desktop\\Pier_v1-main\\Pier_v1\\도면추출\\samples\\샘플02_운곡교_교각입력데이터.xlsx",
|
||||
"drawing": "C:\\Users\\User\\Desktop\\도면추출\\엔지니어(sample2)_T형교각_운곡교\\C0050202-001-운곡교 종평면도(완도방향).dwg",
|
||||
"candidates": [
|
||||
"C:\\Users\\User\\Desktop\\도면추출\\엔지니어(sample2)_T형교각_운곡교\\C0050202-001-운곡교 종평면도(완도방향).dwg"
|
||||
@@ -22,7 +22,7 @@
|
||||
{
|
||||
"sample": 3,
|
||||
"bridge": "대호지교",
|
||||
"workbook": "C:\\Users\\User\\Desktop\\Pier_v1-main\\Pier_v1\\도면추출_연동패키지_20261102\\samples\\샘플03_대호지교_교각입력데이터.xlsx",
|
||||
"workbook": "C:\\Users\\User\\Desktop\\Pier_v1-main\\Pier_v1\\도면추출\\samples\\샘플03_대호지교_교각입력데이터.xlsx",
|
||||
"drawing": "C:\\Users\\User\\Desktop\\Pier_v1-main\\Pier_v1\\pierzainer_ground\\data\\input\\samples_20261102\\recovered\\03_original_pdf_soundings.dxf",
|
||||
"candidates": [],
|
||||
"output": "C:\\Users\\User\\Desktop\\Pier_v1-main\\Pier_v1\\pierzainer_ground\\data\\output\\samples_20261102\\03_대호지교",
|
||||
@@ -930,7 +930,7 @@
|
||||
{
|
||||
"sample": 4,
|
||||
"bridge": "목동교",
|
||||
"workbook": "C:\\Users\\User\\Desktop\\Pier_v1-main\\Pier_v1\\도면추출_연동패키지_20261102\\samples\\샘플04_목동교_교각입력데이터.xlsx",
|
||||
"workbook": "C:\\Users\\User\\Desktop\\Pier_v1-main\\Pier_v1\\도면추출\\samples\\샘플04_목동교_교각입력데이터.xlsx",
|
||||
"drawing": "C:\\Users\\User\\Desktop\\Pier_v1-main\\Pier_v1\\pierzainer_ground\\data\\input\\samples_20261102\\recovered\\04_@서울-세종 9공구 1000현황.dwg",
|
||||
"candidates": [
|
||||
"C:\\Users\\User\\Desktop\\도면추출\\엔지니어(sample4)_π형교각_목동교\\01 공통사항(목동교 종평면도).dwg"
|
||||
@@ -956,7 +956,7 @@
|
||||
{
|
||||
"sample": 5,
|
||||
"bridge": "승천천교",
|
||||
"workbook": "C:\\Users\\User\\Desktop\\Pier_v1-main\\Pier_v1\\도면추출_연동패키지_20261102\\samples\\샘플05_승천천교_교각입력데이터.xlsx",
|
||||
"workbook": "C:\\Users\\User\\Desktop\\Pier_v1-main\\Pier_v1\\도면추출\\samples\\샘플05_승천천교_교각입력데이터.xlsx",
|
||||
"drawing": "C:\\Users\\User\\Desktop\\Pier_v1-main\\Pier_v1\\pierzainer_ground\\data\\input\\samples_20261102\\recovered\\05_project_topography_original.dwg",
|
||||
"candidates": [
|
||||
"C:\\Users\\User\\Desktop\\도면추출\\엔지니어(sample5)_π형교각_승천천교\\01 승천천교(DR) 종평면도.dwg"
|
||||
@@ -984,7 +984,7 @@
|
||||
{
|
||||
"sample": 6,
|
||||
"bridge": "계문철교",
|
||||
"workbook": "C:\\Users\\User\\Desktop\\Pier_v1-main\\Pier_v1\\도면추출_연동패키지_20261102\\samples\\샘플06_계문철교_교각입력데이터.xlsx",
|
||||
"workbook": "C:\\Users\\User\\Desktop\\Pier_v1-main\\Pier_v1\\도면추출\\samples\\샘플06_계문철교_교각입력데이터.xlsx",
|
||||
"drawing": "C:\\Users\\User\\Desktop\\Pier_v1-main\\Pier_v1\\pierzainer_ground\\data\\input\\samples_20261102\\recovered\\06_서수평장1-현황+선형+노리-20200410.dwg",
|
||||
"candidates": [
|
||||
"C:\\Users\\User\\Desktop\\도면추출\\엔지니어(sample6)_π형교각_계문철교\\01 계문철교 종평면도.dwg"
|
||||
@@ -1011,7 +1011,7 @@
|
||||
{
|
||||
"sample": 7,
|
||||
"bridge": "기양천교",
|
||||
"workbook": "C:\\Users\\User\\Desktop\\Pier_v1-main\\Pier_v1\\도면추출_연동패키지_20261102\\samples\\샘플07_기양천교_교각입력데이터.xlsx",
|
||||
"workbook": "C:\\Users\\User\\Desktop\\Pier_v1-main\\Pier_v1\\도면추출\\samples\\샘플07_기양천교_교각입력데이터.xlsx",
|
||||
"drawing": "C:\\Users\\User\\Desktop\\Pier_v1-main\\Pier_v1\\pierzainer_ground\\data\\input\\samples_20261102\\recovered\\06_서수평장1-현황+선형+노리-20200410.dwg",
|
||||
"candidates": [
|
||||
"C:\\Users\\User\\Desktop\\도면추출\\엔지니어(sample7)_π형교각_기양천교\\01 기양천교종평면도.dwg"
|
||||
@@ -1038,7 +1038,7 @@
|
||||
{
|
||||
"sample": 8,
|
||||
"bridge": "옥성교",
|
||||
"workbook": "C:\\Users\\User\\Desktop\\Pier_v1-main\\Pier_v1\\도면추출_연동패키지_20261102\\samples\\샘플08_옥성교_교각입력데이터.xlsx",
|
||||
"workbook": "C:\\Users\\User\\Desktop\\Pier_v1-main\\Pier_v1\\도면추출\\samples\\샘플08_옥성교_교각입력데이터.xlsx",
|
||||
"drawing": "C:\\Users\\User\\Desktop\\도면추출\\엔지니어(sample8)_T형교각_옥성교\\01 옥성교 종평면도.dwg",
|
||||
"candidates": [
|
||||
"C:\\Users\\User\\Desktop\\도면추출\\엔지니어(sample8)_T형교각_옥성교\\01 옥성교 종평면도.dwg"
|
||||
@@ -1048,7 +1048,7 @@
|
||||
{
|
||||
"sample": 9,
|
||||
"bridge": "새재1교",
|
||||
"workbook": "C:\\Users\\User\\Desktop\\Pier_v1-main\\Pier_v1\\도면추출_연동패키지_20261102\\samples\\샘플09_새재1교_교각입력데이터.xlsx",
|
||||
"workbook": "C:\\Users\\User\\Desktop\\Pier_v1-main\\Pier_v1\\도면추출\\samples\\샘플09_새재1교_교각입력데이터.xlsx",
|
||||
"drawing": "C:\\Users\\User\\Desktop\\도면추출\\엔지니어(sample9)_T형교각_새재1교\\01 새재1교 종평면도.dwg",
|
||||
"candidates": [
|
||||
"C:\\Users\\User\\Desktop\\도면추출\\엔지니어(sample9)_T형교각_새재1교\\01 새재1교 종평면도.dwg"
|
||||
@@ -1058,7 +1058,7 @@
|
||||
{
|
||||
"sample": 10,
|
||||
"bridge": "도하4교",
|
||||
"workbook": "C:\\Users\\User\\Desktop\\Pier_v1-main\\Pier_v1\\도면추출_연동패키지_20261102\\samples\\샘플10_도하4교_교각입력데이터.xlsx",
|
||||
"workbook": "C:\\Users\\User\\Desktop\\Pier_v1-main\\Pier_v1\\도면추출\\samples\\샘플10_도하4교_교각입력데이터.xlsx",
|
||||
"drawing": "C:\\Users\\User\\Desktop\\도면추출\\엔지니어(sample10)_T형교각_도하4교\\01.종평면도.dwg",
|
||||
"candidates": [
|
||||
"C:\\Users\\User\\Desktop\\도면추출\\엔지니어(sample10)_T형교각_도하4교\\01.종평면도.dwg"
|
||||
@@ -1068,7 +1068,7 @@
|
||||
{
|
||||
"sample": 11,
|
||||
"bridge": "곡천교",
|
||||
"workbook": "C:\\Users\\User\\Desktop\\Pier_v1-main\\Pier_v1\\도면추출_연동패키지_20261102\\samples\\샘플11_곡천교_교각입력데이터.xlsx",
|
||||
"workbook": "C:\\Users\\User\\Desktop\\Pier_v1-main\\Pier_v1\\도면추출\\samples\\샘플11_곡천교_교각입력데이터.xlsx",
|
||||
"drawing": "C:\\Users\\User\\Desktop\\도면추출\\엔지니어(sample11)_π형교각_곡천교\\01 종평면도_곡천교.dwg",
|
||||
"candidates": [
|
||||
"C:\\Users\\User\\Desktop\\도면추출\\엔지니어(sample11)_π형교각_곡천교\\01 종평면도_곡천교.dwg"
|
||||
@@ -1078,7 +1078,7 @@
|
||||
{
|
||||
"sample": 12,
|
||||
"bridge": "감북교",
|
||||
"workbook": "C:\\Users\\User\\Desktop\\Pier_v1-main\\Pier_v1\\도면추출_연동패키지_20261102\\samples\\샘플12_감북교_교각입력데이터.xlsx",
|
||||
"workbook": "C:\\Users\\User\\Desktop\\Pier_v1-main\\Pier_v1\\도면추출\\samples\\샘플12_감북교_교각입력데이터.xlsx",
|
||||
"drawing": "C:\\Users\\User\\Desktop\\도면추출\\엔지니어(sample12)_π형교각_감북교\\01 감북교 종평면도.dwg",
|
||||
"candidates": [
|
||||
"C:\\Users\\User\\Desktop\\도면추출\\엔지니어(sample12)_π형교각_감북교\\01 감북교 종평면도.dwg"
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
{
|
||||
"sample": 1,
|
||||
"bridge": "산외교",
|
||||
"workbook": "C:\\Users\\User\\Desktop\\Pier_v1-main\\Pier_v1\\도면추출_연동패키지_20261102\\samples\\샘플01_산외교_교각입력데이터.xlsx",
|
||||
"workbook": "C:\\Users\\User\\Desktop\\Pier_v1-main\\Pier_v1\\도면추출\\samples\\샘플01_산외교_교각입력데이터.xlsx",
|
||||
"drawing": "C:\\Users\\User\\Desktop\\도면추출\\엔지니어(sample1)_π형교각_산외교\\02.종평면도(울산)_2017.0619-수정.dwg",
|
||||
"candidates": [
|
||||
"C:\\Users\\User\\Desktop\\도면추출\\엔지니어(sample1)_π형교각_산외교\\02.종평면도(울산)_2017.0619-수정.dwg"
|
||||
@@ -41,7 +41,7 @@
|
||||
{
|
||||
"sample": 2,
|
||||
"bridge": "운곡교",
|
||||
"workbook": "C:\\Users\\User\\Desktop\\Pier_v1-main\\Pier_v1\\도면추출_연동패키지_20261102\\samples\\샘플02_운곡교_교각입력데이터.xlsx",
|
||||
"workbook": "C:\\Users\\User\\Desktop\\Pier_v1-main\\Pier_v1\\도면추출\\samples\\샘플02_운곡교_교각입력데이터.xlsx",
|
||||
"drawing": "C:\\Users\\User\\Desktop\\도면추출\\엔지니어(sample2)_T형교각_운곡교\\C0050202-001-운곡교 종평면도(완도방향).dwg",
|
||||
"candidates": [
|
||||
"C:\\Users\\User\\Desktop\\도면추출\\엔지니어(sample2)_T형교각_운곡교\\C0050202-001-운곡교 종평면도(완도방향).dwg"
|
||||
@@ -75,7 +75,7 @@
|
||||
{
|
||||
"sample": 3,
|
||||
"bridge": "대호지교",
|
||||
"workbook": "C:\\Users\\User\\Desktop\\Pier_v1-main\\Pier_v1\\도면추출_연동패키지_20261102\\samples\\샘플03_대호지교_교각입력데이터.xlsx",
|
||||
"workbook": "C:\\Users\\User\\Desktop\\Pier_v1-main\\Pier_v1\\도면추출\\samples\\샘플03_대호지교_교각입력데이터.xlsx",
|
||||
"drawing": "C:\\Users\\User\\Desktop\\Pier_v1-main\\Pier_v1\\pierzainer_ground\\data\\input\\samples_20261102\\recovered\\03_original_pdf_soundings.dxf",
|
||||
"candidates": [],
|
||||
"output": "C:\\Users\\User\\Desktop\\Pier_v1-main\\Pier_v1\\pierzainer_ground\\data\\output\\samples_20261102\\03_대호지교",
|
||||
@@ -1007,7 +1007,7 @@
|
||||
{
|
||||
"sample": 4,
|
||||
"bridge": "목동교",
|
||||
"workbook": "C:\\Users\\User\\Desktop\\Pier_v1-main\\Pier_v1\\도면추출_연동패키지_20261102\\samples\\샘플04_목동교_교각입력데이터.xlsx",
|
||||
"workbook": "C:\\Users\\User\\Desktop\\Pier_v1-main\\Pier_v1\\도면추출\\samples\\샘플04_목동교_교각입력데이터.xlsx",
|
||||
"drawing": "C:\\Users\\User\\Desktop\\Pier_v1-main\\Pier_v1\\pierzainer_ground\\data\\input\\samples_20261102\\recovered\\04_@서울-세종 9공구 1000현황.dwg",
|
||||
"candidates": [
|
||||
"C:\\Users\\User\\Desktop\\도면추출\\엔지니어(sample4)_π형교각_목동교\\01 공통사항(목동교 종평면도).dwg"
|
||||
@@ -1057,7 +1057,7 @@
|
||||
{
|
||||
"sample": 5,
|
||||
"bridge": "승천천교",
|
||||
"workbook": "C:\\Users\\User\\Desktop\\Pier_v1-main\\Pier_v1\\도면추출_연동패키지_20261102\\samples\\샘플05_승천천교_교각입력데이터.xlsx",
|
||||
"workbook": "C:\\Users\\User\\Desktop\\Pier_v1-main\\Pier_v1\\도면추출\\samples\\샘플05_승천천교_교각입력데이터.xlsx",
|
||||
"drawing": "C:\\Users\\User\\Desktop\\Pier_v1-main\\Pier_v1\\pierzainer_ground\\data\\input\\samples_20261102\\recovered\\05_project_topography_original.dwg",
|
||||
"candidates": [
|
||||
"C:\\Users\\User\\Desktop\\도면추출\\엔지니어(sample5)_π형교각_승천천교\\01 승천천교(DR) 종평면도.dwg"
|
||||
@@ -1109,7 +1109,7 @@
|
||||
{
|
||||
"sample": 6,
|
||||
"bridge": "계문철교",
|
||||
"workbook": "C:\\Users\\User\\Desktop\\Pier_v1-main\\Pier_v1\\도면추출_연동패키지_20261102\\samples\\샘플06_계문철교_교각입력데이터.xlsx",
|
||||
"workbook": "C:\\Users\\User\\Desktop\\Pier_v1-main\\Pier_v1\\도면추출\\samples\\샘플06_계문철교_교각입력데이터.xlsx",
|
||||
"drawing": "C:\\Users\\User\\Desktop\\Pier_v1-main\\Pier_v1\\pierzainer_ground\\data\\input\\samples_20261102\\recovered\\06_서수평장1-현황+선형+노리-20200410.dwg",
|
||||
"candidates": [
|
||||
"C:\\Users\\User\\Desktop\\도면추출\\엔지니어(sample6)_π형교각_계문철교\\01 계문철교 종평면도.dwg"
|
||||
@@ -1160,7 +1160,7 @@
|
||||
{
|
||||
"sample": 7,
|
||||
"bridge": "기양천교",
|
||||
"workbook": "C:\\Users\\User\\Desktop\\Pier_v1-main\\Pier_v1\\도면추출_연동패키지_20261102\\samples\\샘플07_기양천교_교각입력데이터.xlsx",
|
||||
"workbook": "C:\\Users\\User\\Desktop\\Pier_v1-main\\Pier_v1\\도면추출\\samples\\샘플07_기양천교_교각입력데이터.xlsx",
|
||||
"drawing": "C:\\Users\\User\\Desktop\\Pier_v1-main\\Pier_v1\\pierzainer_ground\\data\\input\\samples_20261102\\recovered\\06_서수평장1-현황+선형+노리-20200410.dwg",
|
||||
"candidates": [
|
||||
"C:\\Users\\User\\Desktop\\도면추출\\엔지니어(sample7)_π형교각_기양천교\\01 기양천교종평면도.dwg"
|
||||
@@ -1211,7 +1211,7 @@
|
||||
{
|
||||
"sample": 8,
|
||||
"bridge": "옥성교",
|
||||
"workbook": "C:\\Users\\User\\Desktop\\Pier_v1-main\\Pier_v1\\도면추출_연동패키지_20261102\\samples\\샘플08_옥성교_교각입력데이터.xlsx",
|
||||
"workbook": "C:\\Users\\User\\Desktop\\Pier_v1-main\\Pier_v1\\도면추출\\samples\\샘플08_옥성교_교각입력데이터.xlsx",
|
||||
"drawing": "C:\\Users\\User\\Desktop\\도면추출\\엔지니어(sample8)_T형교각_옥성교\\01 옥성교 종평면도.dwg",
|
||||
"candidates": [
|
||||
"C:\\Users\\User\\Desktop\\도면추출\\엔지니어(sample8)_T형교각_옥성교\\01 옥성교 종평면도.dwg"
|
||||
@@ -1245,7 +1245,7 @@
|
||||
{
|
||||
"sample": 9,
|
||||
"bridge": "새재1교",
|
||||
"workbook": "C:\\Users\\User\\Desktop\\Pier_v1-main\\Pier_v1\\도면추출_연동패키지_20261102\\samples\\샘플09_새재1교_교각입력데이터.xlsx",
|
||||
"workbook": "C:\\Users\\User\\Desktop\\Pier_v1-main\\Pier_v1\\도면추출\\samples\\샘플09_새재1교_교각입력데이터.xlsx",
|
||||
"drawing": "C:\\Users\\User\\Desktop\\도면추출\\엔지니어(sample9)_T형교각_새재1교\\01 새재1교 종평면도.dwg",
|
||||
"candidates": [
|
||||
"C:\\Users\\User\\Desktop\\도면추출\\엔지니어(sample9)_T형교각_새재1교\\01 새재1교 종평면도.dwg"
|
||||
@@ -1279,7 +1279,7 @@
|
||||
{
|
||||
"sample": 10,
|
||||
"bridge": "도하4교",
|
||||
"workbook": "C:\\Users\\User\\Desktop\\Pier_v1-main\\Pier_v1\\도면추출_연동패키지_20261102\\samples\\샘플10_도하4교_교각입력데이터.xlsx",
|
||||
"workbook": "C:\\Users\\User\\Desktop\\Pier_v1-main\\Pier_v1\\도면추출\\samples\\샘플10_도하4교_교각입력데이터.xlsx",
|
||||
"drawing": "C:\\Users\\User\\Desktop\\도면추출\\엔지니어(sample10)_T형교각_도하4교\\01.종평면도.dwg",
|
||||
"candidates": [
|
||||
"C:\\Users\\User\\Desktop\\도면추출\\엔지니어(sample10)_T형교각_도하4교\\01.종평면도.dwg"
|
||||
@@ -1313,7 +1313,7 @@
|
||||
{
|
||||
"sample": 11,
|
||||
"bridge": "곡천교",
|
||||
"workbook": "C:\\Users\\User\\Desktop\\Pier_v1-main\\Pier_v1\\도면추출_연동패키지_20261102\\samples\\샘플11_곡천교_교각입력데이터.xlsx",
|
||||
"workbook": "C:\\Users\\User\\Desktop\\Pier_v1-main\\Pier_v1\\도면추출\\samples\\샘플11_곡천교_교각입력데이터.xlsx",
|
||||
"drawing": "C:\\Users\\User\\Desktop\\도면추출\\엔지니어(sample11)_π형교각_곡천교\\01 종평면도_곡천교.dwg",
|
||||
"candidates": [
|
||||
"C:\\Users\\User\\Desktop\\도면추출\\엔지니어(sample11)_π형교각_곡천교\\01 종평면도_곡천교.dwg"
|
||||
@@ -1347,7 +1347,7 @@
|
||||
{
|
||||
"sample": 12,
|
||||
"bridge": "감북교",
|
||||
"workbook": "C:\\Users\\User\\Desktop\\Pier_v1-main\\Pier_v1\\도면추출_연동패키지_20261102\\samples\\샘플12_감북교_교각입력데이터.xlsx",
|
||||
"workbook": "C:\\Users\\User\\Desktop\\Pier_v1-main\\Pier_v1\\도면추출\\samples\\샘플12_감북교_교각입력데이터.xlsx",
|
||||
"drawing": "C:\\Users\\User\\Desktop\\도면추출\\엔지니어(sample12)_π형교각_감북교\\01 감북교 종평면도.dwg",
|
||||
"candidates": [
|
||||
"C:\\Users\\User\\Desktop\\도면추출\\엔지니어(sample12)_π형교각_감북교\\01 감북교 종평면도.dwg"
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
# 프로그램 내부 지반 생성 팝업
|
||||
|
||||
현재 지반 생성 버튼은 별도 Windows 창 대신 프로그램 내부 dialog를 연다.
|
||||
- Excel 시작: 현재 Excel이 연결되며 종평면도 DWG/DXF를 선택한 뒤 지반 생성을 누른다.
|
||||
- 도면 시작: 추출 폴더의 종평면도 원본과 Excel이 연결되며 지반 생성을 누른다.
|
||||
- 입력을 바꾸려면 팝업의 파일 선택을 사용한다. Excel 연결 정보가 없는 프로젝트는 Excel도 선택한다.
|
||||
- 기존 Python build_from_files 엔진을 창 없이 실행한다. BAT를 브라우저 안에 직접 삽입하는 방식이 아니며, 독립 실행용 BAT는 유지한다.
|
||||
- 진행 로그와 오류를 팝업에 표시한다. 닫아도 작업은 계속되며 다시 열 수 있다.
|
||||
- 완료 결과는 기존 JSON 로더에 전달한다. 지반·지층 패널을 벗어나면 복귀 후 반영한다.
|
||||
- 결과는 data/output/app_<작업 ID>에 저장한다. 원본 자료는 변경하지 않는다.
|
||||
- Windows 로컬 Vite 서버가 필요하다. 정적 호스팅에서는 실행할 수 없다.
|
||||
|
||||
검증: TypeScript 검사 및 기존 후보 선택 테스트 3건 통과. 브라우저에서 실제 prepare API, 팝업 표시, 입력 누락 오류, 닫기 및 즉시 재열기 확인. 이번 팝업 수정에서 새 도면 전체 생성은 실행하지 않았다.
|
||||
|
||||
주요 파일: ground-link.ts, ground-link-server.ts, ground-popup.css, pierzainer_ground/web_job.py. 기존 main/landing 입력 연결을 재사용한다.
|
||||
@@ -0,0 +1,60 @@
|
||||
import { spawn } from 'node:child_process';
|
||||
import { mkdir,writeFile,readFile,readdir } from 'node:fs/promises';
|
||||
import { existsSync } from 'node:fs';
|
||||
import path from 'node:path';
|
||||
import { randomUUID } from 'node:crypto';
|
||||
import type { Plugin } from 'vite';
|
||||
import { resolvePython,describeSpawnError } from './python-runtime.ts';
|
||||
export const GROUND_LINK_API='/__pierzainer/ground-link';
|
||||
export function startGroundBat(bat:string,context:string,cwd:string){
|
||||
return spawn(process.env.ComSpec??'cmd.exe',['/d','/s','/c',`""${bat}""`],{cwd,windowsHide:true,windowsVerbatimArguments:true,env:{...process.env,PIERZAINER_GROUND_CONTEXT:context},stdio:'ignore'});
|
||||
}
|
||||
|
||||
export async function findGroundDrawing(folder:string):Promise<string|undefined>{
|
||||
const matches:string[]=[];
|
||||
const walk=async(dir:string,depth:number)=>{for(const entry of await readdir(dir,{withFileTypes:true})){const file=path.join(dir,entry.name);if(entry.isDirectory()&&depth<2)await walk(file,depth+1);else if(entry.isFile()&&/\.(dwg|dxf)$/i.test(entry.name)&&/종평면|종평|종단|평종면/.test(entry.name))matches.push(file);}};
|
||||
if(folder)await walk(folder,0);const originals=matches.filter(file=>/\.dwg$/i.test(file));return originals.length===1?originals[0]:matches.length===1?matches[0]:undefined;
|
||||
}
|
||||
export function groundLinkPlugin(root:string):Plugin{
|
||||
const base=path.join(root,'pierzainer_ground'),cache=path.join(base,'data/cache/app-link'),stages=new Map<string,{excel:string;folder:string;name:string}>(),jobs=new Map<string,{output:string;logs:string;state:string}>();
|
||||
const handler=async(req:any,res:any,next:()=>void)=>{
|
||||
const pathname=new URL(req.url??'/','http://localhost').pathname;if(!pathname.startsWith(GROUND_LINK_API+'/'))return next();
|
||||
const reply=(code:number,value:unknown)=>{res.writeHead(code,{'Content-Type':'application/json; charset=utf-8','Cache-Control':'no-store'});res.end(JSON.stringify(value));};
|
||||
const host=req.headers.host??'',address=req.socket.remoteAddress??'';
|
||||
if(req.method!=='POST'||! /^(localhost|127\.0\.0\.1|\[::1\])(?::\d+)?$/i.test(host)||!['127.0.0.1','::1','::ffff:127.0.0.1'].includes(address)||req.headers['x-pierzainer-action']!=='ground-link'||req.headers.origin&&req.headers.origin!==`http://${host}`&&req.headers.origin!==`https://${host}`){reply(403,{error:'이 PC의 Pierzainer에서 실행하세요.'});return;}
|
||||
try{
|
||||
let raw='';for await(const part of req){raw+=part;if(raw.length>280*1024*1024)throw new Error('Excel 파일이 너무 큽니다(최대 20MB).');}const body=JSON.parse(raw||'{}'),action=pathname.slice(GROUND_LINK_API.length+1);
|
||||
if(action==='stage'){
|
||||
if(typeof body.name!=='string'||!body.name.toLowerCase().endsWith('.xlsx')||typeof body.base64!=='string'||!/^[A-Za-z0-9+/]*={0,2}$/.test(body.base64))throw new Error('교각 Excel(.xlsx) 파일을 선택하세요.');
|
||||
const bytes=Buffer.from(body.base64,'base64');if(bytes.length>20*1024*1024||bytes[0]!==80||bytes[1]!==75)throw new Error('유효한 xlsx 파일이 아닙니다.');
|
||||
const id=randomUUID(),dir=path.join(cache,id);await mkdir(dir,{recursive:true});const excel=path.join(dir,'piers.xlsx');await writeFile(excel,bytes);stages.set(id,{excel,name:body.name,folder:typeof body.folder==='string'?body.folder:''});reply(200,{id});return;
|
||||
}
|
||||
if(action==='prepare'){
|
||||
const stage=stages.get(body.stageId);const drawing=stage?.folder?await findGroundDrawing(stage.folder):undefined;reply(200,{drawing:drawing??'',excelSelected:!!stage,excelName:stage?.name??''});return;
|
||||
}
|
||||
if(action==='upload'){
|
||||
if(typeof body.name!=='string'||!/\.(dwg|dxf|xlsx)$/i.test(body.name)||typeof body.base64!=='string'||! /^[A-Za-z0-9+/]*={0,2}$/.test(body.base64))throw new Error('DWG/DXF 또는 Excel을 선택하세요.');
|
||||
const bytes=Buffer.from(body.base64,'base64');if(bytes.length>200*1024*1024)throw new Error('최대 200MB입니다.');const dir=path.join(cache,randomUUID());await mkdir(dir,{recursive:true});const file=path.join(dir,path.basename(body.name));await writeFile(file,bytes);reply(200,{file});return;
|
||||
}
|
||||
if(action==='launch'){
|
||||
const stage=stages.get(body.stageId),drawing=String(body.drawing??''),piers=String(body.excel??stage?.excel??'');
|
||||
const original=stage?.folder?await findGroundDrawing(stage.folder):undefined;
|
||||
const cached=(file:string)=>{const r=path.relative(cache,path.resolve(file));return !!r&&!r.startsWith('..')&&!path.isAbsolute(r);};
|
||||
if(!existsSync(drawing)||!/\.(dwg|dxf)$/i.test(drawing)||drawing!==original&&!cached(drawing))throw new Error('종평면도를 선택하세요.');
|
||||
if(!existsSync(piers)||!/\.xlsx$/i.test(piers)||!cached(piers))throw new Error('교각 Excel을 선택하세요.');
|
||||
const id=randomUUID(),output=path.join(base,'data/output',`app_${id}`),job={output,logs:'',state:'running'};jobs.set(id,job);
|
||||
const python=resolvePython(root);
|
||||
const child=spawn(python,['-B','-u','-X','utf8','-m','pierzainer_ground.web_job',drawing,piers,output],{cwd:base,windowsHide:true,stdio:['ignore','pipe','pipe']});
|
||||
const append=(data:Buffer)=>{job.logs=(job.logs+data.toString('utf8')).slice(-200000);};child.stdout.on('data',append);child.stderr.on('data',append);
|
||||
child.once('error',error=>{job.state='error';job.logs+='\n'+describeSpawnError(error,python);});child.once('close',code=>{job.state=code===0?'done':'error';});reply(200,{id});return;
|
||||
}
|
||||
if(action==='result'){
|
||||
const job=jobs.get(body.id);if(!job)throw new Error('지반 생성 작업을 찾을 수 없습니다.');
|
||||
if(job.state!=='done'){reply(200,{ready:false,state:job.state,logs:job.logs});return;}
|
||||
for(const filename of ['ground_model_3d_with_maps.json','ground_model.json']){const file=path.join(job.output,filename);if(existsSync(file)){const text=await readFile(file,'utf8');JSON.parse(text);reply(200,{ready:true,filename,text,state:job.state,logs:job.logs});return;}}
|
||||
reply(200,{ready:false});return;
|
||||
}reply(404,{error:'지원하지 않는 지반 연동 요청입니다.'});
|
||||
}catch(error){reply(400,{error:(error as Error).message});}
|
||||
};
|
||||
return{name:'pierzainer-ground-link',configureServer(server){server.middlewares.use((req,res,next)=>void handler(req,res,next));},configurePreviewServer(server){server.middlewares.use((req,res,next)=>void handler(req,res,next));}};
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
import { describe,it,expect } from 'vitest';
|
||||
import { mkdir,writeFile } from 'node:fs/promises';
|
||||
import path from 'node:path';
|
||||
import { randomUUID } from 'node:crypto';
|
||||
import { findGroundDrawing } from './ground-link-server';
|
||||
const base=path.join(import.meta.dirname,'data/cache/link-tests');
|
||||
describe('지반 프로그램 원본 종평면도 연결',()=>{
|
||||
it('Excel 시작은 도면을 임의로 지정하지 않는다',async()=>expect(await findGroundDrawing('')).toBeUndefined());
|
||||
it('폴더의 종평면도 원본 DWG를 선택하고 변환 DXF와 중복하지 않는다',async()=>{const dir=path.join(base,randomUUID());await mkdir(dir,{recursive:true});await writeFile(path.join(dir,'산외교 종평면도.dwg'),'');await writeFile(path.join(dir,'종평면도.dxf'),'');await writeFile(path.join(dir,'받침배치도.dwg'),'');expect(await findGroundDrawing(dir)).toBe(path.join(dir,'산외교 종평면도.dwg'));});
|
||||
it('서로 다른 종평면도 원본이 여럿이면 사용자 선택으로 남긴다',async()=>{const dir=path.join(base,randomUUID());await mkdir(dir,{recursive:true});await writeFile(path.join(dir,'A교 종평면도.dwg'),'');await writeFile(path.join(dir,'B교 종평면도.dwg'),'');expect(await findGroundDrawing(dir)).toBeUndefined();});
|
||||
});
|
||||
@@ -0,0 +1,75 @@
|
||||
import './ground-popup.css';
|
||||
const API='/__pierzainer/ground-link';
|
||||
let importGround: ((text: string, name: string) => Promise<void>) | undefined;
|
||||
export function registerGroundImporter(importer: (text: string, name: string) => Promise<void>) { importGround = importer; }
|
||||
let pending:{file:File;folder?:string}|undefined,staged:Promise<string|undefined>=Promise.resolve(undefined),version=0;
|
||||
const request=async(action:string,body:object)=>{const r=await fetch(`${API}/${action}`,{method:'POST',headers:{'Content-Type':'application/json','X-Pierzainer-Action':'ground-link'},body:JSON.stringify(body)});const value=await r.json();if(!r.ok)throw new Error(value.error??'지반 프로그램 연동 실패');return value;};
|
||||
const base64=(file:File)=>new Promise<string>((resolve,reject)=>{const reader=new FileReader();reader.onerror=()=>reject(new Error('Excel 파일을 읽지 못했습니다.'));reader.onload=()=>resolve(String(reader.result).split(',')[1]);reader.readAsDataURL(file);});
|
||||
document.addEventListener('change',event=>{const input=event.target as HTMLInputElement;if(input.id==='file'&&input.files?.[0])pending={file:input.files[0]};if(input.id==='project-file'){pending=undefined;version++;staged=Promise.resolve(undefined);}},true);
|
||||
window.addEventListener('pierzainer:ground-source',(event:Event)=>{const d=(event as CustomEvent).detail;pending={file:new File([d.bytes],d.name,{type:'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'}),folder:d.folder};});
|
||||
document.addEventListener('click',event=>{if(!(event.target as Element).closest('#dlg-apply')||!pending)return;const source=pending;pending=undefined;version++;staged=(async()=>{const data=await request('stage',{name:source.file.name,base64:await base64(source.file),folder:source.folder});return data.id as string;})();staged.catch(()=>{});},true);
|
||||
|
||||
let opening=false,running=false,launchSerial=0;
|
||||
let popup:HTMLDialogElement;
|
||||
window.addEventListener('pierzainer:project-changed',()=>{
|
||||
version++;launchSerial++;running=false;opening=false;
|
||||
if(popup){popup.close();popup.querySelector<HTMLElement>('[data-status]')!.textContent='프로젝트가 변경되어 이전 작업의 결과를 연결하지 않습니다.';}
|
||||
});
|
||||
function getPopup(){
|
||||
if(popup)return popup;
|
||||
popup=document.createElement('dialog');popup.className='ground-popup';popup.setAttribute('aria-labelledby','ground-popup-title');
|
||||
popup.innerHTML=`<header><div><small>GROUND MODEL</small><h2 id="ground-popup-title">지반 모델 생성</h2></div><button type="button" data-close aria-label="닫기">×</button></header>
|
||||
<p>종평면도와 교각 Excel로 지반면·위성사진·2D 지도 JSON을 생성합니다.</p>
|
||||
<label for="ground-drawing-file">종평면도 DXF / DWG</label><div class="ground-file-row"><span data-drawing-name></span><button type="button" data-pick="drawing">종평면도 선택</button><input id="ground-drawing-file" data-drawing type="file" accept=".dwg,.dxf" hidden></div>
|
||||
<label for="ground-excel-file">교각 Excel</label><div class="ground-file-row"><span data-excel-name></span><button type="button" data-pick="excel">Excel 선택</button><input id="ground-excel-file" data-excel type="file" accept=".xlsx" hidden></div>
|
||||
<p class="ground-popup-note">기존 생성 엔진을 사용합니다. 지도 다운로드에는 인터넷 연결이 필요합니다.</p>
|
||||
<button type="button" data-run>지반 생성</button><p data-status role="status" aria-live="polite"></p><pre data-logs tabindex="0" aria-label="생성 진행 로그"></pre><footer><button type="button" data-close>닫기</button></footer>`;
|
||||
popup.querySelectorAll<HTMLButtonElement>('[data-pick]').forEach(button=>button.addEventListener('click',()=>popup.querySelector<HTMLInputElement>(`[data-${button.dataset.pick}]`)!.click()));
|
||||
popup.querySelectorAll('[data-close]').forEach(button=>button.addEventListener('click',()=>popup.close()));document.body.append(popup);return popup;
|
||||
}
|
||||
window.addEventListener('pierzainer:open-ground',async()=>{
|
||||
if(opening&&popup?.open)return;if(running&&popup){popup.showModal();opening=true;return;}opening=true;
|
||||
const dialog=getPopup(),ticket=++launchSerial,snapshot=version;
|
||||
const status=dialog.querySelector<HTMLElement>('[data-status]')!,logs=dialog.querySelector<HTMLElement>('[data-logs]')!,run=dialog.querySelector<HTMLButtonElement>('[data-run]')!;
|
||||
const drawingInput=dialog.querySelector<HTMLInputElement>('[data-drawing]')!,excelInput=dialog.querySelector<HTMLInputElement>('[data-excel]')!;
|
||||
drawingInput.value='';excelInput.value='';drawingInput.disabled=excelInput.disabled=false;dialog.querySelector('[data-drawing-name]')!.textContent='파일 확인 중…';dialog.querySelector('[data-excel-name]')!.textContent='파일 확인 중…';run.disabled=true;status.textContent='입력 파일 확인 중…';logs.textContent='';dialog.showModal();
|
||||
let stageId:string|undefined,drawing='';
|
||||
try{stageId=await staged;const prepared=await request('prepare',{stageId});if(snapshot!==version||ticket!==launchSerial)return;drawing=prepared.drawing;
|
||||
const display=(kind:string,name:string,connected:boolean)=>{dialog.querySelector(`[data-${kind}-name]`)!.textContent=name;dialog.querySelector(`[data-pick="${kind}"]`)!.textContent=connected?'파일 변경':kind==='drawing'?'종평면도 선택':'Excel 선택';};
|
||||
const drawingName=drawing.split(/[\\/]/).pop()||'종평면도를 선택하세요.';const excelName=prepared.excelName||'교각 Excel을 선택하세요.';
|
||||
display('drawing',drawingName,!!drawing);display('excel',excelName,prepared.excelSelected);
|
||||
drawingInput.onchange=()=>display('drawing',drawingInput.files?.[0]?.name||drawingName,!!drawingInput.files?.[0]||!!drawing);
|
||||
excelInput.onchange=()=>display('excel',excelInput.files?.[0]?.name||excelName,!!excelInput.files?.[0]||prepared.excelSelected);status.textContent='입력을 확인하고 지반 생성을 누르세요.';run.disabled=false;
|
||||
}catch(error){if(snapshot!==version||ticket!==launchSerial)return;status.textContent=(error as Error).message;opening=false;return;}
|
||||
run.onclick=async()=>{
|
||||
if(snapshot!==version){status.textContent='프로젝트가 변경되었습니다. 닫고 다시 열어 주세요.';return;}
|
||||
run.disabled=true;drawingInput.disabled=excelInput.disabled=true;
|
||||
try{
|
||||
const upload=async(file:File)=>(await request('upload',{name:file.name,base64:await base64(file)})).file as string;
|
||||
status.textContent='입력 파일 전달 중…';const chosen=drawingInput.files?.[0],excel=excelInput.files?.[0];
|
||||
if(chosen)drawing=await upload(chosen);if(!drawing)throw new Error('종평면도를 선택하세요.');
|
||||
const excelPath=excel?await upload(excel):undefined;
|
||||
if(snapshot!==version||ticket!==launchSerial)return;
|
||||
if(!excelPath&&!stageId)throw new Error('교각 Excel을 선택하세요.');
|
||||
const job=await request('launch',{stageId,drawing,excel:excelPath});if(snapshot!==version||ticket!==launchSerial)return;running=true;status.textContent='지반·지도 생성 중… 닫아도 생성은 계속됩니다.';
|
||||
const deadline=Date.now()+30*60*1000;
|
||||
const poll=async()=>{
|
||||
if(snapshot!==version||ticket!==launchSerial)return;
|
||||
try{
|
||||
const result=await request('result',{id:job.id});logs.textContent=result.logs??'';logs.scrollTop=logs.scrollHeight;
|
||||
if(snapshot!==version||ticket!==launchSerial)return;
|
||||
if(result.state==='error')throw new Error('지반 생성 실패. 진행 로그를 확인하세요.');
|
||||
if(result.ready){
|
||||
if(!importGround)throw new Error('프로젝트 지반모델 불러오기를 사용할 수 없습니다.');
|
||||
await importGround(result.text,result.filename);
|
||||
status.textContent='지반 생성 완료. 프로젝트 공통 모델로 불러왔습니다. 관리창에서 비교 후 적용하세요.';
|
||||
running=false;run.disabled=false;drawingInput.disabled=excelInput.disabled=false;return;
|
||||
}
|
||||
if(Date.now()>deadline)throw new Error('응답 대기 시간이 지났습니다. 결과 폴더를 확인하세요.');setTimeout(poll,2000);
|
||||
}catch(error){if(snapshot!==version||ticket!==launchSerial)return;status.textContent=(error as Error).message;running=false;run.disabled=false;drawingInput.disabled=excelInput.disabled=false;}
|
||||
};setTimeout(poll,1000);
|
||||
}catch(error){if(snapshot!==version||ticket!==launchSerial)return;status.textContent=(error as Error).message;running=false;run.disabled=false;drawingInput.disabled=excelInput.disabled=false;}
|
||||
};
|
||||
});
|
||||
// Closing hides the panel; the current job and its polling continue.
|
||||
document.addEventListener('close',event=>{if(event.target===popup)opening=false;},true);
|
||||
@@ -0,0 +1,5 @@
|
||||
.ground-popup{box-sizing:border-box;width:min(860px,94vw);max-height:90dvh;overflow:auto;border:1px solid #d2dfed;border-radius:16px;padding:26px;background:#fff;color:#14263d;box-shadow:0 24px 90px #10263f40;font-family:inherit}
|
||||
.ground-popup::backdrop{background:#10263f70;backdrop-filter:blur(3px)}
|
||||
.ground-popup header{display:flex;align-items:center;justify-content:space-between}.ground-popup h2{margin:6px 0 16px;font-size:23px}.ground-popup small{color:#087fcb;letter-spacing:.14em}
|
||||
.ground-popup button{font:inherit;cursor:pointer;padding:9px 18px;border-radius:7px;border:1px solid #cbd9e8;background:#f2f7fc;color:#14263d}.ground-popup button:disabled{opacity:.5;cursor:wait}.ground-popup [data-run]{background:#087fcb;color:white;border-color:#087fcb;margin-top:18px}.ground-popup label{display:block;font-weight:600;margin-top:20px}.ground-popup input{display:block;margin-top:9px;max-width:100%;font:inherit}.ground-popup [data-drawing-name],.ground-popup [data-excel-name]{overflow-wrap:anywhere;font-size:12px;color:#64748b;margin-top:7px}.ground-popup-note{font-size:12px;color:#64748b}.ground-popup pre{height:210px;overflow:auto;white-space:pre-wrap;overflow-wrap:anywhere;background:#f5f8fc;border:1px solid #dce6f0;border-radius:8px;padding:12px;font-size:12px}.ground-popup footer{text-align:right}.ground-popup [data-status]{font-size:13px}
|
||||
.ground-popup .ground-file-row{display:flex;align-items:center;gap:14px;margin-top:10px;padding:12px 14px;border:1px solid #dce6f0;border-radius:8px;background:#f8fafc}.ground-popup .ground-file-row span{flex:1;min-width:0;overflow-wrap:anywhere;font-size:14px;color:#14263d;margin:0}.ground-popup .ground-file-row button{flex-shrink:0}.ground-popup input[hidden]{display:none}
|
||||
@@ -1,6 +1,7 @@
|
||||
"""Two-file, AI-free ground-model generator."""
|
||||
from pathlib import Path
|
||||
import os
|
||||
import json
|
||||
import queue
|
||||
import re
|
||||
import threading
|
||||
@@ -10,16 +11,34 @@ from tkinter import filedialog, messagebox, scrolledtext, ttk
|
||||
from .drawing_job import ROOT, build_from_files
|
||||
|
||||
|
||||
def read_launch_context():
|
||||
filename=os.environ.get('PIERZAINER_GROUND_CONTEXT')
|
||||
if not filename:return {}
|
||||
file=Path(filename).resolve()
|
||||
if not file.is_relative_to((ROOT/'data/cache').resolve()):raise ValueError('지반 연동 설정 경로가 올바르지 않습니다.')
|
||||
data=json.loads(file.read_text(encoding='utf-8'))
|
||||
for key,extensions in [('drawing',('.dwg','.dxf')),('piers',('.xlsx',))]:
|
||||
value=data.get(key,'')
|
||||
if value and (not Path(value).is_file() or Path(value).suffix.lower() not in extensions):raise ValueError(f'{key} 입력 파일이 없습니다.')
|
||||
if data.get('output') and not Path(data['output']).resolve().is_relative_to((ROOT/'data/output').resolve()):raise ValueError('결과 폴더는 지반 프로젝트 내부여야 합니다.')
|
||||
if data.get('ready_file') and not Path(data['ready_file']).resolve().is_relative_to((ROOT/'data/cache').resolve()):raise ValueError('실행 확인 경로가 올바르지 않습니다.')
|
||||
return data
|
||||
|
||||
|
||||
class GroundModelApp(tk.Tk):
|
||||
def __init__(self):
|
||||
def __init__(self,context=None):
|
||||
super().__init__()
|
||||
self.title('Pierzainer 지반모델링 · 도면 + Excel 자동 생성 v2')
|
||||
self.geometry('1000x640');self.minsize(850,540)
|
||||
self.drawing=tk.StringVar();self.piers=tk.StringVar()
|
||||
context=context or {};self._linked_output=context.get('output')
|
||||
self.drawing=tk.StringVar(value=context.get('drawing',''));self.piers=tk.StringVar(value=context.get('piers',''))
|
||||
self.output=tk.StringVar(value=str(ROOT/'data/output'))
|
||||
self.status=tk.StringVar(value='종평면도와 교각 Excel을 선택하세요')
|
||||
self.messages=queue.Queue();self.busy=False
|
||||
self._build();self.after(100,self._poll)
|
||||
if self._linked_output or self.drawing.get():self._output_folder()
|
||||
if context.get('message'):self.status.set(context['message'])
|
||||
if context.get('ready_file'):Path(context['ready_file']).write_text('ready',encoding='utf-8')
|
||||
|
||||
def _build(self):
|
||||
main=ttk.Frame(self,padding=16);main.pack(fill='both',expand=True)
|
||||
@@ -28,12 +47,12 @@ class GroundModelApp(tk.Tk):
|
||||
for row,key,label in ((1,'drawing','① 종평면도 DXF/DWG'),(2,'piers','② 교각 Excel')):
|
||||
ttk.Label(main,text=label).grid(row=row,column=0,sticky='w',pady=6)
|
||||
ttk.Entry(main,textvariable=getattr(self,key)).grid(row=row,column=1,sticky='ew',padx=10)
|
||||
ttk.Button(main,text='찾기',command=lambda k=key:self._browse(k)).grid(row=row,column=2)
|
||||
ttk.Button(main,text='종평면도 선택하기' if key=='drawing' else 'Excel 선택하기',command=lambda k=key:self._browse(k)).grid(row=row,column=2)
|
||||
ttk.Label(main,text='결과 저장 위치').grid(row=3,column=0,sticky='w',pady=6)
|
||||
ttk.Entry(main,textvariable=self.output,state='readonly').grid(row=3,column=1,columnspan=2,sticky='ew',padx=(10,0))
|
||||
ttk.Label(main,text='두 파일만 선택하면 지반면 + 위성사진 + 2D 지도를 생성합니다. AI 연결 없이 OSM/Esri 인터넷 지도를 사용합니다.\n원본에 좌표계 표기가 없으면 프로젝트 기본 EPSG:5186을 적용하고, 좌표계 가정으로 표시합니다.',foreground='#4f6070',wraplength=920).grid(row=4,column=0,columnspan=3,sticky='w',pady=12)
|
||||
buttons=ttk.Frame(main);buttons.grid(row=5,column=0,columnspan=3,sticky='ew',pady=6)
|
||||
self.run_button=ttk.Button(buttons,text='지반 모델 자동 생성',command=self._start_run);self.run_button.pack(side='left')
|
||||
self.run_button=ttk.Button(buttons,text='지반 생성',command=self._start_run);self.run_button.pack(side='left')
|
||||
ttk.Button(buttons,text='결과 폴더 열기',command=self._open_out).pack(side='left',padx=10)
|
||||
ttk.Label(main,textvariable=self.status).grid(row=6,column=0,columnspan=3,sticky='w',pady=6)
|
||||
self.log=scrolledtext.ScrolledText(main,height=18,font=('Consolas',10))
|
||||
@@ -52,7 +71,7 @@ class GroundModelApp(tk.Tk):
|
||||
|
||||
def _output_folder(self):
|
||||
name=re.sub(r'[^\w.-]+','_',Path(self.drawing.get()).stem).strip('.') or 'new_drawing'
|
||||
self.output.set(str(ROOT/'data/output'/('drawing_'+name)))
|
||||
self.output.set(self._linked_output or str(ROOT/'data/output'/('drawing_'+name)))
|
||||
|
||||
def _open_out(self):
|
||||
path=Path(self.output.get())
|
||||
@@ -93,7 +112,7 @@ class GroundModelApp(tk.Tk):
|
||||
|
||||
|
||||
def main():
|
||||
app=GroundModelApp();app.mainloop();return 0
|
||||
app=GroundModelApp(read_launch_context());app.mainloop();return 0
|
||||
|
||||
|
||||
if __name__=='__main__':raise SystemExit(main())
|
||||
@@ -29,6 +29,18 @@ class TerrainData:
|
||||
stats: dict = field(default_factory=dict)
|
||||
|
||||
|
||||
def _exe_path_arg(exe: str, file: Path) -> str:
|
||||
"""Windows .exe를 WSL/Linux에서 부를 때 경로를 Windows 형식으로 바꾼다."""
|
||||
import os
|
||||
if os.name == "nt" or not exe.lower().endswith(".exe"):
|
||||
return str(file)
|
||||
wslpath = shutil.which("wslpath")
|
||||
if not wslpath:
|
||||
return str(file)
|
||||
result = subprocess.run([wslpath, "-w", str(Path(file).resolve())], check=False, capture_output=True, text=True)
|
||||
return result.stdout.strip() if result.returncode == 0 and result.stdout.strip() else str(file)
|
||||
|
||||
|
||||
def convert_dwg_to_dxf(dwg: str | Path, out_dir: str | Path) -> Path:
|
||||
"""LibreDWG의 dwg2dxf 로 DWG를 DXF로 바꾼다."""
|
||||
exe = shutil.which("dwg2dxf")
|
||||
@@ -55,7 +67,7 @@ def convert_dwg_to_dxf(dwg: str | Path, out_dir: str | Path) -> Path:
|
||||
temporary=out.with_name(out.stem+'.converting.dxf')
|
||||
try:
|
||||
temporary.unlink(missing_ok=True)
|
||||
result=subprocess.run([exe, "-y", "-o", str(temporary), str(dwg)], check=False, capture_output=True, timeout=300)
|
||||
result=subprocess.run([exe, "-y", "-o", _exe_path_arg(exe,temporary), _exe_path_arg(exe,dwg)], check=False, capture_output=True, timeout=300)
|
||||
if result.returncode!=0 or not temporary.is_file() or temporary.stat().st_size==0:
|
||||
raise RuntimeError(f"DWG 변환에 실패했습니다: {dwg}")
|
||||
temporary.replace(out)
|
||||
|
||||
@@ -17,6 +17,45 @@ from pierzainer_ground.dtm import DTM
|
||||
ROOT=Path(__file__).resolve().parent.parent
|
||||
|
||||
|
||||
def reject_height_outliers(entities, radius=15.0, max_dz=10.0, min_levels=3, same=1e-3):
|
||||
"""Drop height entities that disagree with the surrounding surveyed surface.
|
||||
|
||||
Drawings often keep plan symbols, hatching or design outlines at a stray
|
||||
constant elevation (e.g. EL 5.624 or -112.719 among 20-40 m contours).
|
||||
Each entity's height is compared with the median of the *distinct* nearby
|
||||
height levels (each level votes once, so a dense stray group of short
|
||||
ticks cannot outvote real contours); the worst height level is removed
|
||||
first and the test is repeated, so a large stray group cannot mask itself.
|
||||
Sparse areas fall back to a 3x search radius.
|
||||
Heights within `same` (1 mm) form one level, absorbing CAD float noise.
|
||||
Returns (keep flags, [(index, z, deviation)]).
|
||||
"""
|
||||
from scipy.spatial import cKDTree
|
||||
n=len(entities)
|
||||
keep=np.ones(n,bool)
|
||||
if n<3:return keep.tolist(),[]
|
||||
xy=np.vstack([e[0] for e in entities]);owner=np.concatenate([np.full(len(e[0]),i) for i,e in enumerate(entities)])
|
||||
zs=np.array([float(e[1]) for e in entities]);sample_z=zs[owner]
|
||||
tree=cKDTree(xy);rejected=[]
|
||||
near=lambda e,r:np.unique(np.concatenate(tree.query_ball_point(e[0],r)) if len(e[0]) else np.array([],int)).astype(int)
|
||||
neighbours=[near(e,radius) for e in entities];wide=[near(e,3*radius) for e in entities]
|
||||
for _ in range(64):
|
||||
alive=keep[owner];dev=np.zeros(n)
|
||||
for i in np.flatnonzero(keep):
|
||||
nb=neighbours[i];nb=nb[alive[nb]&(np.abs(sample_z[nb]-zs[i])>same)]
|
||||
if len(np.unique(np.round(sample_z[nb]/same)))<min_levels:nb=wide[i];nb=nb[alive[nb]&(np.abs(sample_z[nb]-zs[i])>same)]
|
||||
levels=np.unique(np.round(sample_z[nb]/same))*same
|
||||
# Peaks/pits legitimately exceed the median; require the height to
|
||||
# lie clearly outside the whole local range as well.
|
||||
outside=max(levels[0]-zs[i],zs[i]-levels[-1]) if len(levels) else 0.0
|
||||
if len(levels)>=min_levels and outside>max_dz/2:dev[i]=zs[i]-float(np.median(levels))
|
||||
worst=int(np.argmax(np.abs(dev)))
|
||||
if abs(dev[worst])<=max_dz:break
|
||||
group=np.flatnonzero(keep&(np.abs(zs-zs[worst])<=same)&(np.abs(dev)>max_dz))
|
||||
keep[group]=False;rejected.extend((int(i),float(zs[i]),float(dev[i])) for i in group)
|
||||
return keep.tolist(),rejected
|
||||
|
||||
|
||||
def read_survey_block(source, project, doc=None):
|
||||
"""Read actual height geometry in an explicitly selected survey block."""
|
||||
if doc is None:
|
||||
@@ -54,9 +93,11 @@ def read_survey_block(source, project, doc=None):
|
||||
if e.is_closed: xy.append(xy[0])
|
||||
contours.append((xy,float(a[0,2]),e.dxf.handle)); types['constant_height_polylines']+=1
|
||||
# POINT entities have priority over densified contour vertices.
|
||||
for xy,z,handle in contours:
|
||||
samples=_densify(xy,project['contour_step_m'])
|
||||
points.extend((x,y,z) for x,y in samples)
|
||||
sampled=[(np.asarray(_densify(xy,project['contour_step_m']),dtype=float).reshape(-1,2),z) for xy,z,handle in contours]
|
||||
sampled=[(np.array([[x,y]]),z) for x,y,z in points]+sampled
|
||||
keep,rejected=reject_height_outliers(sampled,project.get('outlier_radius_m',15.0),project.get('outlier_dz_m',10.0)) if project.get('reject_outliers',True) else ([True]*len(sampled),[])
|
||||
if rejected:types['rejected_height_outliers']=len(rejected)
|
||||
points=[(x,y,z) for (xy,z),ok in zip(sampled,keep) if ok for x,y in xy]
|
||||
a=np.array(points,dtype=float)
|
||||
if len(a)<3:
|
||||
raise ValueError('선택한 블록에서 실제 표고점·등고선을 3점 이상 읽지 못했습니다.')
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
"""Run the existing generator for the in-app dialog, without a native window."""
|
||||
import sys
|
||||
from .drawing_job import build_from_files
|
||||
|
||||
if __name__ == '__main__':
|
||||
try:
|
||||
build_from_files(sys.argv[1], sys.argv[2], lambda message: print(message, flush=True), output=sys.argv[3])
|
||||
except Exception as error:
|
||||
print(str(error), file=sys.stderr, flush=True)
|
||||
sys.exit(1)
|
||||
@@ -0,0 +1,26 @@
|
||||
import { describe,it,expect } from 'vitest';
|
||||
import path from 'node:path';
|
||||
import { resolvePython,describeSpawnError } from './python-runtime';
|
||||
|
||||
const root='/repo',venv=path.join(root,'pierzainer_ground','.venv');
|
||||
const has=(...files:string[])=>(file:string)=>files.includes(file);
|
||||
|
||||
describe('resolvePython',()=>{
|
||||
it('uses the Windows venv on win32',()=>{
|
||||
const exe=path.join(venv,'Scripts','python.exe');
|
||||
expect(resolvePython(root,'win32',has(exe),{})).toBe(exe);
|
||||
});
|
||||
it('uses the POSIX venv on Linux/WSL',()=>{
|
||||
const bin=path.join(venv,'bin','python');
|
||||
expect(resolvePython(root,'linux',has(bin),{})).toBe(bin);
|
||||
});
|
||||
it('falls back to PIERZAINER_PYTHON, then python3 / python',()=>{
|
||||
expect(resolvePython(root,'linux',has(),{PIERZAINER_PYTHON:'/opt/py'})).toBe('/opt/py');
|
||||
expect(resolvePython(root,'linux',has(),{})).toBe('python3');
|
||||
expect(resolvePython(root,'win32',has(),{})).toBe('python');
|
||||
});
|
||||
it('explains ENOENT instead of the raw spawn message',()=>{
|
||||
const error=Object.assign(new Error('spawn python ENOENT'),{code:'ENOENT'});
|
||||
expect(describeSpawnError(error,'python')).toContain('Python 실행 파일을 찾지 못했습니다');
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,20 @@
|
||||
import { existsSync } from 'node:fs';
|
||||
import path from 'node:path';
|
||||
|
||||
/**
|
||||
* Python used by the local dev-server tools (ground engine, quantity workbook, DWG export).
|
||||
* Order: Windows venv → POSIX venv (WSL/Linux) → PIERZAINER_PYTHON → python3/python on PATH.
|
||||
*/
|
||||
export function resolvePython(root:string,platform:NodeJS.Platform=process.platform,exists:(file:string)=>boolean=existsSync,env:NodeJS.ProcessEnv=process.env):string{
|
||||
const venv=path.join(root,'pierzainer_ground','.venv');
|
||||
const candidates=platform==='win32'?[path.join(venv,'Scripts','python.exe')]:[path.join(venv,'bin','python'),path.join(venv,'Scripts','python.exe')];
|
||||
const found=candidates.find(file=>exists(file));if(found)return found;
|
||||
if(env.PIERZAINER_PYTHON)return env.PIERZAINER_PYTHON;
|
||||
return platform==='win32'?'python':'python3';
|
||||
}
|
||||
|
||||
/** Human-readable reason for a failed spawn (ENOENT otherwise shows only "spawn python ENOENT"). */
|
||||
export function describeSpawnError(error:NodeJS.ErrnoException,python:string):string{
|
||||
if(error.code==='ENOENT')return `Python 실행 파일을 찾지 못했습니다(${python}). pierzainer_ground/.venv를 만들고 requirements.txt를 설치하거나 PIERZAINER_PYTHON을 지정하세요.`;
|
||||
return error.message;
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
import os,json,unittest,uuid
|
||||
from pathlib import Path
|
||||
from unittest.mock import patch
|
||||
from pierzainer_ground.app import read_launch_context,GroundModelApp,ROOT
|
||||
|
||||
class AppLinkTest(unittest.TestCase):
|
||||
def setUp(self):
|
||||
self.cache=ROOT/'data/cache'/('gui_link_test_'+uuid.uuid4().hex);self.cache.mkdir(parents=True)
|
||||
self.excel=ROOT.parent/'도면추출/samples/샘플01_산외교_교각입력데이터.xlsx'
|
||||
self.drawing=ROOT/'data/input/sanwoe/02.종평면도(울산)_2017.0619-수정.dwg'
|
||||
def config(self,drawing=''):
|
||||
return dict(piers=str(self.excel),drawing=drawing,output=str(ROOT/'data/output'/self.cache.name),ready_file=str(self.cache/'ready'))
|
||||
def test_excel_has_empty_drawing_and_keeps_workbook(self):
|
||||
file=self.cache/'context.json';file.write_text(json.dumps(self.config()),encoding='utf-8')
|
||||
with patch.dict(os.environ,PIERZAINER_GROUND_CONTEXT=str(file)):
|
||||
context=read_launch_context();self.assertEqual(context['drawing'],'');self.assertEqual(context['piers'],str(self.excel))
|
||||
def test_native_gui_prefills_both_and_calls_existing_pipeline(self):
|
||||
context=self.config(str(self.drawing));app=GroundModelApp(context);app.withdraw()
|
||||
try:
|
||||
self.assertEqual(app.drawing.get(),str(self.drawing));self.assertEqual(app.piers.get(),str(self.excel));self.assertEqual(app.output.get(),context['output']);self.assertEqual(app.run_button['text'],'지반 생성')
|
||||
with patch('pierzainer_ground.app.build_from_files',return_value={'map_status':{'status':'mapped'}}) as run:
|
||||
app._start_run();kind,message=app.messages.get(timeout=3);self.assertEqual(kind,'done');self.assertEqual(run.call_args.args[:2],(str(self.drawing),str(self.excel)));self.assertEqual(run.call_args.kwargs['output'],context['output'])
|
||||
finally:
|
||||
for token in app.tk.call('after','info'):app.after_cancel(token)
|
||||
app.destroy()
|
||||
def test_bad_output_is_rejected(self):
|
||||
context=self.config();context['output']=str(ROOT.parent);file=self.cache/'context.json';file.write_text(json.dumps(context),encoding='utf-8')
|
||||
with patch.dict(os.environ,PIERZAINER_GROUND_CONTEXT=str(file)),self.assertRaises(ValueError):read_launch_context()
|
||||
if __name__=='__main__':unittest.main()
|
||||
@@ -25,4 +25,23 @@ class SurveyPolylineTests(unittest.TestCase):
|
||||
doc=ezdxf.new();doc.modelspace().add_polyline3d([(1,1,20),(2,2,30),(3,3,40)])
|
||||
with self.assertRaises(ValueError):read_survey_block(Path('unused.dxf'),self.options(),doc=doc)
|
||||
|
||||
def contours(self,msp,levels):
|
||||
for k,z in enumerate(levels):
|
||||
msp.add_lwpolyline([(0,10*k),(200,10*k)],dxfattribs={'elevation':z})
|
||||
|
||||
def test_stray_constant_height_symbols_are_rejected(self):
|
||||
# Ungok case: dense short ticks at EL 5.624 and a few at -112.719 among 20-40 m contours.
|
||||
doc=ezdxf.new();msp=doc.modelspace();self.contours(msp,[28,29,30,31,32,33])
|
||||
for i in range(60):msp.add_lwpolyline([(40+2*i,20),(40+2*i,22)],dxfattribs={'elevation':5.624})
|
||||
for i in range(4):msp.add_lwpolyline([(100+i,25),(100+i,27)],dxfattribs={'elevation':-112.719})
|
||||
points,counts,_=read_survey_block(Path('unused.dxf'),self.options(),doc=doc)
|
||||
self.assertEqual(counts['rejected_height_outliers'],64)
|
||||
self.assertGreaterEqual(points[:,2].min(),28)
|
||||
|
||||
def test_real_peak_above_contours_is_kept(self):
|
||||
doc=ezdxf.new();msp=doc.modelspace();self.contours(msp,[70,72,74,76,78,80])
|
||||
msp.add_lwpolyline([(100,25),(100,27)],dxfattribs={'elevation':84})
|
||||
points,counts,_=read_survey_block(Path('unused.dxf'),self.options(),doc=doc)
|
||||
self.assertNotIn('rejected_height_outliers',counts);self.assertEqual(points[:,2].max(),84)
|
||||
|
||||
if __name__=='__main__':unittest.main()
|
||||
Regular → Executable
File mode changed.
Regular → Executable
File mode changed.
Regular → Executable
File mode changed.
Regular → Executable
File mode changed.
Regular → Executable
File mode changed.
Regular → Executable
File mode changed.
Regular → Executable
File mode changed.
Regular → Executable
File mode changed.
Regular → Executable
File mode changed.
Regular → Executable
File mode changed.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1 @@
|
||||
{"schemaVersion":1,"project":{"name":"샘플 01 · 산외교","bridge":"산외교","client":"","author":"","crs":"EPSG:5187","memo":"도면추출 연동 샘플 + 원도면 지반. 설계 지반고 유지. 지도 CRS는 원자료 확인이 필요한 가정(inferred_location_checked)."},"source":{"fileName":"샘플01_산외교_교각입력데이터.xlsx","sheets":["Pier","IP","Bearing"]},"piers":[{"id":"P1","input":{"columnDiameterMm":2000,"footingLengthMm":10400,"footingWidthMm":8150,"footingHeightMm":2000,"blindingMarginMm":100,"blindingThicknessMm":100,"pileKind":"강관","pileOuterMm":609.6,"pileThicknessMm":12,"copingH1Mm":1000,"copingH2Mm":1500,"levelWidthMm":2100,"name":"P1","sheet":"Pier","type":"T형","copingTopEl":71.0632,"footingBottomEl":42.763,"groundEl":52.099,"foundationType":"직접기초","pileLengthMm":0,"copingWidthMm":4000,"copingLengthMm":12500,"columnCount":1,"ips":[{"name":"IP1","x":180993.7987,"y":324479.775,"angleDeg":0},{"name":"IP2","x":180993.0547,"y":324478.3023,"angleDeg":0},{"name":"IP3","x":180988.2522,"y":324468.7966,"angleDeg":0},{"name":"IP4","x":0,"y":0,"angleDeg":0}],"bearings":[{"no":1,"x":180991.8227,"y":324477.5242,"z":71.4178,"azimuthDeg":296.79913888888893,"row":"전열"},{"no":2,"x":180988.9134,"y":324471.7116,"z":71.2882,"azimuthDeg":296.7994166666667,"row":"전열"},{"no":3,"x":180993.2484,"y":324476.8038,"z":71.4401,"azimuthDeg":296.81624999999997,"row":"후열"},{"no":4,"x":180990.2925,"y":324471.0147,"z":71.3096,"azimuthDeg":296.81597222222223,"row":"후열"}],"bearingAzimuthFrame":"model-xy"},"defaults":{"columnDiameterMm":2000,"footingLengthMm":10400,"footingWidthMm":8150,"footingHeightMm":2000,"blindingMarginMm":100,"blindingThicknessMm":100,"pileKind":"강관","pileOuterMm":609.6,"pileThicknessMm":12,"copingH1Mm":1000,"copingH2Mm":1500,"levelWidthMm":2100,"name":"P1","sheet":"Pier","type":"T형","copingTopEl":71.0632,"footingBottomEl":42.763,"groundEl":52.099,"foundationType":"직접기초","pileLengthMm":0,"copingWidthMm":4000,"copingLengthMm":12500,"columnCount":1,"ips":[{"name":"IP1","x":180993.7987,"y":324479.775,"angleDeg":0},{"name":"IP2","x":180993.0547,"y":324478.3023,"angleDeg":0},{"name":"IP3","x":180988.2522,"y":324468.7966,"angleDeg":0},{"name":"IP4","x":0,"y":0,"angleDeg":0}],"bearings":[{"no":1,"x":180991.8227,"y":324477.5242,"z":71.4178,"azimuthDeg":296.79913888888893,"row":"전열"},{"no":2,"x":180988.9134,"y":324471.7116,"z":71.2882,"azimuthDeg":296.7994166666667,"row":"전열"},{"no":3,"x":180993.2484,"y":324476.8038,"z":71.4401,"azimuthDeg":296.81624999999997,"row":"후열"},{"no":4,"x":180990.2925,"y":324471.0147,"z":71.3096,"azimuthDeg":296.81597222222223,"row":"후열"}],"bearingAzimuthFrame":"model-xy"},"draft":{"columnDiameterMm":2000,"footingLengthMm":10400,"footingWidthMm":8150,"footingHeightMm":2000,"blindingMarginMm":100,"blindingThicknessMm":100,"pileKind":"강관","pileOuterMm":609.6,"pileThicknessMm":12,"copingH1Mm":1000,"copingH2Mm":1500,"levelWidthMm":2100,"name":"P1","sheet":"Pier","type":"T형","copingTopEl":71.0632,"footingBottomEl":42.763,"groundEl":52.099,"foundationType":"직접기초","pileLengthMm":0,"copingWidthMm":4000,"copingLengthMm":12500,"columnCount":1,"ips":[{"name":"IP1","x":180993.7987,"y":324479.775,"angleDeg":0},{"name":"IP2","x":180993.0547,"y":324478.3023,"angleDeg":0},{"name":"IP3","x":180988.2522,"y":324468.7966,"angleDeg":0},{"name":"IP4","x":0,"y":0,"angleDeg":0}],"bearings":[{"no":1,"x":180991.8227,"y":324477.5242,"z":71.4178,"azimuthDeg":296.79913888888893,"row":"전열"},{"no":2,"x":180988.9134,"y":324471.7116,"z":71.2882,"azimuthDeg":296.7994166666667,"row":"전열"},{"no":3,"x":180993.2484,"y":324476.8038,"z":71.4401,"azimuthDeg":296.81624999999997,"row":"후열"},{"no":4,"x":180990.2925,"y":324471.0147,"z":71.3096,"azimuthDeg":296.81597222222223,"row":"후열"}],"bearingAzimuthFrame":"model-xy"}},{"id":"P2","input":{"columnDiameterMm":2000,"footingLengthMm":10400,"footingWidthMm":8150,"footingHeightMm":2000,"blindingMarginMm":100,"blindingThicknessMm":100,"pileKind":"강관","pileOuterMm":609.6,"pileThicknessMm":12,"copingH1Mm":1000,"copingH2Mm":1500,"levelWidthMm":2100,"name":"P2","sheet":"Pier","type":"T형","copingTopEl":71.9164,"footingBottomEl":38.916,"groundEl":41.319,"foundationType":"말뚝기초","pileLengthMm":7000,"copingWidthMm":4000,"copingLengthMm":12500,"columnCount":1,"ips":[{"name":"IP1","x":181033.8891,"y":324459.3055,"angleDeg":0},{"name":"IP2","x":181033.1327,"y":324457.8391,"angleDeg":0},{"name":"IP3","x":181028.2505,"y":324448.3741,"angleDeg":0},{"name":"IP4","x":0,"y":0,"angleDeg":0}],"bearings":[{"no":1,"x":181031.8943,"y":324457.0714,"z":72.2629,"azimuthDeg":297.2810833333333,"row":"전열"},{"no":2,"x":181028.9384,"y":324451.2823,"z":72.1334,"azimuthDeg":297.2813611111111,"row":"전열"},{"no":3,"x":181033.3136,"y":324456.3392,"z":72.2932,"azimuthDeg":297.29819444444445,"row":"후열"},{"no":4,"x":181030.3037,"y":324450.578,"z":72.1626,"azimuthDeg":297.29783333333336,Line truncated
|
||||
@@ -0,0 +1 @@
|
||||
{"schemaVersion":1,"project":{"name":"샘플 02 · 운곡교","bridge":"운곡교","client":"","author":"","crs":"EPSG:5186","memo":"도면추출 연동 샘플 + 원도면 지반. 설계 지반고 유지. 지도 CRS는 원자료 확인이 필요한 가정(project_default_not_source_verified)."},"source":{"fileName":"샘플02_운곡교_교각입력데이터.xlsx","sheets":["Pier","IP","Bearing"]},"piers":[{"id":"P1","input":{"columnDiameterMm":2000,"footingLengthMm":10400,"footingWidthMm":8150,"footingHeightMm":2000,"blindingMarginMm":100,"blindingThicknessMm":100,"pileKind":"강관","pileOuterMm":609.6,"pileThicknessMm":12,"copingH1Mm":1000,"copingH2Mm":1500,"levelWidthMm":2100,"name":"P1","sheet":"Pier","type":"T형","copingTopEl":43.411,"footingBottomEl":26.208,"groundEl":28.931,"foundationType":"말뚝기초","pileLengthMm":24400,"copingWidthMm":3500,"copingLengthMm":12500,"columnCount":1,"ips":[{"name":"IP1","x":179132.091213,"y":259866.694501,"angleDeg":0},{"name":"IP2","x":179144.095968,"y":259864.658395,"angleDeg":0},{"name":"IP3","x":179144.086088,"y":259864.66007,"angleDeg":0},{"name":"IP4","x":0,"y":0,"angleDeg":0}],"bearings":[{"no":1,"x":179132.9863,"y":259865.8348,"z":43.625,"azimuthDeg":14.051138888888886,"row":"전열"},{"no":2,"x":179135.4565,"y":259865.4158,"z":43.697,"azimuthDeg":14.046083333333343,"row":"전열"},{"no":3,"x":179137.9267,"y":259864.9969,"z":43.768,"azimuthDeg":14.041055555555545,"row":"전열"},{"no":4,"x":179140.3968,"y":259864.578,"z":43.84,"azimuthDeg":14.036000000000001,"row":"전열"},{"no":5,"x":179142.867,"y":259864.1591,"z":43.912,"azimuthDeg":14.031000000000006,"row":"전열"},{"no":6,"x":179133.2876,"y":259867.0998,"z":43.6,"azimuthDeg":12.74124999999998,"row":"후열"},{"no":7,"x":179135.7577,"y":259866.6809,"z":43.672,"azimuthDeg":12.737694444444458,"row":"후열"},{"no":8,"x":179138.2278,"y":259866.262,"z":43.744,"azimuthDeg":12.734138888888879,"row":"후열"},{"no":9,"x":179140.6978,"y":259865.8431,"z":43.816,"azimuthDeg":12.730611111111102,"row":"후열"},{"no":10,"x":179143.1679,"y":259865.4242,"z":43.887,"azimuthDeg":12.72705555555558,"row":"후열"}],"bearingAzimuthFrame":"model-xy"},"defaults":{"columnDiameterMm":2000,"footingLengthMm":10400,"footingWidthMm":8150,"footingHeightMm":2000,"blindingMarginMm":100,"blindingThicknessMm":100,"pileKind":"강관","pileOuterMm":609.6,"pileThicknessMm":12,"copingH1Mm":1000,"copingH2Mm":1500,"levelWidthMm":2100,"name":"P1","sheet":"Pier","type":"T형","copingTopEl":43.411,"footingBottomEl":26.208,"groundEl":28.931,"foundationType":"말뚝기초","pileLengthMm":24400,"copingWidthMm":3500,"copingLengthMm":12500,"columnCount":1,"ips":[{"name":"IP1","x":179132.091213,"y":259866.694501,"angleDeg":0},{"name":"IP2","x":179144.095968,"y":259864.658395,"angleDeg":0},{"name":"IP3","x":179144.086088,"y":259864.66007,"angleDeg":0},{"name":"IP4","x":0,"y":0,"angleDeg":0}],"bearings":[{"no":1,"x":179132.9863,"y":259865.8348,"z":43.625,"azimuthDeg":14.051138888888886,"row":"전열"},{"no":2,"x":179135.4565,"y":259865.4158,"z":43.697,"azimuthDeg":14.046083333333343,"row":"전열"},{"no":3,"x":179137.9267,"y":259864.9969,"z":43.768,"azimuthDeg":14.041055555555545,"row":"전열"},{"no":4,"x":179140.3968,"y":259864.578,"z":43.84,"azimuthDeg":14.036000000000001,"row":"전열"},{"no":5,"x":179142.867,"y":259864.1591,"z":43.912,"azimuthDeg":14.031000000000006,"row":"전열"},{"no":6,"x":179133.2876,"y":259867.0998,"z":43.6,"azimuthDeg":12.74124999999998,"row":"후열"},{"no":7,"x":179135.7577,"y":259866.6809,"z":43.672,"azimuthDeg":12.737694444444458,"row":"후열"},{"no":8,"x":179138.2278,"y":259866.262,"z":43.744,"azimuthDeg":12.734138888888879,"row":"후열"},{"no":9,"x":179140.6978,"y":259865.8431,"z":43.816,"azimuthDeg":12.730611111111102,"row":"후열"},{"no":10,"x":179143.1679,"y":259865.4242,"z":43.887,"azimuthDeg":12.72705555555558,"row":"후열"}],"bearingAzimuthFrame":"model-xy"},"draft":{"columnDiameterMm":2000,"footingLengthMm":10400,"footingWidthMm":8150,"footingHeightMm":2000,"blindingMarginMm":100,"blindingThicknessMm":100,"pileKind":"강관","pileOuterMm":609.6,"pileThicknessMm":12,"copingH1Mm":1000,"copingH2Mm":1500,"levelWidthMm":2100,"name":"P1","sheet":"Pier","type":"T형","copingTopEl":43.411,"footingBottomEl":26.208,"groundEl":28.931,"foundationType":"말뚝기초","pileLengthMm":24400,"copingWidthMm":3500,"copingLengthMm":12500,"columnCount":1,"ips":[{"name":"IP1","x":179132.091213,"y":259866.694501,"angleDeg":0},{"name":"IP2","x":179144.095968,"y":259864.658395,"angleDeg":0},{"name":"IP3","x":179144.086088,"y":259864.66007,"angleDeg":0},{"name":"IP4","x":0,"y":0,"angleDeg":0}],"bearings":[{"no":1,"x":179132.9863,"y":259865.8348,"z":43.625,"azimuthDeg":14.051138888888886,"row":"전열"},{"no":2,"x":179135.4565,"y":259865.4158,"z":43.697,"azimuthDeg":14.046083333333343,"row":"전열"},{"no":3,"x":179137.9267,"y":259864.9969,"z":43.768,"azimuthDeg":14.041055555555545,"row":"전열"},{"no":4,"x":179140.3968,"y":25986Line truncated
|
||||
@@ -0,0 +1 @@
|
||||
{"schemaVersion":1,"project":{"name":"샘플 03 · 대호지교","bridge":"대호지교","client":"","author":"","crs":"EPSG:5186","memo":"도면추출 연동 샘플 + 원도면 지반. 설계 지반고 유지. 지도 CRS는 원자료 확인이 필요한 가정(project_default_not_source_verified)."},"source":{"fileName":"샘플03_대호지교_교각입력데이터.xlsx","sheets":["Pier","IP","Bearing"]},"piers":[{"id":"P1","input":{"columnDiameterMm":2000,"footingLengthMm":10400,"footingWidthMm":8150,"footingHeightMm":2000,"blindingMarginMm":100,"blindingThicknessMm":100,"pileKind":"강관","pileOuterMm":609.6,"pileThicknessMm":12,"copingH1Mm":1000,"copingH2Mm":1500,"levelWidthMm":2100,"name":"P1","sheet":"Pier","type":"2주형","copingTopEl":7.738,"footingBottomEl":1.4,"groundEl":-0.342,"foundationType":"현장타설말뚝","pileLengthMm":29802,"copingWidthMm":3500,"copingLengthMm":24500,"columnCount":2,"ips":[{"name":"IP1","x":153837.294388,"y":480726.410803,"angleDeg":0},{"name":"IP2","x":153833.31775,"y":480714.93,"angleDeg":0},{"name":"IP3","x":153829.341111,"y":480703.449196,"angleDeg":0},{"name":"IP4","x":0,"y":0,"angleDeg":0}],"bearings":[{"no":1,"x":153836.266,"y":480725.3912,"z":7.8178,"azimuthDeg":109.10472222222222,"row":"전열"},{"no":2,"x":153835.2514,"y":480722.462,"z":7.8798,"azimuthDeg":109.10472222222222,"row":"전열"},{"no":3,"x":153834.2368,"y":480719.5327,"z":7.9418,"azimuthDeg":109.10472222222222,"row":"전열"},{"no":4,"x":153833.2222,"y":480716.6034,"z":8.0038,"azimuthDeg":109.10472222222222,"row":"전열"},{"no":5,"x":153832.2076,"y":480713.6742,"z":8.0038,"azimuthDeg":109.10472222222222,"row":"전열"},{"no":6,"x":153831.193,"y":480710.7449,"z":7.9418,"azimuthDeg":109.10472222222222,"row":"전열"},{"no":7,"x":153830.1783,"y":480707.8157,"z":7.8798,"azimuthDeg":109.10472222222222,"row":"전열"},{"no":8,"x":153829.1637,"y":480704.8864,"z":7.8178,"azimuthDeg":109.10472222222222,"row":"전열"},{"no":9,"x":153837.4944,"y":480724.9657,"z":7.8243,"azimuthDeg":109.10472222222222,"row":"후열"},{"no":10,"x":153836.4798,"y":480722.0365,"z":7.8863,"azimuthDeg":109.10472222222222,"row":"후열"},{"no":11,"x":153835.4652,"y":480719.1072,"z":7.9483,"azimuthDeg":109.10472222222222,"row":"후열"},{"no":12,"x":153834.4506,"y":480716.178,"z":8.0103,"azimuthDeg":109.10472222222222,"row":"후열"},{"no":13,"x":153833.436,"y":480713.2487,"z":8.0103,"azimuthDeg":109.10472222222222,"row":"후열"},{"no":14,"x":153832.4213,"y":480710.3195,"z":7.9483,"azimuthDeg":109.10472222222222,"row":"후열"},{"no":15,"x":153831.4067,"y":480707.3902,"z":7.8863,"azimuthDeg":109.10472222222222,"row":"후열"},{"no":16,"x":153830.3921,"y":480704.4609,"z":7.8243,"azimuthDeg":109.10472222222222,"row":"후열"}],"bearingAzimuthFrame":"model-xy"},"defaults":{"columnDiameterMm":2000,"footingLengthMm":10400,"footingWidthMm":8150,"footingHeightMm":2000,"blindingMarginMm":100,"blindingThicknessMm":100,"pileKind":"강관","pileOuterMm":609.6,"pileThicknessMm":12,"copingH1Mm":1000,"copingH2Mm":1500,"levelWidthMm":2100,"name":"P1","sheet":"Pier","type":"2주형","copingTopEl":7.738,"footingBottomEl":1.4,"groundEl":-0.342,"foundationType":"현장타설말뚝","pileLengthMm":29802,"copingWidthMm":3500,"copingLengthMm":24500,"columnCount":2,"ips":[{"name":"IP1","x":153837.294388,"y":480726.410803,"angleDeg":0},{"name":"IP2","x":153833.31775,"y":480714.93,"angleDeg":0},{"name":"IP3","x":153829.341111,"y":480703.449196,"angleDeg":0},{"name":"IP4","x":0,"y":0,"angleDeg":0}],"bearings":[{"no":1,"x":153836.266,"y":480725.3912,"z":7.8178,"azimuthDeg":109.10472222222222,"row":"전열"},{"no":2,"x":153835.2514,"y":480722.462,"z":7.8798,"azimuthDeg":109.10472222222222,"row":"전열"},{"no":3,"x":153834.2368,"y":480719.5327,"z":7.9418,"azimuthDeg":109.10472222222222,"row":"전열"},{"no":4,"x":153833.2222,"y":480716.6034,"z":8.0038,"azimuthDeg":109.10472222222222,"row":"전열"},{"no":5,"x":153832.2076,"y":480713.6742,"z":8.0038,"azimuthDeg":109.10472222222222,"row":"전열"},{"no":6,"x":153831.193,"y":480710.7449,"z":7.9418,"azimuthDeg":109.10472222222222,"row":"전열"},{"no":7,"x":153830.1783,"y":480707.8157,"z":7.8798,"azimuthDeg":109.10472222222222,"row":"전열"},{"no":8,"x":153829.1637,"y":480704.8864,"z":7.8178,"azimuthDeg":109.10472222222222,"row":"전열"},{"no":9,"x":153837.4944,"y":480724.9657,"z":7.8243,"azimuthDeg":109.10472222222222,"row":"후열"},{"no":10,"x":153836.4798,"y":480722.0365,"z":7.8863,"azimuthDeg":109.10472222222222,"row":"후열"},{"no":11,"x":153835.4652,"y":480719.1072,"z":7.9483,"azimuthDeg":109.10472222222222,"row":"후열"},{"no":12,"x":153834.4506,"y":480716.178,"z":8.0103,"azimuthDeg":109.10472222222222,"row":"후열"},{"no":13,"x":153833.436,"y":480713.2487,"z":8.0103,"azimuthDeg":109.10472222222222,"row":"후열"},{"no":14,"x":153832.4213,"y":480710.3195,"z":7.9483,"azimuthDeg":109.10472222222222,"row":"후열"},{"no":15,"x":153831.4067,"y":480707.3902,"z":7.8863,"azimuthDeg":109.10472222222222,"Line truncated
|
||||
@@ -0,0 +1 @@
|
||||
{"schemaVersion":1,"project":{"name":"샘플 04 · 목동교","bridge":"목동교","client":"","author":"","crs":"EPSG:5186","memo":"도면추출 연동 샘플 + 원도면 지반. 설계 지반고 유지. 지도 CRS는 원자료 확인이 필요한 가정(project_default_not_source_verified)."},"source":{"fileName":"샘플04_목동교_교각입력데이터.xlsx","sheets":["Pier","IP","Bearing"]},"piers":[{"id":"P1","input":{"columnDiameterMm":2000,"footingLengthMm":10400,"footingWidthMm":8150,"footingHeightMm":2000,"blindingMarginMm":100,"blindingThicknessMm":100,"pileKind":"강관","pileOuterMm":609.6,"pileThicknessMm":12,"copingH1Mm":1000,"copingH2Mm":1500,"levelWidthMm":2100,"name":"P1","sheet":"Pier","type":"2주형","copingTopEl":133.8541,"footingBottomEl":110.854,"groundEl":118.79,"foundationType":"직접기초","pileLengthMm":0,"copingWidthMm":3500,"copingLengthMm":16500,"columnCount":2,"ips":[{"name":"IP1","x":218127.628104,"y":531065.25932,"angleDeg":0},{"name":"IP2","x":218138.896901,"y":531074.320997,"angleDeg":0},{"name":"IP3","x":218140.182759,"y":531075.355006,"angleDeg":0},{"name":"IP4","x":0,"y":0,"angleDeg":0}],"bearings":[{"no":1,"x":218129.3712,"y":531065.8269,"z":133.9411,"azimuthDeg":321.06191666666666,"row":"전열"},{"no":2,"x":218131.265,"y":531067.3497,"z":133.9896,"azimuthDeg":321.0619722222222,"row":"전열"},{"no":3,"x":218133.3535,"y":531069.0291,"z":134.043,"azimuthDeg":321.06202777777776,"row":"전열"},{"no":4,"x":218135.4421,"y":531070.7086,"z":134.0965,"azimuthDeg":321.06208333333336,"row":"전열"},{"no":5,"x":218137.5306,"y":531072.3881,"z":134.15,"azimuthDeg":321.06213888888885,"row":"전열"},{"no":6,"x":218139.4243,"y":531073.9109,"z":134.1985,"azimuthDeg":321.06219444444446,"row":"전열"},{"no":7,"x":218128.5503,"y":531066.8348,"z":133.953,"azimuthDeg":320.60875,"row":"후열"},{"no":8,"x":218130.4438,"y":531068.3578,"z":134.0015,"azimuthDeg":320.60897222222223,"row":"후열"},{"no":9,"x":218132.5324,"y":531070.0373,"z":134.055,"azimuthDeg":320.60922222222223,"row":"후열"},{"no":10,"x":218134.6209,"y":531071.7168,"z":134.1084,"azimuthDeg":320.6094444444444,"row":"후열"},{"no":11,"x":218136.7095,"y":531073.3962,"z":134.1619,"azimuthDeg":320.60966666666667,"row":"후열"},{"no":12,"x":218138.6034,"y":531074.9188,"z":134.2103,"azimuthDeg":320.6098888888889,"row":"후열"}],"bearingAzimuthFrame":"model-xy"},"defaults":{"columnDiameterMm":2000,"footingLengthMm":10400,"footingWidthMm":8150,"footingHeightMm":2000,"blindingMarginMm":100,"blindingThicknessMm":100,"pileKind":"강관","pileOuterMm":609.6,"pileThicknessMm":12,"copingH1Mm":1000,"copingH2Mm":1500,"levelWidthMm":2100,"name":"P1","sheet":"Pier","type":"2주형","copingTopEl":133.8541,"footingBottomEl":110.854,"groundEl":118.79,"foundationType":"직접기초","pileLengthMm":0,"copingWidthMm":3500,"copingLengthMm":16500,"columnCount":2,"ips":[{"name":"IP1","x":218127.628104,"y":531065.25932,"angleDeg":0},{"name":"IP2","x":218138.896901,"y":531074.320997,"angleDeg":0},{"name":"IP3","x":218140.182759,"y":531075.355006,"angleDeg":0},{"name":"IP4","x":0,"y":0,"angleDeg":0}],"bearings":[{"no":1,"x":218129.3712,"y":531065.8269,"z":133.9411,"azimuthDeg":321.06191666666666,"row":"전열"},{"no":2,"x":218131.265,"y":531067.3497,"z":133.9896,"azimuthDeg":321.0619722222222,"row":"전열"},{"no":3,"x":218133.3535,"y":531069.0291,"z":134.043,"azimuthDeg":321.06202777777776,"row":"전열"},{"no":4,"x":218135.4421,"y":531070.7086,"z":134.0965,"azimuthDeg":321.06208333333336,"row":"전열"},{"no":5,"x":218137.5306,"y":531072.3881,"z":134.15,"azimuthDeg":321.06213888888885,"row":"전열"},{"no":6,"x":218139.4243,"y":531073.9109,"z":134.1985,"azimuthDeg":321.06219444444446,"row":"전열"},{"no":7,"x":218128.5503,"y":531066.8348,"z":133.953,"azimuthDeg":320.60875,"row":"후열"},{"no":8,"x":218130.4438,"y":531068.3578,"z":134.0015,"azimuthDeg":320.60897222222223,"row":"후열"},{"no":9,"x":218132.5324,"y":531070.0373,"z":134.055,"azimuthDeg":320.60922222222223,"row":"후열"},{"no":10,"x":218134.6209,"y":531071.7168,"z":134.1084,"azimuthDeg":320.6094444444444,"row":"후열"},{"no":11,"x":218136.7095,"y":531073.3962,"z":134.1619,"azimuthDeg":320.60966666666667,"row":"후열"},{"no":12,"x":218138.6034,"y":531074.9188,"z":134.2103,"azimuthDeg":320.6098888888889,"row":"후열"}],"bearingAzimuthFrame":"model-xy"},"draft":{"columnDiameterMm":2000,"footingLengthMm":10400,"footingWidthMm":8150,"footingHeightMm":2000,"blindingMarginMm":100,"blindingThicknessMm":100,"pileKind":"강관","pileOuterMm":609.6,"pileThicknessMm":12,"copingH1Mm":1000,"copingH2Mm":1500,"levelWidthMm":2100,"name":"P1","sheet":"Pier","type":"2주형","copingTopEl":133.8541,"footingBottomEl":110.854,"groundEl":118.79,"foundationType":"직접기초","pileLengthMm":0,"copingWidthMm":3500,"copingLengthMm":16500,"columnCount":2,"ips":[{"name":"IP1","x":218127.628104,"y":531065.25932,"angleDeg":0},{"name":"IP2","x":218138.896901,"y":531074.320997,"angleDeg":0},{"name":"IP3"Line truncated
|
||||
@@ -0,0 +1 @@
|
||||
{"schemaVersion":1,"project":{"name":"샘플 05 · 승천천교","bridge":"승천천교","client":"","author":"","crs":"EPSG:5186","memo":"도면추출 연동 샘플 + 원도면 지반. 설계 지반고 유지. 지도 CRS는 원자료 확인이 필요한 가정(project_default_not_source_verified)."},"source":{"fileName":"샘플05_승천천교_교각입력데이터.xlsx","sheets":["Pier","IP","Bearing"]},"piers":[],"history":[{"version":"sample-20261102","note":"교각 Excel과 원도면 지반·위성사진·2D 지도 통합. 좌표·스키마·형상 검증.","at":"2026-11-02T14:34:50.364983"}],"bearingBasis":"excel","groundModel":{"schema":2,"generated":"2026-11-02","piers":[{"id":"P1","centerEl":55,"excelEl":null}],"terrainGrid":{"origin":[458809.512,224222.818],"step":5,"nx":41,"ny":41,"z":[null,null,null,null,null,null,null,null,null,null,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55.322,55.896,55.661,55.11,55,55,55,55,55,55,55,55,55,55,null,null,null,null,null,null,null,null,null,null,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55.689,56.161,55.677,55,55,55,55,55,55,55,55,55,55,55,null,null,null,null,null,null,null,null,null,null,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55.78,55.857,55.371,55,55,55,55,55,55,55,55,55,55,55,null,null,null,null,null,null,null,null,null,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55.009,55.119,55.196,55.273,55,55,55,55,55,55,55,55,55,55,55,null,null,null,null,null,null,null,null,null,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,null,null,null,null,null,null,null,null,null,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,null,null,null,null,null,null,null,null,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,null,null,null,null,null,null,null,null,null,null,null,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,null,null,null,null,null,null,null,null,null,null,null,null,null,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,null,null,null,null,null,null,null,null,null,null,null,null,null,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,null,null,null,null,null,null,null,null,null,null,null,null,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,null,null,null,null,null,null,null,null,null,null,null,null,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,null,null,null,null,null,null,null,null,null,null,null,null,null,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,null,null,null,null,null,null,null,null,null,null,null,null,null,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,null,null,null,null,null,null,null,null,null,null,null,null,null,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,null,null,null,null,null,null,null,null,null,null,null,null,null,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,null,null,null,null,null,null,null,null,null,null,null,null,null,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,null,null,null,null,null,null,null,null,null,null,null,null,null,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,null,null,null,null,null,null,null,null,null,null,null,null,null,null,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,null,null,null,null,null,null,null,null,null,null,null,null,null,null,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,null,null,null,null,null,null,null,null,null,null,null,null,null,null,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,null,null,null,null,null,null,null,null,null,null,null,null,null,null,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,null,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,null,null,null,nullLine truncated
|
||||
@@ -0,0 +1 @@
|
||||
{"schemaVersion":1,"project":{"name":"샘플 06 · 계문철교","bridge":"계문철교","client":"","author":"","crs":"EPSG:5186","memo":"도면추출 연동 샘플 + 원도면 지반. 설계 지반고 유지. 지도 CRS는 원자료 확인이 필요한 가정(project_default_not_source_verified)."},"source":{"fileName":"샘플06_계문철교_교각입력데이터.xlsx","sheets":["Pier","IP","Bearing"]},"piers":[{"id":"P1","input":{"columnDiameterMm":2000,"footingLengthMm":10400,"footingWidthMm":8150,"footingHeightMm":2000,"blindingMarginMm":100,"blindingThicknessMm":100,"pileKind":"강관","pileOuterMm":609.6,"pileThicknessMm":12,"copingH1Mm":1000,"copingH2Mm":1500,"levelWidthMm":2100,"name":"P1","sheet":"Pier","type":"2주형","copingTopEl":18.5041,"footingBottomEl":4.804,"groundEl":7.06,"foundationType":"말뚝기초","pileLengthMm":21000,"copingWidthMm":3500,"copingLengthMm":21000,"columnCount":2,"ips":[{"name":"IP1","x":194908.7711,"y":376920.628019,"angleDeg":0},{"name":"IP2","x":194909.621705,"y":376910.212695,"angleDeg":0},{"name":"IP3","x":194910.472309,"y":376899.797371,"angleDeg":0},{"name":"IP4","x":0,"y":0,"angleDeg":0}],"bearings":[{"no":1,"x":194908.2982,"y":376919.5055,"z":19.6384,"azimuthDeg":83.45638888888891,"row":"전열"},{"no":2,"x":194908.5459,"y":376916.4756,"z":19.4854,"azimuthDeg":83.447,"row":"전열"},{"no":3,"x":194908.7936,"y":376913.4458,"z":19.3333,"azimuthDeg":83.43755555555555,"row":"전열"},{"no":4,"x":194909.0413,"y":376910.4159,"z":19.1822,"azimuthDeg":83.42797222222225,"row":"전열"},{"no":5,"x":194909.2891,"y":376907.386,"z":19.0292,"azimuthDeg":83.41830555555555,"row":"전열"},{"no":6,"x":194909.5368,"y":376904.3561,"z":18.8771,"azimuthDeg":83.40855555555555,"row":"전열"},{"no":7,"x":194909.7845,"y":376901.3262,"z":18.7251,"azimuthDeg":83.39869444444446,"row":"전열"},{"no":8,"x":194909.4601,"y":376919.6004,"z":19.6539,"azimuthDeg":87.6826388888889,"row":"후열"},{"no":9,"x":194909.7075,"y":376916.5705,"z":19.5019,"azimuthDeg":87.69441666666665,"row":"후열"},{"no":10,"x":194909.9548,"y":376913.5406,"z":19.3499,"azimuthDeg":87.7063333333333,"row":"후열"},{"no":11,"x":194910.2022,"y":376910.5106,"z":19.1979,"azimuthDeg":87.71836111111111,"row":"후열"},{"no":12,"x":194910.4496,"y":376907.4807,"z":19.0459,"azimuthDeg":87.7305,"row":"후열"},{"no":13,"x":194910.6969,"y":376904.4508,"z":18.8939,"azimuthDeg":87.74277777777775,"row":"후열"},{"no":14,"x":194910.9443,"y":376901.4209,"z":18.7419,"azimuthDeg":87.7551666666667,"row":"후열"}],"bearingAzimuthFrame":"model-xy"},"defaults":{"columnDiameterMm":2000,"footingLengthMm":10400,"footingWidthMm":8150,"footingHeightMm":2000,"blindingMarginMm":100,"blindingThicknessMm":100,"pileKind":"강관","pileOuterMm":609.6,"pileThicknessMm":12,"copingH1Mm":1000,"copingH2Mm":1500,"levelWidthMm":2100,"name":"P1","sheet":"Pier","type":"2주형","copingTopEl":18.5041,"footingBottomEl":4.804,"groundEl":7.06,"foundationType":"말뚝기초","pileLengthMm":21000,"copingWidthMm":3500,"copingLengthMm":21000,"columnCount":2,"ips":[{"name":"IP1","x":194908.7711,"y":376920.628019,"angleDeg":0},{"name":"IP2","x":194909.621705,"y":376910.212695,"angleDeg":0},{"name":"IP3","x":194910.472309,"y":376899.797371,"angleDeg":0},{"name":"IP4","x":0,"y":0,"angleDeg":0}],"bearings":[{"no":1,"x":194908.2982,"y":376919.5055,"z":19.6384,"azimuthDeg":83.45638888888891,"row":"전열"},{"no":2,"x":194908.5459,"y":376916.4756,"z":19.4854,"azimuthDeg":83.447,"row":"전열"},{"no":3,"x":194908.7936,"y":376913.4458,"z":19.3333,"azimuthDeg":83.43755555555555,"row":"전열"},{"no":4,"x":194909.0413,"y":376910.4159,"z":19.1822,"azimuthDeg":83.42797222222225,"row":"전열"},{"no":5,"x":194909.2891,"y":376907.386,"z":19.0292,"azimuthDeg":83.41830555555555,"row":"전열"},{"no":6,"x":194909.5368,"y":376904.3561,"z":18.8771,"azimuthDeg":83.40855555555555,"row":"전열"},{"no":7,"x":194909.7845,"y":376901.3262,"z":18.7251,"azimuthDeg":83.39869444444446,"row":"전열"},{"no":8,"x":194909.4601,"y":376919.6004,"z":19.6539,"azimuthDeg":87.6826388888889,"row":"후열"},{"no":9,"x":194909.7075,"y":376916.5705,"z":19.5019,"azimuthDeg":87.69441666666665,"row":"후열"},{"no":10,"x":194909.9548,"y":376913.5406,"z":19.3499,"azimuthDeg":87.7063333333333,"row":"후열"},{"no":11,"x":194910.2022,"y":376910.5106,"z":19.1979,"azimuthDeg":87.71836111111111,"row":"후열"},{"no":12,"x":194910.4496,"y":376907.4807,"z":19.0459,"azimuthDeg":87.7305,"row":"후열"},{"no":13,"x":194910.6969,"y":376904.4508,"z":18.8939,"azimuthDeg":87.74277777777775,"row":"후열"},{"no":14,"x":194910.9443,"y":376901.4209,"z":18.7419,"azimuthDeg":87.7551666666667,"row":"후열"}],"bearingAzimuthFrame":"model-xy"},"draft":{"columnDiameterMm":2000,"footingLengthMm":10400,"footingWidthMm":8150,"footingHeightMm":2000,"blindingMarginMm":100,"blindingThicknessMm":100,"pileKind":"강관","pileOuterMm":609.6,"pileThicknessMm":12,"copingH1Mm":1000,"copingH2Mm":1500,"levelWidthMm":2100,"name":"P1","sheet":"PieLine truncated
|
||||
@@ -0,0 +1 @@
|
||||
{"schemaVersion":1,"project":{"name":"샘플 07 · 기양천교","bridge":"기양천교","client":"","author":"","crs":"EPSG:5186","memo":"도면추출 연동 샘플 + 원도면 지반. 설계 지반고 유지. 지도 CRS는 원자료 확인이 필요한 가정(project_default_not_source_verified)."},"source":{"fileName":"샘플07_기양천교_교각입력데이터.xlsx","sheets":["Pier","IP","Bearing"]},"piers":[{"id":"P1","input":{"columnDiameterMm":2000,"footingLengthMm":10400,"footingWidthMm":8150,"footingHeightMm":2000,"blindingMarginMm":100,"blindingThicknessMm":100,"pileKind":"강관","pileOuterMm":609.6,"pileThicknessMm":12,"copingH1Mm":1000,"copingH2Mm":1500,"levelWidthMm":2100,"name":"P1","sheet":"Pier","type":"2주형","copingTopEl":15.7665,"footingBottomEl":0.966,"groundEl":5.97,"foundationType":"말뚝기초","pileLengthMm":13600,"copingWidthMm":3500,"copingLengthMm":22500,"columnCount":2,"ips":[{"name":"IP1","x":195901.933872,"y":376676.684353,"angleDeg":0},{"name":"IP2","x":195904.750042,"y":376666.017388,"angleDeg":0},{"name":"IP3","x":195907.564243,"y":376655.357883,"angleDeg":0},{"name":"IP4","x":0,"y":0,"angleDeg":0}],"bearings":[{"no":1,"x":195901.7932,"y":376675.2306,"z":15.9498,"azimuthDeg":94.7138333333333,"row":"전열"},{"no":2,"x":195902.6065,"y":376672.1472,"z":16.0318,"azimuthDeg":94.67783333333335,"row":"전열"},{"no":3,"x":195903.4195,"y":376669.0643,"z":16.1134,"azimuthDeg":94.642,"row":"전열"},{"no":4,"x":195904.2324,"y":376665.9822,"z":16.1956,"azimuthDeg":94.60630555555554,"row":"전열"},{"no":5,"x":195905.045,"y":376662.9006,"z":16.2764,"azimuthDeg":94.57072222222223,"row":"전열"},{"no":6,"x":195905.8574,"y":376659.8197,"z":16.3568,"azimuthDeg":94.53527777777776,"row":"전열"},{"no":7,"x":195906.6696,"y":376656.7394,"z":16.4367,"azimuthDeg":94.4999722222222,"row":"전열"},{"no":8,"x":195902.9584,"y":376675.1501,"z":15.9811,"azimuthDeg":93.19136111111112,"row":"후열"},{"no":9,"x":195903.7717,"y":376672.0673,"z":16.0627,"azimuthDeg":93.15808333333337,"row":"후열"},{"no":10,"x":195904.5848,"y":376668.9852,"z":16.1438,"azimuthDeg":93.12494444444445,"row":"후열"},{"no":11,"x":195905.3977,"y":376665.9037,"z":16.2256,"azimuthDeg":93.09191666666669,"row":"후열"},{"no":12,"x":195906.2105,"y":376662.8229,"z":16.3059,"azimuthDeg":93.05902777777777,"row":"후열"},{"no":13,"x":195907.0231,"y":376659.7426,"z":16.3859,"azimuthDeg":93.02625,"row":"후열"},{"no":14,"x":195907.8355,"y":376656.663,"z":16.4654,"azimuthDeg":92.99358333333333,"row":"후열"}],"bearingAzimuthFrame":"model-xy"},"defaults":{"columnDiameterMm":2000,"footingLengthMm":10400,"footingWidthMm":8150,"footingHeightMm":2000,"blindingMarginMm":100,"blindingThicknessMm":100,"pileKind":"강관","pileOuterMm":609.6,"pileThicknessMm":12,"copingH1Mm":1000,"copingH2Mm":1500,"levelWidthMm":2100,"name":"P1","sheet":"Pier","type":"2주형","copingTopEl":15.7665,"footingBottomEl":0.966,"groundEl":5.97,"foundationType":"말뚝기초","pileLengthMm":13600,"copingWidthMm":3500,"copingLengthMm":22500,"columnCount":2,"ips":[{"name":"IP1","x":195901.933872,"y":376676.684353,"angleDeg":0},{"name":"IP2","x":195904.750042,"y":376666.017388,"angleDeg":0},{"name":"IP3","x":195907.564243,"y":376655.357883,"angleDeg":0},{"name":"IP4","x":0,"y":0,"angleDeg":0}],"bearings":[{"no":1,"x":195901.7932,"y":376675.2306,"z":15.9498,"azimuthDeg":94.7138333333333,"row":"전열"},{"no":2,"x":195902.6065,"y":376672.1472,"z":16.0318,"azimuthDeg":94.67783333333335,"row":"전열"},{"no":3,"x":195903.4195,"y":376669.0643,"z":16.1134,"azimuthDeg":94.642,"row":"전열"},{"no":4,"x":195904.2324,"y":376665.9822,"z":16.1956,"azimuthDeg":94.60630555555554,"row":"전열"},{"no":5,"x":195905.045,"y":376662.9006,"z":16.2764,"azimuthDeg":94.57072222222223,"row":"전열"},{"no":6,"x":195905.8574,"y":376659.8197,"z":16.3568,"azimuthDeg":94.53527777777776,"row":"전열"},{"no":7,"x":195906.6696,"y":376656.7394,"z":16.4367,"azimuthDeg":94.4999722222222,"row":"전열"},{"no":8,"x":195902.9584,"y":376675.1501,"z":15.9811,"azimuthDeg":93.19136111111112,"row":"후열"},{"no":9,"x":195903.7717,"y":376672.0673,"z":16.0627,"azimuthDeg":93.15808333333337,"row":"후열"},{"no":10,"x":195904.5848,"y":376668.9852,"z":16.1438,"azimuthDeg":93.12494444444445,"row":"후열"},{"no":11,"x":195905.3977,"y":376665.9037,"z":16.2256,"azimuthDeg":93.09191666666669,"row":"후열"},{"no":12,"x":195906.2105,"y":376662.8229,"z":16.3059,"azimuthDeg":93.05902777777777,"row":"후열"},{"no":13,"x":195907.0231,"y":376659.7426,"z":16.3859,"azimuthDeg":93.02625,"row":"후열"},{"no":14,"x":195907.8355,"y":376656.663,"z":16.4654,"azimuthDeg":92.99358333333333,"row":"후열"}],"bearingAzimuthFrame":"model-xy"},"draft":{"columnDiameterMm":2000,"footingLengthMm":10400,"footingWidthMm":8150,"footingHeightMm":2000,"blindingMarginMm":100,"blindingThicknessMm":100,"pileKind":"강관","pileOuterMm":609.6,"pileThicknessMm":12,"copingH1Mm":1000,"copingH2Mm":1500,"levelWidthMm":2100,"name":"P1","sheetLine truncated
|
||||
@@ -0,0 +1 @@
|
||||
{"schemaVersion":1,"project":{"name":"샘플 08 · 옥성교","bridge":"옥성교","client":"","author":"","crs":"EPSG:5186","memo":"도면추출 연동 샘플 + 원도면 지반. 설계 지반고 유지. 지도 CRS는 원자료 확인이 필요한 가정(project_default_not_source_verified)."},"source":{"fileName":"샘플08_옥성교_교각입력데이터.xlsx","sheets":["Pier","IP","Bearing"]},"piers":[{"id":"P1","input":{"columnDiameterMm":2000,"footingLengthMm":10400,"footingWidthMm":8150,"footingHeightMm":2000,"blindingMarginMm":100,"blindingThicknessMm":100,"pileKind":"강관","pileOuterMm":609.6,"pileThicknessMm":12,"copingH1Mm":1000,"copingH2Mm":1500,"levelWidthMm":2100,"name":"P1","sheet":"Pier","type":"T형","copingTopEl":21.1279,"footingBottomEl":12.175,"groundEl":18.09,"foundationType":"말뚝기초","pileLengthMm":22000,"copingWidthMm":3500,"copingLengthMm":13500,"columnCount":1,"ips":[{"name":"IP1","x":207605.780013,"y":429978.461366,"angleDeg":0},{"name":"IP2","x":207599.646855,"y":429976.251707,"angleDeg":0},{"name":"IP3","x":207593.513698,"y":429974.042048,"angleDeg":0},{"name":"IP4","x":0,"y":0,"angleDeg":0}],"bearings":[{"no":1,"x":207604.1324,"y":429978.4314,"z":21.3981,"azimuthDeg":142.18688888888886,"row":"전열"},{"no":2,"x":207601.8028,"y":429977.5921,"z":21.4317,"azimuthDeg":142.18688888888886,"row":"전열"},{"no":3,"x":207599.4732,"y":429976.7528,"z":21.4653,"azimuthDeg":142.18688888888886,"row":"전열"},{"no":4,"x":207597.1436,"y":429975.9134,"z":21.4115,"azimuthDeg":142.18688888888886,"row":"전열"},{"no":5,"x":207594.814,"y":429975.0741,"z":21.3509,"azimuthDeg":142.18688888888886,"row":"전열"},{"no":6,"x":207604.868,"y":429977.4835,"z":21.4193,"azimuthDeg":142.18688888888886,"row":"후열"},{"no":7,"x":207602.5384,"y":429976.6442,"z":21.4529,"azimuthDeg":142.18688888888886,"row":"후열"},{"no":8,"x":207600.2088,"y":429975.8048,"z":21.4865,"azimuthDeg":142.18688888888886,"row":"후열"},{"no":9,"x":207597.8792,"y":429974.9655,"z":21.4326,"azimuthDeg":142.18688888888886,"row":"후열"},{"no":10,"x":207595.5496,"y":429974.1262,"z":21.372,"azimuthDeg":142.18688888888886,"row":"후열"}],"bearingAzimuthFrame":"model-xy"},"defaults":{"columnDiameterMm":2000,"footingLengthMm":10400,"footingWidthMm":8150,"footingHeightMm":2000,"blindingMarginMm":100,"blindingThicknessMm":100,"pileKind":"강관","pileOuterMm":609.6,"pileThicknessMm":12,"copingH1Mm":1000,"copingH2Mm":1500,"levelWidthMm":2100,"name":"P1","sheet":"Pier","type":"T형","copingTopEl":21.1279,"footingBottomEl":12.175,"groundEl":18.09,"foundationType":"말뚝기초","pileLengthMm":22000,"copingWidthMm":3500,"copingLengthMm":13500,"columnCount":1,"ips":[{"name":"IP1","x":207605.780013,"y":429978.461366,"angleDeg":0},{"name":"IP2","x":207599.646855,"y":429976.251707,"angleDeg":0},{"name":"IP3","x":207593.513698,"y":429974.042048,"angleDeg":0},{"name":"IP4","x":0,"y":0,"angleDeg":0}],"bearings":[{"no":1,"x":207604.1324,"y":429978.4314,"z":21.3981,"azimuthDeg":142.18688888888886,"row":"전열"},{"no":2,"x":207601.8028,"y":429977.5921,"z":21.4317,"azimuthDeg":142.18688888888886,"row":"전열"},{"no":3,"x":207599.4732,"y":429976.7528,"z":21.4653,"azimuthDeg":142.18688888888886,"row":"전열"},{"no":4,"x":207597.1436,"y":429975.9134,"z":21.4115,"azimuthDeg":142.18688888888886,"row":"전열"},{"no":5,"x":207594.814,"y":429975.0741,"z":21.3509,"azimuthDeg":142.18688888888886,"row":"전열"},{"no":6,"x":207604.868,"y":429977.4835,"z":21.4193,"azimuthDeg":142.18688888888886,"row":"후열"},{"no":7,"x":207602.5384,"y":429976.6442,"z":21.4529,"azimuthDeg":142.18688888888886,"row":"후열"},{"no":8,"x":207600.2088,"y":429975.8048,"z":21.4865,"azimuthDeg":142.18688888888886,"row":"후열"},{"no":9,"x":207597.8792,"y":429974.9655,"z":21.4326,"azimuthDeg":142.18688888888886,"row":"후열"},{"no":10,"x":207595.5496,"y":429974.1262,"z":21.372,"azimuthDeg":142.18688888888886,"row":"후열"}],"bearingAzimuthFrame":"model-xy"},"draft":{"columnDiameterMm":2000,"footingLengthMm":10400,"footingWidthMm":8150,"footingHeightMm":2000,"blindingMarginMm":100,"blindingThicknessMm":100,"pileKind":"강관","pileOuterMm":609.6,"pileThicknessMm":12,"copingH1Mm":1000,"copingH2Mm":1500,"levelWidthMm":2100,"name":"P1","sheet":"Pier","type":"T형","copingTopEl":21.1279,"footingBottomEl":12.175,"groundEl":18.09,"foundationType":"말뚝기초","pileLengthMm":22000,"copingWidthMm":3500,"copingLengthMm":13500,"columnCount":1,"ips":[{"name":"IP1","x":207605.780013,"y":429978.461366,"angleDeg":0},{"name":"IP2","x":207599.646855,"y":429976.251707,"angleDeg":0},{"name":"IP3","x":207593.513698,"y":429974.042048,"angleDeg":0},{"name":"IP4","x":0,"y":0,"angleDeg":0}],"bearings":[{"no":1,"x":207604.1324,"y":429978.4314,"z":21.3981,"azimuthDeg":142.18688888888886,"row":"전열"},{"no":2,"x":207601.8028,"y":429977.5921,"z":21.4317,"azimuthDeg":142.18688888888886,"row":"전열"},{"no":3,"x":207599.4732,"y":429976.7528,"z":21.4653,"azimuthDeg":142.18688888888886,"row":"전열Line truncated
|
||||
@@ -0,0 +1 @@
|
||||
{"schemaVersion":1,"project":{"name":"샘플 09 · 새재1교","bridge":"새재1교","client":"","author":"","crs":"EPSG:5186","memo":"도면추출 연동 샘플 + 원도면 지반. 설계 지반고 유지. 지도 CRS는 원자료 확인이 필요한 가정(project_default_not_source_verified)."},"source":{"fileName":"샘플09_새재1교_교각입력데이터.xlsx","sheets":["Pier","IP","Bearing"]},"piers":[{"id":"P1","input":{"columnDiameterMm":2000,"footingLengthMm":10400,"footingWidthMm":8150,"footingHeightMm":2000,"blindingMarginMm":100,"blindingThicknessMm":100,"pileKind":"강관","pileOuterMm":609.6,"pileThicknessMm":12,"copingH1Mm":1000,"copingH2Mm":1500,"levelWidthMm":2100,"name":"P1","sheet":"Pier","type":"T형","copingTopEl":32.5316,"footingBottomEl":10.032,"groundEl":16.95,"foundationType":"직접기초","pileLengthMm":0,"copingWidthMm":3000,"copingLengthMm":12500,"columnCount":1,"ips":[{"name":"IP1","x":208547.804218,"y":428110.699674,"angleDeg":0},{"name":"IP2","x":208542.956234,"y":428106.806474,"angleDeg":0},{"name":"IP3","x":208538.108532,"y":428102.913503,"angleDeg":0},{"name":"IP4","x":0,"y":0,"angleDeg":0}],"bearings":[{"no":1,"x":208546.25,"y":428110.0923,"z":32.7901,"azimuthDeg":139.06241666666665,"row":"전열"},{"no":2,"x":208544.2952,"y":428108.5226,"z":32.8911,"azimuthDeg":139.07152777777776,"row":"전열"},{"no":3,"x":208542.3406,"y":428106.9529,"z":32.9921,"azimuthDeg":139.08055555555552,"row":"전열"},{"no":4,"x":208540.3859,"y":428105.3832,"z":33.0931,"azimuthDeg":139.0895277777778,"row":"전열"},{"no":5,"x":208538.4314,"y":428103.8136,"z":33.1941,"azimuthDeg":139.0984166666667,"row":"전열"},{"no":6,"x":208546.9329,"y":428109.3626,"z":32.7757,"azimuthDeg":134.73080555555555,"row":"후열"},{"no":7,"x":208544.978,"y":428107.7926,"z":32.8767,"azimuthDeg":134.75805555555553,"row":"후열"},{"no":8,"x":208543.0231,"y":428106.2227,"z":32.9777,"azimuthDeg":134.78505555555557,"row":"후열"},{"no":9,"x":208541.0682,"y":428104.6528,"z":33.0787,"azimuthDeg":134.8118333333333,"row":"후열"},{"no":10,"x":208539.1134,"y":428103.083,"z":33.1797,"azimuthDeg":134.83838888888891,"row":"후열"}],"bearingAzimuthFrame":"model-xy"},"defaults":{"columnDiameterMm":2000,"footingLengthMm":10400,"footingWidthMm":8150,"footingHeightMm":2000,"blindingMarginMm":100,"blindingThicknessMm":100,"pileKind":"강관","pileOuterMm":609.6,"pileThicknessMm":12,"copingH1Mm":1000,"copingH2Mm":1500,"levelWidthMm":2100,"name":"P1","sheet":"Pier","type":"T형","copingTopEl":32.5316,"footingBottomEl":10.032,"groundEl":16.95,"foundationType":"직접기초","pileLengthMm":0,"copingWidthMm":3000,"copingLengthMm":12500,"columnCount":1,"ips":[{"name":"IP1","x":208547.804218,"y":428110.699674,"angleDeg":0},{"name":"IP2","x":208542.956234,"y":428106.806474,"angleDeg":0},{"name":"IP3","x":208538.108532,"y":428102.913503,"angleDeg":0},{"name":"IP4","x":0,"y":0,"angleDeg":0}],"bearings":[{"no":1,"x":208546.25,"y":428110.0923,"z":32.7901,"azimuthDeg":139.06241666666665,"row":"전열"},{"no":2,"x":208544.2952,"y":428108.5226,"z":32.8911,"azimuthDeg":139.07152777777776,"row":"전열"},{"no":3,"x":208542.3406,"y":428106.9529,"z":32.9921,"azimuthDeg":139.08055555555552,"row":"전열"},{"no":4,"x":208540.3859,"y":428105.3832,"z":33.0931,"azimuthDeg":139.0895277777778,"row":"전열"},{"no":5,"x":208538.4314,"y":428103.8136,"z":33.1941,"azimuthDeg":139.0984166666667,"row":"전열"},{"no":6,"x":208546.9329,"y":428109.3626,"z":32.7757,"azimuthDeg":134.73080555555555,"row":"후열"},{"no":7,"x":208544.978,"y":428107.7926,"z":32.8767,"azimuthDeg":134.75805555555553,"row":"후열"},{"no":8,"x":208543.0231,"y":428106.2227,"z":32.9777,"azimuthDeg":134.78505555555557,"row":"후열"},{"no":9,"x":208541.0682,"y":428104.6528,"z":33.0787,"azimuthDeg":134.8118333333333,"row":"후열"},{"no":10,"x":208539.1134,"y":428103.083,"z":33.1797,"azimuthDeg":134.83838888888891,"row":"후열"}],"bearingAzimuthFrame":"model-xy"},"draft":{"columnDiameterMm":2000,"footingLengthMm":10400,"footingWidthMm":8150,"footingHeightMm":2000,"blindingMarginMm":100,"blindingThicknessMm":100,"pileKind":"강관","pileOuterMm":609.6,"pileThicknessMm":12,"copingH1Mm":1000,"copingH2Mm":1500,"levelWidthMm":2100,"name":"P1","sheet":"Pier","type":"T형","copingTopEl":32.5316,"footingBottomEl":10.032,"groundEl":16.95,"foundationType":"직접기초","pileLengthMm":0,"copingWidthMm":3000,"copingLengthMm":12500,"columnCount":1,"ips":[{"name":"IP1","x":208547.804218,"y":428110.699674,"angleDeg":0},{"name":"IP2","x":208542.956234,"y":428106.806474,"angleDeg":0},{"name":"IP3","x":208538.108532,"y":428102.913503,"angleDeg":0},{"name":"IP4","x":0,"y":0,"angleDeg":0}],"bearings":[{"no":1,"x":208546.25,"y":428110.0923,"z":32.7901,"azimuthDeg":139.06241666666665,"row":"전열"},{"no":2,"x":208544.2952,"y":428108.5226,"z":32.8911,"azimuthDeg":139.07152777777776,"row":"전열"},{"no":3,"x":208542.3406,"y":428106.9529,"z":32.9921,"azimuthDeg":139.08055555555552,"row":"전열"},{"no":4,"x":2085Line truncated
|
||||
@@ -0,0 +1 @@
|
||||
{"schemaVersion":1,"project":{"name":"샘플 10 · 도하4교","bridge":"도하4교","client":"","author":"","crs":"EPSG:5186","memo":"도면추출 연동 샘플 + 원도면 지반. 설계 지반고 유지. 지도 CRS는 원자료 확인이 필요한 가정(project_default_not_source_verified)."},"source":{"fileName":"샘플10_도하4교_교각입력데이터.xlsx","sheets":["Pier","IP","Bearing"]},"piers":[{"id":"P1","input":{"columnDiameterMm":2000,"footingLengthMm":10400,"footingWidthMm":8150,"footingHeightMm":2000,"blindingMarginMm":100,"blindingThicknessMm":100,"pileKind":"강관","pileOuterMm":609.6,"pileThicknessMm":12,"copingH1Mm":1000,"copingH2Mm":1500,"levelWidthMm":2100,"name":"P1","sheet":"Pier","type":"T형","copingTopEl":98.552,"footingBottomEl":78.852,"groundEl":85.365,"foundationType":"직접기초","pileLengthMm":0,"copingWidthMm":4000,"copingLengthMm":12500,"columnCount":1,"ips":[{"name":"IP1","x":200987.223238,"y":583704.910196,"angleDeg":0},{"name":"IP2","x":200987.580804,"y":583703.299406,"angleDeg":0},{"name":"IP3","x":200989.888734,"y":583692.902485,"angleDeg":0},{"name":"IP4","x":0,"y":0,"angleDeg":0}],"bearings":[{"no":1,"x":200987.095,"y":583702.013,"z":98.859,"azimuthDeg":77.47163888888889,"row":"전열"},{"no":2,"x":200988.549,"y":583695.473,"z":98.725,"azimuthDeg":77.47163888888889,"row":"전열"},{"no":3,"x":200988.565,"y":583702.34,"z":98.847,"azimuthDeg":77.49702777777776,"row":"후열"},{"no":4,"x":200990.015,"y":583695.798,"z":98.713,"azimuthDeg":77.49700000000001,"row":"후열"}],"bearingAzimuthFrame":"model-xy"},"defaults":{"columnDiameterMm":2000,"footingLengthMm":10400,"footingWidthMm":8150,"footingHeightMm":2000,"blindingMarginMm":100,"blindingThicknessMm":100,"pileKind":"강관","pileOuterMm":609.6,"pileThicknessMm":12,"copingH1Mm":1000,"copingH2Mm":1500,"levelWidthMm":2100,"name":"P1","sheet":"Pier","type":"T형","copingTopEl":98.552,"footingBottomEl":78.852,"groundEl":85.365,"foundationType":"직접기초","pileLengthMm":0,"copingWidthMm":4000,"copingLengthMm":12500,"columnCount":1,"ips":[{"name":"IP1","x":200987.223238,"y":583704.910196,"angleDeg":0},{"name":"IP2","x":200987.580804,"y":583703.299406,"angleDeg":0},{"name":"IP3","x":200989.888734,"y":583692.902485,"angleDeg":0},{"name":"IP4","x":0,"y":0,"angleDeg":0}],"bearings":[{"no":1,"x":200987.095,"y":583702.013,"z":98.859,"azimuthDeg":77.47163888888889,"row":"전열"},{"no":2,"x":200988.549,"y":583695.473,"z":98.725,"azimuthDeg":77.47163888888889,"row":"전열"},{"no":3,"x":200988.565,"y":583702.34,"z":98.847,"azimuthDeg":77.49702777777776,"row":"후열"},{"no":4,"x":200990.015,"y":583695.798,"z":98.713,"azimuthDeg":77.49700000000001,"row":"후열"}],"bearingAzimuthFrame":"model-xy"},"draft":{"columnDiameterMm":2000,"footingLengthMm":10400,"footingWidthMm":8150,"footingHeightMm":2000,"blindingMarginMm":100,"blindingThicknessMm":100,"pileKind":"강관","pileOuterMm":609.6,"pileThicknessMm":12,"copingH1Mm":1000,"copingH2Mm":1500,"levelWidthMm":2100,"name":"P1","sheet":"Pier","type":"T형","copingTopEl":98.552,"footingBottomEl":78.852,"groundEl":85.365,"foundationType":"직접기초","pileLengthMm":0,"copingWidthMm":4000,"copingLengthMm":12500,"columnCount":1,"ips":[{"name":"IP1","x":200987.223238,"y":583704.910196,"angleDeg":0},{"name":"IP2","x":200987.580804,"y":583703.299406,"angleDeg":0},{"name":"IP3","x":200989.888734,"y":583692.902485,"angleDeg":0},{"name":"IP4","x":0,"y":0,"angleDeg":0}],"bearings":[{"no":1,"x":200987.095,"y":583702.013,"z":98.859,"azimuthDeg":77.47163888888889,"row":"전열"},{"no":2,"x":200988.549,"y":583695.473,"z":98.725,"azimuthDeg":77.47163888888889,"row":"전열"},{"no":3,"x":200988.565,"y":583702.34,"z":98.847,"azimuthDeg":77.49702777777776,"row":"후열"},{"no":4,"x":200990.015,"y":583695.798,"z":98.713,"azimuthDeg":77.49700000000001,"row":"후열"}],"bearingAzimuthFrame":"model-xy"}},{"id":"P2","input":{"columnDiameterMm":2000,"footingLengthMm":10400,"footingWidthMm":8150,"footingHeightMm":2000,"blindingMarginMm":100,"blindingThicknessMm":100,"pileKind":"강관","pileOuterMm":609.6,"pileThicknessMm":12,"copingH1Mm":1000,"copingH2Mm":1500,"levelWidthMm":2100,"name":"P2","sheet":"Pier","type":"T형","copingTopEl":98.108,"footingBottomEl":78.408,"groundEl":85.754,"foundationType":"직접기초","pileLengthMm":0,"copingWidthMm":4000,"copingLengthMm":12500,"columnCount":1,"ips":[{"name":"IP1","x":201041.036417,"y":583716.399861,"angleDeg":0},{"name":"IP2","x":201041.367881,"y":583714.783498,"angleDeg":0},{"name":"IP3","x":201043.507331,"y":583704.350605,"angleDeg":0},{"name":"IP4","x":0,"y":0,"angleDeg":0}],"bearings":[{"no":1,"x":201040.861,"y":583713.505,"z":98.415,"azimuthDeg":78.39847222222221,"row":"전열"},{"no":2,"x":201042.209,"y":583706.942,"z":98.281,"azimuthDeg":78.39847222222221,"row":"전열"},{"no":3,"x":201042.336,"y":583713.808,"z":98.402,"azimuthDeg":78.42386111111114,"row":"후열"},{"no":4,"x":201043.68,"y":583707.244,"z":98.268,"azimuthDeg":78.42383333333333,"row"Line truncated
|
||||
@@ -0,0 +1 @@
|
||||
{"schemaVersion":1,"project":{"name":"샘플 11 · 곡천교","bridge":"곡천교","client":"","author":"","crs":"EPSG:5186","memo":"도면추출 연동 샘플 + 원도면 지반. 설계 지반고 유지. 지도 CRS는 원자료 확인이 필요한 가정(project_default_not_source_verified)."},"source":{"fileName":"샘플11_곡천교_교각입력데이터.xlsx","sheets":["Pier","IP","Bearing"]},"piers":[{"id":"P1","input":{"columnDiameterMm":2000,"footingLengthMm":10400,"footingWidthMm":8150,"footingHeightMm":2000,"blindingMarginMm":100,"blindingThicknessMm":100,"pileKind":"강관","pileOuterMm":609.6,"pileThicknessMm":12,"copingH1Mm":1000,"copingH2Mm":1500,"levelWidthMm":2100,"name":"P1","sheet":"Pier","type":"2주형","copingTopEl":86.8393,"footingBottomEl":61.44,"groundEl":64.692,"foundationType":"직접기초","pileLengthMm":0,"copingWidthMm":3500,"copingLengthMm":17000,"columnCount":2,"ips":[{"name":"IP1","x":226998.64978,"y":492646.179517,"angleDeg":0},{"name":"IP2","x":226998.640605,"y":492646.174649,"angleDeg":0},{"name":"IP3","x":227013.515037,"y":492654.066886,"angleDeg":0},{"name":"IP4","x":0,"y":0,"angleDeg":0}],"bearings":[{"no":1,"x":226999.795,"y":492646.0899,"z":87.3778,"azimuthDeg":347.36733333333336,"row":"전열"},{"no":2,"x":227002.2906,"y":492647.414,"z":87.2989,"azimuthDeg":347.3780277777778,"row":"전열"},{"no":3,"x":227004.7862,"y":492648.7381,"z":87.2201,"azimuthDeg":347.38875,"row":"전열"},{"no":4,"x":227007.282,"y":492650.0623,"z":87.1413,"azimuthDeg":347.39947222222224,"row":"전열"},{"no":5,"x":227009.7779,"y":492651.3866,"z":87.0623,"azimuthDeg":347.4102222222222,"row":"전열"},{"no":6,"x":227012.2739,"y":492652.7109,"z":86.9834,"azimuthDeg":347.421,"row":"전열"},{"no":7,"x":226999.5196,"y":492647.3558,"z":87.3832,"azimuthDeg":348.11983333333336,"row":"후열"},{"no":8,"x":227002.0154,"y":492648.6799,"z":87.3043,"azimuthDeg":348.1310555555556,"row":"후열"},{"no":9,"x":227004.5113,"y":492650.0041,"z":87.2254,"azimuthDeg":348.1422777777778,"row":"후열"},{"no":10,"x":227007.0073,"y":492651.3283,"z":87.1466,"azimuthDeg":348.15352777777775,"row":"후열"},{"no":11,"x":227009.5035,"y":492652.6527,"z":87.0676,"azimuthDeg":348.1647777777778,"row":"후열"},{"no":12,"x":227011.9998,"y":492653.9771,"z":86.9886,"azimuthDeg":348.17605555555554,"row":"후열"}],"bearingAzimuthFrame":"model-xy"},"defaults":{"columnDiameterMm":2000,"footingLengthMm":10400,"footingWidthMm":8150,"footingHeightMm":2000,"blindingMarginMm":100,"blindingThicknessMm":100,"pileKind":"강관","pileOuterMm":609.6,"pileThicknessMm":12,"copingH1Mm":1000,"copingH2Mm":1500,"levelWidthMm":2100,"name":"P1","sheet":"Pier","type":"2주형","copingTopEl":86.8393,"footingBottomEl":61.44,"groundEl":64.692,"foundationType":"직접기초","pileLengthMm":0,"copingWidthMm":3500,"copingLengthMm":17000,"columnCount":2,"ips":[{"name":"IP1","x":226998.64978,"y":492646.179517,"angleDeg":0},{"name":"IP2","x":226998.640605,"y":492646.174649,"angleDeg":0},{"name":"IP3","x":227013.515037,"y":492654.066886,"angleDeg":0},{"name":"IP4","x":0,"y":0,"angleDeg":0}],"bearings":[{"no":1,"x":226999.795,"y":492646.0899,"z":87.3778,"azimuthDeg":347.36733333333336,"row":"전열"},{"no":2,"x":227002.2906,"y":492647.414,"z":87.2989,"azimuthDeg":347.3780277777778,"row":"전열"},{"no":3,"x":227004.7862,"y":492648.7381,"z":87.2201,"azimuthDeg":347.38875,"row":"전열"},{"no":4,"x":227007.282,"y":492650.0623,"z":87.1413,"azimuthDeg":347.39947222222224,"row":"전열"},{"no":5,"x":227009.7779,"y":492651.3866,"z":87.0623,"azimuthDeg":347.4102222222222,"row":"전열"},{"no":6,"x":227012.2739,"y":492652.7109,"z":86.9834,"azimuthDeg":347.421,"row":"전열"},{"no":7,"x":226999.5196,"y":492647.3558,"z":87.3832,"azimuthDeg":348.11983333333336,"row":"후열"},{"no":8,"x":227002.0154,"y":492648.6799,"z":87.3043,"azimuthDeg":348.1310555555556,"row":"후열"},{"no":9,"x":227004.5113,"y":492650.0041,"z":87.2254,"azimuthDeg":348.1422777777778,"row":"후열"},{"no":10,"x":227007.0073,"y":492651.3283,"z":87.1466,"azimuthDeg":348.15352777777775,"row":"후열"},{"no":11,"x":227009.5035,"y":492652.6527,"z":87.0676,"azimuthDeg":348.1647777777778,"row":"후열"},{"no":12,"x":227011.9998,"y":492653.9771,"z":86.9886,"azimuthDeg":348.17605555555554,"row":"후열"}],"bearingAzimuthFrame":"model-xy"},"draft":{"columnDiameterMm":2000,"footingLengthMm":10400,"footingWidthMm":8150,"footingHeightMm":2000,"blindingMarginMm":100,"blindingThicknessMm":100,"pileKind":"강관","pileOuterMm":609.6,"pileThicknessMm":12,"copingH1Mm":1000,"copingH2Mm":1500,"levelWidthMm":2100,"name":"P1","sheet":"Pier","type":"2주형","copingTopEl":86.8393,"footingBottomEl":61.44,"groundEl":64.692,"foundationType":"직접기초","pileLengthMm":0,"copingWidthMm":3500,"copingLengthMm":17000,"columnCount":2,"ips":[{"name":"IP1","x":226998.64978,"y":492646.179517,"angleDeg":0},{"name":"IP2","x":226998.640605,"y":492646.174649,"angleDeg":0},{"name":"IP3","x":227013.515037,"y":492654.066886,"angleDeg":0},{"Line truncated
|
||||
@@ -0,0 +1 @@
|
||||
{"schemaVersion":1,"project":{"name":"샘플 12 · 감북교","bridge":"감북교","client":"","author":"","crs":"EPSG:5186","memo":"도면추출 연동 샘플 + 원도면 지반. 설계 지반고 유지. 지도 CRS는 원자료 확인이 필요한 가정(inferred_false_northing_convention_not_source_verified)."},"source":{"fileName":"샘플12_감북교_교각입력데이터.xlsx","sheets":["Pier","IP","Bearing"]},"piers":[{"id":"P1","input":{"columnDiameterMm":2000,"footingLengthMm":10400,"footingWidthMm":8150,"footingHeightMm":2000,"blindingMarginMm":100,"blindingThicknessMm":100,"pileKind":"강관","pileOuterMm":609.6,"pileThicknessMm":12,"copingH1Mm":1000,"copingH2Mm":1500,"levelWidthMm":2100,"name":"P1","sheet":"Pier","type":"2주형","copingTopEl":56.5998,"footingBottomEl":43.604,"groundEl":44.64,"foundationType":"현장타설말뚝","pileLengthMm":17566,"copingWidthMm":3000,"copingLengthMm":20000,"columnCount":2,"ips":[{"name":"IP1","x":214529.86606,"y":547194.678176,"angleDeg":0},{"name":"IP2","x":214548.146791,"y":547202.413639,"angleDeg":0},{"name":"IP3","x":214548.137582,"y":547202.409742,"angleDeg":0},{"name":"IP4","x":0,"y":0,"angleDeg":0}],"bearings":[{"no":1,"x":214531.1568,"y":547194.6814,"z":56.8196,"azimuthDeg":337.06444444444446,"row":"전열"},{"no":2,"x":214533.8276,"y":547195.8116,"z":56.8776,"azimuthDeg":337.06444444444446,"row":"전열"},{"no":3,"x":214536.4983,"y":547196.9417,"z":56.9356,"azimuthDeg":337.06444444444446,"row":"전열"},{"no":4,"x":214539.169,"y":547198.0718,"z":56.9936,"azimuthDeg":337.06444444444446,"row":"전열"},{"no":5,"x":214541.8398,"y":547199.2019,"z":57.0516,"azimuthDeg":337.06444444444446,"row":"전열"},{"no":6,"x":214544.5105,"y":547200.332,"z":57.1096,"azimuthDeg":337.06444444444446,"row":"전열"},{"no":7,"x":214547.1812,"y":547201.4622,"z":57.1676,"azimuthDeg":337.06444444444446,"row":"전열"},{"no":8,"x":214530.7671,"y":547195.6024,"z":56.7998,"azimuthDeg":337.06444444444446,"row":"후열"},{"no":9,"x":214533.4379,"y":547196.7325,"z":56.8578,"azimuthDeg":337.06444444444446,"row":"후열"},{"no":10,"x":214536.1086,"y":547197.8626,"z":56.9158,"azimuthDeg":337.06444444444446,"row":"후열"},{"no":11,"x":214538.7793,"y":547198.9927,"z":56.9738,"azimuthDeg":337.06444444444446,"row":"후열"},{"no":12,"x":214541.4501,"y":547200.1229,"z":57.0318,"azimuthDeg":337.06444444444446,"row":"후열"},{"no":13,"x":214544.1208,"y":547201.253,"z":57.0898,"azimuthDeg":337.06444444444446,"row":"후열"},{"no":14,"x":214546.7916,"y":547202.3831,"z":57.1478,"azimuthDeg":337.06444444444446,"row":"후열"}],"bearingAzimuthFrame":"model-xy"},"defaults":{"columnDiameterMm":2000,"footingLengthMm":10400,"footingWidthMm":8150,"footingHeightMm":2000,"blindingMarginMm":100,"blindingThicknessMm":100,"pileKind":"강관","pileOuterMm":609.6,"pileThicknessMm":12,"copingH1Mm":1000,"copingH2Mm":1500,"levelWidthMm":2100,"name":"P1","sheet":"Pier","type":"2주형","copingTopEl":56.5998,"footingBottomEl":43.604,"groundEl":44.64,"foundationType":"현장타설말뚝","pileLengthMm":17566,"copingWidthMm":3000,"copingLengthMm":20000,"columnCount":2,"ips":[{"name":"IP1","x":214529.86606,"y":547194.678176,"angleDeg":0},{"name":"IP2","x":214548.146791,"y":547202.413639,"angleDeg":0},{"name":"IP3","x":214548.137582,"y":547202.409742,"angleDeg":0},{"name":"IP4","x":0,"y":0,"angleDeg":0}],"bearings":[{"no":1,"x":214531.1568,"y":547194.6814,"z":56.8196,"azimuthDeg":337.06444444444446,"row":"전열"},{"no":2,"x":214533.8276,"y":547195.8116,"z":56.8776,"azimuthDeg":337.06444444444446,"row":"전열"},{"no":3,"x":214536.4983,"y":547196.9417,"z":56.9356,"azimuthDeg":337.06444444444446,"row":"전열"},{"no":4,"x":214539.169,"y":547198.0718,"z":56.9936,"azimuthDeg":337.06444444444446,"row":"전열"},{"no":5,"x":214541.8398,"y":547199.2019,"z":57.0516,"azimuthDeg":337.06444444444446,"row":"전열"},{"no":6,"x":214544.5105,"y":547200.332,"z":57.1096,"azimuthDeg":337.06444444444446,"row":"전열"},{"no":7,"x":214547.1812,"y":547201.4622,"z":57.1676,"azimuthDeg":337.06444444444446,"row":"전열"},{"no":8,"x":214530.7671,"y":547195.6024,"z":56.7998,"azimuthDeg":337.06444444444446,"row":"후열"},{"no":9,"x":214533.4379,"y":547196.7325,"z":56.8578,"azimuthDeg":337.06444444444446,"row":"후열"},{"no":10,"x":214536.1086,"y":547197.8626,"z":56.9158,"azimuthDeg":337.06444444444446,"row":"후열"},{"no":11,"x":214538.7793,"y":547198.9927,"z":56.9738,"azimuthDeg":337.06444444444446,"row":"후열"},{"no":12,"x":214541.4501,"y":547200.1229,"z":57.0318,"azimuthDeg":337.06444444444446,"row":"후열"},{"no":13,"x":214544.1208,"y":547201.253,"z":57.0898,"azimuthDeg":337.06444444444446,"row":"후열"},{"no":14,"x":214546.7916,"y":547202.3831,"z":57.1478,"azimuthDeg":337.06444444444446,"row":"후열"}],"bearingAzimuthFrame":"model-xy"},"draft":{"columnDiameterMm":2000,"footingLengthMm":10400,"footingWidthMm":8150,"footingHeightMm":2000,"blindingMarginMm":100,"blindingThicknessMm":100,"pileKind":"강관","pileOuterMm":609.6,"Line truncated
|
||||
Binary file not shown.
@@ -0,0 +1,64 @@
|
||||
// Run with Windows Node and an isolated Chrome on CDP 9444; Vite must be on 5173.
|
||||
const fs = require('node:fs'), path = require('node:path'), assert = require('node:assert/strict');
|
||||
const preview=process.argv.includes('--horizontal-preview');
|
||||
const lowerPreview=process.argv.includes('--lower-preview');
|
||||
const out = path.resolve(__dirname, lowerPreview?'../.verify/landing-lower-20261109':process.argv.includes('--all')?'../.verify/landing-hero-20261109':'../.verify/landing-horizontal-20261109');
|
||||
fs.mkdirSync(out, { recursive: true });
|
||||
const report = { checks: [], errors: [] };
|
||||
let ws, send;
|
||||
const delay = ms => new Promise(r => setTimeout(r, ms));
|
||||
(async () => {
|
||||
const target = await (await fetch('http://127.0.0.1:9444/json/new?about:blank', { method: 'PUT' })).json();
|
||||
ws = new WebSocket(target.webSocketDebuggerUrl);
|
||||
await new Promise((r, j) => { ws.onopen = r; ws.onerror = j; });
|
||||
let seq = 0; const pending = new Map();
|
||||
ws.onmessage = ({ data }) => {
|
||||
const m = JSON.parse(data), p = pending.get(m.id);
|
||||
if (p) { clearTimeout(p.timer); pending.delete(m.id); m.error ? p.reject(new Error(JSON.stringify(m.error))) : p.resolve(m.result); }
|
||||
if (m.method === 'Runtime.exceptionThrown') report.errors.push(m.params.exceptionDetails.exception?.description || m.params.exceptionDetails.text);
|
||||
};
|
||||
send = (method, params = {}) => new Promise((resolve, reject) => {
|
||||
const id = ++seq, timer = setTimeout(() => reject(new Error('Timeout ' + method)), 30000);
|
||||
pending.set(id, { resolve, reject, timer }); ws.send(JSON.stringify({ id, method, params }));
|
||||
});
|
||||
const ev = async expression => {
|
||||
const r = await send('Runtime.evaluate', { expression, awaitPromise: true, returnByValue: true });
|
||||
if (r.exceptionDetails) throw new Error(r.exceptionDetails.exception?.description || r.exceptionDetails.text);
|
||||
return r.result.value;
|
||||
};
|
||||
const until = async expression => {
|
||||
for (let i = 0; i < 120; i++) { if (await ev(expression)) return; await delay(150); }
|
||||
throw new Error('Wait ' + expression);
|
||||
};
|
||||
const check = (name, value) => { assert.ok(value, name); report.checks.push(name); console.log('PASS', name); };
|
||||
const click = expression => ev(`(()=>{const e=${expression};if(!e||e.disabled)throw new Error('Missing target');e.click();})()`);
|
||||
const shot = async name => {
|
||||
const r = await send('Page.captureScreenshot', { format: 'png' });
|
||||
fs.writeFileSync(path.join(out, name + '.png'), Buffer.from(r.data, 'base64'));
|
||||
};
|
||||
await send('Page.enable'); await send('Runtime.enable'); await send('DOM.enable');
|
||||
await send('Emulation.setDeviceMetricsOverride', { width: 1600, height: 1000, deviceScaleFactor: 1, mobile: false });
|
||||
await send('Page.navigate', { url: process.env.PIERZAINER_URL || 'http://127.0.0.1:5173/' });
|
||||
await until(`typeof window.openSampleProject==='function'`);
|
||||
const projectPath=process.env.OKSEONG_PROJECT||path.resolve(__dirname,'../.verify/ground-abutments-20261109/saved.pzr.json');
|
||||
const projectText=fs.readFileSync(projectPath,'utf8');
|
||||
const hash=require('node:crypto').createHash('sha256').update(projectText).digest('hex');
|
||||
await ev(`window.__heroProject=JSON.parse(${JSON.stringify(projectText)})`);
|
||||
const variants=lowerPreview ? [['lower-33',.65,0,30,true,true],['lower-27',.5,0,30,true,true],['lower-19',.35,0,30,true,true],['lower-27-cutaway',.5,0,30,true,true,8]] : preview ? [['horizontal',.85,0,30,true],['horizontal-smooth',.85,0,30,true,true]] : process.argv.includes('--all') ? [['low',.35,0],['balanced',.55,.12],['high',.8,-.12],['trim30',.55,.12,30],['trim20',.55,.12,20],['refined',.85,.12,30,true]] : [['horizontal-smooth',.85,0,30,true,true]];
|
||||
for(const [name,elevation,along,margin,refined,smooth,cutaway] of variants){
|
||||
const result=await ev(`(async()=>{const {renderLandingHero}=await import('/scripts/render-landing-hero.ts');return renderLandingHero(window.__heroProject,${elevation},${along},${margin},${refined},${smooth},${cutaway});})()`);
|
||||
for(const type of ['png','webp'])fs.writeFileSync(path.join(out,name+'.'+type),Buffer.from(result[type].split(',')[1],'base64'));
|
||||
fs.writeFileSync(path.join(out,name+'.json'),JSON.stringify({...result.metadata,sourceSha256:hash},null,2));
|
||||
check(name+' includes six piers and two abutments',result.metadata.piers===6&&result.metadata.abutments===2&&result.metadata.points.length===8);
|
||||
check(name+' all projected markers stay inside image',result.metadata.points.every(p=>p.x>0&&p.x<result.metadata.width&&p.y>0&&p.y<result.metadata.height));
|
||||
check(name+' light samples actual terrain densely',result.metadata.terrainFlow.filter(Boolean).length>100&&result.metadata.terrainFlow.every(p=>!p||Math.abs(p.world[1]-p.el-.12)<.0001));
|
||||
if(refined)check('both road extensions contain continuous terrain-supported sections',result.metadata.roads.length===2&&result.metadata.roads.every(r=>r.missingSections===0&&r.validSections===81&&r.triangles>0));
|
||||
if(smooth){
|
||||
check('outline trims real pixels without filling missing terrain',result.metadata.outline.addedOutsideSourcePixels===0&&result.metadata.outline.retainedTerrainRatio>.8&&result.metadata.outline.retainedTerrainRatio<.99);
|
||||
check('smooth outline preserves all eight structure tops',await ev(`(()=>{const c=document.createElement('canvas');c.width=${result.metadata.width*2};c.height=${result.metadata.height*2};return new Promise(resolve=>{const i=new Image();i.onload=()=>{const ctx=c.getContext('2d');ctx.drawImage(i,0,0);resolve(${JSON.stringify(result.metadata.points)}.every(p=>{let n=0;for(let x=-8;x<=8;x++)for(let y=0;y<30;y++)n+=ctx.getImageData(Math.round(p.x*2+x),Math.round(p.y*2+y),1,1).data[3]>0;return n>15;}));};i.src=${JSON.stringify(result.png)};});})()`));
|
||||
}
|
||||
}
|
||||
check('no runtime exceptions',report.errors.length===0);report.result='PASS';
|
||||
})().catch(e=>{report.result='FAIL';report.failure=e.stack;process.exitCode=1;}).finally(()=>{
|
||||
fs.writeFileSync(path.join(out,'report.json'),JSON.stringify(report,null,2));console.log(JSON.stringify(report));ws?.close();
|
||||
});
|
||||
@@ -1,12 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
# Headless Chrome screenshot of the sample page (WSL2 → Windows Chrome).
|
||||
# Usage: scripts/capture-sample.sh <output.png> [url]
|
||||
# Requires the dev server: npm run dev -- --host 127.0.0.1 --port 5173
|
||||
set -euo pipefail
|
||||
OUT_WSL="${1:?output png path (WSL path)}"
|
||||
URL="${2:-http://127.0.0.1:5173/?sample=1}"
|
||||
CHROME="/mnt/c/Program Files/Google/Chrome/Application/chrome.exe"
|
||||
mkdir -p "$(dirname "$OUT_WSL")"
|
||||
timeout 200 "$CHROME" --headless=new --no-sandbox --use-gl=angle --use-angle=swiftshader \
|
||||
--enable-unsafe-swiftshader --enable-logging=stderr --v=0 --window-size=1600,1000 \
|
||||
--timeout=45000 --screenshot="$(wslpath -w "$OUT_WSL")" "$URL"
|
||||
@@ -0,0 +1,42 @@
|
||||
"""Create a review sheet from native Three.js captures; validate local structure crops."""
|
||||
import json
|
||||
from pathlib import Path
|
||||
from PIL import Image, ImageChops, ImageDraw, ImageFont
|
||||
|
||||
root = Path(__file__).resolve().parents[1]
|
||||
out = root / '.verify/landing-horizontal-20261109'
|
||||
metadata = json.loads((out / 'horizontal-smooth.json').read_text())
|
||||
raw = Image.open(out / 'horizontal.png').convert('RGBA')
|
||||
smooth = Image.open(out / 'horizontal-smooth.png').convert('RGBA')
|
||||
checks = []
|
||||
for point in metadata['points']:
|
||||
x, y = point['x'] * 2, point['y'] * 2
|
||||
box = (int(x - 48), int(y - 8), int(x + 48), int(y + 120))
|
||||
assert ImageChops.difference(raw.crop(box), smooth.crop(box)).getbbox() is None, point['name']
|
||||
checks.append(point['name'] + ' local structure pixels unchanged')
|
||||
assert metadata['along'] == 0
|
||||
assert metadata['outline']['addedOutsideSourcePixels'] == 0
|
||||
checks.extend(['horizontal camera has zero along-axis component', 'no pixels added outside source'])
|
||||
|
||||
sheet = Image.new('RGB', (1600, 1050), '#f5f8fb')
|
||||
draw = ImageDraw.Draw(sheet)
|
||||
font = ImageFont.truetype('/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf', 23)
|
||||
small = ImageFont.truetype('/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf', 17)
|
||||
previous = out / 'before-horizontal/okseong-model-hero.png'
|
||||
panels = [
|
||||
('PREVIOUS / diagonal view, rough survey boundary', previous if previous.exists() else root / '랜딩페이지/assets/okseong-model-hero.png'),
|
||||
('PROPOSAL / horizontal orthographic view, inward curved boundary', out / 'horizontal-smooth.png'),
|
||||
]
|
||||
for i, (label, path) in enumerate(panels):
|
||||
y = 25 + i * 510
|
||||
draw.rounded_rectangle((20, y, 1580, y + 480), radius=20, fill='white', outline='#dce4ed')
|
||||
draw.text((45, y + 20), label, font=font, fill='#19334d')
|
||||
image = Image.open(path).convert('RGBA')
|
||||
image = image.crop(image.getbbox())
|
||||
image.thumbnail((1500, 380), Image.Resampling.LANCZOS)
|
||||
sheet.paste(image, ((1600 - image.width) // 2, y + 80 + (380 - image.height) // 2), image)
|
||||
if i == 1:
|
||||
draw.text((45, y + 445), '6 piers + 2 abutments preserved / original survey unchanged / preview only', font=small, fill='#52667a')
|
||||
sheet.save(out / 'comparison.png')
|
||||
(out / 'review-report.json').write_text(json.dumps({'result': 'PASS', 'checks': checks}, indent=2))
|
||||
print(f'PASS {len(checks)} review checks; {out / "comparison.png"}')
|
||||
@@ -0,0 +1,26 @@
|
||||
// Read-only diagnosis: concrete scene vs rebar paths for every pier/foundation combination.
|
||||
import { createServer } from 'vite';
|
||||
import { mkdir, writeFile } from 'node:fs/promises';
|
||||
const server = await createServer({ configFile: false, server: { middlewareMode: true, hmr: false, watch: null }, appType: 'custom' });
|
||||
try {
|
||||
const { loadP1 } = await server.ssrLoadModule('/tests/helpers.ts');
|
||||
const { buildPier } = await server.ssrLoadModule('/src/core/geometry.ts');
|
||||
const { buildPierScene } = await server.ssrLoadModule('/src/view/scene.ts');
|
||||
const { buildRebar3D } = await server.ssrLoadModule('/src/view/rebar3d.ts');
|
||||
const { rebarSummary } = await server.ssrLoadModule('/src/core/rebar/summary.ts');
|
||||
const result = [];
|
||||
for (const [type, columnCount] of [['T형', 1], ['2주형', 2], ['3주형', 3]]) {
|
||||
for (const foundationType of ['직접기초', '말뚝기초', '현장타설말뚝']) {
|
||||
const model = buildPier({ ...loadP1(), type, columnCount, foundationType });
|
||||
const record = { type, foundationType, columns: model.columns.length, footings: model.footings.length, piles: model.piles.length };
|
||||
for (const [name, run] of Object.entries({ concrete: () => buildPierScene(model), rebar3d: () => buildRebar3D(model), summary: () => rebarSummary(model) })) {
|
||||
try { run(); record[name] = { ok: true }; }
|
||||
catch (error) { record[name] = { ok: false, message: error.message, stack: error.stack.split('\n').slice(0, 5) }; }
|
||||
}
|
||||
result.push(record);
|
||||
}
|
||||
}
|
||||
await mkdir('.verify/cast-in-place-20261105', { recursive: true });
|
||||
await writeFile('.verify/cast-in-place-20261105/diagnosis.json', JSON.stringify(result, null, 2));
|
||||
console.table(result.map(({ type, foundationType, concrete, rebar3d, summary }) => ({ type, foundationType, concrete: concrete.ok, rebar3d: rebar3d.ok, summary: summary.ok })));
|
||||
} finally { await server.close(); }
|
||||
@@ -0,0 +1,22 @@
|
||||
import { createServer } from 'vite';
|
||||
import { readFileSync } from 'node:fs';
|
||||
const server = await createServer({ server: { middlewareMode: true, hmr: false } });
|
||||
try {
|
||||
const { buildPier } = await server.ssrLoadModule('/src/core/geometry.ts');
|
||||
const { generateDrawing, DEFAULT_SETTINGS } = await server.ssrLoadModule('/도면작성/drawing.ts');
|
||||
const {presentationEntities} = await server.ssrLoadModule('/도면작성/presentation.ts');
|
||||
const {entityBox,viewCollisions,occupiedBounds} = await server.ssrLoadModule('/도면작성/occupancy.ts');
|
||||
const {bearingDetail} = await server.ssrLoadModule('/도면작성/bearing-detail.ts');
|
||||
const sample = JSON.parse(readFileSync('랜딩페이지/assets/samples/'+(process.argv[2]||'sample01.pzr.json'), 'utf8'));
|
||||
const input = sample.piers[0].input;
|
||||
const doc = generateDrawing(buildPier(input), input, sample.project, DEFAULT_SETTINGS);
|
||||
console.log(JSON.stringify(doc.quality.issues.map(q => ({q, a:doc.views.find(v=>v.id===q.view)?.entities[q.first], b:doc.views.find(v=>v.id===q.view)?.entities[q.second]})), null, 2));
|
||||
console.log(JSON.stringify(doc.views.map(v=>({id:v.id,scale:v.scale,slot:v.slot}))));
|
||||
for(const q of doc.quality.issues.filter(q=>q.kind==='text-text'))console.log(JSON.stringify(presentationEntities(doc.views.find(v=>v.id===q.view)).filter(p=>p.entity.kind==='text'&&[q.first,q.second].includes(p.index)).map(p=>({entity:p.entity,box:entityBox(p.entity)}))));
|
||||
for(const scale of [50,75,100,125,150,200,250,300]){
|
||||
const {entities}=bearingDetail(buildPier(input),scale);
|
||||
for(const e of entities){if(e.kind==='dimension')e.height=3*scale;if(e.kind==='text')e.height=Math.max(e.height,2.5*scale);}
|
||||
const v={id:'detail',entities,scale},b=occupiedBounds(v);
|
||||
console.log(JSON.stringify({scale,width:(b.maxX-b.minX)/scale,issues:viewCollisions(v).map(q=>({a:entities[q.first],b:entities[q.second]}))}));
|
||||
}
|
||||
} finally { await server.close(); }
|
||||
@@ -0,0 +1,52 @@
|
||||
// Read the user's linked artifact in an isolated browser profile, without changing its content.
|
||||
const fs = require('node:fs');
|
||||
const path = require('node:path');
|
||||
const out = path.resolve(__dirname, '../.verify/design-system-artifact-20261105');
|
||||
fs.mkdirSync(out, { recursive: true });
|
||||
async function inspect(target, name, screenshot) {
|
||||
const ws = new WebSocket(target.webSocketDebuggerUrl);
|
||||
await new Promise((resolve, reject) => { ws.onopen = resolve; ws.onerror = reject; });
|
||||
let seq = 0;
|
||||
const pending = new Map();
|
||||
ws.onmessage = ({ data }) => {
|
||||
const message = JSON.parse(data);
|
||||
const wait = pending.get(message.id);
|
||||
if (!wait) return;
|
||||
clearTimeout(wait.timer); pending.delete(message.id);
|
||||
if (message.error) wait.reject(new Error(JSON.stringify(message.error))); else wait.resolve(message.result);
|
||||
};
|
||||
const send = (method, params = {}) => new Promise((resolve, reject) => {
|
||||
const id = ++seq;
|
||||
const timer = setTimeout(() => { pending.delete(id); reject(new Error(`Timeout ${method}`)); }, 15000);
|
||||
pending.set(id, { resolve, reject, timer });
|
||||
ws.send(JSON.stringify({ id, method, params }));
|
||||
});
|
||||
try {
|
||||
await send('Runtime.enable');
|
||||
if (screenshot) {
|
||||
await send('Page.enable');
|
||||
await send('Emulation.setDeviceMetricsOverride', { width: 1600, height: 1000, deviceScaleFactor: 1, mobile: false });
|
||||
await new Promise((resolve) => setTimeout(resolve, 6000));
|
||||
}
|
||||
const text = await send('Runtime.evaluate', { expression: 'document.body.innerText', returnByValue: true });
|
||||
const html = await send('Runtime.evaluate', { expression: 'document.documentElement.outerHTML', returnByValue: true });
|
||||
const frames = await send('Runtime.evaluate', { expression: '[...document.querySelectorAll("iframe")].map(f=>({src:f.src,title:f.title,srcdocLength:f.srcdoc.length}))', returnByValue: true });
|
||||
fs.writeFileSync(path.join(out, `${name}.txt`), text.result?.value || '');
|
||||
fs.writeFileSync(path.join(out, `${name}.html`), html.result?.value || '');
|
||||
fs.writeFileSync(path.join(out, `${name}-frames.json`), JSON.stringify(frames.result?.value, null, 2));
|
||||
console.log(JSON.stringify({ name, title: target.title, url: target.url, text: (text.result?.value || '').slice(0, 10000), frames: frames.result?.value }));
|
||||
if (screenshot) {
|
||||
const shot = await send('Page.captureScreenshot', { format: 'png' });
|
||||
fs.writeFileSync(path.join(out, 'overview.png'), Buffer.from(shot.data, 'base64'));
|
||||
}
|
||||
} finally { ws.close(); }
|
||||
}
|
||||
(async () => {
|
||||
let targets = await (await fetch('http://127.0.0.1:9444/json')).json();
|
||||
const page = targets.find((target) => target.type === 'page' && target.url.includes('9LPwY9MMugHfvF5auhpVW2'));
|
||||
if (!page) throw new Error('Linked artifact page not found');
|
||||
await inspect(page, 'page', true);
|
||||
targets = await (await fetch('http://127.0.0.1:9444/json')).json();
|
||||
let index = 0;
|
||||
for (const target of targets.filter((target) => target.type === 'iframe')) await inspect(target, `frame-${++index}`, false);
|
||||
})().catch((error) => { console.error(error); process.exitCode = 1; });
|
||||
@@ -0,0 +1,21 @@
|
||||
// Read focused-control and native-menu behaviour in the last verification tab.
|
||||
const fs = require('node:fs');
|
||||
const path = require('node:path');
|
||||
(async () => {
|
||||
const pages = await (await fetch('http://127.0.0.1:9444/json/list')).json();
|
||||
const page = pages.find(p=>p.url==='http://127.0.0.1:5173/');
|
||||
const ws = new WebSocket(page.webSocketDebuggerUrl);
|
||||
await new Promise(r=>ws.onopen=r);
|
||||
let seq=0; const pending=new Map();
|
||||
ws.onmessage=({data})=>{const m=JSON.parse(data);if(pending.has(m.id)){pending.get(m.id)(m.result);pending.delete(m.id);}};
|
||||
const send=(method,params={})=>new Promise(r=>{const id=++seq;pending.set(id,r);ws.send(JSON.stringify({id,method,params}));});
|
||||
const ev=async expression=>(await send('Runtime.evaluate',{expression,returnByValue:true})).result.value;
|
||||
const inspect=`({open:document.getElementById('file-menu').open,active:document.activeElement.outerHTML,summaryTab:document.querySelector('#file-menu summary').tabIndex})`;
|
||||
const result={before:await ev(inspect)};
|
||||
await ev(`document.querySelector('#file-menu summary').focus()`);
|
||||
await send('Input.dispatchKeyEvent',{type:'keyDown',key:'Enter',code:'Enter',text:'\r',windowsVirtualKeyCode:13});
|
||||
await send('Input.dispatchKeyEvent',{type:'keyUp',key:'Enter',code:'Enter',windowsVirtualKeyCode:13});
|
||||
result.after=await ev(inspect);
|
||||
fs.writeFileSync(path.resolve(__dirname,'../.verify/unified-input-20261106/keyboard-diagnosis.json'),JSON.stringify(result,null,2));
|
||||
console.log(result);ws.close();
|
||||
})().catch(e=>{console.error(e);process.exitCode=1;});
|
||||
@@ -0,0 +1,57 @@
|
||||
import * as THREE from 'three';
|
||||
|
||||
/** Rounded capture footprint; the underlying survey grid remains untouched. */
|
||||
export function roundedTerrainPlanes(axis: THREE.Vector3, start: number, end: number, halfWidth: number, radius: number) {
|
||||
const lateral = new THREE.Vector3(-axis.z, 0, axis.x);
|
||||
const corners = [[end-radius,halfWidth-radius,0],[start+radius,halfWidth-radius,90],[start+radius,-halfWidth+radius,180],[end-radius,-halfWidth+radius,270]];
|
||||
const points: [number,number][]=[];
|
||||
for(const [s,t,angle] of corners) for(let i=0;i<=8;i++) {
|
||||
const a=(angle+i*90/8)*Math.PI/180;
|
||||
points.push([s+radius*Math.cos(a),t+radius*Math.sin(a)]);
|
||||
}
|
||||
return points.map((p,i)=>{
|
||||
const q=points[(i+1)%points.length],ds=q[0]-p[0],dt=q[1]-p[1];
|
||||
const normal=axis.clone().multiplyScalar(-dt).addScaledVector(lateral,ds).normalize();
|
||||
const origin=axis.clone().multiplyScalar(p[0]).addScaledVector(lateral,p[1]);
|
||||
return new THREE.Plane(normal,-normal.dot(origin));
|
||||
});
|
||||
}
|
||||
|
||||
/** Landing-only road ribbons, joining the photographed road to ground at each abutment. */
|
||||
export function buildRoadExtensions(terrain: THREE.Mesh, anchors: {name:string;kind:string;point:THREE.Vector3}[], axis: THREE.Vector3, top: number) {
|
||||
const piers=anchors.filter(a=>a.kind==='pier').toSorted((a,b)=>a.point.dot(axis)-b.point.dot(axis));
|
||||
const abuts=anchors.filter(a=>a.kind==='abutment').toSorted((a,b)=>a.point.dot(axis)-b.point.dot(axis));
|
||||
if(piers.length<2||abuts.length!==2)throw new Error('Road extensions require two abutments and at least two piers');
|
||||
const group=new THREE.Group();group.name='landing-road-extensions';
|
||||
const ray=new THREE.Raycaster(),down=new THREE.Vector3(0,-1,0),widthM=8;
|
||||
const sample=(x:number,z:number)=>{
|
||||
ray.set(new THREE.Vector3(x,top+100,z),down);
|
||||
return ray.intersectObject(terrain,false)[0]?.point;
|
||||
};
|
||||
const descriptions=[];
|
||||
const ends=[{name:'A1–P1',points:[abuts[0].point,piers[0].point,piers[1].point],from:0,to:.58},
|
||||
{name:'P6–A2',points:[piers.at(-2)!.point,piers.at(-1)!.point,abuts[1].point],from:.42,to:1}];
|
||||
for(const end of ends){
|
||||
const curve=new THREE.CatmullRomCurve3(end.points.map(p=>new THREE.Vector3(p.x,0,p.z)),false,'catmullrom',.2);
|
||||
const steps=80,positions:number[]=[],colors:number[]=[],indices:number[]=[];
|
||||
let previous=-1,validSections=0,missingSections=0;
|
||||
for(let i=0;i<=steps;i++){
|
||||
const t=i/steps,u=end.from+(end.to-end.from)*t,p=curve.getPoint(u),tangent=curve.getTangent(u).normalize();
|
||||
const cross=new THREE.Vector3(-tangent.z,0,tangent.x);
|
||||
const offsets=Array.from({length:17},(_,j)=>-widthM/2+widthM*j/16);
|
||||
const hits=offsets.map(o=>sample(p.x+cross.x*o,p.z+cross.z*o));
|
||||
if(hits.some(h=>!h)){previous=-1;missingSections++;continue;}
|
||||
const first=positions.length/3;
|
||||
const blend=end.from===0?1-THREE.MathUtils.smoothstep(t,.72,1):THREE.MathUtils.smoothstep(t,0,.28);
|
||||
const color=new THREE.Color('#dcd8c7').multiplyScalar(1+Math.sin(i*2.33)*.018);
|
||||
hits.forEach((hit,j)=>{positions.push(hit!.x,hit!.y+.15,hit!.z);colors.push(color.r,color.g,color.b,blend*(j===0||j===offsets.length-1?0:.96));});
|
||||
if(previous>=0)for(let j=0;j<offsets.length-1;j++)indices.push(previous+j,first+j,previous+j+1,previous+j+1,first+j,first+j+1);
|
||||
previous=first;validSections++;
|
||||
}
|
||||
const geometry=new THREE.BufferGeometry();geometry.setAttribute('position',new THREE.Float32BufferAttribute(positions,3));geometry.setAttribute('color',new THREE.Float32BufferAttribute(colors,4));geometry.setIndex(indices);geometry.computeVertexNormals();
|
||||
const mesh=new THREE.Mesh(geometry,new THREE.MeshBasicMaterial({vertexColors:true,side:THREE.DoubleSide,transparent:true,depthWrite:false,polygonOffset:true,polygonOffsetFactor:-2,polygonOffsetUnits:-2}));
|
||||
mesh.name=end.name;mesh.renderOrder=2;group.add(mesh);
|
||||
descriptions.push({name:end.name,widthM,validSections,missingSections,triangles:indices.length/3,visualizationOnly:true});
|
||||
}
|
||||
return {group,descriptions};
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
/** Capture-only silhouette trimming. Samples real alpha; never fills missing survey data. */
|
||||
export function smoothLandingOutline(source: HTMLCanvasElement, terrain: HTMLCanvasElement, preserveExposedStructures = false) {
|
||||
const width=source.width,height=source.height,scale=width/2172;
|
||||
const alpha=terrain.getContext('2d')!.getImageData(0,0,width,height).data;
|
||||
const tops:number[]=[],bottoms:number[]=[];
|
||||
for(let x=0;x<width;x++) {
|
||||
let top=height,bottom=-1;
|
||||
for(let y=0;y<height;y++)if(alpha[(y*width+x)*4+3]>240){top=Math.min(top,y);bottom=y;}
|
||||
tops.push(top);bottoms.push(bottom);
|
||||
}
|
||||
const support=tops.map((top,x)=>bottoms[x]-top>60*scale?x:-1).filter(x=>x>=0);
|
||||
if(!support.length)throw new Error('No continuous terrain silhouette');
|
||||
const left=support[0]+Math.ceil(12*scale),right=support.at(-1)!-Math.ceil(12*scale);
|
||||
const inset=Math.ceil(4*scale),radius=Math.ceil(18*scale),average=Math.ceil(8*scale);
|
||||
const eroded=(values:number[],upper:boolean)=>values.map((_,x)=>{
|
||||
const local=values.slice(Math.max(0,x-radius-average),Math.min(width,x+radius+average+1));
|
||||
return (upper?Math.max(...local):Math.min(...local))+(upper?inset:-inset);
|
||||
});
|
||||
const upper=eroded(tops,true),lower=eroded(bottoms,false);
|
||||
const mean=(values:number[],x:number)=>{
|
||||
const samples=values.slice(Math.max(0,x-average),Math.min(width,x+average+1));
|
||||
return samples.reduce((a,b)=>a+b,0)/samples.length;
|
||||
};
|
||||
const points:[number,number][]=[];
|
||||
const cap=Math.ceil(24*scale),step=Math.ceil(12*scale);
|
||||
for(let x=left+cap;x<=right-cap;x+=step)points.push([x,mean(upper,x)]);
|
||||
points.push([right-cap,mean(upper,right-cap)],[right,mean(upper,right-cap)+cap],[right,mean(lower,right-cap)-cap],[right-cap,mean(lower,right-cap)]);
|
||||
for(let x=right-cap-step;x>=left+cap;x-=step)points.push([x,mean(lower,x)]);
|
||||
points.push([left+cap,mean(lower,left+cap)],[left,mean(lower,left+cap)-cap],[left,mean(upper,left+cap)+cap],[left+cap,mean(upper,left+cap)]);
|
||||
const mid=(a:[number,number],b:[number,number])=>[(a[0]+b[0])/2,(a[1]+b[1])/2];
|
||||
const first=mid(points.at(-1)!,points[0]);
|
||||
let path=`M${first[0]} ${first[1]}`;
|
||||
points.forEach((p,i)=>{const next=mid(p,points[(i+1)%points.length]);path+=`Q${p[0]} ${p[1]} ${next[0]} ${next[1]}`;});path+='Z';
|
||||
const canvas=document.createElement('canvas');canvas.width=width;canvas.height=height;
|
||||
const ctx=canvas.getContext('2d')!;ctx.drawImage(source,0,0);
|
||||
const original=ctx.getImageData(0,0,width,height).data;
|
||||
ctx.globalCompositeOperation='destination-in';ctx.fill(new Path2D(path));
|
||||
const outputImage=ctx.getImageData(0,0,width,height),output=outputImage.data;
|
||||
// A cutaway may expose piles beyond the terrain silhouette. Preserve their rendered pixels.
|
||||
if(preserveExposedStructures){
|
||||
for(let i=0;i<alpha.length;i+=4)if(alpha[i+3]===0&&original[i+3]>0)output.set(original.subarray(i,i+4),i);
|
||||
ctx.putImageData(outputImage,0,0);
|
||||
}
|
||||
// Compare to terrain alpha only: smoothing should remove its rough border, not invent pixels.
|
||||
let before=0,after=0,addedPixels=0;
|
||||
for(let i=3;i<alpha.length;i+=4){if(alpha[i]>240){before++;if(output[i]>240)after++;}if(original[i]===0&&output[i]>0)addedPixels++;}
|
||||
return {canvas,metadata:{method:'inward-alpha-envelope-quadratic',path,retainedTerrainRatio:after/before,addedOutsideSourcePixels:addedPixels}};
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
"""Promote one rendered camera variant; preserve the previous landing image."""
|
||||
import json
|
||||
import shutil
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
root = Path(__file__).resolve().parents[1]
|
||||
assets = root / '랜딩페이지/assets'
|
||||
variant = sys.argv[1] if len(sys.argv) > 1 else 'horizontal-smooth'
|
||||
if variant not in ('balanced', 'low', 'high', 'trim30', 'trim20', 'refined', 'horizontal-smooth'):
|
||||
raise SystemExit('Unknown camera variant')
|
||||
source = root / ('.verify/landing-horizontal-20261109' if variant == 'horizontal-smooth' else '.verify/landing-hero-20261109')
|
||||
metadata = json.loads((source / f'{variant}.json').read_text())
|
||||
if variant == 'horizontal-smooth':
|
||||
assert metadata['along'] == 0 and metadata['outline']['addedOutsideSourcePixels'] == 0
|
||||
assert metadata['piers'] == 6 and metadata['abutments'] == 2
|
||||
# Full curve control points remain in the capture audit, outside the service bundle.
|
||||
metadata['outline'].pop('path')
|
||||
backup = source / ('before-horizontal' if variant == 'horizontal-smooth' else 'before-refined' if variant == 'refined' else 'before-trim30')
|
||||
backup.mkdir(exist_ok=True)
|
||||
for name in ('okseong-model-hero.png', 'okseong-model-hero.webp', 'okseong-hero-capture.ts'):
|
||||
if (assets / name).exists() and not (backup / name).exists():
|
||||
shutil.copyfile(assets / name, backup / name)
|
||||
for kind in ('png', 'webp'):
|
||||
shutil.copyfile(source / f'{variant}.{kind}', assets / f'okseong-model-hero.{kind}')
|
||||
metadata['terrainFlow'] = [None if p is None else {'x': p['x'], 'y': p['y']} for p in metadata['terrainFlow']]
|
||||
(assets / 'okseong-hero-capture.ts').write_text(
|
||||
'// Generated by scripts/promote-landing-hero.py from actual model projection.\n'
|
||||
'export const heroCapture = ' + json.dumps(metadata, ensure_ascii=False, indent=2) + ' as const;\n'
|
||||
)
|
||||
Loaded 100 of 2865 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user