128 lines
4.4 KiB
TypeScript
128 lines
4.4 KiB
TypeScript
/* =============================================================================
|
|
* B07_wf4_DesignDetail_UI_CadViewer.ts
|
|
* WebCAD PoC 뷰어 — cad-simple-viewer(MIT) 부트스트랩 + 기하 JSON 렌더링
|
|
*
|
|
* 아키텍처 (PLAN.md WebCAD 합의):
|
|
* - 브라우저는 DXF/DWG를 파싱하지 않는다. GPL 컨버터는 vite 별칭 스텁으로 차단.
|
|
* - 서버(ezdxf)가 보낸 기하 JSON을 data-model(MIT) API로 도면 DB에 직접 구성.
|
|
* - AcApDocManager는 싱글톤이므로 뷰어 컨테이너를 모듈 수준에 유지하고
|
|
* 페이지 재진입 시 새 레이아웃에 재부착한다.
|
|
* ========================================================================== */
|
|
|
|
import { AcApDocManager } from "@mlightcad/cad-simple-viewer";
|
|
import {
|
|
acdbHostApplicationServices,
|
|
AcCmColor,
|
|
AcDbLayerTableRecord,
|
|
AcDbLine,
|
|
AcDbPolyline,
|
|
AcDbText,
|
|
AcGePoint2d,
|
|
AcGePoint3d,
|
|
} from "@mlightcad/data-model";
|
|
import type { CadDrawingJson, CadEntityJson } from "./B07_wf4_DesignDetail_Api_Fetch";
|
|
|
|
/** 뷰어 캔버스를 담는 영속 컨테이너 (SPA 라우팅 간 유지) */
|
|
let viewerHolder: HTMLDivElement | null = null;
|
|
/** 도면 JSON이 이미 DB에 적재되었는지 여부 (PoC: 1회 적재) */
|
|
let drawingLoaded = false;
|
|
|
|
function ensureViewerHolder(): HTMLDivElement {
|
|
if (!viewerHolder) {
|
|
viewerHolder = document.createElement("div");
|
|
viewerHolder.className = "b07-cad-canvas";
|
|
}
|
|
return viewerHolder;
|
|
}
|
|
|
|
function ensureDocManager(holder: HTMLDivElement): AcApDocManager {
|
|
try {
|
|
return AcApDocManager.instance;
|
|
} catch {
|
|
// 최초 1회 생성 — 워커 미배포 환경이므로 MTEXT는 메인 스레드 렌더링 사용.
|
|
AcApDocManager.createInstance({
|
|
container: holder,
|
|
autoResize: true,
|
|
useMainThreadDraw: true,
|
|
});
|
|
return AcApDocManager.instance;
|
|
}
|
|
}
|
|
|
|
function toEntity(json: CadEntityJson): AcDbLine | AcDbPolyline | AcDbText | null {
|
|
if (json.type === "LWPOLYLINE" && json.points && json.points.length >= 2) {
|
|
const polyline = new AcDbPolyline();
|
|
json.points.forEach(([x, y], index) => {
|
|
polyline.addVertexAt(index, new AcGePoint2d(x, y));
|
|
});
|
|
polyline.closed = json.closed ?? false;
|
|
polyline.layer = json.layer;
|
|
return polyline;
|
|
}
|
|
if (json.type === "LINE" && json.start && json.end) {
|
|
const line = new AcDbLine(
|
|
new AcGePoint3d(json.start[0], json.start[1], 0),
|
|
new AcGePoint3d(json.end[0], json.end[1], 0),
|
|
);
|
|
line.layer = json.layer;
|
|
return line;
|
|
}
|
|
if (json.type === "TEXT" && json.text && json.insert) {
|
|
const text = new AcDbText();
|
|
text.textString = json.text;
|
|
text.position = new AcGePoint3d(json.insert[0], json.insert[1], 0);
|
|
text.height = json.height ?? 2.5;
|
|
text.rotation = ((json.rotation ?? 0) * Math.PI) / 180;
|
|
text.layer = json.layer;
|
|
return text;
|
|
}
|
|
return null;
|
|
}
|
|
|
|
function loadDrawingIntoDatabase(manager: AcApDocManager, drawing: CadDrawingJson): number {
|
|
const db = manager.curDocument.database;
|
|
db.createDefaultData();
|
|
|
|
for (const layerJson of drawing.layers) {
|
|
const color = new AcCmColor();
|
|
color.colorIndex = layerJson.color_aci;
|
|
db.tables.layerTable.add(new AcDbLayerTableRecord({ name: layerJson.name, color }));
|
|
}
|
|
|
|
const modelSpace = db.tables.blockTable.modelSpace;
|
|
let appended = 0;
|
|
for (const entityJson of drawing.entities) {
|
|
const entity = toEntity(entityJson);
|
|
if (entity) {
|
|
modelSpace.appendEntity(entity);
|
|
appended += 1;
|
|
}
|
|
}
|
|
return appended;
|
|
}
|
|
|
|
/**
|
|
* PoC CAD 뷰어를 host에 부착하고 서버 기하 JSON을 렌더링한다.
|
|
* @returns 적재된 엔티티 수 (재진입 시 0 — 이미 적재됨)
|
|
*/
|
|
export function mountPocCadViewer(host: HTMLElement, drawing: CadDrawingJson): number {
|
|
const holder = ensureViewerHolder();
|
|
host.append(holder);
|
|
|
|
const manager = ensureDocManager(holder);
|
|
let appended = 0;
|
|
if (!drawingLoaded) {
|
|
appended = loadDrawingIntoDatabase(manager, drawing);
|
|
drawingLoaded = true;
|
|
|
|
// 파일 오픈 흐름이 아니므로 layoutSwitched 이벤트를 직접 발화해야
|
|
// 뷰가 레이아웃 뷰 생성·가시화·초기 줌을 수행한다 (미발화 시 빈 화면).
|
|
const db = manager.curDocument.database;
|
|
const modelSpaceBtrId = db.tables.blockTable.modelSpace.objectId;
|
|
manager.setActiveLayout();
|
|
acdbHostApplicationServices().layoutManager.setCurrentLayoutBtrId(modelSpaceBtrId, db);
|
|
manager.curView.zoomToFitDrawing();
|
|
}
|
|
return appended;
|
|
}
|