polygon 나누는 함수 수정

This commit is contained in:
hyojun.choi 2024-08-07 15:04:55 +09:00
parent 69568966ba
commit 46ecb8fdee
2 changed files with 127 additions and 2 deletions

View File

@ -2,7 +2,7 @@ import { fabric } from 'fabric'
import { v4 as uuidv4 } from 'uuid' import { v4 as uuidv4 } from 'uuid'
import { QLine } from '@/components/fabric/QLine' import { QLine } from '@/components/fabric/QLine'
import { distanceBetweenPoints, findTopTwoIndexesByDistance, getDirectionByPoint, sortedPointLessEightPoint, sortedPoints } from '@/util/canvas-util' import { distanceBetweenPoints, findTopTwoIndexesByDistance, getDirectionByPoint, sortedPointLessEightPoint, sortedPoints } from '@/util/canvas-util'
import { calculateAngle, dividePolygon, drawHelpLineInHexagon } from '@/util/qpolygon-utils' import { calculateAngle, dividePolygon, drawHelpLineInHexagon, splitPolygonWithLines } from '@/util/qpolygon-utils'
export const QPolygon = fabric.util.createClass(fabric.Polygon, { export const QPolygon = fabric.util.createClass(fabric.Polygon, {
type: 'QPolygon', type: 'QPolygon',
@ -450,6 +450,6 @@ export const QPolygon = fabric.util.createClass(fabric.Polygon, {
}) })
}, },
divideLine() { divideLine() {
dividePolygon(this) splitPolygonWithLines(this)
}, },
}) })

View File

@ -2,6 +2,7 @@ import { fabric } from 'fabric'
import { QLine } from '@/components/fabric/QLine' import { QLine } from '@/components/fabric/QLine'
import { calculateIntersection, distanceBetweenPoints, findClosestPoint, getDirectionByPoint } from '@/util/canvas-util' import { calculateIntersection, distanceBetweenPoints, findClosestPoint, getDirectionByPoint } from '@/util/canvas-util'
import { QPolygon } from '@/components/fabric/QPolygon' import { QPolygon } from '@/components/fabric/QPolygon'
import polygonSplitter from 'polygon-splitter'
const TWO_PI = Math.PI * 2 const TWO_PI = Math.PI * 2
@ -954,3 +955,127 @@ export default function offsetPolygon(vertices, offset) {
} }
} }
} }
export const splitPolygonWithLines = (polygon) => {
//todo: polygon의 모든 line들 모음 hip, ridge, connectRidge
const allLines = [...polygon.hips, ...polygon.ridges, ...polygon.connectRidges]
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 = []
const polygonPoints = [...polygon.points].map((point, index) => {
return { ...point, index }
})
// 시작점은 시작 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
while (!isSamePoint(currentPoint, arrivalPoint)) {
// startHip에서 만나는 출발선 두개. 두개의 선을 출발하여 arrivalPoint에 도착할 때 까지 count를 세고, 더 낮은 count를 가진 길을 선택한다.
let connectedLines = allLinesCopy.filter(
(line) => isSamePoint(line.startPoint, currentPoint) || (isSamePoint(line.endPoint, currentPoint) && line !== currentLine),
)
if (connectedLines.length === 0) {
throw new Error('connectedLines is empty')
}
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
routes.push(currentPoint)
}
}
routes.push(endLine.startPoint)
const roof = new QPolygon(routes, {
fontSize: polygon.fontSize,
stroke: 'black',
fill: 'transparent',
strokeWidth: 3,
name: 'roof',
})
polygon.canvas.add(roof)
polygon.canvas.renderAll()
})
}
const isSamePoint = (a, b) => {
return a.x === b.x && a.y === b.y
}
/**
* Calculate the angle between two lines.
* @param {Object} line1 - The first line defined by two points {x1, y1} and {x2, y2}.
* @param {Object} line2 - The second line defined by two points {x1, y1} and {x2, y2}.
* @returns {number} - The angle between the two lines in degrees.
*/
function calculateAngleBetweenLines(line1, line2) {
const { x1: x1_1, y1: y1_1, x2: x2_1, y2: y2_1 } = line1
const { x1: x1_2, y1: y1_2, x2: x2_2, y2: y2_2 } = line2
// Calculate direction vectors
const vector1 = { x: x2_1 - x1_1, y: y2_1 - y1_1 }
const vector2 = { x: x2_2 - x1_2, y: y2_2 - y1_2 }
// Calculate dot product and magnitudes
const dotProduct = vector1.x * vector2.x + vector1.y * vector2.y
const magnitude1 = Math.sqrt(vector1.x * vector1.x + vector1.y * vector1.y)
const magnitude2 = Math.sqrt(vector2.x * vector2.x + vector2.y * vector2.y)
// Calculate the cosine of the angle
const cosTheta = dotProduct / (magnitude1 * magnitude2)
// Calculate the angle in radians and then convert to degrees
const angleInRadians = Math.acos(cosTheta)
const angleInDegrees = (angleInRadians * 180) / Math.PI
return angleInDegrees
}