import { useEffect, useRef, useState } from 'react' import QRect from '@/components/fabric/QRect' import QPolygon from '@/components/fabric/QPolygon' import { getStartIndex, rearrangeArray, findTopTwoIndexesByDistance, getDirection, getCenterPoint } from '@/util/canvas-util' import { useRecoilState, useSetRecoilState } from 'recoil' import { fontSizeState, roofState, sortedPolygonArray, wallState } from '@/store/canvasAtom' import { QLine } from '@/components/fabric/QLine' export const Mode = { DRAW_LINE: 'drawLine', // 기준선 긋기모드 EDIT: 'edit', TEMPLATE: 'template', PATTERNA: 'patterna', PATTERNB: 'patternb', TEXTBOX: 'textbox', DRAW_RECT: 'drawRect', DEFAULT: 'default', } export function useMode() { const [mode, setMode] = useState() const points = useRef([]) const historyPoints = useRef([]) const historyLines = useRef([]) const [canvas, setCanvas] = useState(null) const [zoom, setZoom] = useState(100) const [fontSize] = useRecoilState(fontSizeState) const [shape, setShape] = useState(0) const [sortedArray, setSortedArray] = useRecoilState(sortedPolygonArray) const [roof, setRoof] = useRecoilState(roofState) const [wall, setWall] = useRecoilState(wallState) const addEvent = (mode) => { switch (mode) { case 'default': canvas?.off('mouse:down') break case 'drawLine': drawLineMode() break case 'edit': editMode() break case 'template': templateMode() break case 'patterna': applyTemplateA() break case 'patternb': applyTemplateB() break case 'textbox': textboxMode() break case 'drawRect': drawRectMode() break } } const changeMode = (canvas, mode) => { setMode(mode) // mode변경 시 이전 이벤트 제거 setCanvas(canvas) canvas?.off('mouse:down') addEvent(mode) } const editMode = () => { canvas?.on('mouse:down', function (options) { const pointer = canvas?.getPointer(options.e) const circle = new fabric.Circle({ radius: 1, fill: 'transparent', // 원 안을 비웁니다. stroke: 'black', // 원 테두리 색상을 검은색으로 설정합니다. left: pointer.x, top: pointer.y, originX: 'center', originY: 'center', selectable: false, }) historyPoints.current.push(circle) points.current.push(circle) canvas?.add(circle) if (points.current.length === 2) { const length = Number(prompt('길이를 입력하세요:')) // length 값이 숫자가 아닌 경우 if (isNaN(length) || length === 0) { //마지막 추가 된 points 제거합니다. const lastPoint = historyPoints.current[historyPoints.current.length - 1] canvas?.remove(lastPoint) historyPoints.current.pop() points.current.pop() return } if (length) { const vector = { x: points.current[1].left - points.current[0].left, y: points.current[1].top - points.current[0].top, } const slope = Math.abs(vector.y / vector.x) // 기울기 계산 let scaledVector if (slope >= 1) { // 기울기가 1 이상이면 x축 방향으로 그림 scaledVector = { x: 0, y: vector.y >= 0 ? Number(length) : -Number(length), } } else { // 기울기가 1 미만이면 y축 방향으로 그림 scaledVector = { x: vector.x >= 0 ? Number(length) : -Number(length), y: 0, } } const line = new QLine( [points.current[0].left, points.current[0].top, points.current[0].left + scaledVector.x, points.current[0].top + scaledVector.y], { stroke: 'black', strokeWidth: 2, selectable: false, viewLengthText: true, direction: getDirection(points.current[0], points.current[1]), fontSize: fontSize, }, ) pushHistoryLine(line) // 라인의 끝에 점을 추가합니다. const endPointCircle = new fabric.Circle({ radius: 1, fill: 'transparent', // 원 안을 비웁니다. stroke: 'black', // 원 테두리 색상을 검은색으로 설정합니다. left: points.current[0].left + scaledVector.x, top: points.current[0].top + scaledVector.y, originX: 'center', originY: 'center', selectable: false, }) canvas?.add(endPointCircle) historyPoints.current.push(endPointCircle) points.current.forEach((point) => { canvas?.remove(point) }) points.current = [endPointCircle] } } canvas?.renderAll() }) } const pushHistoryLine = (line) => { if (historyLines.current.length > 0 && historyLines.current[historyLines.current.length - 1].direction === line.direction) { // 같은 방향의 선이 두 번 연속으로 그려지면 이전 선을 제거하고, 새로운 선과 merge한다. const lastLine = historyLines.current.pop() canvas?.remove(lastLine) const mergedLine = new QLine([lastLine.x1, lastLine.y1, line.x2, line.y2], { stroke: 'black', strokeWidth: 2, selectable: false, viewLengthText: true, direction: lastLine.direction, fontSize: fontSize, }) historyLines.current.push(mergedLine) canvas?.add(mergedLine) } else { historyLines.current.push(line) canvas?.add(line) } } /** * 마우스로 그린 점 기준으로 외벽선을 완성시켜준다. * makePolygon 함수에 포함되어있던 내용을 다른 템플릿 적용에서도 사용할수 있도록 함수로 대체 */ const drawWallPolygon = () => { const firstPoint = historyPoints.current[0] const lastPoint = historyPoints.current[historyPoints.current.length - 1] historyPoints.current.forEach((point) => { canvas?.remove(point) }) drawLineWithLength(lastPoint, firstPoint) points.current = [] historyPoints.current = [] // handleOuterlines() const wall = makePolygon() setWall(wall) return wall } const templateMode = () => { changeMode(canvas, Mode.EDIT) if (historyPoints.current.length >= 4) { // handleOuterlinesTest() //외곽선 그리기 테스트 // drawWallPolygon() //아래 내용 drawWallPolygon()으로 대체 const firstPoint = historyPoints.current[0] const lastPoint = historyPoints.current[historyPoints.current.length - 1] historyPoints.current.forEach((point) => { canvas?.remove(point) }) drawLineWithLength(lastPoint, firstPoint) points.current = [] historyPoints.current = [] const roof = handleOuterlinesTest() const wall = makePolygon() roof.setWall(wall) setWall(wall) roof.drawHelpLine() } } const textboxMode = () => { canvas?.on('mouse:down', function (options) { if (canvas?.getActiveObject()?.type === 'textbox') return const pointer = canvas?.getPointer(options.e) const textbox = new fabric.Textbox('텍스트를 입력하세요', { left: pointer.x, top: pointer.y, width: 150, // 텍스트박스의 너비를 설정합니다. fontSize: fontSize, // 텍스트의 크기를 설정합니다. }) canvas?.add(textbox) canvas?.setActiveObject(textbox) // 생성된 텍스트박스를 활성 객체로 설정합니다. canvas?.renderAll() // textbox가 active가 풀린 경우 editing mode로 변경 textbox?.on('editing:exited', function () { changeMode(canvas, Mode.EDIT) }) }) } const drawLineMode = () => { canvas?.on('mouse:down', function (options) { const pointer = canvas?.getPointer(options.e) const line = new QLine( [pointer.x, 0, pointer.x, canvas.height], // y축에 1자 선을 그립니다. { stroke: 'black', strokeWidth: 2, viewLengthText: true, selectable: false, fontSize: fontSize, }, ) canvas?.add(line) canvas?.renderAll() }) } const drawRectMode = () => { let rect, isDown, origX, origY canvas.on('mouse:down', function (o) { isDown = true const pointer = canvas.getPointer(o.e) origX = pointer.x origY = pointer.y rect = new fabric.Rect({ left: origX, top: origY, originX: 'left', originY: 'top', width: pointer.x - origX, height: pointer.y - origY, angle: 0, fill: 'transparent', stroke: 'black', transparentCorners: false, }) canvas.add(rect) }) canvas.on('mouse:move', function (o) { if (!isDown) return const pointer = canvas.getPointer(o.e) if (origX > pointer.x) { rect.set({ left: Math.abs(pointer.x) }) } if (origY > pointer.y) { rect.set({ top: Math.abs(pointer.y) }) } rect.set({ width: Math.abs(origX - pointer.x) }) rect.set({ height: Math.abs(origY - pointer.y) }) }) canvas.on('mouse:up', function (o) { const pointer = canvas.getPointer(o.e) const qRect = new QRect({ left: origX, top: origY, originX: 'left', originY: 'top', width: pointer.x - origX, height: pointer.y - origY, angle: 0, viewLengthText: true, fill: 'transparent', stroke: 'black', transparentCorners: false, fontSize: fontSize, }) canvas.remove(rect) canvas.add(qRect) isDown = false }) } /** * 두 점을 연결하는 선과 길이를 그립니다. * a : 시작점, b : 끝점 */ const drawLineWithLength = (a, b) => { const line = new QLine([a.left, a.top, b.left, b.top], { stroke: 'black', strokeWidth: 2, selectable: false, viewLengthText: true, direction: getDirection(a, b), fontSize: fontSize, }) pushHistoryLine(line) canvas?.renderAll() } const makePolygon = (otherLines) => { // 캔버스에서 모든 라인 객체를 찾습니다. const lines = otherLines || historyLines.current if (!otherLines) { //외각선 기준 const topIndex = findTopTwoIndexesByDistance(sortedArray) //배열중에 큰 2값을 가져옴 TODO: 나중에는 인자로 받아서 다각으로 수정 해야됨 //일단 배열 6개 짜리 기준의 선 번호 if (topIndex[0] === 4) { if (topIndex[1] === 5) { //1번 setShape(1) } } else if (topIndex[0] === 1) { //4번 if (topIndex[1] === 2) { setShape(4) } } else if (topIndex[0] === 0) { if (topIndex[1] === 1) { //2번 setShape(2) } else if (topIndex[1] === 5) { setShape(3) } } historyLines.current = [] } // 각 라인의 시작점과 끝점을 사용하여 다각형의 점 배열을 생성합니다. const points = lines.map((line) => ({ x: line.x1, y: line.y1 })) // 모든 라인 객체를 캔버스에서 제거합니다. lines.forEach((line) => { canvas?.remove(line) }) // 점 배열을 사용하여 새로운 다각형 객체를 생성합니다. const polygon = new QPolygon( points, { stroke: 'black', fill: 'transparent', viewLengthText: true, selectable: true, fontSize: fontSize, }, canvas, ) // 새로운 다각형 객체를 캔버스에 추가합니다. canvas.add(polygon) // 캔버스를 다시 그립니다. if (!otherLines) { // polygon.fillCell() canvas.renderAll() polygon.setViewLengthText(false) setMode(Mode.DEFAULT) } return polygon } /** * 해당 캔버스를 비운다. */ const handleClear = () => { canvas?.clear() points.current = [] historyPoints.current = [] historyLines.current = [] } const zoomIn = () => { canvas?.setZoom(canvas.getZoom() + 0.1) setZoom(Math.round(zoom + 10)) } const zoomOut = () => { canvas?.setZoom(canvas.getZoom() - 0.1) setZoom(Math.ceil(zoom - 10)) } const handleOuterlines = () => { const newOuterlines = [] for (let i = 0; i < historyLines.current.length; i++) { const next = historyLines.current[i + 1] const prev = historyLines.current[i - 1] ?? historyLines.current[historyLines.current.length - 1] if (next) { if (next.direction === 'right') { // 다름 라인이 오른쪽으로 이동 if (historyLines.current[i].direction === 'top') { if (prev.direction !== 'right') { if (historyLines.current.length === 4) { newOuterlines.push({ x1: historyLines.current[i].x1 - 50, y1: historyLines.current[i].y1 + 50, x2: historyLines.current[i].x2 - 50, y2: historyLines.current[i].y2 - 50, }) } else if (historyLines.current.length === 6) { newOuterlines.push({ x1: historyLines.current[i].x1 - 50, y1: historyLines.current[i].y1 + 50, x2: historyLines.current[i].x2 - 50, y2: historyLines.current[i].y2 - 50, }) } else if (historyLines.current.length === 8) { newOuterlines.push({ x1: historyLines.current[i].x1 + 50, y1: historyLines.current[i].y1 - 50, x2: historyLines.current[i].x2 + 50, y2: historyLines.current[i].y2 + 50, }) } } else { newOuterlines.push({ x1: historyLines.current[i].x1 + 50, y1: historyLines.current[i].y1 + 50, x2: historyLines.current[i].x2 + 50, y2: historyLines.current[i].y2 + 50, }) } } else { // bottom if (prev?.direction !== 'right') { if (historyLines.current.length === 4) { newOuterlines.push({ x1: historyLines.current[i].x1 - 50, y1: historyLines.current[i].y1 - 50, x2: historyLines.current[i].x2 - 50, y2: historyLines.current[i].y2 + 50, }) } else if (historyLines.current.length === 6) { newOuterlines.push({ x1: historyLines.current[i].x1 - 50, y1: historyLines.current[i].y1 - 50, x2: historyLines.current[i].x2 - 50, y2: historyLines.current[i].y2 + 50, }) } else if (historyLines.current.length === 8) { newOuterlines.push({ x1: historyLines.current[i].x1 + 50, y1: historyLines.current[i].y1 + 50, x2: historyLines.current[i].x2 + 50, y2: historyLines.current[i].y2 - 50, }) } } else { newOuterlines.push({ x1: historyLines.current[i].x1 - 50, y1: historyLines.current[i].y1 + 50, x2: historyLines.current[i].x2 - 50, y2: historyLines.current[i].y2 + 50, }) } } } else if (next.direction === 'left') { if (historyLines.current[i].direction === 'top') { if (prev?.direction !== 'left') { if (historyLines.current.length === 4) { newOuterlines.push({ x1: historyLines.current[i].x1 + 50, y1: historyLines.current[i].y1 + 50, x2: historyLines.current[i].x2 + 50, y2: historyLines.current[i].y2 - 50, }) } else if (historyLines.current.length === 6) { newOuterlines.push({ x1: historyLines.current[i].x1 + 50, y1: historyLines.current[i].y1 + 50, x2: historyLines.current[i].x2 + 50, y2: historyLines.current[i].y2 - 50, }) } else if (historyLines.current.length === 8) { newOuterlines.push({ x1: historyLines.current[i].x1 - 50, y1: historyLines.current[i].y1 - 50, x2: historyLines.current[i].x2 - 50, y2: historyLines.current[i].y2 + 50, }) } } else { newOuterlines.push({ x1: historyLines.current[i].x1 + 50, y1: historyLines.current[i].y1 - 50, x2: historyLines.current[i].x2 + 50, y2: historyLines.current[i].y2 - 50, }) } } else { // bottom if (prev?.direction !== 'left') { if (historyLines.current.length === 4) { newOuterlines.push({ x1: historyLines.current[i].x1 + 50, y1: historyLines.current[i].y1 - 50, x2: historyLines.current[i].x2 + 50, y2: historyLines.current[i].y2 + 50, }) } else if (historyLines.current.length === 6) { newOuterlines.push({ x1: historyLines.current[i].x1 + 50, y1: historyLines.current[i].y1 - 50, x2: historyLines.current[i].x2 + 50, y2: historyLines.current[i].y2 + 50, }) } else if (historyLines.current.length === 8) { newOuterlines.push({ x1: historyLines.current[i].x1 - 50, y1: historyLines.current[i].y1 + 50, x2: historyLines.current[i].x2 - 50, y2: historyLines.current[i].y2 - 50, }) } } else { newOuterlines.push({ x1: historyLines.current[i].x1 - 50, y1: historyLines.current[i].y1 - 50, x2: historyLines.current[i].x2 - 50, y2: historyLines.current[i].y2 - 50, }) } } } else if (next.direction === 'top') { if (historyLines.current[i].direction === 'right') { if (prev?.direction !== 'top') { if (historyLines.current.length === 4) { newOuterlines.push({ x1: historyLines.current[i].x1 - 50, y1: historyLines.current[i].y1 + 50, x2: historyLines.current[i].x2 + 50, y2: historyLines.current[i].y2 + 50, }) } else if (historyLines.current.length === 6) { newOuterlines.push({ x1: historyLines.current[i].x1 - 50, y1: historyLines.current[i].y1 + 50, x2: historyLines.current[i].x2 + 50, y2: historyLines.current[i].y2 + 50, }) } else if (historyLines.current.length === 8) { newOuterlines.push({ x1: historyLines.current[i].x1 + 50, y1: historyLines.current[i].y1 - 50, x2: historyLines.current[i].x2 - 50, y2: historyLines.current[i].y2 - 50, }) } } else { newOuterlines.push({ x1: historyLines.current[i].x1 + 50, y1: historyLines.current[i].y1 + 50, x2: historyLines.current[i].x2 + 50, y2: historyLines.current[i].y2 + 50, }) } } else { // left if (prev?.direction !== 'top') { if (historyLines.current.length === 4) { newOuterlines.push({ x1: historyLines.current[i].x1 + 50, y1: historyLines.current[i].y1 + 50, x2: historyLines.current[i].x2 - 50, y2: historyLines.current[i].y2 + 50, }) } else if (historyLines.current.length === 6) { newOuterlines.push({ x1: historyLines.current[i].x1 + 50, y1: historyLines.current[i].y1 + 50, x2: historyLines.current[i].x2 - 50, y2: historyLines.current[i].y2 + 50, }) } else if (historyLines.current.length === 8) { newOuterlines.push({ x1: historyLines.current[i].x1 - 50, y1: historyLines.current[i].y1 - 50, x2: historyLines.current[i].x2 + 50, y2: historyLines.current[i].y2 - 50, }) } } else { newOuterlines.push({ x1: historyLines.current[i].x1 + 50, y1: historyLines.current[i].y1 - 50, x2: historyLines.current[i].x2 + 50, y2: historyLines.current[i].y2 - 50, }) } } } else if (next.direction === 'bottom') { if (historyLines.current[i].direction === 'right') { if (prev?.direction !== 'bottom') { if (historyLines.current.length === 4) { newOuterlines.push({ x1: historyLines.current[i].x1 - 50, y1: historyLines.current[i].y1 - 50, x2: historyLines.current[i].x2 + 50, y2: historyLines.current[i].y2 - 50, }) } else if (historyLines.current.length === 6) { newOuterlines.push({ x1: historyLines.current[i].x1 - 50, y1: historyLines.current[i].y1 - 50, x2: historyLines.current[i].x2 + 50, y2: historyLines.current[i].y2 - 50, }) } else if (historyLines.current.length === 8) { newOuterlines.push({ x1: historyLines.current[i].x1 + 50, y1: historyLines.current[i].y1 + 50, x2: historyLines.current[i].x2 - 50, y2: historyLines.current[i].y2 + 50, }) } } else { newOuterlines.push({ x1: historyLines.current[i].x1 - 50, y1: historyLines.current[i].y1 + 50, x2: historyLines.current[i].x2 - 50, y2: historyLines.current[i].y2 + 50, }) } } else { // left if (prev.direction !== 'bottom') { if (historyLines.current.length === 4) { newOuterlines.push({ x1: historyLines.current[i].x1 + 50, y1: historyLines.current[i].y1 - 50, x2: historyLines.current[i].x2 - 50, y2: historyLines.current[i].y2 - 50, }) } else if (historyLines.current.length === 6) { newOuterlines.push({ x1: historyLines.current[i].x1 + 50, y1: historyLines.current[i].y1 - 50, x2: historyLines.current[i].x2 - 50, y2: historyLines.current[i].y2 - 50, }) } else if (historyLines.current.length === 8) { newOuterlines.push({ x1: historyLines.current[i].x1 - 50, y1: historyLines.current[i].y1 + 50, x2: historyLines.current[i].x2 + 50, y2: historyLines.current[i].y2 + 50, }) } } else { newOuterlines.push({ x1: historyLines.current[i].x1 - 50, y1: historyLines.current[i].y1 - 50, x2: historyLines.current[i].x2 + 50, y2: historyLines.current[i].y2 - 50, }) } } } } else { const tmp = newOuterlines[newOuterlines.length - 1] newOuterlines.push({ x1: tmp.x2, y1: tmp.y2, x2: newOuterlines[0].x1, y2: newOuterlines[0].y1, }) } } makePolygon(newOuterlines) } /** *벽 지붕 외곽선 생성 */ const handleOuterlinesTest = (polygon, offset = 71) => { var offsetPoints = [] const sortedIndex = getStartIndex(polygon.lines) let tmpArraySorted = rearrangeArray(polygon.lines, sortedIndex) if (tmpArraySorted[0].direction === 'right') { //시계방향 tmpArraySorted = tmpArraySorted.reverse() //그럼 배열을 거꾸로 만들어서 무조건 반시계방향으로 배열 보정 } setSortedArray(tmpArraySorted) //recoil에 넣음 const points = tmpArraySorted.map((line) => ({ x: line.x1, y: line.y1, })) for (var i = 0; i < points.length; i++) { var prev = points[(i - 1 + points.length) % points.length] var current = points[i] var next = points[(i + 1) % points.length] // 두 벡터 계산 (prev -> current, current -> next) var vector1 = { x: current.x - prev.x, y: current.y - prev.y } var vector2 = { x: next.x - current.x, y: next.y - current.y } // 벡터의 길이 계산 var length1 = Math.sqrt(vector1.x * vector1.x + vector1.y * vector1.y) var length2 = Math.sqrt(vector2.x * vector2.x + vector2.y * vector2.y) // 벡터를 단위 벡터로 정규화 var unitVector1 = { x: vector1.x / length1, y: vector1.y / length1 } var unitVector2 = { x: vector2.x / length2, y: vector2.y / length2 } // 법선 벡터 계산 (왼쪽 방향) var normal1 = { x: -unitVector1.y, y: unitVector1.x } var normal2 = { x: -unitVector2.y, y: unitVector2.x } // 법선 벡터 평균 계산 var averageNormal = { x: (normal1.x + normal2.x) / 2, y: (normal1.y + normal2.y) / 2, } // 평균 법선 벡터를 단위 벡터로 정규화 var lengthNormal = Math.sqrt(averageNormal.x * averageNormal.x + averageNormal.y * averageNormal.y) var unitNormal = { x: averageNormal.x / lengthNormal, y: averageNormal.y / lengthNormal, } // 오프셋 적용 var offsetPoint = { x1: current.x + unitNormal.x * offset, y1: current.y + unitNormal.y * offset, } offsetPoints.push(offsetPoint) } const roof = makePolygon(offsetPoints) setRoof(roof) return roof } /** *벽 지붕 외곽선 생성 polygon을 입력받아 만들기 */ const handleOuterlinesTest2 = (polygon, offset = 71) => { const offsetPoints = [] const sortedIndex = getStartIndex(polygon.lines) let tmpArraySorted = rearrangeArray(polygon.lines, sortedIndex) if (tmpArraySorted[0].direction === 'right') { //시계방향 tmpArraySorted = tmpArraySorted.reverse() //그럼 배열을 거꾸로 만들어서 무조건 반시계방향으로 배열 보정 } setSortedArray(tmpArraySorted) //recoil에 넣음 const points = tmpArraySorted.map((line) => ({ x: line.x1, y: line.y1, })) for (let i = 0; i < points.length; i++) { const prev = points[(i - 1 + points.length) % points.length] const current = points[i] const next = points[(i + 1) % points.length] // 두 벡터 계산 (prev -> current, current -> next) const vector1 = { x: current.x - prev.x, y: current.y - prev.y } const vector2 = { x: next.x - current.x, y: next.y - current.y } // 벡터의 길이 계산 const length1 = Math.sqrt(vector1.x * vector1.x + vector1.y * vector1.y) const length2 = Math.sqrt(vector2.x * vector2.x + vector2.y * vector2.y) // 벡터를 단위 벡터로 정규화 const unitVector1 = { x: vector1.x / length1, y: vector1.y / length1 } const unitVector2 = { x: vector2.x / length2, y: vector2.y / length2 } // 법선 벡터 계산 (왼쪽 방향) const normal1 = { x: -unitVector1.y, y: unitVector1.x } const normal2 = { x: -unitVector2.y, y: unitVector2.x } // 법선 벡터 평균 계산 const averageNormal = { x: (normal1.x + normal2.x) / 2, y: (normal1.y + normal2.y) / 2, } // 평균 법선 벡터를 단위 벡터로 정규화 const lengthNormal = Math.sqrt(averageNormal.x * averageNormal.x + averageNormal.y * averageNormal.y) const unitNormal = { x: averageNormal.x / lengthNormal, y: averageNormal.y / lengthNormal, } // 오프셋 적용 const offsetPoint = { x1: current.x + unitNormal.x * offset, y1: current.y + unitNormal.y * offset, } offsetPoints.push(offsetPoint) } const roof = makePolygon(offsetPoints) roof.setWall(polygon) setRoof(roof) roof.drawHelpLine() } const togglePolygonLine = (obj) => { const rtnLines = [] if (obj.type === 'QPolygon') { const points = obj.getCurrentPoints() points.forEach((point, index) => { const nextPoint = points[(index + 1) % points.length] // 마지막 점이면 첫 번째 점으로 연결 const line = new QLine([point.x, point.y, nextPoint.x, nextPoint.y], { stroke: 'black', strokeWidth: 2, selectable: false, fontSize: fontSize, // fontSize는 필요에 따라 조정 parent: obj, }) obj.visible = false canvas.add(line) rtnLines.push(line) }) canvas.renderAll() } if (obj.type === 'QLine') { const parent = obj.parent canvas ?.getObjects() .filter((obj) => obj.parent === parent) .forEach((obj) => { rtnLines.push(obj) canvas.remove(obj) }) parent.visible = true canvas.renderAll() } return rtnLines } const applyTemplateA = () => { changeMode(canvas, Mode.EDIT) const polygon = drawWallPolygon() handleClear() if (polygon.lines.length === 4) { //4각형 handleOuterLineTemplateA4Points(polygon) } else if (polygon.lines.length === 6) { //6각형 handleOuterLineTemplateA6Points(polygon) } } const handleOuterLineTemplateA4Points = (polygon) => { const edge = 20 const eaves = 50 // 폴리곤의 각 변을 선으로 생성 const createLine = (start, end, stroke, property) => new QLine([start.x, start.y, end.x, end.y], { stroke, strokeWidth: 5, property, fontSize: 14, }) const lines = polygon.points.map((start, i) => { const end = polygon.points[(i + 1) % polygon.points.length] const line = createLine(start, end, '#A0D468', 'normal') canvas.add(line) return line }) const edgeIndexArray = [] const normalIndexArray = [] lines.forEach((line, i) => { if (i % 2 === 0) { line.set('stroke', 'skyblue') line.set('property', 'edge') edgeIndexArray.push(i) } else { normalIndexArray.push(i) } canvas.add(line) }) const centerPointX = (lines[1].x1 + lines[1].x2) / 2 const centerPointY = (lines[0].y1 + lines[0].y2) / 2 const horiCenterHalfLine = (lines[1].x2 - lines[1].x1) / 2 const createCenterLine = (x1, y1, x2, y2, stroke, strokeWidth, property, dashArray = []) => new QLine([x1, y1, x2, y2], { stroke, strokeWidth, property, fontSize: 14, strokeDashArray: dashArray, }) const vertCenterLine = createCenterLine(centerPointX, lines[0].y1 - edge, centerPointX, lines[0].y2 + edge, 'blue', 4, 'center') canvas.add(vertCenterLine) const horiCenterLineLeft = createCenterLine( lines[1].x1 - eaves, centerPointY, lines[1].x1 + horiCenterHalfLine, centerPointY, 'black', 2, 'center', [5, 5], ) canvas.add(horiCenterLineLeft) const horiCenterLineRight = createCenterLine( horiCenterLineLeft.x2, centerPointY, horiCenterLineLeft.x2 + horiCenterHalfLine + eaves, centerPointY, 'black', 2, 'center', [5, 5], ) canvas.add(horiCenterLineRight) const drawArray = lines .map((line) => { if (line.x1 === line.x2 && line.y1 < line.y2) { return [{ x1: line.x1 - eaves, y1: line.y1 - edge, x2: line.x1 - eaves, y2: line.y2 + edge }] } else if (line.x1 === line.x2 && line.y1 > line.y2) { return [{ x1: line.x1 + eaves, y1: line.y1 + edge, x2: line.x1 + eaves, y2: line.y2 - edge }] } else if (line.x1 < line.x2 && line.y1 === line.y2) { return [ { x1: line.x1 - eaves, y1: line.y1 + edge, x2: line.x1 + horiCenterHalfLine, y2: line.y2 + edge }, { x1: line.x1 + horiCenterHalfLine, y1: line.y1 + edge, x2: line.x1 + horiCenterHalfLine + horiCenterHalfLine + eaves, y2: line.y2 + edge, }, ] } else if (line.x1 > line.x2 && line.y1 === line.y2) { return [ { x1: line.x2 - eaves, y1: line.y1 - edge, x2: line.x2 + horiCenterHalfLine, y2: line.y2 - edge }, { x1: line.x2 + horiCenterHalfLine, y1: line.y1 - edge, x2: line.x2 + horiCenterHalfLine + horiCenterHalfLine + eaves, y2: line.y2 - edge, }, ] } return [] }) .flat() drawArray.forEach((line) => { const outLine = createLine({ x: line.x1, y: line.y1 }, { x: line.x2, y: line.y2 }, 'blue', 'normal') canvas.add(outLine) }) } //탬플릿A 적용 const handleOuterLineTemplateA6Points = (polygon) => { let lines = [] let outLines = [] // 폴리곤의 각 변을 선으로 생성 for (let i = 0; i < polygon.points.length; i++) { const start = polygon.points[i] const end = polygon.points[(i + 1) % polygon.points.length] // 다음 점, 마지막 점의 경우 첫 점으로 const line = new QLine([start.x, start.y, end.x, end.y], { stroke: '#A0D468', strokeWidth: 5, property: 'normal', fontSize: 14, }) // 선을 배열에 추가 lines.push(line) canvas.add(line) } let highLineLength = 0 let lowLineLength = 0 let prevHighIndex = 0 let prevHighLength = 0 let prevLowIndex = 0 let prevLowLength = 0 let edgeIndexArray = [] let normalIndexArray = [] for (let i = 0; i < lines.length; i++) { let line = lines[i] if (!(i % 2) == 0) { //홀수일떄 line.line.set('stroke', 'skyblue') line.line.set('property', 'egde') let length = Math.abs(line.get('x1') - line.get('x2')) + Math.abs(line.get('y1') - line.get('y2')) if (length > prevHighLength) { //잴긴거 찾음 prevHighIndex = i prevHighLength = length highLineLength = length } if (prevLowLength === 0) { //최초에는 없어서 한번 넣음 prevLowIndex = i prevLowLength = length } if (length <= prevLowLength) { //그뒤부터는 짧은거 대로 넣음 prevLowIndex = i prevLowLength = length lowLineLength = length } edgeIndexArray.push(i) } else { normalIndexArray.push(i) } // 캔버스에 선 추가 canvas.add(line) } let prevDirecArray //긴선 앞배열 let nextDirecArray //긴선 뒷배열 let horizontalDirection //뽈록이 좌우 방향 if (prevHighIndex === 1) { //카라바 기준 1과 5밖에 없음 prevDirecArray = lines[prevHighIndex - 1] nextDirecArray = lines[prevHighIndex + 1] //밑에쪽이 긴 방향 horizontalDirection = prevDirecArray.height > nextDirecArray.height ? 'left' : 'right' } else { prevDirecArray = lines[prevHighIndex - 1] nextDirecArray = lines[0] //위에가 긴 방향 horizontalDirection = prevDirecArray.height > nextDirecArray.height ? 'right' : 'left' } const edge = 20 //케라바 const eaves = 50 //처마 let firstLine = lines[1] let secondLine = lines[3] let lastLine = lines[5] let vertCenterLine let secondVertCenterLine if (prevHighIndex === 1) { if (horizontalDirection === 'left') { //배열 순서대로 뒤에꺼를 찾아서 계산한다 const firstSubLine = lines[2] const middleSubLine = lines[4] //ㄴ자 일경우 //긴면 세로선 그리기 let vertCenterPoint = (firstLine.x1 + firstLine.x2) / 2 //가장 긴선 중앙선 가운데 점 vertCenterLine = new QLine( [ vertCenterPoint, firstSubLine.y1 + edge, //다음 선의 높이만큼 가져와서 edge길이를 합함 vertCenterPoint, firstSubLine.y2 - edge, //다음 선의 높이만큼 가져옴 edge길이를 합함 ], { stroke: 'blue', strokeWidth: 5, property: 'bigHoriCenter', fontSize: 14, }, ) canvas.add(vertCenterLine) //긴면 가로선 그리기 let horiCenterPoint = (firstSubLine.y1 + firstSubLine.y2) / 2 let horiCenterLine1 = new QLine( [firstLine.x1 - eaves, horiCenterPoint, firstLine.x1 - eaves + firstLine.length / 2 + eaves, horiCenterPoint], { stroke: 'black', strokeWidth: 4, property: 'centerLine', strokeDashArray: [5, 5], fontSize: 14, }, ) canvas.add(horiCenterLine1) let horiCenterLine2 = new QLine( [ firstLine.x1 - eaves + firstLine.length / 2 + eaves, horiCenterPoint, firstLine.x1 - eaves + firstLine.length / 2 + eaves + firstLine.length / 2 + eaves, horiCenterPoint, ], { stroke: 'black', strokeWidth: 4, property: 'centerLine', strokeDashArray: [5, 5], fontSize: 14, }, ) canvas.add(horiCenterLine2) //작은 지붕쪽 높이 길이를 구하는 로직 let secondVertCenterPoint = (lastLine.x1 + lastLine.x2) / 2 secondVertCenterLine = new QLine([secondVertCenterPoint, middleSubLine.y1, secondVertCenterPoint, middleSubLine.y2 - edge], { stroke: 'blue', strokeWidth: 4, property: 'centerLine', fontSize: 14, }) canvas.add(secondVertCenterLine) //작은 지붕쪽 너비 길이를 구한는 로직 let secondHoriCenterLength = (Math.abs(lastLine.get('x1') - lastLine.get('x2')) + Math.abs(lastLine.get('y1') - lastLine.get('y2'))) / 2 let secondHoriCenterPoint = (secondVertCenterLine.y1 + secondVertCenterLine.y2) / 2 let secondHoriCenterLine = new QLine( [secondVertCenterLine.x1, secondHoriCenterPoint, secondVertCenterLine.x1 + secondHoriCenterLength + eaves, secondHoriCenterPoint], { stroke: 'black', strokeWidth: 4, property: 'centerLine', strokeDashArray: [5, 5], fontSize: 14, }, ) canvas.add(secondHoriCenterLine) //일반라인 외각선 그리기 normalIndexArray.forEach((index) => { const line = lines[index] if (index === 0) { let drawline = new QLine([line.x1 - eaves, line.y1 - edge, line.x2 - eaves, line.y2 + edge], { stroke: 'blue', strokeWidth: 4, property: 'centerLine', fontSize: 14, }) canvas.add(drawline) } else { let tmpEdge = index === 2 ? edge : 0 let drawline = new QLine([line.x1 + eaves, line.y1 + tmpEdge, line.x2 + eaves, line.y2 - edge], { stroke: 'blue', strokeWidth: 4, property: 'centerLine', fontSize: 14, }) canvas.add(drawline) } }) //케라바 라인 외각선 그리기 const firstOuterLine = lines[1] const middleOuterLine = lines[3] const lastOuterLine = lines[5] //첫번째 외곽선 1번 let halfLength = firstOuterLine.length / 2 let drawFirstLine1 = new QLine( [firstOuterLine.x1 - eaves, firstOuterLine.y1 + edge, firstOuterLine.x1 + halfLength, firstOuterLine.y2 + edge], { stroke: 'blue', strokeWidth: 4, property: 'centerLine', fontSize: 14, }, ) canvas.add(drawFirstLine1) //첫번째 외곽선 2번 let drawFirstLine2 = new QLine([drawFirstLine1.x2, firstOuterLine.y1 + edge, firstOuterLine.x2 + eaves, firstOuterLine.y2 + edge], { stroke: 'blue', strokeWidth: 4, property: 'centerLine', fontSize: 14, }) canvas.add(drawFirstLine2) //중간라인 외각선 let drawMiddleLine = new QLine([drawFirstLine2.x2, middleOuterLine.y1 - edge, drawFirstLine2.x1, middleOuterLine.y2 - edge], { stroke: 'blue', strokeWidth: 4, property: 'centerLine', fontSize: 14, }) canvas.add(drawMiddleLine) //마지막 외각선 halfLength = lastLine.length / 2 let drawLastLine1 = new QLine([lastOuterLine.x2 + halfLength, lastOuterLine.y1 - edge, lastOuterLine.x2 - eaves, lastOuterLine.y2 - edge], { stroke: 'blue', strokeWidth: 4, property: 'centerLine', fontSize: 14, }) canvas.add(drawLastLine1) let drawLastLine2 = new QLine([drawLastLine1.x1, lastOuterLine.y1 - edge, lastOuterLine.x1 + length + eaves, lastOuterLine.y2 - edge], { stroke: 'blue', strokeWidth: 4, property: 'centerLine', fontSize: 14, }) canvas.add(drawLastLine2) let drawLastInLine1 = new QLine( [secondVertCenterLine.x1, secondVertCenterLine.y1, secondVertCenterLine.x1 + halfLength + eaves, secondVertCenterLine.y1], { stroke: 'blue', strokeWidth: 4, property: 'centerLine', fontSize: 14, }, ) canvas.add(drawLastInLine1) let drawLastInLine2 = new QLine([secondVertCenterLine.x1, vertCenterLine.y2, vertCenterLine.x2, vertCenterLine.y2], { stroke: 'blue', strokeWidth: 4, property: 'centerLine', fontSize: 14, }) canvas.add(drawLastInLine2) } else { //아래쪽 길게 오른쪽 방향 //배열 순서대로 뒤에꺼를 찾아서 계산한다 firstLine = lines[1] secondLine = lines[5] lastLine = lines[3] const firstSubLine = lines[0] const middleSubLine = lines[4] //ㄴ자 일경우 //긴면 세로선 그리기 let vertCenterPoint = (firstLine.x1 + firstLine.x2) / 2 //가장 긴선 중앙선 가운데 점 vertCenterLine = new QLine( [ vertCenterPoint, firstSubLine.y1 - edge, //다음 선의 높이만큼 가져와서 edge길이를 합함 vertCenterPoint, firstSubLine.y2 + edge, //다음 선의 높이만큼 가져옴 edge길이를 합함 ], { stroke: 'blue', strokeWidth: 5, property: 'bigHoriCenter', fontSize: 14, }, ) canvas.add(vertCenterLine) //긴면 가로선 그리기 let horiCenterPoint = (firstSubLine.y1 + firstSubLine.y2) / 2 let horiCenterLine1 = new QLine( [firstLine.x1 - eaves, horiCenterPoint, firstLine.x1 - eaves + firstLine.length / 2 + eaves, horiCenterPoint], { stroke: 'black', strokeWidth: 4, property: 'centerLine', strokeDashArray: [5, 5], fontSize: 14, }, ) canvas.add(horiCenterLine1) let horiCenterLine2 = new QLine( [ firstLine.x1 - eaves + firstLine.length / 2 + eaves, horiCenterPoint, firstLine.x1 - eaves + firstLine.length / 2 + eaves + firstLine.length / 2 + eaves, horiCenterPoint, ], { stroke: 'black', strokeWidth: 4, property: 'centerLine', strokeDashArray: [5, 5], fontSize: 14, }, ) canvas.add(horiCenterLine2) //작은 지붕쪽 높이 길이를 구하는 로직 let secondVertCenterPoint = (lastLine.x1 + lastLine.x2) / 2 secondVertCenterLine = new QLine([secondVertCenterPoint, middleSubLine.y1 - edge, secondVertCenterPoint, middleSubLine.y2], { stroke: 'blue', strokeWidth: 4, property: 'centerLine', fontSize: 14, }) canvas.add(secondVertCenterLine) //작은 지붕쪽 너비 길이를 구한는 로직 let secondHoriCenterLength = (Math.abs(lastLine.get('x1') - lastLine.get('x2')) + Math.abs(lastLine.get('y1') - lastLine.get('y2'))) / 2 let secondHoriCenterPoint = (secondVertCenterLine.y1 + secondVertCenterLine.y2) / 2 let secondHoriCenterLine = new QLine( [secondVertCenterLine.x1 - secondHoriCenterLength - eaves, secondHoriCenterPoint, secondVertCenterLine.x1, secondHoriCenterPoint], { stroke: 'black', strokeWidth: 4, property: 'centerLine', strokeDashArray: [5, 5], fontSize: 14, }, ) canvas.add(secondHoriCenterLine) //일반라인 외각선 그리기 normalIndexArray.forEach((index) => { const line = lines[index] if (index === 0 || index === 4) { let tmpEdge = index === 4 ? 0 : edge let drawline = new QLine([line.x1 - eaves, line.y1 - edge, line.x2 - eaves, line.y2 + tmpEdge], { stroke: 'blue', strokeWidth: 4, property: 'centerLine', fontSize: 14, }) canvas.add(drawline) } else { let drawline = new QLine([line.x1 + eaves, line.y1 + edge, line.x2 + eaves, line.y2 - edge], { stroke: 'blue', strokeWidth: 4, property: 'centerLine', fontSize: 14, }) canvas.add(drawline) } }) //케라바 라인 외각선 그리기 const firstOuterLine = lines[1] const middleOuterLine = lines[5] const lastOuterLine = lines[3] //첫번째 외곽선 1번 let halfLength = firstOuterLine.length / 2 let drawFirstLine1 = new QLine( [firstOuterLine.x1 - eaves, firstOuterLine.y1 + edge, firstOuterLine.x1 + halfLength, firstOuterLine.y2 + edge], { stroke: 'blue', strokeWidth: 4, property: 'centerLine', fontSize: 14, }, ) canvas.add(drawFirstLine1) //첫번째 외곽선 2번 let drawFirstLine2 = new QLine([drawFirstLine1.x2, firstOuterLine.y1 + edge, firstOuterLine.x2 + eaves, firstOuterLine.y2 + edge], { stroke: 'blue', strokeWidth: 4, property: 'centerLine', fontSize: 14, }) canvas.add(drawFirstLine2) //중간라인 외각선 let drawMiddleLine = new QLine([drawFirstLine1.x1, middleOuterLine.y1 - edge, drawFirstLine1.x2, middleOuterLine.y2 - edge], { stroke: 'blue', strokeWidth: 4, property: 'centerLine', fontSize: 14, }) canvas.add(drawMiddleLine) //마지막 외각선 halfLength = lastLine.length / 2 console.log(lastOuterLine) let drawLastLine1 = new QLine([lastOuterLine.x2 - eaves, lastOuterLine.y1 - edge, lastOuterLine.x1 - halfLength, lastOuterLine.y2 - edge], { stroke: 'blue', strokeWidth: 4, property: 'centerLine', fontSize: 14, }) canvas.add(drawLastLine1) let drawLastLine2 = new QLine([drawLastLine1.x1, lastOuterLine.y1 - edge, lastOuterLine.x1 + length + eaves, lastOuterLine.y2 - edge], { stroke: 'blue', strokeWidth: 4, property: 'centerLine', fontSize: 14, }) canvas.add(drawLastLine2) let drawLastInLine1 = new QLine( [secondVertCenterLine.x1, secondVertCenterLine.y2, secondVertCenterLine.x1 - halfLength - eaves, secondVertCenterLine.y2], { stroke: 'blue', strokeWidth: 4, property: 'centerLine', fontSize: 14, }, ) canvas.add(drawLastInLine1) let drawLastInLine2 = new QLine([secondVertCenterLine.x2, vertCenterLine.y1, vertCenterLine.x1, vertCenterLine.y1], { stroke: 'blue', strokeWidth: 4, property: 'centerLine', fontSize: 14, }) canvas.add(drawLastInLine2) } } else { if (horizontalDirection === 'left') { //아래쪽 길게 오른쪽 방향 //배열 순서대로 뒤에꺼를 찾아서 계산한다 firstLine = lines[5] secondLine = lines[3] lastLine = lines[1] const firstSubLine = lines[4] const middleSubLine = lines[2] //ㄴ자 일경우 //긴면 세로선 그리기 let vertCenterPoint = (firstLine.x1 + firstLine.x2) / 2 //가장 긴선 중앙선 가운데 점 vertCenterLine = new QLine( [ vertCenterPoint, firstSubLine.y2 - edge, //다음 선의 높이만큼 가져와서 edge길이를 합함 vertCenterPoint, firstSubLine.y1 + edge, //다음 선의 높이만큼 가져옴 edge길이를 합함 ], { stroke: 'blue', strokeWidth: 5, property: 'bigHoriCenter', fontSize: 14, }, ) canvas.add(vertCenterLine) //긴면 가로선 그리기 let horiCenterPoint = (firstSubLine.y1 + firstSubLine.y2) / 2 let horiCenterLine1 = new QLine( [firstLine.x2 - eaves, horiCenterPoint, firstLine.x2 - eaves + firstLine.length / 2 + eaves, horiCenterPoint], { stroke: 'black', strokeWidth: 4, property: 'centerLine', strokeDashArray: [5, 5], fontSize: 14, }, ) canvas.add(horiCenterLine1) let horiCenterLine2 = new QLine( [ firstLine.x2 - eaves + firstLine.length / 2 + eaves, horiCenterPoint, firstLine.x2 - eaves + firstLine.length / 2 + eaves + firstLine.length / 2 + eaves, horiCenterPoint, ], { stroke: 'black', strokeWidth: 4, property: 'centerLine', strokeDashArray: [5, 5], fontSize: 14, }, ) canvas.add(horiCenterLine2) //작은 지붕쪽 높이 길이를 구하는 로직 let secondVertCenterPoint = (lastLine.x1 + lastLine.x2) / 2 secondVertCenterLine = new QLine([secondVertCenterPoint, middleSubLine.y1 + edge, secondVertCenterPoint, middleSubLine.y2], { stroke: 'blue', strokeWidth: 4, property: 'centerLine', fontSize: 14, }) canvas.add(secondVertCenterLine) //작은 지붕쪽 너비 길이를 구한는 로직 let secondHoriCenterLength = (Math.abs(lastLine.get('x1') - lastLine.get('x2')) + Math.abs(lastLine.get('y1') - lastLine.get('y2'))) / 2 let secondHoriCenterPoint = (secondVertCenterLine.y1 + secondVertCenterLine.y2) / 2 let secondHoriCenterLine = new QLine( [secondVertCenterLine.x1 + secondHoriCenterLength + eaves, secondHoriCenterPoint, secondVertCenterLine.x1, secondHoriCenterPoint], { stroke: 'black', strokeWidth: 4, property: 'centerLine', strokeDashArray: [5, 5], fontSize: 14, }, ) canvas.add(secondHoriCenterLine) //일반라인 외각선 그리기 normalIndexArray.forEach((index) => { const line = lines[index] if (index === 0) { let drawline = new QLine([line.x1 - eaves, line.y1 - edge, line.x2 - eaves, line.y2 + edge], { stroke: 'blue', strokeWidth: 4, property: 'centerLine', fontSize: 14, }) canvas.add(drawline) } else { let tmpEdge = index === 2 ? 0 : edge let drawline = new QLine([line.x1 + eaves, line.y1 + edge, line.x2 + eaves, line.y2 - tmpEdge], { stroke: 'blue', strokeWidth: 4, property: 'centerLine', fontSize: 14, }) canvas.add(drawline) } }) //케라바 라인 외각선 그리기 const firstOuterLine = lines[5] const middleOuterLine = lines[3] const lastOuterLine = lines[1] //첫번째 외곽선 1번 let halfLength = firstOuterLine.length / 2 let drawFirstLine1 = new QLine( [firstOuterLine.x2 - eaves, firstOuterLine.y1 - edge, firstOuterLine.x2 + halfLength, firstOuterLine.y2 - edge], { stroke: 'blue', strokeWidth: 4, property: 'centerLine', fontSize: 14, }, ) canvas.add(drawFirstLine1) //첫번째 외곽선 2번 let drawFirstLine2 = new QLine([drawFirstLine1.x2, drawFirstLine1.y1, drawFirstLine1.x2 + halfLength + eaves, drawFirstLine1.y2], { stroke: 'blue', strokeWidth: 4, property: 'centerLine', fontSize: 14, }) canvas.add(drawFirstLine2) //중간라인 외각선 let drawMiddleLine = new QLine([drawFirstLine2.x1, middleOuterLine.y1 + edge, drawFirstLine2.x2, middleOuterLine.y2 + edge], { stroke: 'blue', strokeWidth: 4, property: 'centerLine', fontSize: 14, }) canvas.add(drawMiddleLine) //마지막 외각선 halfLength = lastLine.length / 2 console.log(lastOuterLine) let drawLastLine1 = new QLine([lastOuterLine.x1 - eaves, lastOuterLine.y1 + edge, lastOuterLine.x1 + halfLength, lastOuterLine.y2 + edge], { stroke: 'blue', strokeWidth: 4, property: 'centerLine', fontSize: 14, }) canvas.add(drawLastLine1) let drawLastLine2 = new QLine([drawLastLine1.x2, drawLastLine1.y1, drawLastLine1.x2 + halfLength + eaves, drawLastLine1.y1], { stroke: 'blue', strokeWidth: 4, property: 'centerLine', fontSize: 14, }) canvas.add(drawLastLine2) let drawLastInLine1 = new QLine( [secondVertCenterLine.x1, secondVertCenterLine.y2, secondVertCenterLine.x1 + halfLength + eaves, secondVertCenterLine.y2], { stroke: 'blue', strokeWidth: 4, property: 'centerLine', fontSize: 14, }, ) canvas.add(drawLastInLine1) let drawLastInLine2 = new QLine([vertCenterLine.x1, vertCenterLine.y2, secondVertCenterLine.x2, vertCenterLine.y2], { stroke: 'blue', strokeWidth: 4, property: 'centerLine', fontSize: 14, }) canvas.add(drawLastInLine2) } else { //윗쪽 길게 오른쪽 방향 //배열 순서대로 뒤에꺼를 찾아서 계산한다 firstLine = lines[5] secondLine = lines[1] lastLine = lines[3] const firstSubLine = lines[0] const middleSubLine = lines[2] //ㄴ자 일경우 //긴면 세로선 그리기 let vertCenterPoint = (firstLine.x1 + firstLine.x2) / 2 //가장 긴선 중앙선 가운데 점 vertCenterLine = new QLine( [ vertCenterPoint, firstSubLine.y1 - edge, //다음 선의 높이만큼 가져와서 edge길이를 합함 vertCenterPoint, firstSubLine.y2 + edge, //다음 선의 높이만큼 가져옴 edge길이를 합함 ], { stroke: 'blue', strokeWidth: 5, property: 'bigHoriCenter', fontSize: 14, }, ) canvas.add(vertCenterLine) //긴면 가로선 그리기 let horiCenterPoint = (firstSubLine.y1 + firstSubLine.y2) / 2 let horiCenterLine1 = new QLine( [firstLine.x2 - eaves, horiCenterPoint, firstLine.x2 - eaves + firstLine.length / 2 + eaves, horiCenterPoint], { stroke: 'black', strokeWidth: 4, property: 'centerLine', strokeDashArray: [5, 5], fontSize: 14, }, ) canvas.add(horiCenterLine1) let horiCenterLine2 = new QLine( [ firstLine.x2 - eaves + firstLine.length / 2 + eaves, horiCenterPoint, firstLine.x2 - eaves + firstLine.length / 2 + eaves + firstLine.length / 2 + eaves, horiCenterPoint, ], { stroke: 'black', strokeWidth: 4, property: 'centerLine', strokeDashArray: [5, 5], fontSize: 14, }, ) canvas.add(horiCenterLine2) //작은 지붕쪽 높이 길이를 구하는 로직 let secondVertCenterPoint = (lastLine.x1 + lastLine.x2) / 2 secondVertCenterLine = new QLine([secondVertCenterPoint, middleSubLine.y1, secondVertCenterPoint, middleSubLine.y2 + edge], { stroke: 'blue', strokeWidth: 4, property: 'centerLine', fontSize: 14, }) canvas.add(secondVertCenterLine) //작은 지붕쪽 너비 길이를 구한는 로직 let secondHoriCenterLength = (Math.abs(lastLine.get('x1') - lastLine.get('x2')) + Math.abs(lastLine.get('y1') - lastLine.get('y2'))) / 2 let secondHoriCenterPoint = (secondVertCenterLine.y1 + secondVertCenterLine.y2) / 2 let secondHoriCenterLine = new QLine( [secondVertCenterLine.x1, secondHoriCenterPoint, secondVertCenterLine.x1 - secondHoriCenterLength - eaves, secondHoriCenterPoint], { stroke: 'black', strokeWidth: 4, property: 'centerLine', strokeDashArray: [5, 5], fontSize: 14, }, ) canvas.add(secondHoriCenterLine) //일반라인 외각선 그리기 normalIndexArray.forEach((index) => { const line = lines[index] if (index === 0 || index === 2) { let tmpEdge = index === 2 ? 0 : edge let drawline = new QLine([line.x1 - eaves, line.y1 - tmpEdge, line.x2 - eaves, line.y2 + edge], { stroke: 'blue', strokeWidth: 4, property: 'centerLine', fontSize: 14, }) canvas.add(drawline) } else { let drawline = new QLine([line.x1 + eaves, line.y1 + edge, line.x2 + eaves, line.y2 - edge], { stroke: 'blue', strokeWidth: 4, property: 'centerLine', fontSize: 14, }) canvas.add(drawline) } }) //케라바 라인 외각선 그리기 const firstOuterLine = lines[5] const middleOuterLine = lines[1] const lastOuterLine = lines[3] //첫번째 외곽선 1번 let halfLength = firstOuterLine.length / 2 let drawFirstLine1 = new QLine( [firstOuterLine.x2 - eaves, firstOuterLine.y1 - edge, firstOuterLine.x2 + halfLength, firstOuterLine.y2 - edge], { stroke: 'blue', strokeWidth: 4, property: 'centerLine', fontSize: 14, }, ) canvas.add(drawFirstLine1) //첫번째 외곽선 2번 let drawFirstLine2 = new QLine([drawFirstLine1.x2, drawFirstLine1.y1, drawFirstLine1.x2 + halfLength + eaves, drawFirstLine1.y2], { stroke: 'blue', strokeWidth: 4, property: 'centerLine', fontSize: 14, }) canvas.add(drawFirstLine2) //중간라인 외각선 let drawMiddleLine = new QLine([drawFirstLine1.x1, middleOuterLine.y1 + edge, drawFirstLine1.x2, middleOuterLine.y2 + edge], { stroke: 'blue', strokeWidth: 4, property: 'centerLine', fontSize: 14, }) canvas.add(drawMiddleLine) //마지막 외각선 halfLength = lastLine.length / 2 let drawLastLine1 = new QLine([lastOuterLine.x1 - eaves, lastOuterLine.y1 + edge, lastOuterLine.x1 + halfLength, lastOuterLine.y2 + edge], { stroke: 'blue', strokeWidth: 4, property: 'centerLine', fontSize: 14, }) canvas.add(drawLastLine1) let drawLastLine2 = new QLine([drawLastLine1.x2, drawLastLine1.y1, drawLastLine1.x2 + halfLength + eaves, drawLastLine1.y1], { stroke: 'blue', strokeWidth: 4, property: 'centerLine', fontSize: 14, }) canvas.add(drawLastLine2) let drawLastInLine1 = new QLine([vertCenterLine.x2, vertCenterLine.y2, secondVertCenterLine.x1, vertCenterLine.y2], { stroke: 'blue', strokeWidth: 4, property: 'centerLine', fontSize: 14, }) canvas.add(drawLastInLine1) let drawLastInLine2 = new QLine([secondLine.x2 - eaves, secondLine.y1, drawLastLine1.x2, secondLine.y1], { stroke: 'blue', strokeWidth: 4, property: 'centerLine', fontSize: 14, }) canvas.add(drawLastInLine2) } } canvas.renderAll() } /** * 템플릿 B 적용 */ const applyTemplateB = () => { changeMode(canvas, Mode.EDIT) const polygon = drawWallPolygon() const params = { eaves: 50, edge: 20, polygon, } handleInnerLineColor(polygon) // handleOuterLineTemplateB(params) console.log(polygon.lines.length) if (polygon.lines.length === 4) { handleTemplateBRect(params) } else if (polygon.length === 6) { handleTemplateB(params) } } /** * 4각형일때 계산 로직 * @param {obj} params */ const handleTemplateBRect = (params) => { const { eaves, edge, polygon } = params const centerLinePoint = {} const centerDashLinePoint = {} const qlineOpt = { stroke: 'blue', strokeWidth: 2, selectable: false, fontSize: fontSize, } const qlineOptDash = { stroke: 'black', strokeWidth: 2, strokeDashArray: [5, 5], selectable: false, fontSize: fontSize, } const qlineOptDashWithoutLength = { ...qlineOptDash, isActiveLengthText: false, } polygon.lines.forEach((line, index) => { let outline if (index === 0) { outline = new QLine([line.x1 - edge, line.y1 - eaves, line.x2 - edge, line.y2 + eaves], qlineOpt) const centeredPoint = getCenterPoint(line.y1, line.y2) centerLinePoint.x1 = line.x1 - edge centerLinePoint.y1 = centeredPoint centerLinePoint.y2 = centeredPoint centerDashLinePoint.y1 = line.y1 - eaves centerDashLinePoint.y2 = line.y2 + eaves } else if (index === 1) { outline = new QLine([line.x1 - edge, line.y1 + eaves, line.x2 + edge, line.y2 + eaves], qlineOpt) const centeredPoint = getCenterPoint(line.x1, line.x2) centerLinePoint.x2 = line.x2 + edge centerDashLinePoint.x1 = centeredPoint centerDashLinePoint.x2 = centeredPoint } else if (index === 2) { outline = new QLine([line.x1 + edge, line.y1 + eaves, line.x2 + edge, line.y2 - eaves], qlineOpt) } else if (index === 3) { outline = new QLine([line.x1 + edge, line.y1 - eaves, line.x2 - edge, line.y2 - eaves], qlineOpt) } canvas.add(outline) }) const centerLine = new QLine([centerLinePoint.x1, centerLinePoint.y1, centerLinePoint.x2, centerLinePoint.y2], qlineOpt) canvas.add(centerLine) const centerDashLine1 = new QLine( [centerDashLinePoint.x1, centerDashLinePoint.y1, centerDashLinePoint.x2, getCenterPoint(centerDashLinePoint.y1, centerDashLinePoint.y2)], qlineOptDashWithoutLength, ) canvas.add(centerDashLine1) const centerDashLine2 = new QLine( [centerDashLinePoint.x1, getCenterPoint(centerDashLinePoint.y1, centerDashLinePoint.y2), centerDashLinePoint.x2, centerDashLinePoint.y2], qlineOptDashWithoutLength, ) canvas.add(centerDashLine2) canvas.renderAll() } /** * 6각형일때 계산 로직 * @param {obj} params */ const handleTemplateB = (params) => { const { eaves, edge, polygon } = params // 가장 긴 라인이 첫번째일때 let shapeType = 0 console.log(polygon) const odd = polygon.lines.filter((line, index) => index % 2 === 0) const even = polygon.lines.filter((line, index) => index % 2 !== 0) const rerangeOdd = chgLineDirectionVertical(odd) const rerangeEven = chgLineDirectionHorizontal(even) // 가장 긴 라인이 첫번째인지 판단 chkLengthIndex({ arr: odd, type: 'L' }) !== 0 ? (shapeType = 1) : null // 가장 짧은 라인의 인덱스 반환 const shortIndex = chkLengthIndex({ arr: odd, type: 'S' }) const centralLinePoint = { x1: 0, y1: 0, x2: 0, y2: 0, } const centralSubLinePoint = { x1: 0, y1: 0, x2: 0, y2: 0, } const centralDashLinePoint = { x1: 0, y1: 0, x2: 0, y2: 0, } const centralSubDashLinePoint = { x1: 0, y1: 0, x2: 0, y2: 0, } const qlineOpt = { stroke: 'blue', strokeWidth: 2, selectable: false, fontSize: fontSize, } const qlineOptDash = { stroke: 'black', strokeWidth: 2, strokeDashArray: [5, 5], selectable: false, fontSize: fontSize, } rerangeOdd.forEach((line, index) => { const centeredPoint = getCenterPoint(line.y1, line.y2) let points1 = [] let points2 = [] if (polygon.shape === 2 || polygon.shape === 3) { if (index === 0) { points1 = [line.x1 - edge, line.y1 - eaves, line.x1 - edge, centeredPoint] points2 = [line.x2 - edge, centeredPoint, line.x2 - edge, line.y2 + eaves] centralLinePoint.x1 = line.x1 - edge centralLinePoint.y1 = centeredPoint centralLinePoint.y2 = centeredPoint centralDashLinePoint.y1 = line.y1 - eaves centralDashLinePoint.y2 = line.y2 + eaves } else if (index === 1) { if (polygon.shape === 2) { points1 = [line.x1 + edge, line.y1 - eaves, line.x1 + edge, centeredPoint] points2 = [line.x1 + edge, centeredPoint, line.x2 + edge, line.y2 + eaves] centralSubLinePoint.x2 = line.x1 + edge centralSubLinePoint.y2 = centeredPoint } else { points1 = [line.x1 + edge, getCenterPoint(rerangeOdd[2].y1, rerangeOdd[2].y2), line.x2 + edge, line.y2 + eaves] points2 = [line.x1, getCenterPoint(rerangeOdd[2].y1, rerangeOdd[2].y2), line.x1, line.y1 + eaves] centralLinePoint.x2 = line.x1 + edge centralSubLinePoint.y1 = getCenterPoint(rerangeOdd[2].y1, rerangeOdd[2].y2) centralSubLinePoint.y2 = getCenterPoint(rerangeOdd[2].y1, rerangeOdd[2].y2) } } else if (index === 2) { if (polygon.shape === 2) { points1 = [line.x1 + edge, line.y1 - eaves, line.x2 + edge, centralSubLinePoint.y2] points2 = [line.x2, line.y2 - eaves, line.x2, centralSubLinePoint.y2] } else { points1 = [line.x1 + edge, line.y1 - eaves, line.x2 + edge, centeredPoint] points2 = [line.x2 + edge, centeredPoint, line.x2 + edge, line.y2 + eaves] } } } else { if (index === 0) { points1 = [line.x1 - edge, line.y1 - eaves, line.x2 - edge, line.y2 + eaves] centralSubLinePoint.x1 = line.x1 - edge centralSubLinePoint.y1 = getCenterPoint(line.y1, line.y2) centralSubLinePoint.y2 = getCenterPoint(line.y1, line.y2) } else if (index === 1) { if (polygon.shape === 1) { points1 = [line.x1 - edge, centralSubLinePoint.y1, line.x2 - edge, line.y2 + eaves] points2 = [line.x1, centralSubLinePoint.y1, line.x1, line.y1 + eaves] centralLinePoint.x1 = line.x1 - edge centralSubLinePoint.x2 = line.x2 } else { points1 = [line.x1 + edge, line.y1 - eaves, line.x2 + edge, centeredPoint] points2 = [line.x2 + edge, centeredPoint, line.x2 + edge, line.y2 + eaves] centralLinePoint.x2 = line.x1 + edge centralLinePoint.y1 = centeredPoint centralLinePoint.y2 = centeredPoint centralDashLinePoint.y1 = line.y1 - eaves centralDashLinePoint.y2 = line.y2 + eaves } } else { if (polygon.shape === 1) { points1 = [line.x1 + edge, line.y1 - eaves, line.x1 + edge, centeredPoint] points2 = [line.x2 + edge, centeredPoint, line.x2 + edge, line.y2 + eaves] centralLinePoint.x2 = line.x1 + edge centralLinePoint.y1 = centeredPoint centralLinePoint.y2 = centeredPoint centralDashLinePoint.y1 = line.y1 - eaves centralDashLinePoint.y2 = line.y2 + eaves } else { points1 = [line.x1 - edge, line.y1 - eaves, line.x2 - edge, centralSubLinePoint.y1] points2 = [line.x2, line.y2 - eaves, line.x2, centralSubLinePoint.y2] centralLinePoint.x1 = line.x1 - edge centralSubLinePoint.x2 = line.x2 } } } if (points1.length > 0) { const subLine1 = new QLine(points1, qlineOpt) canvas.add(subLine1) } if (points2.length > 0) { const subLine2 = new QLine(points2, qlineOpt) canvas.add(subLine2) } }) rerangeEven.forEach((line, index) => { let points = [] if (polygon.shape === 2 || polygon.shape === 3) { if (index === 0) { points = [line.x1 - edge, line.y1 + eaves, line.x2 + edge, line.y2 + eaves] if (polygon.shape === 3) { centralDashLinePoint.x1 = getCenterPoint(line.x1, line.x2) centralDashLinePoint.x2 = getCenterPoint(line.x1, line.x2) } } else if (index === 2) { points = [line.x1 - edge, line.y1 - eaves, line.x2 + edge, line.y2 - eaves] if (polygon.shape === 2) { centralDashLinePoint.x1 = getCenterPoint(line.x1, line.x2) centralDashLinePoint.x2 = getCenterPoint(line.x1, line.x2) centralLinePoint.x2 = line.x2 + edge } } else { if (polygon.shape === 2) { const subLines = [ [line.x1, line.y1 - eaves, line.x2 + edge, line.y2 - eaves], [line.x1, centralSubLinePoint.y2, centralSubLinePoint.x2, centralSubLinePoint.y2], ] subLines.forEach((sLine, index) => { const subLine = new QLine(sLine, qlineOpt) canvas.add(subLine) }) centralSubDashLinePoint.x1 = getCenterPoint(line.x1, line.x2 + edge) centralSubDashLinePoint.x2 = getCenterPoint(line.x1, line.x2 + edge) centralSubDashLinePoint.y1 = line.y1 - eaves centralSubDashLinePoint.y2 = centralSubLinePoint.y2 } else { const subLines = [ [line.x1, line.y1 + eaves, line.x2 + edge, line.y2 + eaves], [line.x1, centralSubLinePoint.y1, line.x2 + edge, centralSubLinePoint.y2], ] subLines.forEach((sLine, index) => { const subLine = new QLine(sLine, qlineOpt) canvas.add(subLine) }) centralSubDashLinePoint.x1 = getCenterPoint(line.x1, line.x2 + edge) centralSubDashLinePoint.x2 = getCenterPoint(line.x1, line.x2 + edge) centralSubDashLinePoint.y1 = centralSubLinePoint.y1 centralSubDashLinePoint.y2 = line.y2 + eaves } } } else { if (index === 0) { if (polygon.shape === 1) { const subLines = [ [centralSubLinePoint.x1, centralSubLinePoint.y1, centralSubLinePoint.x2, centralSubLinePoint.y2], [line.x1 - edge, line.y1 + eaves, line.x2, line.y1 + eaves], ] subLines.forEach((sLine, index) => { const subLine = new QLine(sLine, qlineOpt) canvas.add(subLine) }) centralSubDashLinePoint.x1 = getCenterPoint(line.x1 - edge, line.x2) centralSubDashLinePoint.x2 = getCenterPoint(line.x1 - edge, line.x2) centralSubDashLinePoint.y1 = centralSubLinePoint.y1 centralSubDashLinePoint.y2 = line.y2 + eaves } else { points = [line.x1 - edge, line.y1 + eaves, line.x2 + edge, line.y2 + eaves] } } else if (index === 1) { if (polygon.shape === 1) { points = [line.x1 - edge, line.y1 + eaves, line.x2 + edge, line.y2 + eaves] centralDashLinePoint.x1 = getCenterPoint(line.x1, line.x2) centralDashLinePoint.x2 = getCenterPoint(line.x1, line.x2) } else { points = [line.x1 - edge, line.y1 - eaves, line.x2 + edge, line.y2 - eaves] centralDashLinePoint.x1 = getCenterPoint(line.x1, line.x2) centralDashLinePoint.x2 = getCenterPoint(line.x1, line.x2) } } else { if (polygon.shape === 1) { points = [line.x1 - edge, line.y1 - eaves, line.x2 + edge, line.y2 - eaves] } else { const subLines = [ [centralSubLinePoint.x1, centralSubLinePoint.y1, centralSubLinePoint.x2, centralSubLinePoint.y2], [line.x1 - edge, line.y1 - eaves, line.x2, line.y1 - eaves], ] subLines.forEach((sLine, index) => { const subLine = new QLine(sLine, qlineOpt) canvas.add(subLine) }) centralSubDashLinePoint.x1 = getCenterPoint(line.x1 - edge, line.x2) centralSubDashLinePoint.x2 = getCenterPoint(line.x1 - edge, line.x2) centralSubDashLinePoint.y1 = line.y1 - eaves centralSubDashLinePoint.y2 = centralSubLinePoint.y2 } } } if (points.length > 0) { const subLine = new QLine(points, qlineOpt) canvas.add(subLine) } }) const centralLine = new QLine([centralLinePoint.x1, centralLinePoint.y1, centralLinePoint.x2, centralLinePoint.y2], qlineOpt) canvas.add(centralLine) const centralDashLine1 = new QLine([centralDashLinePoint.x1, centralDashLinePoint.y1, centralDashLinePoint.x1, centralLinePoint.y2], qlineOptDash) canvas.add(centralDashLine1) const centralDashLine2 = new QLine([centralDashLine1.x2, centralDashLine1.y2, centralDashLinePoint.x2, centralDashLinePoint.y2], qlineOptDash) canvas.add(centralDashLine2) const centralSubDashLine = new QLine( [centralSubDashLinePoint.x1, centralSubDashLinePoint.y1, centralSubDashLinePoint.x2, centralSubDashLinePoint.y2], qlineOptDash, ) canvas.add(centralSubDashLine) canvas.renderAll() } /** * 세로 방샹 라인의 좌표 순서를 위에서 아래로 변경 * @param {array} arr * @returns */ const chgLineDirectionVertical = (arr) => { const newArr = arr.map((line, index) => { if (line.direction !== 'bottom') { const newPoint = { x1: line.x2, y1: line.y2, x2: line.x1, y2: line.y1 } return newPoint } else { return line } }) return newArr } /** * 가로 방향 라인의 좌표 순서를 왼쪽에서 오른쪽으로 변경 * @param {array} arr * @returns */ const chgLineDirectionHorizontal = (arr) => { const newArr = arr.map((line, index) => { if (line.direction !== 'right') { const newPoint = { x1: line.x2, y1: line.y2, x2: line.x1, y2: line.y1 } return newPoint } else { return line } }) return newArr } /** * 라인 배열 중 가장 긴 라인의 인덱스를 반환합니다. */ const chkLengthIndex = (params) => { const { arr, type } = params let maxIndex = 0 for (let i = 1; i < arr.length; i++) { if (type === 'L') { if (arr[maxIndex].length < arr[i].length) { maxIndex = i } } else { if (arr[maxIndex].length > arr[i].length) { maxIndex = i } } } return maxIndex } /** * 외벽선 색깔을 변경 * @param {array} polygon */ const handleInnerLineColor = (polygon) => { polygon.lines.forEach((line, index) => { if (index % 2 === 0) { line.set('stroke', 'rgb(0, 220, 221)') } else { line.set('stroke', 'rgb(0, 224, 61)') } const overLine = new QLine([line.x1, line.y1, line.x2, line.y2], { stroke: line.stroke, strokeWidth: 2, selectable: false, fontSize: fontSize, isActiveLengthText: false, }) canvas.add(overLine) }) canvas.renderAll() } return { mode, changeMode, setCanvas, handleClear, zoomIn, zoomOut, zoom, togglePolygonLine, handleOuterlinesTest2, } }