fix(viewer2d): show lineweight at AutoCAD's display scale (20 px/mm)
Hand test against an AutoCAD capture: the 0.50mm road edge is ~10px there but only ~4px here. Lineweight is zoom-independent screen pixels, so the two captures compare directly - the 8 px/mm mapping was 2.5x too small. AutoCAD's default display scale is one pixel per 0.05mm, so use 20 px/mm (0.35mm = 7px, 0.50mm = 10px, 2.11mm = 42px) and raise the clamp to 48px. Add setLineweightScale()/getLineweightScale() so a host can retune it - AutoCAD exposes the same thing as the Adjust Display Scale slider. Re-measured headless: the 0.35mm road-gutter line now renders ~7px, so both weight classes land on the same scale. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
File diff suppressed because one or more lines are too long
+1
-1
@@ -198,7 +198,7 @@
|
|||||||
}
|
}
|
||||||
.layer-sub-btn:hover { color: var(--ink); border-color: var(--accent); background: rgba(63,185,80,.1); }
|
.layer-sub-btn:hover { color: var(--ink); border-color: var(--accent); background: rgba(63,185,80,.1); }
|
||||||
</style>
|
</style>
|
||||||
<script type="module" crossorigin src="/assets/index-D3FqDGwP.js"></script>
|
<script type="module" crossorigin src="/assets/index-BsOJ4upQ.js"></script>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div id="app"></div>
|
<div id="app"></div>
|
||||||
|
|||||||
@@ -96,10 +96,18 @@ lineweight 는 **화면 픽셀 폭**이다. 줌해도 굵기가 변하지 않는
|
|||||||
따라서 월드 단위가 아니라 스크린 스페이스로 그려야 한다.
|
따라서 월드 단위가 아니라 스크린 스페이스로 그려야 한다.
|
||||||
|
|
||||||
```
|
```
|
||||||
px = mm × 8 (LW_PX_PER_MM, 최대 24px)
|
px = mm × 20 (LW_PX_PER_MM, 최대 48px)
|
||||||
0.25mm ≈ 2px · 0.50mm ≈ 4px · 2.11mm ≈ 17px ← AutoCAD 기본 표시 배율과 동일 눈금
|
0.35mm = 7px · 0.50mm = 10px · 2.11mm = 42px ← AutoCAD 기본 표시 배율(0.05mm당 1px)
|
||||||
```
|
```
|
||||||
|
|
||||||
|
배율은 `setLineweightScale(pxPerMm)` 로 조정 가능하다(AutoCAD "표시 배율" 슬라이더 대응,
|
||||||
|
`null` 이면 기본값 복귀).
|
||||||
|
|
||||||
|
> **처음에는 8px/mm 로 넣었다가 손테스트에서 "얇다"고 반려됐다.** 정답지(AutoCAD
|
||||||
|
> 캡처)의 `도로 가장자리`(0.50mm) 선이 약 10px 인데 8px/mm 면 4px 밖에 안 된다.
|
||||||
|
> lineweight 는 줌 무관 화면 픽셀이므로 두 캡처의 픽셀 두께를 직접 비교하면 되고,
|
||||||
|
> 그 결과가 20px/mm 다. 자세한 대조는 5-5 절.
|
||||||
|
|
||||||
### 3-2. 0.25mm 이하는 헤어라인 유지 — **회귀 방지 장치**
|
### 3-2. 0.25mm 이하는 헤어라인 유지 — **회귀 방지 장치**
|
||||||
|
|
||||||
`-3`(Default)·`-1`(ByLayer → 레이어도 Default)이 도면 대부분을 차지한다.
|
`-3`(Default)·`-1`(ByLayer → 레이어도 Default)이 도면 대부분을 차지한다.
|
||||||
@@ -231,7 +239,40 @@ LWPOLYLINE · #151257
|
|||||||
|
|
||||||
cyan 픽셀 수가 감소(11502→11486) → fat 배치의 정점이 강조색으로 재도색됨을 확인.
|
cyan 픽셀 수가 감소(11502→11486) → fat 배치의 정점이 강조색으로 재도색됨을 확인.
|
||||||
|
|
||||||
### 5-4. 회귀 없음
|
### 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 | 헤어라인(MESH, Default) |
|
||||||
|
|--|--|--|
|
||||||
|
| AutoCAD 정답지 | **≈10 px** | 1 px |
|
||||||
|
| 뷰어 (8px/mm, 반려) | ≈4 px | 1 px |
|
||||||
|
| 뷰어 (20px/mm, 현재) | **10 px** | 1 px |
|
||||||
|
|
||||||
|
헤드리스 재측정으로 교차 확인: 시안색 `노면측구`(0.35mm)가 화면에서 **≈7 px**
|
||||||
|
(= 0.35 × 20). 두 클래스가 같은 배율로 맞는다.
|
||||||
|
|
||||||
|
### 5-6. 회귀 없음
|
||||||
|
|
||||||
- `npx tsc --noEmit` 통과
|
- `npx tsc --noEmit` 통과
|
||||||
- `npm run build` 통과
|
- `npm run build` 통과
|
||||||
@@ -241,8 +282,10 @@ cyan 픽셀 수가 감소(11502→11486) → fat 배치의 정점이 강조색
|
|||||||
|
|
||||||
## 6. 남은 과제
|
## 6. 남은 과제
|
||||||
|
|
||||||
1. **표시 배율 고정** — `LW_PX_PER_MM = 8` 이 상수다. AutoCAD 는 "선가중치 설정 → 표시 배율"
|
1. **표시 배율 UI 부재** — 값은 `setLineweightScale(pxPerMm)` 로 조절되지만 툴바에는
|
||||||
슬라이더로 조절 가능하므로, 필요하면 `setLineweightScale()` 로 노출할 것.
|
on/off 버튼만 있다. 슬라이더가 필요하면 이 API 에 붙이면 된다.
|
||||||
|
0.35mm 가 7px 라 `비탈면방향`(34,758개)이 있는 구간은 화면이 상당히 무거워 보인다 —
|
||||||
|
도면이 지정한 수치대로이긴 하나, 배율을 낮추고 싶으면 이 API 를 쓴다.
|
||||||
2. **ByBlock 근사** — 블록 자식의 `-2` 는 INSERT 굵기를 상속하지만, 중첩 블록에서
|
2. **ByBlock 근사** — 블록 자식의 `-2` 는 INSERT 굵기를 상속하지만, 중첩 블록에서
|
||||||
중간 INSERT 가 `-2` 인 경우까지는 추적하지 않는다(점선 처리와 동일한 기존 정책).
|
중간 INSERT 가 `-2` 인 경우까지는 추적하지 않는다(점선 처리와 동일한 기존 정책).
|
||||||
3. **DXF 레이어 굵기 없음** — `dxf-parser` 의 LAYER 핸들러가 코드 370 을 무시한다.
|
3. **DXF 레이어 굵기 없음** — `dxf-parser` 의 LAYER 핸들러가 코드 370 을 무시한다.
|
||||||
|
|||||||
Vendored
+3
@@ -19,6 +19,9 @@ export class Viewer2D {
|
|||||||
/** Lineweight display (AutoCAD LWDISPLAY); null follows the drawing's own flag. */
|
/** Lineweight display (AutoCAD LWDISPLAY); null follows the drawing's own flag. */
|
||||||
setLineweightEnabled(on: boolean | null): void;
|
setLineweightEnabled(on: boolean | null): void;
|
||||||
getLineweightEnabled(): boolean;
|
getLineweightEnabled(): boolean;
|
||||||
|
/** Lineweight display scale in px per mm (AutoCAD's display-scale slider). Default 20. */
|
||||||
|
setLineweightScale(pxPerMm: number | null): void;
|
||||||
|
getLineweightScale(): number;
|
||||||
getLayerInfo(): { name: string; colorHex: string; count: number; visible: boolean }[];
|
getLayerInfo(): { name: string; colorHex: string; count: number; visible: boolean }[];
|
||||||
setHiddenLayers(nameSet: Set<string>): void;
|
setHiddenLayers(nameSet: Set<string>): void;
|
||||||
/** Model / Paper (Layout) spaces for the loaded drawing. */
|
/** Model / Paper (Layout) spaces for the loaded drawing. */
|
||||||
|
|||||||
@@ -25,15 +25,17 @@ const CLICK_THRESHOLD_PX = 14;
|
|||||||
// ── Lineweight (AutoCAD LWDISPLAY) ─────────────────────────────────────────
|
// ── Lineweight (AutoCAD LWDISPLAY) ─────────────────────────────────────────
|
||||||
// DWG stores lineweight as an i16 in 1/100 mm (-1 ByLayer, -2 ByBlock,
|
// DWG stores lineweight as an i16 in 1/100 mm (-1 ByLayer, -2 ByBlock,
|
||||||
// -3 Default). AutoCAD shows it in *screen* pixels — the width does not grow
|
// -3 Default). AutoCAD shows it in *screen* pixels — the width does not grow
|
||||||
// when you zoom in — at roughly 8 px per mm on the default display-scale
|
// when you zoom in — at one pixel per 0.05 mm on the default display-scale
|
||||||
// slider (0.25 mm ≈ 2 px, 2.11 mm ≈ 17 px), so that is the mapping used here.
|
// slider (0.50 mm = 10 px, 2.11 mm = 42 px). Measured against an AutoCAD
|
||||||
const LW_PX_PER_MM = 8;
|
// capture of the 노면 drawing: its 0.50 mm road edge is ~10 px, so 20 px/mm.
|
||||||
|
// Host apps can retune this with setLineweightScale().
|
||||||
|
const LW_PX_PER_MM = 20;
|
||||||
// LWDEFAULT: what -3 (and a layer that never set one) resolves to.
|
// LWDEFAULT: what -3 (and a layer that never set one) resolves to.
|
||||||
const LW_DEFAULT_MM = 0.25;
|
const LW_DEFAULT_MM = 0.25;
|
||||||
// At or below the CAD default the line stays in the 1-px hairline batch: a
|
// At or below the CAD default the line stays in the 1-px hairline batch: a
|
||||||
// drawing that never assigned weights must look exactly as it did before.
|
// drawing that never assigned weights must look exactly as it did before.
|
||||||
const LW_HAIRLINE_MM = 0.25;
|
const LW_HAIRLINE_MM = 0.25;
|
||||||
const LW_MAX_PX = 24;
|
const LW_MAX_PX = 48;
|
||||||
// Fat lines cost 12 floats + 8 verts per segment (instanced quads). Past this
|
// Fat lines cost 12 floats + 8 verts per segment (instanced quads). Past this
|
||||||
// many segments in one weight bucket, fall back to hairline instead of risking
|
// many segments in one weight bucket, fall back to hairline instead of risking
|
||||||
// a GPU/heap stall on huge survey drawings.
|
// a GPU/heap stall on huge survey drawings.
|
||||||
@@ -105,6 +107,7 @@ export class Viewer2D {
|
|||||||
this._lwForced = null;
|
this._lwForced = null;
|
||||||
this._lwDisplay = false;
|
this._lwDisplay = false;
|
||||||
this._curLwPx = 0;
|
this._curLwPx = 0;
|
||||||
|
this._lwScale = null; // null = LW_PX_PER_MM (setLineweightScale)
|
||||||
SlugTextEngine.shared().catch(() => {}); // warm the font load; sprite fallback covers failure
|
SlugTextEngine.shared().catch(() => {}); // warm the font load; sprite fallback covers failure
|
||||||
|
|
||||||
this._scene = new THREE.Scene();
|
this._scene = new THREE.Scene();
|
||||||
@@ -1377,6 +1380,21 @@ export class Viewer2D {
|
|||||||
/** Whether lineweights are currently being drawn. */
|
/** Whether lineweights are currently being drawn. */
|
||||||
getLineweightEnabled() { return this._lwDisplay; }
|
getLineweightEnabled() { return this._lwDisplay; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Display scale in screen pixels per mm of lineweight — AutoCAD's
|
||||||
|
* "Adjust Display Scale" slider. Default 20 (1 px per 0.05 mm).
|
||||||
|
* @param {number|null} pxPerMm null restores the default.
|
||||||
|
*/
|
||||||
|
setLineweightScale(pxPerMm) {
|
||||||
|
this._lwScale = (pxPerMm > 0) ? pxPerMm : null;
|
||||||
|
if (this._lastResult && !this._isLoading) {
|
||||||
|
this.load(this._lastResult, { keepView: true, keepTheme: true, spaceHandle: this._activeSpaceHex });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Current lineweight display scale (px per mm). */
|
||||||
|
getLineweightScale() { return this._lwScale || LW_PX_PER_MM; }
|
||||||
|
|
||||||
/** Track an entity-owned object so layer toggles can flip its visibility. */
|
/** Track an entity-owned object so layer toggles can flip its visibility. */
|
||||||
_addObj(obj, layer) {
|
_addObj(obj, layer) {
|
||||||
const key = layer ?? this._curLayer;
|
const key = layer ?? this._curLayer;
|
||||||
@@ -2334,7 +2352,8 @@ export class Viewer2D {
|
|||||||
}
|
}
|
||||||
const mm = raw === -3 ? LW_DEFAULT_MM : raw / 100;
|
const mm = raw === -3 ? LW_DEFAULT_MM : raw / 100;
|
||||||
if (!(mm > LW_HAIRLINE_MM)) return 0;
|
if (!(mm > LW_HAIRLINE_MM)) return 0;
|
||||||
return Math.min(LW_MAX_PX, Math.round(mm * LW_PX_PER_MM * 10) / 10);
|
const scale = this._lwScale || LW_PX_PER_MM;
|
||||||
|
return Math.min(LW_MAX_PX, Math.round(mm * scale * 10) / 10);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Active-viewport VIEWTWIST (radians). The sheet is un-twisted by rotating the
|
// Active-viewport VIEWTWIST (radians). The sheet is un-twisted by rotating the
|
||||||
|
|||||||
Reference in New Issue
Block a user