[2321] 수동배치 千鳥(치도리) 강제정렬 — 불가면·「하지않는다」 드래그도 격자 흡착

Co-Authored-By: Claude Opus 4 <noreply@anthropic.com>
This commit is contained in:
ysCha 2026-07-08 16:44:25 +09:00
parent 2eaabf87f4
commit 3f4c38cf68

View File

@ -650,6 +650,15 @@ export function useModuleBasicSetting(tabNum) {
} }
}, [isManualModuleSetup, isManualModuleLayoutSetup]) }, [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 진입여부를 확인 * trestle에서 영역을 가져와 mouse:move 이벤트로 해당 영역에 진입했을때 booleanPointInPolygon 진입여부를 확인
* 확인 셀을 이동시킴 * 확인 셀을 이동시킴
@ -679,6 +688,14 @@ export function useModuleBasicSetting(tabNum) {
return 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 객체 const batchObjects = canvas?.getObjects().filter((obj) => obj.name === POLYGON_TYPE.OBJECT_SURFACE) //도머s 객체
//수동모드 모듈 설치면 선택 잠금 //수동모드 모듈 설치면 선택 잠금
moduleSetupSurfaces.forEach((obj) => { moduleSetupSurfaces.forEach((obj) => {
@ -843,7 +860,7 @@ export function useModuleBasicSetting(tabNum) {
tempModule.left = holdCellCenterX - toFixedWithoutRounding(width / 2, 2) tempModule.left = holdCellCenterX - toFixedWithoutRounding(width / 2, 2)
} }
if (isChidori) { if (isChidori && isChidoriAllowedForFace(moduleSetupSurfaces[i])) {
//움직이는 모듈왼쪽 -> 가운데 //움직이는 모듈왼쪽 -> 가운데
if (Math.abs(smallLeft - holdCellCenterX) < snapDistance) { if (Math.abs(smallLeft - holdCellCenterX) < snapDistance) {
tempModule.left = holdCellCenterX + intvHor / 2 tempModule.left = holdCellCenterX + intvHor / 2
@ -886,7 +903,7 @@ export function useModuleBasicSetting(tabNum) {
tempModule.top = holdCellCenterY - toFixedWithoutRounding(height / 2, 2) tempModule.top = holdCellCenterY - toFixedWithoutRounding(height / 2, 2)
} }
if (isChidori) { if (isChidori && isChidoriAllowedForFace(moduleSetupSurfaces[i])) {
//위쪽 -> 가운데 //위쪽 -> 가운데
if (Math.abs(smallTop - holdCellCenterY) < snapDistance) { if (Math.abs(smallTop - holdCellCenterY) < snapDistance) {
tempModule.top = holdCellCenterY + intvHor / 2 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() tempModule.setCoords()
canvas?.renderAll() canvas?.renderAll()
inside = true inside = true
@ -1194,6 +1224,14 @@ export function useModuleBasicSetting(tabNum) {
return 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 객체 const batchObjects = canvas?.getObjects().filter((obj) => obj.name === POLYGON_TYPE.OBJECT_SURFACE) //도머s 객체
//수동모드 모듈 설치면 선택 잠금 //수동모드 모듈 설치면 선택 잠금
moduleSetupSurfaces.forEach((obj) => { moduleSetupSurfaces.forEach((obj) => {
@ -1396,7 +1434,7 @@ export function useModuleBasicSetting(tabNum) {
tempModule.left = holdCellCenterX - toFixedWithoutRounding(width / 2, 2) tempModule.left = holdCellCenterX - toFixedWithoutRounding(width / 2, 2)
} }
if (isChidori) { if (isChidori && isChidoriAllowedForFace(moduleSetupSurfaces[i])) {
//움직이는 모듈왼쪽 -> 가운데 //움직이는 모듈왼쪽 -> 가운데
if (Math.abs(smallLeft - holdCellCenterX) < snapDistance) { if (Math.abs(smallLeft - holdCellCenterX) < snapDistance) {
tempModule.left = holdCellCenterX + intvHor / 2 tempModule.left = holdCellCenterX + intvHor / 2
@ -1439,7 +1477,7 @@ export function useModuleBasicSetting(tabNum) {
tempModule.top = holdCellCenterY - toFixedWithoutRounding(width / 2, 2) tempModule.top = holdCellCenterY - toFixedWithoutRounding(width / 2, 2)
} }
if (isChidori) { if (isChidori && isChidoriAllowedForFace(moduleSetupSurfaces[i])) {
//위쪽 -> 가운데 //위쪽 -> 가운데
if (Math.abs(smallTop - holdCellCenterY) < snapDistance) { if (Math.abs(smallTop - holdCellCenterY) < snapDistance) {
tempModule.top = holdCellCenterY + intvHor / 2 tempModule.top = holdCellCenterY + intvHor / 2
@ -1587,6 +1625,9 @@ export function useModuleBasicSetting(tabNum) {
if (tempModule) { if (tempModule) {
saveSnapshot() saveSnapshot()
// [MANUAL-CHIDORI-BY-FACE 2026-07-08] 지정배치 그리드 대상 면(trestlePolygon)이 千鳥 不可(plvrYn==='N')면 千鳥 오프셋 없이 정렬 배치.
// 아래 그리드 생성부의 isChidori 는 이 면 기준 값을 따른다(전역 라디오가 ON이어도 不可면 정렬).
const isChidori = moduleSetupOption.isChidori && isChidoriAllowedForFace(trestlePolygon)
let startX, startY let startX, startY
let installedLastHeightCoord = 0 //마지막으로 설치된 모듈의 좌표 let installedLastHeightCoord = 0 //마지막으로 설치된 모듈의 좌표
let installedHeightModuleCount = 0 let installedHeightModuleCount = 0