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:
minsung
2026-08-04 20:34:27 +09:00
co-authored by Claude Opus 5
parent ce3859c487
commit cf1298749b
5 changed files with 6051 additions and 11 deletions
+24 -5
View File
@@ -25,15 +25,17 @@ const CLICK_THRESHOLD_PX = 14;
// ── Lineweight (AutoCAD LWDISPLAY) ─────────────────────────────────────────
// 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
// when you zoom in — at roughly 8 px per mm on the default display-scale
// slider (0.25 mm ≈ 2 px, 2.11 mm ≈ 17 px), so that is the mapping used here.
const LW_PX_PER_MM = 8;
// when you zoom in — at one pixel per 0.05 mm on the default display-scale
// slider (0.50 mm = 10 px, 2.11 mm = 42 px). Measured against an AutoCAD
// 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.
const LW_DEFAULT_MM = 0.25;
// 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.
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
// many segments in one weight bucket, fall back to hairline instead of risking
// a GPU/heap stall on huge survey drawings.
@@ -105,6 +107,7 @@ export class Viewer2D {
this._lwForced = null;
this._lwDisplay = false;
this._curLwPx = 0;
this._lwScale = null; // null = LW_PX_PER_MM (setLineweightScale)
SlugTextEngine.shared().catch(() => {}); // warm the font load; sprite fallback covers failure
this._scene = new THREE.Scene();
@@ -1377,6 +1380,21 @@ export class Viewer2D {
/** Whether lineweights are currently being drawn. */
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. */
_addObj(obj, layer) {
const key = layer ?? this._curLayer;
@@ -2334,7 +2352,8 @@ export class Viewer2D {
}
const mm = raw === -3 ? LW_DEFAULT_MM : raw / 100;
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