import { useEffect, useRef, useState } from 'react' import { useRecoilState, useRecoilValue } from 'recoil' import { adsorptionRangeState, canvasState, verticalHorizontalModeState } from '@/store/canvasAtom' import { useEvent } from '@/hooks/useEvent' import { useMouse } from '@/hooks/useMouse' import { useLine } from '@/hooks/useLine' import { useTempGrid } from '@/hooks/useTempGrid' import { outerLineAngle1State, outerLineAngle2State, outerLineArrow1State, outerLineArrow2State, outerLineDiagonalState, outerLineLength1State, outerLineLength2State, outerLineTypeState, } from '@/store/outerLineAtom' import { calculateIntersection, distanceBetweenPoints, findClosestPoint, isPointOnLine } from '@/util/canvas-util' import { fabric } from 'fabric' import { useAdsorptionPoint } from '@/hooks/useAdsorptionPoint' import { useSwal } from '@/hooks/useSwal' import { usePopup } from '@/hooks/usePopup' import { calculateAngle, isSamePoint } from '@/util/qpolygon-utils' import { POLYGON_TYPE } from '@/common/common' // 보조선 작성 export function useAuxiliaryDrawing(id) { const canvas = useRecoilValue(canvasState) const { addCanvasMouseEventListener, addDocumentEventListener, removeMouseLine, initEvent } = useEvent() // const { addCanvasMouseEventListener, addDocumentEventListener, removeMouseLine, initEvent } = useContext(EventContext) const { getIntersectMousePoint } = useMouse() const { addLine, removeLine } = useLine() const { tempGridMode } = useTempGrid() const { swalFire } = useSwal() const { getAdsorptionPoints } = useAdsorptionPoint() const { closePopup } = usePopup() const adsorptionRange = useRecoilValue(adsorptionRangeState) const [buttonAct, setButtonAct] = useState(1) const mousePointerArr = useRef([]) const roofAdsorptionPoints = useRef([]) const lineHistory = useRef([]) const length1Ref = useRef(0) const length2Ref = useRef(0) const angle1Ref = useRef('') const angle2Ref = useRef('') const [length1, setLength1] = useRecoilState(outerLineLength1State) const [length2, setLength2] = useRecoilState(outerLineLength2State) const [arrow1, setArrow1] = useRecoilState(outerLineArrow1State) const [arrow2, setArrow2] = useRecoilState(outerLineArrow2State) const [type, setType] = useRecoilState(outerLineTypeState) const [angle1, setAngle1] = useRecoilState(outerLineAngle1State) const [angle2, setAngle2] = useRecoilState(outerLineAngle2State) const [outerLineDiagonalLength, setOuterLineDiagonalLength] = useRecoilState(outerLineDiagonalState) const arrow1Ref = useRef(arrow1) const arrow2Ref = useRef(arrow2) const typeRef = useRef(type) const outerLineDiagonalLengthRef = useRef(0) const intersectionPoints = useRef([]) const verticalHorizontalMode = useRecoilValue(verticalHorizontalModeState) useEffect(() => { arrow1Ref.current = arrow1 }, [arrow1]) useEffect(() => { arrow2Ref.current = arrow2 }, [arrow2]) useEffect(() => { typeRef.current = type clear() addDocumentEventListener('keydown', document, keydown[type]) }, [type]) useEffect(() => { // innerLines가 있을경우 삭제 const roofs = canvas?.getObjects().filter((obj) => obj.name === POLYGON_TYPE.ROOF) if (roofs.length === 0) { swalFire({ text: '지붕형상이 없습니다.' }) closePopup(id) return } // 지붕의 각 꼭지점을 흡착점으로 설정 const roofsPoints = roofs.map((roof) => roof.points).flat() roofAdsorptionPoints.current = [...roofsPoints] addCanvasMouseEventListener('mouse:move', mouseMove) addCanvasMouseEventListener('mouse:down', mouseDown) // addDocumentEventListener('contextmenu', document, cutAuxiliary) addDocumentEventListener('keydown', document, keydown[type]) return () => { canvas.remove(...canvas.getObjects().filter((obj) => obj.name === 'innerPoint')) initEvent() canvas.renderAll() } }, []) useEffect(() => { addCanvasMouseEventListener('mouse:down', mouseDown) }, [verticalHorizontalMode]) const clear = () => { addCanvasMouseEventListener('mouse:move', mouseMove) setLength1(0) setLength2(0) setArrow1('') setArrow2('') setAngle1(0) setAngle2(0) setOuterLineDiagonalLength(0) } const move = (object, x, y) => { const line = copy(object, x, y) canvas.remove(object) canvas.setActiveObject(line) } const copy = (object, x, y) => { return addLine([object.x1 + x, object.y1 + y, object.x2 + x, object.y2 + y], { stroke: 'red', strokeWidth: 1, selectable: true, name: 'auxiliaryLine', }) } const keydown = { outerLine: (e) => { if (mousePointerArr.current.length === 0) { return } // 포커스가 length1에 있지 않으면 length1에 포커스를 줌 const activeElem = document.activeElement if (activeElem !== length1Ref.current) { length1Ref?.current?.focus() } const key = e.key if (!length1Ref.current) { return } const lengthNum = Number(length1Ref.current.value) / 10 if (lengthNum === 0) { return } const lastPoint = mousePointerArr.current[0] switch (key) { case 'Down': // IE/Edge에서 사용되는 값 case 'ArrowDown': { setArrow1('↓') mousePointerArr.current.push({ x: lastPoint.x, y: lastPoint.y + lengthNum }) drawLine() break } case 'Up': // IE/Edge에서 사용되는 값 case 'ArrowUp': setArrow1('↑') mousePointerArr.current.push({ x: lastPoint.x, y: lastPoint.y - lengthNum }) drawLine() break case 'Left': // IE/Edge에서 사용되는 값 case 'ArrowLeft': setArrow1('←') mousePointerArr.current.push({ x: lastPoint.x - lengthNum, y: lastPoint.y }) drawLine() break case 'Right': // IE/Edge에서 사용되는 값 case 'ArrowRight': setArrow1('→') mousePointerArr.current.push({ x: lastPoint.x + lengthNum, y: lastPoint.y }) drawLine() break } }, rightAngle: (e) => { if (mousePointerArr.current.length === 0) { return } const key = e.key const activeElem = document.activeElement if (activeElem !== length1Ref.current && activeElem !== length2Ref.current) { length1Ref?.current?.focus() } switch (key) { case 'Down': // IE/Edge에서 사용되는 값 case 'ArrowDown': { checkRightAngle('↓') break } case 'Up': // IE/Edge에서 사용되는 값 case 'ArrowUp': checkRightAngle('↑') break case 'Left': // IE/Edge에서 사용되는 값 case 'ArrowLeft': checkRightAngle('←') break case 'Right': // IE/Edge에서 사용되는 값 case 'ArrowRight': checkRightAngle('→') break } }, doublePitch: (e) => { if (mousePointerArr.current.length === 0) { return } const key = e.key switch (key) { case 'Down': // IE/Edge에서 사용되는 값 case 'ArrowDown': { checkDoublePitch('↓') break } case 'Up': // IE/Edge에서 사용되는 값 case 'ArrowUp': checkDoublePitch('↑') break case 'Left': // IE/Edge에서 사용되는 값 case 'ArrowLeft': checkDoublePitch('←') break case 'Right': // IE/Edge에서 사용되는 값 case 'ArrowRight': checkDoublePitch('→') break } }, angle: (e) => { if (mousePointerArr.current.length === 0) { return } const key = e.key switch (key) { case 'Enter': { const lastPoint = mousePointerArr.current[0] const length = length1Ref.current.value / 10 const angle = angle1Ref.current.value //lastPoint로부터 angle1만큼의 각도로 length1만큼의 길이를 가지는 선을 그림 const radian = (angle * Math.PI) / 180 const x = lastPoint.x + length * Math.cos(radian) const y = lastPoint.y - length * Math.sin(radian) mousePointerArr.current.push({ x, y }) drawLine() } } }, diagonalLine: (e) => { if (mousePointerArr.current.length === 0) { return } const key = e.key switch (key) { case 'Down': // IE/Edge에서 사용되는 값 case 'ArrowDown': { checkDiagonal('↓') break } case 'Up': // IE/Edge에서 사용되는 값 case 'ArrowUp': checkDiagonal('↑') break case 'Left': // IE/Edge에서 사용되는 값 case 'ArrowLeft': checkDiagonal('←') break case 'Right': // IE/Edge에서 사용되는 값 case 'ArrowRight': checkDiagonal('→') break } }, } // 직각 완료될 경우 확인 const checkRightAngle = (direction) => { const activeElem = document.activeElement const canDirection = direction === '↓' || direction === '↑' ? arrow1Ref.current === '←' || arrow1Ref.current === '→' : arrow1Ref.current === '↓' || arrow1Ref.current === '↑' if (activeElem === length1Ref.current || activeElem === angle1Ref.current) { setArrow1(direction) arrow1Ref.current = direction length2Ref.current.focus() } else if (activeElem === length2Ref.current || activeElem === angle2Ref.current) { if (!canDirection) { return } setArrow2(direction) arrow2Ref.current = direction } const length1Num = Number(length1Ref.current.value) / 10 const length2Num = Number(length2Ref.current.value) / 10 if (mousePointerArr.current.length === 0) { return } const lastPoint = mousePointerArr.current[0] if (length1Num === 0 || length2Num === 0 || arrow1Ref.current === '' || arrow2Ref.current === '') { return } if (arrow1Ref.current === '↓' && arrow2Ref.current === '→') { mousePointerArr.current.push({ x: lastPoint.x + length2Num, y: lastPoint.y + length1Num }) } else if (arrow1Ref.current === '↓' && arrow2Ref.current === '←') { mousePointerArr.current.push({ x: lastPoint.x - length2Num, y: lastPoint.y + length1Num }) } else if (arrow1Ref.current === '↑' && arrow2Ref.current === '→') { mousePointerArr.current.push({ x: lastPoint.x + length2Num, y: lastPoint.y - length1Num }) } else if (arrow1Ref.current === '↑' && arrow2Ref.current === '←') { mousePointerArr.current.push({ x: lastPoint.x - length2Num, y: lastPoint.y - length1Num }) } else if (arrow1Ref.current === '→' && arrow2Ref.current === '↓') { mousePointerArr.current.push({ x: lastPoint.x + length1Num, y: lastPoint.y + length2Num }) } else if (arrow1Ref.current === '→' && arrow2Ref.current === '↑') { mousePointerArr.current.push({ x: lastPoint.x + length1Num, y: lastPoint.y - length2Num }) } else if (arrow1Ref.current === '←' && arrow2Ref.current === '↓') { mousePointerArr.current.push({ x: lastPoint.x - length1Num, y: lastPoint.y + length2Num }) } else if (arrow1Ref.current === '←' && arrow2Ref.current === '↑') { mousePointerArr.current.push({ x: lastPoint.x - length1Num, y: lastPoint.y - length2Num }) } drawLine() } //이구배 완료될 경우 확인 ↓, ↑, ←, → const checkDoublePitch = (direction) => { const activeElem = document.activeElement const canDirection = direction === '↓' || direction === '↑' ? arrow1Ref.current === '←' || arrow1Ref.current === '→' : arrow1Ref.current === '↓' || arrow1Ref.current === '↑' if (activeElem === length1Ref.current || activeElem === angle1Ref.current) { setArrow1(direction) arrow1Ref.current = direction angle2Ref.current.focus() } else if (activeElem === length2Ref.current || activeElem === angle2Ref.current) { if (!canDirection) { return } setArrow2(direction) arrow2Ref.current = direction } const angle1Value = Number(angle1Ref.current.value) const angle2Value = Number(angle2Ref.current.value) const length1Value = Number(length1Ref.current.value) const length2Value = Number(length2Ref.current.value) const arrow1Value = arrow1Ref.current const arrow2Value = arrow2Ref.current const lastPoint = mousePointerArr.current[0] if (angle1Value !== 0 && length1Value !== 0 && angle2Value !== 0 && arrow1Value !== '' && arrow2Value !== '') { if (arrow1Value === '↓' && arrow2Value === '→') { mousePointerArr.current.push({ x: lastPoint.x + length1Value / 10, y: lastPoint.y + length2Value / 10 }) } else if (arrow1Value === '↓' && arrow2Value === '←') { mousePointerArr.current.push({ x: lastPoint.x - length1Value / 10, y: lastPoint.y + length2Value / 10 }) } else if (arrow1Value === '↑' && arrow2Value === '→') { mousePointerArr.current.push({ x: lastPoint.x + length1Value / 10, y: lastPoint.y - length2Value / 10 }) } else if (arrow1Value === '↑' && arrow2Value === '←') { mousePointerArr.current.push({ x: lastPoint.x - length1Value / 10, y: lastPoint.y - length2Value / 10 }) } else if (arrow1Value === '→' && arrow2Value === '↓') { mousePointerArr.current.push({ x: lastPoint.x + length2Value / 10, y: lastPoint.y + length1Value / 10 }) } else if (arrow1Value === '→' && arrow2Value === '↑') { mousePointerArr.current.push({ x: lastPoint.x + length2Value / 10, y: lastPoint.y - length1Value / 10 }) } else if (arrow1Value === '←' && arrow2Value === '↓') { mousePointerArr.current.push({ x: lastPoint.x - length2Value / 10, y: lastPoint.y + length1Value / 10 }) } else if (arrow1Value === '←' && arrow2Value === '↑') { mousePointerArr.current.push({ x: lastPoint.x - length2Value / 10, y: lastPoint.y - length1Value / 10 }) } drawLine() angle1Ref.current.focus() } } //대각선 완료될 경우 확인 const checkDiagonal = (direction) => { const activeElem = document.activeElement const diagonalLength = outerLineDiagonalLengthRef.current.value // 대각선 길이 const length1Value = length1Ref.current.value if (diagonalLength <= length1Value) { alert('대각선 길이는 직선 길이보다 길어야 합니다.') return } const canDirection = direction === '↓' || direction === '↑' ? arrow1Ref.current === '←' || arrow1Ref.current === '→' : arrow1Ref.current === '↓' || arrow1Ref.current === '↑' if (activeElem === length1Ref.current) { setArrow1(direction) arrow1Ref.current = direction } else if (activeElem === length2Ref.current || activeElem === angle2Ref.current) { if (!canDirection) { return } setArrow2(direction) arrow2Ref.current = direction } const arrow1Value = arrow1Ref.current const arrow2Value = arrow2Ref.current const getLength2 = () => { return Math.floor(Math.sqrt(diagonalLength ** 2 - length1Value ** 2)) } const length2Value = getLength2() if (diagonalLength !== 0 && length1Value !== 0 && arrow1Value !== '') { setLength2(getLength2()) length2Ref.current.focus() } const lastPoint = mousePointerArr.current[0] if (length1Value !== 0 && length2Value !== 0 && arrow1Value !== '' && arrow2Value !== '') { if (arrow1Value === '↓' && arrow2Value === '→') { mousePointerArr.current.push({ x: lastPoint.x + length2Value / 10, y: lastPoint.y + length1Value / 10 }) } else if (arrow1Value === '↓' && arrow2Value === '←') { mousePointerArr.current.push({ x: lastPoint.x - length2Value / 10, y: lastPoint.y + length1Value / 10 }) } else if (arrow1Value === '↑' && arrow2Value === '→') { mousePointerArr.current.push({ x: lastPoint.x + length2Value / 10, y: lastPoint.y - length1Value / 10 }) } else if (arrow1Value === '↑' && arrow2Value === '←') { mousePointerArr.current.push({ x: lastPoint.x - length2Value / 10, y: lastPoint.y - length1Value / 10 }) } else if (arrow1Value === '→' && arrow2Value === '↓') { mousePointerArr.current.push({ x: lastPoint.x + length1Value / 10, y: lastPoint.y + length2Value / 10 }) } else if (arrow1Value === '→' && arrow2Value === '↑') { mousePointerArr.current.push({ x: lastPoint.x + length1Value / 10, y: lastPoint.y - length2Value / 10 }) } drawLine() } } const drawLine = () => { canvas.remove(...canvas.getObjects().filter((obj) => obj.name === 'innerPoint')) const line = addLine([mousePointerArr.current[0].x, mousePointerArr.current[0].y, mousePointerArr.current[1].x, mousePointerArr.current[1].y], { stroke: 'black', strokeWidth: 1, selectable: false, name: 'auxiliaryLine', }) const historyLines = [...lineHistory.current] const hasSameLine = historyLines.some((history) => { return ( (isSamePoint(history.startPoint, line.startPoint) && isSamePoint(history.endPoint, line.endPoint)) || (isSamePoint(history.startPoint, line.endPoint) && isSamePoint(history.endPoint, line.startPoint)) ) }) mousePointerArr.current = [] clear() if (hasSameLine) { canvas.remove(line) return } lineHistory.current.push(line) } const mouseDown = (e) => { canvas.renderAll() let pointer = getIntersectMousePoint(e) if (mousePointerArr.current.length === 1) { const currentPoint = canvas.getPointer(e.e) const prevPoint = mousePointerArr.current[0] const degreeByTwoPoints = calculateAngle(prevPoint, currentPoint) const degree = Math.round(degreeByTwoPoints / 45) * 45 if (verticalHorizontalMode) { pointer = { x: prevPoint.x + distanceBetweenPoints(currentPoint, prevPoint) * Math.cos((degree * Math.PI) / 180), y: prevPoint.y + distanceBetweenPoints(currentPoint, prevPoint) * Math.sin((degree * Math.PI) / 180), } } mousePointerArr.current.push(pointer) drawLine() } else { const circle = new fabric.Circle({ radius: 3, fill: 'red', left: pointer.x - 3, top: pointer.y - 3, x: pointer.x, y: pointer.y, name: 'innerPoint', selectable: true, }) canvas.add(circle) canvas.renderAll() mousePointerArr.current.push(pointer) } } const mouseMove = (e) => { removeMouseLine() // 가로선 const pointer = canvas.getPointer(e.e) const auxiliaryLines = canvas.getObjects().filter((obj) => obj.name === 'auxiliaryLine' && !obj.isFixed) const otherAdsorptionPoints = [] auxiliaryLines.forEach((line1) => { auxiliaryLines.forEach((line2) => { if (line1 === line2) { return } const intersectionPoint = calculateIntersection(line1, line2) if (!intersectionPoint || intersectionPoints.current.some((point) => point.x === intersectionPoint.x && point.y === intersectionPoint.y)) { return } otherAdsorptionPoints.push(intersectionPoint) }) }) let innerLinePoints = [] canvas .getObjects() .filter((obj) => obj.innerLines) .forEach((polygon) => { polygon.innerLines.forEach((line) => { innerLinePoints.push({ x: line.x1, y: line.y1 }) innerLinePoints.push({ x: line.x2, y: line.y2 }) }) }) const adsorptionPoints = [ ...getAdsorptionPoints(), ...roofAdsorptionPoints.current, ...otherAdsorptionPoints, ...intersectionPoints.current, ...innerLinePoints, ] let arrivalPoint = { x: pointer.x, y: pointer.y } // pointer와 adsorptionPoints의 거리를 계산하여 가장 가까운 점을 찾는다. let adsorptionPoint = findClosestPoint(pointer, adsorptionPoints) if (adsorptionPoint && distanceBetweenPoints(pointer, adsorptionPoint) <= adsorptionRange) { arrivalPoint = { ...adsorptionPoint } } const horizontalLine = new fabric.Line([-1 * canvas.width, arrivalPoint.y, 2 * canvas.width, arrivalPoint.y], { stroke: 'red', strokeWidth: 1, selectable: false, name: 'mouseLine', }) // 세로선 const verticalLine = new fabric.Line([arrivalPoint.x, -1 * canvas.height, arrivalPoint.x, 2 * canvas.height], { stroke: 'red', strokeWidth: 1, selectable: false, name: 'mouseLine', }) // 선들을 캔버스에 추가합니다. canvas?.add(horizontalLine, verticalLine) // 캔버스를 다시 그립니다. canvas?.renderAll() } // 보조선 절삭 const cutAuxiliary = (e) => { const auxiliaryLines = canvas.getObjects().filter((obj) => obj.name === 'auxiliaryLine') if (auxiliaryLines.length === 0) { return } const roofBases = canvas.getObjects().filter((obj) => obj.name === POLYGON_TYPE.ROOF) /*const allLines = [...auxiliaryLines] roofBases.forEach((roofBase) => { allLines.push(...roofBase.lines) })*/ const innerLines = [...auxiliaryLines] const roofLines = [] roofBases.forEach((roofBase) => { innerLines.push(...roofBase.innerLines) roofLines.push(...roofBase.lines) }) auxiliaryLines.forEach((line1) => { let interSectionPointsWithRoofLines = [] //지붕선과 만나는 점을 찾는다. roofLines.forEach((line2) => { const intersectionPoint = calculateIntersection(line1, line2) if (!intersectionPoint) { return } // 기존 점과 겹치는지 확인 if (interSectionPointsWithRoofLines.some((point) => isSamePoint(point, intersectionPoint))) { return } interSectionPointsWithRoofLines.push(intersectionPoint) }) //지붕선과 만나는 점이 두개일 경우 넘친 보조선을 잘라준다 (케라바로 만든 마루) if (interSectionPointsWithRoofLines.length === 2) { const newLine = addLine( [ interSectionPointsWithRoofLines[0].x, interSectionPointsWithRoofLines[0].y, interSectionPointsWithRoofLines[1].x, interSectionPointsWithRoofLines[1].y, ], { stroke: 'black', strokeWidth: 1, selectable: true, name: 'auxiliaryLine', isFixed: true, }, ) lineHistory.current.push(newLine) lineHistory.current = lineHistory.current.filter((history) => history !== line1) removeLine(line1) intersectionPoints.current.push(...interSectionPointsWithRoofLines) return } else if (interSectionPointsWithRoofLines.length === 1) { //지붕선과 만나는 점이 하나일 경우 const distance1 = distanceBetweenPoints({ x: line1.x1, y: line1.y1 }, interSectionPointsWithRoofLines[0]) const distance2 = distanceBetweenPoints({ x: line1.x2, y: line1.y2 }, interSectionPointsWithRoofLines[0]) if (!(distance1 === 0 || distance2 === 0)) { if (distance1 >= distance2) { const newLine = addLine([line1.x1, line1.y1, interSectionPointsWithRoofLines[0].x, interSectionPointsWithRoofLines[0].y], { stroke: 'black', strokeWidth: 1, selectable: false, name: 'auxiliaryLine', isFixed: true, }) lineHistory.current.push(newLine) lineHistory.current = lineHistory.current.filter((history) => history !== line1) removeLine(line1) } else { const newLine = addLine([line1.x2, line1.y2, interSectionPointsWithRoofLines[0].x, interSectionPointsWithRoofLines[0].y], { stroke: 'black', strokeWidth: 1, selectable: false, name: 'auxiliaryLine', isFixed: true, }) lineHistory.current.push(newLine) lineHistory.current = lineHistory.current.filter((history) => history !== line1) removeLine(line1) } intersectionPoints.current.push(interSectionPointsWithRoofLines[0]) } } //보조선과 만나는 점을 찾는다. innerLines.forEach((line2) => { if (line1 === line2) { return } const intersectionPoint = calculateIntersection(line1, line2) if (!intersectionPoint) { return } roofAdsorptionPoints.current.push(intersectionPoint) intersectionPoints.current.push(intersectionPoint) const distance1 = distanceBetweenPoints({ x: line1.x1, y: line1.y1 }, intersectionPoint) const distance2 = distanceBetweenPoints({ x: line1.x2, y: line1.y2 }, intersectionPoint) if (distance1 === 0 || distance2 === 0) { return } //historyLine에서 기존 line을 제거한다. lineHistory.current = lineHistory.current.filter((history) => history !== line1) let newLine if (distance1 >= distance2) { newLine = addLine([line1.x1, line1.y1, intersectionPoint.x, intersectionPoint.y], { stroke: 'black', strokeWidth: 1, selectable: true, name: 'auxiliaryLine', isFixed: true, intersectionPoint, }) } else { newLine = addLine([line1.x2, line1.y2, intersectionPoint.x, intersectionPoint.y], { stroke: 'black', strokeWidth: 1, selectable: true, name: 'auxiliaryLine', isFixed: true, intersectionPoint, }) } lineHistory.current.push(newLine) lineHistory.current = lineHistory.current.filter((history) => history !== line1) removeLine(line1) }) /*auxiliaryLines.forEach((line1) => { allLines.forEach((line2) => { if (line1 === line2) { return } const intersectionPoint = calculateIntersection(line1, line2) if (!intersectionPoint) { return } roofAdsorptionPoints.current.push(intersectionPoint) intersectionPoints.current.push(intersectionPoint) const distance1 = distanceBetweenPoints({ x: line1.x1, y: line1.y1 }, intersectionPoint) const distance2 = distanceBetweenPoints({ x: line1.x2, y: line1.y2 }, intersectionPoint) if (distance1 === 0 || distance2 === 0) { return } //historyLine에서 기존 line을 제거한다. lineHistory.current = lineHistory.current.filter((history) => history !== line1) let newLine if (distance1 >= distance2) { newLine = addLine([line1.x1, line1.y1, intersectionPoint.x, intersectionPoint.y], { stroke: 'black', strokeWidth: 1, selectable: false, name: 'auxiliaryLine', isFixed: true, intersectionPoint, }) } else { newLine = addLine([line1.x2, line1.y2, intersectionPoint.x, intersectionPoint.y], { stroke: 'black', strokeWidth: 1, selectable: false, name: 'auxiliaryLine', isFixed: true, intersectionPoint, }) } lineHistory.current.push(newLine) removeLine(line1) }) })*/ }) addCanvasMouseEventListener('mouse:move', mouseMove) } /** * 일변전으로 돌아가기 */ const handleRollback = () => { const innerPoint = canvas.getObjects().find((obj) => obj.name === 'innerPoint') if (innerPoint) { mousePointerArr.current = [] canvas.remove(innerPoint) canvas.renderAll() return } const lastLine = lineHistory.current.pop() if (lastLine) { roofAdsorptionPoints.current = roofAdsorptionPoints.current.filter( (point) => point.x !== lastLine.intersectionPoint?.x && point.y !== lastLine.intersectionPoint?.y, ) canvas.remove(lastLine) canvas.renderAll() } addCanvasMouseEventListener('mouse:move', mouseMove) } const handleFix = () => { if (!confirm('지붕선 완료하시겠습니까?')) { return } const roofBases = canvas.getObjects().filter((obj) => obj.name === POLYGON_TYPE.ROOF) //lineHistory.current에 있는 선들 중 startPoint와 endPoint가 겹치는 line은 제거 // 겹치는 선 하나는 canvas에서 제거한다. const tempLines = [...lineHistory.current] lineHistory.current = [] tempLines.forEach((line) => { if ( lineHistory.current.some( (history) => JSON.stringify(history.startPoint) === JSON.stringify(line.startPoint) && JSON.stringify(history.endPoint) === JSON.stringify(line.endPoint), ) ) { canvas.remove(line) return } lineHistory.current.push(line) }) const innerLines = lineHistory.current roofBases.forEach((roofBase) => { const tempPolygonPoints = [...roofBase.points].map((obj) => { return { x: Math.round(obj.x), y: Math.round(obj.y) } }) const roofInnerLines = [...roofBase.innerLines, ...innerLines].filter((line) => { const inPolygon1 = tempPolygonPoints.some((point) => Math.round(point.x) === Math.round(line.x1) && Math.round(point.y) === Math.round(line.y1)) || roofBase.inPolygon({ x: Math.round(line.x1), y: Math.round(line.y1) }) || roofBase.lines.some((line) => isPointOnLine(line, { x: Math.round(line.x1), y: Math.round(line.y1) })) const inPolygon2 = tempPolygonPoints.some((point) => Math.round(point.x) === Math.round(line.x2) && Math.round(point.y) === Math.round(line.y2)) || roofBase.inPolygon({ x: Math.round(line.x2), y: Math.round(line.y2) }) || roofBase.lines.some((line) => isPointOnLine(line, { x: Math.round(line.x2), y: Math.round(line.y2) })) if (inPolygon1 && inPolygon2) { line.attributes = { ...line.attributes, roofId: roofBase.id, actualSize: line.attributes?.actualSize ?? 0, planeSize: line.getLength(), } return true } }) roofBase.innerLines = lineHistory.current.length !== 0 ? [...roofInnerLines] : roofBase.innerLines canvas.renderAll() }) closePopup(id) } return { length1, setLength1, length2, setLength2, length1Ref, length2Ref, arrow1, setArrow1, arrow2, setArrow2, arrow1Ref, arrow2Ref, angle1, setAngle1, angle1Ref, angle2, setAngle2, angle2Ref, outerLineDiagonalLength, setOuterLineDiagonalLength, outerLineDiagonalLengthRef, type, setType, handleFix, handleRollback, buttonAct, setButtonAct, move, copy, cutAuxiliary, } }