diff --git a/src/common/common.js b/src/common/common.js index cf60295b..d0016af1 100644 --- a/src/common/common.js +++ b/src/common/common.js @@ -159,6 +159,8 @@ export const SAVE_KEY = [ 'groupName', 'lineDirection', 'groupId', + 'planeSize', + 'actualSize', ] export const OBJECT_PROTOTYPE = [fabric.Line.prototype, fabric.Polygon.prototype, fabric.Triangle.prototype] diff --git a/src/components/fabric/QPolygon.js b/src/components/fabric/QPolygon.js index 873d2c6a..0fb9910c 100644 --- a/src/components/fabric/QPolygon.js +++ b/src/components/fabric/QPolygon.js @@ -138,7 +138,8 @@ export const QPolygon = fabric.util.createClass(fabric.Polygon, { }) this.on('removed', () => { - const children = getAllRelatedObjects(this.id, this.canvas) + // const children = getAllRelatedObjects(this.id, this.canvas) + const children = this.canvas.getObjects().filter((obj) => obj.parentId === this.id && obj.name === 'lengthText') children.forEach((child) => { this.canvas.remove(child) }) diff --git a/src/hooks/roofcover/useAuxiliaryDrawing.js b/src/hooks/roofcover/useAuxiliaryDrawing.js index e9aa7d93..6e95e79c 100644 --- a/src/hooks/roofcover/useAuxiliaryDrawing.js +++ b/src/hooks/roofcover/useAuxiliaryDrawing.js @@ -815,7 +815,7 @@ export function useAuxiliaryDrawing(id) { roofBase.lines.some((line) => isPointOnLine(line, { x: line.x2, y: line.y2 })) if (inPolygon1 && inPolygon2) { - line.attributes = { ...line.attributes, roofId: roofBase.id } + line.attributes = { ...line.attributes, roofId: roofBase.id, actualSize: 0, planeSize: line.getLength() } return true } }) diff --git a/src/hooks/roofcover/useRoofAllocationSetting.js b/src/hooks/roofcover/useRoofAllocationSetting.js index c229549e..921e737a 100644 --- a/src/hooks/roofcover/useRoofAllocationSetting.js +++ b/src/hooks/roofcover/useRoofAllocationSetting.js @@ -2,7 +2,6 @@ import { useRecoilValue } from 'recoil' import { canvasState } from '@/store/canvasAtom' import { useEffect, useState } from 'react' import { setSurfaceShapePattern } from '@/util/canvas-util' -import { splitPolygonWithLines } from '@/util/qpolygon-utils' import { useSwal } from '@/hooks/useSwal' import { usePolygon } from '@/hooks/usePolygon' import { roofDisplaySelector } from '@/store/settingAtom' @@ -13,7 +12,7 @@ import { POLYGON_TYPE } from '@/common/common' export function useRoofAllocationSetting(id) { const canvas = useRecoilValue(canvasState) const roofDisplay = useRecoilValue(roofDisplaySelector) - const { drawDirectionArrow } = usePolygon() + const { drawDirectionArrow, addLengthText, splitPolygonWithLines } = usePolygon() const { closePopup } = usePopup() const { swalFire } = useSwal() diff --git a/src/hooks/useCanvasEvent.js b/src/hooks/useCanvasEvent.js index 9b25eedd..42266c8a 100644 --- a/src/hooks/useCanvasEvent.js +++ b/src/hooks/useCanvasEvent.js @@ -1,7 +1,7 @@ import { useEffect, useState } from 'react' import { useRecoilState, useRecoilValue } from 'recoil' import { v4 as uuidv4 } from 'uuid' -import { canvasSizeState, canvasState, canvasZoomState, currentObjectState, fontFamilyState, fontSizeState } from '@/store/canvasAtom' +import { canvasSizeState, canvasState, canvasZoomState, currentObjectState } from '@/store/canvasAtom' import { QPolygon } from '@/components/fabric/QPolygon' import { usePlan } from '@/hooks/usePlan' import { fontSelector } from '@/store/fontAtom' @@ -12,8 +12,6 @@ export function useCanvasEvent() { const [canvasForEvent, setCanvasForEvent] = useState(null) const [currentObject, setCurrentObject] = useRecoilState(currentObjectState) const canvasSize = useRecoilValue(canvasSizeState) - const fontSize = useRecoilValue(fontSizeState) - const fontFamily = useRecoilValue(fontFamilyState) const [canvasZoom, setCanvasZoom] = useRecoilState(canvasZoomState) const lengthTextOption = useRecoilValue(fontSelector('lengthText')) const { modifiedPlanFlag, setModifiedPlanFlag } = usePlan() @@ -211,7 +209,7 @@ export function useCanvasEvent() { setCurrentObject(target) const { selected } = e - if (selected.length > 0) { + if (selected?.length > 0) { selected.forEach((obj) => { if (obj.type === 'QPolygon') { obj.set({ stroke: 'red' }) @@ -224,7 +222,7 @@ export function useCanvasEvent() { setCurrentObject(null) const { deselected } = e - if (deselected.length > 0) { + if (deselected?.length > 0) { deselected.forEach((obj) => { if (obj.type === 'QPolygon') { obj.set({ stroke: 'black' }) @@ -238,7 +236,7 @@ export function useCanvasEvent() { setCurrentObject(target) const { selected, deselected } = e - if (deselected.length > 0) { + if (deselected?.length > 0) { deselected.forEach((obj) => { if (obj.type === 'QPolygon') { obj.set({ stroke: 'black' }) @@ -246,7 +244,7 @@ export function useCanvasEvent() { }) } - if (selected.length > 0) { + if (selected?.length > 0) { selected.forEach((obj) => { if (obj.type === 'QPolygon') { obj.set({ stroke: 'red' }) diff --git a/src/hooks/usePolygon.js b/src/hooks/usePolygon.js index 5a7d3062..9ea8b3b7 100644 --- a/src/hooks/usePolygon.js +++ b/src/hooks/usePolygon.js @@ -1,11 +1,13 @@ import { ANGLE_TYPE, canvasState, currentAngleTypeSelector, fontFamilyState, fontSizeState, pitchTextSelector } from '@/store/canvasAtom' import { useRecoilValue } from 'recoil' import { fabric } from 'fabric' -import { getDegreeByChon, getDirectionByPoint } from '@/util/canvas-util' +import { getDegreeByChon, getDirectionByPoint, isPointOnLine } from '@/util/canvas-util' import { QPolygon } from '@/components/fabric/QPolygon' -import { isSamePoint } from '@/util/qpolygon-utils' +import { isSamePoint, removeDuplicatePolygons } from '@/util/qpolygon-utils' import { flowDisplaySelector } from '@/store/settingAtom' import { fontSelector } from '@/store/fontAtom' +import { QLine } from '@/components/fabric/QLine' +import { POLYGON_TYPE } from '@/common/common' export const usePolygon = () => { const canvas = useRecoilValue(canvasState) @@ -25,6 +27,7 @@ export const usePolygon = () => { }) canvas?.add(polygon) + addLengthText(polygon) return polygon } @@ -40,7 +43,64 @@ export const usePolygon = () => { } const addLengthText = (polygon) => { - const points = polygon.get('points') + const lengthTexts = canvas.getObjects().filter((obj) => obj.name === 'lengthText' && obj.parentId === polygon.id) + lengthTexts.forEach((text) => { + canvas.remove(text) + }) + const lines = polygon.lines + + lines.forEach((line, i) => { + const length = line.getLength() + const { planeSize, actualSize } = line.attributes + const scaleX = line.scaleX + const scaleY = line.scaleY + const x1 = line.left + const y1 = line.top + const x2 = line.left + line.width * scaleX + const y2 = line.top + line.height * scaleY + + let left, top + + if (line.direction === 'left' || line.direction === 'right') { + left = (x1 + x2) / 2 + top = (y1 + y2) / 2 + 10 + } else if (line.direction === 'top' || line.direction === 'bottom') { + left = (x1 + x2) / 2 + 10 + top = (y1 + y2) / 2 + } + + const minX = line.left + const maxX = line.left + line.width + const minY = line.top + const maxY = line.top + line.length + const degree = (Math.atan2(y2 - y1, x2 - x1) * 180) / Math.PI + + const text = new fabric.Textbox(actualSize ? actualSize.toString() : planeSize ? planeSize.toString() : length.toString(), { + left: left, + top: top, + fontSize: lengthTextFontOptions.fontSize.value, + minX, + maxX, + minY, + maxY, + parentDirection: line.direction, + parentDegree: degree, + parentId: polygon.id, + planeSize, + actualSize, + editable: false, + selectable: true, + lockRotation: true, + lockScalingX: true, + lockScalingY: true, + parent: polygon, + name: 'lengthText', + }) + + canvas.add(text) + }) + + /*const points = polygon.get('points') points.forEach((start, i) => { const end = points[(i + 1) % points.length] const dx = end.x - start.x @@ -71,12 +131,12 @@ export const usePolygon = () => { lockScalingY: true, idx: i, name: 'lengthText', - parent: this, + parent: polygon, }) // this.texts.push(text) canvas.add(text) - }) + })*/ canvas.renderAll() } @@ -409,7 +469,8 @@ export const usePolygon = () => { const addTextByArrows = (arrows, txt, canvas) => { arrows.forEach((arrow, index) => { - const textStr = `${txt}${index + 1} (${currentAngleType === ANGLE_TYPE.SLOPE ? arrow.pitch : getDegreeByChon(arrow.pitch)}${pitchText})` + // const textStr = `${txt}${index + 1} (${currentAngleType === ANGLE_TYPE.SLOPE ? arrow.pitch : getDegreeByChon(arrow.pitch)}${pitchText})` + const textStr = `${txt} (${currentAngleType === ANGLE_TYPE.SLOPE ? arrow.pitch : getDegreeByChon(arrow.pitch)}${pitchText})` const text = new fabric.Text(`${textStr}`, { fontSize: flowFontOptions.fontSize.value, @@ -432,10 +493,272 @@ export const usePolygon = () => { }) } + const splitPolygonWithLines = (polygon) => { + polygon.set({ visible: false }) + let innerLines = [...polygon.innerLines] + let polygonLines = [...polygon.lines] + const roofs = [] + + let delIndexs = [] + let newLines = [] + + polygonLines.forEach((line, index) => { + line.tempIndex = index + innerLines.forEach((innerLine) => { + let newLine1, newLine2 + if (isPointOnLine(line, innerLine.startPoint)) { + // 해당 line을 startPoint로 나눈 line2개를 canvas에 추가 하고 기존 line을 제거한다. + newLine1 = new QLine([line.x1, line.y1, innerLine.startPoint.x, innerLine.startPoint.y], { + fontSize: polygon.fontSize, + stroke: 'black', + strokeWidth: 3, + }) + + newLine2 = new QLine([innerLine.startPoint.x, innerLine.startPoint.y, line.x2, line.y2], { + fontSize: polygon.fontSize, + stroke: 'black', + strokeWidth: 3, + }) + delIndexs.push(polygonLines.indexOf(line)) + canvas.remove(polygonLines[polygonLines.indexOf(line)]) + if (newLine1.length / 10 > 10) { + newLines.push(newLine1) + } + if (newLine2.length / 10 > 10) { + newLines.push(newLine2) + } + } + if (isPointOnLine(line, innerLine.endPoint)) { + newLine1 = new QLine([line.x1, line.y1, innerLine.endPoint.x, innerLine.endPoint.y], { + fontSize: polygon.fontSize, + stroke: 'black', + strokeWidth: 3, + }) + + newLine2 = new QLine([innerLine.endPoint.x, innerLine.endPoint.y, line.x2, line.y2], { + fontSize: polygon.fontSize, + stroke: 'black', + strokeWidth: 3, + }) + delIndexs.push(polygonLines.indexOf(line)) + canvas.remove(polygonLines[polygonLines.indexOf(line)]) + if (newLine1.length / 10 > 10) { + newLines.push(newLine1) + } + if (newLine2.length / 10 > 10) { + newLines.push(newLine2) + } + } + }) + }) + polygonLines = polygonLines.filter((line) => !delIndexs.includes(line.tempIndex)) + polygonLines = [...polygonLines, ...newLines] + + const allLines = [...polygonLines, ...innerLines] + + /** + * 왼쪽 상단을 startPoint로 전부 변경 + */ + allLines.forEach((line) => { + let startPoint // 시작점 + let endPoint // 끝점 + if (line.x1 < line.x2) { + startPoint = { x: line.x1, y: line.y1 } + endPoint = { x: line.x2, y: line.y2 } + } else if (line.x1 > line.x2) { + startPoint = { x: line.x2, y: line.y2 } + endPoint = { x: line.x1, y: line.y1 } + } else { + if (line.y1 < line.y2) { + startPoint = { x: line.x1, y: line.y1 } + endPoint = { x: line.x2, y: line.y2 } + } else { + startPoint = { x: line.x2, y: line.y2 } + endPoint = { x: line.x1, y: line.y1 } + } + } + + line.startPoint = startPoint + line.endPoint = endPoint + }) + + polygonLines.forEach((line) => { + const startPoint = line.startPoint // 시작점 + let arrivalPoint = line.endPoint // 도착점 + + let currentPoint = startPoint + const roofPoints = [startPoint] + + const startLine = line + const visitPoints = [startPoint] + const visitLines = [startLine] + let cnt = 0 + + while (!isSamePoint(currentPoint, arrivalPoint)) { + let nextLines = allLines.filter( + (line2) => + (isSamePoint(line2.startPoint, currentPoint) || isSamePoint(line2.endPoint, currentPoint)) && + line !== line2 && + innerLines.includes(line2) && + !visitLines.includes(line2), + ) + + if (nextLines.length === 0) { + nextLines = allLines.filter( + (line2) => + (isSamePoint(line2.startPoint, currentPoint) || isSamePoint(line2.endPoint, currentPoint)) && + line !== line2 && + !visitLines.includes(line2), + ) + } + + if (!nextLines) { + break + } + + let comparisonPoints = [] + + nextLines.forEach((nextLine) => { + if (isSamePoint(nextLine.startPoint, currentPoint)) { + comparisonPoints.push(nextLine.endPoint) + } else { + comparisonPoints.push(nextLine.startPoint) + } + }) + + comparisonPoints = comparisonPoints.filter((point) => !visitPoints.some((visitPoint) => isSamePoint(visitPoint, point))) + comparisonPoints = comparisonPoints.filter((point) => !isSamePoint(point, currentPoint)) + + const minDistancePoint = comparisonPoints.reduce((prev, current) => { + const prevDistance = Math.sqrt(Math.pow(prev.x - arrivalPoint.x, 2) + Math.pow(prev.y - arrivalPoint.y, 2)) + const currentDistance = Math.sqrt(Math.pow(current.x - arrivalPoint.x, 2) + Math.pow(current.y - arrivalPoint.y, 2)) + + return prevDistance < currentDistance ? prev : current + }, comparisonPoints[0]) + + nextLines.forEach((nextLine) => { + if (isSamePoint(nextLine.startPoint, minDistancePoint) || isSamePoint(nextLine.endPoint, minDistancePoint)) { + visitLines.push(nextLine) + } + }) + + currentPoint = { ...minDistancePoint } + roofPoints.push(currentPoint) + cnt++ + if (cnt > 100) { + throw new Error('무한루프') + } + } + roofs.push(roofPoints) + }) + + const newRoofs = removeDuplicatePolygons(roofs) + + newRoofs.forEach((roofPoint, index) => { + let defense, pitch + const polygonLines = [...polygon.lines] + + let representLines = [] + let representLine + + // 지붕을 그리면서 기존 polygon의 line중 연결된 line을 찾는다. + polygonLines.forEach((line) => { + let startFlag = false + let endFlag = false + const startPoint = line.startPoint + const endPoint = line.endPoint + roofPoint.forEach((point, index) => { + if (isSamePoint(point, startPoint)) { + startFlag = true + } + if (isSamePoint(point, endPoint)) { + endFlag = true + } + }) + + if (startFlag && endFlag) { + if (!representLines.includes(line)) { + representLines.push(line) + } + } + }) + + // representLines중 가장 긴 line을 찾는다. + representLines.forEach((line) => { + if (!representLine) { + representLine = line + } else { + if (representLine.length < line.length) { + representLine = line + } + } + }) + + const direction = newRoofs.length === 1 ? polygon.direction : representLine.direction + const polygonDirection = polygon.direction + + switch (direction) { + case 'top': + defense = 'east' + break + case 'right': + defense = 'south' + break + case 'bottom': + defense = 'west' + break + case 'left': + defense = 'north' + break + } + pitch = polygon.lines[index].attributes?.pitch ?? 0 + + const roof = new QPolygon(roofPoint, { + fontSize: polygon.fontSize, + stroke: 'black', + fill: 'transparent', + strokeWidth: 3, + name: POLYGON_TYPE.ROOF, + originX: 'center', + originY: 'center', + selectable: true, + defense: defense, + direction: newRoofs.length === 1 ? polygonDirection : defense, + pitch: pitch, + }) + + //allLines중 생성된 roof와 관련있는 line을 찾는다. + + roof.lines = [...polygon.lines, ...polygon.innerLines].filter((line) => { + let startFlag = false + let endFlag = false + const startPoint = line.startPoint + const endPoint = line.endPoint + roofPoint.forEach((point, index) => { + if (isSamePoint(point, startPoint)) { + startFlag = true + } + if (isSamePoint(point, endPoint)) { + endFlag = true + } + }) + + return startFlag && endFlag + }) + + canvas.add(roof) + addLengthText(roof) + canvas.remove(polygon) + canvas.renderAll() + }) + } + return { addPolygon, addPolygonByLines, removePolygon, drawDirectionArrow, + addLengthText, + splitPolygonWithLines, } } diff --git a/src/util/qpolygon-utils.js b/src/util/qpolygon-utils.js index d3f02ef8..d84330e8 100644 --- a/src/util/qpolygon-utils.js +++ b/src/util/qpolygon-utils.js @@ -1177,246 +1177,6 @@ export default function offsetPolygon(vertices, offset) { polygon.canvas.renderAll() }) }*/ -export const splitPolygonWithLines = (polygon) => { - const canvas = polygon.canvas - polygon.set({ visible: false }) - let innerLines = [...polygon.innerLines] - let polygonLines = [...polygon.lines] - const roofs = [] - - let delIndexs = [] - let newLines = [] - - polygonLines.forEach((line, index) => { - line.tempIndex = index - innerLines.forEach((innerLine) => { - let newLine1, newLine2 - if (isPointOnLine(line, innerLine.startPoint)) { - // 해당 line을 startPoint로 나눈 line2개를 canvas에 추가 하고 기존 line을 제거한다. - newLine1 = new QLine([line.x1, line.y1, innerLine.startPoint.x, innerLine.startPoint.y], { - fontSize: polygon.fontSize, - stroke: 'black', - strokeWidth: 3, - }) - - newLine2 = new QLine([innerLine.startPoint.x, innerLine.startPoint.y, line.x2, line.y2], { - fontSize: polygon.fontSize, - stroke: 'black', - strokeWidth: 3, - }) - delIndexs.push(polygonLines.indexOf(line)) - canvas.remove(polygonLines[polygonLines.indexOf(line)]) - if (newLine1.length / 10 > 10) { - newLines.push(newLine1) - } - if (newLine2.length / 10 > 10) { - newLines.push(newLine2) - } - } - if (isPointOnLine(line, innerLine.endPoint)) { - newLine1 = new QLine([line.x1, line.y1, innerLine.endPoint.x, innerLine.endPoint.y], { - fontSize: polygon.fontSize, - stroke: 'black', - strokeWidth: 3, - }) - - newLine2 = new QLine([innerLine.endPoint.x, innerLine.endPoint.y, line.x2, line.y2], { - fontSize: polygon.fontSize, - stroke: 'black', - strokeWidth: 3, - }) - delIndexs.push(polygonLines.indexOf(line)) - canvas.remove(polygonLines[polygonLines.indexOf(line)]) - if (newLine1.length / 10 > 10) { - newLines.push(newLine1) - } - if (newLine2.length / 10 > 10) { - newLines.push(newLine2) - } - } - }) - }) - polygonLines = polygonLines.filter((line) => !delIndexs.includes(line.tempIndex)) - polygonLines = [...polygonLines, ...newLines] - - const allLines = [...polygonLines, ...innerLines] - - /** - * 왼쪽 상단을 startPoint로 전부 변경 - */ - allLines.forEach((line) => { - let startPoint // 시작점 - let endPoint // 끝점 - if (line.x1 < line.x2) { - startPoint = { x: line.x1, y: line.y1 } - endPoint = { x: line.x2, y: line.y2 } - } else if (line.x1 > line.x2) { - startPoint = { x: line.x2, y: line.y2 } - endPoint = { x: line.x1, y: line.y1 } - } else { - if (line.y1 < line.y2) { - startPoint = { x: line.x1, y: line.y1 } - endPoint = { x: line.x2, y: line.y2 } - } else { - startPoint = { x: line.x2, y: line.y2 } - endPoint = { x: line.x1, y: line.y1 } - } - } - - line.startPoint = startPoint - line.endPoint = endPoint - }) - - polygonLines.forEach((line) => { - const startPoint = line.startPoint // 시작점 - let arrivalPoint = line.endPoint // 도착점 - - let currentPoint = startPoint - const roofPoints = [startPoint] - - const startLine = line - const visitPoints = [startPoint] - const visitLines = [startLine] - let cnt = 0 - - while (!isSamePoint(currentPoint, arrivalPoint)) { - line.set({ stroke: 'red' }) - canvas.renderAll() - let nextLines = allLines.filter( - (line2) => - (isSamePoint(line2.startPoint, currentPoint) || isSamePoint(line2.endPoint, currentPoint)) && - line !== line2 && - innerLines.includes(line2) && - !visitLines.includes(line2), - ) - - if (nextLines.length === 0) { - nextLines = allLines.filter( - (line2) => - (isSamePoint(line2.startPoint, currentPoint) || isSamePoint(line2.endPoint, currentPoint)) && - line !== line2 && - !visitLines.includes(line2), - ) - } - - if (!nextLines) { - break - } - - let comparisonPoints = [] - - nextLines.forEach((nextLine) => { - if (isSamePoint(nextLine.startPoint, currentPoint)) { - comparisonPoints.push(nextLine.endPoint) - } else { - comparisonPoints.push(nextLine.startPoint) - } - }) - - comparisonPoints = comparisonPoints.filter((point) => !visitPoints.some((visitPoint) => isSamePoint(visitPoint, point))) - comparisonPoints = comparisonPoints.filter((point) => !isSamePoint(point, currentPoint)) - - const minDistancePoint = comparisonPoints.reduce((prev, current) => { - const prevDistance = Math.sqrt(Math.pow(prev.x - arrivalPoint.x, 2) + Math.pow(prev.y - arrivalPoint.y, 2)) - const currentDistance = Math.sqrt(Math.pow(current.x - arrivalPoint.x, 2) + Math.pow(current.y - arrivalPoint.y, 2)) - - return prevDistance < currentDistance ? prev : current - }, comparisonPoints[0]) - - nextLines.forEach((nextLine) => { - if (isSamePoint(nextLine.startPoint, minDistancePoint) || isSamePoint(nextLine.endPoint, minDistancePoint)) { - visitLines.push(nextLine) - } - }) - - currentPoint = { ...minDistancePoint } - roofPoints.push(currentPoint) - cnt++ - if (cnt > 100) { - throw new Error('무한루프') - } - } - roofs.push(roofPoints) - }) - - const newRoofs = removeDuplicatePolygons(roofs) - - newRoofs.forEach((roofPoint, index) => { - let defense, pitch - const polygonLines = [...polygon.lines] - - let representLines = [] - let representLine - - // 지붕을 그리면서 기존 polygon의 line중 연결된 line을 찾는다. - polygonLines.forEach((line) => { - let startFlag = false - let endFlag = false - const startPoint = line.startPoint - const endPoint = line.endPoint - roofPoint.forEach((point, index) => { - if (isSamePoint(point, startPoint)) { - startFlag = true - } - if (isSamePoint(point, endPoint)) { - endFlag = true - } - }) - - if (startFlag && endFlag) { - representLines.push(line) - } - }) - - // representLines중 가장 긴 line을 찾는다. - representLines.forEach((line) => { - if (!representLine) { - representLine = line - } else { - if (representLine.length < line.length) { - representLine = line - } - } - }) - - const direction = newRoofs.length === 1 ? polygon.direction : representLine.direction - const polygonDirection = polygon.direction - - switch (direction) { - case 'top': - defense = 'east' - break - case 'right': - defense = 'south' - break - case 'bottom': - defense = 'west' - break - case 'left': - defense = 'north' - break - } - pitch = polygon.lines[index].attributes?.pitch ?? 0 - - const roof = new QPolygon(roofPoint, { - fontSize: polygon.fontSize, - stroke: 'black', - fill: 'transparent', - strokeWidth: 3, - name: POLYGON_TYPE.ROOF, - originX: 'center', - originY: 'center', - selectable: true, - defense: defense, - direction: newRoofs.length === 1 ? polygonDirection : defense, - pitch: pitch, - }) - - polygon.canvas.add(roof) - canvas.remove(polygon) - polygon.canvas.renderAll() - }) -} function normalizePoint(point) { return { @@ -1434,7 +1194,7 @@ function arePolygonsEqual(polygon1, polygon2) { return normalizedPolygon1.every((point, index) => arePointsEqual(point, normalizedPolygon2[index])) } -function removeDuplicatePolygons(polygons) { +export function removeDuplicatePolygons(polygons) { const uniquePolygons = [] polygons.forEach((polygon) => {