qcast-front/src/hooks/surface/useSurfaceShapeBatch.js

1068 lines
35 KiB
JavaScript

'use client'
import { useEffect } from 'react'
import { useRecoilState, useRecoilValue, useResetRecoilState } from 'recoil'
import { canvasState, globalPitchState } from '@/store/canvasAtom'
import { MENU, POLYGON_TYPE } from '@/common/common'
import { getIntersectionPoint } from '@/util/canvas-util'
import { degreesToRadians } from '@turf/turf'
import { QPolygon } from '@/components/fabric/QPolygon'
import { useSwal } from '@/hooks/useSwal'
import { useMessage } from '@/hooks/useMessage'
import { useEvent } from '@/hooks/useEvent'
import { usePopup } from '@/hooks/usePopup'
import { roofDisplaySelector } from '@/store/settingAtom'
import { usePolygon } from '@/hooks/usePolygon'
import { fontSelector } from '@/store/fontAtom'
import { slopeSelector } from '@/store/commonAtom'
import { QLine } from '@/components/fabric/QLine'
import { useRoofFn } from '@/hooks/common/useRoofFn'
import { outerLinePointsState } from '@/store/outerLineAtom'
import { placementShapeDrawingPointsState } from '@/store/placementShapeDrawingAtom'
export function useSurfaceShapeBatch({ isHidden, setIsHidden }) {
const { getMessage } = useMessage()
const { drawDirectionArrow } = usePolygon()
const lengthTextFont = useRecoilValue(fontSelector('lengthText'))
const resetOuterLinePoints = useResetRecoilState(outerLinePointsState)
const resetPlacementShapeDrawingPoints = useResetRecoilState(placementShapeDrawingPointsState)
const canvas = useRecoilValue(canvasState)
const globalPitch = useRecoilValue(globalPitchState)
const roofDisplay = useRecoilValue(roofDisplaySelector)
const slope = useRecoilValue(slopeSelector(globalPitch))
const { swalFire } = useSwal()
const { addCanvasMouseEventListener, initEvent } = useEvent()
// const { addCanvasMouseEventListener, initEvent } = useContext(EventContext)
const { closePopup } = usePopup()
const { setSurfaceShapePattern } = useRoofFn()
const applySurfaceShape = (surfaceRefs, selectedType, id) => {
let length1, length2, length3, length4, length5
const surfaceId = selectedType?.id
const azimuth = surfaceRefs.azimuth.current
if (surfaceId === 1) {
length1 = surfaceRefs.length1.current.value
length2 = surfaceRefs.length2.current.value
length3 = surfaceRefs.lengthetc.current.value //대각선
} else if ([2, 4].includes(surfaceId)) {
length1 = surfaceRefs.length1.current.value
length2 = surfaceRefs.length2.current.value
} else if ([3, 5, 6, 15, 18].includes(surfaceId)) {
length1 = surfaceRefs.length1.current.value
length2 = surfaceRefs.length2.current.value
length3 = surfaceRefs.length3.current.value
} else if ([8, 12, 13, 16, 17].includes(surfaceId)) {
length1 = surfaceRefs.length1.current.value
length2 = surfaceRefs.length2.current.value
length3 = surfaceRefs.length3.current.value
length4 = surfaceRefs.length4.current.value
} else if ([7, 9, 10, 11, 14].includes(surfaceId)) {
length1 = surfaceRefs.length1.current.value
length2 = surfaceRefs.length2.current.value
length3 = surfaceRefs.length3.current.value
length4 = surfaceRefs.length4.current.value
length5 = surfaceRefs.length5.current.value
}
length1 = parseInt(length1 === undefined ? 0 : length1 / 10)
length2 = parseInt(length2 === undefined ? 0 : length2 / 10)
length3 = parseInt(length3 === undefined ? 0 : length3 / 10)
length4 = parseInt(length4 === undefined ? 0 : length4 / 10)
length5 = parseInt(length5 === undefined ? 0 : length5 / 10)
let isDrawing = true
let obj = null
let points = []
//일단 팝업을 가린다
if (checkSurfaceShape(surfaceId, { length1, length2, length3, length4, length5 })) {
addCanvasMouseEventListener('mouse:move', (e) => {
if (!isDrawing) {
return
}
const pointer = canvas?.getPointer(e.e)
canvas?.remove(...canvas?.getObjects().filter((obj) => obj.name === MENU.BATCH_CANVAS.SURFACE_SHAPE_BATCH_TEMP))
points = getSurfaceShape(surfaceId, pointer, { length1, length2, length3, length4, length5 })
const { xInversion, yInversion, rotate } = surfaceRefs
const options = {
fill: 'transparent',
stroke: 'black',
strokeWidth: 1,
strokeDasharray: [10, 4],
fontSize: 12,
selectable: true,
lockMovementX: true, // X 축 이동 잠금
lockMovementY: true, // Y 축 이동 잠금
lockRotation: true, // 회전 잠금
lockScalingX: true, // X 축 크기 조정 잠금
lockScalingY: true, // Y 축 크기 조정 잠금
name: MENU.BATCH_CANVAS.SURFACE_SHAPE_BATCH_TEMP,
flipX: xInversion !== yInversion,
// angle: xInversion && yInversion ? Math.abs((rotate + 180) % 360) : Math.abs(rotate),
// angle: rotate,
originX: 'center',
originY: 'center',
pitch: globalPitch,
}
obj = new QPolygon(points, options)
let imageRotate = 0
if (xInversion && !yInversion) {
if (rotate % 180 === 0 || rotate < 0) {
imageRotate = Math.abs(rotate % 360)
} else {
imageRotate = Math.abs((rotate - 180) % 4)
}
} else if (xInversion && yInversion) {
imageRotate = Math.abs((rotate + 360) % 360)
} else if (xInversion !== yInversion && rotate < 0) {
imageRotate = Math.abs(rotate)
} else if (!xInversion && yInversion) {
if (rotate % 180 === 0 || rotate < 0) {
imageRotate = Math.abs(rotate % 360)
} else {
if (rotate < 0) {
imageRotate = Math.abs((rotate + 180) % 360)
} else {
imageRotate = Math.abs((rotate - 180) % 360)
}
}
} else {
imageRotate = (rotate + 360) % 360
}
obj.set({ angle: imageRotate })
obj.setCoords() //좌표 변경 적용
canvas?.add(obj)
canvas?.renderAll()
})
addCanvasMouseEventListener('mouse:down', (e) => {
isDrawing = false
canvas?.remove(obj)
//각도 추가
let originAngle = 0 //기본 남쪽
let direction = 'south'
if (azimuth === 'left') {
//서
originAngle = 90
direction = 'west'
} else if (azimuth === 'right') {
//동
originAngle = 270
direction = 'east'
} else if (azimuth === 'up') {
//북
originAngle = 180
direction = 'north'
}
//회전, flip등이 먹은 기준으로 새로생성
const batchSurface = new QPolygon(obj.getCurrentPoints(), {
fill: 'transparent',
stroke: 'red',
strokeWidth: 1,
strokeDasharray: [10, 4],
fontSize: 12,
selectable: true,
lockMovementX: true, // X 축 이동 잠금
lockMovementY: true, // Y 축 이동 잠금
lockRotation: true, // 회전 잠금
lockScalingX: true, // X 축 크기 조정 잠금
lockScalingY: true, // Y 축 크기 조정 잠금
name: POLYGON_TYPE.ROOF,
originX: 'center',
originY: 'center',
pitch: globalPitch,
surfaceId: surfaceId,
direction: direction,
})
canvas?.add(batchSurface)
canvas.setActiveObject(batchSurface)
setSurfaceShapePattern(batchSurface, roofDisplay.column)
drawDirectionArrow(batchSurface)
if (setIsHidden) setIsHidden(false)
// closePopup(id)
initEvent()
})
} else {
if (setIsHidden) setIsHidden(false)
}
}
//면형상 입력 validate
const checkSurfaceShape = (surfaceId, lengths) => {
const { length1, length2, length3, length4, length5 } = lengths
let check = true
if (surfaceId === 1) {
if (length1 === 0) {
swalFire({ text: getMessage('common.canvas.validate.size'), icon: 'error' })
check = false
}
if (length2 === 0) {
if (length3 === 0) {
swalFire({ text: getMessage('common.canvas.validate.size'), icon: 'error' })
check = false
}
}
} else if ([2, 4].includes(surfaceId)) {
if (length1 === 0 || length2 === 0) {
swalFire({ text: getMessage('common.canvas.validate.size'), icon: 'error' })
check = false
}
} else if ([3, 5, 6, 15, 18].includes(surfaceId)) {
if (length1 === 0 || length2 === 0 || length3 === 0) {
swalFire({ text: getMessage('common.canvas.validate.size'), icon: 'error' })
check = false
}
if (surfaceId === 3 && length3 >= length1) {
swalFire({ text: getMessage('surface.shape.validate.size.1to3'), icon: 'error' })
check = false
}
if (surfaceId === 5 || surfaceId === 15) {
if (length3 >= length2) {
swalFire({ text: getMessage('surface.shape.validate.size.2to3'), icon: 'error' })
check = false
}
}
if (surfaceId === 18) {
if (length2 >= length3) {
swalFire({ text: getMessage('surface.shape.validate.size.3to2'), icon: 'error' })
check = false
}
}
if (surfaceId === 6) {
if (length2 >= length3) {
swalFire({ text: getMessage('surface.shape.validate.size.3to2'), icon: 'error' })
check = false
}
}
} else if ([8, 12, 13, 16, 17].includes(surfaceId)) {
if (length1 === 0 || length2 === 0 || length3 === 0 || length4 === 0) {
swalFire({ text: getMessage('common.canvas.validate.size'), icon: 'error' })
check = false
}
if (surfaceId === 8) {
if (length2 >= length1) {
swalFire({ text: getMessage('surface.shape.validate.size.1to2'), icon: 'error' })
check = false
}
if (length4 >= length3) {
swalFire({ text: getMessage('surface.shape.validate.size.3to4'), icon: 'error' })
check = false
}
}
if (surfaceId === 12 || surfaceId === 13 || surfaceId === 16) {
if (length2 >= length1) {
swalFire({ text: getMessage('surface.shape.validate.size.1to2'), icon: 'error' })
check = false
}
if (length4 >= length3) {
swalFire({ text: getMessage('surface.shape.validate.size.1to2'), icon: 'error' })
check = false
}
}
if (surfaceId === 17) {
if (length2 >= length1) {
swalFire({ text: getMessage('surface.shape.validate.size.1to2'), icon: 'error' })
check = false
}
if (length3 >= length4) {
swalFire({ text: getMessage('surface.shape.validate.size.4to3'), icon: 'error' })
check = false
}
}
} else if ([7, 9, 10, 11, 14].includes(surfaceId)) {
if (length1 === 0 || length2 === 0 || length3 === 0 || length4 === 0 || length5 === 0) {
swalFire({ text: getMessage('common.canvas.validate.size'), icon: 'error' })
check = false
}
if (surfaceId === 9 || surfaceId === 10) {
if (length2 + length3 >= length1) {
swalFire({ text: getMessage('surface.shape.validate.size.1to23'), icon: 'error' })
check = false
}
if (length5 >= length4) {
swalFire({ text: getMessage('surface.shape.validate.size.4to5'), icon: 'error' })
check = false
}
}
if (surfaceId === 11) {
if (length1 > length2 + length3) {
swalFire({ text: getMessage('surface.shape.validate.size.1to23low'), icon: 'error' })
check = false
}
if (length5 >= length4) {
swalFire({ text: getMessage('surface.shape.validate.size.4to5'), icon: 'error' })
check = false
}
}
if (surfaceId === 14) {
if (length2 + length3 >= length1) {
swalFire({ text: getMessage('surface.shape.validate.size.1to23'), icon: 'error' })
check = false
}
if (length5 >= length4) {
swalFire({ text: getMessage('surface.shape.validate.size.4to5'), icon: 'error' })
check = false
}
}
}
return check
}
//면형상 가져오기
const getSurfaceShape = (surfaceId, pointer, lengths) => {
let points = []
const { length1, length2, length3, length4, length5 } = lengths
switch (surfaceId) {
case 1: {
let newLength2 = length2
if (length3 !== 0) {
newLength2 = Math.sqrt(length3 ** 2 - (length1 / 2) ** 2)
}
points = [
{ x: pointer.x, y: pointer.y - parseInt(newLength2) / 2 },
{ x: pointer.x - parseInt(length1) / 2, y: pointer.y + parseInt(newLength2) / 2 },
{ x: pointer.x + parseInt(length1) / 2, y: pointer.y + parseInt(newLength2) / 2 },
]
break
}
case 2: {
points = [
{ x: pointer.x - length1 / 2, y: pointer.y + length2 / 2 },
{ x: pointer.x + length1 / 2, y: pointer.y + length2 / 2 },
{ x: pointer.x + length1 / 2, y: pointer.y - length2 / 2 },
{ x: pointer.x - length1 / 2, y: pointer.y - length2 / 2 },
]
break
}
case 3: {
points = [
{ x: pointer.x - length1 / 2, y: pointer.y + length2 / 2 },
{ x: pointer.x + length1 / 2, y: pointer.y + length2 / 2 },
{ x: pointer.x + length3 / 2, y: pointer.y - length2 / 2 },
{ x: pointer.x - length3 / 2, y: pointer.y - length2 / 2 },
]
break
}
case 4: {
points = [
{ x: pointer.x - length1 / 2, y: pointer.y + length2 / 2 },
{ x: pointer.x + length1 / 2, y: pointer.y + length2 / 2 },
{ x: pointer.x + length1 / 2, y: pointer.y - length2 / 2 },
]
break
}
case 5: {
points = [
{ x: pointer.x - length1 / 2, y: pointer.y - length3 / 2 },
{ x: pointer.x - length1 / 2, y: pointer.y + length3 / 2 },
{ x: pointer.x + length1 / 2, y: pointer.y + length3 / 2 },
{ x: pointer.x + length1 / 2, y: pointer.y + length3 / 2 - length2 },
]
break
}
case 6: {
const angleInRadians = Math.asin(length2 / length3)
points = [
{ x: pointer.x - length1 / 2, y: pointer.y + length2 / 2 },
{
x: pointer.x - length1 / 2 + length3 * Math.cos(angleInRadians),
y: pointer.y + length2 / 2 - length3 * Math.sin(angleInRadians),
},
{
x: pointer.x + length1 / 2 + length3 * Math.cos(angleInRadians),
y: pointer.y + length2 / 2 - length3 * Math.sin(angleInRadians),
},
{ x: pointer.x + length1 / 2, y: pointer.y + length2 / 2 },
]
break
}
case 7: {
points = [
{ x: pointer.x - (length1 + length2 + length3) / 2, y: pointer.y - (length4 + length5) / 2 },
{ x: pointer.x - (length1 + length2 + length3) / 2, y: pointer.y + (length4 + length5) / 2 },
{ x: pointer.x - (length1 + length2 + length3) / 2 + length1, y: pointer.y + (length4 + length5) / 2 },
{
x: pointer.x - (length1 + length2 + length3) / 2 + length1,
y: pointer.y + (length4 + length5) / 2 - length5,
},
{
x: pointer.x - (length1 + length2 + length3) / 2 + length1 + length2,
y: pointer.y + (length4 + length5) / 2 - length5,
},
{
x: pointer.x - (length1 + length2 + length3) / 2 + length1 + length2,
y: pointer.y + (length4 + length5) / 2 - length5 + length5,
},
{
x: pointer.x - (length1 + length2 + length3) / 2 + length1 + length2 + length3,
y: pointer.y + (length4 + length5) / 2 - length5 + length5,
},
{
x: pointer.x - (length1 + length2 + length3) / 2 + length1 + length2 + length3,
y: pointer.y + (length4 + length5) / 2 - length5 + length5 - (length4 + length5),
},
]
break
}
case 8: {
points = [
{ x: pointer.x - length1 / 2, y: pointer.y + length4 / 2 },
{ x: pointer.x - length1 / 2 + length1, y: pointer.y + length4 / 2 },
{ x: pointer.x - length1 / 2 + length1, y: pointer.y + length4 / 2 - length3 },
{ x: pointer.x - length1 / 2 + length1 - (length1 - length2), y: pointer.y + length4 / 2 - length3 },
{
x: pointer.x - length1 / 2 + length1 - (length1 - length2),
y: pointer.y + length4 / 2 - length3 + (length3 - length4),
},
{
x: pointer.x - length1 / 2 + length1 - (length1 - length2) - length2,
y: pointer.y + length4 / 2 - length3 + (length3 - length4),
},
]
break
}
case 9: {
points = [
{ x: pointer.x - length1 / 2, y: pointer.y + length4 / 2 },
{ x: pointer.x - length1 / 2 + length1, y: pointer.y + length4 / 2 },
{ x: pointer.x - length1 / 2 + length1, y: pointer.y + length4 / 2 - length4 },
{ x: pointer.x - length1 / 2 + length1 - length3, y: pointer.y + length4 / 2 - length4 },
{
x: pointer.x - length1 / 2 + length1 - length3,
y: pointer.y + length4 / 2 - length4 + (length4 - length5),
},
{
x: pointer.x - length1 / 2 + length1 - length3 - length2,
y: pointer.y + length4 / 2 - length4 + (length4 - length5),
},
]
break
}
case 10: {
points = [
{ x: pointer.x + length1 / 2, y: pointer.y + length4 / 2 },
{ x: pointer.x + length1 / 2 - length1, y: pointer.y + length4 / 2 },
{ x: pointer.x + length1 / 2 - length1, y: pointer.y + length4 / 2 - length5 },
{ x: pointer.x + length1 / 2 - length1 + length2, y: pointer.y + length4 / 2 - length5 },
{
x: pointer.x + length1 / 2 - length1 + length2,
y: pointer.y + length4 / 2 - length5 - (length4 - length5),
},
{
x: pointer.x + length1 / 2 - length1 + length2 + length3,
y: pointer.y + length4 / 2 - length5 - (length4 - length5),
},
]
break
}
case 11: {
points = [
{ x: pointer.x - length1 / 2, y: pointer.y + length4 / 2 },
{ x: pointer.x - length1 / 2 + length1, y: pointer.y + length4 / 2 },
{ x: pointer.x - length1 / 2 + length1, y: pointer.y + length4 / 2 - length5 },
{ x: pointer.x - length1 / 2 + length1 - length2, y: pointer.y + length4 / 2 - length5 },
{
x: pointer.x - length1 / 2 + length1 - length2,
y: pointer.y + length4 / 2 - length5 - (length4 - length5),
},
{
x: pointer.x - length1 / 2 + length1 - length2 - length3,
y: pointer.y + length4 / 2 - length5 - (length4 - length5),
},
]
break
}
case 12: {
const leftHypotenuse = Math.sqrt(((length1 - length2) / 2) ** 2 + length3 ** 2)
const rightHypotenuse = (length4 / length3) * leftHypotenuse
const leftAngle = Math.acos((length1 - length2) / 2 / leftHypotenuse)
points = [
{
x: pointer.x - length1 / 2 + leftHypotenuse * Math.cos(leftAngle),
y: pointer.y + length3 / 2 - leftHypotenuse * Math.sin(leftAngle),
},
{ x: pointer.x - length1 / 2, y: pointer.y + length3 / 2 },
{ x: pointer.x + length1 / 2, y: pointer.y + length3 / 2 },
{
x: pointer.x + length1 / 2 - rightHypotenuse * Math.cos(leftAngle),
y: pointer.y + length3 / 2 - rightHypotenuse * Math.sin(leftAngle),
},
{
x: pointer.x + length1 / 2 - rightHypotenuse * Math.cos(leftAngle) - length2,
y: pointer.y + length3 / 2 - rightHypotenuse * Math.sin(leftAngle),
},
]
break
}
case 13: {
const pointsArray = [
{ x: 0, y: 0 },
{ x: 0, y: 0 },
{ x: 0, y: 0 },
{ x: 0, y: 0 },
{ x: 0, y: 0 },
]
const tmpPolygon = new QPolygon(
[
{ x: 0, y: length3 },
{ x: length1 - length2, y: length3 },
{ x: (length1 - length2) / 2, y: length3 - length3 },
],
{
fill: 'transparent',
stroke: 'black', //black
strokeWidth: 1,
selectable: false,
fontSize: 0,
},
)
const coord = getIntersectionPoint(tmpPolygon.lines[1].startPoint, tmpPolygon.lines[2].startPoint, length3 - length4)
const scale = (length1 - length2) / coord.x
tmpPolygon.set({ scaleX: scale })
tmpPolygon.setViewLengthText(false)
pointsArray[0].x = 0
pointsArray[0].y = length3 //바닥면부터 시작하게
pointsArray[1].x = pointsArray[0].x + length1
pointsArray[1].y = pointsArray[0].y
pointsArray[2].x = pointsArray[1].x
pointsArray[2].y = pointsArray[1].y - length4
pointsArray[3].x = pointsArray[2].x - length2
pointsArray[3].y = pointsArray[2].y
pointsArray[4].x = tmpPolygon.getCurrentPoints()[2].x
pointsArray[4].y = tmpPolygon.getCurrentPoints()[2].y
points = [
{
x: pointer.x - length1 / 2,
y: pointer.y + length4 / 2,
},
{
x: pointer.x + length1 / 2,
y: pointer.y + length4 / 2,
},
{
x: pointer.x + length1 / 2,
y: pointer.y - length4 / 2,
},
{
x: pointer.x - (length2 - length1 / 2),
y: pointer.y - length4 / 2,
},
{
x: pointer.x - length1 / 2 + pointsArray[4].x,
y: pointer.y - length3 + length4 / 2,
},
]
break
}
case 14: {
points = [
{ x: pointer.x - length1 / 2 + length2, y: pointer.y + length4 / 2 },
{ x: pointer.x - length1 / 2, y: pointer.y + length4 / 2 },
{ x: pointer.x - length1 / 2, y: pointer.y + length4 / 2 - length4 },
{ x: pointer.x - length1 / 2 + length1, y: pointer.y + length4 / 2 - length4 },
{ x: pointer.x - length1 / 2 + length1, y: pointer.y + length4 / 2 - length4 + length4 },
{ x: pointer.x - length1 / 2 + length1 - length3, y: pointer.y + length4 / 2 - length4 + length4 },
{
x: pointer.x - length1 / 2 + length2 + (length1 - length2 - length3) / 2,
y: pointer.y + length4 / 2 - length4 + length5,
},
]
break
}
case 15: {
points = [
{ x: pointer.x - length1 / 2, y: pointer.y + length2 - length2 / 2 },
{ x: pointer.x - length1 / 2, y: pointer.y + length2 - length2 / 2 - length3 },
{ x: pointer.x, y: pointer.y + length2 - length2 / 2 - length3 - (length2 - length3) },
{ x: pointer.x + length1 / 2, y: pointer.y + length2 - length2 / 2 - length3 },
{ x: pointer.x + length1 / 2, y: pointer.y + length2 - length2 / 2 - length3 + length3 },
]
break
}
case 16: {
points = [
{
x: pointer.x - length1 / 2,
y: pointer.y + length3 / 2,
},
{
x: pointer.x - length1 / 2 + (length1 - length2) / 2,
y: pointer.y + length3 / 2 - (length3 - length4),
},
{
x: pointer.x - length1 / 2 + (length1 - length2) / 2,
y: pointer.y + length3 / 2 - (length3 - length4) - length4,
},
{
x: pointer.x - length1 / 2 + (length1 - length2) / 2 + length2,
y: pointer.y + length3 / 2 - (length3 - length4) - length4,
},
{
x: pointer.x - length1 / 2 + (length1 - length2) / 2 + length2,
y: pointer.y + length3 / 2 - (length3 - length4) - length4 + length4,
},
{
x: pointer.x - length1 / 2 + length1,
y: pointer.y + length3 / 2,
},
]
break
}
case 17: {
const angle = (Math.asin(length3 / length4) * 180) / Math.PI // 높이와 빗변으로 먼저 각도구하기
const topL = (length1 - length2) / 2 / Math.cos((angle * Math.PI) / 180) // 꺽이는부분 윗쪽 길이
points = [
{
x: pointer.x - length1 / 2 + length1,
y: pointer.y + length3 / 2,
},
{
x: pointer.x - length1 / 2,
y: pointer.y + length3 / 2,
},
{
x: pointer.x - length1 / 2 + length4 * Math.cos(degreesToRadians(angle)),
y: pointer.y + length3 / 2 - length4 * Math.sin(degreesToRadians(angle)),
},
{
x: pointer.x - length1 / 2 + length4 * Math.cos(degreesToRadians(angle)) + length2,
y: pointer.y + length3 / 2 - length4 * Math.sin(degreesToRadians(angle)),
},
{
x: pointer.x - length1 / 2 + length4 * Math.cos(degreesToRadians(angle)) + length2 + topL * Math.cos(degreesToRadians(angle)),
y: pointer.y + length3 / 2 - length4 * Math.sin(degreesToRadians(angle)) + topL * Math.sin(degreesToRadians(angle)),
},
]
break
}
case 18: {
const a = Math.sqrt(length3 * length3 - length2 * length2) // 입력된 밑변과 높이
const sinA = a / length3
const angleInRadians = Math.asin(sinA)
const angleInDegrees = angleInRadians * (180 / Math.PI)
const b = a - length1 / 2
const c = b / Math.tan(angleInRadians)
const d = Math.sqrt(b * b + c * c)
const newAngleInRadians = (90 - angleInDegrees) * (Math.PI / 180)
points = [
{ x: pointer.x - (length1 + b) / 2, y: pointer.y + length2 / 2 },
{ x: pointer.x + length1 / 2 - b / 2, y: pointer.y + length2 / 2 },
{
x: pointer.x + length1 / 2 - b / 2 + d * Math.cos(newAngleInRadians),
y: pointer.y + length2 / 2 - d * Math.sin(newAngleInRadians),
},
{
x: pointer.x - (length1 + b) / 2 + length3 * Math.cos(newAngleInRadians),
y: pointer.y + length2 / 2 - length3 * Math.sin(newAngleInRadians),
},
]
break
}
}
return points
}
const deleteAllSurfacesAndObjects = () => {
swalFire({
text: getMessage('batch.canvas.delete.all'),
type: 'confirm',
confirmFn: () => {
canvas.clear()
resetOuterLinePoints()
resetPlacementShapeDrawingPoints()
swalFire({ text: getMessage('plan.message.delete') })
},
// denyFn: () => {
// swalFire({ text: '취소되었습니다.', icon: 'error' })
// },
})
}
const findAllChildren = (parentId) => {
let allChildren = []
// 직계 자식 객체들 찾기
const directChildren = canvas.getObjects().filter((obj) => obj.parentId === parentId)
directChildren.forEach((child) => {
allChildren.push(child) // 현재 자식 추가
// 자식이 그룹인 경우
if (child.type === 'group') {
// 그룹 내부의 객체들 추가
child.getObjects().forEach((groupItem) => {
allChildren.push(groupItem)
// 그룹 내부 객체의 자식들도 찾기
const nestedChildren = findAllChildren(groupItem.id)
allChildren.push(...nestedChildren)
})
}
// 현재 자식의 하위 자식들 찾기
const childrenOfChild = findAllChildren(child.id)
allChildren.push(...childrenOfChild)
})
// 중복 제거하여 반환
return [...new Set(allChildren)]
}
const findGroupObjects = (parentId) => {
let groupObjectsArray = []
// 직계 자식 객체들 찾기
const directChildren = canvas.getObjects().filter((obj) => obj.parentId === parentId)
// 각 자식 객체에 대해 처리
directChildren.forEach((child) => {
groupObjectsArray.push(child) // 현재 자식 추가
// 자식이 그룹인 경우 그룹 내부 객체들도 처리
if (child.type === 'group') {
child.getObjects().forEach((groupItem) => {
// 그룹 내부 각 아이템의 하위 객체들 찾기
const nestedObjects = findGroupObjects(groupItem.id)
groupObjectsArray.push(...nestedObjects)
})
}
// 일반 자식의 하위 객체들 찾기
const childObjects = findGroupObjects(child.id)
groupObjectsArray.push(...childObjects)
})
return groupObjectsArray
}
const moveSurfaceShapeBatch = () => {
const roof = canvas.getActiveObject()
if (roof) {
const childrenObjects = canvas.getObjects().filter((obj) => obj.parentId === roof.id)
const selectionArray = [roof, ...childrenObjects]
const selection = new fabric.ActiveSelection(selectionArray, {
canvas: canvas,
draggable: true,
lockMovementX: false, // X축 이동 허용
lockMovementY: false, // Y축 이동 허용
originX: 'center',
originY: 'center',
})
canvas.setActiveObject(selection)
addCanvasMouseEventListener('mouse:up', (e) => {
canvas.selection = true
canvas.discardActiveObject() // 모든 선택 해제
canvas.requestRenderAll() // 화면 업데이트
selection.getObjects().forEach((obj) => {
obj.set({
lockMovementX: true,
lockMovementY: true,
})
obj.setCoords()
if (obj.type === 'group') {
reGroupObject(obj)
}
})
canvas.renderAll()
roof.fire('polygonMoved')
drawDirectionArrow(roof)
initEvent()
})
}
}
const reGroupObject = (groupObj) => {
groupObj._restoreObjectsState() //이건 실행만 되도 그룹이 변경됨
const reGroupObjects = []
groupObj._objects.forEach((obj) => {
const newObj = new QPolygon(obj.getCurrentPoints(), {
...obj,
points: obj.getCurrentPoints(),
scaleX: 1,
scaleY: 1,
})
reGroupObjects.push(newObj)
canvas.remove(obj)
if (obj.direction) {
drawDirectionArrow(obj)
}
})
const reGroup = new fabric.Group(reGroupObjects, {
subTargetCheck: true,
name: groupObj.name,
id: groupObj.id,
groupYn: true,
parentId: groupObj.parentId,
})
canvas?.add(reGroup)
canvas?.remove(groupObj)
}
const resizeSurfaceShapeBatch = (side, target, width, height) => {
const objectWidth = target.width
const objectHeight = target.height
const changeWidth = width / 10 / objectWidth
const changeHeight = height / 10 / objectHeight
let sideX = 'left'
let sideY = 'top'
//그룹 중심점 변경
if (side === 2) {
sideX = 'right'
sideY = 'top'
} else if (side === 3) {
sideX = 'left'
sideY = 'bottom'
} else if (side === 4) {
sideX = 'right'
sideY = 'bottom'
}
//변경 전 좌표
const newCoords = target.getPointByOrigin(sideX, sideY)
target.set({
originX: sideX,
originY: sideY,
left: newCoords.x,
top: newCoords.y,
})
target.scaleX = changeWidth
target.scaleY = changeHeight
const currentPoints = target.getCurrentPoints()
target.set({
scaleX: 1,
scaleY: 1,
width: parseInt((width / 10).toFixed(0)),
height: parseInt((height / 10).toFixed(0)),
})
//크기 변경후 좌표를 재 적용
const changedCoords = target.getPointByOrigin('center', 'center')
target.set({
originX: 'center',
originY: 'center',
left: changedCoords.x,
top: changedCoords.y,
})
//면형상 리사이즈시에만
target.fire('polygonMoved')
target.points = currentPoints
target.fire('modified')
setSurfaceShapePattern(target, roofDisplay.column)
if (target.direction) {
drawDirectionArrow(target)
}
target.setCoords()
canvas.renderAll()
}
const changeSurfaceLinePropertyEvent = () => {
let tmpLines = []
const roof = canvas.getActiveObject()
if (roof) {
roof.set({
selectable: false,
})
roof.lines.forEach((obj, index) => {
const tmpLine = new QLine([obj.x1, obj.y1, obj.x2, obj.y2], {
...obj,
stroke: 'rgb(3, 255, 0)',
strokeWidth: 8,
selectable: true,
name: 'lineProperty',
lineIndex: index,
})
tmpLines.push(tmpLine)
canvas.add(tmpLine)
})
addCanvasMouseEventListener('mouse:down', (e) => {
const selectedLine = e.target
if (selectedLine && selectedLine.name !== 'roof') {
tmpLines.forEach((line) => {
line.set({
stroke: 'rgb(3, 255, 0)',
name: 'lineProperty',
})
})
selectedLine.set({
stroke: 'red',
name: 'selectedLineProperty',
})
} else {
tmpLines.forEach((line) => {
line.set({
stroke: 'rgb(3, 255, 0)',
name: 'lineProperty',
})
})
}
})
canvas.renderAll()
}
canvas.discardActiveObject()
}
const changeSurfaceLineProperty = (property, roof) => {
if (!property) {
swalFire({ text: getMessage('modal.line.property.change'), icon: 'error' })
return
}
const selectedLine = canvas.getActiveObjects()[0] //배열로 떨어짐 한개만 선택가능
if (selectedLine && selectedLine.name === 'selectedLineProperty') {
swalFire({
text: getMessage('modal.line.property.change.confirm'),
type: 'confirm',
confirmFn: () => {
const lineIndex = selectedLine.lineIndex
roof.lines[lineIndex].attributes = {
...roof.lines[lineIndex].attributes,
type: property.value,
}
canvas.renderAll()
},
})
} else {
swalFire({ text: getMessage('modal.line.property.change.unselect'), icon: 'error' })
}
}
const changeSurfaceLinePropertyReset = (roof) => {
const lines = canvas.getObjects().filter((obj) => obj.name === 'lineProperty' || obj.name === 'selectedLineProperty')
lines.forEach((line) => {
canvas.remove(line)
})
if (roof) {
roof.set({
selectable: true,
})
}
canvas?.renderAll()
}
const updateFlippedPoints = (polygon) => {
if (!(polygon instanceof fabric.Polygon)) {
console.error('The object is not a Polygon.')
return
}
const { flipX, flipY, width, height, points, left, top, scaleX, scaleY } = polygon
// 현재 points의 사본 가져오기
const newPoints = points.map((point) => {
let x = point.x
let y = point.y
// flipX 적용
if (flipX) {
x = width - x
}
// flipY 적용
if (flipY) {
y = height - y
}
// 스케일 및 전역 좌표 고려
x = (x - width / 2) * scaleX + width / 2
y = (y - height / 2) * scaleY + height / 2
return { x, y }
})
// flipX, flipY를 초기화
polygon.flipX = false
polygon.flipY = false
// points 업데이트
polygon.set({ points: newPoints })
polygon.setCoords()
return polygon
}
return {
applySurfaceShape,
deleteAllSurfacesAndObjects,
moveSurfaceShapeBatch,
resizeSurfaceShapeBatch,
changeSurfaceLinePropertyEvent,
changeSurfaceLineProperty,
changeSurfaceLinePropertyReset,
}
}