From 61ffcee949385551d1f966a940a68ab767eed7e9 Mon Sep 17 00:00:00 2001 From: sangwook yoo Date: Wed, 24 Jun 2026 10:50:35 +0900 Subject: [PATCH] =?UTF-8?q?feat(roof-shape):=20=EC=A7=80=EB=B6=95=ED=98=95?= =?UTF-8?q?=EC=83=81=20=ED=8C=A8=ED=84=B4=20=EC=B9=B4=ED=83=88=EB=A1=9C?= =?UTF-8?q?=EA=B7=B8=20=EC=83=81=EC=88=98=20=EB=AA=A8=EB=93=88=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [작업내용] : - ROOF_SHAPE_PATTERNS(8) + ROOF_FLOW/ROOF_SHAPE_TYPE/ROOF_RIDGE 상수 - 매칭 키 type+ridge+flows, flows 집합만으로 8패턴 유일 식별 - getRoofShapePatternByShapeNum 접근자 - 매칭 함수·PDF 분석 확장은 다음 작업으로 분리 Co-Authored-By: Claude Opus 4.8 --- src/common/roofShapePattern.js | 106 +++++++++++++++++++++++++++++++++ 1 file changed, 106 insertions(+) create mode 100644 src/common/roofShapePattern.js diff --git a/src/common/roofShapePattern.js b/src/common/roofShapePattern.js new file mode 100644 index 00000000..1a4a1abc --- /dev/null +++ b/src/common/roofShapePattern.js @@ -0,0 +1,106 @@ +// 지붕형상 설정 팝업(RoofShapeSetting)의 8개 패턴 카탈로그. +// PDF 분석→지붕형상 자동 매칭의 룩업 테이블. 매칭 키: type + ridge + flows(집합). +// 설계 근거: docs/superpowers/specs/2026-06-24-roof-shape-pattern-catalog-design.md + +// 화면축 흐름방향 (방위적용 前 — 지붕형상 설정 시점에는 실제 방위가 없다) +export const ROOF_FLOW = { TOP: 'top', BOTTOM: 'bottom', LEFT: 'left', RIGHT: 'right' } + +// 지붕 유형 +export const ROOF_SHAPE_TYPE = { HIP: 'hip', GABLE: 'gable', SHED: 'shed', MANUAL: 'manual' } + +// 용마루 방향 +export const ROOF_RIDGE = { HIP: 'hip', HORIZONTAL: 'horizontal', VERTICAL: 'vertical', SHED: 'shed', NONE: 'none' } + +// shapeNum = useRoofShapeSetting.shapeMenu 의 id 이자 자동 클릭 대상(setShapeNum 값). +// flows 집합만으로 8패턴이 상호 유일하게 식별된다. +// 5~8 화면축↔버튼 매핑은 useRoofShapeSetting case 4~8 에서 전사(정규 winding: outerLines[0].direction==='bottom'). +export const ROOF_SHAPE_PATTERNS = [ + { + shapeNum: 1, + key: 'ridge', + nameKey: 'modal.roof.shape.setting.ridge', + type: ROOF_SHAPE_TYPE.HIP, + ridge: ROOF_RIDGE.HIP, + flows: [ROOF_FLOW.TOP, ROOF_FLOW.BOTTOM, ROOF_FLOW.LEFT, ROOF_FLOW.RIGHT], + autoMatchable: true, + note: '寄棟 — 전 변 처마, 사방 흐름', + }, + { + shapeNum: 2, + key: 'patternA', + nameKey: 'modal.roof.shape.setting.patten.a', + type: ROOF_SHAPE_TYPE.GABLE, + ridge: ROOF_RIDGE.HORIZONTAL, + flows: [ROOF_FLOW.TOP, ROOF_FLOW.BOTTOM], + autoMatchable: true, + note: '切妻 — 상하 처마/좌우 케라바, 가로 용마루', + }, + { + shapeNum: 3, + key: 'patternB', + nameKey: 'modal.roof.shape.setting.patten.b', + type: ROOF_SHAPE_TYPE.GABLE, + ridge: ROOF_RIDGE.VERTICAL, + flows: [ROOF_FLOW.LEFT, ROOF_FLOW.RIGHT], + autoMatchable: true, + note: '切妻 — 좌우 처마/상하 케라바, 세로 용마루', + }, + { + shapeNum: 5, + key: 'west', + nameKey: 'commons.west', + type: ROOF_SHAPE_TYPE.SHED, + ridge: ROOF_RIDGE.SHED, + flows: [ROOF_FLOW.BOTTOM], + direction: 'west', + autoMatchable: true, + note: '片流れ — 처마/흐름 bottom, 케라바 좌우', + }, + { + shapeNum: 6, + key: 'east', + nameKey: 'commons.east', + type: ROOF_SHAPE_TYPE.SHED, + ridge: ROOF_RIDGE.SHED, + flows: [ROOF_FLOW.TOP], + direction: 'east', + autoMatchable: true, + note: '片流れ — 처마/흐름 top, 케라바 좌우', + }, + { + shapeNum: 7, + key: 'south', + nameKey: 'commons.south', + type: ROOF_SHAPE_TYPE.SHED, + ridge: ROOF_RIDGE.SHED, + flows: [ROOF_FLOW.RIGHT], + direction: 'south', + autoMatchable: true, + note: '片流れ — 처마/흐름 right, 케라바 상하', + }, + { + shapeNum: 8, + key: 'north', + nameKey: 'commons.north', + type: ROOF_SHAPE_TYPE.SHED, + ridge: ROOF_RIDGE.SHED, + flows: [ROOF_FLOW.LEFT], + direction: 'north', + autoMatchable: true, + note: '片流れ — 처마/흐름 left, 케라바 상하', + }, + { + // 변별로 설정 — 자동매칭 비대상(폴백). 깨끗한 매칭 실패 시 후보로만 표시. + shapeNum: 4, + key: 'side', + nameKey: 'modal.roof.shape.setting.side', + type: ROOF_SHAPE_TYPE.MANUAL, + ridge: ROOF_RIDGE.NONE, + flows: [], + autoMatchable: false, + note: '변별로 설정 — 자동매칭 비대상(폴백)', + }, +] + +// shapeNum 으로 카탈로그 항목 조회. 없으면 null. +export const getRoofShapePatternByShapeNum = (shapeNum) => ROOF_SHAPE_PATTERNS.find((pattern) => pattern.shapeNum === shapeNum) || null