육지붕 모듈 작업

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) //
setModuleSelectionData({
...moduleSelectionData,
flatModule: option,
module: option,
})
moduleSelectedDataTrigger({
...moduleSelectionData,
flatModule: option,
module: option,
})
}
useEffect(() => {
if (isObjectNotEmpty(moduleSelectionData.flatModule) && moduleList.length > 0) {
handleChangeModule(moduleSelectionData.flatModule)
if (isObjectNotEmpty(moduleSelectionData.module) && moduleList.length > 0) {
handleChangeModule(moduleSelectionData.module)
}
}, [moduleList])

View File

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

View File

@ -3,7 +3,7 @@ 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 { 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 { moduleSetupSurfaceState, moduleIsSetupState } from '@/store/canvasAtom'
import { useEvent } from '@/hooks/useEvent'
@ -239,7 +239,6 @@ export function useModuleBasicSetting(tabNum) {
toggleSelection(isExistSurface)
})
} else {
let offsetLength = canvasSetting.roofSizeSet === '3' ? -30 : (trestleDetail.eaveIntvl / 10) * -1
setSurfaceShapePattern(roof, roofDisplay.column, true, roof.roofMaterial) //패턴 변경
// let offsetPoints = createPaddingPolygon(createRoofPolygon(roof.points), roof.lines).vertices //안쪽 offset
let offsetPoints = null
@ -252,10 +251,16 @@ export function useModuleBasicSetting(tabNum) {
//margin polygon 의 point가 기준 polygon의 밖에 있는지 판단한다.
const allPointsOutside = result.every((point) => !originPolygon.inPolygon(point))
if (allPointsOutside) {
offsetPoints = createMarginPolygon(polygon, roof.lines).vertices
if (canvasSetting.roofSizeSet == '3') {
//육지붕일때는 그냥 하드코딩
offsetPoints = offsetPolygon(roof.points, -30) //육지붕일때
} else {
offsetPoints = createPaddingPolygon(polygon, roof.lines).vertices
//육지붕이 아닐때
if (allPointsOutside) {
offsetPoints = createMarginPolygon(polygon, roof.lines).vertices
} else {
offsetPoints = createPaddingPolygon(polygon, roof.lines).vertices
}
}
//모듈설치영역?? 생성
@ -263,7 +268,7 @@ export function useModuleBasicSetting(tabNum) {
const surfaceId = uuidv4()
let isNorth = false
if (canvasSetting.roofSizeSet !== '3') {
if (canvasSetting.roofSizeSet != '3') {
//북면이 있지만
if (roof.directionText && roof.directionText.indexOf('北') > -1) {
//북쪽일때 해당 서북서, 동북동은 제외한다고 한다
@ -2895,8 +2900,13 @@ export function useModuleBasicSetting(tabNum) {
targetRoof.angle = -angle
targetSurface.angle = -angle
const newLines = createLinesFromPolygon(targetSurface.getCurrentPoints())
targetSurface.set({ lines: newLines })
targetRoof.fire('modified')
targetSurface.fire('modified')
targetRoof.setCoords()
targetSurface.setCoords()
moduleSetupSurfaces.push(targetSurface)
}
canvas.remove(obj)
@ -2990,37 +3000,92 @@ export function useModuleBasicSetting(tabNum) {
let moduleGroup = []
const flatRoofDownFlowSetupModule = (surfaceMaxLines, maxLengthLine, moduleSetupArray, moduleSetupSurface, marginWidth, marginHeight) => {
checkedModule.forEach((module, index) => {
const { width, height } = getModuleWidthHeight(maxLengthLine, moduleSetupSurface, module)
const flatRoofDownFlowSetupModule = (
surfaceMaxLines,
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 //최 좌측
const maxRightEndPoint = surfaceMaxLines.right.x1 //최 우측
const maxTopEndPoint = surfaceMaxLines.top.y1 //최 상단
if (moduleIndex === 0) {
flowLines = getFlowLines(moduleSetupSurface, height)
if (flowLines.bottom.type === 'curve') {
flowLines = getFlowLines(moduleSetupSurface, width)
}
}
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 = width //최대배치인지 확인하려고 넣음
//육지붕이 아닐때만 넣는다 육지붕일땐 클릭 이벤트에 별도로 넣어놓음
const moduleArray = []
for (let j = 0; j < diffTopEndPoint; j++) {
bottomMargin = marginHeight * j
for (let i = 0; i <= totalWidth; i++) {
leftMargin = marginWidth * i
let calcAreaWidth = flowLines.right.x1 - flowLines.left.x1 //오른쪽 x에서 왼쪽 x를 뺀 가운데를 찾는 로직
let calcModuleWidthCount = calcAreaWidth / (width + intvHor) //뺀 공간에서 모듈을 몇개를 넣을수 있는지 확인하는 로직
let calcMaxModuleWidthCount = calcModuleWidthCount //최대 모듈 단수가 있기 때문에 최대 단수보다 카운트가 크면 최대 단수로 씀씀
let totalModuleWidthCount = Math.floor(calcMaxModuleWidthCount) //치조배치일경우는 한개 더 넣는다
square = [
[startColPoint + tempMaxWidth * i + leftMargin, startPoint.y1 - height * j - bottomMargin],
[startColPoint + tempMaxWidth * i + width + leftMargin, startPoint.y1 - height * j - bottomMargin],
[startColPoint + tempMaxWidth * i + width + leftMargin, startPoint.y1 - height * j - height - bottomMargin],
[startColPoint + tempMaxWidth * i + leftMargin, startPoint.y1 - height * j - height - bottomMargin],
[startColPoint + tempMaxWidth * i + leftMargin, startPoint.y1 - height * j - bottomMargin],
let calcAreaheight = flowLines.bottom.y1 - flowLines.top.y1 //오른쪽 y에서 왼쪽 y를 뺀 가운데를 찾는 로직
let calcModuleHeightCount = calcAreaheight / (height + intvVer) //뺀 공간에서 모듈을 몇개를 넣을수 있는지 확인하는 로직
let calcMaxModuleHeightCount = calcModuleHeightCount //최대 모듈 단수가 있기 때문에 최대 단수보다 카운트가 크면 최대 단수로 씀씀
let totalModuleHeightCount = Math.floor(calcMaxModuleHeightCount) //치조배치일경우는 한개 더 넣는다
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])
@ -3029,15 +3094,47 @@ export function useModuleBasicSetting(tabNum) {
moduleOptions = { ...moduleOptions, fill: module.color, surfaceId: moduleSetupSurface.id, moduleInfo: module }
let tempModule = new QPolygon(points, { ...moduleOptions, turfPoints: squarePolygon })
canvas?.add(tempModule)
moduleSetupArray.push(tempModule)
moduleGroup.push(tempModule)
let disjointFromTrestle = checkModuleDisjointSurface(squarePolygon, polygonToTurfPolygon(moduleSetupSurface, true))
let isDisjoint = checkModuleDisjointObjects(squarePolygon, containsBatchObjects)
if (disjointFromTrestle && isDisjoint) {
//최초 한번은 그냥 그린다
//겹치는지 확인해서 포함된 모듈만 그린다
canvas?.add(tempModule)
moduleSetupArray.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) => {
const { width, height } = getModuleWidthHeight(maxLengthLine, moduleSetupSurface, module)
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) => {
const { width, height } = getModuleWidthHeight(maxLengthLine, moduleSetupSurface, module)
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) => {
const { width, height } = getModuleWidthHeight(maxLengthLine, moduleSetupSurface, module)
const flowLines = getFlowLines(moduleSetupSurface, width)
@ -3186,20 +3299,13 @@ export function useModuleBasicSetting(tabNum) {
const containsBatchObjects = objectsIncludeSurface(turfModuleSetupSurface) //배치면에 오브젝트(도머, 개구등)이 있는지 확인하는 로직
const surfaceMaxLines = findSetupSurfaceMaxLines(moduleSetupSurface)
const marginWidth = 1
const marginHeight = 3
const intvHor = 30
const intvVer = 10
canvas.renderAll()
if (compasDeg >= 0 && compasDeg < 90) {
flatRoofDownFlowSetupModule(surfaceMaxLines, maxLengthLine, moduleSetupArray, moduleSetupSurface, marginWidth, marginHeight)
} 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)
}
//육지붕은 왼쪽 기준으로 그려진다
flatRoofDownFlowSetupModule(surfaceMaxLines, maxLengthLine, moduleSetupArray, moduleSetupSurface, intvHor, intvVer, containsBatchObjects)
const setupedModules = moduleSetupArray.filter((module, index) => {
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()
}
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
}