Merge branch 'feature/test' into feature/test-jy

# Conflicts:
#	src/components/fabric/QPolygon.js
This commit is contained in:
Jaeyoung Lee 2024-07-18 17:25:19 +09:00
commit 8bd304705f
6 changed files with 367 additions and 419 deletions

View File

@ -150,19 +150,33 @@ export default function Roof2() {
{ x: 550, y: 300 }, { x: 550, y: 300 },
{ x: 550, y: 450 }, { x: 550, y: 450 },
] ]
const type1A = [
{ x: 67, y: 81 },
{ x: 67, y: 660 },
{ x: 437, y: 660 },
{ x: 437, y: 1190 },
{ x: 858, y: 1190 },
{ x: 858, y: 81 },
]
const type1B = [
{ x: 137, y: 42 },
{ x: 137, y: 621 },
{ x: 667, y: 621 },
{ x: 667, y: 991 },
{ x: 1088, y: 991 },
{ x: 1088, y: 42 },
]
if (canvas) { if (canvas) {
const polygon = new QPolygon( const polygon = new QPolygon(type1, {
type4, fill: 'transparent',
{ stroke: 'black',
fill: 'transparent', strokeWidth: 1,
stroke: 'black', selectable: true,
strokeWidth: 1, fontSize: fontSize,
selectable: true, name: 'QPolygon1',
fontSize: fontSize, })
name: 'QPolygon1',
},
canvas, //
)
canvas?.add(polygon) canvas?.add(polygon)

View File

@ -0,0 +1,108 @@
import { fabric } from 'fabric'
export class QLine extends fabric.Group {
line
text
fontSize
length = 0
x1
y1
x2
y2
direction
type = 'HelpLine'
parent
#lengthTxt = 0
constructor(points, option, lengthTxt) {
const [x1, y1, x2, y2] = points
if (!option.fontSize) {
throw new Error('Font size is required.')
}
const line = new fabric.Line(points, { ...option, strokeWidth: 1 })
super([line], {})
this.x1 = x1
this.y1 = y1
this.x2 = x2
this.y2 = y2
this.line = line
this.fontSize = option.fontSize
this.direction = option.direction
this.parent = option.parent
if (lengthTxt > 0) {
this.#lengthTxt = Number(lengthTxt)
}
this.#init()
this.#addControl()
}
#init() {
this.#addLengthText(true)
}
#addControl() {
this.on('moving', () => {
this.#addLengthText(false)
})
this.on('modified', (e) => {
this.#addLengthText(false)
})
this.on('selected', () => {
Object.keys(this.controls).forEach((controlKey) => {
if (controlKey !== 'ml' && controlKey !== 'mr') {
this.setControlVisible(controlKey, false)
}
})
})
}
#addLengthText(isFirst) {
if (this.text) {
this.removeWithUpdate(this.text)
this.text = null
}
if (isFirst && this.#lengthTxt > 0) {
const text = new fabric.Textbox(this.#lengthTxt.toFixed(0).toString(), {
left: (this.x1 + this.x2) / 2,
top: (this.y1 + this.y2) / 2,
fontSize: this.fontSize,
})
this.length = this.#lengthTxt
this.text = text
this.addWithUpdate(text)
return
}
const scaleX = this.scaleX
const scaleY = this.scaleY
const x1 = this.left
const y1 = this.top
const x2 = this.left + this.width * scaleX
const y2 = this.top + this.height * scaleY
const dx = x2 - x1
const dy = y2 - y1
this.length = Number(Math.sqrt(dx * dx + dy * dy).toFixed(0))
const text = new fabric.Textbox(this.length.toFixed(0).toString(), {
left: (x1 + x2) / 2,
top: (y1 + y2) / 2,
fontSize: this.fontSize,
})
this.text = text
this.addWithUpdate(text)
}
setFontSize(fontSize) {
this.fontSize = fontSize
this.text.set({ fontSize })
this.addWithUpdate()
}
}

View File

@ -10,11 +10,17 @@ export class QLine extends fabric.Group {
x2 x2
y2 y2
direction direction
idx
type = 'QLine' type = 'QLine'
parent parent
#lengthTxt = 0 #lengthTxt = 0
constructor(points, option = { isActiveLengthText: true }, lengthTxt) { constructor(points, option = { isActiveLengthText: true }, lengthTxt) {
// 소수점 전부 제거
points.forEach((point) => {
point = Math.round(point)
})
const [x1, y1, x2, y2] = points const [x1, y1, x2, y2] = points
if (!option.fontSize) { if (!option.fontSize) {
@ -32,6 +38,7 @@ export class QLine extends fabric.Group {
this.fontSize = option.fontSize this.fontSize = option.fontSize
this.direction = option.direction this.direction = option.direction
this.parent = option.parent this.parent = option.parent
this.idx = option.idx
if (lengthTxt > 0) { if (lengthTxt > 0) {
this.#lengthTxt = Number(lengthTxt) this.#lengthTxt = Number(lengthTxt)

View File

@ -1,6 +1,8 @@
import { fabric } from 'fabric' import { fabric } from 'fabric'
import { import {
calculateIntersection,
distanceBetweenPoints, distanceBetweenPoints,
findClosestLineToPoint,
findTopTwoIndexesByDistance, findTopTwoIndexesByDistance,
getDegreeByChon, getDegreeByChon,
getDirectionByPoint, getDirectionByPoint,
@ -24,17 +26,21 @@ export default class QPolygon extends fabric.Group {
helpPoints = [] helpPoints = []
helpLines = [] helpLines = []
wall
constructor(points, options, canvas) { constructor(points, options, canvas) {
if (points.length !== 4 && points.length !== 6) { /*if (points.length !== 4 && points.length !== 6) {
throw new Error('Points must be 4 or 6.') throw new Error('Points must be 4 or 6.')
} }*/
if (points.length !== 4 && points.length !== 6) {
throw new Error('Points must be 4 or 6.')
}
if (!options.fontSize) { if (!options.fontSize) {
throw new Error('Font size is required.') throw new Error('Font size is required.')
} }
// 소수점 전부 제거
points.forEach((point) => {
point.x = Math.round(point.x)
point.y = Math.round(point.y)
})
const sortPoints = sortedPoints(points) const sortPoints = sortedPoints(points)
const polygon = new fabric.Polygon(sortPoints, options) const polygon = new fabric.Polygon(sortPoints, options)
@ -84,6 +90,10 @@ export default class QPolygon extends fabric.Group {
}) })
} }
setWall(wall) {
this.wall = wall
}
setFontSize(fontSize) { setFontSize(fontSize) {
this.fontSize = fontSize this.fontSize = fontSize
this.texts.forEach((text) => { this.texts.forEach((text) => {
@ -114,10 +124,7 @@ export default class QPolygon extends fabric.Group {
const dy = end.y - start.y const dy = end.y - start.y
const length = Math.sqrt(dx * dx + dy * dy) const length = Math.sqrt(dx * dx + dy * dy)
const midPoint = new fabric.Point( const midPoint = new fabric.Point((start.x + end.x) / 2, (start.y + end.y) / 2)
(start.x + end.x) / 2,
(start.y + end.y) / 2,
)
// Create new text object if it doesn't exist // Create new text object if it doesn't exist
const text = new fabric.Text(length.toFixed(0), { const text = new fabric.Text(length.toFixed(0), {
@ -161,16 +168,8 @@ export default class QPolygon extends fabric.Group {
return return
} }
for ( for (let x = bounds.left; x < bounds.left + bounds.width; x += cell.width + cell.padding) {
let x = bounds.left; for (let y = bounds.top; y < bounds.top + bounds.height; y += cell.height + cell.padding) {
x < bounds.left + bounds.width;
x += cell.width + cell.padding
) {
for (
let y = bounds.top;
y < bounds.top + bounds.height;
y += cell.height + cell.padding
) {
const rect = new fabric.Rect({ const rect = new fabric.Rect({
left: x, left: x,
top: y, top: y,
@ -188,11 +187,7 @@ export default class QPolygon extends fabric.Group {
new fabric.Point(rect.left + rect.width, rect.top + rect.height), new fabric.Point(rect.left + rect.width, rect.top + rect.height),
] ]
const isInside = rectPoints.every( const isInside = rectPoints.every((rectPoint) => this.inPolygon(rectPoint) && this.#distanceFromEdge(rectPoint) >= cell.padding)
(rectPoint) =>
this.inPolygon(rectPoint) &&
this.#distanceFromEdge(rectPoint) >= cell.padding,
)
if (isInside) { if (isInside) {
this.addWithUpdate(rect) this.addWithUpdate(rect)
@ -209,24 +204,13 @@ export default class QPolygon extends fabric.Group {
* return {boolean} * return {boolean}
*/ */
isValid() { isValid() {
const leftLinesLengthSum = this.lines const leftLinesLengthSum = this.lines.filter((line) => line.direction === 'left').reduce((sum, line) => sum + line.length, 0)
.filter((line) => line.direction === 'left') const rightLinesLengthSum = this.lines.filter((line) => line.direction === 'right').reduce((sum, line) => sum + line.length, 0)
.reduce((sum, line) => sum + line.length, 0)
const rightLinesLengthSum = this.lines
.filter((line) => line.direction === 'right')
.reduce((sum, line) => sum + line.length, 0)
const topLinesLengthSum = this.lines const topLinesLengthSum = this.lines.filter((line) => line.direction === 'top').reduce((sum, line) => sum + line.length, 0)
.filter((line) => line.direction === 'top') const bottomLinesLengthSum = this.lines.filter((line) => line.direction === 'bottom').reduce((sum, line) => sum + line.length, 0)
.reduce((sum, line) => sum + line.length, 0)
const bottomLinesLengthSum = this.lines
.filter((line) => line.direction === 'bottom')
.reduce((sum, line) => sum + line.length, 0)
return ( return leftLinesLengthSum === rightLinesLengthSum && topLinesLengthSum === bottomLinesLengthSum
leftLinesLengthSum === rightLinesLengthSum &&
topLinesLengthSum === bottomLinesLengthSum
)
} }
inPolygon(point) { inPolygon(point) {
@ -251,10 +235,7 @@ export default class QPolygon extends fabric.Group {
continue continue
} }
let xInt = let xInt = ((point.y - vertex1.y) * (vertex2.x - vertex1.x)) / (vertex2.y - vertex1.y) + vertex1.x
((point.y - vertex1.y) * (vertex2.x - vertex1.x)) /
(vertex2.y - vertex1.y) +
vertex1.x
if (xInt < point.x) { if (xInt < point.x) {
intersects++ intersects++
} }
@ -274,9 +255,7 @@ export default class QPolygon extends fabric.Group {
const dx = vertex2.x - vertex1.x const dx = vertex2.x - vertex1.x
const dy = vertex2.y - vertex1.y const dy = vertex2.y - vertex1.y
const t = const t = ((point.x - vertex1.x) * dx + (point.y - vertex1.y) * dy) / (dx * dx + dy * dy)
((point.x - vertex1.x) * dx + (point.y - vertex1.y) * dy) /
(dx * dx + dy * dy)
let closestPoint let closestPoint
if (t < 0) { if (t < 0) {
@ -358,9 +337,7 @@ export default class QPolygon extends fabric.Group {
return return
} }
//외각선 기준 //외각선 기준
const topIndex = findTopTwoIndexesByDistance(this.lines).sort( const topIndex = findTopTwoIndexesByDistance(this.lines).sort((a, b) => a - b) //배열중에 큰 2값을 가져옴 TODO: 나중에는 인자로 받아서 다각으로 수정 해야됨
(a, b) => a - b,
) //배열중에 큰 2값을 가져옴 TODO: 나중에는 인자로 받아서 다각으로 수정 해야됨
//일단 배열 6개 짜리 기준의 선 번호 //일단 배열 6개 짜리 기준의 선 번호
if (topIndex[0] === 4) { if (topIndex[0] === 4) {
@ -431,23 +408,15 @@ export default class QPolygon extends fabric.Group {
const direction = smallestLines[0].direction const direction = smallestLines[0].direction
if (direction === 'top' || direction === 'bottom') { if (direction === 'top' || direction === 'bottom') {
needPlusLine = needPlusLine = smallestLines[0].x1 < smallestLines[1].x1 ? smallestLines[0] : smallestLines[1]
smallestLines[0].x1 < smallestLines[1].x1 needMinusLine = needPlusLine === smallestLines[0] ? smallestLines[1] : smallestLines[0]
? smallestLines[0]
: smallestLines[1]
needMinusLine =
needPlusLine === smallestLines[0] ? smallestLines[1] : smallestLines[0]
type = 1 // 가로가 긴 사각형 type = 1 // 가로가 긴 사각형
} }
if (direction === 'left' || direction === 'right') { if (direction === 'left' || direction === 'right') {
needPlusLine = needPlusLine = smallestLines[0].y1 < smallestLines[1].y1 ? smallestLines[0] : smallestLines[1]
smallestLines[0].y1 < smallestLines[1].y1 needMinusLine = needPlusLine === smallestLines[0] ? smallestLines[1] : smallestLines[0]
? smallestLines[0]
: smallestLines[1]
needMinusLine =
needPlusLine === smallestLines[0] ? smallestLines[1] : smallestLines[0]
type = 2 // 세로가 긴 사각형 type = 2 // 세로가 긴 사각형
} }
@ -458,33 +427,21 @@ export default class QPolygon extends fabric.Group {
if (type === 1) { if (type === 1) {
point1 = { point1 = {
x: needPlusLine.x1 + smallestLength / 2, x: needPlusLine.x1 + smallestLength / 2,
y: y: needPlusLine.y1 > needPlusLine.y2 ? needPlusLine.y1 - smallestLength / 2 : needPlusLine.y2 - smallestLength / 2,
needPlusLine.y1 > needPlusLine.y2
? needPlusLine.y1 - smallestLength / 2
: needPlusLine.y2 - smallestLength / 2,
} }
point2 = { point2 = {
x: needMinusLine.x1 - smallestLength / 2, x: needMinusLine.x1 - smallestLength / 2,
y: y: needMinusLine.y1 > needMinusLine.y2 ? needMinusLine.y1 - smallestLength / 2 : needMinusLine.y2 - smallestLength / 2,
needMinusLine.y1 > needMinusLine.y2
? needMinusLine.y1 - smallestLength / 2
: needMinusLine.y2 - smallestLength / 2,
} }
} else if (type === 2) { } else if (type === 2) {
point1 = { point1 = {
x: x: needPlusLine.x1 > needPlusLine.x2 ? needPlusLine.x1 - smallestLength / 2 : needPlusLine.x2 - smallestLength / 2,
needPlusLine.x1 > needPlusLine.x2
? needPlusLine.x1 - smallestLength / 2
: needPlusLine.x2 - smallestLength / 2,
y: needPlusLine.y1 + smallestLength / 2, y: needPlusLine.y1 + smallestLength / 2,
} }
point2 = { point2 = {
x: x: needMinusLine.x1 > needMinusLine.x2 ? needMinusLine.x1 - smallestLength / 2 : needMinusLine.x2 - smallestLength / 2,
needMinusLine.x1 > needMinusLine.x2
? needMinusLine.x1 - smallestLength / 2
: needMinusLine.x2 - smallestLength / 2,
y: needMinusLine.y1 - smallestLength / 2, y: needMinusLine.y1 - smallestLength / 2,
} }
} }
@ -572,357 +529,144 @@ export default class QPolygon extends fabric.Group {
} }
#drawHelpLineInHexagon(chon) { #drawHelpLineInHexagon(chon) {
let type = this.shape const historyLines = []
const helpPoints = []
const notInterSectionLines = []
const ridge = []
const maxLength = this.lines.reduce((max, obj) => Math.min(max, obj.length), 999999)
this.points.forEach((point, index) => {
const wallPoint = this.wall.points[index]
// 두 점의 좌표
const x1 = point.x
const y1 = point.y
const x2 = wallPoint.x
const y2 = wallPoint.y
// 1 = 0, 3 let newX2, newY2
// 2 = 2, 5
// 3 = 1, 4
// 4 = 0, 3
// 라인 기준점 1,2 // x1, y1을 기준으로 x2, y2와의 거리를 유지한 새로운 직선 생성
let lines, lines2 const angle = Math.atan2(y2 - y1, x2 - x1)
// 용마루 시작점 2개
let vPoint1, vPoint2
// 용마루 시작점과 만나는 지붕의 중앙
let centerPoint1, centerPoint2
// 가장 긴 라인 newX2 = x1 + (maxLength + 50) * Math.cos(angle)
let longestLines newY2 = y1 + (maxLength + 50) * Math.sin(angle)
// 용마루 길이 const line = new QLine([x1, y1, newX2, newY2], {
let ridgeLength = 0 fontSize: this.fontSize,
let ridgeStartPoint1, ridgeStartPoint2 stroke: 'blue',
idx: index,
})
historyLines.push(line)
this.addWithUpdate(line)
let ridgeEndPoint1, ridgeEndPoint2 this.canvas.renderAll()
})
let ridgeLength1, ridgeLength2 /**
* 삼각 지붕
*/
historyLines.forEach((line, index) => {
const prevLine = historyLines[(index - 1 + historyLines.length) % historyLines.length]
let ridgeHelpLinePoint1, ridgeHelpLinePoint2 let intersectionPoint = calculateIntersection(line, prevLine)
if (type === 1) { if (!intersectionPoint) {
lines = [this.lines[0], this.lines[3]] notInterSectionLines.push(line)
lines2 = [this.lines[1], this.lines[4]] return
longestLines = [this.lines[4], this.lines[5]]
ridgeLength1 = lines2[0].length
ridgeLength2 = longestLines[0].length - lines[1].length
vPoint1 = {
x: lines[0].x1 + lines[0].length / 2,
y: lines[0].y1 + lines[0].length / 2,
}
vPoint2 = {
x: lines[1].x1 + lines[1].length / 2,
y: lines[1].y1 - lines[1].length / 2,
}
centerPoint1 = {
x: (lines[0].x1 + lines[0].x2) / 2,
y: (lines[0].y1 + lines[0].y2) / 2,
}
centerPoint2 = {
x: (lines[1].x1 + lines[1].x2) / 2,
y: (lines[1].y1 + lines[1].y2) / 2,
} }
ridgeEndPoint1 = [ const helpLine1 = new QLine([prevLine.x1, prevLine.y1, intersectionPoint.x, intersectionPoint.y], {
vPoint1.x, fontSize: this.fontSize,
vPoint1.y, stroke: 'red',
vPoint1.x + ridgeLength1, })
vPoint1.y,
]
ridgeEndPoint2 = [
vPoint2.x,
vPoint2.y,
vPoint2.x,
vPoint2.y - ridgeLength2,
]
ridgeHelpLinePoint1 = [ const helpLine2 = new QLine([line.x1, line.y1, intersectionPoint.x, intersectionPoint.y], {
lines2[0].x2, fontSize: this.fontSize,
lines2[0].y2, stroke: 'red',
ridgeEndPoint1[2], })
ridgeEndPoint1[3], notInterSectionLines.pop()
] helpPoints.push(intersectionPoint)
ridgeHelpLinePoint2 = [
lines2[1].x2, this.addWithUpdate(helpLine1)
lines2[1].y2, this.addWithUpdate(helpLine2)
ridgeEndPoint2[2], this.removeWithUpdate(prevLine)
ridgeEndPoint2[3], this.removeWithUpdate(line)
] this.canvas.renderAll()
} else if (type === 2) { })
lines = [this.lines[2], this.lines[5]] // 용마루
lines2 = [this.lines[0], this.lines[3]]
longestLines = [this.lines[0], this.lines[1]] const ridgePoint = []
ridgeLength1 = lines2[1].length
ridgeLength2 = longestLines[0].length - lines[1].length helpPoints.forEach((helpPoint, index) => {
vPoint1 = { const closestLine = findClosestLineToPoint(helpPoint, notInterSectionLines)
x: lines[0].x1 - lines[0].length / 2,
y: lines[0].y1 - lines[0].length / 2, // 가까운 선의 중심점
} const centerClosestLinePoint = {
vPoint2 = { x: (closestLine.x1 + closestLine.x2) / 2,
x: lines[1].x1 - lines[1].length / 2, y: (closestLine.y1 + closestLine.y2) / 2,
y: lines[1].y1 + lines[1].length / 2,
}
centerPoint1 = {
x: (lines[0].x1 + lines[0].x2) / 2,
y: (lines[0].y1 + lines[0].y2) / 2,
}
centerPoint2 = {
x: (lines[1].x1 + lines[1].x2) / 2,
y: (lines[1].y1 + lines[1].y2) / 2,
} }
ridgeEndPoint1 = [ const direction = getDirectionByPoint(helpPoint, centerClosestLinePoint)
vPoint1.x,
vPoint1.y,
vPoint1.x - ridgeLength1,
vPoint1.y,
]
ridgeEndPoint2 = [ let newX, newY
vPoint2.x,
vPoint2.y,
vPoint2.x,
vPoint2.y + ridgeLength2,
]
ridgeHelpLinePoint1 = [ switch (direction) {
lines2[1].x2, case 'left': {
lines2[1].y2, newX = ((closestLine.x2 - closestLine.x1) * (helpPoint.y - closestLine.y1)) / (closestLine.y2 - closestLine.y1) + closestLine.x1
ridgeEndPoint1[2], newY = helpPoint.y
ridgeEndPoint1[3], break
] }
ridgeHelpLinePoint2 = [ case 'right': {
lines2[0].x2, newX = ((closestLine.x2 - closestLine.x1) * (helpPoint.y - closestLine.y1)) / (closestLine.y2 - closestLine.y1) + closestLine.x1
lines2[0].y2, newY = helpPoint.y
ridgeEndPoint2[2], break
ridgeEndPoint2[3], }
] case 'top': {
} else if (type === 3) { newX = helpPoint.x
lines = [this.lines[1], this.lines[4]] newY = ((closestLine.y2 - closestLine.y1) * (helpPoint.x - closestLine.x1)) / (closestLine.x2 - closestLine.x1) + closestLine.y1
lines2 = [this.lines[2], this.lines[5]] break
longestLines = [this.lines[0], this.lines[5]] }
ridgeLength1 = this.lines[3].length case 'bottom': {
ridgeLength2 = longestLines[0].length - lines[0].length newX = helpPoint.x
vPoint1 = { newY = ((closestLine.y2 - closestLine.y1) * (helpPoint.x - closestLine.x1)) / (closestLine.x2 - closestLine.x1) + closestLine.y1
x: lines[0].x1 + lines[0].length / 2, break
y: lines[0].y1 - lines[0].length / 2, }
}
vPoint2 = {
x: lines[1].x1 - lines[1].length / 2,
y: lines[1].y1 - lines[1].length / 2,
}
centerPoint1 = {
x: (lines[0].x1 + lines[0].x2) / 2,
y: (lines[0].y1 + lines[0].y2) / 2,
}
centerPoint2 = {
x: (lines[1].x1 + lines[1].x2) / 2,
y: (lines[1].y1 + lines[1].y2) / 2,
} }
ridgeEndPoint1 = [ const ridgeHelpLine = new QLine([closestLine.x1, closestLine.y1, newX, newY], {
vPoint1.x, fontSize: this.fontSize,
vPoint1.y, stroke: 'purple',
vPoint1.x, strokeWidth: 5,
vPoint1.y - ridgeLength2, })
]
ridgeEndPoint2 = [ ridgePoint.push({ x: newX, y: newY })
vPoint2.x,
vPoint2.y,
vPoint2.x - ridgeLength1,
vPoint2.y,
]
ridgeHelpLinePoint1 = [ const ridge = new QLine([helpPoint.x, helpPoint.y, newX, newY], {
lines2[1].x2, fontSize: this.fontSize,
lines2[1].y2, stroke: 'skyblue',
ridgeEndPoint1[2], strokeWidth: 5,
ridgeEndPoint1[3], })
]
ridgeHelpLinePoint2 = [
lines2[0].x2,
lines2[0].y2,
ridgeEndPoint2[2],
ridgeEndPoint2[3],
]
} else if (type === 4) {
lines = [this.lines[0], this.lines[3]]
lines2 = [this.lines[1], this.lines[4]]
longestLines = [this.lines[1], this.lines[2]]
ridgeLength1 = longestLines[0].length - lines[0].length
ridgeLength2 = this.lines[4].length
vPoint1 = {
x: lines[0].x1 + lines[0].length / 2,
y: lines[0].y1 + lines[0].length / 2,
}
vPoint2 = {
x: lines[1].x1 - lines[1].length / 2,
y: lines[1].y1 + lines[1].length / 2,
}
centerPoint1 = {
x: (lines[0].x1 + lines[0].x2) / 2,
y: (lines[0].y1 + lines[0].y2) / 2,
}
centerPoint2 = {
x: (lines[1].x1 + lines[1].x2) / 2,
y: (lines[1].y1 + lines[1].y2) / 2,
}
ridgeEndPoint1 = [ this.addWithUpdate(ridge)
vPoint1.x, this.canvas.renderAll()
vPoint1.y,
vPoint1.x + ridgeLength1,
vPoint1.y,
]
ridgeEndPoint2 = [ this.addWithUpdate(ridgeHelpLine)
vPoint2.x, this.removeWithUpdate(closestLine)
vPoint2.y, this.canvas.renderAll()
vPoint2.x, })
vPoint2.y + ridgeLength2,
]
ridgeHelpLinePoint1 = [ // 용마루 끼리 연결
lines2[0].x2, for (let i = 0; i < ridgePoint.length; i = i + 2) {
lines2[0].y2, const currentRidgeEndPoint = ridgePoint[i]
ridgeEndPoint1[2], const nextRidgeEndPoint = ridgePoint[(i + 1) % ridgePoint.length]
ridgeEndPoint1[3], const ridgeConnectLine = new QLine([currentRidgeEndPoint.x, currentRidgeEndPoint.y, nextRidgeEndPoint.x, nextRidgeEndPoint.y], {
] fontSize: this.fontSize,
ridgeHelpLinePoint2 = [ stroke: 'green',
lines2[1].x2, strokeWidth: 5,
lines2[1].y2, })
ridgeEndPoint2[2], this.addWithUpdate(ridgeConnectLine)
ridgeEndPoint2[3], this.canvas.renderAll()
]
} }
const realLine1 = new QLine(
[lines[0].x1, lines[0].y1, vPoint1.x, vPoint1.y],
{ fontSize: this.fontSize, stroke: 'blue', strokeWidth: 1 },
getRoofHypotenuse(lines[0].length / 2),
)
const realLine2 = new QLine(
[lines[0].x2, lines[0].y2, vPoint1.x, vPoint1.y],
{ fontSize: this.fontSize, stroke: 'blue', strokeWidth: 1 },
getRoofHypotenuse(lines[0].length / 2),
)
const realLine3 = new QLine(
[lines[1].x1, lines[1].y1, vPoint2.x, vPoint2.y],
{ fontSize: this.fontSize, stroke: 'blue', strokeWidth: 1 },
getRoofHypotenuse(lines[1].length / 2),
)
const realLine4 = new QLine(
[lines[1].x2, lines[1].y2, vPoint2.x, vPoint2.y],
{ fontSize: this.fontSize, stroke: 'blue', strokeWidth: 1 },
getRoofHypotenuse(lines[1].length / 2),
)
// 옆으로 누워있는 지붕의 높이 점선
const realLine5 = new QLine(
[vPoint1.x, vPoint1.y, centerPoint1.x, centerPoint1.y],
{
fontSize: this.fontSize,
stroke: 'blue',
strokeWidth: 1,
strokeDashArray: [5, 5],
},
getRoofHeight(lines[0].length / 2, getDegreeByChon(chon)),
)
// 옆으로 누워있는 지붕의 높이 점선
const realLine6 = new QLine(
[vPoint2.x, vPoint2.y, centerPoint2.x, centerPoint2.y],
{
fontSize: this.fontSize,
stroke: 'blue',
strokeWidth: 1,
strokeDashArray: [5, 5],
},
getRoofHeight(lines[1].length / 2, getDegreeByChon(chon)),
)
// 용마루 보조선
const ridgeHelpLine1 = new QLine(
ridgeHelpLinePoint1,
{
fontSize: this.fontSize,
stroke: 'blue',
strokeWidth: 1,
},
getRoofHypotenuse(lines[0].length / 2),
)
// 용마루 보조선
const ridgeHelpLine2 = new QLine(
ridgeHelpLinePoint2,
{
fontSize: this.fontSize,
stroke: 'blue',
strokeWidth: 1,
},
getRoofHypotenuse(lines[1].length / 2),
)
// 용마루
const ridge1 = new QLine(
[vPoint1.x, vPoint1.y, ridgeEndPoint1[2], ridgeEndPoint1[3]],
{
fontSize: this.fontSize,
stroke: 'blue',
strokeWidth: 1,
},
)
// 용마루
const ridge2 = new QLine(
[vPoint2.x, vPoint2.y, ridgeEndPoint2[2], ridgeEndPoint2[3]],
{
fontSize: this.fontSize,
stroke: 'blue',
strokeWidth: 1,
},
)
const ridgeEndLine = new QLine(
[
ridgeEndPoint1[2],
ridgeEndPoint1[3],
ridgeEndPoint2[2],
ridgeEndPoint2[3],
],
{
fontSize: this.fontSize,
stroke: 'blue',
strokeWidth: 1,
},
Math.abs(realLine1.length - realLine3.length),
)
this.helpLines = [
realLine1,
realLine2,
realLine3,
realLine4,
realLine5,
realLine6,
ridge1,
ridge2,
ridgeEndLine,
]
this.addWithUpdate(realLine1)
this.addWithUpdate(realLine2)
this.addWithUpdate(realLine3)
this.addWithUpdate(realLine4)
this.addWithUpdate(realLine5)
this.addWithUpdate(realLine6)
this.addWithUpdate(ridgeHelpLine1)
this.addWithUpdate(ridgeHelpLine2)
this.addWithUpdate(ridge1)
this.addWithUpdate(ridge2)
this.addWithUpdate(ridgeEndLine)
this.canvas.renderAll() this.canvas.renderAll()
} }

View File

@ -222,9 +222,12 @@ export function useMode() {
points.current = [] points.current = []
historyPoints.current = [] historyPoints.current = []
handleOuterlinesTest() const roof = handleOuterlinesTest()
const wall = makePolygon() const wall = makePolygon()
roof.setWall(wall)
setWall(wall) setWall(wall)
roof.drawHelpLine()
} }
} }
@ -788,7 +791,8 @@ export function useMode() {
const roof = makePolygon(offsetPoints) const roof = makePolygon(offsetPoints)
setRoof(roof) setRoof(roof)
roof.drawHelpLine()
return roof
} }
/** /**
@ -855,6 +859,7 @@ export function useMode() {
} }
const roof = makePolygon(offsetPoints) const roof = makePolygon(offsetPoints)
roof.setWall(polygon)
setRoof(roof) setRoof(roof)
roof.drawHelpLine() roof.drawHelpLine()
} }

View File

@ -352,6 +352,18 @@ export function calculateIntersection(line1, line2) {
return { x: intersectX, y: intersectY } return { x: intersectX, y: intersectY }
} }
function findOrthogonalPoint(x1, y1, x2, y2, x3, y3, x4, y4) {
// Calculate the intersection point of two lines
const intersectionX =
((x1 * y2 - y1 * x2) * (x3 - x4) - (x1 - x2) * (x3 * y4 - y3 * x4)) /
((x1 - x2) * (y3 - y4) - (y1 - y2) * (x3 - x4))
const intersectionY =
((x1 * y2 - y1 * x2) * (y3 - y4) - (y1 - y2) * (x3 * y4 - y3 * x4)) /
((x1 - x2) * (y3 - y4) - (y1 - y2) * (x3 - x4))
return { x: intersectionX, y: intersectionY }
}
/** /**
* points배열을 입력받아 반시계방향으로 정렬된 points를 반환합니다. * points배열을 입력받아 반시계방향으로 정렬된 points를 반환합니다.
* @param points * @param points
@ -417,3 +429,61 @@ export const sortedPoints = (points) => {
return resultPoints return resultPoints
} }
/**
* point가 위에 있는지 확인
* @param line
* @param point
* @returns {boolean}
*/
// 직선의 방정식.
// 방정식은 ax + by + c = 0이며, 점의 좌표를 대입하여 계산된 값은 직선과 점 사이의 관계를 나타낸다.
export function isPointOnLine(line, point) {
const a = line.y2 - line.y1
const b = line.x1 - line.x2
const c = line.x2 * line.y1 - line.x1 * line.y2
return a * point.x + b * point.y + c === 0
}
/**
* 점과 가까운 line 찾기
* @param point
* @param lines {Array}
* @returns {null}
*/
export function findClosestLineToPoint(point, lines) {
let closestLine = null
let closestDistance = Infinity
for (const line of lines) {
const distance = calculateDistance(point, line)
if (distance < closestDistance) {
closestDistance = distance
closestLine = line
}
}
return closestLine
}
/**
* 점과 직선사이의 최단 거리
* @param point
* @param line
* @returns {number}
*/
export function calculateDistance(point, line) {
const x1 = line.x1
const y1 = line.y1
const x2 = line.x2
const y2 = line.y2
const x0 = point.x
const y0 = point.y
const numerator = Math.abs(
(y2 - y1) * x0 - (x2 - x1) * y0 + x2 * y1 - y2 * x1,
)
const denominator = Math.sqrt(Math.pow(y2 - y1, 2) + Math.pow(x2 - x1, 2))
return numerator / denominator
}