From 9fa1ad9e7eeddd4840404c1f2397ff9f4407e3dc Mon Sep 17 00:00:00 2001 From: Jaeyoung Lee Date: Mon, 9 Dec 2024 16:13:10 +0900 Subject: [PATCH 1/3] =?UTF-8?q?=EB=8F=99=EC=84=A0=EC=9D=B4=EB=8F=99=20?= =?UTF-8?q?=EA=B8=B0=EB=8A=A5=20=EC=88=98=EC=A0=95=20=EC=A4=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/fabric/QPolygon.js | 6 - .../modal/movement/type/FlowLine.jsx | 22 +- src/hooks/roofcover/useMovementSetting.js | 263 ++-- src/hooks/useMode.js | 3 +- src/util/qpolygon-utils.js | 1093 +---------------- 5 files changed, 183 insertions(+), 1204 deletions(-) diff --git a/src/components/fabric/QPolygon.js b/src/components/fabric/QPolygon.js index 2202bac0..0f7bd815 100644 --- a/src/components/fabric/QPolygon.js +++ b/src/components/fabric/QPolygon.js @@ -186,12 +186,6 @@ export const QPolygon = fabric.util.createClass(fabric.Polygon, { }) }, - containsPoint: function (point) { - const isInside = this.inPolygon(point) - this.set('selectable', isInside) - return isInside - }, - // 보조선 그리기 drawHelpLine() { // drawHelpLineInHexagon(this, pitch) diff --git a/src/components/floor-plan/modal/movement/type/FlowLine.jsx b/src/components/floor-plan/modal/movement/type/FlowLine.jsx index c6a8ca49..96d9b3d3 100644 --- a/src/components/floor-plan/modal/movement/type/FlowLine.jsx +++ b/src/components/floor-plan/modal/movement/type/FlowLine.jsx @@ -1,6 +1,5 @@ import { useMessage } from '@/hooks/useMessage' -import { useEffect, useState } from 'react' -import { useEvent } from '@/hooks/useEvent' +import { useState } from 'react' const FLOW_LINE_TYPE = { DOWN_LEFT: 'downLeft', @@ -11,16 +10,6 @@ export default function FlowLine({ FLOW_LINE_REF }) { const { getMessage } = useMessage() const [type, setType] = useState(FLOW_LINE_TYPE.DOWN_LEFT) - useEffect(() => { - if (type === FLOW_LINE_TYPE.DOWN_LEFT) { - FLOW_LINE_REF.UP_RIGHT_INPUT_REF.current.value = '' - FLOW_LINE_REF.DOWN_LEFT_INPUT_REF.current.focus() - } else { - FLOW_LINE_REF.DOWN_LEFT_INPUT_REF.current.value = '' - FLOW_LINE_REF.UP_RIGHT_INPUT_REF.current.focus() - } - }, [type]) - return ( <>
@@ -45,7 +34,7 @@ export default function FlowLine({ FLOW_LINE_REF }) {
- + {/**/}
@@ -68,12 +57,7 @@ export default function FlowLine({ FLOW_LINE_REF }) {
- +
mm
diff --git a/src/hooks/roofcover/useMovementSetting.js b/src/hooks/roofcover/useMovementSetting.js index 509c53f3..ced2e72b 100644 --- a/src/hooks/roofcover/useMovementSetting.js +++ b/src/hooks/roofcover/useMovementSetting.js @@ -4,8 +4,7 @@ import { usePopup } from '@/hooks/usePopup' import { useMessage } from '@/hooks/useMessage' import { useEffect, useRef, useState } from 'react' import { useEvent } from '@/hooks/useEvent' -import { POLYGON_TYPE } from '@/common/common' -import { OUTER_LINE_TYPE } from '@/store/outerLineAtom' +import { LINE_TYPE, POLYGON_TYPE } from '@/common/common' //동선이동 형 올림 내림 export function useMovementSetting(id) { @@ -28,8 +27,8 @@ export function useMovementSetting(id) { const typeRef = useRef(type) const FLOW_LINE_REF = { - DOWN_LEFT_INPUT_REF: useRef(null), - UP_RIGHT_INPUT_REF: useRef(null), + POINTER_INPUT_REF: useRef(null), + FILLED_INPUT_REF: useRef(null), DOWN_LEFT_RADIO_REF: useRef(null), UP_RIGHT_RADIO_REF: useRef(null), } @@ -42,37 +41,42 @@ export function useMovementSetting(id) { } useEffect(() => { - removeFlowLine() typeRef.current = type - const outerLines = canvas.getObjects().filter((obj) => obj.name === 'outerLine') // 기존 outerLine의 selectable true - outerLines.forEach((line) => { - line.set({ stroke: 'black' }) - line.set({ visible: false }) - }) canvas.getObjects().forEach((obj) => { obj.set({ selectable: false }) }) const roofs = canvas.getObjects().filter((obj) => obj.name === POLYGON_TYPE.ROOF) // 기존 wallLine의 visible false roofs.forEach((roof) => { + roof.set({ selectable: false }) + roof.set({ strokeWidth: 1 }) + roof.set({ stroke: '#000000' }) roof.innerLines.forEach((line) => { line.bringToFront() line.set({ selectable: false }) line.set({ strokeWidth: 1 }) + line.set({ stroke: '#000000' }) + }) + roof.separatePolygon?.forEach((polygon) => { + polygon.bringToFront() + polygon.set({ selectable: false }) + polygon.set({ strokeWidth: 1 }) + polygon.set({ stroke: '#000000' }) }) }) if (type === TYPE.FLOW_LINE) { roofs.forEach((roof) => { roof.innerLines.forEach((line) => { - line.bringToFront() - line.set({ selectable: true }) - line.set({ strokeWidth: 4 }) + if (line.name === LINE_TYPE.SUBLINE.RIDGE) { + line.bringToFront() + line.set({ selectable: true }) + line.set({ strokeWidth: 4 }) + line.set({ stroke: '#1083E3' }) + } }) }) } else if (type === TYPE.UP_DOWN) { - const outerLines = canvas.getObjects().filter((obj) => obj.name === 'outerLine') // 기존 outerLine의 selectable true - outerLines.forEach((line) => { - line.set({ stroke: 'black' }) - line.set({ visible: true }) + const wallLine = canvas.getObjects().filter((obj) => obj.name === 'wallLine') // 기존 outerLine의 selectable true + wallLine.forEach((line) => { line.bringToFront() line.set({ selectable: true }) }) @@ -81,26 +85,48 @@ export function useMovementSetting(id) { }, [type]) useEffect(() => { - /*const wallLines = canvas.getObjects().filter((obj) => obj.name === POLYGON_TYPE.WALL) // 기존 wallLine의 visible false - wallLines.forEach((line) => { - line.set({ visible: false }) - })*/ - canvas.renderAll() addCanvasMouseEventListener('mouse:move', mouseMoveEvent) addCanvasMouseEventListener('mouse:down', mouseDownEvent) + return () => { initEvent() - removeFlowLine() + const wallLines = canvas.getObjects().filter((obj) => obj.name === POLYGON_TYPE.WALL) wallLines.forEach((line) => { line.set({ visible: true }) }) - const outerLines = canvas.getObjects().filter((obj) => obj.name === 'outerLine') // 기존 outerLine의 selectable true - outerLines.forEach((line) => { - line.set({ stroke: 'black' }) - line.set({ visible: false }) + const wallLine = canvas.getObjects().filter((obj) => obj.name === 'wallLine') // 기존 outerLine의 selectable true + wallLine.forEach((line) => { + let wallStroke, wallStrokeWidth + switch (line.attributes.type) { + case LINE_TYPE.WALLLINE.EAVES: + wallStroke = '#45CD7D' + wallStrokeWidth = 4 + break + case LINE_TYPE.WALLLINE.HIPANDGABLE: + wallStroke = '#45CD7D' + wallStrokeWidth = 4 + break + case LINE_TYPE.WALLLINE.GABLE: + wallStroke = '#3FBAE6' + wallStrokeWidth = 4 + break + case LINE_TYPE.WALLLINE.JERKINHEAD: + wallStroke = '#3FBAE6' + wallStrokeWidth = 4 + break + case LINE_TYPE.WALLLINE.SHED: + wallStroke = '#000000' + wallStrokeWidth = 4 + break + case LINE_TYPE.WALLLINE.WALL: + wallStroke = '#000000' + wallStrokeWidth = 4 + break + } + line.set({ selectable: false, stroke: wallStroke, strokeWidth: wallStrokeWidth }) }) canvas.renderAll() @@ -108,19 +134,14 @@ export function useMovementSetting(id) { }, []) useEffect(() => { - const outerLines = canvas.getObjects().filter((obj) => obj.name === 'outerLine') // 기존 outerLine의 selectable true - outerLines.forEach((line) => { - line.set({ stroke: 'black' }) - }) selectedObject.current = null - if (!currentObject) { return } clearRef() selectedObject.current = currentObject - if (currentObject.name === OUTER_LINE_TYPE.OUTER_LINE) { + if (currentObject.name === 'wallLine') { currentObject.set({ stroke: '#EA10AC' }) currentObject.bringToFront() } @@ -129,34 +150,26 @@ export function useMovementSetting(id) { const clearRef = () => { if (type === TYPE.FLOW_LINE) { - FLOW_LINE_REF.DOWN_LEFT_INPUT_REF.current.value = '' - FLOW_LINE_REF.UP_RIGHT_INPUT_REF.current.value = '' - FLOW_LINE_REF.DOWN_LEFT_RADIO_REF.current.checked = false + FLOW_LINE_REF.FILLED_INPUT_REF.current.value = '' + FLOW_LINE_REF.DOWN_LEFT_RADIO_REF.current.checked = true FLOW_LINE_REF.UP_RIGHT_RADIO_REF.current.checked = false } if (type === TYPE.UP_DOWN) { UP_DOWN_REF.UP_INPUT_REF.current.value = '' UP_DOWN_REF.DOWN_INPUT_REF.current.value = '' - UP_DOWN_REF.UP_RADIO_REF.current.checked = false + UP_DOWN_REF.UP_RADIO_REF.current.checked = true UP_DOWN_REF.DOWN_RADIO_REF.current.checked = false } } const mouseDownEvent = (e) => { if (typeRef.current === TYPE.FLOW_LINE) { - flowLineDownEvent(e) + saveFlowLine(e) } else { updownDownEvent(e) } } - const removeFlowLine = () => { - const flowLine = canvas.getObjects().filter((obj) => obj.name === 'flowLine') - flowLine.forEach((line) => { - canvas.remove(line) - }) - } - const mouseMoveEvent = (e) => { if (typeRef.current === TYPE.FLOW_LINE) { flowLineMoveEvent(e) @@ -165,61 +178,92 @@ export function useMovementSetting(id) { } } //동선 이동 마우스 클릭 이벤트 - const flowLineDownEvent = (e) => { + const saveFlowLine = (e) => { const target = selectedObject.current if (!target) { return } - const direction = target.direction - - removeFlowLine() - let newPoint = [] - if (direction === 'left' || direction === 'right') { - if (FLOW_LINE_REF.DOWN_LEFT_RADIO_REF.current.checked) { - newPoint = [ - target.x1, - target.y1 + Number(FLOW_LINE_REF.DOWN_LEFT_INPUT_REF.current.value / 10), - target.x2, - target.y2 + Number(FLOW_LINE_REF.DOWN_LEFT_INPUT_REF.current.value / 10), - ] - } else { - newPoint = [ - target.x1, - target.y1 - Number(FLOW_LINE_REF.UP_RIGHT_INPUT_REF.current.value / 10), - target.x2, - target.y2 - Number(FLOW_LINE_REF.UP_RIGHT_INPUT_REF.current.value / 10), - ] - } + if (Math.sign(target.x1 - target.x2) !== 0) { + newPoint = [ + target.x1, + target.y1 - Number(FLOW_LINE_REF.FILLED_INPUT_REF.current.value / 10), + target.x2, + target.y2 - Number(FLOW_LINE_REF.FILLED_INPUT_REF.current.value / 10), + ] } else { - if (FLOW_LINE_REF.DOWN_LEFT_RADIO_REF.current.checked) { - newPoint = [ - target.x1 - Number(FLOW_LINE_REF.DOWN_LEFT_INPUT_REF.current.value / 10), - target.y1, - target.x2 - Number(FLOW_LINE_REF.DOWN_LEFT_INPUT_REF.current.value / 10), - target.y2, - ] - } else { - newPoint = [ - target.x1 + Number(FLOW_LINE_REF.UP_RIGHT_INPUT_REF.current.value / 10), - target.y1, - target.x2 + Number(FLOW_LINE_REF.UP_RIGHT_INPUT_REF.current.value / 10), - target.y2, - ] - } + newPoint = [ + target.x1 + Number(FLOW_LINE_REF.FILLED_INPUT_REF.current.value / 10), + target.y1, + target.x2 + Number(FLOW_LINE_REF.FILLED_INPUT_REF.current.value / 10), + target.y2, + ] } - const cloned = new fabric.Line(newPoint, { - stroke: 'red', - strokeWidth: 4, - name: 'flowLine', - currentLine: target, - }) + clearRef() + const cloned = new fabric.Line(newPoint, {}) + let currentObject = selectedObject.current + const currentX1 = currentObject.x1, + currentY1 = currentObject.y1, + currentX2 = currentObject.x2, + currentY2 = currentObject.y2 + + const roof = canvas.getObjects().find((obj) => obj.id === currentObject.attributes.roofId) + if (roof.separatePolygon.length > 0) { + const separatePolygon = roof.separatePolygon + separatePolygon + .filter((polygon) => + polygon.points.some((point) => (point.x === currentX1 && point.y === currentY1) || (point.x === currentX2 && point.y === currentY2)), + ) + .forEach((polygon) => { + const newPoints = polygon.points.map((point) => { + if (point.x === currentX1 && point.y === currentY1) { + return { x: newPoint[0], y: newPoint[1] } + } else if (point.x === currentX2 && point.y === currentY2) { + return { x: newPoint[2], y: newPoint[3] } + } else { + return point + } + }) + polygon.set({ points: newPoints }) + }) + } else { + roof.innerLines + .filter((line) => currentObject !== line) + .filter( + (line) => + (line.x1 === currentX1 && line.y1 === currentY1) || + (line.x2 === currentX1 && line.y2 === currentY1) || + (line.x1 === currentX2 && line.y1 === currentY2) || + (line.x2 === currentX2 && line.y2 === currentY2), + ) + .forEach((line) => { + console.log('line : ', line) + if (line.x1 === currentX1 && line.y1 === currentY1) { + line.set({ x1: newPoint[0], y1: newPoint[1] }) + } else if (line.x2 === currentX1 && line.y2 === currentY1) { + line.set({ x2: newPoint[0], y2: newPoint[1] }) + } else if (line.x1 === currentX2 && line.y1 === currentY2) { + line.set({ x1: newPoint[2], y1: newPoint[3] }) + } else if (line.x2 === currentX2 && line.y2 === currentY2) { + line.set({ x2: newPoint[2], y2: newPoint[3] }) + } + line.setCoords() + }) + } + + currentObject.set({ x1: cloned.x1, y1: cloned.y1, x2: cloned.x2, y2: cloned.y2 }) + currentObject.setCoords() + + console.log('currentObject : ', currentObject.x1, currentObject.y1, currentObject.x2, currentObject.y2) - canvas.add(cloned) canvas.renderAll() canvas.discardActiveObject() + + if (roof.separatePolygon.length > 0) { + console.log('roof.separatePolygon : ', roof.separatePolygon) + } } //형 올림내림 마우스 클릭 이벤트 @@ -231,35 +275,25 @@ export function useMovementSetting(id) { if (!target) { return } - const direction = target.direction const { top: targetTop, left: targetLeft } = target const currentX = canvas.getPointer(e.e).x const currentY = Math.floor(canvas.getPointer(e.e).y) - if (direction === 'left' || direction === 'right') { + if (Math.sign(target.x1 - target.x2) !== 0) { if (targetTop > currentY) { - console.log('targetTop > currentY') FLOW_LINE_REF.UP_RIGHT_RADIO_REF.current.checked = true - FLOW_LINE_REF.DOWN_LEFT_INPUT_REF.current.value = '' - - FLOW_LINE_REF.UP_RIGHT_INPUT_REF.current.value = Math.floor((Number(Math.abs(targetTop - currentY)) / 10000).toFixed(5) * 100000) + FLOW_LINE_REF.FILLED_INPUT_REF.current.value = Math.floor((Number(Math.round(targetTop - currentY)) / 10000).toFixed(5) * 100000) } else { FLOW_LINE_REF.DOWN_LEFT_RADIO_REF.current.checked = true - FLOW_LINE_REF.UP_RIGHT_INPUT_REF.current.value = '' - - FLOW_LINE_REF.DOWN_LEFT_INPUT_REF.current.value = Math.floor((Number(Math.abs(targetTop - currentY)) / 10000).toFixed(5) * 100000) + FLOW_LINE_REF.FILLED_INPUT_REF.current.value = Math.floor((Number(Math.round(targetTop - currentY)) / 10000).toFixed(5) * 100000) } } else { if (targetLeft > currentX) { - FLOW_LINE_REF.DOWN_LEFT_RADIO_REF.current.checked = true - FLOW_LINE_REF.UP_RIGHT_INPUT_REF.current.value = '' - - FLOW_LINE_REF.DOWN_LEFT_INPUT_REF.current.value = Math.floor((Number(Math.abs(targetLeft - currentX)) / 10000).toFixed(5) * 100000) - } else { FLOW_LINE_REF.UP_RIGHT_RADIO_REF.current.checked = true - FLOW_LINE_REF.DOWN_LEFT_INPUT_REF.current.value = '' - - FLOW_LINE_REF.UP_RIGHT_INPUT_REF.current.value = Math.floor((Number(Math.abs(targetLeft - currentX)) / 10000).toFixed(5) * 100000) + FLOW_LINE_REF.FILLED_INPUT_REF.current.value = Math.floor((Number(Math.round(currentX - targetLeft)) / 10000).toFixed(5) * 100000) + } else { + FLOW_LINE_REF.DOWN_LEFT_RADIO_REF.current.checked = true + FLOW_LINE_REF.FILLED_INPUT_REF.current.value = Math.floor((Number(Math.round(currentX - targetLeft)) / 10000).toFixed(5) * 100000) } } @@ -307,24 +341,7 @@ export function useMovementSetting(id) { const handleSave = () => { if (type === TYPE.FLOW_LINE) { - const flowLine = canvas.getObjects().find((obj) => obj.name === 'flowLine') - - const currentLine = flowLine.currentLine - if (!flowLine || !currentLine) { - return - } - - currentLine.set({ - x1: flowLine.x1, - y1: flowLine.y1, - x2: flowLine.x2, - y2: flowLine.y2, - }) - currentLine.startPoint = { x: flowLine.x1, y: flowLine.y1 } - currentLine.endPoint = { x: flowLine.x2, y: flowLine.y2 } - - canvas.remove(flowLine) - canvas.renderAll() + saveFlowLine() } else { // 형 올림내림 if (UP_DOWN_REF.UP_RADIO_REF.current.checked) { diff --git a/src/hooks/useMode.js b/src/hooks/useMode.js index 6f6f3ad7..99819ad6 100644 --- a/src/hooks/useMode.js +++ b/src/hooks/useMode.js @@ -1806,7 +1806,8 @@ export function useMode() { break } const wallLine = new fabric.Line([line.x1, line.y1, line.x2, line.y2], { - attributes: { wallId: wall.id }, + name: 'wallLine', + attributes: { wallId: wall.id, roofId: roof.id }, stroke: wallStroke, strokeWidth: wallStrokeWidth, selectable: false, diff --git a/src/util/qpolygon-utils.js b/src/util/qpolygon-utils.js index 4f1e9178..b2253953 100644 --- a/src/util/qpolygon-utils.js +++ b/src/util/qpolygon-utils.js @@ -1,6 +1,6 @@ import { fabric } from 'fabric' import { QLine } from '@/components/fabric/QLine' -import { calculateIntersection, distanceBetweenPoints, findClosestPoint, getDegreeByChon, getDirectionByPoint } from '@/util/canvas-util' +import { getDegreeByChon } from '@/util/canvas-util' import { QPolygon } from '@/components/fabric/QPolygon' import * as turf from '@turf/turf' @@ -15,445 +15,6 @@ export const defineQPloygon = () => { } } -export const drawHelpLineInHexagon = (polygon, pitch) => { - const centerLines = drawCenterLines(polygon) - - let helpLines = [] - - const interSectionPoints = [] - const tempInterSectionPoints = [] - - const ridgeStartPoints = [] - const ridgeEndPoints = [] - - let centerInterSectionPoints = [] - - // polygon.lines = polygon.lines.sort((a, b) => a.length - b.length) - polygon.wall.lines = getOneSideLines(polygon.wall) - - const maxLength = Math.max(...polygon.lines.map((line) => line.length)) - - polygon.points.forEach((point, index) => { - const wallPoint = polygon.wall.points[index] - - const angle = Math.atan2(wallPoint.y - point.y, wallPoint.x - point.x) - - const degree = fabric.util.radiansToDegrees(angle) - - const newX2 = Math.floor(point.x + maxLength * Math.cos(angle)) - const newY2 = Math.floor(point.y + maxLength * Math.sin(angle)) - - const helpLine = new QLine([point.x, point.y, newX2, newY2], { - fontSize: polygon.fontSize, - stroke: 'green', - startPoint: point, - degree: degree, - idx: index, - }) - - // polygon.canvas?.add(helpLine) - - helpLines.push(helpLine) - }) - - helpLines.forEach((line, index) => { - for (let i = index + 1; i < helpLines.length; i++) { - const nextLine = helpLines[i] - if (!line.connectedPoint) { - line.connectedPoint = null - line.connectedPoints = [] - } - if (!nextLine.connectedPoint) { - nextLine.connectedPoint = null - nextLine.connectedPoints = [] - } - - const interSectionPoint = calculateIntersection(line, nextLine) - - if ( - interSectionPoint && - polygon.inPolygon(interSectionPoint) && - polygon.wall.inPolygon(interSectionPoint) && - Math.abs(distanceBetweenPoints(line.startPoint, interSectionPoint) - distanceBetweenPoints(nextLine.startPoint, interSectionPoint)) < 2 - ) { - const area = calculateTriangleArea(line.startPoint, nextLine.startPoint, interSectionPoint) - const currentLineConnectedPoint = line.connectedPoint - const nextLineConnectedPoint = nextLine.connectedPoint - - if (area <= 1) { - return - } - - if (currentLineConnectedPoint && currentLineConnectedPoint.area < area) { - return - } - - //startPoint는 line의 startPoint와 nextLine의 startPoint를 비교하여 x가 같은경우 y가 더 작은 값, y가 같은경우 x가 더 작은 값을 선택한다. - const startPoint = - line.startPoint.x === nextLine.startPoint.x - ? line.startPoint.y < nextLine.startPoint.y - ? line.startPoint - : nextLine.startPoint - : line.startPoint.x < nextLine.startPoint.x - ? line.startPoint - : nextLine.startPoint - - const endPoint = - line.startPoint.x === nextLine.startPoint.x - ? line.startPoint.y > nextLine.startPoint.y - ? line.startPoint - : nextLine.startPoint - : line.startPoint.x > nextLine.startPoint.x - ? line.startPoint - : nextLine.startPoint - - line.connectedPoint = { interSectionPoint, area, startPoint, endPoint } - line.connectedPoints.push({ interSectionPoint, area, startPoint, endPoint }) - nextLine.connectedPoint = { interSectionPoint, area, startPoint, endPoint } - nextLine.connectedPoints.push({ interSectionPoint, area, startPoint, endPoint }) - } - } - }) - - helpLines.forEach((line) => { - if (line.connectedPoint) { - tempInterSectionPoints.push(line.connectedPoint) - } - }) - - // interSectionPoints에서 interSectionPoint가 중복인 값이 있는 경우만 선택한다. - tempInterSectionPoints.forEach((point) => { - // intersectionPoint가 중복인 경우 - const isDuplicated = - tempInterSectionPoints.filter((p) => p.interSectionPoint.x === point.interSectionPoint.x && p.interSectionPoint.y === point.interSectionPoint.y) - .length > 1 - if (isDuplicated) { - interSectionPoints.push(point) - } - }) - - // interSectionPoints에서 interSectionPoint 기준으로 중복을 제거한다. - const uniqueInterSectionPoints = Array.from( - new Set(interSectionPoints.map((point) => `${point.interSectionPoint.x},${point.interSectionPoint.y}`)), - ).map((key) => { - const { interSectionPoint, area, startPoint, endPoint } = interSectionPoints.find( - (point) => `${point.interSectionPoint.x},${point.interSectionPoint.y}` === key, - ) - return { interSectionPoint, area, startPoint, endPoint } - }) - - uniqueInterSectionPoints.forEach((point) => { - ridgeStartPoints.push(point.interSectionPoint) - - const line = new QLine([point.startPoint.x, point.startPoint.y, point.interSectionPoint.x, point.interSectionPoint.y], { - stroke: 'purple', - fontSize: polygon.fontSize, - name: 'hip', - }) - - const line2 = new QLine([point.endPoint.x, point.endPoint.y, point.interSectionPoint.x, point.interSectionPoint.y], { - stroke: 'purple', - fontSize: polygon.fontSize, - name: 'hip', - }) - - line.startPoint = point.startPoint - line.endPoint = point.interSectionPoint - - line2.startPoint = point.endPoint - line2.endPoint = point.interSectionPoint - - polygon.hips.push(line) - polygon.hips.push(line2) - - polygon.canvas.add(line) - polygon.canvas.add(line2) - }) - - const removedIdx = [] - - helpLines.forEach((line) => { - const connectedPoints = line.connectedPoints - connectedPoints.forEach((connectedPoint) => { - uniqueInterSectionPoints.forEach((point) => { - const interSectionPoint = point.interSectionPoint - - if (connectedPoint.interSectionPoint.x === interSectionPoint.x && connectedPoint.interSectionPoint.y === interSectionPoint.y) { - removedIdx.push(line.idx) - } - }) - }) - }) - - let notIntersectedLines = helpLines.filter((line) => !removedIdx.includes(line.idx)) - - notIntersectedLines = notIntersectedLines.map((line) => { - return { ...line, centerInterSectionPoints: [] } - }) - - notIntersectedLines.forEach((line) => { - centerLines.forEach((centerLine) => { - const interSectionPoint = calculateIntersection(line, centerLine) - - if (interSectionPoint && polygon.inPolygon(interSectionPoint) && polygon.wall.inPolygon(interSectionPoint)) { - line.centerInterSectionPoints.push(interSectionPoint) - interSectionPoint.lineIdx = line.idx - centerInterSectionPoints.push(interSectionPoint) - } - }) - }) - - // centerInterSectionPoints에서 ridgeStartPoints와 x가 같거나 y가 같은것중 가장 가까운 점들을 찾는다. - ridgeStartPoints.forEach((point) => { - const xPoints = centerInterSectionPoints.filter((centerPoint) => Math.abs(centerPoint.x - point.x) < 2) - - const yPoints = centerInterSectionPoints.filter((centerPoint) => Math.abs(centerPoint.y - point.y) < 2) - let closestPoint - if (xPoints.length === 0) { - closestPoint = findClosestPoint(point, yPoints) - } else if (yPoints.length === 0) { - closestPoint = findClosestPoint(point, xPoints) - } - - if (closestPoint) { - const line = new QLine([point.x, point.y, closestPoint.x, closestPoint.y], { - stroke: 'purple', - fontSize: polygon.fontSize, - name: 'ridge', - direction: getDirectionByPoint(point, closestPoint), - }) - - line.startPoint = point - line.endPoint = closestPoint - - polygon.ridges.push(line) - polygon.canvas.add(line) - ridgeEndPoints.push(closestPoint) - - notIntersectedLines = notIntersectedLines.filter((line) => line.idx !== closestPoint.lineIdx) - } - }) - - centerInterSectionPoints = [] - notIntersectedLines.forEach((line) => { - centerInterSectionPoints.push(...line.centerInterSectionPoints) - }) - - // ridgeEndPoints끼리 이어준다. - const remainingPoints = [...ridgeEndPoints] - - // ridgeEndPoint에서 centerInterSectionPoints와 45도인 점을 찾아 이어준다. - - ridgeEndPoints.forEach((ridgePoint) => { - const filteredCenterInterSectionPoints = centerInterSectionPoints.filter((centerPoint) => { - const degree = calculateAngle(ridgePoint, centerPoint) - return Math.abs(degree) === 45 || Math.abs(degree) === 135 - })[0] - - if (filteredCenterInterSectionPoints) { - const line = new QLine([ridgePoint.x, ridgePoint.y, filteredCenterInterSectionPoints.x, filteredCenterInterSectionPoints.y], { - stroke: 'purple', - fontSize: polygon.fontSize, - name: 'hip', - }) - - if (line.length === 0) { - return - } - - line.startPoint = ridgePoint - line.endPoint = filteredCenterInterSectionPoints - - polygon.hips.push(line) - polygon.canvas.add(line) - - ridgeStartPoints.push(filteredCenterInterSectionPoints) - - polygon.points.forEach((point) => { - const degree = calculateAngle(ridgePoint, point) - - if (Math.abs(degree) % 45 < 1) { - const line = new QLine([ridgePoint.x, ridgePoint.y, point.x, point.y], { - stroke: 'purple', - fontSize: polygon.fontSize, - name: 'hip', - }) - - polygon.hips.push(line) - polygon.canvas.add(line) - } - }) - } - }) - - // ridgeEndPoint끼리 연결한다. - while (remainingPoints.length > 1) { - const startPoint = remainingPoints.shift() - const endPoint = remainingPoints.shift() - - if (!(startPoint.x === endPoint.x && startPoint.y === endPoint.y)) { - const line = new QLine([startPoint.x, startPoint.y, endPoint.x, endPoint.y], { - stroke: 'purple', - fontSize: polygon.fontSize, - name: 'connectRidge', - }) - - line.startPoint = startPoint - line.endPoint = endPoint - - polygon.connectRidges.push(line) - - polygon.points.forEach((point) => { - const degree = calculateAngle(startPoint, point) - - if (Math.abs(degree) === 45 || Math.abs(degree) === 135) { - const line = new QLine([startPoint.x, startPoint.y, point.x, point.y], { - stroke: 'purple', - fontSize: polygon.fontSize, - name: 'hip', - }) - - line.startPoint = startPoint - line.endPoint = point - - polygon.hips.push(line) - polygon.canvas.add(line) - } - }) - - polygon.points.forEach((point) => { - const degree = calculateAngle(endPoint, point) - - if (Math.abs(degree) === 45 || Math.abs(degree) === 135) { - const line = new QLine([endPoint.x, endPoint.y, point.x, point.y], { - stroke: 'purple', - fontSize: polygon.fontSize, - name: 'hip', - }) - - line.startPoint = endPoint - line.endPoint = point - - polygon.hips.push(line) - polygon.canvas.add(line) - } - }) - - polygon.canvas.add(line) - } else { - polygon.points.forEach((point) => { - const degree = calculateAngle(startPoint, point) - - if (Math.abs(degree) === 45 || Math.abs(degree) === 135) { - const line = new QLine([startPoint.x, startPoint.y, point.x, point.y], { - stroke: 'purple', - fontSize: polygon.fontSize, - name: 'hip', - }) - - line.startPoint = startPoint - line.endPoint = point - - polygon.hips.push(line) - polygon.canvas.add(line) - } - }) - } - } -} - -export const drawCenterLines = (polygon) => { - const centerLines = [] - - const oneSideLines = polygon.lines.map((line) => getOneSideLine(line)) - - const horizontalLines = oneSideLines.filter((line) => line.direction === 'right') - const verticalLines = oneSideLines.filter((line) => line.direction === 'bottom') - // horizontalLines 를 y1 좌표 기준으로 정렬한다. - horizontalLines.sort((a, b) => a.y1 - b.y1) - // verticalLines 를 x1 좌표 기준으로 정렬한다. - verticalLines.sort((a, b) => a.x1 - b.x1) - - let maxHorizontalLineLength = 0 - let maxVerticalLineLength = 0 - // 모든 가로선의 중심선을 긋는다. - horizontalLines.forEach((line, index) => { - const nextLine = horizontalLines[(index + 1) % horizontalLines.length] - - polygon.canvas.renderAll() - - const startCenterX = Math.min(line.x1, nextLine.x1) - const startCenterY = (line.y1 + nextLine.y1) / 2 - - const endCenterX = line.x2 > nextLine.x2 ? line.x2 : nextLine.x2 - const endCenterY = startCenterY - - const centerLine = new QLine([startCenterX, startCenterY, endCenterX, endCenterY], { - fontSize: polygon.fontSize, - stroke: 'red', - strokeWidth: 1, - direction: 'horizontal', - }) - - centerLines.push(centerLine) - }) - - // 모든 세로선의 중심선을 긋는다. - verticalLines.forEach((line, index) => { - const nextLine = verticalLines[(index + 1) % verticalLines.length] - - const startCenterX = (line.x1 + nextLine.x1) / 2 - const startCenterY = Math.min(line.y1, nextLine.y1) - - const endCenterX = startCenterX - let endCenterY = line.y2 > nextLine.y2 ? line.y2 : nextLine.y2 - - const centerLine = new QLine([startCenterX, startCenterY, endCenterX, endCenterY], { - fontSize: polygon.fontSize, - stroke: 'blue', - strokeWidth: 1, - direction: 'vertical', - }) - - centerLines.push(centerLine) - }) - - return centerLines -} - -const getOneSideLines = (polygon) => { - return [...polygon.lines].map((line) => { - let newX1, newY1, newX2, newY2 - if (line.direction === 'top') { - newX1 = line.x2 - newY1 = line.y2 - newX2 = line.x1 - newY2 = line.y1 - - line.x1 = newX1 - line.y1 = newY1 - line.x2 = newX2 - line.y2 = newY2 - line.direction = 'bottom' - line.startPoint = { x: newX1, y: newY1 } - line.endPoint = { x: newX2, y: newY2 } - } else if (line.direction === 'left') { - newX1 = line.x2 - newY1 = line.y2 - newX2 = line.x1 - newY2 = line.y1 - - line.x1 = newX1 - line.y1 = newY1 - line.x2 = newX2 - line.y2 = newY2 - line.direction = 'right' - line.startPoint = { x: newX1, y: newY1 } - line.endPoint = { x: newX2, y: newY2 } - } - return line - }) -} export const calculateAngle = (point1, point2) => { const deltaX = point2.x - point1.x const deltaY = point2.y - point1.y @@ -461,267 +22,6 @@ export const calculateAngle = (point1, point2) => { return angleInRadians * (180 / Math.PI) } -/** - * 3개의 점을 이용해 직각 이등변 삼각형인지 확인 - * @param point1 - * @param point2 - * @param point3 - * @returns {boolean} - */ -const isRightIsoscelesTriangle = (point1, point2, point3) => { - const distance = (p1, p2) => Math.sqrt(Math.pow(p2.x - p1.x, 2) + Math.pow(p2.y - p1.y, 2)) - - const d1 = distance(point1, point2) - const d2 = distance(point2, point3) - const d3 = distance(point3, point1) - - const distances = [d1, d2, d3].sort((a, b) => a - b) - - // Check if the two smaller distances are equal and the largest distance is the hypotenuse - return distances[0] === distances[1] && Math.abs(Math.pow(distances[0], 2) * 2 - Math.pow(distances[2], 2)) < 1 -} - -/** - * 세개의 점으로 삼각형의 넓이를 구한다. - * @param point1 - * @param point2 - * @param point3 - * @returns {number} - */ -const calculateTriangleArea = (point1, point2, point3) => { - const { x: x1, y: y1 } = point1 - const { x: x2, y: y2 } = point2 - const { x: x3, y: y3 } = point3 - - return Math.abs(x1 * (y2 - y3) + x2 * (y3 - y1) + x3 * (y1 - y2)) / 2 -} - -// polygon을 나눈다. -export const dividePolygon = (polygon) => { - let hips = polygon.hips - const ridges = polygon.ridges.map((ridge) => getOneSideLine(ridge)) - const connectRidges = polygon.connectRidges - const polygonLines = polygon.lines - - hips.forEach((hip) => { - // hips의 startPoint와 endPoint를 polygon의 points와 비교하여 같은 점이 endPoint일 경우 startPoint로 변경한다. - const startPoint = polygon.points.find((point) => point.x === hip.endPoint.x && point.y === hip.endPoint.y) - if (startPoint) { - const temp = hip.startPoint - hip.startPoint = hip.endPoint - hip.endPoint = temp - } - }) - hips = [...hips, ...connectRidges] - - polygonLines.forEach((line, index) => { - let ridge - - const startPoint = line.startPoint - const endPoint = line.endPoint - let polygonPoints = [] - - polygonPoints.push(startPoint) - - polygonPoints.push(endPoint) - - const startHip = hips.find((hip) => hip.startPoint.x === startPoint.x && hip.startPoint.y === startPoint.y) - const endHip = hips.find((hip) => hip.startPoint.x === endPoint.x && hip.startPoint.y === endPoint.y) - - if (!startHip || !endHip) { - return - } - - if (startHip && endHip && startHip.endPoint.x === endHip.endPoint.x && startHip.endPoint.y === endHip.endPoint.y) { - polygonPoints.push(startHip.endPoint) - - const newPolygon = new QPolygon(polygonPoints, { - fontSize: polygon.fontSize, - parentId: polygon.id, - name: 'roof', - selectable: false, - stroke: 'black', - fill: 'transparent', - strokeWidth: 3, - }) - - polygon.canvas.add(newPolygon) - return - } - - let connectedRidge - const restRidgeConnection = connectRidges[0] - - if (!restRidgeConnection || restRidgeConnection.length === 0) { - connectedRidge = ridges.find( - (ridge) => - (ridge.startPoint.x === startHip.endPoint.x && - ridge.startPoint.y === startHip.endPoint.y && - ridge.endPoint.x === endHip.endPoint.x && - ridge.endPoint.y === endHip.endPoint.y) || - (ridge.startPoint.x === endHip.endPoint.x && - ridge.startPoint.y === endHip.endPoint.y && - ridge.endPoint.x === startHip.endPoint.x && - ridge.endPoint.y === startHip.endPoint.y), - ) - } else { - connectedRidge = ridges.find( - (ridge) => - (ridge.startPoint.x === startHip.endPoint.x && ridge.startPoint.y === startHip.endPoint.y) || - (ridge.endPoint.x === startHip.endPoint.x && ridge.endPoint.y === startHip.endPoint.y), - ) - } - - const hipStartPoint = startHip.endPoint - const hipEndPoint = endHip.endPoint - - if (connectedRidge.startPoint.x === hipStartPoint.x && connectedRidge.startPoint.y === hipStartPoint.y) { - if (connectedRidge.endPoint.x === hipEndPoint.x && connectedRidge.endPoint.y === hipEndPoint.y) { - polygonPoints.push(connectedRidge.endPoint) - polygonPoints.push(connectedRidge.startPoint) - - const newPolygon = new QPolygon(polygonPoints, { - fontSize: polygon.fontSize, - parentId: polygon.id, - name: 'roof', - selectable: false, - stroke: 'black', - fill: 'transparent', - strokeWidth: 3, - }) - - polygon.canvas.add(newPolygon) - return - } - } else if (connectedRidge.endPoint.x === hipStartPoint.x && connectedRidge.endPoint.y === hipStartPoint.y) { - if (connectedRidge.startPoint.x === hipEndPoint.x && connectedRidge.startPoint.y === hipEndPoint.y) { - polygonPoints.push(connectedRidge.startPoint) - polygonPoints.push(connectedRidge.endPoint) - - const newPolygon = new QPolygon(polygonPoints, { - fontSize: polygon.fontSize, - parentId: polygon.id, - name: 'roof', - selectable: false, - stroke: 'black', - fill: 'transparent', - strokeWidth: 3, - sort: true, - }) - - polygon.canvas.add(newPolygon) - return - } - } - - // 지붕이 꺾여있는 경우 - - if ( - (restRidgeConnection.startPoint.x === startHip.endPoint.x && restRidgeConnection.startPoint.y === startHip.endPoint.y) || - (restRidgeConnection.endPoint.x === startHip.endPoint.x && restRidgeConnection.endPoint.y === startHip.endPoint.y) - ) { - polygonPoints = [startPoint, startHip.endPoint] - let lastPoint - - if (restRidgeConnection.startPoint.x === startHip.endPoint.x && restRidgeConnection.startPoint.y === startHip.endPoint.y) { - lastPoint = restRidgeConnection.endPoint - polygonPoints.push(restRidgeConnection.endPoint) - } else { - lastPoint = restRidgeConnection.startPoint - polygonPoints.push(restRidgeConnection.startPoint) - } - - connectedRidge = ridges.find( - (ridge) => - (ridge.startPoint.x === lastPoint.x && ridge.startPoint.y === lastPoint.y) || - (ridge.endPoint.x === lastPoint.x && ridge.endPoint.y === lastPoint.y), - ) - - if (connectedRidge.startPoint.x === lastPoint.x && connectedRidge.startPoint.y === lastPoint.y) { - polygonPoints.push(connectedRidge.endPoint) - } else { - polygonPoints.push(connectedRidge.startPoint) - } - - polygonPoints.push(endPoint) - } else { - polygonPoints = [endPoint, endHip.endPoint] - let lastPoint - - if (restRidgeConnection.startPoint.x === endHip.endPoint.x && restRidgeConnection.startPoint.y === endHip.endPoint.y) { - lastPoint = restRidgeConnection.endPoint - polygonPoints.push(restRidgeConnection.endPoint) - } else { - lastPoint = restRidgeConnection.startPoint - polygonPoints.push(restRidgeConnection.startPoint) - } - - connectedRidge = ridges.find( - (ridge) => - (ridge.startPoint.x === lastPoint.x && ridge.startPoint.y === lastPoint.y) || - (ridge.endPoint.x === lastPoint.x && ridge.endPoint.y === lastPoint.y), - ) - - if (connectedRidge.startPoint.x === startHip.endPoint.x && connectedRidge.startPoint.y === startHip.endPoint.y) { - lastPoint = connectedRidge.startPoint - polygonPoints.push(connectedRidge.startPoint) - } else { - lastPoint = connectedRidge.endPoint - polygonPoints.push(connectedRidge.endPoint) - } - - polygonPoints.push(startPoint) - } - - const newPolygon = new QPolygon(polygonPoints, { - fontSize: polygon.fontSize, - parentId: polygon.id, - name: 'roof', - selectable: false, - stroke: 'black', - fill: 'transparent', - strokeWidth: 3, - }) - - polygon.canvas.add(newPolygon) - }) -} - -const getOneSideLine = (line) => { - // left, top 방향의 line은 right, bottom 방향의 line으로 변경한다. - const newLine = { ...line } - let newX1, newY1, newX2, newY2 - if (newLine.direction === 'top') { - newX1 = newLine.x2 - newY1 = newLine.y2 - newX2 = newLine.x1 - newY2 = newLine.y1 - - newLine.x1 = newX1 - newLine.y1 = newY1 - newLine.x2 = newX2 - newLine.y2 = newY2 - newLine.direction = 'bottom' - newLine.startPoint = { x: newX1, y: newY1 } - newLine.endPoint = { x: newX2, y: newY2 } - } else if (line.direction === 'left') { - newX1 = newLine.x2 - newY1 = newLine.y2 - newX2 = newLine.x1 - newY2 = newLine.y1 - - newLine.x1 = newX1 - newLine.y1 = newY1 - newLine.x2 = newX2 - newLine.y2 = newY2 - newLine.direction = 'right' - newLine.startPoint = { x: newX1, y: newY1 } - newLine.endPoint = { x: newX2, y: newY2 } - } - - return newLine -} - function inwardEdgeNormal(vertex1, vertex2) { // Assuming that polygon vertices are in clockwise order const dx = vertex2.x - vertex1.x @@ -735,7 +35,7 @@ function inwardEdgeNormal(vertex1, vertex2) { } function outwardEdgeNormal(vertex1, vertex2) { - var n = inwardEdgeNormal(vertex1, vertex2) + const n = inwardEdgeNormal(vertex1, vertex2) return { x: -n.x, @@ -786,14 +86,12 @@ function createPolygon(vertices) { } } -// based on http://local.wasp.uwa.edu.au/~pbourke/geometry/lineline2d/, edgeA => "line a", edgeB => "line b" - function edgesIntersection(edgeA, edgeB) { const den = (edgeB.vertex2.y - edgeB.vertex1.y) * (edgeA.vertex2.x - edgeA.vertex1.x) - (edgeB.vertex2.x - edgeB.vertex1.x) * (edgeA.vertex2.y - edgeA.vertex1.y) - if (den == 0) { + if (den === 0) { return null // lines are parallel or coincident } @@ -818,8 +116,8 @@ function edgesIntersection(edgeA, edgeB) { } function appendArc(arcSegments, vertices, center, radius, startVertex, endVertex, isPaddingBoundary) { - var startAngle = Math.atan2(startVertex.y - center.y, startVertex.x - center.x) - var endAngle = Math.atan2(endVertex.y - center.y, endVertex.x - center.x) + let startAngle = Math.atan2(startVertex.y - center.y, startVertex.x - center.x) + let endAngle = Math.atan2(endVertex.y - center.y, endVertex.x - center.x) if (startAngle < 0) { startAngle += TWO_PI @@ -959,218 +257,6 @@ export default function offsetPolygon(vertices, offset) { } } -/*export const splitPolygonWithLines = (polygon) => { - const roofs = [] - const allLines = [...polygon.innerLines] - - const polygonLines = polygon.lines - const innerLines = polygon.innerLines - - allLines.forEach((line) => { - line.startPoint = { x: line.x1, y: line.y1 } - line.endPoint = { x: line.x2, y: line.y2 } - }) - - // allLines에 x1,y1,x2,y2를 비교해서 중복되는 값을 제거한다. - allLines.forEach((line, index) => { - const startPoint = line.startPoint - const endPoint = line.endPoint - - allLines.forEach((line2, index2) => { - if (index !== index2) { - if ( - (isSamePoint(startPoint, line2.startPoint) && isSamePoint(endPoint, line2.endPoint)) || - (isSamePoint(endPoint, line2.startPoint) && isSamePoint(startPoint, line2.endPoint)) - ) { - allLines.splice(index2, 1) - } - } - }) - }) - - /!** - * 좌표 테스트용 - *!/ - /!*allLines.forEach((line) => { - const text = new fabric.Text(`(${line.startPoint.x},${line.startPoint.y})`, { - left: line.startPoint.x, - top: line.startPoint.y, - fontSize: 15, - }) - - polygon.canvas.add(text) - polygon.canvas.renderAll() - - const text2 = new fabric.Text(`(${line.endPoint.x},${line.endPoint.y})`, { - left: line.endPoint.x, - top: line.endPoint.y, - fontSize: 15, - }) - - polygon.canvas.add(text2) - polygon.canvas.renderAll() - }) - - polygon.points.forEach((point, index) => { - const text = new fabric.Text(`(${point.x},${point.y})`, { - left: point.x, - top: point.y, - fontSize: 15, - }) - - polygon.canvas.add(text) - polygon.canvas.renderAll() - })*!/ - /!** - * 좌표 테스트용 끝 - *!/ - - polygon.points.forEach((point, index) => { - allLines.forEach((line) => { - if (line.endPoint.x === point.x && line.endPoint.y === point.y) { - const temp = line.startPoint - line.startPoint = line.endPoint - line.endPoint = temp - } - }) - }) - - polygon.points.forEach((point, index) => { - const routes = [] - - // 시작점은 시작 hip라인의 출발점 - const startPoint = { x: Math.round(point.x), y: Math.round(point.y) } - // 도착점은 마지막 hip라인의 끝나는 점 - let endPoint = polygon.points[(index + 1) % polygon.points.length] - endPoint = { x: Math.round(endPoint.x), y: Math.round(endPoint.y) } - - const startLine = allLines.find((line) => line.startPoint.x === startPoint.x && line.startPoint.y === startPoint.y) - const endLine = allLines.find((line) => line.startPoint.x === endPoint.x && line.startPoint.y === endPoint.y) - - const arrivalPoint = endLine.endPoint - routes.push(startLine.startPoint) - routes.push(startLine.endPoint) - - //hip끼리 만나는 경우는 아무것도 안해도됨 - if (!isSamePoint(startLine.endPoint, arrivalPoint)) { - // polygon line까지 추가 - const allLinesCopy = [...allLines, ...polygon.lines] - // hip이 만나지 않는 경우 갈 수 있는 길을 다 돌아야함 - let currentPoint = startLine.endPoint - let currentLine = startLine - let movedLines = [] - let subMovedLines = [] - while (!isSamePoint(currentPoint, arrivalPoint)) { - // startHip에서 만나는 출발선 두개. 두개의 선을 출발하여 arrivalPoint에 도착할 때 까지 count를 세고, 더 낮은 count를 가진 길을 선택한다. - let connectedLines = allLinesCopy.filter((line) => isSamePoint(line.startPoint, currentPoint) || isSamePoint(line.endPoint, currentPoint)) - - connectedLines = connectedLines.filter((line) => line !== currentLine) - - connectedLines = connectedLines.filter((line) => !subMovedLines.includes(line)) - - //마지막 선이 endLine의 startPoint와 같은경우 그 전까지 movedLine을 제거한다. - const endLineMeetLineCnt = connectedLines.filter((line) => { - return isSamePoint(line.endPoint, endLine.startPoint) || isSamePoint(line.startPoint, endLine.startPoint) - }).length - - if (endLineMeetLineCnt !== 0) { - movedLines.push(subMovedLines) - - console.log(movedLines, index) - } - - connectedLines = connectedLines.filter((line) => { - return !isSamePoint(line.endPoint, endLine.startPoint) && !isSamePoint(line.startPoint, endLine.startPoint) - }) - - if (connectedLines.length === 0) { - return - } - - let tempPoints = [] - - for (let i = 0; i < connectedLines.length; i++) { - if (isSamePoint(connectedLines[i].startPoint, currentPoint)) { - tempPoints.push({ point: connectedLines[i].endPoint, index: i, line: connectedLines[i] }) - } else { - tempPoints.push({ point: connectedLines[i].startPoint, index: i, line: connectedLines[i] }) - } - } - - //tempPoints에서 arrivalPoint와 가장 가까운 점을 찾는다. - let minDistance = Number.MAX_SAFE_INTEGER - let minIndex = 0 - tempPoints.forEach((tempPoint, index) => { - const distance = Math.sqrt(Math.pow(tempPoint.point.x - arrivalPoint.x, 2) + Math.pow(tempPoint.point.y - arrivalPoint.y, 2)) - if (distance < minDistance) { - minDistance = distance - minIndex = tempPoint.index - } - }) - - currentPoint = tempPoints[minIndex].point - currentLine = tempPoints[minIndex].line - if (currentLine !== startLine) { - subMovedLines.push(currentLine) - } - routes.push(currentPoint) - } - } - - routes.push(endLine.startPoint) - roofs.push(routes) - }) - - // 중복 제거 - roofs.forEach((roofPoint, index) => { - const samePointLengthRoofPoints = roofs.filter((roof) => roof.length === roofPoint.length && roof !== roofPoint) - - samePointLengthRoofPoints.forEach((samePointRoof) => { - if (arraysHaveSamePoints(samePointRoof, roofPoint)) { - roofs.splice(roofs.indexOf(samePointRoof), 1) - } - }) - }) - - roofs.forEach((roofPoint, index) => { - let defense, pitch - const direction = getDirectionByPoint(roofPoint[0], roofPoint[roofPoint.length - 1]) - - 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: defense, - pitch: pitch, - }) - - polygon.canvas.add(roof) - polygon.canvas.renderAll() - }) -}*/ - function normalizePoint(point) { return { x: Math.round(point.x), @@ -1204,34 +290,6 @@ export const isSamePoint = (a, b) => { return Math.abs(Math.round(a.x) - Math.round(b.x)) <= 2 && Math.abs(Math.round(a.y) - Math.round(b.y)) <= 2 } -/** - * Calculate the angle between two lines. - * @param {Object} line1 - The first line defined by two points {x1, y1} and {x2, y2}. - * @param {Object} line2 - The second line defined by two points {x1, y1} and {x2, y2}. - * @returns {number} - The angle between the two lines in degrees. - */ -function calculateAngleBetweenLines(line1, line2) { - const { x1: x1_1, y1: y1_1, x2: x2_1, y2: y2_1 } = line1 - const { x1: x1_2, y1: y1_2, x2: x2_2, y2: y2_2 } = line2 - - // Calculate direction vectors - const vector1 = { x: x2_1 - x1_1, y: y2_1 - y1_1 } - const vector2 = { x: x2_2 - x1_2, y: y2_2 - y1_2 } - - // Calculate dot product and magnitudes - const dotProduct = vector1.x * vector2.x + vector1.y * vector2.y - const magnitude1 = Math.sqrt(vector1.x * vector1.x + vector1.y * vector1.y) - const magnitude2 = Math.sqrt(vector2.x * vector2.x + vector2.y * vector2.y) - - // Calculate the cosine of the angle - const cosTheta = dotProduct / (magnitude1 * magnitude2) - - // Calculate the angle in radians and then convert to degrees - const angleInRadians = Math.acos(cosTheta) - - return (angleInRadians * 180) / Math.PI -} - /** * 박공지붕(templateA, templateB)을 그린다. * @param roofId @@ -1253,7 +311,7 @@ export const drawGabledRoof = (roofId, canvas) => { const minY = Math.min(...roofPoints.map((point) => point.y)) const maxY = Math.max(...roofPoints.map((point) => point.y)) - // 맞은편 라인을 찾기 위해 현재 polygon으로 만들수 있는 최대한의 길이를 구한다. + // 맞은편 라인을 찾기 위해 현재 polygon 으로 만들수 있는 최대한의 길이를 구한다. const checkLength = Math.abs(Math.sqrt(Math.pow(maxX - minX, 2) + Math.pow(maxY - minY, 2))) // 처마라인의 기본속성 입력 @@ -1267,13 +325,11 @@ export const drawGabledRoof = (roofId, canvas) => { const ridges = [] eaves.sort((a, b) => a.length - b.length) - eaves.forEach((eave, index) => { + eaves.forEach((eave) => { if (ridges.length < ridgeCount) { const index = eave.index, currentRoof = eave.roof const currentWall = wallLines[index] - // const prevRoof = index === 0 ? roofLines[wallLines.length - 1] : roofLines[index - 1] - // const nextRoof = index === roofLines.length - 1 ? roofLines[0] : index === roofLines.length ? roofLines[1] : roofLines[index + 1] //현재 지붕의 중심 좌표 const midX = Math.round(((currentRoof.x1 + currentRoof.x2) / 2) * 10) / 10 @@ -1281,7 +337,7 @@ export const drawGabledRoof = (roofId, canvas) => { const deltaX = currentWall.x2 - currentWall.x1 const deltaY = currentWall.y2 - currentWall.y1 const length = Math.sqrt(deltaX * deltaX + deltaY * deltaY) - // currentWall과 직각인 기울기 계산 + // currentWall 과 직각인 기울기 계산 const perpendicularDeltaX = deltaY / length const perpendicularDeltaY = -deltaX / length // midX와 midY를 기준으로 직각 기울기를 사용하여 midWallX와 midWallY 계산 @@ -1376,14 +432,15 @@ export const drawGabledRoof = (roofId, canvas) => { const ridge = new QLine([centerLineX1, centerLineY1, centerLineX2, centerLineY2], { fontSize: roof.fontSize, - stroke: 'blue', - strokeWidth: 1, + stroke: '#1083E3', + strokeWidth: 2, name: LINE_TYPE.SUBLINE.RIDGE, attributes: { roofId: roof.id, currentRoof: currentRoof.id }, }) canvas.add(ridge) canvas.renderAll() ridges.push(ridge) + roof.innerLines.push(ridge) } }) eaves.forEach((eave) => { @@ -1398,7 +455,7 @@ export const drawGabledRoof = (roofId, canvas) => { const deltaX = currentWall.x2 - currentWall.x1 const deltaY = currentWall.y2 - currentWall.y1 const length = Math.sqrt(deltaX * deltaX + deltaY * deltaY) - // currentWall과 직각인 기울기 계산 + // currentWall 과 직각인 기울기 계산 const perpendicularDeltaX = deltaY / length const perpendicularDeltaY = -deltaX / length // midX와 midY를 기준으로 직각 기울기를 사용하여 midWallX와 midWallY 계산 @@ -1409,7 +466,7 @@ export const drawGabledRoof = (roofId, canvas) => { let points = [] const intersectRidge = [] - // 현재 roof가 wall보다 작을때 이전, 다음 지붕의 offset만큼 포인트를 조정한다. + // 현재 roof 가 wall 보다 작을때 이전, 다음 지붕의 offset 만큼 포인트를 조정한다. if (currentRoof.attributes.planeSize > currentWall.attributes.planeSize) { points.push({ x: currentRoof.x1, y: currentRoof.y1 }, { x: currentRoof.x2, y: currentRoof.y2 }) } else if (currentRoof.attributes.planeSize === currentWall.attributes.planeSize) { @@ -1481,15 +538,8 @@ export const drawGabledRoof = (roofId, canvas) => { } }) - intersectRidge.forEach((intersect, index) => { + intersectRidge.forEach((intersect) => { const line = intersect.line - const ridge = new fabric.Line([line.x1, line.y1, line.x2, line.y2], { - stroke: 'red', - strokeWidth: 2, - selectable: false, - }) - canvas.add(ridge) - canvas.renderAll() if (currentRoof.attributes.planeSize > currentWall.attributes.planeSize) { points.push({ x: line.x1, y: line.y1 }, { x: line.x2, y: line.y2 }) } else if (currentRoof.attributes.planeSize === currentWall.attributes.planeSize) { @@ -1545,8 +595,8 @@ export const drawGabledRoof = (roofId, canvas) => { points.push({ x: lineX1, y: lineY1 }, { x: lineX2, y: lineY2 }) } - canvas.remove(ridge) - canvas.renderAll() + // canvas.remove(ridge) + // canvas.renderAll() }) points = points.filter((point, index, self) => index === self.findIndex((p) => p.x === point.x && p.y === point.y)) @@ -1558,6 +608,7 @@ export const drawGabledRoof = (roofId, canvas) => { const sortedPoints = [startPoint] points.forEach((p, index) => { const lastPoint = sortedPoints[sortedPoints.length - 1] + console.log('lastPoint', lastPoint) if (index === 0) { const underStartPoint = points.filter((point) => point.y > startPoint.y) const nextPoint = underStartPoint @@ -1667,7 +718,7 @@ export const drawGabledRoof = (roofId, canvas) => { } }) //기준선 제거 - ridges.forEach((ridge) => canvas.remove(ridge)) + // ridges.forEach((ridge) => canvas.remove(ridge)) } /** @@ -1684,7 +735,6 @@ export const drawShedRoof = (roofId, canvas) => { } const sheds = roof.lines.filter((line) => line.attributes !== undefined && line.attributes.type === LINE_TYPE.WALLLINE.SHED) - // const eaves = roof.lines.filter((line) => line.attributes !== undefined && line.attributes.type === LINE_TYPE.WALLLINE.EAVES) const gables = roof.lines.filter((line) => line.attributes !== undefined && line.attributes.type === LINE_TYPE.WALLLINE.GABLE) let shedDegree = sheds[0].attributes.degree || 0 @@ -1753,12 +803,8 @@ const drawRidge = (roof, canvas) => { currentRoof = item.roof const prevRoof = index === 0 ? roofLines[wallLines.length - 1] : roofLines[index - 1] const nextRoof = index === roofLines.length - 1 ? roofLines[0] : index === roofLines.length ? roofLines[1] : roofLines[index + 1] - // const beforePrevRoof = index <= 1 ? roofLines[roofLines.length - 2 + index] : roofLines[index - 2] - // const afterNextRoof = index >= roofLines.length - 2 ? roofLines[(index + 2) % roofLines.length] : roofLines[index + 2] let startXPoint, startYPoint, endXPoint, endYPoint - // console.log('currentRoof : ', currentRoof.direction, currentRoof.attributes.planeSize) - let wallLine = wallLines.filter((w) => w.id === currentRoof.attributes.wallLine) if (wallLine.length > 0) { wallLine = wallLine[0] @@ -1942,7 +988,7 @@ const drawRidge = (roof, canvas) => { }) //겹쳐지는 마루는 하나로 합침 - roof.ridges.forEach((ridge, index) => { + roof.ridges.forEach((ridge) => { roof.ridges .filter((ridge2) => !(ridge.x1 === ridge2.x1 && ridge.y1 === ridge2.y1 && ridge.x2 === ridge2.x2 && ridge.y2 === ridge2.y2)) .forEach((ridge2) => { @@ -2026,7 +1072,7 @@ const drawHips = (roof, canvas) => { const roofLines = roof.lines const ridgeLines = canvas?.getObjects().filter((object) => object.name === LINE_TYPE.SUBLINE.RIDGE && object.attributes.roofId === roof.id) - //마루에서 시작되는 hip을 먼저 그립니다. + //마루에서 시작되는 hip 을 먼저 그립니다. roofLines .filter((roof) => roof.attributes.type === LINE_TYPE.WALLLINE.EAVES && roof.attributes.ridgeCoordinate !== undefined) .forEach((currentRoof, index) => { @@ -2086,7 +1132,7 @@ const drawHips = (roof, canvas) => { const hipLines = canvas?.getObjects().filter((object) => object.name === LINE_TYPE.SUBLINE.HIP && object.attributes.roofId === roof.id) - //마루에서 시작되지 않는 hip을 그립니다. + //마루에서 시작되지 않는 hip 을 그립니다. roofLines .filter((roof) => { let isHip = false @@ -2159,50 +1205,9 @@ const drawHips = (roof, canvas) => { } /** - * 라인 사이가 지붕골 인지 확인. - * @param polygon - * @param line1 - * @param line2 - * @returns {boolean} - */ -const checkValley = (polygon, line1, line2) => { - let points = [ - { x: line1.x1, y: line1.y1 }, - { x: line1.x2, y: line1.y2 }, - { x: line2.x1, y: line2.y1 }, - { x: line2.x2, y: line2.y2 }, - ] - - const uniquePointsMap = new Map() - points.forEach((point) => { - const key = `${point.x},${point.y}` - if (!uniquePointsMap.has(key)) { - uniquePointsMap.set(key, point) - } - }) - points = Array.from(uniquePointsMap.values()) - - const centroidX = points.reduce((acc, point) => acc + point.x, 0) / points.length - const centroidY = points.reduce((acc, point) => acc + point.y, 0) / points.length - - let isValley = false - const pPoints = polygon.points - pPoints.forEach((point, index) => { - let j = (index + 1) % pPoints.length - let xi = pPoints[index].x + polygon.left, - yi = pPoints[index].y + polygon.top - let xj = pPoints[j].x + polygon.left, - yj = pPoints[j].y + polygon.top - - let intersect = yi > centroidY !== yj > centroidY && centroidX < ((xj - xi) * (centroidY - yi)) / (yj - yi) + xi - if (intersect) isValley = !isValley - }) - return isValley -} - -/* - 3개 이상 이어지지 않은 라인 포인트 계산 - 모임지붕에서 point는 3개 이상의 라인과 접해야 함. + * 3개 이상 이어지지 않은 라인 포인트 계산 + * 모임지붕에서 point 는 3개 이상의 라인과 접해야 함. + * @param polygon */ const connectLinePoint = (polygon) => { // 연결되지 않은 모든 라인의 포인트를 구한다. @@ -2560,9 +1565,8 @@ const changeEavesRoof = (currentRoof, canvas) => { ?.getObjects() .filter( (object) => - object.attributes !== undefined && - object.attributes.roofId === roofId && - object.attributes.currentRoof === currentRoof.id && + object.attributes?.roofId === roofId && + object.attributes?.currentRoof === currentRoof.id && object.x1 !== undefined && object.x2 !== undefined, ) @@ -2724,9 +1728,8 @@ const changeGableRoof = (currentRoof, canvas) => { ?.getObjects() .filter( (object) => - object.attributes !== undefined && - object.attributes.roofId === roofId && - object.attributes.currentRoof === currentRoof.id && + object.attributes?.roofId === roofId && + object.attributes?.currentRoof === currentRoof.id && object.x1 !== undefined && object.x2 !== undefined, ) @@ -2847,7 +1850,6 @@ const changeGableRoof = (currentRoof, canvas) => { const hip1Height = Math.round(hip1Base / Math.tan(((90 - prevDegree) * Math.PI) / 180)) hip1.attributes.planeSize = Math.round(Math.sqrt(Math.pow(hip1.x1 - hip1.x2, 2) + Math.pow(hip1.y1 - hip1.y2, 2))) * 10 hip1.attributes.actualSize = Math.round(Math.sqrt(Math.pow(hip1.attributes.planeSize, 2) + Math.pow(hip1Height, 2))) - // roof.innerLines.push(hip1) let hip2 = new QLine([currentRoof.x2, currentRoof.y2, midX, midY], { fontSize: roof.fontSize, @@ -2866,7 +1868,6 @@ const changeGableRoof = (currentRoof, canvas) => { const hip2Height = Math.round(hip2Base / Math.tan(((90 - nextDegree) * Math.PI) / 180)) hip2.attributes.planeSize = Math.round(Math.sqrt(Math.pow(hip2.x1 - hip2.x2, 2) + Math.pow(hip2.y1 - hip2.y2, 2))) * 10 hip2.attributes.actualSize = Math.round(Math.sqrt(Math.pow(hip2.attributes.planeSize, 2) + Math.pow(hip2Height, 2))) - // roof.innerLines.push(hip2) hip1.set({ visible: false }) hip1.setViewLengthText(false) hip2.set({ visible: false }) @@ -2922,9 +1923,8 @@ const changeHipAndGableRoof = (currentRoof, canvas) => { ?.getObjects() .filter( (object) => - object.attributes !== undefined && - object.attributes.roofId === roofId && - object.attributes.currentRoof === currentRoof.id && + object.attributes?.roofId === roofId && + object.attributes?.currentRoof === currentRoof.id && object.x1 !== undefined && object.x2 !== undefined, ) @@ -3352,7 +2352,6 @@ const changeJerkInHeadRoof = (currentRoof, canvas) => { hip2.attributes.planeSize = Math.round(Math.sqrt(Math.pow(hip2.x1 - hip2.x2, 2) + Math.pow(hip2.y1 - hip2.y2, 2))) * 10 hip2.attributes.actualSize = Math.round(Math.sqrt(Math.pow(hip2.attributes.planeSize, 2) + Math.pow(hip2Height, 2))) canvas?.add(hip2) - // roof.innerLines.push(hip2) hip1.set({ visible: false }) hip1.setViewLengthText(false) @@ -3433,9 +2432,8 @@ const changeWallRoof = (currentRoof, canvas) => { ?.getObjects() .filter( (object) => - object.attributes !== undefined && - object.attributes.roofId === roofId && - object.attributes.currentRoof === currentRoof.id && + object.attributes?.roofId === roofId && + object.attributes?.currentRoof === currentRoof.id && object.x1 !== undefined && object.x2 !== undefined, ) @@ -3713,8 +2711,8 @@ const reDrawPolygon = (polygon, canvas) => { const newLines = newPolygon.lines - newLines.forEach((line, index) => { - lines.forEach((l, i) => { + newLines.forEach((line) => { + lines.forEach((l) => { if (line.x1 === l.x1 && line.y1 === l.y1) { line.id = l.id line.attributes = l.attributes @@ -3801,21 +2799,6 @@ function arePointsEqual(point1, point2) { return Math.abs(point1.x - point2.x) <= 1 && Math.abs(point1.y - point2.y) <= 1 } -function arraysHaveSamePoints(array1, array2) { - if (array1.length !== array2.length) return false - - const sortedArray1 = array1.slice().sort((a, b) => a.x - b.x || a.y - b.y) - const sortedArray2 = array2.slice().sort((a, b) => a.x - b.x || a.y - b.y) - - for (let i = 0; i < sortedArray1.length; i++) { - if (!arePointsEqual(sortedArray1[i], sortedArray2[i])) { - return false - } - } - - return true -} - export const toGeoJSON = (pointsArray) => { // 객체 배열을 GeoJSON 형식의 좌표 배열로 변환 const coordinates = pointsArray.map((point) => [point.x, point.y]) @@ -3834,14 +2817,14 @@ export const inPolygon = (polygonPoints, rectPoints) => { const rectFeature = turf.polygon([rectCoordinates]) // 사각형의 모든 꼭짓점이 다각형 내부에 있는지 확인 - const allPointsInsidePolygon = rectCoordinates.every((coord) => { - const point = turf.point(coord) + const allPointsInsidePolygon = rectCoordinates.every((coordinate) => { + const point = turf.point(coordinate) return turf.booleanPointInPolygon(point, polygonFeature) }) // 다각형의 모든 점이 사각형 내부에 있지 않은지 확인 - const noPolygonPointsInsideRect = polygonCoordinates.every((coord) => { - const point = turf.point(coord) + const noPolygonPointsInsideRect = polygonCoordinates.every((coordinate) => { + const point = turf.point(coordinate) return !turf.booleanPointInPolygon(point, rectFeature) }) From 7dfab6c896e095ef6e052b884fa52253469aa616 Mon Sep 17 00:00:00 2001 From: basssy Date: Mon, 9 Dec 2024 18:20:48 +0900 Subject: [PATCH 2/3] =?UTF-8?q?=EB=A1=9C=EA=B7=B8=EC=9D=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/main/ChangePasswordPop.jsx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/components/main/ChangePasswordPop.jsx b/src/components/main/ChangePasswordPop.jsx index 188a3fe7..20089921 100644 --- a/src/components/main/ChangePasswordPop.jsx +++ b/src/components/main/ChangePasswordPop.jsx @@ -73,15 +73,15 @@ export default function ChangePasswordPop(props) { } await patch({ url: '/api/login/v1.0/user/change-password', data: param }).then((res) => { - if (res.result.code === 200) { - if (res.result.resultCode === 'S') { + if (res?.result?.code === 200) { + if (res?.result?.resultCode === 'S') { alert(getMessage('main.popup.login.success')) setSessionState({ ...sessionState, pwdInitYn: 'Y' }) //메인으로 이동 props.setChagePasswordPopOpen(false) - router.push('/') + router.push('/login') } else { - alert(res.result.resultMsg) + alert(res?.result?.resultMsg) } } else { console.log('error') From 40d481af601daa5cab506b1f7dce7748e3f4d1db Mon Sep 17 00:00:00 2001 From: basssy Date: Tue, 10 Dec 2024 08:33:17 +0900 Subject: [PATCH 3/3] =?UTF-8?q?=EB=B9=84=EB=B0=80=EB=B2=88=ED=98=B8=20?= =?UTF-8?q?=EB=B3=80=EA=B2=BD=20=ED=8C=9D=EC=97=85=20=ED=9B=84=20=EC=B2=98?= =?UTF-8?q?=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/main/ChangePasswordPop.jsx | 30 +++++++++++++---------- 1 file changed, 17 insertions(+), 13 deletions(-) diff --git a/src/components/main/ChangePasswordPop.jsx b/src/components/main/ChangePasswordPop.jsx index 20089921..2af060e7 100644 --- a/src/components/main/ChangePasswordPop.jsx +++ b/src/components/main/ChangePasswordPop.jsx @@ -72,21 +72,25 @@ export default function ChangePasswordPop(props) { chgPwd: _password1, } - await patch({ url: '/api/login/v1.0/user/change-password', data: param }).then((res) => { - if (res?.result?.code === 200) { - if (res?.result?.resultCode === 'S') { - alert(getMessage('main.popup.login.success')) - setSessionState({ ...sessionState, pwdInitYn: 'Y' }) - //메인으로 이동 - props.setChagePasswordPopOpen(false) - router.push('/login') + await patch({ url: '/api/login/v1.0/user/change-password', data: param }) + .then((res) => { + if (res?.result?.code === 200) { + if (res?.result?.resultCode === 'S') { + alert(getMessage('main.popup.login.success')) + //로그인 화면으로 이동해서 다시 로그인해야되서 setSessionState필요없음 + // setSessionState({ ...sessionState, pwdInitYn: 'Y' }) + props.setChagePasswordPopOpen(false) + router.push('/login') + } else { + alert(res?.result?.resultMsg) + } } else { - alert(res?.result?.resultMsg) + console.log('code not 200 error') } - } else { - console.log('error') - } - }) + }) + .catch((error) => { + console.log('catch::::::::', error) + }) } return (