qcast-front/src/hooks/module/useTrestle.js

2232 lines
83 KiB
JavaScript

import { useRecoilValue } from 'recoil'
import { canvasState, currentAngleTypeSelector } from '@/store/canvasAtom'
import { POLYGON_TYPE } 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'
// 회로 및 가대설정
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 apply = () => {
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) => {
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
if (!construction) {
alert('앞에서 셋팅 안됨')
return
}
const plvrYn = construction.plvrYn
let moduleRowsTotCnt = 0
let isEaveBar = construction.setupCover
let isSnowGuard = construction.setupSnowCover
const direction = parent.direction
const rack = surface.trestleDetail.rack
let { rackQty, rackIntvlPct, rackYn, cvrPlvrYn } = surface.trestleDetail
if (!rack) {
//25/02/06 가대없음의 경우 랙정보가 없음
return
}
const rackInfos = Object.keys(rack).map((key) => {
return { key, value: rack[key] }
})
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
if (plvrYn === 'N' && isChidory) {
alert('치조불가공법입니다.')
clear()
throw new Error('치조불가공법입니다.')
}
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) => {
//TODO : 방향별로 처마력바 설치해야함
const bottomPoints = findTopTwoPoints([...module.points], direction)
if (!bottomPoints) return
const eaveBar = new fabric.Line([bottomPoints[0].x, bottomPoints[0].y, bottomPoints[1].x, bottomPoints[1].y], {
parent: surface,
name: 'eaveBar',
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 bottomPoints = findTopTwoPoints([...module.points], 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: 'halfEaveBar',
stroke: 'blue',
strokeWidth: 4,
selectable: false,
surfaceId: surface.id,
parentId: module.id,
visible: isTrestleDisplay,
})
canvas.add(halfEaveBar)
canvas.renderAll()
})
rightExposedHalfBottomPoints.forEach((module) => {
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: 'halfEaveBar',
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 {
return (
rack.value.moduleTpCd === leftRowsInfo.moduleTotalTp &&
rack.value.moduleRows === leftRowsInfo.rowsInfo.reduce((acc, row) => acc + row.count, 0) &&
rack.value.moduleTpRows1 === leftRowsInfo.rowsInfo[0].count &&
rack.value.moduleTpRows2 === leftRowsInfo.rowsInfo[1].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 {
return (
rack.value.moduleTpCd === rightRowsInfo.moduleTotalTp &&
rack.value.moduleRows === rightRowsInfo.rowsInfo.reduce((acc, row) => acc + row.count, 0) &&
rack.value.moduleTpRows1 === rightRowsInfo.rowsInfo[0].count &&
rack.value.moduleTpRows2 === rightRowsInfo.rowsInfo[1].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 {
return (
rack.value.moduleTpCd === centerRowsInfo.moduleTotalTp &&
rack.value.moduleRows === centerRowsInfo.rowsInfo.reduce((acc, row) => acc + row.count, 0) &&
rack.value.moduleTpRows1 === centerRowsInfo.rowsInfo[0].count &&
rack.value.moduleTpRows2 === centerRowsInfo.rowsInfo[1].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 })
})
// 왼쪽아래에 모듈이 없는 모듈들
leftExposedHalfBottomModules.forEach((module) => {
const { width, height } = module
let { x: startX, y: startY } = { ...module.getCenterPoint() }
let { x, y } = { ...module.getCenterPoint() }
//TODO : 방향별로 가대 설치해야함
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 {
return (
rack.value.moduleTpCd === leftRowsInfo.moduleTotalTp &&
rack.value.moduleRows === leftRowsInfo.rowsInfo.reduce((acc, row) => acc + row.count, 0) &&
rack.value.moduleTpRows1 === leftRowsInfo.rowsInfo[0].count &&
rack.value.moduleTpRows2 === leftRowsInfo.rowsInfo[1].count
)
}
})?.value.racks
mostRowsModule = Math.max(leftRows, mostRowsModule)
if (rackYn === 'Y') {
drawRacks(leftRacks, rackQty, rackIntvlPct, module, direction, 'L', rackYn)
}
module.set({ leftRows })
})
// 오른쪽 아래에 모듈이 없는 모듈들
rightExposedHalfBottomPoints.forEach((module) => {
const { width, height } = module
let { x: startX, y: startY } = { ...module.getCenterPoint() }
let { x, y } = { ...module.getCenterPoint() }
//TODO : 방향별로 가대 설치해야함
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 {
return (
rack.value.moduleTpCd === rightRowsInfo.moduleTotalTp &&
rack.value.moduleRows === rightRowsInfo.rowsInfo.reduce((acc, row) => acc + row.count, 0) &&
rack.value.moduleTpRows1 === rightRowsInfo.rowsInfo[0].count &&
rack.value.moduleTpRows2 === rightRowsInfo.rowsInfo[1].count
)
}
})?.value.racks
mostRowsModule = Math.max(rightRows, mostRowsModule)
// 해당 rack으로 그려준다.
if (rackYn === 'Y') {
drawRacks(rightRacks, rackQty, rackIntvlPct, module, direction, 'R', rackYn)
}
module.set({ rightRows })
})
surface.set({ moduleRowsTotCnt: mostRowsModule })
if (rackYn === 'N') {
// rack이 없을경우
installBracketWithOutRack(surface, exposedBottomModules, leftExposedHalfBottomModules, rightExposedHalfBottomPoints, isChidory)
} else if (rackYn === 'Y') {
installBracket(surface)
}
const quotationParam = getTrestleParams(surface)
surface.set({ quotationParam })
})
return setEstimateData()
} catch (e) {
return null
}
}
//module Rack 정보를 얻기위한 데이터 가공
function moduleTransformData(arr) {
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 }
}
// itemList 조회 후 estimateParam에 저장
const setEstimateData = 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 params = { trestles, pcses, modules }
//견적서 itemList 조회
const { data: itemList, data2, result } = await getQuotationItem(params)
if (result.resultCode === 'E') {
swalFire({ text: result.resultMsg, icon: 'error' })
return null
}
//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, pitch: slope, moduleCompass, surfaceCompass } = parent
const roofMaterialIndex = parent.roofMaterial.index
const { nameJp: roofMaterialIdMulti } = roofMaterial
const moduleSelection = moduleSelectionData?.roofConstructions?.find((construction) => construction.roofIndex === roofMaterialIndex)
const { constTp: constructSpecification, constTpJp: constructSpecificationMulti } = moduleSelection.construction
const {
trestleMkrCd,
constMthdCd: supportMethodId,
roofBaseCd,
trestleMkrCdJp: supportMeaker,
constMthdCdJp: supportMethodIdMulti,
} = moduleSelection.trestle
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: roofMaterial.roofMatlCd,
supportMethodId,
constructSpecification,
constructSpecificationMulti,
roofMaterialIdMulti,
supportMethodIdMulti,
supportMeaker,
slope,
classType: currentAngleType === 'slope' ? '0' : '1',
angle: getDegreeByChon(slope),
azimuth: surfaceCompass ?? moduleCompass ?? 0,
moduleList,
}
})
// circuitItemList 중복제거
circuitItemList = circuitItemList.filter((item, index) => circuitItemList.indexOf(item) === index)
circuitItemList = circuitItemList.map((circuitId) => {
return {
itemId: circuitId,
}
})
return { itemList, northArrangement, roofSurfaceList, circuitItemList }
}
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 = 2 + horizontal * 3
let maxY = 2 + vertical * 3
let result
switch (direction) {
case 'south': {
result = centerPoints.find((centerPoint) => Math.abs(centerPoint.x - x) < maxX && Math.abs(centerPoint.y - (y - height)) < maxY)
break
}
case 'north': {
result = centerPoints.find((centerPoint) => Math.abs(centerPoint.x - x) < maxX && Math.abs(centerPoint.y - (y + height)) < maxY)
break
}
case 'east': {
result = centerPoints.find((centerPoint) => Math.abs(centerPoint.x - (x - width)) < maxX && Math.abs(centerPoint.y - y) < maxY)
break
}
case 'west': {
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 = 2 + horizontal * 3
let maxY = 2 + vertical * 3
switch (direction) {
case 'south': {
width = width + horizontal
height = height + vertical
topLeftPoint = { x: x - width / 2, y: y - height }
break
}
case 'north': {
width = width + horizontal
height = height + vertical
topLeftPoint = { x: x + width / 2, y: y + height }
break
}
case 'east': {
topLeftPoint = { x: x - width, y: y + height / 2 }
break
}
case 'west': {
topLeftPoint = { x: x + width, y: y - height / 2 }
break
}
}
result = centerPoints.find((centerPoint) => Math.abs(centerPoint.x - topLeftPoint.x) < maxX && Math.abs(centerPoint.y - topLeftPoint.y) < maxY)
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 = 2 + horizontal * 3
let maxY = 2 + vertical * 3
switch (direction) {
case 'south': {
topRightPoint = { x: x + width / 2, y: y - height }
break
}
case 'north': {
topRightPoint = { x: x - width / 2, y: y + height }
break
}
case 'east': {
topRightPoint = { x: x - width, y: y - height / 2 }
break
}
case 'west': {
topRightPoint = { x: x + width, y: y + height / 2 }
break
}
}
result = centerPoints.find((centerPoint) => Math.abs(centerPoint.x - topRightPoint.x) < maxX && Math.abs(centerPoint.y - topRightPoint.y) < maxY)
return result
}
const drawRacks = (rackInfos, rackQty, rackIntvlPct, module, direction, l, rackYn) => {
if (!rackInfos) {
return
}
const { width, height, left, top, lastX, lastY, surfaceId } = module
const surface = canvas.getObjects().find((obj) => obj.id === surfaceId)
const roof = canvas.getObjects().find((obj) => obj.id === surface.parentId)
const degree = getDegreeByChon(roof.roofMaterial.pitch)
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) / 10
if (smartRackYn === 'Y') {
let smartRackId = uuidv4()
smartRack.forEach(({ seq, setRackTpCd, setRackTpLen, supFitQty }) => {
rackLength = getTrestleLength(setRackTpLen, degree) / 10
if (setRackTpCd === 'RACK') {
const rack = new fabric.Line([startPointX, startPointY, startPointX, startPointY - rackLength], {
name: 'smartRack',
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: '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) / 10
if (smartRackYn === 'Y') {
let smartRackId = uuidv4()
smartRack.forEach(({ seq, setRackTpCd, setRackTpLen, supFitQty }) => {
rackLength = getTrestleLength(setRackTpLen, degree) / 10
if (setRackTpCd === 'RACK') {
const rack = new fabric.Line([startPointX, startPointY, startPointX - rackLength, startPointY], {
name: 'smartRack',
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: '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) / 10
if (smartRackYn === 'Y') {
let smartRackId = uuidv4()
smartRack.forEach(({ seq, setRackTpCd, setRackTpLen, supFitQty }) => {
rackLength = getTrestleLength(setRackTpLen, degree) / 10
if (setRackTpCd === 'RACK') {
const rack = new fabric.Line([startPointX, startPointY, startPointX + rackLength, startPointY], {
name: 'smartRack',
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: '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) / 10
if (smartRackYn === 'Y') {
let smartRackId = uuidv4()
smartRack.forEach(({ seq, setRackTpCd, setRackTpLen, supFitQty }) => {
rackLength = getTrestleLength(setRackTpLen, degree) / 10
if (setRackTpCd === 'RACK') {
const rack = new fabric.Line([startPointX, startPointY, startPointX, startPointY + rackLength], {
name: 'smartRack',
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: 'right',
})
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: '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
}
}
}
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) => {
const { 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 bracket = new fabric.Rect({
left: x2 - bracketLength / 3,
top: name === 'smartRack' ? y2 + rackLen * percent : y2 + (rackLen / 10) * percent,
fill: 'green',
name: '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 bracket = new fabric.Rect({
left: name === 'smartRack' ? x2 + rackLen * percent : x2 + (rackLen / 10) * percent,
top: y2 - bracketLength / 3,
fill: 'green',
name: '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 bracket = new fabric.Rect({
left: name === 'smartRack' ? x2 - rackLen * percent : x2 - (rackLen / 10) * percent,
top: y2 - bracketLength / 3,
fill: 'green',
parentId: rack.parentId,
visible: isTrestleDisplay,
surfaceId: surface.id,
name: '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 bracket = new fabric.Rect({
left: x2 - bracketLength / 3,
top: name === 'smartRack' ? y2 - rackLen * percent : y2 - (rackLen / 10) * percent,
fill: 'green',
name: '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 } = surface.trestleDetail
const direction = surface.direction
rackQty = 3
rackIntvlPct = 10
canvas.renderAll()
exposedBottomModules.forEach((module) => {
canvas.renderAll()
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)) {
// 해당 모듈과 같은 위치 맨 아래에 모듈이 있는 경우 하나 더 설치 필요
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) => {
drawBracketWithOutRack(module, rackIntvlPct, module.rightRows + 1, 'R', surface.direction, moduleIntvlHor, moduleIntvlVer)
if (rackQty === 3 && !findSamePointInBottom(exposedBottomModules, module)) {
// 해당 모듈과 같은 위치 맨 아래에 모듈이 없는 경우 하나 더 설치 필요
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) => {
const { x, y } = module.getCenterPoint()
return exposedBottomModules.find((exposedBottomModule) => {
const { x: exposedX, y: exposedY } = exposedBottomModule.getCenterPoint()
return Math.abs(x - exposedX) < 2 || Math.abs(y - exposedY) < 2
})
}
const drawBracketWithOutRack = (module, rackIntvlPct, count, l, direction, moduleIntvlHor, moduleIntvlVer) => {
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
break
} else if (direction === 'west') {
startPointX = left
startPointY = top + height / rackIntvlPct
break
} else if (direction === 'north') {
startPointX = left + width - width / rackIntvlPct
startPointY = top
break
}
}
case 'R': {
// 오른쪽부분 시작 점
if (direction === 'south') {
startPointX = left + width - width / rackIntvlPct
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
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
}
}
}
for (let i = 0; i < count; i++) {
const bracket = new fabric.Rect({
left: startPointX - 5,
top: startPointY - 5,
fill: 'green',
name: 'bracket',
parentId: module.id,
surfaceId: module.surfaceId,
width: 10,
height: 10,
selectable: false,
visible: isTrestleDisplay,
})
canvas.add(bracket)
canvas.renderAll()
if (direction === 'south') {
startPointY -= height + moduleIntvlVer
} else if (direction === 'north') {
startPointY += height + moduleIntvlVer
} else if (direction === 'east') {
startPointX -= width + moduleIntvlHor
} else if (direction === 'west') {
startPointX += width + moduleIntvlHor
}
}
}
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 })
})
//widthArr 중복 제거 1이상 차이가 나지 않으면 같은 너비로 간주
widthArr = removeCloseValues(Array.from(new Set(widthArr)))
heightArr = removeCloseValues(Array.from(new Set(heightArr)))
centerPoints.forEach((centerPoint, index) => {
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 = 2 + horizontal * 3
const maxY = 2 + vertical * 3
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 } = { ...centerPoint }
// centerPoints중에 현재 centerPoint와 x값이 같고, y값이 y-height값과 같은 centerPoint가 있는지 확인
let bottomCell
let bottomLeftPoint
let bottomRightPoint
let leftBottomCnt
let rightBottomCnt
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
bottomCell = centerPoints.filter((centerPoint) => Math.abs(centerPoint.x - x) < maxX && Math.abs(centerPoint.y - (y + height)) < maxY)
bottomLeftPoint = { x: x - width / 2, y: y + height }
bottomRightPoint = { x: x + width / 2, y: y + height }
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
bottomCell = centerPoints.filter((centerPoint) => Math.abs(centerPoint.x - x) < maxX && Math.abs(centerPoint.y - (y - height)) < maxY)
bottomLeftPoint = { x: x + width / 2, y: y - height }
bottomRightPoint = { x: x - width / 2, y: y - height }
break
case 'east':
bottomCell = centerPoints.filter((centerPoint) => Math.abs(centerPoint.x - (x + width)) < maxX && Math.abs(centerPoint.y - y) < maxY)
width = widthArr.reduce((acc, num) => acc + num, 0) / widthArr.length + horizontal
bottomLeftPoint = { x: x + width, y: y + height / 2 }
bottomRightPoint = { x: x + width, y: y - height / 2 }
break
case 'west':
bottomCell = centerPoints.filter((centerPoint) => Math.abs(centerPoint.x - (x - width)) < maxX && Math.abs(centerPoint.y - y) < maxY)
width = widthArr.reduce((acc, num) => acc + num, 0) / widthArr.length + horizontal
bottomLeftPoint = { x: x - width, y: y - height / 2 }
bottomRightPoint = { x: x - width, y: y + height / 2 }
break
}
if (bottomCell.length === 1) {
return
}
// 바로 아래에 셀이 없는 경우 물떼세 배치가 왼쪽 되어있는 셀을 찾는다.
leftBottomCnt = centerPoints.filter(
(centerPoint) => Math.abs(centerPoint.x - bottomLeftPoint.x) < maxX && Math.abs(centerPoint.y - bottomLeftPoint.y) < maxY,
).length
rightBottomCnt = centerPoints.filter(
(centerPoint) => Math.abs(centerPoint.x - bottomRightPoint.x) < maxX && Math.abs(centerPoint.y - bottomRightPoint.y) < maxY,
).length
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)
}
})
// 노출상면 및 접면 체크
centerPoints.forEach((centerPoint, index) => {
let { x, y, width, height } = { ...centerPoint }
let topCell
let topLeftPoint
let topRightPoint
let leftTopCnt
let rightTopCnt
switch (direction) {
case 'south':
width = width + horizontal
height = height + vertical
topCell = centerPoints.filter((centerPoint) => Math.abs(centerPoint.x - x) < maxX && Math.abs(centerPoint.y - (y - height)) < maxY)
topLeftPoint = { x: x - width / 2, y: y - height }
topRightPoint = { x: x + width / 2, y: y - height }
break
case 'north':
height = height + vertical
topCell = centerPoints.filter((centerPoint) => Math.abs(centerPoint.x - x) < maxX && Math.abs(centerPoint.y - (y + height)) < maxY)
topLeftPoint = { x: x + width / 2, y: y + height }
topRightPoint = { x: x - width / 2, y: y + height }
break
case 'east':
width = width + horizontal
topCell = centerPoints.filter((centerPoint) => Math.abs(centerPoint.x - (x - width)) < maxX && Math.abs(centerPoint.y - y) < maxY)
topLeftPoint = { x: x - width, y: y + height / 2 }
topRightPoint = { x: x - width, y: y - height / 2 }
break
case 'west':
width = width + horizontal
topCell = centerPoints.filter((centerPoint) => Math.abs(centerPoint.x - (x + width)) < maxX && Math.abs(centerPoint.y - y) < maxY)
topLeftPoint = { x: x + width, y: y - height / 2 }
topRightPoint = { x: x + width, y: y + height / 2 }
break
}
if (topCell.length === 1) {
touchDimension++
return
}
leftTopCnt = centerPoints.filter(
(centerPoint) => Math.abs(centerPoint.x - topLeftPoint.x) < maxX && Math.abs(centerPoint.y - topLeftPoint.y) < maxY,
).length
rightTopCnt = centerPoints.filter(
(centerPoint) => Math.abs(centerPoint.x - topRightPoint.x) < maxX && Math.abs(centerPoint.y - topRightPoint.y) < maxY,
).length
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 = 0 // 가로 패딩
const verticalPadding = 0 // 세로 패딩
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 getTrestleLength(length, degree) {
if (roofSizeSet !== 1) {
// 복시도 입력이 아닌경우 그냥 길이 return
return length
}
const radians = (degree * Math.PI) / 180
return length * Math.cos(radians)
}
// 견적서 아이템 조회 api parameter 생성
const getTrestleParams = (surface) => {
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,
}
})
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,
inclCd: addRoof.pitch,
roofPitch: 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,
rackFittingCnt: bracketList.length,
moduleRows: getMostLeftModules(surface),
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,
}
})
}
// 가장 왼쪽에 있는 모듈을 기준으로 같은 단에 있는 모듈들 파라미터 생성
const getMostLeftModules = (surface) => {
const { direction, modules } = 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 { rackYn, cvrPlvrYn, moduleIntvlHor, moduleIntvlVer, rackQty, lessSupFitQty } = surface.trestleDetail
if (rackYn === 'N') {
rackQty = lessSupFitQty
}
// 같은 단에 있는 모듈들의 리스트
let sameLineModuleList = []
let result = []
if (direction === 'south') {
// 모듈의 top으로 groupBy
const groupedByTop = modules.reduce((acc, module) => {
const key = module.top
if (!acc[key]) {
acc[key] = []
}
acc[key].push(module)
return acc
}, {})
// groupedByTop의 키값을 기준으로 정렬한 데이터를 배열로 변환
sameLineModuleList = Object.values(groupedByTop).sort((a, b) => b[0].top - a[0].top)
} else if (direction === 'north') {
const groupedByTop = modules.reduce((acc, module) => {
const key = module.top
if (!acc[key]) {
acc[key] = []
}
acc[key].push(module)
return acc
}, {})
sameLineModuleList = Object.values(groupedByTop).sort((a, b) => a[0].top - b[0].top)
} else if (direction === 'east') {
const groupedByLeft = modules.reduce((acc, module) => {
const key = module.left
if (!acc[key]) {
acc[key] = []
}
acc[key].push(module)
return acc
}, {})
sameLineModuleList = Object.values(groupedByLeft).sort((a, b) => a[0].left - b[0].left)
} else if (direction === 'west') {
const groupedByLeft = modules.reduce((acc, module) => {
const key = module.left
if (!acc[key]) {
acc[key] = []
}
acc[key].push(module)
return acc
}, {})
sameLineModuleList = Object.values(groupedByLeft).sort((a, b) => b[0].left - a[0].left)
}
sameLineModuleList.forEach((modules, index) => {
const moduleRowResultData = {
seq: index,
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) => {
// 해당 모듈 주변에 다른 모듈이 있는지 확인
let {
bottomModule,
topModule,
halfBottomLeftModule,
halfBottomRightModule,
halfTopLeftModule,
halfTopRightModule,
leftModule,
rightModule,
bottomLeftModule,
bottomRightModule,
} = findSideModule(module, surface)
if (bottomModule) {
moduleRowResultData.touchedSurfaceCnt++
}
if (!bottomModule) {
if (halfBottomLeftModule && halfBottomRightModule) {
moduleRowResultData.touchedSurfaceCnt++
} else if ((halfBottomLeftModule && !halfBottomRightModule) || (!halfBottomLeftModule && halfBottomRightModule)) {
moduleRowResultData.touchedHalfSurfaceCnt++
moduleRowResultData.exposedHalfBottomCnt++
if (cvrPlvrYn === 'Y') {
moduleRowResultData.eavesHalfCnt++
if (bottomLeftModule || bottomRightModule || halfBottomLeftModule || halfBottomRightModule) {
//처마커버 한개 노출 추가
moduleRowResultData.exposedSideEavesCnt++
}
}
} else {
moduleRowResultData.exposedBottomCnt++
if (isEaveBar) {
moduleRowResultData.eavesCnt++
if ((rightModule && !leftModule) || (!rightModule && leftModule)) {
// 둘중 하나가 없는경우는 처마커버 노출 추가
moduleRowResultData.exposedSideEavesCnt++
}
}
}
}
if (!topModule) {
if ((halfTopLeftModule && !halfTopRightModule) || (!halfTopLeftModule && halfTopRightModule)) {
moduleRowResultData.exposedHalfTopCnt++
} else if (!halfTopLeftModule && !halfTopRightModule) {
moduleRowResultData.exposedTopCnt++
}
}
})
result.push(moduleRowResultData)
})
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 = 2 + horizontal * 3
const maxY = 2 + vertical * 3
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
bottomModule = centerPoints.find((centerPoint) => Math.abs(centerPoint.x - x) < maxX && Math.abs(centerPoint.y - (y + height)) < maxY)
halfBottomLeftPoint = { x: x - width / 2, y: y + height }
halfBottomRightPoint = { x: x + width / 2, y: y + height }
topModule = centerPoints.find((centerPoint) => Math.abs(centerPoint.x - x) < maxX && Math.abs(centerPoint.y - (y - height)) < maxY)
halfTopLeftPoint = { x: x - width / 2, y: y - height }
halfTopRightPoint = { x: x + width / 2, y: y - height }
leftPoint = { x: x - width, y: y }
rightPoint = { x: x + width, y: y }
bottomLeftModule = { x: x - width, y: y + height }
bottomRightModule = { x: x + width, y: y + height }
break
case 'north':
width = width + horizontal
height = height + vertical
bottomModule = centerPoints.find((centerPoint) => Math.abs(centerPoint.x - x) < maxX && Math.abs(centerPoint.y - (y - height)) < maxY)
halfBottomLeftPoint = { x: x + width / 2, y: y - height }
halfBottomRightPoint = { x: x - width / 2, y: y - height }
topModule = centerPoints.find((centerPoint) => Math.abs(centerPoint.x - x) < maxX && Math.abs(centerPoint.y - (y + height)) < maxY)
halfTopLeftPoint = { x: x + width / 2, y: y + height }
halfTopRightPoint = { x: x - width / 2, y: y + height }
leftPoint = { x: x + width, y: y }
rightPoint = { x: x - width, y: y }
bottomLeftModule = { x: x + width, y: y - height }
bottomRightModule = { x: x - width, y: y - height }
break
case 'east':
bottomModule = centerPoints.find((centerPoint) => Math.abs(centerPoint.x - (x + width)) < maxX && Math.abs(centerPoint.y - y) < maxY)
width = width + horizontal
halfBottomLeftPoint = { x: x + width, y: y + height / 2 }
halfBottomRightPoint = { x: x + width, y: y - height / 2 }
topModule = centerPoints.find((centerPoint) => Math.abs(centerPoint.x - (x - width)) < maxX && Math.abs(centerPoint.y - y) < maxY)
halfTopLeftPoint = { x: x - width, y: y + height / 2 }
halfTopRightPoint = { x: x - width, y: y - height / 2 }
leftPoint = { x: x, y: y + height }
rightPoint = { x: x, y: y - height }
bottomLeftModule = { x: x + width, y: y + height }
bottomRightModule = { x: x + width, y: y - height }
break
case 'west':
bottomModule = centerPoints.find((centerPoint) => Math.abs(centerPoint.x - (x - width)) < maxX && Math.abs(centerPoint.y - y) < maxY)
width = width + horizontal
halfBottomLeftPoint = { x: x - width, y: y - height / 2 }
halfBottomRightPoint = { x: x - width, y: y + height / 2 }
topModule = centerPoints.find((centerPoint) => Math.abs(centerPoint.x - (x + width)) < maxX && Math.abs(centerPoint.y - y) < maxY)
halfTopLeftPoint = { x: x + width, y: y - height / 2 }
halfTopRightPoint = { x: x + width, y: y + height / 2 }
leftPoint = { x: x, y: y - height }
rightPoint = { x: x, y: y + height }
bottomLeftModule = { x: x - width, y: y - height }
bottomRightModule = { x: x - width, y: y + height }
break
}
halfTopLeftModule = centerPoints.find(
(centerPoint) => Math.abs(centerPoint.x - halfTopLeftPoint.x) < maxX && Math.abs(centerPoint.y - halfTopLeftPoint.y) < maxY,
)
halfTopRightModule = centerPoints.find(
(centerPoint) => Math.abs(centerPoint.x - halfTopRightPoint.x) < maxX && Math.abs(centerPoint.y - halfTopRightPoint.y) < maxY,
)
halfBottomLeftModule = centerPoints.find(
(centerPoint) => Math.abs(centerPoint.x - halfBottomLeftPoint.x) < maxX && Math.abs(centerPoint.y - halfBottomLeftPoint.y) < maxY,
)
halfBottomRightModule = centerPoints.find(
(centerPoint) => Math.abs(centerPoint.x - halfBottomRightPoint.x) < maxX && Math.abs(centerPoint.y - halfBottomRightPoint.y) < maxY,
)
leftModule = centerPoints.find((centerPoint) => Math.abs(centerPoint.x - leftPoint.x) < maxX && Math.abs(centerPoint.y - leftPoint.y) < maxY)
rightModule = centerPoints.find((centerPoint) => Math.abs(centerPoint.x - rightPoint.x) < maxX && Math.abs(centerPoint.y - rightPoint.y) < maxY)
bottomLeftModule = centerPoints.find(
(centerPoint) => Math.abs(centerPoint.x - bottomLeftModule.x) < maxX && Math.abs(centerPoint.y - bottomLeftModule.y) < maxY,
)
bottomRightModule = centerPoints.find(
(centerPoint) => Math.abs(centerPoint.x - bottomRightModule.x) < maxX && Math.abs(centerPoint.y - bottomRightModule.y) < maxY,
)
return {
bottomModule,
topModule,
halfBottomLeftModule,
halfBottomRightModule,
halfTopLeftModule,
halfTopRightModule,
leftModule,
rightModule,
bottomLeftModule,
bottomRightModule,
}
}
const clear = () => {
canvas.getObjects().forEach((obj) => {
if (obj.name === 'eaveBar' || obj.name === 'rack' || obj.name === 'halfEaveBar' || obj.name === 'smartRack' || obj.name === 'bracket') {
canvas.remove(obj)
}
})
}
return { apply, getTrestleParams, clear }
}