From 363214654d6985fa330e1db6bf571ce20be93f96 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B9=80=EB=AF=BC=EC=8B=9D?= <43837214+Minsiki@users.noreply.github.com> Date: Thu, 26 Dec 2024 13:23:57 +0900 Subject: [PATCH 1/3] =?UTF-8?q?=EC=97=B4.=EB=8B=A8=20=EC=9D=B4=EB=8F=99/?= =?UTF-8?q?=EB=B3=B5=EC=82=AC=20=EA=B8=B0=EB=8A=A5=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../floor-plan/modal/module/PanelEdit.jsx | 18 +- src/hooks/module/useModule.js | 330 ++++++++++++++++++ 2 files changed, 347 insertions(+), 1 deletion(-) create mode 100644 src/hooks/module/useModule.js diff --git a/src/components/floor-plan/modal/module/PanelEdit.jsx b/src/components/floor-plan/modal/module/PanelEdit.jsx index c63dd0cd..0e7fde7f 100644 --- a/src/components/floor-plan/modal/module/PanelEdit.jsx +++ b/src/components/floor-plan/modal/module/PanelEdit.jsx @@ -9,6 +9,8 @@ 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 default function PanelEdit(props) { const contextPopupPosition = useRecoilValue(contextPopupPositionState) @@ -18,6 +20,7 @@ export default function PanelEdit(props) { const [direction, setDirection] = useState('up') const { getMessage } = useMessage() const canvas = useRecoilValue(canvasState) + const { moduleMove, moduleCopy, moduleMultiMove, moduleMultiCopy } = useModule() useEffect(() => { if (canvas) { @@ -28,7 +31,20 @@ export default function PanelEdit(props) { //모듈 이동 적용 const handleApply = () => { - contextModuleMove(length, direction) + // const activeModuleIds = canvas.getActiveObjects().map((obj) => obj.id) + if (type === 'move') { + moduleMove(length, direction) + } else if (type === 'copy') { + moduleCopy(length, direction) + } else if (type === 'columnMove') { + moduleMultiMove('column', length, direction) + } else if (type === 'columnCopy') { + moduleMultiCopy('column', length, direction) + } else if (type === 'rowMove') { + moduleMultiMove('row', length, direction) + } else if (type === 'rowCopy') { + moduleMultiCopy('row', length, direction) + } closePopup(id) } diff --git a/src/hooks/module/useModule.js b/src/hooks/module/useModule.js new file mode 100644 index 00000000..cc6ef05e --- /dev/null +++ b/src/hooks/module/useModule.js @@ -0,0 +1,330 @@ +import { BATCH_TYPE, POLYGON_TYPE } from '@/common/common' +import { canvasState } from '@/store/canvasAtom' +import { isOverlap, polygonToTurfPolygon } from '@/util/canvas-util' +import { useRecoilValue } from 'recoil' +import { v4 as uuidv4 } from 'uuid' +import * as turf from '@turf/turf' +import { useSwal } from '../useSwal' +import { QPolygon } from '@/components/fabric/QPolygon' + +export function useModule() { + const canvas = useRecoilValue(canvasState) + const { swalFire } = useSwal() + + const moduleMove = (length, direction) => { + 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 = [] + + 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) + }) + + const isNotOverlap = isOverlapArray.some((isOverlap) => isOverlap) // true면 겹침 + const isNotOutSurface = isInSurfaceArray.every((isOutSurface) => isOutSurface) //false면 밖으로 나감 + + //안겹치고 안나갔으면 이동시킨다 아니면 원래 위치로 돌려놓는다 + if (isNotOverlap || !isNotOutSurface) { + 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 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] + + canvas.discardActiveObject() //선택해제 + modules.forEach((module) => { + const { top, left } = getPosotion(module, direction, length) + const moduleOptions = { ...module, left, top, id: uuidv4() } + const rect = new QPolygon(module.points, moduleOptions) + canvas.add(rect) + rect.setCoords() + canvas.renderAll() + + // const isOverlapOtherModules = otherModules.some((otherModule) => rect.intersectsWithObject(otherModule)) + const isOverlapOtherModules = otherModules.some( + (otherModule) => + turf.booleanOverlap(polygonToTurfPolygon(rect, true), polygonToTurfPolygon(otherModule, true)) || + turf.booleanWithin(polygonToTurfPolygon(rect, true), polygonToTurfPolygon(otherModule, true)), + ) + + const isOutsideSurface = + !turf.booleanContains(polygonToTurfPolygon(moduleSetupSurface, true), polygonToTurfPolygon(rect, true)) || + !turf.booleanWithin(polygonToTurfPolygon(rect, true), polygonToTurfPolygon(moduleSetupSurface, true)) + + if (isOverlapOtherModules || isOutsideSurface) { + swalFire({ + title: isOverlapOtherModules ? '겹치는 모듈이 있습니다.' : '영역 밖', + 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() + 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( + objects.some( + (object) => + turf.booleanOverlap(polygonToTurfPolygon(module, true), polygonToTurfPolygon(object, true)) || + turf.booleanWithin(polygonToTurfPolygon(module, true), polygonToTurfPolygon(object, true)), + ), + ) + } + + 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) ? '겹치는 모듈이 있습니다.' : '영역 밖', + 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, true) + const moduleOptions = { ...module, left, top, id: uuidv4() } + const rect = new QPolygon(module.points, 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( + objects.some( + (object) => + turf.booleanOverlap(polygonToTurfPolygon(module, true), polygonToTurfPolygon(object, true)) || + turf.booleanWithin(polygonToTurfPolygon(module, true), polygonToTurfPolygon(object, true)), + ), + ) + } + + isOutsideSurface.push( + !turf.booleanContains(polygonToTurfPolygon(moduleSetupSurface, true), polygonToTurfPolygon(rect, true)) || + !turf.booleanWithin(polygonToTurfPolygon(rect, true), polygonToTurfPolygon(moduleSetupSurface, true)), + ) + }) + + console.log( + '🚀 ~ moduleMultiCopy ~ sOverlapOtherModules, isOverlapObjects, isOutsideSurface:', + isOverlapOtherModules, + isOverlapObjects, + isOutsideSurface, + ) + if ( + isOverlapOtherModules.some((isOverlap) => isOverlap) || + isOverlapObjects.some((isOverlap) => isOverlap) || + isOutsideSurface.some((isOutside) => isOutside) + ) { + swalFire({ + title: isOverlapOtherModules.some((isOverlap) => isOverlap) ? '겹치는 모듈이 있습니다.' : '영역 밖', + icon: 'error', + type: 'confirm', + confirmFn: () => { + canvas.remove(...copyRects) + canvas.renderAll() + }, + }) + } else { + 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(target.height) + 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)) + } + + return { + moduleMove, + moduleMultiMove, + moduleCopy, + moduleMultiCopy, + } +} From f56e5ca4b0e2543d604a135bd2afb2dbb0743d5a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B9=80=EB=AF=BC=EC=8B=9D?= <43837214+Minsiki@users.noreply.github.com> Date: Thu, 26 Dec 2024 18:07:55 +0900 Subject: [PATCH 2/3] =?UTF-8?q?=EC=97=B4.=EB=8B=A8=20=EC=82=AD=EC=A0=9C=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../floor-plan/modal/module/PanelEdit.jsx | 23 +- .../modal/module/column/ColumnRemove.jsx | 27 +- .../floor-plan/modal/module/row/RowRemove.jsx | 29 +- src/hooks/module/useModule.js | 279 +++++++++++++++++- src/hooks/useContextMenu.js | 14 +- 5 files changed, 326 insertions(+), 46 deletions(-) diff --git a/src/components/floor-plan/modal/module/PanelEdit.jsx b/src/components/floor-plan/modal/module/PanelEdit.jsx index 0e7fde7f..a3a89dcf 100644 --- a/src/components/floor-plan/modal/module/PanelEdit.jsx +++ b/src/components/floor-plan/modal/module/PanelEdit.jsx @@ -12,9 +12,18 @@ 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') @@ -32,17 +41,17 @@ export default function PanelEdit(props) { //모듈 이동 적용 const handleApply = () => { // const activeModuleIds = canvas.getActiveObjects().map((obj) => obj.id) - if (type === 'move') { + if (type === PANEL_EDIT_TYPE.MOVE) { moduleMove(length, direction) - } else if (type === 'copy') { + } else if (type === PANEL_EDIT_TYPE.COPY) { moduleCopy(length, direction) - } else if (type === 'columnMove') { + } else if (type === PANEL_EDIT_TYPE.COLUMN_MOVE) { moduleMultiMove('column', length, direction) - } else if (type === 'columnCopy') { + } else if (type === PANEL_EDIT_TYPE.COLUMN_COPY) { moduleMultiCopy('column', length, direction) - } else if (type === 'rowMove') { + } else if (type === PANEL_EDIT_TYPE.ROW_MOVE) { moduleMultiMove('row', length, direction) - } else if (type === 'rowCopy') { + } 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 { top, left } = getPosotion(module, direction, length) + 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) @@ -255,12 +265,6 @@ export function useModule() { ) }) - console.log( - '🚀 ~ moduleMultiCopy ~ sOverlapOtherModules, isOverlapObjects, isOutsideSurface:', - isOverlapOtherModules, - isOverlapObjects, - isOutsideSurface, - ) if ( isOverlapOtherModules.some((isOverlap) => isOverlap) || isOverlapObjects.some((isOverlap) => isOverlap) || @@ -280,6 +284,265 @@ export function useModule() { } } + 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)) + ) + } + + 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() + console.log('🚀 ~ moduleColumnRemove ~ objects:', objects) + 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] = [[], [], []] + console.log( + '🚀 ~ moduleColumnRemove ~ isOverlapOtherModules, isOverlapObjects, isOutsideSurface:', + isOverlapOtherModules, + isOverlapObjects, + isOutsideSurface, + ) + + canvas.discardActiveObject() + canvas.remove(...columnModules) + canvas.renderAll() + + if (type === MODULE_REMOVE_TYPE.LEFT) { + console.log('🚀 ~ moduleColumnRemove ~ rightModules:', rightModules) + 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(getIsOverlapObjects(module, 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(getIsOverlapObjects(module, 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(getIsOverlapObjects(module, objects)) + isOutsideSurface.push(getIsOutsideSurface(module, moduleSetupSurface)) + }) + + targetModules = sideModules + } + console.log('🚀 ~ sideModules.forEach ~ objects:', objects) + console.log( + '🚀 ~ moduleColumnRemove ~ isOverlapOtherModules, isOverlapObjects, isOutsideSurface:', + isOverlapOtherModules, + isOverlapObjects, + isOutsideSurface, + ) + 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(getIsOverlapObjects(module, 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(getIsOverlapObjects(module, 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(getIsOverlapObjects(module, 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) } @@ -326,5 +589,7 @@ export function useModule() { moduleMultiMove, moduleCopy, moduleMultiCopy, + moduleColumnRemove, + moduleRowRemove, } } 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', From f08e1fd4ff58f343d73696ca7952bbd89eac90b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EA=B9=80=EB=AF=BC=EC=8B=9D?= <43837214+Minsiki@users.noreply.github.com> Date: Fri, 27 Dec 2024 16:34:42 +0900 Subject: [PATCH 3/3] =?UTF-8?q?=EB=AA=A8=EB=93=88=20=EC=97=B4.=EB=8B=A8=20?= =?UTF-8?q?=EC=82=AD=EC=A0=9C=EA=B8=B0=EB=8A=A5=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/hooks/module/useModule.js | 186 ++++++++++++---------- src/hooks/module/useModuleBasicSetting.js | 125 ++++++++------- 2 files changed, 163 insertions(+), 148 deletions(-) diff --git a/src/hooks/module/useModule.js b/src/hooks/module/useModule.js index 4e2651fe..5eb95f6a 100644 --- a/src/hooks/module/useModule.js +++ b/src/hooks/module/useModule.js @@ -1,11 +1,12 @@ import { BATCH_TYPE, POLYGON_TYPE } from '@/common/common' import { canvasState } from '@/store/canvasAtom' -import { isOverlap, polygonToTurfPolygon } from '@/util/canvas-util' +import { isOverlap, polygonToTurfPolygon, rectToPolygon } from '@/util/canvas-util' import { useRecoilValue } from 'recoil' import { v4 as uuidv4 } from 'uuid' import * as turf from '@turf/turf' import { useSwal } from '../useSwal' import { QPolygon } from '@/components/fabric/QPolygon' +import { useModuleBasicSetting } from './useModuleBasicSetting' export const MODULE_REMOVE_TYPE = { LEFT: 'left', @@ -20,6 +21,7 @@ export const MODULE_REMOVE_TYPE = { export function useModule() { const canvas = useRecoilValue(canvasState) const { swalFire } = useSwal() + const { checkModuleDisjointObjects } = useModuleBasicSetting() const moduleMove = (length, direction) => { const checkModuleDisjointSurface = (squarePolygon, turfModuleSetupSurface) => { @@ -38,6 +40,8 @@ export function useModule() { .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) @@ -73,16 +77,28 @@ export function useModule() { //나갔는지 확인하는 로직 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) { - selectedModules.forEach((module) => { - module.set({ ...module, left: module.originCoords.left, top: module.originCoords.top }) - module.setCoords() + 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() + }) + }, }) } @@ -95,11 +111,12 @@ export function useModule() { 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) @@ -109,20 +126,28 @@ export function useModule() { rect.setCoords() canvas.renderAll() - // const isOverlapOtherModules = otherModules.some((otherModule) => rect.intersectsWithObject(otherModule)) - const isOverlapOtherModules = otherModules.some( - (otherModule) => - turf.booleanOverlap(polygonToTurfPolygon(rect, true), polygonToTurfPolygon(otherModule, true)) || - turf.booleanWithin(polygonToTurfPolygon(rect, true), polygonToTurfPolygon(otherModule, true)), + isOverlapOtherModules.push( + otherModules.some( + (otherModule) => + turf.booleanOverlap(polygonToTurfPolygon(rect, true), polygonToTurfPolygon(otherModule, true)) || + turf.booleanWithin(polygonToTurfPolygon(rect, true), polygonToTurfPolygon(otherModule, true)), + ), ) - const isOutsideSurface = - !turf.booleanContains(polygonToTurfPolygon(moduleSetupSurface, true), polygonToTurfPolygon(rect, true)) || - !turf.booleanWithin(polygonToTurfPolygon(rect, true), polygonToTurfPolygon(moduleSetupSurface, true)) + isOverlapObjects.push(!checkModuleDisjointObjects(polygonToTurfPolygon(rect, true), objects)) - if (isOverlapOtherModules || isOutsideSurface) { + 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 ? '겹치는 모듈이 있습니다.' : '영역 밖', + title: isOverlapOtherModules ? '겹치는 모듈이 있습니다.' : isOutsideSurface ? '모듈이 오브젝트와 겹칩니다.' : '영역 밖', icon: 'error', type: 'confirm', confirmFn: () => { @@ -133,6 +158,7 @@ export function useModule() { } }) } + const moduleMultiMove = (type, length, direction) => { if (canvas.getActiveObjects().length === 0) return if (canvas.getActiveObjects().length > 1) { @@ -148,6 +174,8 @@ export function useModule() { 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] @@ -175,13 +203,7 @@ export function useModule() { } if (objects.length > 0) { - isOverlapObjects.push( - objects.some( - (object) => - turf.booleanOverlap(polygonToTurfPolygon(module, true), polygonToTurfPolygon(object, true)) || - turf.booleanWithin(polygonToTurfPolygon(module, true), polygonToTurfPolygon(object, true)), - ), - ) + isOverlapObjects.push(!checkModuleDisjointObjects(polygonToTurfPolygon(module, true), objects)) } isOutsideSurface.push( @@ -196,7 +218,11 @@ export function useModule() { isOutsideSurface.some((isOutside) => isOutside) ) { swalFire({ - title: isOverlapOtherModules.some((isOverlap) => isOverlap) ? '겹치는 모듈이 있습니다.' : '영역 밖', + title: isOverlapOtherModules.some((isOverlap) => isOverlap) + ? '겹치는 모듈이 있습니다.' + : isOverlapObjects.some((isOverlap) => isOverlap) + ? '모듈이 오브젝트와 겹칩니다.' + : '영역 밖', icon: 'error', type: 'confirm', confirmFn: () => { @@ -232,9 +258,9 @@ export function useModule() { let [isOverlapOtherModules, isOverlapObjects, isOutsideSurface] = [[], [], []] modules.forEach((module) => { - const { top, left } = getPosotion(module, direction, length, true) + const { top, left } = getPosotion(module, direction, length, false) const moduleOptions = { ...module, left, top, id: uuidv4() } - const rect = new QPolygon(module.points, moduleOptions) + const rect = new QPolygon(module.getCurrentPoints(), moduleOptions) canvas.add(rect) copyRects.push(rect) module.setCoords() @@ -250,13 +276,7 @@ export function useModule() { } if (objects.length > 0) { - isOverlapObjects.push( - objects.some( - (object) => - turf.booleanOverlap(polygonToTurfPolygon(module, true), polygonToTurfPolygon(object, true)) || - turf.booleanWithin(polygonToTurfPolygon(module, true), polygonToTurfPolygon(object, true)), - ), - ) + isOverlapObjects.push(!checkModuleDisjointObjects(polygonToTurfPolygon(module, true), objects)) } isOutsideSurface.push( @@ -271,7 +291,11 @@ export function useModule() { isOutsideSurface.some((isOutside) => isOutside) ) { swalFire({ - title: isOverlapOtherModules.some((isOverlap) => isOverlap) ? '겹치는 모듈이 있습니다.' : '영역 밖', + title: isOverlapOtherModules.some((isOverlap) => isOverlap) + ? '겹치는 모듈이 있습니다.' + : isOverlapObjects.some((isOverlap) => isOverlap) + ? '모듈이 오브젝트와 겹칩니다.' + : '영역 밖', icon: 'error', type: 'confirm', confirmFn: () => { @@ -284,35 +308,11 @@ export function useModule() { } } - 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)) - ) - } - 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() - console.log('🚀 ~ moduleColumnRemove ~ objects:', objects) 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) @@ -321,19 +321,11 @@ export function useModule() { .getObjects() .filter((obj) => obj.name === POLYGON_TYPE.MODULE_SETUP_SURFACE && obj.id === activeModule.surfaceId)[0] let [isOverlapOtherModules, isOverlapObjects, isOutsideSurface] = [[], [], []] - console.log( - '🚀 ~ moduleColumnRemove ~ isOverlapOtherModules, isOverlapObjects, isOutsideSurface:', - isOverlapOtherModules, - isOverlapObjects, - isOutsideSurface, - ) - canvas.discardActiveObject() canvas.remove(...columnModules) canvas.renderAll() if (type === MODULE_REMOVE_TYPE.LEFT) { - console.log('🚀 ~ moduleColumnRemove ~ rightModules:', rightModules) rightModules.forEach((module) => { module.originPos = { left: module.left, @@ -344,7 +336,7 @@ export function useModule() { module.setCoords() canvas.renderAll() isOverlapOtherModules.push(getIsOverlapOtherModules(module, leftModules)) - isOverlapObjects.push(getIsOverlapObjects(module, objects)) + isOverlapObjects.push(!checkModuleDisjointObjects(polygonToTurfPolygon(module, true), objects)) isOutsideSurface.push(getIsOutsideSurface(module, moduleSetupSurface)) }) targetModules = rightModules @@ -359,7 +351,7 @@ export function useModule() { module.setCoords() canvas.renderAll() isOverlapOtherModules.push(getIsOverlapOtherModules(module, rightModules)) - isOverlapObjects.push(getIsOverlapObjects(module, objects)) + isOverlapObjects.push(!checkModuleDisjointObjects(polygonToTurfPolygon(module, true), objects)) isOutsideSurface.push(getIsOutsideSurface(module, moduleSetupSurface)) }) targetModules = leftModules @@ -394,19 +386,12 @@ export function useModule() { sideModules.filter((m) => m.id !== module.id), ), ) - isOverlapObjects.push(getIsOverlapObjects(module, objects)) + isOverlapObjects.push(!checkModuleDisjointObjects(polygonToTurfPolygon(module, true), objects)) isOutsideSurface.push(getIsOutsideSurface(module, moduleSetupSurface)) }) targetModules = sideModules } - console.log('🚀 ~ sideModules.forEach ~ objects:', objects) - console.log( - '🚀 ~ moduleColumnRemove ~ isOverlapOtherModules, isOverlapObjects, isOutsideSurface:', - isOverlapOtherModules, - isOverlapObjects, - isOutsideSurface, - ) if ( (isOverlapOtherModules.some((isOverlap) => isOverlap) || isOverlapObjects.some((isOverlap) => isOverlap) || @@ -414,9 +399,10 @@ export function useModule() { type !== MODULE_REMOVE_TYPE.NONE ) { swalFire({ - title: - isOverlapOtherModules.some((isOverlap) => isOverlap) || isOverlapObjects.some((isOverlap) => isOverlap) - ? '겹치는 모듈이 있습니다.' + title: isOverlapOtherModules.some((isOverlap) => isOverlap) + ? '겹치는 모듈이 있습니다.' + : isOverlapObjects.some((isOverlap) => isOverlap) + ? '모듈이 오브젝트와 겹칩니다.' : '영역 밖', icon: 'error', type: 'confirm', @@ -426,10 +412,10 @@ export function useModule() { module.set({ top: module.originPos.top, left: module.originPos.left }) module.setCoords() }) - canvas.renderAll() }, }) } + canvas.renderAll() } const moduleRowRemove = (type) => { @@ -461,7 +447,7 @@ export function useModule() { module.setCoords() canvas.renderAll() isOverlapOtherModules.push(getIsOverlapOtherModules(module, topModules)) - isOverlapObjects.push(getIsOverlapObjects(module, objects)) + isOverlapObjects.push(!checkModuleDisjointObjects(polygonToTurfPolygon(module, true), objects)) isOutsideSurface.push(getIsOutsideSurface(module, moduleSetupSurface)) }) targetModules = bottomModules @@ -476,7 +462,7 @@ export function useModule() { module.setCoords() canvas.renderAll() isOverlapOtherModules.push(getIsOverlapOtherModules(module, bottomModules)) - isOverlapObjects.push(getIsOverlapObjects(module, objects)) + isOverlapObjects.push(!checkModuleDisjointObjects(polygonToTurfPolygon(module, true), objects)) isOutsideSurface.push(getIsOutsideSurface(module, moduleSetupSurface)) }) targetModules = topModules @@ -512,7 +498,7 @@ export function useModule() { sideModules.filter((m) => m.id !== module.id), ), ) - isOverlapObjects.push(getIsOverlapObjects(module, objects)) + isOverlapObjects.push(!checkModuleDisjointObjects(polygonToTurfPolygon(module, true), objects)) isOutsideSurface.push(getIsOutsideSurface(module, moduleSetupSurface)) }) targetModules = sideModules @@ -525,9 +511,10 @@ export function useModule() { type !== MODULE_REMOVE_TYPE.NONE ) { swalFire({ - title: - isOverlapOtherModules.some((isOverlap) => isOverlap) || isOverlapObjects.some((isOverlap) => isOverlap) - ? '겹치는 모듈이 있습니다.' + title: isOverlapOtherModules.some((isOverlap) => isOverlap) + ? '겹치는 모듈이 있습니다.' + : isOverlapObjects.some((isOverlap) => isOverlap) + ? '모듈이 오브젝트와 겹칩니다.' : '영역 밖', icon: 'error', type: 'confirm', @@ -537,10 +524,10 @@ export function useModule() { module.set({ top: module.originPos.top, left: module.originPos.left }) module.setCoords() }) - canvas.renderAll() }, }) } + canvas.renderAll() } const getRowModules = (target) => { @@ -559,7 +546,7 @@ export function useModule() { top = Number(target.top) - Number(length) top = hasMargin ? top - Number(target.height) : top } else if (direction === 'down') { - top = Number(target.top) + Number(target.height) + Number(length) + top = Number(target.top) + Number(length) top = hasMargin ? top + Number(target.height) : top } else if (direction === 'left') { left = Number(target.left) - Number(length) @@ -584,6 +571,29 @@ export function useModule() { .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, 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, } }