From 3f4c38cf68403d2960368f4a69a9339c82fb1c6e Mon Sep 17 00:00:00 2001 From: ysCha Date: Wed, 8 Jul 2026 16:44:25 +0900 Subject: [PATCH] =?UTF-8?q?[2321]=20=EC=88=98=EB=8F=99=EB=B0=B0=EC=B9=98?= =?UTF-8?q?=20=E5=8D=83=E9=B3=A5(=EC=B9=98=EB=8F=84=EB=A6=AC)=20=EA=B0=95?= =?UTF-8?q?=EC=A0=9C=EC=A0=95=EB=A0=AC=20=E2=80=94=20=EB=B6=88=EA=B0=80?= =?UTF-8?q?=EB=A9=B4=C2=B7=E3=80=8C=ED=95=98=EC=A7=80=EC=95=8A=EB=8A=94?= =?UTF-8?q?=EB=8B=A4=E3=80=8D=20=EB=93=9C=EB=9E=98=EA=B7=B8=EB=8F=84=20?= =?UTF-8?q?=EA=B2=A9=EC=9E=90=20=ED=9D=A1=EC=B0=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Opus 4 --- src/hooks/module/useModuleBasicSetting.js | 49 +++++++++++++++++++++-- 1 file changed, 45 insertions(+), 4 deletions(-) diff --git a/src/hooks/module/useModuleBasicSetting.js b/src/hooks/module/useModuleBasicSetting.js index 7907f79e..7d1cebfd 100644 --- a/src/hooks/module/useModuleBasicSetting.js +++ b/src/hooks/module/useModuleBasicSetting.js @@ -650,6 +650,15 @@ export function useModuleBasicSetting(tabNum) { } }, [isManualModuleSetup, isManualModuleLayoutSetup]) + // [MANUAL-CHIDORI-BY-FACE 2026-07-08] 千鳥(치도리) 가부는 지붕재(면)별로 다르다(plvrYn). + // 千鳥 라디오가 전역 ON이어도 커서 밑 면이 不可(plvrYn==='N')면 그 면에선 千鳥 스냅을 끄고 정렬로 배치한다. + const isChidoriAllowedForFace = (face) => { + const roofIndex = face?.roofMaterial?.index + if (roofIndex == null) return true + const plvrYn = moduleSelectionData?.roofConstructions?.find((c) => Number(c.roofIndex) === Number(roofIndex))?.construction?.plvrYn + return plvrYn !== 'N' + } + /** * trestle에서 영역을 가져와 mouse:move 이벤트로 해당 영역에 진입했을때 booleanPointInPolygon 로 진입여부를 확인 * 확인 후 셀을 이동시킴 @@ -679,6 +688,14 @@ export function useModuleBasicSetting(tabNum) { return } + // [MANUAL-SURFACE-GATE 2026-07-08] 자동배치와 동일하게 선택된 설치면이 없으면 배치 불가 (선택 없이는 千鳥 판정 대상도 없음) + if (moduleSetupSurface.length === 0) { + swalFire({ text: getMessage('module.place.no.surface'), icon: 'warning' }) + setIsManualModuleSetup(false) + setManualSetupMode(`manualSetup_false`) + return + } + const batchObjects = canvas?.getObjects().filter((obj) => obj.name === POLYGON_TYPE.OBJECT_SURFACE) //도머s 객체 //수동모드 모듈 설치면 선택 잠금 moduleSetupSurfaces.forEach((obj) => { @@ -843,7 +860,7 @@ export function useModuleBasicSetting(tabNum) { tempModule.left = holdCellCenterX - toFixedWithoutRounding(width / 2, 2) } - if (isChidori) { + if (isChidori && isChidoriAllowedForFace(moduleSetupSurfaces[i])) { //움직이는 모듈왼쪽 -> 가운데 if (Math.abs(smallLeft - holdCellCenterX) < snapDistance) { tempModule.left = holdCellCenterX + intvHor / 2 @@ -886,7 +903,7 @@ export function useModuleBasicSetting(tabNum) { tempModule.top = holdCellCenterY - toFixedWithoutRounding(height / 2, 2) } - if (isChidori) { + if (isChidori && isChidoriAllowedForFace(moduleSetupSurfaces[i])) { //위쪽 -> 가운데 if (Math.abs(smallTop - holdCellCenterY) < snapDistance) { tempModule.top = holdCellCenterY + intvHor / 2 @@ -986,6 +1003,19 @@ export function useModuleBasicSetting(tabNum) { // } } + // [MANUAL-CHIDORI-BY-FACE 2026-07-08] 千鳥는 「가능면 + 한다」일 때만 허용. 그 외(불가면 전부 / 가능면이어도 「하지 않는다」)는 手動 드래그도 정렬 강제. + // 사용자가 반칸 어긋난 위치에 놓아도 기존 모듈 열/행 격자(pitch)에 흡착시켜 치도리를 제거한다. + if (!(isChidori && isChidoriAllowedForFace(moduleSetupSurfaces[i])) && manualDrawModules && manualDrawModules.length > 0) { + const gridRef = manualDrawModules[0] + if (flowDirection === 'south' || flowDirection === 'north') { + const pitchX = width + intvHor + if (pitchX > 0) tempModule.left = gridRef.left + Math.round((tempModule.left - gridRef.left) / pitchX) * pitchX + } else { + const pitchY = height + intvVer + if (pitchY > 0) tempModule.top = gridRef.top + Math.round((tempModule.top - gridRef.top) / pitchY) * pitchY + } + } + tempModule.setCoords() canvas?.renderAll() inside = true @@ -1194,6 +1224,14 @@ export function useModuleBasicSetting(tabNum) { return } + // [MANUAL-SURFACE-GATE 2026-07-08] 자동배치와 동일하게 선택된 설치면이 없으면 배치 불가 + if (moduleSetupSurface.length === 0) { + swalFire({ text: getMessage('module.place.no.surface'), icon: 'warning' }) + setIsManualModuleLayoutSetup(false) + setManualSetupMode(`manualLayoutSetup_false`) + return + } + const batchObjects = canvas?.getObjects().filter((obj) => obj.name === POLYGON_TYPE.OBJECT_SURFACE) //도머s 객체 //수동모드 모듈 설치면 선택 잠금 moduleSetupSurfaces.forEach((obj) => { @@ -1396,7 +1434,7 @@ export function useModuleBasicSetting(tabNum) { tempModule.left = holdCellCenterX - toFixedWithoutRounding(width / 2, 2) } - if (isChidori) { + if (isChidori && isChidoriAllowedForFace(moduleSetupSurfaces[i])) { //움직이는 모듈왼쪽 -> 가운데 if (Math.abs(smallLeft - holdCellCenterX) < snapDistance) { tempModule.left = holdCellCenterX + intvHor / 2 @@ -1439,7 +1477,7 @@ export function useModuleBasicSetting(tabNum) { tempModule.top = holdCellCenterY - toFixedWithoutRounding(width / 2, 2) } - if (isChidori) { + if (isChidori && isChidoriAllowedForFace(moduleSetupSurfaces[i])) { //위쪽 -> 가운데 if (Math.abs(smallTop - holdCellCenterY) < snapDistance) { tempModule.top = holdCellCenterY + intvHor / 2 @@ -1587,6 +1625,9 @@ export function useModuleBasicSetting(tabNum) { if (tempModule) { saveSnapshot() + // [MANUAL-CHIDORI-BY-FACE 2026-07-08] 지정배치 그리드 대상 면(trestlePolygon)이 千鳥 不可(plvrYn==='N')면 千鳥 오프셋 없이 정렬 배치. + // 아래 그리드 생성부의 isChidori 는 이 면 기준 값을 따른다(전역 라디오가 ON이어도 不可면 정렬). + const isChidori = moduleSetupOption.isChidori && isChidoriAllowedForFace(trestlePolygon) let startX, startY let installedLastHeightCoord = 0 //마지막으로 설치된 모듈의 좌표 let installedHeightModuleCount = 0