qpolygon 방향 line 추가 및 함수 추가

This commit is contained in:
hyojun.choi 2024-07-11 10:57:23 +09:00
parent 68cb952b70
commit 446f5ba093
4 changed files with 178 additions and 14 deletions

View File

@ -46,6 +46,7 @@ export default function Roof2() {
zoomOut,
zoom,
togglePolygonLine,
handleOuterlinesTest2,
} = useMode()
useEffect(() => {
@ -135,12 +136,14 @@ export default function Roof2() {
if (canvas) {
const polygon = new QPolygon(
[
{ x: 100, y: 100 },
{ x: 800, y: 100 },
{ x: 800, y: 800 },
{ x: 500, y: 800 },
{ x: 500, y: 400 },
{ x: 100, y: 400 },
{ x: 198.5, y: 735 },
{ x: 698.5, y: 735 },
{ x: 698.5, y: 585 },
{ x: 448.5, y: 585 },
{ x: 448.5, y: 435 },
{ x: 698.5, y: 435 },
{ x: 698.5, y: 235 },
{ x: 198.5, y: 235 },
],
{
fill: 'transparent',
@ -155,10 +158,10 @@ export default function Roof2() {
canvas?.add(polygon)
addBackgroundInPolygon(polygon)
handleOuterlinesTest2(polygon)
const lines = togglePolygonLine(polygon)
togglePolygonLine(lines[0])
// const lines = togglePolygonLine(polygon)
// togglePolygonLine(lines[0])
}
}

View File

@ -5,6 +5,7 @@ import {
getDirectionByPoint,
getRoofHeight,
getRoofHypotenuse,
sortedPoints,
} from '@/util/canvas-util'
import { QLine } from '@/components/fabric/QLine'
@ -26,15 +27,14 @@ export default class QPolygon extends fabric.Group {
throw new Error('Canvas is required.')
}
const polygon = new fabric.Polygon(points, options)
const sortPoints = sortedPoints(points)
const polygon = new fabric.Polygon(sortPoints, options)
super([polygon], {})
this.fontSize = options.fontSize
this.points = points
this.points = sortPoints
this.polygon = polygon
this.name = options.name
this.#init()
this.#addEvent()
this.#initLines()

View File

@ -723,7 +723,7 @@ export function useMode() {
*/
const handleOuterlinesTest = (offset = 71) => {
var offsetPoints = []
const sortedIndex = getStartIndex(historyLines.current)
let tmpArraySorted = rearrangeArray(historyLines.current, sortedIndex)
@ -789,6 +789,76 @@ export function useMode() {
roof.drawHelpLine()
}
/**
* 지붕 외곽선 생성 polygon을 입력받아 만들기
*/
const handleOuterlinesTest2 = (polygon, offset = 71) => {
const offsetPoints = []
const sortedIndex = getStartIndex(polygon.lines)
let tmpArraySorted = rearrangeArray(polygon.lines, sortedIndex)
if (tmpArraySorted[0].direction === 'right') {
//시계방향
tmpArraySorted = tmpArraySorted.reverse() //그럼 배열을 거꾸로 만들어서 무조건 반시계방향으로 배열 보정
}
setSortedArray(tmpArraySorted) //recoil에 넣음
const points = tmpArraySorted.map((line) => ({
x: line.x1,
y: line.y1,
}))
for (let i = 0; i < points.length; i++) {
const prev = points[(i - 1 + points.length) % points.length]
const current = points[i]
const next = points[(i + 1) % points.length]
// 두 벡터 계산 (prev -> current, current -> next)
const vector1 = { x: current.x - prev.x, y: current.y - prev.y }
const vector2 = { x: next.x - current.x, y: next.y - current.y }
// 벡터의 길이 계산
const length1 = Math.sqrt(vector1.x * vector1.x + vector1.y * vector1.y)
const length2 = Math.sqrt(vector2.x * vector2.x + vector2.y * vector2.y)
// 벡터를 단위 벡터로 정규화
const unitVector1 = { x: vector1.x / length1, y: vector1.y / length1 }
const unitVector2 = { x: vector2.x / length2, y: vector2.y / length2 }
// 법선 벡터 계산 (왼쪽 방향)
const normal1 = { x: -unitVector1.y, y: unitVector1.x }
const normal2 = { x: -unitVector2.y, y: unitVector2.x }
// 법선 벡터 평균 계산
const averageNormal = {
x: (normal1.x + normal2.x) / 2,
y: (normal1.y + normal2.y) / 2,
}
// 평균 법선 벡터를 단위 벡터로 정규화
const lengthNormal = Math.sqrt(
averageNormal.x * averageNormal.x + averageNormal.y * averageNormal.y,
)
const unitNormal = {
x: averageNormal.x / lengthNormal,
y: averageNormal.y / lengthNormal,
}
// 오프셋 적용
const offsetPoint = {
x1: current.x + unitNormal.x * offset,
y1: current.y + unitNormal.y * offset,
}
offsetPoints.push(offsetPoint)
}
const roof = makePolygon(offsetPoints)
setRoof(roof)
// roof.drawHelpLine()
}
const togglePolygonLine = (obj) => {
const rtnLines = []
if (obj.type === 'QPolygon') {
@ -834,5 +904,6 @@ export function useMode() {
zoomOut,
zoom,
togglePolygonLine,
handleOuterlinesTest2,
}
}

View File

@ -155,6 +155,30 @@ export const getStartIndex = (lines) => {
return smallestIndex
}
/**
* points 배열에서 시작점을 찾는 함수
* @param points
* @returns {number}
*/
export const getStartIndexPoint = (points) => {
let smallestIndex = 0
let smallestX1 = points[0].x
let smallestY1 = points[0].y
for (let i = 1; i < points.length; i++) {
if (
points[i].x < smallestX1 ||
(points[i].x === smallestX1 && points[i].y < smallestY1)
) {
smallestIndex = i
smallestX1 = points[i].x
smallestY1 = points[i].y
}
}
return smallestIndex
}
/**
* 함수는 개의 매개변수를 받습니다: array와 index.
* array는 재배열할 대상 배열입니다.
@ -309,3 +333,69 @@ export function calculateIntersection(line1, line2) {
return { x: intersectX, y: intersectY }
}
/**
* points배열을 입력받아 반시계방향으로 정렬된 points를 반환합니다.
* @param points
*/
export const sortedPoints = (points) => {
const copyPoints = [...points]
//points를 x,y좌표를 기준으로 정렬합니다.
copyPoints.sort((a, b) => {
if (a.x === b.x) {
return a.y - b.y
}
return a.x - b.x
})
// 이때 copyPoints를 순회하며 최초엔 x값을 비교하여 같은 점을 찾는다. 이때 이 점이 2번째 점이 된다.
// 그 다음점은 2번째 점과 y값이 같은 점이 된다.
// 또 그다음 점은 3번째 점과 x값이 같은 점이 된다.
// 이를 반복하여 copyPoints를 재배열한다.
const resultPoints = [copyPoints[0]]
let index = 1
let currentPoint = { ...copyPoints[0] }
copyPoints.splice(0, 1)
while (index < points.length) {
if (index === points.length - 1) {
resultPoints.push(copyPoints[0])
index++
break
} else if (index % 2 === 0) {
// 짝수번째는 y값이 같은 점을 찾는다.
for (let i = 0; i < copyPoints.length; i++) {
// 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)
index++
break
}
} else {
// 홀수번째는 x값이 같은 점을 찾는다.
for (let i = 0; i < copyPoints.length; i++) {
// 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,
)
resultPoints.push(max)
currentPoint = max
copyPoints.splice(copyPoints.indexOf(max), 1)
index++
break
}
}
}
return resultPoints
}