From 5b993dddedc941852cd262b68f2ed79ff958bba2 Mon Sep 17 00:00:00 2001 From: umsangdon Date: Sat, 17 Oct 2026 16:07:12 +0900 Subject: [PATCH] =?UTF-8?q?fix(380-4):=20=EA=B8=80=EB=A7=8C=20=EC=9E=88?= =?UTF-8?q?=EB=8A=94=20=EC=83=81=EC=84=B8=20=ED=91=9C=20=EC=9C=84=20CAD=20?= =?UTF-8?q?=EA=B3=BC=ED=99=95=EB=8C=80=20=E2=80=94=20=EB=A7=9E=EC=B6=A4=20?= =?UTF-8?q?=EC=B5=9C=EC=86=8C=20=EB=86=92=EC=9D=B4=20=EA=B3=81=EA=B0=92?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - CAD 맞춤(fitView) = 범위를 위 끝에서 아래로 최소 높이까지 늘림 · 부모가 실을 때 fitMinHeight 로 보냄(안 보내면 종전 그대로) - B06 상세 표 위 CAD = 16(원 마크 아래 끝 ~ 첫 줄 위) — 사토장 등 글만 있는 측점도 배관 측점과 같은 글 크기 · 둘째 줄 안 잘림 - 시험 resources/tester/cad/fit-min-height(종전 3배 넘는 확대 · 같은 배율 · 위 끝 같음 · 큰 범위 그대로) Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01VmC34fsxxbweEG3RUjs3Mn --- .../B06_Section_UI_Cross_Detail_Cad.ts | 3 ++ .../src/drawControllers/fit-view.ts | 12 ++++- .../src/integration/aislo-drawing-bridge.ts | 4 ++ resources/tester/cad/fit-min-height.test.ts | 46 +++++++++++++++++++ ui_template/cad_host/cad_host.ts | 2 + 5 files changed, 66 insertions(+), 1 deletion(-) create mode 100644 resources/tester/cad/fit-min-height.test.ts diff --git a/B06_Section/B06_Section_UI_Cross_Detail_Cad.ts b/B06_Section/B06_Section_UI_Cross_Detail_Cad.ts index d7fd17bed..b9682361d 100644 --- a/B06_Section/B06_Section_UI_Cross_Detail_Cad.ts +++ b/B06_Section/B06_Section_UI_Cross_Detail_Cad.ts @@ -73,6 +73,8 @@ const LAYER_ID = "기본"; const BLANK_LAYER = { id: LAYER_ID, name: "기본", isVisible: true, isLocked: false }; const FONT = 2.0; const LINE = 3.0; +/** 표 위 CAD 맞춤 최소 높이 — 원 마크 아래 끝(−15.5) ~ 첫 줄 위(+0.5) · 글만 있는 측점도 같은 글 크기(380-4). */ +const NOTE_FIT_HEIGHT = 16; /** 옛 글 색 = B07 표 글(`TABLE_LABEL_COLOR`) · 미리 넣음 = 그림처럼 붉은 계열. */ const NOTE_COLOR = "#e8edf4"; const CULVERT_COLOR = "#ff7f7f"; @@ -344,6 +346,7 @@ export function mountNoteCad( recoveryScope: scope, hostTitle: "표 위 CAD", bare: true, + fitMinHeight: NOTE_FIT_HEIGHT, }, ); }); diff --git a/B07_DesignDetail/openwebcad/src/drawControllers/fit-view.ts b/B07_DesignDetail/openwebcad/src/drawControllers/fit-view.ts index bdfe2e259..71dfdf113 100644 --- a/B07_DesignDetail/openwebcad/src/drawControllers/fit-view.ts +++ b/B07_DesignDetail/openwebcad/src/drawControllers/fit-view.ts @@ -18,9 +18,19 @@ export function fitEntities(): Entity[] { return structureFrame.length ? structureFrame : pickable.length ? pickable : getEntities(); } +/** 맞춤 최소 높이(월드) — 부모가 도면마다 보냄(`fitMinHeight` · 380-4) · 0 = 없음. */ +let fitMinHeight = 0; + +/** 실을 때마다 부르는 값 — 수 아니면 0(B07 등 안 보내는 쪽 = 종전 그대로). */ +export const setFitMinHeight = (value: unknown): void => { + fitMinHeight = typeof value === 'number' && value > 0 ? value : 0; +}; + /** 개체 범위를 화면 가운데에 놓는 배율 · 화면 원점(월드 좌표) */ export function fitView(entities: Entity[], canvasSize: Point): { zoom: number; offset: Point } { - const boundingBox = getBoundingBoxOfMultipleEntities(entities); + const boundingBox = { ...getBoundingBoxOfMultipleEntities(entities) }; + // 글 몇 줄뿐인 도면이 칸 높이로 과확대되지 않게 — 범위를 위 끝에서 아래로 최소 높이까지 늘림 + boundingBox.minY = Math.min(boundingBox.minY, boundingBox.maxY - fitMinHeight); const boundingWidth = boundingBox.maxX - boundingBox.minX; const boundingHeight = boundingBox.maxY - boundingBox.minY; diff --git a/B07_DesignDetail/openwebcad/src/integration/aislo-drawing-bridge.ts b/B07_DesignDetail/openwebcad/src/integration/aislo-drawing-bridge.ts index 029dc0a27..397bd25e0 100644 --- a/B07_DesignDetail/openwebcad/src/integration/aislo-drawing-bridge.ts +++ b/B07_DesignDetail/openwebcad/src/integration/aislo-drawing-bridge.ts @@ -26,6 +26,7 @@ import { setBare, } from '../state.ts'; import { setInspectorCollapsed, setRibbonCollapsed } from '../components/ui-state.ts'; +import { setFitMinHeight } from '../drawControllers/fit-view.ts'; import { runCommandInput } from '../commands/run-command.ts'; import { setRecoveryScope } from '../helpers/autosave.ts'; import { registerBoxResizeDrag } from './box-resize-drag.ts'; @@ -73,6 +74,8 @@ interface DrawingLoadMessage { /** 캔버스만 — 제목줄 · 리본 · 패널 · 상태막대를 안 그림(B07 평면도 관리 모달). */ bare?: boolean; originMarker?: boolean; + /** 맞춤 최소 높이(월드) — 글만 있는 작은 도면 과확대 막음(B06 상세 표 위 CAD · 380-4). */ + fitMinHeight?: number; /** 작도 영역 가이드 — {area, marks?, editable?} · 없으면 가이드 없음(`guide-area.ts`). */ guide?: unknown; } @@ -197,6 +200,7 @@ export function registerAisloDrawingBridge() { runCommandInput('SELECT'); // 자동백업을 이 도면 칸으로 옮긴다 — 안 옮기면 백업 한 칸을 서로 덮는다. setRecoveryScope(event.data.recoveryScope ?? event.data.meta?.drawingId ?? null); + setFitMinHeight(event.data.fitMinHeight); getScreenCanvasDrawController().zoomToFitScreen(); notifyParent(AISLO_DRAWING_LOADED_MESSAGE); } catch (error) { diff --git a/resources/tester/cad/fit-min-height.test.ts b/resources/tester/cad/fit-min-height.test.ts new file mode 100644 index 000000000..11af222da --- /dev/null +++ b/resources/tester/cad/fit-min-height.test.ts @@ -0,0 +1,46 @@ +/** + * 380-4 맞춤 최소 높이 — 글만 있는 작은 도면(B06 상세 「표 위 CAD」 사토장 측점)이 칸 높이로 과확대되지 않음. + * 실행: cd B07_DesignDetail/openwebcad && npx vitest run --dir ../../resources/tester/cad fit-min-height + */ +import { Point } from '@flatten-js/core'; +import { afterEach, describe, expect, it } from 'vitest'; +import type { Entity } from '../../../B07_DesignDetail/openwebcad/src/entities/Entity'; +import { fitView, setFitMinHeight } from '../../../B07_DesignDetail/openwebcad/src/drawControllers/fit-view'; + +const box = (xmin: number, ymin: number, xmax: number, ymax: number) => + ({ getBoundingBox: () => ({ xmin, ymin, xmax, ymax }) }) as unknown as Entity; + +// 표 위 CAD 칸(가로로 긴 칸) · 원 마크 측점 = 원(−15.5 ~ −2.5) + 넉 줄 글(위 끝 +0.5) +const CANVAS = new Point(1500, 200); +const PIPE = [box(0, -15.5, 13, -2.5), box(15, -10.5, 60, 0.5)]; +// 글만 있는 측점 = 두 줄(「NO.5」 · 「유용토운반작업장(사토장)」) +const TEXT_ONLY = [box(0, -4.5, 28, 0.5)]; + +afterEach(() => setFitMinHeight(undefined)); + +describe('맞춤 최소 높이(fitMinHeight)', () => { + it('안 보내면 종전 그대로 — 글만 있는 도면은 원 마크 측점보다 3배 넘게 확대', () => { + const pipe = fitView(PIPE, CANVAS).zoom; + const text = fitView(TEXT_ONLY, CANVAS).zoom; + expect(text / pipe).toBeGreaterThan(3); + }); + + it('16 을 보내면 글만 있는 측점도 원 마크 측점과 같은 배율 · 위 끝 그대로', () => { + setFitMinHeight(16); + const pipe = fitView(PIPE, CANVAS); + const text = fitView(TEXT_ONLY, CANVAS); + expect(text.zoom).toBeCloseTo(pipe.zoom, 6); + // 위 끝(+0.5)이 같은 화면 높이 — 화면 위 끝 월드 y = offset.y + 칸 높이 / 배율 + const top = (view: { zoom: number; offset: Point }) => view.offset.y + CANVAS.y / view.zoom; + expect(top(text)).toBeCloseTo(top(pipe), 6); + }); + + it('범위가 최소 높이보다 크면 그대로 · 숫자 아니면 0', () => { + setFitMinHeight(16); + const tall = [box(0, -40, 50, 0.5)]; + const zoom = fitView(tall, CANVAS).zoom; + setFitMinHeight('16'); + expect(fitView(tall, CANVAS).zoom).toBeCloseTo(zoom, 6); + expect(fitView(TEXT_ONLY, CANVAS).zoom).toBeGreaterThan(fitView(PIPE, CANVAS).zoom * 3); + }); +}); diff --git a/ui_template/cad_host/cad_host.ts b/ui_template/cad_host/cad_host.ts index 27cfaf37d..1947b26e7 100644 --- a/ui_template/cad_host/cad_host.ts +++ b/ui_template/cad_host/cad_host.ts @@ -99,6 +99,8 @@ export interface CadLoadExtra { bare?: boolean; /** 좌표 0,0 에 기준점 십자를 그린다(그리기 겹판 · 저장 안 됨) — 안 보내면 없음. */ originMarker?: boolean; + /** 맞춤 최소 높이(월드) — 글만 있는 작은 도면 과확대 막음(380-4) · 안 보내면 범위 그대로. */ + fitMinHeight?: number; /** 작도 영역 가이드(169-1) — 안 보내면 없음. */ guide?: CadGuide | null; }