육지붕 모듈 작업

This commit is contained in:
yjnoh 2025-02-24 13:33:20 +09:00
parent 7b3541f73f
commit aa2425bf81
4 changed files with 177 additions and 56 deletions

View File

@ -47,17 +47,17 @@ export default function PitchModule({}) {
setSelectedModules(option) // setSelectedModules(option) //
setModuleSelectionData({ setModuleSelectionData({
...moduleSelectionData, ...moduleSelectionData,
flatModule: option, module: option,
}) })
moduleSelectedDataTrigger({ moduleSelectedDataTrigger({
...moduleSelectionData, ...moduleSelectionData,
flatModule: option, module: option,
}) })
} }
useEffect(() => { useEffect(() => {
if (isObjectNotEmpty(moduleSelectionData.flatModule) && moduleList.length > 0) { if (isObjectNotEmpty(moduleSelectionData.module) && moduleList.length > 0) {
handleChangeModule(moduleSelectionData.flatModule) handleChangeModule(moduleSelectionData.module)
} }
}, [moduleList]) }, [moduleList])

View File

@ -69,7 +69,7 @@ const PitchPlacement = forwardRef((props, refs) => {
excretaLine.forEach((line) => { excretaLine.forEach((line) => {
line.set({ line.set({
stroke: '#642EFB', stroke: '#642EFB',
strokeWidth: 5, strokeWidth: 3,
surfaceId: surface.surfaceId, surfaceId: surface.surfaceId,
name: 'flatExcretaLine', name: 'flatExcretaLine',
}) })
@ -89,10 +89,10 @@ const PitchPlacement = forwardRef((props, refs) => {
} }
useEffect(() => { useEffect(() => {
if (!moduleSelectionData.flatModule) return // null if (!moduleSelectionData.module) return // null
if (moduleSelectionData && moduleSelectionData.flatModule.itemList.length > 0) { if (moduleSelectionData && moduleSelectionData.module.itemList.length > 0) {
let initCheckedModule = {} let initCheckedModule = {}
moduleSelectionData.flatModule.itemList.forEach((obj, index) => { moduleSelectionData.module.itemList.forEach((obj, index) => {
if (index === 0) { if (index === 0) {
initCheckedModule = { [obj.itemId]: true } initCheckedModule = { [obj.itemId]: true }
} else { } else {

View File

@ -3,7 +3,7 @@ import { useRecoilState, useRecoilValue, useSetRecoilState } from 'recoil'
import { canvasSettingState, canvasState, checkedModuleState, currentObjectState, isManualModuleSetupState } from '@/store/canvasAtom' import { canvasSettingState, canvasState, checkedModuleState, currentObjectState, isManualModuleSetupState } from '@/store/canvasAtom'
import { rectToPolygon, polygonToTurfPolygon, calculateVisibleModuleHeight, getDegreeByChon } from '@/util/canvas-util' import { rectToPolygon, polygonToTurfPolygon, calculateVisibleModuleHeight, getDegreeByChon } from '@/util/canvas-util'
import { addedRoofsState, basicSettingState, roofDisplaySelector } from '@/store/settingAtom' import { addedRoofsState, basicSettingState, roofDisplaySelector } from '@/store/settingAtom'
import offsetPolygon, { calculateAngle } from '@/util/qpolygon-utils' import offsetPolygon, { calculateAngle, createLinesFromPolygon } from '@/util/qpolygon-utils'
import { QPolygon } from '@/components/fabric/QPolygon' import { QPolygon } from '@/components/fabric/QPolygon'
import { moduleSetupSurfaceState, moduleIsSetupState } from '@/store/canvasAtom' import { moduleSetupSurfaceState, moduleIsSetupState } from '@/store/canvasAtom'
import { useEvent } from '@/hooks/useEvent' import { useEvent } from '@/hooks/useEvent'
@ -239,7 +239,6 @@ export function useModuleBasicSetting(tabNum) {
toggleSelection(isExistSurface) toggleSelection(isExistSurface)
}) })
} else { } else {
let offsetLength = canvasSetting.roofSizeSet === '3' ? -30 : (trestleDetail.eaveIntvl / 10) * -1
setSurfaceShapePattern(roof, roofDisplay.column, true, roof.roofMaterial) //패턴 변경 setSurfaceShapePattern(roof, roofDisplay.column, true, roof.roofMaterial) //패턴 변경
// let offsetPoints = createPaddingPolygon(createRoofPolygon(roof.points), roof.lines).vertices //안쪽 offset // let offsetPoints = createPaddingPolygon(createRoofPolygon(roof.points), roof.lines).vertices //안쪽 offset
let offsetPoints = null let offsetPoints = null
@ -252,18 +251,24 @@ export function useModuleBasicSetting(tabNum) {
//margin polygon 의 point가 기준 polygon의 밖에 있는지 판단한다. //margin polygon 의 point가 기준 polygon의 밖에 있는지 판단한다.
const allPointsOutside = result.every((point) => !originPolygon.inPolygon(point)) const allPointsOutside = result.every((point) => !originPolygon.inPolygon(point))
if (canvasSetting.roofSizeSet == '3') {
//육지붕일때는 그냥 하드코딩
offsetPoints = offsetPolygon(roof.points, -30) //육지붕일때
} else {
//육지붕이 아닐때
if (allPointsOutside) { if (allPointsOutside) {
offsetPoints = createMarginPolygon(polygon, roof.lines).vertices offsetPoints = createMarginPolygon(polygon, roof.lines).vertices
} else { } else {
offsetPoints = createPaddingPolygon(polygon, roof.lines).vertices offsetPoints = createPaddingPolygon(polygon, roof.lines).vertices
} }
}
//모듈설치영역?? 생성 //모듈설치영역?? 생성
const surfaceId = uuidv4() const surfaceId = uuidv4()
let isNorth = false let isNorth = false
if (canvasSetting.roofSizeSet !== '3') { if (canvasSetting.roofSizeSet != '3') {
//북면이 있지만 //북면이 있지만
if (roof.directionText && roof.directionText.indexOf('北') > -1) { if (roof.directionText && roof.directionText.indexOf('北') > -1) {
//북쪽일때 해당 서북서, 동북동은 제외한다고 한다 //북쪽일때 해당 서북서, 동북동은 제외한다고 한다
@ -2895,8 +2900,13 @@ export function useModuleBasicSetting(tabNum) {
targetRoof.angle = -angle targetRoof.angle = -angle
targetSurface.angle = -angle targetSurface.angle = -angle
const newLines = createLinesFromPolygon(targetSurface.getCurrentPoints())
targetSurface.set({ lines: newLines })
targetRoof.fire('modified') targetRoof.fire('modified')
targetSurface.fire('modified') targetSurface.fire('modified')
targetRoof.setCoords()
targetSurface.setCoords()
moduleSetupSurfaces.push(targetSurface) moduleSetupSurfaces.push(targetSurface)
} }
canvas.remove(obj) canvas.remove(obj)
@ -2990,37 +3000,92 @@ export function useModuleBasicSetting(tabNum) {
let moduleGroup = [] let moduleGroup = []
const flatRoofDownFlowSetupModule = (surfaceMaxLines, maxLengthLine, moduleSetupArray, moduleSetupSurface, marginWidth, marginHeight) => { const flatRoofDownFlowSetupModule = (
checkedModule.forEach((module, index) => { surfaceMaxLines,
const { width, height } = getModuleWidthHeight(maxLengthLine, moduleSetupSurface, module) maxLengthLine,
moduleSetupArray,
moduleSetupSurface,
intvHor,
intvVer,
containsBatchObjects,
) => {
let setupModule = []
const flowLines = getFlowLines(moduleSetupSurface, height) let installedLastHeightCoord = 0 //마지막으로 설치된 모듈의 좌표
let installedModuleHeightCount = 0 //마지막으로 설치된 모듈의 카운트
let flowLines
let startPoint = flowLines.bottom checkedModule.forEach((module, moduleIndex) => {
//모듈의 넓이 높이를 가져옴 (복시도 촌수 적용)
//1번 깔았던 모듈 기준으로 잡야아함
let { width, height } = getModuleWidthHeight(maxLengthLine, moduleSetupSurface, module)
const maxLeftEndPoint = surfaceMaxLines.left.x1 //최 좌측 if (moduleIndex === 0) {
const maxRightEndPoint = surfaceMaxLines.right.x1 //최 우측 flowLines = getFlowLines(moduleSetupSurface, height)
const maxTopEndPoint = surfaceMaxLines.top.y1 //최 상단 if (flowLines.bottom.type === 'curve') {
flowLines = getFlowLines(moduleSetupSurface, width)
}
}
let totalLeftEndPoint = maxLeftEndPoint - startPoint.x1 //육지붕이 아닐때만 넣는다 육지붕일땐 클릭 이벤트에 별도로 넣어놓음
let totalTopEndPoint = maxTopEndPoint - startPoint.y1 const moduleArray = []
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 = width //최대배치인지 확인하려고 넣음
for (let j = 0; j < diffTopEndPoint; j++) { let calcAreaWidth = flowLines.right.x1 - flowLines.left.x1 //오른쪽 x에서 왼쪽 x를 뺀 가운데를 찾는 로직
bottomMargin = marginHeight * j let calcModuleWidthCount = calcAreaWidth / (width + intvHor) //뺀 공간에서 모듈을 몇개를 넣을수 있는지 확인하는 로직
for (let i = 0; i <= totalWidth; i++) { let calcMaxModuleWidthCount = calcModuleWidthCount //최대 모듈 단수가 있기 때문에 최대 단수보다 카운트가 크면 최대 단수로 씀씀
leftMargin = marginWidth * i let totalModuleWidthCount = Math.floor(calcMaxModuleWidthCount) //치조배치일경우는 한개 더 넣는다
square = [ let calcAreaheight = flowLines.bottom.y1 - flowLines.top.y1 //오른쪽 y에서 왼쪽 y를 뺀 가운데를 찾는 로직
[startColPoint + tempMaxWidth * i + leftMargin, startPoint.y1 - height * j - bottomMargin], let calcModuleHeightCount = calcAreaheight / (height + intvVer) //뺀 공간에서 모듈을 몇개를 넣을수 있는지 확인하는 로직
[startColPoint + tempMaxWidth * i + width + leftMargin, startPoint.y1 - height * j - bottomMargin], let calcMaxModuleHeightCount = calcModuleHeightCount //최대 모듈 단수가 있기 때문에 최대 단수보다 카운트가 크면 최대 단수로 씀씀
[startColPoint + tempMaxWidth * i + width + leftMargin, startPoint.y1 - height * j - height - bottomMargin], let totalModuleHeightCount = Math.floor(calcMaxModuleHeightCount) //치조배치일경우는 한개 더 넣는다
[startColPoint + tempMaxWidth * i + leftMargin, startPoint.y1 - height * j - height - bottomMargin],
[startColPoint + tempMaxWidth * i + leftMargin, startPoint.y1 - height * j - bottomMargin], let calcStartPoint = flowLines.right.type === 'flat' ? (calcAreaWidth - totalModuleWidthCount * width) / 2 : 0 //반씩 나눠서 중앙에 맞춤 bottom 기준으로 양변이 직선일때만 가운데 정렬
let startPointX = flowLines.left.x1 + calcStartPoint //시작점을 만든다
//근데 양변이 곡선이면 중앙에 맞추기 위해 아래와 위의 길이를 재서 모듈의 길이를 나눠서 들어갈수 있는 갯수가 동일하면 가운데로 정렬 시킨다
if (flowLines.left.type === 'curve' && flowLines.right.type === 'curve') {
startPointX = flowLines.left.x1 + (calcAreaWidth - totalModuleWidthCount * width) / 2
if (flowLines.left.x1 < flowLines.bottom.x1) {
startPointX = flowLines.left.x1
}
}
let heightMargin = 0
let widthMargin = 0
let chidoriLength = 0
let moduleMaxRows = totalModuleHeightCount
//첫번재 모듈 설치 후 두번째 모듈을 몇개까지 설치 할 수 있는지 계산
if (moduleIndex > 0) {
moduleMaxRows = moduleMaxRows - installedModuleHeightCount //두번째 모듈일때
}
let isInstall = false
for (let i = 0; i < moduleMaxRows; i++) {
let moduleY = flowLines.bottom.y1 - height * i - 1 //살짝 여유를 준다
//두번째 모듈 -> 혼합일 경우의 설치될 모듈 높이를 계산
if (moduleIndex > 0) {
moduleY = installedLastHeightCoord - intvVer
}
//첫번째는 붙여서 두번째는 마진을 주고 설치
heightMargin = i === 0 ? 0 : intvVer * i
for (let j = 0; j < totalModuleWidthCount; j++) {
let moduleX = startPointX + width * j + 1 //5정도 마진을 준다
widthMargin = j === 0 ? 0 : intvHor * j // 가로 마진값
chidoriLength = 0 //치도리가 아니여도 기본값을 5정도 준다
let square = [
[moduleX + widthMargin, moduleY - height - heightMargin],
[moduleX + widthMargin, moduleY - heightMargin],
[moduleX + width + widthMargin, moduleY - heightMargin],
[moduleX + width + widthMargin, moduleY - height - heightMargin],
[moduleX + widthMargin, moduleY - height - heightMargin],
] ]
let squarePolygon = turf.polygon([square]) let squarePolygon = turf.polygon([square])
@ -3029,15 +3094,47 @@ export function useModuleBasicSetting(tabNum) {
moduleOptions = { ...moduleOptions, fill: module.color, surfaceId: moduleSetupSurface.id, moduleInfo: module } moduleOptions = { ...moduleOptions, fill: module.color, surfaceId: moduleSetupSurface.id, moduleInfo: module }
let tempModule = new QPolygon(points, { ...moduleOptions, turfPoints: squarePolygon }) let tempModule = new QPolygon(points, { ...moduleOptions, turfPoints: squarePolygon })
let disjointFromTrestle = checkModuleDisjointSurface(squarePolygon, polygonToTurfPolygon(moduleSetupSurface, true))
let isDisjoint = checkModuleDisjointObjects(squarePolygon, containsBatchObjects)
if (disjointFromTrestle && isDisjoint) {
//최초 한번은 그냥 그린다
//겹치는지 확인해서 포함된 모듈만 그린다
canvas?.add(tempModule) canvas?.add(tempModule)
moduleSetupArray.push(tempModule) moduleSetupArray.push(tempModule)
moduleGroup.push(tempModule) moduleArray.push(tempModule)
canvas.renderAll()
// ++installedModuleHeightCount
isInstall = true
//마지막에 설치된 모듈의 Y 좌표
installedLastHeightCoord = moduleY - height - heightMargin
} else {
//디버깅용
// tempModule.set({ fill: 'transparent', stroke: 'red', strokeWidth: 1 })
// canvas?.add(tempModule)
// canvas.renderAll()
} }
} }
if (isInstall) {
++installedModuleHeightCount
}
}
setupModule.push(moduleArray)
}) })
} }
const flatRoofLeftFlowSetupModule = (surfaceMaxLines, maxLengthLine, moduleSetupArray, moduleSetupSurface, marginWidth, marginHeight) => { const flatRoofLeftFlowSetupModule = (
surfaceMaxLines,
maxLengthLine,
moduleSetupArray,
moduleSetupSurface,
intvHor,
intvVer,
containsBatchObjects,
) => {
checkedModule.forEach((module, index) => { checkedModule.forEach((module, index) => {
const { width, height } = getModuleWidthHeight(maxLengthLine, moduleSetupSurface, module) const { width, height } = getModuleWidthHeight(maxLengthLine, moduleSetupSurface, module)
const flowLines = getFlowLines(moduleSetupSurface, width) const flowLines = getFlowLines(moduleSetupSurface, width)
@ -3082,7 +3179,15 @@ export function useModuleBasicSetting(tabNum) {
}) })
} }
const flatRoofTopFlowSetupModule = (surfaceMaxLines, maxLengthLine, moduleSetupArray, moduleSetupSurface, marginWidth, marginHeight) => { const flatRoofTopFlowSetupModule = (
surfaceMaxLines,
maxLengthLine,
moduleSetupArray,
moduleSetupSurface,
intvHor,
intvVer,
containsBatchObjects,
) => {
checkedModule.forEach((module, index) => { checkedModule.forEach((module, index) => {
const { width, height } = getModuleWidthHeight(maxLengthLine, moduleSetupSurface, module) const { width, height } = getModuleWidthHeight(maxLengthLine, moduleSetupSurface, module)
const flowLines = getFlowLines(moduleSetupSurface, height) const flowLines = getFlowLines(moduleSetupSurface, height)
@ -3129,7 +3234,15 @@ export function useModuleBasicSetting(tabNum) {
}) })
} }
const flatRoofRightFlowSetupModule = (surfaceMaxLines, moduleSetupArray, moduleSetupSurface, marginWidth, marginHeight) => { const flatRoofRightFlowSetupModule = (
surfaceMaxLines,
maxLengthLine,
moduleSetupArray,
moduleSetupSurface,
intvHor,
intvVer,
containsBatchObjects,
) => {
checkedModule.forEach((module, index) => { checkedModule.forEach((module, index) => {
const { width, height } = getModuleWidthHeight(maxLengthLine, moduleSetupSurface, module) const { width, height } = getModuleWidthHeight(maxLengthLine, moduleSetupSurface, module)
const flowLines = getFlowLines(moduleSetupSurface, width) const flowLines = getFlowLines(moduleSetupSurface, width)
@ -3186,20 +3299,13 @@ export function useModuleBasicSetting(tabNum) {
const containsBatchObjects = objectsIncludeSurface(turfModuleSetupSurface) //배치면에 오브젝트(도머, 개구등)이 있는지 확인하는 로직 const containsBatchObjects = objectsIncludeSurface(turfModuleSetupSurface) //배치면에 오브젝트(도머, 개구등)이 있는지 확인하는 로직
const surfaceMaxLines = findSetupSurfaceMaxLines(moduleSetupSurface) const surfaceMaxLines = findSetupSurfaceMaxLines(moduleSetupSurface)
const marginWidth = 1 const intvHor = 30
const marginHeight = 3 const intvVer = 10
canvas.renderAll() canvas.renderAll()
if (compasDeg >= 0 && compasDeg < 90) { //육지붕은 왼쪽 기준으로 그려진다
flatRoofDownFlowSetupModule(surfaceMaxLines, maxLengthLine, moduleSetupArray, moduleSetupSurface, marginWidth, marginHeight) flatRoofDownFlowSetupModule(surfaceMaxLines, maxLengthLine, moduleSetupArray, moduleSetupSurface, intvHor, intvVer, containsBatchObjects)
} else if (compasDeg >= 90 && compasDeg < 180) {
flatRoofLeftFlowSetupModule(surfaceMaxLines, maxLengthLine, moduleSetupArray, moduleSetupSurface, marginWidth, marginHeight)
} else if (compasDeg >= 180 && compasDeg < 270) {
flatRoofRightFlowSetupModule(surfaceMaxLines, maxLengthLine, moduleSetupArray, moduleSetupSurface, marginWidth, marginHeight)
} else {
flatRoofTopFlowSetupModule(surfaceMaxLines, maxLengthLine, moduleSetupArray, moduleSetupSurface, marginWidth, marginHeight)
}
const setupedModules = moduleSetupArray.filter((module, index) => { const setupedModules = moduleSetupArray.filter((module, index) => {
let disjointFromTrestle = checkModuleDisjointSurface(module.turfPoints, turfModuleSetupSurface) let disjointFromTrestle = checkModuleDisjointSurface(module.turfPoints, turfModuleSetupSurface)

View File

@ -3536,3 +3536,18 @@ export const calcLineActualSize = (points, degree) => {
} }
return Big(planeSize).pow(2).plus(height.pow(2)).sqrt().abs().round().toNumber() return Big(planeSize).pow(2).plus(height.pow(2)).sqrt().abs().round().toNumber()
} }
export const createLinesFromPolygon = (points) => {
const lines = []
for (let i = 0; i < points.length; i++) {
const nextIndex = (i + 1) % points.length
const line = new fabric.Line([points[i].x, points[i].y, points[nextIndex].x, points[nextIndex].y], {
stroke: 'red',
strokeWidth: 2,
selectable: false,
evented: false,
})
lines.push(line)
}
return lines
}