diff --git a/src/hooks/usePolygon.js b/src/hooks/usePolygon.js index 328687fe..baefd30f 100644 --- a/src/hooks/usePolygon.js +++ b/src/hooks/usePolygon.js @@ -1,7 +1,7 @@ import { ANGLE_TYPE, canvasState, currentAngleTypeSelector, pitchTextSelector } from '@/store/canvasAtom' import { useRecoilValue } from 'recoil' import { fabric } from 'fabric' -import { findAndRemoveClosestPoint, getDegreeByChon, getDegreeInOrientation, isPointOnLine } from '@/util/canvas-util' +import { calculateIntersection, findAndRemoveClosestPoint, getDegreeByChon, getDegreeInOrientation, isPointOnLine } from '@/util/canvas-util' import { QPolygon } from '@/components/fabric/QPolygon' import { isSamePoint, removeDuplicatePolygons } from '@/util/qpolygon-utils' import { flowDisplaySelector } from '@/store/settingAtom' @@ -1034,6 +1034,130 @@ export const usePolygon = () => { let allLines = [...polygonLines, ...innerLines] + // allLines를 전부 돌면서 교차점이 있는 경우 그 line을 잘라서 allLines에 추가 + const processIntersections = () => { + const linesToProcess = canvas.getObjects().filter((obj) => obj.type === 'QLine' && obj.name === 'auxiliaryLine' && obj.visible) + const newDividedLines = [] + const processedLines = new Set() + + for (let i = 0; i < linesToProcess.length; i++) { + for (let j = i + 1; j < linesToProcess.length; j++) { + const line1 = linesToProcess[i] + const line2 = linesToProcess[j] + + // 이미 처리된 line들은 건너뛰기 + if (processedLines.has(line1) || processedLines.has(line2)) continue + + // 같은 line이거나 이미 연결된 line은 건너뛰기 + if (line1 === line2) continue + if ( + isSamePoint({ x: line1.x1, y: line1.y1 }, { x: line2.x1, y: line2.y1 }) || + isSamePoint({ x: line1.x1, y: line1.y1 }, { x: line2.x2, y: line2.y2 }) || + isSamePoint({ x: line1.x2, y: line1.y2 }, { x: line2.x1, y: line2.y1 }) || + isSamePoint({ x: line1.x2, y: line1.y2 }, { x: line2.x2, y: line2.y2 }) + ) { + continue + } + + const intersectionPoint = calculateIntersection(line1, line2) + if (intersectionPoint) { + // line1에 교차점 추가 + if (!line1.intersectionPoints) line1.intersectionPoints = [] + line1.intersectionPoints.push(intersectionPoint) + + // line2에 교차점 추가 + if (!line2.intersectionPoints) line2.intersectionPoints = [] + line2.intersectionPoints.push(intersectionPoint) + } + } + } + + // 교차점이 있는 line들을 분할 + linesToProcess.forEach((line) => { + if (line.intersectionPoints && line.intersectionPoints.length > 0) { + // 교차점들을 line의 시작점에서부터의 거리순으로 정렬 + const sortedPoints = line.intersectionPoints.sort((a, b) => { + const distA = Math.hypot(a.x - line.x1, a.y - line.y1) + const distB = Math.hypot(b.x - line.x1, b.y - line.y1) + return distA - distB + }) + + let currentPoint = { x: line.x1, y: line.y1 } + + // 각 교차점까지의 line segment 생성 + sortedPoints.forEach((intersectionPoint) => { + if (!isSamePoint(currentPoint, intersectionPoint)) { + const newLine = new QLine([currentPoint.x, currentPoint.y, intersectionPoint.x, intersectionPoint.y], { + stroke: line.stroke, + strokeWidth: line.strokeWidth, + fontSize: line.fontSize, + attributes: { ...line.attributes }, + name: line.name, + visible: line.visible, + }) + // startPoint와 endPoint 설정 + if (newLine.x1 < newLine.x2) { + newLine.startPoint = { x: newLine.x1, y: newLine.y1 } + newLine.endPoint = { x: newLine.x2, y: newLine.y2 } + } else if (newLine.x1 > newLine.x2) { + newLine.startPoint = { x: newLine.x2, y: newLine.y2 } + newLine.endPoint = { x: newLine.x1, y: newLine.y1 } + } else { + if (newLine.y1 < newLine.y2) { + newLine.startPoint = { x: newLine.x1, y: newLine.y1 } + newLine.endPoint = { x: newLine.x2, y: newLine.y2 } + } else { + newLine.startPoint = { x: newLine.x2, y: newLine.y2 } + newLine.endPoint = { x: newLine.x1, y: newLine.y1 } + } + } + newDividedLines.push(newLine) + } + currentPoint = intersectionPoint + }) + + // 마지막 교차점에서 line 끝점까지의 segment + const endPoint = { x: line.x2, y: line.y2 } + if (!isSamePoint(currentPoint, endPoint)) { + const newLine = new QLine([currentPoint.x, currentPoint.y, endPoint.x, endPoint.y], { + stroke: line.stroke, + strokeWidth: line.strokeWidth, + fontSize: line.fontSize, + attributes: { ...line.attributes }, + name: line.name, + visible: line.visible, + }) + // startPoint와 endPoint 설정 + if (newLine.x1 < newLine.x2) { + newLine.startPoint = { x: newLine.x1, y: newLine.y1 } + newLine.endPoint = { x: newLine.x2, y: newLine.y2 } + } else if (newLine.x1 > newLine.x2) { + newLine.startPoint = { x: newLine.x2, y: newLine.y2 } + newLine.endPoint = { x: newLine.x1, y: newLine.y1 } + } else { + if (newLine.y1 < newLine.y2) { + newLine.startPoint = { x: newLine.x1, y: newLine.y1 } + newLine.endPoint = { x: newLine.x2, y: newLine.y2 } + } else { + newLine.startPoint = { x: newLine.x2, y: newLine.y2 } + newLine.endPoint = { x: newLine.x1, y: newLine.y1 } + } + } + newDividedLines.push(newLine) + } + + processedLines.add(line) + } + }) + + // allLines 업데이트: 분할된 line들 제거하고 새 line들 추가 + allLines = allLines.filter((line) => !processedLines.has(line)) + allLines = [...allLines, ...newDividedLines] + } + + // 교차점 처리 실행 + processIntersections() + /*allLines.forEach((line) => { const originColor = line.stroke