From 28ea1e9b8e6740dc67a637e66cb382b4cf23b981 Mon Sep 17 00:00:00 2001 From: sangwook yoo Date: Wed, 24 Jun 2026 14:51:53 +0900 Subject: [PATCH] =?UTF-8?q?feat(roof-shape):=20PDF=20=EC=A7=80=EB=B6=95?= =?UTF-8?q?=ED=98=95=EC=83=81=20descriptor=20atom=20=EC=A0=80=EC=9E=A5=20?= =?UTF-8?q?=EB=B0=B0=EC=84=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [작업내용] : - pdfRoofShapeDescriptorState atom 추가(outerLineAtom) - analyzePdfAndApply: 분석 시작 시 리셋 + payload.roofShape 저장 - 소비(매칭·pre-select)는 다음 task Co-Authored-By: Claude Opus 4.8 --- .../modal/placementShape/PlacementShapeSetting.jsx | 5 +++++ src/store/outerLineAtom.js | 9 +++++++++ 2 files changed, 14 insertions(+) diff --git a/src/components/floor-plan/modal/placementShape/PlacementShapeSetting.jsx b/src/components/floor-plan/modal/placementShape/PlacementShapeSetting.jsx index 518ee43d..ba74f42d 100644 --- a/src/components/floor-plan/modal/placementShape/PlacementShapeSetting.jsx +++ b/src/components/floor-plan/modal/placementShape/PlacementShapeSetting.jsx @@ -24,6 +24,7 @@ import { usePlan } from '@/hooks/usePlan' import { normalizeDecimal } from '@/util/input-utils' import { CalculatorInput } from '@/components/common/input/CalcInput' import { usePdfImport } from '@/hooks/pdf-import/usePdfImport' +import { pdfRoofShapeDescriptorState } from '@/store/outerLineAtom' import { logger } from '@/util/logger' import { QcastContext } from '@/app/QcastProvider' // [LOW-PITCH-WARN 2026-05-06] 저구배 + 특정 기와 사용 시 시공 매뉴얼 안내 alert @@ -87,6 +88,7 @@ export default function PlacementShapeSetting({ id, pos = { x: 50, y: 180 }, pla const { setPolygonLinesActualSize } = usePolygon() const { setSelectedMenu } = useCanvasMenu() const setCurrentMenu = useSetRecoilState(currentMenuState) + const setPdfRoofShapeDescriptor = useSetRecoilState(pdfRoofShapeDescriptorState) const roofRef = { roofCd: useRef(null), @@ -174,6 +176,7 @@ export default function PlacementShapeSetting({ id, pos = { x: 50, y: 180 }, pla formData.append('floorPages', pdfFloorPages.trim()) } + setPdfRoofShapeDescriptor(null) // 이전 분석 잔여 제거(cross-run staleness 방지) setPdfAnalyzing(true) setIsGlobalLoading(true) const controller = new AbortController() @@ -239,6 +242,8 @@ export default function PlacementShapeSetting({ id, pos = { x: 50, y: 180 }, pla return false } + setPdfRoofShapeDescriptor(payload.roofShape ?? null) // 지붕형상 자동 선택용(C) + // 외벽선은 항상 미확정(autoFix:false)으로만 그린다 — 확정 여부는 이후 '외벽선 자동 확정' 팝업에서 분기한다. const applied = await applyOuterline(payload.outerline, { unit: payload.unit || 'mm', autoFix: false }) if (!applied) { diff --git a/src/store/outerLineAtom.js b/src/store/outerLineAtom.js index b1779609..c660bc71 100644 --- a/src/store/outerLineAtom.js +++ b/src/store/outerLineAtom.js @@ -77,3 +77,12 @@ export const autoOuterLineFixState = atom({ key: 'autoOuterLineFixState', default: true, }) + +/** + * PDF 분석이 산출한 지붕형상 서술자(RoofShapeDescriptor | null). + * analyzePdfAndApply 가 저장 → useRoofShapeSetting 마운트 시 매칭·소비(consume-once). + */ +export const pdfRoofShapeDescriptorState = atom({ + key: 'pdfRoofShapeDescriptorState', + default: null, +})