qcast-front/src/hooks/object/useObjectBatch.js

718 lines
24 KiB
JavaScript

'use client'
import { useMessage } from '@/hooks/useMessage'
import { useRecoilState, useRecoilValue } from 'recoil'
import { canvasState } from '@/store/canvasAtom'
import { INPUT_TYPE, BATCH_TYPE } from '@/common/common'
import { useEvent } from '@/hooks/useEvent'
import { polygonToTurfPolygon, rectToPolygon, triangleToPolygon, pointsToTurfPolygon, setSurfaceShapePattern } from '@/util/canvas-util'
import { useSwal } from '@/hooks/useSwal'
import * as turf from '@turf/turf'
import { QPolygon } from '@/components/fabric/QPolygon'
import { drawDirectionArrow } from '@/util/qpolygon-utils'
export function useObjectBatch() {
const { getMessage } = useMessage()
const canvas = useRecoilValue(canvasState)
const { addCanvasMouseEventListener, initEvent } = useEvent()
const { swalFire } = useSwal()
const applyOpeningAndShadow = (objectPlacement, buttonAct, surfaceShapePolygons) => {
const selectedType = objectPlacement.typeRef.current.find((radio) => radio.checked).value
const isCrossChecked = buttonAct === 1 ? objectPlacement.isCrossRef.current.checked : false
const objName = buttonAct === 1 ? BATCH_TYPE.OPENING : BATCH_TYPE.SHADOW
const objTempName = buttonAct === 1 ? BATCH_TYPE.OPENING_TEMP : BATCH_TYPE.SHADOW_TEMP
let rect, isDown, origX, origY
let selectedSurface
//프리입력
if (selectedType === INPUT_TYPE.FREE) {
addCanvasMouseEventListener('mouse:down', (e) => {
isDown = true
const pointer = canvas.getPointer(e.e)
surfaceShapePolygons.forEach((surface) => {
if (surface.inPolygon({ x: pointer.x, y: pointer.y })) {
selectedSurface = surface
}
})
if (!selectedSurface) {
swalFire({ text: '지붕안에 그려야해요', icon: 'error' })
initEvent() //이벤트 초기화
return
}
origX = pointer.x
origY = pointer.y
rect = new fabric.Rect({
left: origX,
top: origY,
originX: 'left',
originY: 'top',
width: 0,
height: 0,
angle: 0,
stroke: 'black',
})
//개구냐 그림자냐에 따라 변경
rect.set({
fill: buttonAct === 1 ? 'white' : 'rgba(0, 0, 0, 0.4)',
name: objTempName,
})
canvas?.add(rect)
})
addCanvasMouseEventListener('mouse:move', (e) => {
if (!isDown) return
if (selectedSurface) {
const pointer = canvas.getPointer(e.e)
const width = pointer.x - origX
const height = pointer.y - origY
rect.set({ width: Math.abs(width), height: Math.abs(height) })
if (width < 0) {
rect.set({ left: Math.abs(pointer.x) })
}
if (height < 0) {
rect.set({ top: Math.abs(pointer.y) })
}
canvas?.renderAll()
}
})
addCanvasMouseEventListener('mouse:up', (e) => {
if (rect) {
const rectPolygon = pointsToTurfPolygon(rectToPolygon(rect))
const selectedSurfacePolygon = polygonToTurfPolygon(selectedSurface)
//지붕 밖으로 그렸을때
if (!turf.booleanWithin(rectPolygon, selectedSurfacePolygon)) {
swalFire({ text: '개구를 배치할 수 없습니다.', icon: 'error' })
//일단 지워
deleteTempObjects()
return
}
if (!isCrossChecked) {
const preObjects = canvas?.getObjects().filter((obj) => obj.name === BATCH_TYPE.OPENING || obj.name === BATCH_TYPE.SHADOW)
const preObjectsArray = preObjects.map((obj) => rectToPolygon(obj))
const isCross = preObjectsArray.some((object) => turf.booleanOverlap(pointsToTurfPolygon(object), rectPolygon))
if (isCross) {
swalFire({ text: '겹치기 불가요...', icon: 'error' })
deleteTempObjects()
return
}
}
isDown = false
rect.set({ name: objName })
rect.setCoords()
initEvent()
}
})
} else if (selectedType === INPUT_TYPE.DIMENSION) {
const width = objectPlacement.widthRef.current.value / 10
const height = objectPlacement.heightRef.current.value / 10
if (width === '' || height === '' || width <= 0 || height <= 0) {
swalFire({ text: getMessage('common.canvas.validate.size'), icon: 'error' })
return
}
// setShowObjectSettingModal(false) //메뉴보이고
addCanvasMouseEventListener('mouse:move', (e) => {
isDown = true
if (!isDown) return
canvas?.remove(...canvas?.getObjects().filter((obj) => obj.name === objTempName)) //움직일때 일단 지워가면서 움직임
const pointer = canvas.getPointer(e.e)
surfaceShapePolygons.forEach((surface) => {
if (surface.inPolygon({ x: pointer.x, y: pointer.y })) {
selectedSurface = surface
}
})
rect = new fabric.Rect({
fill: 'white',
stroke: 'black',
strokeWidth: 1,
width: width,
height: height,
left: pointer.x - width / 2,
top: pointer.y - height / 2,
selectable: true,
lockMovementX: true,
lockMovementY: true,
lockRotation: true,
lockScalingX: true,
lockScalingY: true,
})
//개구냐 그림자냐에 따라 변경
rect.set({
fill: buttonAct === 1 ? 'white' : 'rgba(0, 0, 0, 0.4)',
name: objTempName,
})
canvas?.add(rect)
})
addCanvasMouseEventListener('mouse:up', (e) => {
if (rect) {
const rectPolygon = pointsToTurfPolygon(rectToPolygon(rect))
const selectedSurfacePolygon = polygonToTurfPolygon(selectedSurface)
//지붕 밖으로 그렸을때
if (!turf.booleanWithin(rectPolygon, selectedSurfacePolygon)) {
swalFire({ text: '개구를 배치할 수 없습니다.', icon: 'error' })
//일단 지워
deleteTempObjects()
return
}
if (!isCrossChecked) {
const preObjects = canvas?.getObjects().filter((obj) => obj.name === BATCH_TYPE.OPENING || obj.name === BATCH_TYPE.SHADOW)
const preObjectsArray = preObjects.map((obj) => rectToPolygon(obj))
const isCross = preObjectsArray.some((object) => turf.booleanOverlap(pointsToTurfPolygon(object), rectPolygon))
if (isCross) {
swalFire({ text: '겹치기 불가요...', icon: 'error' })
deleteTempObjects()
return
}
}
isDown = false
rect.set({ name: objName })
rect.setCoords()
initEvent()
}
})
}
}
const applyDormers = (dormerPlacement, buttonAct, surfaceShapePolygons) => {
const dormerName = buttonAct === 3 ? BATCH_TYPE.TRIANGLE_DORMER : BATCH_TYPE.PENTAGON_DORMER
const dormerTempName = buttonAct === 3 ? BATCH_TYPE.TRIANGLE_DORMER_TEMP : BATCH_TYPE.PENTAGON_DORMER_TEMP
const height = dormerPlacement.heightRef.current.value / 10
const width = dormerPlacement.widthRef.current.value / 10
const pitch = dormerPlacement.pitchRef.current.value
const offsetRef = dormerPlacement.offsetRef.current.value === '' ? 0 : parseInt(dormerPlacement.offsetRef.current.value) / 10
const offsetWidthRef = dormerPlacement.offsetWidthRef.current.value === '' ? 0 : parseInt(dormerPlacement.offsetWidthRef.current.value) / 10
const directionRef = dormerPlacement.directionRef.current
let dormer, dormerOffset, isDown, selectedSurface, pentagonPoints, pentagonOffsetPoints
console.log('dormerPlacement', dormerPlacement)
if (height === '' || pitch === '' || height <= 0 || pitch <= 0) {
swalFire({ text: getMessage('common.canvas.validate.size'), icon: 'error' })
return
}
//삼각형 도머
if (buttonAct === 3) {
const bottomLength = height / (pitch * 0.25)
const bottomOffsetLength = (height + offsetRef) / (pitch * 0.25)
addCanvasMouseEventListener('mouse:move', (e) => {
isDown = true
if (!isDown) return
canvas?.remove(...canvas?.getObjects().filter((obj) => obj.name === dormerTempName)) //움직일때 일단 지워가면서 움직임
const pointer = canvas.getPointer(e.e)
surfaceShapePolygons.forEach((surface) => {
if (surface.inPolygon({ x: pointer.x, y: pointer.y })) {
selectedSurface = surface
}
})
let angle = 0
if (directionRef === 'left') {
//서
angle = 90
} else if (directionRef === 'right') {
//동
angle = 270
} else if (directionRef === 'up') {
//북
angle = 180
}
dormer = new fabric.Triangle({
fill: 'white',
stroke: 'red',
strokeDashArray: [5, 5],
strokeWidth: 1,
width: bottomLength * 2,
height: height,
left: pointer.x,
top: pointer.y,
selectable: true,
lockMovementX: true,
lockMovementY: true,
lockRotation: true,
lockScalingX: true,
lockScalingY: true,
name: dormerTempName,
originX: 'center',
originY: 'top',
angle: angle,
})
canvas?.add(dormer)
if (offsetRef > 0) {
dormerOffset = new fabric.Triangle({
fill: 'gray',
stroke: 'red',
strokeDashArray: [5, 5],
strokeWidth: 1,
width: bottomOffsetLength * 2,
height: height + offsetRef,
left: pointer.x,
top: pointer.y,
selectable: true,
lockMovementX: true,
lockMovementY: true,
lockRotation: true,
lockScalingX: true,
lockScalingY: true,
name: dormerTempName,
originX: 'center',
originY: 'top',
angle: angle,
})
canvas?.add(dormerOffset)
}
})
addCanvasMouseEventListener('mouse:up', (e) => {
if (dormer) {
const trianglePolygon = pointsToTurfPolygon(triangleToPolygon(dormer))
const selectedSurfacePolygon = polygonToTurfPolygon(selectedSurface)
//지붕 밖으로 그렸을때
if (!turf.booleanWithin(trianglePolygon, selectedSurfacePolygon)) {
swalFire({ text: '개구를 배치할 수 없습니다.', icon: 'error' })
//일단 지워
deleteTempObjects()
return
}
//각도 추가
let originAngle = 0 //기본 남쪽
let direction = 'south'
if (directionRef === 'left') {
//서
originAngle = 90
direction = 'west'
} else if (directionRef === 'right') {
//동
originAngle = 270
direction = 'east'
} else if (directionRef === 'up') {
//북
originAngle = 180
direction = 'north'
}
let splitedTriangle = offsetRef > 0 ? splitDormerTriangle(dormerOffset, directionRef) : splitDormerTriangle(dormer, directionRef)
canvas?.remove(offsetRef > 0 ? dormerOffset : dormer)
if (offsetRef > 0)
dormer.set({
name: dormerName,
stroke: 'black',
strokeWidth: 1,
strokeDashArray: [0],
}) //오프셋이 있을땐 같이 도머로 만든다
const leftTriangle = new QPolygon(splitedTriangle[0], {
fill: 'transparent',
stroke: 'black',
strokeWidth: 1,
selectable: true,
lockMovementX: true, // X 축 이동 잠금
lockMovementY: true, // Y 축 이동 잠금
lockRotation: true, // 회전 잠금
viewLengthText: true,
fontSize: 14,
direction: direction,
originX: 'center',
originY: 'center',
name: dormerName,
})
const rightTriangle = new QPolygon(splitedTriangle[1], {
fill: 'transparent',
stroke: 'black',
strokeWidth: 1,
selectable: true,
lockMovementX: true, // X 축 이동 잠금
lockMovementY: true, // Y 축 이동 잠금
lockRotation: true, // 회전 잠금
viewLengthText: true,
fontSize: 14,
direction: direction,
originX: 'center',
originY: 'center',
name: dormerName,
})
canvas?.add(leftTriangle)
canvas?.add(rightTriangle)
//패턴
setSurfaceShapePattern(leftTriangle)
setSurfaceShapePattern(rightTriangle)
//방향
drawDirectionArrow(leftTriangle)
drawDirectionArrow(rightTriangle)
isDown = false
initEvent()
}
})
} else if (buttonAct === 4) {
const heightLength = height - (width / 2) * (pitch * 0.25)
//(동의길이 깊이)+출폭(깊이)-[(입력한 폭값)/2+출폭(폭)]*(0.25*입력한 寸)
const heightOffsetLength = height + offsetRef - (width / 2 + offsetWidthRef) * (pitch * 0.25)
addCanvasMouseEventListener('mouse:move', (e) => {
isDown = true
if (!isDown) return
canvas?.remove(...canvas?.getObjects().filter((obj) => obj.name === dormerTempName)) //움직일때 일단 지워가면서 움직임
const pointer = canvas.getPointer(e.e)
surfaceShapePolygons.forEach((surface) => {
if (surface.inPolygon({ x: pointer.x, y: pointer.y })) {
selectedSurface = surface
}
})
let angle = 0
if (directionRef === 'left') {
//서
angle = 90
} else if (directionRef === 'right') {
//동
angle = 270
} else if (directionRef === 'up') {
//북
angle = 180
}
pentagonPoints = [
{ x: pointer.x, y: pointer.y },
{ x: pointer.x - width / 2, y: pointer.y + (height - heightLength) },
{ x: pointer.x - width / 2, y: pointer.y + height },
{ x: pointer.x + width / 2, y: pointer.y + height },
{ x: pointer.x + width / 2, y: pointer.y + (height - heightLength) },
]
pentagonOffsetPoints = [
{ x: pointer.x, y: pointer.y },
{ x: pointer.x - width / 2 - offsetWidthRef, y: pointer.y + height + offsetRef - heightOffsetLength },
{ x: pointer.x - width / 2 - offsetWidthRef, y: pointer.y + height + offsetRef },
{ x: pointer.x + width / 2 + offsetWidthRef, y: pointer.y + height + offsetRef },
{ x: pointer.x + width / 2 + offsetWidthRef, y: pointer.y + height + offsetRef - heightOffsetLength },
]
dormer = new QPolygon(pentagonPoints, {
fill: 'white',
stroke: 'red',
strokeDashArray: [5, 5],
strokeWidth: 1,
selectable: true,
lockMovementX: true,
lockMovementY: true,
lockRotation: true,
lockScalingX: true,
lockScalingY: true,
name: dormerTempName,
originX: 'center',
originY: 'top',
angle: angle,
})
canvas?.add(dormer)
if (offsetRef > 0 || offsetWidthRef > 0) {
dormerOffset = new QPolygon(pentagonOffsetPoints, {
fill: 'gray',
stroke: 'red',
strokeDashArray: [5, 5],
strokeWidth: 1,
selectable: true,
lockMovementX: true,
lockMovementY: true,
lockRotation: true,
lockScalingX: true,
lockScalingY: true,
name: dormerTempName,
originX: 'center',
originY: 'top',
angle: angle,
})
canvas?.add(dormerOffset)
}
})
addCanvasMouseEventListener('mouse:up', (e) => {
if (dormer) {
// const trianglePolygon = pointsToTurfPolygon(triangleToPolygon(dormer))
// const selectedSurfacePolygon = polygonToTurfPolygon(selectedSurface)
// //지붕 밖으로 그렸을때
// if (!turf.booleanWithin(trianglePolygon, selectedSurfacePolygon)) {
// swalFire({ text: '개구를 배치할 수 없습니다.', icon: 'error' })
// //일단 지워
// deleteTempObjects()
// return
// }
//각도 추가
let originAngle = 0 //기본 남쪽
let direction = 'south'
if (directionRef === 'left') {
//서
originAngle = 90
direction = 'west'
} else if (directionRef === 'right') {
//동
originAngle = 270
direction = 'east'
} else if (directionRef === 'up') {
//북
originAngle = 180
direction = 'north'
}
const offsetMode = offsetRef > 0 || offsetWidthRef > 0 ? 'offset' : 'normal'
let splitedPentagon =
offsetRef > 0 || offsetWidthRef > 0
? splitDormerPentagon(dormerOffset, directionRef, offsetMode)
: splitDormerPentagon(dormer, directionRef, offsetMode)
canvas?.remove(offsetRef > 0 || offsetWidthRef > 0 ? dormerOffset : dormer)
if (offsetRef > 0)
dormer.set({
name: dormerName,
stroke: 'black',
strokeWidth: 1,
strokeDashArray: [0],
}) //오프셋이 있을땐 같이 도머로 만든다
const leftPentagon = new QPolygon(splitedPentagon[0], {
fill: 'transparent',
stroke: 'red',
strokeWidth: 1,
selectable: true,
lockMovementX: true, // X 축 이동 잠금
lockMovementY: true, // Y 축 이동 잠금
lockRotation: true, // 회전 잠금
viewLengthText: true,
fontSize: 14,
direction: direction,
originX: 'center',
originY: 'center',
name: dormerName,
})
const rightPentagon = new QPolygon(splitedPentagon[1], {
fill: 'transparent',
stroke: 'red',
strokeWidth: 1,
selectable: true,
lockMovementX: true, // X 축 이동 잠금
lockMovementY: true, // Y 축 이동 잠금
lockRotation: true, // 회전 잠금
viewLengthText: true,
fontSize: 14,
direction: direction,
originX: 'center',
originY: 'center',
name: dormerName,
})
canvas?.add(leftPentagon)
canvas?.add(rightPentagon)
//패턴
setSurfaceShapePattern(leftPentagon)
setSurfaceShapePattern(rightPentagon)
//방향
drawDirectionArrow(leftPentagon)
drawDirectionArrow(rightPentagon)
isDown = false
initEvent()
}
})
}
}
const deleteTempObjects = () => {
const deleteTarget = canvas
?.getObjects()
.filter(
(obj) =>
obj.name === BATCH_TYPE.OPENING_TEMP ||
obj.name === BATCH_TYPE.SHADOW_TEMP ||
obj.name === BATCH_TYPE.TRIANGLE_DORMER_TEMP ||
obj.name === BATCH_TYPE.PENTAGON_DORMER_TEMP,
)
canvas?.remove(...deleteTarget)
initEvent() //이벤트 초기화
}
const splitDormerTriangle = (triangle, direction) => {
const halfWidth = triangle.width / 2
let leftPoints = []
let rightPoints = []
if (direction === 'down') {
leftPoints = [
{ x: triangle.left, y: triangle.top },
{ x: triangle.left - halfWidth, y: triangle.top + triangle.height },
{ x: triangle.left, y: triangle.top + triangle.height },
]
rightPoints = [
{ x: triangle.left, y: triangle.top },
{ x: triangle.left, y: triangle.top + triangle.height },
{ x: triangle.left + halfWidth, y: triangle.top + triangle.height },
]
} else if (direction === 'up') {
leftPoints = [
{ x: triangle.left, y: triangle.top },
{ x: triangle.left - halfWidth, y: triangle.top - triangle.height },
{ x: triangle.left, y: triangle.top - triangle.height },
]
rightPoints = [
{ x: triangle.left, y: triangle.top },
{ x: triangle.left, y: triangle.top - triangle.height },
{ x: triangle.left + halfWidth, y: triangle.top - triangle.height },
]
} else if (direction === 'left') {
leftPoints = [
{ x: triangle.left, y: triangle.top },
{ x: triangle.left - triangle.height, y: triangle.top - halfWidth },
{ x: triangle.left - triangle.height, y: triangle.top },
]
rightPoints = [
{ x: triangle.left, y: triangle.top },
{ x: triangle.left - triangle.height, y: triangle.top },
{ x: triangle.left - triangle.height, y: triangle.top + halfWidth },
]
} else if (direction === 'right') {
leftPoints = [
{ x: triangle.left, y: triangle.top },
{ x: triangle.left + triangle.height, y: triangle.top },
{ x: triangle.left + triangle.height, y: triangle.top + triangle.height },
]
rightPoints = [
{ x: triangle.left, y: triangle.top },
{ x: triangle.left + triangle.height, y: triangle.top },
{ x: triangle.left + triangle.height, y: triangle.top - triangle.height },
]
}
return [leftPoints, rightPoints]
}
const splitDormerPentagon = (pentagon, direction, offsetMode) => {
const points = pentagon.points
console.log(pentagon.points)
let leftPoints = []
let rightPoints = []
if (direction === 'down') {
leftPoints = [
{ x: points[0].x, y: points[0].y },
{ x: points[1].x, y: points[1].y },
{ x: points[2].x, y: points[2].y },
{ x: points[0].x, y: points[3].y },
]
rightPoints = [
{ x: points[0].x, y: points[0].y },
{ x: points[0].x, y: points[2].y },
{ x: points[3].x, y: points[3].y },
{ x: points[4].x, y: points[4].y },
]
} else if (direction === 'up') {
leftPoints = [
{ x: points[0].x, y: points[0].y },
{ x: points[1].x, y: points[0].y - (points[1].y - points[0].y) },
{ x: points[2].x, y: points[0].y - (points[2].y - points[0].y) },
{ x: points[0].x, y: points[0].y - (points[2].y - points[0].y) },
]
rightPoints = [
{ x: points[0].x, y: points[0].y },
{ x: points[3].x, y: points[0].y - (points[1].y - points[0].y) },
{ x: points[3].x, y: points[0].y - (points[2].y - points[0].y) },
{ x: points[0].x, y: points[0].y - (points[2].y - points[0].y) },
]
} else if (direction === 'left') {
leftPoints = [
{ x: points[0].x, y: points[0].y },
{ x: points[0].x - (points[1].y - points[0].y), y: points[0].y - (points[0].x - points[1].x) },
{ x: points[0].x - (points[1].y - points[0].y) - (points[2].y - points[1].y), y: points[0].y - (points[0].x - points[1].x) },
{ x: points[0].x - (points[1].y - points[0].y) - (points[2].y - points[1].y), y: points[0].y },
]
rightPoints = [
{ x: points[0].x, y: points[0].y },
{ x: points[0].x - (points[1].y - points[0].y), y: points[0].y + (points[0].x - points[1].x) },
{ x: points[0].x - (points[1].y - points[0].y) - (points[2].y - points[1].y), y: points[0].y + (points[0].x - points[1].x) },
{ x: points[0].x - (points[1].y - points[0].y) - (points[2].y - points[1].y), y: points[0].y },
]
} else if (direction === 'right') {
leftPoints = [
{ x: points[0].x, y: points[0].y },
{ x: points[0].x + (points[1].y - points[0].y), y: points[0].y + (points[0].x - points[1].x) },
{ x: points[0].x + (points[1].y - points[0].y) + (points[2].y - points[1].y), y: points[0].y + (points[0].x - points[1].x) },
{ x: points[0].x + (points[1].y - points[0].y) + (points[2].y - points[1].y), y: points[0].y },
]
rightPoints = [
{ x: points[0].x, y: points[0].y },
{ x: points[0].x + (points[1].y - points[0].y), y: points[0].y - (points[0].x - points[1].x) },
{ x: points[0].x + (points[1].y - points[0].y) + (points[2].y - points[1].y), y: points[0].y - (points[0].x - points[1].x) },
{ x: points[0].x + (points[1].y - points[0].y) + (points[2].y - points[1].y), y: points[0].y },
]
}
console.log(leftPoints, rightPoints)
return [leftPoints, rightPoints]
}
return {
applyOpeningAndShadow,
applyDormers,
splitDormerTriangle,
splitDormerPentagon,
}
}