From 3df466a7179858864d91465e7dbe5ba536862f85 Mon Sep 17 00:00:00 2001 From: yjnoh Date: Wed, 12 Mar 2025 16:44:41 +0900 Subject: [PATCH] =?UTF-8?q?=EB=A0=88=EC=9D=B4=EC=95=84=EC=9B=83=20?= =?UTF-8?q?=EC=84=A4=EC=B9=98=20=EB=8D=B0=EB=AA=A8=20=EC=9E=91=EC=97=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../floor-plan/modal/basic/BasicSetting.jsx | 46 +- .../floor-plan/modal/basic/step/Placement.jsx | 32 ++ src/hooks/module/useModuleBasicSetting.js | 499 +++++++++++++++++- src/store/canvasAtom.js | 5 + 4 files changed, 571 insertions(+), 11 deletions(-) diff --git a/src/components/floor-plan/modal/basic/BasicSetting.jsx b/src/components/floor-plan/modal/basic/BasicSetting.jsx index 291ef086..f607d3cb 100644 --- a/src/components/floor-plan/modal/basic/BasicSetting.jsx +++ b/src/components/floor-plan/modal/basic/BasicSetting.jsx @@ -6,7 +6,7 @@ import PitchModule from '@/components/floor-plan/modal/basic/step/pitch/PitchMod import PitchPlacement from '@/components/floor-plan/modal/basic/step/pitch/PitchPlacement' import Placement from '@/components/floor-plan/modal/basic/step/Placement' import { useRecoilValue, useRecoilState } from 'recoil' -import { canvasSettingState, canvasState, isManualModuleSetupState } from '@/store/canvasAtom' +import { canvasSettingState, canvasState, isManualModuleLayoutSetupState, isManualModuleSetupState } from '@/store/canvasAtom' import { usePopup } from '@/hooks/usePopup' import { Orientation } from '@/components/floor-plan/modal/basic/step/Orientation' import { useModuleBasicSetting } from '@/hooks/module/useModuleBasicSetting' @@ -29,6 +29,8 @@ export default function BasicSetting({ id, pos = { x: 50, y: 230 } }) { const orientationRef = useRef(null) const { initEvent } = useEvent() const [isManualModuleSetup, setIsManualModuleSetup] = useRecoilState(isManualModuleSetupState) + const [isManualModuleLayoutSetup, setIsManualModuleLayoutSetup] = useRecoilState(isManualModuleLayoutSetupState) + const moduleSelectionData = useRecoilValue(moduleSelectionDataState) const addedRoofs = useRecoilValue(addedRoofsState) const loginUserState = useRecoilValue(loginUserStore) @@ -37,8 +39,16 @@ export default function BasicSetting({ id, pos = { x: 50, y: 230 } }) { const [basicSetting, setBasicSettings] = useRecoilState(basicSettingState) const [isClosePopup, setIsClosePopup] = useState({ close: false, id: 0 }) + const [manualSetupMode, setManualSetupMode] = useState('manualSetup') + + const [layoutSetup, setLayoutSetup] = useState({ + col: 1, + row: 1, + }) + // const { initEvent } = useContext(EventContext) - const { manualModuleSetup, autoModuleSetup, manualFlatroofModuleSetup, autoFlatroofModuleSetup } = useModuleBasicSetting(tabNum) + const { manualModuleSetup, autoModuleSetup, manualFlatroofModuleSetup, autoFlatroofModuleSetup, manualModuleLayoutSetup } = + useModuleBasicSetting(tabNum) const { updateObjectDate } = useMasterController() const handleBtnNextStep = () => { if (tabNum === 1) { @@ -86,7 +96,10 @@ export default function BasicSetting({ id, pos = { x: 50, y: 230 } }) { const placementRef = { isChidori: useRef('false'), setupLocation: useRef('eaves'), - isMaxSetup: useRef('false'), + layoutSetup: useRef({ + col: 1, + row: 1, + }), } const placementFlatRef = { @@ -94,9 +107,15 @@ export default function BasicSetting({ id, pos = { x: 50, y: 230 } }) { } const handleManualModuleSetup = () => { + setManualSetupMode(`manualSetup_${!isManualModuleSetup}`) setIsManualModuleSetup(!isManualModuleSetup) } + const handleManualModuleLayoutSetup = () => { + setManualSetupMode(`manualLayoutSetup_${!isManualModuleLayoutSetup}`) + setIsManualModuleLayoutSetup(!isManualModuleLayoutSetup) + } + const updateObjectDataApi = async (params) => { const res = await updateObjectDate(params) } @@ -125,14 +144,24 @@ export default function BasicSetting({ id, pos = { x: 50, y: 230 } }) { useEffect(() => { if (basicSetting.roofSizeSet !== '3') { - manualModuleSetup(placementRef) + if (manualSetupMode.indexOf('manualSetup') > -1) { + manualModuleSetup(placementRef) + } else if (manualSetupMode.indexOf('manualLayoutSetup') > -1) { + manualModuleLayoutSetup(placementRef) + } } else { manualFlatroofModuleSetup(placementFlatRef) } if (isClosePopup.close) { closePopup(isClosePopup.id) } - }, [isManualModuleSetup, isClosePopup]) + }, [manualSetupMode, isClosePopup]) + + useEffect(() => { + if (isManualModuleLayoutSetup) { + manualModuleLayoutSetup(placementRef) + } + }, [layoutSetup]) return ( @@ -156,7 +185,9 @@ export default function BasicSetting({ id, pos = { x: 50, y: 230 } }) { {tabNum === 1 && } {/*배치면 초기설정 - 입력방법: 복시도 입력 || 실측값 입력*/} {basicSetting.roofSizeSet && basicSetting.roofSizeSet != '3' && tabNum === 2 && } - {basicSetting.roofSizeSet && basicSetting.roofSizeSet != '3' && tabNum === 3 && } + {basicSetting.roofSizeSet && basicSetting.roofSizeSet != '3' && tabNum === 3 && ( + + )} {/*배치면 초기설정 - 입력방법: 육지붕*/} {basicSetting.roofSizeSet && basicSetting.roofSizeSet == '3' && tabNum === 2 && } @@ -184,6 +215,9 @@ export default function BasicSetting({ id, pos = { x: 50, y: 230 } }) { + diff --git a/src/components/floor-plan/modal/basic/step/Placement.jsx b/src/components/floor-plan/modal/basic/step/Placement.jsx index d4b979c7..d2fca8b2 100644 --- a/src/components/floor-plan/modal/basic/step/Placement.jsx +++ b/src/components/floor-plan/modal/basic/step/Placement.jsx @@ -111,6 +111,11 @@ const Placement = forwardRef((props, refs) => { setSelectedItems({ ...selectedItems, [e.target.name]: e.target.checked }) } + const handleLayoutSetup = (e) => { + props.setLayoutSetup({ ...props.layoutSetup, [e.target.name]: Number(e.target.value) }) + refs.layoutSetup.current = { ...props.layoutSetup, [e.target.name]: Number(e.target.value) } + } + return ( <>
@@ -233,6 +238,33 @@ const Placement = forwardRef((props, refs) => {
+
+
레이아웃 입력
+
+
+
+ + {' '} + × + +
+
+
+
{/*
diff --git a/src/hooks/module/useModuleBasicSetting.js b/src/hooks/module/useModuleBasicSetting.js index 44a0d02e..aa008fc8 100644 --- a/src/hooks/module/useModuleBasicSetting.js +++ b/src/hooks/module/useModuleBasicSetting.js @@ -1,7 +1,14 @@ import { useState } from 'react' import { useRecoilState, useRecoilValue, useSetRecoilState } from 'recoil' -import { canvasSettingState, canvasState, checkedModuleState, currentObjectState, isManualModuleSetupState } from '@/store/canvasAtom' -import { rectToPolygon, polygonToTurfPolygon, calculateVisibleModuleHeight, getDegreeByChon } from '@/util/canvas-util' +import { + canvasSettingState, + canvasState, + checkedModuleState, + currentObjectState, + isManualModuleLayoutSetupState, + isManualModuleSetupState, +} from '@/store/canvasAtom' +import { rectToPolygon, polygonToTurfPolygon, calculateVisibleModuleHeight, getDegreeByChon, toFixedWithoutRounding } from '@/util/canvas-util' import { basicSettingState, roofDisplaySelector } from '@/store/settingAtom' import offsetPolygon, { calculateAngle, createLinesFromPolygon } from '@/util/qpolygon-utils' import { QPolygon } from '@/components/fabric/QPolygon' @@ -35,6 +42,7 @@ export function useModuleBasicSetting(tabNum) { const { setSurfaceShapePattern } = useRoofFn() const checkedModule = useRecoilValue(checkedModuleState) const [isManualModuleSetup, setIsManualModuleSetup] = useRecoilState(isManualModuleSetupState) + const [isManualModuleLayoutSetup, setIsManualModuleLayoutSetup] = useRecoilState(isManualModuleLayoutSetupState) const setModuleStatistics = useSetRecoilState(moduleStatisticsState) const canvasSetting = useRecoilValue(canvasSettingState) @@ -417,13 +425,18 @@ export function useModuleBasicSetting(tabNum) { setSaleStoreNorthFlg(true) } } - }, [isManualModuleSetup]) + }, [isManualModuleSetup, isManualModuleLayoutSetup]) /** * trestle에서 영역을 가져와 mouse:move 이벤트로 해당 영역에 진입했을때 booleanPointInPolygon 로 진입여부를 확인 * 확인 후 셀을 이동시킴 */ const manualModuleSetup = (placementRef) => { + //레이아웃 수동설치 토글 + if (isManualModuleLayoutSetup) { + setIsManualModuleLayoutSetup(false) + } + const moduleSetupSurfaces = canvas?.getObjects().filter((obj) => obj.name === POLYGON_TYPE.MODULE_SETUP_SURFACE) //모듈설치면를 가져옴 if (isManualModuleSetup) { @@ -730,7 +743,7 @@ export function useModuleBasicSetting(tabNum) { tempModule.setCoords() //좌표 재정렬 if (turf.booleanContains(turfPolygon, tempTurfModule) || turf.booleanWithin(tempTurfModule, turfPolygon)) { //마우스 클릭시 set으로 해당 위치에 셀을 넣음 - const isOverlap = manualDrawModules.some((module) => turf.booleanOverlap(tempTurfModule, polygonToTurfPolygon(module))) //겹치는지 확인 + const isOverlap = manualDrawModules.some((module) => turf.booleanOverlap(tempTurfModule, polygonToTurfPolygon(module, true))) //겹치는지 확인 if (!isOverlap) { canvas?.remove(tempModule) @@ -778,6 +791,480 @@ export function useModuleBasicSetting(tabNum) { } } + const manualModuleLayoutSetup = (placementRef) => { + if (isManualModuleSetup) { + setIsManualModuleSetup(false) + } + + const moduleSetupSurfaces = canvas?.getObjects().filter((obj) => obj.name === POLYGON_TYPE.MODULE_SETUP_SURFACE) //모듈설치면를 가져옴 + + if (isManualModuleLayoutSetup) { + if (checkedModule.length === 0) { + swalFire({ text: getMessage('module.place.select.module') }) + setIsManualModuleLayoutSetup(!isManualModuleLayoutSetup) + return + } + + if (checkedModule.length > 1) { + swalFire({ text: getMessage('module.place.select.one.module') }) + setIsManualModuleLayoutSetup(!isManualModuleLayoutSetup) + return + } + + const batchObjects = canvas?.getObjects().filter((obj) => obj.name === POLYGON_TYPE.OBJECT_SURFACE) //도머s 객체 + //수동모드 모듈 설치면 선택 잠금 + moduleSetupSurfaces.forEach((obj) => { + obj.set({ + selectable: false, + evented: false, + }) + }) + + //모듈 기본 옵션 + const moduleOptions = { + fill: checkedModule[0].color, + stroke: 'black', + strokeWidth: 0.3, + selectable: true, // 선택 가능하게 설정 + lockMovementX: true, // X 축 이동 잠금 + lockMovementY: true, // Y 축 이동 잠금 + lockRotation: true, // 회전 잠금 + lockScalingX: true, // X 축 크기 조정 잠금 + lockScalingY: true, // Y 축 크기 조정 잠금 + name: POLYGON_TYPE.MODULE, + } + + const objectsIncludeSurface = (turfModuleSetupSurface) => { + let containsBatchObjects = [] + containsBatchObjects = batchObjects.filter((batchObject) => { + let convertBatchObject = polygonToTurfPolygon(batchObject) + // 폴리곤 안에 도머 폴리곤이 포함되어있는지 확인해서 반환하는 로직 + return ( + turf.booleanContains(turfModuleSetupSurface, convertBatchObject) || + turf.booleanWithin(convertBatchObject, turfModuleSetupSurface) || + turf.booleanOverlap(turfModuleSetupSurface, convertBatchObject) + ) + }) + + return containsBatchObjects + } + + if (moduleSetupSurfaces.length !== 0) { + const col = placementRef.layoutSetup.current.col + const row = placementRef.layoutSetup.current.row + + let tempModule + let manualDrawModules = [] + let inside = false + let turfPolygon + let flowDirection + let trestlePolygon + let width, height, intvHor, intvVer + let containsBatchObjects + + addCanvasMouseEventListener('mouse:move', (e) => { + //마우스 이벤트 삭제 후 재추가 + const mousePoint = canvas.getPointer(e.e) + + for (let i = 0; i < moduleSetupSurfaces.length; i++) { + //배치면이 여러개 일때 옮겨가면서 동작해야함 + turfPolygon = polygonToTurfPolygon(moduleSetupSurfaces[i]) + trestlePolygon = moduleSetupSurfaces[i] + manualDrawModules = moduleSetupSurfaces[i].modules // 앞에서 자동으로 했을때 추가됨 + flowDirection = moduleSetupSurfaces[i].direction //도형의 방향 + + containsBatchObjects = objectsIncludeSurface(turfPolygon) //배치면에 오브젝트(도머, 개구등)이 있는지 확인하는 로직 + + const moduleWidth = Number(checkedModule[0].longAxis) / 10 + const moduleHeight = Number(checkedModule[0].shortAxis) / 10 + let tmpWidth = flowDirection === 'south' || flowDirection === 'north' ? moduleWidth : moduleHeight + let tmpHeight = flowDirection === 'south' || flowDirection === 'north' ? moduleHeight : moduleWidth + + width = + canvasSetting.roofSizeSet == '1' + ? calculateVisibleModuleHeight(tmpWidth, tmpHeight, getDegreeByChon(moduleSetupSurfaces[i].roofMaterial.pitch), flowDirection).width + : tmpWidth + height = + canvasSetting.roofSizeSet == '1' + ? calculateVisibleModuleHeight(tmpWidth, tmpHeight, getDegreeByChon(moduleSetupSurfaces[i].roofMaterial.pitch), flowDirection).height + : tmpHeight + + intvHor = + flowDirection === 'south' || flowDirection === 'north' + ? moduleSetupSurfaces[i].trestleDetail.moduleIntvlHor / 10 + : moduleSetupSurfaces[i].trestleDetail.moduleIntvlVer / 10 + intvVer = + flowDirection === 'south' || flowDirection === 'north' + ? moduleSetupSurfaces[i].trestleDetail.moduleIntvlVer / 10 + : moduleSetupSurfaces[i].trestleDetail.moduleIntvlHor / 10 + + let calcHalfWidth = (Number((width * col).toFixed(1)) + Number((intvHor * (col - 1)).toFixed(1))) / 2 + let calcHalfHeight = (Number((height * row).toFixed(1)) + Number((intvVer * (row - 1)).toFixed(1))) / 2 + + //아래래 + let points = [ + { + x: Number(mousePoint.x.toFixed(1)) - calcHalfWidth, + y: Number(mousePoint.y.toFixed(1)) - calcHalfHeight, + }, + { + x: Number(mousePoint.x.toFixed(1)) - calcHalfWidth, + y: Number(mousePoint.y.toFixed(1)) + calcHalfHeight, + }, + { + x: Number(mousePoint.x.toFixed(1)) + calcHalfWidth, + y: Number(mousePoint.y.toFixed(1)) + calcHalfHeight, + }, + { + x: Number(mousePoint.x.toFixed(1)) + calcHalfWidth, + y: Number(mousePoint.y.toFixed(1)) - calcHalfHeight, + }, + ] + + // const points = [ + // { + // x: Number(mousePoint.x.toFixed(1)) + Number((width / 2).toFixed(1)), + // y: Number(mousePoint.y.toFixed(1)) - Number((height / 2).toFixed(1)), + // }, + // { + // x: Number(mousePoint.x.toFixed(1)) + Number((width / 2).toFixed(1)), + // y: Number(mousePoint.y.toFixed(1)) + Number((height / 2).toFixed(1)), + // }, + // { + // x: Number(mousePoint.x.toFixed(1)) - Number((width / 2).toFixed(1)), + // y: Number(mousePoint.y.toFixed(1)) - Number((height / 2).toFixed(1)), + // }, + // { + // x: Number(mousePoint.x.toFixed(1)) - Number((width / 2).toFixed(1)), + // y: Number(mousePoint.y.toFixed(1)) + Number((height / 2).toFixed(1)), + // }, + // ] + + const turfPoints = coordToTurfPolygon(points) + + if (turf.booleanWithin(turfPoints, turfPolygon)) { + let isDrawing = false + + if (isDrawing) return + canvas?.remove(...canvas?.getObjects().filter((obj) => obj.name === 'tempModule')) //움직일때 일단 지워가면서 움직임 + + tempModule = new fabric.Rect({ + fill: 'rgba(224, 221, 222, 0.7)', + stroke: 'black', + strokeWidth: 1, + strokeDashArray: [10, 5], + // width: Number(width.toFixed(1)), //작은버전 + // height: Number(height.toFixed(1)), //작은버전 + // left: Number(mousePoint.x.toFixed(1) - Number((width / 2).toFixed(1))), //작은버전 + // top: Number(mousePoint.y.toFixed(1) - Number((height / 2).toFixed(1))), //작은버전 + width: Number((width * col).toFixed(1)) + Number((intvHor * (col - 1)).toFixed(1)), //큰버전 + height: Number((height * row).toFixed(1)) + Number((intvVer * (row - 1)).toFixed(1)), //큰버전 + left: Number(mousePoint.x.toFixed(1)) - calcHalfWidth.toFixed(1), //큰버전 + top: Number(mousePoint.y.toFixed(1)) - calcHalfHeight.toFixed(1), //큰버전 + selectable: false, + lockMovementX: true, + lockMovementY: true, + lockRotation: true, + lockScalingX: true, + lockScalingY: true, + name: 'tempModule', + parentId: moduleSetupSurfaces[i].parentId, + }) + + //북면이고 북면설치상점이 아니면 그냥 return + if (trestlePolygon.isNorth && !saleStoreNorthFlg) { + return + } else { + canvas?.add(tempModule) //움직여가면서 추가됨 + } + + /** + * 스냅기능 + */ + let snapDistance = flowDirection === 'south' || flowDirection === 'north' ? 70 : 40 + let trestleSnapDistance = 15 + + const trestleLeft = Number(moduleSetupSurfaces[i].left.toFixed(1)) - Number((moduleSetupSurfaces[i].width / 2).toFixed(1)) + const trestleTop = Number(moduleSetupSurfaces[i].top.toFixed(1)) - Number((moduleSetupSurfaces[i].height / 2).toFixed(1)) + const trestleRight = Number(moduleSetupSurfaces[i].left.toFixed(1)) + Number((moduleSetupSurfaces[i].width / 2).toFixed(1)) + const trestleBottom = Number(moduleSetupSurfaces[i].top.toFixed(1)) + Number((moduleSetupSurfaces[i].height / 2).toFixed(1)) + const bigCenterY = (trestleTop + trestleTop + moduleSetupSurfaces[i].height) / 2 + + // 이동하는 모듈의 경계 좌표 + const smallLeft = Number(tempModule.left.toFixed(1)) + const smallTop = Number(tempModule.top.toFixed(1)) + const smallRight = smallLeft + Number(tempModule.width.toFixed(1)) + const smallBottom = smallTop + Number(tempModule.height.toFixed(1)) + const smallCenterX = smallLeft + Number((tempModule.width / 2).toFixed(1)) + const smallCenterY = smallTop + Number((tempModule.height / 2).toFixed(1)) + + /** + * 미리 깔아놓은 셀이 있을때 셀에 흡착됨 + */ + // if (manualDrawModules) { + // manualDrawModules.forEach((cell) => { + // const holdCellLeft = cell.left + // const holdCellTop = cell.top + // const holdCellRight = holdCellLeft + Number(cell.width.toFixed(1)) + // const holdCellBottom = holdCellTop + Number(cell.height.toFixed(1)) + // const holdCellCenterX = holdCellLeft + Number((cell.width / 2).toFixed(1)) + // const holdCellCenterY = holdCellTop + Number((cell.height / 2).toFixed(1)) + + // //설치된 셀에 좌측에 스냅 + // if (Math.abs(smallRight - holdCellLeft) < snapDistance) { + // tempModule.left = holdCellLeft - width - intvHor + // } + + // //설치된 셀에 우측에 스냅 + // if (Math.abs(smallLeft - holdCellRight) < snapDistance) { + // tempModule.left = holdCellRight + intvHor + // } + + // //설치된 셀에 위쪽에 스냅 + // if (Math.abs(smallBottom - holdCellTop) < snapDistance) { + // tempModule.top = holdCellTop - height - intvVer + // } + + // //설치된 셀에 밑쪽에 스냅 + // if (Math.abs(smallTop - holdCellBottom) < snapDistance) { + // tempModule.top = holdCellBottom + intvVer + // } + // //가운데 -> 가운데 + // if (Math.abs(smallCenterX - holdCellCenterX) < snapDistance) { + // tempModule.left = holdCellCenterX - Number((width / 2).toFixed(1)) + // } + // //왼쪽 -> 가운데 + // if (Math.abs(smallLeft - holdCellCenterX) < snapDistance) { + // tempModule.left = holdCellCenterX + // } + // // 오른쪽 -> 가운데 + // if (Math.abs(smallRight - holdCellCenterX) < snapDistance) { + // tempModule.left = holdCellCenterX - width + // } + // //세로 가운데 -> 가운데 + // if (Math.abs(smallCenterY - holdCellCenterY) < snapDistance) { + // tempModule.top = holdCellCenterY - Number((height / 2).toFixed(1)) + // } + // // //위쪽 -> 가운데 + // // if (Math.abs(smallTop - holdCellCenterY) < cellSnapDistance) { + // // tempModule.top = holdCellCenterY + // // } + // // //아랫쪽 -> 가운데 + // // if (Math.abs(smallBottom - holdCellCenterY) < cellSnapDistance) { + // // tempModule.top = holdCellCenterY - height + // // } + // }) + // } + + // 위쪽 변에 스냅 + if (Math.abs(smallTop - trestleTop) < trestleSnapDistance) { + tempModule.top = trestleTop + 1 + } + + // 아래쪽 변에 스냅 + if (Math.abs(smallBottom - trestleBottom) < trestleSnapDistance) { + tempModule.top = trestleTop + moduleSetupSurfaces[i].height - tempModule.height - 1 + } + + // 왼쪽변에 스냅 + if (Math.abs(smallLeft - trestleLeft) < trestleSnapDistance) { + tempModule.left = trestleLeft + 1 + } + //오른쪽 변에 스냅 + if (Math.abs(smallRight - trestleRight) < trestleSnapDistance) { + tempModule.left = trestleRight - tempModule.width - 1 + } + + if (flowDirection === 'south' || flowDirection === 'north') { + // 모듈왼쪽이 세로중앙선에 붙게 스냅 + // if (Math.abs(smallLeft - (trestleLeft + moduleSetupSurfaces[i].width / 2)) < snapDistance) { + // tempModule.left = trestleLeft + moduleSetupSurfaces[i].width / 2 + // } + + // 모듈이 가운데가 세로중앙선에 붙게 스냅 + if (Math.abs(smallCenterX - (trestleLeft + moduleSetupSurfaces[i].width / 2)) < trestleSnapDistance) { + tempModule.left = trestleLeft + moduleSetupSurfaces[i].width / 2 - tempModule.width / 2 + } + + // 모듈오른쪽이 세로중앙선에 붙게 스냅 + // if (Math.abs(smallRight - (trestleLeft + moduleSetupSurfaces[i].width / 2)) < trestleSnapDistance) { + // tempModule.left = trestleLeft + moduleSetupSurfaces[i].width / 2 - tempModule.width * tempModule.scaleX + // } + } else { + // 모듈이 가로중앙선에 스냅 + if (Math.abs(smallTop + tempModule.height / 2 - bigCenterY) < trestleSnapDistance) { + tempModule.top = bigCenterY - tempModule.height / 2 + } + + // if (Math.abs(smallTop - (trestleTop + moduleSetupSurfaces[i].height / 2)) < trestleSnapDistance) { + // tempModule.top = trestleTop + moduleSetupSurfaces[i].height / 2 + // } + // 모듈 밑면이 가로중앙선에 스냅 + // if (Math.abs(smallBottom - (trestleTop + moduleSetupSurfaces[i].height / 2)) < trestleSnapDistance) { + // tempModule.top = trestleTop + moduleSetupSurfaces[i].height / 2 - tempModule.height * tempModule.scaleY + // } + } + + tempModule.setCoords() + canvas?.renderAll() + inside = true + break + } else { + inside = false + } + } + + if (!inside) { + // tempModule.set({ fill: 'red' }) + canvas?.remove(...canvas?.getObjects().filter((obj) => obj.name === 'tempModule')) + canvas?.renderAll() + } + }) + + addCanvasMouseEventListener('mouse:up', (e) => { + let isIntersection = true + if (!inside) return + if (tempModule) { + let startX, startY + + console.log(tempModule) + + //그려진 가이드 라인의 포인트를 기준으로 시작점을 만든다 + if (flowDirection === 'south') { + startX = toFixedWithoutRounding(tempModule.left, 1) + startY = toFixedWithoutRounding(tempModule.top + tempModule.height, 1) + + for (let i = 0; i < placementRef.layoutSetup.current.row; i++) { + let tempY = startY - i * height + let tempHeightMargin = i === 0 ? 0 : i * intvVer + for (let j = 0; j < placementRef.layoutSetup.current.col; j++) { + let tempX = startX + j * width + let tempWidthMargin = j === 0 ? 0 : j * intvHor + + let rectPoints = [ + { x: tempX + tempWidthMargin, y: tempY - height - tempHeightMargin }, + { x: tempX + tempWidthMargin, y: tempY - tempHeightMargin }, + { x: tempX + width + tempWidthMargin, y: tempY - tempHeightMargin }, + { x: tempX + width + tempWidthMargin, y: tempY - height - tempHeightMargin }, + ] + // console.log('🚀 ~ addCanvasMouseEventListener ~ rectPoints:', rectPoints) + + tempModule.set({ points: rectPoints }) + const tempTurfModule = polygonToTurfPolygon(tempModule) + tempModule.setCoords() //좌표 재정렬 + + if (turf.booleanContains(turfPolygon, tempTurfModule) || turf.booleanWithin(tempTurfModule, turfPolygon)) { + //마우스 클릭시 set으로 해당 위치에 셀을 넣음 + const isOverlap = manualDrawModules.some((module) => turf.booleanOverlap(tempTurfModule, polygonToTurfPolygon(module))) //겹치는지 확인 + if (!isOverlap) { + canvas?.remove(tempModule) + + //안겹치면 넣는다 + // tempModule.setCoords() + moduleOptions.surfaceId = trestlePolygon.id + + let manualModule = new QPolygon(tempModule.points, { + ...moduleOptions, + moduleInfo: checkedModule[0], + // left: toFixedWithoutRounding(tempX + tempWidthMargin, 1), + // top: toFixedWithoutRounding(tempY - height - tempHeightMargin, 1), + width: toFixedWithoutRounding(width, 1), + height: toFixedWithoutRounding(height, 1), + }) + + let isDisjoint = checkModuleDisjointObjects(tempTurfModule, containsBatchObjects) + + //오브젝트와 겹치지 않으면 넣는다 + if (isDisjoint) { + canvas?.add(manualModule) + manualDrawModules.push(manualModule) + setModuleStatisticsData() + } + // getModuleStatistics() + } else { + swalFire({ text: getMessage('module.place.overlab') }) + return + } + } + } + } + } else if (flowDirection === 'north') { + startX = tempModule.points[3].x + startY = tempModule.points[3].y + } else if (flowDirection === 'east') { + startX = tempModule.points[2].x + startY = tempModule.points[2].y + } else { + startX = tempModule.points[0].x + startY = tempModule.points[0].y + } + + //도머 객체를 가져옴 + // if (batchObjects) { + // batchObjects.forEach((object) => { + // let dormerTurfPolygon = polygonToTurfPolygon(object, true) + // const intersection = turf.intersect(turf.featureCollection([dormerTurfPolygon, tempTurfModule])) //겹치는지 확인 + // //겹치면 안됨 + // if (intersection) { + // swalFire({ text: getMessage('module.place.overobject') }) + // isIntersection = false + // } + // }) + // } + + // if (!isIntersection) return + + // tempModule.setCoords() //좌표 재정렬 + // if (turf.booleanContains(turfPolygon, tempTurfModule) || turf.booleanWithin(tempTurfModule, turfPolygon)) { + // //마우스 클릭시 set으로 해당 위치에 셀을 넣음 + // const isOverlap = manualDrawModules.some((module) => turf.booleanOverlap(tempTurfModule, polygonToTurfPolygon(module))) //겹치는지 확인 + // if (!isOverlap) { + // canvas?.remove(tempModule) + + // //안겹치면 넣는다 + // // tempModule.setCoords() + // moduleOptions.surfaceId = trestlePolygon.id + + // // console.log('tempModule.points', tempModule.points) + + // let manualModule = new QPolygon(tempModule.points, { + // ...moduleOptions, + // moduleInfo: checkedModule[0], + // left: Number(tempModule.left.toFixed(1)), + // top: Number(tempModule.top.toFixed(1)), + // width: Number(tempModule.width.toFixed(1)), + // height: Number(tempModule.height.toFixed(1)), + // }) + // canvas?.add(manualModule) + // manualDrawModules.push(manualModule) + // setModuleStatisticsData() + // // getModuleStatistics() + // } else { + // swalFire({ text: getMessage('module.place.overlab') }) + // } + // } else { + // swalFire({ text: getMessage('module.place.out') }) + // } + } + }) + } + } else { + if (moduleSetupSurfaces) { + //수동모드 해제시 모듈 설치면 선택 잠금 + moduleSetupSurfaces.forEach((obj) => { + obj.set({ + selectable: true, + evented: true, + }) + }) + } + + removeMouseEvent('mouse:up') + removeMouseEvent('mouse:move') + canvas?.remove(...canvas?.getObjects().filter((obj) => obj.name === 'tempModule')) //움직일때 일단 지워가면서 움직임 + } + } + //자동 모듈 설치(그리드 방식) const autoModuleSetup = (placementRef) => { initEvent() //마우스 이벤트 초기화 @@ -789,7 +1276,8 @@ export function useModuleBasicSetting(tabNum) { const isChidori = placementRef.isChidori.current === 'true' ? true : false const setupLocation = placementRef.setupLocation.current - const isMaxSetup = placementRef.isMaxSetup.current === 'true' ? true : false + const isMaxSetup = false + // const isMaxSetup = placementRef.isMaxSetup.current === 'true' ? true : false const moduleSetupSurfaces = moduleSetupSurface //선택 설치면 const notSelectedTrestlePolygons = canvas @@ -2726,6 +3214,7 @@ export function useModuleBasicSetting(tabNum) { selectedModules, makeModuleInstArea, manualModuleSetup, + manualModuleLayoutSetup, autoModuleSetup, restoreModuleInstArea, manualFlatroofModuleSetup, diff --git a/src/store/canvasAtom.js b/src/store/canvasAtom.js index 772e55be..3e795f22 100644 --- a/src/store/canvasAtom.js +++ b/src/store/canvasAtom.js @@ -384,3 +384,8 @@ export const isManualModuleSetupState = atom({ key: 'isManualModuleSetupState', default: false, }) + +export const isManualModuleLayoutSetupState = atom({ + key: 'isManualModuleLayoutSetupState', + default: false, +})