From 1647bc58a08f42efc734b59507a54d83d041f78f Mon Sep 17 00:00:00 2001 From: "hyojun.choi" Date: Tue, 3 Sep 2024 15:07:11 +0900 Subject: [PATCH 01/34] =?UTF-8?q?=EB=A9=B4=ED=98=95=EC=83=81=20=3D>=20?= =?UTF-8?q?=EB=AA=A8=EB=93=88=20=ED=9A=8C=EB=A1=9C=EA=B5=AC=EC=84=B1=20=3D?= =?UTF-8?q?>=20=EB=AA=A8=EB=93=88=20=EC=B1=84=EC=9A=B0=EA=B8=B0=20?= =?UTF-8?q?=EC=9E=91=EC=97=85=EC=A4=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/Roof2.jsx | 48 +++---------- src/components/ui/SurfaceShape.jsx | 105 +++++++++++++++++++---------- 2 files changed, 79 insertions(+), 74 deletions(-) diff --git a/src/components/Roof2.jsx b/src/components/Roof2.jsx index ff570d90..00661aca 100644 --- a/src/components/Roof2.jsx +++ b/src/components/Roof2.jsx @@ -535,44 +535,6 @@ export default function Roof2(props) { }) } - const setCurrentPattern = (polygon) => { - const { width, height, roofStyle } = roofMaterial - const roofRatio = window.devicePixelRatio || 1 - const patternSourceCanvas = document.createElement('canvas') - - if (roofStyle === 1) { - patternSourceCanvas.width = width * roofRatio - patternSourceCanvas.height = height * roofRatio - } else if (roofStyle === 2) { - patternSourceCanvas.width = width * 2 - patternSourceCanvas.height = height * 2 - } - - const ctx = patternSourceCanvas.getContext('2d') - - ctx.scale(roofRatio, roofRatio) - ctx.strokeStyle = 'green' - ctx.lineWidth = 0.4 - // 벽돌 패턴 그리기 - if (roofStyle === 1) { - ctx.strokeRect(0, 0, 50, 30) - } else if (roofStyle === 2) { - // 지그재그 - ctx.strokeRect(0, 0, 200, 100) - ctx.strokeRect(100, 100, 200, 100) - } - - // 패턴 생성 - const pattern = new fabric.Pattern({ - source: patternSourceCanvas, - repeat: 'repeat', - }) - polygon.set('fill', null) - - polygon.set('fill', pattern) - canvas?.renderAll() - } - /** * canvas 내용 불러오기 */ @@ -1531,6 +1493,9 @@ export default function Roof2(props) { }) } + const moduleConfiguration = () => { + createRoofRack() + } return ( <> {canvas && ( @@ -1764,8 +1729,11 @@ export default function Roof2(props) { - + + {type === 1 ? (
길이1 - + {length3 === 0 && ( <> 길이2 - + )} - 길이3 + 길이3
) : type === 2 ? (
길이1 - + 길이2 - +
) : type === 3 ? ( <> 길이1 - + 길이2 - + 길이3 - + ) : type === 4 ? ( <> 길이1 - + 길이2 - + ) : type === 5 ? ( <> 길이1 - + 길이2 - + ) : type === 6 ? ( <> 길이1 - + 길이2 - + 길이3 - + ) : type === 7 ? ( <> 길이1 - + 길이2 - + 길이3 - + ) : type === 8 ? ( <> 길이1 - + 길이2 - + 길이3 - + ) : type === 9 ? ( <> 길이1 - + 길이2 - + 길이3 - + + + ) : type === 10 ? ( + <> + 길이1 + + 길이2 + + 길이3 + + 길이4 + + 길이5 + ) : ( <> From dba5d20e6d058757da89f69ec0f7eca32e9dd435 Mon Sep 17 00:00:00 2001 From: "hyojun.choi" Date: Tue, 3 Sep 2024 16:07:28 +0900 Subject: [PATCH 03/34] =?UTF-8?q?=EB=A9=B4=ED=98=95=EC=83=81=20=EB=B0=B0?= =?UTF-8?q?=EC=B9=98=20=EB=B2=84=ED=8A=BC=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/Roof2.jsx | 970 ----------------------------- src/components/ui/SurfaceShape.jsx | 642 ++++++++++++------- 2 files changed, 400 insertions(+), 1212 deletions(-) diff --git a/src/components/Roof2.jsx b/src/components/Roof2.jsx index 00661aca..9d6d0d1d 100644 --- a/src/components/Roof2.jsx +++ b/src/components/Roof2.jsx @@ -577,922 +577,6 @@ export default function Roof2(props) { canvas?.renderAll() } - const createPentagon2 = () => { - const a = 400 //Number(prompt('a')) - const b = 200 //Number(prompt('b')) - const c = 250 //Number(prompt('c')) - const d = 150 //Number(prompt('d')) - - const t = (c * (a - b)) / (200 + c) - - const t2 = Math.sqrt(c * c + t * t) - - const t3 = Math.sqrt((c - d) * (c - d) + (a - b - t) * (a - b - t)) - - const angle = Math.atan(t2 / t) - const angle2 = Math.atan(t3 / (a - b - t)) - - let isDrawing = true - let pentagon - canvas?.on('mouse:move', (e) => { - if (!isDrawing) { - return - } - canvas?.remove(...canvas?.getObjects().filter((obj) => obj.name === 'guideTriangle')) - const pointer = canvas?.getPointer(e.e) - - pentagon = new QPolygon( - [ - { x: pointer.x - a / 2, y: pointer.y + a / 2 - d }, - { x: pointer.x + a / 2, y: pointer.y + a / 2 - d }, - { x: pointer.x + a / 2, y: pointer.y + a / 2 - d - d }, - { x: pointer.x + a / 2 - b, y: pointer.y + a / 2 - d - d }, - { - x: pointer.x + a / 2 - b - t3 * Math.cos(angle), - y: pointer.y + a / 2 - d - d - t3 * Math.sin(angle), - }, - /*{ - x: pointer.x - a / 2 + t2 * Math.cos(angle), - y: pointer.y + a / 2 - d - t2 * Math.sin(angle), - },*/ - ], - { - fill: 'transparent', - stroke: 'gray', - strokeWidth: 1, - selectable: true, - fontSize: fontSize, - name: 'guideTriangle', - }, - ) - - canvas?.add(pentagon) - }) - - canvas?.on('mouse:down', (e) => { - isDrawing = false - pentagon.set('name', 'roof') - pentagon.set('stroke', 2) - canvas?.renderAll() - }) - } - - const createTemplate10 = () => { - const length1 = Number(prompt('1번')) - const length2 = Number(prompt('2번')) - const length3 = Number(prompt('3번')) - const length4 = Number(prompt('4번')) - const length5 = Number(prompt('5번')) - - let isDrawing = true - canvas?.on('mouse:move', (e) => { - if (!isDrawing) { - return - } - canvas?.remove(...canvas?.getObjects().filter((obj) => obj.name === 'guideTriangle')) - const pointer = canvas?.getPointer(e.e) - const triangle = new QPolygon( - [ - { x: pointer.x - (length1 + length2 + length3) / 2, y: pointer.y - (length4 + length5) / 2 }, - { x: pointer.x - (length1 + length2 + length3) / 2, y: pointer.y + (length4 + length5) / 2 }, - { x: pointer.x - (length1 + length2 + length3) / 2 + length1, y: pointer.y + (length4 + length5) / 2 }, - { x: pointer.x - (length1 + length2 + length3) / 2 + length1, y: pointer.y + (length4 + length5) / 2 - length5 }, - { x: pointer.x - (length1 + length2 + length3) / 2 + length1 + length2, y: pointer.y + (length4 + length5) / 2 - length5 }, - { x: pointer.x - (length1 + length2 + length3) / 2 + length1 + length2, y: pointer.y + (length4 + length5) / 2 - length5 + length5 }, - { - x: pointer.x - (length1 + length2 + length3) / 2 + length1 + length2 + length3, - y: pointer.y + (length4 + length5) / 2 - length5 + length5, - }, - { - x: pointer.x - (length1 + length2 + length3) / 2 + length1 + length2 + length3, - y: pointer.y + (length4 + length5) / 2 - length5 + length5 - (length4 + length5), - }, - ], - { - fill: 'transparent', - stroke: 'black', - strokeWidth: 2, - selectable: true, - fontSize: fontSize, - name: 'guideTriangle', - }, - ) - - canvas?.add(triangle) - }) - - canvas?.on('mouse:down', (e) => { - isDrawing = false - }) - } - const createTemplate11 = () => { - const length1 = 200 //Number(prompt('1번')) - const length2 = 100 //Number(prompt('2번')) - const length3 = 400 //Number(prompt('3번')) - const length4 = 300 //Number(prompt('4번')) - - let isDrawing = true - canvas?.on('mouse:move', (e) => { - if (!isDrawing) { - return - } - canvas?.remove(...canvas?.getObjects().filter((obj) => obj.name === 'guideTriangle')) - const pointer = canvas?.getPointer(e.e) - const triangle = new QPolygon( - [ - { x: pointer.x - length1 / 2, y: pointer.y + length4 / 2 }, - { x: pointer.x - length1 / 2 + length1, y: pointer.y + length4 / 2 }, - { x: pointer.x - length1 / 2 + length1, y: pointer.y + length4 / 2 - length3 }, - { x: pointer.x - length1 / 2 + length1 - (length1 - length2), y: pointer.y + length4 / 2 - length3 }, - { x: pointer.x - length1 / 2 + length1 - (length1 - length2), y: pointer.y + length4 / 2 - length3 + (length3 - length4) }, - { x: pointer.x - length1 / 2 + length1 - (length1 - length2) - length2, y: pointer.y + length4 / 2 - length3 + (length3 - length4) }, - ], - { - fill: 'transparent', - stroke: 'black', - strokeWidth: 2, - selectable: true, - fontSize: fontSize, - name: 'guideTriangle', - }, - ) - - canvas?.add(triangle) - }) - - canvas?.on('mouse:down', (e) => { - isDrawing = false - }) - } - const createTemplate12 = () => { - const length1 = 200 //Number(prompt('1번')) - const length2 = 100 //Number(prompt('2번')) - const length3 = 400 //Number(prompt('3번')) - const length4 = 300 //Number(prompt('4번')) - - let isDrawing = true - canvas?.on('mouse:move', (e) => { - if (!isDrawing) { - return - } - canvas?.remove(...canvas?.getObjects().filter((obj) => obj.name === 'guideTriangle')) - const pointer = canvas?.getPointer(e.e) - const triangle = new QPolygon( - [ - { x: pointer.x - length1 / 2, y: pointer.y + length4 / 2 }, - { x: pointer.x - length1 / 2 + length1, y: pointer.y + length4 / 2 }, - { x: pointer.x - length1 / 2 + length1, y: pointer.y + length4 / 2 - length4 }, - { x: pointer.x - length1 / 2 + length1 - length2, y: pointer.y + length4 / 2 - length4 }, - { x: pointer.x - length1 / 2 + length1 - length2, y: pointer.y + length4 / 2 - length4 - (length3 - length4) }, - { x: pointer.x - length1 / 2 + length1 - length2 - (length1 - length2), y: pointer.y + length4 / 2 - length4 - (length3 - length4) }, - ], - { - fill: 'transparent', - stroke: 'black', - strokeWidth: 2, - selectable: true, - fontSize: fontSize, - name: 'guideTriangle', - }, - ) - - canvas?.add(triangle) - }) - - canvas?.on('mouse:down', (e) => { - isDrawing = false - }) - } - const createTemplate13 = () => { - const length1 = 300 //Number(prompt('1번')) - const length2 = 150 //Number(prompt('2번')) - const length3 = 100 //Number(prompt('3번')) - const length4 = 400 //Number(prompt('4번')) - const length5 = 200 //Number(prompt('5번')) - - let isDrawing = true - canvas?.on('mouse:move', (e) => { - if (!isDrawing) { - return - } - canvas?.remove(...canvas?.getObjects().filter((obj) => obj.name === 'guideTriangle')) - const pointer = canvas?.getPointer(e.e) - const triangle = new QPolygon( - [ - { x: pointer.x - length1 / 2, y: pointer.y + length4 / 2 }, - { x: pointer.x - length1 / 2 + length1, y: pointer.y + length4 / 2 }, - { x: pointer.x - length1 / 2 + length1, y: pointer.y + length4 / 2 - length4 }, - { x: pointer.x - length1 / 2 + length1 - length3, y: pointer.y + length4 / 2 - length4 }, - { x: pointer.x - length1 / 2 + length1 - length3, y: pointer.y + length4 / 2 - length4 + (length4 - length5) }, - { x: pointer.x - length1 / 2 + length1 - length3 - length2, y: pointer.y + length4 / 2 - length4 + (length4 - length5) }, - ], - { - fill: 'transparent', - stroke: 'black', - strokeWidth: 2, - selectable: true, - fontSize: fontSize, - name: 'guideTriangle', - }, - ) - - canvas?.add(triangle) - }) - - canvas?.on('mouse:down', (e) => { - isDrawing = false - }) - } - const createTemplate14 = () => { - const length1 = 300 //Number(prompt('1번')) - const length2 = 150 //Number(prompt('2번')) - const length3 = 100 //Number(prompt('3번')) - const length4 = 400 //Number(prompt('4번')) - const length5 = 200 //Number(prompt('5번')) - - let isDrawing = true - canvas?.on('mouse:move', (e) => { - if (!isDrawing) { - return - } - canvas?.remove(...canvas?.getObjects().filter((obj) => obj.name === 'guideTriangle')) - const pointer = canvas?.getPointer(e.e) - const triangle = new QPolygon( - [ - { x: pointer.x + length1 / 2, y: pointer.y + length4 / 2 }, - { x: pointer.x + length1 / 2 - length1, y: pointer.y + length4 / 2 }, - { x: pointer.x + length1 / 2 - length1, y: pointer.y + length4 / 2 - length4 }, - { x: pointer.x + length1 / 2 - length1 + length3, y: pointer.y + length4 / 2 - length4 }, - { x: pointer.x + length1 / 2 - length1 + length3, y: pointer.y + length4 / 2 - length4 + (length4 - length5) }, - { x: pointer.x + length1 / 2 - length1 + length3 + length2, y: pointer.y + length4 / 2 - length4 + (length4 - length5) }, - ], - { - fill: 'transparent', - stroke: 'black', - strokeWidth: 2, - selectable: true, - fontSize: fontSize, - name: 'guideTriangle', - }, - ) - - canvas?.add(triangle) - }) - - canvas?.on('mouse:down', (e) => { - isDrawing = false - }) - } - const createTemplate15 = () => { - const length1 = 300 //Number(prompt('1번')) - const length2 = 150 //Number(prompt('2번')) - const length3 = 100 //Number(prompt('3번')) - const length4 = 400 //Number(prompt('4번')) - const length5 = 200 //Number(prompt('5번')) - - let isDrawing = true - canvas?.on('mouse:move', (e) => { - if (!isDrawing) { - return - } - canvas?.remove(...canvas?.getObjects().filter((obj) => obj.name === 'guideTriangle')) - const pointer = canvas?.getPointer(e.e) - const triangle = new QPolygon( - [ - { x: pointer.x + length1 / 2, y: pointer.y + length4 / 2 }, - { x: pointer.x + length1 / 2 - length1, y: pointer.y + length4 / 2 }, - { x: pointer.x + length1 / 2 - length1, y: pointer.y + length4 / 2 - length5 }, - { x: pointer.x + length1 / 2 - length1 + length2, y: pointer.y + length4 / 2 - length5 }, - { x: pointer.x + length1 / 2 - length1 + length2, y: pointer.y + length4 / 2 - length5 - (length4 - length5) }, - { x: pointer.x + length1 / 2 - length1 + length2 + length3, y: pointer.y + length4 / 2 - length5 - (length4 - length5) }, - ], - { - fill: 'transparent', - stroke: 'black', - strokeWidth: 2, - selectable: true, - fontSize: fontSize, - name: 'guideTriangle', - }, - ) - - canvas?.add(triangle) - }) - - canvas?.on('mouse:down', (e) => { - isDrawing = false - }) - } - const createTemplate16 = () => { - const length1 = 300 //Number(prompt('1번')) - const length2 = 150 //Number(prompt('2번')) - const length3 = 100 //Number(prompt('3번')) - const length4 = 400 //Number(prompt('4번')) - const length5 = 200 //Number(prompt('5번')) - - let isDrawing = true - canvas?.on('mouse:move', (e) => { - if (!isDrawing) { - return - } - canvas?.remove(...canvas?.getObjects().filter((obj) => obj.name === 'guideTriangle')) - const pointer = canvas?.getPointer(e.e) - const triangle = new QPolygon( - [ - { x: pointer.x - length1 / 2, y: pointer.y + length4 / 2 }, - { x: pointer.x - length1 / 2 + length1, y: pointer.y + length4 / 2 }, - { x: pointer.x - length1 / 2 + length1, y: pointer.y + length4 / 2 - length5 }, - { x: pointer.x - length1 / 2 + length1 - length2, y: pointer.y + length4 / 2 - length5 }, - { x: pointer.x - length1 / 2 + length1 - length2, y: pointer.y + length4 / 2 - length5 - (length4 - length5) }, - { x: pointer.x - length1 / 2 + length1 - length2 - length3, y: pointer.y + length4 / 2 - length5 - (length4 - length5) }, - ], - { - fill: 'transparent', - stroke: 'black', - strokeWidth: 2, - selectable: true, - fontSize: fontSize, - name: 'guideTriangle', - }, - ) - - canvas?.add(triangle) - }) - - canvas?.on('mouse:down', (e) => { - isDrawing = false - }) - } - const createTemplate17 = () => { - const length1 = 300 //Number(prompt('1번')) - const length2 = 150 //Number(prompt('2번')) - const length3 = 250 //Number(prompt('3번')) - const length4 = 400 //Number(prompt('4번')) - const length5 = 200 //Number(prompt('5번')) - - let isDrawing = true - canvas?.on('mouse:move', (e) => { - if (!isDrawing) { - return - } - canvas?.remove(...canvas?.getObjects().filter((obj) => obj.name === 'guideTriangle')) - const pointer = canvas?.getPointer(e.e) - const triangle = new QPolygon( - [ - { x: pointer.x - length1 / 2, y: pointer.y + length4 / 2 }, - { x: pointer.x - length1 / 2 + length1, y: pointer.y + length4 / 2 }, - { x: pointer.x - length1 / 2 + length1, y: pointer.y + length4 / 2 - length5 }, - { x: pointer.x - length1 / 2 + length1 - length2, y: pointer.y + length4 / 2 - length5 }, - { x: pointer.x - length1 / 2 + length1 - length2, y: pointer.y + length4 / 2 - length5 - (length4 - length5) }, - { x: pointer.x - length1 / 2 + length1 - length2 - length3, y: pointer.y + length4 / 2 - length5 - (length4 - length5) }, - ], - { - fill: 'transparent', - stroke: 'black', - strokeWidth: 2, - selectable: true, - fontSize: fontSize, - name: 'guideTriangle', - }, - ) - - canvas?.add(triangle) - }) - - canvas?.on('mouse:down', (e) => { - isDrawing = false - }) - } - const createTemplate18 = () => { - const length1 = 300 //Number(prompt('1번')) - const length2 = 150 //Number(prompt('2번')) - const length3 = 250 //Number(prompt('3번')) - const length4 = 400 //Number(prompt('4번')) - const length5 = 200 //Number(prompt('5번')) - - let isDrawing = true - canvas?.on('mouse:move', (e) => { - if (!isDrawing) { - return - } - canvas?.remove(...canvas?.getObjects().filter((obj) => obj.name === 'guideTriangle')) - const pointer = canvas?.getPointer(e.e) - const triangle = new QPolygon( - [ - { x: pointer.x + length1 / 2, y: pointer.y + length4 / 2 }, - { x: pointer.x + length1 / 2 - length1, y: pointer.y + length4 / 2 }, - { x: pointer.x + length1 / 2 - length1, y: pointer.y + length4 / 2 - length5 }, - { x: pointer.x + length1 / 2 - length1 + length2, y: pointer.y + length4 / 2 - length5 }, - { x: pointer.x + length1 / 2 - length1 + length2, y: pointer.y + length4 / 2 - length5 - (length4 - length5) }, - { x: pointer.x + length1 / 2 - length1 + length2 + length3, y: pointer.y + length4 / 2 - length5 - (length4 - length5) }, - ], - { - fill: 'transparent', - stroke: 'black', - strokeWidth: 2, - selectable: true, - fontSize: fontSize, - name: 'guideTriangle', - }, - ) - - canvas?.add(triangle) - }) - - canvas?.on('mouse:down', (e) => { - isDrawing = false - }) - } - const createTemplate19 = () => { - const length1 = 500 //Number(prompt('1번')) - const length2 = 300 //Number(prompt('2번')) - const length3 = 400 //Number(prompt('3번')) - const length4 = 300 //Number(prompt('4번')) - - // 좌측 빗변 - const leftHypotenuse = Math.sqrt(((length1 - length2) / 2) ** 2 + length3 ** 2) - const rightHypotenuse = (length4 / length3) * leftHypotenuse - - const leftAngle = Math.acos((length1 - length2) / 2 / leftHypotenuse) - - let isDrawing = true - canvas?.on('mouse:move', (e) => { - if (!isDrawing) { - return - } - canvas?.remove(...canvas?.getObjects().filter((obj) => obj.name === 'guideTriangle')) - const pointer = canvas?.getPointer(e.e) - const triangle = new QPolygon( - [ - { x: pointer.x - length1 / 2 + leftHypotenuse * Math.cos(leftAngle), y: pointer.y + length3 / 2 - leftHypotenuse * Math.sin(leftAngle) }, - { x: pointer.x - length1 / 2, y: pointer.y + length3 / 2 }, - { x: pointer.x + length1 / 2, y: pointer.y + length3 / 2 }, - { x: pointer.x + length1 / 2 - rightHypotenuse * Math.cos(leftAngle), y: pointer.y + length3 / 2 - rightHypotenuse * Math.sin(leftAngle) }, - { - x: pointer.x + length1 / 2 - rightHypotenuse * Math.cos(leftAngle) - length2, - y: pointer.y + length3 / 2 - rightHypotenuse * Math.sin(leftAngle), - }, - ], - { - fill: 'transparent', - stroke: 'black', - strokeWidth: 2, - selectable: true, - fontSize: fontSize, - name: 'guideTriangle', - }, - ) - - canvas?.add(triangle) - }) - - canvas?.on('mouse:down', (e) => { - isDrawing = false - }) - } - const createTemplate20 = () => { - const length1 = 500 //Number(prompt('1번')) - const length2 = 300 //Number(prompt('2번')) - const length3 = 400 //Number(prompt('3번')) - const length4 = 300 //Number(prompt('4번')) - - // 좌측 빗변 - const rightHypotenuse = Math.sqrt(((length1 - length2) / 2) ** 2 + length3 ** 2) - const leftHypotenuse = (length4 / length3) * rightHypotenuse - - const rightAngle = Math.acos((length1 - length2) / 2 / rightHypotenuse) - - let isDrawing = true - canvas?.on('mouse:move', (e) => { - if (!isDrawing) { - return - } - canvas?.remove(...canvas?.getObjects().filter((obj) => obj.name === 'guideTriangle')) - const pointer = canvas?.getPointer(e.e) - const triangle = new QPolygon( - [ - { - x: pointer.x + length1 / 2 - rightHypotenuse * Math.cos(rightAngle), - y: pointer.y + length3 / 2 - rightHypotenuse * Math.sin(rightAngle), - }, - { x: pointer.x + length1 / 2, y: pointer.y + length3 / 2 }, - { x: pointer.x - length1 / 2, y: pointer.y + length3 / 2 }, - { x: pointer.x - length1 / 2 + leftHypotenuse * Math.cos(rightAngle), y: pointer.y + length3 / 2 - leftHypotenuse * Math.sin(rightAngle) }, - { - x: pointer.x - length1 / 2 + leftHypotenuse * Math.cos(rightAngle) + length2, - y: pointer.y + length3 / 2 - leftHypotenuse * Math.sin(rightAngle), - }, - ], - { - fill: 'transparent', - stroke: 'black', - strokeWidth: 2, - selectable: true, - fontSize: fontSize, - name: 'guideTriangle', - }, - ) - - canvas?.add(triangle) - }) - - canvas?.on('mouse:down', (e) => { - isDrawing = false - }) - } - /** - * 19~22번은 못함 - */ - const createTemplate23 = () => { - const length1 = 300 //Number(prompt('1번')) - const length2 = 100 //Number(prompt('2번')) - const length3 = 150 //Number(prompt('3번')) - const length4 = 400 //Number(prompt('4번')) - const length5 = 300 //Number(prompt('5번')) - - let isDrawing = true - canvas?.on('mouse:move', (e) => { - if (!isDrawing) { - return - } - canvas?.remove(...canvas?.getObjects().filter((obj) => obj.name === 'guideTriangle')) - const pointer = canvas?.getPointer(e.e) - const triangle = new QPolygon( - [ - { x: pointer.x - length1 / 2 + length2, y: pointer.y + length4 / 2 }, - { x: pointer.x - length1 / 2, y: pointer.y + length4 / 2 }, - { x: pointer.x - length1 / 2, y: pointer.y + length4 / 2 - length4 }, - { x: pointer.x - length1 / 2 + length1, y: pointer.y + length4 / 2 - length4 }, - { x: pointer.x - length1 / 2 + length1, y: pointer.y + length4 / 2 - length4 + length4 }, - { x: pointer.x - length1 / 2 + length1 - length3, y: pointer.y + length4 / 2 - length4 + length4 }, - { x: pointer.x - length1 / 2 + length2 + (length1 - length2 - length3) / 2, y: pointer.y + length4 / 2 - length4 + length5 }, - ], - { - fill: 'transparent', - stroke: 'black', - strokeWidth: 2, - selectable: true, - fontSize: fontSize, - name: 'guideTriangle', - }, - ) - - canvas?.add(triangle) - }) - - canvas?.on('mouse:down', (e) => { - isDrawing = false - }) - } - - const createTemplate24 = () => { - const length1 = 300 //Number(prompt('1번')) - const length2 = 400 //Number(prompt('2번')) - const length3 = 300 //Number(prompt('3번')) - - let isDrawing = true - canvas?.on('mouse:move', (e) => { - if (!isDrawing) { - return - } - canvas?.remove(...canvas?.getObjects().filter((obj) => obj.name === 'guideTriangle')) - const pointer = canvas?.getPointer(e.e) - const triangle = new QPolygon( - [ - { x: pointer.x - length1 / 2, y: pointer.y + length2 - length2 / 2 }, - { x: pointer.x - length1 / 2, y: pointer.y + length2 - length2 / 2 - length3 }, - { x: pointer.x, y: pointer.y + length2 - length2 / 2 - length3 - (length2 - length3) }, - { x: pointer.x + length1 / 2, y: pointer.y + length2 - length2 / 2 - length3 }, - { x: pointer.x + length1 / 2, y: pointer.y + length2 - length2 / 2 - length3 + length3 }, - ], - { - fill: 'transparent', - stroke: 'black', - strokeWidth: 2, - selectable: true, - fontSize: fontSize, - name: 'guideTriangle', - }, - ) - - canvas?.add(triangle) - }) - - canvas?.on('mouse:down', (e) => { - isDrawing = false - }) - } - const createTemplate25 = () => { - const length1 = 300 //Number(prompt('1번')) - const length2 = 200 //Number(prompt('2번')) - const length3 = 300 //Number(prompt('3번')) - const length4 = 200 //Number(prompt('3번')) - - let isDrawing = true - canvas?.on('mouse:move', (e) => { - if (!isDrawing) { - return - } - canvas?.remove(...canvas?.getObjects().filter((obj) => obj.name === 'guideTriangle')) - const pointer = canvas?.getPointer(e.e) - const triangle = new QPolygon( - [ - { - x: pointer.x - length1 / 2, - y: pointer.y + length3 / 2, - }, - { - x: pointer.x - length1 / 2 + (length1 - length2) / 2, - y: pointer.y + length3 / 2 - (length3 - length4), - }, - { - x: pointer.x - length1 / 2 + (length1 - length2) / 2, - y: pointer.y + length3 / 2 - (length3 - length4) - length4, - }, - { - x: pointer.x - length1 / 2 + (length1 - length2) / 2 + length2, - y: pointer.y + length3 / 2 - (length3 - length4) - length4, - }, - { - x: pointer.x - length1 / 2 + (length1 - length2) / 2 + length2, - y: pointer.y + length3 / 2 - (length3 - length4) - length4 + length4, - }, - { - x: pointer.x - length1 / 2 + length1, - y: pointer.y + length3 / 2, - }, - ], - { - fill: 'transparent', - stroke: 'black', - strokeWidth: 2, - selectable: true, - fontSize: fontSize, - name: 'guideTriangle', - }, - ) - - canvas?.add(triangle) - }) - - canvas?.on('mouse:down', (e) => { - isDrawing = false - }) - } - const createTemplate26 = () => { - const length1 = 500 //Number(prompt('1번')) - const length2 = 200 //Number(prompt('2번')) - const length3 = 300 //Number(prompt('3번')) - const length4 = 400 //Number(prompt('3번')) - - const angle = (Math.asin(length3 / length4) * 180) / Math.PI // 높이와 빗변으로 먼저 각도구하기 - - const topL = (length1 - length2) / 2 / Math.cos((angle * Math.PI) / 180) // 꺽이는부분 윗쪽 길이 - - let isDrawing = true - canvas?.on('mouse:move', (e) => { - if (!isDrawing) { - return - } - canvas?.remove(...canvas?.getObjects().filter((obj) => obj.name === 'guideTriangle')) - const pointer = canvas?.getPointer(e.e) - const triangle = new QPolygon( - [ - { - x: pointer.x - length1 / 2 + length1, - y: pointer.y + length3 / 2, - }, - { - x: pointer.x - length1 / 2, - y: pointer.y + length3 / 2, - }, - { - x: pointer.x - length1 / 2 + length4 * Math.cos(degreesToRadians(angle)), - y: pointer.y + length3 / 2 - length4 * Math.sin(degreesToRadians(angle)), - }, - { - x: pointer.x - length1 / 2 + length4 * Math.cos(degreesToRadians(angle)) + length2, - y: pointer.y + length3 / 2 - length4 * Math.sin(degreesToRadians(angle)), - }, - { - x: pointer.x - length1 / 2 + length4 * Math.cos(degreesToRadians(angle)) + length2 + topL * Math.cos(degreesToRadians(angle)), - y: pointer.y + length3 / 2 - length4 * Math.sin(degreesToRadians(angle)) + topL * Math.sin(degreesToRadians(angle)), - }, - ], - { - fill: 'transparent', - stroke: 'black', - strokeWidth: 2, - selectable: true, - fontSize: fontSize, - name: 'guideTriangle', - }, - ) - - canvas?.add(triangle) - }) - - canvas?.on('mouse:down', (e) => { - isDrawing = false - }) - } - const createTemplate27 = () => { - const length1 = 500 //Number(prompt('1번')) - const length2 = 200 //Number(prompt('2번')) - const length3 = 300 //Number(prompt('3번')) - const length4 = 400 //Number(prompt('3번')) - - const angle = (Math.asin(length3 / length4) * 180) / Math.PI // 높이와 빗변으로 먼저 각도구하기 - - const topL = (length1 - length2) / 2 / Math.cos((angle * Math.PI) / 180) // 꺽이는부분 윗쪽 길이 - - let isDrawing = true - canvas?.on('mouse:move', (e) => { - if (!isDrawing) { - return - } - canvas?.remove(...canvas?.getObjects().filter((obj) => obj.name === 'guideTriangle')) - const pointer = canvas?.getPointer(e.e) - const triangle = new QPolygon( - [ - { - x: pointer.x - length1 / 2, - y: pointer.y + length3 / 2, - }, - { - x: pointer.x - length1 / 2 + length1, - y: pointer.y + length3 / 2, - }, - { - x: pointer.x - length1 / 2 + length1 - length4 * Math.cos(degreesToRadians(angle)), - y: pointer.y + length3 / 2 - length4 * Math.sin(degreesToRadians(angle)), - }, - { - x: pointer.x - length1 / 2 + length1 - length4 * Math.cos(degreesToRadians(angle)) - length2, - y: pointer.y + length3 / 2 - length4 * Math.sin(degreesToRadians(angle)), - }, - { - x: pointer.x - length1 / 2 + length1 - length4 * Math.cos(degreesToRadians(angle)) - length2 - topL * Math.cos(degreesToRadians(angle)), - y: pointer.y + length3 / 2 - length4 * Math.sin(degreesToRadians(angle)) + topL * Math.sin(degreesToRadians(angle)), - }, - ], - { - fill: 'transparent', - stroke: 'black', - strokeWidth: 2, - selectable: true, - fontSize: fontSize, - name: 'guideTriangle', - }, - ) - - canvas?.add(triangle) - }) - - canvas?.on('mouse:down', (e) => { - isDrawing = false - }) - } - const createTemplate28 = () => { - const length1 = Number(prompt('밑변')) - const length2 = Number(prompt('높이')) - const length3 = Number(prompt('빗변')) - - const a = Math.sqrt(length3 * length3 - length2 * length2) // 입력된 밑변과 높이 - - const sinA = a / length3 - const angleInRadians = Math.asin(sinA) - const angleInDegrees = angleInRadians * (180 / Math.PI) - const b = a - length1 / 2 - - const c = b / Math.tan(angleInRadians) - const d = Math.sqrt(b * b + c * c) - - if (isNaN(a)) { - alert('값이 잘못되었습니다.') - return - } - if (b < 0) { - alert('값이 잘못되었습니다.') - return - } - if (angleInDegrees === 0 || angleInRadians === 0) { - alert('값이 잘못되었습니다.') - return - } - - let isDrawing = true - let pentagon - canvas?.on('mouse:move', (e) => { - if (!isDrawing) { - return - } - canvas?.remove(...canvas?.getObjects().filter((obj) => obj.name === 'guideTriangle')) - const pointer = canvas?.getPointer(e.e) - const newAngleInRadians = (90 - angleInDegrees) * (Math.PI / 180) - - pentagon = new QPolygon( - [ - { x: pointer.x - (length1 + b) / 2, y: pointer.y + length2 / 2 }, - { x: pointer.x + length1 / 2 - b / 2, y: pointer.y + length2 / 2 }, - { - x: pointer.x + length1 / 2 - b / 2 + d * Math.cos(newAngleInRadians), - y: pointer.y + length2 / 2 - d * Math.sin(newAngleInRadians), - }, - { - x: pointer.x - (length1 + b) / 2 + length3 * Math.cos(newAngleInRadians), - y: pointer.y + length2 / 2 - length3 * Math.sin(newAngleInRadians), - }, - ], - { - fill: 'transparent', - stroke: 'gray', - strokeWidth: 1, - selectable: true, - fontSize: fontSize, - name: 'guideTriangle', - }, - ) - - canvas?.add(pentagon) - }) - - canvas?.on('mouse:down', (e) => { - isDrawing = false - pentagon.set('name', 'roof') - pentagon.set('stroke', 2) - canvas?.renderAll() - }) - } - const createTemplate29 = () => { - const length1 = Number(prompt('밑변')) - const length2 = Number(prompt('높이')) - const length3 = Number(prompt('빗변')) - - const a = Math.sqrt(length3 * length3 - length2 * length2) // 입력된 밑변과 높이 - - const sinA = a / length3 - const angleInRadians = Math.asin(sinA) - const angleInDegrees = angleInRadians * (180 / Math.PI) - const b = a - length1 / 2 - - const c = b / Math.tan(angleInRadians) - const d = Math.sqrt(b * b + c * c) - - if (isNaN(a)) { - alert('값이 잘못되었습니다.') - return - } - if (b < 0) { - alert('값이 잘못되었습니다.') - return - } - if (angleInDegrees === 0 || angleInRadians === 0) { - alert('값이 잘못되었습니다.') - return - } - - let isDrawing = true - let pentagon - canvas?.on('mouse:move', (e) => { - if (!isDrawing) { - return - } - canvas?.remove(...canvas?.getObjects().filter((obj) => obj.name === 'guideTriangle')) - const pointer = canvas?.getPointer(e.e) - const newAngleInRadians = (90 - angleInDegrees) * (Math.PI / 180) - - pentagon = new QPolygon( - [ - { - x: pointer.x + length1 / 2 - b / 2 - length3 * Math.cos(newAngleInRadians), - y: pointer.y + length2 / 2 - length3 * Math.sin(newAngleInRadians), - }, - { x: pointer.x + length1 / 2 - b / 2, y: pointer.y + length2 / 2 }, - { x: pointer.x - (length1 + b) / 2, y: pointer.y + length2 / 2 }, - { x: pointer.x - (length1 + b) / 2 - d * Math.cos(newAngleInRadians), y: pointer.y + length2 / 2 - d * Math.sin(newAngleInRadians) }, - ], - { - fill: 'transparent', - stroke: 'gray', - strokeWidth: 1, - selectable: true, - fontSize: fontSize, - name: 'guideTriangle', - }, - ) - - canvas?.add(pentagon) - }) - - canvas?.on('mouse:down', (e) => { - isDrawing = false - pentagon.set('name', 'roof') - pentagon.set('stroke', 2) - canvas?.renderAll() - }) - } - const moduleConfiguration = () => { createRoofRack() } @@ -1675,60 +759,6 @@ export default function Roof2(props) { - - - - - - - - - - - - - - - - - - diff --git a/src/components/ui/SurfaceShape.jsx b/src/components/ui/SurfaceShape.jsx index 6a5147c8..774f8e28 100644 --- a/src/components/ui/SurfaceShape.jsx +++ b/src/components/ui/SurfaceShape.jsx @@ -4,6 +4,7 @@ import { useRecoilValue, useSetRecoilState } from 'recoil' import { modalState } from '@/store/modalAtom' import { QPolygon } from '@/components/fabric/QPolygon' import { fontSizeState, roofMaterialState } from '@/store/canvasAtom' +import { degreesToRadians } from '@turf/turf' /** * 면형상 배치 모달 @@ -40,6 +41,7 @@ export const SurfaceShapeModal = ({ canvas }) => { const onSave = () => { let isDrawing = true let obj = null + let points = [] canvas?.on('mouse:move', (e) => { if (!isDrawing) { return @@ -54,210 +56,420 @@ export const SurfaceShapeModal = ({ canvas }) => { newLength2 = Math.sqrt(length3 ** 2 - (length1 / 2) ** 2) } - obj = new QPolygon( - [ - { x: pointer.x, y: pointer.y - parseInt(newLength2) / 2 }, - { x: pointer.x - parseInt(length1) / 2, y: pointer.y + parseInt(newLength2) / 2 }, - { x: pointer.x + parseInt(length1) / 2, y: pointer.y + parseInt(newLength2) / 2 }, - ], - { - fill: 'transparent', - stroke: 'black', - strokeWidth: 2, - selectable: false, - fontSize: fontSize, - name: 'guideTriangle', - }, - ) + points = [ + { x: pointer.x, y: pointer.y - parseInt(newLength2) / 2 }, + { x: pointer.x - parseInt(length1) / 2, y: pointer.y + parseInt(newLength2) / 2 }, + { x: pointer.x + parseInt(length1) / 2, y: pointer.y + parseInt(newLength2) / 2 }, + ] break } case 2: { - obj = new QPolygon( - [ - { x: pointer.x - length1 / 2, y: pointer.y + length2 / 2 }, - { x: pointer.x + length1 / 2, y: pointer.y + length2 / 2 }, - { x: pointer.x + length1 / 2, y: pointer.y - length2 / 2 }, - { x: pointer.x - length1 / 2, y: pointer.y - length2 / 2 }, - ], - { - fill: 'transparent', - stroke: 'black', - strokeWidth: 2, - selectable: false, - fontSize: fontSize, - name: 'guideTriangle', - }, - ) + points = [ + { x: pointer.x - length1 / 2, y: pointer.y + length2 / 2 }, + { x: pointer.x + length1 / 2, y: pointer.y + length2 / 2 }, + { x: pointer.x + length1 / 2, y: pointer.y - length2 / 2 }, + { x: pointer.x - length1 / 2, y: pointer.y - length2 / 2 }, + ] + break } case 3: { - obj = new QPolygon( - [ - { x: pointer.x - length1 / 2, y: pointer.y + length2 / 2 }, - { x: pointer.x + length1 / 2, y: pointer.y + length2 / 2 }, - { x: pointer.x + length3 / 2, y: pointer.y - length2 / 2 }, - { x: pointer.x - length3 / 2, y: pointer.y - length2 / 2 }, - ], - { - fill: 'transparent', - stroke: 'black', - strokeWidth: 2, - selectable: false, - fontSize: fontSize, - name: 'guideTriangle', - }, - ) + points = [ + { x: pointer.x - length1 / 2, y: pointer.y + length2 / 2 }, + { x: pointer.x + length1 / 2, y: pointer.y + length2 / 2 }, + { x: pointer.x + length3 / 2, y: pointer.y - length2 / 2 }, + { x: pointer.x - length3 / 2, y: pointer.y - length2 / 2 }, + ] + break } case 4: { - obj = new QPolygon( - [ - { x: pointer.x - length1 / 2, y: pointer.y + length2 / 2 }, - { x: pointer.x + length1 / 2, y: pointer.y + length2 / 2 }, - { x: pointer.x + length1 / 2, y: pointer.y - length2 / 2 }, - ], - { - fill: 'transparent', - stroke: 'black', - strokeWidth: 2, - selectable: false, - fontSize: fontSize, - name: 'guideTriangle', - }, - ) + points = [ + { x: pointer.x - length1 / 2, y: pointer.y + length2 / 2 }, + { x: pointer.x + length1 / 2, y: pointer.y + length2 / 2 }, + { x: pointer.x + length1 / 2, y: pointer.y - length2 / 2 }, + ] break } case 5: { - obj = new QPolygon( - [ - { x: pointer.x + length1 / 2, y: pointer.y + length2 / 2 }, - { x: pointer.x - length1 / 2, y: pointer.y + length2 / 2 }, - { x: pointer.x - length1 / 2, y: pointer.y - length2 / 2 }, - ], - { - fill: 'transparent', - stroke: 'black', - strokeWidth: 2, - selectable: false, - fontSize: fontSize, - name: 'guideTriangle', - }, - ) + points = [ + { x: pointer.x + length1 / 2, y: pointer.y + length2 / 2 }, + { x: pointer.x - length1 / 2, y: pointer.y + length2 / 2 }, + { x: pointer.x - length1 / 2, y: pointer.y - length2 / 2 }, + ] + break } case 6: { - obj = new QPolygon( - [ - { x: pointer.x - length1 / 2, y: pointer.y - length3 / 2 }, - { x: pointer.x - length1 / 2, y: pointer.y + length3 / 2 }, - { x: pointer.x + length1 / 2, y: pointer.y + length3 / 2 }, - { x: pointer.x + length1 / 2, y: pointer.y + length3 / 2 - length2 }, - ], - { - fill: 'transparent', - stroke: 'black', - strokeWidth: 2, - selectable: false, - fontSize: fontSize, - name: 'guideTriangle', - }, - ) + points = [ + { x: pointer.x - length1 / 2, y: pointer.y - length3 / 2 }, + { x: pointer.x - length1 / 2, y: pointer.y + length3 / 2 }, + { x: pointer.x + length1 / 2, y: pointer.y + length3 / 2 }, + { x: pointer.x + length1 / 2, y: pointer.y + length3 / 2 - length2 }, + ] + break } case 7: { - obj = new QPolygon( - [ - { x: pointer.x - length1 / 2, y: pointer.y - length2 / 2 }, - { x: pointer.x - length1 / 2, y: pointer.y + length2 / 2 }, - { x: pointer.x + length1 / 2, y: pointer.y + length2 / 2 }, - { x: pointer.x + length1 / 2, y: pointer.y + length2 / 2 - length3 }, - ], - { - fill: 'transparent', - stroke: 'black', - strokeWidth: 2, - selectable: false, - fontSize: fontSize, - name: 'guideTriangle', - }, - ) + points = [ + { x: pointer.x - length1 / 2, y: pointer.y - length2 / 2 }, + { x: pointer.x - length1 / 2, y: pointer.y + length2 / 2 }, + { x: pointer.x + length1 / 2, y: pointer.y + length2 / 2 }, + { x: pointer.x + length1 / 2, y: pointer.y + length2 / 2 - length3 }, + ] + break } case 8: { const angleInRadians = Math.asin(length2 / length3) - obj = new QPolygon( - [ - { x: pointer.x - length1 / 2, y: pointer.y + length2 / 2 }, - { x: pointer.x - length1 / 2 + length3 * Math.cos(angleInRadians), y: pointer.y + length2 / 2 - length3 * Math.sin(angleInRadians) }, - { x: pointer.x + length1 / 2 + length3 * Math.cos(angleInRadians), y: pointer.y + length2 / 2 - length3 * Math.sin(angleInRadians) }, - { x: pointer.x + length1 / 2, y: pointer.y + length2 / 2 }, - ], - { - fill: 'transparent', - stroke: 'black', - strokeWidth: 2, - selectable: false, - fontSize: fontSize, - name: 'guideTriangle', - }, - ) + points = [ + { x: pointer.x - length1 / 2, y: pointer.y + length2 / 2 }, + { x: pointer.x - length1 / 2 + length3 * Math.cos(angleInRadians), y: pointer.y + length2 / 2 - length3 * Math.sin(angleInRadians) }, + { x: pointer.x + length1 / 2 + length3 * Math.cos(angleInRadians), y: pointer.y + length2 / 2 - length3 * Math.sin(angleInRadians) }, + { x: pointer.x + length1 / 2, y: pointer.y + length2 / 2 }, + ] + break } case 9: { const angleInRadians = Math.asin(length2 / length3) - obj = new QPolygon( - [ - { x: pointer.x + length1 / 2, y: pointer.y + length2 / 2 }, - { x: pointer.x + length1 / 2 - length3 * Math.cos(angleInRadians), y: pointer.y + length2 / 2 - length3 * Math.sin(angleInRadians) }, - { x: pointer.x - length1 / 2 - length3 * Math.cos(angleInRadians), y: pointer.y + length2 / 2 - length3 * Math.sin(angleInRadians) }, - { x: pointer.x - length1 / 2, y: pointer.y + length2 / 2 }, - ], - { - fill: 'transparent', - stroke: 'black', - strokeWidth: 2, - selectable: false, - fontSize: fontSize, - name: 'guideTriangle', - }, - ) + points = [ + { x: pointer.x + length1 / 2, y: pointer.y + length2 / 2 }, + { x: pointer.x + length1 / 2 - length3 * Math.cos(angleInRadians), y: pointer.y + length2 / 2 - length3 * Math.sin(angleInRadians) }, + { x: pointer.x - length1 / 2 - length3 * Math.cos(angleInRadians), y: pointer.y + length2 / 2 - length3 * Math.sin(angleInRadians) }, + { x: pointer.x - length1 / 2, y: pointer.y + length2 / 2 }, + ] + break } case 10: { - console.log(length1, length2, length3, length4, length5) - obj = new QPolygon( - [ - { x: pointer.x - (length1 + length2 + length3) / 2, y: pointer.y - (length4 + length5) / 2 }, - { x: pointer.x - (length1 + length2 + length3) / 2, y: pointer.y + (length4 + length5) / 2 }, - { x: pointer.x - (length1 + length2 + length3) / 2 + length1, y: pointer.y + (length4 + length5) / 2 }, - { x: pointer.x - (length1 + length2 + length3) / 2 + length1, y: pointer.y + (length4 + length5) / 2 - length5 }, - { x: pointer.x - (length1 + length2 + length3) / 2 + length1 + length2, y: pointer.y + (length4 + length5) / 2 - length5 }, - { x: pointer.x - (length1 + length2 + length3) / 2 + length1 + length2, y: pointer.y + (length4 + length5) / 2 - length5 + length5 }, - { - x: pointer.x - (length1 + length2 + length3) / 2 + length1 + length2 + length3, - y: pointer.y + (length4 + length5) / 2 - length5 + length5, - }, - { - x: pointer.x - (length1 + length2 + length3) / 2 + length1 + length2 + length3, - y: pointer.y + (length4 + length5) / 2 - length5 + length5 - (length4 + length5), - }, - ], + points = [ + { x: pointer.x - (length1 + length2 + length3) / 2, y: pointer.y - (length4 + length5) / 2 }, + { x: pointer.x - (length1 + length2 + length3) / 2, y: pointer.y + (length4 + length5) / 2 }, + { x: pointer.x - (length1 + length2 + length3) / 2 + length1, y: pointer.y + (length4 + length5) / 2 }, + { x: pointer.x - (length1 + length2 + length3) / 2 + length1, y: pointer.y + (length4 + length5) / 2 - length5 }, + { x: pointer.x - (length1 + length2 + length3) / 2 + length1 + length2, y: pointer.y + (length4 + length5) / 2 - length5 }, + { x: pointer.x - (length1 + length2 + length3) / 2 + length1 + length2, y: pointer.y + (length4 + length5) / 2 - length5 + length5 }, { - fill: 'transparent', - stroke: 'black', - strokeWidth: 2, - selectable: true, - fontSize: fontSize, - name: 'guideTriangle', + x: pointer.x - (length1 + length2 + length3) / 2 + length1 + length2 + length3, + y: pointer.y + (length4 + length5) / 2 - length5 + length5, }, - ) + { + x: pointer.x - (length1 + length2 + length3) / 2 + length1 + length2 + length3, + y: pointer.y + (length4 + length5) / 2 - length5 + length5 - (length4 + length5), + }, + ] + + break + } + case 11: { + points = [ + { x: pointer.x - length1 / 2, y: pointer.y + length4 / 2 }, + { x: pointer.x - length1 / 2 + length1, y: pointer.y + length4 / 2 }, + { x: pointer.x - length1 / 2 + length1, y: pointer.y + length4 / 2 - length3 }, + { x: pointer.x - length1 / 2 + length1 - (length1 - length2), y: pointer.y + length4 / 2 - length3 }, + { x: pointer.x - length1 / 2 + length1 - (length1 - length2), y: pointer.y + length4 / 2 - length3 + (length3 - length4) }, + { x: pointer.x - length1 / 2 + length1 - (length1 - length2) - length2, y: pointer.y + length4 / 2 - length3 + (length3 - length4) }, + ] + + break + } + case 12: { + points = [ + { x: pointer.x - length1 / 2, y: pointer.y + length4 / 2 }, + { x: pointer.x - length1 / 2 + length1, y: pointer.y + length4 / 2 }, + { x: pointer.x - length1 / 2 + length1, y: pointer.y + length4 / 2 - length4 }, + { x: pointer.x - length1 / 2 + length1 - length2, y: pointer.y + length4 / 2 - length4 }, + { x: pointer.x - length1 / 2 + length1 - length2, y: pointer.y + length4 / 2 - length4 - (length3 - length4) }, + { x: pointer.x - length1 / 2 + length1 - length2 - (length1 - length2), y: pointer.y + length4 / 2 - length4 - (length3 - length4) }, + ] + + break + } + case 13: { + points = [ + { x: pointer.x - length1 / 2, y: pointer.y + length4 / 2 }, + { x: pointer.x - length1 / 2 + length1, y: pointer.y + length4 / 2 }, + { x: pointer.x - length1 / 2 + length1, y: pointer.y + length4 / 2 - length4 }, + { x: pointer.x - length1 / 2 + length1 - length3, y: pointer.y + length4 / 2 - length4 }, + { x: pointer.x - length1 / 2 + length1 - length3, y: pointer.y + length4 / 2 - length4 + (length4 - length5) }, + { x: pointer.x - length1 / 2 + length1 - length3 - length2, y: pointer.y + length4 / 2 - length4 + (length4 - length5) }, + ] + break + } + case 14: { + points = [ + { x: pointer.x + length1 / 2, y: pointer.y + length4 / 2 }, + { x: pointer.x + length1 / 2 - length1, y: pointer.y + length4 / 2 }, + { x: pointer.x + length1 / 2 - length1, y: pointer.y + length4 / 2 - length4 }, + { x: pointer.x + length1 / 2 - length1 + length3, y: pointer.y + length4 / 2 - length4 }, + { x: pointer.x + length1 / 2 - length1 + length3, y: pointer.y + length4 / 2 - length4 + (length4 - length5) }, + { x: pointer.x + length1 / 2 - length1 + length3 + length2, y: pointer.y + length4 / 2 - length4 + (length4 - length5) }, + ] + break + } + case 15: { + points = [ + { x: pointer.x + length1 / 2, y: pointer.y + length4 / 2 }, + { x: pointer.x + length1 / 2 - length1, y: pointer.y + length4 / 2 }, + { x: pointer.x + length1 / 2 - length1, y: pointer.y + length4 / 2 - length5 }, + { x: pointer.x + length1 / 2 - length1 + length2, y: pointer.y + length4 / 2 - length5 }, + { x: pointer.x + length1 / 2 - length1 + length2, y: pointer.y + length4 / 2 - length5 - (length4 - length5) }, + { x: pointer.x + length1 / 2 - length1 + length2 + length3, y: pointer.y + length4 / 2 - length5 - (length4 - length5) }, + ] + break + } + case 16: { + points = [ + { x: pointer.x - length1 / 2, y: pointer.y + length4 / 2 }, + { x: pointer.x - length1 / 2 + length1, y: pointer.y + length4 / 2 }, + { x: pointer.x - length1 / 2 + length1, y: pointer.y + length4 / 2 - length5 }, + { x: pointer.x - length1 / 2 + length1 - length2, y: pointer.y + length4 / 2 - length5 }, + { x: pointer.x - length1 / 2 + length1 - length2, y: pointer.y + length4 / 2 - length5 - (length4 - length5) }, + { x: pointer.x - length1 / 2 + length1 - length2 - length3, y: pointer.y + length4 / 2 - length5 - (length4 - length5) }, + ] + break + } + case 17: { + points = [ + { x: pointer.x - length1 / 2, y: pointer.y + length4 / 2 }, + { x: pointer.x - length1 / 2 + length1, y: pointer.y + length4 / 2 }, + { x: pointer.x - length1 / 2 + length1, y: pointer.y + length4 / 2 - length5 }, + { x: pointer.x - length1 / 2 + length1 - length2, y: pointer.y + length4 / 2 - length5 }, + { x: pointer.x - length1 / 2 + length1 - length2, y: pointer.y + length4 / 2 - length5 - (length4 - length5) }, + { x: pointer.x - length1 / 2 + length1 - length2 - length3, y: pointer.y + length4 / 2 - length5 - (length4 - length5) }, + ] + break + } + case 18: { + points = [ + { x: pointer.x + length1 / 2, y: pointer.y + length4 / 2 }, + { x: pointer.x + length1 / 2 - length1, y: pointer.y + length4 / 2 }, + { x: pointer.x + length1 / 2 - length1, y: pointer.y + length4 / 2 - length5 }, + { x: pointer.x + length1 / 2 - length1 + length2, y: pointer.y + length4 / 2 - length5 }, + { x: pointer.x + length1 / 2 - length1 + length2, y: pointer.y + length4 / 2 - length5 - (length4 - length5) }, + { x: pointer.x + length1 / 2 - length1 + length2 + length3, y: pointer.y + length4 / 2 - length5 - (length4 - length5) }, + ] + break + } + + case 19: { + const leftHypotenuse = Math.sqrt(((length1 - length2) / 2) ** 2 + length3 ** 2) + const rightHypotenuse = (length4 / length3) * leftHypotenuse + + const leftAngle = Math.acos((length1 - length2) / 2 / leftHypotenuse) + + points = [ + { x: pointer.x - length1 / 2 + leftHypotenuse * Math.cos(leftAngle), y: pointer.y + length3 / 2 - leftHypotenuse * Math.sin(leftAngle) }, + { x: pointer.x - length1 / 2, y: pointer.y + length3 / 2 }, + { x: pointer.x + length1 / 2, y: pointer.y + length3 / 2 }, + { + x: pointer.x + length1 / 2 - rightHypotenuse * Math.cos(leftAngle), + y: pointer.y + length3 / 2 - rightHypotenuse * Math.sin(leftAngle), + }, + { + x: pointer.x + length1 / 2 - rightHypotenuse * Math.cos(leftAngle) - length2, + y: pointer.y + length3 / 2 - rightHypotenuse * Math.sin(leftAngle), + }, + ] + + break + } + case 20: { + // 좌측 빗변 + const rightHypotenuse = Math.sqrt(((length1 - length2) / 2) ** 2 + length3 ** 2) + const leftHypotenuse = (length4 / length3) * rightHypotenuse + + const rightAngle = Math.acos((length1 - length2) / 2 / rightHypotenuse) + points = [ + { + x: pointer.x + length1 / 2 - rightHypotenuse * Math.cos(rightAngle), + y: pointer.y + length3 / 2 - rightHypotenuse * Math.sin(rightAngle), + }, + { x: pointer.x + length1 / 2, y: pointer.y + length3 / 2 }, + { x: pointer.x - length1 / 2, y: pointer.y + length3 / 2 }, + { + x: pointer.x - length1 / 2 + leftHypotenuse * Math.cos(rightAngle), + y: pointer.y + length3 / 2 - leftHypotenuse * Math.sin(rightAngle), + }, + { + x: pointer.x - length1 / 2 + leftHypotenuse * Math.cos(rightAngle) + length2, + y: pointer.y + length3 / 2 - leftHypotenuse * Math.sin(rightAngle), + }, + ] + break + } + + case 23: { + points = [ + { x: pointer.x - length1 / 2 + length2, y: pointer.y + length4 / 2 }, + { x: pointer.x - length1 / 2, y: pointer.y + length4 / 2 }, + { x: pointer.x - length1 / 2, y: pointer.y + length4 / 2 - length4 }, + { x: pointer.x - length1 / 2 + length1, y: pointer.y + length4 / 2 - length4 }, + { x: pointer.x - length1 / 2 + length1, y: pointer.y + length4 / 2 - length4 + length4 }, + { x: pointer.x - length1 / 2 + length1 - length3, y: pointer.y + length4 / 2 - length4 + length4 }, + { x: pointer.x - length1 / 2 + length2 + (length1 - length2 - length3) / 2, y: pointer.y + length4 / 2 - length4 + length5 }, + ] + break + } + + case 24: { + points = [ + { x: pointer.x - length1 / 2, y: pointer.y + length2 - length2 / 2 }, + { x: pointer.x - length1 / 2, y: pointer.y + length2 - length2 / 2 - length3 }, + { x: pointer.x, y: pointer.y + length2 - length2 / 2 - length3 - (length2 - length3) }, + { x: pointer.x + length1 / 2, y: pointer.y + length2 - length2 / 2 - length3 }, + { x: pointer.x + length1 / 2, y: pointer.y + length2 - length2 / 2 - length3 + length3 }, + ] + break + } + + case 25: { + points = [ + { + x: pointer.x - length1 / 2, + y: pointer.y + length3 / 2, + }, + { + x: pointer.x - length1 / 2 + (length1 - length2) / 2, + y: pointer.y + length3 / 2 - (length3 - length4), + }, + { + x: pointer.x - length1 / 2 + (length1 - length2) / 2, + y: pointer.y + length3 / 2 - (length3 - length4) - length4, + }, + { + x: pointer.x - length1 / 2 + (length1 - length2) / 2 + length2, + y: pointer.y + length3 / 2 - (length3 - length4) - length4, + }, + { + x: pointer.x - length1 / 2 + (length1 - length2) / 2 + length2, + y: pointer.y + length3 / 2 - (length3 - length4) - length4 + length4, + }, + { + x: pointer.x - length1 / 2 + length1, + y: pointer.y + length3 / 2, + }, + ] + break + } + case 26: { + const angle = (Math.asin(length3 / length4) * 180) / Math.PI // 높이와 빗변으로 먼저 각도구하기 + + const topL = (length1 - length2) / 2 / Math.cos((angle * Math.PI) / 180) // 꺽이는부분 윗쪽 길이 + + points = [ + { + x: pointer.x - length1 / 2 + length1, + y: pointer.y + length3 / 2, + }, + { + x: pointer.x - length1 / 2, + y: pointer.y + length3 / 2, + }, + { + x: pointer.x - length1 / 2 + length4 * Math.cos(degreesToRadians(angle)), + y: pointer.y + length3 / 2 - length4 * Math.sin(degreesToRadians(angle)), + }, + { + x: pointer.x - length1 / 2 + length4 * Math.cos(degreesToRadians(angle)) + length2, + y: pointer.y + length3 / 2 - length4 * Math.sin(degreesToRadians(angle)), + }, + { + x: pointer.x - length1 / 2 + length4 * Math.cos(degreesToRadians(angle)) + length2 + topL * Math.cos(degreesToRadians(angle)), + y: pointer.y + length3 / 2 - length4 * Math.sin(degreesToRadians(angle)) + topL * Math.sin(degreesToRadians(angle)), + }, + ] + break + } + case 27: { + const angle = (Math.asin(length3 / length4) * 180) / Math.PI // 높이와 빗변으로 먼저 각도구하기 + + const topL = (length1 - length2) / 2 / Math.cos((angle * Math.PI) / 180) // 꺽이는부분 윗쪽 길이 + points = [ + { + x: pointer.x - length1 / 2, + y: pointer.y + length3 / 2, + }, + { + x: pointer.x - length1 / 2 + length1, + y: pointer.y + length3 / 2, + }, + { + x: pointer.x - length1 / 2 + length1 - length4 * Math.cos(degreesToRadians(angle)), + y: pointer.y + length3 / 2 - length4 * Math.sin(degreesToRadians(angle)), + }, + { + x: pointer.x - length1 / 2 + length1 - length4 * Math.cos(degreesToRadians(angle)) - length2, + y: pointer.y + length3 / 2 - length4 * Math.sin(degreesToRadians(angle)), + }, + { + x: pointer.x - length1 / 2 + length1 - length4 * Math.cos(degreesToRadians(angle)) - length2 - topL * Math.cos(degreesToRadians(angle)), + y: pointer.y + length3 / 2 - length4 * Math.sin(degreesToRadians(angle)) + topL * Math.sin(degreesToRadians(angle)), + }, + ] + break + } + case 28: { + const a = Math.sqrt(length3 * length3 - length2 * length2) // 입력된 밑변과 높이 + + const sinA = a / length3 + const angleInRadians = Math.asin(sinA) + const angleInDegrees = angleInRadians * (180 / Math.PI) + const b = a - length1 / 2 + + const c = b / Math.tan(angleInRadians) + const d = Math.sqrt(b * b + c * c) + const newAngleInRadians = (90 - angleInDegrees) * (Math.PI / 180) + points = [ + { x: pointer.x - (length1 + b) / 2, y: pointer.y + length2 / 2 }, + { x: pointer.x + length1 / 2 - b / 2, y: pointer.y + length2 / 2 }, + { + x: pointer.x + length1 / 2 - b / 2 + d * Math.cos(newAngleInRadians), + y: pointer.y + length2 / 2 - d * Math.sin(newAngleInRadians), + }, + { + x: pointer.x - (length1 + b) / 2 + length3 * Math.cos(newAngleInRadians), + y: pointer.y + length2 / 2 - length3 * Math.sin(newAngleInRadians), + }, + ] + break + } + case 29: { + const a = Math.sqrt(length3 * length3 - length2 * length2) // 입력된 밑변과 높이 + + const sinA = a / length3 + const angleInRadians = Math.asin(sinA) + const angleInDegrees = angleInRadians * (180 / Math.PI) + const b = a - length1 / 2 + + const c = b / Math.tan(angleInRadians) + const d = Math.sqrt(b * b + c * c) + const newAngleInRadians = (90 - angleInDegrees) * (Math.PI / 180) + points = [ + { + x: pointer.x + length1 / 2 - b / 2 - length3 * Math.cos(newAngleInRadians), + y: pointer.y + length2 / 2 - length3 * Math.sin(newAngleInRadians), + }, + { x: pointer.x + length1 / 2 - b / 2, y: pointer.y + length2 / 2 }, + { x: pointer.x - (length1 + b) / 2, y: pointer.y + length2 / 2 }, + { x: pointer.x - (length1 + b) / 2 - d * Math.cos(newAngleInRadians), y: pointer.y + length2 / 2 - d * Math.sin(newAngleInRadians) }, + ] break } } + obj = new QPolygon(points, { + fill: 'transparent', + stroke: 'black', + strokeWidth: 2, + selectable: false, + fontSize: fontSize, + name: 'guideTriangle', + }) canvas?.add(obj) setCurrentPattern(obj) canvas?.renderAll() @@ -332,40 +544,25 @@ export const SurfaceShapeModal = ({ canvas }) => { canvas?.renderAll() } + const ButtonComp = () => { + // Generate 29 buttons + const buttons = [] + for (let i = 1; i <= 29; i++) { + buttons.push( + , + ) + } + + return
{buttons}
+ } + return ( <>
면형상배치{type}
- - - - - - - - - - +
{type === 1 ? (
@@ -377,16 +574,16 @@ export const SurfaceShapeModal = ({ canvas }) => { )} - 길이3 + 대각선
- ) : type === 2 ? ( + ) : [2, 4, 5].includes(type) ? (
길이1 길이2
- ) : type === 3 ? ( + ) : [3, 6, 7, 8, 9, 24, 28, 29].includes(type) ? ( <> 길이1 @@ -395,21 +592,7 @@ export const SurfaceShapeModal = ({ canvas }) => { 길이3 - ) : type === 4 ? ( - <> - 길이1 - - 길이2 - - - ) : type === 5 ? ( - <> - 길이1 - - 길이2 - - - ) : type === 6 ? ( + ) : [11, 12, 19, 20, 21, 22, 25, 26, 27].includes(type) ? ( <> 길이1 @@ -417,35 +600,10 @@ export const SurfaceShapeModal = ({ canvas }) => { 길이3 + 길이4 + - ) : type === 7 ? ( - <> - 길이1 - - 길이2 - - 길이3 - - - ) : type === 8 ? ( - <> - 길이1 - - 길이2 - - 길이3 - - - ) : type === 9 ? ( - <> - 길이1 - - 길이2 - - 길이3 - - - ) : type === 10 ? ( + ) : [10, 13, 14, 15, 16, 17, 18, 23].includes(type) ? ( <> 길이1 From 7702fddb191d69c5a89891d88dbcc29dafdc5347 Mon Sep 17 00:00:00 2001 From: yjnoh Date: Tue, 3 Sep 2024 16:10:29 +0900 Subject: [PATCH 04/34] =?UTF-8?q?template=2021,22=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/Roof2.jsx | 246 +++++++++++++++++++++++++++++++++++++-- src/util/canvas-util.js | 20 ++++ 2 files changed, 256 insertions(+), 10 deletions(-) diff --git a/src/components/Roof2.jsx b/src/components/Roof2.jsx index 00661aca..ff0d330f 100644 --- a/src/components/Roof2.jsx +++ b/src/components/Roof2.jsx @@ -21,7 +21,7 @@ import { } from '@/store/canvasAtom' import { QLine } from '@/components/fabric/QLine' import { getCanvasState, insertCanvasState } from '@/lib/canvas' -import { calculateIntersection, distanceBetweenPoints } from '@/util/canvas-util' +import { calculateIntersection, distanceBetweenPoints, getIntersectionPoint } from '@/util/canvas-util' import { QPolygon } from '@/components/fabric/QPolygon' import ThumbnailList from './ui/ThumbnailLIst' import QContextMenu from './common/context-menu/QContextMenu' @@ -30,7 +30,7 @@ import { useAxios } from '@/hooks/useAxios' import QPolygonContextMenu from '@/components/common/context-menu/QPolygonContextMenu' import QLineContextMenu from '@/components/common/context-menu/QLineContextMenu' import QEmptyContextMenu from '@/components/common/context-menu/QEmptyContextMenu' -import { degreesToRadians, radiansToDegrees } from '@turf/turf' +import { degreesToRadians, point, radiansToDegrees } from '@turf/turf' import InitSettingsModal from './InitSettingsModal' import GridSettingsModal from './GridSettingsModal' @@ -1100,6 +1100,234 @@ export default function Roof2(props) { isDrawing = false }) } + + const createTemplate21 = () => { + const length1 = 500 //Number(prompt('1번')) + const length2 = 240 //Number(prompt('2번')) + const length3 = 300 //Number(prompt('3번')) + const length4 = 200 //Number(prompt('4번')) + + if (length1 < length2) { + alert('1번보다 작게 입력해주세요.') + return + } + + if (length3 < length4) { + alert('3번보다 작게 입력해주세요.') + return + } + + const pointsArray = [ + { x: 0, y: 0 }, + { x: 0, y: 0 }, + { x: 0, y: 0 }, + { x: 0, y: 0 }, + { x: 0, y: 0 }, + ] + + const tmpPolygon = new QPolygon( + [ + { x: 0, y: length3 }, + { x: length1 - length2, y: length3 }, + { x: (length1 - length2) / 2, y: length3 - length3 }, + ], + { + fill: 'transparent', + stroke: 'black', //black + strokeWidth: 2, + selectable: true, + fontSize: 0, + }, + ) + + const coord = getIntersectionPoint(tmpPolygon.lines[1].startPoint, tmpPolygon.lines[2].startPoint, length3 - length4) + const scale = (length1 - length2) / coord.x + + tmpPolygon.set({ scaleX: scale }) + + pointsArray[0].x = 0 + pointsArray[0].y = length3 //바닥면부터 시작하게 + pointsArray[1].x = pointsArray[0].x + length1 + pointsArray[1].y = pointsArray[0].y + pointsArray[2].x = pointsArray[1].x + pointsArray[2].y = pointsArray[1].y - length4 + pointsArray[3].x = pointsArray[2].x - length2 + pointsArray[3].y = pointsArray[2].y + pointsArray[4].x = tmpPolygon.getCurrentPoints()[2].x + pointsArray[4].y = tmpPolygon.getCurrentPoints()[2].y + + const tmp1Polygon = new QPolygon(pointsArray, { + fill: 'transparent', + stroke: 'black', //black + strokeWidth: 2, + selectable: true, + fontSize: 0, + }) + + // canvas?.add(tmp1Polygon) + + let isDrawing = true + canvas?.on('mouse:move', (e) => { + if (!isDrawing) { + return + } + canvas?.remove(...canvas?.getObjects().filter((obj) => obj.name === 'guideTriangle')) + const pointer = canvas?.getPointer(e.e) + const triangle = new QPolygon( + [ + { + x: pointer.x - length1 / 2, + y: pointer.y + length4 / 2, + }, + { + x: pointer.x + length1 / 2, + y: pointer.y + length4 / 2, + }, + { + x: pointer.x + length1 / 2, + y: pointer.y - length4 / 2, + }, + { + x: pointer.x - (length2 - length1 / 2), + y: pointer.y - length4 / 2, + }, + { + x: pointer.x - length1 / 2 + pointsArray[4].x, + y: pointer.y - length3 + length4 / 2, + }, + ], + { + fill: 'transparent', + stroke: 'black', + strokeWidth: 2, + selectable: true, + fontSize: fontSize, + name: 'guideTriangle', + }, + ) + canvas?.add(triangle) + }) + + canvas?.on('mouse:down', (e) => { + isDrawing = false + }) + } + + const createTemplate22 = () => { + const length1 = 500 //Number(prompt('1번')) + const length2 = 240 //Number(prompt('2번')) + const length3 = 300 //Number(prompt('3번')) + const length4 = 200 //Number(prompt('4번')) + + if (length1 < length2) { + alert('1번보다 작게 입력해주세요.') + return + } + + if (length3 < length4) { + alert('3번보다 작게 입력해주세요.') + return + } + + const pointsArray = [ + { x: 0, y: 0 }, + { x: 0, y: 0 }, + { x: 0, y: 0 }, + { x: 0, y: 0 }, + { x: 0, y: 0 }, + ] + + const tmpPolygon = new QPolygon( + [ + { x: 0, y: length3 }, + { x: length1 - length2, y: length3 }, + { x: (length1 - length2) / 2, y: length3 - length3 }, + ], + { + fill: 'transparent', + stroke: 'black', //black + strokeWidth: 2, + selectable: true, + fontSize: 0, + }, + ) + + const coord = getIntersectionPoint(tmpPolygon.lines[1].startPoint, tmpPolygon.lines[2].startPoint, length3 - length4) + const scale = (length1 - length2) / coord.x + + tmpPolygon.set({ scaleX: scale }) + + pointsArray[0].x = 0 + pointsArray[0].y = length3 //바닥면부터 시작하게 + pointsArray[1].x = pointsArray[0].x + length1 + pointsArray[1].y = pointsArray[0].y + pointsArray[2].x = pointsArray[1].x + pointsArray[2].y = pointsArray[1].y - length4 + pointsArray[3].x = pointsArray[2].x - length2 + pointsArray[3].y = pointsArray[2].y + pointsArray[4].x = tmpPolygon.getCurrentPoints()[2].x + pointsArray[4].y = tmpPolygon.getCurrentPoints()[2].y + + const tmp1Polygon = new QPolygon(pointsArray, { + fill: 'transparent', + stroke: 'black', //black + strokeWidth: 2, + selectable: true, + fontSize: 0, + }) + + tmp1Polygon.set('flipX', true) //반전시킴 + tmp1Polygon.setCoords() + + let isDrawing = true + canvas?.on('mouse:move', (e) => { + if (!isDrawing) { + return + } + canvas?.remove(...canvas?.getObjects().filter((obj) => obj.name === 'guideTriangle')) + const pointer = canvas?.getPointer(e.e) + const triangle = new QPolygon( + [ + { + x: pointer.x - length1 / 2, + y: pointer.y + length4 / 2, + }, + { + x: pointer.x + length1 / 2, + y: pointer.y + length4 / 2, + }, + { + x: pointer.x + length1 / 2, + y: pointer.y - length4 / 2, + }, + { + x: pointer.x - (length2 - length1 / 2), + y: pointer.y - length4 / 2, + }, + { + x: pointer.x - length1 / 2 + pointsArray[4].x, + y: pointer.y - length3 + length4 / 2, + }, + ], + { + fill: 'transparent', + stroke: 'black', + strokeWidth: 2, + selectable: true, + fontSize: fontSize, + name: 'guideTriangle', + flipX: true, + }, + ) + triangle.setCoords() + canvas?.add(triangle) + }) + + canvas?.on('mouse:down', (e) => { + isDrawing = false + }) + } + /** * 19~22번은 못함 */ @@ -1501,14 +1729,6 @@ export default function Roof2(props) { {canvas && ( <>
- + + diff --git a/src/util/canvas-util.js b/src/util/canvas-util.js index 268370c1..4efd9138 100644 --- a/src/util/canvas-util.js +++ b/src/util/canvas-util.js @@ -705,3 +705,23 @@ export const getClosestVerticalLine = (pointer, verticalLineArray) => { return closestLine } + +/** + * 빗변과 높이를 가지고 빗변의 x값을 구함 + * @param {} p1 + * @param {*} p2 + * @param {*} y + * @returns + */ +export const getIntersectionPoint = (p1, p2, y) => { + const { x: x1, y: y1 } = p1 + const { x: x2, y: y2 } = p2 + + // 기울기와 y 절편을 이용해 선의 방정식을 구합니다. + const slope = (y2 - y1) / (x2 - x1) + const intercept = y1 - slope * x1 + + // y = 150일 때의 x 좌표를 구합니다. + const x = (y - intercept) / slope + return { x, y } +} From 905ddd07b378c163d5af25c0af05f67ef29c4596 Mon Sep 17 00:00:00 2001 From: "hyojun.choi" Date: Tue, 3 Sep 2024 16:26:44 +0900 Subject: [PATCH 05/34] =?UTF-8?q?=EB=B2=84=ED=8A=BC=20=EC=A0=9C=EA=B1=B0?= =?UTF-8?q?=20=EB=B0=8F=2021,22=EB=B2=88=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/Roof2.jsx | 1204 ---------------------------- src/components/ui/SurfaceShape.jsx | 199 ++++- 2 files changed, 191 insertions(+), 1212 deletions(-) diff --git a/src/components/Roof2.jsx b/src/components/Roof2.jsx index ff0d330f..03749bd2 100644 --- a/src/components/Roof2.jsx +++ b/src/components/Roof2.jsx @@ -577,1150 +577,6 @@ export default function Roof2(props) { canvas?.renderAll() } - const createPentagon2 = () => { - const a = 400 //Number(prompt('a')) - const b = 200 //Number(prompt('b')) - const c = 250 //Number(prompt('c')) - const d = 150 //Number(prompt('d')) - - const t = (c * (a - b)) / (200 + c) - - const t2 = Math.sqrt(c * c + t * t) - - const t3 = Math.sqrt((c - d) * (c - d) + (a - b - t) * (a - b - t)) - - const angle = Math.atan(t2 / t) - const angle2 = Math.atan(t3 / (a - b - t)) - - let isDrawing = true - let pentagon - canvas?.on('mouse:move', (e) => { - if (!isDrawing) { - return - } - canvas?.remove(...canvas?.getObjects().filter((obj) => obj.name === 'guideTriangle')) - const pointer = canvas?.getPointer(e.e) - - pentagon = new QPolygon( - [ - { x: pointer.x - a / 2, y: pointer.y + a / 2 - d }, - { x: pointer.x + a / 2, y: pointer.y + a / 2 - d }, - { x: pointer.x + a / 2, y: pointer.y + a / 2 - d - d }, - { x: pointer.x + a / 2 - b, y: pointer.y + a / 2 - d - d }, - { - x: pointer.x + a / 2 - b - t3 * Math.cos(angle), - y: pointer.y + a / 2 - d - d - t3 * Math.sin(angle), - }, - /*{ - x: pointer.x - a / 2 + t2 * Math.cos(angle), - y: pointer.y + a / 2 - d - t2 * Math.sin(angle), - },*/ - ], - { - fill: 'transparent', - stroke: 'gray', - strokeWidth: 1, - selectable: true, - fontSize: fontSize, - name: 'guideTriangle', - }, - ) - - canvas?.add(pentagon) - }) - - canvas?.on('mouse:down', (e) => { - isDrawing = false - pentagon.set('name', 'roof') - pentagon.set('stroke', 2) - canvas?.renderAll() - }) - } - - const createTemplate10 = () => { - const length1 = Number(prompt('1번')) - const length2 = Number(prompt('2번')) - const length3 = Number(prompt('3번')) - const length4 = Number(prompt('4번')) - const length5 = Number(prompt('5번')) - - let isDrawing = true - canvas?.on('mouse:move', (e) => { - if (!isDrawing) { - return - } - canvas?.remove(...canvas?.getObjects().filter((obj) => obj.name === 'guideTriangle')) - const pointer = canvas?.getPointer(e.e) - const triangle = new QPolygon( - [ - { x: pointer.x - (length1 + length2 + length3) / 2, y: pointer.y - (length4 + length5) / 2 }, - { x: pointer.x - (length1 + length2 + length3) / 2, y: pointer.y + (length4 + length5) / 2 }, - { x: pointer.x - (length1 + length2 + length3) / 2 + length1, y: pointer.y + (length4 + length5) / 2 }, - { x: pointer.x - (length1 + length2 + length3) / 2 + length1, y: pointer.y + (length4 + length5) / 2 - length5 }, - { x: pointer.x - (length1 + length2 + length3) / 2 + length1 + length2, y: pointer.y + (length4 + length5) / 2 - length5 }, - { x: pointer.x - (length1 + length2 + length3) / 2 + length1 + length2, y: pointer.y + (length4 + length5) / 2 - length5 + length5 }, - { - x: pointer.x - (length1 + length2 + length3) / 2 + length1 + length2 + length3, - y: pointer.y + (length4 + length5) / 2 - length5 + length5, - }, - { - x: pointer.x - (length1 + length2 + length3) / 2 + length1 + length2 + length3, - y: pointer.y + (length4 + length5) / 2 - length5 + length5 - (length4 + length5), - }, - ], - { - fill: 'transparent', - stroke: 'black', - strokeWidth: 2, - selectable: true, - fontSize: fontSize, - name: 'guideTriangle', - }, - ) - - canvas?.add(triangle) - }) - - canvas?.on('mouse:down', (e) => { - isDrawing = false - }) - } - const createTemplate11 = () => { - const length1 = 200 //Number(prompt('1번')) - const length2 = 100 //Number(prompt('2번')) - const length3 = 400 //Number(prompt('3번')) - const length4 = 300 //Number(prompt('4번')) - - let isDrawing = true - canvas?.on('mouse:move', (e) => { - if (!isDrawing) { - return - } - canvas?.remove(...canvas?.getObjects().filter((obj) => obj.name === 'guideTriangle')) - const pointer = canvas?.getPointer(e.e) - const triangle = new QPolygon( - [ - { x: pointer.x - length1 / 2, y: pointer.y + length4 / 2 }, - { x: pointer.x - length1 / 2 + length1, y: pointer.y + length4 / 2 }, - { x: pointer.x - length1 / 2 + length1, y: pointer.y + length4 / 2 - length3 }, - { x: pointer.x - length1 / 2 + length1 - (length1 - length2), y: pointer.y + length4 / 2 - length3 }, - { x: pointer.x - length1 / 2 + length1 - (length1 - length2), y: pointer.y + length4 / 2 - length3 + (length3 - length4) }, - { x: pointer.x - length1 / 2 + length1 - (length1 - length2) - length2, y: pointer.y + length4 / 2 - length3 + (length3 - length4) }, - ], - { - fill: 'transparent', - stroke: 'black', - strokeWidth: 2, - selectable: true, - fontSize: fontSize, - name: 'guideTriangle', - }, - ) - - canvas?.add(triangle) - }) - - canvas?.on('mouse:down', (e) => { - isDrawing = false - }) - } - const createTemplate12 = () => { - const length1 = 200 //Number(prompt('1번')) - const length2 = 100 //Number(prompt('2번')) - const length3 = 400 //Number(prompt('3번')) - const length4 = 300 //Number(prompt('4번')) - - let isDrawing = true - canvas?.on('mouse:move', (e) => { - if (!isDrawing) { - return - } - canvas?.remove(...canvas?.getObjects().filter((obj) => obj.name === 'guideTriangle')) - const pointer = canvas?.getPointer(e.e) - const triangle = new QPolygon( - [ - { x: pointer.x - length1 / 2, y: pointer.y + length4 / 2 }, - { x: pointer.x - length1 / 2 + length1, y: pointer.y + length4 / 2 }, - { x: pointer.x - length1 / 2 + length1, y: pointer.y + length4 / 2 - length4 }, - { x: pointer.x - length1 / 2 + length1 - length2, y: pointer.y + length4 / 2 - length4 }, - { x: pointer.x - length1 / 2 + length1 - length2, y: pointer.y + length4 / 2 - length4 - (length3 - length4) }, - { x: pointer.x - length1 / 2 + length1 - length2 - (length1 - length2), y: pointer.y + length4 / 2 - length4 - (length3 - length4) }, - ], - { - fill: 'transparent', - stroke: 'black', - strokeWidth: 2, - selectable: true, - fontSize: fontSize, - name: 'guideTriangle', - }, - ) - - canvas?.add(triangle) - }) - - canvas?.on('mouse:down', (e) => { - isDrawing = false - }) - } - const createTemplate13 = () => { - const length1 = 300 //Number(prompt('1번')) - const length2 = 150 //Number(prompt('2번')) - const length3 = 100 //Number(prompt('3번')) - const length4 = 400 //Number(prompt('4번')) - const length5 = 200 //Number(prompt('5번')) - - let isDrawing = true - canvas?.on('mouse:move', (e) => { - if (!isDrawing) { - return - } - canvas?.remove(...canvas?.getObjects().filter((obj) => obj.name === 'guideTriangle')) - const pointer = canvas?.getPointer(e.e) - const triangle = new QPolygon( - [ - { x: pointer.x - length1 / 2, y: pointer.y + length4 / 2 }, - { x: pointer.x - length1 / 2 + length1, y: pointer.y + length4 / 2 }, - { x: pointer.x - length1 / 2 + length1, y: pointer.y + length4 / 2 - length4 }, - { x: pointer.x - length1 / 2 + length1 - length3, y: pointer.y + length4 / 2 - length4 }, - { x: pointer.x - length1 / 2 + length1 - length3, y: pointer.y + length4 / 2 - length4 + (length4 - length5) }, - { x: pointer.x - length1 / 2 + length1 - length3 - length2, y: pointer.y + length4 / 2 - length4 + (length4 - length5) }, - ], - { - fill: 'transparent', - stroke: 'black', - strokeWidth: 2, - selectable: true, - fontSize: fontSize, - name: 'guideTriangle', - }, - ) - - canvas?.add(triangle) - }) - - canvas?.on('mouse:down', (e) => { - isDrawing = false - }) - } - const createTemplate14 = () => { - const length1 = 300 //Number(prompt('1번')) - const length2 = 150 //Number(prompt('2번')) - const length3 = 100 //Number(prompt('3번')) - const length4 = 400 //Number(prompt('4번')) - const length5 = 200 //Number(prompt('5번')) - - let isDrawing = true - canvas?.on('mouse:move', (e) => { - if (!isDrawing) { - return - } - canvas?.remove(...canvas?.getObjects().filter((obj) => obj.name === 'guideTriangle')) - const pointer = canvas?.getPointer(e.e) - const triangle = new QPolygon( - [ - { x: pointer.x + length1 / 2, y: pointer.y + length4 / 2 }, - { x: pointer.x + length1 / 2 - length1, y: pointer.y + length4 / 2 }, - { x: pointer.x + length1 / 2 - length1, y: pointer.y + length4 / 2 - length4 }, - { x: pointer.x + length1 / 2 - length1 + length3, y: pointer.y + length4 / 2 - length4 }, - { x: pointer.x + length1 / 2 - length1 + length3, y: pointer.y + length4 / 2 - length4 + (length4 - length5) }, - { x: pointer.x + length1 / 2 - length1 + length3 + length2, y: pointer.y + length4 / 2 - length4 + (length4 - length5) }, - ], - { - fill: 'transparent', - stroke: 'black', - strokeWidth: 2, - selectable: true, - fontSize: fontSize, - name: 'guideTriangle', - }, - ) - - canvas?.add(triangle) - }) - - canvas?.on('mouse:down', (e) => { - isDrawing = false - }) - } - const createTemplate15 = () => { - const length1 = 300 //Number(prompt('1번')) - const length2 = 150 //Number(prompt('2번')) - const length3 = 100 //Number(prompt('3번')) - const length4 = 400 //Number(prompt('4번')) - const length5 = 200 //Number(prompt('5번')) - - let isDrawing = true - canvas?.on('mouse:move', (e) => { - if (!isDrawing) { - return - } - canvas?.remove(...canvas?.getObjects().filter((obj) => obj.name === 'guideTriangle')) - const pointer = canvas?.getPointer(e.e) - const triangle = new QPolygon( - [ - { x: pointer.x + length1 / 2, y: pointer.y + length4 / 2 }, - { x: pointer.x + length1 / 2 - length1, y: pointer.y + length4 / 2 }, - { x: pointer.x + length1 / 2 - length1, y: pointer.y + length4 / 2 - length5 }, - { x: pointer.x + length1 / 2 - length1 + length2, y: pointer.y + length4 / 2 - length5 }, - { x: pointer.x + length1 / 2 - length1 + length2, y: pointer.y + length4 / 2 - length5 - (length4 - length5) }, - { x: pointer.x + length1 / 2 - length1 + length2 + length3, y: pointer.y + length4 / 2 - length5 - (length4 - length5) }, - ], - { - fill: 'transparent', - stroke: 'black', - strokeWidth: 2, - selectable: true, - fontSize: fontSize, - name: 'guideTriangle', - }, - ) - - canvas?.add(triangle) - }) - - canvas?.on('mouse:down', (e) => { - isDrawing = false - }) - } - const createTemplate16 = () => { - const length1 = 300 //Number(prompt('1번')) - const length2 = 150 //Number(prompt('2번')) - const length3 = 100 //Number(prompt('3번')) - const length4 = 400 //Number(prompt('4번')) - const length5 = 200 //Number(prompt('5번')) - - let isDrawing = true - canvas?.on('mouse:move', (e) => { - if (!isDrawing) { - return - } - canvas?.remove(...canvas?.getObjects().filter((obj) => obj.name === 'guideTriangle')) - const pointer = canvas?.getPointer(e.e) - const triangle = new QPolygon( - [ - { x: pointer.x - length1 / 2, y: pointer.y + length4 / 2 }, - { x: pointer.x - length1 / 2 + length1, y: pointer.y + length4 / 2 }, - { x: pointer.x - length1 / 2 + length1, y: pointer.y + length4 / 2 - length5 }, - { x: pointer.x - length1 / 2 + length1 - length2, y: pointer.y + length4 / 2 - length5 }, - { x: pointer.x - length1 / 2 + length1 - length2, y: pointer.y + length4 / 2 - length5 - (length4 - length5) }, - { x: pointer.x - length1 / 2 + length1 - length2 - length3, y: pointer.y + length4 / 2 - length5 - (length4 - length5) }, - ], - { - fill: 'transparent', - stroke: 'black', - strokeWidth: 2, - selectable: true, - fontSize: fontSize, - name: 'guideTriangle', - }, - ) - - canvas?.add(triangle) - }) - - canvas?.on('mouse:down', (e) => { - isDrawing = false - }) - } - const createTemplate17 = () => { - const length1 = 300 //Number(prompt('1번')) - const length2 = 150 //Number(prompt('2번')) - const length3 = 250 //Number(prompt('3번')) - const length4 = 400 //Number(prompt('4번')) - const length5 = 200 //Number(prompt('5번')) - - let isDrawing = true - canvas?.on('mouse:move', (e) => { - if (!isDrawing) { - return - } - canvas?.remove(...canvas?.getObjects().filter((obj) => obj.name === 'guideTriangle')) - const pointer = canvas?.getPointer(e.e) - const triangle = new QPolygon( - [ - { x: pointer.x - length1 / 2, y: pointer.y + length4 / 2 }, - { x: pointer.x - length1 / 2 + length1, y: pointer.y + length4 / 2 }, - { x: pointer.x - length1 / 2 + length1, y: pointer.y + length4 / 2 - length5 }, - { x: pointer.x - length1 / 2 + length1 - length2, y: pointer.y + length4 / 2 - length5 }, - { x: pointer.x - length1 / 2 + length1 - length2, y: pointer.y + length4 / 2 - length5 - (length4 - length5) }, - { x: pointer.x - length1 / 2 + length1 - length2 - length3, y: pointer.y + length4 / 2 - length5 - (length4 - length5) }, - ], - { - fill: 'transparent', - stroke: 'black', - strokeWidth: 2, - selectable: true, - fontSize: fontSize, - name: 'guideTriangle', - }, - ) - - canvas?.add(triangle) - }) - - canvas?.on('mouse:down', (e) => { - isDrawing = false - }) - } - const createTemplate18 = () => { - const length1 = 300 //Number(prompt('1번')) - const length2 = 150 //Number(prompt('2번')) - const length3 = 250 //Number(prompt('3번')) - const length4 = 400 //Number(prompt('4번')) - const length5 = 200 //Number(prompt('5번')) - - let isDrawing = true - canvas?.on('mouse:move', (e) => { - if (!isDrawing) { - return - } - canvas?.remove(...canvas?.getObjects().filter((obj) => obj.name === 'guideTriangle')) - const pointer = canvas?.getPointer(e.e) - const triangle = new QPolygon( - [ - { x: pointer.x + length1 / 2, y: pointer.y + length4 / 2 }, - { x: pointer.x + length1 / 2 - length1, y: pointer.y + length4 / 2 }, - { x: pointer.x + length1 / 2 - length1, y: pointer.y + length4 / 2 - length5 }, - { x: pointer.x + length1 / 2 - length1 + length2, y: pointer.y + length4 / 2 - length5 }, - { x: pointer.x + length1 / 2 - length1 + length2, y: pointer.y + length4 / 2 - length5 - (length4 - length5) }, - { x: pointer.x + length1 / 2 - length1 + length2 + length3, y: pointer.y + length4 / 2 - length5 - (length4 - length5) }, - ], - { - fill: 'transparent', - stroke: 'black', - strokeWidth: 2, - selectable: true, - fontSize: fontSize, - name: 'guideTriangle', - }, - ) - - canvas?.add(triangle) - }) - - canvas?.on('mouse:down', (e) => { - isDrawing = false - }) - } - const createTemplate19 = () => { - const length1 = 500 //Number(prompt('1번')) - const length2 = 300 //Number(prompt('2번')) - const length3 = 400 //Number(prompt('3번')) - const length4 = 300 //Number(prompt('4번')) - - // 좌측 빗변 - const leftHypotenuse = Math.sqrt(((length1 - length2) / 2) ** 2 + length3 ** 2) - const rightHypotenuse = (length4 / length3) * leftHypotenuse - - const leftAngle = Math.acos((length1 - length2) / 2 / leftHypotenuse) - - let isDrawing = true - canvas?.on('mouse:move', (e) => { - if (!isDrawing) { - return - } - canvas?.remove(...canvas?.getObjects().filter((obj) => obj.name === 'guideTriangle')) - const pointer = canvas?.getPointer(e.e) - const triangle = new QPolygon( - [ - { x: pointer.x - length1 / 2 + leftHypotenuse * Math.cos(leftAngle), y: pointer.y + length3 / 2 - leftHypotenuse * Math.sin(leftAngle) }, - { x: pointer.x - length1 / 2, y: pointer.y + length3 / 2 }, - { x: pointer.x + length1 / 2, y: pointer.y + length3 / 2 }, - { x: pointer.x + length1 / 2 - rightHypotenuse * Math.cos(leftAngle), y: pointer.y + length3 / 2 - rightHypotenuse * Math.sin(leftAngle) }, - { - x: pointer.x + length1 / 2 - rightHypotenuse * Math.cos(leftAngle) - length2, - y: pointer.y + length3 / 2 - rightHypotenuse * Math.sin(leftAngle), - }, - ], - { - fill: 'transparent', - stroke: 'black', - strokeWidth: 2, - selectable: true, - fontSize: fontSize, - name: 'guideTriangle', - }, - ) - - canvas?.add(triangle) - }) - - canvas?.on('mouse:down', (e) => { - isDrawing = false - }) - } - const createTemplate20 = () => { - const length1 = 500 //Number(prompt('1번')) - const length2 = 300 //Number(prompt('2번')) - const length3 = 400 //Number(prompt('3번')) - const length4 = 300 //Number(prompt('4번')) - - // 좌측 빗변 - const rightHypotenuse = Math.sqrt(((length1 - length2) / 2) ** 2 + length3 ** 2) - const leftHypotenuse = (length4 / length3) * rightHypotenuse - - const rightAngle = Math.acos((length1 - length2) / 2 / rightHypotenuse) - - let isDrawing = true - canvas?.on('mouse:move', (e) => { - if (!isDrawing) { - return - } - canvas?.remove(...canvas?.getObjects().filter((obj) => obj.name === 'guideTriangle')) - const pointer = canvas?.getPointer(e.e) - const triangle = new QPolygon( - [ - { - x: pointer.x + length1 / 2 - rightHypotenuse * Math.cos(rightAngle), - y: pointer.y + length3 / 2 - rightHypotenuse * Math.sin(rightAngle), - }, - { x: pointer.x + length1 / 2, y: pointer.y + length3 / 2 }, - { x: pointer.x - length1 / 2, y: pointer.y + length3 / 2 }, - { x: pointer.x - length1 / 2 + leftHypotenuse * Math.cos(rightAngle), y: pointer.y + length3 / 2 - leftHypotenuse * Math.sin(rightAngle) }, - { - x: pointer.x - length1 / 2 + leftHypotenuse * Math.cos(rightAngle) + length2, - y: pointer.y + length3 / 2 - leftHypotenuse * Math.sin(rightAngle), - }, - ], - { - fill: 'transparent', - stroke: 'black', - strokeWidth: 2, - selectable: true, - fontSize: fontSize, - name: 'guideTriangle', - }, - ) - - canvas?.add(triangle) - }) - - canvas?.on('mouse:down', (e) => { - isDrawing = false - }) - } - - const createTemplate21 = () => { - const length1 = 500 //Number(prompt('1번')) - const length2 = 240 //Number(prompt('2번')) - const length3 = 300 //Number(prompt('3번')) - const length4 = 200 //Number(prompt('4번')) - - if (length1 < length2) { - alert('1번보다 작게 입력해주세요.') - return - } - - if (length3 < length4) { - alert('3번보다 작게 입력해주세요.') - return - } - - const pointsArray = [ - { x: 0, y: 0 }, - { x: 0, y: 0 }, - { x: 0, y: 0 }, - { x: 0, y: 0 }, - { x: 0, y: 0 }, - ] - - const tmpPolygon = new QPolygon( - [ - { x: 0, y: length3 }, - { x: length1 - length2, y: length3 }, - { x: (length1 - length2) / 2, y: length3 - length3 }, - ], - { - fill: 'transparent', - stroke: 'black', //black - strokeWidth: 2, - selectable: true, - fontSize: 0, - }, - ) - - const coord = getIntersectionPoint(tmpPolygon.lines[1].startPoint, tmpPolygon.lines[2].startPoint, length3 - length4) - const scale = (length1 - length2) / coord.x - - tmpPolygon.set({ scaleX: scale }) - - pointsArray[0].x = 0 - pointsArray[0].y = length3 //바닥면부터 시작하게 - pointsArray[1].x = pointsArray[0].x + length1 - pointsArray[1].y = pointsArray[0].y - pointsArray[2].x = pointsArray[1].x - pointsArray[2].y = pointsArray[1].y - length4 - pointsArray[3].x = pointsArray[2].x - length2 - pointsArray[3].y = pointsArray[2].y - pointsArray[4].x = tmpPolygon.getCurrentPoints()[2].x - pointsArray[4].y = tmpPolygon.getCurrentPoints()[2].y - - const tmp1Polygon = new QPolygon(pointsArray, { - fill: 'transparent', - stroke: 'black', //black - strokeWidth: 2, - selectable: true, - fontSize: 0, - }) - - // canvas?.add(tmp1Polygon) - - let isDrawing = true - canvas?.on('mouse:move', (e) => { - if (!isDrawing) { - return - } - canvas?.remove(...canvas?.getObjects().filter((obj) => obj.name === 'guideTriangle')) - const pointer = canvas?.getPointer(e.e) - const triangle = new QPolygon( - [ - { - x: pointer.x - length1 / 2, - y: pointer.y + length4 / 2, - }, - { - x: pointer.x + length1 / 2, - y: pointer.y + length4 / 2, - }, - { - x: pointer.x + length1 / 2, - y: pointer.y - length4 / 2, - }, - { - x: pointer.x - (length2 - length1 / 2), - y: pointer.y - length4 / 2, - }, - { - x: pointer.x - length1 / 2 + pointsArray[4].x, - y: pointer.y - length3 + length4 / 2, - }, - ], - { - fill: 'transparent', - stroke: 'black', - strokeWidth: 2, - selectable: true, - fontSize: fontSize, - name: 'guideTriangle', - }, - ) - canvas?.add(triangle) - }) - - canvas?.on('mouse:down', (e) => { - isDrawing = false - }) - } - - const createTemplate22 = () => { - const length1 = 500 //Number(prompt('1번')) - const length2 = 240 //Number(prompt('2번')) - const length3 = 300 //Number(prompt('3번')) - const length4 = 200 //Number(prompt('4번')) - - if (length1 < length2) { - alert('1번보다 작게 입력해주세요.') - return - } - - if (length3 < length4) { - alert('3번보다 작게 입력해주세요.') - return - } - - const pointsArray = [ - { x: 0, y: 0 }, - { x: 0, y: 0 }, - { x: 0, y: 0 }, - { x: 0, y: 0 }, - { x: 0, y: 0 }, - ] - - const tmpPolygon = new QPolygon( - [ - { x: 0, y: length3 }, - { x: length1 - length2, y: length3 }, - { x: (length1 - length2) / 2, y: length3 - length3 }, - ], - { - fill: 'transparent', - stroke: 'black', //black - strokeWidth: 2, - selectable: true, - fontSize: 0, - }, - ) - - const coord = getIntersectionPoint(tmpPolygon.lines[1].startPoint, tmpPolygon.lines[2].startPoint, length3 - length4) - const scale = (length1 - length2) / coord.x - - tmpPolygon.set({ scaleX: scale }) - - pointsArray[0].x = 0 - pointsArray[0].y = length3 //바닥면부터 시작하게 - pointsArray[1].x = pointsArray[0].x + length1 - pointsArray[1].y = pointsArray[0].y - pointsArray[2].x = pointsArray[1].x - pointsArray[2].y = pointsArray[1].y - length4 - pointsArray[3].x = pointsArray[2].x - length2 - pointsArray[3].y = pointsArray[2].y - pointsArray[4].x = tmpPolygon.getCurrentPoints()[2].x - pointsArray[4].y = tmpPolygon.getCurrentPoints()[2].y - - const tmp1Polygon = new QPolygon(pointsArray, { - fill: 'transparent', - stroke: 'black', //black - strokeWidth: 2, - selectable: true, - fontSize: 0, - }) - - tmp1Polygon.set('flipX', true) //반전시킴 - tmp1Polygon.setCoords() - - let isDrawing = true - canvas?.on('mouse:move', (e) => { - if (!isDrawing) { - return - } - canvas?.remove(...canvas?.getObjects().filter((obj) => obj.name === 'guideTriangle')) - const pointer = canvas?.getPointer(e.e) - const triangle = new QPolygon( - [ - { - x: pointer.x - length1 / 2, - y: pointer.y + length4 / 2, - }, - { - x: pointer.x + length1 / 2, - y: pointer.y + length4 / 2, - }, - { - x: pointer.x + length1 / 2, - y: pointer.y - length4 / 2, - }, - { - x: pointer.x - (length2 - length1 / 2), - y: pointer.y - length4 / 2, - }, - { - x: pointer.x - length1 / 2 + pointsArray[4].x, - y: pointer.y - length3 + length4 / 2, - }, - ], - { - fill: 'transparent', - stroke: 'black', - strokeWidth: 2, - selectable: true, - fontSize: fontSize, - name: 'guideTriangle', - flipX: true, - }, - ) - triangle.setCoords() - canvas?.add(triangle) - }) - - canvas?.on('mouse:down', (e) => { - isDrawing = false - }) - } - - /** - * 19~22번은 못함 - */ - const createTemplate23 = () => { - const length1 = 300 //Number(prompt('1번')) - const length2 = 100 //Number(prompt('2번')) - const length3 = 150 //Number(prompt('3번')) - const length4 = 400 //Number(prompt('4번')) - const length5 = 300 //Number(prompt('5번')) - - let isDrawing = true - canvas?.on('mouse:move', (e) => { - if (!isDrawing) { - return - } - canvas?.remove(...canvas?.getObjects().filter((obj) => obj.name === 'guideTriangle')) - const pointer = canvas?.getPointer(e.e) - const triangle = new QPolygon( - [ - { x: pointer.x - length1 / 2 + length2, y: pointer.y + length4 / 2 }, - { x: pointer.x - length1 / 2, y: pointer.y + length4 / 2 }, - { x: pointer.x - length1 / 2, y: pointer.y + length4 / 2 - length4 }, - { x: pointer.x - length1 / 2 + length1, y: pointer.y + length4 / 2 - length4 }, - { x: pointer.x - length1 / 2 + length1, y: pointer.y + length4 / 2 - length4 + length4 }, - { x: pointer.x - length1 / 2 + length1 - length3, y: pointer.y + length4 / 2 - length4 + length4 }, - { x: pointer.x - length1 / 2 + length2 + (length1 - length2 - length3) / 2, y: pointer.y + length4 / 2 - length4 + length5 }, - ], - { - fill: 'transparent', - stroke: 'black', - strokeWidth: 2, - selectable: true, - fontSize: fontSize, - name: 'guideTriangle', - }, - ) - - canvas?.add(triangle) - }) - - canvas?.on('mouse:down', (e) => { - isDrawing = false - }) - } - - const createTemplate24 = () => { - const length1 = 300 //Number(prompt('1번')) - const length2 = 400 //Number(prompt('2번')) - const length3 = 300 //Number(prompt('3번')) - - let isDrawing = true - canvas?.on('mouse:move', (e) => { - if (!isDrawing) { - return - } - canvas?.remove(...canvas?.getObjects().filter((obj) => obj.name === 'guideTriangle')) - const pointer = canvas?.getPointer(e.e) - const triangle = new QPolygon( - [ - { x: pointer.x - length1 / 2, y: pointer.y + length2 - length2 / 2 }, - { x: pointer.x - length1 / 2, y: pointer.y + length2 - length2 / 2 - length3 }, - { x: pointer.x, y: pointer.y + length2 - length2 / 2 - length3 - (length2 - length3) }, - { x: pointer.x + length1 / 2, y: pointer.y + length2 - length2 / 2 - length3 }, - { x: pointer.x + length1 / 2, y: pointer.y + length2 - length2 / 2 - length3 + length3 }, - ], - { - fill: 'transparent', - stroke: 'black', - strokeWidth: 2, - selectable: true, - fontSize: fontSize, - name: 'guideTriangle', - }, - ) - - canvas?.add(triangle) - }) - - canvas?.on('mouse:down', (e) => { - isDrawing = false - }) - } - const createTemplate25 = () => { - const length1 = 300 //Number(prompt('1번')) - const length2 = 200 //Number(prompt('2번')) - const length3 = 300 //Number(prompt('3번')) - const length4 = 200 //Number(prompt('3번')) - - let isDrawing = true - canvas?.on('mouse:move', (e) => { - if (!isDrawing) { - return - } - canvas?.remove(...canvas?.getObjects().filter((obj) => obj.name === 'guideTriangle')) - const pointer = canvas?.getPointer(e.e) - const triangle = new QPolygon( - [ - { - x: pointer.x - length1 / 2, - y: pointer.y + length3 / 2, - }, - { - x: pointer.x - length1 / 2 + (length1 - length2) / 2, - y: pointer.y + length3 / 2 - (length3 - length4), - }, - { - x: pointer.x - length1 / 2 + (length1 - length2) / 2, - y: pointer.y + length3 / 2 - (length3 - length4) - length4, - }, - { - x: pointer.x - length1 / 2 + (length1 - length2) / 2 + length2, - y: pointer.y + length3 / 2 - (length3 - length4) - length4, - }, - { - x: pointer.x - length1 / 2 + (length1 - length2) / 2 + length2, - y: pointer.y + length3 / 2 - (length3 - length4) - length4 + length4, - }, - { - x: pointer.x - length1 / 2 + length1, - y: pointer.y + length3 / 2, - }, - ], - { - fill: 'transparent', - stroke: 'black', - strokeWidth: 2, - selectable: true, - fontSize: fontSize, - name: 'guideTriangle', - }, - ) - - canvas?.add(triangle) - }) - - canvas?.on('mouse:down', (e) => { - isDrawing = false - }) - } - const createTemplate26 = () => { - const length1 = 500 //Number(prompt('1번')) - const length2 = 200 //Number(prompt('2번')) - const length3 = 300 //Number(prompt('3번')) - const length4 = 400 //Number(prompt('3번')) - - const angle = (Math.asin(length3 / length4) * 180) / Math.PI // 높이와 빗변으로 먼저 각도구하기 - - const topL = (length1 - length2) / 2 / Math.cos((angle * Math.PI) / 180) // 꺽이는부분 윗쪽 길이 - - let isDrawing = true - canvas?.on('mouse:move', (e) => { - if (!isDrawing) { - return - } - canvas?.remove(...canvas?.getObjects().filter((obj) => obj.name === 'guideTriangle')) - const pointer = canvas?.getPointer(e.e) - const triangle = new QPolygon( - [ - { - x: pointer.x - length1 / 2 + length1, - y: pointer.y + length3 / 2, - }, - { - x: pointer.x - length1 / 2, - y: pointer.y + length3 / 2, - }, - { - x: pointer.x - length1 / 2 + length4 * Math.cos(degreesToRadians(angle)), - y: pointer.y + length3 / 2 - length4 * Math.sin(degreesToRadians(angle)), - }, - { - x: pointer.x - length1 / 2 + length4 * Math.cos(degreesToRadians(angle)) + length2, - y: pointer.y + length3 / 2 - length4 * Math.sin(degreesToRadians(angle)), - }, - { - x: pointer.x - length1 / 2 + length4 * Math.cos(degreesToRadians(angle)) + length2 + topL * Math.cos(degreesToRadians(angle)), - y: pointer.y + length3 / 2 - length4 * Math.sin(degreesToRadians(angle)) + topL * Math.sin(degreesToRadians(angle)), - }, - ], - { - fill: 'transparent', - stroke: 'black', - strokeWidth: 2, - selectable: true, - fontSize: fontSize, - name: 'guideTriangle', - }, - ) - - canvas?.add(triangle) - }) - - canvas?.on('mouse:down', (e) => { - isDrawing = false - }) - } - const createTemplate27 = () => { - const length1 = 500 //Number(prompt('1번')) - const length2 = 200 //Number(prompt('2번')) - const length3 = 300 //Number(prompt('3번')) - const length4 = 400 //Number(prompt('3번')) - - const angle = (Math.asin(length3 / length4) * 180) / Math.PI // 높이와 빗변으로 먼저 각도구하기 - - const topL = (length1 - length2) / 2 / Math.cos((angle * Math.PI) / 180) // 꺽이는부분 윗쪽 길이 - - let isDrawing = true - canvas?.on('mouse:move', (e) => { - if (!isDrawing) { - return - } - canvas?.remove(...canvas?.getObjects().filter((obj) => obj.name === 'guideTriangle')) - const pointer = canvas?.getPointer(e.e) - const triangle = new QPolygon( - [ - { - x: pointer.x - length1 / 2, - y: pointer.y + length3 / 2, - }, - { - x: pointer.x - length1 / 2 + length1, - y: pointer.y + length3 / 2, - }, - { - x: pointer.x - length1 / 2 + length1 - length4 * Math.cos(degreesToRadians(angle)), - y: pointer.y + length3 / 2 - length4 * Math.sin(degreesToRadians(angle)), - }, - { - x: pointer.x - length1 / 2 + length1 - length4 * Math.cos(degreesToRadians(angle)) - length2, - y: pointer.y + length3 / 2 - length4 * Math.sin(degreesToRadians(angle)), - }, - { - x: pointer.x - length1 / 2 + length1 - length4 * Math.cos(degreesToRadians(angle)) - length2 - topL * Math.cos(degreesToRadians(angle)), - y: pointer.y + length3 / 2 - length4 * Math.sin(degreesToRadians(angle)) + topL * Math.sin(degreesToRadians(angle)), - }, - ], - { - fill: 'transparent', - stroke: 'black', - strokeWidth: 2, - selectable: true, - fontSize: fontSize, - name: 'guideTriangle', - }, - ) - - canvas?.add(triangle) - }) - - canvas?.on('mouse:down', (e) => { - isDrawing = false - }) - } - const createTemplate28 = () => { - const length1 = Number(prompt('밑변')) - const length2 = Number(prompt('높이')) - const length3 = Number(prompt('빗변')) - - const a = Math.sqrt(length3 * length3 - length2 * length2) // 입력된 밑변과 높이 - - const sinA = a / length3 - const angleInRadians = Math.asin(sinA) - const angleInDegrees = angleInRadians * (180 / Math.PI) - const b = a - length1 / 2 - - const c = b / Math.tan(angleInRadians) - const d = Math.sqrt(b * b + c * c) - - if (isNaN(a)) { - alert('값이 잘못되었습니다.') - return - } - if (b < 0) { - alert('값이 잘못되었습니다.') - return - } - if (angleInDegrees === 0 || angleInRadians === 0) { - alert('값이 잘못되었습니다.') - return - } - - let isDrawing = true - let pentagon - canvas?.on('mouse:move', (e) => { - if (!isDrawing) { - return - } - canvas?.remove(...canvas?.getObjects().filter((obj) => obj.name === 'guideTriangle')) - const pointer = canvas?.getPointer(e.e) - const newAngleInRadians = (90 - angleInDegrees) * (Math.PI / 180) - - pentagon = new QPolygon( - [ - { x: pointer.x - (length1 + b) / 2, y: pointer.y + length2 / 2 }, - { x: pointer.x + length1 / 2 - b / 2, y: pointer.y + length2 / 2 }, - { - x: pointer.x + length1 / 2 - b / 2 + d * Math.cos(newAngleInRadians), - y: pointer.y + length2 / 2 - d * Math.sin(newAngleInRadians), - }, - { - x: pointer.x - (length1 + b) / 2 + length3 * Math.cos(newAngleInRadians), - y: pointer.y + length2 / 2 - length3 * Math.sin(newAngleInRadians), - }, - ], - { - fill: 'transparent', - stroke: 'gray', - strokeWidth: 1, - selectable: true, - fontSize: fontSize, - name: 'guideTriangle', - }, - ) - - canvas?.add(pentagon) - }) - - canvas?.on('mouse:down', (e) => { - isDrawing = false - pentagon.set('name', 'roof') - pentagon.set('stroke', 2) - canvas?.renderAll() - }) - } - const createTemplate29 = () => { - const length1 = Number(prompt('밑변')) - const length2 = Number(prompt('높이')) - const length3 = Number(prompt('빗변')) - - const a = Math.sqrt(length3 * length3 - length2 * length2) // 입력된 밑변과 높이 - - const sinA = a / length3 - const angleInRadians = Math.asin(sinA) - const angleInDegrees = angleInRadians * (180 / Math.PI) - const b = a - length1 / 2 - - const c = b / Math.tan(angleInRadians) - const d = Math.sqrt(b * b + c * c) - - if (isNaN(a)) { - alert('값이 잘못되었습니다.') - return - } - if (b < 0) { - alert('값이 잘못되었습니다.') - return - } - if (angleInDegrees === 0 || angleInRadians === 0) { - alert('값이 잘못되었습니다.') - return - } - - let isDrawing = true - let pentagon - canvas?.on('mouse:move', (e) => { - if (!isDrawing) { - return - } - canvas?.remove(...canvas?.getObjects().filter((obj) => obj.name === 'guideTriangle')) - const pointer = canvas?.getPointer(e.e) - const newAngleInRadians = (90 - angleInDegrees) * (Math.PI / 180) - - pentagon = new QPolygon( - [ - { - x: pointer.x + length1 / 2 - b / 2 - length3 * Math.cos(newAngleInRadians), - y: pointer.y + length2 / 2 - length3 * Math.sin(newAngleInRadians), - }, - { x: pointer.x + length1 / 2 - b / 2, y: pointer.y + length2 / 2 }, - { x: pointer.x - (length1 + b) / 2, y: pointer.y + length2 / 2 }, - { x: pointer.x - (length1 + b) / 2 - d * Math.cos(newAngleInRadians), y: pointer.y + length2 / 2 - d * Math.sin(newAngleInRadians) }, - ], - { - fill: 'transparent', - stroke: 'gray', - strokeWidth: 1, - selectable: true, - fontSize: fontSize, - name: 'guideTriangle', - }, - ) - - canvas?.add(pentagon) - }) - - canvas?.on('mouse:down', (e) => { - isDrawing = false - pentagon.set('name', 'roof') - pentagon.set('stroke', 2) - canvas?.renderAll() - }) - } - const moduleConfiguration = () => { createRoofRack() } @@ -1895,66 +751,6 @@ export default function Roof2(props) { - - - - - - - - - - - - - - - - - - - - diff --git a/src/components/ui/SurfaceShape.jsx b/src/components/ui/SurfaceShape.jsx index 774f8e28..06e2e0e3 100644 --- a/src/components/ui/SurfaceShape.jsx +++ b/src/components/ui/SurfaceShape.jsx @@ -5,6 +5,7 @@ import { modalState } from '@/store/modalAtom' import { QPolygon } from '@/components/fabric/QPolygon' import { fontSizeState, roofMaterialState } from '@/store/canvasAtom' import { degreesToRadians } from '@turf/turf' +import { getIntersectionPoint } from '@/util/canvas-util' /** * 면형상 배치 모달 @@ -39,6 +40,10 @@ export const SurfaceShapeModal = ({ canvas }) => { } const onSave = () => { + if (!checkValid()) { + alert('안됨') + return + } let isDrawing = true let obj = null let points = [] @@ -303,7 +308,136 @@ export const SurfaceShapeModal = ({ canvas }) => { ] break } + case 21: { + const pointsArray = [ + { x: 0, y: 0 }, + { x: 0, y: 0 }, + { x: 0, y: 0 }, + { x: 0, y: 0 }, + { x: 0, y: 0 }, + ] + const tmpPolygon = new QPolygon( + [ + { x: 0, y: length3 }, + { x: length1 - length2, y: length3 }, + { x: (length1 - length2) / 2, y: length3 - length3 }, + ], + { + fill: 'transparent', + stroke: 'black', //black + strokeWidth: 2, + selectable: true, + fontSize: 0, + }, + ) + + const coord = getIntersectionPoint(tmpPolygon.lines[1].startPoint, tmpPolygon.lines[2].startPoint, length3 - length4) + const scale = (length1 - length2) / coord.x + + tmpPolygon.set({ scaleX: scale }) + + pointsArray[0].x = 0 + pointsArray[0].y = length3 //바닥면부터 시작하게 + pointsArray[1].x = pointsArray[0].x + length1 + pointsArray[1].y = pointsArray[0].y + pointsArray[2].x = pointsArray[1].x + pointsArray[2].y = pointsArray[1].y - length4 + pointsArray[3].x = pointsArray[2].x - length2 + pointsArray[3].y = pointsArray[2].y + pointsArray[4].x = tmpPolygon.getCurrentPoints()[2].x + pointsArray[4].y = tmpPolygon.getCurrentPoints()[2].y + + points = [ + { + x: pointer.x - length1 / 2, + y: pointer.y + length4 / 2, + }, + { + x: pointer.x + length1 / 2, + y: pointer.y + length4 / 2, + }, + { + x: pointer.x + length1 / 2, + y: pointer.y - length4 / 2, + }, + { + x: pointer.x - (length2 - length1 / 2), + y: pointer.y - length4 / 2, + }, + { + x: pointer.x - length1 / 2 + pointsArray[4].x, + y: pointer.y - length3 + length4 / 2, + }, + ] + + break + } + case 22: { + const pointsArray = [ + { x: 0, y: 0 }, + { x: 0, y: 0 }, + { x: 0, y: 0 }, + { x: 0, y: 0 }, + { x: 0, y: 0 }, + ] + + const tmpPolygon = new QPolygon( + [ + { x: 0, y: length3 }, + { x: length1 - length2, y: length3 }, + { x: (length1 - length2) / 2, y: length3 - length3 }, + ], + { + fill: 'transparent', + stroke: 'black', //black + strokeWidth: 2, + selectable: true, + fontSize: 0, + }, + ) + + const coord = getIntersectionPoint(tmpPolygon.lines[1].startPoint, tmpPolygon.lines[2].startPoint, length3 - length4) + const scale = (length1 - length2) / coord.x + + tmpPolygon.set({ scaleX: scale }) + + pointsArray[0].x = 0 + pointsArray[0].y = length3 //바닥면부터 시작하게 + pointsArray[1].x = pointsArray[0].x + length1 + pointsArray[1].y = pointsArray[0].y + pointsArray[2].x = pointsArray[1].x + pointsArray[2].y = pointsArray[1].y - length4 + pointsArray[3].x = pointsArray[2].x - length2 + pointsArray[3].y = pointsArray[2].y + pointsArray[4].x = tmpPolygon.getCurrentPoints()[2].x + pointsArray[4].y = tmpPolygon.getCurrentPoints()[2].y + + points = [ + { + x: pointer.x - length1 / 2, + y: pointer.y + length4 / 2, + }, + { + x: pointer.x + length1 / 2, + y: pointer.y + length4 / 2, + }, + { + x: pointer.x + length1 / 2, + y: pointer.y - length4 / 2, + }, + { + x: pointer.x - (length2 - length1 / 2), + y: pointer.y - length4 / 2, + }, + { + x: pointer.x - length1 / 2 + pointsArray[4].x, + y: pointer.y - length3 + length4 / 2, + }, + ] + + break + } case 23: { points = [ { x: pointer.x - length1 / 2 + length2, y: pointer.y + length4 / 2 }, @@ -462,14 +596,27 @@ export const SurfaceShapeModal = ({ canvas }) => { break } } - obj = new QPolygon(points, { - fill: 'transparent', - stroke: 'black', - strokeWidth: 2, - selectable: false, - fontSize: fontSize, - name: 'guideTriangle', - }) + if (type !== 22) { + obj = new QPolygon(points, { + fill: 'transparent', + stroke: 'black', + strokeWidth: 2, + selectable: false, + fontSize: fontSize, + name: 'guideTriangle', + }) + } else { + obj = new QPolygon(points, { + fill: 'transparent', + stroke: 'black', + strokeWidth: 2, + selectable: false, + fontSize: fontSize, + name: 'guideTriangle', + flipX: true, + }) + } + canvas?.add(obj) setCurrentPattern(obj) canvas?.renderAll() @@ -482,6 +629,42 @@ export const SurfaceShapeModal = ({ canvas }) => { setOpen(false) } + const checkValid = () => { + let result = true + switch (type) { + case 1: { + if (length3 !== 0 && length1 > length3) { + return false + } + break + } + case 21: { + if (length1 < length2) { + alert('1번보다 작게 입력해주세요.') + return false + } + + if (length3 < length4) { + alert('3번보다 작게 입력해주세요.') + return false + } + } + case 22: { + if (length1 < length2) { + alert('1번보다 작게 입력해주세요.') + return false + } + + if (length3 < length4) { + alert('3번보다 작게 입력해주세요.') + return false + } + } + } + + return result + } + const setLength = (e) => { let { name, value } = e.target value = value.replace(/[^-0-9]/g, '') From cfea4c5525efdd390fd8848efacab4bbd7391caf Mon Sep 17 00:00:00 2001 From: "hyojun.choi" Date: Tue, 3 Sep 2024 16:33:06 +0900 Subject: [PATCH 06/34] =?UTF-8?q?9=EB=B2=88=EA=B9=8C=EC=A7=80=20validation?= =?UTF-8?q?=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/ui/SurfaceShape.jsx | 40 ++++++++++++++++++++++++++---- 1 file changed, 35 insertions(+), 5 deletions(-) diff --git a/src/components/ui/SurfaceShape.jsx b/src/components/ui/SurfaceShape.jsx index 06e2e0e3..1ba27d16 100644 --- a/src/components/ui/SurfaceShape.jsx +++ b/src/components/ui/SurfaceShape.jsx @@ -634,30 +634,60 @@ export const SurfaceShapeModal = ({ canvas }) => { switch (type) { case 1: { if (length3 !== 0 && length1 > length3) { - return false + return + } + break + } + case 3: { + if (length3 > length1) { + return + } + break + } + case 6: { + if (length3 > length1) { + return + } + break + } + case 7: { + if (length3 > length1) { + return + } + break + } + case 8: { + if (length2 > length3) { + return + } + break + } + case 9: { + if (length2 > length3) { + return } break } case 21: { if (length1 < length2) { alert('1번보다 작게 입력해주세요.') - return false + return } if (length3 < length4) { alert('3번보다 작게 입력해주세요.') - return false + return } } case 22: { if (length1 < length2) { alert('1번보다 작게 입력해주세요.') - return false + return } if (length3 < length4) { alert('3번보다 작게 입력해주세요.') - return false + return } } } From 507253fd0778e931e61c38f575b663a75285799d Mon Sep 17 00:00:00 2001 From: yoosangwook Date: Wed, 4 Sep 2024 08:58:07 +0900 Subject: [PATCH 07/34] chore: Update environment variables and dependencies --- .env.development | 4 +++- .env.production | 4 +++- package.json | 1 + yarn.lock | 16 ++++++++++++++++ 4 files changed, 23 insertions(+), 2 deletions(-) diff --git a/.env.development b/.env.development index 9a1529ed..4cc98669 100644 --- a/.env.development +++ b/.env.development @@ -5,4 +5,6 @@ NEXT_PUBLIC_TEST="테스트변수입니다. development" DATABASE_URL="sqlserver://mssql.devgrr.kr:1433;database=qcast;user=qcast;password=Qwertqaz12345;trustServerCertificate=true" -SESSION_SECRET="i3iHH1yp2/2SpQSIySQ4bpyc4g0D+zCF9FAn5xUG0+Y=" \ No newline at end of file +SESSION_SECRET="i3iHH1yp2/2SpQSIySQ4bpyc4g0D+zCF9FAn5xUG0+Y=" + +CONVERTER_API_URL="https://v2.convertapi.com/convert/dwg/to/png?Secret=secret_bV5zuYMyyIYFlOb3" \ No newline at end of file diff --git a/.env.production b/.env.production index 8970b77b..145db4d0 100644 --- a/.env.production +++ b/.env.production @@ -4,4 +4,6 @@ NEXT_PUBLIC_API_SERVER_PATH="http://localhost:8080" DATABASE_URL="" -SESSION_SECRET="i3iHH1yp2/2SpQSIySQ4bpyc4g0D+zCF9FAn5xUG0+Y=" \ No newline at end of file +SESSION_SECRET="i3iHH1yp2/2SpQSIySQ4bpyc4g0D+zCF9FAn5xUG0+Y=" + +CONVERTER_API_URL="https://v2.convertapi.com/convert/dwg/to/png?Secret=secret_bV5zuYMyyIYFlOb3" \ No newline at end of file diff --git a/package.json b/package.json index bbd8c881..a91884a8 100644 --- a/package.json +++ b/package.json @@ -32,6 +32,7 @@ }, "devDependencies": { "@turf/turf": "^7.0.0", + "convertapi": "^1.14.0", "dayjs": "^1.11.13", "postcss": "^8", "prettier": "^3.3.3", diff --git a/yarn.lock b/yarn.lock index d41582a6..1a73ec7a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4017,6 +4017,15 @@ asynckit@^0.4.0: resolved "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz" integrity sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q== +axios@^1.6.2: + version "1.7.7" + resolved "https://registry.yarnpkg.com/axios/-/axios-1.7.7.tgz#2f554296f9892a72ac8d8e4c5b79c14a91d0a47f" + integrity sha512-S4kL7XrjgBmvdGut0sN3yJxqYzrDOnivkBiN0OFs6hLiUam3UPvswUo0kqGyhqUZGEOytHyumEdXsAkgCOUf3Q== + dependencies: + follow-redirects "^1.15.6" + form-data "^4.0.0" + proxy-from-env "^1.1.0" + axios@^1.7.3: version "1.7.3" resolved "https://registry.npmjs.org/axios/-/axios-1.7.3.tgz" @@ -4252,6 +4261,13 @@ console-control-strings@^1.0.0, console-control-strings@^1.1.0: resolved "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz" integrity sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ== +convertapi@^1.14.0: + version "1.14.0" + resolved "https://registry.yarnpkg.com/convertapi/-/convertapi-1.14.0.tgz#a291a98cb986ae1e0f2340a130adbe17f65c8c76" + integrity sha512-9Rzkn+Mjs4jVLQ5pRUC8KpIjnT9WFUkuJZ5yjCJaDJsDM7Na2lWPKtDJdkfKcYCNDuo1h+OYZedne5SLp60EkQ== + dependencies: + axios "^1.6.2" + cookie@0.6.0: version "0.6.0" resolved "https://registry.npmjs.org/cookie/-/cookie-0.6.0.tgz" From b2b528fc074e558e2e198b703a8c6a25b2002a1c Mon Sep 17 00:00:00 2001 From: yoosangwook Date: Wed, 4 Sep 2024 08:58:36 +0900 Subject: [PATCH 08/34] feat: Add CAD file conversion functionality to Playground component --- src/components/Playground.jsx | 20 +++++++++++++++++++- src/lib/cadAction.js | 13 +++++++++++++ 2 files changed, 32 insertions(+), 1 deletion(-) create mode 100644 src/lib/cadAction.js diff --git a/src/components/Playground.jsx b/src/components/Playground.jsx index d7b06e58..4d8007b9 100644 --- a/src/components/Playground.jsx +++ b/src/components/Playground.jsx @@ -6,6 +6,7 @@ import ColorPicker from './common/color-picker/ColorPicker' import { useAxios } from '@/hooks/useAxios' import { useMessage } from '@/hooks/useMessage' +import { convertDwgToPng } from '@/lib/cadAction' // import { get } from '@/lib/Axios' import QSelect from '@/components/ui/QSelect' @@ -13,7 +14,8 @@ import QSelect from '@/components/ui/QSelect' import styles from './playground.module.css' export default function Playground() { - const { get } = useAxios() + const fileRef = useRef(null) + const { get, post } = useAxios() const testVar = process.env.NEXT_PUBLIC_TEST const { getMessage } = useMessage() @@ -28,6 +30,16 @@ export default function Playground() { console.log('users', users) } + const handleConvert = async () => { + console.log('file', fileRef.current.files[0]) + + const formData = new FormData() + formData.append('file', fileRef.current.files[0]) + + const result = await post({ url: process.env.CONVERTER_API_URL, data: formData }) + await convertDwgToPng(result.Files[0].FileName, result.Files[0].FileData) + } + const data = [ { id: 1, @@ -70,6 +82,12 @@ export default function Playground() {
{color}
+
+ +
+ +
+
) diff --git a/src/lib/cadAction.js b/src/lib/cadAction.js new file mode 100644 index 00000000..be69fecb --- /dev/null +++ b/src/lib/cadAction.js @@ -0,0 +1,13 @@ +const convertDwgToPng = async (fileName, data) => { + console.log('fileName', fileName) + const imagePath = 'public/cad-images' + try { + await fs.readdir(imagePath) + } catch { + await fs.mkdir(imagePath) + } + + return fs.writeFile(`${imagePath}/${fileName}`, data, 'base64') +} + +export { convertDwgToPng } From dfcb27d09e40d7e0b19c82e191c2a4d7e0c6cf17 Mon Sep 17 00:00:00 2001 From: yjnoh Date: Wed, 4 Sep 2024 10:37:11 +0900 Subject: [PATCH 09/34] =?UTF-8?q?template=20svg=EC=82=AD=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- public/drawTemplates/153302.svg | 23 ------------------- public/drawTemplates/shape21.svg | 4 ---- .../context-menu/QPolygonContextMenu.jsx | 17 ++++++++++++++ src/components/ui/SurfaceShape.jsx | 4 ++-- 4 files changed, 19 insertions(+), 29 deletions(-) delete mode 100644 public/drawTemplates/153302.svg delete mode 100644 public/drawTemplates/shape21.svg diff --git a/public/drawTemplates/153302.svg b/public/drawTemplates/153302.svg deleted file mode 100644 index 3b1c97b0..00000000 --- a/public/drawTemplates/153302.svg +++ /dev/null @@ -1,23 +0,0 @@ - - - - -Created by potrace 1.15, written by Peter Selinger 2001-2017 - - - - - - - diff --git a/public/drawTemplates/shape21.svg b/public/drawTemplates/shape21.svg deleted file mode 100644 index a2d901e7..00000000 --- a/public/drawTemplates/shape21.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/src/components/common/context-menu/QPolygonContextMenu.jsx b/src/components/common/context-menu/QPolygonContextMenu.jsx index b3246165..5c886816 100644 --- a/src/components/common/context-menu/QPolygonContextMenu.jsx +++ b/src/components/common/context-menu/QPolygonContextMenu.jsx @@ -7,6 +7,13 @@ export default function QPolygonContextMenu(props) { // const children = useRecoilValue(modalContent) const [contextMenu, setContextMenu] = useState({ visible: false, x: 0, y: 0 }) + const optionName = canvasProps.getActiveObject().initOptions.name + + let contextType = '' + + if (optionName.indexOf('guide') > -1) { + contextType = 'surface' + } useEffect(() => { if (!contextRef.current) return @@ -63,6 +70,16 @@ export default function QPolygonContextMenu(props) {
  • handleMenuClick(3)}> Option 3
  • + {contextType === 'surface' ? ( + <> +
  • handleMenuClick(4)}> + 모듈,회로구성 +
  • +
  • handleMenuClick(4)}> + 모듈 채우기 +
  • + + ) : null} )} diff --git a/src/components/ui/SurfaceShape.jsx b/src/components/ui/SurfaceShape.jsx index 06e2e0e3..46bac2a5 100644 --- a/src/components/ui/SurfaceShape.jsx +++ b/src/components/ui/SurfaceShape.jsx @@ -601,7 +601,7 @@ export const SurfaceShapeModal = ({ canvas }) => { fill: 'transparent', stroke: 'black', strokeWidth: 2, - selectable: false, + selectable: true, fontSize: fontSize, name: 'guideTriangle', }) @@ -610,7 +610,7 @@ export const SurfaceShapeModal = ({ canvas }) => { fill: 'transparent', stroke: 'black', strokeWidth: 2, - selectable: false, + selectable: true, fontSize: fontSize, name: 'guideTriangle', flipX: true, From 3fa147b12e7f9800ac2bdd88dfe1ef13a035ec3b Mon Sep 17 00:00:00 2001 From: yjnoh Date: Wed, 4 Sep 2024 12:45:52 +0900 Subject: [PATCH 10/34] =?UTF-8?q?=ED=8F=B4=EB=A6=AC=EA=B3=A4=20context=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../common/context-menu/QPolygonContextMenu.jsx | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/components/common/context-menu/QPolygonContextMenu.jsx b/src/components/common/context-menu/QPolygonContextMenu.jsx index 5c886816..8558ee72 100644 --- a/src/components/common/context-menu/QPolygonContextMenu.jsx +++ b/src/components/common/context-menu/QPolygonContextMenu.jsx @@ -7,12 +7,12 @@ export default function QPolygonContextMenu(props) { // const children = useRecoilValue(modalContent) const [contextMenu, setContextMenu] = useState({ visible: false, x: 0, y: 0 }) - const optionName = canvasProps.getActiveObject().initOptions.name + const polygon = canvasProps.getActiveObject() //액티브된 객체를 가져옴 let contextType = '' - if (optionName.indexOf('guide') > -1) { - contextType = 'surface' + if (polygon.initOptions.name.indexOf('guide') > -1) { + contextType = 'surface' //면형상 } useEffect(() => { @@ -20,6 +20,9 @@ export default function QPolygonContextMenu(props) { const handleContextMenu = (e) => { e.preventDefault() //기존 contextmenu 막고 + + // Fabric.js 상의 객체에 직접 이벤트를 트리거할 수는 없으므로, + // 캔버스 요소에 이벤트를 디스패치하여 처리 setContextMenu({ visible: true, x: e.pageX, y: e.pageY }) canvasProps.upperCanvasEl.removeEventListener('contextmenu', handleContextMenu) //한번 노출 후 이벤트 삭제 } @@ -72,9 +75,6 @@ export default function QPolygonContextMenu(props) { {contextType === 'surface' ? ( <> -
  • handleMenuClick(4)}> - 모듈,회로구성 -
  • handleMenuClick(4)}> 모듈 채우기
  • From 7a150be0692e5cd8e853e0b89c8b78f3e90134a0 Mon Sep 17 00:00:00 2001 From: yoosangwook Date: Wed, 4 Sep 2024 13:00:00 +0900 Subject: [PATCH 11/34] feat: Add CAD file conversion functionality to Playground component --- .env.development | 4 +-- .env.production | 2 +- src/components/Playground.jsx | 23 ++++++++++---- src/components/Roof2.jsx | 56 +++++++++++++++++++++++++++++++++-- src/hooks/useAxios.js | 6 +++- src/hooks/useCanvas.js | 29 ++++++++++++++++++ src/lib/cadAction.js | 13 +++++--- src/store/canvasAtom.js | 18 +++++++++++ 8 files changed, 136 insertions(+), 15 deletions(-) diff --git a/.env.development b/.env.development index 4cc98669..f8aa1483 100644 --- a/.env.development +++ b/.env.development @@ -1,10 +1,10 @@ NEXT_PUBLIC_TEST="테스트변수입니다. development" - NEXT_PUBLIC_API_SERVER_PATH="http://1.248.227.176:38080" +NEXT_PUBLIC_API_SERVER_PATH="http://1.248.227.176:38080" # NEXT_PUBLIC_API_SERVER_PATH="http://localhost:8080" DATABASE_URL="sqlserver://mssql.devgrr.kr:1433;database=qcast;user=qcast;password=Qwertqaz12345;trustServerCertificate=true" SESSION_SECRET="i3iHH1yp2/2SpQSIySQ4bpyc4g0D+zCF9FAn5xUG0+Y=" -CONVERTER_API_URL="https://v2.convertapi.com/convert/dwg/to/png?Secret=secret_bV5zuYMyyIYFlOb3" \ No newline at end of file +NEXT_PUBLIC_CONVERTER_API_URL="https://v2.convertapi.com/convert/dwg/to/png?Secret=secret_bV5zuYMyyIYFlOb3" \ No newline at end of file diff --git a/.env.production b/.env.production index 145db4d0..91d91ce1 100644 --- a/.env.production +++ b/.env.production @@ -6,4 +6,4 @@ DATABASE_URL="" SESSION_SECRET="i3iHH1yp2/2SpQSIySQ4bpyc4g0D+zCF9FAn5xUG0+Y=" -CONVERTER_API_URL="https://v2.convertapi.com/convert/dwg/to/png?Secret=secret_bV5zuYMyyIYFlOb3" \ No newline at end of file +NEXT_PUBLIC_CONVERTER_API_URL="https://v2.convertapi.com/convert/dwg/to/png?Secret=secret_bV5zuYMyyIYFlOb3" \ No newline at end of file diff --git a/src/components/Playground.jsx b/src/components/Playground.jsx index 4d8007b9..2734ac8c 100644 --- a/src/components/Playground.jsx +++ b/src/components/Playground.jsx @@ -1,7 +1,7 @@ 'use client' -import { useState } from 'react' -import { Button, Table, TableBody, TableCell, TableColumn, TableHeader, TableRow } from '@nextui-org/react' +import { useRef, useState } from 'react' +import { Button } from '@nextui-org/react' import ColorPicker from './common/color-picker/ColorPicker' import { useAxios } from '@/hooks/useAxios' @@ -12,11 +12,16 @@ import { convertDwgToPng } from '@/lib/cadAction' import QSelect from '@/components/ui/QSelect' import styles from './playground.module.css' +import { useRecoilState } from 'recoil' +import { cadFileNameState, useCadFileState } from '@/store/canvasAtom' export default function Playground() { + const [useCadFile, setUseCadFile] = useRecoilState(useCadFileState) + const [cadFileName, setCadFileName] = useRecoilState(cadFileNameState) const fileRef = useRef(null) - const { get, post } = useAxios() + const { get, promisePost } = useAxios() const testVar = process.env.NEXT_PUBLIC_TEST + const converterUrl = process.env.NEXT_PUBLIC_CONVERTER_API_URL const { getMessage } = useMessage() const [color, setColor] = useState('#ff0000') @@ -36,8 +41,16 @@ export default function Playground() { const formData = new FormData() formData.append('file', fileRef.current.files[0]) - const result = await post({ url: process.env.CONVERTER_API_URL, data: formData }) - await convertDwgToPng(result.Files[0].FileName, result.Files[0].FileData) + await promisePost({ url: converterUrl, data: formData }) + .then((res) => { + console.log('response: ', res) + convertDwgToPng(res.data.Files[0].FileName, res.data.Files[0].FileData) + setUseCadFile(true) + setCadFileName(res.data.Files[0].FileName) + }) + .catch((err) => { + console.error(err) + }) } const data = [ diff --git a/src/components/Roof2.jsx b/src/components/Roof2.jsx index 03749bd2..aa99b3c9 100644 --- a/src/components/Roof2.jsx +++ b/src/components/Roof2.jsx @@ -1,7 +1,7 @@ 'use client' import { useCanvas } from '@/hooks/useCanvas' -import { useCallback, useEffect, useRef, useState } from 'react' +import { useEffect, useRef, useState } from 'react' import { v4 as uuidv4 } from 'uuid' import { useMode } from '@/hooks/useMode' import { Mode } from '@/common/common' @@ -9,6 +9,8 @@ import { Button } from '@nextui-org/react' import RangeSlider from './ui/RangeSlider' import { useRecoilState, useRecoilValue } from 'recoil' import { + cadFileCompleteState, + cadFileNameState, canvasSizeState, compassState, currentObjectState, @@ -17,6 +19,7 @@ import { roofState, sortedPolygonArray, templateTypeState, + useCadFileState, wallState, } from '@/store/canvasAtom' import { QLine } from '@/components/fabric/QLine' @@ -38,7 +41,18 @@ import { SurfaceShapeModal } from '@/components/ui/SurfaceShape' export default function Roof2(props) { const { name, userId, email, isLoggedIn } = props - const { canvas, handleRedo, handleUndo, setCanvasBackgroundWithDots, saveImage, addCanvas } = useCanvas('canvas') + const { + canvas, + handleRedo, + handleUndo, + setCanvasBackgroundWithDots, + saveImage, + addCanvas, + handleCadImageLoad, + handleCadImageInit, + backImg, + setBackImg, + } = useCanvas('canvas') const { get } = useAxios() @@ -84,6 +98,13 @@ export default function Roof2(props) { canvas, } + // cad 파일 업로드 + const [useCadFile, setUseCadFile] = useRecoilState(useCadFileState) + const [cadFileName, setCadFileName] = useRecoilState(cadFileNameState) + const [cadFileComplete, setCadFileComplete] = useRecoilState(cadFileCompleteState) + let imgPath + useCadFile && (imgPath = `/cadImages/${cadFileName}`) + const { mode, setMode, @@ -130,6 +151,11 @@ export default function Roof2(props) { return } changeMode(canvas, mode) + + if (!cadFileComplete && useCadFile) { + // cad 파일 로드 + useCadFile && handleCadImageLoad(imgPath, canvas) + } }, [canvas, mode]) const makeLine = () => { @@ -757,6 +783,32 @@ export default function Roof2(props) { + + diff --git a/src/hooks/useAxios.js b/src/hooks/useAxios.js index 3fa1f4f4..4c7be165 100644 --- a/src/hooks/useAxios.js +++ b/src/hooks/useAxios.js @@ -45,6 +45,10 @@ export function useAxios() { .catch(console.error) } + const promisePost = async ({ url, data }) => { + return await getInstances(url).post(url, data) + } + const put = async ({ url, data }) => { return await getInstances(url) .put(url, data) @@ -66,5 +70,5 @@ export function useAxios() { .catch(console.error) } - return { get, post, put, patch, del } + return { get, post, promisePost, put, patch, del } } diff --git a/src/hooks/useCanvas.js b/src/hooks/useCanvas.js index 0dc724f3..e4902c33 100644 --- a/src/hooks/useCanvas.js +++ b/src/hooks/useCanvas.js @@ -17,6 +17,7 @@ export function useCanvas(id) { const [canvas, setCanvas] = useState() const [isLocked, setIsLocked] = useState(false) const [history, setHistory] = useState([]) + const [backImg, setBackImg] = useState() const [canvasSize] = useRecoilState(canvasSizeState) const [fontSize] = useRecoilState(fontSizeState) const { setCanvasForEvent, attachDefaultEventOnCanvas } = useCanvasEvent() @@ -444,6 +445,30 @@ export function useCanvas(id) { // }, 1000) } + /** + * cad 파일 사용시 이미지 로딩 함수 + */ + const handleCadImageLoad = (url) => { + console.log('image load url: ', url) + + fabric.Image.fromURL(url, function (img) { + img.set({ + left: 0, + top: 0, + width: 1500, + height: 1500, + selectable: true, + }) + canvas.add(img) + canvas.renderAll() + setBackImg(img) + }) + } + + const handleCadImageInit = () => { + canvas.clear() + } + return { canvas, addShape, @@ -459,5 +484,9 @@ export function useCanvas(id) { setCanvasBackgroundWithDots, addCanvas, removeMouseLines, + handleCadImageLoad, + handleCadImageInit, + backImg, + setBackImg, } } diff --git a/src/lib/cadAction.js b/src/lib/cadAction.js index be69fecb..05bc878a 100644 --- a/src/lib/cadAction.js +++ b/src/lib/cadAction.js @@ -1,13 +1,18 @@ +'use server' + +import fs from 'fs/promises' + +const imageSavePath = 'public/cadImages' + const convertDwgToPng = async (fileName, data) => { console.log('fileName', fileName) - const imagePath = 'public/cad-images' try { - await fs.readdir(imagePath) + await fs.readdir(imageSavePath) } catch { - await fs.mkdir(imagePath) + await fs.mkdir(imageSavePath) } - return fs.writeFile(`${imagePath}/${fileName}`, data, 'base64') + return await fs.writeFile(`${imageSavePath}/${fileName}`, data, 'base64') } export { convertDwgToPng } diff --git a/src/store/canvasAtom.js b/src/store/canvasAtom.js index ed90c2e7..f2bbfa3a 100644 --- a/src/store/canvasAtom.js +++ b/src/store/canvasAtom.js @@ -126,3 +126,21 @@ export const customSettingsState = atom({ default: {}, dangerouslyAllowMutability: true, }) + +// cad 도면 파일 사용 여부 +export const useCadFileState = atom({ + key: 'useCadFile', + default: false, +}) + +// cad 도면 파일 이름 +export const cadFileNameState = atom({ + key: 'cadFileName', + default: '', +}) + +// cad 도면 파일 조정 완료 +export const cadFileCompleteState = atom({ + key: 'cadFileComplete', + default: false, +}) From 4b226a670a2455ce8047fa7b8a23c43de9c86f67 Mon Sep 17 00:00:00 2001 From: "hyojun.choi" Date: Wed, 4 Sep 2024 13:53:36 +0900 Subject: [PATCH 12/34] =?UTF-8?q?=EB=A9=B4=ED=98=95=EC=83=81=20=EB=B0=A9?= =?UTF-8?q?=ED=96=A5=20=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/fabric/QPolygon.js | 1 + src/components/ui/SurfaceShape.jsx | 45 ++++++++++++++++++++++++++++++ src/hooks/useCanvas.js | 1 + src/hooks/useMode.js | 12 ++------ 4 files changed, 50 insertions(+), 9 deletions(-) diff --git a/src/components/fabric/QPolygon.js b/src/components/fabric/QPolygon.js index 355fdf7f..f255edc3 100644 --- a/src/components/fabric/QPolygon.js +++ b/src/components/fabric/QPolygon.js @@ -19,6 +19,7 @@ export const QPolygon = fabric.util.createClass(fabric.Polygon, { innerLines: [], children: [], initOptions: null, + defense: null, initialize: function (points, options, canvas) { // 소수점 전부 제거 points.forEach((point) => { diff --git a/src/components/ui/SurfaceShape.jsx b/src/components/ui/SurfaceShape.jsx index 21f3edd7..f6fda227 100644 --- a/src/components/ui/SurfaceShape.jsx +++ b/src/components/ui/SurfaceShape.jsx @@ -28,6 +28,8 @@ export const SurfaceShapeModal = ({ canvas }) => { const [length4, setLength4] = useState(0) const [length5, setLength5] = useState(0) + const [defense, setDefense] = useState('south') + /** * 최대 5개의 length */ @@ -603,6 +605,11 @@ export const SurfaceShapeModal = ({ canvas }) => { strokeWidth: 2, selectable: true, fontSize: fontSize, + lockMovementX: true, // X 축 이동 잠금 + lockMovementY: true, // Y 축 이동 잠금 + lockRotation: true, // 회전 잠금 + lockScalingX: true, // X 축 크기 조정 잠금 + lockScalingY: true, // Y 축 크기 조정 잠금 name: 'guideTriangle', }) } else { @@ -613,11 +620,17 @@ export const SurfaceShapeModal = ({ canvas }) => { selectable: true, fontSize: fontSize, name: 'guideTriangle', + lockMovementX: true, // X 축 이동 잠금 + lockMovementY: true, // Y 축 이동 잠금 + lockRotation: true, // 회전 잠금 + lockScalingX: true, // X 축 크기 조정 잠금 + lockScalingY: true, // Y 축 크기 조정 잠금 flipX: true, }) } canvas?.add(obj) + obj.set({ defense: defense }) setCurrentPattern(obj) canvas?.renderAll() }) @@ -832,6 +845,38 @@ export const SurfaceShapeModal = ({ canvas }) => { ) : ( <> )} +
    +
    + +
    +
    + + +
    +
    + +
    +
    - {/* - */} + { + + } diff --git a/src/hooks/useMode.js b/src/hooks/useMode.js index bcbf2c48..4b7d9eb5 100644 --- a/src/hooks/useMode.js +++ b/src/hooks/useMode.js @@ -81,8 +81,9 @@ export function useMode() { // } if (!canvas) return setCanvas(canvas) + canvas?.off('mouse:move') canvas?.on('mouse:move', drawMouseLines) - }, [canvas]) // 빈 배열을 전달하여 컴포넌트가 마운트될 때만 실행되도록 함 + }, [canvas, zoom]) // 빈 배열을 전달하여 컴포넌트가 마운트될 때만 실행되도록 함 useEffect(() => { if (canvas?.getObjects().find((obj) => obj.name === 'connectLine')) { @@ -278,7 +279,7 @@ export function useMode() { } // 가로선을 그립니다. - const horizontalLine = new fabric.Line([0, newY, canvasSize.horizontal, newY], { + const horizontalLine = new fabric.Line([0, newY, 2 * canvas.width, newY], { stroke: 'red', strokeWidth: 1, selectable: false, @@ -286,7 +287,7 @@ export function useMode() { }) // 세로선을 그립니다. - const verticalLine = new fabric.Line([newX, 0, newX, canvasSize.vertical], { + const verticalLine = new fabric.Line([newX, 0, newX, 2 * canvas.height], { stroke: 'red', strokeWidth: 1, selectable: false, @@ -1138,11 +1139,17 @@ export function useMode() { } const zoomIn = () => { + if (canvas.getZoom() + 0.1 > 1.6) { + return + } canvas?.setZoom(canvas.getZoom() + 0.1) setZoom(Math.round(zoom + 10)) } const zoomOut = () => { + if (canvas.getZoom() - 0.1 < 0.5) { + return + } canvas?.setZoom(canvas.getZoom() - 0.1) setZoom(Math.ceil(zoom - 10)) } From 9187123225ac4cdf31207fd72d451518b2cfee70 Mon Sep 17 00:00:00 2001 From: "hyojun.choi" Date: Wed, 4 Sep 2024 15:09:07 +0900 Subject: [PATCH 14/34] =?UTF-8?q?=EB=B0=A9=ED=96=A5=20=EB=B3=80=EC=88=98?= =?UTF-8?q?=EB=AA=85=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/fabric/QPolygon.js | 2 +- src/components/ui/SurfaceShape.jsx | 21 +++++++++++---------- src/hooks/useCanvas.js | 1 - 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/components/fabric/QPolygon.js b/src/components/fabric/QPolygon.js index f255edc3..97fbc281 100644 --- a/src/components/fabric/QPolygon.js +++ b/src/components/fabric/QPolygon.js @@ -19,7 +19,7 @@ export const QPolygon = fabric.util.createClass(fabric.Polygon, { innerLines: [], children: [], initOptions: null, - defense: null, + direction: null, initialize: function (points, options, canvas) { // 소수점 전부 제거 points.forEach((point) => { diff --git a/src/components/ui/SurfaceShape.jsx b/src/components/ui/SurfaceShape.jsx index f6fda227..e2459d90 100644 --- a/src/components/ui/SurfaceShape.jsx +++ b/src/components/ui/SurfaceShape.jsx @@ -28,7 +28,8 @@ export const SurfaceShapeModal = ({ canvas }) => { const [length4, setLength4] = useState(0) const [length5, setLength5] = useState(0) - const [defense, setDefense] = useState('south') + // 방향 + const [direction, setDirection] = useState('south') /** * 최대 5개의 length @@ -630,7 +631,7 @@ export const SurfaceShapeModal = ({ canvas }) => { } canvas?.add(obj) - obj.set({ defense: defense }) + obj.set({ direction: direction }) setCurrentPattern(obj) canvas?.renderAll() }) @@ -848,30 +849,30 @@ export const SurfaceShapeModal = ({ canvas }) => {
    diff --git a/src/hooks/useCanvas.js b/src/hooks/useCanvas.js index b0b704b1..e4902c33 100644 --- a/src/hooks/useCanvas.js +++ b/src/hooks/useCanvas.js @@ -428,7 +428,6 @@ export function useCanvas(id) { 'minY', 'x', 'y', - 'defense', ]) const str = JSON.stringify(objs) From 3804d612d4bae4f5a7eb2cd0e93700540c0f5079 Mon Sep 17 00:00:00 2001 From: "hyojun.choi" Date: Wed, 4 Sep 2024 15:15:24 +0900 Subject: [PATCH 15/34] =?UTF-8?q?Qpolygon=20=EC=B6=94=EA=B0=80=EC=8B=9C=20?= =?UTF-8?q?=EB=8B=A4=EB=A5=B8=20Qpoiygon=EC=9D=98=20=EA=B8=B8=EC=9D=B4=20?= =?UTF-8?q?=EC=82=AC=EB=9D=BC=EC=A7=80=EB=8A=94=20=ED=98=84=EC=83=81=20?= =?UTF-8?q?=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/fabric/QPolygon.js | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/components/fabric/QPolygon.js b/src/components/fabric/QPolygon.js index 97fbc281..bb35d4a8 100644 --- a/src/components/fabric/QPolygon.js +++ b/src/components/fabric/QPolygon.js @@ -101,6 +101,7 @@ export const QPolygon = fabric.util.createClass(fabric.Polygon, { toObject: function (propertiesToInclude) { return fabric.util.object.extend(this.callSuper('toObject', propertiesToInclude), { + id: this.id, type: this.type, text: this.text, hips: this.hips, @@ -163,11 +164,13 @@ export const QPolygon = fabric.util.createClass(fabric.Polygon, { }, addLengthText() { - if (this.texts.length > 0) { - this.texts.forEach((text) => { + this.canvas + ?.getObjects() + .filter((obj) => obj.name === 'lengthText' && obj.parent === this) + .forEach((text) => { this.canvas.remove(text) }) - } + let points = this.getCurrentPoints() points.forEach((start, i) => { From 566de9b2901d104457105cc3e9933fc0cb897efe Mon Sep 17 00:00:00 2001 From: "hyojun.choi" Date: Wed, 4 Sep 2024 15:21:16 +0900 Subject: [PATCH 16/34] =?UTF-8?q?QPolygon=20setViewLengthText=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/components/fabric/QPolygon.js | 9 ++++++--- src/hooks/useMode.js | 1 + 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/src/components/fabric/QPolygon.js b/src/components/fabric/QPolygon.js index bb35d4a8..a3329ac5 100644 --- a/src/components/fabric/QPolygon.js +++ b/src/components/fabric/QPolygon.js @@ -693,9 +693,12 @@ export const QPolygon = fabric.util.createClass(fabric.Polygon, { this.wall = wall }, setViewLengthText(isView) { - this.texts.forEach((text) => { - text.set({ visible: isView }) - }) + this.canvas + ?.getObjects() + .filter((obj) => obj.name === 'lengthText' && obj.parent === this) + .forEach((text) => { + text.set({ visible: isView }) + }) }, divideLine() { splitPolygonWithLines(this) diff --git a/src/hooks/useMode.js b/src/hooks/useMode.js index 4b7d9eb5..d4c5ece0 100644 --- a/src/hooks/useMode.js +++ b/src/hooks/useMode.js @@ -4605,6 +4605,7 @@ export function useMode() { }) canvas?.add(trestlePoly) + trestlePoly.setViewLengthText(false) }) removeHelpPointAndHelpLine() } From 0119e3fac28e7079cf6be2abd8624183f6e326c8 Mon Sep 17 00:00:00 2001 From: "hyojun.choi" Date: Wed, 4 Sep 2024 15:43:07 +0900 Subject: [PATCH 17/34] =?UTF-8?q?polygon=20scaleX,Y=20=EC=B6=94=EA=B0=80?= =?UTF-8?q?=20=EB=B0=8F=20fontSize=20=ED=95=A8=EC=88=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/components/Roof2.jsx | 3 +++ src/components/fabric/QPolygon.js | 15 ++++++++++++++- 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/src/components/Roof2.jsx b/src/components/Roof2.jsx index 2d275a36..70deec93 100644 --- a/src/components/Roof2.jsx +++ b/src/components/Roof2.jsx @@ -596,10 +596,13 @@ export default function Roof2(props) { const changeLength = (e) => { setScale(e) const polygon = canvas?.getActiveObject() + if (polygon.type !== 'QPolygon') { return } + polygon.setScaleX(e) + canvas?.renderAll() } diff --git a/src/components/fabric/QPolygon.js b/src/components/fabric/QPolygon.js index a3329ac5..0c503185 100644 --- a/src/components/fabric/QPolygon.js +++ b/src/components/fabric/QPolygon.js @@ -213,7 +213,12 @@ export const QPolygon = fabric.util.createClass(fabric.Polygon, { }, setFontSize(fontSize) { this.fontSize = fontSize - this.text.set({ fontSize }) + this.canvas + ?.getObjects() + .filter((obj) => obj.name === 'lengthText' && obj.parent === this) + .forEach((text) => { + text.set({ fontSize: fontSize }) + }) }, _render: function (ctx) { this.callSuper('_render', ctx) @@ -700,6 +705,14 @@ export const QPolygon = fabric.util.createClass(fabric.Polygon, { text.set({ visible: isView }) }) }, + setScaleX(scale) { + this.scaleX = scale + this.addLengthText() + }, + setScaleY(scale) { + this.scaleY = scale + this.addLengthText() + }, divideLine() { splitPolygonWithLines(this) }, From 6c86b1181c05bc41d41666392014425c66c2f588 Mon Sep 17 00:00:00 2001 From: yjnoh Date: Wed, 4 Sep 2024 16:15:33 +0900 Subject: [PATCH 18/34] =?UTF-8?q?=EB=A9=B4=ED=98=95=EC=83=81=20=EA=B0=80?= =?UTF-8?q?=EB=8C=80=20=EB=B0=B0=EC=B9=98=EC=8B=9C=20=EC=9D=B4=EB=8F=99?= =?UTF-8?q?=EC=9C=BC=EB=A1=9C=20=EC=9D=B8=ED=95=9C=20=EC=A2=8C=ED=91=9C=20?= =?UTF-8?q?=ED=8B=80=EC=96=B4=EC=A7=90=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/hooks/useMode.js | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/src/hooks/useMode.js b/src/hooks/useMode.js index d4c5ece0..2c3efd8c 100644 --- a/src/hooks/useMode.js +++ b/src/hooks/useMode.js @@ -648,7 +648,7 @@ export function useMode() { } case 'Enter': { - const result = prompt('입력하세요 (a(A패턴),b(B패턴),t(지붕))') + const result = prompt('입력하세요 (a(A패턴), b(B패턴), t(지붕), e(변별))') switch (result) { case 'a': @@ -660,6 +660,8 @@ export function useMode() { case 't': templateMode() break + case 'e': + templateSideMode() } } } @@ -1051,6 +1053,18 @@ export function useMode() { setTemplateType(1) } } + + const templateSideMode = () => { + changeMode(canvas, Mode.EDIT) + + if (historyPoints.current.length >= 4) { + const wall = drawWallPolygon() + setWall(wall) + + console.log('sideWall', wall) + } + } + /** * 두 점을 연결하는 선과 길이를 그립니다. * a : 시작점, b : 끝점 @@ -4583,8 +4597,10 @@ export function useMode() { canvas?.off('mouse:move') canvas?.off('mouse:out') const roofs = canvas?.getObjects().filter((obj) => obj.name === 'roof') + roofs.forEach((roof, index) => { - const offsetPolygonPoint = offsetPolygon(roof.points, -20) + // const offsetPolygonPoint = offsetPolygon(roof.points(), -20) //이동되서 찍을라고 바꿈 + const offsetPolygonPoint = offsetPolygon(roof.getCurrentPoints(), -20) const trestlePoly = new QPolygon(offsetPolygonPoint, { fill: 'transparent', From 10b88ede0f1db31cb0a1220e3ef19e951bd51db3 Mon Sep 17 00:00:00 2001 From: "hyojun.choi" Date: Wed, 4 Sep 2024 16:30:35 +0900 Subject: [PATCH 19/34] =?UTF-8?q?=EC=98=A4=EB=A5=98=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/Roof2.jsx | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/components/Roof2.jsx b/src/components/Roof2.jsx index 70deec93..f77f68c0 100644 --- a/src/components/Roof2.jsx +++ b/src/components/Roof2.jsx @@ -594,13 +594,12 @@ export default function Roof2(props) { } const changeLength = (e) => { - setScale(e) const polygon = canvas?.getActiveObject() - if (polygon.type !== 'QPolygon') { + if (polygon?.type !== 'QPolygon') { return } - + setScale(e) polygon.setScaleX(e) canvas?.renderAll() From dabce818436b502f2604f91fdb3c2f896bcf1d06 Mon Sep 17 00:00:00 2001 From: yoosangwook Date: Wed, 4 Sep 2024 18:19:10 +0900 Subject: [PATCH 20/34] Fix file conversion success and failure toast messages --- src/components/Playground.jsx | 3 +++ src/components/Roof2.jsx | 28 ++++++++++++++++------------ 2 files changed, 19 insertions(+), 12 deletions(-) diff --git a/src/components/Playground.jsx b/src/components/Playground.jsx index 2734ac8c..7055c7aa 100644 --- a/src/components/Playground.jsx +++ b/src/components/Playground.jsx @@ -14,6 +14,7 @@ import QSelect from '@/components/ui/QSelect' import styles from './playground.module.css' import { useRecoilState } from 'recoil' import { cadFileNameState, useCadFileState } from '@/store/canvasAtom' +import { QToast } from '@/hooks/useToast' export default function Playground() { const [useCadFile, setUseCadFile] = useRecoilState(useCadFileState) @@ -47,9 +48,11 @@ export default function Playground() { convertDwgToPng(res.data.Files[0].FileName, res.data.Files[0].FileData) setUseCadFile(true) setCadFileName(res.data.Files[0].FileName) + QToast({ message: '파일 변환 완료', type: 'success' }) }) .catch((err) => { console.error(err) + QToast({ message: '파일 변환 실패', type: 'error' }) }) } diff --git a/src/components/Roof2.jsx b/src/components/Roof2.jsx index f77f68c0..93e03304 100644 --- a/src/components/Roof2.jsx +++ b/src/components/Roof2.jsx @@ -789,9 +789,11 @@ export default function Roof2(props) { +
    +
    + {/* Compass Circle */} +
    + {/* N, S, E, W Labels */} +
    N
    +
    S
    +
    + E +
    +
    + W +
    +
    + + {/* Compass Pointer */} +
    + {/* Red Upper Triangle */} +
    +
    +
    {!canvas ? null : mode === Mode.DRAW_LINE ? ( diff --git a/src/hooks/useCanvas.js b/src/hooks/useCanvas.js index e4902c33..043a561f 100644 --- a/src/hooks/useCanvas.js +++ b/src/hooks/useCanvas.js @@ -428,6 +428,7 @@ export function useCanvas(id) { 'minY', 'x', 'y', + 'stickeyPoint', ]) const str = JSON.stringify(objs) diff --git a/src/store/canvasAtom.js b/src/store/canvasAtom.js index f2bbfa3a..a675b508 100644 --- a/src/store/canvasAtom.js +++ b/src/store/canvasAtom.js @@ -144,3 +144,9 @@ export const cadFileCompleteState = atom({ key: 'cadFileComplete', default: false, }) + +export const globalCompassState = atom({ + key: 'globalCompass', + default: 0, + dangerouslyAllowMutability: true, +}) diff --git a/src/util/qpolygon-utils.js b/src/util/qpolygon-utils.js index f89652f1..5e00b197 100644 --- a/src/util/qpolygon-utils.js +++ b/src/util/qpolygon-utils.js @@ -2717,7 +2717,12 @@ export const drawDirectionArrow = (polygon) => { let arrow = null let points = [] + if (polygon.arrow) { + polygon.canvas.remove(polygon.arrow) + } + let centerPoint = polygon.getCenterPoint() + let stickeyPoint const polygonMaxX = Math.max(...polygon.points.map((point) => point.x)) const polygonMinX = Math.min(...polygon.points.map((point) => point.x)) @@ -2736,6 +2741,8 @@ export const drawDirectionArrow = (polygon) => { { x: centerPoint.x - 20, y: polygonMinY - 50 }, { x: centerPoint.x - 20, y: polygonMinY - 20 }, ] + + stickeyPoint = { x: centerPoint.x, y: polygonMinY - 80 } break case 'south': points = [ @@ -2748,6 +2755,7 @@ export const drawDirectionArrow = (polygon) => { { x: centerPoint.x - 20, y: polygonMaxY + 50 }, { x: centerPoint.x - 20, y: polygonMaxY + 20 }, ] + stickeyPoint = { x: centerPoint.x, y: polygonMaxY + 80 } break case 'west': points = [ @@ -2760,6 +2768,8 @@ export const drawDirectionArrow = (polygon) => { { x: polygonMinX - 50, y: centerPoint.y - 20 }, { x: polygonMinX - 20, y: centerPoint.y - 20 }, ] + + stickeyPoint = { x: polygonMinX - 80, y: centerPoint.y } break case 'east': points = [ @@ -2772,16 +2782,227 @@ export const drawDirectionArrow = (polygon) => { { x: polygonMaxX + 50, y: centerPoint.y - 20 }, { x: polygonMaxX + 20, y: centerPoint.y - 20 }, ] + + stickeyPoint = { x: polygonMaxX + 80, y: centerPoint.y } break } arrow = new fabric.Polygon(points, { selectable: false, + name: 'arrow', fill: 'transparent', stroke: 'black', + direction: direction, + parent: polygon, + stickeyPoint: stickeyPoint, }) polygon.arrow = arrow polygon.canvas.add(arrow) polygon.canvas.renderAll() } + +/** + * 방향을 나타낸 화살표에 각도에 따라 글씨 추가 + * @param canvas + * @param compass + */ +export const drawDirectionStringToArrow = (canvas, compass, fontSize) => { + const arrows = canvas?.getObjects().filter((obj) => obj.name === 'arrow') + + if (arrows.length === 0) { + return + } + + const eastArrows = arrows.filter((arrow) => arrow.direction === 'east') + const westArrows = arrows.filter((arrow) => arrow.direction === 'west') + const northArrows = arrows.filter((arrow) => arrow.direction === 'north') + const southArrows = arrows.filter((arrow) => arrow.direction === 'south') + + let southText = '南' + let eastText = '東' + let westText = '西' + let northText = '北' + + if (compass === 0 || compass === 360) { + // 남,동,서 가능 + // 그대로 + } else if (compass < 45) { + //남(남남동),동(동북동),서(서남서) 가능 + //북(북북서) + southText = '南南東' + eastText = '東北東' + westText = '西南西' + northText = '北北西' + } else if (compass === 45) { + // 남, 서 가능 + // 남(남동) + // 서(남서) + // 북(북서) + // 동(북동) + southText = '南東' + westText = '南西' + northText = '北西' + eastText = '北東' + } else if (compass < 90) { + // 북(서북서) + // 동 (북북동) + // 남(동남동) + // 서(남남서) + northText = '北西北' + eastText = '北北東' + southText = '東南東' + westText = '南南西' + } else if (compass === 90) { + // 동(북) + // 서(남) + // 남(동) + // 북(서) + eastText = '北' + westText = '南' + southText = '東' + northText = '西' + } else if (compass < 135) { + // 남,서,북 가능 + // 동(북북서) + // 서(남남동) + // 남(동북동) + // 북(서남서) + eastText = '北北西' + westText = '南南東' + southText = '東北東' + northText = '西南西' + } else if (compass === 135) { + // 서,북 가능 + + // 서(남동) + // 북(남서) + // 남(북동) + // 동(북서) + + westText = '南東' + northText = '南西' + southText = '北東' + eastText = '北西' + } else if (compass < 180) { + // 북,동,서 가능 + // 북(남남서) + // 동(서북서) + // 남(북북동) + // 서(동남동) + + northText = '南南西' + eastText = '西北西' + southText = '北北東' + westText = '東南東' + } else if (compass === 180) { + // 북,동,서 가능 + // 북(남) + // 동(서) + // 남(북) + // 서(동) + northText = '南' + eastText = '西' + southText = '北' + westText = '東' + } else if (compass < 225) { + // 서,북,동 가능 + // 북(남남동) + // 동(서남서) + // 남(북북서) + // 서(동남동) + northText = '南南東' + eastText = '西南西' + southText = '北北西' + westText = '東南東' + } else if (compass === 225) { + // 북,동 가능 + // 북(남동) + // 동(남서) + // 남(북서) + // 서(북동) + northText = '南東' + eastText = '南西' + southText = '北西' + westText = '北東' + } else if (compass < 270) { + // 북동남 가능 + // 북(동남동) + // 동(남남서) + // 남(서북서) + // 서(북북동) + northText = '東南東' + eastText = '南南西' + southText = '西北西' + westText = '北北東' + } else if (compass === 270) { + // 북동남 가능 + // 북(동) + // 동(남) + // 남(서) + // 서(북) + northText = '東' + eastText = '南' + southText = '西' + westText = '北' + } else if (compass < 315) { + // 북,동,남 가능 + // 북(동북동) + // 동(남남동) + // 남(서남서) + // 서(북북서) + northText = '東北東' + eastText = '南南東' + southText = '西南西' + westText = '北北西' + } else if (compass === 315) { + // 동,남 가능 + // 북(북동) + // 동(남동) + // 남(남서) + // 서(북서) + northText = '北東' + eastText = '南東' + southText = '南西' + westText = '北西' + } else if (compass < 360) { + // 남,동,서 가능 + // 북(북북동) + // 동(동남동) + // 남(남남서) + // 서(서북서) + northText = '北北東' + eastText = '東南東' + southText = '南南西' + westText = '西北西' + } + + clearDirectionText(canvas) + + addTextByArrows(eastArrows, eastText, canvas) + addTextByArrows(westArrows, westText, canvas) + addTextByArrows(northArrows, northText, canvas) + addTextByArrows(southArrows, southText, canvas) +} + +const clearDirectionText = (canvas) => { + const texts = canvas.getObjects().filter((obj) => obj.name === 'directionText') + texts.forEach((text) => { + canvas.remove(text) + }) +} + +const addTextByArrows = (arrows, txt, canvas) => { + arrows.forEach((arrow, index) => { + const text = new fabric.Text(`${txt}${index + 1}`, { + fontSize: arrow.parent.fontSize, + fill: 'black', + originX: 'center', + originY: 'center', + name: 'directionText', + left: arrow.stickeyPoint.x, + top: arrow.stickeyPoint.y, + }) + canvas.add(text) + }) +} From 70aeaa2957d897e7c50152c8a340df32ac084ac7 Mon Sep 17 00:00:00 2001 From: "hyojun.choi" Date: Thu, 5 Sep 2024 14:40:02 +0900 Subject: [PATCH 25/34] =?UTF-8?q?mouseout=20=EC=B4=88=EA=B8=B0=EC=85=8B?= =?UTF-8?q?=ED=8C=85=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/hooks/useMode.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/hooks/useMode.js b/src/hooks/useMode.js index fe88c39c..b4d1e398 100644 --- a/src/hooks/useMode.js +++ b/src/hooks/useMode.js @@ -81,6 +81,8 @@ export function useMode() { // } if (!canvas) return setCanvas(canvas) + canvas?.off('mouse:out', removeMouseLines) + canvas?.on('mouse:out', removeMouseLines) canvas?.off('mouse:move') canvas?.on('mouse:move', drawMouseLines) }, [canvas, zoom]) // 빈 배열을 전달하여 컴포넌트가 마운트될 때만 실행되도록 함 From dcdbb626f79b08ff808d057d9d28e4e88149c774 Mon Sep 17 00:00:00 2001 From: yoosangwook Date: Fri, 6 Sep 2024 10:19:31 +0900 Subject: [PATCH 26/34] Refactor file upload and image handling in Playground and Roof2 components --- src/app/api/html2canvas/route.js | 28 ++++++++++++++++++++++++++++ src/components/Playground.jsx | 32 ++++++++++++++++++++++++++------ src/components/Roof2.jsx | 20 ++++++++++++++++---- src/hooks/useCanvas.js | 4 ++-- src/store/canvasAtom.js | 11 +++++++++++ 5 files changed, 83 insertions(+), 12 deletions(-) create mode 100644 src/app/api/html2canvas/route.js diff --git a/src/app/api/html2canvas/route.js b/src/app/api/html2canvas/route.js new file mode 100644 index 00000000..c1e6284d --- /dev/null +++ b/src/app/api/html2canvas/route.js @@ -0,0 +1,28 @@ +'use server' + +import fs from 'fs/promises' + +import { NextResponse } from 'next/server' + +export async function GET(req) { + const path = 'public/mapImages' + const q = req.nextUrl.searchParams.get('q') + const fileNm = req.nextUrl.searchParams.get('fileNm') + const targetUrl = `https://maps.googleapis.com/maps/api/staticmap?center=${q}&zoom=21&maptype=satellite&size=750x750&scale=2&key=AIzaSyDO7nVR1N_D2tKy60hgGFavpLaXkHpiHpc` + const decodeUrl = decodeURIComponent(targetUrl) + + const response = await fetch(decodeUrl) + + const data = await response.arrayBuffer() + const buffer = Buffer.from(data) + + try { + await fs.readdir(path) + } catch { + await fs.mkdir(path) + } finally { + await fs.writeFile(`${path}/${fileNm}.png`, buffer) + } + + return NextResponse.json({ fileNm: `${fileNm}.png` }) +} diff --git a/src/components/Playground.jsx b/src/components/Playground.jsx index 624113de..46560aca 100644 --- a/src/components/Playground.jsx +++ b/src/components/Playground.jsx @@ -1,25 +1,28 @@ 'use client' import { useRef, useState } from 'react' -import { Button } from '@nextui-org/react' -import ColorPicker from './common/color-picker/ColorPicker' +import { useRecoilState } from 'recoil' +import { v4 as uuidv4 } from 'uuid' import { useAxios } from '@/hooks/useAxios' import { useMessage } from '@/hooks/useMessage' import { convertDwgToPng } from '@/lib/cadAction' -// import { get } from '@/lib/Axios' +import { cadFileNameState, googleMapFileNameState, useCadFileState, useGoogleMapFileState } from '@/store/canvasAtom' import QSelect from '@/components/ui/QSelect' +import { Button } from '@nextui-org/react' +import ColorPicker from './common/color-picker/ColorPicker' +import { toastUp } from '@/hooks/useToast' import styles from './playground.module.css' -import { useRecoilState } from 'recoil' -import { cadFileNameState, useCadFileState } from '@/store/canvasAtom' -import { toastUp } from '@/hooks/useToast' export default function Playground() { const [useCadFile, setUseCadFile] = useRecoilState(useCadFileState) const [cadFileName, setCadFileName] = useRecoilState(cadFileNameState) + const [useGoogleMapFile, setUseGoogleMapFile] = useRecoilState(useGoogleMapFileState) + const [googleMapFileName, setGoogleMapFileName] = useRecoilState(googleMapFileNameState) const fileRef = useRef(null) + const queryRef = useRef(null) const { get, promisePost } = useAxios() const testVar = process.env.NEXT_PUBLIC_TEST const converterUrl = process.env.NEXT_PUBLIC_CONVERTER_API_URL @@ -56,6 +59,15 @@ export default function Playground() { }) } + const handleDownImage = async () => { + setUseGoogleMapFile(true) + const queryString = queryRef.current.value === '' ? '서울시 서대문구 연세로5다길 22-3 발리빌라 3층' : queryRef.current.value + const res = await get({ url: `http://localhost:3000/api/html2canvas?q=${queryString}&fileNm=${uuidv4()}` }) + console.log('res', res) + setGoogleMapFileName(res.fileNm) + toastUp({ message: '이미지 저장 완료', type: 'success' }) + } + const data = [ { id: 1, @@ -99,11 +111,19 @@ export default function Playground() {
    {color}
    +

    캐드 파일 이미지 사용

    +
    +

    구글 맵 이미지 사용

    + +
    + +
    +
    ) diff --git a/src/components/Roof2.jsx b/src/components/Roof2.jsx index ecbc083b..670f58c4 100644 --- a/src/components/Roof2.jsx +++ b/src/components/Roof2.jsx @@ -16,11 +16,13 @@ import { currentObjectState, fontSizeState, globalCompassState, + googleMapFileNameState, roofMaterialState, roofState, sortedPolygonArray, templateTypeState, useCadFileState, + useGoogleMapFileState, wallState, } from '@/store/canvasAtom' import { QLine } from '@/components/fabric/QLine' @@ -49,7 +51,7 @@ export default function Roof2(props) { setCanvasBackgroundWithDots, saveImage, addCanvas, - handleCadImageLoad, + handleBackImageLoadToCanvas, handleCadImageInit, backImg, setBackImg, @@ -99,13 +101,18 @@ export default function Roof2(props) { canvas, } + let imgPath // cad 파일 업로드 const [useCadFile, setUseCadFile] = useRecoilState(useCadFileState) const [cadFileName, setCadFileName] = useRecoilState(cadFileNameState) const [cadFileComplete, setCadFileComplete] = useRecoilState(cadFileCompleteState) - let imgPath useCadFile && (imgPath = `/cadImages/${cadFileName}`) + // 구글맵 이미지 업로드 + const [useGoogleMapFile, setUseGoogleMapFile] = useRecoilState(useGoogleMapFileState) + const [googleMapFileName, setGoogleMapFileName] = useRecoilState(googleMapFileNameState) + useGoogleMapFile && (imgPath = `/mapImages/${googleMapFileName}`) + const [globalCampass, setGlobalCampass] = useRecoilState(globalCompassState) const { @@ -157,7 +164,11 @@ export default function Roof2(props) { if (!cadFileComplete && useCadFile) { // cad 파일 로드 - useCadFile && handleCadImageLoad(imgPath, canvas) + useCadFile && handleBackImageLoadToCanvas(imgPath, canvas) + } + + if (useGoogleMapFile) { + handleBackImageLoadToCanvas(imgPath, canvas) } }, [canvas, mode]) @@ -812,6 +823,7 @@ export default function Roof2(props) { backImg .set({ selectable: false, + opacity: 0.7, }) .sendToBack() canvas.clear() @@ -821,7 +833,7 @@ export default function Roof2(props) { } }} > - cad 파일 조정 완료 + 배경 이미지 조정 완료
    + {useGoogleMapFile && ( + <> +
    +

    Zoom Controller : {zoom}

    + + +
    +
    + +
    + + )}
    diff --git a/yarn.lock b/yarn.lock index 1a73ec7a..6bd3608f 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5515,6 +5515,11 @@ react-dom@^18: loose-envify "^1.1.0" scheduler "^0.23.2" +react-icons@^5.3.0: + version "5.3.0" + resolved "https://registry.yarnpkg.com/react-icons/-/react-icons-5.3.0.tgz#ccad07a30aebd40a89f8cfa7d82e466019203f1c" + integrity sha512-DnUk8aFbTyQPSkCfF8dbX6kQjXA9DktMeJqfjrg6cK9vwQVMxmcA3BfP4QoiztVmEHtwlTgLFsPuH2NskKT6eg== + react-is@^16.13.1: version "16.13.1" resolved "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz" From 2852e5eb1d4214e11d046f7ec27733266790bc1f Mon Sep 17 00:00:00 2001 From: yoosangwook Date: Mon, 9 Sep 2024 10:10:13 +0900 Subject: [PATCH 29/34] feat: Add floor plan page and component --- src/app/[locale]/floor-plan/page.jsx | 5 +++++ src/components/floor-plan/FloorPlan.jsx | 7 +++++++ 2 files changed, 12 insertions(+) create mode 100644 src/app/[locale]/floor-plan/page.jsx create mode 100644 src/components/floor-plan/FloorPlan.jsx diff --git a/src/app/[locale]/floor-plan/page.jsx b/src/app/[locale]/floor-plan/page.jsx new file mode 100644 index 00000000..7ca0fc3e --- /dev/null +++ b/src/app/[locale]/floor-plan/page.jsx @@ -0,0 +1,5 @@ +import FloorPlan from '@/components/floor-plan/FloorPlan' + +export default function floorPlanPage() { + return +} diff --git a/src/components/floor-plan/FloorPlan.jsx b/src/components/floor-plan/FloorPlan.jsx new file mode 100644 index 00000000..27e03cf6 --- /dev/null +++ b/src/components/floor-plan/FloorPlan.jsx @@ -0,0 +1,7 @@ +export default function FloorPlan() { + return ( + <> +

    도면 작성 페이지

    + + ) +} From 958a8888c3d3f8c5e55a38d8c96954ea2b16ea74 Mon Sep 17 00:00:00 2001 From: "hyojun.choi" Date: Mon, 9 Sep 2024 11:03:30 +0900 Subject: [PATCH 30/34] =?UTF-8?q?=EC=98=A4=EB=B8=8C=EC=A0=9D=ED=8A=B8=20?= =?UTF-8?q?=EB=B0=B0=EC=B9=98=20=EB=AA=A8=EB=93=9C=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/common/common.js | 2 + src/components/Roof2.jsx | 10 ++ src/components/ui/ObjectPlacement.jsx | 155 ++++++++++++++++++++++++ src/hooks/useMode.js | 164 +++++++++++++++++++++++++- src/store/canvasAtom.js | 12 ++ 5 files changed, 339 insertions(+), 4 deletions(-) create mode 100644 src/components/ui/ObjectPlacement.jsx diff --git a/src/common/common.js b/src/common/common.js index 91a9583a..b1cca49e 100644 --- a/src/common/common.js +++ b/src/common/common.js @@ -12,6 +12,8 @@ export const Mode = { CELL_POWERCON: 'cellPowercon', //파워콘 DRAW_HELP_LINE: 'drawHelpLine', // 보조선 그리기 모드 지붕 존재해야함 ADSORPTION_POINT: 'adsorptionPoint', //흡착점 모드 + OPENING: 'opening', //개구 모드 + SHADOW: 'shadow', //그림자 생성 모드 DEFAULT: 'default', } diff --git a/src/components/Roof2.jsx b/src/components/Roof2.jsx index ecbc083b..d4ae8c1e 100644 --- a/src/components/Roof2.jsx +++ b/src/components/Roof2.jsx @@ -39,6 +39,7 @@ import GridSettingsModal from './GridSettingsModal' import { SurfaceShapeModal } from '@/components/ui/SurfaceShape' import { drawDirectionStringToArrow } from '@/util/qpolygon-utils' import ThumbnailList from '@/components/ui/ThumbnailLIst' +import ObjectPlacement from '@/components/ui/ObjectPlacement' export default function Roof2(props) { const { name, userId, email, isLoggedIn } = props @@ -753,6 +754,15 @@ export default function Roof2(props) { > 면형상 + {/**/} diff --git a/src/components/ui/ObjectPlacement.jsx b/src/components/ui/ObjectPlacement.jsx new file mode 100644 index 00000000..7bb10f14 --- /dev/null +++ b/src/components/ui/ObjectPlacement.jsx @@ -0,0 +1,155 @@ +import React, { useCallback, useEffect, useRef, useState } from 'react' +import { Button, Input } from '@nextui-org/react' +import { useRecoilState, useSetRecoilState } from 'recoil' +import { modalState } from '@/store/modalAtom' +import { fabric } from 'fabric' +import { QPolygon } from '@/components/fabric/QPolygon' +import { modeState, objectPlacementModeState } from '@/store/canvasAtom' + +const BATCH_TYPE = { + OPENING: 'opening', + SHADOW: 'shadow', +} + +const INPUT_TYPE = { + FREE: 'free', + DIMENSION: 'dimension', +} + +const ObjectPlacement = ({ canvas }) => { + const [open, setOpen] = useRecoilState(modalState) + const [mode, setMode] = useRecoilState(modeState) + const [objectPlacementMode, setObjectPlacementModeState] = useRecoilState(objectPlacementModeState) + const [width, setWidth] = useState(0) + const [height, setHeight] = useState(0) + const [areaBoundary, setAreaBoundary] = useState(true) + + // opening or shadow 개구 / 그림자 + const [batchType, setBatchType] = useState(BATCH_TYPE.OPENING) + + // free or dimension 프리 / 치수 + const [inputType, setInputType] = useState(INPUT_TYPE.FREE) + + const handleSave = () => { + setMode(batchType) + setOpen(false) + } + + return ( +
    +
    + +
    + +
    +

    개구 · 그림자 배치

    +
    + +
    +
    + + +
    +
    + +
    +
    설정
    + +
    + +
    + +
    + +
    + +
    +
    + + { + setObjectPlacementModeState({ ...objectPlacementMode, width: e.target.value }) + }} + /> +
    + +
    + + { + setObjectPlacementModeState({ ...objectPlacementMode, height: e.target.value }) + }} + /> +
    +
    + +
    + +
    + +
    + +
    +
    +
    + ) +} + +export default ObjectPlacement diff --git a/src/hooks/useMode.js b/src/hooks/useMode.js index b4d1e398..f575e954 100644 --- a/src/hooks/useMode.js +++ b/src/hooks/useMode.js @@ -27,6 +27,7 @@ import { guideLineState, horiGuideLinesState, vertGuideLinesState, + objectPlacementModeState, } from '@/store/canvasAtom' import { QLine } from '@/components/fabric/QLine' import { fabric } from 'fabric' @@ -74,6 +75,8 @@ export function useMode() { const [horiGuideLines, setHoriGuideLines] = useRecoilState(horiGuideLinesState) const [vertGuideLines, setVertGuideLines] = useRecoilState(vertGuideLinesState) + const [objectPlacementMode, setObjectPlacementModeState] = useRecoilState(objectPlacementModeState) + useEffect(() => { // if (!canvas) { // canvas?.setZoom(0.8) @@ -104,11 +107,7 @@ export function useMode() { }, [endPoint]) useEffect(() => { - canvas?.off('mouse:out', removeMouseLines) - canvas?.on('mouse:out', removeMouseLines) changeMode(canvas, mode) - canvas?.off('mouse:move') - canvas?.on('mouse:move', drawMouseLines) }, [mode, horiGuideLines, vertGuideLines]) useEffect(() => { @@ -423,6 +422,17 @@ export function useMode() { break case 'adsorptionPoint': canvas?.on('mouse:down', mouseEvent.adsorptionPoint) + break + case 'shadow': + canvas?.on('mouse:down', mouseEvent.shadowMode.down) + canvas?.on('mouse:move', mouseEvent.shadowMode.move) + canvas?.on('mouse:up', mouseEvent.shadowMode.up) + break + case 'opening': + canvas?.on('mouse:down', mouseEvent.openingMode.down) + canvas?.on('mouse:move', mouseEvent.openingMode.move) + canvas?.on('mouse:up', mouseEvent.openingMode.up) + break case 'default': canvas?.off('mouse:down') @@ -587,6 +597,9 @@ export function useMode() { const mouseAndkeyboardEventClear = () => { canvas?.off('mouse:down') + canvas?.off('mouse:move') + canvas?.off('mouse:up') + canvas?.off('mouse:out') Object.keys(mouseEvent).forEach((key) => { canvas?.off('mouse:down', mouseEvent[key]) document.removeEventListener('contextmenu', mouseEvent[key]) @@ -682,6 +695,9 @@ export function useMode() { changeMouseEvent(mode) changeKeyboardEvent(mode) + canvas?.on('mouse:move', drawMouseLines) + canvas?.on('mouse:out', removeMouseLines) + switch (mode) { case 'template': templateMode() @@ -992,6 +1008,146 @@ export function useMode() { canvas.add(circle) canvas.renderAll() }, + //면 형상 배치 모드 + surfaceShapeMode: (o) => {}, + // 그림자 모드 + shadowMode: { + rect: null, + isDown: false, + origX: 0, + origY: 0, + down: (o) => { + if (mode !== Mode.SHADOW) return + mouseEvent.shadowMode.isDown = true + const pointer = canvas.getPointer(o.e) + mouseEvent.shadowMode.origX = pointer.x + mouseEvent.shadowMode.origY = pointer.y + mouseEvent.shadowMode.rect = new fabric.Rect({ + fill: 'grey', + left: mouseEvent.shadowMode.origX, + top: mouseEvent.shadowMode.origY, + originX: 'left', + originY: 'top', + opacity: 0.3, + width: 0, + height: 0, + angle: 0, + transparentCorners: false, + }) + canvas.add(mouseEvent.shadowMode.rect) + }, + move: (e) => { + if (!mouseEvent.shadowMode.isDown) return + const pointer = canvas.getPointer(e.e) + if (mouseEvent.shadowMode.origX > pointer.x) { + mouseEvent.shadowMode.rect.set({ left: Math.abs(pointer.x) }) + } + if (mouseEvent.shadowMode.origY > pointer.y) { + mouseEvent.shadowMode.rect.set({ top: Math.abs(pointer.y) }) + } + + mouseEvent.shadowMode.rect.set({ width: Math.abs(mouseEvent.shadowMode.origX - pointer.x) }) + mouseEvent.shadowMode.rect.set({ height: Math.abs(mouseEvent.shadowMode.origY - pointer.y) }) + }, + up: (o) => { + mouseEvent.shadowMode.isDown = false + setMode(Mode.DEFAULT) + }, + }, + openingMode: { + rect: null, + isDown: false, + origX: 0, + origY: 0, + down: (o) => { + if (mode !== Mode.OPENING) return + mouseEvent.openingMode.isDown = true + const pointer = canvas.getPointer(o.e) + mouseEvent.openingMode.origX = pointer.x + mouseEvent.openingMode.origY = pointer.y + mouseEvent.openingMode.rect = new fabric.Rect({ + fill: 'white', + stroke: 'black', + strokeWidth: 1, + left: mouseEvent.openingMode.origX, + top: mouseEvent.openingMode.origY, + originX: 'left', + originY: 'top', + width: pointer.x - mouseEvent.openingMode.origX, + height: pointer.y - mouseEvent.openingMode.origY, + angle: 0, + transparentCorners: false, + }) + canvas.add(mouseEvent.openingMode.rect) + }, + move: (e) => { + if (!mouseEvent.openingMode.isDown) return + const pointer = canvas.getPointer(e.e) + if (mouseEvent.openingMode.origX > pointer.x) { + mouseEvent.openingMode.rect.set({ left: Math.abs(pointer.x) }) + } + if (mouseEvent.openingMode.origY > pointer.y) { + mouseEvent.openingMode.rect.set({ top: Math.abs(pointer.y) }) + } + + mouseEvent.openingMode.rect.set({ width: Math.abs(mouseEvent.openingMode.origX - pointer.x) }) + mouseEvent.openingMode.rect.set({ height: Math.abs(mouseEvent.openingMode.origY - pointer.y) }) + }, + up: (o) => { + mouseEvent.openingMode.isDown = false + + const { areaBoundary } = objectPlacementMode + + //roof의 내부에 있는지 확인 + if (!checkInsideRoof(mouseEvent.openingMode.rect)) { + setMode(Mode.DEFAULT) + } + + // 영역 교차인지 확인 + if (!areaBoundary) { + const isCross = checkCrossAreaBoundary(mouseEvent.openingMode.rect) + if (isCross) { + alert('영역이 교차되었습니다.') + canvas.remove(mouseEvent.openingMode.rect) + } + } + + mouseEvent.openingMode.rect.set({ name: 'opening' }) + }, + }, + } + + const checkCrossAreaBoundary = (rect) => { + const openings = canvas?._objects.filter((obj) => obj.name === 'opening') + if (openings.length === 0) { + return false + } + + for (let i = 0; i < openings.length; i++) { + const rect2 = openings[i] + // Check if one rectangle is to the left of the other + if (rect.x + rect.width <= rect2.x || rect2.x + rect2.width <= rect.x) { + return true + } + + // Check if one rectangle is above the other + if (rect.y + rect.height <= rect2.y || rect2.y + rect2.height <= rect.y) { + return true + } + } + + return false + } + + const checkInsideRoof = (rect) => { + let result = true + const roofs = canvas?._objects.filter((obj) => obj.name === 'roof') + if (roofs.length === 0) { + alert('지붕을 먼저 그려주세요') + canvas?.remove(rect) + return false + } + return result } const getInterSectPointByMouseLine = () => { diff --git a/src/store/canvasAtom.js b/src/store/canvasAtom.js index a675b508..d5720ca7 100644 --- a/src/store/canvasAtom.js +++ b/src/store/canvasAtom.js @@ -150,3 +150,15 @@ export const globalCompassState = atom({ default: 0, dangerouslyAllowMutability: true, }) + +// 면형상 배치 모드 +export const surfacePlacementModeState = atom({ + key: 'surfacePlacementMode', + default: { width: 0, height: 0, areaBoundary: true, inputType: 'free' }, +}) + +// 오브젝트 배치 모드 +export const objectPlacementModeState = atom({ + key: 'objectPlacementMode', + default: { width: 0, height: 0, areaBoundary: true, inputType: 'free', batchType: 'opening' }, +}) From 38754db30d33fe34ef7aae4ff7f5019477a4c9d9 Mon Sep 17 00:00:00 2001 From: "hyojun.choi" Date: Mon, 9 Sep 2024 11:05:44 +0900 Subject: [PATCH 31/34] =?UTF-8?q?=EB=AA=A8=EB=93=A0=20=EB=AA=A8=EB=93=9C?= =?UTF-8?q?=EC=97=90=EC=84=9C=20=EC=82=AC=EC=9A=A9=EB=90=98=EB=8A=94=20?= =?UTF-8?q?=EA=B3=B5=ED=86=B5=20=EC=9D=B4=EB=B2=A4=ED=8A=B8=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/hooks/useMode.js | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/hooks/useMode.js b/src/hooks/useMode.js index f575e954..46709a76 100644 --- a/src/hooks/useMode.js +++ b/src/hooks/useMode.js @@ -600,10 +600,6 @@ export function useMode() { canvas?.off('mouse:move') canvas?.off('mouse:up') canvas?.off('mouse:out') - Object.keys(mouseEvent).forEach((key) => { - canvas?.off('mouse:down', mouseEvent[key]) - document.removeEventListener('contextmenu', mouseEvent[key]) - }) Object.keys(keyboardEvent).forEach((key) => { document.removeEventListener('keydown', keyboardEvent[key]) @@ -687,6 +683,7 @@ export function useMode() { const changeMode = (canvas, mode) => { mouseAndkeyboardEventClear() + addCommonMouseEvent() setMode(mode) setCanvas(canvas) @@ -695,9 +692,6 @@ export function useMode() { changeMouseEvent(mode) changeKeyboardEvent(mode) - canvas?.on('mouse:move', drawMouseLines) - canvas?.on('mouse:out', removeMouseLines) - switch (mode) { case 'template': templateMode() @@ -729,6 +723,12 @@ export function useMode() { } } + // 모든 모드에서 사용되는 공통 이벤트 추가 + const addCommonMouseEvent = () => { + canvas?.on('mouse:move', drawMouseLines) + canvas?.on('mouse:out', removeMouseLines) + } + const changeKeyboardEvent = (mode) => { if (mode === Mode.EDIT) { switch (mode) { From b81d69589830d495e3d55f84831817497f69e603 Mon Sep 17 00:00:00 2001 From: "hyojun.choi" Date: Mon, 9 Sep 2024 12:37:27 +0900 Subject: [PATCH 32/34] =?UTF-8?q?polygon=20=EC=9D=B4=EB=8F=99=20=EC=8B=9C?= =?UTF-8?q?=20=EB=AC=B6=EC=97=AC=EC=9E=88=EB=8A=94=20arrow=EB=8F=84=20?= =?UTF-8?q?=EC=9E=AC=20=EC=83=9D=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/fabric/QPolygon.js | 3 +++ src/hooks/useMode.js | 44 +++++++++++++++++++++++-------- src/store/canvasAtom.js | 2 +- src/util/qpolygon-utils.js | 21 ++++++++++----- 4 files changed, 52 insertions(+), 18 deletions(-) diff --git a/src/components/fabric/QPolygon.js b/src/components/fabric/QPolygon.js index b03a593d..1708c8d3 100644 --- a/src/components/fabric/QPolygon.js +++ b/src/components/fabric/QPolygon.js @@ -127,6 +127,9 @@ export const QPolygon = fabric.util.createClass(fabric.Polygon, { this.on('modified', (e) => { this.addLengthText() + if (this.arrow) { + drawDirectionArrow(this) + } }) this.on('selected', () => { diff --git a/src/hooks/useMode.js b/src/hooks/useMode.js index 46709a76..6639512b 100644 --- a/src/hooks/useMode.js +++ b/src/hooks/useMode.js @@ -32,7 +32,7 @@ import { import { QLine } from '@/components/fabric/QLine' import { fabric } from 'fabric' import { QPolygon } from '@/components/fabric/QPolygon' -import offsetPolygon from '@/util/qpolygon-utils' +import offsetPolygon, { inPolygon } from '@/util/qpolygon-utils' import { isObjectNotEmpty } from '@/util/common-utils' import * as turf from '@turf/turf' import { Mode } from '@/common/common' @@ -1061,8 +1061,25 @@ export function useMode() { origY: 0, down: (o) => { if (mode !== Mode.OPENING) return - mouseEvent.openingMode.isDown = true + const roofs = canvas?._objects.filter((obj) => obj.name === 'roof') + if (roofs.length === 0) { + alert('지붕을 먼저 그려주세요') + setMode(Mode.DEFAULT) + return + } const pointer = canvas.getPointer(o.e) + let selectRoof = null + roofs.forEach((roof) => { + if (roof.inPolygon({ x: pointer.x, y: pointer.y })) { + selectRoof = roof + } + }) + if (!selectRoof) { + alert('지붕 내부에만 생성 가능합니다.') + return + } + mouseEvent.openingMode.isDown = true + mouseEvent.openingMode.origX = pointer.x mouseEvent.openingMode.origY = pointer.y mouseEvent.openingMode.rect = new fabric.Rect({ @@ -1123,17 +1140,21 @@ export function useMode() { return false } + const rectPoints = [ + { x: rect.left, y: rect.top }, + { x: rect.left, y: rect.top + rect.height }, + { x: rect.left + rect.width, y: rect.top + rect.height }, + { x: rect.left + rect.width, y: rect.top }, + ] + for (let i = 0; i < openings.length; i++) { const rect2 = openings[i] - // Check if one rectangle is to the left of the other - if (rect.x + rect.width <= rect2.x || rect2.x + rect2.width <= rect.x) { - return true - } - - // Check if one rectangle is above the other - if (rect.y + rect.height <= rect2.y || rect2.y + rect2.height <= rect.y) { - return true - } + const rect2Points = [ + { x: rect2.left, y: rect2.top }, + { x: rect2.left, y: rect2.top + rect2.height }, + { x: rect2.left + rect2.width, y: rect2.top + rect2.height }, + { x: rect2.left + rect2.width, y: rect2.top }, + ] } return false @@ -1147,6 +1168,7 @@ export function useMode() { canvas?.remove(rect) return false } + return result } diff --git a/src/store/canvasAtom.js b/src/store/canvasAtom.js index 24697a02..ae020901 100644 --- a/src/store/canvasAtom.js +++ b/src/store/canvasAtom.js @@ -171,5 +171,5 @@ export const surfacePlacementModeState = atom({ // 오브젝트 배치 모드 export const objectPlacementModeState = atom({ key: 'objectPlacementMode', - default: { width: 0, height: 0, areaBoundary: true, inputType: 'free', batchType: 'opening' }, + default: { width: 0, height: 0, areaBoundary: false, inputType: 'free', batchType: 'opening' }, }) diff --git a/src/util/qpolygon-utils.js b/src/util/qpolygon-utils.js index 5e00b197..8d8a28ec 100644 --- a/src/util/qpolygon-utils.js +++ b/src/util/qpolygon-utils.js @@ -2714,6 +2714,12 @@ export const drawDirectionArrow = (polygon) => { if (!direction) { return } + + polygon.canvas + .getObjects() + .filter((obj) => obj.name === 'directionText' && obj.parent === polygon.arrow) + .forEach((obj) => polygon.canvas.remove(obj)) + let arrow = null let points = [] @@ -2721,13 +2727,13 @@ export const drawDirectionArrow = (polygon) => { polygon.canvas.remove(polygon.arrow) } - let centerPoint = polygon.getCenterPoint() + let centerPoint = { x: polygon.width / 2 + polygon.left, y: polygon.height / 2 + polygon.top } let stickeyPoint - const polygonMaxX = Math.max(...polygon.points.map((point) => point.x)) - const polygonMinX = Math.min(...polygon.points.map((point) => point.x)) - const polygonMaxY = Math.max(...polygon.points.map((point) => point.y)) - const polygonMinY = Math.min(...polygon.points.map((point) => point.y)) + const polygonMaxX = Math.max(...polygon.getCurrentPoints().map((point) => point.x)) + const polygonMinX = Math.min(...polygon.getCurrentPoints().map((point) => point.x)) + const polygonMaxY = Math.max(...polygon.getCurrentPoints().map((point) => point.y)) + const polygonMinY = Math.min(...polygon.getCurrentPoints().map((point) => point.y)) switch (direction) { case 'north': @@ -2800,6 +2806,7 @@ export const drawDirectionArrow = (polygon) => { polygon.arrow = arrow polygon.canvas.add(arrow) polygon.canvas.renderAll() + drawDirectionStringToArrow(polygon.canvas, 0) } /** @@ -2807,7 +2814,7 @@ export const drawDirectionArrow = (polygon) => { * @param canvas * @param compass */ -export const drawDirectionStringToArrow = (canvas, compass, fontSize) => { +export const drawDirectionStringToArrow = (canvas, compass = 0) => { const arrows = canvas?.getObjects().filter((obj) => obj.name === 'arrow') if (arrows.length === 0) { @@ -3000,8 +3007,10 @@ const addTextByArrows = (arrows, txt, canvas) => { originX: 'center', originY: 'center', name: 'directionText', + selectable: false, left: arrow.stickeyPoint.x, top: arrow.stickeyPoint.y, + parent: arrow, }) canvas.add(text) }) From 4d34dabe0e16d60ca67f35935bdb5c3a69b67260 Mon Sep 17 00:00:00 2001 From: "hyojun.choi" Date: Mon, 9 Sep 2024 13:19:32 +0900 Subject: [PATCH 33/34] =?UTF-8?q?QPolygon=EC=A0=9C=EA=B1=B0=20=EC=8B=9C=20?= =?UTF-8?q?=EC=97=AE=EC=97=AC=EC=9E=88=EB=8A=94=20=ED=99=94=EC=82=B4?= =?UTF-8?q?=ED=91=9C=EC=99=80=20=ED=99=94=EC=82=B4=ED=91=9C=20=EB=B0=A9?= =?UTF-8?q?=ED=96=A5=20=ED=85=8D=EC=8A=A4=ED=8A=B8=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/fabric/QPolygon.js | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/components/fabric/QPolygon.js b/src/components/fabric/QPolygon.js index 1708c8d3..3c8b2148 100644 --- a/src/components/fabric/QPolygon.js +++ b/src/components/fabric/QPolygon.js @@ -147,6 +147,17 @@ export const QPolygon = fabric.util.createClass(fabric.Polygon, { this.canvas.remove(text) }) this.texts = null + + if (this.arrow) { + this.canvas.remove(this.arrow) + this.canvas + .getObjects() + .filter((obj) => obj.name === 'directionText' && obj.parent === this.arrow) + .forEach((text) => { + this.canvas.remove(text) + }) + this.arrow = null + } }) // polygon.fillCell({ width: 50, height: 30, padding: 10 }) From be5731b92584e7fcd19f3602caf4e4238a412c10 Mon Sep 17 00:00:00 2001 From: leeyongjae Date: Mon, 9 Sep 2024 14:19:11 +0900 Subject: [PATCH 34/34] =?UTF-8?q?[=EB=A9=94=EC=8B=9C=EC=A7=80]=20=EA=B3=B5?= =?UTF-8?q?=ED=86=B5=20=EB=A9=94=EC=8B=9C=EC=A7=80=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/locales/ja.json | 89 ++++++++++++++++++++++++++++++++++++++++++++- src/locales/ko.json | 89 ++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 176 insertions(+), 2 deletions(-) diff --git a/src/locales/ja.json b/src/locales/ja.json index a1725dfd..146bb78a 100644 --- a/src/locales/ja.json +++ b/src/locales/ja.json @@ -1,3 +1,90 @@ { - "hi": "こんにちは" + "hi": "こんにちは", + "common.message.no.data": "No data", + "common.message.no.dataDown": "ダウンロードするデータがありません", + "common.message.noData": "表示するデータがありません", + "common.message.search": "search success", + "common.message.insert": "insert success", + "common.message.update": "update success", + "common.message.delete": "削除", + "common.message.restoration": "復元", + "common.message.cancel": "キャンセル", + "common.message.send": "メールを送信しました.", + "common.message.no.delete": "削除するデータがありません", + "common.message.save": "保存", + "common.message.transfer": "転送", + "common.message.batch.exec": "batch success", + "common.message.not.mov": "移動できません.", + "common.message.required.data": "{0} は入力必須項目となります。", + "common.message.save.error": "データの保存中にエラーが発生しました。 サイト管理者にお問い合わせください。", + "common.message.transfer.error": "データの転送中にエラーが発生しました。 サイト管理者にお問い合わせください。", + "common.message.delete.error": "データの削除中にエラーが発生しました。 サイト管理者にお問い合わせください。", + "common.message.batch.error": "バッチの実行中にエラーが発生しました。 サイト管理者に連絡してください。", + "common.message.send.error": "データの送信中にエラーが発生しました。サイト管理者にお問い合わせください", + "common.message.communication.error": "ネットワークエラーが発生しました。サイト管理者に連絡してください。", + "common.message.data.error": "{0} はデータ形式が無効です。", + "common.message.data.setting.error": "{0} は削除されたか、すでに構成されているデータです。", + "common.message.parameter.error": "パラメータエラー", + "common.message.product.parameter.error": "存在しない製品があります。", + "common.message.customer.parameter.error": "存在しない顧客があります。", + "common.message.file.exists.error": "ファイルが正常にアップロードされないためにエラーが発生しました", + "common.message.file.download.exists": "ファイルが存在しません。", + "common.message.file.download.error": "ァイルのダウンロードエラー", + "common.message.file.template.validation01": "フォルダをアップロードできません", + "common.message.file.template.validation02": "アップロードできるのはExcelファイルのみです。", + "common.message.file.template.validation03": "登録できない拡張子です", + "common.message.file.template.validation04": "容量を超えています アップロード可能な容量:{0} MB", + "common.message.file.template.validation05": "アップロードファイルを選択して下さい", + "common.message.multi.insert": "合計 {0} 件数 ({1}成功、 {2} 失敗 {3})", + "common.message.error": "エラーが発生しました。サイト管理者に連絡してください。", + "common.message.data.save": "保存しますか?", + "common.message.data.delete": " 削除しますか?", + "common.message.data.exists": "{0} はすでに存在するデータです。", + "common.message.data.no.exists": "{0} は存在しないデータです。", + "common.message.all": "All", + "common.message.tab.close.all": "すべてのタブを閉じますか?", + "common.message.transfer.save": "{0}件転送しますか?", + "common.message.confirm.save": "保存しますか?", + "common.message.confirm.confirm": "承認しますか?", + "common.message.confirm.request": "承認リクエストしますか?", + "common.message.confirm.delete": "削除しますか?", + "common.message.confirm.close": "閉じますか?", + "common.message.confirm.unclose": "クローズ中止しますか?", + "common.message.confirm.cancel": "キャンセルしますか?", + "common.message.confirm.uncancel": "キャンセル中止しますか?", + "common.message.confirm.copy": "コピーしますか?", + "common.message.confirm.createSo": "S/O作成しますか?", + "common.message.confirm.mark": "保存完了", + "common.message.confirm.mail": "メールを送信しますか?", + "common.message.confirm.printPriceItem": "価格を印刷しますか?", + "common.message.confirm.allAppr ": "Do you want to Batch approve the selected data?", + "common.message.confirm.deliveryFee": "送料を登録しますか?", + "common.message.success.delete": "削除完了", + "common.message.success.close": "閉じる", + "common.message.success.unclose": "キャンセルしました", + "common.message.validation.date": "終了日を開始日より前にすることはできません。 もう一度入力してください。", + "common.message.no.editfield": "フィールドを編集できません", + "common.message.success.rmmail": "リスク管理チームにメールを送信しました。", + "common.message.password.validation01": "パスワードの変更が一致しません。", + "common.message.password.validation02": "英語、数字、特殊文字を組み合わせた8桁以上を入力してください。", + "common.message.password.validation03": "パスワードをIDと同じにすることはできません。", + "common.message.menu.validation01": "注文を保存するメニューはありません.", + "common.message.menu.validation02": "The same sort order exists.", + "common.message.menuCode.check01": "登録可能", + "common.message.menuCode.check02": "登録できません", + "common.message.pleaseSelect": "{0}を選択してください", + "common.message.pleaseInput": "{0}を入力してください。", + "common.message.pleaseInputOr": "{0}または{1}を入力してください。", + "common.message.approved ": "承認済み", + "common.message.errorFieldExist": "エラー項目が存在します", + "common.message.storeIdExist ": "既に利用されている販売店IDです", + "common.message.userIdExist ": "すでに使用しているユーザーID。", + "common.message.noExists ": "削除された掲示物です", + "common.message.emailReqTo": "メール宛先が必要です", + "common.message.downloadPeriod": "ダウンロード検索期間を{0}日以内に選択してください。", + "common.message.backToSubmit": "販売店ブロック解除実行しますか?", + "common.message.backToG3": "Back to G3処理実行しますか?", + "common.message.writeToConfirm": "作成解除を実行しますか?", + "common.message.password.init.success": "パスワード [{0}] に初期化されました。", + "common.message.no.edit.save": "この文書は変更できません。" } diff --git a/src/locales/ko.json b/src/locales/ko.json index 282d9722..04b14c9f 100644 --- a/src/locales/ko.json +++ b/src/locales/ko.json @@ -1,3 +1,90 @@ { - "hi": "안녕하세요" + "hi": "안녕하세요", + "common.message.no.data": "No data", + "common.message.no.dataDown": "No data to download", + "common.message.noData": "No data to display", + "common.message.search": "search success", + "common.message.insert": "insert success", + "common.message.update": "update success", + "common.message.delete": "Deleted", + "common.message.restoration": "Restored", + "common.message.cancel": "Canceled", + "common.message.send": "The mail has been sent.", + "common.message.no.delete": "There is no data to delete.", + "common.message.save": "Saved.", + "common.message.transfer": "Transfered", + "common.message.batch.exec": "batch success", + "common.message.not.mov": "Its impossible to move.", + "common.message.required.data": "{0} is required input value.", + "common.message.save.error": "An error occurred while saving the data. Please contact site administrator.", + "common.message.transfer.error": "An error occurred while transfer the data. Please contact site administrator.", + "common.message.delete.error": "An error occurred while deleting data. Please contact site administrator.", + "common.message.batch.error": "An error occurred while executing the batch. Please contact site administrator.", + "common.message.send.error": "Error sending data, please contact your administrator.", + "common.message.communication.error": "Network error occurred. \n Please contact site administrator.", + "common.message.data.error": "{0} The data format is not valid.", + "common.message.data.setting.error": "{0} is data that has been deleted or already configured.", + "common.message.parameter.error": "Parameter Error", + "common.message.product.parameter.error": "존재하지 않는 제품이 있습니다.", + "common.message.customer.parameter.error": "존재하지 않는 고객이 있습니다.", + "common.message.file.exists.error": "Error due to file not uploading normally", + "common.message.file.download.exists": "File does not exist.", + "common.message.file.download.error": "File download error", + "common.message.file.template.validation01": "Unable to upload folder", + "common.message.file.template.validation02": "Only Excel files can be uploaded.", + "common.message.file.template.validation03": "Non-registerable extension", + "common.message.file.template.validation04": "Exceed capacity \n Uploadable capacity : {0} MB", + "common.message.file.template.validation05": "업로드 파일을 선택해주세요.", + "common.message.multi.insert": "Total {0} cases ({1} successes, {2} failures {3})", + "common.message.error": "Error occurred, please contact site administrator.", + "common.message.data.save": "Do you want to save it?", + "common.message.data.delete": "Do you want to delete it?", + "common.message.data.exists": "{0} is data that already exists.", + "common.message.data.no.exists": "{0} is data that does not exist.", + "common.message.all": "All", + "common.message.tab.close.all": "Close all tabs?", + "common.message.transfer.save": "Want to {0} transfer it?", + "common.message.confirm.save": "Want to save it?", + "common.message.confirm.confirm": "Want to approve?", + "common.message.confirm.request": "Would you like to request a Approval?", + "common.message.confirm.delete": "Do you want to delete it?", + "common.message.confirm.close": "Want to close?", + "common.message.confirm.unclose": "Do you want to cancel the close?", + "common.message.confirm.cancel": "Want to cancellation?", + "common.message.confirm.uncancel": "Do you want to cancel the cancellation?", + "common.message.confirm.copy": "Do you want to copy?", + "common.message.confirm.createSo": "Create Sales Order?", + "common.message.confirm.mark": "Saved.", + "common.message.confirm.mail": "Do you want to send mail?", + "common.message.confirm.printPriceItem": "Would you like to print item price?", + "common.message.confirm.allAppr ": "Do you want to Batch approve the selected data?", + "common.message.confirm.deliveryFee": "Do you want to register shipping fee?", + "common.message.success.delete": "Deleted.", + "common.message.success.close": "Closed.", + "common.message.success.unclose": "Cancel Closed.", + "common.message.validation.date": "The end date cannot be earlier than the start date. Please enter it again.", + "common.message.no.editfield": "Can not edit field", + "common.message.success.rmmail": "You have successfully sent mail to the Risk Management team.", + "common.message.password.validation01": "Change passwords do not match.", + "common.message.password.validation02": "Please enter at least 8 digits combining English, numbers, and special characters.", + "common.message.password.validation03": "Password cannot be the same as ID.", + "common.message.menu.validation01": "There is no menu to save the order.", + "common.message.menu.validation02": "The same sort order exists.", + "common.message.menuCode.check01": "Registerable", + "common.message.menuCode.check02": "Unable to register", + "common.message.pleaseSelect": "Please Select {0}", + "common.message.pleaseInput": "Please Input a {0}.", + "common.message.pleaseInputOr": "Please Input a {0} or {1}.", + "common.message.approved ": "Approved.", + "common.message.errorFieldExist": "Error Field Exist", + "common.message.storeIdExist ": "이미 사용하고 있는 판매점 ID 입니다.", + "common.message.userIdExist ": "이미 사용하고 있는 사용자 ID 입니다.", + "common.message.noExists ": "삭제된 게시물 입니다.", + "common.message.emailReqTo": "Email To is required", + "common.message.downloadPeriod": "Please select the download search period within {0} days.", + "common.message.backToSubmit": "판매점 블록 해제를 실행하시겠습니까?", + "common.message.backToG3": "Back to G3 처리를 실행하시겠습니까?", + "common.message.writeToConfirm": "작성 해제를 실행하시겠습니까?", + "common.message.password.init.success": "비밀번호 [{0}]로 초기화 되었습니다.", + "common.message.no.edit.save": "This document cannot be changed." }