From 8412462a8b7ef229fa834e3780573477e4882040 Mon Sep 17 00:00:00 2001 From: "hyojun.choi" Date: Wed, 30 Apr 2025 13:08:58 +0900 Subject: [PATCH] =?UTF-8?q?=EB=9D=BC=EC=9D=B8=20=EC=9C=84=EC=97=90=20?= =?UTF-8?q?=EC=9E=88=EB=8A=94=EC=A7=80=20=ED=99=95=EC=9D=B8=20=ED=95=A8?= =?UTF-8?q?=EC=88=98=20=EC=88=98=EC=A0=95=20=EC=A7=80=EB=B6=95=EC=9E=AC=20?= =?UTF-8?q?=ED=95=A0=EB=8B=B9=20=EC=8B=9C=20=EC=98=A4=EB=A5=98=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/hooks/common/useRoofFn.js | 250 +++++++++++++++++----------------- src/hooks/usePolygon.js | 4 +- src/util/canvas-util.js | 8 +- 3 files changed, 133 insertions(+), 129 deletions(-) diff --git a/src/hooks/common/useRoofFn.js b/src/hooks/common/useRoofFn.js index c49128e7..38246273 100644 --- a/src/hooks/common/useRoofFn.js +++ b/src/hooks/common/useRoofFn.js @@ -23,102 +23,65 @@ export function useRoofFn() { //면형상 선택 클릭시 지붕 패턴 입히기 function setSurfaceShapePattern(polygon, mode = 'onlyBorder', trestleMode = false, roofMaterial, isForceChange = false, isDisplay = false) { - if (!polygon) { - return - } - if (polygon.points.length < 3) { - return - } - if (isForceChange && !isDisplay) { - /*if (polygon.roofMaterial) { + try { + if (!polygon) { + return + } + if (polygon.points.length < 3) { + return + } + if (isForceChange && !isDisplay) { + /*if (polygon.roofMaterial) { polygon.roofMaterial = null }*/ - } - if (!roofMaterial) { - roofMaterial = polygon.roofMaterial ?? selectedRoofMaterial - } - - const ratio = window.devicePixelRatio || 1 - const layout = roofMaterial.layout - - let width = (roofMaterial.width || 226) / 10 - let height = (roofMaterial.length || 158) / 10 - const index = roofMaterial.index ?? 0 - let roofStyle = 2 - const inputPatternSize = { width: width, height: height } //임시 사이즈 - const patternSize = { ...inputPatternSize } // 입력된 값을 뒤집기 위해 - - if (polygon.direction === 'east' || polygon.direction === 'west') { - //세로형이면 width height를 바꿈 - ;[patternSize.width, patternSize.height] = [inputPatternSize.height, patternSize.width] - } - - // 패턴 소스를 위한 임시 캔버스 생성 - const patternSourceCanvas = document.createElement('canvas') - patternSourceCanvas.width = polygon.width * ratio - patternSourceCanvas.height = polygon.height * ratio - const ctx = patternSourceCanvas.getContext('2d') - let offset = roofStyle === 1 ? 0 : patternSize.width / 2 - - const rows = Math.floor(patternSourceCanvas.height / patternSize.height) - const cols = Math.floor(patternSourceCanvas.width / patternSize.width) - - ctx.strokeStyle = mode === 'allPainted' ? 'black' : ROOF_COLOR[index] - ctx.lineWidth = 2 - ctx.fillStyle = mode === 'allPainted' ? 'rgba(0, 159, 64, 0.7)' : 'white' - - if (trestleMode) { - ctx.strokeStyle = 'black' - ctx.lineWidth = 0.2 - ctx.fillStyle = 'rgba(0, 0, 0, 0.1)' - } else { - ctx.fillStyle = 'rgba(255, 255, 255, 1)' - } - - if (polygon.direction === 'east' || polygon.direction === 'west') { - offset = roofStyle === 1 ? 0 : patternSize.height / 2 - for (let col = 0; col <= cols; col++) { - const x = col * patternSize.width - const yStart = 0 - const yEnd = patternSourceCanvas.height - ctx.beginPath() - ctx.moveTo(x, yStart) // 선 시작점 - ctx.lineTo(x, yEnd) // 선 끝점 - ctx.stroke() - if (mode === 'allPainted' || trestleMode) { - ctx.fillRect(x, yStart, patternSize.width, yEnd - yStart) - } - - for (let row = 0; row <= rows; row++) { - const y = layout === ROOF_MATERIAL_LAYOUT.STAIRS ? row * patternSize.height + (col % 2 === 0 ? 0 : offset) : row * patternSize.height - const xStart = col * patternSize.width - const xEnd = xStart + patternSize.width - ctx.beginPath() - ctx.moveTo(xStart, y) // 선 시작점 - ctx.lineTo(xEnd, y) // 선 끝점 - ctx.stroke() - if (mode === 'allPainted' || trestleMode) { - ctx.fillRect(xStart, y, xEnd - xStart, patternSize.height) - } - } } - } else { - for (let row = 0; row <= rows; row++) { - const y = row * patternSize.height + if (!roofMaterial) { + roofMaterial = polygon.roofMaterial ?? selectedRoofMaterial + } - ctx.beginPath() - ctx.moveTo(0, y) // 선 시작점 - ctx.lineTo(patternSourceCanvas.width, y) // 선 끝점 - ctx.stroke() - if (mode === 'allPainted' || trestleMode) { - ctx.fillRect(0, y, patternSourceCanvas.width, patternSize.height) - } + const ratio = window.devicePixelRatio || 1 + const layout = roofMaterial.layout + let width = (roofMaterial.width || 226) / 10 + let height = (roofMaterial.length || 158) / 10 + const index = roofMaterial.index ?? 0 + let roofStyle = 2 + const inputPatternSize = { width: width, height: height } //임시 사이즈 + const patternSize = { ...inputPatternSize } // 입력된 값을 뒤집기 위해 + + if (polygon.direction === 'east' || polygon.direction === 'west') { + //세로형이면 width height를 바꿈 + ;[patternSize.width, patternSize.height] = [inputPatternSize.height, patternSize.width] + } + + // 패턴 소스를 위한 임시 캔버스 생성 + const patternSourceCanvas = document.createElement('canvas') + patternSourceCanvas.width = polygon.width * ratio + patternSourceCanvas.height = polygon.height * ratio + const ctx = patternSourceCanvas.getContext('2d') + let offset = roofStyle === 1 ? 0 : patternSize.width / 2 + + const rows = Math.floor(patternSourceCanvas.height / patternSize.height) + const cols = Math.floor(patternSourceCanvas.width / patternSize.width) + + ctx.strokeStyle = mode === 'allPainted' ? 'black' : ROOF_COLOR[index] + ctx.lineWidth = 2 + ctx.fillStyle = mode === 'allPainted' ? 'rgba(0, 159, 64, 0.7)' : 'white' + + if (trestleMode) { + ctx.strokeStyle = 'black' + ctx.lineWidth = 0.2 + ctx.fillStyle = 'rgba(0, 0, 0, 0.1)' + } else { + ctx.fillStyle = 'rgba(255, 255, 255, 1)' + } + + if (polygon.direction === 'east' || polygon.direction === 'west') { + offset = roofStyle === 1 ? 0 : patternSize.height / 2 for (let col = 0; col <= cols; col++) { - const x = layout === ROOF_MATERIAL_LAYOUT.STAIRS ? col * patternSize.width + (row % 2 === 0 ? 0 : offset) : col * patternSize.width - const yStart = row * patternSize.height - const yEnd = yStart + patternSize.height - + const x = col * patternSize.width + const yStart = 0 + const yEnd = patternSourceCanvas.height ctx.beginPath() ctx.moveTo(x, yStart) // 선 시작점 ctx.lineTo(x, yEnd) // 선 끝점 @@ -126,49 +89,90 @@ export function useRoofFn() { if (mode === 'allPainted' || trestleMode) { ctx.fillRect(x, yStart, patternSize.width, yEnd - yStart) } + + for (let row = 0; row <= rows; row++) { + const y = layout === ROOF_MATERIAL_LAYOUT.STAIRS ? row * patternSize.height + (col % 2 === 0 ? 0 : offset) : row * patternSize.height + const xStart = col * patternSize.width + const xEnd = xStart + patternSize.width + ctx.beginPath() + ctx.moveTo(xStart, y) // 선 시작점 + ctx.lineTo(xEnd, y) // 선 끝점 + ctx.stroke() + if (mode === 'allPainted' || trestleMode) { + ctx.fillRect(xStart, y, xEnd - xStart, patternSize.height) + } + } + } + } else { + for (let row = 0; row <= rows; row++) { + const y = row * patternSize.height + + ctx.beginPath() + ctx.moveTo(0, y) // 선 시작점 + ctx.lineTo(patternSourceCanvas.width, y) // 선 끝점 + ctx.stroke() + if (mode === 'allPainted' || trestleMode) { + ctx.fillRect(0, y, patternSourceCanvas.width, patternSize.height) + } + + for (let col = 0; col <= cols; col++) { + const x = layout === ROOF_MATERIAL_LAYOUT.STAIRS ? col * patternSize.width + (row % 2 === 0 ? 0 : offset) : col * patternSize.width + const yStart = row * patternSize.height + const yEnd = yStart + patternSize.height + + ctx.beginPath() + ctx.moveTo(x, yStart) // 선 시작점 + ctx.lineTo(x, yEnd) // 선 끝점 + ctx.stroke() + if (mode === 'allPainted' || trestleMode) { + ctx.fillRect(x, yStart, patternSize.width, yEnd - yStart) + } + } } } - } - const hachingPatternSourceCanvas = document.createElement('canvas') + const hachingPatternSourceCanvas = document.createElement('canvas') - if (mode === 'lineHatch') { - hachingPatternSourceCanvas.width = polygon.width * ratio - hachingPatternSourceCanvas.height = polygon.height * ratio + if (mode === 'lineHatch') { + hachingPatternSourceCanvas.width = polygon.width * ratio + hachingPatternSourceCanvas.height = polygon.height * ratio - const ctx1 = hachingPatternSourceCanvas.getContext('2d') + const ctx1 = hachingPatternSourceCanvas.getContext('2d') - const gap = 10 + const gap = 10 - ctx1.strokeStyle = 'green' // 선 색상 - ctx1.lineWidth = 0.3 // 선 두께 + ctx1.strokeStyle = 'green' // 선 색상 + ctx1.lineWidth = 0.3 // 선 두께 - for (let x = 0; x < hachingPatternSourceCanvas.width + hachingPatternSourceCanvas.height; x += gap) { - ctx1.beginPath() - ctx1.moveTo(x, 0) // 선 시작점 - ctx1.lineTo(0, x) // 선 끝점 - ctx1.stroke() + for (let x = 0; x < hachingPatternSourceCanvas.width + hachingPatternSourceCanvas.height; x += gap) { + ctx1.beginPath() + ctx1.moveTo(x, 0) // 선 시작점 + ctx1.lineTo(0, x) // 선 끝점 + ctx1.stroke() + } } + + const combinedPatternCanvas = document.createElement('canvas') + combinedPatternCanvas.width = polygon.width * ratio + combinedPatternCanvas.height = polygon.height * ratio + const combinedCtx = combinedPatternCanvas.getContext('2d') + // 첫 번째 패턴을 그린 후 두 번째 패턴을 덧입힘 + combinedCtx.drawImage(patternSourceCanvas, 0, 0) + combinedCtx.drawImage(hachingPatternSourceCanvas, 0, 0) + + // 패턴 생성 + const pattern = new fabric.Pattern({ + source: combinedPatternCanvas, + repeat: 'repeat', + }) + + polygon.set('fill', null) + polygon.set('fill', pattern) + polygon.roofMaterial = roofMaterial + polygon.canvas?.renderAll() + } catch (e) { + console.log(e) } - - const combinedPatternCanvas = document.createElement('canvas') - combinedPatternCanvas.width = polygon.width * ratio - combinedPatternCanvas.height = polygon.height * ratio - const combinedCtx = combinedPatternCanvas.getContext('2d') - // 첫 번째 패턴을 그린 후 두 번째 패턴을 덧입힘 - combinedCtx.drawImage(patternSourceCanvas, 0, 0) - combinedCtx.drawImage(hachingPatternSourceCanvas, 0, 0) - - // 패턴 생성 - const pattern = new fabric.Pattern({ - source: combinedPatternCanvas, - repeat: 'repeat', - }) - - polygon.set('fill', null) - polygon.set('fill', pattern) - polygon.roofMaterial = roofMaterial - polygon.canvas?.renderAll() } function removeRoofMaterial(roof = currentObject) { diff --git a/src/hooks/usePolygon.js b/src/hooks/usePolygon.js index 8fc150e7..49472b08 100644 --- a/src/hooks/usePolygon.js +++ b/src/hooks/usePolygon.js @@ -1234,13 +1234,13 @@ export const usePolygon = () => { function getPath(start, end, graph, epsilon = 1) { if (isDirectlyConnected(start, end, graph, epsilon)) { console.log('직선 연결 있음. 무시.') - return null + return [] } const path = findShortestPath(start, end, graph, epsilon) if (!path || path.length < 3) { console.log('경로 존재하나 3개 미만 좌표. 무시.') - return null + return [] } return path diff --git a/src/util/canvas-util.js b/src/util/canvas-util.js index 9eb6e0e5..74c5c2a4 100644 --- a/src/util/canvas-util.js +++ b/src/util/canvas-util.js @@ -520,17 +520,17 @@ export const sortedPointLessEightPoint = (points) => { // 직선의 방정식. // 방정식은 ax + by + c = 0이며, 점의 좌표를 대입하여 계산된 값은 직선과 점 사이의 관계를 나타낸다. export function isPointOnLine({ x1, y1, x2, y2 }, { x, y }, epsilon = 2) { - const a = y2 - y1 + /*const a = y2 - y1 const b = x1 - x2 const c = x2 * y1 - x1 * y2 - return Math.abs(a * x + b * y + c) < 1000 + return Math.abs(a * x + b * y + c) < 1000*/ /*/!*const a = line.y2 - line.y1 const b = line.x1 - line.x2 const c = line.x2 * line.y1 - line.x1 * line.y2 const result = Math.abs(a * point.x + b * point.y + c) / 100 // 점이 선 위에 있는지 확인 - return result <= 10*!/ + return result <= 10*!*/ // 직선 방정식 만족 여부 확인 const crossProduct = (y - y1) * (x2 - x1) - (x - x1) * (y2 - y1) if (Math.abs(crossProduct) > 10) return false // 작은 오차 허용 @@ -539,7 +539,7 @@ export function isPointOnLine({ x1, y1, x2, y2 }, { x, y }, epsilon = 2) { const withinXRange = Math.min(x1, x2) <= x && x <= Math.max(x1, x2) const withinYRange = Math.min(y1, y2) <= y && y <= Math.max(y1, y2) - return withinXRange && withinYRange*/ + return withinXRange && withinYRange } /** * 점과 가까운 line 찾기