From cb38a3815fb6397200f12a33edbcc971fe4bab1a Mon Sep 17 00:00:00 2001 From: "hyojun.choi" Date: Tue, 23 Jul 2024 15:47:08 +0900 Subject: [PATCH] =?UTF-8?q?=EC=9E=91=EC=97=85=EC=A4=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/Roof2.jsx | 32 +++++- src/components/fabric/QLine.js | 1 + src/util/canvas-util.js | 75 ++++++++++++-- src/util/qpolygon-utils.js | 179 ++++++++++++++++++++++----------- 4 files changed, 214 insertions(+), 73 deletions(-) diff --git a/src/components/Roof2.jsx b/src/components/Roof2.jsx index eadb2c33..cdaae411 100644 --- a/src/components/Roof2.jsx +++ b/src/components/Roof2.jsx @@ -10,6 +10,7 @@ import { useRecoilState, useRecoilValue } from 'recoil' import { canvasAtom, canvasListState, canvasSizeState, fontSizeState, sortedPolygonArray } from '@/store/canvasAtom' import { QLine } from '@/components/fabric/QLine' import { getTests, getCanvasState, insertCanvasState } from '@/lib/canvas' +import { calculateIntersection2 } from '@/util/canvas-util' export default function Roof2() { const { canvas, handleRedo, handleUndo, setCanvasBackgroundWithDots, saveImage, addCanvas } = useCanvas('canvas') @@ -198,7 +199,7 @@ export default function Roof2() { ] if (canvas) { - const polygon = new QPolygon(eightPoint, { + const polygon = new QPolygon(type2, { fill: 'transparent', stroke: 'black', strokeWidth: 1, @@ -232,7 +233,18 @@ export default function Roof2() { const makeQLine = () => { if (canvas) { const line = new QLine( - [200, 200, 500, 500], + [50, 250, 900, 250], + { + stroke: 'black', + strokeWidth: 5, + fontSize: fontSize, + selectable: true, + }, + 50, + ) + + const line2 = new QLine( + [450, 450, 821, 78], { stroke: 'black', strokeWidth: 5, @@ -243,6 +255,22 @@ export default function Roof2() { ) canvas?.add(line) + canvas?.add(line2) + + const interSectionPoint = calculateIntersection2(line, line2) + + if (interSectionPoint) { + console.log(interSectionPoint) + + const circle = new fabric.Circle({ + radius: 5, + fill: 'red', + left: interSectionPoint.x - 5, + top: interSectionPoint.y - 5, + }) + + canvas?.add(circle) + } } } diff --git a/src/components/fabric/QLine.js b/src/components/fabric/QLine.js index ccc07282..4cc0fe08 100644 --- a/src/components/fabric/QLine.js +++ b/src/components/fabric/QLine.js @@ -73,6 +73,7 @@ export class QLine extends fabric.Group { }) this.on('selected', () => { + console.log(this) Object.keys(this.controls).forEach((controlKey) => { if (controlKey !== 'ml' && controlKey !== 'mr') { this.setControlVisible(controlKey, false) diff --git a/src/util/canvas-util.js b/src/util/canvas-util.js index 09f06f7f..61ab85df 100644 --- a/src/util/canvas-util.js +++ b/src/util/canvas-util.js @@ -312,7 +312,31 @@ export function calculateIntersection(line1, line2) { if (t >= 0 && t <= 1 && u >= 0 && u <= 1) { const intersectionX = x1_1 + t * (x2_1 - x1_1) const intersectionY = y1_1 + t * (y2_1 - y1_1) - return { x: Math.round(intersectionX), y: Math.round(intersectionY) } + + // Determine the min and max for line1 and line2 for both x and y + const line1MinX = Math.min(line1.x1, line1.x2) + const line1MaxX = Math.max(line1.x1, line1.x2) + const line2MinX = Math.min(line2.x1, line2.x2) + const line2MaxX = Math.max(line2.x1, line2.x2) + + const line1MinY = Math.min(line1.y1, line1.y2) + const line1MaxY = Math.max(line1.y1, line1.y2) + const line2MinY = Math.min(line2.y1, line2.y2) + const line2MaxY = Math.max(line2.y1, line2.y2) + + // 교차점이 선분의 범위 내에 있는지 확인 + if ( + intersectionX >= line1MinX && + intersectionX <= line1MaxX && + intersectionX >= line2MinX && + intersectionX <= line2MaxX && + intersectionY >= line1MinY && + intersectionY <= line1MaxY && + intersectionY >= line2MinY && + intersectionY <= line2MaxY + ) { + return { x: Math.round(intersectionX), y: Math.round(intersectionY) } + } } return null // 교차점이 선분의 범위 내에 없음 @@ -339,7 +363,6 @@ export const findIntersection1 = (line1, line2) => { if (determinant === 0) { // 두 선이 평행하거나 일직선일 경우 - console.log('두 직선은 평행하거나 일직선입니다.') return null } @@ -351,7 +374,37 @@ export const findIntersection1 = (line1, line2) => { export const calculateIntersection2 = (line1, line2) => { const result = intersect([line1.x1, line1.y1], [line1.x2, line1.y2], [line2.x1, line2.y1], [line2.x2, line2.y2]) - return { x: Math.round(result[0]), y: Math.round(result[1]) } + + if (!result) { + return null + } + + // Determine the min and max for line1 and line2 for both x and y + const line1MinX = Math.min(line1.x1, line1.x2) + const line1MaxX = Math.max(line1.x1, line1.x2) + const line2MinX = Math.min(line2.x1, line2.x2) + const line2MaxX = Math.max(line2.x1, line2.x2) + + const line1MinY = Math.min(line1.y1, line1.y2) + const line1MaxY = Math.max(line1.y1, line1.y2) + const line2MinY = Math.min(line2.y1, line2.y2) + const line2MaxY = Math.max(line2.y1, line2.y2) + + // Check if the intersection X and Y are within the range of both lines + if ( + result[0] >= line1MinX && + result[0] <= line1MaxX && + result[0] >= line2MinX && + result[0] <= line2MaxX && + result[1] >= line1MinY && + result[1] <= line1MaxY && + result[1] >= line2MinY && + result[1] <= line2MaxY + ) { + return { x: Math.round(result[0]), y: Math.round(result[1]) } + } else { + return null // Intersection is out of range + } } export function findOrthogonalPoint(line1, line2) { @@ -401,10 +454,10 @@ export const sortedPoints = (points) => { // y값이 같은 point가 많은 경우 그 중 x값이 가장 큰걸 찾는다. const temp = copyPoints.filter((point) => point.y === currentPoint.y) // temp중 x값이 가장 큰 값 - const max = temp.reduce((prev, current) => (prev.x >= current.x ? prev : current)) - resultPoints.push(max) - currentPoint = max - copyPoints.splice(copyPoints.indexOf(max), 1) + const min = temp.reduce((prev, current) => (prev.x <= current.x ? prev : current)) + resultPoints.push(min) + currentPoint = min + copyPoints.splice(copyPoints.indexOf(min), 1) index++ break } @@ -414,11 +467,11 @@ export const sortedPoints = (points) => { // x값이 같은 point가 많은 경우 그 중 y값이 가장 큰걸 찾는다. const temp = copyPoints.filter((point) => point.x === currentPoint.x) // temp중 y값이 가장 큰 값 - const max = temp.reduce((prev, current) => (prev.y >= current.y ? prev : current)) + const min = temp.reduce((prev, current) => (prev.y >= current.y ? prev : current)) - resultPoints.push(max) - currentPoint = max - copyPoints.splice(copyPoints.indexOf(max), 1) + resultPoints.push(min) + currentPoint = min + copyPoints.splice(copyPoints.indexOf(min), 1) index++ break } diff --git a/src/util/qpolygon-utils.js b/src/util/qpolygon-utils.js index 4afc2d92..ab4a276c 100644 --- a/src/util/qpolygon-utils.js +++ b/src/util/qpolygon-utils.js @@ -49,20 +49,23 @@ export const drawHelpLineInHexagon2 = (polygon, chon) => { const horizontalLines = oneSideLines.filter((line) => line.direction === 'right') const verticalLines = oneSideLines.filter((line) => line.direction === 'bottom') - // horizontalLines 를 y1 좌표 기준으로 정렬한다. horizontalLines.sort((a, b) => a.y1 - b.y1) // verticalLines 를 x1 좌표 기준으로 정렬한다. verticalLines.sort((a, b) => a.x1 - b.x1) - const horizontalMaxLength = horizontalLines.reduce((max, obj) => Math.max(max, obj.length), 0) + const maxHorizontalLineLength = horizontalLines.reduce((prev, current) => (prev.length > current.length ? prev.length : current.length)) + const maxVerticalLineLength = verticalLines.reduce((prev, current) => (prev.length > current.length ? prev.length : current.length)) - const verticalMaxLength = verticalLines.reduce((max, obj) => Math.max(max, obj.length), 0) // 모든 가로선의 중심선을 긋는다. - debugger horizontalLines.forEach((line, index) => { const nextLine = horizontalLines[(index + 1) % horizontalLines.length] + line.line.set({ strokeWidth: 5 }) + nextLine.line.set({ strokeWidth: 5 }) + + polygon.canvas.renderAll() + const startCenterX = Math.min(line.x1, nextLine.x1) const startCenterY = (line.y1 + nextLine.y1) / 2 @@ -76,8 +79,8 @@ export const drawHelpLineInHexagon2 = (polygon, chon) => { direction: 'horizontal', }) - polygon.canvas.add(centerLine) - polygon.canvas.renderAll() + /*polygon.canvas.add(centerLine) + polygon.canvas.renderAll()*/ centerLines.push(centerLine) }) @@ -99,14 +102,11 @@ export const drawHelpLineInHexagon2 = (polygon, chon) => { direction: 'vertical', }) - polygon.canvas.add(centerLine) - polygon.canvas.renderAll() - + /*polygon.canvas.add(centerLine) + polygon.canvas.renderAll()*/ centerLines.push(centerLine) }) - const maxLength = horizontalMaxLength < verticalMaxLength ? horizontalMaxLength : verticalMaxLength - polygon.points.forEach((point, index) => { const wallPoint = polygon.wall.points[index] // 두 점의 좌표 @@ -120,50 +120,67 @@ export const drawHelpLineInHexagon2 = (polygon, chon) => { // x1, y1을 기준으로 x2, y2와의 거리를 유지한 새로운 직선 생성 const angle = Math.atan2(y2 - y1, x2 - x1) - newX2 = Math.floor(x1 + (maxLength / 2 + 50) * Math.cos(angle)) - newY2 = Math.floor(y1 + (maxLength / 2 + 50) * Math.sin(angle)) + let previousIndex = index === 0 ? polygon.lines.length - 1 : index - 1 + const maxLength = Math.max(polygon.lines[index].length, polygon.lines[previousIndex].length) + + newX2 = Math.floor(x1 + (maxLength / 2 + polygon.points.length * 20) * Math.cos(angle)) + newY2 = Math.floor(y1 + (maxLength / 2 + polygon.points.length * 20) * Math.sin(angle)) const line = new QLine([x1, y1, newX2, newY2], { fontSize: polygon.fontSize, stroke: 'green', idx: index, }) + line.set({ degree: fabric.util.radiansToDegrees(angle) }) polygon.canvas.add(line) helpLines.push(line) polygon.canvas.renderAll() + debugger }) helpLines.forEach((line, index) => { - if (line.isAlreadyInterSection) { - return + for (let i = index + 1; i < helpLines.length; i++) { + const nextLine = helpLines[i] + + if (line.isAlreadyInterSection || nextLine.isAlreadyInterSection) { + continue + } + + let intersectionPoint = calculateIntersection(line, nextLine) + + if (!intersectionPoint) { + continue + } + + const circle = new fabric.Circle({ + radius: 3, + fill: 'red', + left: intersectionPoint.x - 3, + top: intersectionPoint.y - 3, + }) + + polygon.canvas.add(circle) + + line.set({ isAlreadyInterSection: true }) + nextLine.set({ isAlreadyInterSection: true }) + + const helpLine1 = new QLine([nextLine.x1, nextLine.y1, intersectionPoint.x, intersectionPoint.y], { + fontSize: polygon.fontSize, + stroke: 'skyblue', + }) + + const helpLine2 = new QLine([line.x1, line.y1, intersectionPoint.x, intersectionPoint.y], { + fontSize: polygon.fontSize, + stroke: 'skyblue', + }) + + ridgeStartPoints.push(intersectionPoint) + polygon.canvas.add(helpLine1) + polygon.canvas.add(helpLine2) + polygon.canvas.remove(nextLine) + polygon.canvas.remove(line) + polygon.canvas.renderAll() } - const nextLine = helpLines[(index + 1 + helpLines.length) % helpLines.length] - polygon.canvas.renderAll() - - let intersectionPoint = calculateIntersection(line, nextLine) - if (!intersectionPoint) { - return - } - - line.set({ isAlreadyInterSection: true }) - nextLine.set({ isAlreadyInterSection: true }) - - const helpLine1 = new QLine([nextLine.x1, nextLine.y1, intersectionPoint.x, intersectionPoint.y], { - fontSize: polygon.fontSize, - stroke: 'skyblue', - }) - - const helpLine2 = new QLine([line.x1, line.y1, intersectionPoint.x, intersectionPoint.y], { - fontSize: polygon.fontSize, - stroke: 'skyblue', - }) - - ridgeStartPoints.push(intersectionPoint) - polygon.canvas.add(helpLine1) - polygon.canvas.add(helpLine2) - polygon.canvas.remove(nextLine) - polygon.canvas.remove(line) - polygon.canvas.renderAll() }) // 안만나는 선들 @@ -172,30 +189,70 @@ export const drawHelpLineInHexagon2 = (polygon, chon) => { const interSectionPoints = [] notInterSectionLines.forEach((line, index) => { - line.line.set({ strokeWidth: (index + 1) * 5 }) + let subCenterLines + if (maxHorizontalLineLength > maxVerticalLineLength) { + if (Math.abs(line.degree) < 90) { + subCenterLines = centerLines.filter((centerLine) => centerLine.direction === 'horizontal') + } else { + subCenterLines = centerLines.filter((centerLine) => centerLine.direction === 'vertical') + } + } else { + if (Math.abs(line.degree) < 90) { + subCenterLines = centerLines.filter((centerLine) => centerLine.direction === 'vertical') + } else { + subCenterLines = centerLines.filter((centerLine) => centerLine.direction === 'horizontal') + } + } centerLines.forEach((centerLine) => { - const interSectionPoint = findIntersection1(line, centerLine) - console.log('interSectionPoint', interSectionPoint) + const interSectionPoint = calculateIntersection2(line, centerLine) - if (!polygon.inPolygon(interSectionPoint) || !interSectionPoint) { + if (!interSectionPoint) { return } - line.interSectionPoints.push(interSectionPoint) - interSectionPoints.push(interSectionPoint) + + ridgeStartPoints.forEach((point) => { + if (Math.abs(interSectionPoint.x - point.x) <= 2 || Math.abs(interSectionPoint.y - point.y) <= 2) { + line.interSectionPoints.push(interSectionPoint) + interSectionPoints.push(interSectionPoint) + + const newLine = new QLine([line.x1, line.y1, interSectionPoint.x, interSectionPoint.y], { + stroke: 'black', + fontSize: polygon.fontSize, + }) + + const circle = new fabric.Circle({ + radius: 3, + fill: 'blue', + left: interSectionPoint.x - 3, + top: interSectionPoint.y - 3, + }) + polygon.canvas.add(circle) + polygon.canvas.add(newLine) + + polygon.canvas.remove(line) + + line.set({ isAlreadyInterSection: true }) + } + }) }) }) - interSectionPoints.forEach((point) => { - const circle = new fabric.Circle({ - radius: 3, - fill: 'red', - left: point.x, - top: point.y, - }) + ridgeStartPoints.forEach((point, index) => { + for (let i = index + 1; i < ridgeStartPoints.length; i++) { + const currentPoint = ridgeStartPoints[index] + const nextPoint = ridgeStartPoints[i] - polygon.canvas.add(circle) - polygon.canvas.renderAll() + if (currentPoint.x === nextPoint.x || currentPoint.y === nextPoint.y) { + const ridge = new QLine([currentPoint.x, currentPoint.y, nextPoint.x, nextPoint.y], { + stroke: 'black', + fontSize: polygon.fontSize, + }) + polygon.canvas.add(ridge) + polygon.canvas.renderAll() + break + } + } }) ridgeStartPoints.forEach((point, index) => { @@ -203,7 +260,7 @@ export const drawHelpLineInHexagon2 = (polygon, chon) => { let distance = Infinity let startPoint interSectionPoints.forEach((interSectionPoint) => { - if (Math.abs(point.x - interSectionPoint.x) < 3 || Math.abs(point.y - interSectionPoint.y) < 3) { + if (Math.abs(point.x - interSectionPoint.x) < 1 || Math.abs(point.y - interSectionPoint.y) < 1) { if (distanceBetweenPoints(point, interSectionPoint) < distance) { startPoint = point distance = distanceBetweenPoints(point, interSectionPoint) @@ -230,10 +287,11 @@ export const drawHelpLineInHexagon2 = (polygon, chon) => { polygon.canvas.add(helpLine) polygon.canvas.remove(line) polygon.canvas.renderAll() + debugger } }) - for (let i = 0; i < ridgeEndPoints.length; i = i + 2) { + /*for (let i = 0; i < ridgeEndPoints.length; i = i + 2) { const currentRidgeEndPoint = ridgeEndPoints[i] const nextRidgeEndPoint = ridgeEndPoints[(i + 1) % ridgeEndPoints.length] const ridgeConnectLine = new QLine([currentRidgeEndPoint.x, currentRidgeEndPoint.y, nextRidgeEndPoint.x, nextRidgeEndPoint.y], { @@ -243,7 +301,8 @@ export const drawHelpLineInHexagon2 = (polygon, chon) => { polygon.canvas.add(ridgeConnectLine) polygon.canvas.renderAll() - } + debugger + }*/ } export const drawHelpLineInHexagon = (polygon, chon) => {