다각형 시도 중

This commit is contained in:
Jaeyoung Lee 2024-07-30 17:58:03 +09:00
parent e29d581f10
commit 3feaf79306
4 changed files with 1070 additions and 1596 deletions

View File

@ -10,7 +10,6 @@ import { canvasSizeState, fontSizeState, sortedPolygonArray } from '@/store/canv
import { QLine } from '@/components/fabric/QLine' import { QLine } from '@/components/fabric/QLine'
import { getCanvasState, insertCanvasState } from '@/lib/canvas' import { getCanvasState, insertCanvasState } from '@/lib/canvas'
import { calculateIntersection2 } from '@/util/canvas-util' import { calculateIntersection2 } from '@/util/canvas-util'
import { CustomLine } from '@/components/fabric/QLine'
import { QPolygon } from '@/components/fabric/QPolygon' import { QPolygon } from '@/components/fabric/QPolygon'
export default function Roof2() { export default function Roof2() {
@ -45,6 +44,7 @@ export default function Roof2() {
handleOuterlinesTest2, handleOuterlinesTest2,
applyTemplateB, applyTemplateB,
makeRoofPatternPolygon, makeRoofPatternPolygon,
drawRoofPolygon,
} = useMode() } = useMode()
// const [canvasState, setCanvasState] = useRecoilState(canvasAtom) // const [canvasState, setCanvasState] = useRecoilState(canvasAtom)
@ -237,11 +237,32 @@ export default function Roof2() {
{ x: 350, y: 100 }, { x: 350, y: 100 },
] ]
const complicatedType = [
{ x: 100, y: 100 },
{ x: 100, y: 1100 },
{ x: 400, y: 1100 },
{ x: 400, y: 800 },
{ x: 700, y: 800 },
{ x: 700, y: 1100 },
{ x: 1000, y: 1100 },
{ x: 1000, y: 600 },
{ x: 700, y: 600 },
{ x: 700, y: 300 },
{ x: 1000, y: 300 },
{ x: 1000, y: 100 },
]
const diagonalType = [
{ x: 100, y: 100 },
{ x: 100, y: 600 },
{ x: 600, y: 600 },
{ x: 400, y: 100 }]
if (canvas) { if (canvas) {
const polygon = new QPolygon(type1A, { const polygon = new QPolygon(diagonalType, {
// const polygon = new QPolygon(eightPoint, { // const polygon = new QPolygon(eightPoint, {
fill: 'transparent', fill: 'transparent',
stroke: 'black', stroke: 'green',
strokeWidth: 1, strokeWidth: 1,
selectable: true, selectable: true,
fontSize: fontSize, fontSize: fontSize,
@ -249,8 +270,9 @@ export default function Roof2() {
}) })
canvas?.add(polygon) canvas?.add(polygon)
drawRoofPolygon(polygon)
handleOuterlinesTest2(polygon) // handleOuterlinesTest2(polygon)
// const lines = togglePolygonLine(polygon) // const lines = togglePolygonLine(polygon)
// togglePolygonLine(lines[0]) // togglePolygonLine(lines[0])

File diff suppressed because it is too large Load Diff

View File

@ -1,9 +1,22 @@
import { useEffect, useRef, useState } from 'react' import { useEffect, useRef, useState } from 'react'
import QRect from '@/components/fabric/QRect' import QRect from '@/components/fabric/QRect'
import { findTopTwoIndexesByDistance, getCenterPoint, getDirection, getStartIndex, rearrangeArray } from '@/util/canvas-util' import {
findTopTwoIndexesByDistance,
getCenterPoint,
getDirection,
getStartIndex,
rearrangeArray,
} from '@/util/canvas-util'
import { useRecoilState } from 'recoil' import { useRecoilState } from 'recoil'
import { canvasSizeState, fontSizeState, roofPolygonPatternArrayState, roofState, sortedPolygonArray, wallState } from '@/store/canvasAtom' import {
canvasSizeState,
fontSizeState,
roofPolygonPatternArrayState,
roofState,
sortedPolygonArray,
wallState,
} from '@/store/canvasAtom'
import { QLine } from '@/components/fabric/QLine' import { QLine } from '@/components/fabric/QLine'
import { fabric } from 'fabric' import { fabric } from 'fabric'
import { QPolygon } from '@/components/fabric/QPolygon' import { QPolygon } from '@/components/fabric/QPolygon'
@ -1156,6 +1169,11 @@ export function useMode() {
roof.drawHelpLine() roof.drawHelpLine()
} }
const drawRoofPolygon = (wall, offset = 71) => {
console.log(wall)
}
const togglePolygonLine = (obj) => { const togglePolygonLine = (obj) => {
const rtnLines = [] const rtnLines = []
if (obj.type === 'QPolygon') { if (obj.type === 'QPolygon') {
@ -2252,7 +2270,13 @@ export function useMode() {
canvas.add(centerLine2) canvas.add(centerLine2)
canvas.remove(outLines[idx]) //기존 라인 삭제 canvas.remove(outLines[idx]) //기존 라인 삭제
halfHoriCenterLinePoint.push({ index: idx, x1: centerLine1.x1, y1: centerLine1.y1, x2: centerLine1.x2, y2: centerLine1.y2 }) //각 카라바 라인의 1번이 마지막점을 잡아서 센터선으로 설정 halfHoriCenterLinePoint.push({
index: idx,
x1: centerLine1.x1,
y1: centerLine1.y1,
x2: centerLine1.x2,
y2: centerLine1.y2,
}) //각 카라바 라인의 1번이 마지막점을 잡아서 센터선으로 설정
} }
}) })
@ -2453,7 +2477,13 @@ export function useMode() {
canvas.add(centerLine2) canvas.add(centerLine2)
canvas.remove(outline) //기존 라인 삭제 canvas.remove(outline) //기존 라인 삭제
halfHoriCenterLinePoint.push({ index: index, x1: centerLine1.x1, y1: centerLine1.y1, x2: centerLine1.x2, y2: centerLine1.y2 }) //각 카라바 라인의 1번이 마지막점을 잡아서 센터선으로 설정 halfHoriCenterLinePoint.push({
index: index,
x1: centerLine1.x1,
y1: centerLine1.y1,
x2: centerLine1.x2,
y2: centerLine1.y2,
}) //각 카라바 라인의 1번이 마지막점을 잡아서 센터선으로 설정
} }
} }
}) })
@ -3211,5 +3241,6 @@ export function useMode() {
handleOuterlinesTest, handleOuterlinesTest,
handleOuterlinesTest2, handleOuterlinesTest2,
makeRoofPatternPolygon, makeRoofPatternPolygon,
drawRoofPolygon,
} }
} }

View File

@ -285,7 +285,8 @@ export const drawHelpLineInHexagon = (polygon, chon) => {
}*/ }*/
} }
export const drawHelpLineInHexagon2 = (polygon, chon) => {} export const drawHelpLineInHexagon2 = (polygon, chon) => {
}
export const drawCenterLines = (polygon) => { export const drawCenterLines = (polygon) => {
const centerLines = [] const centerLines = []
@ -384,3 +385,982 @@ const calculateAngle = (point1, point2) => {
const angleInRadians = Math.atan2(deltaY, deltaX) const angleInRadians = Math.atan2(deltaY, deltaX)
return angleInRadians * (180 / Math.PI) return angleInRadians * (180 / Math.PI)
} }
export const drawHippedRoof = (polygon, chon) => {
drawRoofRidge(polygon, chon)
// drawHips(polygon, chon)
// connectLinePoint()
}
/*
외벽의 모양이 돌출된 ㄷ의 형태일때
현재 라인의 외벽길이가 붙어있는 두외벽의 길이보다 짧거나 같다면
지붕의 꼭지점에서 외벽의 꼭지점으로 45 방향으로 선을 그려 만나는 지점이 마루의 시작점이 되고
시작점에서 부터 (가장 긴선 - ( 삼각형의 빗변 에서 직각까지의 수직길이 x 2)) 길이가 마루의 끝점이 된다.
다만 마루의 길이는 나머지 나머지 지붕의 길이중 짧은선의 길이를 넘어갈수 없다.
*/
const drawRoofRidge = (polygon) => {
let prevLine, currentLine, nextLine, prevWall, currentWall, nextWall
let startXPoint, startYPoint, endXPoint, endYPoint
let dVector, ridgeMaxLength, ridgeMinLength, ridgeRun
polygon.lines.forEach(
(value, index) => {
if (index === 0) {
prevLine = polygon.lines[polygon.lines.length - 1]
prevWall = polygon.wall.lines[polygon.wall.lines.length - 1]
} else {
prevLine = polygon.lines[index - 1]
prevWall = polygon.wall.lines[index - 1]
}
currentLine = polygon.lines[index]
currentWall = polygon.wall.lines[index]
if (index === polygon.lines.length - 1) {
nextLine = polygon.lines[0]
nextWall = polygon.wall.lines[0]
} else if (index === polygon.lines.length) {
nextLine = polygon.lines[1]
nextWall = polygon.wall.lines[1]
} else {
nextLine = polygon.lines[index + 1]
nextWall = polygon.wall.lines[index + 1]
}
console.log(polygon.lines)
// let ridgeBaseLine = polygon.lines.filter((line) => line.idx === currentLine.idx)[0]
// if (this.getLineDirection(prevLine) !== this.getLineDirection(nextLine) && currentWall.length < currentLine.length) {
if (getLineDirection(prevWall) !== getLineDirection(nextWall) && currentWall.length < currentLine.length) {
dVector = getDirectionForDegree(prevWall, currentWall)
let {
minLineLength,
currentLineLength,
maxLineLength,
} = getRoofBaseLine(polygon, prevWall, currentWall, nextWall, dVector)
console.log('currentLine.length : ' + currentWall.length)
// 마루는 세개의 벽중에서 가장 길 수 없다.
console.log('currentLineLength : ', currentLineLength, 'minLineLength : ', minLineLength, 'maxLineLength : ', maxLineLength)
console.log('minLineLength <= currentLineLength <= maxLineLength', (minLineLength <= currentLineLength && currentLineLength <= maxLineLength))
if (currentLineLength <= maxLineLength) {
// console.log('currentLine.length : ' + currentLine.length)
ridgeMaxLength = Math.min(minLineLength, maxLineLength)
ridgeMinLength = Math.max(minLineLength, maxLineLength) - currentLineLength
ridgeRun = Math.min(ridgeMinLength, ridgeMaxLength)
// console.log(ridgeRun)
switch (dVector) {
case 45:
startXPoint = currentWall.x1 + (currentLineLength / 2)
startYPoint = currentWall.y1 - (currentLineLength / 2)
endXPoint = startXPoint
endYPoint = startYPoint - ridgeRun
break
case 135:
startXPoint = currentWall.x1 + (currentLineLength / 2)
startYPoint = currentWall.y1 + (currentLineLength / 2)
endXPoint = startXPoint + ridgeRun
endYPoint = startYPoint
break
case 225:
startXPoint = currentWall.x1 - (currentLineLength / 2)
startYPoint = currentWall.y1 + (currentLineLength / 2)
endXPoint = startXPoint
endYPoint = startYPoint + ridgeRun
break
case 315:
startXPoint = currentWall.x1 - (currentLineLength / 2)
startYPoint = currentWall.y1 - (currentLineLength / 2)
endXPoint = startXPoint - ridgeRun
endYPoint = startYPoint
break
}
let isDuplicate = false
polygon.ridges.forEach((ridge) => {
if (ridge.x1 === Math.min(startXPoint, endXPoint) && ridge.y1 === Math.min(startYPoint, endYPoint) && ridge.x2 === Math.max(startXPoint, endXPoint) && ridge.y2 === Math.max(startYPoint, endYPoint)) {
isDuplicate = true
}
})
if (!isDuplicate && polygon.ridges.length < getMaxRidge(polygon.lines.length)) {
const ridge = new QLine([Math.min(startXPoint, endXPoint), Math.min(startYPoint, endYPoint), Math.max(startXPoint, endXPoint), Math.max(startYPoint, endYPoint)], {
fontSize: polygon.fontSize,
stroke: 'blue',
strokeWidth: 1,
})
polygon.canvas.add(ridge)
polygon.ridges.push(ridge)
polygon.innerLines.push(ridge)
}
}
}
},
)
}
const drawHips = (polygon) => {
/*
마루에서 시작되는 hip을 먼저 그립니다.
*/
this.ridges.forEach((ridge) => {
let leftTop, rightTop, leftBottom, rightBottom
if (ridge.x1 !== ridge.x2 && ridge.y1 === ridge.y2) {
// console.log('가로방향 마루')
//왼쪽 좌표 기준 225, 315도 방향 라인확인
leftTop = this.lines.filter((line) => line.x1 < ridge.x1 && line.y1 < ridge.y1
&& Math.abs(line.x1 - ridge.x1) === Math.abs(line.y1 - ridge.y1))
.reduce((prev, current) => {
if (prev <= 0) {
return current
} else {
return Math.min(ridge.x1 - current.x1) < Math.min(ridge.x1 - prev.x1) ? current : prev
}
}, [])
leftBottom = this.lines.filter((line) => line.x1 < ridge.x1 && line.y1 > ridge.y1
&& Math.abs(line.x1 - ridge.x1) === Math.abs(line.y1 - ridge.y1))
.reduce((prev, current) => {
if (prev <= 0) {
return current
} else {
return Math.min(ridge.x1 - current.x1) < Math.min(ridge.x1 - prev.x1) ? current : prev
}
}, [])
//오른쪽 좌표 기준 45, 135도 방향 라인확인
rightTop = this.lines.filter((line) => line.x1 > ridge.x2 && line.y1 < ridge.y2
&& Math.abs(line.x1 - ridge.x2) === Math.abs(line.y1 - ridge.y2))
.reduce((prev, current) => {
if (prev <= 0) {
return current
} else {
return Math.min(current.x1 - ridge.x2) < Math.min(prev.x1 - ridge.x2) ? current : prev
}
}, [])
rightBottom = this.lines.filter((line) => line.x1 > ridge.x2 && line.y1 > ridge.y2
&& Math.abs(line.x1 - ridge.x2) === Math.abs(line.y1 - ridge.y2))
.reduce((prev, current) => {
if (prev <= 0) {
return current
} else {
return Math.min(current.x1 - ridge.x2) < Math.min(prev.x1 - ridge.x2) ? current : prev
}
}, [])
if (leftTop.length > 0) {
const hip = new QLine([leftTop.x1, leftTop.y1, ridge.x1, ridge.y1], {
fontSize: this.fontSize,
stroke: 'red',
strokeWidth: 1,
})
this.addWithUpdate(hip)
this.hips.push(hip)
this.innerLines.push(hip)
}
if (leftBottom.length > 0) {
const hip = new QLine([leftBottom.x1, leftBottom.y1, ridge.x1, ridge.y1], {
fontSize: this.fontSize,
stroke: 'red',
strokeWidth: 1,
})
this.addWithUpdate(hip)
this.hips.push(hip)
this.innerLines.push(hip)
}
if (rightTop.length > 0) {
const hip = new QLine([rightTop.x1, rightTop.y1, ridge.x2, ridge.y2], {
fontSize: this.fontSize,
stroke: 'red',
strokeWidth: 1,
})
this.addWithUpdate(hip)
this.hips.push(hip)
this.innerLines.push(hip)
}
if (rightBottom.length > 0) {
const hip = new QLine([rightBottom.x1, rightBottom.y1, ridge.x2, ridge.y2], {
fontSize: this.fontSize,
stroke: 'red',
strokeWidth: 1,
})
this.addWithUpdate(hip)
this.hips.push(hip)
this.innerLines.push(hip)
}
}
if (ridge.y1 !== ridge.y2 && ridge.x1 === ridge.x2) {
// console.log('세로방향 마루')
//위쪽 좌표 기준 45, 315도 방향 라인확인
leftTop = this.lines.filter((line) => line.x1 < ridge.x1 && line.y1 < ridge.y1
&& Math.abs(line.x1 - ridge.x1) === Math.abs(line.y1 - ridge.y1))
.reduce((prev, current) => {
if (prev <= 0) {
return current
} else {
return Math.min(ridge.y1 - current.y1) < Math.min(ridge.y1 - prev.y1) ? current : prev
}
}, [])
rightTop = this.lines.filter((line) => line.x1 > ridge.x1 && line.y1 < ridge.y1
&& Math.abs(line.x1 - ridge.x1) === Math.abs(line.y1 - ridge.y1))
.reduce((prev, current) => {
if (prev <= 0) {
return current
} else {
return Math.min(ridge.y1 - current.y1) < Math.min(ridge.y1 - prev.y1) ? current : prev
}
}, [])
//아래쪽 좌표 기준 135, 225도 방향 라인확인
leftBottom = this.lines.filter((line) => line.x1 < ridge.x2 && line.y1 > ridge.y2
&& Math.abs(line.x1 - ridge.x2) === Math.abs(line.y1 - ridge.y2))
.reduce((prev, current) => {
if (prev <= 0) {
return current
} else {
return Math.min(current.y1 - ridge.y2) < Math.min(prev.y1 - ridge.y2) ? current : prev
}
}, [])
rightBottom = this.lines.filter((line) => line.x1 > ridge.x2 && line.y1 > ridge.y2
&& Math.abs(line.x1 - ridge.x2) === Math.abs(line.y1 - ridge.y2))
.reduce((prev, current) => {
if (prev.length <= 0) {
return current
} else {
return Math.min(current.y1 - ridge.y2) < Math.min(prev.y1 - ridge.y2) ? current : prev
}
}, [])
if (leftTop.length > 0) {
const hip = new QLine([leftTop.x1, leftTop.y1, ridge.x1, ridge.y1], {
fontSize: this.fontSize,
stroke: 'red',
strokeWidth: 1,
})
this.addWithUpdate(hip)
this.hips.push(hip)
this.innerLines.push(hip)
}
if (rightTop.length > 0) {
const hip = new QLine([rightTop.x1, rightTop.y1, ridge.x1, ridge.y1], {
fontSize: this.fontSize,
stroke: 'red',
strokeWidth: 1,
})
this.addWithUpdate(hip)
this.hips.push(hip)
this.innerLines.push(hip)
}
if (leftBottom.length > 0) {
const hip = new QLine([leftBottom.x1, leftBottom.y1, ridge.x2, ridge.y2], {
fontSize: this.fontSize,
stroke: 'red',
strokeWidth: 1,
})
this.addWithUpdate(hip)
this.hips.push(hip)
this.innerLines.push(hip)
}
if (rightBottom.length > 0) {
const hip = new QLine([rightBottom.x1, rightBottom.y1, ridge.x2, ridge.y2], {
fontSize: this.fontSize,
stroke: 'red',
strokeWidth: 1,
})
this.addWithUpdate(hip)
this.hips.push(hip)
this.innerLines.push(hip)
}
}
})
// 가장 가까운 마루를 확인하여 그릴 수 있는 라인이 존재하면 먼저 그린다.
let prevLine, currentLine, nextLine
this.lines.forEach(
(value, index) => {
if (index === 0) {
prevLine = this.lines[this.lines.length - 1]
} else {
prevLine = this.lines[index - 1]
}
currentLine = this.lines[index]
if (index === this.lines.length - 1) {
nextLine = this.lines[0]
} else if (index === this.lines.length) {
nextLine = this.lines[1]
} else {
nextLine = this.lines[index + 1]
}
if (!this.isAlreadyHip(currentLine)) {
let dVector = this.getDirectionForDegree(prevLine, currentLine)
let nearRidge
switch (dVector) {
case 45:
nearRidge = this.ridges.filter(ridge => (currentLine.x1 < ridge.x1 && currentLine.y1 > ridge.y1)
|| (currentLine.x1 < ridge.x2 && currentLine.y1 > ridge.y2)
&& (Math.abs(currentLine.x1 - ridge.x1) === Math.abs(currentLine.y1 - ridge.y1)
|| Math.abs(currentLine.x1 - ridge.x2) === Math.abs(currentLine.y1 - ridge.y2)))
.reduce((prev, current) => {
if (prev !== undefined) {
if (Math.abs(currentLine.x1 - current.x1) === Math.abs(currentLine.y1 - current.y1)) {
return Math.min(Math.abs(current.x1 - currentLine.x1)) < Math.min(Math.abs(prev.x1 - currentLine.x1)) ? current : prev
} else if (Math.abs(currentLine.x1 - current.x2) === Math.abs(currentLine.y1 - current.y2)) {
return Math.min(Math.abs(current.x1 - currentLine.x1)) < Math.min(Math.abs(prev.x1 - currentLine.x1)) ? current : prev
} else {
return prev
}
} else {
if (Math.abs(currentLine.x1 - current.x1) === Math.abs(currentLine.y1 - current.y1)) {
return current
} else if (Math.abs(currentLine.x1 - current.x2) === Math.abs(currentLine.y1 - current.y2)) {
return current
} else {
return undefined
}
}
}, undefined)
break
case 135:
nearRidge = this.ridges.filter(ridge => (currentLine.x1 < ridge.x1 && currentLine.y1 < ridge.y1
|| currentLine.x1 < ridge.x2 && currentLine.y1 < ridge.y2)
&& (Math.abs(currentLine.x1 - ridge.x1) === Math.abs(currentLine.y1 - ridge.y1)
|| Math.abs(currentLine.x1 - ridge.x2) === Math.abs(currentLine.y1 - ridge.y2)))
.reduce((prev, current) => {
if (prev !== undefined) {
if (Math.abs(currentLine.x1 - current.x1) === Math.abs(currentLine.y1 - current.y1)) {
return Math.min(Math.abs(current.x1 - currentLine.x1)) < Math.min(Math.abs(prev.x1 - currentLine.x1)) ? current : prev
} else if (Math.abs(currentLine.x1 - current.x2) === Math.abs(currentLine.y1 - current.y2)) {
return Math.min(Math.abs(current.x1 - currentLine.x1)) < Math.min(Math.abs(prev.x1 - currentLine.x1)) ? current : prev
} else {
return prev
}
} else {
if (Math.abs(currentLine.x1 - current.x1) === Math.abs(currentLine.y1 - current.y1)) {
return current
} else if (Math.abs(currentLine.x1 - current.x2) === Math.abs(currentLine.y1 - current.y2)) {
return current
} else {
return undefined
}
}
}, undefined)
break
case 225:
nearRidge = this.ridges.filter(ridge => (currentLine.x1 > ridge.x1 && currentLine.y1 < ridge.y1
|| currentLine.x1 > ridge.x2 && currentLine.y1 < ridge.y2)
&& (Math.abs(currentLine.x1 - ridge.x1) === Math.abs(currentLine.y1 - ridge.y1)
|| Math.abs(currentLine.x1 - ridge.x2) === Math.abs(currentLine.y1 - ridge.y2)))
.reduce((prev, current) => {
if (prev !== undefined) {
if (Math.abs(currentLine.x1 - current.x1) === Math.abs(currentLine.y1 - current.y1)) {
return Math.min(Math.abs(current.x1 - currentLine.x1)) < Math.min(Math.abs(prev.x1 - currentLine.x1)) ? current : prev
} else if (Math.abs(currentLine.x1 - current.x2) === Math.abs(currentLine.y1 - current.y2)) {
return Math.min(Math.abs(current.x1 - currentLine.x1)) < Math.min(Math.abs(prev.x1 - currentLine.x1)) ? current : prev
} else {
return prev
}
} else {
if (Math.abs(currentLine.x1 - current.x1) === Math.abs(currentLine.y1 - current.y1)) {
return current
} else if (Math.abs(currentLine.x1 - current.x2) === Math.abs(currentLine.y1 - current.y2)) {
return current
} else {
return undefined
}
}
}, undefined)
break
case 315:
nearRidge = this.ridges.filter(ridge => (currentLine.x1 > ridge.x1 && currentLine.y1 > ridge.y1
|| currentLine.x1 > ridge.x2 && currentLine.y1 > ridge.y2)
&& (Math.abs(currentLine.x1 - ridge.x1) === Math.abs(currentLine.y1 - ridge.y1)
|| Math.abs(currentLine.x1 - ridge.x2) === Math.abs(currentLine.y1 - ridge.y2)))
.reduce((prev, current) => {
if (prev !== undefined) {
if (Math.abs(currentLine.x1 - current.x1) === Math.abs(currentLine.y1 - current.y1)) {
return Math.min(Math.abs(current.x1 - currentLine.x1)) < Math.min(Math.abs(prev.x1 - currentLine.x1)) ? current : prev
} else if (Math.abs(currentLine.x1 - current.x2) === Math.abs(currentLine.y1 - current.y2)) {
return Math.min(Math.abs(current.x1 - currentLine.x1)) < Math.min(Math.abs(prev.x1 - currentLine.x1)) ? current : prev
} else {
return prev
}
} else {
if (Math.abs(currentLine.x1 - current.x1) === Math.abs(currentLine.y1 - current.y1)) {
return current
} else if (Math.abs(currentLine.x1 - current.x2) === Math.abs(currentLine.y1 - current.y2)) {
return current
} else {
return undefined
}
}
}, undefined)
break
}
// console.log('nearRidge : ', nearRidge)
if (nearRidge !== undefined && nearRidge.length > 0) {
let endXPoint, endYPoint
let minX, maxX, minY, maxY
switch (dVector) {
case 45:
if (currentLine.x1 < nearRidge.x1 && currentLine.y1 > nearRidge.y1
&& Math.abs(currentLine.x1 - nearRidge.x1) === Math.abs(currentLine.y1 - nearRidge.y1)) {
endXPoint = nearRidge.x1
endYPoint = nearRidge.y1
minX = Math.min(currentLine.x1, nearRidge.x1)
minY = Math.min(currentLine.y1, nearRidge.y1)
maxX = Math.max(currentLine.x1, nearRidge.x1)
maxY = Math.max(currentLine.y1, nearRidge.y1)
}
if (currentLine.x1 < nearRidge.x2 && currentLine.y1 > nearRidge.y2
&& Math.abs(currentLine.x1 - nearRidge.x2) === Math.abs(currentLine.y1 - nearRidge.y2)) {
endXPoint = nearRidge.x2
endYPoint = nearRidge.y2
minX = Math.min(currentLine.x1, nearRidge.x2)
minY = Math.min(currentLine.y1, nearRidge.y2)
maxX = Math.max(currentLine.x1, nearRidge.x2)
maxY = Math.max(currentLine.y1, nearRidge.y2)
}
break
case 135:
if (currentLine.x1 < nearRidge.x1 && currentLine.y1 < nearRidge.y1
&& Math.abs(currentLine.x1 - nearRidge.x1) === Math.abs(currentLine.y1 - nearRidge.y1)) {
endXPoint = nearRidge.x1
endYPoint = nearRidge.y1
minX = Math.min(currentLine.x1, nearRidge.x1)
minY = Math.min(currentLine.y1, nearRidge.y1)
maxX = Math.max(currentLine.x1, nearRidge.x1)
maxY = Math.max(currentLine.y1, nearRidge.y1)
}
if (currentLine.x1 < nearRidge.x2 && currentLine.y1 < nearRidge.y2
&& Math.abs(currentLine.x1 - nearRidge.x2) === Math.abs(currentLine.y1 - nearRidge.y2)) {
endXPoint = nearRidge.x2
endYPoint = nearRidge.y2
minX = Math.min(currentLine.x1, nearRidge.x2)
minY = Math.min(currentLine.y1, nearRidge.y2)
maxX = Math.max(currentLine.x1, nearRidge.x2)
maxY = Math.max(currentLine.y1, nearRidge.y2)
}
break
case 225:
if (currentLine.x1 > nearRidge.x1 && currentLine.y1 < nearRidge.y1
&& Math.abs(currentLine.x1 - nearRidge.x1) === Math.abs(currentLine.y1 - nearRidge.y1)) {
endXPoint = nearRidge.x1
endYPoint = nearRidge.y1
minX = Math.min(currentLine.x1, nearRidge.x1)
minY = Math.min(currentLine.y1, nearRidge.y1)
maxX = Math.max(currentLine.x1, nearRidge.x1)
maxY = Math.max(currentLine.y1, nearRidge.y1)
}
if (currentLine.x1 > nearRidge.x2 && currentLine.y1 < nearRidge.y2
&& Math.abs(currentLine.x1 - nearRidge.x2) === Math.abs(currentLine.y1 - nearRidge.y2)) {
endXPoint = nearRidge.x2
endYPoint = nearRidge.y2
minX = Math.min(currentLine.x1, nearRidge.x2)
minY = Math.min(currentLine.y1, nearRidge.y2)
maxX = Math.max(currentLine.x1, nearRidge.x2)
maxY = Math.max(currentLine.y1, nearRidge.y2)
}
break
case 315:
if (currentLine.x1 > nearRidge.x1 && currentLine.y1 > nearRidge.y1
&& Math.abs(currentLine.x1 - nearRidge.x1) === Math.abs(currentLine.y1 - nearRidge.y1)) {
endXPoint = nearRidge.x1
endYPoint = nearRidge.y1
minX = Math.min(currentLine.x1, nearRidge.x1)
minY = Math.min(currentLine.y1, nearRidge.y1)
maxX = Math.max(currentLine.x1, nearRidge.x1)
maxY = Math.max(currentLine.y1, nearRidge.y1)
}
if (currentLine.x1 > nearRidge.x2 && currentLine.y1 > nearRidge.y2
&& Math.abs(currentLine.x1 - nearRidge.x2) === Math.abs(currentLine.y1 - nearRidge.y2)) {
endXPoint = nearRidge.x2
endYPoint = nearRidge.y2
minX = Math.min(currentLine.x1, nearRidge.x2)
minY = Math.min(currentLine.y1, nearRidge.y2)
maxX = Math.max(currentLine.x1, nearRidge.x2)
maxY = Math.max(currentLine.y1, nearRidge.y2)
}
break
}
let lineCoordinate = [
{ x: minX, y: minY },
{ x: minX, y: maxY },
{ x: maxX, y: maxY },
{ x: maxX, y: minY },
]
let innerPoint = this.lines.filter(line => {
if (this.getPointInPolygon(lineCoordinate, { x: line.x1, y: line.y1 })) {
return line
}
})
if (innerPoint <= 0) {
const hip = new QLine([currentLine.x1, currentLine.y1, endXPoint, endYPoint], {
fontSize: this.fontSize,
stroke: 'red',
strokeWidth: 1,
})
this.addWithUpdate(hip)
this.hips.push(hip)
this.innerLines.push(hip)
}
}
}
})
// 마루와 연결되지 않은 hip을 그린다.
console.log('마루와 연결되지 않은 hip')
this.lines.forEach((line, index) => {
if (!this.isAlreadyHip(line)) {
let prevLine, currentLine, nextLine
if (index === 0) {
prevLine = this.lines[this.lines.length - 1]
} else {
prevLine = this.lines[index - 1]
}
currentLine = this.lines[index]
if (index === this.lines.length - 1) {
nextLine = this.lines[0]
} else if (index === this.lines.length) {
nextLine = this.lines[1]
} else {
nextLine = this.lines[index + 1]
}
let endXPoint, endYPoint
let dVector = this.getDirectionForDegree(prevLine, currentLine)
let minX = Math.min(currentLine.x1, currentLine.x2, prevLine.x1, nextLine.x2)
let maxX = Math.max(currentLine.x1, currentLine.x2, prevLine.x1, nextLine.x2)
let minY = Math.min(currentLine.y1, currentLine.y2, prevLine.y1, nextLine.y2)
let maxY = Math.max(currentLine.y1, currentLine.y2, prevLine.y1, nextLine.y2)
let lineCoordinate = [
{ x: minX, y: minY },
{ x: minX, y: maxY },
{ x: maxX, y: maxY },
{ x: maxX, y: minY },
]
let acrossLine = getAcrossLine(currentLine, dVector)
let hypotenuse, adjacent
if (this.getLineDirection(prevLine) === this.getLineDirection(nextLine)) {
hypotenuse = Math.round(getRoofHypotenuse(Math.abs(currentLine.x1 - acrossLine.x1) / 2))
} else {
hypotenuse = Math.min(Math.round(getRoofHypotenuse(currentLine.length / 2))
, Math.round(getRoofHypotenuse(Math.abs(currentLine.x1 - acrossLine.x1) / 2)))
}
adjacent = getAdjacent(hypotenuse)
switch (dVector) {
case 45:
endXPoint = currentLine.x1 + adjacent
endYPoint = currentLine.y1 - adjacent
break
case 135:
endXPoint = currentLine.x1 + adjacent
endYPoint = currentLine.y1 + adjacent
break
case 225:
endXPoint = currentLine.x1 - adjacent
endYPoint = currentLine.y1 + adjacent
break
case 315:
endXPoint = currentLine.x1 - adjacent
endYPoint = currentLine.y1 - adjacent
break
}
const hip = new QLine([currentLine.x1, currentLine.y1, endXPoint, endYPoint], {
fontSize: this.fontSize,
stroke: 'red',
strokeWidth: 1,
})
this.addWithUpdate(hip)
this.hips.push(hip)
this.innerLines.push(hip)
}
})
// this.canvas.renderAll()
}
const getRoofBaseLine = (polygon, prevLine, currentLine, nextLine, dVector) => {
let minX = Math.min(currentLine.x1, currentLine.x2, prevLine.x1, nextLine.x2)
let maxX = Math.max(currentLine.x1, currentLine.x2, prevLine.x1, nextLine.x2)
let minY = Math.min(currentLine.y1, currentLine.y2, prevLine.y1, nextLine.y2)
let maxY = Math.max(currentLine.y1, currentLine.y2, prevLine.y1, nextLine.y2)
let lineCoordinate = [
{ x: minX, y: minY },
{ x: minX, y: maxY },
{ x: maxX, y: maxY },
{ x: maxX, y: minY },
]
let innerPointLine = polygon.lines.filter(line => {
if (getPointInPolygon(lineCoordinate, { x: line.x1, y: line.y1 })) {
return line
}
})
let coordinateLength
let innerPointX
if (innerPointLine.length > 0) {
innerPointX = innerPointLine.reduce((a, b) => {
return a.x1 < b.x1 ? a : b
})
}
if (dVector === 45 || dVector === 225) {
if (innerPointX !== undefined) {
coordinateLength = Math.abs(currentLine.y1 - innerPointX.y1)
} else {
coordinateLength = Math.abs(lineCoordinate[0].y - lineCoordinate[2].y)
}
//계산된 좌표길이가 마루를 작성 할 최소 기준에 미치지 못하면 그릴수 없다.
if (coordinateLength < currentLine.length) {
return {
minLineLength: coordinateLength,
currentLineLength: currentLine.length,
maxLineLength: coordinateLength,
}
} else {
return {
minLineLength: Math.min(prevLine.length, nextLine.length),
currentLineLength: currentLine.length,
maxLineLength: coordinateLength,
}
}
}
if (dVector === 135 || dVector === 315) {
if (innerPointX !== undefined) {
coordinateLength = Math.abs(currentLine.x1 - innerPointX.x1)
} else {
coordinateLength = Math.abs(lineCoordinate[0].x - lineCoordinate[2].x)
}
//계산된 좌표길이가 마루를 작성 할 최소 기준에 미치지 못하면 그릴수 없다.
if (coordinateLength < currentLine.length) {
return {
minLineLength: coordinateLength,
currentLineLength: currentLine.length,
maxLineLength: coordinateLength,
}
} else {
return {
minLineLength: Math.min(prevLine.length, nextLine.length),
currentLineLength: currentLine.length,
maxLineLength: coordinateLength,
}
}
}
}
const getPointInPolygon = (polygon, point) => {
let inside = false
let minX = Math.min(polygon[0].x, polygon[1].x, polygon[2].x, polygon[3].x),
maxX = Math.max(polygon[0].x, polygon[1].x, polygon[2].x, polygon[3].x),
minY = Math.min(polygon[0].y, polygon[1].y, polygon[2].y, polygon[3].y),
maxY = Math.max(polygon[0].y, polygon[1].y, polygon[2].y, polygon[3].y)
if (minX < point.x && point.x < maxX && minY < point.y && point.y < maxY) {
inside = true
}
return inside
}
/**
* 라인과 마주하는 다른 라인과의 가장 가까운 거리를 구한다.
* @param currentLine 현재 라인
* @param dVector 현재 라인의 방향
* @returns {*[]|null}
*/
const getAcrossLine = (currentLine, dVector) => {
let acrossLine
switch (dVector) {
case 45:
acrossLine = this.lines.filter(line => line.x1 > currentLine.x1 && line.y1 <= currentLine.y1)
.reduce((prev, current) => {
if (prev.length > 0) {
return Math.abs(currentLine.x1 - current.x1) < Math.abs(currentLine.x1 - prev.x1) ? current : prev
} else {
return current
}
}, [])
break
case 135:
acrossLine = this.lines.filter(line => line.x1 > currentLine.x1 && line.y1 >= currentLine.y1)
.reduce((prev, current) => {
if (prev.length > 0) {
return Math.abs(currentLine.x1 - current.x1) < Math.abs(currentLine.x1 - prev.x1) ? current : prev
} else {
return current
}
}, [])
break
case 225:
acrossLine = this.lines.filter(line => line.x1 < currentLine.x1 && line.y1 >= currentLine.y1)
.reduce((prev, current) => {
if (prev.length > 0) {
return Math.abs(currentLine.x1 - current.x1) < Math.abs(currentLine.x1 - prev.x1) ? current : prev
} else {
return current
}
}, [])
break
case 315:
acrossLine = this.lines.filter(line => line.x1 < currentLine.x1 && line.y1 <= currentLine.y1)
.reduce((prev, current) => {
if (prev.length > 0) {
return Math.abs(currentLine.x1 - current.x1) < Math.abs(currentLine.x1 - prev.x1) ? current : prev
} else {
return current
}
}, [])
break
}
return acrossLine
}
/*
추녀마루(hip) 중복방지를 위해 마루와 함께 그려진 추녀마루를 확인한다
*/
const isAlreadyHip = (line) => {
let isAlreadyHip = false
this.hips.forEach(hip => {
if (line.x1 === hip.x1 && line.y1 === hip.y1) {
isAlreadyHip = true
}
})
return isAlreadyHip
}
/*
3 이상 이어지지 않은 라인 포인트 계산
모임지붕에서 point는 3 이상의 라인과 접해야 .
*/
const connectLinePoint = () => {
// 연결되지 않은 모든 라인의 포인트를 구한다.
let missedPoints = []
//마루
this.ridges.forEach(ridge => {
if (this.hips.filter(hip => hip.x2 === ridge.x1 && hip.y2 === ridge.y1).length < 2) {
missedPoints.push({ x: ridge.x1, y: ridge.y1 })
}
if (this.hips.filter(hip => hip.x2 === ridge.x2 && hip.y2 === ridge.y2).length < 2) {
missedPoints.push({ x: ridge.x2, y: ridge.y2 })
}
})
//추녀마루
this.hips.forEach(hip => {
let count = 0
count += this.ridges.filter(ridge =>
(ridge.x1 === hip.x2 && ridge.y1 === hip.y2) || (ridge.x2 === hip.x2 && ridge.y2 === hip.y2),
).length
count += this.hips.filter(hip2 =>
(hip2.x1 === hip.x2 && hip2.y1 === hip.y2) || (hip2.x2 === hip.x2 && hip2.y2 === hip.y2),
).length
if (count < 3) {
missedPoints.push({ x: hip.x2, y: hip.y2 })
}
})
let missedLine = []
//중복포인트제거
missedPoints = [
...new Set(missedPoints.map((line) => JSON.stringify(line))),
].map((line) => JSON.parse(line))
missedPoints.forEach(p1 => {
let p2 = missedPoints.filter(p => p.x !== p1.x && p.y !== p1.y).reduce((prev, current) => {
if (prev !== undefined) {
return Math.sqrt(Math.pow(Math.abs(current.x - p1.x), 2) + Math.pow(Math.abs(current.y - p1.y), 2))
< Math.sqrt(Math.pow(Math.abs(prev.x - p1.x), 2) + Math.pow(Math.abs(prev.y - p1.y), 2)) ? current : prev
} else {
return current
}
}, undefined)
if (p2 !== undefined) {
if (p1.x < p2.x && p1.y < p2.y) {
missedLine.push({ x1: p1.x, y1: p1.y, x2: p2.x, y2: p2.y })
}
if (p1.x > p2.x && p1.y < p2.y) {
missedLine.push({ x1: p2.x, y1: p2.y, x2: p1.x, y2: p1.y })
}
if (p1.x > p2.x && p1.y > p2.y) {
missedLine.push({ x1: p2.x, y1: p2.y, x2: p1.x, y2: p1.y })
}
if (p1.x < p2.x && p1.y > p2.y) {
missedLine.push({ x1: p1.x, y1: p1.y, x2: p2.x, y2: p2.y })
}
}
})
//중복라인제거
missedLine = [
...new Set(missedLine.map((line) => JSON.stringify(line))),
].map((line) => JSON.parse(line))
missedLine.forEach((p, index) => {
const line = new QLine([p.x1, p.y1, p.x2, p.y2], {
fontSize: this.fontSize,
stroke: 'green',
strokeWidth: 1,
})
this.addWithUpdate(line)
this.innerLines.push(line)
})
missedPoints = []
missedLine = []
this.innerLines.forEach((line, index) => {
if (this.innerLines.filter(innerLine => (line.x2 === innerLine.x1 && line.y2 === innerLine.y1)
|| (line.x2 === innerLine.x2 && line.y2 === innerLine.y2)).length < 3) {
missedPoints.push({ x: line.x2, y: line.y2 })
}
})
missedPoints = [
...new Set(missedPoints.map((line) => JSON.stringify(line))),
].map((line) => JSON.parse(line))
console.log(missedPoints)
missedPoints.forEach(p1 => {
let p2 = missedPoints.filter(p => !(p.x === p1.x && p.y === p1.y)).reduce((prev, current) => {
console.log('current : ', current)
console.log('prev : ', prev)
if (prev !== undefined) {
return Math.abs(current.x - p1.x) + Math.abs(current.y - p1.y) < Math.abs(prev.x - p1.x) + Math.abs(prev.y - p1.y) ? current : prev
} else {
return current
}
}, undefined)
if (p2 !== undefined) {
console.log(p1.x, p2.x, p1.y, p2.y)
if (p1.x === p2.x && p1.y < p2.y) {
missedLine.push({ x1: p1.x, y1: p1.y, x2: p2.x, y2: p2.y })
}
if (p1.x === p2.x && p1.y > p2.y) {
missedLine.push({ x1: p1.x, y1: p2.y, x2: p2.x, y2: p1.y })
}
if (p1.x < p2.x && p1.y === p2.y) {
missedLine.push({ x1: p1.x, y1: p1.y, x2: p2.x, y2: p2.y })
}
if (p1.x > p2.x && p1.y === p2.y) {
missedLine.push({ x1: p2.x, y1: p1.y, x2: p1.x, y2: p2.y })
}
}
})
//중복라인제거
missedLine = [
...new Set(missedLine.map((line) => JSON.stringify(line))),
].map((line) => JSON.parse(line))
console.log(missedLine)
missedLine.forEach((p, index) => {
const line = new QLine([p.x1, p.y1, p.x2, p.y2], {
fontSize: this.fontSize,
stroke: 'purple',
strokeWidth: 1,
})
this.addWithUpdate(line)
this.innerLines.push(line)
})
}
/*
최대 생성 마루 갯수
*/
const getMaxRidge = (length) => {
return ((length - 4) / 2) + 1
}
/*
라인의 사잇각 계산
*/
const getDirectionForDegree = (line1, line2) => {
let degree = getLineDirection(line1) + getLineDirection(line2)
let vector
switch (degree) {
case 'rb':
vector = 45
break
case 'br':
vector = 45
break
case 'lb':
vector = 135
break
case 'bl':
vector = 135
break
case 'lt':
vector = 225
break
case 'tl':
vector = 225
break
case 'rt':
vector = 315
break
case 'tr':
vector = 315
break
}
return vector
}
/*
현재 라인의 방향을 계산
*/
const getLineDirection = (line) => {
let x1, x2, y1, y2, xp, yp
x1 = Math.round(line.x1)
x2 = Math.round(line.x2)
y1 = Math.round(line.y1)
y2 = Math.round(line.y2)
xp = x1 - x2
yp = y1 - y2
if (xp === 0) {
if (yp < 0) {
return 'b'
} else {
return 't'
}
}
if (yp === 0) {
if (xp < 0) {
return 'r'
} else {
return 'l'
}
}
}