splitPolygonWithLines usePolygon으로 수정
방향 index 제거
This commit is contained in:
parent
1cdd5432f5
commit
dcd364bca0
@ -159,6 +159,8 @@ export const SAVE_KEY = [
|
|||||||
'groupName',
|
'groupName',
|
||||||
'lineDirection',
|
'lineDirection',
|
||||||
'groupId',
|
'groupId',
|
||||||
|
'planeSize',
|
||||||
|
'actualSize',
|
||||||
]
|
]
|
||||||
|
|
||||||
export const OBJECT_PROTOTYPE = [fabric.Line.prototype, fabric.Polygon.prototype, fabric.Triangle.prototype]
|
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 { canvasState } from '@/store/canvasAtom'
|
||||||
import { useEffect, useState } from 'react'
|
import { useEffect, useState } from 'react'
|
||||||
import { setSurfaceShapePattern } from '@/util/canvas-util'
|
import { setSurfaceShapePattern } from '@/util/canvas-util'
|
||||||
import { splitPolygonWithLines } from '@/util/qpolygon-utils'
|
|
||||||
import { useSwal } from '@/hooks/useSwal'
|
import { useSwal } from '@/hooks/useSwal'
|
||||||
import { usePolygon } from '@/hooks/usePolygon'
|
import { usePolygon } from '@/hooks/usePolygon'
|
||||||
import { roofDisplaySelector } from '@/store/settingAtom'
|
import { roofDisplaySelector } from '@/store/settingAtom'
|
||||||
@ -13,7 +12,7 @@ import { POLYGON_TYPE } from '@/common/common'
|
|||||||
export function useRoofAllocationSetting(id) {
|
export function useRoofAllocationSetting(id) {
|
||||||
const canvas = useRecoilValue(canvasState)
|
const canvas = useRecoilValue(canvasState)
|
||||||
const roofDisplay = useRecoilValue(roofDisplaySelector)
|
const roofDisplay = useRecoilValue(roofDisplaySelector)
|
||||||
const { drawDirectionArrow } = usePolygon()
|
const { drawDirectionArrow, addLengthText, splitPolygonWithLines } = usePolygon()
|
||||||
const { closePopup } = usePopup()
|
const { closePopup } = usePopup()
|
||||||
|
|
||||||
const { swalFire } = useSwal()
|
const { swalFire } = useSwal()
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
import { useEffect, useState } from 'react'
|
import { useEffect, useState } from 'react'
|
||||||
import { useRecoilState, useRecoilValue } from 'recoil'
|
import { useRecoilState, useRecoilValue } from 'recoil'
|
||||||
import { v4 as uuidv4 } from 'uuid'
|
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 { QPolygon } from '@/components/fabric/QPolygon'
|
||||||
import { usePlan } from '@/hooks/usePlan'
|
import { usePlan } from '@/hooks/usePlan'
|
||||||
import { fontSelector } from '@/store/fontAtom'
|
import { fontSelector } from '@/store/fontAtom'
|
||||||
@ -12,8 +12,6 @@ export function useCanvasEvent() {
|
|||||||
const [canvasForEvent, setCanvasForEvent] = useState(null)
|
const [canvasForEvent, setCanvasForEvent] = useState(null)
|
||||||
const [currentObject, setCurrentObject] = useRecoilState(currentObjectState)
|
const [currentObject, setCurrentObject] = useRecoilState(currentObjectState)
|
||||||
const canvasSize = useRecoilValue(canvasSizeState)
|
const canvasSize = useRecoilValue(canvasSizeState)
|
||||||
const fontSize = useRecoilValue(fontSizeState)
|
|
||||||
const fontFamily = useRecoilValue(fontFamilyState)
|
|
||||||
const [canvasZoom, setCanvasZoom] = useRecoilState(canvasZoomState)
|
const [canvasZoom, setCanvasZoom] = useRecoilState(canvasZoomState)
|
||||||
const lengthTextOption = useRecoilValue(fontSelector('lengthText'))
|
const lengthTextOption = useRecoilValue(fontSelector('lengthText'))
|
||||||
const { modifiedPlanFlag, setModifiedPlanFlag } = usePlan()
|
const { modifiedPlanFlag, setModifiedPlanFlag } = usePlan()
|
||||||
@ -211,7 +209,7 @@ export function useCanvasEvent() {
|
|||||||
setCurrentObject(target)
|
setCurrentObject(target)
|
||||||
const { selected } = e
|
const { selected } = e
|
||||||
|
|
||||||
if (selected.length > 0) {
|
if (selected?.length > 0) {
|
||||||
selected.forEach((obj) => {
|
selected.forEach((obj) => {
|
||||||
if (obj.type === 'QPolygon') {
|
if (obj.type === 'QPolygon') {
|
||||||
obj.set({ stroke: 'red' })
|
obj.set({ stroke: 'red' })
|
||||||
@ -224,7 +222,7 @@ export function useCanvasEvent() {
|
|||||||
setCurrentObject(null)
|
setCurrentObject(null)
|
||||||
const { deselected } = e
|
const { deselected } = e
|
||||||
|
|
||||||
if (deselected.length > 0) {
|
if (deselected?.length > 0) {
|
||||||
deselected.forEach((obj) => {
|
deselected.forEach((obj) => {
|
||||||
if (obj.type === 'QPolygon') {
|
if (obj.type === 'QPolygon') {
|
||||||
obj.set({ stroke: 'black' })
|
obj.set({ stroke: 'black' })
|
||||||
@ -238,7 +236,7 @@ export function useCanvasEvent() {
|
|||||||
setCurrentObject(target)
|
setCurrentObject(target)
|
||||||
const { selected, deselected } = e
|
const { selected, deselected } = e
|
||||||
|
|
||||||
if (deselected.length > 0) {
|
if (deselected?.length > 0) {
|
||||||
deselected.forEach((obj) => {
|
deselected.forEach((obj) => {
|
||||||
if (obj.type === 'QPolygon') {
|
if (obj.type === 'QPolygon') {
|
||||||
obj.set({ stroke: 'black' })
|
obj.set({ stroke: 'black' })
|
||||||
@ -246,7 +244,7 @@ export function useCanvasEvent() {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
if (selected.length > 0) {
|
if (selected?.length > 0) {
|
||||||
selected.forEach((obj) => {
|
selected.forEach((obj) => {
|
||||||
if (obj.type === 'QPolygon') {
|
if (obj.type === 'QPolygon') {
|
||||||
obj.set({ stroke: 'red' })
|
obj.set({ stroke: 'red' })
|
||||||
|
|||||||
@ -1,11 +1,13 @@
|
|||||||
import { ANGLE_TYPE, canvasState, currentAngleTypeSelector, fontFamilyState, fontSizeState, pitchTextSelector } from '@/store/canvasAtom'
|
import { ANGLE_TYPE, canvasState, currentAngleTypeSelector, fontFamilyState, fontSizeState, pitchTextSelector } from '@/store/canvasAtom'
|
||||||
import { useRecoilValue } from 'recoil'
|
import { useRecoilValue } from 'recoil'
|
||||||
import { fabric } from 'fabric'
|
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 { QPolygon } from '@/components/fabric/QPolygon'
|
||||||
import { isSamePoint } from '@/util/qpolygon-utils'
|
import { isSamePoint, removeDuplicatePolygons } from '@/util/qpolygon-utils'
|
||||||
import { flowDisplaySelector } from '@/store/settingAtom'
|
import { flowDisplaySelector } from '@/store/settingAtom'
|
||||||
import { fontSelector } from '@/store/fontAtom'
|
import { fontSelector } from '@/store/fontAtom'
|
||||||
|
import { QLine } from '@/components/fabric/QLine'
|
||||||
|
import { POLYGON_TYPE } from '@/common/common'
|
||||||
|
|
||||||
export const usePolygon = () => {
|
export const usePolygon = () => {
|
||||||
const canvas = useRecoilValue(canvasState)
|
const canvas = useRecoilValue(canvasState)
|
||||||
@ -25,6 +27,7 @@ export const usePolygon = () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
canvas?.add(polygon)
|
canvas?.add(polygon)
|
||||||
|
addLengthText(polygon)
|
||||||
|
|
||||||
return polygon
|
return polygon
|
||||||
}
|
}
|
||||||
@ -40,7 +43,64 @@ export const usePolygon = () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const addLengthText = (polygon) => {
|
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) => {
|
points.forEach((start, i) => {
|
||||||
const end = points[(i + 1) % points.length]
|
const end = points[(i + 1) % points.length]
|
||||||
const dx = end.x - start.x
|
const dx = end.x - start.x
|
||||||
@ -71,12 +131,12 @@ export const usePolygon = () => {
|
|||||||
lockScalingY: true,
|
lockScalingY: true,
|
||||||
idx: i,
|
idx: i,
|
||||||
name: 'lengthText',
|
name: 'lengthText',
|
||||||
parent: this,
|
parent: polygon,
|
||||||
})
|
})
|
||||||
|
|
||||||
// this.texts.push(text)
|
// this.texts.push(text)
|
||||||
canvas.add(text)
|
canvas.add(text)
|
||||||
})
|
})*/
|
||||||
canvas.renderAll()
|
canvas.renderAll()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -409,7 +469,8 @@ export const usePolygon = () => {
|
|||||||
|
|
||||||
const addTextByArrows = (arrows, txt, canvas) => {
|
const addTextByArrows = (arrows, txt, canvas) => {
|
||||||
arrows.forEach((arrow, index) => {
|
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}`, {
|
const text = new fabric.Text(`${textStr}`, {
|
||||||
fontSize: flowFontOptions.fontSize.value,
|
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 {
|
return {
|
||||||
addPolygon,
|
addPolygon,
|
||||||
addPolygonByLines,
|
addPolygonByLines,
|
||||||
removePolygon,
|
removePolygon,
|
||||||
drawDirectionArrow,
|
drawDirectionArrow,
|
||||||
|
addLengthText,
|
||||||
|
splitPolygonWithLines,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1177,246 +1177,6 @@ export default function offsetPolygon(vertices, offset) {
|
|||||||
polygon.canvas.renderAll()
|
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) {
|
function normalizePoint(point) {
|
||||||
return {
|
return {
|
||||||
@ -1434,7 +1194,7 @@ function arePolygonsEqual(polygon1, polygon2) {
|
|||||||
return normalizedPolygon1.every((point, index) => arePointsEqual(point, normalizedPolygon2[index]))
|
return normalizedPolygon1.every((point, index) => arePointsEqual(point, normalizedPolygon2[index]))
|
||||||
}
|
}
|
||||||
|
|
||||||
function removeDuplicatePolygons(polygons) {
|
export function removeDuplicatePolygons(polygons) {
|
||||||
const uniquePolygons = []
|
const uniquePolygons = []
|
||||||
|
|
||||||
polygons.forEach((polygon) => {
|
polygons.forEach((polygon) => {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user