3342 lines
124 KiB
JavaScript
3342 lines
124 KiB
JavaScript
import { useRecoilValue } from 'recoil'
|
|
import { canvasState, currentAngleTypeSelector } from '@/store/canvasAtom'
|
|
import { POLYGON_TYPE, TRESTLE_MATERIAL } from '@/common/common'
|
|
import { moduleSelectionDataState } from '@/store/selectedModuleOptions'
|
|
import { getDegreeByChon } from '@/util/canvas-util'
|
|
import { v4 as uuidv4 } from 'uuid'
|
|
import { useMasterController } from '@/hooks/common/useMasterController'
|
|
import { basicSettingState, trestleDisplaySelector } from '@/store/settingAtom'
|
|
import { useSwal } from '@/hooks/useSwal'
|
|
import { useContext } from 'react'
|
|
import { QcastContext } from '@/app/QcastProvider'
|
|
import { useCircuitTrestle } from '@/hooks/useCirCuitTrestle'
|
|
import { useMessage } from '@/hooks/useMessage'
|
|
|
|
// 모듈간 같은 행, 열의 마진이 10 이하인 경우는 같은 행, 열로 간주
|
|
const MODULE_MARGIN = 10
|
|
// 회로 및 가대설정
|
|
export const useTrestle = () => {
|
|
const canvas = useRecoilValue(canvasState)
|
|
const moduleSelectionData = useRecoilValue(moduleSelectionDataState) //다음으로 넘어가는 최종 데이터
|
|
const { getQuotationItem } = useMasterController()
|
|
const currentAngleType = useRecoilValue(currentAngleTypeSelector)
|
|
const roofSizeSet = useRecoilValue(basicSettingState).roofSizeSet
|
|
const isTrestleDisplay = useRecoilValue(trestleDisplaySelector)
|
|
const { swalFire } = useSwal()
|
|
const { setIsGlobalLoading } = useContext(QcastContext)
|
|
|
|
const { getSelectedPcsItemList } = useCircuitTrestle()
|
|
const { resetCircuits } = useCircuitTrestle()
|
|
const { getMessage } = useMessage()
|
|
|
|
const apply = () => {
|
|
const notAllocationModules = canvas.getObjects().filter((obj) => obj.name === POLYGON_TYPE.MODULE && !obj.circuit)
|
|
if (notAllocationModules.length > 0) {
|
|
swalFire({
|
|
text: '回路番号が設定されていないモジュールがあります。 番号を設定しなおすか、 パネルを削除してください。',
|
|
icon: 'error',
|
|
})
|
|
setIsGlobalLoading(false)
|
|
return
|
|
}
|
|
try {
|
|
//처마력바가 체크되어 있는 경우 exposedBottomPoints를 이용해 처마력바 그려줘야함.
|
|
// exposedBottomPoints는 노출 최하면 들의 centerPoint 배열.
|
|
|
|
const surfaces = canvas.getObjects().filter((obj) => obj.name === POLYGON_TYPE.MODULE_SETUP_SURFACE)
|
|
// 기존 eaveBar를 삭제
|
|
canvas.getObjects().forEach((obj) => {
|
|
if (obj.name === 'eaveBar' || obj.name === 'rack' || obj.name === 'halfEaveBar' || obj.name === 'smartRack') {
|
|
canvas.remove(obj)
|
|
}
|
|
})
|
|
canvas.getObjects().forEach((obj) => {
|
|
if (obj.name === 'bracket') {
|
|
canvas.remove(obj)
|
|
}
|
|
})
|
|
surfaces.forEach((surface) => {
|
|
getSameLineModules(surface)
|
|
const parent = canvas.getObjects().find((obj) => obj.id === surface.parentId)
|
|
const roofMaterialIndex = parent.roofMaterial.index
|
|
if (+roofSizeSet === 3) {
|
|
return
|
|
}
|
|
const construction = moduleSelectionData?.roofConstructions?.find((construction) => construction.roofIndex === roofMaterialIndex).construction
|
|
if (!construction) {
|
|
return
|
|
}
|
|
|
|
const plvrYn = construction.plvrYn
|
|
let moduleRowsTotCnt = 0
|
|
let isEaveBar = construction.setupCover
|
|
let isSnowGuard = construction.setupSnowCover
|
|
let cvrLmtRow = construction.cvrLmtRow
|
|
const direction = parent.direction
|
|
const rack = surface.trestleDetail.rack
|
|
let { rackQty, rackIntvlPct, rackYn, cvrPlvrYn, lessSupFitIntvlPct, lessSupFitQty } = surface.trestleDetail
|
|
|
|
if (!rack && lessSupFitIntvlPct === 0 && lessSupFitQty === 0) {
|
|
//25/02/06 가대없음의 경우 랙정보가 없음
|
|
return
|
|
}
|
|
|
|
let rackInfos = []
|
|
|
|
if (rack) {
|
|
rackInfos = Object.keys(rack).map((key) => {
|
|
return { key, value: rack[key] }
|
|
})
|
|
}
|
|
|
|
// 모듈들의 centerPoint들을 이용해 각 모듈의 정보(가장 아랫라인 모듈, 가장 윗라인 모듈, 접면, 반접면 등 계산)
|
|
const result = calculateForApi(surface)
|
|
|
|
if (!result) {
|
|
return
|
|
}
|
|
const centerPoints = result.centerPoints
|
|
|
|
const exposedBottomModules = [] // 아래 두면이 모두 노출 되어있는 경우
|
|
const leftExposedHalfBottomModules = [] // 왼쪽 면만 노출되어있는 경우
|
|
const rightExposedHalfBottomPoints = [] // 오른쪽 면만 노출되어 있는 경우
|
|
const leftExposedHalfTopModules = [] // 왼쪽 면만 노출되어 있는 경우
|
|
const rightExposedHalfTopPoints = [] // 오른쪽 면만 노출되어 있는 경우
|
|
const modules = canvas.getObjects().filter((obj) => obj.name === POLYGON_TYPE.MODULE)
|
|
|
|
modules.forEach((module) => {
|
|
const { x, y } = module.getCenterPoint()
|
|
const isExposedBottom = result.exposedBottomPoints.some((point) => Math.abs(point.x - x) < 2 && Math.abs(point.y - y) < 2)
|
|
const isLeftExposedHalfBottom = result.leftExposedHalfBottomPoints.some((point) => Math.abs(point.x - x) < 2 && Math.abs(point.y - y) < 2)
|
|
const isRightExposedHalfBottom = result.rightExposedHalfBottomPoints.some((point) => Math.abs(point.x - x) < 2 && Math.abs(point.y - y) < 2)
|
|
const isRightExposedHalfTop = result.rightExposedHalfTopPoints.some((point) => Math.abs(point.x - x) < 2 && Math.abs(point.y - y) < 2)
|
|
const isLeftExposedHalfTop = result.leftExposedHalfTopPoints.some((point) => Math.abs(point.x - x) < 2 && Math.abs(point.y - y) < 2)
|
|
if (isExposedBottom) {
|
|
exposedBottomModules.push(module)
|
|
}
|
|
if (isLeftExposedHalfBottom) {
|
|
leftExposedHalfBottomModules.push(module)
|
|
}
|
|
if (isRightExposedHalfBottom) {
|
|
rightExposedHalfBottomPoints.push(module)
|
|
}
|
|
if (isRightExposedHalfTop) {
|
|
leftExposedHalfTopModules.push(module)
|
|
}
|
|
if (isLeftExposedHalfTop) {
|
|
rightExposedHalfTopPoints.push(module)
|
|
}
|
|
})
|
|
|
|
// 4개중 한개라도 있는 경우 치조배치로 간주한다.
|
|
const isChidory =
|
|
leftExposedHalfBottomModules.length > 0 ||
|
|
rightExposedHalfBottomPoints.length > 0 ||
|
|
leftExposedHalfTopModules.length > 0 ||
|
|
rightExposedHalfTopPoints.length > 0
|
|
surface.isChidory = isChidory
|
|
|
|
if (plvrYn === 'N' && isChidory) {
|
|
swalFire({ text: getMessage('chidory.can.not.install'), icon: 'error' })
|
|
clear()
|
|
throw new Error(getMessage('chidory.can.not.install'))
|
|
}
|
|
|
|
surface.set({ isChidory: isChidory })
|
|
|
|
canvas
|
|
.getObjects()
|
|
.filter((obj) => ['eaveBar', 'halfEaveBar'].includes(obj.name) && obj.parentId === surface.id)
|
|
.forEach((obj) => {
|
|
canvas.remove(obj)
|
|
})
|
|
|
|
if (isEaveBar) {
|
|
// 처마력바설치 true인 경우 설치
|
|
exposedBottomModules.forEach((module) => {
|
|
const level = module.level
|
|
if (level > cvrLmtRow) {
|
|
return
|
|
}
|
|
const bottomPoints = findTopTwoPoints([...module.getCurrentPoints()], direction)
|
|
if (!bottomPoints) return
|
|
const eaveBar = new fabric.Line([bottomPoints[0].x, bottomPoints[0].y, bottomPoints[1].x, bottomPoints[1].y], {
|
|
parent: surface,
|
|
name: TRESTLE_MATERIAL.EAVE_BAR,
|
|
stroke: 'blue',
|
|
strokeWidth: 4,
|
|
selectable: false,
|
|
surfaceId: surface.id,
|
|
parentId: module.id,
|
|
visible: isTrestleDisplay,
|
|
})
|
|
canvas.add(eaveBar)
|
|
canvas.renderAll()
|
|
})
|
|
|
|
if (isChidory && cvrPlvrYn === 'Y') {
|
|
leftExposedHalfBottomModules.forEach((module) => {
|
|
const level = module.level
|
|
if (level > cvrLmtRow) {
|
|
return
|
|
}
|
|
const bottomPoints = findTopTwoPoints([...module.getCurrentPoints()], direction)
|
|
let barPoints = []
|
|
//설치해야할 반처마커버 포인트를 방향에 따라 설정
|
|
|
|
if (direction === 'south') {
|
|
barPoints = [bottomPoints[0].x, bottomPoints[0].y, bottomPoints[1].x - module.width / 2, bottomPoints[1].y]
|
|
} else if (direction === 'north') {
|
|
barPoints = [bottomPoints[0].x + module.width / 2, bottomPoints[0].y, bottomPoints[1].x, bottomPoints[1].y]
|
|
} else if (direction === 'east') {
|
|
barPoints = [bottomPoints[0].x, bottomPoints[0].y, bottomPoints[1].x, bottomPoints[0].y - module.height / 2]
|
|
} else if (direction === 'west') {
|
|
barPoints = [bottomPoints[0].x, bottomPoints[0].y, bottomPoints[1].x, bottomPoints[1].y - module.height / 2]
|
|
}
|
|
|
|
if (!bottomPoints) return
|
|
const halfEaveBar = new fabric.Line(barPoints, {
|
|
parent: surface,
|
|
name: TRESTLE_MATERIAL.HALF_EAVE_BAR,
|
|
stroke: 'blue',
|
|
strokeWidth: 4,
|
|
selectable: false,
|
|
surfaceId: surface.id,
|
|
parentId: module.id,
|
|
visible: isTrestleDisplay,
|
|
})
|
|
canvas.add(halfEaveBar)
|
|
canvas.renderAll()
|
|
})
|
|
|
|
rightExposedHalfBottomPoints.forEach((module) => {
|
|
const level = module.level
|
|
if (level > cvrLmtRow) {
|
|
return
|
|
}
|
|
const bottomPoints = findTopTwoPoints([...module.points], direction)
|
|
let barPoints = []
|
|
//설치해야할 반처마커버 포인트를 방향에 따라 설정
|
|
|
|
if (direction === 'south') {
|
|
barPoints = [bottomPoints[0].x + module.width / 2, bottomPoints[0].y, bottomPoints[1].x, bottomPoints[1].y]
|
|
} else if (direction === 'north') {
|
|
barPoints = [bottomPoints[0].x, bottomPoints[0].y, bottomPoints[0].x + module.width / 2, bottomPoints[1].y]
|
|
} else if (direction === 'east') {
|
|
barPoints = [bottomPoints[0].x, bottomPoints[1].y + module.height / 2, bottomPoints[1].x, bottomPoints[1].y]
|
|
} else if (direction === 'west') {
|
|
barPoints = [bottomPoints[0].x, bottomPoints[1].y - module.height / 2, bottomPoints[1].x, bottomPoints[1].y]
|
|
}
|
|
|
|
if (!bottomPoints) return
|
|
const halfEaveBar = new fabric.Line(barPoints, {
|
|
parent: surface,
|
|
name: TRESTLE_MATERIAL.HALF_EAVE_BAR,
|
|
stroke: 'blue',
|
|
strokeWidth: 4,
|
|
selectable: false,
|
|
parentId: module.id,
|
|
visible: isTrestleDisplay,
|
|
})
|
|
canvas.add(halfEaveBar)
|
|
canvas.renderAll()
|
|
})
|
|
}
|
|
}
|
|
const horizontal = ['south', 'north'].includes(direction) ? surface.trestleDetail.moduleIntvlHor : surface.trestleDetail.moduleIntvlVer
|
|
|
|
const vertical = ['south', 'north'].includes(direction) ? surface.trestleDetail.moduleIntvlVer : surface.trestleDetail.moduleIntvlHor
|
|
|
|
let mostRowsModule = 0 // 모듈 최대 단 수
|
|
// 가대 설치를 위한 가장 아래 모듈로부터 위로 몇단인지 계산
|
|
// 오른쪽,왼쪽 둘 다 아래에 아무것도 없는, 처마 커버를 필요로 하는 모듈
|
|
exposedBottomModules.forEach((module) => {
|
|
let { width, height } = { ...module }
|
|
width = Math.floor(width)
|
|
height = Math.floor(height)
|
|
let { x: startX, y: startY } = { ...module.getCenterPoint() }
|
|
let { x, y } = { ...module.getCenterPoint() }
|
|
|
|
let leftRows = 1
|
|
let rightRows = 1
|
|
let centerRows = 1
|
|
let hasNextModule = true
|
|
let findLeft = true
|
|
let findRight = true
|
|
|
|
let leftFindModuleList = [module]
|
|
let rightFindModuleList = [module]
|
|
let centerFindModuleList = [module]
|
|
|
|
//우선 절반을 나눈 뒤 왼쪽부터 찾는다.
|
|
while (hasNextModule) {
|
|
//바로 위에 있는지 확인한다.
|
|
let nextModule = findNextModule({ x, y, width, height, horizontal, vertical }, centerPoints, direction)
|
|
|
|
if (nextModule) {
|
|
// 바로 위 모듈을 찾는다.
|
|
leftRows++
|
|
leftFindModuleList.push(nextModule)
|
|
x = nextModule.x
|
|
y = nextModule.y
|
|
} else {
|
|
// 바로 위가 없을 경우 먼저 왼쪽위가 있는지 확인 한다.
|
|
if (findLeft) {
|
|
nextModule = findNextLeftModule({ x, y, width, height, horizontal, vertical }, centerPoints, direction)
|
|
findLeft = false
|
|
} else {
|
|
nextModule = findNextRightModule({ x, y, width, height, horizontal, vertical }, centerPoints, direction)
|
|
findLeft = true
|
|
}
|
|
|
|
if (nextModule) {
|
|
// 바로 위 모듈을 찾는다.
|
|
leftRows++
|
|
leftFindModuleList.push(nextModule)
|
|
x = nextModule.x
|
|
y = nextModule.y
|
|
} else {
|
|
hasNextModule = false
|
|
}
|
|
}
|
|
}
|
|
|
|
hasNextModule = true
|
|
x = startX
|
|
y = startY
|
|
|
|
// 오른쪽 찾는다.
|
|
while (hasNextModule) {
|
|
//바로 위에 있는지 확인한다.
|
|
let nextModule = findNextModule({ x, y, width, height, horizontal, vertical }, centerPoints, direction)
|
|
|
|
if (nextModule) {
|
|
// 바로 위 모듈을 찾는다.
|
|
rightRows++
|
|
rightFindModuleList.push(nextModule)
|
|
x = nextModule.x
|
|
y = nextModule.y
|
|
} else {
|
|
// 바로 위가 없을 경우 먼저 왼쪽위가 있는지 확인 한다.
|
|
if (findRight) {
|
|
nextModule = findNextRightModule({ x, y, width, height, horizontal, vertical }, centerPoints, direction)
|
|
findRight = false
|
|
} else {
|
|
nextModule = findNextLeftModule({ x, y, width, height, horizontal, vertical }, centerPoints, direction)
|
|
findRight = true
|
|
}
|
|
|
|
if (nextModule) {
|
|
// 바로 위 모듈을 찾는다.
|
|
rightRows++
|
|
rightFindModuleList.push(nextModule)
|
|
x = nextModule.x
|
|
y = nextModule.y
|
|
} else {
|
|
hasNextModule = false
|
|
}
|
|
}
|
|
}
|
|
|
|
hasNextModule = true
|
|
x = startX
|
|
y = startY
|
|
|
|
// 센터 찾는다.
|
|
while (hasNextModule) {
|
|
//바로 위에 있는지 확인한다.
|
|
let nextModule = findNextModule({ x, y, width, height, horizontal, vertical }, centerPoints, direction)
|
|
|
|
if (nextModule) {
|
|
// 바로 위 모듈을 찾는다.
|
|
centerFindModuleList.push(nextModule)
|
|
centerRows++
|
|
x = nextModule.x
|
|
y = nextModule.y
|
|
} else {
|
|
hasNextModule = false
|
|
}
|
|
}
|
|
|
|
const leftModuleInfos = leftFindModuleList.map((module) => {
|
|
return {
|
|
moduleTpCd: module.moduleInfo.moduleTpCd,
|
|
}
|
|
})
|
|
|
|
const rightModuleInfos = rightFindModuleList.map((module) => {
|
|
return {
|
|
moduleTpCd: module.moduleInfo.moduleTpCd,
|
|
}
|
|
})
|
|
|
|
const centerModuleInfos = centerFindModuleList.map((module) => {
|
|
return {
|
|
moduleTpCd: module.moduleInfo.moduleTpCd,
|
|
}
|
|
})
|
|
|
|
const leftRowsInfo = moduleTransformData(leftModuleInfos)
|
|
const rightRowsInfo = moduleTransformData(rightModuleInfos)
|
|
const centerRowsInfo = moduleTransformData(centerModuleInfos)
|
|
|
|
// 모듈의 왼쪽 부터 그릴 랙 정보를 가져온다.
|
|
const leftRacks = rackInfos.find((rack) => {
|
|
if (leftRowsInfo.rowsInfo.length === 1) {
|
|
return (
|
|
rack.value.moduleTpCd === leftRowsInfo.moduleTotalTp &&
|
|
rack.value.moduleRows === leftRowsInfo.rowsInfo.reduce((acc, row) => acc + row.count, 0)
|
|
)
|
|
} else {
|
|
//C1C2C3인 경우
|
|
let newLeftRowsInfo = normalizeModules(rack.value.moduleTpCd, leftRowsInfo)
|
|
|
|
return (
|
|
rack.value.moduleTpCd === newLeftRowsInfo.moduleTotalTp &&
|
|
rack.value.moduleRows === newLeftRowsInfo.rowsInfo.reduce((acc, row) => acc + row.count, 0) &&
|
|
newLeftRowsInfo.rowsInfo.every((row, index) => {
|
|
const rackRowCount = Number(rack.value[`moduleTpRows${index + 1}`]) // 동적으로 접근
|
|
return rackRowCount === row.count
|
|
})
|
|
)
|
|
}
|
|
})?.value.racks
|
|
|
|
// 모듈의 오른쪽 부터 그릴 랙 정보를 가져온다.
|
|
const rightRacks = rackInfos.find((rack) => {
|
|
if (rightRowsInfo.rowsInfo.length === 1) {
|
|
return (
|
|
rack.value.moduleTpCd === rightRowsInfo.moduleTotalTp &&
|
|
rack.value.moduleRows === rightRowsInfo.rowsInfo.reduce((acc, row) => acc + row.count, 0)
|
|
)
|
|
} else {
|
|
let newRightRowsInfo = normalizeModules(rack.value.moduleTpCd, rightRowsInfo)
|
|
|
|
return (
|
|
rack.value.moduleTpCd === newRightRowsInfo.moduleTotalTp &&
|
|
rack.value.moduleRows === newRightRowsInfo.rowsInfo.reduce((acc, row) => acc + row.count, 0) &&
|
|
newRightRowsInfo.rowsInfo.every((row, index) => {
|
|
const rackRowCount = Number(rack.value[`moduleTpRows${index + 1}`]) // 동적으로 접근
|
|
return rackRowCount === row.count
|
|
})
|
|
)
|
|
}
|
|
})?.value.racks
|
|
// 해당 rack으로 그려준다.
|
|
|
|
const centerRacks = rackInfos.find((rack) => {
|
|
if (centerRowsInfo.rowsInfo.length === 1) {
|
|
return (
|
|
rack.value.moduleTpCd === centerRowsInfo.moduleTotalTp &&
|
|
rack.value.moduleRows === centerRowsInfo.rowsInfo.reduce((acc, row) => acc + row.count, 0)
|
|
)
|
|
} else {
|
|
let newCenterRowsInfo = normalizeModules(rack.value.moduleTpCd, centerRowsInfo)
|
|
|
|
return (
|
|
rack.value.moduleTpCd === newCenterRowsInfo.moduleTotalTp &&
|
|
rack.value.moduleRows === newCenterRowsInfo.rowsInfo.reduce((acc, row) => acc + row.count, 0) &&
|
|
newCenterRowsInfo.rowsInfo.every((row, index) => {
|
|
const rackRowCount = Number(rack.value[`moduleTpRows${index + 1}`]) // 동적으로 접근
|
|
return rackRowCount === row.count
|
|
})
|
|
)
|
|
}
|
|
})?.value.racks
|
|
|
|
mostRowsModule = Math.max(leftRows, rightRows, centerRows, mostRowsModule)
|
|
|
|
if (rackYn === 'Y') {
|
|
drawRacks(leftRacks, rackQty, rackIntvlPct, module, direction, 'L', rackYn)
|
|
drawRacks(rightRacks, rackQty, rackIntvlPct, module, direction, 'R', rackYn)
|
|
|
|
if (rackQty === 3) {
|
|
//rack 갯수가 3개인 경우는 중간렉도 추가해줘야함
|
|
drawRacks(centerRacks, rackQty, rackIntvlPct, module, direction, 'C', rackYn)
|
|
} else if (rackQty === 4) {
|
|
drawRacks(leftRacks, rackQty, rackIntvlPct / 3, module, direction, 'L', rackYn)
|
|
drawRacks(rightRacks, rackQty, rackIntvlPct / 3, module, direction, 'R', rackYn)
|
|
}
|
|
}
|
|
module.set({ leftRows, rightRows, centerRows, leftFindModuleList, rightFindModuleList, centerFindModuleList })
|
|
})
|
|
// 왼쪽아래에 모듈이 없는 모듈들
|
|
leftExposedHalfBottomModules.forEach((module) => {
|
|
const { width, height } = module
|
|
let { x: startX, y: startY } = { ...module.getCenterPoint() }
|
|
let { x, y } = { ...module.getCenterPoint() }
|
|
|
|
let leftRows = 1
|
|
let hasNextModule = true
|
|
let findLeft = true
|
|
let findModuleList = [module]
|
|
|
|
//우선 절반을 나눈 뒤 왼쪽부터 찾는다.
|
|
while (hasNextModule) {
|
|
//바로 위에 있는지 확인한다.
|
|
let nextModule = findNextModule({ x, y, width, height, horizontal, vertical }, centerPoints, direction)
|
|
|
|
if (nextModule) {
|
|
// 바로 위 모듈을 찾는다.
|
|
leftRows++
|
|
findModuleList.push(nextModule)
|
|
x = nextModule.x
|
|
y = nextModule.y
|
|
} else {
|
|
// 바로 위가 없을 경우 먼저 왼쪽위가 있는지 확인 한다.
|
|
if (findLeft) {
|
|
nextModule = findNextLeftModule({ x, y, width, height, horizontal, vertical }, centerPoints, direction)
|
|
findLeft = false
|
|
} else {
|
|
nextModule = nextModule = findNextRightModule(
|
|
{
|
|
x,
|
|
y,
|
|
width,
|
|
height,
|
|
horizontal,
|
|
vertical,
|
|
},
|
|
centerPoints,
|
|
direction,
|
|
)
|
|
findLeft = true
|
|
}
|
|
|
|
if (nextModule) {
|
|
// 바로 위 모듈을 찾는다.
|
|
leftRows++
|
|
findModuleList.push(nextModule)
|
|
x = nextModule.x
|
|
y = nextModule.y
|
|
} else {
|
|
hasNextModule = false
|
|
}
|
|
}
|
|
}
|
|
|
|
const leftModuleInfos = findModuleList.map((module) => {
|
|
return {
|
|
moduleTpCd: module.moduleInfo.moduleTpCd,
|
|
}
|
|
})
|
|
const leftRowsInfo = moduleTransformData(leftModuleInfos)
|
|
|
|
// 모듈의 왼쪽 부터 그릴 랙 정보를 가져온다.
|
|
const leftRacks = rackInfos.find((rack) => {
|
|
if (leftRowsInfo.rowsInfo.length === 1) {
|
|
return (
|
|
rack.value.moduleTpCd === leftRowsInfo.moduleTotalTp &&
|
|
rack.value.moduleRows === leftRowsInfo.rowsInfo.reduce((acc, row) => acc + row.count, 0)
|
|
)
|
|
} else {
|
|
let newLeftRowsInfo = normalizeModules(rack.value.moduleTpCd, leftRowsInfo)
|
|
|
|
return (
|
|
rack.value.moduleTpCd === newLeftRowsInfo.moduleTotalTp &&
|
|
rack.value.moduleRows === newLeftRowsInfo.rowsInfo.reduce((acc, row) => acc + row.count, 0) &&
|
|
newLeftRowsInfo.rowsInfo.every((row, index) => {
|
|
const rackRowCount = Number(rack.value[`moduleTpRows${index + 1}`]) // 동적으로 접근
|
|
return rackRowCount === row.count
|
|
})
|
|
)
|
|
}
|
|
})?.value.racks
|
|
|
|
mostRowsModule = Math.max(leftRows, mostRowsModule)
|
|
if (rackYn === 'Y') {
|
|
drawRacks(leftRacks, rackQty, rackIntvlPct, module, direction, 'L', rackYn)
|
|
}
|
|
|
|
module.set({ leftRows, leftFindModuleList: findModuleList })
|
|
})
|
|
// 오른쪽 아래에 모듈이 없는 모듈들
|
|
rightExposedHalfBottomPoints.forEach((module) => {
|
|
const { width, height } = module
|
|
let { x: startX, y: startY } = { ...module.getCenterPoint() }
|
|
let { x, y } = { ...module.getCenterPoint() }
|
|
|
|
let rightRows = 1
|
|
let hasNextModule = true
|
|
let findRight = true
|
|
let findModuleList = [module]
|
|
|
|
// 오른쪽 찾는다.
|
|
while (hasNextModule) {
|
|
//바로 위에 있는지 확인한다.
|
|
let nextModule = findNextModule({ x, y, width, height, horizontal, vertical }, centerPoints, direction)
|
|
|
|
if (nextModule) {
|
|
// 바로 위 모듈을 찾는다.
|
|
rightRows++
|
|
findModuleList.push(nextModule)
|
|
x = nextModule.x
|
|
y = nextModule.y
|
|
} else {
|
|
// 바로 위가 없을 경우 먼저 왼쪽위가 있는지 확인 한다.
|
|
if (findRight) {
|
|
nextModule = findNextRightModule({ x, y, width, height, horizontal, vertical }, centerPoints, direction)
|
|
findRight = false
|
|
} else {
|
|
nextModule = findNextLeftModule({ x, y, width, height, horizontal, vertical }, centerPoints, direction)
|
|
findRight = true
|
|
}
|
|
|
|
if (nextModule) {
|
|
// 바로 위 모듈을 찾는다.
|
|
rightRows++
|
|
findModuleList.push(nextModule)
|
|
x = nextModule.x
|
|
y = nextModule.y
|
|
} else {
|
|
hasNextModule = false
|
|
}
|
|
}
|
|
}
|
|
|
|
const rightRowsInfos = findModuleList.map((module) => {
|
|
return {
|
|
moduleTpCd: module.moduleInfo.moduleTpCd,
|
|
}
|
|
})
|
|
|
|
const rightRowsInfo = moduleTransformData(rightRowsInfos)
|
|
|
|
// 모듈의 오른쪽 부터 그릴 랙 정보를 가져온다.
|
|
const rightRacks = rackInfos.find((rack) => {
|
|
if (rightRowsInfo.rowsInfo.length === 1) {
|
|
return (
|
|
rack.value.moduleTpCd === rightRowsInfo.moduleTotalTp &&
|
|
rack.value.moduleRows === rightRowsInfo.rowsInfo.reduce((acc, row) => acc + row.count, 0)
|
|
)
|
|
} else {
|
|
// 변환 C1C2만 있는경우 C3 0개로 추가해준다.
|
|
let newRightRowsInfo = normalizeModules(rack.value.moduleTpCd, rightRowsInfo)
|
|
|
|
return (
|
|
rack.value.moduleTpCd === newRightRowsInfo.moduleTotalTp &&
|
|
rack.value.moduleRows === newRightRowsInfo.rowsInfo.reduce((acc, row) => acc + row.count, 0) &&
|
|
newRightRowsInfo.rowsInfo.every((row, index) => {
|
|
const rackRowCount = Number(rack.value[`moduleTpRows${index + 1}`]) // 동적으로 접근
|
|
return rackRowCount === row.count
|
|
})
|
|
)
|
|
}
|
|
})?.value.racks
|
|
mostRowsModule = Math.max(rightRows, mostRowsModule)
|
|
// 해당 rack으로 그려준다.
|
|
if (rackYn === 'Y') {
|
|
drawRacks(rightRacks, rackQty, rackIntvlPct, module, direction, 'R', rackYn)
|
|
}
|
|
|
|
module.set({ rightRows, rightFindModuleList: findModuleList })
|
|
})
|
|
|
|
surface.set({ moduleRowsTotCnt: mostRowsModule })
|
|
|
|
if (rackYn === 'N') {
|
|
// rack이 없을경우
|
|
installBracketWithOutRack(surface, exposedBottomModules, leftExposedHalfBottomModules, rightExposedHalfBottomPoints, isChidory)
|
|
} else if (rackYn === 'Y') {
|
|
installBracket(surface)
|
|
}
|
|
|
|
const quotationParam = getTrestleParams(surface, exposedBottomModules)
|
|
|
|
surface.set({ quotationParam })
|
|
})
|
|
|
|
return true
|
|
} catch (e) {
|
|
// 에러 발생시 가대 초기화
|
|
console.error(e)
|
|
clear()
|
|
setViewCircuitNumberTexts(true)
|
|
setIsGlobalLoading(false)
|
|
return false
|
|
}
|
|
}
|
|
|
|
//module Rack 정보를 얻기위한 데이터 가공
|
|
function moduleTransformData(arr) {
|
|
//arr의 moduleTpCd를 이용하여 정렬
|
|
arr = arr.sort((a, b) => a.moduleTpCd.localeCompare(b.moduleTpCd))
|
|
|
|
let counts = {}
|
|
|
|
arr.forEach((item) => {
|
|
counts[item.moduleTpCd] = (counts[item.moduleTpCd] || 0) + 1
|
|
})
|
|
|
|
let moduleTotalTp = Object.keys(counts).join('')
|
|
let rowsInfo = Object.entries(counts).map(([moduleTpCd, count]) => ({ moduleTpCd, count }))
|
|
|
|
return { moduleTotalTp, rowsInfo }
|
|
}
|
|
|
|
function normalizeModules(rackTpCd, data) {
|
|
// rackTpCd를 숫자를 기준으로 자른다.
|
|
const allModules = rackTpCd.match(/[A-Za-z]+\d+/g) || [] // 모든 모듈 유형
|
|
|
|
// 현재 존재하는 모듈 유형을 추출
|
|
const existingModules = data.rowsInfo.map((row) => row.moduleTpCd)
|
|
|
|
const result = { ...data, rowsInfo: [...data.rowsInfo] }
|
|
|
|
// 없는 모듈을 추가 (count: 0)
|
|
allModules.forEach((module) => {
|
|
if (!existingModules.includes(module)) {
|
|
result.rowsInfo.push({ moduleTpCd: module, count: 0 })
|
|
}
|
|
})
|
|
|
|
// rowsInfo를 C1, C2, C3 순서로 정렬
|
|
result.rowsInfo.sort((a, b) => allModules.indexOf(a.moduleTpCd) - allModules.indexOf(b.moduleTpCd))
|
|
|
|
// moduleTotalTp를 C1C2C3로 설정
|
|
result.moduleTotalTp = allModules.join('')
|
|
|
|
return result
|
|
}
|
|
|
|
// itemList 조회 후 estimateParam에 저장
|
|
const getEstimateData = async () => {
|
|
const surfaces = canvas.getObjects().filter((obj) => obj.name === POLYGON_TYPE.MODULE_SETUP_SURFACE)
|
|
//surfaces.pcses들을 배열로 묶는다
|
|
const pcses = surfaces[0].pcses.filter((pcs) => pcs !== null && pcs !== undefined)
|
|
|
|
// surfaces.forEach((surface, index) => {
|
|
// if (index !== 0) {
|
|
// if (surface.pcses) {
|
|
// pcses.concat(surface.pcses)
|
|
// }
|
|
// }
|
|
// })
|
|
|
|
const allModules = surfaces.map((surface) => surface.modules).flat()
|
|
// 모듈 파라미터 생성
|
|
const modules = getModulesParam(allModules)
|
|
const trestles = []
|
|
//가대 파라미터 생성
|
|
surfaces.forEach((surface) => {
|
|
if (surface.quotationParam) {
|
|
trestles.push(surface.quotationParam)
|
|
}
|
|
})
|
|
|
|
// trestles 배열에서 null인 경우 제거
|
|
|
|
const dblCblTotCnt = getTotalConnectCableCnt()
|
|
const params = { trestles, pcses, modules, dblCblTotCnt }
|
|
|
|
//견적서 itemList 조회
|
|
const { data, data2, result } = await getQuotationItem(params)
|
|
|
|
if (result.resultCode === 'E') {
|
|
swalFire({ text: result.resultMsg, icon: 'error' })
|
|
clear()
|
|
setViewCircuitNumberTexts(true)
|
|
setIsGlobalLoading(false)
|
|
return
|
|
}
|
|
|
|
let itemList
|
|
if (!data || data.length === 0) {
|
|
return
|
|
}
|
|
itemList = data
|
|
|
|
//northArrangement 북면 설치 여부
|
|
const northArrangement = getNorthArrangement()
|
|
// circuitItemList의 경우는 moduleList에서 circuitId만 groupBy한다.
|
|
let circuitItemList = []
|
|
|
|
// roofSurfaceList 생성
|
|
const roofSurfaceList = surfaces.map((surface) => {
|
|
const parent = canvas.getObjects().find((obj) => obj.id === surface.parentId)
|
|
const { directionText, roofMaterial, moduleCompass, surfaceCompass } = parent
|
|
const slope = Number(roofMaterial.pitch)
|
|
const roofMaterialIndex = parent.roofMaterial.index
|
|
const { nameJp: roofMaterialIdMulti } = roofMaterial
|
|
const moduleSelection = moduleSelectionData?.roofConstructions?.find((construction) => construction.roofIndex === roofMaterialIndex)
|
|
let construction = moduleSelection?.construction
|
|
let constructSpecification = +roofSizeSet === 3 ? null : construction.constTp
|
|
let constructSpecificationMulti = +roofSizeSet === 3 ? null : construction.constTpJp
|
|
|
|
const trestle = moduleSelection?.trestle
|
|
|
|
let trestleMkrCd = +roofSizeSet === 3 ? null : trestle.trestleMkrCd
|
|
let supportMethodId = +roofSizeSet === 3 ? null : trestle.constMthdCd
|
|
let roofBaseCd = +roofSizeSet === 3 ? null : trestle.roofBaseCd
|
|
let supportMeaker = +roofSizeSet === 3 ? null : trestle.trestleMkrCdJp
|
|
let supportMethodIdMulti = +roofSizeSet === 3 ? null : trestle.constMthdCdJp
|
|
|
|
const modules = surface.modules
|
|
const moduleList = modules.map((module) => {
|
|
circuitItemList.push(module.pcsItemId)
|
|
return {
|
|
itemId: module.moduleInfo.itemId,
|
|
circuit: module.circuitNumber,
|
|
pcItemId: module.pcsItemId,
|
|
}
|
|
})
|
|
|
|
return {
|
|
roofSurfaceId: surface.id,
|
|
roofSurface: directionText.replace(/[0-9]/g, ''),
|
|
roofMaterialId: +roofSizeSet === 3 ? '陸屋根' : roofMaterial.roofMatlCd, // 육지붕의 경우 지붕재 ID 값이 없기 때문에 임의 값 지정
|
|
supportMethodId,
|
|
constructSpecification,
|
|
constructSpecificationMulti,
|
|
roofMaterialIdMulti: +roofSizeSet === 3 ? '陸屋根' : roofMaterialIdMulti,
|
|
supportMethodIdMulti,
|
|
supportMeaker,
|
|
slope: +roofSizeSet === 3 ? 0 : slope,
|
|
classType: currentAngleType === 'slope' ? '0' : '1',
|
|
angle: +roofSizeSet === 3 ? 0 : getDegreeByChon(slope),
|
|
azimuth: getAzimuth(parent),
|
|
moduleList,
|
|
}
|
|
})
|
|
|
|
// circuitItemList 중복제거
|
|
circuitItemList = circuitItemList.filter((item, index) => circuitItemList.indexOf(item) === index)
|
|
circuitItemList = getSelectedPcsItemList()
|
|
|
|
return { itemList, northArrangement, roofSurfaceList, circuitItemList }
|
|
}
|
|
|
|
// 발전 시뮬레이션 용 각도 재계산
|
|
const getAzimuth = (parent) => {
|
|
const { moduleCompass, surfaceCompass, direction } = parent
|
|
|
|
if (surfaceCompass) {
|
|
return -surfaceCompass
|
|
}
|
|
|
|
let resultAzimuth = moduleCompass
|
|
|
|
switch (direction) {
|
|
case 'south': {
|
|
return resultAzimuth
|
|
}
|
|
case 'north': {
|
|
if (resultAzimuth < 0) {
|
|
return 180 + resultAzimuth
|
|
} else if (resultAzimuth === 0) {
|
|
return 180
|
|
} else if (resultAzimuth < 180) {
|
|
return resultAzimuth - 180
|
|
} else if (resultAzimuth === 180) {
|
|
return 0
|
|
}
|
|
}
|
|
case 'west': {
|
|
if (resultAzimuth > -180 && resultAzimuth < 0) {
|
|
return 90 + resultAzimuth
|
|
} else if (resultAzimuth === 0) {
|
|
return 90 - resultAzimuth
|
|
} else if (resultAzimuth < 180) {
|
|
if (resultAzimuth > 90) {
|
|
return -180 + (resultAzimuth - 90)
|
|
}
|
|
return 180 + (resultAzimuth - 90)
|
|
} else if (resultAzimuth === 180) {
|
|
return -180 + (resultAzimuth - 90)
|
|
}
|
|
}
|
|
|
|
case 'east': {
|
|
if (resultAzimuth === 0) {
|
|
return -180 + (90 - resultAzimuth)
|
|
} else if (resultAzimuth > 0 && resultAzimuth < 180) {
|
|
return resultAzimuth - 90
|
|
} else if (resultAzimuth === 180) {
|
|
return resultAzimuth - 90
|
|
} else if (resultAzimuth > -180 && resultAzimuth < 0) {
|
|
if (resultAzimuth <= -90) {
|
|
return 180 + (90 + resultAzimuth)
|
|
}
|
|
return -180 + (90 + resultAzimuth)
|
|
}
|
|
}
|
|
}
|
|
|
|
return 0
|
|
}
|
|
|
|
// 북면설치가 한개라도 되어있는지 확인
|
|
const getNorthArrangement = () => {
|
|
const surfaces = canvas.getObjects().filter((obj) => obj.name === POLYGON_TYPE.MODULE_SETUP_SURFACE)
|
|
let northArrangement = '0'
|
|
|
|
surfaces.forEach((surface) => {
|
|
const parent = canvas.getObjects().find((obj) => obj.id === surface.parentId)
|
|
const directionText = parent.directionText
|
|
// ['西北西','東北東'] 의 경우를 제외하고는 北이 들어간 경우 전부 북면으로 간주
|
|
if (directionText.includes('北') && !directionText.includes('西北西') && !directionText.includes('東北東')) {
|
|
if (surface.modules.length > 0) {
|
|
northArrangement = '1'
|
|
}
|
|
}
|
|
})
|
|
|
|
return northArrangement
|
|
}
|
|
|
|
// 다음 윗 모듈을 찾는다.
|
|
const findNextModule = (currentPoint, centerPoints, direction) => {
|
|
let { x, y, horizontal, vertical } = { ...currentPoint }
|
|
let { widthArr, heightArr } = centerPoints[0]
|
|
|
|
let width = widthArr.reduce((acc, num) => acc + num, 0) / widthArr.length + horizontal
|
|
let height = heightArr.reduce((acc, num) => acc + num, 0) / heightArr.length + vertical
|
|
|
|
let maxX = MODULE_MARGIN
|
|
let maxY = MODULE_MARGIN
|
|
|
|
let result
|
|
switch (direction) {
|
|
case 'south': {
|
|
heightArr.forEach((height) => {
|
|
if (result) return
|
|
result = centerPoints.find((centerPoint) => Math.abs(centerPoint.x - x) < maxX && Math.abs(centerPoint.y - (y - height)) < maxY)
|
|
})
|
|
|
|
break
|
|
}
|
|
case 'north': {
|
|
heightArr.forEach((height) => {
|
|
if (result) return
|
|
result = centerPoints.find((centerPoint) => Math.abs(centerPoint.x - x) < maxX && Math.abs(centerPoint.y - (y + height)) < maxY)
|
|
})
|
|
break
|
|
}
|
|
case 'east': {
|
|
widthArr.forEach((width) => {
|
|
if (result) return
|
|
result = centerPoints.find((centerPoint) => Math.abs(centerPoint.x - (x - width)) < maxX && Math.abs(centerPoint.y - y) < maxY)
|
|
})
|
|
break
|
|
}
|
|
case 'west': {
|
|
widthArr.forEach((width) => {
|
|
if (result) return
|
|
result = centerPoints.find((centerPoint) => Math.abs(centerPoint.x - (x + width)) < maxX && Math.abs(centerPoint.y - y) < maxY)
|
|
})
|
|
break
|
|
}
|
|
}
|
|
|
|
return result
|
|
}
|
|
|
|
// 다음 왼쪽 모듈을 찾는다.
|
|
const findNextLeftModule = (currentPoint, centerPoints, direction) => {
|
|
let { x, y, horizontal, vertical } = { ...currentPoint }
|
|
let { widthArr, heightArr } = centerPoints[0]
|
|
|
|
let width = widthArr.reduce((acc, num) => acc + num, 0) / widthArr.length + horizontal
|
|
let height = heightArr.reduce((acc, num) => acc + num, 0) / heightArr.length + vertical
|
|
|
|
let result
|
|
let topLeftPoint
|
|
let maxX = MODULE_MARGIN
|
|
let maxY = MODULE_MARGIN
|
|
|
|
switch (direction) {
|
|
case 'south': {
|
|
width = width + horizontal
|
|
height = height + vertical
|
|
heightArr.forEach((h) => {
|
|
topLeftPoint = { x: x - width / 2, y: y - h }
|
|
if (result) return
|
|
result = centerPoints.find(
|
|
(centerPoint) => Math.abs(centerPoint.x - topLeftPoint.x) < maxX && Math.abs(centerPoint.y - topLeftPoint.y) < maxY,
|
|
)
|
|
})
|
|
|
|
break
|
|
}
|
|
case 'north': {
|
|
width = width + horizontal
|
|
height = height + vertical
|
|
heightArr.forEach((h) => {
|
|
topLeftPoint = { x: x + width / 2, y: y + h }
|
|
if (result) return
|
|
result = centerPoints.find(
|
|
(centerPoint) => Math.abs(centerPoint.x - topLeftPoint.x) < maxX && Math.abs(centerPoint.y - topLeftPoint.y) < maxY,
|
|
)
|
|
})
|
|
break
|
|
}
|
|
case 'east': {
|
|
widthArr.forEach((w) => {
|
|
topLeftPoint = { x: x - w, y: y + height / 2 }
|
|
if (result) return
|
|
result = centerPoints.find(
|
|
(centerPoint) => Math.abs(centerPoint.x - topLeftPoint.x) < maxX && Math.abs(centerPoint.y - topLeftPoint.y) < maxY,
|
|
)
|
|
})
|
|
|
|
break
|
|
}
|
|
case 'west': {
|
|
widthArr.forEach((w) => {
|
|
topLeftPoint = { x: x + w, y: y - height / 2 }
|
|
if (result) return
|
|
result = centerPoints.find(
|
|
(centerPoint) => Math.abs(centerPoint.x - topLeftPoint.x) < maxX && Math.abs(centerPoint.y - topLeftPoint.y) < maxY,
|
|
)
|
|
})
|
|
break
|
|
}
|
|
}
|
|
|
|
return result
|
|
}
|
|
|
|
// 다음 오른쪽 모듈을 찾는다.
|
|
const findNextRightModule = (currentPoint, centerPoints, direction) => {
|
|
let { x, y, horizontal, vertical } = { ...currentPoint }
|
|
let { widthArr, heightArr } = centerPoints[0]
|
|
|
|
let width = widthArr.reduce((acc, num) => acc + num, 0) / widthArr.length + horizontal
|
|
let height = heightArr.reduce((acc, num) => acc + num, 0) / heightArr.length + vertical
|
|
let result
|
|
let topRightPoint
|
|
|
|
let maxX = MODULE_MARGIN
|
|
let maxY = MODULE_MARGIN
|
|
|
|
switch (direction) {
|
|
case 'south': {
|
|
heightArr.forEach((h) => {
|
|
topRightPoint = { x: x + width / 2, y: y - h }
|
|
if (result) return
|
|
result = centerPoints.find(
|
|
(centerPoint) => Math.abs(centerPoint.x - topRightPoint.x) < maxX && Math.abs(centerPoint.y - topRightPoint.y) < maxY,
|
|
)
|
|
})
|
|
|
|
break
|
|
}
|
|
case 'north': {
|
|
heightArr.forEach((h) => {
|
|
topRightPoint = { x: x - width / 2, y: y + h }
|
|
if (result) return
|
|
result = centerPoints.find(
|
|
(centerPoint) => Math.abs(centerPoint.x - topRightPoint.x) < maxX && Math.abs(centerPoint.y - topRightPoint.y) < maxY,
|
|
)
|
|
})
|
|
break
|
|
}
|
|
case 'east': {
|
|
widthArr.forEach((w) => {
|
|
topRightPoint = { x: x - w, y: y - height / 2 }
|
|
if (result) return
|
|
result = centerPoints.find(
|
|
(centerPoint) => Math.abs(centerPoint.x - topRightPoint.x) < maxX && Math.abs(centerPoint.y - topRightPoint.y) < maxY,
|
|
)
|
|
})
|
|
break
|
|
}
|
|
case 'west': {
|
|
widthArr.forEach((w) => {
|
|
topRightPoint = { x: x + w, y: y + height / 2 }
|
|
if (result) return
|
|
result = centerPoints.find(
|
|
(centerPoint) => Math.abs(centerPoint.x - topRightPoint.x) < maxX && Math.abs(centerPoint.y - topRightPoint.y) < maxY,
|
|
)
|
|
})
|
|
break
|
|
}
|
|
}
|
|
|
|
return result
|
|
}
|
|
|
|
// rack을 그린다.
|
|
const drawRacks = (rackInfos, rackQty, rackIntvlPct, module, direction, l, rackYn) => {
|
|
const { width, height, left, top, lastX, lastY, surfaceId } = module
|
|
const surface = canvas.getObjects().find((obj) => obj.id === surfaceId)
|
|
if (!rackInfos) {
|
|
const maxRows = surface.trestleDetail.moduleMaxRows
|
|
const maxCols = surface.trestleDetail.moduleMaxCols
|
|
const msg = `段数の上限は${maxRows}段です。 上限より上の段には設置できません`
|
|
swalFire({ title: msg, type: 'alert' })
|
|
throw new Error('rackInfos is null')
|
|
}
|
|
|
|
const roof = canvas.getObjects().find((obj) => obj.id === surface.parentId)
|
|
const degree = getDegreeByChon(roof.roofMaterial.pitch)
|
|
rackIntvlPct = rackIntvlPct === 0 ? 1 : rackIntvlPct // 0인 경우 1로 변경
|
|
rackIntvlPct = 100 / rackIntvlPct // 퍼센트로 변경
|
|
const moduleLeft = lastX ?? left
|
|
const moduleTop = lastY ?? top
|
|
|
|
let startPointX, startPointY
|
|
|
|
switch (l) {
|
|
case 'L': {
|
|
// 왼쪽부분 시작 점
|
|
if (direction === 'south') {
|
|
startPointX = module.left + width / rackIntvlPct
|
|
startPointY = module.top + module.height
|
|
break
|
|
} else if (direction === 'east') {
|
|
startPointX = module.left + width
|
|
startPointY = module.top + height - height / rackIntvlPct
|
|
break
|
|
} else if (direction === 'west') {
|
|
startPointX = module.left
|
|
startPointY = module.top + height / rackIntvlPct
|
|
break
|
|
} else if (direction === 'north') {
|
|
startPointX = module.left + width - width / rackIntvlPct
|
|
startPointY = module.top
|
|
break
|
|
}
|
|
}
|
|
|
|
case 'R': {
|
|
// 오른쪽부분 시작 점
|
|
if (direction === 'south') {
|
|
startPointX = module.left + module.width - width / rackIntvlPct
|
|
startPointY = module.top + module.height / 2 + height / 2
|
|
break
|
|
} else if (direction === 'east') {
|
|
startPointX = module.left + width
|
|
startPointY = module.top + height / rackIntvlPct
|
|
break
|
|
} else if (direction === 'west') {
|
|
startPointX = module.left
|
|
startPointY = module.top + height - height / rackIntvlPct
|
|
break
|
|
} else if (direction === 'north') {
|
|
startPointX = module.left + width / rackIntvlPct
|
|
startPointY = module.top
|
|
break
|
|
}
|
|
}
|
|
case 'C': {
|
|
// 중간부분 시작점
|
|
if (direction === 'south') {
|
|
const x = module.left + module.width / 2
|
|
const y = module.top + module.height / 2
|
|
startPointX = x
|
|
startPointY = y + height / 2
|
|
break
|
|
} else if (direction === 'east') {
|
|
const x = module.left + width
|
|
const y = module.top + module.height / 2
|
|
startPointX = x
|
|
startPointY = y
|
|
break
|
|
} else if (direction === 'west') {
|
|
const x = module.left
|
|
const y = module.top + module.height / 2
|
|
startPointX = x
|
|
startPointY = y
|
|
break
|
|
} else if (direction === 'north') {
|
|
const x = module.left + module.width / 2
|
|
const y = module.top
|
|
startPointX = x
|
|
startPointY = y
|
|
break
|
|
}
|
|
}
|
|
}
|
|
|
|
switch (direction) {
|
|
case 'south': {
|
|
rackInfos.forEach((rackInfo) => {
|
|
const { rackLen, itemId, supFitQty, supFitIntvlPct, rackRowsCd, smartRack, smartRackYn } = rackInfo
|
|
let rackLength = getTrestleLength(rackLen, degree, surface) / 10
|
|
|
|
if (smartRackYn === 'Y') {
|
|
let smartRackId = uuidv4()
|
|
smartRack.forEach(({ seq, setRackTpCd, setRackTpLen, supFitQty }) => {
|
|
rackLength = getTrestleLength(setRackTpLen, degree, surface) / 10
|
|
if (setRackTpCd === 'RACK') {
|
|
const rack = new fabric.Line([startPointX, startPointY, startPointX, startPointY - rackLength], {
|
|
name: TRESTLE_MATERIAL.SMART_RACK,
|
|
stroke: 'red',
|
|
strokeWidth: 4,
|
|
selectable: true,
|
|
shadow: {
|
|
color: 'black', // Outline color
|
|
blur: 10,
|
|
offsetX: 0,
|
|
offsetY: 0,
|
|
},
|
|
visible: isTrestleDisplay,
|
|
parentId: module.id,
|
|
surfaceId: surface.id,
|
|
supFitQty,
|
|
supFitIntvlPct,
|
|
rackLen: rackLength,
|
|
rackRowsCd,
|
|
seq,
|
|
smartRackId,
|
|
rackId: itemId,
|
|
direction: 'top',
|
|
})
|
|
startPointY -= rackLength + 8
|
|
canvas.add(rack)
|
|
canvas.renderAll()
|
|
} else if (setRackTpCd === 'INTVL') {
|
|
startPointY -= rackLength
|
|
}
|
|
})
|
|
} else {
|
|
const rack = new fabric.Line([startPointX, startPointY, startPointX, startPointY - rackLength], {
|
|
name: TRESTLE_MATERIAL.RACK,
|
|
stroke: 'red',
|
|
strokeWidth: 4,
|
|
selectable: false,
|
|
fill: 'red',
|
|
shadow: {
|
|
color: 'black', // Outline color
|
|
blur: 10,
|
|
offsetX: 0,
|
|
offsetY: 0,
|
|
},
|
|
parentId: module.id,
|
|
surfaceId: surface.id,
|
|
visible: isTrestleDisplay,
|
|
supFitQty,
|
|
supFitIntvlPct,
|
|
rackLen,
|
|
rackRowsCd,
|
|
rackId: itemId,
|
|
direction: 'top',
|
|
})
|
|
|
|
canvas.add(rack)
|
|
canvas.renderAll()
|
|
}
|
|
|
|
startPointY -= rackLength + 8
|
|
})
|
|
|
|
break
|
|
}
|
|
case 'east': {
|
|
rackInfos.forEach((rackInfo) => {
|
|
const { rackLen, itemId, supFitQty, supFitIntvlPct, rackRowsCd, smartRack, smartRackYn } = rackInfo
|
|
|
|
let rackLength = getTrestleLength(rackLen, degree, surface) / 10
|
|
if (smartRackYn === 'Y') {
|
|
let smartRackId = uuidv4()
|
|
smartRack.forEach(({ seq, setRackTpCd, setRackTpLen, supFitQty }) => {
|
|
rackLength = getTrestleLength(setRackTpLen, degree, surface) / 10
|
|
if (setRackTpCd === 'RACK') {
|
|
const rack = new fabric.Line([startPointX, startPointY, startPointX - rackLength, startPointY], {
|
|
name: TRESTLE_MATERIAL.SMART_RACK,
|
|
stroke: 'red',
|
|
strokeWidth: 4,
|
|
selectable: false,
|
|
shadow: {
|
|
color: 'black', // Outline color
|
|
blur: 10,
|
|
offsetX: 0,
|
|
offsetY: 0,
|
|
},
|
|
parentId: module.id,
|
|
surfaceId: surface.id,
|
|
visible: isTrestleDisplay,
|
|
supFitQty,
|
|
supFitIntvlPct,
|
|
rackLen: rackLength,
|
|
rackRowsCd,
|
|
seq,
|
|
smartRackId,
|
|
rackId: itemId,
|
|
direction: 'left',
|
|
})
|
|
startPointX -= rackLength + 8
|
|
canvas.add(rack)
|
|
canvas.renderAll()
|
|
} else if (setRackTpCd === 'INTVL') {
|
|
startPointX -= rackLength
|
|
}
|
|
})
|
|
} else {
|
|
const rack = new fabric.Line([startPointX, startPointY, startPointX - rackLength, startPointY], {
|
|
name: TRESTLE_MATERIAL.RACK,
|
|
stroke: 'red',
|
|
shadow: {
|
|
color: 'black', // Outline color
|
|
blur: 10,
|
|
offsetX: 0,
|
|
offsetY: 0,
|
|
},
|
|
parentId: module.id,
|
|
surfaceId: surface.id,
|
|
strokeWidth: 4,
|
|
selectable: false,
|
|
visible: isTrestleDisplay,
|
|
supFitQty,
|
|
supFitIntvlPct,
|
|
rackLen,
|
|
rackYn,
|
|
rackRowsCd,
|
|
rackId: itemId,
|
|
direction: 'left',
|
|
})
|
|
|
|
canvas.add(rack)
|
|
canvas.renderAll()
|
|
}
|
|
|
|
startPointX -= rackLength + 8
|
|
})
|
|
break
|
|
}
|
|
|
|
case 'west': {
|
|
rackInfos.forEach((rackInfo) => {
|
|
const { rackLen, itemId, supFitQty, supFitIntvlPct, rackRowsCd, smartRack, smartRackYn } = rackInfo
|
|
let rackLength = getTrestleLength(rackLen, degree, surface) / 10
|
|
if (smartRackYn === 'Y') {
|
|
let smartRackId = uuidv4()
|
|
smartRack.forEach(({ seq, setRackTpCd, setRackTpLen, supFitQty }) => {
|
|
rackLength = getTrestleLength(setRackTpLen, degree, surface) / 10
|
|
if (setRackTpCd === 'RACK') {
|
|
const rack = new fabric.Line([startPointX, startPointY, startPointX + rackLength, startPointY], {
|
|
name: TRESTLE_MATERIAL.SMART_RACK,
|
|
stroke: 'red',
|
|
strokeWidth: 4,
|
|
selectable: false,
|
|
shadow: {
|
|
color: 'black', // Outline color
|
|
blur: 10,
|
|
offsetX: 0,
|
|
offsetY: 0,
|
|
},
|
|
parentId: module.id,
|
|
surfaceId: surface.id,
|
|
visible: isTrestleDisplay,
|
|
supFitQty,
|
|
supFitIntvlPct,
|
|
rackLen: rackLength,
|
|
rackRowsCd,
|
|
seq,
|
|
smartRackId,
|
|
rackId: itemId,
|
|
direction: 'right',
|
|
})
|
|
startPointX += rackLength + 8
|
|
canvas.add(rack)
|
|
canvas.renderAll()
|
|
} else if (setRackTpCd === 'INTVL') {
|
|
startPointX += rackLength
|
|
}
|
|
})
|
|
} else {
|
|
const rack = new fabric.Line([startPointX, startPointY, startPointX + rackLength, startPointY], {
|
|
name: TRESTLE_MATERIAL.RACK,
|
|
stroke: 'red',
|
|
shadow: {
|
|
color: 'black', // Outline color
|
|
blur: 10,
|
|
offsetX: 0,
|
|
offsetY: 0,
|
|
},
|
|
parentId: module.id,
|
|
surfaceId: surface.id,
|
|
visible: isTrestleDisplay,
|
|
strokeWidth: 4,
|
|
selectable: false,
|
|
supFitQty,
|
|
supFitIntvlPct,
|
|
rackLen,
|
|
rackRowsCd,
|
|
rackId: itemId,
|
|
direction: 'right',
|
|
})
|
|
|
|
canvas.add(rack)
|
|
canvas.renderAll()
|
|
}
|
|
|
|
startPointX += rackLength + 8
|
|
})
|
|
break
|
|
}
|
|
case 'north': {
|
|
rackInfos.forEach((rackInfo) => {
|
|
const { rackLen, itemId, supFitQty, supFitIntvlPct, rackRowsCd, smartRack, smartRackYn } = rackInfo
|
|
let rackLength = getTrestleLength(rackLen, degree, surface) / 10
|
|
if (smartRackYn === 'Y') {
|
|
let smartRackId = uuidv4()
|
|
smartRack.forEach(({ seq, setRackTpCd, setRackTpLen, supFitQty }) => {
|
|
rackLength = getTrestleLength(setRackTpLen, degree, surface) / 10
|
|
if (setRackTpCd === 'RACK') {
|
|
const rack = new fabric.Line([startPointX, startPointY, startPointX, startPointY + rackLength], {
|
|
name: TRESTLE_MATERIAL.SMART_RACK,
|
|
stroke: 'red',
|
|
strokeWidth: 4,
|
|
selectable: false,
|
|
shadow: {
|
|
color: 'black', // Outline color
|
|
blur: 10,
|
|
offsetX: 0,
|
|
offsetY: 0,
|
|
},
|
|
parentId: module.id,
|
|
surfaceId: surface.id,
|
|
visible: isTrestleDisplay,
|
|
supFitQty,
|
|
supFitIntvlPct,
|
|
rackLen,
|
|
rackRowsCd,
|
|
seq,
|
|
smartRackId,
|
|
rackId: itemId,
|
|
direction: 'bottom',
|
|
})
|
|
canvas.add(rack)
|
|
canvas.renderAll()
|
|
startPointY += rackLength + 8
|
|
} else if (setRackTpCd === 'INTVL') {
|
|
startPointY += rackLength
|
|
}
|
|
})
|
|
} else {
|
|
const rack = new fabric.Line([startPointX, startPointY, startPointX, startPointY + rackLength], {
|
|
name: TRESTLE_MATERIAL.RACK,
|
|
stroke: 'red',
|
|
shadow: {
|
|
color: 'black', // Outline color
|
|
blur: 10,
|
|
offsetX: 0,
|
|
offsetY: 0,
|
|
},
|
|
parentId: module.id,
|
|
surfaceId: surface.id,
|
|
visible: isTrestleDisplay,
|
|
strokeWidth: 4,
|
|
selectable: false,
|
|
supFitQty,
|
|
supFitIntvlPct,
|
|
rackLen,
|
|
rackRowsCd,
|
|
rackId: itemId,
|
|
direction: 'bottom',
|
|
})
|
|
|
|
canvas.add(rack)
|
|
canvas.renderAll()
|
|
}
|
|
startPointY += rackLength + 8
|
|
})
|
|
break
|
|
}
|
|
}
|
|
}
|
|
|
|
//파라미터로 받은 배치면의 rack을 가지고 지지금구를 그린다.
|
|
const installBracket = (surface) => {
|
|
const modules = surface.modules
|
|
const racks = []
|
|
modules.forEach((module) => {
|
|
canvas
|
|
.getObjects()
|
|
.filter((obj) => obj.name === 'rack' || obj.name === 'smartRack')
|
|
.forEach((rack) => {
|
|
if (rack.parentId === module.id) {
|
|
canvas.remove(canvas.getObjects().filter((obj) => obj.name === 'bracket' && obj.parentId === rack.id))
|
|
racks.push(rack)
|
|
}
|
|
})
|
|
})
|
|
|
|
canvas.renderAll()
|
|
|
|
racks.forEach((rack) => {
|
|
let { x1, y1, x2, y2, direction, supFitQty, supFitIntvlPct, rackLen, name } = rack
|
|
|
|
const bracketLength = 10
|
|
|
|
if (direction === 'top') {
|
|
const result = getBracketPoints(supFitQty, supFitIntvlPct)
|
|
result.forEach((percent) => {
|
|
const len = name === 'smartRack' ? y2 - (y2 - y1) * percent - bracketLength / 2 : y2 - (y2 - y1) * percent - bracketLength / 2
|
|
const bracket = new fabric.Rect({
|
|
left: x2 - bracketLength / 3,
|
|
top: len,
|
|
fill: 'green',
|
|
name: TRESTLE_MATERIAL.BRACKET,
|
|
parentId: rack.parentId,
|
|
visible: isTrestleDisplay,
|
|
surfaceId: surface.id,
|
|
width: bracketLength,
|
|
height: bracketLength,
|
|
selectable: false,
|
|
})
|
|
|
|
canvas.add(bracket)
|
|
})
|
|
canvas.renderAll()
|
|
} else if (direction === 'left') {
|
|
const result = getBracketPoints(supFitQty, supFitIntvlPct)
|
|
|
|
result.forEach((percent) => {
|
|
const len =
|
|
name === 'smartRack' ? x1 - Math.abs(x2 - x1) * percent - bracketLength / 2 : x1 - Math.abs(x2 - x1) * percent - bracketLength / 2
|
|
const bracket = new fabric.Rect({
|
|
left: len,
|
|
top: y2 - bracketLength / 3,
|
|
fill: 'green',
|
|
name: TRESTLE_MATERIAL.BRACKET,
|
|
parentId: rack.parentId,
|
|
visible: isTrestleDisplay,
|
|
surfaceId: surface.id,
|
|
width: bracketLength,
|
|
height: bracketLength,
|
|
selectable: false,
|
|
})
|
|
|
|
canvas.add(bracket)
|
|
})
|
|
canvas.renderAll()
|
|
} else if (direction === 'right') {
|
|
const result = getBracketPoints(supFitQty, supFitIntvlPct)
|
|
|
|
result.forEach((percent) => {
|
|
const len =
|
|
name === 'smartRack' ? x2 - Math.abs(x2 - x1) * percent - bracketLength / 2 : x2 - Math.abs(x2 - x1) * percent - bracketLength / 2
|
|
const bracket = new fabric.Rect({
|
|
left: len,
|
|
top: y2 - bracketLength / 3,
|
|
fill: 'green',
|
|
parentId: rack.parentId,
|
|
visible: isTrestleDisplay,
|
|
surfaceId: surface.id,
|
|
name: TRESTLE_MATERIAL.BRACKET,
|
|
width: bracketLength,
|
|
height: bracketLength,
|
|
selectable: false,
|
|
})
|
|
|
|
canvas.add(bracket)
|
|
})
|
|
canvas.renderAll()
|
|
} else if (direction === 'bottom') {
|
|
const result = getBracketPoints(supFitQty, supFitIntvlPct)
|
|
|
|
result.forEach((percent) => {
|
|
const len = name === 'smartRack' ? y2 - (y2 - y1) * percent - bracketLength / 2 : y2 - (y2 - y1) * percent - bracketLength / 2
|
|
const bracket = new fabric.Rect({
|
|
left: x2 - bracketLength / 3,
|
|
top: len,
|
|
fill: 'green',
|
|
name: TRESTLE_MATERIAL.BRACKET,
|
|
parentId: rack.parentId,
|
|
visible: isTrestleDisplay,
|
|
surfaceId: surface.id,
|
|
width: bracketLength,
|
|
height: bracketLength,
|
|
selectable: false,
|
|
})
|
|
|
|
canvas.add(bracket)
|
|
})
|
|
canvas.renderAll()
|
|
}
|
|
})
|
|
}
|
|
|
|
//랙 없음 인 경우 지지금구 설치
|
|
const installBracketWithOutRack = (surface, exposedBottomModules, leftExposedHalfBottomModules, rightExposedHalfBottomPoints, isChidory) => {
|
|
let { rackQty, rackIntvlPct, moduleIntvlHor, moduleIntvlVer, lessSupFitQty, lessSupFitIntvlPct, moduleMaxRows } = surface.trestleDetail
|
|
let checkList = []
|
|
|
|
exposedBottomModules.forEach((module) => {
|
|
checkList.push(module.leftRows, module.rightRows, module.centerRows)
|
|
})
|
|
|
|
leftExposedHalfBottomModules.forEach((module) => {
|
|
checkList.push(module.leftRows, module.rightRows, module.centerRows)
|
|
})
|
|
|
|
rightExposedHalfBottomPoints.forEach((module) => {
|
|
checkList.push(module.leftRows, module.rightRows, module.centerRows)
|
|
})
|
|
|
|
checkList = checkList.filter((item) => item !== undefined && item !== null)
|
|
|
|
const isAllCheckMaxRows = checkList.every((item) => item <= moduleMaxRows)
|
|
|
|
if (!isAllCheckMaxRows) {
|
|
const msg = `段数の上限は${moduleMaxRows}段です。 上限より上の段には設置できません`
|
|
swalFire({ title: msg, type: 'alert' })
|
|
throw new Error('moduleMaxRows exceeded')
|
|
}
|
|
|
|
rackQty = lessSupFitQty
|
|
rackIntvlPct = lessSupFitIntvlPct
|
|
const direction = surface.direction
|
|
|
|
canvas.renderAll()
|
|
exposedBottomModules.forEach((module) => {
|
|
drawBracketWithOutRack(module, rackIntvlPct, module.leftRows + 1, 'L', surface.direction, moduleIntvlHor, moduleIntvlVer)
|
|
drawBracketWithOutRack(module, rackIntvlPct, module.rightRows + 1, 'R', surface.direction, moduleIntvlHor, moduleIntvlVer)
|
|
if (!isChidory && rackQty === 3) {
|
|
// 치도리가 아니면서 갯수가 3개인 경우 센터도 설치 필요함
|
|
drawBracketWithOutRack(module, rackIntvlPct, module.centerRows + 1, 'C', surface.direction, moduleIntvlHor, moduleIntvlVer)
|
|
}
|
|
|
|
if (isChidory && rackQty === 3) {
|
|
drawBracketWithOutRack(module, rackIntvlPct / 3, module.leftRows + 1, 'L', surface.direction, moduleIntvlHor, moduleIntvlVer)
|
|
}
|
|
if (rackQty === 4) {
|
|
drawBracketWithOutRack(module, rackIntvlPct / 3, module.leftRows + 1, 'L', surface.direction, moduleIntvlHor, moduleIntvlVer)
|
|
drawBracketWithOutRack(module, rackIntvlPct / 3, module.rightRows + 1, 'R', surface.direction, moduleIntvlHor, moduleIntvlVer)
|
|
}
|
|
|
|
if (!isChidory && rackQty === 5) {
|
|
drawBracketWithOutRack(module, rackIntvlPct / 3, module.leftRows + 1, 'L', surface.direction, moduleIntvlHor, moduleIntvlVer)
|
|
drawBracketWithOutRack(module, rackIntvlPct / 3, module.rightRows + 1, 'R', surface.direction, moduleIntvlHor, moduleIntvlVer)
|
|
drawBracketWithOutRack(module, rackIntvlPct / 3, module.rightRows + 1, 'C', surface.direction, moduleIntvlHor, moduleIntvlVer)
|
|
}
|
|
})
|
|
|
|
leftExposedHalfBottomModules.forEach((module) => {
|
|
drawBracketWithOutRack(module, rackIntvlPct, module.leftRows + 1, 'L', surface.direction, moduleIntvlHor, moduleIntvlVer)
|
|
if (rackQty === 3 && !findSamePointInBottom(exposedBottomModules, module)) {
|
|
// 해당 모듈과 같은 위치 맨 아래에 모듈이 없는 경우 하나 더 설치 필요
|
|
if (module.level % 2 !== 0) {
|
|
drawBracketWithOutRack(module, rackIntvlPct / 3, module.leftRows + 1, 'L', surface.direction, moduleIntvlHor, moduleIntvlVer)
|
|
}
|
|
}
|
|
if (rackQty === 4) {
|
|
drawBracketWithOutRack(module, rackIntvlPct / 3, module.leftRows + 1, 'L', surface.direction, moduleIntvlHor, moduleIntvlVer)
|
|
}
|
|
})
|
|
|
|
rightExposedHalfBottomPoints.forEach((module) => {
|
|
console.log('rightmodule.level', module.level)
|
|
drawBracketWithOutRack(module, rackIntvlPct, module.rightRows + 1, 'R', surface.direction, moduleIntvlHor, moduleIntvlVer)
|
|
if (rackQty === 3 && !findSamePointInBottom(exposedBottomModules, module, direction)) {
|
|
// 해당 모듈과 같은 위치 맨 아래에 모듈이 없는 경우 하나 더 설치 필요
|
|
if (module.level % 2 === 0) {
|
|
drawBracketWithOutRack(module, rackIntvlPct / 3, module.rightRows + 1, 'R', surface.direction, moduleIntvlHor, moduleIntvlVer)
|
|
}
|
|
}
|
|
if (rackQty === 4) {
|
|
drawBracketWithOutRack(module, rackIntvlPct / 3, module.rightRows + 1, 'R', surface.direction, moduleIntvlHor, moduleIntvlVer)
|
|
}
|
|
})
|
|
}
|
|
|
|
// 방향에 따라 가장 아래모듈중 같은 좌표가 있는지 확인
|
|
const findSamePointInBottom = (exposedBottomModules, module, direction) => {
|
|
const { x, y } = module.getCenterPoint()
|
|
|
|
switch (direction) {
|
|
case 'south': {
|
|
return exposedBottomModules.find((exposedBottomModule) => {
|
|
const { x: exposedX, y: exposedY } = exposedBottomModule.getCenterPoint()
|
|
return Math.abs(x - exposedX) < 2 && Math.abs(y - exposedY) > module.height
|
|
})
|
|
}
|
|
case 'north': {
|
|
return exposedBottomModules.find((exposedBottomModule) => {
|
|
const { x: exposedX, y: exposedY } = exposedBottomModule.getCenterPoint()
|
|
return Math.abs(x - exposedX) < 2 && Math.abs(y - exposedY) > module.height
|
|
})
|
|
}
|
|
case 'east': {
|
|
return exposedBottomModules.find((exposedBottomModule) => {
|
|
const { x: exposedX, y: exposedY } = exposedBottomModule.getCenterPoint()
|
|
return Math.abs(y - exposedY) < 2 && Math.abs(x - exposedX) > module.width
|
|
})
|
|
}
|
|
case 'west': {
|
|
return exposedBottomModules.find((exposedBottomModule) => {
|
|
const { x: exposedX, y: exposedY } = exposedBottomModule.getCenterPoint()
|
|
return Math.abs(y - exposedY) < 2 && Math.abs(x - exposedX) > module.width
|
|
})
|
|
}
|
|
}
|
|
}
|
|
|
|
// 랙 없음의 지지금구를 그린다.
|
|
const drawBracketWithOutRack = (module, rackIntvlPct, count, l, direction, moduleIntvlHor, moduleIntvlVer) => {
|
|
const { leftFindModuleList, rightFindModuleList, centerFindModuleList } = module
|
|
|
|
rackIntvlPct = rackIntvlPct === 0 ? 1 : rackIntvlPct // 0인 경우 1로 변경
|
|
rackIntvlPct = 100 / rackIntvlPct // 퍼센트로 변경
|
|
|
|
let { width, height, left, top } = module
|
|
let startPointX
|
|
let startPointY
|
|
|
|
switch (l) {
|
|
case 'L': {
|
|
// 왼쪽부분 시작 점
|
|
if (direction === 'south') {
|
|
startPointX = left + width / rackIntvlPct
|
|
startPointY = top + height
|
|
break
|
|
} else if (direction === 'east') {
|
|
startPointX = left + width
|
|
startPointY = top + height - height / rackIntvlPct - 10
|
|
break
|
|
} else if (direction === 'west') {
|
|
startPointX = left
|
|
startPointY = top + height / rackIntvlPct
|
|
break
|
|
} else if (direction === 'north') {
|
|
startPointX = left + width - width / rackIntvlPct - 10
|
|
startPointY = top
|
|
break
|
|
}
|
|
}
|
|
|
|
case 'R': {
|
|
// 오른쪽부분 시작 점
|
|
if (direction === 'south') {
|
|
startPointX = left + width - width / rackIntvlPct - 10
|
|
startPointY = top + height / 2 + height / 2
|
|
break
|
|
} else if (direction === 'east') {
|
|
startPointX = left + width
|
|
startPointY = top + height / rackIntvlPct
|
|
break
|
|
} else if (direction === 'west') {
|
|
startPointX = left
|
|
startPointY = top + height - height / rackIntvlPct - 10
|
|
break
|
|
} else if (direction === 'north') {
|
|
startPointX = left + width / rackIntvlPct
|
|
startPointY = top
|
|
break
|
|
}
|
|
}
|
|
case 'C': {
|
|
// 중간부분 시작점
|
|
if (direction === 'south') {
|
|
const x = left + width / 2
|
|
const y = top + height / 2
|
|
startPointX = x
|
|
startPointY = y + height / 2
|
|
break
|
|
} else if (direction === 'east') {
|
|
const x = left + width
|
|
const y = top + height / 2
|
|
startPointX = x
|
|
startPointY = y
|
|
break
|
|
} else if (direction === 'west') {
|
|
const x = left
|
|
const y = top + height / 2
|
|
startPointX = x
|
|
startPointY = y
|
|
break
|
|
} else if (direction === 'north') {
|
|
const x = left + width / 2
|
|
const y = top
|
|
startPointX = x
|
|
startPointY = y
|
|
break
|
|
}
|
|
}
|
|
}
|
|
|
|
switch (direction) {
|
|
case 'south': {
|
|
startPointY -= 5
|
|
break
|
|
}
|
|
case 'east': {
|
|
startPointX -= 5
|
|
break
|
|
}
|
|
case 'west': {
|
|
startPointX -= 5
|
|
break
|
|
}
|
|
case 'north': {
|
|
startPointY -= 5
|
|
break
|
|
}
|
|
}
|
|
|
|
for (let i = 0; i < count; i++) {
|
|
let moduleWidth, moduleHeight
|
|
|
|
switch (l) {
|
|
case 'L': {
|
|
let leftFindModule = leftFindModuleList[i]
|
|
if (!leftFindModule) {
|
|
leftFindModule = leftFindModuleList[leftFindModuleList.length - 1]
|
|
}
|
|
moduleWidth = leftFindModule.width
|
|
moduleHeight = leftFindModule.height
|
|
break
|
|
}
|
|
case 'R': {
|
|
let rightFindModule = rightFindModuleList[i]
|
|
if (!rightFindModule) {
|
|
rightFindModule = rightFindModuleList[rightFindModuleList.length - 1]
|
|
}
|
|
moduleWidth = rightFindModule.width
|
|
moduleHeight = rightFindModule.height
|
|
break
|
|
}
|
|
case 'C': {
|
|
let centerFindModule = centerFindModuleList[i]
|
|
if (!centerFindModule) {
|
|
centerFindModule = centerFindModuleList[centerFindModuleList.length - 1]
|
|
}
|
|
|
|
moduleWidth = centerFindModule.width
|
|
moduleHeight = centerFindModule.height
|
|
break
|
|
}
|
|
}
|
|
|
|
const bracket = new fabric.Rect({
|
|
left: startPointX,
|
|
top: startPointY,
|
|
fill: i === 0 || i === count - 1 ? '#D70065' : 'green',
|
|
name: TRESTLE_MATERIAL.BRACKET,
|
|
parentId: module.id,
|
|
surfaceId: module.surfaceId,
|
|
width: 10,
|
|
height: 10,
|
|
selectable: false,
|
|
visible: isTrestleDisplay,
|
|
})
|
|
canvas.add(bracket)
|
|
canvas.renderAll()
|
|
const maxIntvl = Math.max(moduleIntvlHor, moduleIntvlVer)
|
|
if (direction === 'south') {
|
|
startPointY -= moduleHeight + maxIntvl / 10
|
|
} else if (direction === 'north') {
|
|
startPointY += moduleHeight + maxIntvl / 10
|
|
} else if (direction === 'east') {
|
|
startPointX -= moduleWidth + maxIntvl / 10
|
|
} else if (direction === 'west') {
|
|
startPointX += moduleWidth + maxIntvl / 10
|
|
}
|
|
}
|
|
}
|
|
|
|
const getBracketPoints = (n, percent) => {
|
|
if (n < 2) {
|
|
return []
|
|
}
|
|
|
|
const points = []
|
|
const topY = percent / 100 // 맨 위의 점의 y 좌표 (10%)
|
|
const bottomY = 1 - percent / 100 // 맨 아래의 점의 y 좌표 (90%)
|
|
|
|
// 맨 위의 점 추가
|
|
points.push(topY)
|
|
|
|
// 중간 점들 추가
|
|
const interval = (bottomY - topY) / (n - 1)
|
|
for (let i = 1; i < n - 1; i++) {
|
|
points.push(topY + i * interval)
|
|
}
|
|
|
|
// 맨 아래의 점 추가
|
|
points.push(bottomY)
|
|
|
|
return points
|
|
}
|
|
|
|
function findTopTwoPoints(points, direction) {
|
|
switch (direction) {
|
|
case 'south':
|
|
points.sort((a, b) => b.y - a.y)
|
|
break
|
|
case 'north':
|
|
points.sort((a, b) => a.y - b.y)
|
|
break
|
|
case 'east':
|
|
points.sort((a, b) => b.x - a.x)
|
|
break
|
|
case 'west':
|
|
points.sort((a, b) => a.x - b.x)
|
|
break
|
|
}
|
|
|
|
return points.slice(0, 2)
|
|
}
|
|
|
|
const getCenterPoints = (moduleSurface) => {
|
|
const centerPoints = []
|
|
let widthArr = []
|
|
let heightArr = []
|
|
const modules = moduleSurface.modules
|
|
modules.forEach((module, index) => {
|
|
module.tempIndex = index
|
|
const { x, y } = module.getCenterPoint()
|
|
const { width, height } = { ...module }
|
|
widthArr.push(width)
|
|
heightArr.push(height)
|
|
centerPoints.push({
|
|
x,
|
|
y,
|
|
width: Math.floor(width),
|
|
height: Math.floor(height),
|
|
index,
|
|
moduleInfo: module.moduleInfo,
|
|
module,
|
|
})
|
|
})
|
|
|
|
//widthArr 중복 제거 1이상 차이가 나지 않으면 같은 너비로 간주
|
|
widthArr = removeCloseValues(Array.from(new Set(widthArr)))
|
|
heightArr = removeCloseValues(Array.from(new Set(heightArr)))
|
|
const widthAvg = widthArr.reduce((acc, num) => acc + num, 0) / widthArr.length
|
|
const heightAvg = heightArr.reduce((acc, num) => acc + num, 0) / heightArr.length
|
|
widthArr.push(widthAvg)
|
|
heightArr.push(heightAvg)
|
|
centerPoints.forEach((centerPoint, index) => {
|
|
// widthArr의 평균값을 추가한다.
|
|
|
|
centerPoint.widthArr = [...widthArr]
|
|
|
|
centerPoint.heightArr = [...heightArr]
|
|
})
|
|
|
|
function removeCloseValues(arr, threshold = 1) {
|
|
arr.sort((a, b) => a - b) // 배열을 정렬
|
|
|
|
let result = []
|
|
|
|
for (let i = 0; i < arr.length; i++) {
|
|
if (i === 0 || Math.abs(arr[i] - arr[i - 1]) >= threshold) {
|
|
result.push(arr[i])
|
|
}
|
|
}
|
|
|
|
return result
|
|
}
|
|
|
|
return centerPoints
|
|
}
|
|
|
|
const calculateForApi = (moduleSurface) => {
|
|
const centerPoints = getCenterPoints(moduleSurface)
|
|
const direction = moduleSurface.direction
|
|
const modules = moduleSurface.modules
|
|
|
|
const horizontal = ['south', 'north'].includes(direction)
|
|
? moduleSurface.trestleDetail.moduleIntvlHor
|
|
: moduleSurface.trestleDetail.moduleIntvlVer
|
|
|
|
const vertical = ['south', 'north'].includes(direction) ? moduleSurface.trestleDetail.moduleIntvlVer : moduleSurface.trestleDetail.moduleIntvlHor
|
|
|
|
const maxX = MODULE_MARGIN
|
|
const maxY = MODULE_MARGIN
|
|
|
|
if (centerPoints.length === 0) return
|
|
|
|
//완전 노출 하면
|
|
let exposedBottom = 0
|
|
// 반 노출 하면
|
|
let exposedHalfBottom = 0
|
|
// 완전 노출 상면
|
|
let exposedTop = 0
|
|
//반 노출 상면
|
|
let exposedHalfTop = 0
|
|
// 완전 접면
|
|
let touchDimension = 0
|
|
//반접면
|
|
let halfTouchDimension = 0
|
|
|
|
// 노출bottom면의 points
|
|
let exposedBottomPoints = []
|
|
|
|
// 반노출 bottom면의 points
|
|
let leftExposedHalfBottomPoints = []
|
|
let rightExposedHalfBottomPoints = []
|
|
let leftExposedHalfTopPoints = []
|
|
let rightExposedHalfTopPoints = []
|
|
|
|
centerPoints.forEach((centerPoint, index) => {
|
|
let { x, y, width, height, widthArr, heightArr, module } = { ...centerPoint }
|
|
|
|
/* 디버깅용
|
|
const originFill = module.fill
|
|
module.set('fill', 'red')
|
|
canvas.renderAll()*/
|
|
|
|
// centerPoints중에 현재 centerPoint와 x값이 같고, y값이 y-height값과 같은 centerPoint가 있는지 확인
|
|
let bottomCell
|
|
let bottomLeftPoint
|
|
let bottomRightPoint
|
|
let leftBottomCnt = 0
|
|
let rightBottomCnt = 0
|
|
|
|
switch (direction) {
|
|
case 'south':
|
|
//widthArr의 값을 전부 더한 후 widthArr의 길이로 나누어 평균값을 구한다.
|
|
width = widthArr.reduce((acc, num) => acc + num, 0) / widthArr.length + horizontal
|
|
height = heightArr.reduce((acc, num) => acc + num, 0) / heightArr.length + vertical
|
|
heightArr.forEach((h) => {
|
|
if (bottomCell) return
|
|
bottomCell = centerPoints.find((centerPoint) => Math.abs(centerPoint.x - x) < maxX && Math.abs(centerPoint.y - (y + h)) < maxY)
|
|
if (leftBottomCnt === 0) {
|
|
bottomLeftPoint = { x: x - width / 2, y: y + h }
|
|
leftBottomCnt = centerPoints.filter(
|
|
(centerPoint) => Math.abs(centerPoint.x - bottomLeftPoint.x) < maxX && Math.abs(centerPoint.y - bottomLeftPoint.y) < maxY,
|
|
).length
|
|
}
|
|
|
|
if (rightBottomCnt === 0) {
|
|
bottomRightPoint = { x: x + width / 2, y: y + h }
|
|
rightBottomCnt = centerPoints.filter(
|
|
(centerPoint) => Math.abs(centerPoint.x - bottomRightPoint.x) < maxX && Math.abs(centerPoint.y - bottomRightPoint.y) < maxY,
|
|
).length
|
|
}
|
|
})
|
|
|
|
break
|
|
case 'north':
|
|
width = widthArr.reduce((acc, num) => acc + num, 0) / widthArr.length + horizontal
|
|
height = heightArr.reduce((acc, num) => acc + num, 0) / heightArr.length + vertical
|
|
heightArr.forEach((h) => {
|
|
if (bottomCell) return
|
|
bottomCell = centerPoints.find((centerPoint) => Math.abs(centerPoint.x - x) < maxX && Math.abs(centerPoint.y - (y - h)) < maxY)
|
|
if (leftBottomCnt === 0) {
|
|
bottomLeftPoint = { x: x + width / 2, y: y - h }
|
|
leftBottomCnt = centerPoints.filter(
|
|
(centerPoint) => Math.abs(centerPoint.x - bottomLeftPoint.x) < maxX && Math.abs(centerPoint.y - bottomLeftPoint.y) < maxY,
|
|
).length
|
|
}
|
|
if (rightBottomCnt === 0) {
|
|
bottomRightPoint = { x: x - width / 2, y: y - h }
|
|
rightBottomCnt = centerPoints.filter(
|
|
(centerPoint) => Math.abs(centerPoint.x - bottomRightPoint.x) < maxX && Math.abs(centerPoint.y - bottomRightPoint.y) < maxY,
|
|
).length
|
|
}
|
|
})
|
|
break
|
|
case 'east':
|
|
widthArr.forEach((w) => {
|
|
if (bottomCell) return
|
|
bottomCell = centerPoints.find((centerPoint) => Math.abs(centerPoint.x - (x + w)) < maxX && Math.abs(centerPoint.y - y) < maxY)
|
|
if (leftBottomCnt === 0) {
|
|
bottomLeftPoint = { x: x + w, y: y + height / 2 }
|
|
leftBottomCnt = centerPoints.filter(
|
|
(centerPoint) => Math.abs(centerPoint.x - bottomLeftPoint.x) < maxX && Math.abs(centerPoint.y - bottomLeftPoint.y) < maxY,
|
|
).length
|
|
}
|
|
if (rightBottomCnt === 0) {
|
|
bottomRightPoint = { x: x + w, y: y - height / 2 }
|
|
rightBottomCnt = centerPoints.filter(
|
|
(centerPoint) => Math.abs(centerPoint.x - bottomRightPoint.x) < maxX && Math.abs(centerPoint.y - bottomRightPoint.y) < maxY,
|
|
).length
|
|
}
|
|
})
|
|
break
|
|
case 'west':
|
|
widthArr.forEach((w) => {
|
|
if (bottomCell) return
|
|
bottomCell = centerPoints.find((centerPoint) => Math.abs(centerPoint.x - (x - w)) < maxX && Math.abs(centerPoint.y - y) < maxY)
|
|
if (leftBottomCnt === 0) {
|
|
bottomLeftPoint = { x: x - w, y: y - height / 2 }
|
|
leftBottomCnt = centerPoints.filter(
|
|
(centerPoint) => Math.abs(centerPoint.x - bottomLeftPoint.x) < maxX && Math.abs(centerPoint.y - bottomLeftPoint.y) < maxY,
|
|
).length
|
|
}
|
|
if (rightBottomCnt === 0) {
|
|
bottomRightPoint = { x: x - w, y: y + height / 2 }
|
|
rightBottomCnt = centerPoints.filter(
|
|
(centerPoint) => Math.abs(centerPoint.x - bottomRightPoint.x) < maxX && Math.abs(centerPoint.y - bottomRightPoint.y) < maxY,
|
|
).length
|
|
}
|
|
})
|
|
|
|
break
|
|
}
|
|
/**
|
|
* 디버깅용
|
|
|
|
module.set('fill', originFill)
|
|
canvas.renderAll()
|
|
*/
|
|
if (bottomCell) {
|
|
return
|
|
}
|
|
|
|
// 바로 아래에 셀이 없는 경우 물떼세 배치가 왼쪽 되어있는 셀을 찾는다.
|
|
|
|
if (leftBottomCnt + rightBottomCnt === 1) {
|
|
exposedHalfBottom++
|
|
if (leftBottomCnt === 1) {
|
|
rightExposedHalfBottomPoints.push(centerPoint)
|
|
}
|
|
if (rightBottomCnt === 1) {
|
|
leftExposedHalfBottomPoints.push(centerPoint)
|
|
}
|
|
} else if (leftBottomCnt + rightBottomCnt === 0) {
|
|
exposedBottomPoints.push(centerPoint)
|
|
} else if (leftBottomCnt + rightBottomCnt === 2) {
|
|
touchDimension++
|
|
}
|
|
})
|
|
// 노출상면 및 접면 체크
|
|
|
|
centerPoints.forEach((centerPoint, index) => {
|
|
let { x, y, width, height, widthArr, heightArr, module } = { ...centerPoint }
|
|
const originFill = module.fill
|
|
/* 디버깅용
|
|
module.set('fill', 'blue')
|
|
canvas.renderAll()*/
|
|
let topCell
|
|
let topLeftPoint
|
|
let topRightPoint
|
|
let leftTopCnt = 0
|
|
let rightTopCnt = 0
|
|
|
|
switch (direction) {
|
|
case 'south':
|
|
width = width + horizontal
|
|
height = height + vertical
|
|
heightArr.forEach((h) => {
|
|
if (topCell) return
|
|
topCell = centerPoints.find((centerPoint) => Math.abs(centerPoint.x - x) < maxX && Math.abs(centerPoint.y - (y - h)) < maxY)
|
|
|
|
if (leftTopCnt === 0) {
|
|
topLeftPoint = { x: x - width / 2, y: y - h }
|
|
leftTopCnt = centerPoints.filter(
|
|
(centerPoint) => Math.abs(centerPoint.x - topLeftPoint.x) < maxX && Math.abs(centerPoint.y - topLeftPoint.y) < maxY,
|
|
).length
|
|
}
|
|
if (rightTopCnt === 0) {
|
|
topRightPoint = { x: x + width / 2, y: y - h }
|
|
rightTopCnt = centerPoints.filter(
|
|
(centerPoint) => Math.abs(centerPoint.x - topRightPoint.x) < maxX && Math.abs(centerPoint.y - topRightPoint.y) < maxY,
|
|
).length
|
|
}
|
|
})
|
|
break
|
|
case 'north':
|
|
height = height + vertical
|
|
heightArr.forEach((h) => {
|
|
if (topCell) return
|
|
topCell = centerPoints.find((centerPoint) => Math.abs(centerPoint.x - x) < maxX && Math.abs(centerPoint.y - (y + h)) < maxY)
|
|
if (leftTopCnt === 0) {
|
|
topLeftPoint = { x: x + width / 2, y: y + h }
|
|
leftTopCnt = centerPoints.filter(
|
|
(centerPoint) => Math.abs(centerPoint.x - topLeftPoint.x) < maxX && Math.abs(centerPoint.y - topLeftPoint.y) < maxY,
|
|
).length
|
|
}
|
|
if (rightTopCnt === 0) {
|
|
topRightPoint = { x: x - width / 2, y: y + h }
|
|
rightTopCnt = centerPoints.filter(
|
|
(centerPoint) => Math.abs(centerPoint.x - topRightPoint.x) < maxX && Math.abs(centerPoint.y - topRightPoint.y) < maxY,
|
|
).length
|
|
}
|
|
})
|
|
break
|
|
case 'east':
|
|
width = width + horizontal
|
|
widthArr.forEach((w) => {
|
|
if (topCell) return
|
|
topCell = centerPoints.find((centerPoint) => Math.abs(centerPoint.x - (x - w)) < maxX && Math.abs(centerPoint.y - y) < maxY)
|
|
if (leftTopCnt === 0) {
|
|
topLeftPoint = { x: x - w, y: y + height / 2 }
|
|
leftTopCnt = centerPoints.filter(
|
|
(centerPoint) => Math.abs(centerPoint.x - topLeftPoint.x) < maxX && Math.abs(centerPoint.y - topLeftPoint.y) < maxY,
|
|
).length
|
|
}
|
|
|
|
if (rightTopCnt === 0) {
|
|
topRightPoint = { x: x - w, y: y - height / 2 }
|
|
rightTopCnt = centerPoints.filter(
|
|
(centerPoint) => Math.abs(centerPoint.x - topRightPoint.x) < maxX && Math.abs(centerPoint.y - topRightPoint.y) < maxY,
|
|
).length
|
|
}
|
|
})
|
|
break
|
|
case 'west':
|
|
width = width + horizontal
|
|
widthArr.forEach((w) => {
|
|
if (topCell) return
|
|
topCell = centerPoints.find((centerPoint) => Math.abs(centerPoint.x - (x + w)) < maxX && Math.abs(centerPoint.y - y) < maxY)
|
|
if (leftTopCnt === 0) {
|
|
topLeftPoint = { x: x + w, y: y - height / 2 }
|
|
leftTopCnt = centerPoints.filter(
|
|
(centerPoint) => Math.abs(centerPoint.x - topLeftPoint.x) < maxX && Math.abs(centerPoint.y - topLeftPoint.y) < maxY,
|
|
).length
|
|
}
|
|
if (rightTopCnt === 0) {
|
|
topRightPoint = { x: x + w, y: y + height / 2 }
|
|
rightTopCnt = centerPoints.filter(
|
|
(centerPoint) => Math.abs(centerPoint.x - topRightPoint.x) < maxX && Math.abs(centerPoint.y - topRightPoint.y) < maxY,
|
|
).length
|
|
}
|
|
})
|
|
break
|
|
}
|
|
|
|
if (topCell) {
|
|
touchDimension++
|
|
return
|
|
}
|
|
|
|
/**
|
|
* 디버깅 용
|
|
|
|
module.set('fill', originFill)
|
|
canvas.renderAll()
|
|
*/
|
|
|
|
if (leftTopCnt + rightTopCnt === 2) {
|
|
touchDimension++
|
|
return
|
|
}
|
|
|
|
if (leftTopCnt + rightTopCnt === 1) {
|
|
exposedHalfTop++
|
|
halfTouchDimension++
|
|
if (leftTopCnt === 1) {
|
|
rightExposedHalfTopPoints.push(centerPoint)
|
|
}
|
|
if (rightTopCnt === 1) {
|
|
leftExposedHalfTopPoints.push(centerPoint)
|
|
}
|
|
return
|
|
}
|
|
if (leftTopCnt + rightTopCnt === 0) {
|
|
exposedTop++
|
|
}
|
|
})
|
|
// 완전 노출 하면 계산
|
|
|
|
const groupPoints = groupCoordinates(centerPoints, modules[0], direction)
|
|
|
|
groupPoints.forEach((group) => {
|
|
let maxY = group.reduce((acc, cur) => (acc.y > cur.y ? acc : cur)).y
|
|
let minY = group.reduce((acc, cur) => (acc.y < cur.y ? acc : cur)).y
|
|
let maxX = group.reduce((acc, cur) => (acc.x > cur.x ? acc : cur)).x
|
|
let minX = group.reduce((acc, cur) => (acc.x < cur.x ? acc : cur)).x
|
|
|
|
let maxYCenterPoints = group.filter((centerPoint) => Math.abs(centerPoint.y - maxY) < 2)
|
|
let minYCenterPoints = group.filter((centerPoint) => Math.abs(centerPoint.y - minY) < 2)
|
|
let maxXCenterPoints = group.filter((centerPoint) => Math.abs(centerPoint.x - maxX) < 2)
|
|
let minXCenterPoints = group.filter((centerPoint) => Math.abs(centerPoint.x - minX) < 2)
|
|
|
|
switch (direction) {
|
|
case 'south':
|
|
exposedBottom += maxYCenterPoints.length
|
|
break
|
|
case 'north':
|
|
exposedBottom += minYCenterPoints.length
|
|
break
|
|
case 'east':
|
|
exposedBottom += maxXCenterPoints.length
|
|
break
|
|
case 'west':
|
|
exposedBottom += minXCenterPoints.length
|
|
break
|
|
}
|
|
})
|
|
|
|
return {
|
|
exposedBottom,
|
|
exposedHalfBottom,
|
|
exposedTop,
|
|
exposedHalfTop,
|
|
touchDimension,
|
|
halfTouchDimension,
|
|
exposedBottomPoints,
|
|
leftExposedHalfBottomPoints,
|
|
rightExposedHalfBottomPoints,
|
|
leftExposedHalfTopPoints,
|
|
rightExposedHalfTopPoints,
|
|
centerPoints,
|
|
}
|
|
}
|
|
|
|
// polygon 내부 cell들의 centerPoint 배열을 그룹화 해서 반환
|
|
const groupCoordinates = (points, moduleExample, direction) => {
|
|
const groups = []
|
|
const visited = new Set()
|
|
const width = Math.floor(moduleExample.width)
|
|
const height = Math.floor(moduleExample.height)
|
|
const horizonPadding = 3 // 가로 패딩
|
|
const verticalPadding = 7 // 세로 패딩
|
|
|
|
function isAdjacent(p1, p2) {
|
|
const dx = Math.abs(p1.x - p2.x)
|
|
const dy = Math.abs(p1.y - p2.y)
|
|
|
|
return (
|
|
(Math.abs(width + horizonPadding - dx) < 2 && dy < 2) ||
|
|
(dx < 2 && Math.abs(dy - height + verticalPadding)) < 2 ||
|
|
(Math.abs(dx - width / 2 + horizonPadding / 2) < 2 && Math.abs(dy - height + verticalPadding) < 2)
|
|
)
|
|
}
|
|
|
|
function dfs(point, group) {
|
|
visited.add(`${point.x},${point.y}`)
|
|
group.push(point)
|
|
|
|
for (const nextPoint of points) {
|
|
const key = `${nextPoint.x},${nextPoint.y}`
|
|
if (!visited.has(key) && isAdjacent(point, nextPoint)) {
|
|
dfs(nextPoint, group)
|
|
}
|
|
}
|
|
}
|
|
|
|
for (const point of points) {
|
|
const key = `${point.x},${point.y}`
|
|
if (!visited.has(key)) {
|
|
const group = []
|
|
dfs(point, group)
|
|
groups.push(group)
|
|
}
|
|
}
|
|
|
|
return groups
|
|
}
|
|
|
|
function areConnected(m1, m2, surface) {
|
|
/*const m1Fill = m1.fill
|
|
const m2Fill = m2.fill
|
|
m1.set({ fill: 'red' })
|
|
m2.set({ fill: 'blue' })
|
|
canvas.renderAll()*/
|
|
|
|
let sizes = []
|
|
|
|
const { width: currentWidth, height: currentHeight, moduleInfo: currentModuleInfo } = m1
|
|
const { width: neighborWidth, height: neighborHeight, moduleInfo: neighborModuleInfo } = m2
|
|
|
|
const maxWidth = Math.max(currentWidth, neighborWidth)
|
|
const maxHeight = Math.max(currentHeight, neighborHeight)
|
|
|
|
const { moduleTpCd: currentModuleTpCd } = currentModuleInfo
|
|
const { moduleTpCd: neighborModuleTpCd } = neighborModuleInfo
|
|
const { x: m1X, y: m1Y } = m1.getCenterPoint()
|
|
const { x: m2X, y: m2Y } = m2.getCenterPoint()
|
|
|
|
sizes.push({ width: currentWidth, height: currentHeight })
|
|
|
|
if (currentModuleTpCd !== neighborModuleTpCd) {
|
|
sizes.push({ width: neighborWidth, height: neighborHeight })
|
|
}
|
|
|
|
/*m1.set({ fill: m1Fill })
|
|
m2.set({ fill: m2Fill })
|
|
canvas.renderAll()*/
|
|
|
|
return sizes.some(({ width, height }) => {
|
|
let maxX
|
|
let maxY
|
|
let halfMaxX
|
|
let halfMaxY
|
|
const { direction, trestleDetail } = surface
|
|
let moduleIntvlHor, moduleIntvlVer
|
|
if (+roofSizeSet === 3) {
|
|
//육지붕의 경우 값 고정
|
|
moduleIntvlHor = 300
|
|
moduleIntvlVer = 100
|
|
} else {
|
|
moduleIntvlHor = trestleDetail.moduleIntvlHor
|
|
moduleIntvlVer = trestleDetail.moduleIntvlVer
|
|
}
|
|
|
|
if (direction === 'south' || direction === 'north') {
|
|
maxX = width + moduleIntvlHor / 10
|
|
maxY = height + moduleIntvlVer / 10
|
|
halfMaxX = moduleIntvlHor / 10
|
|
halfMaxY = moduleIntvlVer / 10
|
|
|
|
const leftTopPoint = { x: m1X - width - moduleIntvlHor / 10, y: m1Y - height - moduleIntvlVer / 10 }
|
|
const rightTopPoint = { x: m1X + width + moduleIntvlHor / 10, y: m1Y - height - moduleIntvlVer / 10 }
|
|
const leftBottomPoint = { x: m1X - width - moduleIntvlHor / 10, y: m1Y + height + moduleIntvlVer / 10 }
|
|
const rightBottomPoint = { x: m1X + width + moduleIntvlHor / 10, y: m1Y + height + moduleIntvlVer / 10 }
|
|
// {x: m2X, y: m2Y} 가 leftTopPoint, rightTopPoint, leftBottomPoint, rightBottomPoint 내부에 있는지 확인한다.
|
|
if (
|
|
isPointInRect(
|
|
{
|
|
x: leftTopPoint.x,
|
|
y: leftTopPoint.y,
|
|
width: Math.abs(rightTopPoint.x - leftTopPoint.x),
|
|
height: Math.abs(leftTopPoint.y - leftBottomPoint.y),
|
|
},
|
|
{ x: m2X, y: m2Y },
|
|
)
|
|
) {
|
|
return true
|
|
}
|
|
if (currentModuleTpCd !== neighborModuleTpCd) {
|
|
maxX = currentWidth / 2 + neighborWidth / 2 + moduleIntvlHor / 10
|
|
maxY = currentHeight / 2 + neighborHeight / 2 + moduleIntvlVer / 10
|
|
}
|
|
|
|
// console.log(maxX, maxY, halfMaxX, halfMaxY)
|
|
|
|
if (Math.abs(m1X - m2X) < 1) {
|
|
return Math.abs(Math.abs(m1Y - m2Y) - maxY) < 1 || Math.abs(m2Y - m1Y) <= halfMaxY
|
|
} else if (Math.abs(m1Y - m2Y) < 1) {
|
|
return Math.abs(Math.abs(m1X - m2X) - maxX) < 1 || Math.abs(m2X - m1X) <= halfMaxX
|
|
}
|
|
|
|
return (
|
|
(Math.abs(m1X - m2X) < maxX - moduleIntvlHor / 10 + 1 && Math.abs(m1Y - m2Y) < maxY - moduleIntvlVer / 10) ||
|
|
(Math.abs(Math.abs(m1X - m2X) - maxX / 2) < halfMaxX + 1 && Math.abs(Math.abs(m1Y - m2Y) - maxY) < halfMaxY + 1) ||
|
|
(Math.abs(Math.abs(m1X - m2X) - maxX) < halfMaxX + 1 && Math.abs(Math.abs(m1Y - m2Y) - maxY / 2) < halfMaxY + 1)
|
|
)
|
|
} else if (direction === 'east' || direction === 'west') {
|
|
maxX = height + moduleIntvlHor / 10
|
|
maxY = width + moduleIntvlVer / 10
|
|
halfMaxX = moduleIntvlVer / 10
|
|
halfMaxY = moduleIntvlHor / 10
|
|
|
|
// 모듈을 기준으로 왼쪽 상, 오른쪽 상, 왼쪽 하, 오른쪽 하의 각 포인트를 계산
|
|
const leftTopPoint = { x: m1X - width - moduleIntvlVer / 10, y: m1Y + height + moduleIntvlHor / 10 }
|
|
const rightTopPoint = { x: m1X - width - moduleIntvlVer / 10, y: m1Y - height - moduleIntvlHor / 10 }
|
|
const leftBottomPoint = { x: m1X + width + moduleIntvlVer / 10, y: m1Y + height + moduleIntvlHor / 10 }
|
|
const rightBottomPoint = { x: m1X + width + +moduleIntvlVer / 10, y: m1Y - height - moduleIntvlHor / 10 }
|
|
|
|
// {x: m2X, y: m2Y} 가 leftTopPoint, rightTopPoint, leftBottomPoint, rightBottomPoint 내부에 있는지 확인한다.
|
|
if (
|
|
isPointInRect(
|
|
{
|
|
x: rightTopPoint.x,
|
|
y: rightTopPoint.y,
|
|
width: Math.abs(rightBottomPoint.x - rightTopPoint.x),
|
|
height: Math.abs(leftTopPoint.y - rightTopPoint.y),
|
|
},
|
|
{ x: m2X, y: m2Y },
|
|
)
|
|
) {
|
|
return true
|
|
}
|
|
|
|
if (currentModuleTpCd !== neighborModuleTpCd) {
|
|
maxX = currentHeight / 2 + neighborHeight / 2 + moduleIntvlVer / 10
|
|
maxY = currentWidth / 2 + neighborWidth / 2 + moduleIntvlHor / 10
|
|
}
|
|
|
|
if (Math.abs(m1X - m2X) < 1) {
|
|
return Math.abs(Math.abs(m1Y - m2Y) - maxX) < 1 || Math.abs(m2Y - m1Y) <= halfMaxY
|
|
} else if (Math.abs(m1Y - m2Y) < 1) {
|
|
return Math.abs(Math.abs(m1X - m2X) - maxY) < 1 || Math.abs(m2X - m1X) <= halfMaxX
|
|
}
|
|
|
|
return (
|
|
(Math.abs(m1X - m2X) <= maxY - moduleIntvlVer / 10 && Math.abs(m1Y - m2Y) <= maxX - moduleIntvlHor / 10) ||
|
|
(Math.abs(Math.abs(m1X - m2X) - maxY / 2) < halfMaxY + 1 && Math.abs(Math.abs(m1Y - m2Y) - maxX) < halfMaxX + 1) ||
|
|
(Math.abs(Math.abs(m1X - m2X) - maxY) < halfMaxY + 1 && Math.abs(Math.abs(m1Y - m2Y) - maxX / 2) < halfMaxX + 1)
|
|
)
|
|
}
|
|
})
|
|
}
|
|
|
|
function isPointInRect(rect, point) {
|
|
return point.x >= rect.x && point.x <= rect.x + rect.width && point.y >= rect.y && point.y <= rect.y + rect.height
|
|
}
|
|
|
|
// 25-04-02 추가
|
|
// 그룹화
|
|
function groupPoints(modules, surface) {
|
|
const groups = []
|
|
const visited = new Set()
|
|
|
|
for (const point of modules) {
|
|
const { x: pointX, y: pointY } = point.getCenterPoint()
|
|
const key = `${pointX},${pointY}`
|
|
if (visited.has(key)) continue
|
|
|
|
const queue = [point]
|
|
const group = []
|
|
|
|
while (queue.length > 0) {
|
|
const current = queue.shift()
|
|
const { x: currentX, y: currentY } = current.getCenterPoint()
|
|
const currentKey = `${currentX},${currentY}`
|
|
if (visited.has(currentKey)) continue
|
|
|
|
visited.add(currentKey)
|
|
group.push(current)
|
|
|
|
for (const neighbor of modules) {
|
|
const { x: neighborX, y: neighborY } = neighbor.getCenterPoint()
|
|
const neighborKey = `${neighborX},${neighborY}`
|
|
if (!visited.has(neighborKey) && areConnected(current, neighbor, surface)) {
|
|
queue.push(neighbor)
|
|
}
|
|
}
|
|
}
|
|
|
|
groups.push(group)
|
|
}
|
|
|
|
return groups
|
|
}
|
|
|
|
// 각도에 따른 길이 반환
|
|
function getTrestleLength(length, degree, surface) {
|
|
if (surface.from !== 'roofCover') {
|
|
// 지붕덮개로부터 온게 아니면 그냥 length 리턴
|
|
return length
|
|
}
|
|
const radians = (degree * Math.PI) / 180
|
|
return length * Math.cos(radians)
|
|
}
|
|
|
|
// 견적서 아이템 조회 api parameter 생성
|
|
const getTrestleParams = (surface, exposedBottomModules) => {
|
|
const result = calculateForApi(surface)
|
|
|
|
const eaveBar = canvas.getObjects().filter((obj) => obj.surfaceId === surface.id && obj.name === 'eaveBar')
|
|
const halfEaveBar = canvas.getObjects().filter((obj) => obj.surfaceId === surface.id && obj.name === 'halfEaveBar')
|
|
|
|
const rackList = canvas.getObjects().filter((obj) => obj.surfaceId === surface.id && obj.name === 'rack')
|
|
const smartRackList = canvas.getObjects().filter((obj) => obj.surfaceId === surface.id && obj.name === 'smartRack')
|
|
// smartRackList을 smartRackId 기준으로 그룹화 한 배열
|
|
const smartRackGroup = smartRackList.reduce((acc, cur) => {
|
|
if (!acc[cur.smartRackId]) {
|
|
acc[cur.smartRackId] = []
|
|
}
|
|
acc[cur.smartRackId].push(cur)
|
|
return acc
|
|
}, {})
|
|
|
|
const bracketList = canvas.getObjects().filter((obj) => obj.surfaceId === surface.id && obj.name === 'bracket')
|
|
let rackParams = rackList.map((rack, index) => {
|
|
return {
|
|
seq: index,
|
|
itemId: rack.rackId,
|
|
rackFittingCnt: rack.supFitQty,
|
|
rackRows: rack.rackRowsCd,
|
|
}
|
|
})
|
|
|
|
let smartRackParams = Object.values(smartRackGroup).map((smartRack, index) => {
|
|
return {
|
|
seq: index,
|
|
itemId: smartRack[0].rackId,
|
|
rackFittingCnt: smartRack[0].supFitQty,
|
|
rackRows: smartRack[0].rackRowsCd,
|
|
}
|
|
})
|
|
|
|
rackParams = [...rackParams, ...smartRackParams]
|
|
|
|
const parent = canvas.getObjects().find((obj) => obj.id === surface.parentId)
|
|
const roofMaterialIndex = parent.roofMaterial.index
|
|
const moduleSelection = moduleSelectionData?.roofConstructions?.find((construction) => construction.roofIndex === roofMaterialIndex)
|
|
const { common, module } = moduleSelectionData
|
|
|
|
// const { constTp } = construction
|
|
let { cvrPlvrYn, rackYn } = surface.trestleDetail
|
|
const { trestleMkrCd, constMthdCd, roofBaseCd } = moduleSelection.trestle
|
|
const { illuminationTp, instHt, stdSnowLd, stdWindSpeed } = common
|
|
const { constTp } = moduleSelection.construction
|
|
const { addRoof } = moduleSelection
|
|
|
|
return {
|
|
moduleTpCd: module.itemTp,
|
|
roofMatlCd: parent.roofMaterial.roofMatlCd,
|
|
mixMatlNo: module.mixMatlNo,
|
|
raftBaseCd: addRoof.raft ?? addRoof.raftBaseCd,
|
|
inclCd: addRoof.pitch,
|
|
roofPitch: !!addRoof.hajebichi ? addRoof.hajebichi : Number(addRoof.roofPchBase),
|
|
exposedLowerBottomTotCnt: result.exposedBottom, // 노출 최하면 갯수
|
|
exposedHalfBottomTotCnt: result.exposedHalfBottom, // 노출 반하면 갯수
|
|
exposedTopTotCnt: result.exposedTop, // 노출 상면 총 수
|
|
exposedHalfTopTotCnt: result.exposedHalfTop, // 노출 반상면 총 수
|
|
exposedBottomTotCnt: result.exposedBottomPoints.length, // 노출 하면 수
|
|
touchedSurfaceTotCnt: result.touchDimension, // 접면 총 수
|
|
touchedHalfSurfaceTotCnt: result.halfTouchDimension, // 반접면 총 수
|
|
moduleTotCnt: surface.modules.length, // 모듈 총 수
|
|
moduleRowsTotCnt: surface.moduleRowsTotCnt, // 모듈 총 단 수
|
|
eavesTotCnt: eaveBar.length,
|
|
eavesHalfTotCnt: halfEaveBar.length,
|
|
rackYn,
|
|
racks: rackParams,
|
|
rackTotCnt: rackList.length ?? 0 + smartRackGroup.length ?? 0,
|
|
rackFittingTotCnt: bracketList.length,
|
|
moduleRows: getMostLeftModules(surface, exposedBottomModules),
|
|
cvrYn: moduleSelection.construction.setupCover ? 'Y' : 'N',
|
|
snowGdYn: moduleSelection.construction.setupSnowCover ? 'Y' : 'N',
|
|
plvrYn: cvrPlvrYn,
|
|
// modules: getModules(surface), // 2025-02-06 api 수정
|
|
trestleMkrCd,
|
|
constMthdCd,
|
|
roofBaseCd,
|
|
illuminationTp,
|
|
instHt,
|
|
stdSnowLd,
|
|
stdWindSpeed,
|
|
constTp,
|
|
}
|
|
}
|
|
|
|
// 전체 모듈 파라미터 생성
|
|
const getModulesParam = (allModules) => {
|
|
const params = allModules.map((module, index) => {
|
|
return {
|
|
moduleTpCd: module.moduleInfo.itemTp,
|
|
moduleItemId: module.moduleInfo.itemId,
|
|
}
|
|
})
|
|
|
|
//params를 moduleTpCd, moduleItemId로 그룹화 하면서 cnt를 계산
|
|
const groupedParams = params.reduce((acc, cur) => {
|
|
const key = `${cur.moduleTpCd}-${cur.moduleItemId}`
|
|
if (!acc[key]) {
|
|
acc[key] = {
|
|
moduleTpCd: cur.moduleTpCd,
|
|
moduleItemId: cur.moduleItemId,
|
|
cnt: 0,
|
|
}
|
|
}
|
|
acc[key].cnt++
|
|
return acc
|
|
}, {})
|
|
|
|
// map 형태의 데이터를 배열로 변환
|
|
return Object.values(groupedParams).map((groupedParam, index) => {
|
|
return {
|
|
moduleTpCd: groupedParam.moduleTpCd,
|
|
moduleItemId: groupedParam.moduleItemId,
|
|
moduleCnt: groupedParam.cnt,
|
|
}
|
|
})
|
|
}
|
|
|
|
// 키값의 차이가 2이하인 경우 한개로 합침
|
|
function mergeCloseKeys(data) {
|
|
// 키 값을 숫자로 변환 후 정렬
|
|
const keys = Object.keys(data)
|
|
.map(parseFloat)
|
|
.sort((a, b) => a - b)
|
|
const result = {}
|
|
|
|
let baseKey = keys[0]
|
|
result[baseKey.toString()] = [...data[baseKey.toString()]]
|
|
|
|
for (let i = 1; i < keys.length; i++) {
|
|
const currentKey = keys[i]
|
|
const prevKey = baseKey
|
|
|
|
if (Math.abs(currentKey - prevKey) <= 2) {
|
|
// 키 차이가 2 이하인 경우 병합
|
|
result[baseKey.toString()].push(...data[currentKey.toString()])
|
|
} else {
|
|
// 새로운 그룹 시작
|
|
baseKey = currentKey
|
|
result[baseKey.toString()] = [...data[currentKey.toString()]]
|
|
}
|
|
}
|
|
|
|
return result
|
|
}
|
|
|
|
const getSameLineModules = (surface) => {
|
|
const { direction, modules, isChidory } = surface
|
|
|
|
if (!modules || modules.length === 0) {
|
|
return
|
|
}
|
|
|
|
// 같은 단에 있는 모듈들의 리스트
|
|
let sameLineModuleList = []
|
|
|
|
if (direction === 'south') {
|
|
// 모듈의 top으로 groupBy
|
|
let groupedByTop = modules.reduce((acc, module) => {
|
|
const key = module.top
|
|
if (!acc[key]) {
|
|
acc[key] = []
|
|
}
|
|
acc[key].push(module)
|
|
return acc
|
|
}, {})
|
|
groupedByTop = mergeCloseKeys(groupedByTop)
|
|
// groupedByTop의 키값을 기준으로 정렬한 데이터를 배열로 변환
|
|
sameLineModuleList = Object.values(groupedByTop).sort((a, b) => b[0].top - a[0].top)
|
|
} else if (direction === 'north') {
|
|
let groupedByTop = modules.reduce((acc, module) => {
|
|
const key = module.top
|
|
if (!acc[key]) {
|
|
acc[key] = []
|
|
}
|
|
acc[key].push(module)
|
|
return acc
|
|
}, {})
|
|
groupedByTop = mergeCloseKeys(groupedByTop)
|
|
sameLineModuleList = Object.values(groupedByTop).sort((a, b) => a[0].top - b[0].top)
|
|
} else if (direction === 'east') {
|
|
let groupedByLeft = modules.reduce((acc, module) => {
|
|
const key = module.left
|
|
if (!acc[key]) {
|
|
acc[key] = []
|
|
}
|
|
acc[key].push(module)
|
|
return acc
|
|
}, {})
|
|
groupedByLeft = mergeCloseKeys(groupedByLeft)
|
|
sameLineModuleList = Object.values(groupedByLeft).sort((a, b) => b[0].left - a[0].left)
|
|
} else if (direction === 'west') {
|
|
let groupedByLeft = modules.reduce((acc, module) => {
|
|
const key = module.left
|
|
if (!acc[key]) {
|
|
acc[key] = []
|
|
}
|
|
acc[key].push(module)
|
|
return acc
|
|
}, {})
|
|
//groupedByLeft의 키값의 차이가 2이하인 경우 같은 라인으로 합친다.
|
|
groupedByLeft = mergeCloseKeys(groupedByLeft)
|
|
sameLineModuleList = Object.values(groupedByLeft).sort((a, b) => a[0].left - b[0].left)
|
|
}
|
|
|
|
sameLineModuleList.forEach((modules, index) => {
|
|
modules.forEach((module) => {
|
|
module.set({ level: index + 1 }) // 각 모듈에 level 속성 추가
|
|
})
|
|
})
|
|
|
|
return sameLineModuleList
|
|
}
|
|
|
|
// 가장 왼쪽에 있는 모듈을 기준으로 같은 단에 있는 모듈들 파라미터 생성
|
|
const getMostLeftModules = (surface, exposedBottomModules) => {
|
|
const { direction, modules, isChidory } = surface
|
|
const parent = canvas.getObjects().find((obj) => obj.id === surface.parentId)
|
|
const roofMaterialIndex = parent.roofMaterial.index
|
|
const construction = moduleSelectionData?.roofConstructions?.find((construction) => construction.roofIndex === roofMaterialIndex).construction
|
|
let isEaveBar = construction.setupCover
|
|
let isSnowGuard = construction.setupSnowCover
|
|
let cvrLmtRow = construction.cvrLmtRow
|
|
let { rackYn, cvrPlvrYn, moduleIntvlHor, moduleIntvlVer, rackQty, lessSupFitQty } = surface.trestleDetail
|
|
let result = []
|
|
if (rackYn === 'N') {
|
|
rackQty = lessSupFitQty
|
|
}
|
|
const sameLineModuleList = getSameLineModules(surface, exposedBottomModules)
|
|
|
|
sameLineModuleList.forEach((modules, index) => {
|
|
const moduleRowResultData = {
|
|
seq: index + 1,
|
|
moduleItemId: modules[0].moduleInfo.itemId,
|
|
moduleTpCd: modules[0].moduleInfo.itemTp,
|
|
moduleCnt: modules.length,
|
|
exposedBottomCnt: 0,
|
|
exposedHalfBottomCnt: 0,
|
|
exposedTopCnt: 0,
|
|
exposedHalfTopCnt: 0,
|
|
touchedSurfaceCnt: 0,
|
|
touchedHalfSurfaceCnt: 0,
|
|
exposedBottomBracketCnt: 0,
|
|
exposedHalfBottomBracketCnt: 0,
|
|
exposedTopBracketCnt: 0,
|
|
exposedHalfTopBracketCnt: 0,
|
|
touchedSurfaceBracketCnt: 0,
|
|
touchedHalfSurfaceBracketCnt: 0,
|
|
eavesCnt: 0,
|
|
eavesHalfCnt: 0,
|
|
exposedSideEavesCnt: 0,
|
|
}
|
|
|
|
if (direction === 'south') {
|
|
modules.sort((a, b) => a.left - b.left)
|
|
} else if (direction === 'north') {
|
|
modules.sort((a, b) => b.left - a.left)
|
|
} else if (direction === 'east') {
|
|
modules.sort((a, b) => a.top - b.top)
|
|
} else if (direction === 'west') {
|
|
modules.sort((a, b) => b.top - a.top)
|
|
}
|
|
// 모듈 하면,최하면 등 구해야함
|
|
modules.forEach((module, index) => {
|
|
const level = module.level
|
|
// 해당 모듈 주변에 다른 모듈이 있는지 확인
|
|
let {
|
|
bottomModule,
|
|
topModule,
|
|
halfBottomLeftModule,
|
|
halfBottomRightModule,
|
|
halfTopLeftModule,
|
|
halfTopRightModule,
|
|
leftModule,
|
|
rightModule,
|
|
bottomLeftModule,
|
|
bottomRightModule,
|
|
} = findSideModule(module, surface)
|
|
|
|
if (bottomModule) {
|
|
moduleRowResultData.touchedSurfaceCnt++
|
|
if (rackYn === 'N') {
|
|
moduleRowResultData.touchedSurfaceBracketCnt += rackQty
|
|
}
|
|
}
|
|
if (!bottomModule) {
|
|
if (halfBottomLeftModule && halfBottomRightModule) {
|
|
moduleRowResultData.touchedSurfaceCnt++
|
|
if (rackYn === 'N') {
|
|
moduleRowResultData.touchedSurfaceBracketCnt += rackQty
|
|
}
|
|
} else if ((halfBottomLeftModule && !halfBottomRightModule) || (!halfBottomLeftModule && halfBottomRightModule)) {
|
|
moduleRowResultData.touchedHalfSurfaceCnt++
|
|
moduleRowResultData.exposedHalfBottomCnt++
|
|
|
|
if (rackYn === 'N') {
|
|
if (rackQty !== 3) {
|
|
// 3개가 아닌경우는 반반
|
|
moduleRowResultData.exposedHalfBottomBracketCnt += rackQty / 2
|
|
moduleRowResultData.touchedHalfSurfaceBracketCnt += rackQty / 2
|
|
} else {
|
|
// 3개인 경우 왼쪽 아래가 없는 경우 touched는 2개, exposed는 1개
|
|
if (!halfBottomLeftModule && findSamePointInBottom(exposedBottomModules, module, direction)) {
|
|
moduleRowResultData.exposedHalfBottomBracketCnt += 2
|
|
moduleRowResultData.touchedHalfSurfaceBracketCnt += 1
|
|
} else if (!halfBottomLeftModule && !findSamePointInBottom(exposedBottomModules, module, direction)) {
|
|
// 왼쪽 아래가 없고, 하단에 같은 점이 없는 경우는 touched는 1개, exposed는 2개
|
|
if (level % 2 === 0) {
|
|
moduleRowResultData.exposedHalfBottomBracketCnt += 1
|
|
moduleRowResultData.touchedHalfSurfaceBracketCnt += 2
|
|
} else {
|
|
moduleRowResultData.exposedHalfBottomBracketCnt += 2
|
|
moduleRowResultData.touchedHalfSurfaceBracketCnt += 1
|
|
}
|
|
} else if (!halfBottomRightModule && findSamePointInBottom(exposedBottomModules, module, direction)) {
|
|
// 오른쪽 아래가 없고, 하단에 같은 점이 있는 경우는 exposed는 2개, touched는 1개
|
|
moduleRowResultData.exposedHalfBottomBracketCnt += 1
|
|
moduleRowResultData.touchedHalfSurfaceBracketCnt += 2
|
|
} else if (!halfBottomRightModule && !findSamePointInBottom(exposedBottomModules, module, direction)) {
|
|
// 오른쪽 아래가 없고, 하단에 같은 점이 없는 경우는 exposed는 1개, touched는 2개
|
|
if (level % 2 === 0) {
|
|
moduleRowResultData.exposedHalfBottomBracketCnt += 2
|
|
moduleRowResultData.touchedHalfSurfaceBracketCnt += 1
|
|
} else {
|
|
moduleRowResultData.exposedHalfBottomBracketCnt += 1
|
|
moduleRowResultData.touchedHalfSurfaceBracketCnt += 2
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (cvrPlvrYn === 'Y') {
|
|
if (level <= cvrLmtRow) {
|
|
moduleRowResultData.eavesHalfCnt++
|
|
if (bottomLeftModule || bottomRightModule || halfBottomLeftModule || halfBottomRightModule) {
|
|
//처마커버 한개 노출 추가
|
|
moduleRowResultData.exposedSideEavesCnt++
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
moduleRowResultData.exposedBottomCnt++
|
|
if (rackYn === 'N') {
|
|
moduleRowResultData.exposedBottomBracketCnt += rackQty
|
|
}
|
|
if (isEaveBar) {
|
|
if (level <= cvrLmtRow) {
|
|
moduleRowResultData.eavesCnt++
|
|
if ((rightModule && !leftModule) || (!rightModule && leftModule)) {
|
|
// 둘중 하나가 없는경우는 처마커버 노출 추가
|
|
moduleRowResultData.exposedSideEavesCnt++
|
|
} else if (!rightModule && !leftModule) {
|
|
// 양쪽 둘다 없는경우는 처마커버 노출 2개 추가
|
|
moduleRowResultData.exposedSideEavesCnt += 2
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (!topModule) {
|
|
if ((halfTopLeftModule && !halfTopRightModule) || (!halfTopLeftModule && halfTopRightModule)) {
|
|
moduleRowResultData.exposedHalfTopCnt++
|
|
if (rackYn === 'N') {
|
|
if (rackQty !== 3) {
|
|
moduleRowResultData.exposedHalfTopBracketCnt += rackQty / 2
|
|
} else {
|
|
if (halfTopLeftModule) {
|
|
if (level % 2 === 0) {
|
|
moduleRowResultData.exposedHalfTopBracketCnt += 2
|
|
} else {
|
|
moduleRowResultData.exposedHalfTopBracketCnt += 1
|
|
}
|
|
} else if (halfTopRightModule) {
|
|
if (level % 2 === 0) {
|
|
moduleRowResultData.exposedHalfTopBracketCnt += 1
|
|
} else {
|
|
moduleRowResultData.exposedHalfTopBracketCnt += 2
|
|
}
|
|
}
|
|
}
|
|
}
|
|
} else if (!halfTopLeftModule && !halfTopRightModule) {
|
|
moduleRowResultData.exposedTopCnt++
|
|
if (rackYn === 'N') {
|
|
moduleRowResultData.exposedTopBracketCnt += rackQty
|
|
}
|
|
}
|
|
}
|
|
})
|
|
|
|
result.push(moduleRowResultData)
|
|
})
|
|
|
|
canvas.renderAll()
|
|
|
|
return result
|
|
}
|
|
|
|
// 해당 모듈이 해당 설치면에서 상하좌우, 대각선에 있는지 확인
|
|
const findSideModule = (module, surface) => {
|
|
const { direction, modules } = surface
|
|
let { rackYn, cvrPlvrYn, moduleIntvlHor, moduleIntvlVer, rackQty, lessSupFitQty } = surface.trestleDetail
|
|
|
|
const centerPoints = getCenterPoints(surface)
|
|
|
|
const horizontal = ['south', 'north'].includes(direction) ? moduleIntvlHor : moduleIntvlVer
|
|
|
|
const vertical = ['south', 'north'].includes(direction) ? moduleIntvlVer : moduleIntvlHor
|
|
const maxX = MODULE_MARGIN
|
|
const maxY = MODULE_MARGIN
|
|
let { widthArr, heightArr } = centerPoints[0]
|
|
let width = widthArr.reduce((acc, num) => acc + num, 0) / widthArr.length
|
|
let height = heightArr.reduce((acc, num) => acc + num, 0) / heightArr.length
|
|
let { x, y } = { ...module.getCenterPoint() }
|
|
|
|
let halfBottomLeftPoint
|
|
let halfBottomRightPoint
|
|
let halfTopLeftPoint
|
|
let halfTopRightPoint
|
|
let leftPoint
|
|
let rightPoint
|
|
let bottomLeftPoint
|
|
let bottomRightPoint
|
|
|
|
let bottomModule
|
|
let topModule
|
|
let halfBottomLeftModule
|
|
let halfBottomRightModule
|
|
let halfTopLeftModule
|
|
let halfTopRightModule
|
|
let leftModule
|
|
let rightModule
|
|
let bottomLeftModule
|
|
let bottomRightModule
|
|
|
|
switch (direction) {
|
|
case 'south':
|
|
width = width + horizontal
|
|
height = height + vertical
|
|
heightArr.forEach((h) => {
|
|
if (!bottomModule) {
|
|
bottomModule = centerPoints.find((centerPoint) => Math.abs(centerPoint.x - x) < maxX && Math.abs(centerPoint.y - (y + h)) < maxY)
|
|
}
|
|
if (!topModule) {
|
|
topModule = centerPoints.find((centerPoint) => Math.abs(centerPoint.x - x) < maxX && Math.abs(centerPoint.y - (y - h)) < maxY)
|
|
}
|
|
if (!halfBottomLeftModule) {
|
|
halfBottomLeftPoint = { x: x - width / 2, y: y + h }
|
|
halfBottomLeftModule = centerPoints.find(
|
|
(centerPoint) => Math.abs(centerPoint.x - halfBottomLeftPoint.x) < maxX && Math.abs(centerPoint.y - halfBottomLeftPoint.y) < maxY,
|
|
)
|
|
}
|
|
if (!halfBottomRightModule) {
|
|
halfBottomRightPoint = { x: x + width / 2, y: y + h }
|
|
halfBottomRightModule = centerPoints.find(
|
|
(centerPoint) => Math.abs(centerPoint.x - halfBottomRightPoint.x) < maxX && Math.abs(centerPoint.y - halfBottomRightPoint.y) < maxY,
|
|
)
|
|
}
|
|
if (!halfTopLeftModule) {
|
|
halfTopLeftPoint = { x: x - width / 2, y: y - h }
|
|
halfTopLeftModule = centerPoints.find(
|
|
(centerPoint) => Math.abs(centerPoint.x - halfTopLeftPoint.x) < maxX && Math.abs(centerPoint.y - halfTopLeftPoint.y) < maxY,
|
|
)
|
|
}
|
|
if (!halfTopRightModule) {
|
|
halfTopRightPoint = { x: x + width / 2, y: y - h }
|
|
halfTopRightModule = centerPoints.find(
|
|
(centerPoint) => Math.abs(centerPoint.x - halfTopRightPoint.x) < maxX && Math.abs(centerPoint.y - halfTopRightPoint.y) < maxY,
|
|
)
|
|
}
|
|
if (!leftModule) {
|
|
leftPoint = { x: x - width, y: y }
|
|
leftModule = centerPoints.find(
|
|
(centerPoint) => Math.abs(centerPoint.x - leftPoint.x) < maxX && Math.abs(centerPoint.y - leftPoint.y) < maxY,
|
|
)
|
|
}
|
|
if (!rightModule) {
|
|
rightPoint = { x: x + width, y: y }
|
|
rightModule = centerPoints.find(
|
|
(centerPoint) => Math.abs(centerPoint.x - rightPoint.x) < maxX && Math.abs(centerPoint.y - rightPoint.y) < maxY,
|
|
)
|
|
}
|
|
if (!bottomLeftModule) {
|
|
bottomLeftPoint = { x: x - width, y: y + h }
|
|
bottomLeftModule = centerPoints.find(
|
|
(centerPoint) => Math.abs(centerPoint.x - bottomLeftPoint.x) < maxX && Math.abs(centerPoint.y - bottomLeftPoint.y) < maxY,
|
|
)
|
|
}
|
|
if (!bottomRightModule) {
|
|
bottomRightPoint = { x: x + width, y: y + h }
|
|
bottomRightModule = centerPoints.find(
|
|
(centerPoint) => Math.abs(centerPoint.x - bottomRightPoint.x) < maxX && Math.abs(centerPoint.y - bottomRightPoint.y) < maxY,
|
|
)
|
|
}
|
|
})
|
|
|
|
break
|
|
case 'north':
|
|
width = width + horizontal
|
|
height = height + vertical
|
|
heightArr.forEach((h) => {
|
|
if (!bottomModule) {
|
|
bottomModule = centerPoints.find((centerPoint) => Math.abs(centerPoint.x - x) < maxX && Math.abs(centerPoint.y - (y - h)) < maxY)
|
|
}
|
|
if (!topModule) {
|
|
topModule = centerPoints.find((centerPoint) => Math.abs(centerPoint.x - x) < maxX && Math.abs(centerPoint.y - (y + h)) < maxY)
|
|
}
|
|
if (!halfBottomLeftModule) {
|
|
halfBottomLeftPoint = { x: x + width / 2, y: y - h }
|
|
halfBottomLeftModule = centerPoints.find(
|
|
(centerPoint) => Math.abs(centerPoint.x - halfBottomLeftPoint.x) < maxX && Math.abs(centerPoint.y - halfBottomLeftPoint.y) < maxY,
|
|
)
|
|
}
|
|
if (!halfBottomRightModule) {
|
|
halfBottomRightPoint = { x: x - width / 2, y: y - h }
|
|
halfBottomRightModule = centerPoints.find(
|
|
(centerPoint) => Math.abs(centerPoint.x - halfBottomRightPoint.x) < maxX && Math.abs(centerPoint.y - halfBottomRightPoint.y) < maxY,
|
|
)
|
|
}
|
|
if (!halfTopLeftModule) {
|
|
halfTopLeftPoint = { x: x + width / 2, y: y + h }
|
|
halfTopLeftModule = centerPoints.find(
|
|
(centerPoint) => Math.abs(centerPoint.x - halfTopLeftPoint.x) < maxX && Math.abs(centerPoint.y - halfTopLeftPoint.y) < maxY,
|
|
)
|
|
}
|
|
if (!halfTopRightModule) {
|
|
halfTopRightPoint = { x: x - width / 2, y: y + h }
|
|
halfTopRightModule = centerPoints.find(
|
|
(centerPoint) => Math.abs(centerPoint.x - halfTopRightPoint.x) < maxX && Math.abs(centerPoint.y - halfTopRightPoint.y) < maxY,
|
|
)
|
|
}
|
|
if (!leftModule) {
|
|
leftPoint = { x: x + width, y: y }
|
|
leftModule = centerPoints.find(
|
|
(centerPoint) => Math.abs(centerPoint.x - leftPoint.x) < maxX && Math.abs(centerPoint.y - leftPoint.y) < maxY,
|
|
)
|
|
}
|
|
if (!rightModule) {
|
|
rightPoint = { x: x - width, y: y }
|
|
rightModule = centerPoints.find(
|
|
(centerPoint) => Math.abs(centerPoint.x - rightPoint.x) < maxX && Math.abs(centerPoint.y - rightPoint.y) < maxY,
|
|
)
|
|
}
|
|
if (!bottomLeftModule) {
|
|
bottomLeftPoint = { x: x + width, y: y - h }
|
|
bottomLeftModule = centerPoints.find(
|
|
(centerPoint) => Math.abs(centerPoint.x - bottomLeftPoint.x) < maxX && Math.abs(centerPoint.y - bottomLeftPoint.y) < maxY,
|
|
)
|
|
}
|
|
if (!bottomRightModule) {
|
|
bottomRightPoint = { x: x - width, y: y - h }
|
|
bottomRightModule = centerPoints.find(
|
|
(centerPoint) => Math.abs(centerPoint.x - bottomRightPoint.x) < maxX && Math.abs(centerPoint.y - bottomRightPoint.y) < maxY,
|
|
)
|
|
}
|
|
})
|
|
|
|
break
|
|
case 'east':
|
|
widthArr.forEach((w) => {
|
|
if (!bottomModule) {
|
|
bottomModule = centerPoints.find((centerPoint) => Math.abs(centerPoint.x - (x + w)) < maxX && Math.abs(centerPoint.y - y) < maxY)
|
|
}
|
|
if (!topModule) {
|
|
topModule = centerPoints.find((centerPoint) => Math.abs(centerPoint.x - (x - w)) < maxX && Math.abs(centerPoint.y - y) < maxY)
|
|
}
|
|
if (!halfBottomLeftModule) {
|
|
halfBottomLeftPoint = { x: x + w, y: y - height / 2 }
|
|
halfBottomLeftModule = centerPoints.find(
|
|
(centerPoint) => Math.abs(centerPoint.x - halfBottomLeftPoint.x) < maxX && Math.abs(centerPoint.y - halfBottomLeftPoint.y) < maxY,
|
|
)
|
|
}
|
|
if (!halfBottomRightModule) {
|
|
halfBottomRightPoint = { x: x + w, y: y - height / 2 }
|
|
halfBottomRightModule = centerPoints.find(
|
|
(centerPoint) => Math.abs(centerPoint.x - halfBottomRightPoint.x) < maxX && Math.abs(centerPoint.y - halfBottomRightPoint.y) < maxY,
|
|
)
|
|
}
|
|
if (!halfTopLeftModule) {
|
|
halfTopLeftPoint = { x: x - w, y: y + height / 2 }
|
|
halfTopLeftModule = centerPoints.find(
|
|
(centerPoint) => Math.abs(centerPoint.x - halfTopLeftPoint.x) < maxX && Math.abs(centerPoint.y - halfTopLeftPoint.y) < maxY,
|
|
)
|
|
}
|
|
if (!halfTopRightModule) {
|
|
halfTopRightPoint = { x: x - w, y: y - height / 2 }
|
|
halfTopRightModule = centerPoints.find(
|
|
(centerPoint) => Math.abs(centerPoint.x - halfTopRightPoint.x) < maxX && Math.abs(centerPoint.y - halfTopRightPoint.y) < maxY,
|
|
)
|
|
}
|
|
if (!leftModule) {
|
|
leftPoint = { x: x, y: y + height }
|
|
leftModule = centerPoints.find(
|
|
(centerPoint) => Math.abs(centerPoint.x - leftPoint.x) < maxX && Math.abs(centerPoint.y - leftPoint.y) < maxY,
|
|
)
|
|
}
|
|
if (!rightModule) {
|
|
rightPoint = { x: x, y: y - height }
|
|
rightModule = centerPoints.find(
|
|
(centerPoint) => Math.abs(centerPoint.x - rightPoint.x) < maxX && Math.abs(centerPoint.y - rightPoint.y) < maxY,
|
|
)
|
|
}
|
|
if (!bottomLeftModule) {
|
|
bottomLeftPoint = { x: x + w, y: y + height }
|
|
bottomLeftModule = centerPoints.find(
|
|
(centerPoint) => Math.abs(centerPoint.x - bottomLeftPoint.x) < maxX && Math.abs(centerPoint.y - bottomLeftPoint.y) < maxY,
|
|
)
|
|
}
|
|
if (!bottomRightModule) {
|
|
bottomRightPoint = { x: x + w, y: y - height }
|
|
bottomRightModule = centerPoints.find(
|
|
(centerPoint) => Math.abs(centerPoint.x - bottomRightPoint.x) < maxX && Math.abs(centerPoint.y - bottomRightPoint.y) < maxY,
|
|
)
|
|
}
|
|
})
|
|
break
|
|
case 'west':
|
|
widthArr.forEach((w) => {
|
|
if (!bottomModule) {
|
|
bottomModule = centerPoints.find((centerPoint) => Math.abs(centerPoint.x - (x - w)) < maxX && Math.abs(centerPoint.y - y) < maxY)
|
|
}
|
|
if (!topModule) {
|
|
topModule = centerPoints.find((centerPoint) => Math.abs(centerPoint.x - (x + w)) < maxX && Math.abs(centerPoint.y - y) < maxY)
|
|
}
|
|
if (!halfBottomLeftModule) {
|
|
halfBottomLeftPoint = { x: x - w, y: y - height / 2 }
|
|
halfBottomLeftModule = centerPoints.find(
|
|
(centerPoint) => Math.abs(centerPoint.x - halfBottomLeftPoint.x) < maxX && Math.abs(centerPoint.y - halfBottomLeftPoint.y) < maxY,
|
|
)
|
|
}
|
|
if (!halfBottomRightModule) {
|
|
halfBottomRightPoint = { x: x - w, y: y + height / 2 }
|
|
halfBottomRightModule = centerPoints.find(
|
|
(centerPoint) => Math.abs(centerPoint.x - halfBottomRightPoint.x) < maxX && Math.abs(centerPoint.y - halfBottomRightPoint.y) < maxY,
|
|
)
|
|
}
|
|
if (!halfTopLeftModule) {
|
|
halfTopLeftPoint = { x: x + w, y: y - height / 2 }
|
|
halfTopLeftModule = centerPoints.find(
|
|
(centerPoint) => Math.abs(centerPoint.x - halfTopLeftPoint.x) < maxX && Math.abs(centerPoint.y - halfTopLeftPoint.y) < maxY,
|
|
)
|
|
}
|
|
if (!halfTopRightModule) {
|
|
halfTopRightPoint = { x: x + w, y: y + height / 2 }
|
|
halfTopRightModule = centerPoints.find(
|
|
(centerPoint) => Math.abs(centerPoint.x - halfTopRightPoint.x) < maxX && Math.abs(centerPoint.y - halfTopRightPoint.y) < maxY,
|
|
)
|
|
}
|
|
if (!leftModule) {
|
|
leftPoint = { x: x, y: y - height }
|
|
leftModule = centerPoints.find(
|
|
(centerPoint) => Math.abs(centerPoint.x - leftPoint.x) < maxX && Math.abs(centerPoint.y - leftPoint.y) < maxY,
|
|
)
|
|
}
|
|
if (!rightModule) {
|
|
rightPoint = { x: x, y: y + height }
|
|
rightModule = centerPoints.find(
|
|
(centerPoint) => Math.abs(centerPoint.x - rightPoint.x) < maxX && Math.abs(centerPoint.y - rightPoint.y) < maxY,
|
|
)
|
|
}
|
|
if (!bottomLeftModule) {
|
|
bottomLeftPoint = { x: x - w, y: y - height }
|
|
bottomLeftModule = centerPoints.find(
|
|
(centerPoint) => Math.abs(centerPoint.x - bottomLeftPoint.x) < maxX && Math.abs(centerPoint.y - bottomLeftPoint.y) < maxY,
|
|
)
|
|
}
|
|
if (!bottomRightModule) {
|
|
bottomRightPoint = { x: x - w, y: y + height }
|
|
bottomRightModule = centerPoints.find(
|
|
(centerPoint) => Math.abs(centerPoint.x - bottomRightPoint.x) < maxX && Math.abs(centerPoint.y - bottomRightPoint.y) < maxY,
|
|
)
|
|
}
|
|
})
|
|
break
|
|
}
|
|
|
|
return {
|
|
bottomModule,
|
|
topModule,
|
|
halfBottomLeftModule,
|
|
halfBottomRightModule,
|
|
halfTopLeftModule,
|
|
halfTopRightModule,
|
|
leftModule,
|
|
rightModule,
|
|
bottomLeftModule,
|
|
bottomRightModule,
|
|
}
|
|
}
|
|
|
|
const clear = () => {
|
|
canvas
|
|
.getObjects()
|
|
.filter((obj) => obj.name === POLYGON_TYPE.MODULE_SETUP_SURFACE)
|
|
.forEach((obj) => {
|
|
obj.isComplete = false
|
|
})
|
|
|
|
canvas.getObjects().forEach((obj) => {
|
|
if (obj.name === 'eaveBar' || obj.name === 'rack' || obj.name === 'halfEaveBar' || obj.name === 'smartRack' || obj.name === 'bracket') {
|
|
canvas.remove(obj)
|
|
}
|
|
})
|
|
resetCircuits()
|
|
}
|
|
|
|
// 전모듈 의 회로번호 visible false 처리
|
|
// 가대 설치 전 필요
|
|
const setViewCircuitNumberTexts = (visible) => {
|
|
const circuitNumberTexts = canvas.getObjects().filter((obj) => obj.name === 'circuitNumber')
|
|
circuitNumberTexts.forEach((text) => {
|
|
text.visible = visible
|
|
})
|
|
canvas.renderAll()
|
|
}
|
|
|
|
// 가대 설치 완료 전,후 모든 surface의 isComplete를 변경
|
|
const setAllModuleSurfaceIsComplete = (bool) => {
|
|
const surfaces = canvas.getObjects().filter((obj) => obj.name === POLYGON_TYPE.MODULE_SETUP_SURFACE)
|
|
surfaces.forEach((surface) => {
|
|
surface.isComplete = bool
|
|
})
|
|
}
|
|
|
|
// 배치면 전체에 가대 설치 여부
|
|
const isAllComplete = () => {
|
|
const surfaces = canvas.getObjects().filter((obj) => obj.name === POLYGON_TYPE.MODULE_SETUP_SURFACE)
|
|
if (surfaces.length === 0) {
|
|
return false
|
|
}
|
|
return surfaces.every((surface) => surface.isComplete)
|
|
}
|
|
|
|
const groupByType = (originArr = []) => {
|
|
const grouped = {}
|
|
const newArr = [...originArr]
|
|
|
|
// 타입별로 객체들을 분류
|
|
for (const item of newArr) {
|
|
if (!grouped[item.circuitNumber]) {
|
|
grouped[item.circuitNumber] = []
|
|
}
|
|
grouped[item.circuitNumber].push(item)
|
|
}
|
|
|
|
// 객체를 배열로 변환
|
|
return Object.values(grouped)
|
|
}
|
|
|
|
function groupByCircuitAndSurface(arr) {
|
|
const circuitGroups = {}
|
|
|
|
for (const item of arr) {
|
|
const { circuitNumber, surfaceId } = item
|
|
if (!circuitGroups[circuitNumber]) {
|
|
circuitGroups[circuitNumber] = new Map()
|
|
}
|
|
|
|
const surfaceMap = circuitGroups[circuitNumber]
|
|
const key = surfaceId
|
|
|
|
if (!surfaceMap.has(key)) {
|
|
surfaceMap.set(key, [])
|
|
}
|
|
|
|
surfaceMap.get(key).push(item)
|
|
}
|
|
|
|
// 결과: circuitNumber별 surface 그룹 수
|
|
const result = {}
|
|
for (const [circuit, surfaceMap] of Object.entries(circuitGroups)) {
|
|
result[circuit] = surfaceMap.size
|
|
}
|
|
|
|
return result
|
|
}
|
|
|
|
function countMatchingCircuitNumbers(arrays) {
|
|
let cnt = 0
|
|
|
|
// 모든 고유한 circuitNumber 찾기
|
|
const allCircuitNumbers = new Set()
|
|
arrays.forEach((arr) => {
|
|
arr.forEach((item) => {
|
|
allCircuitNumbers.add(item.circuitNumber)
|
|
})
|
|
})
|
|
|
|
// 각 circuitNumber가 몇 개의 배열에 나타나는지 세기
|
|
allCircuitNumbers.forEach((circuitNum) => {
|
|
let arrayCount = 0
|
|
|
|
arrays.forEach((arr) => {
|
|
const hasCircuitNum = arr.some((item) => item.circuitNumber === circuitNum)
|
|
if (hasCircuitNum) {
|
|
arrayCount++
|
|
}
|
|
})
|
|
|
|
// 2개 이상의 배열에 나타나는 경우에만 카운트 (배열 개수 - 1)
|
|
if (arrayCount >= 2) {
|
|
cnt += arrayCount - 1
|
|
}
|
|
})
|
|
|
|
return cnt
|
|
}
|
|
|
|
// 양단 케이블 구하는 공식
|
|
const getTotalConnectCableCnt = () => {
|
|
let cnt = 0
|
|
const surfaces = canvas.getObjects().filter((obj) => obj.name === POLYGON_TYPE.MODULE_SETUP_SURFACE)
|
|
const modules = canvas.getObjects().filter((obj) => obj.name === POLYGON_TYPE.MODULE)
|
|
|
|
surfaces.forEach((surface) => {
|
|
const modules = surface.modules
|
|
// 1. 현재 surface의 모듈들을 그룹화
|
|
const groupInSurface = groupPoints(modules, surface)
|
|
|
|
cnt += countMatchingCircuitNumbers(groupInSurface)
|
|
})
|
|
|
|
const groupByCircuitAndSurfaceCnt = groupByCircuitAndSurface(modules)
|
|
|
|
Object.keys(groupByCircuitAndSurfaceCnt).forEach((key) => {
|
|
cnt += groupByCircuitAndSurfaceCnt[key] - 1
|
|
})
|
|
|
|
return cnt
|
|
}
|
|
|
|
return {
|
|
apply,
|
|
getTrestleParams,
|
|
clear,
|
|
setViewCircuitNumberTexts,
|
|
getEstimateData,
|
|
setAllModuleSurfaceIsComplete,
|
|
isAllComplete,
|
|
groupCoordinates,
|
|
groupPoints,
|
|
}
|
|
}
|