From c880b0bf13e9b9bcebb0eb31d15a228a57bfb36e Mon Sep 17 00:00:00 2001 From: yjnoh Date: Tue, 31 Dec 2024 08:59:01 +0900 Subject: [PATCH] =?UTF-8?q?=EB=AA=A8=EB=93=88=20api=20=EC=97=B0=EB=8F=99?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/common/select/QSelectBox.jsx | 21 +- .../floor-plan/modal/basic/step/Module.jsx | 316 +++++-- .../floor-plan/modal/basic/step/Placement.jsx | 93 +-- .../floor-plan/modal/module/PanelEdit.jsx | 9 +- src/hooks/module/useModuleBasicSetting.js | 782 +++++++++++------- src/store/canvasAtom.js | 12 + 6 files changed, 780 insertions(+), 453 deletions(-) diff --git a/src/components/common/select/QSelectBox.jsx b/src/components/common/select/QSelectBox.jsx index 9f86474d..108eb7d1 100644 --- a/src/components/common/select/QSelectBox.jsx +++ b/src/components/common/select/QSelectBox.jsx @@ -17,7 +17,7 @@ import { useOnClickOutside } from 'usehooks-ts' */ export default function QSelectBox({ title = '', - options, + options = [], onChange, value, disabled = false, @@ -39,7 +39,11 @@ export default function QSelectBox({ //value가 없으면 showKey가 있으면 우선 보여준다 if (showKey !== '' && !value) { - return options[0][showKey] + if (options.length > 0) { + return title + } else { + return options[0][showKey] + } } //value가 있으면 sourceKey와 targetKey를 비교하여 보여준다 @@ -65,7 +69,7 @@ export default function QSelectBox({ useEffect(() => { // value && handleClickSelectOption(value) setSelected(handleInitState()) - }, [value, sourceKey, targetKey, showKey]) + }, [options, value, sourceKey, targetKey, showKey]) useOnClickOutside(ref, handleClose) @@ -73,11 +77,12 @@ export default function QSelectBox({
{} : () => setOpenSelect(!openSelect)}>

{selected}

) diff --git a/src/components/floor-plan/modal/basic/step/Module.jsx b/src/components/floor-plan/modal/basic/step/Module.jsx index e3e5c7bc..0e6750e7 100644 --- a/src/components/floor-plan/modal/basic/step/Module.jsx +++ b/src/components/floor-plan/modal/basic/step/Module.jsx @@ -1,9 +1,75 @@ import QSelectBox from '@/components/common/select/QSelectBox' import { useMessage } from '@/hooks/useMessage' +import { canvasSettingState, selectedModuleState, checkedModuleState, pitchSelector } from '@/store/canvasAtom' +import { useEffect, useReducer, useState } from 'react' +import { useRecoilValue, useRecoilState } from 'recoil' +import { useMasterController } from '@/hooks/common/useMasterController' +import { useCommonCode } from '@/hooks/common/useCommonCode' +import { addedRoofsState } from '@/store/settingAtom' export default function Module({}) { + const canvasSetting = useRecoilValue(canvasSettingState) //캔버스 기본 셋팅 + const addedRoofs = useRecoilValue(addedRoofsState) //지붕재 선택 + + const [globalPitch, setGlobalPitch] = useRecoilState(pitchSelector) + + const [roofTab, setRoofTab] = useState(0) + const [moduleList, setModuleList] = useState([{}]) + const [roofMaterial, setRoofMaterial] = useState(addedRoofs[0]) + const [raftCodes, setRaftCodes] = useState([]) + + const { getModuleTypeItemList, getTrestleList } = useMasterController() const { getMessage } = useMessage() - const SelectOption01 = [{ name: '0' }, { name: '0' }, { name: '0' }, { name: '0' }] + const { findCommonCode } = useCommonCode() + + const [selectedModules, setSelectedModules] = useRecoilState(selectedModuleState) //선택된 모듈 + const [selectedTrestle, setSelectedTrestle] = useState({}) //선택된 가대 + const [selectedConstMthd, setSelectedConstMthd] = useState({}) //선택된 공법 + const [selectedRoofBase, setSelectedRoofBase] = useState({}) //선택된 지붕밑바탕 + + const [selectedOptions, dispatchSelectedOptions] = useReducer( + (prevState, nextState) => { + return { ...prevState, ...nextState } + }, + { + module: {}, + roofs: [], + }, + ) + + const displayPitch = canvasSetting.roofAngleSet === 'slope' ? '寸' : '度' + + const [trestleList, setTrestleList] = useState([]) + const [constMthdList, setConstMthdList] = useState([]) + const [roofBaseList, setRoofBaseList] = useState([]) + + let optionParams = { + moduleTpCd: '', + roofMatlCd: '', + raftBaseCd: '', + trestleMkrCd: '', + constMthdCd: '', + roofBaseCd: '', + } + + useEffect(() => { + //서까래 코드 + const raftCodeList = findCommonCode('203800') + + raftCodeList.forEach((obj) => { + obj.name = obj.clCodeNm + obj.id = obj.clCode + }) + setRaftCodes(raftCodeList) + + //지붕재 선택 + const roofsIds = addedRoofs.filter((obj) => obj.roofMatlCd).map((obj) => obj.roofMatlCd) + if (roofsIds.length === 0) { + return + } + getModuleData(roofsIds) + }, []) + const moduleData = { header: [ { name: getMessage('module'), width: 150, prop: 'module', type: 'color-box' }, @@ -14,23 +80,7 @@ export default function Module({}) { { name: `${getMessage('width')} (mm)`, prop: 'width' }, { name: `${getMessage('output')} (W)`, prop: 'output' }, ], - rows: [ - { - module: { name: 'Re.RISE-G3 440', color: '#AA6768' }, - height: { name: '1134' }, - width: { name: '1722' }, - output: { name: '440' }, - }, - { - module: { - name: 'Re.RISE MS-G3 290', - color: '#67A2AA', - }, - height: { name: '1134' }, - width: { name: '1722' }, - output: { name: '240' }, - }, - ], + rows: [], } const surfaceTypes = [ { id: 1, name: 'Ⅱ', value: 'Ⅱ' }, @@ -42,6 +92,109 @@ export default function Module({}) { const windSpeeds = Array.from({ length: 7 }).map((data, index) => { return { id: index, name: index * 2 + 30, value: index * 2 + 30 } }) + + const handleRoofTab = (tab) => { + setRoofMaterial(addedRoofs[tab]) + setRoofTab(tab) + } + + const handleChangeModule = (option) => { + setSelectedModules(option) //선택값 저장 + + optionParams = { + moduleTpCd: option.itemTp, + roofMatlCd: roofMaterial.roofMatlCd, + raftBaseCd: '', + } + + getModuleOptionsListData(optionParams, 'trestleList') + + dispatchSelectedOptions({ + module: option, + }) + } + + const handleChangeTrestle = (option) => { + setSelectedTrestle(option) //선택값 저장 + + optionParams = { + moduleTpCd: selectedModules.itemTp, + roofMatlCd: roofMaterial.roofMatlCd, + raftBaseCd: '', + trestleMkrCd: option.trestleMkrCd, + } + + getModuleOptionsListData(optionParams, 'constMthdList') + + selectedOptions.roofs.map((roof) => { + if (roof.id === tab) { + roof.trestle = option + } else { + roof.trestle = { + id: tab, + trestle: option, + } + } + }) + dispatchSelectedOptions({ + roofs: selectedOptions.roofs, + }) + } + + const handleChangeConstMthd = (option) => { + setSelectedConstMthd(option) //선택된값 저장 + + optionParams = { + moduleTpCd: selectedModules.itemTp, + roofMatlCd: roofMaterial.roofMatlCd, + raftBaseCd: '', + trestleMkrCd: selectedTrestle.trestleMkrCd, + constMthdCd: option.constMthdCd, + } + + getModuleOptionsListData(optionParams, 'roofBaseList') + } + + useEffect(() => { + console.log('roofMaterial', roofMaterial) + }, [roofMaterial]) + + const getModuleData = async (roofsIds) => { + const list = await getModuleTypeItemList(roofsIds) + //selectbox에 이름을 넣는다 + list.data.forEach((item) => { + item.name = item.itemNm + }) + //셀렉트박스 데이터 초기화 + setModuleList(list.data) + setTrestleList([]) + setConstMthdList([]) + setRoofBaseList([]) + } + + const getModuleOptionsListData = async (params, optionsName) => { + const optionsList = await getTrestleList(params) + + if (optionsName === 'trestleList') { + setTrestleList(optionsList.data) + setConstMthdList([]) + setRoofBaseList([]) + } + + if (optionsName === 'constMthdList') { + setConstMthdList(optionsList.data) + setRoofBaseList([]) + } + + if (optionsName === 'roofBaseList') { + setRoofBaseList(optionsList.data) + } + } + + useEffect(() => { + console.log('selectedOptions', selectedOptions) + }, [selectedOptions]) + return ( <>
@@ -50,7 +203,7 @@ export default function Module({}) {
{getMessage('modal.module.basic.setting.module.setting')}
- +
@@ -67,34 +220,22 @@ export default function Module({}) { - {moduleData.rows.map((row) => ( - <> - - {moduleData.header.map((header) => ( - <> - {header.type === 'color-box' && ( - -
- - {row[header.prop].name} -
- - )} - {!header.type && header.type !== 'color-box' && {row[header.prop].name}} - - ))} - - - ))} - - {Array.from({ length: 3 - moduleData.rows.length }).map((_, i) => ( - - - - - - - ))} + {selectedModules.itemList && + selectedModules.itemList.map((row) => ( + <> + + +
+ + {row.itemNm} +
+ + {Number(row.shortAxis).toFixed(0)} + {Number(row.longAxis).toFixed(0)} + {Number(row.wpOut).toFixed(0)} + + + ))}
@@ -153,37 +294,72 @@ export default function Module({}) {
- - - - + {addedRoofs.map((roof, index) => ( + + ))} + {/* + + + */}
-
{getMessage('modal.module.basic.setting.module.roof.material')}:スレーツ(4寸)
+
+ {getMessage('modal.module.basic.setting.module.roof.material')}:{roofMaterial.nameJp}({globalPitch} + {displayPitch}) +
-
{getMessage('modal.module.basic.setting.module.rafter.margin')}
-
-
-
- -
-
- 垂木の間隔 -
- + {roofMaterial && ['C', 'R'].includes(roofMaterial.raftAuth) && ( + <> +
{getMessage('modal.module.basic.setting.module.rafter.margin')}
+
+
+
+ {raftCodes.length > 0 && ( + <> + + + )} +
+
+ 垂木の間隔 +
+ +
+
-
-
+ + )}
{getMessage('modal.module.basic.setting.module.trestle.maker')}
- +
@@ -191,7 +367,13 @@ export default function Module({}) {
{getMessage('modal.module.basic.setting.module.construction.method')}
- +
@@ -199,7 +381,7 @@ export default function Module({}) {
{getMessage('modal.module.basic.setting.module.under.roof')}
- +
diff --git a/src/components/floor-plan/modal/basic/step/Placement.jsx b/src/components/floor-plan/modal/basic/step/Placement.jsx index a087f3dc..d6748d01 100644 --- a/src/components/floor-plan/modal/basic/step/Placement.jsx +++ b/src/components/floor-plan/modal/basic/step/Placement.jsx @@ -1,40 +1,40 @@ import { forwardRef, useEffect, useState } from 'react' import { useMessage } from '@/hooks/useMessage' import { useModuleBasicSetting } from '@/hooks/module/useModuleBasicSetting' +import { selectedModuleState, checkedModuleState } from '@/store/canvasAtom' +import { useRecoilValue, useRecoilState, useSetRecoilState } from 'recoil' const Placement = forwardRef((props, refs) => { const { getMessage } = useMessage() + const selectedModules = useRecoilValue(selectedModuleState) const [isChidori, setIsChidori] = useState('false') const [setupLocation, setSetupLocation] = useState('center') const [isMaxSetup, setIsMaxSetup] = useState('false') - const { makeModuleInstArea } = useModuleBasicSetting() + const [selectedItems, setSelectedItems] = useState({}) + const setCheckedModules = useSetRecoilState(checkedModuleState) + //모듈 배치면 생성 useEffect(() => { makeModuleInstArea() }, []) + //체크된 모듈 데이터 + useEffect(() => { + const checkedModuleIds = Object.keys(selectedItems).filter((key) => selectedItems[key]) + const moduleArray = selectedModules.itemList.filter((item) => { + return checkedModuleIds.includes(item.itemId) + }) + setCheckedModules(moduleArray) + }, [selectedItems]) + const moduleData = { header: [ { type: 'check', name: '', prop: 'check', width: 70 }, { type: 'color-box', name: getMessage('module'), prop: 'module' }, { type: 'text', name: `${getMessage('output')} (W)`, prop: 'output', width: 70 }, ], - rows: [ - { - check: false, - module: { name: 'Re.RISE-G3 440', color: '#AA6768' }, - output: { name: '440' }, - }, - { - check: false, - module: { - name: 'Re.RISE MS-G3 290', - color: '#67A2AA', - }, - output: { name: '240' }, - }, - ], + rows: [], } const handleChangeChidori = (e) => { @@ -48,8 +48,6 @@ const Placement = forwardRef((props, refs) => { } const handleMaxSetup = (e) => { - console.log(e.target.checked) - if (e.target.checked) { setIsMaxSetup('true') refs.isMaxSetup.current = 'true' @@ -59,6 +57,11 @@ const Placement = forwardRef((props, refs) => { } } + //체크된 모듈 아이디 추출 + const handleSelectedItem = (e) => { + setSelectedItems({ ...selectedItems, [e.target.name]: e.target.checked }) + } + return ( <>
@@ -83,40 +86,26 @@ const Placement = forwardRef((props, refs) => { - {moduleData.rows.map((row) => ( - <> - - {moduleData.header.map((header) => ( - <> - {header.type === 'color-box' && ( - -
- - {row[header.prop].name} -
- - )} - {header.type === 'check' && ( - -
- - -
- - )} - {header.type && header.type !== 'color-box' && header.type !== 'check' && ( - {row[header.prop].name} - )} - - ))} - - - ))} - - - - - + {selectedModules.itemList && + selectedModules.itemList.map((item) => ( + <> + + +
+ + +
+ + +
+ + {item.itemNm} +
+ + {item.wpOut} + + + ))}
diff --git a/src/components/floor-plan/modal/module/PanelEdit.jsx b/src/components/floor-plan/modal/module/PanelEdit.jsx index c63dd0cd..ec9d9e1b 100644 --- a/src/components/floor-plan/modal/module/PanelEdit.jsx +++ b/src/components/floor-plan/modal/module/PanelEdit.jsx @@ -33,10 +33,6 @@ export default function PanelEdit(props) { } const contextModuleMove = (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 추출 @@ -51,7 +47,7 @@ export default function PanelEdit(props) { const isInSurfaceArray = [] if (selectedModules) { - canvas.remove(...selectedModules) + canvas.remove(...selectedModules) //지워야 겹치는지 확인 가능 selectedModules.forEach((module) => { module.set({ @@ -79,10 +75,9 @@ export default function PanelEdit(props) { ) 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) }) diff --git a/src/hooks/module/useModuleBasicSetting.js b/src/hooks/module/useModuleBasicSetting.js index c9b00b8a..d9f8ae84 100644 --- a/src/hooks/module/useModuleBasicSetting.js +++ b/src/hooks/module/useModuleBasicSetting.js @@ -1,5 +1,5 @@ import { useRecoilState, useRecoilValue } from 'recoil' -import { canvasState } from '@/store/canvasAtom' +import { canvasState, checkedModuleState, selectedModuleState } from '@/store/canvasAtom' import { rectToPolygon, setSurfaceShapePattern, polygonToTurfPolygon } from '@/util/canvas-util' import { basicSettingState, roofDisplaySelector } from '@/store/settingAtom' import offsetPolygon, { calculateAngle } from '@/util/qpolygon-utils' @@ -27,6 +27,7 @@ export function useModuleBasicSetting() { const compasDeg = useRecoilValue(compasDegAtom) const { setSurfaceShapePattern } = useRoofFn() const [basicSetting, setBasicSettings] = useRecoilState(basicSettingState) + const checkedModule = useRecoilValue(checkedModuleState) useEffect(() => { // console.log('basicSetting', basicSetting) @@ -42,21 +43,6 @@ export function useModuleBasicSetting() { // const { addTargetMouseEventListener, addCanvasMouseEventListener, initEvent } = useContext(EventContext) let selectedModuleInstSurfaceArray = [] - const moduleOptions = { - fill: '#BFFD9F', - stroke: 'black', - strokeWidth: 0.1, - selectable: true, // 선택 가능하게 설정 - lockMovementX: true, // X 축 이동 잠금 - lockMovementY: true, // Y 축 이동 잠금 - lockRotation: true, // 회전 잠금 - lockScalingX: true, // X 축 크기 조정 잠금 - lockScalingY: true, // Y 축 크기 조정 잠금 - parentId: moduleSetupSurface.parentId, - surfaceId: moduleSetupSurface.id, - name: 'module', - } - //모듈,회로에서 다른메뉴 -> 배치면으로 갈 경수 초기화 const restoreModuleInstArea = () => { //설치면 삭제 @@ -127,18 +113,6 @@ export function useModuleBasicSetting() { setupSurface.setViewLengthText(false) canvas.add(setupSurface) //모듈설치면 만들기 - //육지붕이 아닐때만 넣는다 육지붕일땐 클릭 이벤트에 별도로 넣어놓음 - if (canvasSetting.roofSizeSet !== 3) { - const flowLines = { - bottom: bottomTopFlowLine(setupSurface).find((obj) => obj.target === 'bottom'), - top: bottomTopFlowLine(setupSurface).find((obj) => obj.target === 'top'), - left: leftRightFlowLine(setupSurface).find((obj) => obj.target === 'left'), - right: leftRightFlowLine(setupSurface).find((obj) => obj.target === 'right'), - } - - setupSurface.set({ flowLines: flowLines }) - } - //지붕면 선택 금지 roof.set({ selectable: false, @@ -193,6 +167,16 @@ export function useModuleBasicSetting() { * 확인 후 셀을 이동시킴 */ const manualModuleSetup = () => { + if (checkedModule.length === 0) { + swalFire({ text: '모듈을 선택해주세요.' }) + return + } + + if (checkedModule.length > 1) { + swalFire({ text: '모듈은 하나만 선택해주세요.' }) + return + } + const moduleSetupSurfaces = canvas?.getObjects().filter((obj) => obj.name === POLYGON_TYPE.MODULE_SETUP_SURFACE) //모듈설치면를 가져옴 const batchObjects = canvas ?.getObjects() @@ -204,6 +188,19 @@ export function useModuleBasicSetting() { obj.name === BATCH_TYPE.SHADOW, ) //도머s 객체 + const moduleOptions = { + fill: checkedModule[0].color, + stroke: 'black', + strokeWidth: 0.1, + selectable: true, // 선택 가능하게 설정 + lockMovementX: true, // X 축 이동 잠금 + lockMovementY: true, // Y 축 이동 잠금 + lockRotation: true, // 회전 잠금 + lockScalingX: true, // X 축 크기 조정 잠금 + lockScalingY: true, // Y 축 크기 조정 잠금 + name: 'module', + } + if (moduleSetupSurfaces.length !== 0) { let tempModule let manualDrawModules = [] @@ -221,8 +218,10 @@ export function useModuleBasicSetting() { trestlePolygon = moduleSetupSurfaces[i] manualDrawModules = moduleSetupSurfaces[i].modules // 앞에서 자동으로 했을때 추가됨 flowDirection = moduleSetupSurfaces[i].flowDirection //도형의 방향 - let width = flowDirection === 'south' || flowDirection === 'north' ? 172 : 113 - let height = flowDirection === 'south' || flowDirection === 'north' ? 113 : 172 + const moduleWidth = Number(checkedModule[0].longAxis) / 10 + const moduleHeight = Number(checkedModule[0].shortAxis) / 10 + let width = flowDirection === 'south' || flowDirection === 'north' ? moduleWidth : moduleHeight + let height = flowDirection === 'south' || flowDirection === 'north' ? moduleHeight : moduleWidth const points = [ { x: mousePoint.x - width / 2, y: mousePoint.y - height / 2 }, @@ -470,12 +469,17 @@ export function useModuleBasicSetting() { //자동 모듈 설치(그리드 방식) const autoModuleSetup = (placementRef) => { initEvent() //마우스 이벤트 초기화 + + if (checkedModule.length === 0) { + swalFire({ text: '모듈을 선택해주세요.' }) + return + } + const isChidori = placementRef.isChidori.current === 'true' ? true : false const setupLocation = placementRef.setupLocation.current const isMaxSetup = placementRef.isMaxSetup.current === 'true' ? true : false const moduleSetupSurfaces = moduleSetupSurface //선택 설치면 - const notSelectedTrestlePolygons = canvas ?.getObjects() .filter((obj) => obj.name === POLYGON_TYPE.MODULE_SETUP_SURFACE && !moduleSetupSurfaces.includes(obj)) //설치면이 아닌것 @@ -526,8 +530,7 @@ export function useModuleBasicSetting() { } }) - const moduleOptions = { - fill: '#BFFD9F', + let moduleOptions = { stroke: 'black', strokeWidth: 0.3, selectable: true, // 선택 가능하게 설정 @@ -536,8 +539,6 @@ export function useModuleBasicSetting() { lockRotation: true, // 회전 잠금 lockScalingX: true, // X 축 크기 조정 잠금 lockScalingY: true, // Y 축 크기 조정 잠금 - parentId: moduleSetupSurface.parentId, - surfaceId: moduleSetupSurface.id, name: 'module', } @@ -606,377 +607,519 @@ export function useModuleBasicSetting() { return turf.booleanContains(turfModuleSetupSurface, squarePolygon) || turf.booleanWithin(squarePolygon, turfModuleSetupSurface) } - const downFlowSetupModule = (surfaceMaxLines, width, height, moduleSetupArray, moduleSetupSurface, isCenter = false) => { - const flowModuleLine = moduleSetupSurface.flowLines - let startPoint = flowModuleLine.bottom + /** + * 모듈의 너비와 높이를 계산하는 함수 + * @param {object} maxLengthLine 최대 길이 라인 + * @param {object} moduleSetupSurface 모듈 설치면 + * @param {object} module 모듈 + * @returns {object} 모듈의 너비와 높이 + */ + const getModuleWidthHeight = (maxLengthLine, moduleSetupSurface, module) => { + let width = + (maxLengthLine.flowDirection === 'east' || maxLengthLine.flowDirection === 'west' ? Number(module.longAxis) : Number(module.shortAxis)) / 10 + let height = + (maxLengthLine.flowDirection === 'east' || maxLengthLine.flowDirection === 'west' ? Number(module.shortAxis) : Number(module.longAxis)) / 10 - if (isCenter) { - //중앙배치일 경우에는 계산한다 + //배치면때는 방향쪽으로 패널이 넓게 누워져야함 + if (moduleSetupSurface.flowDirection !== undefined) { + width = + (moduleSetupSurface.flowDirection === 'south' || moduleSetupSurface.flowDirection === 'north' + ? Number(module.longAxis) + : Number(module.shortAxis)) / 10 + height = + (moduleSetupSurface.flowDirection === 'south' || moduleSetupSurface.flowDirection === 'north' + ? Number(module.shortAxis) + : Number(module.longAxis)) / 10 + } + return { width, height } + } - if (flowModuleLine.bottom.type === 'flat' && flowModuleLine.left.type === 'flat' && flowModuleLine.right.type === 'flat') { - //하단 기준으로 양면이 직선이면 하단 방면으로 가운데로 배치 - const halfWidthLength = Math.abs(startPoint.x1 + startPoint.x2) / 2 //밑에 길이에서 반을 가른다 - const halfModuleWidthLength = width / 2 - startPoint = { ...startPoint, x1: halfWidthLength - halfModuleWidthLength } - - if (flowModuleLine.top.type === 'flat') { - //상단까지 평면이면 직사각,정사각이라 가정하고 상자의 중심으로 계산 - const heightLength = Math.abs(flowModuleLine.left.y1 - flowModuleLine.left.y2) //옆에에 길이에서 반을 가른다 - const heightMargin = Math.abs(heightLength - height * Math.floor(heightLength / height)) / 2 - startPoint = { ...startPoint, y1: startPoint.y1 - heightMargin } - } + const getFlowLines = (moduleSetupSurface, module) => { + let flowLines = {} + if (canvasSetting.roofSizeSet !== 3) { + flowLines = { + bottom: bottomTopFlowLine(moduleSetupSurface, module).find((obj) => obj.target === 'bottom'), + top: bottomTopFlowLine(moduleSetupSurface, module).find((obj) => obj.target === 'top'), + left: leftRightFlowLine(moduleSetupSurface, module).find((obj) => obj.target === 'left'), + right: leftRightFlowLine(moduleSetupSurface, module).find((obj) => obj.target === 'right'), } } - // else { - // //중앙배치가 아닐때도 흐름 방향 기준면으로 양면이 직선이면 가운데 배치 - // if (flowModuleLine.bottom.type === 'flat' && flowModuleLine.left.type === 'flat' && flowModuleLine.right.type === 'flat') { - // //하단 기준으로 양면이 직선이면 하단 방면으로 가운데로 배치 - // const halfWidthLength = Math.abs(startPoint.x1 + startPoint.x2) / 2 //밑에 길이에서 반을 가른다 - // const halfModuleWidthLength = width / 2 - // startPoint = { ...startPoint, x1: halfWidthLength - halfModuleWidthLength } - // } - // } - const maxLeftEndPoint = surfaceMaxLines.left.x1 //최 좌측 - const maxRightEndPoint = surfaceMaxLines.right.x1 //최 우측 - const maxTopEndPoint = surfaceMaxLines.top.y1 //최 상단 + console.log('flowLines', flowLines) - let totalLeftEndPoint = maxLeftEndPoint - startPoint.x1 - let totalTopEndPoint = maxTopEndPoint - startPoint.y1 - let totalWidth = Math.ceil(Math.abs(maxRightEndPoint - maxLeftEndPoint) / width) - let diffLeftEndPoint = Math.abs(totalLeftEndPoint / width) - let diffTopEndPoint = Math.abs(totalTopEndPoint / height) - let startColPoint = Math.abs(width * Math.ceil(diffLeftEndPoint) - startPoint.x1) - let tempMaxWidth = isMaxSetup ? width / 2 : width //최대배치인지 확인하려고 넣음 - if (isMaxSetup) totalWidth = totalWidth * 2 //최대배치시 2배로 늘려서 반씩 검사하기위함 + return flowLines + } + + const downFlowSetupModule = (surfaceMaxLines, maxLengthLine, moduleSetupArray, moduleSetupSurface, containsBatchObjects, isCenter = false) => { + let setupModule = [] + + checkedModule.forEach((module, index) => { + const { width, height } = getModuleWidthHeight(maxLengthLine, moduleSetupSurface, module) + const flowLines = getFlowLines(moduleSetupSurface, module) + //육지붕이 아닐때만 넣는다 육지붕일땐 클릭 이벤트에 별도로 넣어놓음 + let startPoint = flowLines.bottom + const moduleArray = [] + + if (isCenter) { + //중앙배치일 경우에는 계산한다 + if (flowLines.bottom.type === 'flat' && flowLines.left.type === 'flat' && flowLines.right.type === 'flat') { + //하단 기준으로 양면이 직선이면 하단 방면으로 가운데로 배치 + const halfWidthLength = Math.abs(startPoint.x1 + startPoint.x2) / 2 //밑에 길이에서 반을 가른다 + const halfModuleWidthLength = width / 2 + startPoint = { ...startPoint, x1: halfWidthLength - halfModuleWidthLength } + + if (flowLines.top.type === 'flat') { + //상단까지 평면이면 직사각,정사각이라 가정하고 상자의 중심으로 계산 + const heightLength = Math.abs(flowLines.left.y1 - flowLines.left.y2) //옆에에 길이에서 반을 가른다 + const heightMargin = Math.abs(heightLength - height * Math.floor(heightLength / height)) / 2 + startPoint = { ...startPoint, y1: startPoint.y1 - heightMargin } + } + } + } + // else { + // //중앙배치가 아닐때도 흐름 방향 기준면으로 양면이 직선이면 가운데 배치 + // if (flowModuleLine.bottom.type === 'flat' && flowModuleLine.left.type === 'flat' && flowModuleLine.right.type === 'flat') { + // //하단 기준으로 양면이 직선이면 하단 방면으로 가운데로 배치 + // const halfWidthLength = Math.abs(startPoint.x1 + startPoint.x2) / 2 //밑에 길이에서 반을 가른다 + // const halfModuleWidthLength = width / 2 + // startPoint = { ...startPoint, x1: halfWidthLength - halfModuleWidthLength } + // } + // } + + const maxLeftEndPoint = surfaceMaxLines.left.x1 //최 좌측 + const maxRightEndPoint = surfaceMaxLines.right.x1 //최 우측 + const maxTopEndPoint = surfaceMaxLines.top.y1 //최 상단 + + let totalLeftEndPoint = maxLeftEndPoint - startPoint.x1 + let totalTopEndPoint = maxTopEndPoint - startPoint.y1 + let totalWidth = Math.ceil(Math.abs(maxRightEndPoint - maxLeftEndPoint) / width) + let diffLeftEndPoint = Math.abs(totalLeftEndPoint / width) + let diffTopEndPoint = Math.abs(totalTopEndPoint / height) + let startColPoint = Math.abs(width * Math.ceil(diffLeftEndPoint) - startPoint.x1) + let tempMaxWidth = isMaxSetup ? width / 2 : width //최대배치인지 확인하려고 넣음 + if (isMaxSetup) totalWidth = totalWidth * 2 //최대배치시 2배로 늘려서 반씩 검사하기위함 + + for (let j = 0; j < diffTopEndPoint; j++) { + bottomMargin = 0 + for (let i = 0; i <= totalWidth; i++) { + leftMargin = 0 + chidoriLength = 0 + if (isChidori) { + chidoriLength = j % 2 === 0 ? 0 : width / 2 + } + + square = [ + [startColPoint + tempMaxWidth * i - chidoriLength + leftMargin, startPoint.y1 - height * j - bottomMargin], + [startColPoint + tempMaxWidth * i + width - chidoriLength + leftMargin, startPoint.y1 - height * j - bottomMargin], + [startColPoint + tempMaxWidth * i + width - chidoriLength + leftMargin, startPoint.y1 - height * j - height - bottomMargin], + [startColPoint + tempMaxWidth * i - chidoriLength + leftMargin, startPoint.y1 - height * j - height - bottomMargin], + [startColPoint + tempMaxWidth * i - chidoriLength + leftMargin, startPoint.y1 - height * j - bottomMargin], + ] + + let squarePolygon = turf.polygon([square]) + let turfCoordnates = squarePolygon.geometry.coordinates[0].slice(0, -1) + let points = turfCoordnates.map((coord) => ({ x: coord[0], y: coord[1] })) + + moduleOptions = { ...moduleOptions, fill: module.color, surfaceId: moduleSetupSurface.id } + let tempModule = new QPolygon(points, { ...moduleOptions, turfPoints: squarePolygon }) + + let disjointFromTrestle = checkModuleDisjointSurface(squarePolygon, polygonToTurfPolygon(moduleSetupSurface, true)) + let isDisjoint = checkModuleDisjointObjects(squarePolygon, containsBatchObjects) + + if (disjointFromTrestle && isDisjoint) { + if (index > 0) { + setupModule.forEach((item) => { + const isOverlap = item.some((item2) => turf.booleanOverlap(squarePolygon, polygonToTurfPolygon(item2, true))) + if (!isOverlap) { + canvas?.add(tempModule) + moduleSetupArray.push(tempModule) + moduleArray.push(tempModule) + } + }) + } else { + //최초 한번은 그냥 그린다 + //겹치는지 확인해서 포함된 모듈만 그린다 + canvas?.add(tempModule) + moduleSetupArray.push(tempModule) + moduleArray.push(tempModule) + } + } else { + tempModule.set({ fill: 'rgba(255,190,41, 0.4)', stroke: 'black', strokeWidth: 1 }) + } + } + } + setupModule.push(moduleArray) + }) + } + + const leftFlowSetupModule = (surfaceMaxLines, maxLengthLine, moduleSetupArray, moduleSetupSurface, containsBatchObjects, isCenter = false) => { + let setupModule = [] + + checkedModule.forEach((module, index) => { + const { width, height } = getModuleWidthHeight(maxLengthLine, moduleSetupSurface, module) + const flowLines = getFlowLines(moduleSetupSurface, module) + //육지붕이 아닐때만 넣는다 육지붕일땐 클릭 이벤트에 별도로 넣어놓음 + let startPoint = flowLines.left + const moduleArray = [] + + //중앙배치일 경우에는 계산한다 + if (isCenter) { + if (flowLines.left.type === 'flat' && flowLines.bottom.type === 'flat' && flowLines.top.type === 'flat') { + //좌측 기준으로 양면이 직선이면 하단 방면으로 가운데로 배치 + const halfWidthLength = Math.abs(startPoint.y1 + startPoint.y2) / 2 //밑에 길이에서 반을 가른다 + const halfModuleWidthLength = height / 2 + startPoint = { ...startPoint, y1: halfWidthLength - halfModuleWidthLength } + if (flowLines.right.type === 'flat') { + //우측까지 평면이면 직사각,정사각이라 가정하고 상자의 중심으로 계산 + const widthLength = Math.abs(flowLines.top.x1 - flowLines.top.x2) //옆에에 길이에서 반을 가른다 + const widthMargin = Math.abs(widthLength - width * Math.floor(widthLength / width)) / 2 + startPoint = { ...startPoint, x1: startPoint.x1 + widthMargin } + } + } + } + + const maxRightEndPoint = surfaceMaxLines.right.x1 //최 우측 + const maxTopEndPoint = surfaceMaxLines.top.y1 //최 상단 + const maxBottomEndPoint = surfaceMaxLines.bottom.y1 //최하단 + + let totalTopEndPoint = Math.abs(maxTopEndPoint - startPoint.y1) //전체 높이에서 현재 높이를 뺌 + let diffTopEndPoint = Math.abs(totalTopEndPoint / height) + let totalHeight = Math.ceil(Math.abs(maxBottomEndPoint - maxTopEndPoint) / height) + let totalWidth = Math.abs(startPoint.x1 - maxRightEndPoint) / width + let startRowPoint = startPoint.y1 - height * Math.ceil(diffTopEndPoint) + + let tempMaxHeight = isMaxSetup ? height / 2 : height //최대배치인지 확인하려고 넣음 + if (isMaxSetup) totalHeight = totalHeight * 2 //최대배치시 2배로 늘려서 반씩 검사 - for (let j = 0; j < diffTopEndPoint; j++) { - bottomMargin = 1 * j for (let i = 0; i <= totalWidth; i++) { - leftMargin = 1 * i - chidoriLength = 0 - if (isChidori) { - chidoriLength = j % 2 === 0 ? 0 : width / 2 + bottomMargin = 0 + for (let j = 0; j < totalHeight; j++) { + leftMargin = 0 + chidoriLength = 0 + if (isChidori) { + chidoriLength = i % 2 === 0 ? 0 : height / 2 + } + + square = [ + [startPoint.x1 + width * i + leftMargin, startRowPoint + tempMaxHeight * j + bottomMargin - chidoriLength], + [startPoint.x1 + width * i + width + leftMargin, startRowPoint + tempMaxHeight * j + bottomMargin - chidoriLength], + [startPoint.x1 + width * i + width + leftMargin, startRowPoint + tempMaxHeight * j + height + bottomMargin - chidoriLength], + [startPoint.x1 + width * i + leftMargin, startRowPoint + tempMaxHeight * j + height + bottomMargin - chidoriLength], + [startPoint.x1 + width * i + leftMargin, startRowPoint + tempMaxHeight * j + bottomMargin - chidoriLength], + ] + + let squarePolygon = turf.polygon([square]) + let turfCoordnates = squarePolygon.geometry.coordinates[0].slice(0, -1) + let points = turfCoordnates.map((coord) => ({ x: coord[0], y: coord[1] })) + + // if (disjointFromTrestle && isDisjoint) { + moduleOptions = { ...moduleOptions, fill: module.color, surfaceId: moduleSetupSurface.id } + let tempModule = new QPolygon(points, { ...moduleOptions, turfPoints: squarePolygon }) + let disjointFromTrestle = checkModuleDisjointSurface(squarePolygon, polygonToTurfPolygon(moduleSetupSurface, true)) + let isDisjoint = checkModuleDisjointObjects(squarePolygon, containsBatchObjects) + + if (disjointFromTrestle && isDisjoint) { + if (index > 0) { + setupModule.forEach((item) => { + const isOverlap = item.some((item2) => turf.booleanOverlap(squarePolygon, polygonToTurfPolygon(item2, true))) + if (!isOverlap) { + canvas?.add(tempModule) + moduleSetupArray.push(tempModule) + moduleArray.push(tempModule) + } + }) + } else { + //최초 한번은 그냥 그린다 + //겹치는지 확인해서 포함된 모듈만 그린다 + canvas?.add(tempModule) + moduleSetupArray.push(tempModule) + moduleArray.push(tempModule) + } + } } - - square = [ - [startColPoint + tempMaxWidth * i - chidoriLength + leftMargin, startPoint.y1 - height * j - bottomMargin], - [startColPoint + tempMaxWidth * i + width - chidoriLength + leftMargin, startPoint.y1 - height * j - bottomMargin], - [startColPoint + tempMaxWidth * i + width - chidoriLength + leftMargin, startPoint.y1 - height * j - height - bottomMargin], - [startColPoint + tempMaxWidth * i - chidoriLength + leftMargin, startPoint.y1 - height * j - height - bottomMargin], - [startColPoint + tempMaxWidth * i - chidoriLength + leftMargin, startPoint.y1 - height * j - bottomMargin], - ] - - let squarePolygon = turf.polygon([square]) - let turfCoordnates = squarePolygon.geometry.coordinates[0].slice(0, -1) - let points = turfCoordnates.map((coord) => ({ x: coord[0], y: coord[1] })) - - moduleOptions.surfaceId = moduleSetupSurface.id - let tempModule = new QPolygon(points, { ...moduleOptions, turfPoints: squarePolygon }) - canvas?.add(tempModule) - moduleSetupArray.push(tempModule) } - } + setupModule.push(moduleArray) + }) } - const leftFlowSetupModule = (surfaceMaxLines, width, height, moduleSetupArray, moduleSetupSurface, isCenter = false) => { - const flowModuleLine = moduleSetupSurface.flowLines - let startPoint = flowModuleLine.left + const topFlowSetupModule = (surfaceMaxLines, maxLengthLine, moduleSetupArray, moduleSetupSurface, containsBatchObjects, isCenter = false) => { + let setupModule = [] - //중앙배치일 경우에는 계산한다 - if (isCenter) { - if (flowModuleLine.left.type === 'flat' && flowModuleLine.bottom.type === 'flat' && flowModuleLine.top.type === 'flat') { - //좌측 기준으로 양면이 직선이면 하단 방면으로 가운데로 배치 - const halfWidthLength = Math.abs(startPoint.y1 + startPoint.y2) / 2 //밑에 길이에서 반을 가른다 - const halfModuleWidthLength = height / 2 - startPoint = { ...startPoint, y1: halfWidthLength - halfModuleWidthLength } - if (flowModuleLine.right.type === 'flat') { - //우측까지 평면이면 직사각,정사각이라 가정하고 상자의 중심으로 계산 - const widthLength = Math.abs(flowModuleLine.top.x1 - flowModuleLine.top.x2) //옆에에 길이에서 반을 가른다 - const widthMargin = Math.abs(widthLength - width * Math.floor(widthLength / width)) / 2 - startPoint = { ...startPoint, x1: startPoint.x1 + widthMargin } + checkedModule.forEach((module, index) => { + const { width, height } = getModuleWidthHeight(maxLengthLine, moduleSetupSurface, module) + const flowLines = getFlowLines(moduleSetupSurface, module) + let startPoint = flowLines.top + const moduleArray = [] + + if (isCenter) { + //중앙배치일 경우에는 계산한다 + if (flowLines.top.type === 'flat' && flowLines.left.type === 'flat' && flowLines.right.type === 'flat') { + //하단 기준으로 양면이 직선이면 하단 방면으로 가운데로 배치 + const halfWidthLength = Math.abs(startPoint.x1 + startPoint.x2) / 2 //밑에 길이에서 반을 가른다 + const halfModuleWidthLength = width / 2 + startPoint = { ...startPoint, x1: halfWidthLength - halfModuleWidthLength } + + if (flowLines.bottom.type === 'flat') { + //상단까지 평면이면 직사각,정사각이라 가정하고 상자의 중심으로 계산 + const heightLength = Math.abs(flowLines.left.y1 - flowLines.left.y2) //옆에에 길이에서 반을 가른다 + const heightMargin = Math.abs(heightLength - height * Math.floor(heightLength / height)) / 2 + startPoint = { ...startPoint, x1: halfWidthLength - halfModuleWidthLength, y1: startPoint.y1 - heightMargin } + } } } - } + // else { + // //중앙배치가 아닐때도 흐름 방향 기준면으로 양면이 직선이면 가운데 배치 + // if (flowModuleLine.bottom.type === 'flat' && flowModuleLine.left.type === 'flat' && flowModuleLine.right.type === 'flat') { + // //하단 기준으로 양면이 직선이면 하단 방면으로 가운데로 배치 + // const halfWidthLength = Math.abs(startPoint.x1 + startPoint.x2) / 2 //밑에 길이에서 반을 가른다 + // const halfModuleWidthLength = width / 2 + // startPoint = { ...startPoint, x1: halfWidthLength - halfModuleWidthLength } + // } + // } - const maxRightEndPoint = surfaceMaxLines.right.x1 //최 우측 - const maxTopEndPoint = surfaceMaxLines.top.y1 //최 상단 - const maxBottomEndPoint = surfaceMaxLines.bottom.y1 //최하단 + const maxLeftEndPoint = surfaceMaxLines.left.x1 //최 좌측 + const maxRightEndPoint = surfaceMaxLines.right.x1 //최 우측 + const maxBottomEndPoint = surfaceMaxLines.bottom.y1 //최하단 - let totalTopEndPoint = Math.abs(maxTopEndPoint - startPoint.y1) //전체 높이에서 현재 높이를 뺌 - let diffTopEndPoint = Math.abs(totalTopEndPoint / height) - let totalHeight = Math.ceil(Math.abs(maxBottomEndPoint - maxTopEndPoint) / height) - let totalWidth = Math.abs(startPoint.x1 - maxRightEndPoint) / width - let startRowPoint = startPoint.y1 - height * Math.ceil(diffTopEndPoint) + let totalLeftEndPoint = maxLeftEndPoint - startPoint.x1 + let totalRightEndPoint = maxLeftEndPoint - maxRightEndPoint + let totalBottomEndPoint = maxBottomEndPoint - startPoint.y1 + let diffLeftEndPoint = Math.abs(totalLeftEndPoint / width) + let diffRightEndPoint = Math.ceil(Math.abs(totalRightEndPoint / width)) + let diffBottomEndPoint = Math.ceil(Math.abs(totalBottomEndPoint / height)) + let startColPoint = Math.abs(width * Math.ceil(diffLeftEndPoint) - startPoint.x1) + let tempMaxWidth = isMaxSetup ? width / 2 : width //최대배치인지 확인하려고 넣음 + if (isMaxSetup) diffRightEndPoint = diffRightEndPoint * 2 //최대배치시 2배로 늘려서 반씩 검사하기위함 - let tempMaxHeight = isMaxSetup ? height / 2 : height //최대배치인지 확인하려고 넣음 - if (isMaxSetup) totalHeight = totalHeight * 2 //최대배치시 2배로 늘려서 반씩 검사 + for (let j = 0; j < diffBottomEndPoint; j++) { + bottomMargin = 0 + for (let i = 0; i < diffRightEndPoint; i++) { + leftMargin = 0 + chidoriLength = 0 + if (isChidori) { + chidoriLength = j % 2 === 0 ? 0 : width / 2 + } + square = [ + [startColPoint + tempMaxWidth * i + chidoriLength + leftMargin, startPoint.y1 + height * j + bottomMargin], + [startColPoint + tempMaxWidth * i + chidoriLength + leftMargin, startPoint.y1 + height * j + height + bottomMargin], + [startColPoint + tempMaxWidth * i + width + chidoriLength + leftMargin, startPoint.y1 + height * j + height + bottomMargin], + [startColPoint + tempMaxWidth * i + width + chidoriLength + leftMargin, startPoint.y1 + height * j + bottomMargin], + [startColPoint + tempMaxWidth * i + chidoriLength + leftMargin, startPoint.y1 + height * j + bottomMargin], + ] - for (let i = 0; i <= totalWidth; i++) { - bottomMargin = i === 0 ? 1 : 2 - for (let j = 0; j < totalHeight; j++) { - leftMargin = i === 0 ? 1 : 2 - chidoriLength = 0 - if (isChidori) { - chidoriLength = i % 2 === 0 ? 0 : height / 2 + let squarePolygon = turf.polygon([square]) + let turfCoordnates = squarePolygon.geometry.coordinates[0].slice(0, -1) + let points = turfCoordnates.map((coord) => ({ x: coord[0], y: coord[1] })) + + // if (disjointFromTrestle && isDisjoint) { + moduleOptions = { ...moduleOptions, fill: module.color, surfaceId: moduleSetupSurface.id } + let tempModule = new QPolygon(points, { ...moduleOptions, turfPoints: squarePolygon }) + + let disjointFromTrestle = checkModuleDisjointSurface(squarePolygon, polygonToTurfPolygon(moduleSetupSurface, true)) + let isDisjoint = checkModuleDisjointObjects(squarePolygon, containsBatchObjects) + + if (disjointFromTrestle && isDisjoint) { + if (index > 0) { + setupModule.forEach((item) => { + const isOverlap = item.some((item2) => turf.booleanOverlap(squarePolygon, polygonToTurfPolygon(item2, true))) + if (!isOverlap) { + canvas?.add(tempModule) + moduleSetupArray.push(tempModule) + moduleArray.push(tempModule) + } + }) + } else { + //최초 한번은 그냥 그린다 + //겹치는지 확인해서 포함된 모듈만 그린다 + canvas?.add(tempModule) + moduleSetupArray.push(tempModule) + moduleArray.push(tempModule) + } + } } - - square = [ - [startPoint.x1 + width * i + leftMargin, startRowPoint + tempMaxHeight * j + bottomMargin - chidoriLength], - [startPoint.x1 + width * i + width + leftMargin, startRowPoint + tempMaxHeight * j + bottomMargin - chidoriLength], - [startPoint.x1 + width * i + width + leftMargin, startRowPoint + tempMaxHeight * j + height + bottomMargin - chidoriLength], - [startPoint.x1 + width * i + leftMargin, startRowPoint + tempMaxHeight * j + height + bottomMargin - chidoriLength], - [startPoint.x1 + width * i + leftMargin, startRowPoint + tempMaxHeight * j + bottomMargin - chidoriLength], - ] - - let squarePolygon = turf.polygon([square]) - let turfCoordnates = squarePolygon.geometry.coordinates[0].slice(0, -1) - let points = turfCoordnates.map((coord) => ({ x: coord[0], y: coord[1] })) - - // if (disjointFromTrestle && isDisjoint) { - moduleOptions.surfaceId = moduleSetupSurface.id - let tempModule = new QPolygon(points, { ...moduleOptions, turfPoints: squarePolygon }) - canvas?.add(tempModule) - moduleSetupArray.push(tempModule) } - } + setupModule.push(moduleArray) + }) } - const topFlowSetupModule = (surfaceMaxLines, width, height, moduleSetupArray, moduleSetupSurface, isCenter = false) => { - const flowModuleLine = moduleSetupSurface.flowLines - let startPoint = flowModuleLine.top + const rightFlowSetupModule = (surfaceMaxLines, maxLengthLine, moduleSetupArray, moduleSetupSurface, containsBatchObjects, isCenter = false) => { + let setupModule = [] - if (isCenter) { - //중앙배치일 경우에는 계산한다 - if (flowModuleLine.top.type === 'flat' && flowModuleLine.left.type === 'flat' && flowModuleLine.right.type === 'flat') { - //하단 기준으로 양면이 직선이면 하단 방면으로 가운데로 배치 - const halfWidthLength = Math.abs(startPoint.x1 + startPoint.x2) / 2 //밑에 길이에서 반을 가른다 - const halfModuleWidthLength = width / 2 - startPoint = { ...startPoint, x1: halfWidthLength - halfModuleWidthLength } + checkedModule.forEach((module, index) => { + const { width, height } = getModuleWidthHeight(maxLengthLine, moduleSetupSurface, module) + const flowLines = getFlowLines(moduleSetupSurface, module) + let startPoint = flowLines.right + const moduleArray = [] - if (flowModuleLine.bottom.type === 'flat') { - //상단까지 평면이면 직사각,정사각이라 가정하고 상자의 중심으로 계산 - const heightLength = Math.abs(flowModuleLine.left.y1 - flowModuleLine.left.y2) //옆에에 길이에서 반을 가른다 - const heightMargin = Math.abs(heightLength - height * Math.floor(heightLength / height)) / 2 - startPoint = { ...startPoint, x1: halfWidthLength - halfModuleWidthLength, y1: startPoint.y1 - heightMargin } + if (isCenter) { + if (flowLines.left.type === 'flat' && flowLines.bottom.type === 'flat' && flowLines.top.type === 'flat') { + //좌측 기준으로 양면이 직선이면 하단 방면으로 가운데로 배치 + const halfWidthLength = Math.abs(startPoint.y1 + startPoint.y2) / 2 //밑에 길이에서 반을 가른다 + const halfModuleWidthLength = height / 2 + startPoint = { ...startPoint, y1: halfWidthLength + halfModuleWidthLength } + + if (flowLines.right.type === 'flat') { + //우측까지 평면이면 직사각,정사각이라 가정하고 상자의 중심으로 계산 + const widthLength = Math.abs(flowLines.top.x1 - flowLines.top.x2) //옆에에 길이에서 반을 가른다 + const widthMargin = Math.abs(widthLength - width * Math.floor(widthLength / width)) / 2 + startPoint = { ...startPoint, x1: startPoint.x1 - widthMargin } + } } } - } - // else { - // //중앙배치가 아닐때도 흐름 방향 기준면으로 양면이 직선이면 가운데 배치 - // if (flowModuleLine.bottom.type === 'flat' && flowModuleLine.left.type === 'flat' && flowModuleLine.right.type === 'flat') { - // //하단 기준으로 양면이 직선이면 하단 방면으로 가운데로 배치 - // const halfWidthLength = Math.abs(startPoint.x1 + startPoint.x2) / 2 //밑에 길이에서 반을 가른다 - // const halfModuleWidthLength = width / 2 - // startPoint = { ...startPoint, x1: halfWidthLength - halfModuleWidthLength } - // } - // } - const maxLeftEndPoint = surfaceMaxLines.left.x1 //최 좌측 - const maxRightEndPoint = surfaceMaxLines.right.x1 //최 우측 - const maxBottomEndPoint = surfaceMaxLines.bottom.y1 //최하단 + const maxLeftEndPoint = surfaceMaxLines.left.x1 //최 좌측 + const maxTopEndPoint = surfaceMaxLines.top.y1 //최 상단 + const maxBottomEndPoint = surfaceMaxLines.bottom.y1 //최하단 - let totalLeftEndPoint = maxLeftEndPoint - startPoint.x1 - let totalRightEndPoint = maxLeftEndPoint - maxRightEndPoint - let totalBottomEndPoint = maxBottomEndPoint - startPoint.y1 - let diffLeftEndPoint = Math.abs(totalLeftEndPoint / width) - let diffRightEndPoint = Math.ceil(Math.abs(totalRightEndPoint / width)) - let diffBottomEndPoint = Math.ceil(Math.abs(totalBottomEndPoint / height)) - let startColPoint = Math.abs(width * Math.ceil(diffLeftEndPoint) - startPoint.x1) - let tempMaxWidth = isMaxSetup ? width / 2 : width //최대배치인지 확인하려고 넣음 - if (isMaxSetup) diffRightEndPoint = diffRightEndPoint * 2 //최대배치시 2배로 늘려서 반씩 검사하기위함 + let totalTopEndPoint = Math.abs(maxTopEndPoint - startPoint.y1) //전체 높이에서 현재 높이를 뺌 + let diffTopEndPoint = Math.abs(totalTopEndPoint / height) + let totalHeight = Math.ceil(Math.abs(maxBottomEndPoint - maxTopEndPoint) / height) + let totalWidth = Math.abs(startPoint.x1 - maxLeftEndPoint) / width + let startRowPoint = startPoint.y1 - height * Math.ceil(diffTopEndPoint) - 3 // -3으로 위치살짝 보정 - for (let j = 0; j < diffBottomEndPoint; j++) { - bottomMargin = j === 0 ? 1 : 2 - for (let i = 0; i < diffRightEndPoint; i++) { - leftMargin = i === 0 ? 1 : 2 - chidoriLength = 0 - if (isChidori) { - chidoriLength = j % 2 === 0 ? 0 : width / 2 - } - square = [ - [startColPoint + tempMaxWidth * i + chidoriLength + leftMargin, startPoint.y1 + height * j + bottomMargin], - [startColPoint + tempMaxWidth * i + chidoriLength + leftMargin, startPoint.y1 + height * j + height + bottomMargin], - [startColPoint + tempMaxWidth * i + width + chidoriLength + leftMargin, startPoint.y1 + height * j + height + bottomMargin], - [startColPoint + tempMaxWidth * i + width + chidoriLength + leftMargin, startPoint.y1 + height * j + bottomMargin], - [startColPoint + tempMaxWidth * i + chidoriLength + leftMargin, startPoint.y1 + height * j + bottomMargin], - ] + let tempMaxHeight = isMaxSetup ? height / 2 : height //최대배치인지 확인하려고 넣음 + if (isMaxSetup) totalHeight = totalHeight * 2 //최대배치시 2배로 늘려서 반씩 검사 - let squarePolygon = turf.polygon([square]) - let turfCoordnates = squarePolygon.geometry.coordinates[0].slice(0, -1) - let points = turfCoordnates.map((coord) => ({ x: coord[0], y: coord[1] })) + for (let i = 0; i <= totalWidth; i++) { + bottomMargin = 0 + for (let j = 0; j < totalHeight; j++) { + leftMargin = 0 + chidoriLength = 0 + if (isChidori) { + chidoriLength = i % 2 === 0 ? 0 : height / 2 + } - // if (disjointFromTrestle && isDisjoint) { - moduleOptions.surfaceId = moduleSetupSurface.id - let tempModule = new QPolygon(points, { ...moduleOptions, turfPoints: squarePolygon }) - canvas?.add(tempModule) - moduleSetupArray.push(tempModule) - } - } - } + square = [ + [startPoint.x1 - width * i - leftMargin, startRowPoint + tempMaxHeight * j + bottomMargin + chidoriLength], + [startPoint.x1 - width * i - width - leftMargin, startRowPoint + tempMaxHeight * j + bottomMargin + chidoriLength], + [startPoint.x1 - width * i - width - leftMargin, startRowPoint + tempMaxHeight * j + height + bottomMargin + chidoriLength], + [startPoint.x1 - width * i - leftMargin, startRowPoint + tempMaxHeight * j + height + bottomMargin + chidoriLength], + [startPoint.x1 - width * i - leftMargin, startRowPoint + tempMaxHeight * j + bottomMargin + chidoriLength], + ] - const rightFlowSetupModule = (surfaceMaxLines, width, height, moduleSetupArray, moduleSetupSurface, isCenter = false) => { - const flowModuleLine = moduleSetupSurface.flowLines - let startPoint = flowModuleLine.right + let squarePolygon = turf.polygon([square]) + let turfCoordnates = squarePolygon.geometry.coordinates[0].slice(0, -1) + let points = turfCoordnates.map((coord) => ({ x: coord[0], y: coord[1] })) - if (isCenter) { - if (flowModuleLine.left.type === 'flat' && flowModuleLine.bottom.type === 'flat' && flowModuleLine.top.type === 'flat') { - //좌측 기준으로 양면이 직선이면 하단 방면으로 가운데로 배치 - const halfWidthLength = Math.abs(startPoint.y1 + startPoint.y2) / 2 //밑에 길이에서 반을 가른다 - const halfModuleWidthLength = height / 2 - startPoint = { ...startPoint, y1: halfWidthLength + halfModuleWidthLength } + // if (disjointFromTrestle && isDisjoint) { + moduleOptions = { ...moduleOptions, fill: module.color, surfaceId: moduleSetupSurface.id } + let tempModule = new QPolygon(points, { ...moduleOptions, turfPoints: squarePolygon }) + let disjointFromTrestle = checkModuleDisjointSurface(squarePolygon, polygonToTurfPolygon(moduleSetupSurface, true)) + let isDisjoint = checkModuleDisjointObjects(squarePolygon, containsBatchObjects) - if (flowModuleLine.right.type === 'flat') { - //우측까지 평면이면 직사각,정사각이라 가정하고 상자의 중심으로 계산 - const widthLength = Math.abs(flowModuleLine.top.x1 - flowModuleLine.top.x2) //옆에에 길이에서 반을 가른다 - const widthMargin = Math.abs(widthLength - width * Math.floor(widthLength / width)) / 2 - startPoint = { ...startPoint, x1: startPoint.x1 - widthMargin } + if (disjointFromTrestle && isDisjoint) { + if (index > 0) { + setupModule.forEach((item) => { + const isOverlap = item.some((item2) => turf.booleanOverlap(squarePolygon, polygonToTurfPolygon(item2, true))) + if (!isOverlap) { + canvas?.add(tempModule) + moduleSetupArray.push(tempModule) + moduleArray.push(tempModule) + } + }) + } else { + //최초 한번은 그냥 그린다 + //겹치는지 확인해서 포함된 모듈만 그린다 + canvas?.add(tempModule) + moduleSetupArray.push(tempModule) + moduleArray.push(tempModule) + } + } } } - } - - const maxLeftEndPoint = surfaceMaxLines.left.x1 //최 좌측 - const maxTopEndPoint = surfaceMaxLines.top.y1 //최 상단 - const maxBottomEndPoint = surfaceMaxLines.bottom.y1 //최하단 - - let totalTopEndPoint = Math.abs(maxTopEndPoint - startPoint.y1) //전체 높이에서 현재 높이를 뺌 - let diffTopEndPoint = Math.abs(totalTopEndPoint / height) - let totalHeight = Math.ceil(Math.abs(maxBottomEndPoint - maxTopEndPoint) / height) - let totalWidth = Math.abs(startPoint.x1 - maxLeftEndPoint) / width - let startRowPoint = startPoint.y1 - height * Math.ceil(diffTopEndPoint) - 3 // -3으로 위치살짝 보정 - - let tempMaxHeight = isMaxSetup ? height / 2 : height //최대배치인지 확인하려고 넣음 - if (isMaxSetup) totalHeight = totalHeight * 2 //최대배치시 2배로 늘려서 반씩 검사 - - for (let i = 0; i <= totalWidth; i++) { - bottomMargin = i === 0 ? 1 : 2 - for (let j = 0; j < totalHeight; j++) { - leftMargin = j === 0 ? 1 : 2 - chidoriLength = 0 - if (isChidori) { - chidoriLength = i % 2 === 0 ? 0 : height / 2 - } - - square = [ - [startPoint.x1 - width * i - leftMargin, startRowPoint + tempMaxHeight * j + bottomMargin + chidoriLength], - [startPoint.x1 - width * i - width - leftMargin, startRowPoint + tempMaxHeight * j + bottomMargin + chidoriLength], - [startPoint.x1 - width * i - width - leftMargin, startRowPoint + tempMaxHeight * j + height + bottomMargin + chidoriLength], - [startPoint.x1 - width * i - leftMargin, startRowPoint + tempMaxHeight * j + height + bottomMargin + chidoriLength], - [startPoint.x1 - width * i - leftMargin, startRowPoint + tempMaxHeight * j + bottomMargin + chidoriLength], - ] - - let squarePolygon = turf.polygon([square]) - let turfCoordnates = squarePolygon.geometry.coordinates[0].slice(0, -1) - let points = turfCoordnates.map((coord) => ({ x: coord[0], y: coord[1] })) - - // if (disjointFromTrestle && isDisjoint) { - moduleOptions.surfaceId = moduleSetupSurface.id - let tempModule = new QPolygon(points, { ...moduleOptions, turfPoints: squarePolygon }) - canvas?.add(tempModule) - moduleSetupArray.push(tempModule) - } - } + setupModule.push(moduleArray) + }) } moduleSetupSurfaces.forEach((moduleSetupSurface, index) => { moduleSetupSurface.fire('mousedown') const moduleSetupArray = [] + const turfModuleSetupSurface = polygonToTurfPolygon(moduleSetupSurface) //폴리곤을 turf 객체로 변환 + const containsBatchObjects = objectsIncludeSurface(turfModuleSetupSurface) //배치면에 오브젝트(도머, 개구등)이 있는지 확인하는 로직 + const surfaceMaxLines = findSetupSurfaceMaxLines(moduleSetupSurface) + let maxLengthLine = moduleSetupSurface.lines.reduce((acc, cur) => { return acc.length > cur.length ? acc : cur }) - const turfModuleSetupSurface = polygonToTurfPolygon(moduleSetupSurface) //폴리곤을 turf 객체로 변환 - const containsBatchObjects = objectsIncludeSurface(turfModuleSetupSurface) //배치면에 오브젝트(도머, 개구등)이 있는지 확인하는 로직 - - let width = maxLengthLine.flowDirection === 'east' || maxLengthLine.flowDirection === 'west' ? 172.2 : 113.4 - let height = maxLengthLine.flowDirection === 'east' || maxLengthLine.flowDirection === 'west' ? 113.4 : 172.2 - - //배치면때는 방향쪽으로 패널이 넓게 누워져야함 - if (moduleSetupSurface.flowDirection !== undefined) { - width = moduleSetupSurface.flowDirection === 'south' || moduleSetupSurface.flowDirection === 'north' ? 172.2 : 113.4 - height = moduleSetupSurface.flowDirection === 'south' || moduleSetupSurface.flowDirection === 'north' ? 113.4 : 172.2 - } - - const surfaceMaxLines = findSetupSurfaceMaxLines(moduleSetupSurface) - //처마면 배치 if (setupLocation === 'eaves') { // 흐름방향이 남쪽일때 if (moduleSetupSurface.flowDirection === 'south') { - downFlowSetupModule(surfaceMaxLines, width, height, moduleSetupArray, moduleSetupSurface) + downFlowSetupModule(surfaceMaxLines, maxLengthLine, moduleSetupArray, moduleSetupSurface, containsBatchObjects) } if (moduleSetupSurface.flowDirection === 'west') { - leftFlowSetupModule(surfaceMaxLines, width, height, moduleSetupArray, moduleSetupSurface) + leftFlowSetupModule(surfaceMaxLines, maxLengthLine, moduleSetupArray, moduleSetupSurface, containsBatchObjects) } if (moduleSetupSurface.flowDirection === 'east') { - rightFlowSetupModule(surfaceMaxLines, width, height, moduleSetupArray, moduleSetupSurface) + rightFlowSetupModule(surfaceMaxLines, maxLengthLine, moduleSetupArray, moduleSetupSurface, containsBatchObjects) } if (moduleSetupSurface.flowDirection === 'north') { - topFlowSetupModule(surfaceMaxLines, width, height, moduleSetupArray, moduleSetupSurface) + topFlowSetupModule(surfaceMaxLines, maxLengthLine, moduleSetupArray, moduleSetupSurface, containsBatchObjects) } } else if (setupLocation === 'ridge') { //용마루 if (moduleSetupSurface.flowDirection === 'south') { - topFlowSetupModule(surfaceMaxLines, width, height, moduleSetupArray, moduleSetupSurface) + topFlowSetupModule(surfaceMaxLines, maxLengthLine, moduleSetupArray, moduleSetupSurface, containsBatchObjects) } if (moduleSetupSurface.flowDirection === 'west') { - rightFlowSetupModule(surfaceMaxLines, width, height, moduleSetupArray, moduleSetupSurface) + rightFlowSetupModule(surfaceMaxLines, maxLengthLine, moduleSetupArray, moduleSetupSurface, containsBatchObjects) } if (moduleSetupSurface.flowDirection === 'east') { - leftFlowSetupModule(surfaceMaxLines, width, height, moduleSetupArray, moduleSetupSurface) + leftFlowSetupModule(surfaceMaxLines, maxLengthLine, moduleSetupArray, moduleSetupSurface, containsBatchObjects) } if (moduleSetupSurface.flowDirection === 'north') { - downFlowSetupModule(surfaceMaxLines, width, height, moduleSetupArray, moduleSetupSurface) + downFlowSetupModule(surfaceMaxLines, maxLengthLine, moduleSetupArray, moduleSetupSurface, containsBatchObjects) } } else if (setupLocation === 'center') { //중가면 if (moduleSetupSurface.flowDirection === 'south') { - downFlowSetupModule(surfaceMaxLines, width, height, moduleSetupArray, moduleSetupSurface, true) + downFlowSetupModule(surfaceMaxLines, maxLengthLine, moduleSetupArray, moduleSetupSurface, containsBatchObjects, true) } if (moduleSetupSurface.flowDirection === 'west') { - leftFlowSetupModule(surfaceMaxLines, width, height, moduleSetupArray, moduleSetupSurface, true) + leftFlowSetupModule(surfaceMaxLines, maxLengthLine, moduleSetupArray, moduleSetupSurface, containsBatchObjects, true) } if (moduleSetupSurface.flowDirection === 'east') { - rightFlowSetupModule(surfaceMaxLines, width, height, moduleSetupArray, moduleSetupSurface, true) + rightFlowSetupModule(surfaceMaxLines, maxLengthLine, moduleSetupArray, moduleSetupSurface, containsBatchObjects, true) } if (moduleSetupSurface.flowDirection === 'north') { - topFlowSetupModule(surfaceMaxLines, width, height, moduleSetupArray, moduleSetupSurface, true) + topFlowSetupModule(surfaceMaxLines, maxLengthLine, moduleSetupArray, moduleSetupSurface, containsBatchObjects, true) } } - const setupedModules = moduleSetupArray.filter((module, index) => { - let disjointFromTrestle = checkModuleDisjointSurface(module.turfPoints, turfModuleSetupSurface) - let isDisjoint = checkModuleDisjointObjects(module.turfPoints, containsBatchObjects) + // const setupedModules = moduleSetupArray.filter((module, index) => { + // let disjointFromTrestle = checkModuleDisjointSurface(module.turfPoints, turfModuleSetupSurface) + // let isDisjoint = checkModuleDisjointObjects(module.turfPoints, containsBatchObjects) - if (!(disjointFromTrestle && isDisjoint)) { - canvas?.remove(module) - // module.set({ fill: 'rgba(255,190,41, 0.4)', stroke: 'black', strokeWidth: 1 }) - return false - } else { - return module - } - }) + // if (!(disjointFromTrestle && isDisjoint)) { + // canvas?.remove(module) + // // module.set({ fill: 'rgba(255,190,41, 0.4)', stroke: 'black', strokeWidth: 1 }) + // return false + // } else { + // return module + // } + // }) - canvas?.renderAll() + // canvas?.renderAll() //나간애들 제외하고 설치된 애들로 겹친애들 삭제 하기 - setupedModules.forEach((module, index) => { + moduleSetupArray.forEach((module, index) => { if (isMaxSetup && index > 0) { - const isOverlap = turf.booleanOverlap(polygonToTurfPolygon(setupedModules[index - 1]), polygonToTurfPolygon(module)) + const isOverlap = turf.booleanOverlap(polygonToTurfPolygon(moduleSetupArray[index - 1]), polygonToTurfPolygon(module)) //겹치는지 확인 if (isOverlap) { //겹쳐있으면 삭제 canvas?.remove(module) // module.set({ fill: 'rgba(72, 161, 250, 0.4)', stroke: 'black', strokeWidth: 0.1 }) canvas.renderAll() - setupedModules.splice(index, 1) + moduleSetupArray.splice(index, 1) return false } } }) - moduleSetupSurface.set({ modules: setupedModules }) + // moduleSetupSurface.set({ modules: moduleSetupArray }) // const moduleArray = [...moduleIsSetup] // moduleArray.push({ @@ -985,7 +1128,7 @@ export function useModuleBasicSetting() { // }) // setModuleIsSetup(moduleArray) }) - calculateForApi() + // calculateForApi() } const calculateForApi = () => { @@ -1247,8 +1390,9 @@ export function useModuleBasicSetting() { return hull } - const bottomTopFlowLine = (surface) => { + const bottomTopFlowLine = (surface, module) => { const flowArray = [] + const bottomFlow = surface.lines.reduce( (acc, line, index) => { if (line.y1 > acc.y1 || (line.y1 === acc.y1 && line.x1 > acc.x1)) { @@ -1305,7 +1449,7 @@ export function useModuleBasicSetting() { const angle2 = Math.abs(Math.round(Math.atan(height2 / adjust2) * (180 / Math.PI) * 1000) / 1000) const angle3 = 180 - (angle1 + angle2) - const charlie = 173.3 // 평행선길이 약간 여유를 줌 + const charlie = Number(module.longAxis) / 10 + 3 // 평행선길이 약간 여유를 줌 const alpha = (charlie * Math.sin((angle1 * Math.PI) / 180)) / Math.sin((angle3 * Math.PI) / 180) const beta = Math.sqrt(alpha ** 2 + charlie ** 2 - 2 * alpha * charlie * Math.cos((angle2 * Math.PI) / 180)) const h = beta * Math.sin((angle1 * Math.PI) / 180) // 높이 @@ -1322,8 +1466,8 @@ export function useModuleBasicSetting() { strokeWidth: 1, selectable: true, }) - // canvas?.add(finalLine) - // canvas?.renderAll() + canvas?.add(finalLine) + canvas?.renderAll() let rtnObj //평평하면 @@ -1364,7 +1508,7 @@ export function useModuleBasicSetting() { return rtnObjArray } - const leftRightFlowLine = (surface) => { + const leftRightFlowLine = (surface, module) => { const flowArray = [] const leftFlow = surface.lines.reduce( (acc, line, index) => { @@ -1420,7 +1564,7 @@ export function useModuleBasicSetting() { const angle2 = Math.abs(Math.round(Math.atan(adjust2 / height2) * (180 / Math.PI) * 1000) / 1000) const angle3 = 180 - (angle1 + angle2) - const charlie = 173.3 // 평행선길이 약간 여유를줌 + const charlie = Number(module.shortAxis) / 10 + 3 // 평행선길이 약간 여유를 줌 const alpha = (charlie * Math.sin((angle1 * Math.PI) / 180)) / Math.sin((angle3 * Math.PI) / 180) const beta = Math.sqrt(alpha ** 2 + charlie ** 2 - 2 * alpha * charlie * Math.cos((angle2 * Math.PI) / 180)) @@ -1445,8 +1589,8 @@ export function useModuleBasicSetting() { strokeWidth: 1, selectable: true, }) - // canvas?.add(finalLine) - // canvas?.renderAll() + canvas?.add(finalLine) + canvas?.renderAll() let rtnObj //평평하면 diff --git a/src/store/canvasAtom.js b/src/store/canvasAtom.js index 89f7e14d..618893ec 100644 --- a/src/store/canvasAtom.js +++ b/src/store/canvasAtom.js @@ -373,3 +373,15 @@ export const moduleIsSetupState = atom({ default: [], dangerouslyAllowMutability: true, }) + +export const selectedModuleState = atom({ + key: 'selectedModuleState', + default: [], + dangerouslyAllowMutability: true, +}) + +export const checkedModuleState = atom({ + key: 'checkedModuleState', + default: [], + dangerouslyAllowMutability: true, +})