diff --git a/next.config.mjs b/next.config.mjs index 107c5460..8cc4c040 100644 --- a/next.config.mjs +++ b/next.config.mjs @@ -1,6 +1,6 @@ /** @type {import('next').NextConfig} */ const nextConfig = { - // reactStrictMode: false, + reactStrictMode: false, webpack: (config) => { config.externals.push({ "utf-8-validate": "commonjs utf-8-validate", diff --git a/src/app/error.jsx b/src/app/error.jsx new file mode 100644 index 00000000..07d75e7e --- /dev/null +++ b/src/app/error.jsx @@ -0,0 +1,15 @@ +'use client' + +export default function ServerError() { + return ( + + + + 500 + Internal Server Error. + We are already working to solve the problem. + + + + ) +} diff --git a/src/app/not-found.jsx b/src/app/not-found.jsx new file mode 100644 index 00000000..8127943b --- /dev/null +++ b/src/app/not-found.jsx @@ -0,0 +1,25 @@ +'use client' + +import Link from 'next/link' + +export default function NotFound() { + return ( + + + + 404 + Something's missing. + + Sorry, we can't find that page. You'll find lots to explore on the home page.{' '} + + + Back to Homepage + + + + + ) +} diff --git a/src/components/Roof2.jsx b/src/components/Roof2.jsx index fa730830..76a64e93 100644 --- a/src/components/Roof2.jsx +++ b/src/components/Roof2.jsx @@ -5,11 +5,11 @@ import { Button } from '@nextui-org/react' import QRect from '@/components/fabric/QRect' import RangeSlider from './ui/RangeSlider' -import { useRecoilState } from 'recoil' -import { canvasSizeState, fontSizeState, sortedPolygonArray } from '@/store/canvasAtom' +import { useRecoilState, useRecoilValue } from 'recoil' +import { canvasSizeState, fontSizeState, roofState, sortedPolygonArray } from '@/store/canvasAtom' import { QLine } from '@/components/fabric/QLine' import { getCanvasState, insertCanvasState } from '@/lib/canvas' -import { calculateIntersection2 } from '@/util/canvas-util' +import { calculateIntersection } from '@/util/canvas-util' import { QPolygon } from '@/components/fabric/QPolygon' export default function Roof2() { @@ -107,28 +107,24 @@ export default function Roof2() { } } - /** - * canvas 사이즈 변경 함수 - */ - const canvasSizeMode = () => { - if (canvas) { - canvas.setWidth(horizontalSize) - canvas.setHeight(verticalSize) - canvas.renderAll() - - setCanvasSize(() => ({ - vertical: verticalSize, - horizontal: horizontalSize, - })) - } - } + useEffect(() => { + setCanvasSize({ ...canvasSize, vertical: verticalSize, horizontal: horizontalSize }) + }, [verticalSize, horizontalSize]) /** * 값 변경시 */ + // useEffect(() => { + // canvasSizeMode() + // }, [verticalSize, horizontalSize]) useEffect(() => { - canvasSizeMode() - }, [verticalSize, horizontalSize]) + const { vertical, horizontal } = canvasSize + if (vertical !== verticalSize || horizontal !== horizontalSize) { + canvas.setWidth(horizontalSize) + canvas.setHeight(verticalSize) + canvas.renderAll() + } + }, [canvasSize, canvas]) const makeQPolygon = () => { const type1 = [ @@ -207,14 +203,14 @@ export default function Roof2() { ] const eightPoint3 = [ - { x: 200, y: 200 }, - { x: 200, y: 1000 }, - { x: 1000, y: 1000 }, - { x: 1000, y: 800 }, - { x: 600, y: 800 }, - { x: 600, y: 350 }, - { x: 1000, y: 350 }, - { x: 1000, y: 200 }, + { x: 190, y: 147 }, + { x: 190, y: 747 }, + { x: 490, y: 747 }, + { x: 490, y: 497 }, + { x: 640, y: 497 }, + { x: 640, y: 747 }, + { x: 1090, y: 747 }, + { x: 1090, y: 147 }, ] const eightPoint4 = [ @@ -270,25 +266,39 @@ export default function Roof2() { { x: 300, y: 100 }, ] - if (canvas) { - const polygon = new QPolygon(diagonalType, { - // const polygon = new QPolygon(eightPoint, { - fill: 'transparent', - stroke: 'green', - strokeWidth: 1, - selectable: true, - fontSize: fontSize, - name: 'QPolygon1', - }) + const twelvePoint = [ + { x: 195, y: 166 }, + { x: 195, y: 466 }, + { x: 395, y: 466 }, + { x: 395, y: 766 }, + { x: 545, y: 766 }, + { x: 545, y: 466 }, + { x: 695, y: 466 }, + { x: 695, y: 666 }, + { x: 845, y: 666 }, + { x: 845, y: 466 }, + { x: 995, y: 466 }, + { x: 995, y: 166 }, + ] + + const types = [type1, type2, type3, type4, type1A, type1B, eightPoint, eightPoint2, eightPoint3, eightPoint4, twelvePoint] + + const polygon = new QPolygon(type1B, { + fill: 'transparent', + stroke: 'black', + strokeWidth: 1, + selectable: true, + fontSize: fontSize, + name: 'QPolygon1', + }) canvas?.add(polygon) drawRoofPolygon(polygon) // handleOuterlinesTest2(polygon) - // const lines = togglePolygonLine(polygon) - // togglePolygonLine(lines[0]) - } + // const lines = togglePolygonLine(polygon) + // togglePolygonLine(lines[0]) } const rotateShape = () => { @@ -321,7 +331,7 @@ export default function Roof2() { canvas?.add(line) canvas?.add(line2) - const interSectionPoint = calculateIntersection2(line, line2) + const interSectionPoint = calculateIntersection(line, line2) if (interSectionPoint) { const circle = new fabric.Circle({ @@ -429,8 +439,12 @@ export default function Roof2() { drawRoofPatterns(2)}> 지붕패턴2 - changeMode(canvas, Mode.MODULE)}> - 모듈 + changeMode(canvas, Mode.ROOT_TRESTLE)} + > + 지붕가대생성 changeMode(canvas, Mode.TEXTBOX)}> 텍스트박스 모드 diff --git a/src/components/fabric/QLine2.js b/src/components/fabric/QLine2.js deleted file mode 100644 index d75cff2c..00000000 --- a/src/components/fabric/QLine2.js +++ /dev/null @@ -1,184 +0,0 @@ -/** - * 문제 없는경우 제거 - */ -import { fabric } from 'fabric' -import { getDirection, getDirectionByPoint } from '@/util/canvas-util' - -export class QLine2 extends fabric.Group { - line - text - fontSize - length = 0 - x1 - y1 - x2 - y2 - direction - idx - type = 'QLine2' - parent - isAlreadyInterSection = false - - interSectionPoints = [] - lengthTxt = 0 - - initPoints - initOption - initLengthTxt - - constructor(points, option = { isActiveLengthText: true }, lengthTxt) { - // 소수점 전부 제거 - points.forEach((point) => { - point = Math.round(point) - }) - - const [x1, y1, x2, y2] = points - - if (!option.fontSize) { - throw new Error('Font size is required.') - } - - const line = new fabric.Line(points, { ...option, strokeWidth: 1 }) - - // 길이가 1이하인 선은 생성하지 않음 - if (Math.abs(x1 - x2) <= 1 && Math.abs(y1 - y2) <= 1) { - super([], {}) - this.initPoints = points - this.initOption = option - this.initLengthTxt = lengthTxt - } else { - super([line], {}) - this.initPoints = points - this.initOption = option - this.initLengthTxt = lengthTxt - - this.x1 = x1 - this.y1 = y1 - this.x2 = x2 - this.y2 = y2 - this.line = line - this.fontSize = option.fontSize - this.direction = option.direction ?? getDirectionByPoint({ x: x1, y: y1 }, { x: x2, y: y2 }) - this.parent = option.parent - this.idx = option.idx - - if (lengthTxt > 0) { - this.lengthTxt = Number(lengthTxt) - } - - option.isActiveLengthText ?? this.init() - this.addControl() - } - } - - init() { - this.addLengthText(true) - } - - addControl() { - this.on('moving', () => { - this.addLengthText(false) - }) - - this.on('modified', (e) => { - this.addLengthText(false) - }) - - this.on('selected', () => { - console.log(this) - Object.keys(this.controls).forEach((controlKey) => { - if (controlKey !== 'ml' && controlKey !== 'mr') { - this.setControlVisible(controlKey, false) - } - }) - }) - } - - static fromObject(object, callback) { - const { points, initOption, initLengthTxt } = object - const instance = new QLine(points, initOption, initLengthTxt) - callback && callback(instance) - return instance - } - - addLengthText(isFirst) { - if (this.text) { - this.removeWithUpdate(this.text) - this.text = null - } - - if (isFirst && this.lengthTxt > 0) { - const text = new fabric.Textbox(this.lengthTxt.toFixed(0).toString(), { - left: (this.x1 + this.x2) / 2, - top: (this.y1 + this.y2) / 2, - fontSize: this.fontSize, - }) - this.length = this.lengthTxt - this.text = text - this.addWithUpdate(text) - return - } - - const scaleX = this.scaleX - const scaleY = this.scaleY - const x1 = this.left - const y1 = this.top - const x2 = this.left + this.width * scaleX - const y2 = this.top + this.height * scaleY - const dx = x2 - x1 - const dy = y2 - y1 - this.length = Number(Math.sqrt(dx * dx + dy * dy).toFixed(0)) - - const text = new fabric.Textbox(this.length.toFixed(0).toString(), { - left: (x1 + x2) / 2, - top: (y1 + y2) / 2, - fontSize: this.fontSize, - }) - this.text = text - this.addWithUpdate(text) - } - - setFontSize(fontSize) { - this.fontSize = fontSize - this.text.set({ fontSize }) - this.addWithUpdate() - } - - fromObject(object, callback) { - console.log('fromObject', object, callback) - } - - async = true - - toObject(propertiesToInclude) { - return fabric.util.object.extend(this.callSuper('toObject'), { - length: this.length, - line: this.line, - text: this.text, - fontSize: this.fontSize, - x1: this.x1, - y1: this.y1, - x2: this.x2, - y2: this.y2, - direction: this.direction, - idx: this.idx, - type: this.type, - parent: this.parent, - isAlreadyInterSection: this.isAlreadyInterSection, - interSectionPoints: this.interSectionPoints, - lengthTxt: this.lengthTxt, - setFontSize: this.setFontSize, - addLengthText: this.addLengthText, - init: this.init, - addControl: this.addControl, - initPoints: this.initPoints, - initOption: this.initOption, - initLengthTxt: this.initLengthTxt, - points: this.points, - }) - } - - _set(key, value) { - this.callSuper('_set', key, value) - } -} diff --git a/src/components/fabric/QPolygon.js b/src/components/fabric/QPolygon.js index d4327a94..a9c7e751 100644 --- a/src/components/fabric/QPolygon.js +++ b/src/components/fabric/QPolygon.js @@ -1,12 +1,8 @@ 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 { distanceBetweenPoints, findTopTwoIndexesByDistance, getDirectionByPoint, sortedPointLessEightPoint, sortedPoints } from '@/util/canvas-util' +import { drawHelpLineInHexagon } from '@/util/qpolygon-utils' import { drawHippedRoof } from '@/util/qpolygon-utils' export const QPolygon = fabric.util.createClass(fabric.Polygon, { @@ -15,19 +11,22 @@ export const QPolygon = fabric.util.createClass(fabric.Polygon, { texts: [], id: null, length: 0, - ridges: [], hips: [], + ridges: [], + connectRidges: [], innerLines: [], - initialize: function(points, options, canvas) { - console.log('sorted 전 points : ', points) + initialize: function (points, options, canvas) { // 소수점 전부 제거 points.forEach((point) => { point.x = Math.round(point.x) point.y = Math.round(point.y) }) - points = sortedPoints(points) + if (points.length <= 8) { + points = sortedPointLessEightPoint(points) + } else { + points = sortedPoints(points) + } - console.log('sorted 후 points : ', points) this.callSuper('initialize', points, options) if (options.id) { this.id = options.id @@ -133,7 +132,7 @@ export const QPolygon = fabric.util.createClass(fabric.Polygon, { }, addLengthText() { - const points = this.getCurrentPoints() + let points = this.points points.forEach((start, i) => { const thisText = this.canvas.getObjects().find((obj) => obj.name === 'lengthText' && obj.parentId === this.id && obj.idx === i) @@ -219,9 +218,9 @@ export const QPolygon = fabric.util.createClass(fabric.Polygon, { top: rectTop, width: rectWidth, height: rectHeight, - stroke: 'black', // or any other color - fill: 'transparent', + fill: '#BFFD9F', selectable: false, + opacity: 0.6, }) this.canvas.add(rect) @@ -320,4 +319,5 @@ export const QPolygon = fabric.util.createClass(fabric.Polygon, { text.set({ visible: isView }) }) }, + divideLine() {}, }) diff --git a/src/components/fabric/QPolygon3.js b/src/components/fabric/QPolygon3.js deleted file mode 100644 index b3770831..00000000 --- a/src/components/fabric/QPolygon3.js +++ /dev/null @@ -1,941 +0,0 @@ -/** - * 문제 없는경우 제거 - */ - -import { fabric } from 'fabric' -import { - calculateIntersection, - calculateIntersection2, - distanceBetweenPoints, - findClosestLineToPoint, - findTopTwoIndexesByDistance, - getDegreeByChon, - getDirectionByPoint, - getRoofHeight, - getRoofHypotenuse, - sortedPoints, -} from '@/util/canvas-util' -import { QLine } from '@/components/fabric/QLine' -import { drawHelpLineInHexagon } from '@/util/qpolygon-utils' - -export default class QPolygon3 extends fabric.Group { - type = 'QPolygon3' - polygon - points - texts = [] - lines = [] - canvas - fontSize - qCells = [] - name - shape = 0 // 점 6개일때의 shape 모양 - helpPoints = [] - helpLines = [] - - wall - - initPoints - initOption - - constructor(points, options, canvas) { - /*if (points.length !== 4 && points.length !== 6) { - throw new Error('Points must be 4 or 6.') - }*/ - if (!options.fontSize) { - throw new Error('Font size is required.') - } - - // 소수점 전부 제거 - points.forEach((point) => { - point.x = Math.round(point.x) - point.y = Math.round(point.y) - }) - - const sortPoints = sortedPoints(points) - const polygon = new fabric.Polygon(sortPoints, options) - - super([polygon], {}) - - this.fontSize = options.fontSize - this.points = sortPoints - this.polygon = polygon - this.name = options.name - - this.initPoints = points - this.initOption = options - - this.init() - this.addEvent() - this.initLines() - this.setShape() - } - - initLines() { - this.points.forEach((point, i) => { - const nextPoint = this.points[(i + 1) % this.points.length] - const line = new QLine([point.x, point.y, nextPoint.x, nextPoint.y], { - stroke: this.stroke, - strokeWidth: this.strokeWidth, - fontSize: this.fontSize, - idx: i, - direction: getDirectionByPoint(point, nextPoint), - }) - - this.lines.push(line) - }) - } - - init() { - this.addLengthText() - } - - addEvent() { - this.on('scaling', (e) => { - this.updateLengthText() - }) - - this.on('selected', function () { - // 모든 컨트롤 떼기 - - Object.keys(this.controls).forEach((controlKey) => { - if (controlKey !== 'mtr') { - this.setControlVisible(controlKey, false) - } - }) - }) - } - - setWall(wall) { - this.wall = wall - } - - setFontSize(fontSize) { - this.fontSize = fontSize - this.texts.forEach((text) => { - text.set({ fontSize }) - }) - - this.getObjects().forEach((obj) => { - if (obj.type[0] === 'Q') { - obj.setFontSize(fontSize) - } - }) - - this.canvas.add() - } - - addLengthText() { - if (this.texts.length > 0) { - this.texts.forEach((text) => { - this.canvas.remove(text) - }) - this.texts = [] - } - const points = this.points - - points.forEach((start, i) => { - const end = points[(i + 1) % points.length] - const dx = end.x - start.x - const dy = end.y - start.y - const length = Math.sqrt(dx * dx + dy * dy) - - const midPoint = new fabric.Point((start.x + end.x) / 2, (start.y + end.y) / 2) - - // Create new text object if it doesn't exist - const text = new fabric.Text(length.toFixed(0), { - left: midPoint.x, - top: midPoint.y, - fontSize: this.fontSize, - selectable: false, - }) - - this.texts.push(text) - this.canvas.add(text) - }) - - this.canvas.renderAll() - } - - updateLengthText() { - const points = this.getCurrentPoints() - - points.forEach((start, i) => { - const end = points[(i + 1) % points.length] - const dx = end.x - start.x - const dy = end.y - start.y - const length = Math.sqrt(dx * dx + dy * dy) - - // Update the text object with the new length - this.texts[i].set({ text: length.toFixed(0) }) - }) - - this.canvas.renderAll() - } - - fillCell(cell = { width: 50, height: 100, padding: 10 }) { - const points = this.getCurrentPoints() - let bounds - - try { - bounds = fabric.util.makeBoundingBoxFromPoints(points) - } catch (error) { - alert('다각형의 꼭지점이 4개 이상이어야 합니다.') - return - } - - for (let x = bounds.left; x < bounds.left + bounds.width; x += cell.width + cell.padding) { - for (let y = bounds.top; y < bounds.top + bounds.height; y += cell.height + cell.padding) { - const rect = new fabric.Rect({ - left: x, - top: y, - width: cell.width, - height: cell.height, - fill: 'transparent', - stroke: 'black', - selectable: false, - }) - - const rectPoints = [ - new fabric.Point(rect.left, rect.top), - new fabric.Point(rect.left + rect.width, rect.top), - new fabric.Point(rect.left, rect.top + rect.height), - new fabric.Point(rect.left + rect.width, rect.top + rect.height), - ] - - const isInside = rectPoints.every((rectPoint) => this.inPolygon(rectPoint) && this.distanceFromEdge(rectPoint) >= cell.padding) - - if (isInside) { - this.canvas.add(rect) - } - } - } - - this.canvas.renderAll() - } - - /** - * this.lines의 direction이 top 인 line의 모든 합이 bottom 인 line의 모든 합과 같은지 확인 - * this.lines의 direction이 left 인 line의 모든 합이 right 인 line의 모든 합과 같은지 확인 - * return {boolean} - */ - isValid() { - const leftLinesLengthSum = this.lines.filter((line) => line.direction === 'left').reduce((sum, line) => sum + line.length, 0) - const rightLinesLengthSum = this.lines.filter((line) => line.direction === 'right').reduce((sum, line) => sum + line.length, 0) - - const topLinesLengthSum = this.lines.filter((line) => line.direction === 'top').reduce((sum, line) => sum + line.length, 0) - const bottomLinesLengthSum = this.lines.filter((line) => line.direction === 'bottom').reduce((sum, line) => sum + line.length, 0) - - return leftLinesLengthSum === rightLinesLengthSum && topLinesLengthSum === bottomLinesLengthSum - } - - inPolygon(point) { - const vertices = this.getCurrentPoints() - let intersects = 0 - - for (let i = 0; i < vertices.length; i++) { - let vertex1 = vertices[i] - let vertex2 = vertices[(i + 1) % vertices.length] - - if (vertex1.y > vertex2.y) { - let tmp = vertex1 - vertex1 = vertex2 - vertex2 = tmp - } - - if (point.y === vertex1.y || point.y === vertex2.y) { - point.y += 0.01 - } - - if (point.y <= vertex1.y || point.y > vertex2.y) { - continue - } - - let xInt = ((point.y - vertex1.y) * (vertex2.x - vertex1.x)) / (vertex2.y - vertex1.y) + vertex1.x - if (xInt < point.x) { - intersects++ - } - } - - return intersects % 2 === 1 - } - - distanceFromEdge(point) { - const vertices = this.getCurrentPoints() - let minDistance = Infinity - - for (let i = 0; i < vertices.length; i++) { - let vertex1 = vertices[i] - let vertex2 = vertices[(i + 1) % vertices.length] - - const dx = vertex2.x - vertex1.x - const dy = vertex2.y - vertex1.y - - const t = ((point.x - vertex1.x) * dx + (point.y - vertex1.y) * dy) / (dx * dx + dy * dy) - - let closestPoint - if (t < 0) { - closestPoint = vertex1 - } else if (t > 1) { - closestPoint = vertex2 - } else { - closestPoint = new fabric.Point(vertex1.x + t * dx, vertex1.y + t * dy) - } - - const distance = distanceBetweenPoints(point, closestPoint) - if (distance < minDistance) { - minDistance = distance - } - } - - return minDistance - } - - setViewLengthText(boolean) { - this.texts.forEach((text) => { - text.visible = boolean - }) - - this.canvas.renderAll() - } - - getCurrentPoints() { - const scaleX = this.scaleX - const scaleY = this.scaleY - - const left = this.left - const top = this.top - - // 시작점 - const point = this.points[0] - - const movingX = left - point.x * scaleX - const movingY = top - point.y * scaleY - - return this.points.map((point) => { - return { - x: point.x * scaleX + movingX, - y: point.y * scaleY + movingY, - } - }) - } - - fillBackground(pattern) { - this.polygon.set({ fill: pattern }) - this.canvas.requestRenderAll() - } - - // 보조선 그리기 - drawHelpLine(chon = 4) { - drawHelpLineInHexagon(this, chon) - /*if (!this.isValid()) { - return - }*/ - - /*if (this.lines.length === 4) { - this.drawHelpLineInRect(chon) - } else if (this.lines.length === 6 || this.lines.length === 8) { - // TODO : 6각형 - drawHelpLineInHexagon2(this, chon) - } /!* else if (this.lines.length === 8) { - // TODO : 8각형 - 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) {} - - getObject() { - return this - } - sou - - toObject(propertiesToInclude) { - return fabric.util.object.extend(this.callSuper('toObject'), { - points: this.points, - fontSize: this.fontSize, - name: this.name, - shape: this.shape, - texts: this.texts, - lines: this.lines, - wall: this.wall, - initPoints: this.initPoints, - initOption: this.initOption, - objects: this.getObjects().map((obj) => obj.toObject(propertiesToInclude)), - pattern: this.pattern, - }) - } - - _set(key, value) { - this.callSuper('_set', key, value) - } -} diff --git a/src/hooks/useCanvas.js b/src/hooks/useCanvas.js index dee2983b..5d63c758 100644 --- a/src/hooks/useCanvas.js +++ b/src/hooks/useCanvas.js @@ -42,18 +42,18 @@ export function useCanvas(id) { useEffect(() => { canvas ?.getObjects() - .filter((obj) => obj.type === 'textbox' || obj.type === 'text' || obj.type === 'i-text') + ?.filter((obj) => obj.type === 'textbox' || obj.type === 'text' || obj.type === 'i-text') .forEach((obj) => { obj.set({ fontSize: fontSize }) }) canvas ?.getObjects() - .filter((obj) => obj.type === 'QLine' || obj.type === 'QPolygon' || obj.type === 'QRect') + ?.filter((obj) => obj.type === 'QLine' || obj.type === 'QPolygon' || obj.type === 'QRect') .forEach((obj) => { obj.setFontSize(fontSize) }) - canvas?.renderAll() + canvas?.getObjects().length > 0 && canvas?.renderAll() }, [fontSize]) /** @@ -103,7 +103,7 @@ export function useCanvas(id) { } const initialize = () => { - canvas?.clear() + canvas.getObjects().length > 0 && canvas?.clear() // settings for all canvas in the app fabric.Object.prototype.transparentCorners = false fabric.Object.prototype.cornerColor = '#2BEBC8' diff --git a/src/hooks/useMode.js b/src/hooks/useMode.js index d1faa991..96fc3516 100644 --- a/src/hooks/useMode.js +++ b/src/hooks/useMode.js @@ -3,7 +3,16 @@ import QRect from '@/components/fabric/QRect' 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, + roofPolygonArrayState, + roofPolygonPatternArrayState, + roofState, + sortedPolygonArray, + templateTypeState, + wallState, +} from '@/store/canvasAtom' import { QLine } from '@/components/fabric/QLine' import { fabric } from 'fabric' import { QPolygon } from '@/components/fabric/QPolygon' @@ -17,6 +26,8 @@ export const Mode = { TEXTBOX: 'textbox', DRAW_RECT: 'drawRect', ROOF_PATTERN: 'roofPattern', + MODULE: 'module', + ROOT_TRESTLE: 'rootTrestle', DEFAULT: 'default', } @@ -39,6 +50,8 @@ export function useMode() { const pointCount = useRef(0) const [roofPolygonPattern, setRoofPolygonPattern] = useRecoilState(roofPolygonPatternArrayState) + const [roofPolygonArray, setRoofPolygonArray] = useRecoilState(roofPolygonArrayState) + const [templateType, setTemplateType] = useRecoilState(templateTypeState) const [canvasSize] = useRecoilState(canvasSizeState) @@ -225,6 +238,9 @@ export function useMode() { case 'roofPattern': makeRoofPatternPolygon() break + case 'rootTrestle': + makeRoofTrestle() + break } } @@ -1013,9 +1029,7 @@ export function useMode() { /** *벽 지붕 외곽선 생성 */ - const handleOuterlinesTest = (offsetInputX, offsetInputY = 0) => { - const polygon = drawWallPolygon() - + const handleOuterlinesTest = (polygon, offsetInputX, offsetInputY = 0) => { let offsetPoints = [] const originalMax = 71 const transformedMax = 100 @@ -1083,7 +1097,7 @@ export function useMode() { offsetPoints.push(offsetPoint) } - makePolygon(offsetPoints) + return makePolygon(offsetPoints) } /** @@ -1501,6 +1515,7 @@ export function useMode() { } else if (polygon.lines.length === 8) { handleOuterLineTemplateA8Points(polygon) } + setTemplateType(2) } const handleOuterLineTemplateA4Points = (polygon) => { @@ -1622,15 +1637,15 @@ export function useMode() { const dashedCenterLineOpt = { stroke: 'black', - strokeWidth: 4, + strokeWidth: 1, property: 'centerLine', - strokeDashArray: [5, 5], + strokeDashArray: [10, 5], fontSize: 14, } const centerLineOpt = { stroke: 'blue', - strokeWidth: 5, + strokeWidth: 1, property: 'bigHoriCenter', fontSize: 14, } @@ -1642,7 +1657,7 @@ export function useMode() { const line = new QLine([start.x, start.y, end.x, end.y], { stroke: '#A0D468', - strokeWidth: 5, + strokeWidth: 2, property: 'normal', fontSize: 14, }) @@ -2944,6 +2959,8 @@ export function useMode() { console.log('6각형') handleTemplateB(params) } + + setTemplateType(3) } /** @@ -3497,13 +3514,34 @@ export function useMode() { fontSize: 15, // fontSize는 필요에 따라 조정 } + let polygonArray = [] + roofPolygonPattern.roofPatternPolygonArray.forEach((patternPolygon, index) => { const drawPolygon = new QPolygon(patternPolygon, commonOption) - drawPolygon.setViewLengthText(false) - drawPolygon.sendToBack() canvas.add(drawPolygon) + drawPolygon.setViewLengthText(false) + polygonArray.push(drawPolygon) }) canvas.renderAll() + + setRoofPolygonArray(polygonArray) + } + + const makeRoofTrestle = () => { + if (Object.keys(roofPolygonPattern).length === 0 && roofPolygonPattern.constructor === Object) { + alert('객체가 비어있습니다.') + return + } + + // 오목한 부분 인덱스 찾기 + const polygons = roofPolygonArray + let concavePolygonObj = [] + + polygons.forEach((polygon, index) => { + const trestlePolygon = handleOuterlinesTest(polygon, -12) + trestlePolygon.set('stroke', 'red').set('strokeDashArray', [9, 5]).set('strokeWidth', 0.3).setViewLengthText(false) + trestlePolygon.fillCell({ width: 100, height: 30, padding: 10 }) + }) } return { @@ -3518,6 +3556,7 @@ export function useMode() { handleOuterlinesTest, handleOuterlinesTest2, makeRoofPatternPolygon, + makeRoofTrestle, drawRoofPolygon, } } diff --git a/src/store/canvasAtom.js b/src/store/canvasAtom.js index a5195f83..c51a7061 100644 --- a/src/store/canvasAtom.js +++ b/src/store/canvasAtom.js @@ -42,6 +42,12 @@ export const roofPolygonPatternArrayState = atom({ dangerouslyAllowMutability: true, }) +export const roofPolygonArrayState = atom({ + key: 'roofPolygonArray', + default: [], + dangerouslyAllowMutability: true, +}) + export const templateTypeState = atom({ key: 'templateType', default: 1, //1:모임지붕, 2:A타입, 3:B타입 diff --git a/src/util/canvas-util.js b/src/util/canvas-util.js index 939c48f4..7374c024 100644 --- a/src/util/canvas-util.js +++ b/src/util/canvas-util.js @@ -430,6 +430,68 @@ export const sortedPoints = (points) => { }) } +export const sortedPointLessEightPoint = (points) => { + const copyPoints = [...points] + //points를 x,y좌표를 기준으로 정렬합니다. + copyPoints.sort((a, b) => { + if (a.x === b.x) { + return a.y - b.y + } + return a.x - b.x + }) + + const resultPoints = [copyPoints[0]] + let index = 1 + let currentPoint = { ...copyPoints[0] } + copyPoints.splice(0, 1) + while (index < points.length) { + if (index === points.length - 1) { + resultPoints.push(copyPoints[0]) + index++ + break + } else if (index % 2 === 0) { + // 짝수번째는 y값이 같은 점을 찾는다. + for (let i = 0; i < copyPoints.length; i++) { + // y값이 같은 point가 많은 경우 그 중 x값이 가장 큰걸 찾는다. + let temp = copyPoints.filter((point) => point.y === currentPoint.y) + if (temp.length === 0) { + // temp가 비어있을 경우 copyPoints에서 가장 가까운 점을 찾는다. + temp = Array.of(findClosestPointByY(currentPoint, copyPoints)) + } + // temp중 x값이 가장 가까운 값 + + const min = temp.reduce((prev, current) => (Math.abs(current.x - currentPoint.x) <= Math.abs(prev.x - currentPoint.x) ? current : prev)) + + resultPoints.push(min) + currentPoint = min + copyPoints.splice(copyPoints.indexOf(min), 1) + index++ + break + } + } else { + // 홀수번째는 x값이 같은 점을 찾는다. + for (let i = 0; i < copyPoints.length; i++) { + // x값이 같은 point가 많은 경우 그 중 y값이 가장 큰걸 찾는다. + let temp = copyPoints.filter((point) => point.x === currentPoint.x) + if (temp.length === 0) { + // temp가 비어있을 경우 copyPoints에서 가장 가까운 점을 찾는다. + + temp = Array.of(findClosestPointByX(currentPoint, copyPoints)) + } + // temp중 y값이 가장 가까운 값 + const min = temp.reduce((prev, current) => (Math.abs(current.y - currentPoint.y) <= Math.abs(prev.y - currentPoint.y) ? current : prev)) + + resultPoints.push(min) + currentPoint = min + copyPoints.splice(copyPoints.indexOf(min), 1) + index++ + break + } + } + } + return resultPoints +} + /** * point가 선 위에 있는지 확인 * @param line
Internal Server Error.
We are already working to solve the problem.
Something's missing.
+ Sorry, we can't find that page. You'll find lots to explore on the home page.{' '} +