splitPolygonWithLines usePolygon으로 수정
방향 index 제거
This commit is contained in:
parent
1cdd5432f5
commit
dcd364bca0
@ -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]
|
||||
|
||||
@ -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()
|
||||
|
||||
@ -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' })
|
||||
|
||||
@ -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,
|
||||
}
|
||||
}
|
||||
|
||||
@ -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) => {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user