From 01faaead930fccd45e4758140e370ffadc49ccb7 Mon Sep 17 00:00:00 2001 From: Jaeyoung Lee Date: Fri, 19 Jul 2024 20:30:12 +0900 Subject: [PATCH] =?UTF-8?q?=ED=85=8C=EC=8A=A4=ED=8A=B8=20=EC=A4=91=20?= =?UTF-8?q?=EC=A7=81=EA=B0=81=EC=9D=BC=20=EA=B2=BD=EC=9A=B0=20=EC=A7=80?= =?UTF-8?q?=EB=B6=95=20=EB=9D=BC=EC=9D=B8=20=EA=B7=B8=EB=A6=AC=EA=B8=B0=20?= =?UTF-8?q?=EC=B2=98=EB=A6=AC.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/fabric/QPolygon.js | 256 ++++++++++++++++++++++++++---- 1 file changed, 224 insertions(+), 32 deletions(-) diff --git a/src/components/fabric/QPolygon.js b/src/components/fabric/QPolygon.js index ef880c35..843166b0 100644 --- a/src/components/fabric/QPolygon.js +++ b/src/components/fabric/QPolygon.js @@ -27,6 +27,8 @@ export default class QPolygon extends fabric.Group { helpLines = [] wall + ridges = [] + hips = [] constructor(points, options, canvas) { /*if (points.length !== 4 && points.length !== 6) { @@ -672,11 +674,111 @@ export default class QPolygon extends fabric.Group { } #drawHelpLineInOctagon(chon) { - console.log(this.lines) + this.drawRoofRidge() + this.drawHips() + this.connectLinePoint() + } - let prevLine, currentLine, nextLine - let point + /*마루 그리기 + 외벽의 모양이 돌출된 ㄷ의 형태일때 + 현재 라인의 외벽길이가 붙어있는 두외벽의 길이보다 짧거나 같다면 + 지붕의 두 꼭지점에서 외벽의 두 꼭지점으로 45도 방향으로 선을 그려 만나는 지점이 마루의 시작점이 되고 + 시작점에서 부터 (가장 긴선 - ( 삼각형의 빗변 에서 직각까지의 수직길이 x 2))의 길이가 마루의 끝점이 된다. + 다만 마루의 길이는 나머지 나머지 두 지붕의 길이중 짧은선의 길이를 넘어갈수 없다. + */ + drawRoofRidge() { + let prevLine, currentLine, nextLine, prevWall, currentWall, nextWall + let startXPoint, startYPoint, endXPoint, endYPoint + let dVector, ridgeMaxLength, ridgeMinLength, ridgeRun + this.lines.forEach( + (value, index) => { + if (index === 0) { + prevLine = this.lines[this.lines.length - 1] + prevWall = this.wall.lines[this.wall.lines.length - 1] + } else { + prevLine = this.lines[index - 1] + prevWall = this.wall.lines[index - 1] + } + currentLine = this.lines[index] + currentWall = this.wall.lines[index] + + if (index === this.lines.length - 1) { + nextLine = this.lines[0] + nextWall = this.wall.lines[0] + } else if (index === this.lines.length) { + nextLine = this.lines[1] + nextWall = this.wall.lines[1] + } else { + nextLine = this.lines[index + 1] + nextWall = this.wall.lines[index + 1] + } + if (this.getLineDirection(prevLine) !== this.getLineDirection(nextLine)) { + if (currentWall.length <= prevWall.length && currentWall.length <= nextWall.length) { + ridgeMaxLength = Math.min(prevLine.length, currentLine.length, nextLine.length) + ridgeMinLength = Math.max(prevLine.length, currentLine.length, nextLine.length) - currentLine.length + ridgeRun = ridgeMinLength < ridgeMaxLength ? ridgeMinLength : ridgeMaxLength + dVector = this.getDirectionForDegree(prevLine, currentLine) + switch (dVector) { + case 45: + startXPoint = currentLine.x1 + (currentLine.length / 2) + startYPoint = currentLine.y1 - (currentLine.length / 2) + endXPoint = startXPoint + endYPoint = startYPoint - ridgeRun + break + case 135: + startXPoint = currentLine.x1 + (currentLine.length / 2) + startYPoint = currentLine.y1 + (currentLine.length / 2) + endXPoint = startXPoint + ridgeRun + endYPoint = startYPoint + break + case 225: + startXPoint = currentLine.x1 - (currentLine.length / 2) + startYPoint = currentLine.y1 + (currentLine.length / 2) + endXPoint = startXPoint + endYPoint = startYPoint + ridgeRun + break + case 315: + startXPoint = currentLine.x1 - (currentLine.length / 2) + startYPoint = currentLine.y1 - (currentLine.length / 2) + endXPoint = startXPoint - ridgeRun + endYPoint = startYPoint + break + } + if (this.ridges.length < this.getMaxRidge(this.lines.length)) { + const ridge = new QLine([startXPoint, startYPoint, endXPoint, endYPoint], { + fontSize: this.fontSize, + stroke: 'blue', + strokeWidth: 1, + }) + this.addWithUpdate(ridge) + this.ridges.push(ridge) + } + //마루와 연결될 추녀마루을 그려준다. + const leftHip = new QLine([currentLine.x1, currentLine.y1, startXPoint, startYPoint], { + fontSize: this.fontSize, + stroke: 'red', + strokeWidth: 1, + }) + const rightHip = new QLine([currentLine.x2, currentLine.y2, startXPoint, startYPoint], { + fontSize: this.fontSize, + stroke: 'red', + strokeWidth: 1, + }) + this.addWithUpdate(leftHip) + this.addWithUpdate(rightHip) + this.hips.push(leftHip) + this.hips.push(rightHip) + } + } + }, + ) + + this.canvas.renderAll() + } + + drawHips() { + let prevLine, currentLine, nextLine, endXPoint, endYPoint this.lines.forEach( (value, index) => { if (index === 0) { @@ -689,52 +791,139 @@ export default class QPolygon extends fabric.Group { if (index === this.lines.length - 1) { nextLine = this.lines[0] } else if (index === this.lines.length) { - nextLine = this.lines[0] + nextLine = this.lines[1] } else { nextLine = this.lines[index + 1] } - // point = this.getPointBetweenLine(currentLine, nextLine) - - this.getRoofRidge(prevLine, currentLine, nextLine) + if (!this.isAlreadyHip(currentLine)) { + this.ridges.forEach(ridge => { + if (Math.abs(currentLine.x1 - ridge.x1) === Math.abs(currentLine.y1 - ridge.y1)) { + endXPoint = ridge.x1 + endYPoint = ridge.y1 + } + if (Math.abs(currentLine.x1 - ridge.x2) === Math.abs(currentLine.y1 - ridge.y2)) { + endXPoint = ridge.x2 + endYPoint = ridge.y2 + } + // TODO [ljyoung] : 마루와 만나지 않는 hip 계산 + }) + 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.canvas.renderAll() } - getRoofRidge(prevLine, currentLine, nextLine) { - if (this.getLineDirection(prevLine) !== this.getLineDirection(nextLine)) { - console.log(this.getLineDirection(prevLine), this.getLineDirection(currentLine), this.getLineDirection(nextLine)) - console.log(currentLine.length) - if (currentLine.length < prevLine.length && currentLine.length < nextLine.length) { - console.log(currentLine.length) + /* + 추녀마루(hip) 중복방지를 위해 마루와 함께 그려진 추녀마루를 확인한다 + */ + 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개 이상의 라인과 접해야 함. + */ + connectLinePoint() { + let missedPoints = [] + let missedLine = [] + this.ridges.forEach(ridge => { + if (this.findConnectionLineCount(ridge.x1, ridge.y1) < 2) { + missedPoints.push({ x: ridge.x1, y: ridge.y1 }) + } + if (this.findConnectionLineCount(ridge.x2, ridge.y2) < 2) { + missedPoints.push({ x: ridge.x2, y: ridge.y2 }) + } + }) + console.log(missedPoints) + + missedPoints.forEach(p1 => { + let nearX, nearY, diffX, diffY, diffMinX, diffMinY + //가장 가까운 포인트를 확인 + missedPoints.forEach(p2 => { + diffX = Math.abs(p1.x - p2.x) + diffY = Math.abs(p1.y - p2.y) + if (diffMinX === undefined && diffMinY === undefined && diffX > 0 && diffY > 0) { + diffMinX = diffX + diffMinY = diffY + } + console.log(nearX, nearY, diffX, diffY, diffMinX, diffMinY) + if (diffX !== 0 && diffY !== 0 && (diffX === diffY) + && diffX <= diffMinX && diffY <= diffMinY) { + nearX = p2.x + nearY = p2.y + diffMinX = Math.abs(p1.x - p2.x) + diffMinY = Math.abs(p1.y - p2.y) + } + }) + console.log(nearX, nearY) + if (nearX !== undefined && nearY !== undefined) { + if (p1.x < nearX && p1.y < nearY) { + missedLine.push({ x1: p1.x, y1: p1.y, x2: nearX, y2: nearY }) + } else if (p1.x > nearX && p1.y < nearY) { + missedLine.push({ x1: nearX, y1: p1.y, x2: p1.x, y2: nearY }) + } else if (p1.x > nearX && p1.y > nearY) { + missedLine.push({ x1: nearX, y1: nearY, x2: p1.x, y2: p1.y }) + } else if (p1.x < nearX && p1.y > nearY) { + missedLine.push({ x1: nearX, y1: nearY, x2: p1.x, y2: p1.y }) + } + } + }) + // TODO [ljyoung] : 중복라인제거 + console.log(missedLine) + missedLine.forEach(p => { + const line = new QLine([p.x1, p.y1, p.x2, p.y2], { + fontSize: this.fontSize, + stroke: 'green', + strokeWidth: 1, + }) + this.addWithUpdate(line) + }) + + this.canvas.renderAll() + } + + /* + hip은 항상 마루에 연결되고 마루에는 2개 이상의 hip이 연결된다. + hip의 시작은 처마꼭지점이며 끝은 마루이기 때문에 힙의 끝 좌표와 비교한다. + */ + findConnectionLineCount(x, y) { + let count = 0 + this.hips.forEach((hip, index) => { + if (x === hip.x2 && y === hip.y2) { + count++ + } + }) + return count + } + + /* + 최대 생성 마루 갯수 + */ getMaxRidge(length) { let a1 = 4 let d = 2 return ((length - a1) / d) + 1 } - getPointBetweenLine(line1, line2) { - let dVector = this.getDirectionForDegree(line1, line2) - let xp = line1.x2, yp = line1.y2 - - console.log(xp, yp) - - // let alpha = 45.0 * Math.PI / 180 - // let a = c * Math.sin(alpha) - - switch (dVector) { - case 45: - - break - } - - return 'a' - } - + /* + 두 라인의 사잇각 계산 + */ getDirectionForDegree(line1, line2) { let degree = this.getLineDirection(line1) + this.getLineDirection(line2) let vector @@ -769,6 +958,9 @@ export default class QPolygon extends fabric.Group { return vector } + /* + 현재 라인의 방향을 계산 + */ getLineDirection(line) { let x1, x2, y1, y2, xp, yp x1 = Math.round(line.x1)