diff --git a/src/components/Roof2.jsx b/src/components/Roof2.jsx index f22ddf7c..536c397e 100644 --- a/src/components/Roof2.jsx +++ b/src/components/Roof2.jsx @@ -10,7 +10,6 @@ import { canvasSizeState, fontSizeState, sortedPolygonArray } from '@/store/canv import { QLine } from '@/components/fabric/QLine' import { getCanvasState, insertCanvasState } from '@/lib/canvas' import { calculateIntersection2 } from '@/util/canvas-util' -import { CustomLine } from '@/components/fabric/QLine' import { QPolygon } from '@/components/fabric/QPolygon' export default function Roof2() { @@ -45,6 +44,7 @@ export default function Roof2() { handleOuterlinesTest2, applyTemplateB, makeRoofPatternPolygon, + drawRoofPolygon, } = useMode() // const [canvasState, setCanvasState] = useRecoilState(canvasAtom) @@ -237,11 +237,32 @@ export default function Roof2() { { 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) { - const polygon = new QPolygon(type1A, { + const polygon = new QPolygon(diagonalType, { // const polygon = new QPolygon(eightPoint, { fill: 'transparent', - stroke: 'black', + stroke: 'green', strokeWidth: 1, selectable: true, fontSize: fontSize, @@ -249,8 +270,9 @@ export default function Roof2() { }) canvas?.add(polygon) + drawRoofPolygon(polygon) - handleOuterlinesTest2(polygon) + // handleOuterlinesTest2(polygon) // const lines = togglePolygonLine(polygon) // togglePolygonLine(lines[0]) diff --git a/src/components/fabric/QPolygon.js b/src/components/fabric/QPolygon.js index ee485d77..defc3a4f 100644 --- a/src/components/fabric/QPolygon.js +++ b/src/components/fabric/QPolygon.js @@ -1,8 +1,13 @@ import { fabric } from 'fabric' import { v4 as uuidv4 } from 'uuid' import { QLine } from '@/components/fabric/QLine' -import { distanceBetweenPoints, findTopTwoIndexesByDistance, getDirectionByPoint, sortedPoints } from '@/util/canvas-util' -import { drawHelpLineInHexagon } from '@/util/qpolygon-utils' +import { + distanceBetweenPoints, + findTopTwoIndexesByDistance, + getDirectionByPoint, + sortedPoints, +} from '@/util/canvas-util' +import { drawHippedRoof } from '@/util/qpolygon-utils' export const QPolygon = fabric.util.createClass(fabric.Polygon, { type: 'QPolygon', @@ -10,13 +15,19 @@ export const QPolygon = fabric.util.createClass(fabric.Polygon, { texts: [], id: null, length: 0, - initialize: function (points, options, canvas) { + ridges: [], + hips: [], + innerLines: [], + initialize: function(points, options, canvas) { + console.log('sorted 전 points : ', points) // 소수점 전부 제거 points.forEach((point) => { point.x = Math.round(point.x) point.y = Math.round(point.y) }) points = sortedPoints(points) + + console.log('sorted 후 points : ', points) this.callSuper('initialize', points, options) if (options.id) { this.id = options.id @@ -65,13 +76,13 @@ export const QPolygon = fabric.util.createClass(fabric.Polygon, { this.shape = shape }, - toObject: function (propertiesToInclude) { + toObject: function(propertiesToInclude) { return fabric.util.object.extend(this.callSuper('toObject', propertiesToInclude), { type: this.type, text: this.text, }) }, - init: function () { + init: function() { this.addLengthText() this.on('moving', () => { @@ -117,7 +128,8 @@ export const QPolygon = fabric.util.createClass(fabric.Polygon, { // 보조선 그리기 drawHelpLine(chon = 4) { - drawHelpLineInHexagon(this, chon) + // drawHelpLineInHexagon(this, chon) + drawHippedRoof(this, chon) }, addLengthText() { @@ -127,7 +139,10 @@ export const QPolygon = fabric.util.createClass(fabric.Polygon, { const thisText = this.canvas.getObjects().find((obj) => obj.name === 'lengthText' && obj.parentId === this.id && obj.idx === i) if (thisText) { - thisText.set({ left: (start.x + points[(i + 1) % points.length].x) / 2, top: (start.y + points[(i + 1) % points.length].y) / 2 }) + thisText.set({ + left: (start.x + points[(i + 1) % points.length].x) / 2, + top: (start.y + points[(i + 1) % points.length].y) / 2, + }) return } @@ -158,10 +173,10 @@ export const QPolygon = fabric.util.createClass(fabric.Polygon, { this.fontSize = fontSize this.text.set({ fontSize }) }, - _render: function (ctx) { + _render: function(ctx) { this.callSuper('_render', ctx) }, - _set: function (key, value) { + _set: function(key, value) { this.callSuper('_set', key, value) }, setCanvas(canvas) { @@ -288,7 +303,7 @@ export const QPolygon = fabric.util.createClass(fabric.Polygon, { } }) }, - setWall: function (wall) { + setWall: function(wall) { this.wall = wall }, setViewLengthText(isView) { @@ -296,1578 +311,4 @@ export const QPolygon = fabric.util.createClass(fabric.Polygon, { text.set({ visible: isView }) }) }, -}) - } - - fillBackground(pattern) { - this.polygon.set({ fill: pattern }) - this.canvas.requestRenderAll() - } - - // 보조선 그리기 - drawHelpLine(chon = 4) { - if (!this.isValid()) { - return - } - - /* if (this.lines.length === 4) { - this.#drawHelpLineInRect(chon) - } else if (this.lines.length === 6) { - // TODO : 6각형 - this.#drawHelpLineInHexagon(chon) - } else if (this.lines.length === 8) { - // TODO : 8각형 - this.#drawHelpLineInOctagon(chon) - }*/ - this.#drawHelpLineInOctagon(chon) - } - - /** - * 현재 점 6개만 가능 - */ - setShape() { - let shape = 0 - if (this.lines.length !== 6) { - return - } - //외각선 기준 - const topIndex = findTopTwoIndexesByDistance(this.lines).sort((a, b) => a - b) //배열중에 큰 2값을 가져옴 TODO: 나중에는 인자로 받아서 다각으로 수정 해야됨 - - //일단 배열 6개 짜리 기준의 선 번호 - if (topIndex[0] === 4) { - if (topIndex[1] === 5) { - //1번 - shape = 1 - } - } else if (topIndex[0] === 1) { - //4번 - if (topIndex[1] === 2) { - shape = 4 - } - } else if (topIndex[0] === 0) { - if (topIndex[1] === 1) { - //2번 - shape = 2 - } else if (topIndex[1] === 5) { - //3번 - shape = 3 - } - } - - this.shape = shape - } - - /** - * 현재 점 6개만 가능 - * @returns {number} - */ - getShape() { - return this.shape - } - - drawHelpLineInRect(chon) { - let type = 1 - let smallestLength = Infinity - let maxLength = 0 - - this.lines.forEach((line) => { - if (line.length < smallestLength) { - smallestLength = line.length - } - if (line.length > maxLength) { - maxLength = line.length - } - }) - - // QPolygon 객체의 모든 선들을 가져옵니다. - const lines = [...this.lines] - - // 이 선들을 길이에 따라 정렬합니다. - lines.sort((a, b) => a.length - b.length) - - // 정렬된 배열에서 가장 작은 두 선을 선택합니다. - let smallestLines - - if (smallestLength === maxLength) { - // 정사각형인 경우 0, 2번째 라인이 가장 짧은 라인 - - smallestLines = [lines[0], lines[2]] - } else { - smallestLines = lines.slice(0, 2) - } - - let needPlusLine - let needMinusLine - - const direction = smallestLines[0].direction - - if (direction === 'top' || direction === 'bottom') { - needPlusLine = smallestLines[0].x1 < smallestLines[1].x1 ? smallestLines[0] : smallestLines[1] - needMinusLine = needPlusLine === smallestLines[0] ? smallestLines[1] : smallestLines[0] - - type = 1 // 가로가 긴 사각형 - } - - if (direction === 'left' || direction === 'right') { - needPlusLine = smallestLines[0].y1 < smallestLines[1].y1 ? smallestLines[0] : smallestLines[1] - needMinusLine = needPlusLine === smallestLines[0] ? smallestLines[1] : smallestLines[0] - - type = 2 // 세로가 긴 사각형 - } - - let point1 - let point2 - - if (type === 1) { - point1 = { - x: needPlusLine.x1 + smallestLength / 2, - y: needPlusLine.y1 > needPlusLine.y2 ? needPlusLine.y1 - smallestLength / 2 : needPlusLine.y2 - smallestLength / 2, - } - - point2 = { - x: needMinusLine.x1 - smallestLength / 2, - y: needMinusLine.y1 > needMinusLine.y2 ? needMinusLine.y1 - smallestLength / 2 : needMinusLine.y2 - smallestLength / 2, - } - } else if (type === 2) { - point1 = { - x: needPlusLine.x1 > needPlusLine.x2 ? needPlusLine.x1 - smallestLength / 2 : needPlusLine.x2 - smallestLength / 2, - y: needPlusLine.y1 + smallestLength / 2, - } - - point2 = { - x: needMinusLine.x1 > needMinusLine.x2 ? needMinusLine.x1 - smallestLength / 2 : needMinusLine.x2 - smallestLength / 2, - y: needMinusLine.y1 - smallestLength / 2, - } - } - - // 빗변1 - const realLine1 = new QLine( - [needPlusLine.x1, needPlusLine.y1, point1.x, point1.y], - { fontSize: this.fontSize, stroke: 'black', strokeWidth: 1 }, - getRoofHypotenuse(smallestLength / 2), - ) - - // 빗변2 - const realLine2 = new QLine( - [needPlusLine.x2, needPlusLine.y2, point1.x, point1.y], - { fontSize: this.fontSize, stroke: 'black', strokeWidth: 1 }, - getRoofHypotenuse(smallestLength / 2), - ) - - // 빗변3 - const realLine3 = new QLine( - [needMinusLine.x1, needMinusLine.y1, point2.x, point2.y], - { fontSize: this.fontSize, stroke: 'black', strokeWidth: 1 }, - getRoofHypotenuse(smallestLength / 2), - ) - - // 빗변4 - const realLine4 = new QLine( - [needMinusLine.x2, needMinusLine.y2, point2.x, point2.y], - { fontSize: this.fontSize, stroke: 'black', strokeWidth: 1 }, - getRoofHypotenuse(smallestLength / 2), - ) - - let centerPoint1 - let centerPoint2 - - if (type === 1) { - centerPoint1 = { x: point1.x - smallestLength / 2, y: point1.y } - centerPoint2 = { x: point2.x + smallestLength / 2, y: point2.y } - } else if (type === 2) { - centerPoint1 = { x: point1.x, y: point1.y - smallestLength / 2 } - centerPoint2 = { x: point2.x, y: point2.y + smallestLength / 2 } - } - - // 옆으로 누워있는 지붕의 높이 - const realLine5 = new QLine( - [point1.x, point1.y, centerPoint1.x, centerPoint1.y], - { - fontSize: this.fontSize, - stroke: 'black', - strokeWidth: 1, - strokeDashArray: [5, 5], - }, - getRoofHeight(smallestLength / 2, getDegreeByChon(chon)), - ) - - // 옆으로 누워있는 지붕의 높이 - const realLine6 = new QLine( - [point2.x, point2.y, centerPoint2.x, centerPoint2.y], - { - fontSize: this.fontSize, - stroke: 'black', - strokeWidth: 1, - strokeDashArray: [5, 5], - }, - getRoofHeight(smallestLength / 2, getDegreeByChon(chon)), - ) - - // 용마루 - const ridge = new QLine([point1.x, point1.y, point2.x, point2.y], { - fontSize: this.fontSize, - stroke: 'black', - strokeWidth: 1, - }) - - this.canvas.add(realLine1) - this.canvas.add(realLine2) - this.canvas.add(realLine3) - this.canvas.add(realLine4) - this.canvas.add(realLine5) - this.canvas.add(realLine6) - if (smallestLength !== maxLength) { - // 정사각형이 아닌경우에만 용마루를 추가한다. - this.canvas.add(ridge) - } - } - - drawHelpLineInHexagon2(chon) { - const oneSideLines = [...this.lines].map((line) => { - let newX1, newY1, newX2, newY2 - if (line.direction === 'top') { - newX1 = line.x2 - newY1 = line.y2 - newX2 = line.x1 - newY2 = line.y1 - - line.x1 = newX1 - line.y1 = newY1 - line.x2 = newX2 - line.y2 = newY2 - line.direction = 'bottom' - } else if (line.direction === 'left') { - newX1 = line.x2 - newY1 = line.y2 - newX2 = line.x1 - newY2 = line.y1 - - line.x1 = newX1 - line.y1 = newY1 - line.x2 = newX2 - line.y2 = newY2 - line.direction = 'right' - } - return line - }) - - const centerLines = [] - const helpLines = [] - const ridgeStartPoints = [] - - const horizontalLines = oneSideLines.filter((line) => line.direction === 'right') - const verticalLines = oneSideLines.filter((line) => line.direction === 'bottom') - - const horizontalMaxLength = horizontalLines.reduce((max, obj) => Math.max(max, obj.length), 0) - const verticalMaxLength = verticalLines.reduce((max, obj) => Math.max(max, obj.length), 0) - // 모든 가로선의 중심선을 긋는다. - horizontalLines.forEach((line, index) => { - const nextLine = horizontalLines[(index + 1) % horizontalLines.length] - - const startCenterX = Math.max(line.x1, nextLine.x1) - const startCenterY = (line.y1 + nextLine.y1) / 2 - - let endCenterX = line.length >= nextLine.length ? startCenterX + line.length : startCenterX + nextLine.length - const endCenterY = startCenterY - - if (endCenterX > Math.max(line.x2, nextLine.x2)) { - endCenterX = Math.max(line.x2, nextLine.x2) - } - - const centerLine = new QLine([startCenterX, startCenterY, endCenterX, endCenterY], { - fontSize: this.fontSize, - stroke: 'red', - strokeWidth: 1, - direction: 'horizontal', - }) - - // this.addWithUpdate(centerLine) - - centerLines.push(centerLine) - }) - - // 모든 세로선의 중심선을 긋는다. - verticalLines.forEach((line, index) => { - const nextLine = verticalLines[(index + 1) % verticalLines.length] - - const startCenterX = (line.x1 + nextLine.x1) / 2 - const startCenterY = Math.min(line.y1, nextLine.y1) - - const endCenterX = startCenterX - let endCenterY = line.length >= nextLine.length ? startCenterY + line.length : startCenterY + nextLine.length - - if (endCenterY > Math.max(line.y2, nextLine.y2)) { - endCenterY = Math.max(line.y2, nextLine.y2) - } - - const centerLine = new QLine([startCenterX, startCenterY, endCenterX, endCenterY], { - fontSize: this.fontSize, - stroke: 'blue', - strokeWidth: 1, - direction: 'vertical', - }) - // this.addWithUpdate(centerLine) - - centerLines.push(centerLine) - }) - - const maxLength = horizontalMaxLength < verticalMaxLength ? horizontalMaxLength : verticalMaxLength - - 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 - - let newX2, newY2 - - // x1, y1을 기준으로 x2, y2와의 거리를 유지한 새로운 직선 생성 - const angle = Math.atan2(y2 - y1, x2 - x1) - - newX2 = Math.floor(x1 + (maxLength / 2 + 50) * Math.cos(angle)) - newY2 = Math.floor(y1 + (maxLength / 2 + 50) * Math.sin(angle)) - - const line = new QLine([x1, y1, newX2, newY2], { - fontSize: this.fontSize, - stroke: 'green', - idx: index, - }) - this.addWithUpdate(line) - helpLines.push(line) - this.canvas.renderAll() - }) - - helpLines.forEach((line, index) => { - if (line.isAlreadyInterSection) { - return - } - const nextLine = helpLines[(index + 1 + helpLines.length) % helpLines.length] - this.canvas.renderAll() - - let intersectionPoint = calculateIntersection(line, nextLine) - if (!intersectionPoint) { - return - } - - line.set({ isAlreadyInterSection: true }) - nextLine.set({ isAlreadyInterSection: true }) - - const helpLine1 = new QLine([nextLine.x1, nextLine.y1, intersectionPoint.x, intersectionPoint.y], { - fontSize: this.fontSize, - stroke: 'skyblue', - }) - - const helpLine2 = new QLine([line.x1, line.y1, intersectionPoint.x, intersectionPoint.y], { - fontSize: this.fontSize, - stroke: 'skyblue', - }) - - ridgeStartPoints.push(intersectionPoint) - this.addWithUpdate(helpLine1) - this.addWithUpdate(helpLine2) - this.removeWithUpdate(nextLine) - this.removeWithUpdate(line) - this.canvas.renderAll() - }) - - // 안만나는 선들 - const notInterSectionLines = helpLines.filter((line) => !line.isAlreadyInterSection) - const ridgeEndPoints = [] - const interSectionPoints = [] - - notInterSectionLines.forEach((line, index) => { - line.line.set({ strokeWidth: (index + 1) * 5 }) - - centerLines.forEach((centerLine) => { - const interSectionPoint = calculateIntersection2(line, centerLine) - - if (!this.inPolygon(interSectionPoint) || !interSectionPoint) { - return - } - line.interSectionPoints.push(interSectionPoint) - interSectionPoints.push(interSectionPoint) - }) - }) - - ridgeStartPoints.forEach((point, index) => { - let arrivalPoint - let distance = Infinity - let startPoint - interSectionPoints.forEach((interSectionPoint) => { - if (Math.abs(point.x - interSectionPoint.x) < 3 || Math.abs(point.y - interSectionPoint.y) < 3) { - if (distanceBetweenPoints(point, interSectionPoint) < distance) { - startPoint = point - distance = distanceBetweenPoints(point, interSectionPoint) - arrivalPoint = interSectionPoint - } - } - }) - - if (arrivalPoint) { - const line = notInterSectionLines.filter((line) => line.interSectionPoints.includes(arrivalPoint))[0] - - const ridge = new QLine([startPoint.x, startPoint.y, arrivalPoint.x, arrivalPoint.y], { - stroke: 'black', - fontSize: this.fontSize, - }) - - const helpLine = new QLine([line.x1, line.y1, arrivalPoint.x, arrivalPoint.y], { - stroke: 'red', - fontSize: this.fontSize, - }) - - ridgeEndPoints.push(arrivalPoint) - this.addWithUpdate(ridge) - this.addWithUpdate(helpLine) - this.removeWithUpdate(line) - this.canvas.renderAll() - } - }) - - ridgeEndPoints.forEach((point, index) => { - const currentRidgeEndPoint = ridgeEndPoints[index] - const nextRidgeEndPoint = ridgeEndPoints[(index + 1) % ridgeEndPoints.length] - const ridgeConnectLine = new QLine([currentRidgeEndPoint.x, currentRidgeEndPoint.y, nextRidgeEndPoint.x, nextRidgeEndPoint.y], { - fontSize: this.fontSize, - stroke: 'green', - }) - - this.addWithUpdate(ridgeConnectLine) - this.canvas.renderAll() - }) - } - - drawHelpLineInHexagon(chon) { - const historyLines = [] - const helpPoints = [] - const notInterSectionLines = [] - const ridge = [] - const maxLength = this.lines.reduce((max, obj) => Math.max(max, obj.length), 0) - 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 - const historyLines = [] - const helpPoints = [] - const notInterSectionLines = [] - const ridge = [] - const maxLength = this.lines.reduce((max, obj) => Math.max(max, obj.length), 0) - 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 - - let newX2, newY2 - - // x1, y1을 기준으로 x2, y2와의 거리를 유지한 새로운 직선 생성 - const angle = Math.atan2(y2 - y1, x2 - x1) - - newX2 = x1 + (maxLength / 2) * Math.cos(angle) - newY2 = y1 + (maxLength / 2) * Math.sin(angle) - - const line = new QLine([x1, y1, newX2, newY2], { - fontSize: this.fontSize, - stroke: 'blue', - idx: index, - }) - historyLines.push(line) - this.canvas.add(line) - - this.canvas.renderAll() - }) - - /** - * 삼각 지붕 - */ - historyLines.forEach((line, index) => { - const prevLine = historyLines[(index - 1 + historyLines.length) % historyLines.length] - - let intersectionPoint = calculateIntersection(line, prevLine) - - if (!intersectionPoint) { - notInterSectionLines.push(line) - return - } - - const helpLine1 = new QLine([prevLine.x1, prevLine.y1, intersectionPoint.x, intersectionPoint.y], { - fontSize: this.fontSize, - stroke: 'red', - }) - - const helpLine2 = new QLine([line.x1, line.y1, intersectionPoint.x, intersectionPoint.y], { - fontSize: this.fontSize, - stroke: 'red', - }) - notInterSectionLines.pop() - helpPoints.push(intersectionPoint) - - this.canvas.add(helpLine1) - this.canvas.add(helpLine2) - this.canvas.remove(prevLine) - this.canvas.remove(line) - this.canvas.renderAll() - }) - // 용마루 - - const ridgePoint = [] - - helpPoints.forEach((helpPoint, index) => { - const closestLine = findClosestLineToPoint(helpPoint, notInterSectionLines) - - // 가까운 선의 중심점 - const centerClosestLinePoint = { - x: (closestLine.x1 + closestLine.x2) / 2, - y: (closestLine.y1 + closestLine.y2) / 2, - } - - const direction = getDirectionByPoint(helpPoint, centerClosestLinePoint) - - let newX, newY - - switch (direction) { - case 'left': { - newX = ((closestLine.x2 - closestLine.x1) * (helpPoint.y - closestLine.y1)) / (closestLine.y2 - closestLine.y1) + closestLine.x1 - newY = helpPoint.y - break - } - case 'right': { - newX = ((closestLine.x2 - closestLine.x1) * (helpPoint.y - closestLine.y1)) / (closestLine.y2 - closestLine.y1) + closestLine.x1 - newY = helpPoint.y - break - } - case 'top': { - newX = helpPoint.x - newY = ((closestLine.y2 - closestLine.y1) * (helpPoint.x - closestLine.x1)) / (closestLine.x2 - closestLine.x1) + closestLine.y1 - break - } - case 'bottom': { - newX = helpPoint.x - newY = ((closestLine.y2 - closestLine.y1) * (helpPoint.x - closestLine.x1)) / (closestLine.x2 - closestLine.x1) + closestLine.y1 - break - } - } - - const ridgeHelpLine = new QLine([closestLine.x1, closestLine.y1, newX, newY], { - fontSize: this.fontSize, - stroke: 'purple', - strokeWidth: 5, - }) - - ridgePoint.push({ x: newX, y: newY }) - - const ridge = new QLine([helpPoint.x, helpPoint.y, newX, newY], { - fontSize: this.fontSize, - stroke: 'skyblue', - strokeWidth: 5, - }) - - this.canvas.add(ridge) - this.canvas.renderAll() - - this.canvas.add(ridgeHelpLine) - this.canvas.remove(closestLine) - this.canvas.renderAll() - }) - - // 용마루 끼리 연결 - for (let i = 0; i < ridgePoint.length; i = i + 2) { - const currentRidgeEndPoint = ridgePoint[i] - const nextRidgeEndPoint = ridgePoint[(i + 1) % ridgePoint.length] - const ridgeConnectLine = new QLine([currentRidgeEndPoint.x, currentRidgeEndPoint.y, nextRidgeEndPoint.x, nextRidgeEndPoint.y], { - fontSize: this.fontSize, - stroke: 'green', - strokeWidth: 5, - }) - this.canvas.add(ridgeConnectLine) - this.canvas.renderAll() - } - - this.canvas.renderAll() - }) - } - - #drawHelpLineInOctagon(chon) { - this.drawRoofRidge() - // this.drawHips() - // this.connectLinePoint() - } - - /*마루 그리기 - 외벽의 모양이 돌출된 ㄷ의 형태일때 - 현재 라인의 외벽길이가 붙어있는 두외벽의 길이보다 짧거나 같다면 - 지붕의 두 꼭지점에서 외벽의 두 꼭지점으로 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) && currentWall.length < currentLine.length) { - if (this.getLineDirection(prevWall) !== this.getLineDirection(nextWall) && currentWall.length < currentLine.length) { - dVector = this.getDirectionForDegree(prevWall, currentWall) - let { - minLineLength, - currentLineLength, - maxLineLength, - } = this.getRoofBaseLine(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 - this.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 && this.ridges.length < this.getMaxRidge(this.lines.length)) { - const ridge = new QLine([Math.min(startXPoint, endXPoint), Math.min(startYPoint, endYPoint), Math.max(startXPoint, endXPoint), Math.max(startYPoint, endYPoint)], { - fontSize: this.fontSize, - stroke: 'blue', - strokeWidth: 1, - }) - this.addWithUpdate(ridge) - this.ridges.push(ridge) - this.innerLines.push(ridge) - } - } - } - }, - ) - // this.canvas.renderAll() - } - - drawHips() { - /* - 마루에서 시작되는 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 = this.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() - } - - getRoofBaseLine(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 = this.lines.filter(line => { - if (this.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, - } - } - } - } - - 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} - */ - 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) 중복방지를 위해 마루와 함께 그려진 추녀마루를 확인한다 - */ - 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 = [] - //마루 - 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) - }) - } - - /* - 최대 생성 마루 갯수 - */ - getMaxRidge(length) { - return ((length - 4) / 2) + 1 - } - - /* - 두 라인의 사잇각 계산 - */ - getDirectionForDegree(line1, line2) { - let degree = this.getLineDirection(line1) + this.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 - } - - /* - 현재 라인의 방향을 계산 - */ - 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' - } - } - } -} +}) \ No newline at end of file diff --git a/src/hooks/useMode.js b/src/hooks/useMode.js index 890672a7..6d4412b6 100644 --- a/src/hooks/useMode.js +++ b/src/hooks/useMode.js @@ -1,9 +1,22 @@ import { useEffect, useRef, useState } from 'react' 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 { 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 { fabric } from 'fabric' import { QPolygon } from '@/components/fabric/QPolygon' @@ -1156,6 +1169,11 @@ export function useMode() { roof.drawHelpLine() } + const drawRoofPolygon = (wall, offset = 71) => { + console.log(wall) + + } + const togglePolygonLine = (obj) => { const rtnLines = [] if (obj.type === 'QPolygon') { @@ -2252,7 +2270,13 @@ export function useMode() { canvas.add(centerLine2) 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.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, handleOuterlinesTest2, makeRoofPatternPolygon, + drawRoofPolygon, } } diff --git a/src/util/qpolygon-utils.js b/src/util/qpolygon-utils.js index ba5be5e7..5fe55ecd 100644 --- a/src/util/qpolygon-utils.js +++ b/src/util/qpolygon-utils.js @@ -6,10 +6,10 @@ import { calculateIntersection2, distanceBetweenPoints, findClosestPoint } from export const defineQPloygon = () => { fabric.QPolygon = fabric.util.createClass(fabric.Group, {}) // fromObject 메서드를 QLine 클래스에 직접 추가 - fabric.QPolygon.fromObject = function (object, callback) { + fabric.QPolygon.fromObject = function(object, callback) { const { initOption, initPoints, initLengthTxt } = object - fabric.util.enlivenObjects(object.objects, function (enlivenedObjects) { + fabric.util.enlivenObjects(object.objects, function(enlivenedObjects) { return callback(new QPolygon(initPoints, object, initLengthTxt)) }) } @@ -285,7 +285,8 @@ export const drawHelpLineInHexagon = (polygon, chon) => { }*/ } -export const drawHelpLineInHexagon2 = (polygon, chon) => {} +export const drawHelpLineInHexagon2 = (polygon, chon) => { +} export const drawCenterLines = (polygon) => { const centerLines = [] @@ -384,3 +385,982 @@ const calculateAngle = (point1, point2) => { const angleInRadians = Math.atan2(deltaY, deltaX) 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' + } + } +} \ No newline at end of file