From 6969e6620e2a12e63932f9e89a2256ff90eb9d15 Mon Sep 17 00:00:00 2001 From: ysCha Date: Tue, 9 Jun 2026 09:41:33 +0900 Subject: [PATCH 1/3] =?UTF-8?q?[2234]=20=EC=88=98=EB=8F=99=201=EB=A7=A4(?= =?UTF-8?q?=E6=89=8B=E5=8B=95=201=E6=9E=9A)=20=EB=8B=A8=EB=B6=80(=E7=AB=AF?= =?UTF-8?q?=E9=83=A8)=20=EB=B0=B0=EC=B9=98=20=EC=8B=9C=20=EC=A7=80?= =?UTF-8?q?=EB=B6=95=20=EB=B0=96(=E5=B1=8B=E6=A0=B9=E5=A4=96)=20=EC=98=A4?= =?UTF-8?q?=ED=8C=90=20=EC=88=98=EC=A0=95=20=E2=80=94=20checkModuleDisjoin?= =?UTF-8?q?tSurface=20=ED=97=88=EC=9A=A9=EC=98=A4=EC=B0=A8(spare)=200?= =?UTF-8?q?=E2=86=920.5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Opus 4 --- src/hooks/module/useModuleBasicSetting.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/hooks/module/useModuleBasicSetting.js b/src/hooks/module/useModuleBasicSetting.js index e9a2aab5..18d92ab7 100644 --- a/src/hooks/module/useModuleBasicSetting.js +++ b/src/hooks/module/useModuleBasicSetting.js @@ -988,7 +988,10 @@ export function useModuleBasicSetting(tabNum) { if (!isIntersection) return tempModule.setCoords() //좌표 재정렬 - if (checkModuleDisjointSurface(tempTurfModule, turfPolygon)) { + // [EDGE-PLACE-TOLERANCE 2026-06-09] 手動 1枚 배치: 端部에 딱 붙인 모듈이 소수 절단 잔차(±0.02)로 屋根 경계를 살짝 넘으면 + // spare=0 판정이 屋根外로 오인 → 「取り付け面からモジュールを取り付けることはできません」 경고. 屋根 절대좌표에 따라 2번째/3번째가 들쭉날쭉. + // 이동/삽입/정렬(isOutsideSurface)과 동일한 0.5 허용오차로 잔차 흡수. + if (checkModuleDisjointSurface(tempTurfModule, turfPolygon, 0.5)) { //마우스 클릭시 set으로 해당 위치에 셀을 넣음 const isOverlap = manualDrawModules.some((module) => turf.booleanOverlap(tempTurfModule, polygonToTurfPolygon(module, true))) //겹치는지 확인 if (!isOverlap) { -- 2.47.2 From 567fa49d61f370714133208876525b4cbcb7519c Mon Sep 17 00:00:00 2001 From: ysCha Date: Tue, 9 Jun 2026 14:53:07 +0900 Subject: [PATCH 2/3] =?UTF-8?q?[2283-1]=20=EC=9E=90=EB=8F=99=EB=B0=B0?= =?UTF-8?q?=EC=B9=98(=E8=87=AA=E5=8B=95=E9=85=8D=E7=BD=AE)=20=EB=8B=A4?= =?UTF-8?q?=EC=A7=80=EB=B6=95=20=EC=84=A0=ED=83=9D=20=EC=8B=9C=20=EB=B6=81?= =?UTF-8?q?=EB=A9=B4=20=EC=97=B4=20=EA=B0=90=EC=86=8C=20=EC=88=98=EC=A0=95?= =?UTF-8?q?=20=E2=80=94=20=EB=8C=80=EC=B9=AD=20=EB=B3=B4=EC=A0=95=20?= =?UTF-8?q?=EB=B9=84=EB=8C=80=EC=B9=AD=20=EC=A7=80=EB=B6=95=20=EC=A0=9C?= =?UTF-8?q?=EC=99=B8=20=EA=B0=80=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 Co-Authored-By: Claude Opus 4 --- src/hooks/module/useModuleBasicSetting.js | 26 +++++++++++++++++------ 1 file changed, 20 insertions(+), 6 deletions(-) diff --git a/src/hooks/module/useModuleBasicSetting.js b/src/hooks/module/useModuleBasicSetting.js index 18d92ab7..45c17ff0 100644 --- a/src/hooks/module/useModuleBasicSetting.js +++ b/src/hooks/module/useModuleBasicSetting.js @@ -2235,6 +2235,9 @@ export function useModuleBasicSetting(tabNum) { // 대칭 지붕을 위해 south의 calcAreaWidth 저장 (north에서 참조) if (symmetricWidthRef && moduleIndex === 0) { symmetricWidthRef.south = calcAreaWidth + // [SYMM-FIX 2026-06-09] 진짜 대칭 판정용 남면 실제 가로폭 저장 + const southBBox = turf.bbox(polygonToTurfPolygon(moduleSetupSurface)) + symmetricWidthRef.southActualWidth = southBBox[2] - southBBox[0] } if (type === MODULE_SETUP_TYPE.LAYOUT) { @@ -2422,8 +2425,13 @@ export function useModuleBasicSetting(tabNum) { // 북쪽: 남쪽과 동일한 방식으로 계산 (대칭을 위해) let calcAreaWidth = Math.abs(flowLines.right.x1 - flowLines.left.x1) //오른쪽 x에서 왼쪽 x를 뺀 가운데를 찾는 로직 - // 대칭 지붕: south의 calcAreaWidth가 있고 north의 값이 south보다 10% 이상 작으면 south 값 사용 - if (symmetricWidthRef?.south && calcAreaWidth < symmetricWidthRef.south * 0.9) { + // [SYMM-FIX 2026-06-09] 진짜 대칭 판정: 북면 실제 폴리곤 가로폭이 남면 실제 가로폭과 비슷(>=90%)할 때만 보정. + // T자처럼 북면이 물리적으로 작으면(실제폭 작음) 보정 제외 → 단독 선택과 동일하게 자연 배치. + const northBBox = turf.bbox(polygonToTurfPolygon(moduleSetupSurface)) + const northActualWidth = northBBox[2] - northBBox[0] + const reallySymmetric = !!(symmetricWidthRef?.southActualWidth && northActualWidth >= symmetricWidthRef.southActualWidth * 0.9) + // 대칭 지붕: south의 calcAreaWidth가 있고 north의 flowLines폭이 south보다 10% 이상 작은데 실제 폴리곤은 대칭이면 south 값 사용 + if (symmetricWidthRef?.south && calcAreaWidth < symmetricWidthRef.south * 0.9 && reallySymmetric) { // flowLines 좌표도 보정 (중심점 유지하면서 너비 확장) const center = (flowLines.right.x1 + flowLines.left.x1) / 2 const halfWidth = symmetricWidthRef.south / 2 @@ -2626,6 +2634,8 @@ export function useModuleBasicSetting(tabNum) { // 대칭 지붕을 위해 west의 calcAreaWidth 저장 (east에서 참조) if (symmetricWidthRef && moduleIndex === 0) { symmetricWidthRef.west = calcAreaWidth + const westBBox = turf.bbox(polygonToTurfPolygon(moduleSetupSurface)) + symmetricWidthRef.westActualHeight = westBBox[3] - westBBox[1] } //단수지정 자동이면 @@ -2810,8 +2820,12 @@ export function useModuleBasicSetting(tabNum) { // 동쪽: 서쪽과 동일한 방식으로 계산 (대칭을 위해) let calcAreaWidth = Math.abs(flowLines.bottom.y1 - flowLines.top.y1) //아래에서 y에서 위를 y를 뺀 가운데를 찾는 로직 - // 대칭 지붕: west의 calcAreaWidth가 있고 east의 값이 west보다 10% 이상 작으면 west 값 사용 - if (symmetricWidthRef?.west && calcAreaWidth < symmetricWidthRef.west * 0.9) { + // 진짜 대칭 판정: 동면 실제 폴리곤 세로높이가 서면 실제 높이와 비슷(>=90%)할 때만 보정 (T자형 비대칭 제외) + const eastBBox = turf.bbox(polygonToTurfPolygon(moduleSetupSurface)) + const eastActualHeight = eastBBox[3] - eastBBox[1] + const eastReallySymmetric = !!(symmetricWidthRef?.westActualHeight && eastActualHeight >= symmetricWidthRef.westActualHeight * 0.9) + // 대칭 지붕: west의 calcAreaWidth가 있고 east의 flowLines높이가 west보다 10% 이상 작은데 실제 폴리곤은 대칭이면 west 값 사용 + if (symmetricWidthRef?.west && calcAreaWidth < symmetricWidthRef.west * 0.9 && eastReallySymmetric) { // flowLines 좌표도 보정 (중심점 유지하면서 높이 확장) const center = (flowLines.bottom.y1 + flowLines.top.y1) / 2 const halfHeight = symmetricWidthRef.west / 2 @@ -2926,8 +2940,8 @@ export function useModuleBasicSetting(tabNum) { } } - // 대칭 지붕을 위한 calcAreaWidth 공유 객체 (south→north, west→east) - const symmetricWidthRef = { south: null, west: null } + // 대칭 지붕을 위한 calcAreaWidth 공유 객체 (south→north, west→east) + 실제 폴리곤 크기(진짜 대칭 판정용) + const symmetricWidthRef = { south: null, west: null, southActualWidth: null, westActualHeight: null } // 대칭 보정을 위해 south/west가 north/east보다 먼저 처리되도록 정렬 const directionOrder = { south: 0, west: 1, north: 2, east: 3 } -- 2.47.2 From 26dbe35ea4358d48d50ac9c7978997f531aa8555 Mon Sep 17 00:00:00 2001 From: ysCha Date: Tue, 9 Jun 2026 16:01:48 +0900 Subject: [PATCH 3/3] =?UTF-8?q?[2283-2]=20=EC=9E=90=EB=8F=99=EB=B0=B0?= =?UTF-8?q?=EC=B9=98(=E8=87=AA=E5=8B=95=E9=85=8D=E7=BD=AE)=20=EB=B9=84?= =?UTF-8?q?=EC=84=A0=ED=83=9D=EB=A9=B4=20=EB=AA=A8=EB=93=88=20=EB=B3=B4?= =?UTF-8?q?=EC=A1=B4=20=E2=80=94=20=E9=81=B8=E6=8A=9E=E9=9D=A2=E3=81=AE?= =?UTF-8?q?=E3=81=BF=E5=86=8D=E9=85=8D=E7=BD=AE=E3=80=81=E6=9C=AA=E9=81=B8?= =?UTF-8?q?=E6=8A=9E=E9=9D=A2=E3=81=AF=E3=81=9D=E3=81=AE=E3=81=BE=E3=81=BE?= =?UTF-8?q?=E7=B6=AD=E6=8C=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/hooks/module/useModuleBasicSetting.js | 26 +++-------------------- 1 file changed, 3 insertions(+), 23 deletions(-) diff --git a/src/hooks/module/useModuleBasicSetting.js b/src/hooks/module/useModuleBasicSetting.js index 45c17ff0..1a8eb36a 100644 --- a/src/hooks/module/useModuleBasicSetting.js +++ b/src/hooks/module/useModuleBasicSetting.js @@ -1951,9 +1951,6 @@ export function useModuleBasicSetting(tabNum) { const isMaxSetup = false const moduleSetupSurfaces = moduleSetupSurface //선택 설치면 - const notSelectedTrestlePolygons = canvas - ?.getObjects() - .filter((obj) => obj.name === POLYGON_TYPE.MODULE_SETUP_SURFACE && !moduleSetupSurfaces.includes(obj)) //설치면이 아닌것 const batchObjects = canvas?.getObjects().filter((obj) => obj.name === POLYGON_TYPE.OBJECT_SURFACE) //도머s 객체 @@ -1962,14 +1959,8 @@ export function useModuleBasicSetting(tabNum) { return } - //어짜피 자동으로 누르면 선택안된데도 다 날아간다 - // canvas.getObjects().forEach((obj) => { - // if (obj.name === POLYGON_TYPE.MODULE) { - // canvas.remove(obj) - // } - // }) - - //자동일때만 선택 안된 모듈 삭제 + // [AUTO-KEEP-UNSELECTED 2026-06-09] 自動配置도 선택 안 된 면의 모듈은 보존 (전체 리셋 → 선택면만 재배치) + // 선택된 설치면의 기존 모듈만 삭제 후 재배치 moduleSetupSurfaces.forEach((obj) => { if (obj.modules) { obj.modules.forEach((module) => { @@ -1980,18 +1971,6 @@ export function useModuleBasicSetting(tabNum) { } }) - if (type === MODULE_SETUP_TYPE.AUTO) { - notSelectedTrestlePolygons.forEach((obj) => { - if (obj.modules) { - obj.modules.forEach((module) => { - canvas?.remove(module) - canvas?.renderAll() - }) - obj.modules = [] - } - }) - } - let moduleOptions = { stroke: 'black', strokeWidth: 0.3, @@ -3048,6 +3027,7 @@ export function useModuleBasicSetting(tabNum) { icon: 'warning', }) } + } const coordToTurfPolygon = (points) => { -- 2.47.2