forked from kimminsung/dwg-dxf-viewer-sample
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
473addbe44 | ||
|
|
daa1ea06e7 | ||
|
|
4bacefa615 | ||
|
|
aa27945d61 | ||
|
|
e51114dbfd | ||
|
|
129f0af25e | ||
|
|
1f80442f6c | ||
|
|
a924b1ec34 | ||
|
|
cf1298749b | ||
|
|
ce3859c487 | ||
|
|
c67a803e4d | ||
|
|
eec33820a6 | ||
|
|
6f200ef692 | ||
|
|
3480945b5a |
No files matched your search
@@ -109,6 +109,12 @@ Vite `?url` import 로 로드됩니다.
|
||||
|------|------|
|
||||
| 구형 한글 DWG TEXT 깨짐 (CP949→Latin-1 mojibake) | [`docs/korean-dwg-text-encoding.md`](./docs/korean-dwg-text-encoding.md) |
|
||||
| Model + Paper 동시 렌더로 글자 겹침 / Layout 탭 | [`docs/model-paper-space.md`](./docs/model-paper-space.md) |
|
||||
| `dist2` 정적 빌드 배포 절차 (공식 배포 스크립트 없음) | [`docs/deploy-dist2-static-build.md`](./docs/deploy-dist2-static-build.md) |
|
||||
| SubDMesh(MESH) 미표시 — parseResult 누락 + 큰 메쉬 잘림 | [`docs/subdmesh-rendering.md`](./docs/subdmesh-rendering.md) |
|
||||
| 선가중치(Lineweight) 미적용 — parseResult 누락 + WebGL 1px 한계 | [`docs/lineweight-rendering.md`](./docs/lineweight-rendering.md) |
|
||||
| acadrust MPL-2.0 고지 누락 (수정본 wasm 공개 배포) | [`docs/license-mpl2-acadrust.md`](./docs/license-mpl2-acadrust.md) |
|
||||
| acadrust 0.6.5 무수정 전환 — strict 파싱 실패, memory.grow 지연, VIEWPORT id | [`docs/acadrust-0.6.5-upgrade.md`](./docs/acadrust-0.6.5-upgrade.md) · 캡처 비교 [`report.html`](./docs/acadrust-0.6.5-upgrade-report.html) |
|
||||
| ↳ 위 둘의 측정 결과 + 상호작용(메쉬 선분이 굵기 버킷 상한을 넘길 위험) | [`docs/improvement-results-2026-08-04.md`](./docs/improvement-results-2026-08-04.md) |
|
||||
|
||||
샘플 패치: `fixDwgKoreanText`, `cadSpaces` + Viewer2D 공간 필터, Model/Layout 탭.
|
||||
원본 `hmwebviewer` 반영 절차는 각 문서를 따른다.
|
||||
@@ -120,6 +126,12 @@ Vite `?url` import 로 로드됩니다.
|
||||
| 조각 | 라이선스 |
|
||||
|------|----------|
|
||||
| Viewer2D 포트 · 샘플 글루 | MIT (hmwebviewer 계열) |
|
||||
| acadrust (WASM 내부) | MPL-2.0 |
|
||||
| dxf-parser · three | MIT |
|
||||
| acadrust 0.6.5 (WASM 내부, crates.io 무수정) | **MPL-2.0** |
|
||||
| dxf-parser · three · opentype.js | MIT |
|
||||
| NanumGothic | OFL |
|
||||
|
||||
acadrust 는 무수정으로 쓰므로 **MPL 원문 동봉 + 소스 입수 위치 고지**만 하면 된다.
|
||||
고지와 MPL 원문은 [`THIRD-PARTY-NOTICES.md`](./THIRD-PARTY-NOTICES.md) 와
|
||||
`public/licenses/`(배포 시 `/licenses/`)에 동봉한다. 0.4.1 패치본에서 옮겨 온 경위:
|
||||
[`docs/acadrust-0.6.5-upgrade.md`](./docs/acadrust-0.6.5-upgrade.md)
|
||||
의무 범위와 조치 근거: [`docs/license-mpl2-acadrust.md`](./docs/license-mpl2-acadrust.md)
|
||||
@@ -0,0 +1,61 @@
|
||||
# Third-party notices
|
||||
|
||||
This viewer bundles third-party code. The notices below apply to the source
|
||||
tree **and** to the built site (`dist2/`, deployed at
|
||||
`https://dwg-dxf-viewer-sample.pages.dev/`), because the build embeds the
|
||||
components listed here.
|
||||
|
||||
Served copies of the license texts live under
|
||||
[`public/licenses/`](./public/licenses/) → `/licenses/…` on the deployed site.
|
||||
|
||||
---
|
||||
|
||||
## acadrust 0.6.5 — Mozilla Public License 2.0 — unmodified
|
||||
|
||||
| | |
|
||||
|---|---|
|
||||
| Component | `acadrust` (DWG/DXF parser, Rust) |
|
||||
| Version | 0.6.5 |
|
||||
| License | MPL-2.0 — full text: [`public/licenses/acadrust-MPL-2.0.txt`](./public/licenses/acadrust-MPL-2.0.txt) (`/licenses/acadrust-MPL-2.0.txt`) |
|
||||
| Upstream | https://github.com/hakanaktt/acadrust · https://crates.io/crates/acadrust/0.6.5 |
|
||||
| Upstream commit | `289a616da6c68518218594aa80802cbe7fa71309` (from the crate's `.cargo_vcs_info.json`) |
|
||||
| Crate SHA-256 | `5eaa72520f70eb6f7f09b06f44e1ed0d8fad5fa743364f2c3715c30df962ec7c` (the `Cargo.lock` checksum the build used) |
|
||||
| Author | Hakan AK |
|
||||
| Shipped as | compiled into `assets/acadrust_dwg_bg-*.wasm` (Executable Form) |
|
||||
|
||||
**This copy is not modified.** The `.wasm` is built from the published crate
|
||||
exactly as crates.io serves it.
|
||||
|
||||
### How to obtain the Source Code Form (MPL-2.0 §3.2)
|
||||
|
||||
Download the crate, which is the complete source compiled into the shipped
|
||||
`.wasm`:
|
||||
|
||||
```bash
|
||||
curl -L -o acadrust-0.6.5.crate https://static.crates.io/crates/acadrust/acadrust-0.6.5.crate
|
||||
tar xzf acadrust-0.6.5.crate
|
||||
```
|
||||
|
||||
or `cargo vendor` in any project that depends on `acadrust = "=0.6.5"`, or the
|
||||
upstream commit above.
|
||||
|
||||
---
|
||||
|
||||
## dwg-wasm — MIT
|
||||
|
||||
The wasm-bindgen wrapper that turns acadrust output into this viewer's
|
||||
`parseResult` (`hmwebviewer/rust/dwg-wasm/`). Our own code, MIT. MPL-2.0 §3.3
|
||||
permits distributing this Larger Work under different terms as long as the
|
||||
MPL-covered files above keep their license — which they do.
|
||||
|
||||
---
|
||||
|
||||
## Other components
|
||||
|
||||
| Component | License |
|
||||
|---|---|
|
||||
| three.js | MIT |
|
||||
| dxf-parser | MIT |
|
||||
| opentype.js | MIT |
|
||||
| NanumGothic (`public/fonts/`) | SIL Open Font License 1.1 |
|
||||
| Viewer2D / sample glue | MIT |
|
||||
@@ -0,0 +1 @@
|
||||
function h(t){let e,n;try{const f=x(t,i.__wbindgen_malloc),c=w,o=i.parse_dwg_json(f,c);var r=o[0],s=o[1];if(o[3])throw r=0,s=0,T(o[2]);return e=r,n=s,l(r,s)}finally{i.__wbindgen_free(e,n,1)}}function A(){return{__proto__:null,"./acadrust_dwg_bg.js":{__proto__:null,__wbg_Error_92b29b0548f8b746:function(e,n){return Error(l(e,n))},__wbg_String_8564e559799eccda:function(e,n){const r=String(n),s=E(r,i.__wbindgen_malloc,i.__wbindgen_realloc),f=w;m().setInt32(e+4,f,!0),m().setInt32(e+0,s,!0)},__wbg___wbindgen_is_string_ea5e6cc2e4141dfe:function(e){return typeof e=="string"},__wbg___wbindgen_throw_344f42d3211c4765:function(e,n){throw new Error(l(e,n))},__wbg_new_32b398fb48b6d94a:function(){return new Array},__wbg_new_7796ffc7ed656783:function(){return new Map},__wbg_new_da52cf8fe3429cb2:function(){return new Object},__wbg_set_575dd786d51585f8:function(e,n,r){return e.set(n,r)},__wbg_set_6be42768c690e380:function(e,n,r){e[n]=r},__wbg_set_8a16b38e4805b298:function(e,n,r){e[n>>>0]=r},__wbindgen_cast_0000000000000001:function(e){return e},__wbindgen_cast_0000000000000002:function(e){return e},__wbindgen_cast_0000000000000003:function(e,n){return l(e,n)},__wbindgen_cast_0000000000000004:function(e){return BigInt.asUintN(64,e)},__wbindgen_init_externref_table:function(){const e=i.__wbindgen_externrefs,n=e.grow(4);e.set(0,void 0),e.set(n+0,void 0),e.set(n+1,null),e.set(n+2,!0),e.set(n+3,!1)}}}}let a=null;function m(){return(a===null||a.buffer.detached===!0||a.buffer.detached===void 0&&a.buffer!==i.memory.buffer)&&(a=new DataView(i.memory.buffer)),a}function l(t,e){return R(t>>>0,e)}let u=null;function b(){return(u===null||u.byteLength===0)&&(u=new Uint8Array(i.memory.buffer)),u}function x(t,e){const n=e(t.length*1,1)>>>0;return b().set(t,n/1),w=t.length,n}function E(t,e,n){if(n===void 0){const o=d.encode(t),_=e(o.length,1)>>>0;return b().subarray(_,_+o.length).set(o),w=o.length,_}let r=t.length,s=e(r,1)>>>0;const f=b();let c=0;for(;c<r;c++){const o=t.charCodeAt(c);if(o>127)break;f[s+c]=o}if(c!==r){c!==0&&(t=t.slice(c)),s=n(s,r,r=c+t.length*3,1)>>>0;const o=b().subarray(s+c,s+r),_=d.encodeInto(t,o);c+=_.written,s=n(s,r,c,1)>>>0}return w=c,s}function T(t){const e=i.__wbindgen_externrefs.get(t);return i.__externref_table_dealloc(t),e}let g=new TextDecoder("utf-8",{ignoreBOM:!0,fatal:!0});g.decode();const D=2146435072;let y=0;function R(t,e){return y+=e,y>=D&&(g=new TextDecoder("utf-8",{ignoreBOM:!0,fatal:!0}),g.decode(),y=e),g.decode(b().subarray(t,t+e))}const d=new TextEncoder;"encodeInto"in d||(d.encodeInto=function(t,e){const n=d.encode(t);return e.set(n),{read:t.length,written:n.length}});let w=0,i;function W(t,e){return i=t.exports,a=null,u=null,i.__wbindgen_start(),i}async function M(t,e){if(typeof Response=="function"&&t instanceof Response){if(typeof WebAssembly.instantiateStreaming=="function")try{return await WebAssembly.instantiateStreaming(t,e)}catch(s){if(t.ok&&n(t.type)&&t.headers.get("Content-Type")!=="application/wasm")console.warn("`WebAssembly.instantiateStreaming` failed because your server does not serve Wasm with `application/wasm` MIME type. Falling back to `WebAssembly.instantiate` which is slower. Original error:\n",s);else throw s}const r=await t.arrayBuffer();return await WebAssembly.instantiate(r,e)}else{const r=await WebAssembly.instantiate(t,e);return r instanceof WebAssembly.Instance?{instance:r,module:t}:r}function n(r){switch(r){case"basic":case"cors":case"default":return!0}return!1}}async function S(t){if(i!==void 0)return i;t!==void 0&&(Object.getPrototypeOf(t)===Object.prototype?{module_or_path:t}=t:console.warn("using deprecated parameters for the initialization function; pass a single object instead")),t===void 0&&(t=new URL("/assets/acadrust_dwg_bg-DmCEpFBu.wasm",import.meta.url));const e=A();(typeof t=="string"||typeof Request=="function"&&t instanceof Request||typeof URL=="function"&&t instanceof URL)&&(t=fetch(t));const{instance:n,module:r}=await M(await t,e);return W(n)}const O="/assets/acadrust_dwg_bg-DmCEpFBu.wasm";let p=null;function v(){return p||(p=S({module_or_path:O}).then(()=>{})),p}function I(t){return JSON.parse(h(t))}export{v as initAcadrustParser,I as parseDwgAcadrust};
|
||||
Binary file not shown.
File diff suppressed because it is too large.
Load diff
File diff suppressed because it is too large.
Load diff
File diff suppressed because it is too large.
Load diff
File diff suppressed because it is too large.
Load diff
File diff suppressed because it is too large.
Load diff
+199
-88
@@ -1,9 +1,9 @@
|
||||
<!doctype html>
|
||||
<html lang="ko">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<title>DWG/DXF · 모듈 조합 샘플</title>
|
||||
<!doctype html>
|
||||
<html lang="ko">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<title>DWG/DXF · 모듈 조합 샘플</title>
|
||||
<style>
|
||||
:root {
|
||||
--bg: #0d1117; --panel: #161b22; --ink: #e6edf3; --muted: #8b949e;
|
||||
@@ -14,6 +14,45 @@
|
||||
* { box-sizing: border-box; }
|
||||
html, body { margin: 0; height: 100%; background: var(--bg); color: var(--ink); font-family: var(--sans); }
|
||||
#app { position: fixed; inset: 0; }
|
||||
|
||||
/* ── 상단 로딩 프로그레스 바 (src/topProgress.ts 가 구동) ───────────────
|
||||
.bar : 실제 진행률. width 트랜지션 = 메인 스레드 의존.
|
||||
.sweep : WASM 파싱 / Viewer2D.load() 같은 동기 블로킹 구간용. transform
|
||||
키프레임은 컴포지터 스레드에서 돌기 때문에 메인 스레드가 멈춰
|
||||
있어도 계속 흐른다 — 그 구간에 줄 수 있는 유일한 피드백. */
|
||||
#progress {
|
||||
position: fixed; top: 0; left: 0; right: 0; height: 3px; z-index: 100;
|
||||
pointer-events: none; overflow: hidden;
|
||||
opacity: 0; transition: opacity .3s ease .15s;
|
||||
}
|
||||
#progress.on { opacity: 1; transition-delay: 0s; }
|
||||
#progress .bar {
|
||||
position: absolute; top: 0; bottom: 0; left: 0; width: 0;
|
||||
background: linear-gradient(90deg, var(--accent), #58a6ff 55%, var(--wasm));
|
||||
box-shadow: 0 0 10px rgba(63,185,80,.65), 0 0 4px rgba(88,166,255,.5);
|
||||
transition: width .28s cubic-bezier(.25,.8,.25,1);
|
||||
}
|
||||
#progress.err .bar {
|
||||
background: var(--danger);
|
||||
box-shadow: 0 0 10px rgba(248,81,73,.7);
|
||||
}
|
||||
#progress .sweep {
|
||||
position: absolute; top: 0; bottom: 0; left: 0; width: 34%;
|
||||
background: linear-gradient(90deg, transparent, rgba(230,237,243,.9), transparent);
|
||||
transform: translateX(-105%); will-change: transform; opacity: 0;
|
||||
}
|
||||
#progress.busy .sweep {
|
||||
opacity: 1;
|
||||
animation: pr-sweep 1.15s cubic-bezier(.4,0,.2,1) infinite;
|
||||
}
|
||||
@keyframes pr-sweep {
|
||||
from { transform: translateX(-105%); }
|
||||
to { transform: translateX(400%); }
|
||||
}
|
||||
@media (prefers-reduced-motion: reduce) {
|
||||
#progress .sweep { animation: none; }
|
||||
#progress .bar { transition: none; }
|
||||
}
|
||||
#toolbar {
|
||||
position: fixed; top: 12px; left: 12px; right: 12px; z-index: 10;
|
||||
display: flex; flex-wrap: wrap; gap: 8px; align-items: center; pointer-events: none;
|
||||
@@ -27,6 +66,25 @@
|
||||
button.primary { background: #238636; border-color: #2ea043; }
|
||||
button.wasm { border-color: var(--wasm); color: var(--wasm); }
|
||||
label.btn input { display: none; }
|
||||
/* 옵션 패널 — 값은 IndexedDB(hmw-viewer/options)에 저장된다 */
|
||||
#optBody { padding: 12px 14px; overflow: auto; font-size: 12px; color: var(--ink); }
|
||||
.opt-sec { margin-bottom: 16px; }
|
||||
.opt-sec > h4 {
|
||||
margin: 0 0 8px; font-size: 11px; font-weight: 700; letter-spacing: .05em;
|
||||
text-transform: uppercase; color: var(--muted);
|
||||
}
|
||||
.opt-row { display: flex; align-items: center; gap: 8px; margin-bottom: 8px; }
|
||||
.opt-row > label { flex: 1; color: var(--ink); }
|
||||
.opt-row input[type=range] { flex: 1; min-width: 90px; accent-color: var(--accent); }
|
||||
.opt-row input[type=number] {
|
||||
width: 58px; background: #0d1117; color: var(--ink);
|
||||
border: 1px solid var(--line); border-radius: 6px; padding: 3px 6px;
|
||||
font: 12px var(--mono); text-align: right;
|
||||
}
|
||||
.opt-row input[type=checkbox] { width: 15px; height: 15px; accent-color: var(--accent); }
|
||||
.opt-unit { font: 11px var(--mono); color: var(--muted); }
|
||||
.opt-note { font: 11px var(--mono); color: var(--accent); line-height: 1.6; word-break: keep-all; }
|
||||
.opt-help { font-size: 11px; color: var(--muted); line-height: 1.5; margin: 4px 0 0; }
|
||||
#status {
|
||||
margin-left: auto; font: 12px var(--mono); color: var(--muted);
|
||||
background: rgba(22,27,34,.85); border: 1px solid var(--line);
|
||||
@@ -130,6 +188,7 @@
|
||||
|
||||
#properties { right: 12px; }
|
||||
#layers { right: 344px; display: none; }
|
||||
#options { right: 676px; width: 340px; height: auto; max-height: 70vh; display: none; }
|
||||
|
||||
#propBody { flex: 1; overflow-y: auto; display: flex; flex-direction: column; }
|
||||
#layerBody { flex: 1; overflow-y: auto; display: flex; flex-direction: column; }
|
||||
@@ -158,85 +217,137 @@
|
||||
background: transparent; color: var(--muted); cursor: pointer; transition: all .15s;
|
||||
}
|
||||
.layer-sub-btn:hover { color: var(--ink); border-color: var(--accent); background: rgba(63,185,80,.1); }
|
||||
</style>
|
||||
<script type="module" crossorigin src="/assets/index-CmUgC68r.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
|
||||
<div id="toolbar">
|
||||
<label class="btn">
|
||||
Open file
|
||||
<input id="file" type="file" accept=".dwg,.dxf" />
|
||||
</label>
|
||||
<button id="sample" class="primary wasm" type="button" title="acadrust-dwg WASM">Sample DWG</button>
|
||||
<button id="sampleCivil" class="primary wasm" type="button" title="Civil Plan & Profile DWG">평면및종단면도.dwg</button>
|
||||
<button id="sampleDxf" class="primary" type="button" title="dxf-parser">Sample DXF</button>
|
||||
<div id="spaces" title="Model Space / Paper Space (Layout)"></div>
|
||||
<button id="fit" type="button">Fit (F)</button>
|
||||
<button id="theme" type="button">Theme</button>
|
||||
<button id="layersBtn" type="button">Layers</button>
|
||||
<button id="propsBtn" type="button">Props (속성)</button>
|
||||
<div id="status">ready</div>
|
||||
</div>
|
||||
|
||||
<div id="coords" title="마우스 위치 CAD 좌표 (Model=UCS, Layout=Paper 도면단위)">
|
||||
<span class="lbl">X</span><span id="coordX">—</span>
|
||||
<span class="sep">|</span>
|
||||
<span class="lbl">Y</span><span id="coordY">—</span>
|
||||
</div>
|
||||
|
||||
<!-- 레이어 (Layers) 관리 패널 -->
|
||||
<div id="layers" class="cad-panel">
|
||||
<div class="hdr">
|
||||
<h3>
|
||||
<span>🎨</span> 레이어 (Layers)
|
||||
<span id="layerCount" style="font-family:var(--mono);font-size:11px;color:var(--muted);background:rgba(255,255,255,.08);padding:1px 6px;border-radius:4px;font-weight:400"></span>
|
||||
</h3>
|
||||
<div class="hdr-actions">
|
||||
<button id="collapseLayersBtn" class="hdr-btn collapse-btn" type="button" title="접기">▾</button>
|
||||
<button id="closeLayersBtn" class="hdr-btn" type="button" title="닫기">✕</button>
|
||||
</div>
|
||||
</div>
|
||||
<div id="layerBody">
|
||||
<div class="layer-search-wrap">
|
||||
<input id="layerSearch" class="layer-search-input" type="text" placeholder="🔍 레이어 검색..." />
|
||||
</div>
|
||||
<div class="layer-sub-actions">
|
||||
<button id="layerShowAll" class="layer-sub-btn" type="button">전체 켜기</button>
|
||||
<button id="layerHideAll" class="layer-sub-btn" type="button">전체 끄기</button>
|
||||
</div>
|
||||
<div id="layerList"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 속성 (Properties) 패널 -->
|
||||
<div id="properties" class="cad-panel">
|
||||
<div class="hdr">
|
||||
<h3><span>📋</span> 속성 (Properties)</h3>
|
||||
<div class="hdr-actions">
|
||||
<button id="zoomSelBtn" type="button" title="선택 요소 위치로 확대">🔍 선택 확대</button>
|
||||
<button id="collapsePropsBtn" class="hdr-btn collapse-btn" type="button" title="접기">▾</button>
|
||||
<button id="closePropsBtn" class="hdr-btn" type="button" title="닫기">✕</button>
|
||||
</div>
|
||||
</div>
|
||||
<div id="propBody"></div>
|
||||
</div>
|
||||
|
||||
<aside id="recipe">
|
||||
<h3>Module recipe</h3>
|
||||
<ol>
|
||||
<li><code class="mod-j">ext2d</code> — .dwg / .dxf 분기</li>
|
||||
<li><code class="mod-w">acadrust-dwg</code> 또는 <code class="mod-j">dxf-parser</code></li>
|
||||
<li><code class="mod-j">dxfAdapter</code> — DXF → 공통 스키마</li>
|
||||
<li><code class="mod-j">Viewer2D</code> + <code class="mod-j">three</code> 렌더</li>
|
||||
<li><code class="mod-j">slugText</code> + TTF 폰트</li>
|
||||
</ol>
|
||||
<p style="margin:10px 0 0">
|
||||
코드: <code>src/main.ts</code> ·
|
||||
지도: <a href="/docs/modules-dwg-dxf.html" target="_blank">docs/modules-dwg-dxf.html</a>
|
||||
</p>
|
||||
</aside>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
</style>
|
||||
<script type="module" crossorigin src="/assets/index-VgpJrp_J.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
|
||||
<div id="toolbar">
|
||||
<label class="btn">
|
||||
Open file
|
||||
<input id="file" type="file" accept=".dwg,.dxf" />
|
||||
</label>
|
||||
<button id="sample" class="primary wasm" type="button" title="acadrust-dwg WASM">Sample DWG</button>
|
||||
<button id="sampleCivil" class="primary wasm" type="button" title="Civil Plan & Profile DWG">평면및종단면도.dwg</button>
|
||||
<button id="sampleDxf" class="primary" type="button" title="dxf-parser">Sample DXF</button>
|
||||
<div id="spaces" title="Model Space / Paper Space (Layout)"></div>
|
||||
<button id="fit" type="button">Fit (F)</button>
|
||||
<button id="theme" type="button">Theme</button>
|
||||
<button id="optionsBtn" type="button" title="표시 옵션 (선가중치 · 그리드 · 줌)">옵션</button>
|
||||
<button id="layersBtn" type="button">Layers</button>
|
||||
<button id="propsBtn" type="button">Props (속성)</button>
|
||||
<div id="status">ready</div>
|
||||
</div>
|
||||
|
||||
<div id="coords" title="마우스 위치 CAD 좌표 (Model=UCS, Layout=Paper 도면단위)">
|
||||
<span class="lbl">X</span><span id="coordX">—</span>
|
||||
<span class="sep">|</span>
|
||||
<span class="lbl">Y</span><span id="coordY">—</span>
|
||||
</div>
|
||||
|
||||
<!-- 레이어 (Layers) 관리 패널 -->
|
||||
<div id="layers" class="cad-panel">
|
||||
<div class="hdr">
|
||||
<h3>
|
||||
<span>🎨</span> 레이어 (Layers)
|
||||
<span id="layerCount" style="font-family:var(--mono);font-size:11px;color:var(--muted);background:rgba(255,255,255,.08);padding:1px 6px;border-radius:4px;font-weight:400"></span>
|
||||
</h3>
|
||||
<div class="hdr-actions">
|
||||
<button id="collapseLayersBtn" class="hdr-btn collapse-btn" type="button" title="접기">▾</button>
|
||||
<button id="closeLayersBtn" class="hdr-btn" type="button" title="닫기">✕</button>
|
||||
</div>
|
||||
</div>
|
||||
<div id="layerBody">
|
||||
<div class="layer-search-wrap">
|
||||
<input id="layerSearch" class="layer-search-input" type="text" placeholder="🔍 레이어 검색..." />
|
||||
</div>
|
||||
<div class="layer-sub-actions">
|
||||
<button id="layerShowAll" class="layer-sub-btn" type="button">전체 켜기</button>
|
||||
<button id="layerHideAll" class="layer-sub-btn" type="button">전체 끄기</button>
|
||||
</div>
|
||||
<div id="layerList"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 옵션 (Options) 패널 — 설정은 IndexedDB 에 저장 -->
|
||||
<div id="options" class="cad-panel">
|
||||
<div class="hdr">
|
||||
<h3><span>⚙️</span> 옵션 (Options)</h3>
|
||||
<div class="hdr-actions">
|
||||
<button id="optReset" type="button" title="기본값으로">↺ 기본값</button>
|
||||
<button id="collapseOptBtn" class="hdr-btn collapse-btn" type="button" title="접기">▾</button>
|
||||
<button id="closeOptBtn" class="hdr-btn" type="button" title="닫기">✕</button>
|
||||
</div>
|
||||
</div>
|
||||
<div id="optBody">
|
||||
<div class="opt-sec">
|
||||
<h4>선가중치 (Lineweight)</h4>
|
||||
<div class="opt-row">
|
||||
<label for="optLwOn">표시 (LWDISPLAY)</label>
|
||||
<input id="optLwOn" type="checkbox" />
|
||||
</div>
|
||||
<div class="opt-row">
|
||||
<label for="optLwScale">표시 배율</label>
|
||||
<input id="optLwScale" type="range" min="2" max="60" step="0.5" value="11" />
|
||||
<input id="optLwScaleNum" type="number" min="1" max="80" step="0.5" value="11" />
|
||||
<span class="opt-unit">px/mm</span>
|
||||
</div>
|
||||
<div id="optLwOut" class="opt-note">—</div>
|
||||
<p class="opt-help">
|
||||
AutoCAD "선가중치 설정 → 표시 배율"과 같다. 모델 공간에서 선가중치는 줌과
|
||||
무관한 화면 픽셀로 그려지므로, 화면 DPI에 맞춰 이 값을 조정한다.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="opt-sec">
|
||||
<h4>화면 (Display)</h4>
|
||||
<div class="opt-row">
|
||||
<label for="optGrid">그리드 표시</label>
|
||||
<input id="optGrid" type="checkbox" />
|
||||
</div>
|
||||
<div class="opt-row">
|
||||
<label for="optZoomSpeed">줌 속도</label>
|
||||
<input id="optZoomSpeed" type="range" min="0.2" max="3" step="0.1" value="1" />
|
||||
<input id="optZoomSpeedNum" type="number" min="0.1" max="5" step="0.1" value="1" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 속성 (Properties) 패널 -->
|
||||
<div id="properties" class="cad-panel">
|
||||
<div class="hdr">
|
||||
<h3><span>📋</span> 속성 (Properties)</h3>
|
||||
<div class="hdr-actions">
|
||||
<button id="zoomSelBtn" type="button" title="선택 요소 위치로 확대">🔍 선택 확대</button>
|
||||
<button id="collapsePropsBtn" class="hdr-btn collapse-btn" type="button" title="접기">▾</button>
|
||||
<button id="closePropsBtn" class="hdr-btn" type="button" title="닫기">✕</button>
|
||||
</div>
|
||||
</div>
|
||||
<div id="propBody"></div>
|
||||
</div>
|
||||
|
||||
<aside id="recipe">
|
||||
<h3>Module recipe</h3>
|
||||
<ol>
|
||||
<li><code class="mod-j">ext2d</code> — .dwg / .dxf 분기</li>
|
||||
<li><code class="mod-w">acadrust-dwg</code> 또는 <code class="mod-j">dxf-parser</code></li>
|
||||
<li><code class="mod-j">dxfAdapter</code> — DXF → 공통 스키마</li>
|
||||
<li><code class="mod-j">Viewer2D</code> + <code class="mod-j">three</code> 렌더</li>
|
||||
<li><code class="mod-j">slugText</code> + TTF 폰트</li>
|
||||
</ol>
|
||||
<p style="margin:10px 0 0">
|
||||
코드: <code>src/main.ts</code> ·
|
||||
지도: <a href="/docs/modules-dwg-dxf.html" target="_blank">docs/modules-dwg-dxf.html</a>
|
||||
</p>
|
||||
<!-- MPL-2.0 §3.2(b): recipients of the wasm must be told where the
|
||||
acadrust source (with our local patch) can be obtained. -->
|
||||
<p style="margin:6px 0 0">
|
||||
오픈소스 고지: <a href="/licenses/THIRD-PARTY-NOTICES.md" target="_blank">THIRD-PARTY-NOTICES</a>
|
||||
(acadrust · MPL-2.0 · <a href="/licenses/acadrust-0.4.1-read_mesh.patch" target="_blank">local patch</a>)
|
||||
</p>
|
||||
</aside>
|
||||
␍
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,70 @@
|
||||
# Third-party notices
|
||||
|
||||
This viewer bundles third-party code. The notices below apply to the source
|
||||
tree **and** to the built site (`dist2/`, deployed at
|
||||
`https://dwg-dxf-viewer-sample.pages.dev/`), because the build embeds the
|
||||
components listed here.
|
||||
|
||||
Served copies of the license texts live under
|
||||
[`public/licenses/`](./public/licenses/) → `/licenses/…` on the deployed site.
|
||||
|
||||
---
|
||||
|
||||
## acadrust 0.4.1 — Mozilla Public License 2.0 — **MODIFIED**
|
||||
|
||||
| | |
|
||||
|---|---|
|
||||
| Component | `acadrust` (DWG/DXF parser, Rust) |
|
||||
| Version | 0.4.1 |
|
||||
| License | MPL-2.0 — full text: [`public/licenses/acadrust-MPL-2.0.txt`](./public/licenses/acadrust-MPL-2.0.txt) (`/licenses/acadrust-MPL-2.0.txt`) |
|
||||
| Upstream | https://github.com/hakanaktt/acadrust · https://crates.io/crates/acadrust/0.4.1 |
|
||||
| Upstream commit | `f249c2f816acf36ee51cd5533716bdd443c2517e` (from the crate's `.cargo_vcs_info.json`) |
|
||||
| Author | Hakan AK |
|
||||
| Shipped as | compiled into `assets/acadrust_dwg_bg-*.wasm` (Executable Form) |
|
||||
|
||||
**This copy is modified.** One file differs from the published crate:
|
||||
|
||||
```
|
||||
src/io/dwg/dwg_stream_readers/object_reader/entities.rs (read_mesh array-count bounds)
|
||||
```
|
||||
|
||||
The modification bounds `read_mesh`'s array counts by the bits remaining in the
|
||||
object stream instead of the blanket 100 000-item guard, which truncated and
|
||||
thereby corrupted large SubD meshes.
|
||||
|
||||
### How to obtain the Source Code Form (MPL-2.0 §3.2)
|
||||
|
||||
1. Get the unmodified crate source — `cargo vendor`, or
|
||||
`https://crates.io/api/v1/crates/acadrust/0.4.1/download`, or the upstream
|
||||
commit above.
|
||||
2. Apply [`public/licenses/acadrust-0.4.1-read_mesh.patch`](./public/licenses/acadrust-0.4.1-read_mesh.patch)
|
||||
(`/licenses/acadrust-0.4.1-read_mesh.patch` on the deployed site):
|
||||
|
||||
```bash
|
||||
tar xf acadrust-0.4.1.crate && cd acadrust-0.4.1
|
||||
patch -p1 < acadrust-0.4.1-read_mesh.patch
|
||||
```
|
||||
|
||||
The result is the exact Source Code Form of the acadrust code compiled into the
|
||||
shipped `.wasm`. Both the original and the modified file remain under MPL-2.0.
|
||||
|
||||
---
|
||||
|
||||
## dwg-wasm — MIT
|
||||
|
||||
The wasm-bindgen wrapper that turns acadrust output into this viewer's
|
||||
`parseResult` (`hmwebviewer/rust/dwg-wasm/`). Our own code, MIT. MPL-2.0 §3.3
|
||||
permits distributing this Larger Work under different terms as long as the
|
||||
MPL-covered files above keep their license — which they do.
|
||||
|
||||
---
|
||||
|
||||
## Other components
|
||||
|
||||
| Component | License |
|
||||
|---|---|
|
||||
| three.js | MIT |
|
||||
| dxf-parser | MIT |
|
||||
| opentype.js | MIT |
|
||||
| NanumGothic (`public/fonts/`) | SIL Open Font License 1.1 |
|
||||
| Viewer2D / sample glue | MIT |
|
||||
@@ -0,0 +1,111 @@
|
||||
--- a/src/io/dwg/dwg_stream_readers/object_reader/entities.rs
|
||||
+++ b/src/io/dwg/dwg_stream_readers/object_reader/entities.rs
|
||||
@@ -1682,20 +1682,49 @@
|
||||
MLineData { scale_factor, justification, start_point, normal, openclosed, lines_in_style, vertex_count, vertices, style_handle }
|
||||
}
|
||||
|
||||
+/// Cap an array count against the bits actually left in the object's main
|
||||
+/// stream instead of the blanket [`MAX_ARRAY_COUNT`].
|
||||
+///
|
||||
+/// MESH is the one entity whose arrays legitimately run past 100 000 items: a
|
||||
+/// road-surface mesh in a civil drawing carries hundreds of thousands of
|
||||
+/// vertices. Clamping those to the blanket cap does not merely truncate the
|
||||
+/// mesh — the reader then continues from the wrong bit offset, so the face,
|
||||
+/// edge and crease lists that follow decode as garbage (observed: a 100 000
|
||||
+/// vertex clamp left a 14-face mesh with face sizes `[64, 0, 64, 23, 0, …]`).
|
||||
+/// Bounding by the remaining bits keeps the corrupt-data protection — no
|
||||
+/// unbounded allocation is possible — without mis-parsing a valid drawing.
|
||||
+///
|
||||
+/// `min_bits_per_item` is the shortest legal encoding of one element: a
|
||||
+/// BitDouble is 2 bits at minimum (the 0.0 / 1.0 forms), so a 3BD vertex is 6
|
||||
+/// and a BitLong is 2.
|
||||
+fn stream_bounded_count(reader: &DwgMergedReader, raw: i32, min_bits_per_item: i64) -> i32 {
|
||||
+ let raw = raw.max(0) as i64;
|
||||
+ let total_bits = (reader.main().data_len() as i64).saturating_mul(8);
|
||||
+ // The handle stream follows the main stream; anything past its start is not
|
||||
+ // array data. handle_start() is 0 when the framing did not supply it.
|
||||
+ let handle_start = reader.handle_start();
|
||||
+ let end_bits = if handle_start > 0 { handle_start.min(total_bits) } else { total_bits };
|
||||
+ let remaining = (end_bits - reader.position_in_bits()).max(0);
|
||||
+ raw.min(remaining / min_bits_per_item.max(1)).min(i32::MAX as i64) as i32
|
||||
+}
|
||||
+
|
||||
pub fn read_mesh(reader: &mut DwgMergedReader) -> MeshData {
|
||||
let version = reader.read_bit_short();
|
||||
let blend_crease = reader.read_bit();
|
||||
let subdivision_level = reader.read_bit_long();
|
||||
|
||||
- let num_verts = safe_count(reader.read_bit_long());
|
||||
+ let raw_verts = reader.read_bit_long();
|
||||
+ let num_verts = stream_bounded_count(reader, raw_verts, 6);
|
||||
let mut vertices = Vec::with_capacity(num_verts as usize);
|
||||
for _ in 0..num_verts { vertices.push(reader.read_3bit_double()); }
|
||||
|
||||
- let total_face_data = safe_count(reader.read_bit_long());
|
||||
+ let raw_face_data = reader.read_bit_long();
|
||||
+ let total_face_data = stream_bounded_count(reader, raw_face_data, 2);
|
||||
let mut faces = Vec::new();
|
||||
let mut i = 0;
|
||||
while i < total_face_data {
|
||||
- let n = safe_count(reader.read_bit_long());
|
||||
+ let raw_n = reader.read_bit_long();
|
||||
+ let n = stream_bounded_count(reader, raw_n, 2);
|
||||
i += 1;
|
||||
let mut face = Vec::new();
|
||||
for _ in 0..n {
|
||||
@@ -1705,7 +1734,8 @@
|
||||
faces.push(face);
|
||||
}
|
||||
|
||||
- let num_edges = safe_count(reader.read_bit_long());
|
||||
+ let raw_edges = reader.read_bit_long();
|
||||
+ let num_edges = stream_bounded_count(reader, raw_edges, 4);
|
||||
let mut edges = Vec::with_capacity(num_edges as usize);
|
||||
for _ in 0..num_edges {
|
||||
let s = reader.read_bit_long();
|
||||
@@ -1713,7 +1743,8 @@
|
||||
edges.push((s, e));
|
||||
}
|
||||
|
||||
- let num_creases = safe_count(reader.read_bit_long());
|
||||
+ let raw_creases = reader.read_bit_long();
|
||||
+ let num_creases = stream_bounded_count(reader, raw_creases, 2);
|
||||
let mut crease_values = Vec::with_capacity(num_creases as usize);
|
||||
for _ in 0..num_creases { crease_values.push(reader.read_bit_double()); }
|
||||
|
||||
@@ -2350,14 +2381,31 @@
|
||||
pub fn read_ole2frame(reader: &mut DwgMergedReader, version: DwgVersion) -> Ole2FrameData {
|
||||
let ver = reader.read_bit_short();
|
||||
let mode = if version.r2000_plus() { reader.read_bit_short() } else { 0 };
|
||||
- // OLE binary data can be very large (embedded images/documents),
|
||||
- // so don't use safe_count (100 KB cap). Use a generous 10 MB cap instead.
|
||||
let data_len = (reader.read_bit_long().max(0) as usize).min(10_000_000);
|
||||
let data = reader.read_bytes(data_len);
|
||||
let trailing_byte = if version.r2000_plus() { reader.read_byte() } else { 3 };
|
||||
- let upper_left = reader.read_3bit_double();
|
||||
- let lower_right = reader.read_3bit_double();
|
||||
+
|
||||
+ let mut upper_left = Vector3::new(0.0, 0.0, 0.0);
|
||||
+ let mut lower_right = Vector3::new(0.0, 0.0, 0.0);
|
||||
+
|
||||
+ // Extract 4-corner coordinates stored in the OLE binary data header starting at offset 2
|
||||
+ if data.len() >= 66 {
|
||||
+ let ul_x = f64::from_le_bytes(data[2..10].try_into().unwrap());
|
||||
+ let ul_y = f64::from_le_bytes(data[10..18].try_into().unwrap());
|
||||
+ let ul_z = f64::from_le_bytes(data[18..26].try_into().unwrap());
|
||||
+ let lr_x = f64::from_le_bytes(data[50..58].try_into().unwrap());
|
||||
+ let lr_y = f64::from_le_bytes(data[58..66].try_into().unwrap());
|
||||
+ let lr_z = if data.len() >= 74 { f64::from_le_bytes(data[66..74].try_into().unwrap()) } else { 0.0 };
|
||||
+
|
||||
+ if ul_x.is_finite() && ul_y.is_finite() && lr_x.is_finite() && lr_y.is_finite()
|
||||
+ && (ul_x != 0.0 || ul_y != 0.0 || lr_x != 0.0 || lr_y != 0.0) {
|
||||
+ upper_left = Vector3::new(ul_x, ul_y, if ul_z.is_finite() { ul_z } else { 0.0 });
|
||||
+ lower_right = Vector3::new(lr_x, lr_y, if lr_z.is_finite() { lr_z } else { 0.0 });
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
let ole_type = if version.r2000_plus() { reader.read_byte() } else { 2 };
|
||||
+
|
||||
Ole2FrameData { version: ver, mode, data, trailing_byte, upper_left, lower_right, ole_type }
|
||||
}
|
||||
|
||||
@@ -0,0 +1,375 @@
|
||||
Mozilla Public License Version 2.0
|
||||
==================================
|
||||
|
||||
1. Definitions
|
||||
--------------
|
||||
|
||||
1.1. "Contributor"
|
||||
means each individual or legal entity that creates, contributes to
|
||||
the creation of, or owns Covered Software.
|
||||
|
||||
1.2. "Contributor Version"
|
||||
means the combination of the Contributions of others (if any) used
|
||||
by a Contributor and that particular Contributor's Contribution.
|
||||
|
||||
1.3. "Contribution"
|
||||
means Covered Software of a particular Contributor.
|
||||
|
||||
1.4. "Covered Software"
|
||||
means Source Code Form to which the initial Contributor has attached
|
||||
the notice in Exhibit A, the Executable Form of such Source Code
|
||||
Form, and Modifications of such Source Code Form, in each case
|
||||
including portions thereof.
|
||||
|
||||
1.5. "Incompatible With Secondary Licenses"
|
||||
means
|
||||
|
||||
(a) that the initial Contributor has attached the notice described
|
||||
in Exhibit B to the Covered Software; or
|
||||
|
||||
(b) that the Covered Software was made available under the terms of
|
||||
version 1.1 or earlier of the License, but not also under the
|
||||
terms of a Secondary License.
|
||||
|
||||
1.6. "Executable Form"
|
||||
means any form of the work other than Source Code Form.
|
||||
|
||||
1.7. "Larger Work"
|
||||
means a work that combines Covered Software with other material, in
|
||||
a separate file or files, that is not Covered Software.
|
||||
|
||||
1.8. "License"
|
||||
means this document.
|
||||
|
||||
1.9. "Licensable"
|
||||
means having the right to grant, to the maximum extent possible,
|
||||
whether at the time of the initial grant or subsequently, any and
|
||||
all of the rights conveyed by this License.
|
||||
|
||||
1.10. "Modifications"
|
||||
means any of the following:
|
||||
|
||||
(a) any file in Source Code Form that results from an addition to,
|
||||
deletion from, or modification of the contents of Covered
|
||||
Software; or
|
||||
|
||||
(b) any new file in Source Code Form that contains any Covered
|
||||
Software.
|
||||
|
||||
1.11. "Patent Claims" of a Contributor
|
||||
means any patent claim(s), including without limitation, method,
|
||||
process, and apparatus claims, in any patent Licensable by such
|
||||
Contributor that would be infringed, but for the grant of the
|
||||
License, by the making, using, selling, offering for sale, having
|
||||
made, import, or transfer of either its Contributions or its
|
||||
Contributor Version.
|
||||
|
||||
1.12. "Secondary License"
|
||||
means either the GNU General Public License, Version 2.0, the GNU
|
||||
Lesser General Public License, Version 2.1, the GNU Affero General
|
||||
Public License, Version 3.0, or any later versions of those
|
||||
licenses.
|
||||
|
||||
1.13. "Source Code Form"
|
||||
means the form of the work preferred for making modifications.
|
||||
|
||||
1.14. "You" (or "Your")
|
||||
means an individual or a legal entity exercising rights under this
|
||||
License. For legal entities, "You" includes any entity that
|
||||
controls, is controlled by, or is under common control with You. For
|
||||
purposes of this definition, "control" means (a) the power, direct
|
||||
or indirect, to cause the direction or management of such entity,
|
||||
whether by contract or otherwise, or (b) ownership of more than
|
||||
fifty percent (50%) of the outstanding shares or beneficial
|
||||
ownership of such entity.
|
||||
|
||||
2. License Grants and Conditions
|
||||
--------------------------------
|
||||
|
||||
2.1. Grants
|
||||
|
||||
Each Contributor hereby grants You a world-wide, royalty-free,
|
||||
non-exclusive license:
|
||||
|
||||
(a) under intellectual property rights (other than patent or trademark)
|
||||
Licensable by such Contributor to use, reproduce, make available,
|
||||
modify, display, perform, distribute, and otherwise exploit its
|
||||
Contributions, either on an unmodified basis, with Modifications, or
|
||||
as part of a Larger Work; and
|
||||
|
||||
(b) under Patent Claims of such Contributor to make, use, sell, offer
|
||||
for sale, have made, import, and otherwise transfer either its
|
||||
Contributions or its Contributor Version.
|
||||
|
||||
2.2. Effective Date
|
||||
|
||||
The licenses granted in Section 2.1 with respect to any Contribution
|
||||
become effective for each Contribution on the date the Contributor first
|
||||
distributes such Contribution.
|
||||
|
||||
2.3. Limitations on Grant Scope
|
||||
|
||||
The licenses granted in this Section 2 are the only rights granted under
|
||||
this License. No additional rights or licenses will be implied from the
|
||||
distribution or licensing of Covered Software under this License.
|
||||
Notwithstanding Section 2.1(b) above, no patent license is granted by a
|
||||
Contributor:
|
||||
|
||||
(a) for any code that a Contributor has removed from Covered Software;
|
||||
or
|
||||
|
||||
(b) for infringements caused by: (i) Your and any other third party's
|
||||
modifications of Covered Software, or (ii) the combination of its
|
||||
Contributions with other software (except as part of its Contributor
|
||||
Version); or
|
||||
|
||||
(c) under Patent Claims infringed by Covered Software in the absence of
|
||||
its Contributions.
|
||||
|
||||
This License does not grant any rights in the trademarks, service marks,
|
||||
or logos of any Contributor (except as may be necessary to comply with
|
||||
the notice requirements in Section 3.4).
|
||||
|
||||
2.4. Subsequent Licenses
|
||||
|
||||
No Contributor makes additional grants as a result of Your choice to
|
||||
distribute the Covered Software under a subsequent version of this
|
||||
License (see Section 10.2) or under the terms of a Secondary License (if
|
||||
permitted under the terms of Section 3.3).
|
||||
|
||||
2.5. Representation
|
||||
|
||||
Each Contributor represents that the Contributor believes its
|
||||
Contributions are its original creation(s) or it has sufficient rights
|
||||
to grant the rights to its Contributions conveyed by this License.
|
||||
|
||||
2.6. Fair Use
|
||||
|
||||
This License is not intended to limit any rights You have under
|
||||
applicable copyright doctrines of fair use, fair dealing, or other
|
||||
equivalents.
|
||||
|
||||
2.7. Conditions
|
||||
|
||||
Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted
|
||||
in Section 2.1.
|
||||
|
||||
3. Responsibilities
|
||||
-------------------
|
||||
|
||||
3.1. Distribution of Source Form
|
||||
|
||||
All distribution of Covered Software in Source Code Form, including any
|
||||
Modifications that You create or to which You contribute, must be under
|
||||
the terms of this License. You must inform recipients that the Source
|
||||
Code Form of the Covered Software is governed by the terms of this
|
||||
License, and how they can obtain a copy of this License. You may not
|
||||
attempt to alter or restrict the recipients' rights in the Source Code
|
||||
Form.
|
||||
|
||||
3.2. Distribution of Executable Form
|
||||
|
||||
If You distribute Covered Software in Executable Form then:
|
||||
|
||||
(a) such Covered Software must also be made available in Source Code
|
||||
Form, as described in Section 3.1, and You must inform recipients of
|
||||
the Executable Form how they can obtain a copy of such Source Code
|
||||
Form by reasonable means in a timely manner, at a charge no more
|
||||
than the cost of distribution to the recipient; and
|
||||
|
||||
(b) You may distribute such Executable Form under the terms of this
|
||||
License, or sublicense it under different terms, provided that the
|
||||
license for the Executable Form does not attempt to limit or alter
|
||||
the recipients' rights in the Source Code Form under this License.
|
||||
|
||||
3.3. Distribution of a Larger Work
|
||||
|
||||
You may create and distribute a Larger Work under terms of Your choice,
|
||||
provided that You also comply with the requirements of this License for
|
||||
the Covered Software. If the Larger Work is a combination of Covered
|
||||
Software with a work governed by one or more Secondary Licenses, and the
|
||||
Covered Software is not Incompatible With Secondary Licenses, this
|
||||
License permits You to additionally distribute such Covered Software
|
||||
under the terms of such Secondary License(s), so that the recipient of
|
||||
the Larger Work may, at their option, further distribute the Covered
|
||||
Software under the terms of either this License or such Secondary
|
||||
License(s).
|
||||
|
||||
3.4. Notices
|
||||
|
||||
You may not remove or alter the substance of any license notices
|
||||
(including copyright notices, patent notices, disclaimers of warranty,
|
||||
or limitations of liability) contained within the Source Code Form of
|
||||
the Covered Software, except that You may alter any license notices to
|
||||
the extent required to remedy known factual inaccuracies.
|
||||
|
||||
3.5. Application of Additional Terms
|
||||
|
||||
You may choose to offer, and to charge a fee for, warranty, support,
|
||||
indemnity or liability obligations to one or more recipients of Covered
|
||||
Software. However, You may do so only on Your own behalf, and not on
|
||||
behalf of any Contributor. You must make it absolutely clear that any
|
||||
such warranty, support, indemnity, or liability obligation is offered by
|
||||
You alone, and You hereby agree to indemnify every Contributor for any
|
||||
liability incurred by such Contributor as a result of warranty, support,
|
||||
indemnity or liability terms You offer. You may include additional
|
||||
disclaimers of warranty and limitations of liability specific to any
|
||||
jurisdiction.
|
||||
|
||||
4. Inability to Comply Due to Statute or Regulation
|
||||
---------------------------------------------------
|
||||
|
||||
If it is impossible for You to comply with any of the terms of this
|
||||
License with respect to some or all of the Covered Software due to
|
||||
statute, judicial order, or regulation then You must: (a) comply with
|
||||
the terms of this License to the maximum extent possible; and (b)
|
||||
describe the limitations and the code they affect. Such description must
|
||||
be placed in a text file included with all distributions of the Covered
|
||||
Software under the name "LEGAL", and included in all Covered Software
|
||||
distributed in Source Code Form. Except to the extent prohibited by
|
||||
statute or regulation, such description must be sufficiently detailed
|
||||
for a recipient of ordinary skill to be able to understand it.
|
||||
|
||||
5. Termination
|
||||
--------------
|
||||
|
||||
5.1. The rights granted under this License will terminate automatically
|
||||
if You fail to comply with any of its terms. However, if You become
|
||||
compliant, then the rights granted under this License from a particular
|
||||
Contributor are reinstated (a) provisionally, unless and until such
|
||||
Contributor explicitly and finally terminates Your grants, and (b) on an
|
||||
ongoing basis, if such Contributor fails to notify You of the
|
||||
non-compliance by some reasonable means prior to 60 days after You have
|
||||
come back into compliance. Moreover, Your grants from a particular
|
||||
Contributor are reinstated on an ongoing basis if such Contributor
|
||||
notifies You of the non-compliance by some reasonable means, this is the
|
||||
first time You have received notice of non-compliance with this License
|
||||
from such Contributor, and You become compliant prior to 30 days after
|
||||
Your receipt of the notice.
|
||||
|
||||
5.2. If You initiate litigation against any entity by asserting a patent
|
||||
infringement claim (excluding declaratory judgment actions,
|
||||
counter-claims, and cross-claims) alleging that a Contributor Version
|
||||
directly or indirectly infringes any patent, then the rights granted to
|
||||
You by any and all Contributors for the Covered Software under Section
|
||||
2.1 of this License shall terminate.
|
||||
|
||||
5.3. In the event of termination under Sections 5.1 or 5.2 above, all
|
||||
end user license agreements (excluding distributors and resellers) which
|
||||
have been validly granted by You or Your distributors under this License
|
||||
prior to termination shall survive termination.
|
||||
|
||||
************************************************************************
|
||||
* *
|
||||
* 6. Disclaimer of Warranty *
|
||||
* ------------------------- *
|
||||
* *
|
||||
* Covered Software is provided under this License on an "as is" *
|
||||
* basis, without warranty of any kind, either expressed, implied, or *
|
||||
* statutory, including, without limitation, warranties that the *
|
||||
* Covered Software is free of defects, merchantable, fit for a *
|
||||
* particular purpose or non-infringing. The entire risk as to the *
|
||||
* quality and performance of the Covered Software is with You. *
|
||||
* Should any Covered Software prove defective in any respect, You *
|
||||
* (not any Contributor) assume the cost of any necessary servicing, *
|
||||
* repair, or correction. This disclaimer of warranty constitutes an *
|
||||
* essential part of this License. No use of any Covered Software is *
|
||||
* authorized under this License except under this disclaimer. *
|
||||
* *
|
||||
************************************************************************
|
||||
|
||||
************************************************************************
|
||||
* *
|
||||
* 7. Limitation of Liability *
|
||||
* -------------------------- *
|
||||
* *
|
||||
* Under no circumstances and under no legal theory, whether tort *
|
||||
* (including negligence), contract, or otherwise, shall any *
|
||||
* Contributor, or anyone who distributes Covered Software as *
|
||||
* permitted above, be liable to You for any direct, indirect, *
|
||||
* special, incidental, or consequential damages of any character *
|
||||
* including, without limitation, damages for lost profits, loss of *
|
||||
* goodwill, work stoppage, computer failure or malfunction, or any *
|
||||
* and all other commercial damages or losses, even if such party *
|
||||
* shall have been informed of the possibility of such damages. This *
|
||||
* limitation of liability shall not apply to liability for death or *
|
||||
* personal injury resulting from such party's negligence to the *
|
||||
* extent applicable law prohibits such limitation. Some *
|
||||
* jurisdictions do not allow the exclusion or limitation of *
|
||||
* incidental or consequential damages, so this exclusion and *
|
||||
* limitation may not apply to You. *
|
||||
* *
|
||||
************************************************************************
|
||||
|
||||
8. Litigation
|
||||
-------------
|
||||
|
||||
Any litigation relating to this License may be brought only in the
|
||||
courts of a jurisdiction where the defendant maintains its principal
|
||||
place of business and such litigation shall be governed by laws of that
|
||||
jurisdiction, without reference to its conflict-of-law provisions.
|
||||
Nothing in this Section shall prevent a party's ability to bring
|
||||
cross-claims or counter-claims.
|
||||
|
||||
9. Miscellaneous
|
||||
----------------
|
||||
|
||||
This License represents the complete agreement concerning the subject
|
||||
matter hereof. If any provision of this License is held to be
|
||||
unenforceable, such provision shall be reformed only to the extent
|
||||
necessary to make it enforceable. Any law or regulation which provides
|
||||
that the language of a contract shall be construed against the drafter
|
||||
shall not be used to construe this License against a Contributor.
|
||||
|
||||
10. Versions of the License
|
||||
---------------------------
|
||||
|
||||
10.1. New Versions
|
||||
|
||||
Mozilla Foundation is the license steward. Except as provided in Section
|
||||
10.3, no one other than the license steward has the right to modify or
|
||||
publish new versions of this License. Each version will be given a
|
||||
distinguishing version number.
|
||||
|
||||
10.2. Effect of New Versions
|
||||
|
||||
You may distribute the Covered Software under the terms of the version
|
||||
of the License under which You originally received the Covered Software,
|
||||
or under the terms of any subsequent version published by the license
|
||||
steward.
|
||||
|
||||
10.3. Modified Versions
|
||||
|
||||
If you create software not governed by this License, and you want to
|
||||
create a new license for such software, you may create and use a
|
||||
modified version of this License if you rename the license and remove
|
||||
any references to the name of the license steward (except to note that
|
||||
such modified license differs from this License).
|
||||
|
||||
10.4. Distributing Source Code Form that is Incompatible With Secondary
|
||||
Licenses
|
||||
|
||||
If You choose to distribute Source Code Form that is Incompatible With
|
||||
Secondary Licenses under the terms of this version of the License, the
|
||||
notice described in Exhibit B of this License must be attached.
|
||||
|
||||
Exhibit A - Source Code Form License Notice
|
||||
-------------------------------------------
|
||||
|
||||
This Source Code Form is subject to the terms of the Mozilla Public
|
||||
License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
|
||||
If it is not possible or desirable to put the notice in a particular
|
||||
file, then You may include the notice in a location (such as a LICENSE
|
||||
file in a relevant directory) where a recipient would be likely to look
|
||||
for such a notice.
|
||||
|
||||
You may add additional accurate notices of copyright ownership.
|
||||
|
||||
Exhibit B - "Incompatible With Secondary Licenses" Notice
|
||||
---------------------------------------------------------
|
||||
|
||||
This Source Code Form is "Incompatible With Secondary Licenses", as
|
||||
defined by the Mozilla Public License, v. 2.0.
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 344 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 22 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 79 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 97 KiB |
@@ -0,0 +1,299 @@
|
||||
<!doctype html>
|
||||
<html lang="ko">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>acadrust 업그레이드 보고서</title>
|
||||
<style>
|
||||
:root {
|
||||
--bg: #ffffff; --fg: #1d2129; --muted: #5b6270; --line: #dfe3ea;
|
||||
--soft: #f4f6f9; --accent: #2457c5; --code-bg: #eef1f6; --shadow: 0 1px 2px rgba(0,0,0,.06);
|
||||
}
|
||||
@media (prefers-color-scheme: dark) {
|
||||
:root:not([data-theme="light"]) {
|
||||
--bg: #12151b; --fg: #e3e6ec; --muted: #9aa3b2; --line: #2b313c;
|
||||
--soft: #1a1f27; --accent: #7aa2ff; --code-bg: #222833; --shadow: none;
|
||||
}
|
||||
}
|
||||
:root[data-theme="dark"] {
|
||||
--bg: #12151b; --fg: #e3e6ec; --muted: #9aa3b2; --line: #2b313c;
|
||||
--soft: #1a1f27; --accent: #7aa2ff; --code-bg: #222833; --shadow: none;
|
||||
}
|
||||
* { box-sizing: border-box; }
|
||||
html { -webkit-text-size-adjust: 100%; }
|
||||
body {
|
||||
margin: 0; background: var(--bg); color: var(--fg);
|
||||
font: 15px/1.65 "Pretendard", "Malgun Gothic", "Apple SD Gothic Neo", system-ui, sans-serif;
|
||||
}
|
||||
main { max-width: 1180px; margin: 0 auto; padding: 32px 16px 80px; }
|
||||
h1 { font-size: 1.75rem; margin: 0 0 .6em; letter-spacing: -.01em; }
|
||||
h2 { font-size: 1.3rem; margin: 2.2em 0 .7em; padding-bottom: .3em; border-bottom: 1px solid var(--line); }
|
||||
h3 { font-size: 1.08rem; margin: 1.8em 0 .6em; }
|
||||
p, li { max-width: 78ch; }
|
||||
a { color: var(--accent); }
|
||||
hr { border: 0; border-top: 1px solid var(--line); margin: 2.4em 0; }
|
||||
blockquote { margin: 0 0 1.4em; padding: .7em 1em; background: var(--soft); border-left: 3px solid var(--accent); border-radius: 4px; color: var(--muted); }
|
||||
blockquote p { margin: .2em 0; }
|
||||
code { font: .88em/1.4 ui-monospace, "Cascadia Mono", Consolas, monospace; background: var(--code-bg); padding: .1em .35em; border-radius: 4px; }
|
||||
pre { background: var(--code-bg); padding: 12px 14px; border-radius: 6px; overflow-x: auto; }
|
||||
pre code { background: none; padding: 0; }
|
||||
.tbl { overflow-x: auto; margin: .8em 0 1.4em; border: 1px solid var(--line); border-radius: 6px; box-shadow: var(--shadow); }
|
||||
table { border-collapse: collapse; width: 100%; font-size: .92em; }
|
||||
th, td { padding: 7px 10px; border-bottom: 1px solid var(--line); text-align: left; vertical-align: top; }
|
||||
th { background: var(--soft); font-weight: 600; white-space: nowrap; }
|
||||
tr:last-child td { border-bottom: 0; }
|
||||
.tbl.shots table { table-layout: fixed; }
|
||||
.tbl.shots th { white-space: normal; }
|
||||
.tbl.shots td { text-align: center; color: var(--muted); font-size: .9em; }
|
||||
img.shot { width: 100%; height: auto; display: block; border-radius: 4px; cursor: zoom-in; background: #0b0d10; }
|
||||
.toolbar { position: fixed; bottom: 12px; right: 12px; z-index: 10; }
|
||||
.toolbar button { font: inherit; font-size: .85em; padding: 5px 10px; border: 1px solid var(--line); background: var(--bg); color: var(--fg); border-radius: 6px; cursor: pointer; }
|
||||
#lb { position: fixed; inset: 0; background: rgba(0,0,0,.88); display: none; align-items: center; justify-content: center; z-index: 20; cursor: zoom-out; padding: 16px; }
|
||||
#lb.open { display: flex; }
|
||||
#lb img { max-width: 100%; max-height: 100%; border-radius: 4px; }
|
||||
@media (max-width: 720px) {
|
||||
body { font-size: 14px; }
|
||||
.tbl.shots table, .tbl.shots tbody, .tbl.shots tr, .tbl.shots td, .tbl.shots thead { display: block; width: 100%; }
|
||||
.tbl.shots thead { display: none; }
|
||||
.tbl.shots td { border-bottom: 1px solid var(--line); }
|
||||
}
|
||||
@media print { .toolbar, #lb { display: none !important; } img.shot { break-inside: avoid; } }
|
||||
|
||||
.badge { display: inline-block; padding: 1px 8px; border-radius: 999px; font-size: .82em; font-weight: 600; white-space: nowrap; }
|
||||
.b-same { background: #e3f4e8; color: #17663a; }
|
||||
.b-better { background: #e6eefc; color: #1f4fae; }
|
||||
@media (prefers-color-scheme: dark) { :root:not([data-theme="light"]) .b-same { background: #173524; color: #8fdcae; } :root:not([data-theme="light"]) .b-better { background: #1b2a48; color: #9dbcff; } }
|
||||
:root[data-theme="dark"] .b-same { background: #173524; color: #8fdcae; }
|
||||
:root[data-theme="dark"] .b-better { background: #1b2a48; color: #9dbcff; }
|
||||
.kpis { display: grid; grid-template-columns: repeat(auto-fit, minmax(170px, 1fr)); gap: 10px; margin: 1em 0 1.6em; }
|
||||
.kpi { border: 1px solid var(--line); border-radius: 8px; padding: 10px 14px; background: var(--soft); }
|
||||
.kpi b { display: block; font-size: 1.45em; line-height: 1.2; }
|
||||
.kpi span { color: var(--muted); font-size: .88em; }
|
||||
td.num, th.num { text-align: right; white-space: nowrap; font-variant-numeric: tabular-nums; }
|
||||
.cap { text-align: left !important; color: var(--fg) !important; font-size: .92em; }
|
||||
.fname { font-weight: 600; }
|
||||
.sub { color: var(--muted); font-size: .85em; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="toolbar"><button type="button" id="theme">테마 전환</button></div>
|
||||
<main>
|
||||
<h1>acadrust 0.4.1 → 0.6.5 업그레이드 보고서</h1>
|
||||
<blockquote>
|
||||
<p>대상: <code>dwg-dxf-viewer-sample</code> 뷰어의 DWG 파서 wasm (<code>hmwebviewer/rust/dwg-wasm</code>)<br>
|
||||
비교: acadrust 0.4.1 + 로컬 패치 (현재 배포본과 같은 wasm) ↔ acadrust 0.6.5 무수정<br>
|
||||
작성: 2026-10-19 · 상태: <code>수정 완료·검증됨</code> (아래 캡처와 수치는 모두 실제 실행 결과)</p>
|
||||
</blockquote>
|
||||
|
||||
<h2>1. 핵심</h2>
|
||||
<div class="kpis">
|
||||
<div class="kpi"><b>22 / 22</b><span>양쪽 모두 정상 로드</span></div>
|
||||
<div class="kpi"><b>17 / 22</b><span>기본 화면 픽셀 동일</span></div>
|
||||
<div class="kpi"><b>5</b><span>화면이 달라진 샘플 — 전부 개선</span></div>
|
||||
<div class="kpi"><b>0</b><span>콘솔 에러 (양쪽)</span></div>
|
||||
</div>
|
||||
<ul>
|
||||
<li><strong>기존 샘플 22개(DWG 21 + DXF 1)가 0.6.5 에서도 모두 정상으로 열린다.</strong> 기본 탭(Model/Layout)과 엔티티 수가 0.4.1 과 같고, 콘솔 에러는 양쪽 모두 0이다.</li>
|
||||
<li><strong>17개는 기본 화면이 픽셀 단위로 같다.</strong> 나머지 5개는 0.4.1 이 잘못 읽던 데이터를 0.6.5 가 바로잡은 결과이며, 나빠진 화면은 없다 (§5).</li>
|
||||
<li><strong>0.4.1 에 로컬 패치로 고쳐 두었던 두 기능(MESH, OLE2FRAME)은 0.6.5 무수정으로 화면이 픽셀 단위로 같다</strong> (§4). 그래서 패치를 버리고 acadrust 를 고치지 않은 채로 쓸 수 있게 됐다.</li>
|
||||
<li>파싱 결과: DWG 21개, 엔티티 381,811개 전부 짝이 맞는다 (누락·추가 0). 값이 바뀐 엔티티는 2,925개(0.77 %)이며 원인을 모두 확인했다 (§7).</li>
|
||||
<li>대가: wasm 크기 brotli 294 KB → 815 KB, 브라우저 로드 시간 약 2~9 % 증가 (§9).</li>
|
||||
</ul>
|
||||
|
||||
<h2>2. 비교 방법</h2>
|
||||
<ul>
|
||||
<li>같은 뷰어 코드(작업 트리)를 띄우고 <strong>파서 wasm 파일만</strong> 0.4.1 판 → 0.6.5 판으로 바꿔 같은 절차를 두 번 실행했다.</li>
|
||||
<li>Chrome headless (실제 GPU, ANGLE D3D11), 화면 1280×800. 샘플마다 새 브라우저 컨텍스트에서 파일을 열고, 상태바에 <code>✓ 파일명</code> 이 뜨면 로드 성공으로 판정했다.</li>
|
||||
<li>캡처는 UI 패널을 숨기고 도면만 찍었다. 두 캡처를 픽셀 단위로 비교해 색 차이(RGB 합 30 초과)가 난 픽셀 비율을 "화면 차이"로 적었다.</li>
|
||||
<li>차이가 난 곳과 기존 패치 기능은 같은 좌표로 확대해 한 번 더 찍었다. 차이 이미지는 달라진 픽셀을 <span style="color:#d0f">자홍색</span>으로 칠한 것이다.</li>
|
||||
<li>별도로 Node 에서 두 wasm 의 파싱 결과(JSON)를 엔티티 handle 단위로 비교했다 (§7).</li>
|
||||
</ul>
|
||||
|
||||
<h2>3. 전체 결과</h2>
|
||||
<div class="tbl"><table>
|
||||
<thead><tr><th>#</th><th>파일</th><th>위치</th><th class="num">MB</th><th>기본 탭</th><th class="num">엔티티</th><th class="num">로드 0.4.1 → 0.6.5</th><th class="num">화면 차이</th><th>판정</th></tr></thead>
|
||||
<tbody>
|
||||
<tr><td>1</td><td class="fname">BasicSample.dwg</td><td class="sub">public/samples</td><td class="num">0.4</td><td>Model</td><td class="num">7,309</td><td class="num">394 → 435 ms</td><td class="num">0 %</td><td><span class="badge b-same">동일</span></td></tr>
|
||||
<tr><td>2</td><td class="fname">C0060202-001-평면및종단면도(1)(대산방향STA.18+492.08-19+411.50).dwg</td><td class="sub">public/samples</td><td class="num">5.4</td><td>Layout</td><td class="num">17,810</td><td class="num">958 → 987 ms</td><td class="num">0 %</td><td><span class="badge b-same">동일</span></td></tr>
|
||||
<tr><td>3</td><td class="fname">C0060203-001-표준단면도(2차로,자연환기300m이상).dwg</td><td class="sub">public/samples</td><td class="num">0.4</td><td>Model</td><td class="num">2,068</td><td class="num">347 → 412 ms</td><td class="num">0 %</td><td><span class="badge b-same">동일</span></td></tr>
|
||||
<tr><td>4</td><td class="fname">C0060203-002-굴착및시공순서도(2차로,자연환기300m이상).dwg</td><td class="sub">public/samples</td><td class="num">0.8</td><td>Model</td><td class="num">5,979</td><td class="num">314 → 356 ms</td><td class="num">0.02 %</td><td><span class="badge b-better">개선</span></td></tr>
|
||||
<tr><td>5</td><td class="fname">bb.dwg</td><td class="sub">public/samples</td><td class="num">0.7</td><td>Layout</td><td class="num">438</td><td class="num">231 → 307 ms</td><td class="num">0 %</td><td><span class="badge b-same">동일</span></td></tr>
|
||||
<tr><td>6</td><td class="fname">dwg_1.60mb.dwg</td><td class="sub">public/samples</td><td class="num">1.6</td><td>Model</td><td class="num">21,330</td><td class="num">1,139 → 1,253 ms</td><td class="num">0.0089 %</td><td><span class="badge b-better">개선</span></td></tr>
|
||||
<tr><td>7</td><td class="fname">dwg_18.3mb.dwg</td><td class="sub">public/samples</td><td class="num">18.4</td><td>Model</td><td class="num">82,393</td><td class="num">3,920 → 4,024 ms</td><td class="num">0 %</td><td><span class="badge b-same">동일</span></td></tr>
|
||||
<tr><td>8</td><td class="fname">simple.dxf</td><td class="sub">public/samples</td><td class="num">0.0</td><td>—</td><td class="num">6</td><td class="num">55 → 54 ms</td><td class="num">0 %</td><td><span class="badge b-same">동일</span></td></tr>
|
||||
<tr><td>9</td><td class="fname">04manhole1-simplify.dwg</td><td class="sub">dist2/samples</td><td class="num">0.4</td><td>Layout</td><td class="num">7,035</td><td class="num">357 → 421 ms</td><td class="num">0 %</td><td><span class="badge b-same">동일</span></td></tr>
|
||||
<tr><td>10</td><td class="fname">대산당진 2공구_노면_20260804_143854.dwg</td><td class="sub">dist2/samples</td><td class="num">37.1</td><td>Model</td><td class="num">65,495</td><td class="num">5,651 → 5,737 ms</td><td class="num">0 %</td><td><span class="badge b-same">동일</span></td></tr>
|
||||
<tr><td>11</td><td class="fname">test.dwg</td><td class="sub">dist2/samples</td><td class="num">18.4</td><td>Model</td><td class="num">82,393</td><td class="num">3,719 → 4,043 ms</td><td class="num">0 %</td><td><span class="badge b-same">동일</span></td></tr>
|
||||
<tr><td>12</td><td class="fname">a. 거더배치 삽도_25.02.28.dwg</td><td class="sub">dwg2model</td><td class="num">0.2</td><td>Layout</td><td class="num">1,433</td><td class="num">453 → 484 ms</td><td class="num">0 %</td><td><span class="badge b-same">동일</span></td></tr>
|
||||
<tr><td>13</td><td class="fname">a. 교대배치 삽도_25.02.28.dwg</td><td class="sub">dwg2model</td><td class="num">0.4</td><td>Layout</td><td class="num">2,138</td><td class="num">320 → 293 ms</td><td class="num">0 %</td><td><span class="badge b-same">동일</span></td></tr>
|
||||
<tr><td>14</td><td class="fname">a. 교량시종점 삽도_25.02.28.dwg</td><td class="sub">dwg2model</td><td class="num">0.4</td><td>Layout</td><td class="num">4,432</td><td class="num">377 → 353 ms</td><td class="num">3.45 %</td><td><span class="badge b-better">개선</span></td></tr>
|
||||
<tr><td>15</td><td class="fname">a. 교량폭원 삽도_25.02.28.dwg</td><td class="sub">dwg2model</td><td class="num">0.5</td><td>Layout</td><td class="num">2,824</td><td class="num">210 → 258 ms</td><td class="num">0 %</td><td><span class="badge b-same">동일</span></td></tr>
|
||||
<tr><td>16</td><td class="fname">a. 교면포장 삽도_25.02.28.dwg</td><td class="sub">dwg2model</td><td class="num">0.2</td><td>Layout</td><td class="num">1,304</td><td class="num">176 → 226 ms</td><td class="num">0 %</td><td><span class="badge b-same">동일</span></td></tr>
|
||||
<tr><td>17</td><td class="fname">a. 중앙분리대 삽도_25.02.28.dwg</td><td class="sub">dwg2model</td><td class="num">0.4</td><td>Layout</td><td class="num">2,159</td><td class="num">267 → 260 ms</td><td class="num">18.37 %</td><td><span class="badge b-better">개선</span></td></tr>
|
||||
<tr><td>18</td><td class="fname">a. 횡단경사 삽도_25.02.28.dwg</td><td class="sub">dwg2model</td><td class="num">0.5</td><td>Layout</td><td class="num">5,635</td><td class="num">343 → 341 ms</td><td class="num">0 %</td><td><span class="badge b-same">동일</span></td></tr>
|
||||
<tr><td>19</td><td class="fname">산외교- ELEVATION 산출근거도 (울산방향).dwg</td><td class="sub">dwg2model</td><td class="num">0.6</td><td>Model</td><td class="num">11,262</td><td class="num">740 → 818 ms</td><td class="num">0.0047 %</td><td><span class="badge b-better">개선</span></td></tr>
|
||||
<tr><td>20</td><td class="fname">산외교-받침배치도 (울산방향) .dwg</td><td class="sub">dwg2model</td><td class="num">0.4</td><td>Model</td><td class="num">6,240</td><td class="num">590 → 689 ms</td><td class="num">0 %</td><td><span class="badge b-same">동일</span></td></tr>
|
||||
<tr><td>21</td><td class="fname">산외교_파이형_교각일반도(울산P11-꺾임).dwg</td><td class="sub">dwg2model</td><td class="num">1.0</td><td>Model</td><td class="num">25,927</td><td class="num">707 → 731 ms</td><td class="num">0 %</td><td><span class="badge b-same">동일</span></td></tr>
|
||||
<tr><td>22</td><td class="fname">산외교_파이형_교각일반도(울산P9).dwg</td><td class="sub">dwg2model</td><td class="num">1.0</td><td>Model</td><td class="num">26,207</td><td class="num">732 → 710 ms</td><td class="num">0 %</td><td><span class="badge b-same">동일</span></td></tr>
|
||||
</tbody></table></div>
|
||||
<p class="sub">로드 시간은 파일 선택부터 상태바 ✓ 표시까지(파싱 + 렌더). <code>simple.dxf</code> 는 wasm 이 아니라 dxf-parser 로 읽으므로 대조군이다. <code>dwg_18.3mb.dwg</code> 와 <code>test.dwg</code> 는 바이트는 다르지만 같은 도면이다.</p>
|
||||
|
||||
<h2>4. 0.4.1 로컬 패치 기능 — 0.6.5 무수정으로 동일</h2>
|
||||
<p>0.4.1 에서는 아래 두 가지를 acadrust 소스를 고쳐서 해결했다. 0.6.5 는 고치지 않은 상태로 같은 화면을 낸다.</p>
|
||||
<h3>MESH(SubDMesh) — 노면·부체도로면 삼각망</h3>
|
||||
<p class="sub">대산당진 2공구_노면_20260804_143854.dwg · 확대 화면 차이 <strong>0 %</strong></p>
|
||||
<div class="tbl shots"><table><thead><tr><th>0.4.1 + 로컬 패치</th><th>0.6.5 무수정</th></tr></thead>
|
||||
<tbody><tr><td><img class="shot" loading="lazy" alt="MESH(SubDMesh) — 노면·부체도로면 삼각망 0.4.1" src="data:image/jpeg;base64,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 truncated
|
||||
<p>0.4.1 원본은 10만 개 상한에서 배열이 잘려 메쉬가 깨졌다 (verts 100000 / faces 14). 패치본과 0.6.5 모두 verts 105,497 / faces 185,444 / edges 290,931.</p>
|
||||
<h3>OLE2FRAME — 삽입 이미지와 위치</h3>
|
||||
<p class="sub">C0060203-001-표준단면도(2차로,자연환기300m이상).dwg · 확대 화면 차이 <strong>0 %</strong></p>
|
||||
<div class="tbl shots"><table><thead><tr><th>0.4.1 + 로컬 패치</th><th>0.6.5 무수정</th></tr></thead>
|
||||
<tbody><tr><td><img class="shot" loading="lazy" alt="OLE2FRAME — 삽입 이미지와 위치 0.4.1" src="data:image/jpeg;base64,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 truncated
|
||||
<p>0.4.1 원본은 프레임 좌표를 읽지 못했다 ((1,1,0)–(0,0,0)). 패치본과 0.6.5 모두 (20584.21, 25712.29)–(39654.45, 13712.29), 추출 이미지 바이트도 동일.</p>
|
||||
|
||||
<h2>5. 화면이 달라진 5개 — 원인과 판정</h2>
|
||||
<p>모두 0.4.1 이 잘못 읽던 값을 0.6.5 가 바로잡은 경우다. 차이 이미지에서 자홍색이 달라진 픽셀이다.</p>
|
||||
<h3>a. 중앙분리대 삽도_25.02.28.dwg</h3>
|
||||
<p><span class="badge b-better">개선</span> 레이아웃 전체 뷰포트를 모델 창으로 오판하던 것이 해소 — 도면을 가로지르던 검은 세로 띠가 사라지고 Fit 이 도면을 채움 · 기본 화면 차이 18.37 %</p>
|
||||
<div class="tbl shots"><table><thead><tr><th>0.4.1</th><th>0.6.5</th><th>차이</th></tr></thead><tbody>
|
||||
<tr><td><img class="shot" loading="lazy" alt="a. 중앙분리대 삽도_25.02.28.dwg 0.4.1" src="data:image/jpeg;base64,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 truncated
|
||||
|
||||
</tbody></table></div>
|
||||
<h3>a. 교량시종점 삽도_25.02.28.dwg</h3>
|
||||
<p><span class="badge b-better">개선</span> 트루컬러 해치(RGB 128,93,59)의 근사 색이 ACI 35 → 37 로 바뀌어 원본에 더 가까워짐 · 기본 화면 차이 3.45 % · 확대 화면 차이 7.80 %</p>
|
||||
<div class="tbl shots"><table><thead><tr><th>0.4.1</th><th>0.6.5</th><th>차이</th></tr></thead><tbody>
|
||||
<tr><td><img class="shot" loading="lazy" alt="a. 교량시종점 삽도_25.02.28.dwg 0.4.1" src="data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/4gHYSUNDX1BST0ZJTEUAAQEAAAHIAAAAAAQwAABtbnRyUkdCIFhZWiAH4AABAAEAAAAAAABhY3NwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAA9tYAAQAAAADTLQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAlkZXNjAAAA8AAAACRyWFlaAAABFAAAABRnWFlaAAABKAAAABRiWFlaAAABPAAAABR3dHB0AAABUAAAABRyVFJDAAABZAAAAChnVFJDAAABZAAAAChiVFJDAAABZAAAAChjcHJ0AAABjAAAADxtbHVjAAAAAAAAAAEAAAAMZW5VUwAAAAgAAAAcAHMAUgBHAEJYWVogAAAAAAAAb6IAADj1AAADkFhZWiAAAAAAAABimQAAt4UAABjaWFlaIAAAAAAAACSgAAAPhAAAts9YWVogAAAAAAAA9tYAAQAAAADTLXBhcmEAAAAAAAQAAAACZmYAAPKnAAANWQAAE9AAAApbAAAAAAAAAABtbHVjAAAAAAAAAAEAAAAMZW5VUwAAACAAAAAcAEcAbwBvAGcAbABlACAASQBuAGMALgAgADIAMAAxADb/2wBDAAYEBQYFBAYGBQYHBwYIChAKCgkJChQODwwQFxQYGBcUFhYaHSUfGhsjHBYWICwgIyYnKSopGR8tMC0oMCUoKSj/2wBDAQcHBwoIChMKChMoGhYaKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCj/wAARCAMgBQADASIAAhEBAxEB/8QAHAABAQEAAwEBAQAAAAAAAAAAAAYHAwQFCAIB/8QAaRAAAQMCAgMHDAkPBwgIBwEBAAECAwQFBhEHEiETFhcxV5TSFBUiQVFVVnWVs9HTMjY3VGF0kpPiIzM1OEJTcXOBkaWxssPUNFJmcoOhtCRDYoKWosHhCCUmR3akwsQYREaEhYbwo2P/xAAaAQEAAwEBAQAAAAAAAAAAAAAAAgMEAQUG/8QAQREBAAIAAwELCAoCAgIDAQAAAAECAwQREhMUITFBUVORktHSM1JhcXKhseEFFSIyNGKBssHwQuIjgkOiJJPxVP/aAAwDAQACEQMRAD8A+qQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEvpBxlS4NtdPM+lnuFxrZ20lBb6fLdKqZ3E1M9jW9tXLsRO6qoiy8Gkm+2m6W6HH2DJMPW64TtpYLhFcY6yNkzvYMlRqIrEXi1tqZ/BmqBqAPCxjdL1arZFLhvD7r9WvlSNafqxlKjG5KqvV7+0ioiZIirtIy6aRr/hWqppcdYRbbrFNIyF92oLglXHTveuTd1YrGOa3PYruLPJEzVUA1AA6V6fcY7ZM+ywUtRcEy3KKqmdFG7ames5rXKmzPtLtyA7oIjq7SN3gwt5Yn/hjyb9jXF+GJ7I/EGH7GlDcbnT21X0dzlkkjdK7JHaroGoqJkq8YGmg6d4juEttnZZ6imp69UTcpamFZY2rmmebUc1V2Z9tCOrKXSLT0k8yYgwu5Y2OfktnmRFyTPj6o2AXoMlxfja8p/0clxfRTR0V6mt1NVI+GNFbG97o0dqtfrbOyXjzK/AuPsO40bPHh65LWz0rGOqE6nki1dbPL2bURdqLxAVYIzSZiqtwsmFet8VPK67X6ktUqTtcurFLrazm5KmTk1dirmnwKWYAEBofv1yv1Jit92qlqHUWIq2igVWNbqQxuajGbETPLNdq7T0MY2LF10uUU2GsZR2KjbEjH07rTHVq9+aqr9dzkVNitTL4M+2BXg+e8W33FdhrEtdJpWjvOI5FVkFotuG4Jp3PTLY/KTKNERc1V6psRV25Gy4BZiJmEbamM5KaS/rHnVLTNRGIqquSbNmaJki5bM88tgHvgj8YR4+dcolwbPhiO37im6JdIp3S7pmueSxuRNXLV+HPMksNYrx5wr02E78uGK2BlG+tr5LXFO11KzJUjRXPeqaznZdjlnq7fhA10EDii/3Oi0vYIs1LUqy2XGnrn1UOo1d0WNjVYuapmmSqvEqF8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABlWIf8ArL/pHYSpJtkdpstXcYcvupJXpCqL8CNTM9fT3b4rlocxZDOrkbHROqWq3j1olSRv97EPH0usqMPYwwjj2Clmnt9qWekuyUzFdIlNK1MpFREzcyNyK5U28efdVPE0nY6tOkTDe8zR9XrdLvfFiY+Sma/Uo6ZXoskszsk1U1UVqtXb2WWXaUNVst4mrME2+9JRzVFRPb46vqWBWq97nRo7UarlRM81yTNUQx/SBiiqx5V02B75Za/CNkudXDDPX3aNyPqla/XSnp1Yjoke5WNyc6TLLPJFXJDVcRYwwzgp9qoL9c4LYlW10dJurXJGqRo1FRXomq3LWbxqnwGbaYMVWnSJhubA2B6mO+Xq5SQZy0eckFFG2Vr1mllRFa1E1cti55qmzbtDcAE2J3ScxHiK4WmuZBR4WvN3jdGj1nonU6MauapqrukrVz2Z8WW1NoHXsOMEu2KcX2bqFYlw+6Bqy7rrbvusW6cWSauXFxqZpjLFKY3wDouvbaRaPrniqgXqdZN01NWSVF7LJM/YZ8SHYw1U4mteMsdXifAl/fT359M6nYyWk1mbnCsa6+c2SZrxZZ7D86NGXbD2j/DljxBo4vNfW2hzpY5U6ikZHLrvVr2K6ZFRUR+WeSLxgWOnyjuVw0QYlpbJDUz18sDEZFTIqyPbujFeiIm1ex1s07aZoZlPhnRJFSI+HR3iqtmyTOGC1XHWVe37JWt/vN5w9c6m60DqistFdaZEerOp6xY1eqIidl9Te5Mlz7uexdhnFouWLNIWIcQrasRMw1ZLJdJbVuFNRxz1VS6PLWe58qK1iKq9jk3trnxZqEzpPxDHc9BOJbbb8IYgsFsoaKGOF1zpWU7MmzRI1jW66vXZ21TLYu3M1PASYySKXfk/Dzodzj6l61Mma7t62vuir2tXLL4SH0k2zFGF8LXK8VWJqXE1ipYkkq7Nf7fToyoYjkzRJY2tydxaqK1U1suM1HqyqrcLpW2WnYysno0mpYK1Fja17mZsbIiZq1EVURctqbQMa0+X+r36Ycp7TTOr6fCqtxLd4WIiq2FsjWN1V/no10r9VVTYme3I3G3VtNcqCmrqGZk9JUxtmhlYubXscmbXJ8CoqEro2wa/DFurai71aXPEd3l6putcqbJZMskY1F4o2Iuq1O5nsTPJP7gLB02Da260lBcNfDEz0nobc9nZUL3K5ZGMfn9bVVRUblsVV+FXBLaEq2nt1h0g11dK2GkpsUXSaaR3ExjVarnL+BEVSSvWKtFl/ulTU3/SVfK6hnVyLa0qJqekRiqqozUijYqomeWauVVyTNVLXQFtoccZ+Flx/aac2LsQ4huGkRmCMIvttsmS2dcqq51kKzuYxZFjRIYkVEVyLkubly2/BtDIbHiPQ5UYixVaLxT4fjwtA2jbZ5WW9zJXZxLuy7s1m6quuibXLn8Kl9gDFmjO3Ynggw5ji61LqxraGltNVV1M9MxznNRu5pK1Va7NERM3ZbVQ9xMGaR4nJIzSdDO5q57lNh2nSN/wKrXI5EX4FzPW0T4qrsU268RXyjooLvZrlLbKp1E5XQSvjyXXj1uyRNuWS7dnw5IHBi3Ft/qLxU4bwLZJqi6Ro1tRda6NYqGi1kR2esqZyvyVq6jM/ZIqrsVCKrdGt9wvSXJkELce2m+LHJfaOseylrJZmqi7rDKmWbM0zSJy9jlk1eyVS309X65YZ0T367WOqWkuNOkKRTIxrlZrTxsXY5FT2LlTiOxvHuvKBiv/AMn/AA4EA3A2HcGadsBJhe0tt7aqkuDqhGyPfmrYmo3PWcuWWsvF3TdjKEmveF9LmFbI/EtzvFtvFLWOmjuDIVVjomtc1zFjjZku3LbnsNXAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABnWkrSjBgu926zU1jul9vFbE6dlJb4le9I0zTWyRFz9iuxOLLM0UxXFX21mCvEtR++AcNd85KMb8yf0D8s00Xlmepolxq3PauVC9M/9w02tr6+mxPbKKKWnqIal0r54UiVrqeBsa5Sa2tt+qajMstuvmiJqqTz8aV76m9Phhp20fU9C61OcxXOe6pnlgZJJk5M2K5rHoiKi6i7cnLkgSj9NN6e1Wv0TY1c1e0tC9U/YP5HpnvMTdWPRLjRjePJtC9E/YLO7YmuNquD7dUzU8kkdTTq+aKmc5/U8rJckZEjldJLukDkybnk1dbVXVUS4gvDsBPvcE9A6ta2dsEDYVclVKkqsgZlr5sc/JrXMzza52WaaqoBHcNd85KMb8yf0Bw13zkoxvzJ/QLmuxDc2191kpkpUo7bcqS3vhe1VfKkrYHSPR+siIqJUN1W5LtjXj101bB6K5jka5WuVMkciZ5fCBi3DXfOSjG/Mn9AcNd85KMb8yf0C9hxNSyXiioqLine truncated
|
||||
<tr><td><img class="shot" loading="lazy" alt="a. 교량시종점 삽도_25.02.28.dwg 확대 0.4.1" src="data:image/jpeg;base64,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 truncated
|
||||
</tbody></table></div>
|
||||
<h3>C0060203-002-굴착및시공순서도(2차로,자연환기300m이상).dwg</h3>
|
||||
<p><span class="badge b-better">개선</span> ATTDEF 정렬을 새로 읽어 동그라미 번호(①)가 원의 오른쪽 아래에서 중앙으로 옮겨짐 · 기본 화면 차이 0.02 % · 확대 화면 차이 0.02 %</p>
|
||||
<div class="tbl shots"><table><thead><tr><th>0.4.1</th><th>0.6.5</th><th>차이</th></tr></thead><tbody>
|
||||
<tr><td><img class="shot" loading="lazy" alt="C0060203-002-굴착및시공순서도(2차로,자연환기300m이상).dwg 0.4.1" src="data:image/jpeg;base64,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sDNCiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiLVfBZ+MKxftA+4rKrVfBZ+MKxftA+4q2j9o3pCw+U/udb2Xe4p8Kf4wr7+0H7gsqtV8Kf4wr7+0H7gsqlb7R3SU8mfc6Pst9wRERVLciIiIiIiIiIiIpdBGyRtUXtB0Quc30HI3URTbZ8Wt/Z3feFCUGnnOWqs0CjTI3+9ERFNZURERERERFNs39/f/Cl/q3KEptm/v7/AOFL/VuUJVj7Q9A+K1v+6s9p3uYiIisWRERERERERERERERERERERF9BLTkEg94XxERejI9wwXuI7iUa97RhrnAegryi7JXZK+ucXHLiSfSV66WT8931rwiSUkopYude0ACtqgBsAJXe1REXWvc3zTCkyo9nmmF9c4vcXOJc4nJJOSSvrXua1zWuIa7ZwB5/OvKLkqMnNERFxcRERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERar4LPxhWL9oH3FZVar4LPxhWL9oH3FW0ftG9IWHyn9zrey73FPhT/ABhX39oP3BZVar4U/wAYV9/aD9wWVSt9o7pKeTPudH2W+4IiIqluREREREREREREXeln6ATjTq6SMx8+WSN/4Lgu9LK6IT6GatcZYfQMjdcFEDEq6o6WMEzE6sse9ERFJUoiIiIisr5TUlNJSeAymRktOyV+XAlj3Ddu3d6fnVaoseHtDghunzTI24/EA9y70cPhE/R69HVc7OO5pOPpxhcFfcE08VVfhFURskj8GqZNLgD1mQPe3+LQqFSuu845Lpq0iNE3zxieg4D3FERWM9NSx2OkqWyl1XNLI10YcMMa3Tgkc8nVt8xUXPDSAda5LciY2Z47sPjgq5EQDJwOakiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIi0lvoPCuCa6eCmElVHXwxBzWLine truncated
|
||||
<tr><td><img class="shot" loading="lazy" alt="C0060203-002-굴착및시공순서도(2차로,자연환기300m이상).dwg 확대 0.4.1" src="data:image/jpeg;base64,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 truncated
|
||||
</tbody></table></div>
|
||||
<h3>dwg_1.60mb.dwg</h3>
|
||||
<p><span class="badge b-better">개선</span> 3D 폴리선 vertex 순서 수정 — 곡선을 가로지르던 가짜 직선(청록)이 사라짐 · 기본 화면 차이 0.0089 % · 확대 화면 차이 0.48 %</p>
|
||||
<div class="tbl shots"><table><thead><tr><th>0.4.1</th><th>0.6.5</th><th>차이</th></tr></thead><tbody>
|
||||
<tr><td><img class="shot" loading="lazy" alt="dwg_1.60mb.dwg 0.4.1" src="data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/4gHYSUNDX1BST0ZJTEUAAQEAAAHIAAAAAAQwAABtbnRyUkdCIFhZWiAH4AABAAEAAAAAAABhY3NwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAA9tYAAQAAAADTLQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAlkZXNjAAAA8AAAACRyWFlaAAABFAAAABRnWFlaAAABKAAAABRiWFlaAAABPAAAABR3dHB0AAABUAAAABRyVFJDAAABZAAAAChnVFJDAAABZAAAAChiVFJDAAABZAAAAChjcHJ0AAABjAAAADxtbHVjAAAAAAAAAAEAAAAMZW5VUwAAAAgAAAAcAHMAUgBHAEJYWVogAAAAAAAAb6IAADj1AAADkFhZWiAAAAAAAABimQAAt4UAABjaWFlaIAAAAAAAACSgAAAPhAAAts9YWVogAAAAAAAA9tYAAQAAAADTLXBhcmEAAAAAAAQAAAACZmYAAPKnAAANWQAAE9AAAApbAAAAAAAAAABtbHVjAAAAAAAAAAEAAAAMZW5VUwAAACAAAAAcAEcAbwBvAGcAbABlACAASQBuAGMALgAgADIAMAAxADb/2wBDAAYEBQYFBAYGBQYHBwYIChAKCgkJChQODwwQFxQYGBcUFhYaHSUfGhsjHBYWICwgIyYnKSopGR8tMC0oMCUoKSj/2wBDAQcHBwoIChMKChMoGhYaKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCj/wAARCAMgBQADASIAAhEBAxEB/8QAHQABAAMBAQEBAQEAAAAAAAAAAAUGBwQDCAIBCf/EAFIQAAEEAgIBAgUCBAIECQkDDQEAAgMEBREGEiETMQcUIkFRMmEVI0JxUoEWJDORFzZDYnSVobGyJTdUVXKDs9PUCDRTY4LB0USS8CY1ZHPhwv/EABoBAQEAAwEBAAAAAAAAAAAAAAABAgMEBQb/xAA6EQEAAgEDAwIDBQgBAwQDAAAAAQIRAyExBBJBUWETInEFFDJCgVJikaGxwdHwI3Lh8TNjgqKSstL/2gAMAwEAAhEDEQA/APmNERVBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERARF9L5am/E0sXSficPLXpwVmONpsX82IN/nk9xtmtD6ySPqIPnyA+aEX0llMBw9vMKfGsjxqESS1PmBdi3Ezq3sXF/Qt1+j+wJHvtRcfwnxF2pHNPjrON7UxLK+PItdHFNsfQQWOOi09u3sB+PdBgKLV+Y/DvjWErC1ByO26tqNxeyq2wGiRrjG4lrm/S7qdOAI8fuFU4OK0L84hxPJ8bYmc7TI5oZ4XEefPlhH237oKoiuP/Bzn5pOmObQyJ0SPlL0TyQNeepcHfcfbx91wWOEcors7yYDJFmt9o67njWt720Hx+6CuovWxXmrSuisxSQytOiyRpaR9vYryQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQd+AqfP53HVNb+Ysxxa1vfZwH/AOlfS+ZwlaxTsSulsNrXvmmGUTxPYfXd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 truncated
|
||||
<tr><td><img class="shot" loading="lazy" alt="dwg_1.60mb.dwg 확대 0.4.1" src="data:image/jpeg;base64,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 truncated
|
||||
</tbody></table></div>
|
||||
<h3>산외교- ELEVATION 산출근거도 (울산방향).dwg</h3>
|
||||
<p><span class="badge b-better">개선</span> 작은 표고 텍스트 2곳의 위치 (ATTDEF 정렬) · 기본 화면 차이 0.0047 %</p>
|
||||
<div class="tbl shots"><table><thead><tr><th>0.4.1</th><th>0.6.5</th><th>차이</th></tr></thead><tbody>
|
||||
<tr><td><img class="shot" loading="lazy" alt="산외교- ELEVATION 산출근거도 (울산방향).dwg 0.4.1" src="data:image/jpeg;base64,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 truncated
|
||||
|
||||
</tbody></table></div>
|
||||
|
||||
<h2>6. 전체 샘플 화면 비교 (기본 화면)</h2>
|
||||
<p>파일을 열었을 때 처음 보이는 화면이다. 이미지를 누르면 크게 볼 수 있다.</p>
|
||||
<div class="tbl shots"><table>
|
||||
<thead><tr><th style="width:22%">파일</th><th>0.4.1</th><th>0.6.5</th></tr></thead>
|
||||
<tbody>
|
||||
<tr><td class="cap"><span class="fname">1. BasicSample.dwg</span><br><span class="sub">Model · 7,309 엔티티</span><br><span class="badge b-same">픽셀 동일</span></td><td><img class="shot" loading="lazy" alt="BasicSample.dwg 0.4.1" src="data:image/jpeg;base64,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 truncated
|
||||
<tr><td class="cap"><span class="fname">2. C0060202-001-평면및종단면도(1)(대산방향STA.18+492.08-19+411.50).dwg</span><br><span class="sub">Layout · 17,810 엔티티</span><br><span class="badge b-same">픽셀 동일</span></td><td><img class="shot" loading="lazy" alt="C0060202-001-평면및종단면도(1)(대산방향STA.18+492.08-19+411.50).dwg 0.4.1" src="data:image/jpeg;base64,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 truncated
|
||||
<tr><td class="cap"><span class="fname">3. C0060203-001-표준단면도(2차로,자연환기300m이상).dwg</span><br><span class="sub">Model · 2,068 엔티티</span><br><span class="badge b-same">픽셀 동일</span></td><td><img class="shot" loading="lazy" alt="C0060203-001-표준단면도(2차로,자연환기300m이상).dwg 0.4.1" src="data:image/jpeg;base64,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 truncated
|
||||
<tr><td class="cap"><span class="fname">4. C0060203-002-굴착및시공순서도(2차로,자연환기300m이상).dwg</span><br><span class="sub">Model · 5,979 엔티티</span><br><span class="badge b-better">개선 · 0.02 %</span><br><span class="sub">§5 참고</span></td><td><img class="shot" loading="lazy" alt="C0060203-002-굴착및시공순서도(2차로,자연환기300m이상).dwg 0.4.1" src="data:image/jpeg;base64,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sDNCiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiLVfBZ+MKxftA+4rKrVfBZ+MKxftA+4q2j9o3pCw+U/udb2Xe4p8Kf4wr7+0H7gsqtV8Kf4wr7+0H7gsqlb7R3SU8mfc6Pst9wRERVLciIiIiIiIiIiIpdBGyRtUXtB0Quc30HI3URTbZ8Wt/Z3feFCUGnnOWqs0CjTI3+9ERFNZURERERERFNs39/f/Cl/q3KEptm/v7/AOFL/VuUJVj7Q9A+K1v+6s9p3uYiIisWRERERERERERERERERERERF9BLTkEg94XxERejI9wwXuI7iUa97RhrnAegryi7JXZK+ucXHLiSfSV66WT8931rwiSUkopYude0ACtqgBsAJXe1REXWvc3zTCkyo9nmmF9c4vcXOJc4nJJOSSvrXua1zWuIa7ZwB5/OvKLkqMnNERFxcRERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERar4LPxhWL9oH3FZVar4LPxhWL9oH3FW0ftG9IWHyn9zrey73FPhT/ABhX39oP3BZVar4U/wAYV9/aD9wWVSt9o7pKeTPudH2W+4IiIqluREREREREREREXeln6ATjTq6SMx8+WSN/4Lgu9LK6IT6GatcZYfQMjdcFEDEq6o6WMEzE6sse9ERFJUoiLine truncated
|
||||
<tr><td class="cap"><span class="fname">5. bb.dwg</span><br><span class="sub">Layout · 438 엔티티</span><br><span class="badge b-same">픽셀 동일</span></td><td><img class="shot" loading="lazy" alt="bb.dwg 0.4.1" src="data:image/jpeg;base64,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 truncated
|
||||
<tr><td class="cap"><span class="fname">6. dwg_1.60mb.dwg</span><br><span class="sub">Model · 21,330 엔티티</span><br><span class="badge b-better">개선 · 0.0089 %</span><br><span class="sub">§5 참고</span></td><td><img class="shot" loading="lazy" alt="dwg_1.60mb.dwg 0.4.1" src="data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/4gHYSUNDX1BST0ZJTEUAAQEAAAHIAAAAAAQwAABtbnRyUkdCIFhZWiAH4AABAAEAAAAAAABhY3NwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAA9tYAAQAAAADTLQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAlkZXNjAAAA8AAAACRyWFlaAAABFAAAABRnWFlaAAABKAAAABRiWFlaAAABPAAAABR3dHB0AAABUAAAABRyVFJDAAABZAAAAChnVFJDAAABZAAAAChiVFJDAAABZAAAAChjcHJ0AAABjAAAADxtbHVjAAAAAAAAAAEAAAAMZW5VUwAAAAgAAAAcAHMAUgBHAEJYWVogAAAAAAAAb6IAADj1AAADkFhZWiAAAAAAAABimQAAt4UAABjaWFlaIAAAAAAAACSgAAAPhAAAts9YWVogAAAAAAAA9tYAAQAAAADTLXBhcmEAAAAAAAQAAAACZmYAAPKnAAANWQAAE9AAAApbAAAAAAAAAABtbHVjAAAAAAAAAAEAAAAMZW5VUwAAACAAAAAcAEcAbwBvAGcAbABlACAASQBuAGMALgAgADIAMAAxADb/2wBDAAYEBQYFBAYGBQYHBwYIChAKCgkJChQODwwQFxQYGBcUFhYaHSUfGhsjHBYWICwgIyYnKSopGR8tMC0oMCUoKSj/2wBDAQcHBwoIChMKChMoGhYaKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCj/wAARCAMgBQADASIAAhEBAxEB/8QAHQABAAMBAQEBAQEAAAAAAAAAAAUGBwQDCAIBCf/EAFIQAAEEAgIBAgUCBAIECQkDDQEAAgMEBREGEiETMQcUIkFRMmEVI0JxUoEWJDORFzZDYnSVobGyJTdUVXKDs9PUCDRTY4LB0USS8CY1ZHPhwv/EABoBAQEAAwEBAAAAAAAAAAAAAAABAgMEBQb/xAA6EQEAAgEDAwIDBQgBAwQDAAAAAQIRAyExBBJBUWETInEFFDJCgVJikaGxwdHwI3Lh8TNjgqKSstL/2gAMAwEAAhEDEQA/APmNERVBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERARF9L5am/E0sXSficPLXpwVmONpsX82IN/nk9xtmtD6ySPqIPnyA+aEX0llMBw9vMKfGsjxqESS1PmBdi3Ezq3sXF/Qt1+j+wJHvtRcfwnxF2pHNPjrON7UxLK+PItdHFNsfQQWOOi09u3sB+PdBgKLV+Y/DvjWErC1ByO26tqNxeyq2wGiRrjG4lrm/S7qdOAI8fuFU4OK0L84hxPJ8bYmc7TI5oZ4XEefPlhH237oKoiuP/Bzn5pOmObQyJ0SPlL0TyQNeepcHfcfbx91wWOEcors7yYDJFmt9o67njWt720Hx+6CuovWxXmrSuisxSQytOiyRpaR9vYryQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQEREBERAREQd+AqfP53HVNb+Ysxxa1vfZwH/AOlfS+ZwlaxTsSulsNrXvmmGUTxPYfXd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 truncated
|
||||
<tr><td class="cap"><span class="fname">7. dwg_18.3mb.dwg</span><br><span class="sub">Model · 82,393 엔티티</span><br><span class="badge b-same">픽셀 동일</span></td><td><img class="shot" loading="lazy" alt="dwg_18.3mb.dwg 0.4.1" src="data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/4gHYSUNDX1BST0ZJTEUAAQEAAAHIAAAAAAQwAABtbnRyUkdCIFhZWiAH4AABAAEAAAAAAABhY3NwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAA9tYAAQAAAADTLQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAlkZXNjAAAA8AAAACRyWFlaAAABFAAAABRnWFlaAAABKAAAABRiWFlaAAABPAAAABR3dHB0AAABUAAAABRyVFJDAAABZAAAAChnVFJDAAABZAAAAChiVFJDAAABZAAAAChjcHJ0AAABjAAAADxtbHVjAAAAAAAAAAEAAAAMZW5VUwAAAAgAAAAcAHMAUgBHAEJYWVogAAAAAAAAb6IAADj1AAADkFhZWiAAAAAAAABimQAAt4UAABjaWFlaIAAAAAAAACSgAAAPhAAAts9YWVogAAAAAAAA9tYAAQAAAADTLXBhcmEAAAAAAAQAAAACZmYAAPKnAAANWQAAE9AAAApbAAAAAAAAAABtbHVjAAAAAAAAAAEAAAAMZW5VUwAAACAAAAAcAEcAbwBvAGcAbABlACAASQBuAGMALgAgADIAMAAxADb/2wBDAAYEBQYFBAYGBQYHBwYIChAKCgkJChQODwwQFxQYGBcUFhYaHSUfGhsjHBYWICwgIyYnKSopGR8tMC0oMCUoKSj/2wBDAQcHBwoIChMKChMoGhYaKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCj/wAARCAMgBQADASIAAhEBAxEB/8QAHAABAAIDAQEBAAAAAAAAAAAAAAUGAwQHAgEI/8QAXRAAAQMDAwIDBAYGBgQLBQIPAQIDBAAFEQYSIRMxIkFRBxQyYRUjQnGBkRZSVpWh0iQzYrHB0UNygpIIFyU0U1RVk6LC8DWUstPh8URjc4MmZHSj4jY3RYR1tcP/xAAbAQEAAwEBAQEAAAAAAAAAAAAAAgMEBQEGB//EAEkRAAEDAgQCBwUFBgYCAgEDBQEAAhEDIQQSMUFRYQUTInGBkaEUMrHR8BVCUsHSI2JykpPhBjOCorLxQ8IkUzQWVGNEVXPi4//aAAwDAQACEQMRAD8A/MdKUr1eJSlKIlKUoiUpSiJSlKIlKUoiUpSiJSlKIlKUoiUpSiJSlKIlKUoiUpSiJSlKIlKUoiUpSiJSlKIlKUoiUpSiJSlKIlKUoiUpSiJSlKIlKUoiUpSiJSlKIlKUoiUpSiJSlKIlKUoiUpSiJSlKIlKUoiUpSiJSlKIlKUoiUpSiJSlKIlKUoiUpSiJSlKIlKUoiUpSiJSlKIlKUoiUpSiJSlKIlKUoiUpSiJSlKIlKUoiUpSiJSlKIlKUoiUpSiJSlKIlKUoiUpSiJSlKIlKUoiUpSiJSlKIlKUoiUpSiJSlKIlKUoiUpSiJSlKIlKUoiUpSiJSlKIlKUoiUpSiJSlKIlKUoiUpSiJSlKIlKUoiUpSiJSlKIlKUoiUpSiJSlKIlKUoiUpSiJSlKIlKUoiUpSiJSlKIlKUoiUpSiJSlKIlKUoiUpSiJSlKIlKUoiUpSiJSlKIlKUoiUpSiJSlKIlKUoiUpSiJSlKIlKUoiUpSiJSlKIlKUoiUpSiJSlKIlKUoiUpSiJSlKIlKUoiUpSiJSlKIlKUoiUpSiJSlKIlKUoiUpSiJSlKIlKUoiUpSiJSlKIlKUoiUpSiJSlKIlKUoiUpSiJSlKIlKUoiUpSiJSlKIlKUoiUpSiJSlKIlKUoiUpSiJSlKIlKUoiUpSiJSlKIlKUoiUpSiJSlKIlKUoiUpSiJSlKIlKUoiUpSiJSlKIlKUoiUpSiJSlKIlKUoiUpSiJSlKIlKUoiUpSiJSlKIlKUoiUpSiJSlKIlKUoiUpSiJSlKIlKUoiUpSiJSlKIlKUoiUpSiJSlKIlKUoiUpSiJSlKIlKUoiUpSiJSlKIlKUoiUpSiJSlKIlKUoiUpSiJSlKIlKUoiUpSiJSlKIlKUoiUpSiJSlKIlKUoiUpSiJSlKIlKUoiUpSiJSlKIlKUoiUpSiJSlKIlKUoiUpSiJSlKIlKUoiUpSiJSlKIlKUoiUpSiJSlKIlKUoiUpSiJSlKIlKUoiUpSiJSlKIlKUoiUpSiJSlKIlKUoiUpSiJSlKIlKUoiUpSiJSlKIlKUoiUpSiJSlKIlKUoiUpSiJSlKIlKUoiUpSiJSlKIlKUoiUpSiJSlKIlKUoiUpSiJSlKIlKUoiUq//AKI6P/b9n92OfzU/RHR/7fs/uxz+ar/Z38vMfNcr7Zw3B/8ATqfpVApV/wD0R0f+37P7sc/mp+iOj/2/Z/djn81PZ38vMfNPtnDcH/06n6VQKVf/ANEdH/t+z+7HP5qfojo/9v2f3Y5/NT2d/LzHzT7Zw3B/9Op+lUClX/8ARHR/7fs/uxz+an6I6P8A2/Z/djn81PZ38vMfNPtnDcH/ANOp+lUClX/9EdH/ALfs/uxz+an6I6P/AG/Z/djn81PZ38vMfNPtnDcH/wBOp+lUClX/APRHR/7fs/uxz+an6I6P/b9n92OfzU9nfy8x80+2cNwf/TqfpVApV/8A0R0f+37P7sc/mp+iOj/2/Z/djn81PZ38vMfNPtnDcH/06n6VQKVf/wBEdH/t+z+7HP5qfojo/wDb9n92OfzU9nfy8x80+2cNwf8A06n6VQKVf/0R0f8At+z+7HP5qfojo/8Ab9n92OfzU9nfy8x80+2cNwf/AE6n6VQKVf8A9EdH/t+z+7HP5qfojo/9v2f3Y5/NT2d/LzHzT7Zw3B/9Op+lUClX/wDRHR/7fs/uxz+an6I6P/b9n92OfzU9nfy8x80+2cNwf/TqfpVApV//AER0f+37P7sc/mp+iOj/ANv2f3Y5/NT2d/LzHzT7Zw3B/wDTqfpVApV//RHR/wC37P7sc/mp+iOj/wBv2f3Y5/NT2d/LzHzT7Zw3B/8ATqfpVApV/wD0R0f+37P7sc/mp+iOj/2/Z/djn81PZ38vMfNPtnDcH/06n6VQKVf/ANEdH/t+z+7HP5qfojo/9v2f3Y5/NT2d/LzHzT7Zw3B/9Op+lUClX/8ARHR/7fs/uxz+an6I6P8A2/Z/djn81PZ38vMfNPtnDcH/ANOp+lUClX/9EdH/ALfs/uxz+an6I6P/AG/Z/djn81PZ38vMfNPtnDcH/wBOp+lUClX/APRHR/7fs/uxz+an6I6P/b9n92OfzU9nfy8x80+2cNwf/TqfpVApV/8A0R0f+37P7sc/mp+iOj/2/Z/djn81PZ38vMfNPtnDcH/06n6VQKVf/wBEdH/t+z+7HP5qfojo/wDb9n92OfzU9nfy8x80+2cNwf8A06n6VQKVf/0R0f8At+z+7HP5qfojo/8Ab9n92OfzU9nfy8x80+2cNwf/AE6n6VQKVf8A9EdH/t+z+7HP5qfojo/9v2f3Y5/NT2d/LzHzT7Zw3B/9Op+lUClX/wDRHR/7fs/uxz+an6I6P/b9n92OfzU9nfy8x80+2cNwf/TqfpVApV//AER0f+37P7sc/mp+iOj/ANv2f3Y5/NT2d/LzHzT7Zw3B/wDTqfpVApV//RHR/wC37P7sc/mp+iOj/wBv2f3Y5/NT2d/LzHzT7Zw3B/8ATqfpVApV/wD0R0f+37P7sc/mp+iOj/2/Z/djn81PZ38vMfNPtnDcH/06n6VQKVf/ANEdH/t+z+7HP5qfojo/9v2f3Y5/NT2d/LzHzT7Zw3B/9Op+lUClX/8ARHR/7fs/uxz+an6I6P8A2/Z/djn81PZ38vMfNPtnDcH/ANOp+lUClX/9EdH/ALfs/uxz+an6I6P/AG/Z/djn81PZ38vMfNPtnDcH/wBOp+lUClX/APRHR/7fs/uxz+an6I6P/b9n92OfzU9nfy8x80+2cNwf/TqfpVApV/8A0R0f+37P7sc/mp+iOj/2/Z/djn81PZ38vMfNPtnDcH/06n6VQKVf/wBEdH/t+z+7HP5qfojo/wDb9n92OfzU9nfy8x80+2cNwf8A06n6VQKVf/0R0f8At+z+7HP5qfojo/8Ab9n92OfzU9nfy8x80+2cNwf/AE6n6VQKVf8A9EdH/t+z+7HP5qfojo/9v2f3Y5/NT2d/LzHzT7Zw3B/9Op+lUClX/wDRHR/7fs/uxz+an6I6P/b9n92OfzU9nfy8x80+2cNwf/TqfpVApV//AER0f+37P7sc/mp+iOj/ANv2f3Y5/NT2d/LzHzT7Zw3B/wDTqfpVApV//RHR/wC37P7sc/mp+iOj/wBv2f3Y5/NT2d/LzHzT7Zw3B/8ATqfpVApV/wD0R0f+37P7sc/mp+iOj/2/Z/djn81PZ38vMfNPtnDcH/06n6VQKVf/ANEdH/t+z+7HP5qfojo/9v2f3Y5/NT2d/LzHzT7Zw3B/9Op+lUClX/8ARHR/7fs/uxz+an6I6P8A2/Z/djn81PZ38vMfNPtnDcH/ANOp+lUClX/9EdH/ALfs/uxz+an6I6P/AG/Z/djn81PZ38vMfNPtnDcH/wBOp+lUClX/APRHR/7fs/uxz+an6I6P/b9n92OfzU9nfy8x80+2cNwf/TqfpVApV/8A0R0f+37P7sc/mp+iOj/2/Z/djn81PZ38vMfNPtnDcH/06n6VQKVf/wBEdH/t+z+7HP5qfojo/Line truncated
|
||||
<tr><td class="cap"><span class="fname">8. simple.dxf</span><br><span class="sub">— · 6 엔티티</span><br><span class="badge b-same">픽셀 동일</span></td><td><img class="shot" loading="lazy" alt="simple.dxf 0.4.1" src="data:image/jpeg;base64,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 truncated
|
||||
<tr><td class="cap"><span class="fname">9. 04manhole1-simplify.dwg</span><br><span class="sub">Layout · 7,035 엔티티</span><br><span class="badge b-same">픽셀 동일</span></td><td><img class="shot" loading="lazy" alt="04manhole1-simplify.dwg 0.4.1" src="data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/4gHYSUNDX1BST0ZJTEUAAQEAAAHIAAAAAAQwAABtbnRyUkdCIFhZWiAH4AABAAEAAAAAAABhY3NwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAA9tYAAQAAAADTLQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAlkZXNjAAAA8AAAACRyWFlaAAABFAAAABRnWFlaAAABKAAAABRiWFlaAAABPAAAABR3dHB0AAABUAAAABRyVFJDAAABZAAAAChnVFJDAAABZAAAAChiVFJDAAABZAAAAChjcHJ0AAABjAAAADxtbHVjAAAAAAAAAAEAAAAMZW5VUwAAAAgAAAAcAHMAUgBHAEJYWVogAAAAAAAAb6IAADj1AAADkFhZWiAAAAAAAABimQAAt4UAABjaWFlaIAAAAAAAACSgAAAPhAAAts9YWVogAAAAAAAA9tYAAQAAAADTLXBhcmEAAAAAAAQAAAACZmYAAPKnAAANWQAAE9AAAApbAAAAAAAAAABtbHVjAAAAAAAAAAEAAAAMZW5VUwAAACAAAAAcAEcAbwBvAGcAbABlACAASQBuAGMALgAgADIAMAAxADb/2wBDAAYEBQYFBAYGBQYHBwYIChAKCgkJChQODwwQFxQYGBcUFhYaHSUfGhsjHBYWICwgIyYnKSopGR8tMC0oMCUoKSj/2wBDAQcHBwoIChMKChMoGhYaKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCj/wAARCAMgBQADASIAAhEBAxEB/8QAHAABAAIDAQEBAAAAAAAAAAAAAAYHAwQFAgEI/8QAZRABAAIBAwMBBAQFCg4OCAMJAAECAwQFEQYSITETIkFRBxRhcRUWMoGRIyQzQlWUobHR0xc0NlJTVFZidJOVssHSCCU3Q2Vyc3WCpbO04vA1Y2SEkqTD1IPE8SYnREWiwuHj5P/EABoBAQADAQEBAAAAAAAAAAAAAAADBAUCAQb/xABEEQEAAQMBBQQHBAgDCAMBAAAAAQIDEQQSITFBUQUTYZEUFVJxobHRIlOBwTJCYpKi0uHwBiNyFjM0Q1STssJEguLx/9oADAMBAAIRAxEAPwD9UgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAADFq89dLpM2ovW9q4qWvMUrNrTERz4iPMz9kORpOoqajW7Zprbfr9Pk12G2WIz0rScPEc9t47uYmfPERE+k/KQdwcnbd/wBFuO233DS2mdFXHOT295itJiLXrbzz6R2TPPpxMTHLQjrLb5x7ZeMWqtj3DPbDhyY8U5KeMk462m9ea8Wnjjz6WiQSURHZ+vNt3jHGTbcOs1WOdXXS1vgw2y1t3RSe/upE1rWK3i0xaa2iInmOfDs33zBjz3wWw5/bRmjBFIp5tMxaYmI+McVtP5pn0B1Rx8PUWiy5NbjpGfv0eqx6TLFsNqcXveK14m0RFo96s8xM+Jh0NFqo1eO1ox3xzXtia3mvMc1rb4TP9dx+b5cTIbAAAAAAAIR1dr9Vg+kTpDR4ddm0ul1Gn11stKXitclq+w7e6JiYn8q0R4/bTx5TWLM3qppieUz5RM/k8mcJuNeueYmLine truncated
|
||||
<tr><td class="cap"><span class="fname">10. 대산당진 2공구_노면_20260804_143854.dwg</span><br><span class="sub">Model · 65,495 엔티티</span><br><span class="badge b-same">픽셀 동일</span></td><td><img class="shot" loading="lazy" alt="대산당진 2공구_노면_20260804_143854.dwg 0.4.1" src="data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/4gHYSUNDX1BST0ZJTEUAAQEAAAHIAAAAAAQwAABtbnRyUkdCIFhZWiAH4AABAAEAAAAAAABhY3NwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAA9tYAAQAAAADTLQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAlkZXNjAAAA8AAAACRyWFlaAAABFAAAABRnWFlaAAABKAAAABRiWFlaAAABPAAAABR3dHB0AAABUAAAABRyVFJDAAABZAAAAChnVFJDAAABZAAAAChiVFJDAAABZAAAAChjcHJ0AAABjAAAADxtbHVjAAAAAAAAAAEAAAAMZW5VUwAAAAgAAAAcAHMAUgBHAEJYWVogAAAAAAAAb6IAADj1AAADkFhZWiAAAAAAAABimQAAt4UAABjaWFlaIAAAAAAAACSgAAAPhAAAts9YWVogAAAAAAAA9tYAAQAAAADTLXBhcmEAAAAAAAQAAAACZmYAAPKnAAANWQAAE9AAAApbAAAAAAAAAABtbHVjAAAAAAAAAAEAAAAMZW5VUwAAACAAAAAcAEcAbwBvAGcAbABlACAASQBuAGMALgAgADIAMAAxADb/2wBDAAYEBQYFBAYGBQYHBwYIChAKCgkJChQODwwQFxQYGBcUFhYaHSUfGhsjHBYWICwgIyYnKSopGR8tMC0oMCUoKSj/2wBDAQcHBwoIChMKChMoGhYaKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCj/wAARCAMgBQADASIAAhEBAxEB/8QAHQABAAICAwEBAAAAAAAAAAAAAAcIBQYCAwQJAf/EAEQQAQABAwMDAgQFAgQEAggHAAABAgMRBAUhBhIxB0ETIlFhCBQycYFCkRUjUqEkM3LBYrEWFyVDREVT0WOCkpSi4fH/xAAaAQEAAwEBAQAAAAAAAAAAAAAAAQIDBAUG/8QAPBEBAAEDAgQDBwIEBAUFAAAAAAECAxEhMQQSQVFhcYEFEyKRobHwMtEUQsHhFSMzciRSgtLjYnOisvH/2gAMAwEAAhEDEQA/AKxgJQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA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 truncated
|
||||
<tr><td class="cap"><span class="fname">11. test.dwg</span><br><span class="sub">Model · 82,393 엔티티</span><br><span class="badge b-same">픽셀 동일</span></td><td><img class="shot" loading="lazy" alt="test.dwg 0.4.1" src="data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/4gHYSUNDX1BST0ZJTEUAAQEAAAHIAAAAAAQwAABtbnRyUkdCIFhZWiAH4AABAAEAAAAAAABhY3NwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAA9tYAAQAAAADTLQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAlkZXNjAAAA8AAAACRyWFlaAAABFAAAABRnWFlaAAABKAAAABRiWFlaAAABPAAAABR3dHB0AAABUAAAABRyVFJDAAABZAAAAChnVFJDAAABZAAAAChiVFJDAAABZAAAAChjcHJ0AAABjAAAADxtbHVjAAAAAAAAAAEAAAAMZW5VUwAAAAgAAAAcAHMAUgBHAEJYWVogAAAAAAAAb6IAADj1AAADkFhZWiAAAAAAAABimQAAt4UAABjaWFlaIAAAAAAAACSgAAAPhAAAts9YWVogAAAAAAAA9tYAAQAAAADTLXBhcmEAAAAAAAQAAAACZmYAAPKnAAANWQAAE9AAAApbAAAAAAAAAABtbHVjAAAAAAAAAAEAAAAMZW5VUwAAACAAAAAcAEcAbwBvAGcAbABlACAASQBuAGMALgAgADIAMAAxADb/2wBDAAYEBQYFBAYGBQYHBwYIChAKCgkJChQODwwQFxQYGBcUFhYaHSUfGhsjHBYWICwgIyYnKSopGR8tMC0oMCUoKSj/2wBDAQcHBwoIChMKChMoGhYaKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCj/wAARCAMgBQADASIAAhEBAxEB/8QAHAABAAIDAQEBAAAAAAAAAAAAAAUGAwQHAgEI/8QAXRAAAQMDAwIEAwUDBwUNBQIPAQIDBAAFEQYSIRMxByJBURQyYRUjQnGBUpGhFiQzYrHB0UNygpLwCBclNFNUVVaTosLS4TWUlbLT8URjc4MmZHSj4jY3RYR1tcP/xAAbAQEAAwEBAQEAAAAAAAAAAAAAAgMEBQEGB//EAEgRAAEDAgQCBwYDBgYCAgEDBQEAAhEDIQQSMUFRYQUTInGBkaEUMrHB0fBCUuEjYnKS0vEGFTOCorJDwiRTNBZUY0RVc+Lj/9oADAMBAAIRAxEAPwD8x0pSvV4lKUoiUpSiJSlKIlKUoiUpSiJSlKIlKUoiUpSiJSlKIlKUoiUpSiJSlKIlKUoiUpSiJSlKIlKUoiUpSiJSlKIlKUoiUpSiJSlKIlKUoiUpSiJSlKIlKUoiUpSiJSlKIlKUoiUpSiJSlKIlKUoiUpSiJSlKIlKUoiUpSiJSlKIlKUoiUpSiJSlKIlKUoiUpSiJSlKIlKUoiUpSiJSlKIlKUoiUpSiJSlKIlKUoiUpSiJSlKIlKUoiUpSiJSlKIlKUoiUpSiJSlKIlKUoiUpSiJSlKIlKUoiUpSiJSlKIlKUoiUpSiJSlKIlKUoiUpSiJSlKIlKUoiUpSiJSlKIlKUoiUpSiJSlKIlKUoiUpSiJSlKIlKUoiUpSiJSlKIlKUoiUpSiJSlKIlKUoiUpSiJSlKIlKUoiUpSiJSlKIlKUoiUpSiJSlKIlKUoiUpSiJSlKIlKUoiUpSiJSlKIlKUoiUpSiJSlKIlKUoiUpSiJSlKIlKUoiUpSiJSlKIlKUoiUpSiJSlKIlKUoiUpSiJSlKIlKUoiUpSiJSlKIlKUoiUpSiJSlKIlKUoiUpSiJSlKIlKUoiUpSiJSlKIlKUoiUpSiJSlKIlKUoiUpSiJSlKIlKUoiUpSiJSlKIlKUoiUpSiJSlKIlKUoiUpSiJSlKIlKUoiUpSiJSlKIlKUoiUpSiJSlKIlKUoiUpSiJSlKIlKUoiUpSiJSlKIlKUoiUpSiJSlKIlKUoiUpSiJSlKIlKUoiUpSiJSlKIlKUoiUpSiJSlKIlKUoiUpSiJSlKIlKUoiUpSiJSlKIlKUoiUpSiJSlKIlKUoiUpSiJSlKIlKUoiUpSiJSlKIlKUoiUpSiJSlKIlKUoiUpSiJSlKIlKUoiUpSiJSlKIlKUoiUpSiJSlKIlKUoiUpSiJSlKIlKUoiUpSiJSlKIlKUoiUpSiJSlKIlKUoiUpSiJSlKIlKUoiUpSiJSlKIlKUoiUpSiJSlKIlKUoiUpSiJSlKIlKUoiUpSiJSlKIlKUoiUpSiJSlKIlKUoiUpSiJSlKIlKUoiUpSiJSlKIlKUoiUpSiJSlKIlKUoiUpSiJSlKIlKUoiUpSiJSlKIlKUoiUpSiJSlKIlKUoiUpSiJSlKIlKUoiUpSiJSlKIlKUoiUpSiJSlKIlKUoiUpSiJSlKIlKUoiUpSiJSlKIlKUoiUpSiJSlKIlKUoiUpSiJS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 truncated
|
||||
<tr><td class="cap"><span class="fname">12. a. 거더배치 삽도_25.02.28.dwg</span><br><span class="sub">Layout · 1,433 엔티티</span><br><span class="badge b-same">픽셀 동일</span></td><td><img class="shot" loading="lazy" alt="a. 거더배치 삽도_25.02.28.dwg 0.4.1" src="data:image/jpeg;base64,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 truncated
|
||||
<tr><td class="cap"><span class="fname">13. a. 교대배치 삽도_25.02.28.dwg</span><br><span class="sub">Layout · 2,138 엔티티</span><br><span class="badge b-same">픽셀 동일</span></td><td><img class="shot" loading="lazy" alt="a. 교대배치 삽도_25.02.28.dwg 0.4.1" src="data:image/jpeg;base64,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 truncated
|
||||
<tr><td class="cap"><span class="fname">14. a. 교량시종점 삽도_25.02.28.dwg</span><br><span class="sub">Layout · 4,432 엔티티</span><br><span class="badge b-better">개선 · 3.45 %</span><br><span class="sub">§5 참고</span></td><td><img class="shot" loading="lazy" alt="a. 교량시종점 삽도_25.02.28.dwg 0.4.1" src="data:image/jpeg;base64,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 truncated
|
||||
<tr><td class="cap"><span class="fname">15. a. 교량폭원 삽도_25.02.28.dwg</span><br><span class="sub">Layout · 2,824 엔티티</span><br><span class="badge b-same">픽셀 동일</span></td><td><img class="shot" loading="lazy" alt="a. 교량폭원 삽도_25.02.28.dwg 0.4.1" src="data:image/jpeg;base64,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 truncated
|
||||
<tr><td class="cap"><span class="fname">16. a. 교면포장 삽도_25.02.28.dwg</span><br><span class="sub">Layout · 1,304 엔티티</span><br><span class="badge b-same">픽셀 동일</span></td><td><img class="shot" loading="lazy" alt="a. 교면포장 삽도_25.02.28.dwg 0.4.1" src="data:image/jpeg;base64,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 truncated
|
||||
<tr><td class="cap"><span class="fname">17. a. 중앙분리대 삽도_25.02.28.dwg</span><br><span class="sub">Layout · 2,159 엔티티</span><br><span class="badge b-better">개선 · 18.37 %</span><br><span class="sub">§5 참고</span></td><td><img class="shot" loading="lazy" alt="a. 중앙분리대 삽도_25.02.28.dwg 0.4.1" src="data:image/jpeg;base64,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 truncated
|
||||
<tr><td class="cap"><span class="fname">18. a. 횡단경사 삽도_25.02.28.dwg</span><br><span class="sub">Layout · 5,635 엔티티</span><br><span class="badge b-same">픽셀 동일</span></td><td><img class="shot" loading="lazy" alt="a. 횡단경사 삽도_25.02.28.dwg 0.4.1" src="data:image/jpeg;base64,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 truncated
|
||||
<tr><td class="cap"><span class="fname">19. 산외교- ELEVATION 산출근거도 (울산방향).dwg</span><br><span class="sub">Model · 11,262 엔티티</span><br><span class="badge b-better">개선 · 0.0047 %</span><br><span class="sub">§5 참고</span></td><td><img class="shot" loading="lazy" alt="산외교- ELEVATION 산출근거도 (울산방향).dwg 0.4.1" src="data:image/jpeg;base64,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 truncated
|
||||
<tr><td class="cap"><span class="fname">20. 산외교-받침배치도 (울산방향) .dwg</span><br><span class="sub">Model · 6,240 엔티티</span><br><span class="badge b-same">픽셀 동일</span></td><td><img class="shot" loading="lazy" alt="산외교-받침배치도 (울산방향) .dwg 0.4.1" src="data:image/jpeg;base64,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 truncated
|
||||
<tr><td class="cap"><span class="fname">21. 산외교_파이형_교각일반도(울산P11-꺾임).dwg</span><br><span class="sub">Model · 25,927 엔티티</span><br><span class="badge b-same">픽셀 동일</span></td><td><img class="shot" loading="lazy" alt="산외교_파이형_교각일반도(울산P11-꺾임).dwg 0.4.1" src="data:image/jpeg;base64,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 truncated
|
||||
<tr><td class="cap"><span class="fname">22. 산외교_파이형_교각일반도(울산P9).dwg</span><br><span class="sub">Model · 26,207 엔티티</span><br><span class="badge b-same">픽셀 동일</span></td><td><img class="shot" loading="lazy" alt="산외교_파이형_교각일반도(울산P9).dwg 0.4.1" src="data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/4gHYSUNDX1BST0ZJTEUAAQEAAAHIAAAAAAQwAABtbnRyUkdCIFhZWiAH4AABAAEAAAAAAABhY3NwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQAA9tYAAQAAAADTLQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAlkZXNjAAAA8AAAACRyWFlaAAABFAAAABRnWFlaAAABKAAAABRiWFlaAAABPAAAABR3dHB0AAABUAAAABRyVFJDAAABZAAAAChnVFJDAAABZAAAAChiVFJDAAABZAAAAChjcHJ0AAABjAAAADxtbHVjAAAAAAAAAAEAAAAMZW5VUwAAAAgAAAAcAHMAUgBHAEJYWVogAAAAAAAAb6IAADj1AAADkFhZWiAAAAAAAABimQAAt4UAABjaWFlaIAAAAAAAACSgAAAPhAAAts9YWVogAAAAAAAA9tYAAQAAAADTLXBhcmEAAAAAAAQAAAACZmYAAPKnAAANWQAAE9AAAApbAAAAAAAAAABtbHVjAAAAAAAAAAEAAAAMZW5VUwAAACAAAAAcAEcAbwBvAGcAbABlACAASQBuAGMALgAgADIAMAAxADb/2wBDAAYEBQYFBAYGBQYHBwYIChAKCgkJChQODwwQFxQYGBcUFhYaHSUfGhsjHBYWICwgIyYnKSopGR8tMC0oMCUoKSj/2wBDAQcHBwoIChMKChMoGhYaKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCgoKCj/wAARCAMgBQADASIAAhEBAxEB/8QAHAABAAIDAQEBAAAAAAAAAAAAAAQFAwYHAgEI/8QAahAAAQMCAwIEDBEIBQkGBAQHAQACAwQRBRIhBjETFEFRBxUWIlRVYXGTlNHSFyMyNTY3U3N0dYGRkrGys9MzQlJWcoKVoSQ0oqPBJSZDRGJm4eLwOGR2g7TCCGO18UZHV8PEGGWEhaTj/8QAGwEBAAMBAQEBAAAAAAAAAAAAAAIDBAEFBgf/xABPEQABAwEDBwcKBAMHBAIBBAMBAAIDEQQSIRMxQVFhcZEFFDJSobHRIjRTcoGSwdLh8DNCYrIVFiMGQ1SCosLxJHOT4mOjNSVEZMOEs/L/2gAMAwEAAhEDEQA/APzGiIuriIiIiIiIiIiIiK82F9m+z3xjT/etVGrzYX2b7PfGNP8AetU4+mN6zW3zeT1T3K16L/tkY374z7tq05bj0X/bIxv3xn3bVpylP+K7eVRyT5hB6jf2hFmpaqeke99NNJE58bonFjrZmOBa5p7hBIWFFUvQUiOsqYzGWTyelsMbAXXAYSSW25iXE23annX1tfVNrYaxlRI2phc10UjTYxlvqctt1rC1tyjIiIptHildRshbS1MkQglM8WU/k5Dlu9vM7rW6j9EcyhIiL61zmOu0lp5wbL1FI+GVkkTi17CHNI5CF4REWWeokny8K64boAAAB8gSaommjgjlkc9kDDHE1xuGNzF1hzDM5x75KxIiIiIiIiIiIiIiIiIiIp2DxGaryij42Mpuyzzl7vWkHufKoKyUzmNnjMweYswzhhsS2+tlZEQ14J++9WQuDZAXZvvYe5bI/CmmKOaXDhSt4pNI4Fz23kDZLCz3Em2QGw59dFEw6mpy7CY5KJkwq3ASSOc8EXkLdLEDcF9fU07Gzl1RROiMb2xsp4XMkBLSB12UG2uuZxuL71AoRC+knZJVNp5s7DG5+e2Wzsw60Hly8nIvSc+IPF0D/TopspjQ03r2HvhEjbjW6c92mFNlMaEDepOK0EFJR0ZhcXuklkDnktJsAyw61zhynu6qTW0MkFbURQ4C+SOORzGvyzHMAbA6GyrpTDFFTwyTx1dOx73ltOXMcC4NG97P9kch5V643QcFwfFa3Lmzf1tv4arvwhzswzbcwx0EYlU34A52AGamnMMcbrhiVWnebiyLJOYnSuMDHsj5GveHEfKAPqWNecRQryiKGgRERcXERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERF9aMzgL2ubLreE0cg6KO0dFh8oa2iM2FRU8UVSakUzCYs0T4IZMjw1ozPI1zuuHBzr8jW30m1VCzaaTGsQwptfLVU9qlknBn+kG2aZvCskYS62Y5mEAyOAAs0oi3/AGv2S6ndla+hZNUUVDViCaaXEzXVMTTYPZktRRsZL12UkkuF3M627gtNp48Hi2Mfs7JiMLMYrpo8TdUCTNTRuYxzYqZ7gDZ5bLI4vBLWuLGut15Z42g21oMQwOsoMPwmagfUhjXvZxJj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 truncated
|
||||
</tbody></table></div>
|
||||
|
||||
<h2>7. 파싱 데이터 비교</h2>
|
||||
<p>Node 에서 두 wasm 으로 같은 DWG 21개를 파싱해 엔티티를 <code>타입#handle</code> 로 짝지은 뒤 필드별로 비교했다. 파일별 엔티티 수와 handle 집합은 완전히 같고, 값이 바뀐 필드는 아래가 전부다.</p>
|
||||
<div class="tbl"><table>
|
||||
<thead><tr><th>바뀐 값</th><th class="num">필드 변경 건수</th><th class="num">파일 수</th><th>원인</th><th>화면 영향</th></tr></thead>
|
||||
<tbody>
|
||||
<tr><td>치수 정의점 <code>pt10</code></td><td class="num">1,175</td><td class="num">12</td><td>0.4.1 이 (0,0,0) 으로 냄 → 실제 좌표</td><td>블록 없는 치수(대체 렌더)의 선택 범위·extents 만</td></tr>
|
||||
<tr><td>ATTDEF 정렬점·정렬·폭 비율</td><td class="num">2,171</td><td class="num">14</td><td>0.4.1 이 읽지 못함 → 실제 값</td><td>블록 안 속성 텍스트 위치·폭이 정확해짐</td></tr>
|
||||
<tr><td>익명 블록 이름</td><td class="num">812</td><td class="num">1</td><td>번호 체계 변경 (<code>*U1</code> → <code>*U7</code>)</td><td>없음 — 렌더는 handle 기준, 이름·블록 테이블 불일치 0건</td></tr>
|
||||
<tr><td>트루컬러 엔티티의 근사 ACI</td><td class="num">116</td><td class="num">3</td><td>근사 계산 개선 (원본 RGB 는 동일)</td><td>원본 색에 더 가까워짐</td></tr>
|
||||
<tr><td>VIEWPORT id 0 → 1</td><td class="num">27</td><td class="num">10</td><td>0.6.5 가 레이아웃 전체 뷰포트에 id 1 부여</td><td>전체 뷰포트 오판 해소 (중앙분리대 검은 띠)</td></tr>
|
||||
<tr><td>VIEWPORT 상태 비트</td><td class="num">26</td><td class="num">2</td><td>비트 0x10000 추가</td><td>없음 (Viewer2D 는 isOn 만 사용)</td></tr>
|
||||
<tr><td>3D 폴리선 점 순서</td><td class="num">7</td><td class="num">1</td><td>0.4.1 이 vertex 를 handle 순으로 정렬</td><td>가짜 직선 제거 (dwg_1.60mb)</td></tr>
|
||||
<tr><td>텍스트 내용</td><td class="num">1</td><td class="num">1</td><td>CP949 기호 디코딩 (<code>500¡¿350</code> → <code>500×350</code>)</td><td>깨진 기호 1건 해소</td></tr>
|
||||
<tr><td>OLE 데이터 길이</td><td class="num">1</td><td class="num">1</td><td>페이로드 재조립으로 512 B 차이</td><td>없음 (추출 이미지 바이트 동일)</td></tr>
|
||||
</tbody></table></div>
|
||||
<p><strong>한글</strong>: 0.4.1 은 평면및종단면도(153개)와 굴착및시공순서도(160개)의 한글을 Latin-1 로 깨진 채 내보냈고, 뷰어의 JS 보정(<code>fixDwgKoreanText</code>)이 복원해 왔다. 0.6.5 는 DWG 21개 전부 처음부터 정상 디코딩한다(깨짐 0). 보정 후 한글 텍스트 수는 두 버전이 모든 파일에서 같다.</p>
|
||||
|
||||
<h2>8. 업그레이드에서 바꾼 것</h2>
|
||||
<p>acadrust 는 crates.io 의 0.6.5 를 <strong>고치지 않고</strong> 쓴다 (<code>acadrust = "=0.6.5"</code>). 0.6.5 에 맞추느라 바꾼 곳은 전부 우리 래퍼 <code>dwg-wasm</code>(MIT) 안이다.</p>
|
||||
<div class="tbl"><table>
|
||||
<thead><tr><th>변경</th><th>이유</th></tr></thead>
|
||||
<tbody>
|
||||
<tr><td>vendored <code>rust/acadrust/</code>(189개 파일) 삭제, crates.io 버전 고정</td><td>무수정 사용. 고지에 적은 버전과 빌드 소스를 일치시킨다</td></tr>
|
||||
<tr><td>손상 레코드 허용 모드(<code>failsafe</code>)로 읽기</td><td>0.6.5 기본 모드는 레코드 하나만 깨져도 도면 전체를 거부한다. <code>a. 거더배치 삽도</code> 가 통째로 열리지 않았다. 허용 모드에서는 정상으로 열리고, 건너뛴 레코드는 알림으로 남는다</td></tr>
|
||||
<tr><td>wasm 메모리를 32 MB 단위로 확장하는 할당자</td><td>그대로 올리면 37 MB 노면 도면 파싱이 3.0 초 → 7.4 초로 느려졌다. 원인은 브라우저 엔진(V8)에서 메모리를 늘리는 비용이 현재 메모리 크기에 비례하는데, 0.6.5 가 64 KB 단위로 수천 번 늘렸기 때문이다 (프로파일로 확인). 수정 후 3.3 초</td></tr>
|
||||
<tr><td>API 변경 대응 (치수 Box 타입, OLE 페이로드)</td><td>컴파일 에러 9개. OLE 이미지 추출 결과는 기존과 바이트 단위로 같다</td></tr>
|
||||
</tbody></table></div>
|
||||
|
||||
<h2>9. 성능·크기</h2>
|
||||
<div class="tbl"><table>
|
||||
<thead><tr><th>항목</th><th class="num">0.4.1 + 패치</th><th class="num">0.6.5</th></tr></thead>
|
||||
<tbody>
|
||||
<tr><td>wasm 크기 (원본 / brotli 압축)</td><td class="num">864 KB / 294 KB</td><td class="num">2,976 KB / 815 KB</td></tr>
|
||||
<tr><td>브라우저 로드 — 대산당진 노면 (37 MB)</td><td class="num" colspan="2">5,651 → 5,737 ms</td></tr>
|
||||
<tr><td>브라우저 로드 — dwg_18.3mb (18 MB)</td><td class="num" colspan="2">3,920 → 4,024 ms</td></tr>
|
||||
<tr><td>Node 파싱만 — 노면 / dwg_18.3mb</td><td class="num">3.0 s / 1.9 s</td><td class="num">3.3 s / 2.1 s</td></tr>
|
||||
<tr><td>wasm 메모리 — 노면 / dwg_18.3mb</td><td class="num">672 / 546 MB</td><td class="num">773 / 505 MB</td></tr>
|
||||
</tbody></table></div>
|
||||
<p>크기가 커진 것은 acadrust 0.6 이 DXF/DWG 쓰기, ACIS 등을 포함해 라이브러리 자체가 커졌기 때문이다. 끌 수 있는 기능 옵션은 없다. 크기 우선 최적화(<code>opt-level = "z"</code>)도 시험했으나 815 → 742 KB(−9 %)를 얻는 대신 파싱이 36 % 느려져 채택하지 않았다.</p>
|
||||
|
||||
<h2>10. 라이선스 영향</h2>
|
||||
<ul>
|
||||
<li>0.4.1 은 acadrust 를 2개 파일 3곳 고쳐 쓰고 있었고, 공개한 패치는 원본에 적용되지 않아 배포 wasm 의 소스를 재현할 수 없었다 (MPL-2.0 §3.2 미충족).</li>
|
||||
<li>0.6.5 는 무수정이므로 MPL-2.0 의무가 <strong>라이선스 원문 동봉 + 소스 입수 위치 고지</strong>로 줄어든다. 고지에는 crates.io 다운로드 주소, upstream 커밋, crate SHA-256(빌드에 쓴 <code>Cargo.lock</code> checksum 과 일치)을 적었다.</li>
|
||||
<li>공개 배포본(pages.dev)은 재빌드·재배포 전까지 옛 고지(0.4.1 패치)를 보여 준다.</li>
|
||||
</ul>
|
||||
|
||||
<h2>11. 남은 것</h2>
|
||||
<ul>
|
||||
<li>pages.dev 재배포 (현재 공개본은 0.4.1 wasm + 옛 고지)</li>
|
||||
<li>뷰어가 0.6.5 에서 새로 읽히는 호 길이 치수·대형 반경 치수(<code>DIMENSION_ARC</code>, <code>DIMENSION_LARGE_RADIAL</code>)를 아직 그리지 않는다. 샘플 22개에는 해당 엔티티가 없다.</li>
|
||||
<li>XDATA 는 acadrust 가 읽지만 뷰어 출력에는 넣지 않는다 (업그레이드 전과 같음).</li>
|
||||
<li>wasm 에 들어가는 Rust 의존 라이브러리(MIT/Apache/BSD 등)의 고지 생성.</li>
|
||||
</ul>
|
||||
<h3>검증하지 못한 것</h3>
|
||||
<div class="tbl"><table><thead><tr><th>항목</th><th>이유</th></tr></thead><tbody>
|
||||
<tr><td>AutoCAD 원본 화면과의 대조</td><td>같은 위치의 AutoCAD 정답 캡처가 없다. 개선 판정은 데이터 근거(원본 RGB, vertex 좌표의 연속성, 뷰포트 id·배율)에 기댄다</td></tr>
|
||||
<tr><td>Firefox / Safari 에서의 로드 시간</td><td>Chrome 과 Node 에서만 측정</td></tr>
|
||||
<tr><td>Layout/Model 탭을 바꾼 뒤의 화면, 2.5D 보기</td><td>기본 화면과 지정 확대 화면만 캡처</td></tr>
|
||||
</tbody></table></div>
|
||||
</main>
|
||||
<div id="lb" role="dialog" aria-label="확대 이미지"><img alt=""></div>
|
||||
<script>
|
||||
(function () {
|
||||
var root = document.documentElement, KEY = 'report-theme';
|
||||
try { var t = localStorage.getItem(KEY); if (t) root.setAttribute('data-theme', t); } catch (e) {}
|
||||
document.getElementById('theme').addEventListener('click', function () {
|
||||
var cur = root.getAttribute('data-theme') ||
|
||||
(matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light');
|
||||
var next = cur === 'dark' ? 'light' : 'dark';
|
||||
root.setAttribute('data-theme', next);
|
||||
try { localStorage.setItem(KEY, next); } catch (e) {}
|
||||
});
|
||||
var lb = document.getElementById('lb'), lbImg = lb.querySelector('img');
|
||||
document.addEventListener('click', function (e) {
|
||||
var img = e.target.closest && e.target.closest('img.shot');
|
||||
if (img) { lbImg.src = img.src; lbImg.alt = img.alt; lb.classList.add('open'); }
|
||||
else if (e.target === lb || e.target === lbImg) lb.classList.remove('open');
|
||||
});
|
||||
document.addEventListener('keydown', function (e) { if (e.key === 'Escape') lb.classList.remove('open'); });
|
||||
})();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,115 @@
|
||||
# acadrust 0.4.1(패치) → 0.6.5(무수정) 업그레이드
|
||||
|
||||
| 항목 | 내용 |
|
||||
|------|------|
|
||||
| 날짜 | 2026-10-19 |
|
||||
| 목적 | 로컬 패치를 없애 MPL-2.0 의무를 "고지 + 소스 링크"로 줄인다 ([`license-mpl2-acadrust.md`](./license-mpl2-acadrust.md)) |
|
||||
| Rust 쪽 변경 | `hmwebviewer` 브랜치 `chore/acadrust-0.6.5` (`feat/subdmesh-render` 에서 분기) |
|
||||
| 이 레포 변경 | `src/viewer2d/acadrust-dwg/` wasm 교체, 고지·문서 갱신 |
|
||||
| 상태 | 수정 완료·검증됨 (샘플 20개 파싱 비교 + 브라우저 로드·스크린샷) |
|
||||
| 캡처 보고서 | [`acadrust-0.6.5-upgrade-report.html`](./acadrust-0.6.5-upgrade-report.html) — 샘플 22개 기존/신규 화면 비교 (이미지 내장) |
|
||||
|
||||
---
|
||||
|
||||
## 1. 결론
|
||||
|
||||
- acadrust 를 고치지 않고도 기존 두 수정(MESH, OLE2FRAME)의 결과가 그대로 나온다.
|
||||
- 화면 회귀는 없다. 패널을 숨기고 도면만 찍은 최종 캡처 기준으로, 샘플 22개 중 17개는 기본 화면이 픽셀 단위로 같다. 나머지 5개의 차이는 모두 데이터가 더 정확해진 결과다 (§4, [캡처 보고서](./acadrust-0.6.5-upgrade-report.html)). §4 의 스크린샷 표는 툴바가 함께 찍힌 첫 캡처 기준이라 탭 이름 차이가 섞여 있다.
|
||||
- 대가: wasm 이 커졌고 (brotli 294 → 815 KB), 대형 도면 파싱이 10~16% 느려졌다 (§5).
|
||||
|
||||
## 2. dwg-wasm 변경 (우리 MIT 코드)
|
||||
|
||||
| 변경 | 이유 |
|
||||
|---|---|
|
||||
| `acadrust = "=0.6.5"` (crates.io, 정확한 버전 고정), vendored `rust/acadrust/` 삭제 | 무수정 사용. 고지에 적은 버전과 빌드 소스를 일치시킨다 |
|
||||
| `match d.as_ref()` | 0.6 에서 `EntityType::Dimension` 이 `Box<Dimension>` 으로 바뀜 |
|
||||
| `DIMENSION_ARC`, `DIMENSION_LARGE_RADIAL` 타입명 추가 | 0.6 이 새로 읽는 치수. 0.4 는 버렸고, Viewer2D 는 아직 이 이름을 그리지 않으므로 화면은 전과 같다 |
|
||||
| OLE: `o.binary_data` → `o.encoded_payload()` | 0.6 은 OLE 페이로드를 envelope + compound file 로 분해해 둔다. 재조립한 바이트로 기존 DIB 탐색을 한다. 추출 이미지는 기존과 바이트 단위로 같다 |
|
||||
| `DwgReadOptions::failsafe()` | 0.6 strict 모드는 레코드 하나가 깨져도 도면 전체를 거부한다. `a. 거더배치 삽도` 가 handle 0x2663(type 37)의 잘못된 배열 개수로 통째로 실패했다. failsafe 에서는 정상 로드되고, 건너뛴 레코드는 notifications 로 간다 |
|
||||
| 전역 할당자: dlmalloc 을 32 MiB 단위로 확장 | 아래 §2.1 |
|
||||
|
||||
### 2.1 wasm 메모리 확장 비용
|
||||
|
||||
0.6.5 를 그대로 올리면 37 MB 노면 도면 파싱이 Node 에서 3.0초 → 7.4초로 느려졌다.
|
||||
|
||||
- **원인 확정** (CPU 프로파일): 시간의 55% 가 `<dlmalloc::sys::System as Allocator>::alloc`, 즉 wasm `memory.grow` 에 있었다.
|
||||
- V8 에서 `memory.grow` 한 번의 비용은 늘리는 양이 아니라 **현재 메모리 크기**에 비례한다 (Node 24 실측: 16 MB 일 때 0.04 ms, 700 MB 일 때 1.6 ms).
|
||||
- 0.6 은 짧게 쓰고 버리는 버퍼가 많아서, 기본 dlmalloc(64 KB 페이지 단위)이 수천 번 확장했다.
|
||||
|
||||
`dwg-wasm/src/lib.rs` 의 `big_step_alloc` 이 같은 dlmalloc 을 `set_granularity(32 MiB)` 로 감싸서 해결한다. acadrust 는 건드리지 않는다. 결과는 7.4초 → 3.3초. 대신 힙 끝에 최대 한 단계(32 MB)가 비어 있을 수 있다.
|
||||
|
||||
## 3. 검증 방법
|
||||
|
||||
1. **파싱 비교 (Node)**: 기존 wasm 과 새 wasm 으로 같은 DWG 19개를 파싱한다. `fixDwgKoreanText` 까지 적용한 뒤, 엔티티를 `타입#handle` 로 짝짓는다. 필드마다 정규화(숫자 12자리)한 해시로 비교했다.
|
||||
2. **브라우저 (Chrome headless, 실 GPU)**: 같은 작업 트리에서 wasm 만 바꿔 20개(DWG 19 + DXF 1)를 로드한다. 상태바 `✓` 판정, 콘솔 에러, 1280×800 스크린샷 픽셀 비교를 했다.
|
||||
3. **네이티브 프로브**: MESH/OLE2FRAME 값을 원본 0.4.1 · 패치본 · 0.6.5 로 비교했다 ([`license-mpl2-acadrust.md`](./license-mpl2-acadrust.md) §3).
|
||||
|
||||
## 4. 결과
|
||||
|
||||
**파싱**: 19/19 성공. 파일별 엔티티 수와 handle 집합이 완전히 같다 (354,502개 중 누락·추가 0). 필드 값이 바뀐 엔티티는 2,815개(0.79%)다.
|
||||
|
||||
| 바뀐 필드 | 건수 / 파일 | 원인 | 화면 영향 |
|
||||
|---|---|---|---|
|
||||
| `DIMENSION_*.pt10` | 1,168 / 9 | 0.4.1 이 정의점을 (0,0,0) 으로 냈다 → 실제 좌표 | 블록 없는 치수(fallback)의 선택 범위·extents 만 |
|
||||
| `ATTDEF` alignmentPt / horiz·vertAlignment / widthFactor | 최대 664 / 13 | 0.4.1 이 읽지 못했다 → 실제 값 | 블록 안 ATTDEF 텍스트 위치·폭이 정확해진다 |
|
||||
| `INSERT.blockName`, `tables.blocks` 이름 | 812 / 1 (ELEVATION) | 익명 블록 번호 체계가 바뀜 (`*U1` → `*U7`) | 없음. 렌더는 handle 기준이고, INSERT 이름과 블록 테이블 이름은 전 파일에서 일치(불일치 0) |
|
||||
| `entityHeader.colorIndex` (트루컬러 엔티티) | 116 / 3 | 트루컬러 → 가장 가까운 ACI 근사가 개선됨. 원본 RGB 는 같다 | 원본 RGB 에 더 가까운 색 (Viewer2D 팔레트 기준 거리 130.8→117.6, 51.5→24.7) |
|
||||
| `VIEWPORT.id` 0 → 1 | 27 / 10 | 0.6.5 가 레이아웃의 전체(paper) 뷰포트에 id 1 을 준다 | 7개 파일에서 전체 뷰포트를 모델 창으로 오판하던 것이 사라졌다 (아래) |
|
||||
| `VIEWPORT.status.bits` | 26 / 2 | 비트 0x10000 추가 | 없음 (Viewer2D 는 `isOn` 만 사용) |
|
||||
| `TEXT.text` | 1 / 1 | `500¡¿350` → `500×350` | CP949 기호 깨짐 1건 해소 |
|
||||
| `OLE2FRAME.dataLength` | 1 / 1 | 페이로드 재조립으로 512 B 차이 | 없음 (이미지 바이트 동일) |
|
||||
| `vars.celweight` | 전 파일 | 29 → -1 | 없음 (미사용) |
|
||||
|
||||
**VIEWPORT 판정**: id 가 1 로 바뀐 VP 는 모두 레이아웃마다 하나뿐인 전체 뷰포트였다 (배율 1.0000, target (0,0)). 진짜 모델 창(id ≥ 2)의 판정은 전 파일에서 그대로다.
|
||||
|
||||
기존에는 `Viewer2D._isModelViewport` 의 휴리스틱이 이 VP 를 모델 창으로 오판했다. 판정 조건 중 "viewCenter ≈ center" 가 맞지 않았기 때문이다. 그래서 모델 공간을 레이아웃 위에 한 번 더 투영했다. `a. 중앙분리대 삽도` 의 기본 화면을 가로지르던 검은 세로 띠가 이것이고, 업그레이드 후 사라졌으며 Fit 도 도면을 제대로 채운다.
|
||||
|
||||
**브라우저**: 기존·신규 모두 20/20 로드 성공. 기본 탭(Model/Layout) 동일, 콘솔 에러 동일 (첫 페이지 favicon 404 1건).
|
||||
|
||||
| 스크린샷 차이 | 파일 | 내용 |
|
||||
|---|---|---|
|
||||
| 0% (픽셀 동일) | 16개 | — |
|
||||
| 16.9% | a. 중앙분리대 삽도 | 검은 띠 제거, Fit 개선, 해치 갈색이 원본 RGB 에 가까워짐 |
|
||||
| 3.3% / 0.5% | a. 교량시종점 / a. 횡단경사 | 트루컬러 근사색 |
|
||||
| 0.6% / 0.005% | a. 교량폭원 / ELEVATION | 툴바의 Layout 탭 이름 폭 |
|
||||
|
||||
Layout 탭 이름은 익명 paper 블록 번호를 따르므로 바뀌었다 (`Paper_Space1` → `Paper_Space194` 등). 원래 내부 이름이 보이던 문제(레이아웃 실제 이름 미사용)는 그대로다.
|
||||
|
||||
notification 수는 4개 파일에서 늘었다 (BasicSample 4→24, 거더배치 5→11 등). 0.6.5 가 진단을 더 많이 남기는 것이다.
|
||||
|
||||
### 4.1 추가 샘플 (`public/samples/` 신규 3개)
|
||||
|
||||
`dwg_18.3mb.dwg` 는 `dist2/samples` 의 같은 파일(md5 동일)이라, 실제 신규는 2개다:
|
||||
`C0060203-002-굴착및시공순서도`, `dwg_1.60mb.dwg`.
|
||||
|
||||
- 3개 모두 기존·신규 파싱 성공이다. 0.6.5 strict 모드에서도 실패하지 않는다. 엔티티 수와 handle 집합이 같고, 브라우저 로드 성공, 콘솔 에러 0이다.
|
||||
- **3D 폴리선 vertex 순서** (`dwg_1.60mb`, 옹벽·관로 7개, `원인 확정`).
|
||||
- 두 버전 모두 vertex 13개는 같고 순서만 다르다.
|
||||
- 0.4.1 은 vertex 를 handle 번호 순으로 정렬했다. 그래서 나중에 추가된 vertex(handle 227026, 가장 서쪽 점)가 중간에 끼어들어, 선이 최대 193 단위 되돌아갔다 오는 가짜 현(chord)이 생겼다.
|
||||
- 0.6.5 는 DWG 연결 순서를 따른다 (x 가 단조 증가하는 매끈한 선). 확대 캡처에서 곡선을 가로지르던 청록 직선이 사라진 것을 확인했다.
|
||||
- **ATTDEF 정렬**: 굴착및시공순서도의 동그라미 번호가 원의 아래쪽에서 중앙으로 옮겨졌다 (§4 의 ATTDEF 행과 같은 원인).
|
||||
- **한글**: 0.6.5 는 CP949 를 원본에서 직접 디코딩한다.
|
||||
- 기존 wasm 은 평면및종단면도(153개)와 굴착및시공순서도(160개)를 Latin-1 로 깨진 채 내보냈고, `fixDwgKoreanText` 가 복원해 왔다.
|
||||
- 0.6.5 는 21개 DWG 전부 원본 깨짐 0이다. 보정 후 한글 텍스트 수는 전 파일에서 같다.
|
||||
- `fixDwgKoreanText` 는 이 샘플들에서 할 일이 없어졌다. 다른 코드페이지 도면 대비용 안전망으로 남겨 둔다.
|
||||
|
||||
## 5. 비용
|
||||
|
||||
| 항목 | 0.4.1 패치본 | 0.6.5 |
|
||||
|---|---|---|
|
||||
| wasm raw / brotli | 864 KB / 294 KB | 2,976 KB / 815 KB |
|
||||
| 노면 37 MB 파싱 (Node) | 3.0 s | 3.3~3.5 s |
|
||||
| dwg_18.3mb 파싱 (Node) | 1.9 s | 2.1 s |
|
||||
| 노면 브라우저 로드 | 5.4 s | 5.7 s |
|
||||
| dwg_18.3mb 브라우저 로드 | 3.7 s | 4.0 s |
|
||||
| wasm 메모리 (노면 / dwg_18.3mb) | 672 / 546 MB | 773 / 505 MB |
|
||||
|
||||
- 크기가 커진 원인: acadrust 0.6 이 DXF/DWG 쓰기, ACIS 등을 포함해 라이브러리 자체가 커졌다. 기본 feature 는 비어 있어 끌 수 있는 것이 없다.
|
||||
- `opt-level = "z"` 를 시험했다: brotli 742 KB(−9%) 대신 파싱이 36% 느려져서(3.5 → 4.7 s) 채택하지 않았다.
|
||||
|
||||
## 6. 남은 것
|
||||
|
||||
- Viewer2D 가 `DIMENSION_ARC` / `DIMENSION_LARGE_RADIAL` 을 그리지 않는다. 블록 렌더 분기에 추가하면 된다. 샘플 20개에는 해당 엔티티가 없다.
|
||||
- XDATA: acadrust 는 `common.extended_data` 로 읽지만 dwg-wasm 이 parseResult 에 내보내지 않는다 (업그레이드 전과 같다).
|
||||
- wasm 에 컴파일되는 Rust 의존성의 라이선스 고지 생성 ([`license-mpl2-acadrust.md`](./license-mpl2-acadrust.md) §6).
|
||||
- `dist2/` 재빌드와 pages.dev 재배포 전까지는 배포본이 옛 고지(0.4.1 패치)를 보여 준다.
|
||||
@@ -0,0 +1,146 @@
|
||||
# `dist2` 정적 빌드 배포 절차
|
||||
|
||||
| 항목 | 내용 |
|
||||
|------|------|
|
||||
| 작성 목적 | Slug GPU 텍스트 cap-height 수정 배포 작업을 기록하고, 공식 배포 스크립트가 없는 이 저장소에서 재사용 가능한 절차로 남김 |
|
||||
| 배포 대상 | `dist2/` (저장소에 커밋되는 정적 빌드 산출물, 실제 서빙 디렉터리) |
|
||||
| 계기 커밋 | `fb8f7ca` fix(viewer2d): correct Slug GPU text scale to match DWG cap-height |
|
||||
| 배포일 | 2026-08-04 |
|
||||
| 상태 | 완료 (origin/master push 완료) |
|
||||
|
||||
---
|
||||
|
||||
## 1. `dist2`란 무엇인가
|
||||
|
||||
이 저장소는 **공식 배포 스크립트가 없다.** `package.json`에는 `dev` / `build` (→ `dist/`, `.gitignore` 대상) / `preview` / `typecheck` 뿐이고, `dist2`를 만드는 스크립트나 CI는 존재하지 않는다.
|
||||
|
||||
그런데도 `dist2/`는 저장소에 **커밋되어 있고** (`git ls-files dist2` 로 확인 가능), 과거 커밋들(`3d3e052` 등)에서 반복적으로 갱신되어 온 정황으로 볼 때 **`vite build`를 수동으로 `--outDir dist2` 옵션과 함께 실행해 만든 산출물을 그대로 커밋 → push 하는 방식**이 이 프로젝트의 사실상 배포 방식이다.
|
||||
|
||||
```
|
||||
src/ ──(vite build)──▶ dist/ (gitignore, 로컬 전용)
|
||||
src/ ──(vite build --outDir dist2)──▶ dist2/ (git 커밋, 실제 배포물)
|
||||
```
|
||||
|
||||
`dist2/samples/`, `dist2/fonts/`, `dist2/docs/`는 `public/`의 사본 + 빌드시 자동 복사분이다.
|
||||
|
||||
### 함정: `dist2`에 소스가 아닌 파일이 섞여 있다
|
||||
|
||||
배포 작업 시작 시 `git status`에 다음 **untracked** 파일이 있었다:
|
||||
|
||||
```
|
||||
dist2/samples/configBak/ (cuiBak.cui, regBak.json — AutoCAD 설정 백업, 테스트용)
|
||||
dist2/samples/dwg_18.3mb.dwg (대용량 테스트 도면)
|
||||
```
|
||||
|
||||
이 파일들은 `public/samples/`에 없다 → 빌드가 만든 게 아니라 **사람이 `dist2`에 직접 넣어둔 테스트 자료**다. Vite의 기본 `emptyOutDir`는 `outDir`가 프로젝트 루트 안에 있으면 `true`(빌드 전 디렉터리 전체 삭제)이므로, 아무 옵션 없이 `vite build --outDir dist2`를 돌리면 **이 파일들이 삭제된다.**
|
||||
|
||||
→ 배포 시 반드시 `--emptyOutDir false`를 붙인다 (아래 3절).
|
||||
|
||||
---
|
||||
|
||||
## 2. 사전 확인
|
||||
|
||||
```bash
|
||||
cd D:\MYCLAUDE_PROJECT\dwg-dxf-viewer-sample
|
||||
git status --short # untracked/미커밋 상태 파악 (dist2 안 이물질 포함)
|
||||
npx tsc --noEmit -p . # 타입체크 먼저 (build 스크립트가 어차피 포함하지만 분리 확인)
|
||||
```
|
||||
|
||||
`npx vite ...`가 이 환경에서 `npm error Missing script: "vite"`로 실패하는 경우가 있었다 (원인 미상 — npx가 로컬 bin 대신 npm script를 찾으려 한 것으로 보임). 재현되면 로컬 바이너리를 직접 호출:
|
||||
|
||||
```bash
|
||||
./node_modules/.bin/vite build --outDir dist2 --emptyOutDir false
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 3. 빌드
|
||||
|
||||
```bash
|
||||
cd D:\MYCLAUDE_PROJECT\dwg-dxf-viewer-sample
|
||||
./node_modules/.bin/vite build --outDir dist2 --emptyOutDir false
|
||||
```
|
||||
|
||||
- `--outDir dist2`: 기본 `dist/`(gitignore) 대신 커밋 대상 디렉터리로 출력
|
||||
- `--emptyOutDir false`: **필수.** `dist2/samples/configBak/`, `dwg_18.3mb.dwg` 등 빌드가 모르는 파일을 보존
|
||||
- 결과: 새 해시가 붙은 `assets/index-*.js`, `assets/acadrust_dwg_bg-*.wasm` 등이 **추가로** 생기고, 예전 해시 파일은 자동 삭제되지 않음 (이 저장소의 기존 관행과 동일 — `dist2/assets`에 여러 세대의 `index-*.js`가 누적돼 있음). 이번 배포에서도 정리하지 않았다.
|
||||
- `dist2/index.html`이 새 해시를 가리키도록 갱신됨
|
||||
|
||||
이번 실행 결과:
|
||||
|
||||
```
|
||||
dist2/index.html 10.88 kB
|
||||
dist2/assets/acadrust_dwg_bg-Dt2ifJSA.wasm 879.93 kB
|
||||
dist2/assets/acadrustParser-CJeZuNZe.js 4.18 kB
|
||||
dist2/assets/index-CmUgC68r.js 1000.36 kB
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 4. 변경분 검토 (커밋 전 필수)
|
||||
|
||||
```bash
|
||||
git status --short dist2 src
|
||||
git diff dist2/index.html # 새 해시 참조로만 바뀌었는지 확인
|
||||
```
|
||||
|
||||
빌드 직전 `dist2/index.html`이 커밋 `199317d`(Entity 선택/Property/Layer 패널) 이전 상태를 가리키고 있었다 — 즉 **이번 배포 전까지 `dist2`가 여러 커밋만큼 stale**했다. `git diff` 결과 UI 패널 CSS/마크업 100줄+ 이 새로 반영된 것으로 확인, 이번 빌드가 그 gap을 포함해 최신화했다.
|
||||
|
||||
---
|
||||
|
||||
## 5. 스테이징 — 빌드 산출물만, 이물질 제외
|
||||
|
||||
```bash
|
||||
git add src/viewer2d/slugText.ts \
|
||||
dist2/index.html \
|
||||
dist2/assets/acadrustParser-CJeZuNZe.js \
|
||||
dist2/assets/acadrust_dwg_bg-Dt2ifJSA.wasm \
|
||||
dist2/assets/index-CmUgC68r.js
|
||||
git status --short # dist2/samples/configBak/, dwg_18.3mb.dwg 는 untracked 로 남아있어야 함
|
||||
```
|
||||
|
||||
`git add dist2` 나 `git add -A`를 쓰지 않는다 — `configBak/`, 대용량 테스트 `.dwg`가 함께 커밋되는 것을 막기 위함.
|
||||
|
||||
---
|
||||
|
||||
## 6. 커밋 & 푸시
|
||||
|
||||
```bash
|
||||
git commit -m "fix(viewer2d): correct Slug GPU text scale to match DWG cap-height
|
||||
|
||||
..."
|
||||
git push origin master
|
||||
```
|
||||
|
||||
- push는 공유 원격(gitea `origin`)에 영향을 주는 되돌리기 어려운 작업 → **사용자 확인 후 실행**했다.
|
||||
- 결과: `fb8f7ca` 커밋으로 push 완료.
|
||||
|
||||
---
|
||||
|
||||
## 7. 체크리스트 (다음 배포 시 재사용)
|
||||
|
||||
- [ ] `git status --short` — `dist2` 안 untracked 이물질 있는지 먼저 확인
|
||||
- [ ] `tsc --noEmit` 통과
|
||||
- [ ] `./node_modules/.bin/vite build --outDir dist2 --emptyOutDir false` (npx가 실패하면 이 경로로)
|
||||
- [ ] `git diff dist2/index.html` 로 해시/마크업 변경분 확인
|
||||
- [ ] `git status --short dist2` 로 새로 생긴 `assets/*` 해시 파일 목록 확인
|
||||
- [ ] 필요한 파일만 개별 `git add` (샘플/백업 이물질 제외)
|
||||
- [ ] 커밋 메시지에 무엇/왜 남김
|
||||
- [ ] push 전 사용자 확인 (원격 공유 저장소)
|
||||
|
||||
---
|
||||
|
||||
## 8. 후속 과제
|
||||
|
||||
1. **공식 배포 스크립트 부재** — `package.json`에 `"build:dist2": "vite build --outDir dist2 --emptyOutDir false"` 같은 스크립트를 추가하면 `--outDir`/`--emptyOutDir` 플래그를 매번 손으로 맞출 필요가 없어진다.
|
||||
2. **누적된 구세대 해시 파일** — `dist2/assets/index-*.js`가 세대별로 계속 쌓여만 있다 (정리 안 됨). 정리하려면 배포 직후 `dist2/index.html`이 참조하지 않는 해시 파일을 찾아 지우는 스텝이 필요하나, 이번 배포에서는 기존 관행을 바꾸지 않기 위해 손대지 않았다.
|
||||
3. **`dist2` 안 테스트 이물질**(`configBak/`, `dwg_18.3mb.dwg`) — 배포 산출물 디렉터리에 테스트 자료가 섞여 있는 구조 자체가 위험(다음 사람이 무심코 `emptyOutDir` 기본값으로 밀어버릴 수 있음). `public/samples/` 같은 소스 디렉터리로 옮기거나 별도 경로 분리를 검토할 것.
|
||||
|
||||
---
|
||||
|
||||
## 9. 참고
|
||||
|
||||
- 빌드 산출물: [`../dist2/`](../dist2/)
|
||||
- Vite 설정: [`../vite.config.ts`](../vite.config.ts)
|
||||
- 이번 배포로 반영된 수정: [`../src/viewer2d/slugText.ts`](../src/viewer2d/slugText.ts)
|
||||
- 관련 배포(원인 무관, 이후 별도 push로 `dist2` 추가 갱신됨): `3480945` perf(viewer2d): toggle layers by visibility instead of reloading the drawing
|
||||
@@ -0,0 +1,227 @@
|
||||
# 개선 결과 보고 — SubDMesh + 선가중치 (2026-08-04)
|
||||
|
||||
| 항목 | 내용 |
|
||||
|------|------|
|
||||
| 작성 목적 | 같은 날 들어간 두 개선(SubDMesh 렌더링, 선가중치 렌더링)의 **측정 결과**와, 개별 문서에는 없는 **두 변경의 상호작용**을 남긴다 |
|
||||
| 개별 문서 | [`subdmesh-rendering.md`](./subdmesh-rendering.md) · [`lineweight-rendering.md`](./lineweight-rendering.md) |
|
||||
| 기준 도면 | `dist2/samples/대산당진 2공구_노면_20260804_143854.dwg` (37.1 MB, AC1032 / AutoCAD 2018) |
|
||||
| 측정 방식 | `Viewer2D.js` 에서 `_meshSegs` · `_lwPx` 를 원본 그대로 들어내 실제 parseResult 에 돌린 값. 브라우저 픽셀 측정이 아니라 **세그먼트 회계** |
|
||||
|
||||
---
|
||||
|
||||
## 1. 요약
|
||||
|
||||
| | 개선 전 | 개선 후 |
|
||||
|--|--------|--------|
|
||||
| MESH 엔티티 파싱 | 0개 | 9개 |
|
||||
| 도로면 메쉬 | 정점 100,000 / 면 14 (**깨진 값**) | 정점 105,497 / 면 185,444 / 모서리 290,931 |
|
||||
| MESH 화면 출력 | 없음 | 315,633 선분 (면 wireframe) |
|
||||
| parseResult 크기 | 116 MB | 130 MB (+12%) |
|
||||
| 파싱 시간 | ~3.2 s | ~3.2 s (변화 없음) |
|
||||
| 선가중치 | 전부 1px 헤어라인 | 3개 굵기 버킷이 fat line 으로 분리 (아래 3절) |
|
||||
|
||||
---
|
||||
|
||||
## 2. 기준 도면 프로필
|
||||
|
||||
파싱 결과 65,495 엔티티.
|
||||
|
||||
```
|
||||
LWPOLYLINE 47,849 MTEXT 13,974 ATTRIB 1,504 TEXT 1,389
|
||||
INSERT 752 ATTDEF 15 MESH 9 LINE 2 CIRCLE 1
|
||||
```
|
||||
|
||||
MESH 9개:
|
||||
|
||||
| handle | layer | 정점 | 면 | 모서리 | 세분레벨 |
|
||||
|--------|-------|------|-----|--------|---------|
|
||||
| 4188 | 도로면 | 105,497 | 185,444 | 290,931 | 0 |
|
||||
| 4189 | 부체도로면 | 11,712 | 12,568 | 24,226 | 0 |
|
||||
| 296564 | 일반도로부체도로연결부 | 48 | 44 | 90 | 0 |
|
||||
| 296766 · 296927 · 297111 · 297259 · 297433 · 297665 | 부체도로(부체도로)연결부 | 28~53 | 25~47 | 51~96 | 0 |
|
||||
|
||||
전부 `subdivisionLevel = 0` 삼각 TIN → Catmull-Clark 세분 미구현이 이 도면에서는
|
||||
화면 차이를 만들지 않는다.
|
||||
|
||||
---
|
||||
|
||||
## 3. 개선 1 — SubDMesh
|
||||
|
||||
원인 분석과 수정 내용은 [`subdmesh-rendering.md`](./subdmesh-rendering.md) 에 있다.
|
||||
여기에는 **결과 수치**만 남긴다.
|
||||
|
||||
### 3-1. 스트림 어긋남 해소
|
||||
|
||||
`read_mesh` 의 배열 상한을 `MAX_ARRAY_COUNT`(100,000) 에서 "남은 스트림 비트 ÷
|
||||
항목 최소 인코딩 길이" 로 바꾼 결과:
|
||||
|
||||
| | 정점 | 면 | 모서리 | 앞쪽 면 크기 |
|
||||
|--|------|-----|--------|-------------|
|
||||
| 전 | 100,000 | 14 | 3 | `[64, 0, 64, 23, 0, 0, 0, 15]` |
|
||||
| 후 | 105,497 | 185,444 | 290,931 | `[3, 3, 3, 3, 3, 3, 3, 3]` |
|
||||
|
||||
오일러 표수 V − E + F = 105,497 − 290,931 + 185,444 = **10**. 경계를 가진
|
||||
다중 컴포넌트 곡면으로 타당한 값이다 (닫힌 단일 구면이면 2).
|
||||
|
||||
### 3-2. 선분 생성
|
||||
|
||||
| 경로 | 선분 수 | 비고 |
|
||||
|------|---------|------|
|
||||
| `edges` (중복 제거된 모서리) | **315,633** | 실제 사용 |
|
||||
| `faceList` 폴백 (면 루프 순회) | 741,072 | 2.35배. 두 경로의 그림 범위는 동일 |
|
||||
|
||||
- 비유한(NaN/Infinity) 좌표 **0건**
|
||||
- 길이 0 선분 6건 (원본 데이터의 축퇴 모서리, 무해)
|
||||
- 선분 bbox 가 메쉬 정점 bbox 와 일치 — x[151,892 … 161,087] y[477,930 … 482,146]
|
||||
- z 는 선분 양 끝 표고의 중간값, 범위 1.5 ~ 68. 이 도면은 LWPOLYLINE(0~68)·
|
||||
TEXT(0~54)도 같은 대역에 있어서 **메쉬만 위로 뜨지 않는다**
|
||||
|
||||
### 3-3. 손상 입력 방어
|
||||
|
||||
| 입력 | 결과 |
|
||||
|------|------|
|
||||
| 빈 객체 / 정점 배열 길이 2 (3의 배수 아님) | 0 선분, 예외 없음 |
|
||||
| 범위 밖 모서리 인덱스 (`[0, 99, -3, 1]`) | 0 선분 (경계 검사에서 탈락) |
|
||||
| 면 개수가 남은 배열보다 큼 (`[9, 0, 1]`) | 0 선분, 루프 탈출 |
|
||||
| 면 개수 0 반복 (`[0, 0, 0]`) | 0 선분, **무한루프 없음** |
|
||||
| 정상 삼각형 (`[3, 0, 1, 2]`) | 3 선분 |
|
||||
|
||||
---
|
||||
|
||||
## 4. 개선 2 — 선가중치
|
||||
|
||||
측정·판정은 [`lineweight-rendering.md`](./lineweight-rendering.md) 3절(헤드리스
|
||||
Chrome `readPixels` 비교)에 있다. 이 문서는 그 결과를 다시 주장하지 않고,
|
||||
아래 5절에서 **세그먼트 부하** 관점만 더한다.
|
||||
|
||||
이 도면의 엔티티 선가중치 원시값 분포 (i16, 1/100 mm):
|
||||
|
||||
```
|
||||
-3 (Default) ×15,176 -1 (ByLayer) ×2,613
|
||||
13 (0.13mm) × 8,794 35 (0.35mm) ×37,944 40 ×119 50 ×849
|
||||
vars.lwdisplay = true vars.celweight = 29
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 5. 새로 확인된 상호작용 — 메쉬 315,633 선분이 어느 버킷에 들어가는가
|
||||
|
||||
두 개선이 같은 `pushSeg` 를 공유한다. 선가중치 작업이 `pushSeg` 를
|
||||
`dash|lineweight` 버킷으로 쪼갰으므로, **메쉬 선분도 그 버킷 규칙을 탄다.**
|
||||
개별 문서 어느 쪽에도 이 얘기가 없어서 실측했다.
|
||||
|
||||
### 5-1. 지금은 안전하다
|
||||
|
||||
MESH 9개 전부:
|
||||
|
||||
```
|
||||
own lineWeight = -3 (Default), layer lineWeight = -3
|
||||
```
|
||||
|
||||
`_lwPx` 는 `-3` → `LW_DEFAULT_MM`(0.25mm) → `!(0.25 > LW_HAIRLINE_MM)` → **0 반환**.
|
||||
즉 315,633 선분이 전부 기존 병합 `LineSegments` 헤어라인 배치에 남고,
|
||||
`LineSegments2` 인스턴싱에는 **한 개도 들어가지 않는다.**
|
||||
|
||||
"0.25mm 이하는 헤어라인 유지" 규칙이 — 원래는 굵기 미지정 도면의 모양 보존이
|
||||
목적이었는데 — 결과적으로 대형 TIN 메쉬가 fat-line 경로로 쏟아지는 것을 막고 있다.
|
||||
|
||||
### 5-2. 현재 버킷 부하
|
||||
|
||||
LINE · LWPOLYLINE · MESH 기준 (ARC/CIRCLE/HATCH 는 미포함이라 실제 값은 이보다 조금 큼):
|
||||
|
||||
| 굵기 px | 선분 수 | 경로 | `LW_MAX_FAT_SEGS`(400,000) 대비 |
|
||||
|--------|---------|------|-------------------------------|
|
||||
| 0 (헤어라인) | 1,760,253 | 병합 `LineSegments` | — |
|
||||
| 2.8 (0.35mm) | 182,539 | fat line | 45.6% |
|
||||
| 3.2 (0.40mm) | 4,254 | fat line | 1.1% |
|
||||
| 4.0 (0.50mm) | 92,130 | fat line | 23.0% |
|
||||
|
||||
헤어라인 1,760,253 중 메쉬가 **315,633 (17.9%)** 을 차지한다.
|
||||
|
||||
### 5-3. 위험 — 메쉬 레이어에 굵기가 지정되면 버킷이 터진다
|
||||
|
||||
버킷 키는 `dash|lwPx` 이고 **도면 전역**이다. 도로면/부체도로면 레이어에
|
||||
0.35mm 를 지정하면 메쉬 선분이 이미 182,539 선분이 있는 2.8px 버킷에 합류한다.
|
||||
|
||||
```
|
||||
182,539 + 315,633 = 498,172 선분 = LW_MAX_FAT_SEGS 의 124.5%
|
||||
```
|
||||
|
||||
상한을 넘으면 `bk.fat = false` 가 되어 **그 버킷 전체가 헤어라인으로 되돌아간다.**
|
||||
메쉬만 헤어라인이 되는 게 아니라, 지금 정상적으로 굵게 나오는 도로 가장자리
|
||||
182,539 선분까지 같이 얇아진다. `console.warn` 한 줄만 남고 화면상으로는
|
||||
"선가중치가 갑자기 안 먹는" 것처럼 보인다.
|
||||
|
||||
**대응 후보** (지금 당장 필요하진 않다 — 이 도면은 5-1 때문에 해당 없음):
|
||||
|
||||
1. MESH 를 선가중치 대상에서 제외 — 메쉬 wireframe 을 굵게 그릴 실익이 없다.
|
||||
`_lwPx` 호출부에서 `type === 'MESH'` 면 0 을 쓰는 게 가장 싸다.
|
||||
2. 상한 초과 시 버킷 전체를 버리지 말고 **큰 기여자만** 헤어라인으로 강등.
|
||||
3. `LW_MAX_FAT_SEGS` 를 GPU 능력 기준으로 잡기 — 현재 40만은 고정 상수다.
|
||||
|
||||
---
|
||||
|
||||
## 6. 회귀 검증
|
||||
|
||||
새 wasm 과 직전 wasm(`git show HEAD:` 로 추출)으로 나머지 샘플 6개를 파싱해
|
||||
엔티티 히스토그램을 비교했다.
|
||||
|
||||
| 도면 | 버전 | 엔티티 | 히스토그램 |
|
||||
|------|------|--------|-----------|
|
||||
| BasicSample.dwg | R2018 | 7,309 | 동일 |
|
||||
| bb.dwg | R2018 | 438 | 동일 |
|
||||
| civil.dwg | R2000 | 17,810 | 동일 |
|
||||
| C0060202-001-평면및종단면도(1) | R2000 | 17,810 | 동일 |
|
||||
| C0060203-001-표준단면도(2차로) | R2007 | 2,068 | 동일 |
|
||||
| dwg_18.3mb.dwg | R2018 | 82,393 | 동일 |
|
||||
|
||||
6개 전부 **완전 일치**. 노면 도면만 65,486 → 65,495 (+9 MESH). `read_mesh` 상한
|
||||
변경이 MESH 이외 엔티티에 영향을 주지 않음을 확인한 것이다.
|
||||
|
||||
추가로 `tsc --noEmit`, `vite build`, 편집한 JS 3개 `node --check` 통과.
|
||||
|
||||
---
|
||||
|
||||
## 7. 반영 상태
|
||||
|
||||
| 대상 | 상태 |
|
||||
|------|------|
|
||||
| hmwebviewer `feat/subdmesh-render` `35f5b1c` | 파서 + 렌더러 + 속성 패널. **푸시 안 됨** |
|
||||
| 이 저장소 `feat/subdmesh-render` `eec3382` | wasm + 속성 패널 + 문서. **푸시 안 됨** |
|
||||
| 이 저장소 `src/viewer2d/Viewer2D.js` | **미커밋.** `_meshSegs` + MESH 디스패치 3군데가 선가중치/fat-line 리팩터와 hunk 가 겹쳐 분리 불가. 같은 코드가 hmwebviewer `35f5b1c` 에는 들어가 있다 |
|
||||
| `dist2/` | **미갱신.** 현재 빌드에 반쯤 배선된 선가중치 UI 가 섞여 있다 |
|
||||
| hmwebviewer wasm 산출물 | 미커밋. 선가중치 소스가 커밋될 때 `npm run build:dwg-wasm` 로 함께 |
|
||||
|
||||
커밋된 wasm 바이너리에는 선가중치 파서 필드(`lwdisplay`, `celweight`,
|
||||
layer/entity `lineWeight`)도 들어 있다. 빌드 시점의 소스에 이미 있었기 때문이며,
|
||||
소비 측 없는 추가 JSON 키라 무해하다.
|
||||
|
||||
---
|
||||
|
||||
## 8. 남은 과제
|
||||
|
||||
1. **5-3 버킷 상한** — 메쉬 레이어에 굵기가 지정된 도면이 들어오면 재현된다.
|
||||
샘플을 만들어 재현시켜 두는 편이 좋다.
|
||||
2. **Catmull-Clark 세분** — `subdivisionLevel > 0` 메쉬는 AutoCAD 보다 각져 보인다.
|
||||
기준 도면에는 해당 없어 미구현.
|
||||
3. **POLYFACE MESH / POLYGON MESH** — 구형 POLYLINE flag 16/64 계열은 여전히
|
||||
미지원. SubDMesh 와 별개 엔티티다.
|
||||
4. **메쉬 채움(shaded) 패스** — `faceList` 를 이미 내보내고 있으므로 삼각화만
|
||||
하면 된다. 2D 와이어프레임 뷰어라 우선순위는 낮다.
|
||||
5. **`dist2` 배포** — 선가중치 작업이 끝난 뒤
|
||||
[`deploy-dist2-static-build.md`](./deploy-dist2-static-build.md) 절차로.
|
||||
|
||||
---
|
||||
|
||||
## 9. 측정 재현
|
||||
|
||||
```bash
|
||||
# 네이티브 메쉬 진단 (면 크기가 3/4 로 균일하지 않으면 스트림 어긋남 의심)
|
||||
cd D:\MYCLAUDE_PROJECT\hmwebviewer\rust\dwg-wasm
|
||||
cargo run --release --bin meshprobe -- <file.dwg>
|
||||
```
|
||||
|
||||
5절의 버킷 표는 `Viewer2D.js` 에서 `_meshSegs` · `_lwPx` 를 들어내 parseResult 에
|
||||
직접 돌려 만들었다 (`LINE` / `LWPOLYLINE` / `MESH` 만 계수). `Viewer2D.js` 는 three
|
||||
와 확장자 없는 TS 모듈을 import 하므로 node 에서 그대로 import 되지 않는다 —
|
||||
함수 본문만 뽑아 `new Function` 으로 감싸는 방식이었다.
|
||||
@@ -0,0 +1,89 @@
|
||||
# acadrust MPL-2.0 — 의무 사항과 조치 내역
|
||||
|
||||
| 항목 | 내용 |
|
||||
|------|------|
|
||||
| 작성 목적 | 파서(acadrust, MPL-2.0)를 담은 wasm 을 공개 배포하면서 지켜야 할 의무를 확정하고 조치 내역 기록 |
|
||||
| 대상 배포물 | `https://dwg-dxf-viewer-sample.pages.dev/` (Cloudflare Pages, **공개**) |
|
||||
| 최초 검토 | 2026-08-04 (0.4.1 + 로컬 패치) |
|
||||
| 갱신 | 2026-10-19 — **acadrust 0.6.5 무수정으로 교체**, 로컬 패치 폐기 |
|
||||
| 상태 | 소스 트리 조치 완료. **배포본(dist2 / pages.dev)은 재빌드·재배포 전까지 옛 고지** |
|
||||
|
||||
---
|
||||
|
||||
## 0. 결론
|
||||
|
||||
1. **acadrust 를 0.6.5 (crates.io) 무수정으로 쓴다.** 로컬 패치가 필요 없어졌으므로
|
||||
"수정본 소스 공개" 의무가 없다. 남는 의무는 MPL 원문 동봉 + 고지 + 소스 위치 안내뿐이다.
|
||||
2. **우리 래퍼 `dwg-wasm` 은 MIT** (MPL 은 파일 단위라 번지지 않는다).
|
||||
0.6.5 대응으로 고친 곳(할당자, failsafe, API 변경)은 전부 이 래퍼 안이다.
|
||||
3. **upstream PR 의무는 없다.**
|
||||
|
||||
## 1. 무엇이 MPL 이고 무엇이 우리 것인가
|
||||
|
||||
| 코드 | 위치 | 라이선스 | 수정 여부 |
|
||||
|------|------|----------|-----------|
|
||||
| **acadrust 0.6.5** (DWG 파서 본체) | crates.io, `dwg-wasm/Cargo.toml` 에서 `=0.6.5` 고정 | **MPL-2.0** | **무수정** |
|
||||
| dwg-wasm (wasm-bindgen 래퍼 + JSON 직렬화) | `hmwebviewer/rust/dwg-wasm/` | MIT (우리 코드) | 수정함 |
|
||||
| Viewer2D 외 프론트엔드 | `src/` | MIT | — |
|
||||
|
||||
## 2. 0.4.1 시절 고지가 틀렸던 이유 (2026-10-19 확인)
|
||||
|
||||
2026-08-04 고지는 "한 파일만 수정"이라고 했지만, 실제 vendored 0.4.1 은
|
||||
**2파일 3건**이 원본과 달랐다 (`hmwebviewer` `feat/subdmesh-render` 브랜치 기준).
|
||||
|
||||
| 파일 | 수정 |
|
||||
|---|---|
|
||||
| `object_reader/entities.rs` | `read_mesh` 배열 개수를 남은 비트로 제한 (대형 SubD 메쉬 손상 수정) |
|
||||
| `object_reader/entities.rs` | OLE2FRAME 네 모서리 좌표를 데이터 헤더에서 추출 |
|
||||
| `dwg_document_builder.rs` | 그 좌표를 엔티티에 대입 |
|
||||
|
||||
공개했던 `acadrust-0.4.1-read_mesh.patch` 는 원본이 아니라 OLE 중간 수정본을 기준으로
|
||||
만들어져서, 원본 0.4.1 에 `git apply` 하면 `entities.rs:2350` 에서 실패했다.
|
||||
즉 배포된 wasm 의 소스를 재현할 수 없었다 → MPL §3.2(a) 미충족.
|
||||
|
||||
## 3. 0.6.5 가 두 수정을 대체하는 근거
|
||||
|
||||
같은 도면을 네이티브 프로브로 읽어 비교했다 (2026-10-19).
|
||||
|
||||
| 샘플 | 원본 0.4.1 | 우리 패치본 | 0.6.5 무수정 |
|
||||
|---|---|---|---|
|
||||
| 대산당진 노면 MESH#1 | verts 100000 / faces 14 (손상) | 105497 / 185444 / 290931 | **105497 / 185444 / 290931** |
|
||||
| C0060203 OLE2FRAME 좌표 | (1,1,0)/(0,0,0) 기본값 | (20584.21, 25712.29)–(39654.45, 13712.29) | **같음** |
|
||||
|
||||
업그레이드에 따른 래퍼 변경과 회귀 결과는 [`acadrust-0.6.5-upgrade.md`](./acadrust-0.6.5-upgrade.md).
|
||||
|
||||
## 4. 적용되는 조항 (무수정 사용 기준)
|
||||
|
||||
| 조항 | 요구 | 조치 |
|
||||
|------|------|------|
|
||||
| §3.2(a)(b) | Executable Form 배포 시 소스를 MPL 로 제공하고 수령자에게 입수 방법을 알릴 것 | 고지에 crates.io 다운로드 URL·커밋·SHA-256 명시 |
|
||||
| §3.1 / §3.4 | 라이선스 사본 동봉, 고지 제거 금지 | `public/licenses/acadrust-MPL-2.0.txt` (0.6.5 `LICENSE` 와 동일 확인) |
|
||||
| §3.3 | Larger Work(우리 앱)는 다른 라이선스 가능 | dwg-wasm·Viewer2D 는 MIT |
|
||||
|
||||
crates.io 는 게시된 버전을 삭제하지 않는다(yank 해도 다운로드 가능). 그래서 정확한 버전
|
||||
링크를 소스 입수 경로로 삼는다. FAQ 가 "링크만으로 충분"하다고 명시하지는 않으므로,
|
||||
상용 납품처럼 더 확실해야 하는 배포에서는 `.crate` 파일(4.1MB)을 함께 두는 방안을 검토한다.
|
||||
|
||||
## 5. 배포물 구성
|
||||
|
||||
| 파일 | 배포 URL | 내용 |
|
||||
|------|----------|------|
|
||||
| `public/licenses/acadrust-MPL-2.0.txt` | `/licenses/acadrust-MPL-2.0.txt` | MPL-2.0 원문 |
|
||||
| `public/licenses/THIRD-PARTY-NOTICES.md` | `/licenses/THIRD-PARTY-NOTICES.md` | 컴포넌트·버전·커밋·SHA-256·소스 입수 방법 |
|
||||
|
||||
`index.html` "Module recipe" 패널 하단에서 두 곳으로 링크한다 (§3.2(b) "reasonable manner").
|
||||
옛 `acadrust-0.4.1-read_mesh.patch` 는 삭제했다.
|
||||
|
||||
## 6. 앞으로 지킬 것 (체크리스트)
|
||||
|
||||
- [ ] acadrust 를 고치지 않는다. 고쳐야 하면 fork 소스 전체를 공개 위치에 두고 고지를 "modified" 로 바꾼다
|
||||
- [ ] acadrust 버전을 올리면 → 고지의 버전·커밋·SHA-256 갱신 (`Cargo.lock` checksum)
|
||||
- [ ] 새 서드파티를 번들하면 → `THIRD-PARTY-NOTICES.md` 에 행 추가
|
||||
- [ ] 배포 전 `/licenses/` 2개 파일이 실제로 서빙되는지 확인
|
||||
- [ ] (미해결) wasm 에 컴파일되는 Rust 의존성(MIT/Apache/BSD 등)의 고지 생성 — `cargo about` 등
|
||||
|
||||
## 7. 참고
|
||||
|
||||
- MPL-2.0 원문: [`../public/licenses/acadrust-MPL-2.0.txt`](../public/licenses/acadrust-MPL-2.0.txt)
|
||||
- FAQ: https://www.mozilla.org/MPL/2.0/FAQ/ (Q6 사내 사용, Q8 실행 파일 배포, Q17 "distribute" 의미)
|
||||
- MESH 수정 경위: [`subdmesh-rendering.md`](./subdmesh-rendering.md)
|
||||
@@ -0,0 +1,337 @@
|
||||
# 선가중치(Lineweight) 미적용 — 원인 분석 및 해결 가이드
|
||||
|
||||
| 항목 | 내용 |
|
||||
|------|------|
|
||||
| 작성 목적 | 모든 선이 1px 헤어라인으로만 그려지던 문제의 원인 규명과 수정·검증 내역 기록 |
|
||||
| 샘플 저장소 | `dwg-dxf-viewer-sample` (본 문서 위치) |
|
||||
| 원본 저장소 | `hmwebviewer` (`rust/dwg-wasm/`, `src/viewer2d/` 동기화 대상) |
|
||||
| 재현 도면 | `대산당진 2공구_노면_20260804_143854.dwg` (65,495 entities · LWDISPLAY=on · 0.13/0.35/0.40/0.50mm 혼재) |
|
||||
| 대조 도면 | `BasicSample.dwg`, `civil.dwg`, `bb.dwg`, `C0060202-001-평면및종단면도(1).dwg` (모두 굵기 미지정) |
|
||||
| 정답지 | AutoCAD 스크린샷 (`dist2/samples/1785826356.png`) |
|
||||
| 수정일 | 2026-08-04 |
|
||||
| 상태 | **해결** — 파서·렌더러 수정 완료, `dist2` 재빌드 완료, 커밋/푸시는 미실행 |
|
||||
|
||||
> **폭(width)과 혼동 주의.** 도곽 외곽선이 예전부터 굵게 그려진 것은 lineweight 가 아니라
|
||||
> LWPOLYLINE 의 **폭**(`constantWidth` / `startWidths` / `endWidths`)이다. 도면단위 실폭이라
|
||||
> 줌하면 같이 커지고, `_widePolyMesh` 가 삼각형 메쉬로 처리한다. lineweight 는 화면 픽셀
|
||||
> 단위(줌해도 폭 고정)이며 이번 문서의 대상이다. 둘은 별개 기능이다.
|
||||
|
||||
---
|
||||
|
||||
## 1. 현상
|
||||
|
||||
AutoCAD 에서는 도로 가장자리·교량라인이 뚜렷하게 굵고 비탈면 선은 가는데,
|
||||
뷰어에서는 **모든 선이 같은 1px**로 그려진다. 색상·선종류(점선)는 정상.
|
||||
|
||||
정답지와 대조하면 굵기 비율이 완전히 소실된 상태였다.
|
||||
|
||||
---
|
||||
|
||||
## 2. 오류 원인
|
||||
|
||||
원인은 **두 겹**이었다. 한쪽만 고쳐서는 화면이 바뀌지 않는다.
|
||||
|
||||
### 2-1. 파서가 lineweight 를 내보내지 않았다 (데이터 부재)
|
||||
|
||||
acadrust 는 lineweight 를 **이미 읽고 있었다.**
|
||||
|
||||
```
|
||||
acadrust/src/entities/mod.rs:260 pub line_weight: LineWeight, // EntityCommon
|
||||
acadrust/src/tables/layer.rs:58 pub line_weight: LineWeight, // Layer
|
||||
acadrust/src/types/line_weight.rs DWG 5비트 테이블 인덱스 ↔ 값 변환까지 구현
|
||||
```
|
||||
|
||||
그런데 `dwg-wasm` 의 JSON 직렬화(`common_json` / `tables_value` / `vars_value`)에서
|
||||
해당 필드가 빠져 있어 parseResult 에 값이 존재하지 않았다.
|
||||
|
||||
확인 방법 — wasm 바이너리의 serde 필드명 문자열을 직접 조회:
|
||||
|
||||
```bash
|
||||
grep -a -c "linetypeScale" acadrust_dwg_bg.wasm # 1 (있음)
|
||||
grep -a -c "entityHeader" acadrust_dwg_bg.wasm # 1 (있음)
|
||||
grep -a -o -i "[a-z_]*weight[a-z_]*" acadrust_dwg_bg.wasm | sort -u # (없음)
|
||||
```
|
||||
|
||||
parseResult 덤프로도 재확인:
|
||||
|
||||
```
|
||||
layer[0] = { colorIndex, frozen, handle, lineType, locked, name, on, plotting } ← lineWeight 없음
|
||||
entityHeader = { colorIndex, invisible, linetypeScale } ← lineWeight 없음
|
||||
```
|
||||
|
||||
### 2-2. 렌더러가 굵기를 그릴 수단이 없었다 (표현 부재)
|
||||
|
||||
Viewer2D 는 성능을 위해 도면의 모든 선분을 **하나의 병합 버퍼**로 그린다.
|
||||
|
||||
```js
|
||||
const lmesh = new THREE.LineSegments(geom, new THREE.LineBasicMaterial({ vertexColors: true }));
|
||||
```
|
||||
|
||||
WebGL 코어 프로파일에서 `LineBasicMaterial.linewidth` 는 **무시되고 항상 1px** 이다
|
||||
(three.js 문서 명시). 즉 2-1 이 해결되어 값이 들어오더라도 이 배치 구조로는
|
||||
굵기를 표현할 수 없다.
|
||||
|
||||
### 2-3. 왜 지금까지 드러나지 않았나
|
||||
|
||||
굵기를 지정한 도면이 저장소 샘플에 사실상 없었다. 엔티티 lineweight 히스토그램:
|
||||
|
||||
| 도면 | LWDISPLAY | 엔티티 lineweight |
|
||||
|------|-----------|-------------------|
|
||||
| `BasicSample.dwg` | true | `-2` ×62, `-1` ×7247 → 전부 ByLayer/ByBlock → 레이어가 전부 Default |
|
||||
| `civil.dwg` / `bb.dwg` / `C0060202` | **false** | `-1` ×17241, `0` ×569 |
|
||||
| **`대산당진 2공구_노면`** | true | `-3` ×15176, `-1` ×2613, **`13` ×8794, `35` ×37944, `40` ×119, `50` ×849** |
|
||||
|
||||
굵기 데이터가 실제로 있는 도면은 노면 도면 하나뿐이었고, 그 도면은 37MB 라
|
||||
로딩 성능 이슈가 해결된 뒤에야 일상적으로 열리기 시작했다.
|
||||
|
||||
---
|
||||
|
||||
## 3. 개선 사항 (설계 결정)
|
||||
|
||||
수정 방향을 정할 때 확정한 규칙들.
|
||||
|
||||
### 3-1. 픽셀 환산 — AutoCAD LWDISPLAY 규격을 따른다
|
||||
|
||||
lineweight 는 **화면 픽셀 폭**이다. 줌해도 굵기가 변하지 않는다(모델 공간 기준).
|
||||
따라서 월드 단위가 아니라 스크린 스페이스로 그려야 한다.
|
||||
|
||||
```
|
||||
px = mm × 11 (LW_PX_PER_MM 기본값, 최대 48px)
|
||||
0.35mm = 3.9px · 0.50mm = 5.5px · 2.11mm = 23px
|
||||
```
|
||||
|
||||
**이 배율은 상수로 확정할 수 있는 값이 아니다.** AutoCAD 도 모델 공간에서는 선가중치를
|
||||
줌과 무관한 픽셀로만 그리고, 그 환산은 "선가중치 설정 → 표시 배율" 슬라이더가 정한다.
|
||||
즉 화면 DPI·모니터에 따라 맞는 값이 달라진다.
|
||||
|
||||
- 코드 기본값: `LW_PX_PER_MM = 11` (사용자가 실제 화면에서 AutoCAD 와 나란히 놓고 맞춘 값)
|
||||
- 런타임 조정: **옵션 패널 → 선가중치 → 표시 배율**, 또는 `setLineweightScale(pxPerMm)`
|
||||
- 조정은 **재파싱 없이 즉시 반영**된다 (3-6 절)
|
||||
|
||||
> 시행착오 기록: 처음 8px/mm(96dpi 어림) → 손테스트 "얇다" 반려 → 정답지 캡처에서
|
||||
> 역산해 20px/mm → 실제 화면 대조 후 최종 11px/mm. 상수 추정이 두 번 빗나갔고,
|
||||
> 그래서 값을 코드에서 빼 옵션으로 노출했다.
|
||||
|
||||
### 3-2. 0.25mm 이하는 헤어라인 유지 — **회귀 방지 장치**
|
||||
|
||||
`-3`(Default)·`-1`(ByLayer → 레이어도 Default)이 도면 대부분을 차지한다.
|
||||
이것까지 2px 로 그리면 **굵기를 지정한 적 없는 기존 도면이 통째로 두꺼워진다.**
|
||||
|
||||
→ `LW_HAIRLINE_MM = 0.25` 이하는 기존 병합 배치에 그대로 남긴다.
|
||||
그 결과 대조 도면 4종은 **픽셀 단위로 이전과 동일**하게 렌더링된다.
|
||||
|
||||
### 3-3. 굵은 선만 별도 배치 — 성능 보존
|
||||
|
||||
전체를 fat line 으로 바꾸면 세그먼트당 인스턴스 8정점이라 대형 도면에서 감당이 안 된다.
|
||||
`dash|lineweight` 조합으로 버킷을 나눠 **굵기가 있는 버킷만** 별도 메쉬로 뽑는다.
|
||||
|
||||
| 버킷 | 메쉬 | 비고 |
|
||||
|------|------|------|
|
||||
| 실선 + 헤어라인 | 기존 병합 `LineSegments` | 변경 없음 |
|
||||
| 점선 + 헤어라인 | `LineSegments` + `LineDashedMaterial` | 변경 없음 |
|
||||
| 굵기 있음 | `LineSegments2` + `LineMaterial` | 신규 (스크린스페이스 쿼드) |
|
||||
|
||||
한 버킷이 `LW_MAX_FAT_SEGS`(40만) 세그먼트를 넘으면 헤어라인으로 폴백하고
|
||||
`console.warn` 을 남긴다. 대형 측량 도면에서 GPU/힙이 터지는 것을 막는 상한.
|
||||
|
||||
### 3-4. 기존 기능을 깨지 않는다
|
||||
|
||||
새 메쉬 타입이 들어오면서 다음 두 기능이 조용히 망가질 수 있었다. 둘 다 대응했다.
|
||||
|
||||
- **레이어 토글** — 인스턴스 지오메트리는 인덱스 재작성이 불가
|
||||
- **선택 하이라이트** — 색상 배열이 여러 버퍼로 쪼개짐
|
||||
|
||||
### 3-6. 배율 조정은 리빌드 없이
|
||||
|
||||
헤어라인 컷오프가 **mm 값**(0.25mm)이라 배율이 바뀌어도 어떤 세그먼트가 어느 버킷에
|
||||
들어가는지는 변하지 않는다. 모든 굵기가 같은 배수로 움직일 뿐이다.
|
||||
|
||||
→ 각 fat 배치가 자기 굵기를 **mm 로 기억**(`_fatBufs[].lwMm`)하고,
|
||||
`setLineweightScale()` 은 `material.linewidth` 만 다시 쓴다. 37MB 도면에서도 슬라이더를
|
||||
끄는 동안 지연이 없다.
|
||||
|
||||
반면 **표시 on/off** 는 굵기가 0이 되어 버킷 구성이 바뀌므로 재빌드가 필요하다.
|
||||
|
||||
### 3-5. 표시 on/off — AutoCAD LWDISPLAY 와 동일하게
|
||||
|
||||
굵기 표시는 CAD 에서 원래 켜고 끌 수 있는 옵션이다. 도면의 헤더 값을 기본으로 따르되
|
||||
사용자가 강제할 수 있어야 한다.
|
||||
|
||||
---
|
||||
|
||||
## 4. 조치 사항
|
||||
|
||||
### 4-1. 파서 — `hmwebviewer/rust/dwg-wasm/src/lib.rs`
|
||||
|
||||
원시 i16 값(1/100 mm, `-1` ByLayer · `-2` ByBlock · `-3` Default)을 세 군데에 추가.
|
||||
|
||||
| 함수 | 추가 필드 |
|
||||
|------|-----------|
|
||||
| `common_json` → `entityHeader` | `lineWeight` |
|
||||
| `tables_value` → `layers[]` | `lineWeight` |
|
||||
| `vars_value` | `lwdisplay`, `celweight` |
|
||||
|
||||
재빌드 + 산출물 복사:
|
||||
|
||||
```bash
|
||||
cd D:\MYCLAUDE_PROJECT\hmwebviewer
|
||||
npm run build:dwg-wasm
|
||||
cp src/viewer2d/acadrust-dwg/acadrust_dwg* \
|
||||
../dwg-dxf-viewer-sample/src/viewer2d/acadrust-dwg/
|
||||
```
|
||||
|
||||
검증(노면 도면):
|
||||
|
||||
```
|
||||
vars.lwdisplay = true vars.celweight = 29
|
||||
entity lineWeight = { -3:15176, -1:2613, 13:8794, 35:37944, 40:119, 50:849 }
|
||||
```
|
||||
|
||||
### 4-2. 렌더러 — `src/viewer2d/Viewer2D.js`
|
||||
|
||||
| 추가/변경 | 내용 |
|
||||
|-----------|------|
|
||||
| `_lwPx(entity, inheritedPx)` | ByLayer→LAYER 테이블, ByBlock→INSERT 굵기, Default→0.25mm 해석 후 픽셀 환산. 0.25mm 이하는 `0`(헤어라인) 반환 |
|
||||
| `_buildLayerMap` | 레이어 lineweight 를 핸들·이름 두 키로 보관 (DXF 레이어는 핸들이 없음) |
|
||||
| `pushSeg` | 세그먼트를 `dash|lineweight` 버킷으로 분기 + 엔티티별 색상 구간(`meta.spans`) 기록 |
|
||||
| 조립부 | 굵은 버킷 → `LineSegments2` + `LineMaterial(worldUnits:false)`. 캡 초과 시 헤어라인 폴백 |
|
||||
| `_registerFat` / `_applyLayerVisibility` | 보이는 인스턴스만 버퍼 앞으로 압축 후 `geometry.instanceCount` 축소. 원본 배열 보존, 이동 위치는 `slotOf` 에 기록 |
|
||||
| `_paintMeta` / `_paintSpan` | 헤어라인 구간 + 모든 버킷 구간을 함께 칠함. 레이어 토글로 재배치되면 `slotOf` 경유로 다시 칠함 |
|
||||
| `_insertEntities` | 자식마다 `_lwPx(child, insertLwPx)` — ByBlock 이 INSERT 굵기를 상속. 루프 종료 시 호출자 값 복구 |
|
||||
| `_onResize` | `LineMaterial.resolution` 재설정 (픽셀 폭 기준이 캔버스 크기라서 필수) |
|
||||
| `setLineweightEnabled(on)` / `getLineweightEnabled()` | 표시 스위치. `null` = 도면의 LWDISPLAY 를 따름 |
|
||||
|
||||
### 4-3. UI
|
||||
|
||||
툴바 **옵션** 버튼 → `옵션 (Options)` 패널 (`index.html` · `src/main.ts`).
|
||||
|
||||
| 항목 | 동작 |
|
||||
|------|------|
|
||||
| 표시 (LWDISPLAY) | on/off. 체크 해제 시 전부 헤어라인 (재빌드) |
|
||||
| 표시 배율 | 슬라이더 + 숫자 입력 (px/mm). 즉시 반영 |
|
||||
| 환산 표시 | 그 도면이 실제로 쓰는 굵기만 `0.35mm → 3.9px` 식으로 표기 |
|
||||
| ↺ 기본값 | 배율·표시·그리드·줌속도 초기화 |
|
||||
|
||||
설정은 **IndexedDB** (`hmw-viewer` DB → `options` 스토어)에 저장한다
|
||||
([`../src/optionsStore.ts`](../src/optionsStore.ts)). 키: `lineweightScale`,
|
||||
`lineweightOn`, `grid`, `zoomSpeed`. 스토리지가 막혀 있어도 조용히 기본값으로 동작한다.
|
||||
|
||||
속성 패널에는 `선가중치 (Lineweight)` 행이 있다 (`src/propertyInspector.ts`).
|
||||
`-1`→`BYLAYER`, `-2`→`BYBLOCK`, `-3`→`DEFAULT (0.25mm)`, 그 외 `0.35mm` 형식.
|
||||
|
||||
### 4-4. 배포
|
||||
|
||||
```bash
|
||||
./node_modules/.bin/vite build --outDir dist2 --emptyOutDir false
|
||||
```
|
||||
|
||||
→ `dist2/assets/index-D3FqDGwP.js`, `acadrust_dwg_bg-DmCEpFBu.wasm`.
|
||||
`--emptyOutDir false` 는 필수 ([`deploy-dist2-static-build.md`](./deploy-dist2-static-build.md) 참조).
|
||||
**커밋/푸시는 하지 않았다** — 공유 원격이라 사용자 확인 필요.
|
||||
|
||||
---
|
||||
|
||||
## 5. 검증
|
||||
|
||||
헤드리스 Chrome(SwiftShader) 1400×1000, 노면 도면, 동일 카메라(30단계 확대)에서
|
||||
`gl.readPixels` 로 직접 계측.
|
||||
|
||||
### 5-1. 굵기 반영
|
||||
|
||||
| | 밝은 픽셀 수 | 중앙 스캔라인 최대 cyan 폭 |
|
||||
|--|--|--|
|
||||
| 선가중치 **ON** | 137,528 | **5 px** |
|
||||
| 선가중치 **OFF** | 122,245 | 2 px |
|
||||
|
||||
0.50mm × 8 = 4px + 안티에일리어싱 → 5px. 설계값과 일치.
|
||||
|
||||
### 5-2. 레이어 토글 무손실
|
||||
|
||||
`도로 가장자리` 레이어 끄기 → 켜기:
|
||||
|
||||
```
|
||||
기준 {"lit":137528,"cyan":12162,"accent":6741}
|
||||
숨김 {"lit":136735,"cyan":12553,"accent":5776}
|
||||
복원 {"lit":137528,"cyan":12162,"accent":6741} ← 기준과 완전 일치
|
||||
```
|
||||
|
||||
### 5-3. 선택 하이라이트
|
||||
|
||||
굵은 선(0.35mm LWPOLYLINE, 레이어 `비탈면방향`) 클릭:
|
||||
|
||||
```
|
||||
LWPOLYLINE · #151257
|
||||
레이어 비탈면방향 · 색상 BYLAYER · 선가중치 (Lineweight) 0.35mm
|
||||
```
|
||||
|
||||
cyan 픽셀 수가 감소(11502→11486) → fat 배치의 정점이 강조색으로 재도색됨을 확인.
|
||||
|
||||
### 5-4. 도면이 실제로 들고 있는 수치
|
||||
|
||||
굵기는 **레이어가 아니라 엔티티**에 들어 있다. 23개 레이어 lineweight 는 **전부 `-3`
|
||||
(Default)** 이라 ByLayer 로는 아무 정보도 나오지 않는다.
|
||||
|
||||
| 레이어 | ACI | lineweight | 개수 |
|
||||
|---|---|---|---|
|
||||
| 도로 가장자리 | 1 (빨강) | **50 = 0.50mm** | 18 |
|
||||
| 도로마킹 | 255 / 7 / 2 / 4 | 50 = 0.50mm | 799 |
|
||||
| 부체도로 가장자리 | 20 | 50 = 0.50mm | 32 |
|
||||
| 비탈면방향 | 140 / 150 | 35 = 0.35mm | 34,758 |
|
||||
| 노면측구 | 4 (시안) | 35 = 0.35mm | 303 |
|
||||
| 시작·끝라인 / Drawing확폭 | 4 / 6 / 2 / 3 | 40 = 0.40mm | 105 |
|
||||
| SubContour · MainContour | 3 / 6 | 13 = 0.13mm | 8,794 |
|
||||
| **도로면 (MESH 삼각망)** | 7 | **-3 Default** | 1 (185,444 faces) |
|
||||
| Station (중심선·라벨) | 1 (빨강) | -1 → 레이어 -3 → Default | 1,082 |
|
||||
|
||||
주의: 화면의 **빨간 선이 두 종류**다. 굵은 쪽이 `도로 가장자리`(0.50mm), 도로 한가운데를
|
||||
지나는 얇은 쪽이 `Station` 중심선(Default → 헤어라인). 정답지에서 굵게 나오는 것은 전자다.
|
||||
|
||||
### 5-5. 정답지 대조 (배율 확정 근거)
|
||||
|
||||
lineweight 는 줌과 무관한 화면 픽셀이므로, 두 캡처의 **절대 픽셀 두께**를 그대로 비교한다.
|
||||
|
||||
| 배율 | `도로 가장자리` 0.50mm | `노면측구` 0.35mm (헤드리스 실측) |
|
||||
|--|--|--|
|
||||
| 8 px/mm (최초, 반려) | 4 px | 2–3 px |
|
||||
| 20 px/mm (캡처 역산) | 10 px | 7 px |
|
||||
| **11 px/mm (현재 기본값)** | **5.5 px** | **3–4 px** |
|
||||
| 25 px/mm (참고) | 12.5 px | 8–9 px |
|
||||
|
||||
캡처 이미지에서 역산한 20 은 실제 화면에서 과했다 — 캡처 DPI 와 사용자 모니터가 달라서다.
|
||||
최종값은 사용자가 뷰어와 AutoCAD 를 나란히 놓고 맞춘 **11**. 이래서 상수로 못 박지 않고
|
||||
옵션으로 뺐다.
|
||||
|
||||
### 5-6. 회귀 없음
|
||||
|
||||
- `npx tsc --noEmit` 통과
|
||||
- `npm run build` 통과
|
||||
- 대조 도면 4종: 굵기 전부 Default → **화면 변화 없음**(설계 3-2 의도대로)
|
||||
|
||||
---
|
||||
|
||||
## 6. 남은 과제
|
||||
|
||||
1. **배율 기본값은 환경 의존** — 11 은 특정 모니터에서 맞춘 값이다. 다른 화면에서는
|
||||
옵션 패널로 다시 맞춰야 한다. `devicePixelRatio` 로 자동 보정하는 것은 검토만 하고
|
||||
넣지 않았다(캡처·원격 데스크톱 등에서 오히려 어긋난다).
|
||||
2. **ByBlock 근사** — 블록 자식의 `-2` 는 INSERT 굵기를 상속하지만, 중첩 블록에서
|
||||
중간 INSERT 가 `-2` 인 경우까지는 추적하지 않는다(점선 처리와 동일한 기존 정책).
|
||||
3. **DXF 레이어 굵기 없음** — `dxf-parser` 의 LAYER 핸들러가 코드 370 을 무시한다.
|
||||
DXF 는 엔티티 자체 굵기(`entity.lineweight`)만 반영되고 ByLayer 는 Default 로 떨어진다.
|
||||
4. **`celweight` 미사용** — 헤더 CELWEIGHT 를 값이 아니라 DWG 5비트 테이블 인덱스로
|
||||
내보내고 있다(노면 도면에서 `29` = ByLayer 인덱스). 현재 렌더링에 쓰지 않으므로
|
||||
방치했으나, 쓰게 되면 `LineWeight::from_dwg_index` 변환을 파서 쪽에 넣어야 한다.
|
||||
5. **40만 세그먼트 캡** — 초과 시 조용히 얇아지는 대신 `console.warn` 만 남는다.
|
||||
상태 표시줄 등 사용자에게 보이는 알림이 필요할 수 있다.
|
||||
|
||||
---
|
||||
|
||||
## 7. 참고
|
||||
|
||||
- 렌더러: [`../src/viewer2d/Viewer2D.js`](../src/viewer2d/Viewer2D.js) —
|
||||
`_lwPx`, `_registerFat`, `_applyLayerVisibility`, `_paintMeta`, `setLineweightEnabled`
|
||||
- 속성 패널: [`../src/propertyInspector.ts`](../src/propertyInspector.ts) — `formatLineweight`
|
||||
- 파서: `hmwebviewer/rust/dwg-wasm/src/lib.rs` — `common_json`, `tables_value`, `vars_value`
|
||||
- 폭(width)과의 차이: `_segWidths` / `_widePolyMesh` (도면단위 실폭)
|
||||
- 같은 유형의 선례(파서 필드 누락 → 렌더 불가): [`subdmesh-rendering.md`](./subdmesh-rendering.md)
|
||||
- 배포 절차: [`deploy-dist2-static-build.md`](./deploy-dist2-static-build.md)
|
||||
@@ -0,0 +1,162 @@
|
||||
# SubDMesh(MESH) 렌더링
|
||||
|
||||
| 항목 | 내용 |
|
||||
|------|------|
|
||||
| 증상 | `대산당진 2공구_노면_*.dwg` 의 노면/부체도로면이 뷰어에 전혀 나오지 않음 |
|
||||
| 원인 | ① dwg-wasm 이 MESH 엔티티를 parseResult 에 아예 내보내지 않음 ② acadrust 의 배열 개수 상한(100,000)이 큰 메쉬를 잘라내 뒤따르는 face/edge 목록까지 깨뜨림 |
|
||||
| 대상 클래스 | `AcDbSubDMesh` (DXF 엔티티명 `MESH`, AutoCAD 2010+) |
|
||||
| 수정일 | 2026-08-04 |
|
||||
| 반영 상태 | 파서(wasm)·속성 패널·문서는 이 커밋에 포함. **`Viewer2D.js` 렌더러 hunk 는 아직 미커밋** — 같은 파일에서 진행 중인 lineweight/fat-line 리팩터와 hunk 가 겹쳐 분리가 안 된다. 렌더러 원본은 본가 hmwebviewer `35f5b1c` 에 들어가 있고, 이 저장소에는 작업 트리에만 있다. 그 리팩터가 커밋될 때 같이 들어간다. |
|
||||
|
||||
---
|
||||
|
||||
## 1. 무엇이 안 나왔나
|
||||
|
||||
문제 도면(AC1032 / AutoCAD 2018)에는 MESH 엔티티가 9개 있다.
|
||||
|
||||
| handle | layer | 정점 | 면 | 모서리 |
|
||||
|--------|-------|------|----|--------|
|
||||
| 4188 | 도로면 | 105,497 | 185,444 | 290,931 |
|
||||
| 4189 | 부체도로면 | 11,712 | 12,568 | 24,226 |
|
||||
| 296564 … 297665 | 연결부 (7개) | 28 ~ 53 | 25 ~ 47 | 51 ~ 96 |
|
||||
|
||||
파싱 결과 엔티티 히스토그램에는 `MESH` 가 **0개** 였다. 즉 뷰어의 렌더 문제가 아니라
|
||||
**파서 출력에 데이터 자체가 없었다.**
|
||||
|
||||
---
|
||||
|
||||
## 2. 원인 두 겹
|
||||
|
||||
### 2-1. dwg-wasm 이 MESH 를 버리고 있었다
|
||||
|
||||
`rust/dwg-wasm/src/lib.rs` 의 `entity_to_json()` 마지막 arm:
|
||||
|
||||
```rust
|
||||
// Not rendered by Viewer2D (leaders, rays, meshes, …) — skip.
|
||||
_ => {}
|
||||
```
|
||||
|
||||
acadrust 자체는 MESH 를 **완전히 읽고 있었다** (`OBJ_MESH` → `entities::read_mesh()` →
|
||||
`EntityType::Mesh`). JSON 직렬화 단계에서만 빠져 있었다.
|
||||
|
||||
### 2-2. acadrust 의 배열 상한이 큰 메쉬를 깨뜨렸다
|
||||
|
||||
`object_reader/mod.rs` 에는 손상 데이터 방어용 상한이 있다.
|
||||
|
||||
```rust
|
||||
const MAX_ARRAY_COUNT: i32 = 100_000;
|
||||
fn safe_count(raw: i32) -> i32 { raw.max(0).min(MAX_ARRAY_COUNT) }
|
||||
```
|
||||
|
||||
`read_mesh()` 가 이 상한을 정점 개수에 그대로 쓰고 있었다. 도로면 메쉬의 실제 정점은
|
||||
105,497개 → 100,000 으로 잘림 → **5,497개 분량의 비트를 안 읽고 다음 필드로 넘어감** →
|
||||
그 뒤의 face/edge/crease 목록이 통째로 어긋난다. 진단 출력이 이렇게 나왔다.
|
||||
|
||||
```
|
||||
MESH #1 verts=100000 faces=14 edges=3
|
||||
first face sizes: [64, 0, 64, 23, 0, 0, 0, 15]
|
||||
```
|
||||
|
||||
정점 수가 그럴듯해 보여서 에러로 드러나지 않는 종류의 고장이다. 정상 TIN 이면 face 는 전부
|
||||
3정점이어야 한다.
|
||||
|
||||
**수정**: `read_mesh()` 전용으로 “남은 스트림 비트 수” 기준 상한을 쓴다
|
||||
(`stream_bounded_count`). 항목 1개의 최소 인코딩 길이(3BD = 6비트, BitLong = 2비트)로
|
||||
남은 비트를 나눈 값이 상한이므로, 무제한 할당 방어는 그대로 유지되면서 정상 도면은
|
||||
잘리지 않는다.
|
||||
|
||||
```
|
||||
MESH #1 verts=105497 faces=185444 edges=290931
|
||||
first face sizes: [3, 3, 3, 3, 3, 3, 3, 3]
|
||||
```
|
||||
|
||||
> acadrust 는 MPL-2.0. 이 저장소 기준으로 **처음 생긴 로컬 패치**다. MPL 은 파일 단위
|
||||
> copyleft 이므로 해당 파일이 MPL 로 남고 소스가 저장소에 포함되면 요건을 만족한다.
|
||||
> `rust/dwg-wasm/Cargo.toml` · `src/lib.rs` 의 "consumed unmodified" 문구를 갱신했다.
|
||||
|
||||
---
|
||||
|
||||
## 3. parseResult 스키마
|
||||
|
||||
MESH 는 **평면 숫자 배열**로 나간다. `{x,y,z}` 객체와 중첩 face 배열을 쓰면 같은 숫자에
|
||||
대해 JSON 이 약 3배로 부푼다 (이 도면 기준 전체 JSON 116MB → 130MB 로 끝난 이유).
|
||||
|
||||
```jsonc
|
||||
{
|
||||
"type": "MESH",
|
||||
"handle": { "value": 4188 }, "layer": "도로면", "entityHeader": { … },
|
||||
"vertices": [x, y, z, x, y, z, …], // 평면
|
||||
"vertexCount": 105497,
|
||||
"faceList": [n, i0, …, i(n-1), n, …],// DXF group 93 배열과 같은 형태 (n각형 허용)
|
||||
"faceCount": 185444,
|
||||
"edges": [a, b, a, b, …], // acadrust 가 중복 제거해 준 모서리 목록
|
||||
"subdivisionLevel": 0,
|
||||
"blendCrease": true,
|
||||
"meshVersion": 2
|
||||
}
|
||||
```
|
||||
|
||||
범위를 벗어난 인덱스는 `u32::MAX` 로 나가므로, 소비 측 경계 검사에서 그 모서리 하나만
|
||||
버려진다 (엉뚱한 정점으로 감기지 않는다).
|
||||
|
||||
---
|
||||
|
||||
## 4. 렌더링
|
||||
|
||||
`Viewer2D._meshSegs()` 가 면 wireframe 을 선분으로 뱉는다. AutoCAD 의 2D 와이어프레임
|
||||
표시와 같은 그림이다.
|
||||
|
||||
- **`edges` 우선.** 이미 중복이 제거돼 있어 삼각형이 공유하는 모서리를 한 번만 그린다.
|
||||
이 도면에서 315,633 선분 (faceList 로 그리면 741,072 → 약 1.8배).
|
||||
- `edges` 가 비어 있으면 `faceList` 로 폴백. 두 경로의 그림 범위(extent)는 동일함을 확인.
|
||||
- z 는 선분 양 끝 정점 표고의 중간값. 이 도면은 LWPOLYLINE·TEXT 도 이미 z 0~68 대역에
|
||||
있으므로 메쉬만 위로 뜨지 않는다.
|
||||
- 세 군데 디스패치 모두에 연결: 모델 공간 switch, 페이퍼 뷰포트 통과 switch,
|
||||
`_insertEntities`(블록 안의 MESH, `xf` 로 좌표 변환).
|
||||
|
||||
### 한계
|
||||
|
||||
`subdivisionLevel > 0` 인 메쉬는 **기본(control) 메쉬만** 그린다. AutoCAD 는 그 정점들을
|
||||
Catmull-Clark 로 세분한 결과를 보여주므로, 그런 메쉬는 AutoCAD 보다 각져 보인다.
|
||||
문제 도면은 9개 전부 `subdivisionLevel = 0` 이라 차이가 없다.
|
||||
|
||||
`POLYFACE MESH` / `POLYGON MESH`(구형 POLYLINE flag 16/64)는 별개 엔티티이며 이 작업
|
||||
범위 밖이다.
|
||||
|
||||
---
|
||||
|
||||
## 5. 검증 도구
|
||||
|
||||
```bash
|
||||
# 네이티브에서 메쉬가 제대로 읽히는지 (hmwebviewer 쪽)
|
||||
cd D:\MYCLAUDE_PROJECT\hmwebviewer\rust\dwg-wasm
|
||||
cargo run --release --bin meshprobe -- <file.dwg>
|
||||
```
|
||||
|
||||
face 크기가 전부 3(또는 4)이 아니라 `[64, 0, 64, 23, …]` 처럼 들쭉날쭉하면 위 2-2 의
|
||||
스트림 어긋남을 다시 의심한다.
|
||||
|
||||
---
|
||||
|
||||
## 6. wasm 재빌드
|
||||
|
||||
MESH 지원은 wasm 안에 들어 있으므로 재빌드가 필요하다. 빌드 스크립트는 hmwebviewer 에만
|
||||
있고, 산출물을 이 저장소로 복사한다.
|
||||
|
||||
```bash
|
||||
cd D:\MYCLAUDE_PROJECT\hmwebviewer
|
||||
npm run build:dwg-wasm # → hmwebviewer/src/viewer2d/acadrust-dwg/
|
||||
cp src/viewer2d/acadrust-dwg/acadrust_dwg* \
|
||||
../dwg-dxf-viewer-sample/src/viewer2d/acadrust-dwg/
|
||||
```
|
||||
|
||||
이후 정적 배포는 [`deploy-dist2-static-build.md`](./deploy-dist2-static-build.md) 절차를 따른다.
|
||||
|
||||
---
|
||||
|
||||
## 7. 참고
|
||||
|
||||
- 렌더러: [`../src/viewer2d/Viewer2D.js`](../src/viewer2d/Viewer2D.js) — `_meshSegs`, `case 'MESH'`
|
||||
- 속성 패널: [`../src/propertyInspector.ts`](../src/propertyInspector.ts) — `case 'MESH'`
|
||||
- 직렬화: `hmwebviewer/rust/dwg-wasm/src/lib.rs` — `EntityType::Mesh`
|
||||
- 비트 파서: `hmwebviewer/rust/acadrust/src/io/dwg/dwg_stream_readers/object_reader/entities.rs` — `read_mesh`, `stream_bounded_count`
|
||||
+135
@@ -14,6 +14,45 @@
|
||||
* { box-sizing: border-box; }
|
||||
html, body { margin: 0; height: 100%; background: var(--bg); color: var(--ink); font-family: var(--sans); }
|
||||
#app { position: fixed; inset: 0; }
|
||||
|
||||
/* ── 상단 로딩 프로그레스 바 (src/topProgress.ts 가 구동) ───────────────
|
||||
.bar : 실제 진행률. width 트랜지션 = 메인 스레드 의존.
|
||||
.sweep : WASM 파싱 / Viewer2D.load() 같은 동기 블로킹 구간용. transform
|
||||
키프레임은 컴포지터 스레드에서 돌기 때문에 메인 스레드가 멈춰
|
||||
있어도 계속 흐른다 — 그 구간에 줄 수 있는 유일한 피드백. */
|
||||
#progress {
|
||||
position: fixed; top: 0; left: 0; right: 0; height: 3px; z-index: 100;
|
||||
pointer-events: none; overflow: hidden;
|
||||
opacity: 0; transition: opacity .3s ease .15s;
|
||||
}
|
||||
#progress.on { opacity: 1; transition-delay: 0s; }
|
||||
#progress .bar {
|
||||
position: absolute; top: 0; bottom: 0; left: 0; width: 0;
|
||||
background: linear-gradient(90deg, var(--accent), #58a6ff 55%, var(--wasm));
|
||||
box-shadow: 0 0 10px rgba(63,185,80,.65), 0 0 4px rgba(88,166,255,.5);
|
||||
transition: width .28s cubic-bezier(.25,.8,.25,1);
|
||||
}
|
||||
#progress.err .bar {
|
||||
background: var(--danger);
|
||||
box-shadow: 0 0 10px rgba(248,81,73,.7);
|
||||
}
|
||||
#progress .sweep {
|
||||
position: absolute; top: 0; bottom: 0; left: 0; width: 34%;
|
||||
background: linear-gradient(90deg, transparent, rgba(230,237,243,.9), transparent);
|
||||
transform: translateX(-105%); will-change: transform; opacity: 0;
|
||||
}
|
||||
#progress.busy .sweep {
|
||||
opacity: 1;
|
||||
animation: pr-sweep 1.15s cubic-bezier(.4,0,.2,1) infinite;
|
||||
}
|
||||
@keyframes pr-sweep {
|
||||
from { transform: translateX(-105%); }
|
||||
to { transform: translateX(400%); }
|
||||
}
|
||||
@media (prefers-reduced-motion: reduce) {
|
||||
#progress .sweep { animation: none; }
|
||||
#progress .bar { transition: none; }
|
||||
}
|
||||
#toolbar {
|
||||
position: fixed; top: 12px; left: 12px; right: 12px; z-index: 10;
|
||||
display: flex; flex-wrap: wrap; gap: 8px; align-items: center; pointer-events: none;
|
||||
@@ -26,7 +65,29 @@
|
||||
button:hover, label.btn:hover { border-color: var(--accent); }
|
||||
button.primary { background: #238636; border-color: #2ea043; }
|
||||
button.wasm { border-color: var(--wasm); color: var(--wasm); }
|
||||
/* 켜져 있는 토글 버튼 (2.5D 보기 등) */
|
||||
#toolbar > button.on { background: #1f6feb; border-color: #58a6ff; color: #fff; }
|
||||
.opt-row.disabled { opacity: .45; pointer-events: none; }
|
||||
label.btn input { display: none; }
|
||||
/* 옵션 패널 — 값은 IndexedDB(hmw-viewer/options)에 저장된다 */
|
||||
#optBody { padding: 12px 14px; overflow: auto; font-size: 12px; color: var(--ink); }
|
||||
.opt-sec { margin-bottom: 16px; }
|
||||
.opt-sec > h4 {
|
||||
margin: 0 0 8px; font-size: 11px; font-weight: 700; letter-spacing: .05em;
|
||||
text-transform: uppercase; color: var(--muted);
|
||||
}
|
||||
.opt-row { display: flex; align-items: center; gap: 8px; margin-bottom: 8px; }
|
||||
.opt-row > label { flex: 1; color: var(--ink); }
|
||||
.opt-row input[type=range] { flex: 1; min-width: 90px; accent-color: var(--accent); }
|
||||
.opt-row input[type=number] {
|
||||
width: 58px; background: #0d1117; color: var(--ink);
|
||||
border: 1px solid var(--line); border-radius: 6px; padding: 3px 6px;
|
||||
font: 12px var(--mono); text-align: right;
|
||||
}
|
||||
.opt-row input[type=checkbox] { width: 15px; height: 15px; accent-color: var(--accent); }
|
||||
.opt-unit { font: 11px var(--mono); color: var(--muted); }
|
||||
.opt-note { font: 11px var(--mono); color: var(--accent); line-height: 1.6; word-break: keep-all; }
|
||||
.opt-help { font-size: 11px; color: var(--muted); line-height: 1.5; margin: 4px 0 0; }
|
||||
#status {
|
||||
margin-left: auto; font: 12px var(--mono); color: var(--muted);
|
||||
background: rgba(22,27,34,.85); border: 1px solid var(--line);
|
||||
@@ -130,6 +191,7 @@
|
||||
|
||||
#properties { right: 12px; }
|
||||
#layers { right: 344px; display: none; }
|
||||
#options { right: 676px; width: 340px; height: auto; max-height: 70vh; display: none; }
|
||||
|
||||
#propBody { flex: 1; overflow-y: auto; display: flex; flex-direction: column; }
|
||||
#layerBody { flex: 1; overflow-y: auto; display: flex; flex-direction: column; }
|
||||
@@ -173,7 +235,9 @@
|
||||
<button id="sampleDxf" class="primary" type="button" title="dxf-parser">Sample DXF</button>
|
||||
<div id="spaces" title="Model Space / Paper Space (Layout)"></div>
|
||||
<button id="fit" type="button">Fit (F)</button>
|
||||
<button id="view25Btn" type="button" title="2.5D 보기 — Top 뷰를 풀고 기울여서 등고선 등의 높낮이(Z)를 본다. 왼쪽 드래그=회전, 가운데/오른쪽 드래그=이동">2.5D 보기</button>
|
||||
<button id="theme" type="button">Theme</button>
|
||||
<button id="optionsBtn" type="button" title="표시 옵션 (선가중치 · 그리드 · 줌)">옵션</button>
|
||||
<button id="layersBtn" type="button">Layers</button>
|
||||
<button id="propsBtn" type="button">Props (속성)</button>
|
||||
<div id="status">ready</div>
|
||||
@@ -209,6 +273,71 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 옵션 (Options) 패널 — 설정은 IndexedDB 에 저장 -->
|
||||
<div id="options" class="cad-panel">
|
||||
<div class="hdr">
|
||||
<h3><span>⚙️</span> 옵션 (Options)</h3>
|
||||
<div class="hdr-actions">
|
||||
<button id="optReset" type="button" title="기본값으로">↺ 기본값</button>
|
||||
<button id="collapseOptBtn" class="hdr-btn collapse-btn" type="button" title="접기">▾</button>
|
||||
<button id="closeOptBtn" class="hdr-btn" type="button" title="닫기">✕</button>
|
||||
</div>
|
||||
</div>
|
||||
<div id="optBody">
|
||||
<div class="opt-sec">
|
||||
<h4>선가중치 (Lineweight)</h4>
|
||||
<div class="opt-row">
|
||||
<label for="optLwOn">표시 (LWDISPLAY)</label>
|
||||
<input id="optLwOn" type="checkbox" />
|
||||
</div>
|
||||
<div class="opt-row">
|
||||
<label for="optLwScale">표시 배율</label>
|
||||
<input id="optLwScale" type="range" min="2" max="60" step="0.5" value="11" />
|
||||
<input id="optLwScaleNum" type="number" min="1" max="80" step="0.5" value="11" />
|
||||
<span class="opt-unit">px/mm</span>
|
||||
</div>
|
||||
<div id="optLwOut" class="opt-note">—</div>
|
||||
<p class="opt-help">
|
||||
AutoCAD "선가중치 설정 → 표시 배율"과 같다. 모델 공간에서 선가중치는 줌과
|
||||
무관한 화면 픽셀로 그려지므로, 화면 DPI에 맞춰 이 값을 조정한다.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="opt-sec">
|
||||
<h4>화면 (Display)</h4>
|
||||
<div class="opt-row">
|
||||
<label for="optGrid">그리드 표시</label>
|
||||
<input id="optGrid" type="checkbox" />
|
||||
</div>
|
||||
<div class="opt-row">
|
||||
<label for="optZoomSpeed">줌 속도</label>
|
||||
<input id="optZoomSpeed" type="range" min="0.2" max="3" step="0.1" value="1" />
|
||||
<input id="optZoomSpeedNum" type="number" min="0.1" max="5" step="0.1" value="1" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="opt-sec">
|
||||
<h4>2.5D 보기</h4>
|
||||
<div class="opt-row">
|
||||
<label for="opt25D">기울여 보기 (Top 해제)</label>
|
||||
<input id="opt25D" type="checkbox" />
|
||||
</div>
|
||||
<div id="optZRow" class="opt-row disabled">
|
||||
<label for="optZScale">높이 과장 (Z)</label>
|
||||
<input id="optZScale" type="range" min="1" max="50" step="0.5" value="1" />
|
||||
<input id="optZScaleNum" type="number" min="1" max="200" step="0.5" value="1" />
|
||||
<span class="opt-unit">×</span>
|
||||
</div>
|
||||
<p class="opt-help">
|
||||
도면은 이미 CAD 표고(Z)를 그대로 갖고 있다. 2.5D 는 같은 직교 카메라를
|
||||
남동 등각(SE Isometric)으로 돌려 그 높낮이를 보여준다 — 재파싱 없음.
|
||||
부지가 넓고 기복이 작아 평평하게 보이면 Z 과장을 올린다.
|
||||
<b>왼쪽 드래그 = 회전, 가운데·오른쪽 드래그 = 이동.</b>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 속성 (Properties) 패널 -->
|
||||
<div id="properties" class="cad-panel">
|
||||
<div class="hdr">
|
||||
@@ -235,6 +364,12 @@
|
||||
코드: <code>src/main.ts</code> ·
|
||||
지도: <a href="/docs/modules-dwg-dxf.html" target="_blank">docs/modules-dwg-dxf.html</a>
|
||||
</p>
|
||||
<!-- MPL-2.0 §3.2(b): recipients of the wasm must be told where the
|
||||
acadrust source can be obtained (unmodified 0.6.5, see the notice). -->
|
||||
<p style="margin:6px 0 0">
|
||||
오픈소스 고지: <a href="/licenses/THIRD-PARTY-NOTICES.md" target="_blank">THIRD-PARTY-NOTICES</a>
|
||||
(acadrust 0.6.5 · MPL-2.0 · <a href="https://crates.io/crates/acadrust/0.6.5" target="_blank" rel="noopener">source</a>)
|
||||
</p>
|
||||
</aside>
|
||||
|
||||
<script type="module" src="/src/main.ts"></script>
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
# Third-party notices
|
||||
|
||||
This viewer bundles third-party code. The notices below apply to the source
|
||||
tree **and** to the built site (`dist2/`, deployed at
|
||||
`https://dwg-dxf-viewer-sample.pages.dev/`), because the build embeds the
|
||||
components listed here.
|
||||
|
||||
Served copies of the license texts live under
|
||||
[`public/licenses/`](./public/licenses/) → `/licenses/…` on the deployed site.
|
||||
|
||||
---
|
||||
|
||||
## acadrust 0.6.5 — Mozilla Public License 2.0 — unmodified
|
||||
|
||||
| | |
|
||||
|---|---|
|
||||
| Component | `acadrust` (DWG/DXF parser, Rust) |
|
||||
| Version | 0.6.5 |
|
||||
| License | MPL-2.0 — full text: [`public/licenses/acadrust-MPL-2.0.txt`](./public/licenses/acadrust-MPL-2.0.txt) (`/licenses/acadrust-MPL-2.0.txt`) |
|
||||
| Upstream | https://github.com/hakanaktt/acadrust · https://crates.io/crates/acadrust/0.6.5 |
|
||||
| Upstream commit | `289a616da6c68518218594aa80802cbe7fa71309` (from the crate's `.cargo_vcs_info.json`) |
|
||||
| Crate SHA-256 | `5eaa72520f70eb6f7f09b06f44e1ed0d8fad5fa743364f2c3715c30df962ec7c` (the `Cargo.lock` checksum the build used) |
|
||||
| Author | Hakan AK |
|
||||
| Shipped as | compiled into `assets/acadrust_dwg_bg-*.wasm` (Executable Form) |
|
||||
|
||||
**This copy is not modified.** The `.wasm` is built from the published crate
|
||||
exactly as crates.io serves it.
|
||||
|
||||
### How to obtain the Source Code Form (MPL-2.0 §3.2)
|
||||
|
||||
Download the crate, which is the complete source compiled into the shipped
|
||||
`.wasm`:
|
||||
|
||||
```bash
|
||||
curl -L -o acadrust-0.6.5.crate https://static.crates.io/crates/acadrust/acadrust-0.6.5.crate
|
||||
tar xzf acadrust-0.6.5.crate
|
||||
```
|
||||
|
||||
or `cargo vendor` in any project that depends on `acadrust = "=0.6.5"`, or the
|
||||
upstream commit above.
|
||||
|
||||
---
|
||||
|
||||
## dwg-wasm — MIT
|
||||
|
||||
The wasm-bindgen wrapper that turns acadrust output into this viewer's
|
||||
`parseResult` (`hmwebviewer/rust/dwg-wasm/`). Our own code, MIT. MPL-2.0 §3.3
|
||||
permits distributing this Larger Work under different terms as long as the
|
||||
MPL-covered files above keep their license — which they do.
|
||||
|
||||
---
|
||||
|
||||
## Other components
|
||||
|
||||
| Component | License |
|
||||
|---|---|
|
||||
| three.js | MIT |
|
||||
| dxf-parser | MIT |
|
||||
| opentype.js | MIT |
|
||||
| NanumGothic (`public/fonts/`) | SIL Open Font License 1.1 |
|
||||
| Viewer2D / sample glue | MIT |
|
||||
@@ -0,0 +1,375 @@
|
||||
Mozilla Public License Version 2.0
|
||||
==================================
|
||||
|
||||
1. Definitions
|
||||
--------------
|
||||
|
||||
1.1. "Contributor"
|
||||
means each individual or legal entity that creates, contributes to
|
||||
the creation of, or owns Covered Software.
|
||||
|
||||
1.2. "Contributor Version"
|
||||
means the combination of the Contributions of others (if any) used
|
||||
by a Contributor and that particular Contributor's Contribution.
|
||||
|
||||
1.3. "Contribution"
|
||||
means Covered Software of a particular Contributor.
|
||||
|
||||
1.4. "Covered Software"
|
||||
means Source Code Form to which the initial Contributor has attached
|
||||
the notice in Exhibit A, the Executable Form of such Source Code
|
||||
Form, and Modifications of such Source Code Form, in each case
|
||||
including portions thereof.
|
||||
|
||||
1.5. "Incompatible With Secondary Licenses"
|
||||
means
|
||||
|
||||
(a) that the initial Contributor has attached the notice described
|
||||
in Exhibit B to the Covered Software; or
|
||||
|
||||
(b) that the Covered Software was made available under the terms of
|
||||
version 1.1 or earlier of the License, but not also under the
|
||||
terms of a Secondary License.
|
||||
|
||||
1.6. "Executable Form"
|
||||
means any form of the work other than Source Code Form.
|
||||
|
||||
1.7. "Larger Work"
|
||||
means a work that combines Covered Software with other material, in
|
||||
a separate file or files, that is not Covered Software.
|
||||
|
||||
1.8. "License"
|
||||
means this document.
|
||||
|
||||
1.9. "Licensable"
|
||||
means having the right to grant, to the maximum extent possible,
|
||||
whether at the time of the initial grant or subsequently, any and
|
||||
all of the rights conveyed by this License.
|
||||
|
||||
1.10. "Modifications"
|
||||
means any of the following:
|
||||
|
||||
(a) any file in Source Code Form that results from an addition to,
|
||||
deletion from, or modification of the contents of Covered
|
||||
Software; or
|
||||
|
||||
(b) any new file in Source Code Form that contains any Covered
|
||||
Software.
|
||||
|
||||
1.11. "Patent Claims" of a Contributor
|
||||
means any patent claim(s), including without limitation, method,
|
||||
process, and apparatus claims, in any patent Licensable by such
|
||||
Contributor that would be infringed, but for the grant of the
|
||||
License, by the making, using, selling, offering for sale, having
|
||||
made, import, or transfer of either its Contributions or its
|
||||
Contributor Version.
|
||||
|
||||
1.12. "Secondary License"
|
||||
means either the GNU General Public License, Version 2.0, the GNU
|
||||
Lesser General Public License, Version 2.1, the GNU Affero General
|
||||
Public License, Version 3.0, or any later versions of those
|
||||
licenses.
|
||||
|
||||
1.13. "Source Code Form"
|
||||
means the form of the work preferred for making modifications.
|
||||
|
||||
1.14. "You" (or "Your")
|
||||
means an individual or a legal entity exercising rights under this
|
||||
License. For legal entities, "You" includes any entity that
|
||||
controls, is controlled by, or is under common control with You. For
|
||||
purposes of this definition, "control" means (a) the power, direct
|
||||
or indirect, to cause the direction or management of such entity,
|
||||
whether by contract or otherwise, or (b) ownership of more than
|
||||
fifty percent (50%) of the outstanding shares or beneficial
|
||||
ownership of such entity.
|
||||
|
||||
2. License Grants and Conditions
|
||||
--------------------------------
|
||||
|
||||
2.1. Grants
|
||||
|
||||
Each Contributor hereby grants You a world-wide, royalty-free,
|
||||
non-exclusive license:
|
||||
|
||||
(a) under intellectual property rights (other than patent or trademark)
|
||||
Licensable by such Contributor to use, reproduce, make available,
|
||||
modify, display, perform, distribute, and otherwise exploit its
|
||||
Contributions, either on an unmodified basis, with Modifications, or
|
||||
as part of a Larger Work; and
|
||||
|
||||
(b) under Patent Claims of such Contributor to make, use, sell, offer
|
||||
for sale, have made, import, and otherwise transfer either its
|
||||
Contributions or its Contributor Version.
|
||||
|
||||
2.2. Effective Date
|
||||
|
||||
The licenses granted in Section 2.1 with respect to any Contribution
|
||||
become effective for each Contribution on the date the Contributor first
|
||||
distributes such Contribution.
|
||||
|
||||
2.3. Limitations on Grant Scope
|
||||
|
||||
The licenses granted in this Section 2 are the only rights granted under
|
||||
this License. No additional rights or licenses will be implied from the
|
||||
distribution or licensing of Covered Software under this License.
|
||||
Notwithstanding Section 2.1(b) above, no patent license is granted by a
|
||||
Contributor:
|
||||
|
||||
(a) for any code that a Contributor has removed from Covered Software;
|
||||
or
|
||||
|
||||
(b) for infringements caused by: (i) Your and any other third party's
|
||||
modifications of Covered Software, or (ii) the combination of its
|
||||
Contributions with other software (except as part of its Contributor
|
||||
Version); or
|
||||
|
||||
(c) under Patent Claims infringed by Covered Software in the absence of
|
||||
its Contributions.
|
||||
|
||||
This License does not grant any rights in the trademarks, service marks,
|
||||
or logos of any Contributor (except as may be necessary to comply with
|
||||
the notice requirements in Section 3.4).
|
||||
|
||||
2.4. Subsequent Licenses
|
||||
|
||||
No Contributor makes additional grants as a result of Your choice to
|
||||
distribute the Covered Software under a subsequent version of this
|
||||
License (see Section 10.2) or under the terms of a Secondary License (if
|
||||
permitted under the terms of Section 3.3).
|
||||
|
||||
2.5. Representation
|
||||
|
||||
Each Contributor represents that the Contributor believes its
|
||||
Contributions are its original creation(s) or it has sufficient rights
|
||||
to grant the rights to its Contributions conveyed by this License.
|
||||
|
||||
2.6. Fair Use
|
||||
|
||||
This License is not intended to limit any rights You have under
|
||||
applicable copyright doctrines of fair use, fair dealing, or other
|
||||
equivalents.
|
||||
|
||||
2.7. Conditions
|
||||
|
||||
Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted
|
||||
in Section 2.1.
|
||||
|
||||
3. Responsibilities
|
||||
-------------------
|
||||
|
||||
3.1. Distribution of Source Form
|
||||
|
||||
All distribution of Covered Software in Source Code Form, including any
|
||||
Modifications that You create or to which You contribute, must be under
|
||||
the terms of this License. You must inform recipients that the Source
|
||||
Code Form of the Covered Software is governed by the terms of this
|
||||
License, and how they can obtain a copy of this License. You may not
|
||||
attempt to alter or restrict the recipients' rights in the Source Code
|
||||
Form.
|
||||
|
||||
3.2. Distribution of Executable Form
|
||||
|
||||
If You distribute Covered Software in Executable Form then:
|
||||
|
||||
(a) such Covered Software must also be made available in Source Code
|
||||
Form, as described in Section 3.1, and You must inform recipients of
|
||||
the Executable Form how they can obtain a copy of such Source Code
|
||||
Form by reasonable means in a timely manner, at a charge no more
|
||||
than the cost of distribution to the recipient; and
|
||||
|
||||
(b) You may distribute such Executable Form under the terms of this
|
||||
License, or sublicense it under different terms, provided that the
|
||||
license for the Executable Form does not attempt to limit or alter
|
||||
the recipients' rights in the Source Code Form under this License.
|
||||
|
||||
3.3. Distribution of a Larger Work
|
||||
|
||||
You may create and distribute a Larger Work under terms of Your choice,
|
||||
provided that You also comply with the requirements of this License for
|
||||
the Covered Software. If the Larger Work is a combination of Covered
|
||||
Software with a work governed by one or more Secondary Licenses, and the
|
||||
Covered Software is not Incompatible With Secondary Licenses, this
|
||||
License permits You to additionally distribute such Covered Software
|
||||
under the terms of such Secondary License(s), so that the recipient of
|
||||
the Larger Work may, at their option, further distribute the Covered
|
||||
Software under the terms of either this License or such Secondary
|
||||
License(s).
|
||||
|
||||
3.4. Notices
|
||||
|
||||
You may not remove or alter the substance of any license notices
|
||||
(including copyright notices, patent notices, disclaimers of warranty,
|
||||
or limitations of liability) contained within the Source Code Form of
|
||||
the Covered Software, except that You may alter any license notices to
|
||||
the extent required to remedy known factual inaccuracies.
|
||||
|
||||
3.5. Application of Additional Terms
|
||||
|
||||
You may choose to offer, and to charge a fee for, warranty, support,
|
||||
indemnity or liability obligations to one or more recipients of Covered
|
||||
Software. However, You may do so only on Your own behalf, and not on
|
||||
behalf of any Contributor. You must make it absolutely clear that any
|
||||
such warranty, support, indemnity, or liability obligation is offered by
|
||||
You alone, and You hereby agree to indemnify every Contributor for any
|
||||
liability incurred by such Contributor as a result of warranty, support,
|
||||
indemnity or liability terms You offer. You may include additional
|
||||
disclaimers of warranty and limitations of liability specific to any
|
||||
jurisdiction.
|
||||
|
||||
4. Inability to Comply Due to Statute or Regulation
|
||||
---------------------------------------------------
|
||||
|
||||
If it is impossible for You to comply with any of the terms of this
|
||||
License with respect to some or all of the Covered Software due to
|
||||
statute, judicial order, or regulation then You must: (a) comply with
|
||||
the terms of this License to the maximum extent possible; and (b)
|
||||
describe the limitations and the code they affect. Such description must
|
||||
be placed in a text file included with all distributions of the Covered
|
||||
Software under the name "LEGAL", and included in all Covered Software
|
||||
distributed in Source Code Form. Except to the extent prohibited by
|
||||
statute or regulation, such description must be sufficiently detailed
|
||||
for a recipient of ordinary skill to be able to understand it.
|
||||
|
||||
5. Termination
|
||||
--------------
|
||||
|
||||
5.1. The rights granted under this License will terminate automatically
|
||||
if You fail to comply with any of its terms. However, if You become
|
||||
compliant, then the rights granted under this License from a particular
|
||||
Contributor are reinstated (a) provisionally, unless and until such
|
||||
Contributor explicitly and finally terminates Your grants, and (b) on an
|
||||
ongoing basis, if such Contributor fails to notify You of the
|
||||
non-compliance by some reasonable means prior to 60 days after You have
|
||||
come back into compliance. Moreover, Your grants from a particular
|
||||
Contributor are reinstated on an ongoing basis if such Contributor
|
||||
notifies You of the non-compliance by some reasonable means, this is the
|
||||
first time You have received notice of non-compliance with this License
|
||||
from such Contributor, and You become compliant prior to 30 days after
|
||||
Your receipt of the notice.
|
||||
|
||||
5.2. If You initiate litigation against any entity by asserting a patent
|
||||
infringement claim (excluding declaratory judgment actions,
|
||||
counter-claims, and cross-claims) alleging that a Contributor Version
|
||||
directly or indirectly infringes any patent, then the rights granted to
|
||||
You by any and all Contributors for the Covered Software under Section
|
||||
2.1 of this License shall terminate.
|
||||
|
||||
5.3. In the event of termination under Sections 5.1 or 5.2 above, all
|
||||
end user license agreements (excluding distributors and resellers) which
|
||||
have been validly granted by You or Your distributors under this License
|
||||
prior to termination shall survive termination.
|
||||
|
||||
************************************************************************
|
||||
* *
|
||||
* 6. Disclaimer of Warranty *
|
||||
* ------------------------- *
|
||||
* *
|
||||
* Covered Software is provided under this License on an "as is" *
|
||||
* basis, without warranty of any kind, either expressed, implied, or *
|
||||
* statutory, including, without limitation, warranties that the *
|
||||
* Covered Software is free of defects, merchantable, fit for a *
|
||||
* particular purpose or non-infringing. The entire risk as to the *
|
||||
* quality and performance of the Covered Software is with You. *
|
||||
* Should any Covered Software prove defective in any respect, You *
|
||||
* (not any Contributor) assume the cost of any necessary servicing, *
|
||||
* repair, or correction. This disclaimer of warranty constitutes an *
|
||||
* essential part of this License. No use of any Covered Software is *
|
||||
* authorized under this License except under this disclaimer. *
|
||||
* *
|
||||
************************************************************************
|
||||
|
||||
************************************************************************
|
||||
* *
|
||||
* 7. Limitation of Liability *
|
||||
* -------------------------- *
|
||||
* *
|
||||
* Under no circumstances and under no legal theory, whether tort *
|
||||
* (including negligence), contract, or otherwise, shall any *
|
||||
* Contributor, or anyone who distributes Covered Software as *
|
||||
* permitted above, be liable to You for any direct, indirect, *
|
||||
* special, incidental, or consequential damages of any character *
|
||||
* including, without limitation, damages for lost profits, loss of *
|
||||
* goodwill, work stoppage, computer failure or malfunction, or any *
|
||||
* and all other commercial damages or losses, even if such party *
|
||||
* shall have been informed of the possibility of such damages. This *
|
||||
* limitation of liability shall not apply to liability for death or *
|
||||
* personal injury resulting from such party's negligence to the *
|
||||
* extent applicable law prohibits such limitation. Some *
|
||||
* jurisdictions do not allow the exclusion or limitation of *
|
||||
* incidental or consequential damages, so this exclusion and *
|
||||
* limitation may not apply to You. *
|
||||
* *
|
||||
************************************************************************
|
||||
|
||||
8. Litigation
|
||||
-------------
|
||||
|
||||
Any litigation relating to this License may be brought only in the
|
||||
courts of a jurisdiction where the defendant maintains its principal
|
||||
place of business and such litigation shall be governed by laws of that
|
||||
jurisdiction, without reference to its conflict-of-law provisions.
|
||||
Nothing in this Section shall prevent a party's ability to bring
|
||||
cross-claims or counter-claims.
|
||||
|
||||
9. Miscellaneous
|
||||
----------------
|
||||
|
||||
This License represents the complete agreement concerning the subject
|
||||
matter hereof. If any provision of this License is held to be
|
||||
unenforceable, such provision shall be reformed only to the extent
|
||||
necessary to make it enforceable. Any law or regulation which provides
|
||||
that the language of a contract shall be construed against the drafter
|
||||
shall not be used to construe this License against a Contributor.
|
||||
|
||||
10. Versions of the License
|
||||
---------------------------
|
||||
|
||||
10.1. New Versions
|
||||
|
||||
Mozilla Foundation is the license steward. Except as provided in Section
|
||||
10.3, no one other than the license steward has the right to modify or
|
||||
publish new versions of this License. Each version will be given a
|
||||
distinguishing version number.
|
||||
|
||||
10.2. Effect of New Versions
|
||||
|
||||
You may distribute the Covered Software under the terms of the version
|
||||
of the License under which You originally received the Covered Software,
|
||||
or under the terms of any subsequent version published by the license
|
||||
steward.
|
||||
|
||||
10.3. Modified Versions
|
||||
|
||||
If you create software not governed by this License, and you want to
|
||||
create a new license for such software, you may create and use a
|
||||
modified version of this License if you rename the license and remove
|
||||
any references to the name of the license steward (except to note that
|
||||
such modified license differs from this License).
|
||||
|
||||
10.4. Distributing Source Code Form that is Incompatible With Secondary
|
||||
Licenses
|
||||
|
||||
If You choose to distribute Source Code Form that is Incompatible With
|
||||
Secondary Licenses under the terms of this version of the License, the
|
||||
notice described in Exhibit B of this License must be attached.
|
||||
|
||||
Exhibit A - Source Code Form License Notice
|
||||
-------------------------------------------
|
||||
|
||||
This Source Code Form is subject to the terms of the Mozilla Public
|
||||
License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
file, You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
|
||||
If it is not possible or desirable to put the notice in a particular
|
||||
file, then You may include the notice in a location (such as a LICENSE
|
||||
file in a relevant directory) where a recipient would be likely to look
|
||||
for such a notice.
|
||||
|
||||
You may add additional accurate notices of copyright ownership.
|
||||
|
||||
Exhibit B - "Incompatible With Secondary Licenses" Notice
|
||||
---------------------------------------------------------
|
||||
|
||||
This Source Code Form is "Incompatible With Secondary Licenses", as
|
||||
defined by the Mozilla Public License, v. 2.0.
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
#!/usr/bin/env node
|
||||
/**
|
||||
* Parse a DWG in Node — no browser, no Viewer2D. Same acadrust wasm and
|
||||
* Korean-text fixup as src/viewer2d/dwgParser.ts.
|
||||
*
|
||||
* Usage:
|
||||
* node scripts/parse-dwg.mjs <file.dwg> # print summary
|
||||
* node scripts/parse-dwg.mjs <file.dwg> out.json # also write full parseResult
|
||||
*
|
||||
* Needs Node >= 22.18 (imports fixDwgKoreanText.ts via built-in type stripping).
|
||||
*/
|
||||
import { readFileSync, writeFileSync } from 'node:fs';
|
||||
import { initSync, parse_dwg_json } from '../src/viewer2d/acadrust-dwg/acadrust_dwg.js';
|
||||
import { fixDwgKoreanText } from '../src/viewer2d/fixDwgKoreanText.ts';
|
||||
|
||||
const [inPath, outPath] = process.argv.slice(2);
|
||||
if (!inPath) {
|
||||
console.error('usage: node scripts/parse-dwg.mjs <file.dwg> [out.json]');
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
const wasmUrl = new URL('../src/viewer2d/acadrust-dwg/acadrust_dwg_bg.wasm', import.meta.url);
|
||||
initSync({ module: readFileSync(wasmUrl) });
|
||||
|
||||
const t0 = performance.now();
|
||||
const result = fixDwgKoreanText(JSON.parse(parse_dwg_json(readFileSync(inPath))));
|
||||
const ms = performance.now() - t0;
|
||||
|
||||
const entities = result.entities ?? [];
|
||||
const byType = {};
|
||||
for (const e of entities) byType[e.type] = (byType[e.type] ?? 0) + 1;
|
||||
|
||||
console.log(`file : ${inPath}`);
|
||||
console.log(`version : ${result.version}`);
|
||||
console.log(`parse : ${ms.toFixed(0)} ms`);
|
||||
console.log(`entities : ${entities.length}`);
|
||||
console.table(Object.entries(byType).sort((a, b) => b[1] - a[1]).map(([type, count]) => ({ type, count })));
|
||||
console.log(`tables : ${Object.keys(result.tables ?? {}).join(', ')}`);
|
||||
if (result.stats) console.log('stats :', result.stats);
|
||||
|
||||
if (outPath) {
|
||||
writeFileSync(outPath, JSON.stringify(result, null, 2));
|
||||
console.log(`wrote : ${outPath}`);
|
||||
}
|
||||
+45
-26
@@ -49,6 +49,15 @@ export class LayerPanelManager {
|
||||
if (options?.hideAllBtnEl) {
|
||||
options.hideAllBtnEl.addEventListener('click', () => this.hideAllLayers());
|
||||
}
|
||||
|
||||
// Delegated click handling: bound once, so render() never has to re-attach
|
||||
// a listener per row (that was O(layers) DOM work on every single toggle).
|
||||
this.listEl.addEventListener('click', (e) => {
|
||||
const row = (e.target as HTMLElement)?.closest?.('.layer-row') as HTMLElement | null;
|
||||
if (!row) return;
|
||||
const layerName = row.dataset.name;
|
||||
if (layerName) this.toggleLayer(layerName);
|
||||
});
|
||||
}
|
||||
|
||||
/** Refresh and re-render layer list from Viewer2D state */
|
||||
@@ -66,7 +75,7 @@ export class LayerPanelManager {
|
||||
public showAllLayers(): void {
|
||||
this.hiddenLayers.clear();
|
||||
this.viewer.setHiddenLayers(this.hiddenLayers);
|
||||
this.render();
|
||||
this.syncRows();
|
||||
}
|
||||
|
||||
public hideAllLayers(): void {
|
||||
@@ -75,7 +84,7 @@ export class LayerPanelManager {
|
||||
this.hiddenLayers.add(l.name);
|
||||
}
|
||||
this.viewer.setHiddenLayers(this.hiddenLayers);
|
||||
this.render();
|
||||
this.syncRows();
|
||||
}
|
||||
|
||||
public toggleLayer(name: string): void {
|
||||
@@ -85,7 +94,34 @@ export class LayerPanelManager {
|
||||
this.hiddenLayers.add(name);
|
||||
}
|
||||
this.viewer.setHiddenLayers(this.hiddenLayers);
|
||||
this.render();
|
||||
this.syncRow(name);
|
||||
}
|
||||
|
||||
/** Patch one row in place — a full render() would rebuild the whole list. */
|
||||
private syncRow(name: string): void {
|
||||
const row = this.listEl?.querySelector<HTMLElement>(
|
||||
`.layer-row[data-name="${cssEscape(name)}"]`
|
||||
);
|
||||
if (!row) return;
|
||||
this.paintRow(row, !this.hiddenLayers.has(name));
|
||||
}
|
||||
|
||||
/** Patch every row (show-all / hide-all) without touching the DOM structure. */
|
||||
private syncRows(): void {
|
||||
if (!this.listEl) return;
|
||||
this.listEl.querySelectorAll<HTMLElement>('.layer-row').forEach((row) => {
|
||||
const name = row.dataset.name;
|
||||
if (name != null) this.paintRow(row, !this.hiddenLayers.has(name));
|
||||
});
|
||||
}
|
||||
|
||||
private paintRow(row: HTMLElement, visible: boolean): void {
|
||||
row.style.opacity = visible ? '1' : '0.4';
|
||||
const btn = row.querySelector<HTMLElement>('.eye-btn');
|
||||
if (btn) {
|
||||
btn.textContent = visible ? '👁️' : '🕶️';
|
||||
btn.title = visible ? '숨기기' : '표시하기';
|
||||
}
|
||||
}
|
||||
|
||||
public render(): void {
|
||||
@@ -141,32 +177,15 @@ export class LayerPanelManager {
|
||||
</div>`;
|
||||
})
|
||||
.join('');
|
||||
|
||||
// Bind eye button click events
|
||||
this.listEl.querySelectorAll('.eye-btn').forEach((btn) => {
|
||||
btn.addEventListener('click', (e) => {
|
||||
e.stopPropagation();
|
||||
const layerName = (btn as HTMLElement).dataset.toggle;
|
||||
if (layerName) {
|
||||
this.toggleLayer(layerName);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// Also toggle when clicking row
|
||||
this.listEl.querySelectorAll('.layer-row').forEach((row) => {
|
||||
row.addEventListener('click', (e) => {
|
||||
const target = e.target as HTMLElement;
|
||||
if (target.closest('.eye-btn')) return;
|
||||
const layerName = (row as HTMLElement).dataset.name;
|
||||
if (layerName) {
|
||||
this.toggleLayer(layerName);
|
||||
}
|
||||
});
|
||||
});
|
||||
// Clicks are handled by the delegated listener bound in the constructor.
|
||||
}
|
||||
}
|
||||
|
||||
/** Escape a layer name for use inside a double-quoted CSS attribute selector. */
|
||||
function cssEscape(str: string): string {
|
||||
return str.replace(/["\\]/g, '\\$&');
|
||||
}
|
||||
|
||||
function escapeHtml(str: string): string {
|
||||
return str
|
||||
.replace(/&/g, '&')
|
||||
|
||||
+123
@@ -29,6 +29,7 @@ import { setDefaultFontUrl } from './viewer2d/slugText';
|
||||
import { renderPropertyInspector } from './propertyInspector';
|
||||
import { LayerPanelManager } from './layerPanel';
|
||||
import { makePanelDraggableAndCollapsible } from './panelUtils';
|
||||
import { getAllOptions, setOption } from './optionsStore';
|
||||
|
||||
// parseDxfBuffer 내부:
|
||||
// dxf-parser → HatchHandler → dxfAdapter
|
||||
@@ -162,6 +163,7 @@ async function loadAndRender(buf: ArrayBuffer, name: string): Promise<CadParseRe
|
||||
const def = pickDefaultSpace(spaces);
|
||||
viewer.load(result, { spaceHandle: def?.handleHex ?? null });
|
||||
viewer.resize();
|
||||
syncOptions();
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -229,6 +231,127 @@ document.getElementById('theme')!.addEventListener('click', () => {
|
||||
viewer.setTheme(dark);
|
||||
fillLayers();
|
||||
});
|
||||
|
||||
// ── 옵션 패널 ────────────────────────────────────────────────────
|
||||
// 값은 IndexedDB(hmw-viewer/options)에 남는다. 선가중치 배율은 재파싱 없이
|
||||
// 즉시 반영되므로 드래그하면서 화면을 보고 맞출 수 있다.
|
||||
const optionsPanel = document.getElementById('options')!;
|
||||
const optLwOn = document.getElementById('optLwOn') as HTMLInputElement;
|
||||
const optLwScale = document.getElementById('optLwScale') as HTMLInputElement;
|
||||
const optLwScaleNum = document.getElementById('optLwScaleNum') as HTMLInputElement;
|
||||
const optLwOut = document.getElementById('optLwOut')!;
|
||||
const optGrid = document.getElementById('optGrid') as HTMLInputElement;
|
||||
const optZoomSpeed = document.getElementById('optZoomSpeed') as HTMLInputElement;
|
||||
const optZoomSpeedNum = document.getElementById('optZoomSpeedNum') as HTMLInputElement;
|
||||
const opt25D = document.getElementById('opt25D') as HTMLInputElement;
|
||||
const optZRow = document.getElementById('optZRow')!;
|
||||
const optZScale = document.getElementById('optZScale') as HTMLInputElement;
|
||||
const optZScaleNum = document.getElementById('optZScaleNum') as HTMLInputElement;
|
||||
|
||||
makePanelDraggableAndCollapsible(optionsPanel, {
|
||||
collapseBtnEl: document.getElementById('collapseOptBtn')!,
|
||||
});
|
||||
document.getElementById('optionsBtn')!.addEventListener('click', () => {
|
||||
optionsPanel.style.display = optionsPanel.style.display === 'flex' ? 'none' : 'flex';
|
||||
});
|
||||
document.getElementById('closeOptBtn')!.addEventListener('click', () => {
|
||||
optionsPanel.style.display = 'none';
|
||||
});
|
||||
|
||||
/** 컨트롤 값을 뷰어의 현재 상태로 되돌린다(도면을 새로 열었을 때도 호출). */
|
||||
function syncOptions() {
|
||||
const s = viewer.getLineweightScale();
|
||||
optLwOn.checked = viewer.getLineweightEnabled();
|
||||
optLwScale.value = String(s);
|
||||
optLwScaleNum.value = String(s);
|
||||
const classes = viewer.getLineweightClasses();
|
||||
optLwOut.textContent = classes.length
|
||||
? classes.map((mm) => `${mm.toFixed(2)}mm → ${Math.round(mm * s * 10) / 10}px`).join(' ')
|
||||
: `이 도면에는 굵은 선이 없다 (0.50mm 였다면 ${Math.round(0.5 * s * 10) / 10}px)`;
|
||||
}
|
||||
|
||||
function applyLwScale(v: number, persist = true) {
|
||||
if (!Number.isFinite(v) || v <= 0) return;
|
||||
viewer.setLineweightScale(v);
|
||||
if (persist) void setOption('lineweightScale', v);
|
||||
syncOptions();
|
||||
}
|
||||
optLwScale.addEventListener('input', () => applyLwScale(parseFloat(optLwScale.value)));
|
||||
optLwScaleNum.addEventListener('input', () => applyLwScale(parseFloat(optLwScaleNum.value)));
|
||||
|
||||
optLwOn.addEventListener('change', () => {
|
||||
viewer.setLineweightEnabled(optLwOn.checked);
|
||||
void setOption('lineweightOn', optLwOn.checked);
|
||||
syncOptions();
|
||||
});
|
||||
|
||||
optGrid.addEventListener('change', () => {
|
||||
viewer.setGrid(optGrid.checked);
|
||||
void setOption('grid', optGrid.checked);
|
||||
});
|
||||
|
||||
function applyZoomSpeed(v: number, persist = true) {
|
||||
if (!Number.isFinite(v) || v <= 0) return;
|
||||
viewer.setZoomSpeed(v);
|
||||
optZoomSpeed.value = String(v);
|
||||
optZoomSpeedNum.value = String(v);
|
||||
if (persist) void setOption('zoomSpeed', v);
|
||||
}
|
||||
optZoomSpeed.addEventListener('input', () => applyZoomSpeed(parseFloat(optZoomSpeed.value)));
|
||||
optZoomSpeedNum.addEventListener('input', () => applyZoomSpeed(parseFloat(optZoomSpeedNum.value)));
|
||||
|
||||
// ── 2.5D 보기 토글 ───────────────────────────────────────────────
|
||||
// Top 뷰를 풀고 남동 등각(SE Isometric)으로 기울인다. 도면 정점은 이미 CAD
|
||||
// 표고(Z)를 갖고 있으므로 재파싱·재생성 없이 카메라만 돌리면 등고선 같은
|
||||
// 높낮이가 그대로 드러난다. 다시 누르면 원래 Top 뷰(회전 잠금)로 돌아온다.
|
||||
// 뷰 상태라 IndexedDB 에 저장하지 않는다 — Z 과장 배율만 저장한다.
|
||||
const view25Btn = document.getElementById('view25Btn')!;
|
||||
|
||||
function apply25D(on: boolean) {
|
||||
viewer.set25D(on);
|
||||
view25Btn.classList.toggle('on', on);
|
||||
view25Btn.textContent = on ? '2.5D 보기 ✓' : '2.5D 보기';
|
||||
opt25D.checked = on;
|
||||
optZRow.classList.toggle('disabled', !on);
|
||||
setStatus(on ? '2.5D 보기 · 왼쪽 드래그=회전, 가운데·오른쪽 드래그=이동' : 'Top 뷰');
|
||||
}
|
||||
view25Btn.addEventListener('click', () => apply25D(!viewer.is25D()));
|
||||
opt25D.addEventListener('change', () => apply25D(opt25D.checked));
|
||||
|
||||
function applyZScale(v: number, persist = true) {
|
||||
if (!Number.isFinite(v) || v <= 0) return;
|
||||
viewer.setZScale(v);
|
||||
optZScale.value = String(v);
|
||||
optZScaleNum.value = String(v);
|
||||
if (persist) void setOption('zScale', v);
|
||||
}
|
||||
optZScale.addEventListener('input', () => applyZScale(parseFloat(optZScale.value)));
|
||||
optZScaleNum.addEventListener('input', () => applyZScale(parseFloat(optZScaleNum.value)));
|
||||
|
||||
document.getElementById('optReset')!.addEventListener('click', () => {
|
||||
viewer.setLineweightScale(null); // 뷰어 기본 배율
|
||||
viewer.setLineweightEnabled(null); // 도면의 LWDISPLAY 를 다시 따름
|
||||
viewer.setGrid(false);
|
||||
applyZoomSpeed(1);
|
||||
applyZScale(1);
|
||||
apply25D(false);
|
||||
optGrid.checked = false;
|
||||
void setOption('lineweightScale', null);
|
||||
void setOption('lineweightOn', null);
|
||||
void setOption('grid', false);
|
||||
syncOptions();
|
||||
});
|
||||
|
||||
// 저장된 옵션 복원 (IndexedDB 는 비동기라 첫 도면 로드와 경쟁하지 않도록 즉시 적용)
|
||||
void getAllOptions().then((o) => {
|
||||
if (typeof o.lineweightScale === 'number') applyLwScale(o.lineweightScale, false);
|
||||
if (typeof o.lineweightOn === 'boolean') viewer.setLineweightEnabled(o.lineweightOn);
|
||||
if (o.grid === true) { viewer.setGrid(true); optGrid.checked = true; }
|
||||
if (typeof o.zoomSpeed === 'number') applyZoomSpeed(o.zoomSpeed, false);
|
||||
if (typeof o.zScale === 'number') applyZScale(o.zScale, false);
|
||||
syncOptions();
|
||||
});
|
||||
syncOptions();
|
||||
document.getElementById('layersBtn')!.addEventListener('click', () => {
|
||||
layersPanel.style.display = layersPanel.style.display === 'flex' ? 'none' : 'flex';
|
||||
});
|
||||
|
||||
@@ -0,0 +1,75 @@
|
||||
/**
|
||||
* 뷰어 옵션 영구 저장소 (IndexedDB).
|
||||
*
|
||||
* localStorage 대신 IndexedDB 를 쓰는 이유: 값이 문자열로 강제되지 않고(숫자/불린/
|
||||
* 객체 그대로), 용량 제한이 사실상 없으며, 나중에 도면별 설정처럼 구조가 커져도
|
||||
* 같은 저장소를 그대로 쓸 수 있다.
|
||||
*
|
||||
* DB 하나(`hmw-viewer`) 안에 key-value 스토어(`options`) 하나만 둔다.
|
||||
* 실패(사생활 보호 모드, 스토리지 차단 등)해도 앱이 죽지 않도록 모든 API 는
|
||||
* 조용히 기본값으로 떨어진다.
|
||||
*/
|
||||
|
||||
const DB_NAME = 'hmw-viewer';
|
||||
const DB_VERSION = 1;
|
||||
const STORE = 'options';
|
||||
|
||||
let dbPromise: Promise<IDBDatabase | null> | null = null;
|
||||
|
||||
function openDb(): Promise<IDBDatabase | null> {
|
||||
if (dbPromise) return dbPromise;
|
||||
dbPromise = new Promise((resolve) => {
|
||||
if (typeof indexedDB === 'undefined') return resolve(null);
|
||||
let req: IDBOpenDBRequest;
|
||||
try {
|
||||
req = indexedDB.open(DB_NAME, DB_VERSION);
|
||||
} catch {
|
||||
return resolve(null);
|
||||
}
|
||||
req.onupgradeneeded = () => {
|
||||
const db = req.result;
|
||||
if (!db.objectStoreNames.contains(STORE)) db.createObjectStore(STORE);
|
||||
};
|
||||
req.onsuccess = () => resolve(req.result);
|
||||
req.onerror = () => resolve(null);
|
||||
req.onblocked = () => resolve(null);
|
||||
});
|
||||
return dbPromise;
|
||||
}
|
||||
|
||||
function tx<T>(mode: IDBTransactionMode, run: (store: IDBObjectStore) => IDBRequest): Promise<T | null> {
|
||||
return openDb().then(
|
||||
(db) =>
|
||||
new Promise<T | null>((resolve) => {
|
||||
if (!db) return resolve(null);
|
||||
try {
|
||||
const t = db.transaction(STORE, mode);
|
||||
const req = run(t.objectStore(STORE));
|
||||
req.onsuccess = () => resolve(req.result as T);
|
||||
req.onerror = () => resolve(null);
|
||||
} catch {
|
||||
resolve(null);
|
||||
}
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
/** 저장된 옵션 하나. 없으면 `fallback`. */
|
||||
export async function getOption<T>(key: string, fallback: T): Promise<T> {
|
||||
const v = await tx<T>('readonly', (s) => s.get(key));
|
||||
return v === null || v === undefined ? fallback : v;
|
||||
}
|
||||
|
||||
/** 옵션 하나 저장. 저장이 막혀 있어도 예외를 던지지 않는다. */
|
||||
export async function setOption(key: string, value: unknown): Promise<void> {
|
||||
await tx('readwrite', (s) => s.put(value, key));
|
||||
}
|
||||
|
||||
/** 전체 옵션을 한 번에 읽는다 (기동 시 1회 호출용). */
|
||||
export async function getAllOptions(): Promise<Record<string, unknown>> {
|
||||
const keys = (await tx<IDBValidKey[]>('readonly', (s) => s.getAllKeys())) ?? [];
|
||||
const vals = (await tx<unknown[]>('readonly', (s) => s.getAll())) ?? [];
|
||||
const out: Record<string, unknown> = {};
|
||||
keys.forEach((k, i) => { out[String(k)] = vals[i]; });
|
||||
return out;
|
||||
}
|
||||
@@ -40,6 +40,16 @@ function formatColor(colorVal: any): string {
|
||||
return String(colorVal);
|
||||
}
|
||||
|
||||
/** DWG lineweight: i16 in 1/100 mm, with -1/-2/-3 reserved for the inherit modes. */
|
||||
function formatLineweight(raw: unknown): string {
|
||||
if (typeof raw !== 'number') return 'BYLAYER';
|
||||
if (raw === -1) return 'BYLAYER';
|
||||
if (raw === -2) return 'BYBLOCK';
|
||||
if (raw === -3) return 'DEFAULT (0.25mm)';
|
||||
if (raw < 0) return String(raw);
|
||||
return `${(raw / 100).toFixed(2)}mm`;
|
||||
}
|
||||
|
||||
export function formatEntityProperties(entity: any): FormattedProperties {
|
||||
if (!entity) {
|
||||
return { id: '', type: '', handle: '', layer: '', general: [], geometry: [] };
|
||||
@@ -51,6 +61,9 @@ export function formatEntityProperties(entity: any): FormattedProperties {
|
||||
const layer = entity.layer ?? entity.layerName ?? '0';
|
||||
const color = formatColor(entity.color ?? d.color);
|
||||
const linetype = entity.lineType ?? entity.linetype ?? d.lineType ?? 'BYLAYER';
|
||||
const lineweight = formatLineweight(
|
||||
entity.entityHeader?.lineWeight ?? entity.lineWeight ?? entity.lineweight ?? d.lineweight,
|
||||
);
|
||||
|
||||
const general: [string, string][] = [
|
||||
['유형 (Type)', type],
|
||||
@@ -58,6 +71,7 @@ export function formatEntityProperties(entity: any): FormattedProperties {
|
||||
['레이어 (Layer)', String(layer)],
|
||||
['색상 (Color)', color],
|
||||
['선종류 (Linetype)', String(linetype)],
|
||||
['선가중치 (Lineweight)', lineweight],
|
||||
];
|
||||
|
||||
const geometry: [string, string][] = [];
|
||||
@@ -155,6 +169,37 @@ export function formatEntityProperties(entity: any): FormattedProperties {
|
||||
break;
|
||||
}
|
||||
|
||||
// MESH (AcDbSubDMesh). dwg-wasm emits flat arrays: vertices [x,y,z,…],
|
||||
// faceList [n, i0 … i(n-1)] repeated, edges [a,b,…].
|
||||
case 'MESH': {
|
||||
const verts: number[] = d.vertices ?? [];
|
||||
const vCount = d.vertexCount ?? Math.floor(verts.length / 3);
|
||||
const fCount = d.faceCount ?? 0;
|
||||
const eCount = Math.floor((d.edges?.length ?? 0) / 2);
|
||||
const sub = d.subdivisionLevel ?? 0;
|
||||
|
||||
geometry.push(['정점 개수 (Vertices)', String(vCount)]);
|
||||
geometry.push(['면 개수 (Faces)', String(fCount)]);
|
||||
geometry.push(['모서리 개수 (Edges)', String(eCount)]);
|
||||
geometry.push(['세분 레벨 (Subdivision)', String(sub)]);
|
||||
geometry.push(['크리스 혼합 (Blend Crease)', d.blendCrease ? '예 (Yes)' : '아니오 (No)']);
|
||||
|
||||
if (vCount > 0) {
|
||||
let minX = Infinity, minY = Infinity, minZ = Infinity;
|
||||
let maxX = -Infinity, maxY = -Infinity, maxZ = -Infinity;
|
||||
for (let i = 0; i + 2 < verts.length; i += 3) {
|
||||
const x = verts[i], y = verts[i + 1], z = verts[i + 2];
|
||||
if (x < minX) minX = x; if (x > maxX) maxX = x;
|
||||
if (y < minY) minY = y; if (y > maxY) maxY = y;
|
||||
if (z < minZ) minZ = z; if (z > maxZ) maxZ = z;
|
||||
}
|
||||
geometry.push(['최소점 (Min)', pt({ x: minX, y: minY, z: minZ })]);
|
||||
geometry.push(['최대점 (Max)', pt({ x: maxX, y: maxY, z: maxZ })]);
|
||||
geometry.push(['표고 범위 (Z Range)', `${f3(minZ)} ~ ${f3(maxZ)}`]);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case 'TEXT':
|
||||
case 'MTEXT':
|
||||
case 'ATTRIB': {
|
||||
|
||||
@@ -0,0 +1,163 @@
|
||||
/**
|
||||
* Top loading bar (NProgress-style) for the DWG/DXF load pipeline.
|
||||
*
|
||||
* Why two layers:
|
||||
* The expensive stages — `parse_dwg_json` on the WASM heap and
|
||||
* `Viewer2D.load()` — are SYNCHRONOUS. While they run, the main thread is
|
||||
* blocked: no rAF ticks, no `width` transitions, no repaint. A JS-driven bar
|
||||
* simply freezes for the seconds that matter most.
|
||||
*
|
||||
* · `.bar` real progress, driven by `width` (accurate, main-thread bound).
|
||||
* · `.sweep` liveness, a `transform` keyframe animation. Transform keyframes
|
||||
* are handed to the compositor thread, so the stripe keeps moving
|
||||
* across a blocked main thread. That is the only feedback the page
|
||||
* can give while the parser is inside WASM.
|
||||
*
|
||||
* The markup and CSS live in index.html (`#progress`), same as the other
|
||||
* panels; this module just drives them.
|
||||
*/
|
||||
|
||||
/** Wait until the browser has actually painted the pending style change. */
|
||||
function nextPaint(): Promise<void> {
|
||||
return new Promise<void>((resolve) => {
|
||||
let settled = false;
|
||||
const finish = () => {
|
||||
if (settled) return;
|
||||
settled = true;
|
||||
resolve();
|
||||
};
|
||||
// Two frames: the first callback still runs BEFORE paint, the second one
|
||||
// only fires once the frame carrying our change has been composited.
|
||||
requestAnimationFrame(() => requestAnimationFrame(finish));
|
||||
// Backgrounded tabs never fire rAF — don't stall the load behind it.
|
||||
setTimeout(finish, 150);
|
||||
});
|
||||
}
|
||||
|
||||
export class TopProgress {
|
||||
private root: HTMLElement;
|
||||
private bar: HTMLElement;
|
||||
private value = 0;
|
||||
private hideTimer = 0;
|
||||
|
||||
constructor(root: HTMLElement) {
|
||||
this.root = root;
|
||||
this.bar = root.querySelector<HTMLElement>('.bar') ?? root;
|
||||
}
|
||||
|
||||
/** Show the bar and reset it to zero (no rewind animation). */
|
||||
start(): void {
|
||||
window.clearTimeout(this.hideTimer);
|
||||
this.root.classList.remove('err');
|
||||
this.value = 0;
|
||||
this.jumpTo(0);
|
||||
this.root.classList.add('on');
|
||||
}
|
||||
|
||||
/**
|
||||
* Move to `v` (0–1). Monotonic — a lower value is ignored, so out-of-order
|
||||
* stage callbacks can never make the bar walk backwards.
|
||||
*/
|
||||
set(v: number): void {
|
||||
const next = Math.max(this.value, Math.min(1, Math.max(0, v)));
|
||||
if (next === this.value) return;
|
||||
this.value = next;
|
||||
this.bar.style.width = `${(next * 100).toFixed(2)}%`;
|
||||
}
|
||||
|
||||
/** Toggle the compositor-driven sweep for a stage that blocks the main thread. */
|
||||
busy(on: boolean): void {
|
||||
this.root.classList.toggle('busy', on);
|
||||
}
|
||||
|
||||
/** Resolve once the pending width/class change is on screen. */
|
||||
paint(): Promise<void> {
|
||||
return nextPaint();
|
||||
}
|
||||
|
||||
/** Fill to 100% and fade out. */
|
||||
done(): void {
|
||||
this.finish();
|
||||
}
|
||||
|
||||
/** Fill to 100% in the error color and fade out. */
|
||||
fail(): void {
|
||||
this.root.classList.add('err');
|
||||
this.finish();
|
||||
}
|
||||
|
||||
private finish(): void {
|
||||
this.busy(false);
|
||||
this.set(1);
|
||||
window.clearTimeout(this.hideTimer);
|
||||
this.hideTimer = window.setTimeout(() => {
|
||||
this.root.classList.remove('on');
|
||||
// Rewind only after the fade-out has finished, so the bar never visibly
|
||||
// slides back to zero.
|
||||
this.hideTimer = window.setTimeout(() => {
|
||||
this.root.classList.remove('err');
|
||||
this.value = 0;
|
||||
this.jumpTo(0);
|
||||
}, 320);
|
||||
}, 260);
|
||||
}
|
||||
|
||||
/** Set the width with the transition suppressed for one frame. */
|
||||
private jumpTo(v: number): void {
|
||||
const prev = this.bar.style.transition;
|
||||
this.bar.style.transition = 'none';
|
||||
this.bar.style.width = `${(v * 100).toFixed(2)}%`;
|
||||
void this.bar.offsetWidth; // force reflow so the next change animates again
|
||||
this.bar.style.transition = prev;
|
||||
}
|
||||
}
|
||||
|
||||
/** 1.4 MB / 812 kB — short byte label for the download readout. */
|
||||
export function formatBytes(n: number): string {
|
||||
if (!Number.isFinite(n) || n < 0) return '?';
|
||||
if (n < 1024) return `${n} B`;
|
||||
if (n < 1024 * 1024) return `${(n / 1024).toFixed(0)} kB`;
|
||||
return `${(n / 1024 / 1024).toFixed(1)} MB`;
|
||||
}
|
||||
|
||||
/**
|
||||
* fetch() that reports download progress.
|
||||
*
|
||||
* Falls back to a plain `arrayBuffer()` when the response has no body stream
|
||||
* or no Content-Length (then `total` is 0 and the caller should show an
|
||||
* indeterminate state). `loaded` is decompressed bytes while Content-Length is
|
||||
* the compressed size, so the ratio is clamped to 1.
|
||||
*/
|
||||
export async function fetchWithProgress(
|
||||
url: string,
|
||||
onProgress: (loaded: number, total: number) => void,
|
||||
): Promise<ArrayBuffer> {
|
||||
const res = await fetch(url);
|
||||
if (!res.ok) throw new Error(`HTTP ${res.status}`);
|
||||
const total = Number(res.headers.get('content-length')) || 0;
|
||||
if (!res.body || !total) {
|
||||
const buf = await res.arrayBuffer();
|
||||
onProgress(buf.byteLength, buf.byteLength);
|
||||
return buf;
|
||||
}
|
||||
|
||||
const reader = res.body.getReader();
|
||||
const chunks: Uint8Array[] = [];
|
||||
let loaded = 0;
|
||||
for (;;) {
|
||||
const { done, value } = await reader.read();
|
||||
if (done) break;
|
||||
if (!value) continue;
|
||||
chunks.push(value);
|
||||
loaded += value.length;
|
||||
onProgress(loaded, total);
|
||||
}
|
||||
|
||||
const out = new Uint8Array(loaded);
|
||||
let offset = 0;
|
||||
for (const c of chunks) {
|
||||
out.set(c, offset);
|
||||
offset += c.length;
|
||||
}
|
||||
return out.buffer;
|
||||
}
|
||||
Vendored
+16
@@ -16,6 +16,22 @@ export class Viewer2D {
|
||||
setAccent(hex: string): void;
|
||||
setTheme(dark: boolean): void;
|
||||
setGrid(visible: boolean): void;
|
||||
setZoomSpeed(speed: number): void;
|
||||
getZoomSpeed(): number;
|
||||
/** 2.5D (tilted 3D) view: orbit the drawing so entity elevation (Z) is visible. */
|
||||
set25D(on: boolean, opts?: { keepView?: boolean }): void;
|
||||
is25D(): boolean;
|
||||
/** Height exaggeration for 2.5D (1 = true scale); ignored in top view. */
|
||||
setZScale(k: number): void;
|
||||
getZScale(): number;
|
||||
/** Lineweight display (AutoCAD LWDISPLAY); null follows the drawing's own flag. */
|
||||
setLineweightEnabled(on: boolean | null): void;
|
||||
getLineweightEnabled(): boolean;
|
||||
/** Lineweight display scale in px per mm (AutoCAD's display-scale slider). Default 20. */
|
||||
setLineweightScale(pxPerMm: number | null): void;
|
||||
getLineweightScale(): number;
|
||||
/** Distinct lineweights (mm) present in the loaded drawing, ascending. */
|
||||
getLineweightClasses(): number[];
|
||||
getLayerInfo(): { name: string; colorHex: string; count: number; visible: boolean }[];
|
||||
setHiddenLayers(nameSet: Set<string>): void;
|
||||
/** Model / Paper (Layout) spaces for the loaded drawing. */
|
||||
|
||||
+899
-95
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,40 @@
|
||||
# acadrust-dwg — DWG 파서 wasm (빌드 정보)
|
||||
|
||||
이 폴더를 다른 레포로 복사해 쓴다면 **이 README 도 같이 복사**한다. 사본이 최신인지 판별할 근거가 여기 있다.
|
||||
|
||||
| 항목 | 값 |
|
||||
|---|---|
|
||||
| acadrust | **0.6.5** — crates.io 판을 **무수정**으로 사용 (upstream commit `289a616da6c68518218594aa80802cbe7fa71309`, crate SHA-256 `5eaa72520f70eb6f7f09b06f44e1ed0d8fad5fa743364f2c3715c30df962ec7c`) |
|
||||
| 래퍼 (dwg-wasm, MIT) | `hmwebviewer` 의 `rust/dwg-wasm`, 브랜치 `chore/acadrust-0.6.5`, 커밋 `7c6786a` |
|
||||
| `acadrust_dwg_bg.wasm` SHA-256 | `2d58b20f172cad3c6a38330c7173d9292107bd2fec8e4085f68507be961761fd` |
|
||||
| 빌드 | 2026-10-19 · wasm-pack 0.15 · rustc 1.92 · `opt-level = "s"`, LTO |
|
||||
| 정본 위치 | `gitea.hmac.kr/kimminsung/dwg-dxf-viewer-sample` → `src/viewer2d/acadrust-dwg/` (master) |
|
||||
|
||||
## 내 사본이 최신인지 확인
|
||||
|
||||
```bash
|
||||
sha256sum acadrust_dwg_bg.wasm # 2d58b20f172cad3c… 이면 이 빌드
|
||||
grep -c -a 'acadrust-0.6.5' acadrust_dwg_bg.wasm # 1 이상 = 0.6.5 빌드, 0 = 옛 0.4.x 빌드
|
||||
```
|
||||
|
||||
`package.json` 의 `version`(0.1.0)은 옛 빌드와 같아서 판별에 쓸 수 없다.
|
||||
`grep` 표식은 wasm 안에 남은 crates.io 경로(`…\acadrust-0.6.5\src\…`)라서, 0.6.5 crate 로 빌드했을 때만 생긴다.
|
||||
|
||||
## 옛 빌드(acadrust 0.4.1 + 로컬 패치)에서 바꿀 때 알아 둘 것
|
||||
|
||||
- **API 는 같다.** `init` / `initSync`, `parse_dwg_json(bytes)`, `parse_dwg(bytes)`, parseResult 구조 모두 그대로다. 파일 4개(`acadrust_dwg.js`, `acadrust_dwg.d.ts`, `acadrust_dwg_bg.wasm`, `acadrust_dwg_bg.wasm.d.ts`)만 바꾸면 된다.
|
||||
- **크기**: 864 KB → 2.9 MB (brotli 294 → 815 KB). 대형 도면 로드는 약 2~9 % 느리다.
|
||||
- **더 정확해진 값** (0.4.1 이 잘못 읽던 것):
|
||||
- 레이아웃 전체 뷰포트의 `VIEWPORT.id` = 1
|
||||
- 3D 폴리선 vertex 순서
|
||||
- ATTDEF 정렬
|
||||
- 치수 `pt10`
|
||||
- 트루컬러의 근사 ACI
|
||||
- **한글**: 한글(CP949)을 원본 출력에서 바로 디코딩한다. JS 쪽 `fixDwgKoreanText` 는 그대로 둬도 무해하다.
|
||||
- **새 타입명**: `DIMENSION_ARC`, `DIMENSION_LARGE_RADIAL`. 0.4.1 은 이 치수를 버렸다.
|
||||
- **손상 레코드**: 도면 전체를 거부하지 않고 건너뛴 뒤 notification 으로 남긴다 (failsafe).
|
||||
- 상세: 정본 레포 `docs/acadrust-0.6.5-upgrade.md`. 22개 샘플 화면 비교: `docs/acadrust-0.6.5-upgrade-report.html`.
|
||||
|
||||
## 라이선스
|
||||
|
||||
acadrust 는 MPL-2.0 이고 무수정으로 쓴다. 배포할 때는 MPL 원문과 소스 입수 위치 고지를 동봉한다 (정본 레포의 `THIRD-PARTY-NOTICES.md`, `public/licenses/`). 래퍼는 MIT.
|
||||
+1
@@ -24,6 +24,7 @@ export interface InitOutput {
|
||||
readonly parse_dwg_json: (a: number, b: number) => [number, number, number, number];
|
||||
readonly __wbindgen_malloc: (a: number, b: number) => number;
|
||||
readonly __wbindgen_realloc: (a: number, b: number, c: number, d: number) => number;
|
||||
readonly __externref_table_alloc: () => number;
|
||||
readonly __wbindgen_externrefs: WebAssembly.Table;
|
||||
readonly __externref_table_dealloc: (a: number) => void;
|
||||
readonly __wbindgen_free: (a: number, b: number, c: number) => void;
|
||||
|
||||
@@ -65,6 +65,10 @@ function __wbg_get_imports() {
|
||||
const ret = typeof(arg0) === 'string';
|
||||
return ret;
|
||||
},
|
||||
__wbg___wbindgen_is_undefined_c05833b95a3cf397: function(arg0) {
|
||||
const ret = arg0 === undefined;
|
||||
return ret;
|
||||
},
|
||||
__wbg___wbindgen_throw_344f42d3211c4765: function(arg0, arg1) {
|
||||
throw new Error(getStringFromWasm0(arg0, arg1));
|
||||
},
|
||||
@@ -80,6 +84,14 @@ function __wbg_get_imports() {
|
||||
const ret = new Object();
|
||||
return ret;
|
||||
},
|
||||
__wbg_now_e7c6795a7f81e10f: function(arg0) {
|
||||
const ret = arg0.now();
|
||||
return ret;
|
||||
},
|
||||
__wbg_performance_3fcf6e32a7e1ed0a: function(arg0) {
|
||||
const ret = arg0.performance;
|
||||
return ret;
|
||||
},
|
||||
__wbg_set_575dd786d51585f8: function(arg0, arg1, arg2) {
|
||||
const ret = arg0.set(arg1, arg2);
|
||||
return ret;
|
||||
@@ -90,6 +102,22 @@ function __wbg_get_imports() {
|
||||
__wbg_set_8a16b38e4805b298: function(arg0, arg1, arg2) {
|
||||
arg0[arg1 >>> 0] = arg2;
|
||||
},
|
||||
__wbg_static_accessor_GLOBAL_4ef717fb391d88b7: function() {
|
||||
const ret = typeof global === 'undefined' ? null : global;
|
||||
return isLikeNone(ret) ? 0 : addToExternrefTable0(ret);
|
||||
},
|
||||
__wbg_static_accessor_GLOBAL_THIS_8d1badc68b5a74f4: function() {
|
||||
const ret = typeof globalThis === 'undefined' ? null : globalThis;
|
||||
return isLikeNone(ret) ? 0 : addToExternrefTable0(ret);
|
||||
},
|
||||
__wbg_static_accessor_SELF_146583524fe1469b: function() {
|
||||
const ret = typeof self === 'undefined' ? null : self;
|
||||
return isLikeNone(ret) ? 0 : addToExternrefTable0(ret);
|
||||
},
|
||||
__wbg_static_accessor_WINDOW_f2829a2234d7819e: function() {
|
||||
const ret = typeof window === 'undefined' ? null : window;
|
||||
return isLikeNone(ret) ? 0 : addToExternrefTable0(ret);
|
||||
},
|
||||
__wbindgen_cast_0000000000000001: function(arg0) {
|
||||
// Cast intrinsic for `F64 -> Externref`.
|
||||
const ret = arg0;
|
||||
@@ -126,6 +154,12 @@ function __wbg_get_imports() {
|
||||
};
|
||||
}
|
||||
|
||||
function addToExternrefTable0(obj) {
|
||||
const idx = wasm.__externref_table_alloc();
|
||||
wasm.__wbindgen_externrefs.set(idx, obj);
|
||||
return idx;
|
||||
}
|
||||
|
||||
let cachedDataViewMemory0 = null;
|
||||
function getDataViewMemory0() {
|
||||
if (cachedDataViewMemory0 === null || cachedDataViewMemory0.buffer.detached === true || (cachedDataViewMemory0.buffer.detached === undefined && cachedDataViewMemory0.buffer !== wasm.memory.buffer)) {
|
||||
@@ -146,6 +180,10 @@ function getUint8ArrayMemory0() {
|
||||
return cachedUint8ArrayMemory0;
|
||||
}
|
||||
|
||||
function isLikeNone(x) {
|
||||
return x === undefined || x === null;
|
||||
}
|
||||
|
||||
function passArray8ToWasm0(arg, malloc) {
|
||||
const ptr = malloc(arg.length * 1, 1) >>> 0;
|
||||
getUint8ArrayMemory0().set(arg, ptr / 1);
|
||||
|
||||
Binary file not shown.
@@ -5,6 +5,7 @@ export const parse_dwg: (a: number, b: number) => [number, number, number];
|
||||
export const parse_dwg_json: (a: number, b: number) => [number, number, number, number];
|
||||
export const __wbindgen_malloc: (a: number, b: number) => number;
|
||||
export const __wbindgen_realloc: (a: number, b: number, c: number, d: number) => number;
|
||||
export const __externref_table_alloc: () => number;
|
||||
export const __wbindgen_externrefs: WebAssembly.Table;
|
||||
export const __externref_table_dealloc: (a: number) => void;
|
||||
export const __wbindgen_free: (a: number, b: number, c: number) => void;
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
/**
|
||||
* DWG parser — rust/dwg-wasm wrapper around the acadrust crate (MPL-2.0,
|
||||
* consumed unmodified; see rust/dwg-wasm). Emits the parseResult shape
|
||||
* Viewer2D.load() consumes. Lazy-imported so the wasm is only fetched when a
|
||||
* DWG is actually opened.
|
||||
* 0.6.5 from crates.io, unmodified; see hmwebviewer rust/dwg-wasm). Emits
|
||||
* the parseResult shape Viewer2D.load() consumes. Lazy-imported so the wasm is
|
||||
* only fetched when a DWG is actually opened.
|
||||
*
|
||||
* History: until 2026-07-10 this module selected between acadrust and
|
||||
* @horu2day/pure-cad-parser (?dwgparser= toggle). The old parser was removed
|
||||
|
||||
Reference in new issue
Block a user