From 41feb2ebec9a540df56f4fd2baa4757fb5b18e92 Mon Sep 17 00:00:00 2001 From: "hyojun.choi" Date: Tue, 15 Oct 2024 16:00:54 +0900 Subject: [PATCH] =?UTF-8?q?=EC=99=B8=EB=B2=BD=EC=84=A0=20=ED=8E=B8?= =?UTF-8?q?=EC=A7=91=20=EB=B0=8F=20=EC=98=A4=ED=94=84=EC=85=8B=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../roofcover/useWallLineOffsetSetting.js | 287 ++++++++++++++---- src/hooks/usePolygon.js | 207 +------------ 2 files changed, 224 insertions(+), 270 deletions(-) diff --git a/src/hooks/roofcover/useWallLineOffsetSetting.js b/src/hooks/roofcover/useWallLineOffsetSetting.js index 882635e0..61d7d4ce 100644 --- a/src/hooks/roofcover/useWallLineOffsetSetting.js +++ b/src/hooks/roofcover/useWallLineOffsetSetting.js @@ -19,7 +19,7 @@ export function useWallLineOffsetSetting() { const arrow1Ref = useRef(null) const arrow2Ref = useRef(null) - const drawLine = (point1, point2, idx) => { + const drawLine = (point1, point2, idx, direction = currentWallLineRef.current.direction) => { const line = addLine([point1.x, point1.y, point2.x, point2.y], { stroke: 'black', strokeWidth: 4, @@ -30,7 +30,7 @@ export function useWallLineOffsetSetting() { y1: point1.y, x2: point2.x, y2: point2.y, - direction: currentWallLineRef.current.direction, + direction: direction, }) line.attributes = { ...currentWallLineRef.current.attributes } @@ -50,6 +50,9 @@ export function useWallLineOffsetSetting() { useEffect(() => { const outerLines = canvas.getObjects().filter((obj) => obj.name === 'outerLine') + if (outerLines.length === 0) { + return + } outerLines.forEach((outerLine) => { outerLine.set({ selectable: true }) showLine(outerLine) @@ -94,6 +97,7 @@ export function useWallLineOffsetSetting() { } currentWallLineRef.current = e.target + console.log(currentWallLineRef.current.idx, currentWallLineRef.current.direction) if (type === TYPES.WALL_LINE_EDIT) { addCircleByLine(currentWallLineRef.current) } @@ -193,38 +197,59 @@ export function useWallLineOffsetSetting() { } })[0] const length = Number(length1Ref.current.value) / 10 + const length2 = Number(length2Ref.current.value) / 10 const currentIdx = currentWallLineRef.current.idx + const currentDirection = currentWallLineRef.current.direction let point1, point2, point3 if (radioTypeRef.current === '1') { // 1지점 선택시 방향은 down, right만 가능 if (arrow1Ref.current === 'down') { - point1 = { x: startPoint.x, y: startPoint.y } - point2 = { x: startPoint.x, y: startPoint.y + length } - point3 = { x: endPoint.x, y: endPoint.y } + if (currentDirection === 'top') { + point1 = { x: endPoint.x, y: endPoint.y } + point2 = { x: startPoint.x, y: startPoint.y + length } + point3 = { x: startPoint.x, y: startPoint.y } + } else { + point1 = { x: startPoint.x, y: startPoint.y } + point2 = { x: startPoint.x, y: startPoint.y + length } + point3 = { x: endPoint.x, y: endPoint.y } + } } else { - point1 = { x: startPoint.x, y: startPoint.y } - point2 = { x: startPoint.x + length, y: startPoint.y } - point3 = { x: endPoint.x, y: endPoint.y } + if (currentDirection === 'left') { + point1 = { x: endPoint.x, y: endPoint.y } + point2 = { x: startPoint.x + length, y: startPoint.y } + point3 = { x: startPoint.x, y: startPoint.y } + } else { + point1 = { x: startPoint.x, y: startPoint.y } + point2 = { x: startPoint.x + length, y: startPoint.y } + point3 = { x: endPoint.x, y: endPoint.y } + } } } else { // 2지점일 경우 방향은 up, left만 가능 if (arrow2Ref.current === 'up') { - point1 = { x: startPoint.x, y: startPoint.y } - point2 = { x: startPoint.x, y: startPoint.y - length } - point3 = { x: endPoint.x, y: endPoint.y } + if (currentDirection === 'bottom') { + point1 = { x: startPoint.x, y: startPoint.y } + point2 = { x: endPoint.x, y: endPoint.y - length2 } + point3 = { x: endPoint.x, y: endPoint.y } + } else { + point1 = { x: endPoint.x, y: endPoint.y } + point2 = { x: endPoint.x, y: endPoint.y - length2 } + point3 = { x: startPoint.x, y: startPoint.y } + } } else { - point1 = { x: startPoint.x, y: startPoint.y } - point2 = { x: startPoint.x - length, y: startPoint.y } - point3 = { x: endPoint.x, y: endPoint.y } + if (currentDirection === 'right') { + point1 = { x: startPoint.x, y: startPoint.y } + point2 = { x: endPoint.x - length2, y: endPoint.y } + point3 = { x: endPoint.x, y: endPoint.y } + } else { + point1 = { x: endPoint.x, y: endPoint.y } + point2 = { x: endPoint.x - length2, y: endPoint.y } + point3 = { x: startPoint.x, y: startPoint.y } + } } } - const outerLines = canvas.getObjects().filter((obj) => obj.name === 'outerLine') - outerLines.forEach((outerLine) => { - if (outerLine.idx >= currentIdx + 1) { - outerLine.idx = outerLine.idx + 1 - } - }) + rearrangeOuterLine(currentIdx + 1) drawLine(point1, point2, currentIdx) drawLine(point2, point3, currentIdx + 1) @@ -235,10 +260,19 @@ export function useWallLineOffsetSetting() { canvas.renderAll() } + const rearrangeOuterLine = (idxParam) => { + const outerLines = canvas.getObjects().filter((obj) => obj.name === 'outerLine') + outerLines.forEach((outerLine) => { + if (outerLine.idx >= idxParam) { + outerLine.idx = outerLine.idx + 1 + } + }) + } + const handleOffsetSave = () => { const direction = currentWallLineRef.current.direction let canDirections = direction === 'left' || direction === 'right' ? ['up', 'down'] : ['left', 'right'] - + const currentIdx = currentWallLineRef.current.idx if (!canDirections.includes(arrow1Ref.current)) { alert('방향을 다시 선택하세요') return @@ -255,72 +289,195 @@ export function useWallLineOffsetSetting() { const nextLine = outerLines.find((line) => line.idx === nextIdx) const length = length1Ref.current.value / 10 - + const currentLineX = Math.floor(Math.max(currentLine.x1, currentLine.x2)) + const currentLineY = Math.floor(Math.max(currentLine.y1, currentLine.y2)) switch (arrow1Ref.current) { case 'up': { - const currentLineY = Math.floor(Math.max(currentLine.y1, currentLine.y2)) - currentLine.set({ y1: currentLineY - length, y2: currentLineY - length }) + if (prevLine.direction === currentLine.direction) { + const newX = + currentLine.direction === 'left' + ? Math.floor(Math.max(currentLine.x1, currentLine.x2)) + : Math.floor(Math.min(currentLine.x1, currentLine.x2)) - if (Math.abs(currentLineY - prevLine.y1) < 2) { - prevLine.set({ y1: currentLineY - length }) + const newPoint1 = { x: newX, y: currentLineY - length } + const newPoint2 = { x: prevLine.x2, y: prevLine.y2 } + rearrangeOuterLine(currentIdx) + drawLine(newPoint1, newPoint2, currentIdx, 'top') + + if (Math.abs(currentLineY - nextLine.y1) < 2) { + nextLine.set({ y1: currentLineY - length }) + } else { + nextLine.set({ y2: currentLineY - length }) + } + } else if (nextLine.direction === currentLine.direction) { + const newX = + currentLine.direction === 'left' + ? Math.floor(Math.min(currentLine.x1, currentLine.x2)) + : Math.floor(Math.max(currentLine.x1, currentLine.x2)) + + const newPoint1 = { x: newX, y: currentLineY - length } + const newPoint2 = { x: nextLine.x1, y: nextLine.y1 } + rearrangeOuterLine(currentIdx + 1) + drawLine(newPoint1, newPoint2, currentIdx + 1, 'top') + + if (Math.abs(currentLineY - prevLine.y1) < 2) { + prevLine.set({ y1: currentLineY - length }) + } else { + prevLine.set({ y2: currentLineY - length }) + } } else { - prevLine.set({ y2: currentLineY - length }) - } - if (Math.abs(currentLineY - nextLine.y1) < 2) { - nextLine.set({ y1: currentLineY - length }) - } else { - nextLine.set({ y2: currentLineY - length }) + if (Math.abs(currentLineY - prevLine.y1) < 2) { + prevLine.set({ y1: prevLine.y1 - length }) + } else { + prevLine.set({ y2: prevLine.y2 - length }) + } + if (Math.abs(currentLineY - nextLine.y1) < 2) { + nextLine.set({ y1: nextLine.y1 - length }) + } else { + nextLine.set({ y2: nextLine.y2 - length }) + } } + currentLine.set({ y1: currentLine.y1 - length, y2: currentLine.y2 - length }) + break } case 'down': { - const currentLineY = Math.floor(Math.max(currentLine.y1, currentLine.y2)) - currentLine.set({ y1: currentLineY + length, y2: currentLineY + length }) + if (prevLine.direction === currentLine.direction) { + const newX = + currentLine.direction === 'left' + ? Math.floor(Math.max(currentLine.x1, currentLine.x2)) + : Math.floor(Math.min(currentLine.x1, currentLine.x2)) + const newPoint1 = { x: newX, y: currentLineY + length } + const newPoint2 = { x: prevLine.x2, y: prevLine.y2 } + rearrangeOuterLine(currentIdx) + drawLine(newPoint1, newPoint2, currentIdx, 'bottom') + if (Math.abs(currentLineY - nextLine.y1) < 2) { + nextLine.set({ y1: currentLineY + length }) + } else { + nextLine.set({ y2: currentLineY + length }) + } + } else if (nextLine.direction === currentLine.direction) { + const newX = + currentLine.direction === 'left' + ? Math.floor(Math.min(currentLine.x1, currentLine.x2)) + : Math.floor(Math.max(currentLine.x1, currentLine.x2)) + const newPoint1 = { x: newX, y: currentLineY + length } + const newPoint2 = { x: nextLine.x1, y: nextLine.y1 } + rearrangeOuterLine(currentIdx + 1) + drawLine(newPoint1, newPoint2, currentIdx + 1, 'bottom') + if (Math.abs(currentLineY - prevLine.y1) < 2) { + prevLine.set({ y1: currentLineY + length }) + } else { + prevLine.set({ y2: currentLineY + length }) + } + } else { + if (Math.abs(currentLineY - prevLine.y1) < 2) { + prevLine.set({ y1: prevLine.y1 + length }) + } else { + prevLine.set({ y2: prevLine.y2 + length }) + } + if (Math.abs(currentLineY - nextLine.y1) < 2) { + nextLine.set({ y1: nextLine.y1 + length }) + } else { + nextLine.set({ y2: nextLine.y2 + length }) + } + } - if (Math.abs(currentLineY - prevLine.y1) < 2) { - prevLine.set({ y1: currentLineY + length }) - } else { - prevLine.set({ y2: currentLineY + length }) - } - if (Math.abs(currentLineY - nextLine.y1) < 2) { - nextLine.set({ y1: currentLineY + length }) - } else { - nextLine.set({ y2: currentLineY + length }) - } + currentLine.set({ y1: currentLine.y1 + length, y2: currentLine.y2 + length }) break } case 'left': { - const currentLineX = Math.floor(Math.max(currentLine.x1, currentLine.x2)) - currentLine.set({ x1: currentLineX - length, x2: currentLineX - length }) + if (prevLine.direction === currentLine.direction) { + const newY = + currentLine.direction === 'top' + ? Math.floor(Math.max(currentLine.y1, currentLine.y2)) + : Math.floor(Math.min(currentLine.y1, currentLine.y2)) + const newPoint1 = { x: currentLineX - length, y: newY } + const newPoint2 = { x: prevLine.x2, y: prevLine.y2 } + rearrangeOuterLine(currentIdx) + drawLine(newPoint1, newPoint2, currentIdx, 'left') + if (Math.abs(currentLineX - nextLine.x1) < 2) { + nextLine.set({ x1: currentLineX - length }) + } else { + nextLine.set({ x2: currentLineX - length }) + } + } else if (nextLine.direction === currentLine.direction) { + const newY = + currentLine.direction === 'top' + ? Math.floor(Math.min(currentLine.y1, currentLine.y2)) + : Math.floor(Math.max(currentLine.y1, currentLine.y2)) + const newPoint1 = { x: currentLineX - length, y: newY } + const newPoint2 = { x: nextLine.x1, y: nextLine.y1 } + rearrangeOuterLine(currentIdx + 1) + drawLine(newPoint1, newPoint2, currentIdx + 1, 'left') + if (Math.abs(currentLineX - prevLine.x1) < 2) { + prevLine.set({ x1: currentLineX - length }) + } else { + prevLine.set({ x2: currentLineX - length }) + } + } else { + if (Math.abs(currentLineX - prevLine.x1) < 2) { + prevLine.set({ x1: prevLine.x1 - length }) + } else { + prevLine.set({ x2: prevLine.x2 - length }) + } - if (Math.abs(currentLineX - prevLine.x1) < 2) { - prevLine.set({ x1: currentLineX - length }) - } else { - prevLine.set({ x2: currentLineX - length }) - } - if (Math.abs(currentLineX - nextLine.x1) < 2) { - nextLine.set({ x1: currentLineX - length }) - } else { - nextLine.set({ x2: currentLineX - length }) + if (Math.abs(currentLineX - nextLine.x1) < 2) { + nextLine.set({ x1: nextLine.x1 - length }) + } else { + nextLine.set({ x2: nextLine.x2 - length }) + } } + + currentLine.set({ x1: currentLine.x1 - length, x2: currentLine.x2 - length }) break } case 'right': { - const currentLineX = Math.floor(Math.max(currentLine.x1, currentLine.x2)) - currentLine.set({ x1: currentLineX + length, x2: currentLineX + length }) + if (prevLine.direction === currentLine.direction) { + const newY = + currentLine.direction === 'top' + ? Math.floor(Math.max(currentLine.y1, currentLine.y2)) + : Math.floor(Math.min(currentLine.y1, currentLine.y2)) + const newPoint1 = { x: currentLineX + length, y: newY } + const newPoint2 = { x: prevLine.x2, y: prevLine.y2 } + rearrangeOuterLine(currentIdx) + drawLine(newPoint1, newPoint2, currentIdx, 'right') + if (Math.abs(currentLineX - nextLine.x1) < 2) { + nextLine.set({ x1: currentLineX + length }) + } else { + nextLine.set({ x2: currentLineX + length }) + } + } else if (nextLine.direction === currentLine.direction) { + const newY = + currentLine.direction === 'top' + ? Math.floor(Math.min(currentLine.y1, currentLine.y2)) + : Math.floor(Math.max(currentLine.y1, currentLine.y2)) + const newPoint1 = { x: currentLineX + length, y: newY } + const newPoint2 = { x: nextLine.x1, y: nextLine.y1 } + rearrangeOuterLine(currentIdx + 1) + drawLine(newPoint1, newPoint2, currentIdx + 1, 'right') - if (Math.abs(currentLineX - prevLine.x1) < 2) { - prevLine.set({ x1: currentLineX + length }) + if (Math.abs(currentLineX - prevLine.x1) < 2) { + prevLine.set({ x1: currentLineX + length }) + } else { + prevLine.set({ x2: currentLineX + length }) + } } else { - prevLine.set({ x2: currentLineX + length }) - } - if (Math.abs(currentLineX - nextLine.x1) < 2) { - nextLine.set({ x1: currentLineX + length }) - } else { - nextLine.set({ x2: currentLineX + length }) + if (Math.abs(currentLineX - prevLine.x1) < 2) { + prevLine.set({ x1: prevLine.x1 + length }) + } else { + prevLine.set({ x2: prevLine.x2 + length }) + } + if (Math.abs(currentLineX - nextLine.x1) < 2) { + nextLine.set({ x1: nextLine.x1 + length }) + } else { + nextLine.set({ x2: nextLine.x2 + length }) + } } + currentLine.set({ x1: currentLine.x1 + length, x2: currentLine.x2 + length }) + break } } diff --git a/src/hooks/usePolygon.js b/src/hooks/usePolygon.js index 4cd63363..7289a0d3 100644 --- a/src/hooks/usePolygon.js +++ b/src/hooks/usePolygon.js @@ -26,6 +26,8 @@ export const usePolygon = () => { } const addPolygonByLines = (lines, options) => { + //lines의 idx를 정렬한다. + lines.sort((a, b) => a.idx - b.idx) const points = createPolygonPointsFromOuterLines(lines) return addPolygon(points, { @@ -98,214 +100,9 @@ export const usePolygon = () => { canvas.renderAll() } - //polygon 나누기 - const splitPolygonWithLines = (polygon) => { - const roofs = [] - const allLines = [...polygon.innerLines] - - allLines.forEach((line) => { - line.startPoint = { x: line.x1, y: line.y1 } - line.endPoint = { x: line.x2, y: line.y2 } - }) - - // allLines에 x1,y1,x2,y2를 비교해서 중복되는 값을 제거한다. - allLines.forEach((line, index) => { - const startPoint = line.startPoint - const endPoint = line.endPoint - - allLines.forEach((line2, index2) => { - if (index !== index2) { - if ( - (isSamePoint(startPoint, line2.startPoint) && isSamePoint(endPoint, line2.endPoint)) || - (isSamePoint(endPoint, line2.startPoint) && isSamePoint(startPoint, line2.endPoint)) - ) { - allLines.splice(index2, 1) - } - } - }) - }) - - /** - * 좌표 테스트용 - */ - /*allLines.forEach((line) => { - const text = new fabric.Text(`(${line.startPoint.x},${line.startPoint.y})`, { - left: line.startPoint.x, - top: line.startPoint.y, - fontSize: 15, - }) - - polygon.canvas.add(text) - polygon.canvas.renderAll() - - const text2 = new fabric.Text(`(${line.endPoint.x},${line.endPoint.y})`, { - left: line.endPoint.x, - top: line.endPoint.y, - fontSize: 15, - }) - - polygon.canvas.add(text2) - polygon.canvas.renderAll() - }) - - polygon.points.forEach((point, index) => { - const text = new fabric.Text(`(${point.x},${point.y})`, { - left: point.x, - top: point.y, - fontSize: 15, - }) - - polygon.canvas.add(text) - polygon.canvas.renderAll() - })*/ - /** - * 좌표 테스트용 끝 - */ - - polygon.points.forEach((point, index) => { - allLines.forEach((line) => { - if (line.endPoint.x === point.x && line.endPoint.y === point.y) { - const temp = line.startPoint - line.startPoint = line.endPoint - line.endPoint = temp - } - }) - }) - - polygon.points.forEach((point, index) => { - const routes = [] - - // 시작점은 시작 hip라인의 출발점 - const startPoint = point - // 도착점은 마지막 hip라인의 끝나는 점 - const endPoint = polygon.points[(index + 1) % polygon.points.length] - - const startLine = allLines.find((line) => line.startPoint.x === startPoint.x && line.startPoint.y === startPoint.y) - const endLine = allLines.find((line) => line.startPoint.x === endPoint.x && line.startPoint.y === endPoint.y) - - const arrivalPoint = endLine.endPoint - routes.push(startLine.startPoint) - routes.push(startLine.endPoint) - - //hip끼리 만나는 경우는 아무것도 안해도됨 - if (!isSamePoint(startLine.endPoint, arrivalPoint)) { - // polygon line까지 추가 - const allLinesCopy = [...allLines, ...polygon.lines] - // hip이 만나지 않는 경우 갈 수 있는 길을 다 돌아야함 - let currentPoint = startLine.endPoint - let currentLine = startLine - let movedLines = [] - let subMovedLines = [] - while (!isSamePoint(currentPoint, arrivalPoint)) { - // startHip에서 만나는 출발선 두개. 두개의 선을 출발하여 arrivalPoint에 도착할 때 까지 count를 세고, 더 낮은 count를 가진 길을 선택한다. - let connectedLines = allLinesCopy.filter((line) => isSamePoint(line.startPoint, currentPoint) || isSamePoint(line.endPoint, currentPoint)) - - connectedLines = connectedLines.filter((line) => line !== currentLine) - - connectedLines = connectedLines.filter((line) => !subMovedLines.includes(line)) - - //마지막 선이 endLine의 startPoint와 같은경우 그 전까지 movedLine을 제거한다. - const endLineMeetLineCnt = connectedLines.filter((line) => { - return isSamePoint(line.endPoint, endLine.startPoint) || isSamePoint(line.startPoint, endLine.startPoint) - }).length - - if (endLineMeetLineCnt !== 0) { - movedLines.push(subMovedLines) - - console.log(movedLines, index) - } - - connectedLines = connectedLines.filter((line) => { - return !isSamePoint(line.endPoint, endLine.startPoint) && !isSamePoint(line.startPoint, endLine.startPoint) - }) - - if (connectedLines.length === 0) { - return - } - - let tempPoints = [] - - for (let i = 0; i < connectedLines.length; i++) { - if (isSamePoint(connectedLines[i].startPoint, currentPoint)) { - tempPoints.push({ point: connectedLines[i].endPoint, index: i, line: connectedLines[i] }) - } else { - tempPoints.push({ point: connectedLines[i].startPoint, index: i, line: connectedLines[i] }) - } - } - - //tempPoints에서 arrivalPoint와 가장 가까운 점을 찾는다. - let minDistance = Number.MAX_SAFE_INTEGER - let minIndex = 0 - tempPoints.forEach((tempPoint, index) => { - const distance = Math.sqrt(Math.pow(tempPoint.point.x - arrivalPoint.x, 2) + Math.pow(tempPoint.point.y - arrivalPoint.y, 2)) - if (distance < minDistance) { - minDistance = distance - minIndex = tempPoint.index - } - }) - - currentPoint = tempPoints[minIndex].point - currentLine = tempPoints[minIndex].line - if (currentLine !== startLine) { - subMovedLines.push(currentLine) - } - routes.push(currentPoint) - } - } - - routes.push(endLine.startPoint) - roofs.push(routes) - }) - - // 중복 제거 - roofs.forEach((roofPoint, index) => { - const samePointLengthRoofPoints = roofs.filter((roof) => roof.length === roofPoint.length && roof !== roofPoint) - - samePointLengthRoofPoints.forEach((samePointRoof) => { - if (arraysHaveSamePoints(samePointRoof, roofPoint)) { - roofs.splice(roofs.indexOf(samePointRoof), 1) - } - }) - }) - - roofs.forEach((roofPoint, index) => { - let defense - const direction = getDirectionByPoint(roofPoint[0], roofPoint[roofPoint.length - 1]) - - switch (direction) { - case 'top': - defense = 'east' - break - case 'right': - defense = 'south' - break - case 'bottom': - defense = 'west' - break - case 'left': - defense = 'north' - break - } - - const roof = new QPolygon(roofPoint, { - fontSize: polygon.fontSize, - stroke: 'black', - fill: 'transparent', - strokeWidth: 3, - name: 'roof', - selectable: false, - defense: defense, - }) - - polygon.canvas.add(roof) - polygon.canvas.renderAll() - }) - } - return { addPolygon, addPolygonByLines, removePolygon, - splitPolygonWithLines, } }