diff --git a/src/components/floor-plan/modal/module/PanelEdit.jsx b/src/components/floor-plan/modal/module/PanelEdit.jsx index c63dd0cd..a3a89dcf 100644 --- a/src/components/floor-plan/modal/module/PanelEdit.jsx +++ b/src/components/floor-plan/modal/module/PanelEdit.jsx @@ -9,15 +9,27 @@ import { deepCopyArray } from '@/util/common-utils' import { canvasState } from '@/store/canvasAtom' import * as turf from '@turf/turf' import { POLYGON_TYPE } from '@/common/common' +import { useModal } from '@nextui-org/react' +import { useModule } from '@/hooks/module/useModule' + +export const PANEL_EDIT_TYPE = { + MOVE: 'move', + COPY: 'copy', + COLUMN_MOVE: 'columnMove', + COLUMN_COPY: 'columnCopy', + ROW_MOVE: 'rowMove', + ROW_COPY: 'rowCopy', +} export default function PanelEdit(props) { const contextPopupPosition = useRecoilValue(contextPopupPositionState) - const { id, pos = contextPopupPosition, type = 'move', apply } = props + const { id, pos = contextPopupPosition, type = PANEL_EDIT_TYPE.MOVE, apply } = props const { closePopup } = usePopup() const [length, setLength] = useState(0) const [direction, setDirection] = useState('up') const { getMessage } = useMessage() const canvas = useRecoilValue(canvasState) + const { moduleMove, moduleCopy, moduleMultiMove, moduleMultiCopy } = useModule() useEffect(() => { if (canvas) { @@ -28,7 +40,20 @@ export default function PanelEdit(props) { //모듈 이동 적용 const handleApply = () => { - contextModuleMove(length, direction) + // const activeModuleIds = canvas.getActiveObjects().map((obj) => obj.id) + if (type === PANEL_EDIT_TYPE.MOVE) { + moduleMove(length, direction) + } else if (type === PANEL_EDIT_TYPE.COPY) { + moduleCopy(length, direction) + } else if (type === PANEL_EDIT_TYPE.COLUMN_MOVE) { + moduleMultiMove('column', length, direction) + } else if (type === PANEL_EDIT_TYPE.COLUMN_COPY) { + moduleMultiCopy('column', length, direction) + } else if (type === PANEL_EDIT_TYPE.ROW_MOVE) { + moduleMultiMove('row', length, direction) + } else if (type === PANEL_EDIT_TYPE.ROW_COPY) { + moduleMultiCopy('row', length, direction) + } closePopup(id) } diff --git a/src/components/floor-plan/modal/module/column/ColumnRemove.jsx b/src/components/floor-plan/modal/module/column/ColumnRemove.jsx index 24219d78..a18d7982 100644 --- a/src/components/floor-plan/modal/module/column/ColumnRemove.jsx +++ b/src/components/floor-plan/modal/module/column/ColumnRemove.jsx @@ -5,21 +5,24 @@ import { usePopup } from '@/hooks/usePopup' import { useMessage } from '@/hooks/useMessage' import { useState } from 'react' import Image from 'next/image' +import { MODULE_REMOVE_TYPE, useModule } from '@/hooks/module/useModule' export default function ColumnRemove(props) { const contextPopupPosition = useRecoilValue(contextPopupPositionState) const { id, pos = contextPopupPosition, apply } = props const { closePopup } = usePopup() - const [selectedType, setSelectedType] = useState(1) + const [selectedType, setSelectedType] = useState(MODULE_REMOVE_TYPE.LEFT) const { getMessage } = useMessage() + const { moduleColumnRemove } = useModule() const types = [ - { name: getMessage('modal.panel.column.remove.type.left'), value: 1 }, - { name: getMessage('modal.panel.column.remove.type.right'), value: 2 }, - { name: getMessage('modal.panel.column.remove.type.side'), value: 3 }, - { name: getMessage('modal.panel.column.remove.type.none'), value: 4 }, + { name: getMessage('modal.panel.column.remove.type.left'), value: MODULE_REMOVE_TYPE.LEFT }, + { name: getMessage('modal.panel.column.remove.type.right'), value: MODULE_REMOVE_TYPE.RIGHT }, + { name: getMessage('modal.panel.column.remove.type.side'), value: MODULE_REMOVE_TYPE.HORIZONTAL_SIDE }, + { name: getMessage('modal.panel.column.remove.type.none'), value: MODULE_REMOVE_TYPE.NONE }, ] const handleApply = () => { - if (apply) apply() + // if (apply) apply() + moduleColumnRemove(selectedType) closePopup(id) } @@ -39,12 +42,12 @@ export default function ColumnRemove(props) {
{types.map((type, index) => { return ( -
+
setSelectedType(Number(e.target.value))} + onClick={(e) => setSelectedType(e.target.value)} value={type.value} checked={selectedType === type.value} /> @@ -54,7 +57,7 @@ export default function ColumnRemove(props) { })}
- {selectedType === 1 && ( + {selectedType === MODULE_REMOVE_TYPE.LEFT && ( react )} - {selectedType === 2 && ( + {selectedType === MODULE_REMOVE_TYPE.RIGHT && ( react )} - {selectedType === 3 && ( + {selectedType === MODULE_REMOVE_TYPE.HORIZONTAL_SIDE && ( react )} - {selectedType === 4 && ( + {selectedType === MODULE_REMOVE_TYPE.NONE && ( react { - if (apply) apply() + // if (apply) apply() + moduleRowRemove(selectedType) closePopup(id) } @@ -39,22 +42,22 @@ export default function RowRemove(props) {
{types.map((type, index) => { return ( -
+
setSelectedType(Number(e.target.value))} + onClick={(e) => setSelectedType(e.target.value)} value={type.value} checked={selectedType === type.value} /> - +
) })}
- {selectedType === 1 && ( + {selectedType === MODULE_REMOVE_TYPE.TOP && ( react )} - {selectedType === 2 && ( + {selectedType === MODULE_REMOVE_TYPE.BOTTOM && ( react )} - {selectedType === 3 && ( + {selectedType === MODULE_REMOVE_TYPE.VERTICAL_SIDE && ( react )} - {selectedType === 4 && ( + {selectedType === MODULE_REMOVE_TYPE.NONE && ( react { + const checkModuleDisjointSurface = (squarePolygon, turfModuleSetupSurface) => { + return turf.booleanContains(turfModuleSetupSurface, squarePolygon) || turf.booleanWithin(squarePolygon, turfModuleSetupSurface) + } + + const selectedObj = canvas.getActiveObjects() //선택된 객체들을 가져옴 + const selectedIds = selectedObj.map((obj) => obj.id) // selectedObj의 ID 추출 + + canvas.discardActiveObject() //선택해제 + + const isSetupModules = canvas.getObjects().filter((obj) => obj.name === 'module' && !selectedIds.includes(obj.id)) // selectedObj에 없는 객체만 필터링 + const selectedModules = canvas.getObjects().filter((obj) => selectedIds.includes(obj.id) && obj.name === 'module') //선택했던 객체들만 가져옴 + const setupSurface = canvas + .getObjects() + .filter((obj) => obj.name === POLYGON_TYPE.MODULE_SETUP_SURFACE && obj.id === selectedModules[0].surfaceId)[0] + const isOverlapArray = [] + const isInSurfaceArray = [] + const isOverlapObjects = [] + const objects = getObjects() + + if (selectedModules) { + canvas.remove(...selectedModules) + selectedModules.forEach((module) => { + module.set({ + originCoords: { + left: module.left, + top: module.top, + }, + }) + + if (direction === 'up') { + module.set({ ...module, top: module.top - Number(length) }) + } else if (direction === 'down') { + module.set({ ...module, top: module.top + Number(length) }) + } else if (direction === 'left') { + module.set({ ...module, left: module.left - Number(length) }) + } else if (direction === 'right') { + module.set({ ...module, left: module.left + Number(length) }) + } + module.setCoords() + canvas.renderAll() + + //다른 모듈과 겹치는지 확인하는 로직 + const isOverlap = isSetupModules.some((isSetupModule) => + turf.booleanOverlap(polygonToTurfPolygon(module, true), polygonToTurfPolygon(isSetupModule, true)), + ) + isOverlapArray.push(isOverlap) + + const turfModuleSetupSurface = polygonToTurfPolygon(setupSurface, true) + const turfModule = polygonToTurfPolygon(module, true) + + //나갔는지 확인하는 로직 + const isInSurface = turf.booleanContains(turfModuleSetupSurface, turfModule) || turf.booleanWithin(turfModule, turfModuleSetupSurface) + isInSurfaceArray.push(isInSurface) + isOverlapObjects.push(!checkModuleDisjointObjects(polygonToTurfPolygon(module, true), objects)) + }) + + const isNotOverlap = isOverlapArray.some((isOverlap) => isOverlap) // true면 겹침 + const isNotOutSurface = isInSurfaceArray.every((isOutSurface) => isOutSurface) //false면 밖으로 나감 + + //안겹치고 안나갔으면 이동시킨다 아니면 원래 위치로 돌려놓는다 + if (isNotOverlap || !isNotOutSurface || isOverlapObjects.some((isOverlap) => isOverlap)) { + swalFire({ + title: isNotOverlap + ? '겹치는 모듈이 있습니다.' + : isOverlapObjects.some((isOverlap) => isOverlap) + ? '모듈이 오브젝트와 겹칩니다.' + : '영역 밖', + icon: 'error', + type: 'confirm', + confirmFn: () => { + selectedModules.forEach((module) => { + module.set({ ...module, left: module.originCoords.left, top: module.originCoords.top }) + module.setCoords() + }) + }, + }) + } + + canvas.add(...selectedModules) + canvas.renderAll() + } + } + + const moduleCopy = (length, direction) => { + if (canvas.getActiveObjects().length === 0) return + const activeModuleIds = canvas.getActiveObjects().map((obj) => obj.id) + const modules = canvas.getObjects().filter((obj) => activeModuleIds.includes(obj.id)) + const objects = getObjects() + const otherModules = canvas.getObjects().filter((obj) => obj.surfaceId === modules[0].surfaceId && obj.name === POLYGON_TYPE.MODULE) + const moduleSetupSurface = canvas + .getObjects() + .filter((obj) => obj.name === POLYGON_TYPE.MODULE_SETUP_SURFACE && obj.id === modules[0].surfaceId)[0] + let [isOverlapOtherModules, isOverlapObjects, isOutsideSurface] = [[], [], []] + canvas.discardActiveObject() //선택해제 + modules.forEach((module) => { + const { top, left } = getPosotion(module, direction, length, true) + const moduleOptions = { ...module, left, top, id: uuidv4() } + const rect = new QPolygon(module.points, moduleOptions) + canvas.add(rect) + rect.setCoords() + canvas.renderAll() + + isOverlapOtherModules.push( + otherModules.some( + (otherModule) => + turf.booleanOverlap(polygonToTurfPolygon(rect, true), polygonToTurfPolygon(otherModule, true)) || + turf.booleanWithin(polygonToTurfPolygon(rect, true), polygonToTurfPolygon(otherModule, true)), + ), + ) + + isOverlapObjects.push(!checkModuleDisjointObjects(polygonToTurfPolygon(rect, true), objects)) + + isOutsideSurface.push( + !turf.booleanContains(polygonToTurfPolygon(moduleSetupSurface, true), polygonToTurfPolygon(rect, true)) || + !turf.booleanWithin(polygonToTurfPolygon(rect, true), polygonToTurfPolygon(moduleSetupSurface, true)), + ) + + if ( + isOverlapOtherModules.some((isOverlap) => isOverlap) || + isOutsideSurface.some((isOutside) => isOutside) || + isOverlapObjects.some((isOverlap) => isOverlap) + ) { + swalFire({ + title: isOverlapOtherModules ? '겹치는 모듈이 있습니다.' : isOutsideSurface ? '모듈이 오브젝트와 겹칩니다.' : '영역 밖', + icon: 'error', + type: 'confirm', + confirmFn: () => { + canvas.remove(rect) + canvas.renderAll() + }, + }) + } + }) + } + + const moduleMultiMove = (type, length, direction) => { + if (canvas.getActiveObjects().length === 0) return + if (canvas.getActiveObjects().length > 1) { + swalFire({ + title: '여러 개의 모듈을 선택할 수 없습니다.', + icon: 'error', + type: 'alert', + }) + canvas.discardActiveObject() + return + } + const activeModule = canvas.getObjects().filter((obj) => canvas.getActiveObjects()[0].id === obj.id)[0] + const modules = type === 'row' ? getRowModules(activeModule) : getColumnModules(activeModule) + const otherModules = getOtherModules(modules) + const objects = getObjects() + console.log('🚀 ~ moduleMultiMove ~ objects:', objects) + + const moduleSetupSurface = canvas + .getObjects() + .filter((obj) => obj.name === POLYGON_TYPE.MODULE_SETUP_SURFACE && obj.id === activeModule.surfaceId)[0] + let [isOverlapOtherModules, isOverlapObjects, isOutsideSurface] = [[], [], []] + + modules.forEach((module) => { + const { top, left } = getPosotion(module, direction, length, false) + module.originPos = { + top: module.top, + left: module.left, + } + + module.set({ top, left }) + module.setCoords() + canvas.renderAll() + + if (otherModules.length > 0) { + isOverlapOtherModules.push( + otherModules.some( + (otherModule) => + turf.booleanOverlap(polygonToTurfPolygon(module, true), polygonToTurfPolygon(otherModule, true)) || + turf.booleanWithin(polygonToTurfPolygon(module, true), polygonToTurfPolygon(otherModule, true)), + ), + ) + } + + if (objects.length > 0) { + isOverlapObjects.push(!checkModuleDisjointObjects(polygonToTurfPolygon(module, true), objects)) + } + + isOutsideSurface.push( + !turf.booleanContains(polygonToTurfPolygon(moduleSetupSurface, true), polygonToTurfPolygon(module, true)) || + !turf.booleanWithin(polygonToTurfPolygon(module, true), polygonToTurfPolygon(moduleSetupSurface, true)), + ) + }) + + if ( + isOverlapOtherModules.some((isOverlap) => isOverlap) || + isOverlapObjects.some((isOverlap) => isOverlap) || + isOutsideSurface.some((isOutside) => isOutside) + ) { + swalFire({ + title: isOverlapOtherModules.some((isOverlap) => isOverlap) + ? '겹치는 모듈이 있습니다.' + : isOverlapObjects.some((isOverlap) => isOverlap) + ? '모듈이 오브젝트와 겹칩니다.' + : '영역 밖', + icon: 'error', + type: 'confirm', + confirmFn: () => { + modules.forEach((module) => { + module.set({ top: module.originPos.top, left: module.originPos.left }) + module.setCoords() + }) + canvas.renderAll() + }, + }) + } + } + + const moduleMultiCopy = (type, length, direction) => { + if (canvas.getActiveObjects().length === 0) return + if (canvas.getActiveObjects().length > 1) { + swalFire({ + title: '여러 개의 모듈을 선택할 수 없습니다.', + icon: 'error', + type: 'alert', + }) + canvas.discardActiveObject() + return + } + const activeModule = canvas.getObjects().filter((obj) => canvas.getActiveObjects()[0].id === obj.id)[0] + const modules = type === 'row' ? getRowModules(activeModule) : getColumnModules(activeModule) + const otherModules = canvas.getObjects().filter((obj) => obj.surfaceId === modules[0].surfaceId && obj.name === POLYGON_TYPE.MODULE) + const objects = getObjects() + const copyRects = [] + const moduleSetupSurface = canvas + .getObjects() + .filter((obj) => obj.name === POLYGON_TYPE.MODULE_SETUP_SURFACE && obj.id === modules[0].surfaceId)[0] + let [isOverlapOtherModules, isOverlapObjects, isOutsideSurface] = [[], [], []] + + modules.forEach((module) => { + const { top, left } = getPosotion(module, direction, length, false) + const moduleOptions = { ...module, left, top, id: uuidv4() } + const rect = new QPolygon(module.getCurrentPoints(), moduleOptions) + canvas.add(rect) + copyRects.push(rect) + module.setCoords() + + if (otherModules.length > 0) { + isOverlapOtherModules.push( + otherModules.some( + (otherModule) => + turf.booleanOverlap(polygonToTurfPolygon(rect, true), polygonToTurfPolygon(otherModule, true)) || + turf.booleanWithin(polygonToTurfPolygon(rect, true), polygonToTurfPolygon(otherModule, true)), + ), + ) + } + + if (objects.length > 0) { + isOverlapObjects.push(!checkModuleDisjointObjects(polygonToTurfPolygon(module, true), objects)) + } + + isOutsideSurface.push( + !turf.booleanContains(polygonToTurfPolygon(moduleSetupSurface, true), polygonToTurfPolygon(rect, true)) || + !turf.booleanWithin(polygonToTurfPolygon(rect, true), polygonToTurfPolygon(moduleSetupSurface, true)), + ) + }) + + if ( + isOverlapOtherModules.some((isOverlap) => isOverlap) || + isOverlapObjects.some((isOverlap) => isOverlap) || + isOutsideSurface.some((isOutside) => isOutside) + ) { + swalFire({ + title: isOverlapOtherModules.some((isOverlap) => isOverlap) + ? '겹치는 모듈이 있습니다.' + : isOverlapObjects.some((isOverlap) => isOverlap) + ? '모듈이 오브젝트와 겹칩니다.' + : '영역 밖', + icon: 'error', + type: 'confirm', + confirmFn: () => { + canvas.remove(...copyRects) + canvas.renderAll() + }, + }) + } else { + canvas.renderAll() + } + } + + const moduleColumnRemove = (type) => { + const activeModule = canvas.getObjects().filter((obj) => canvas.getActiveObjects()[0].id === obj.id)[0] + const columnModules = getColumnModules(activeModule) + const otherModules = getOtherModules(columnModules) + const objects = getObjects() + let targetModules = [] + const rightModules = otherModules.filter((module) => activeModule.left < module.left).sort((a, b) => a.left - b.left) + const leftModules = otherModules.filter((module) => activeModule.left > module.left).sort((a, b) => b.left - a.left) + let width = -1 + const moduleSetupSurface = canvas + .getObjects() + .filter((obj) => obj.name === POLYGON_TYPE.MODULE_SETUP_SURFACE && obj.id === activeModule.surfaceId)[0] + let [isOverlapOtherModules, isOverlapObjects, isOutsideSurface] = [[], [], []] + canvas.discardActiveObject() + canvas.remove(...columnModules) + canvas.renderAll() + + if (type === MODULE_REMOVE_TYPE.LEFT) { + rightModules.forEach((module) => { + module.originPos = { + left: module.left, + top: module.top, + } + if (width === -1) width = module.left - activeModule.left + module.set({ left: module.left - width }) + module.setCoords() + canvas.renderAll() + isOverlapOtherModules.push(getIsOverlapOtherModules(module, leftModules)) + isOverlapObjects.push(!checkModuleDisjointObjects(polygonToTurfPolygon(module, true), objects)) + isOutsideSurface.push(getIsOutsideSurface(module, moduleSetupSurface)) + }) + targetModules = rightModules + } else if (type === MODULE_REMOVE_TYPE.RIGHT) { + leftModules.forEach((module) => { + module.originPos = { + left: module.left, + top: module.top, + } + if (width === -1) width = activeModule.left - module.left + module.set({ left: module.left + width }) + module.setCoords() + canvas.renderAll() + isOverlapOtherModules.push(getIsOverlapOtherModules(module, rightModules)) + isOverlapObjects.push(!checkModuleDisjointObjects(polygonToTurfPolygon(module, true), objects)) + isOutsideSurface.push(getIsOutsideSurface(module, moduleSetupSurface)) + }) + targetModules = leftModules + } else if (type === MODULE_REMOVE_TYPE.HORIZONTAL_SIDE) { + const sideModules = [...leftModules, ...rightModules] + leftModules.forEach((module) => { + module.originPos = { + left: module.left, + top: module.top, + } + if (width === -1) width = activeModule.left - module.left + module.set({ left: module.left + width / 2 }) + module.setCoords() + canvas.renderAll() + }) + + rightModules.forEach((module) => { + module.originPos = { + left: module.left, + top: module.top, + } + if (width === -1) width = module.left - activeModule.left + module.set({ left: module.left - width / 2 }) + module.setCoords() + canvas.renderAll() + }) + canvas.renderAll() + sideModules.forEach((module) => { + isOverlapOtherModules.push( + getIsOverlapOtherModules( + module, + sideModules.filter((m) => m.id !== module.id), + ), + ) + isOverlapObjects.push(!checkModuleDisjointObjects(polygonToTurfPolygon(module, true), objects)) + isOutsideSurface.push(getIsOutsideSurface(module, moduleSetupSurface)) + }) + + targetModules = sideModules + } + if ( + (isOverlapOtherModules.some((isOverlap) => isOverlap) || + isOverlapObjects.some((isOverlap) => isOverlap) || + isOutsideSurface.some((isOutside) => isOutside)) && + type !== MODULE_REMOVE_TYPE.NONE + ) { + swalFire({ + title: isOverlapOtherModules.some((isOverlap) => isOverlap) + ? '겹치는 모듈이 있습니다.' + : isOverlapObjects.some((isOverlap) => isOverlap) + ? '모듈이 오브젝트와 겹칩니다.' + : '영역 밖', + icon: 'error', + type: 'confirm', + confirmFn: () => { + canvas.add(...columnModules) + targetModules.forEach((module) => { + module.set({ top: module.originPos.top, left: module.originPos.left }) + module.setCoords() + }) + }, + }) + } + canvas.renderAll() + } + + const moduleRowRemove = (type) => { + const activeModule = canvas.getObjects().filter((obj) => canvas.getActiveObjects()[0].id === obj.id)[0] + const rowModules = getRowModules(activeModule) + const otherModules = getOtherModules(rowModules) + const objects = getObjects() + let targetModules = [] + const topModules = otherModules.filter((module) => activeModule.top > module.top).sort((a, b) => b.top - a.top) + const bottomModules = otherModules.filter((module) => activeModule.top < module.top).sort((a, b) => a.top - b.top) + let height = -1 + const moduleSetupSurface = canvas + .getObjects() + .filter((obj) => obj.name === POLYGON_TYPE.MODULE_SETUP_SURFACE && obj.id === activeModule.surfaceId)[0] + let [isOverlapOtherModules, isOverlapObjects, isOutsideSurface] = [[], [], []] + + canvas.discardActiveObject() + canvas.remove(...rowModules) + canvas.renderAll() + + if (type === MODULE_REMOVE_TYPE.TOP) { + bottomModules.forEach((module) => { + module.originPos = { + left: module.left, + top: module.top, + } + if (height === -1) height = module.top - activeModule.top + module.set({ top: module.top - height }) + module.setCoords() + canvas.renderAll() + isOverlapOtherModules.push(getIsOverlapOtherModules(module, topModules)) + isOverlapObjects.push(!checkModuleDisjointObjects(polygonToTurfPolygon(module, true), objects)) + isOutsideSurface.push(getIsOutsideSurface(module, moduleSetupSurface)) + }) + targetModules = bottomModules + } else if (type === MODULE_REMOVE_TYPE.BOTTOM) { + topModules.forEach((module) => { + module.originPos = { + left: module.left, + top: module.top, + } + if (height === -1) height = activeModule.top - module.top + module.set({ top: module.top + height }) + module.setCoords() + canvas.renderAll() + isOverlapOtherModules.push(getIsOverlapOtherModules(module, bottomModules)) + isOverlapObjects.push(!checkModuleDisjointObjects(polygonToTurfPolygon(module, true), objects)) + isOutsideSurface.push(getIsOutsideSurface(module, moduleSetupSurface)) + }) + targetModules = topModules + } else if (type === MODULE_REMOVE_TYPE.VERTICAL_SIDE) { + topModules.forEach((module) => { + module.originPos = { + left: module.left, + top: module.top, + } + if (height === -1) height = activeModule.top - module.top + module.set({ top: module.top + height / 2 }) + module.setCoords() + canvas.renderAll() + }) + + bottomModules.forEach((module) => { + module.originPos = { + left: module.left, + top: module.top, + } + if (height === -1) height = module.top - activeModule.top + module.set({ top: module.top - height / 2 }) + module.setCoords() + canvas.renderAll() + }) + + const sideModules = [...topModules, ...bottomModules] + canvas.renderAll() + sideModules.forEach((module) => { + isOverlapOtherModules.push( + getIsOverlapOtherModules( + module, + sideModules.filter((m) => m.id !== module.id), + ), + ) + isOverlapObjects.push(!checkModuleDisjointObjects(polygonToTurfPolygon(module, true), objects)) + isOutsideSurface.push(getIsOutsideSurface(module, moduleSetupSurface)) + }) + targetModules = sideModules + } + + if ( + (isOverlapOtherModules.some((isOverlap) => isOverlap) || + isOverlapObjects.some((isOverlap) => isOverlap) || + isOutsideSurface.some((isOutside) => isOutside)) && + type !== MODULE_REMOVE_TYPE.NONE + ) { + swalFire({ + title: isOverlapOtherModules.some((isOverlap) => isOverlap) + ? '겹치는 모듈이 있습니다.' + : isOverlapObjects.some((isOverlap) => isOverlap) + ? '모듈이 오브젝트와 겹칩니다.' + : '영역 밖', + icon: 'error', + type: 'confirm', + confirmFn: () => { + canvas.add(...rowModules) + targetModules.forEach((module) => { + module.set({ top: module.originPos.top, left: module.originPos.left }) + module.setCoords() + }) + }, + }) + } + canvas.renderAll() + } + + const getRowModules = (target) => { + return canvas.getObjects().filter((obj) => target.surfaceId === obj.surfaceId && obj.name === POLYGON_TYPE.MODULE && obj.top === target.top) + } + + const getColumnModules = (target) => { + return canvas.getObjects().filter((obj) => target.surfaceId === obj.surfaceId && obj.name === POLYGON_TYPE.MODULE && obj.left === target.left) + } + + const getPosotion = (target, direction, length, hasMargin = false) => { + let top = target.top + let left = target.left + + if (direction === 'up') { + top = Number(target.top) - Number(length) + top = hasMargin ? top - Number(target.height) : top + } else if (direction === 'down') { + top = Number(target.top) + Number(length) + top = hasMargin ? top + Number(target.height) : top + } else if (direction === 'left') { + left = Number(target.left) - Number(length) + left = hasMargin ? left - Number(target.width) : left + } else if (direction === 'right') { + left = Number(target.left) + Number(length) + left = hasMargin ? left + Number(target.width) : left + } + return { top, left } + } + + const getOtherModules = (modules) => { + const moduleIds = modules.map((module) => module.id) + return canvas + .getObjects() + .filter((obj) => obj.surfaceId === modules[0].surfaceId && obj.name === POLYGON_TYPE.MODULE && !moduleIds.includes(obj.id)) + } + + const getObjects = () => { + return canvas + ?.getObjects() + .filter((obj) => [BATCH_TYPE.OPENING, BATCH_TYPE.TRIANGLE_DORMER, BATCH_TYPE.PENTAGON_DORMER, BATCH_TYPE.SHADOW].includes(obj.name)) + } + + const getIsOverlapOtherModules = (module, otherModules) => { + return otherModules.some( + (otherModule) => + turf.booleanOverlap(polygonToTurfPolygon(module, true), polygonToTurfPolygon(otherModule, true)) || + turf.booleanWithin(polygonToTurfPolygon(module, true), polygonToTurfPolygon(otherModule, true)), + ) + } + + const getIsOverlapObjects = (module, objects) => { + return !objects.some( + (object) => + turf.booleanOverlap(polygonToTurfPolygon(module, true), polygonToTurfPolygon(object, true)) || + turf.booleanWithin(polygonToTurfPolygon(module, true), polygonToTurfPolygon(object, true)), + ) + } + + const getIsOutsideSurface = (module, moduleSetupSurface) => { + return ( + !turf.booleanContains(polygonToTurfPolygon(moduleSetupSurface, true), polygonToTurfPolygon(module, true)) || + !turf.booleanWithin(polygonToTurfPolygon(module, true), polygonToTurfPolygon(moduleSetupSurface, true)) + ) + } + + return { + moduleMove, + moduleMultiMove, + moduleCopy, + moduleMultiCopy, + moduleColumnRemove, + moduleRowRemove, + } +} diff --git a/src/hooks/module/useModuleBasicSetting.js b/src/hooks/module/useModuleBasicSetting.js index c9b00b8a..cbd740bf 100644 --- a/src/hooks/module/useModuleBasicSetting.js +++ b/src/hooks/module/useModuleBasicSetting.js @@ -429,7 +429,8 @@ export function useModuleBasicSetting() { dormerTurfPolygon = batchObjectGroupToTurfPolygon(object) } else { //개구, 그림자 - dormerTurfPolygon = polygonToTurfPolygon(rectToPolygon(object)) + object.set({ points: rectToPolygon(object) }) + dormerTurfPolygon = polygonToTurfPolygon(object) } const intersection = turf.intersect(turf.featureCollection([dormerTurfPolygon, tempTurfModule])) //겹치는지 확인 @@ -566,35 +567,35 @@ export function useModuleBasicSetting() { return containsBatchObjects } - /** - * 도머나 개구가 모듈에 걸치는지 확인하는 로직 - * @param {*} squarePolygon - * @param {*} containsBatchObjects - * @returns - */ - const checkModuleDisjointObjects = (squarePolygon, containsBatchObjects) => { - let isDisjoint = false - - if (containsBatchObjects.length > 0) { - let convertBatchObject - //도머가 있으면 적용되는 로직 - isDisjoint = containsBatchObjects.every((batchObject) => { - if (batchObject.type === 'group') { - convertBatchObject = batchObjectGroupToTurfPolygon(batchObject) - } else { - convertBatchObject = polygonToTurfPolygon(batchObject) - } - /** - * 도머가 여러개일수있으므로 겹치는게 있다면... - * 안겹치는지 확인하는 로직이라 안겹치면 true를 반환 - */ - return turf.booleanDisjoint(squarePolygon, convertBatchObject) - }) - } else { - isDisjoint = true - } - return isDisjoint - } + // /** + // * 도머나 개구가 모듈에 걸치는지 확인하는 로직 + // * @param {*} squarePolygon + // * @param {*} containsBatchObjects + // * @returns + // */ + // const checkModuleDisjointObjects = (squarePolygon, containsBatchObjects) => { + // let isDisjoint = false + // + // if (containsBatchObjects.length > 0) { + // let convertBatchObject + // //도머가 있으면 적용되는 로직 + // isDisjoint = containsBatchObjects.every((batchObject) => { + // if (batchObject.type === 'group') { + // convertBatchObject = batchObjectGroupToTurfPolygon(batchObject) + // } else { + // convertBatchObject = polygonToTurfPolygon(batchObject) + // } + // /** + // * 도머가 여러개일수있으므로 겹치는게 있다면... + // * 안겹치는지 확인하는 로직이라 안겹치면 true를 반환 + // */ + // return turf.booleanDisjoint(squarePolygon, convertBatchObject) + // }) + // } else { + // isDisjoint = true + // } + // return isDisjoint + // } /** * 배치면 안에 있는지 확인 @@ -1997,36 +1998,6 @@ export function useModuleBasicSetting() { return containsBatchObjects } - /** - * 도머나 개구가 모듈에 걸치는지 확인하는 로직 - * @param {*} squarePolygon - * @param {*} containsBatchObjects - * @returns - */ - const checkModuleDisjointObjects = (squarePolygon, containsBatchObjects) => { - let isDisjoint = false - - if (containsBatchObjects.length > 0) { - let convertBatchObject - //도머가 있으면 적용되는 로직 - isDisjoint = containsBatchObjects.every((batchObject) => { - if (batchObject.type === 'group') { - convertBatchObject = batchObjectGroupToTurfPolygon(batchObject) - } else { - convertBatchObject = polygonToTurfPolygon(batchObject) - } - /** - * 도머가 여러개일수있으므로 겹치는게 있다면... - * 안겹치는지 확인하는 로직이라 안겹치면 true를 반환 - */ - return turf.booleanDisjoint(squarePolygon, convertBatchObject) - }) - } else { - isDisjoint = true - } - return isDisjoint - } - /** * 배치면 안에 있는지 확인 * @param {*} squarePolygon @@ -2287,6 +2258,39 @@ export function useModuleBasicSetting() { //드래그 하기위해 기능 활성화 } + /** + * 도머나 개구가 모듈에 걸치는지 확인하는 로직 + * @param {*} squarePolygon + * @param {*} containsBatchObjects + * @returns + */ + const checkModuleDisjointObjects = (squarePolygon, containsBatchObjects) => { + let isDisjoint = false + + if (containsBatchObjects.length > 0) { + let convertBatchObject + //도머가 있으면 적용되는 로직 + isDisjoint = containsBatchObjects.every((batchObject) => { + if (batchObject.type === 'group') { + convertBatchObject = batchObjectGroupToTurfPolygon(batchObject) + } else { + if (!batchObject.points) { + batchObject.set({ points: rectToPolygon(batchObject) }) + } + convertBatchObject = polygonToTurfPolygon(batchObject) + } + /** + * 도머가 여러개일수있으므로 겹치는게 있다면... + * 안겹치는지 확인하는 로직이라 안겹치면 true를 반환 + */ + return turf.booleanDisjoint(squarePolygon, convertBatchObject) + }) + } else { + isDisjoint = true + } + return isDisjoint + } + return { makeModuleInstArea, manualModuleSetup, @@ -2294,5 +2298,6 @@ export function useModuleBasicSetting() { restoreModuleInstArea, manualFlatroofModuleSetup, autoFlatroofModuleSetup, + checkModuleDisjointObjects, } } diff --git a/src/hooks/useContextMenu.js b/src/hooks/useContextMenu.js index 38564f7b..ad662534 100644 --- a/src/hooks/useContextMenu.js +++ b/src/hooks/useContextMenu.js @@ -23,7 +23,7 @@ import { useCommonUtils } from './common/useCommonUtils' import { useMessage } from '@/hooks/useMessage' import { useCanvasEvent } from '@/hooks/useCanvasEvent' import { contextMenuListState, contextMenuState } from '@/store/contextMenu' -import PanelEdit from '@/components/floor-plan/modal/module/PanelEdit' +import PanelEdit, { PANEL_EDIT_TYPE } from '@/components/floor-plan/modal/module/PanelEdit' import DimensionLineSetting from '@/components/floor-plan/modal/dimensionLine/DimensionLineSetting' import ColumnRemove from '@/components/floor-plan/modal/module/column/ColumnRemove' import ColumnInsert from '@/components/floor-plan/modal/module/column/ColumnInsert' @@ -609,24 +609,24 @@ export function useContextMenu() { { id: 'move', name: getMessage('contextmenu.move'), - component: , + component: , }, { id: 'copy', name: getMessage('contextmenu.copy'), - component: , + component: , }, ], [ { id: 'columnMove', name: getMessage('contextmenu.column.move'), - component: , + component: , }, { id: 'columnCopy', name: getMessage('contextmenu.column.copy'), - component: , + component: , }, { id: 'columnRemove', @@ -643,12 +643,12 @@ export function useContextMenu() { { id: 'rowMove', name: getMessage('contextmenu.row.move'), - component: , + component: , }, { id: 'rowCopy', name: getMessage('contextmenu.row.copy'), - component: , + component: , }, { id: 'rowRemove',