From 706ad9aed8d0626d2a8465d152cf1f5865f081b9 Mon Sep 17 00:00:00 2001 From: "hyojun.choi" Date: Thu, 14 Nov 2024 15:36:57 +0900 Subject: [PATCH 1/2] =?UTF-8?q?=EC=A7=80=EB=B6=95=EB=A9=B4=20=ED=95=A0?= =?UTF-8?q?=EB=8B=B9=20=EC=98=A4=EB=A5=98=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/floor-plan/MenuDepth01.jsx | 4 +- .../roofcover/useRoofAllocationSetting.js | 2 +- src/hooks/usePolygon.js | 151 ++++++++++++------ src/util/canvas-util.js | 24 +++ src/util/qpolygon-utils.js | 14 +- 5 files changed, 139 insertions(+), 56 deletions(-) diff --git a/src/components/floor-plan/MenuDepth01.jsx b/src/components/floor-plan/MenuDepth01.jsx index 351fdc97..5b1897b3 100644 --- a/src/components/floor-plan/MenuDepth01.jsx +++ b/src/components/floor-plan/MenuDepth01.jsx @@ -1,7 +1,7 @@ 'use client' import { useMessage } from '@/hooks/useMessage' -import { currentMenuState } from '@/store/canvasAtom' +import { canvasState, currentMenuState } from '@/store/canvasAtom' import { useRecoilState, useRecoilValue } from 'recoil' import { menuTypeState, subMenusState } from '@/store/menuAtom' import useMenu from '@/hooks/common/useMenu' @@ -9,6 +9,7 @@ import { useEffect } from 'react' export default function MenuDepth01() { const type = useRecoilValue(menuTypeState) + const canvas = useRecoilValue(canvasState) const { getMessage } = useMessage() const { handleMenu } = useMenu() const [currentMenu, setCurrentMenu] = useRecoilState(currentMenuState) @@ -24,6 +25,7 @@ export default function MenuDepth01() { useEffect(() => { handleMenu(type) + canvas.discardActiveObject() }, [currentMenu]) return (
diff --git a/src/hooks/roofcover/useRoofAllocationSetting.js b/src/hooks/roofcover/useRoofAllocationSetting.js index 5626e075..9a9973cb 100644 --- a/src/hooks/roofcover/useRoofAllocationSetting.js +++ b/src/hooks/roofcover/useRoofAllocationSetting.js @@ -107,7 +107,7 @@ export function useRoofAllocationSetting(id) { } }) }) - if (currentObject && currentObject.name && !currentObject.name.toLowerCase().includes('text')) { + if (currentObject && currentObject.name && ['auxiliaryLine', 'ridge', 'hip'].includes(currentObject.name)) { currentObject.set({ strokeWidth: 4, stroke: '#EA10AC', diff --git a/src/hooks/usePolygon.js b/src/hooks/usePolygon.js index b3730493..b83d8b1a 100644 --- a/src/hooks/usePolygon.js +++ b/src/hooks/usePolygon.js @@ -1,7 +1,7 @@ import { ANGLE_TYPE, canvasState, currentAngleTypeSelector, fontFamilyState, fontSizeState, pitchTextSelector } from '@/store/canvasAtom' import { useRecoilValue } from 'recoil' import { fabric } from 'fabric' -import { getDegreeByChon, getDegreeInOrientation, getDirectionByPoint, isPointOnLine } from '@/util/canvas-util' +import { findAndRemoveClosestPoint, getDegreeByChon, getDegreeInOrientation, getDirectionByPoint, isPointOnLine } from '@/util/canvas-util' import { QPolygon } from '@/components/fabric/QPolygon' import { isSamePoint, removeDuplicatePolygons } from '@/util/qpolygon-utils' import { flowDisplaySelector } from '@/store/settingAtom' @@ -86,8 +86,8 @@ export const usePolygon = () => { parentDirection: line.direction, parentDegree: degree, parentId: polygon.id, - planeSize, - actualSize, + planeSize: planeSize ?? length, + actualSize: actualSize ?? length, editable: false, selectable: true, lockRotation: true, @@ -669,62 +669,107 @@ export const usePolygon = () => { const splitPolygonWithLines = (polygon) => { polygon.set({ visible: false }) let innerLines = [...polygon.innerLines] + + canvas.renderAll() let polygonLines = [...polygon.lines] const roofs = [] - let delIndexs = [] - let newLines = [] - - polygonLines.forEach((line, index) => { - line.tempIndex = index + //polygonLines를 순회하며 innerLines와 교차하는 점을 line의 속성에 배열로 저장한다. + polygonLines.forEach((line) => { + const intersections = [] innerLines.forEach((innerLine) => { - let newLine1, newLine2 if (isPointOnLine(line, innerLine.startPoint)) { - // 해당 line을 startPoint로 나눈 line2개를 canvas에 추가 하고 기존 line을 제거한다. - newLine1 = new QLine([line.x1, line.y1, innerLine.startPoint.x, innerLine.startPoint.y], { - fontSize: polygon.fontSize, - stroke: 'black', - strokeWidth: 3, - }) - - newLine2 = new QLine([innerLine.startPoint.x, innerLine.startPoint.y, line.x2, line.y2], { - fontSize: polygon.fontSize, - stroke: 'black', - strokeWidth: 3, - }) - delIndexs.push(polygonLines.indexOf(line)) - canvas.remove(polygonLines[polygonLines.indexOf(line)]) - if (newLine1.length / 10 > 10) { - newLines.push(newLine1) - } - if (newLine2.length / 10 > 10) { - newLines.push(newLine2) + if (isSamePoint(line.startPoint, innerLine.startPoint) || isSamePoint(line.endPoint, innerLine.startPoint)) { + return } + intersections.push(innerLine.startPoint) } if (isPointOnLine(line, innerLine.endPoint)) { - newLine1 = new QLine([line.x1, line.y1, innerLine.endPoint.x, innerLine.endPoint.y], { - fontSize: polygon.fontSize, - stroke: 'black', - strokeWidth: 3, - }) - - newLine2 = new QLine([innerLine.endPoint.x, innerLine.endPoint.y, line.x2, line.y2], { - fontSize: polygon.fontSize, - stroke: 'black', - strokeWidth: 3, - }) - delIndexs.push(polygonLines.indexOf(line)) - canvas.remove(polygonLines[polygonLines.indexOf(line)]) - if (newLine1.length / 10 > 10) { - newLines.push(newLine1) - } - if (newLine2.length / 10 > 10) { - newLines.push(newLine2) + if (isSamePoint(line.startPoint, innerLine.endPoint) || isSamePoint(line.startPoint, innerLine.endPoint)) { + return } + intersections.push(innerLine.endPoint) } }) + line.set({ intersections }) }) - polygonLines = polygonLines.filter((line) => !delIndexs.includes(line.tempIndex)) + + const divideLines = polygonLines.filter((line) => line.intersections.length > 0) + let newLines = [] + divideLines.forEach((line) => { + const { intersections, startPoint, endPoint } = line + + if (intersections.length === 1) { + // 한 점만 교차하는 경우 + const newLinePoint1 = [line.x1, line.y1, intersections[0].x, intersections[0].y] + const newLinePoint2 = [intersections[0].x, intersections[0].y, line.x2, line.y2] + const newLine1 = new QLine(newLinePoint1, { + stroke: 'blue', + strokeWidth: 3, + fontSize: polygon.fontSize, + attributes: line.attributes, + }) + const newLine2 = new QLine(newLinePoint2, { + stroke: 'blue', + strokeWidth: 3, + fontSize: polygon.fontSize, + attributes: line.attributes, + }) + newLine1.attributes = { + ...line.attributes, + planeSize: Math.round(Math.sqrt(Math.pow(newLine1.x1 - newLine1.x2, 2) + Math.pow(newLine1.y1 - newLine1.y2, 2))) * 10, + actualSize: Math.round(Math.sqrt(Math.pow(newLine1.x1 - newLine1.x2, 2) + Math.pow(newLine1.y1 - newLine1.y2, 2))) * 10, + } + newLine2.attributes = { + ...line.attributes, + planeSize: Math.round(Math.sqrt(Math.pow(newLine2.x1 - newLine2.x2, 2) + Math.pow(newLine2.y1 - newLine2.y2, 2))) * 10, + actualSize: Math.round(Math.sqrt(Math.pow(newLine2.x1 - newLine2.x2, 2) + Math.pow(newLine2.y1 - newLine2.y2, 2))) * 10, + } + newLines.push(newLine1) + newLines.push(newLine2) + } else { + // 두 점 이상 교차하는 경우 + //1. intersections중에 startPoint와 가장 가까운 점을 찾는다. + //2. 가장 가까운 점을 기준으로 line을 나눈다. + + let currentPoint = startPoint + + while (intersections.length !== 0) { + const minDistancePoint = findAndRemoveClosestPoint(currentPoint, intersections) + const newLinePoint = [currentPoint.x, currentPoint.y, minDistancePoint.x, minDistancePoint.y] + const newLine = new QLine(newLinePoint, { + stroke: 'blue', + strokeWidth: 3, + fontSize: polygon.fontSize, + attributes: line.attributes, + }) + newLine.attributes = { + ...line.attributes, + planeSize: Math.round(Math.sqrt(Math.pow(newLine.x1 - newLine.x2, 2) + Math.pow(newLine.y1 - newLine.y2, 2))) * 10, + actualSize: Math.round(Math.sqrt(Math.pow(newLine.x1 - newLine.x2, 2) + Math.pow(newLine.y1 - newLine.y2, 2))) * 10, + } + newLines.push(newLine) + currentPoint = minDistancePoint + } + + const newLinePoint = [currentPoint.x, currentPoint.y, endPoint.x, endPoint.y] + const newLine = new QLine(newLinePoint, { + stroke: 'blue', + strokeWidth: 3, + fontSize: polygon.fontSize, + attributes: line.attributes, + }) + newLine.attributes = { + ...line.attributes, + planeSize: Math.round(Math.sqrt(Math.pow(newLine.x1 - newLine.x2, 2) + Math.pow(newLine.y1 - newLine.y2, 2))) * 10, + actualSize: Math.round(Math.sqrt(Math.pow(newLine.x1 - newLine.x2, 2) + Math.pow(newLine.y1 - newLine.y2, 2))) * 10, + } + newLines.push(newLine) + } + }) + + //polygonLines에서 divideLines를 제거하고 newLines를 추가한다. + polygonLines = polygonLines.filter((line) => !divideLines.includes(line)) polygonLines = [...polygonLines, ...newLines] const allLines = [...polygonLines, ...innerLines] @@ -756,6 +801,9 @@ export const usePolygon = () => { }) polygonLines.forEach((line) => { + line.set({ strokeWidth: 5, stroke: 'green' }) + canvas.add(line) + canvas.renderAll() const startPoint = line.startPoint // 시작점 let arrivalPoint = line.endPoint // 도착점 @@ -819,17 +867,18 @@ export const usePolygon = () => { roofPoints.push(currentPoint) cnt++ if (cnt > 100) { - throw new Error('무한루프') + break } } roofs.push(roofPoints) + canvas.remove(line) + canvas.renderAll() }) - const newRoofs = removeDuplicatePolygons(roofs) + const newRoofs = removeDuplicatePolygons(roofs.filter((roof) => roof.length < 100)) newRoofs.forEach((roofPoint, index) => { let defense, pitch - const polygonLines = [...polygon.lines] let representLines = [] let representLine @@ -901,7 +950,7 @@ export const usePolygon = () => { //allLines중 생성된 roof와 관련있는 line을 찾는다. - roof.lines = [...polygon.lines, ...polygon.innerLines].filter((line) => { + roof.lines = [...polygonLines, ...polygon.innerLines].filter((line) => { let startFlag = false let endFlag = false const startPoint = line.startPoint diff --git a/src/util/canvas-util.js b/src/util/canvas-util.js index 4ef2a2ec..65c46b74 100644 --- a/src/util/canvas-util.js +++ b/src/util/canvas-util.js @@ -977,3 +977,27 @@ export const getDegreeInOrientation = (degree) => { return value * 15 } + +export function findAndRemoveClosestPoint(targetPoint, points) { + if (points.length === 0) { + return null + } + + let closestPoint = points[0] + let closestDistance = distanceBetweenPoints(targetPoint, points[0]) + let closestIndex = 0 + + for (let i = 1; i < points.length; i++) { + const distance = distanceBetweenPoints(targetPoint, points[i]) + if (distance < closestDistance) { + closestDistance = distance + closestPoint = points[i] + closestIndex = i + } + } + + // Remove the closest point from the array + points.splice(closestIndex, 1) + + return closestPoint +} diff --git a/src/util/qpolygon-utils.js b/src/util/qpolygon-utils.js index ed375ec5..a229d1a7 100644 --- a/src/util/qpolygon-utils.js +++ b/src/util/qpolygon-utils.js @@ -2949,7 +2949,8 @@ const changeJerkInHeadRoof = (currentRoof, canvas) => { gable3.attributes.planeSize = Math.round(Math.sqrt(Math.pow(gable3.x1 - gable3.x2, 2) + Math.pow(gable3.y1 - gable3.y2, 2))) * 10 gable3.attributes.actualSize = Math.round(Math.sqrt(Math.pow(gable3.x1 - gable3.x2, 2) + Math.pow(gable3.y1 - gable3.y2, 2))) * 10 canvas?.add(gable3) - roof.innerLines.push(gable3) + + // roof.innerLines.push(gable3) const hip1 = new QLine([currentRoof.x1, currentRoof.y1, gable1.x1, gable1.y1], { fontSize: roof.fontSize, @@ -2967,7 +2968,7 @@ const changeJerkInHeadRoof = (currentRoof, canvas) => { hip1.attributes.planeSize = Math.round(Math.sqrt(Math.pow(hip1.x1 - hip1.x2, 2) + Math.pow(hip1.y1 - hip1.y2, 2))) * 10 hip1.attributes.actualSize = Math.round(Math.sqrt(Math.pow(hip1.attributes.planeSize, 2) + Math.pow(hip1Height, 2))) canvas?.add(hip1) - roof.innerLines.push(hip1) + // roof.innerLines.push(hip1) const hip2 = new QLine([currentRoof.x2, currentRoof.y2, gable2.x1, gable2.y1], { fontSize: roof.fontSize, @@ -2985,7 +2986,14 @@ const changeJerkInHeadRoof = (currentRoof, canvas) => { hip2.attributes.planeSize = Math.round(Math.sqrt(Math.pow(hip2.x1 - hip2.x2, 2) + Math.pow(hip2.y1 - hip2.y2, 2))) * 10 hip2.attributes.actualSize = Math.round(Math.sqrt(Math.pow(hip2.attributes.planeSize, 2) + Math.pow(hip2Height, 2))) canvas?.add(hip2) - roof.innerLines.push(hip2) + // roof.innerLines.push(hip2) + + hip1.set({ visible: false }) + hip1.setViewLengthText(false) + gable3.set({ visible: false }) + gable3.setViewLengthText(false) + hip2.set({ visible: false }) + hip2.setViewLengthText(false) } } } From 3a3b32b1d171310dc9bff89e94fae5fd09a0eed0 Mon Sep 17 00:00:00 2001 From: basssy Date: Thu, 14 Nov 2024 15:38:17 +0900 Subject: [PATCH 2/2] =?UTF-8?q?=EA=B2=AC=EC=A0=81=EC=84=9C=20=EC=83=81?= =?UTF-8?q?=EC=84=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/estimate/Estimate.jsx | 53 ++++++++++++++++------------ src/locales/ja.json | 8 ++--- src/locales/ko.json | 8 ++--- 3 files changed, 38 insertions(+), 31 deletions(-) diff --git a/src/components/estimate/Estimate.jsx b/src/components/estimate/Estimate.jsx index 1030962c..3f41b359 100644 --- a/src/components/estimate/Estimate.jsx +++ b/src/components/estimate/Estimate.jsx @@ -17,6 +17,8 @@ import { SessionContext } from '@/app/SessionProvider' import Select, { components } from 'react-select' import { convertNumberToPriceDecimal } from '@/util/common-utils' import ProductFeaturesPop from './popup/ProductFeaturesPop' +import { v4 as uuidv4 } from 'uuid' + export default function Estimate({ params }) { const [itemChangeYn, setItemChangeYn] = useState(false) const { session } = useContext(SessionContext) @@ -307,22 +309,25 @@ export default function Estimate({ params }) { //제품 삭제 const removeItem = () => { const array = [...selection] - let tempList = [] + let delList = [] state.itemList.filter((row) => { array.map((row2) => { if (row2 === row.dispOrder) { - tempList.push({ ...row }) + delList.push({ ...row }) } }) }) - // 필터안하고 플래그로 관리하는거로 변경하기 - const result = state.itemList.filter((item) => { - return !tempList.some((other) => other.dispOrder === item.dispOrder) + const updateList = state.itemList.map((item) => { + const isDeleted = delList.some((row) => item.dispOrder === row.dispOrder) + return { + ...item, + delFlg: isDeleted ? '1' : '0', + } }) setState({ - itemList: result, + itemList: updateList, }) setSelection(new Set()) @@ -331,8 +336,8 @@ export default function Estimate({ params }) { useEffect(() => { if (itemChangeYn) { - // console.log('아이템에 뭔가 변화가 일어났어', itemChangeYn) - // console.log('아이템상태가져오기::::::::::', state.itemList) + console.log('아이템에 뭔가 변화가 일어났어', itemChangeYn) + console.log('아이템상태가져오기::::::::::', state.itemList) } //다시 false로 돌리기 여기서할지 가격정보 변경하는거 끝나고할지.. @@ -527,8 +532,8 @@ export default function Estimate({ params }) { return ( <> -
-
+
+
@@ -613,7 +618,7 @@ export default function Estimate({ params }) { {originFiles.length > 0 && originFiles.map((originFile) => { return ( -
  • +
  • handleEstimateFileDownload(originFile)}> {originFile.faileName}