765 lines
23 KiB
JavaScript
765 lines
23 KiB
JavaScript
import { ANGLE_TYPE, canvasState, currentAngleTypeSelector, fontFamilyState, fontSizeState, pitchTextSelector } from '@/store/canvasAtom'
|
|
import { useRecoilValue } from 'recoil'
|
|
import { fabric } from 'fabric'
|
|
import { getDegreeByChon, getDirectionByPoint, isPointOnLine } from '@/util/canvas-util'
|
|
import { QPolygon } from '@/components/fabric/QPolygon'
|
|
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)
|
|
const isFlowDisplay = useRecoilValue(flowDisplaySelector)
|
|
const flowFontOptions = useRecoilValue(fontSelector('flowText'))
|
|
const lengthTextFontOptions = useRecoilValue(fontSelector('lengthText'))
|
|
const currentAngleType = useRecoilValue(currentAngleTypeSelector)
|
|
const pitchText = useRecoilValue(pitchTextSelector)
|
|
|
|
const addPolygon = (points, options) => {
|
|
const polygon = new QPolygon(points, {
|
|
...options,
|
|
fontSize: lengthTextFontOptions.fontSize.value,
|
|
fill: options.fill || 'transparent',
|
|
stroke: options.stroke || '#000000',
|
|
selectable: true,
|
|
})
|
|
|
|
canvas?.add(polygon)
|
|
addLengthText(polygon)
|
|
|
|
return polygon
|
|
}
|
|
|
|
const addPolygonByLines = (lines, options) => {
|
|
//lines의 idx를 정렬한다.
|
|
lines.sort((a, b) => a.idx - b.idx)
|
|
const points = createPolygonPointsFromOuterLines(lines)
|
|
|
|
return addPolygon(points, {
|
|
...options,
|
|
})
|
|
}
|
|
|
|
const addLengthText = (polygon) => {
|
|
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
|
|
const dy = end.y - start.y
|
|
const length = Number(Math.sqrt(dx * dx + dy * dy).toFixed(1)) * 10
|
|
|
|
const midPoint = new fabric.Point((start.x + end.x) / 2, (start.y + end.y) / 2)
|
|
|
|
const degree = (Math.atan2(dy, dx) * 180) / Math.PI
|
|
|
|
// Create new text object if it doesn't exist
|
|
const text = new fabric.Text(length.toString(), {
|
|
left: midPoint.x,
|
|
top: midPoint.y,
|
|
parentId: polygon.id,
|
|
fontSize: lengthTextFontOptions.fontSize.value,
|
|
minX: Math.min(start.x, end.x),
|
|
maxX: Math.max(start.x, end.x),
|
|
minY: Math.min(start.y, end.y),
|
|
maxY: Math.max(start.y, end.y),
|
|
parentDirection: getDirectionByPoint(start, end),
|
|
parentDegree: degree,
|
|
dirty: true,
|
|
editable: true,
|
|
selectable: true,
|
|
lockRotation: true,
|
|
lockScalingX: true,
|
|
lockScalingY: true,
|
|
idx: i,
|
|
name: 'lengthText',
|
|
parent: polygon,
|
|
})
|
|
|
|
// this.texts.push(text)
|
|
canvas.add(text)
|
|
})*/
|
|
canvas.renderAll()
|
|
}
|
|
|
|
const createPolygonPointsFromOuterLines = (outerLines) => {
|
|
if (!outerLines || outerLines.length === 0) {
|
|
return []
|
|
}
|
|
|
|
// Extract points from outerLines
|
|
|
|
return outerLines.map((line) => ({
|
|
x: line.x1,
|
|
y: line.y1,
|
|
}))
|
|
}
|
|
|
|
const removePolygon = (polygon) => {
|
|
const texts = canvas.getObjects().filter((obj) => obj.parentId === polygon.id)
|
|
texts.forEach((text) => {
|
|
canvas.remove(text)
|
|
})
|
|
|
|
canvas.remove(polygon)
|
|
canvas.renderAll()
|
|
}
|
|
|
|
/**
|
|
* poolygon의 방향에 따라 화살표를 추가한다.
|
|
* @param polygon
|
|
*/
|
|
const drawDirectionArrow = (polygon) => {
|
|
const direction = polygon.direction
|
|
if (!direction) {
|
|
return
|
|
}
|
|
|
|
//동일 아이디가 있으면 일단 지우고 다시 그린다
|
|
const existArrow = polygon.canvas.getObjects().filter((obj) => obj.name === 'arrow' && obj.parentId === polygon.id)
|
|
if (existArrow.length > 0) {
|
|
polygon.canvas.remove(...existArrow)
|
|
}
|
|
|
|
polygon.canvas
|
|
.getObjects()
|
|
.filter((obj) => obj.name === 'flowText' && obj.parent === polygon.arrow)
|
|
.forEach((obj) => polygon.canvas.remove(obj))
|
|
|
|
let arrow = null
|
|
let points = []
|
|
|
|
if (polygon.arrow) {
|
|
polygon.canvas.remove(polygon.arrow)
|
|
}
|
|
|
|
let centerPoint = { x: polygon.left, y: polygon.top }
|
|
let stickeyPoint
|
|
|
|
const polygonMaxX = Math.max(...polygon.getCurrentPoints().map((point) => point.x))
|
|
const polygonMinX = Math.min(...polygon.getCurrentPoints().map((point) => point.x))
|
|
const polygonMaxY = Math.max(...polygon.getCurrentPoints().map((point) => point.y))
|
|
const polygonMinY = Math.min(...polygon.getCurrentPoints().map((point) => point.y))
|
|
|
|
switch (direction) {
|
|
case 'north':
|
|
points = [
|
|
{ x: centerPoint.x, y: polygonMinY - 50 },
|
|
{ x: centerPoint.x + 20, y: polygonMinY - 50 },
|
|
{ x: centerPoint.x + 20, y: polygonMinY - 80 },
|
|
{ x: centerPoint.x + 50, y: polygonMinY - 80 },
|
|
{ x: centerPoint.x, y: polygonMinY - 110 },
|
|
{ x: centerPoint.x - 50, y: polygonMinY - 80 },
|
|
{ x: centerPoint.x - 20, y: polygonMinY - 80 },
|
|
{ x: centerPoint.x - 20, y: polygonMinY - 50 },
|
|
]
|
|
|
|
stickeyPoint = { x: centerPoint.x, y: polygonMinY - 110 }
|
|
break
|
|
case 'south':
|
|
points = [
|
|
{ x: centerPoint.x, y: polygonMaxY + 50 },
|
|
{ x: centerPoint.x + 20, y: polygonMaxY + 50 },
|
|
{ x: centerPoint.x + 20, y: polygonMaxY + 80 },
|
|
{ x: centerPoint.x + 50, y: polygonMaxY + 80 },
|
|
{ x: centerPoint.x, y: polygonMaxY + 110 },
|
|
{ x: centerPoint.x - 50, y: polygonMaxY + 80 },
|
|
{ x: centerPoint.x - 20, y: polygonMaxY + 80 },
|
|
{ x: centerPoint.x - 20, y: polygonMaxY + 50 },
|
|
]
|
|
stickeyPoint = { x: centerPoint.x, y: polygonMaxY + 110 }
|
|
break
|
|
case 'west':
|
|
points = [
|
|
{ x: polygonMinX - 50, y: centerPoint.y },
|
|
{ x: polygonMinX - 50, y: centerPoint.y + 20 },
|
|
{ x: polygonMinX - 80, y: centerPoint.y + 20 },
|
|
{ x: polygonMinX - 80, y: centerPoint.y + 50 },
|
|
{ x: polygonMinX - 110, y: centerPoint.y },
|
|
{ x: polygonMinX - 80, y: centerPoint.y - 50 },
|
|
{ x: polygonMinX - 80, y: centerPoint.y - 20 },
|
|
{ x: polygonMinX - 50, y: centerPoint.y - 20 },
|
|
]
|
|
|
|
stickeyPoint = { x: polygonMinX - 110, y: centerPoint.y }
|
|
break
|
|
case 'east':
|
|
points = [
|
|
{ x: polygonMaxX + 50, y: centerPoint.y },
|
|
{ x: polygonMaxX + 50, y: centerPoint.y + 20 },
|
|
{ x: polygonMaxX + 80, y: centerPoint.y + 20 },
|
|
{ x: polygonMaxX + 80, y: centerPoint.y + 50 },
|
|
{ x: polygonMaxX + 110, y: centerPoint.y },
|
|
{ x: polygonMaxX + 80, y: centerPoint.y - 50 },
|
|
{ x: polygonMaxX + 80, y: centerPoint.y - 20 },
|
|
{ x: polygonMaxX + 50, y: centerPoint.y - 20 },
|
|
]
|
|
|
|
stickeyPoint = { x: polygonMaxX + 110, y: centerPoint.y }
|
|
break
|
|
}
|
|
|
|
arrow = new QPolygon(points, {
|
|
selectable: false,
|
|
name: 'arrow',
|
|
fill: 'transparent',
|
|
stroke: 'black',
|
|
direction: direction,
|
|
parent: polygon,
|
|
stickeyPoint: stickeyPoint,
|
|
visible: isFlowDisplay,
|
|
pitch: polygon.pitch,
|
|
parentId: polygon.id,
|
|
})
|
|
|
|
arrow.setViewLengthText(false)
|
|
polygon.arrow = arrow
|
|
polygon.canvas.add(arrow)
|
|
polygon.canvas.renderAll()
|
|
drawDirectionStringToArrow(polygon.canvas, 0)
|
|
}
|
|
|
|
/**
|
|
* 방향을 나타낸 화살표에 각도에 따라 글씨 추가
|
|
* @param canvas
|
|
* @param compass
|
|
*/
|
|
const drawDirectionStringToArrow = (canvas, compass = 0) => {
|
|
const arrows = canvas?.getObjects().filter((obj) => obj.name === 'arrow')
|
|
|
|
if (arrows.length === 0) {
|
|
return
|
|
}
|
|
|
|
const eastArrows = arrows.filter((arrow) => arrow.direction === 'east')
|
|
const westArrows = arrows.filter((arrow) => arrow.direction === 'west')
|
|
const northArrows = arrows.filter((arrow) => arrow.direction === 'north')
|
|
const southArrows = arrows.filter((arrow) => arrow.direction === 'south')
|
|
|
|
let southText = '南'
|
|
let eastText = '東'
|
|
let westText = '西'
|
|
let northText = '北'
|
|
|
|
if (compass === 0 || compass === 360) {
|
|
// 남,동,서 가능
|
|
// 그대로
|
|
} else if (compass < 45) {
|
|
//남(남남동),동(동북동),서(서남서) 가능
|
|
//북(북북서)
|
|
southText = '南南東'
|
|
eastText = '東北東'
|
|
westText = '西南西'
|
|
northText = '北北西'
|
|
} else if (compass === 45) {
|
|
// 남, 서 가능
|
|
// 남(남동)
|
|
// 서(남서)
|
|
// 북(북서)
|
|
// 동(북동)
|
|
southText = '南東'
|
|
westText = '南西'
|
|
northText = '北西'
|
|
eastText = '北東'
|
|
} else if (compass < 90) {
|
|
// 북(서북서)
|
|
// 동 (북북동)
|
|
// 남(동남동)
|
|
// 서(남남서)
|
|
northText = '北西北'
|
|
eastText = '北北東'
|
|
southText = '東南東'
|
|
westText = '南南西'
|
|
} else if (compass === 90) {
|
|
// 동(북)
|
|
// 서(남)
|
|
// 남(동)
|
|
// 북(서)
|
|
eastText = '北'
|
|
westText = '南'
|
|
southText = '東'
|
|
northText = '西'
|
|
} else if (compass < 135) {
|
|
// 남,서,북 가능
|
|
// 동(북북서)
|
|
// 서(남남동)
|
|
// 남(동북동)
|
|
// 북(서남서)
|
|
eastText = '北北西'
|
|
westText = '南南東'
|
|
southText = '東北東'
|
|
northText = '西南西'
|
|
} else if (compass === 135) {
|
|
// 서,북 가능
|
|
|
|
// 서(남동)
|
|
// 북(남서)
|
|
// 남(북동)
|
|
// 동(북서)
|
|
|
|
westText = '南東'
|
|
northText = '南西'
|
|
southText = '北東'
|
|
eastText = '北西'
|
|
} else if (compass < 180) {
|
|
// 북,동,서 가능
|
|
// 북(남남서)
|
|
// 동(서북서)
|
|
// 남(북북동)
|
|
// 서(동남동)
|
|
|
|
northText = '南南西'
|
|
eastText = '西北西'
|
|
southText = '北北東'
|
|
westText = '東南東'
|
|
} else if (compass === 180) {
|
|
// 북,동,서 가능
|
|
// 북(남)
|
|
// 동(서)
|
|
// 남(북)
|
|
// 서(동)
|
|
northText = '南'
|
|
eastText = '西'
|
|
southText = '北'
|
|
westText = '東'
|
|
} else if (compass < 225) {
|
|
// 서,북,동 가능
|
|
// 북(남남동)
|
|
// 동(서남서)
|
|
// 남(북북서)
|
|
// 서(동남동)
|
|
northText = '南南東'
|
|
eastText = '西南西'
|
|
southText = '北北西'
|
|
westText = '東南東'
|
|
} else if (compass === 225) {
|
|
// 북,동 가능
|
|
// 북(남동)
|
|
// 동(남서)
|
|
// 남(북서)
|
|
// 서(북동)
|
|
northText = '南東'
|
|
eastText = '南西'
|
|
southText = '北西'
|
|
westText = '北東'
|
|
} else if (compass < 270) {
|
|
// 북동남 가능
|
|
// 북(동남동)
|
|
// 동(남남서)
|
|
// 남(서북서)
|
|
// 서(북북동)
|
|
northText = '東南東'
|
|
eastText = '南南西'
|
|
southText = '西北西'
|
|
westText = '北北東'
|
|
} else if (compass === 270) {
|
|
// 북동남 가능
|
|
// 북(동)
|
|
// 동(남)
|
|
// 남(서)
|
|
// 서(북)
|
|
northText = '東'
|
|
eastText = '南'
|
|
southText = '西'
|
|
westText = '北'
|
|
} else if (compass < 315) {
|
|
// 북,동,남 가능
|
|
// 북(동북동)
|
|
// 동(남남동)
|
|
// 남(서남서)
|
|
// 서(북북서)
|
|
northText = '東北東'
|
|
eastText = '南南東'
|
|
southText = '西南西'
|
|
westText = '北北西'
|
|
} else if (compass === 315) {
|
|
// 동,남 가능
|
|
// 북(북동)
|
|
// 동(남동)
|
|
// 남(남서)
|
|
// 서(북서)
|
|
northText = '北東'
|
|
eastText = '南東'
|
|
southText = '南西'
|
|
westText = '北西'
|
|
} else if (compass < 360) {
|
|
// 남,동,서 가능
|
|
// 북(북북동)
|
|
// 동(동남동)
|
|
// 남(남남서)
|
|
// 서(서북서)
|
|
northText = '北北東'
|
|
eastText = '東南東'
|
|
southText = '南南西'
|
|
westText = '西北西'
|
|
}
|
|
|
|
clearFlowText(canvas)
|
|
|
|
addTextByArrows(eastArrows, eastText, canvas)
|
|
addTextByArrows(westArrows, westText, canvas)
|
|
addTextByArrows(northArrows, northText, canvas)
|
|
addTextByArrows(southArrows, southText, canvas)
|
|
}
|
|
|
|
const clearFlowText = (canvas) => {
|
|
const texts = canvas.getObjects().filter((obj) => obj.name === 'flowText')
|
|
texts.forEach((text) => {
|
|
canvas.remove(text)
|
|
})
|
|
}
|
|
|
|
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} (${currentAngleType === ANGLE_TYPE.SLOPE ? arrow.pitch : getDegreeByChon(arrow.pitch)}${pitchText})`
|
|
|
|
const text = new fabric.Text(`${textStr}`, {
|
|
fontSize: flowFontOptions.fontSize.value,
|
|
fill: flowFontOptions.fontColor.value,
|
|
fontFamily: flowFontOptions.fontFamily.value,
|
|
fontWeight: flowFontOptions.fontWeight.value,
|
|
pitch: arrow.pitch,
|
|
originX: 'center',
|
|
originY: 'center',
|
|
name: 'flowText',
|
|
originText: `${txt}${index + 1}`,
|
|
selectable: false,
|
|
left: arrow.stickeyPoint.x,
|
|
top: arrow.stickeyPoint.y,
|
|
parent: arrow,
|
|
parentId: arrow.id,
|
|
visible: isFlowDisplay,
|
|
})
|
|
canvas.add(text)
|
|
})
|
|
}
|
|
|
|
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,
|
|
}
|
|
}
|