From 8f5b2c3730cc3c8ddf8b33bff45a167a57336e76 Mon Sep 17 00:00:00 2001 From: ysCha Date: Wed, 4 Mar 2026 12:58:56 +0900 Subject: [PATCH 1/3] =?UTF-8?q?[1514]sk=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/util/skeleton-utils.js | 26 +++++++++++++++++++++----- 1 file changed, 21 insertions(+), 5 deletions(-) diff --git a/src/util/skeleton-utils.js b/src/util/skeleton-utils.js index 6a3c567e..d58b622a 100644 --- a/src/util/skeleton-utils.js +++ b/src/util/skeleton-utils.js @@ -404,9 +404,15 @@ export const skeletonBuilder = (roofId, canvas, textMode) => { }, { x: 0, y: 0 }) // baseLine을 offset만큼 바깥으로 평행이동 - const offsetLine = (line) => { + const offsetLine = (line, index) => { const sp = line.startPoint, ep = line.endPoint - const offset = line.attributes?.offset ?? 0 + let offset = line.attributes?.offset ?? 0 + + // 모든 offset이 동일할 때 수치적 안정성을 위해 약간의 변화 추가 + if (baseLines.every(l => (l.attributes?.offset ?? 0) === offset)) { + offset += index * 0.01 // 각 라인에 약간의 차이 추가 + } + const edx = ep.x - sp.x, edy = ep.y - sp.y const len = Math.hypot(edx, edy) if (len === 0) return { sp: { ...sp }, ep: { ...ep } } @@ -433,29 +439,39 @@ export const skeletonBuilder = (roofId, canvas, textMode) => { isSamePoint(point, line.startPoint) || isSamePoint(point, line.endPoint) ) if (adjLines.length < 2) return { ...point } - const oL1 = offsetLine(adjLines[0]), oL2 = offsetLine(adjLines[1]) + const idx1 = baseLines.indexOf(adjLines[0]) + const idx2 = baseLines.indexOf(adjLines[1]) + const oL1 = offsetLine(adjLines[0], idx1), oL2 = offsetLine(adjLines[1], idx2) return lineIntersect(oL1.sp, oL1.ep, oL2.sp, oL2.ep) || { ...point } }) // 중복 좌표 및 일직선 위의 불필요한 점 제거 (L자 확장 시 사각형으로 단순화) const simplifyPolygon = (pts) => { let result = [...pts] + + // L자형 보호를 위해 최소 4개 점 유지 + if (result.length <= 4) return result + let changed = true while (changed) { changed = false for (let i = result.length - 1; i >= 0; i--) { const next = result[(i + 1) % result.length] - if (Math.abs(result[i].x - next.x) < 0.5 && Math.abs(result[i].y - next.y) < 0.5) { + if (Math.abs(result[i].x - next.x) < 1.0 && Math.abs(result[i].y - next.y) < 1.0) { result.splice(i, 1) changed = true } } + // 최소 4개 점 유지 확인 + if (result.length <= 4) break + for (let i = result.length - 1; i >= 0 && result.length > 3; i--) { const prev = result[(i - 1 + result.length) % result.length] const curr = result[i] const next = result[(i + 1) % result.length] const cross = (curr.x - prev.x) * (next.y - prev.y) - (curr.y - prev.y) * (next.x - prev.x) - if (Math.abs(cross) < 1) { + // 임계값 증가로 과도한 단순화 방지 + if (Math.abs(cross) < 20) { result.splice(i, 1) changed = true } From 4c248f57660ce0c630a82ffbe4f98c3c69e08ba2 Mon Sep 17 00:00:00 2001 From: ysCha Date: Wed, 4 Mar 2026 13:53:47 +0900 Subject: [PATCH 2/3] =?UTF-8?q?[1514]sk=EC=88=98=EC=A0=952?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/util/skeleton-utils.js | 76 ++++++++++++++++++++------------------ 1 file changed, 40 insertions(+), 36 deletions(-) diff --git a/src/util/skeleton-utils.js b/src/util/skeleton-utils.js index d58b622a..8ee92c3c 100644 --- a/src/util/skeleton-utils.js +++ b/src/util/skeleton-utils.js @@ -416,9 +416,13 @@ export const skeletonBuilder = (roofId, canvas, textMode) => { const edx = ep.x - sp.x, edy = ep.y - sp.y const len = Math.hypot(edx, edy) if (len === 0) return { sp: { ...sp }, ep: { ...ep } } + + // 수직 벡터 계산 (항상 바깥 방향) let nx = -edy / len, ny = edx / len - const mid = { x: (sp.x + ep.x) / 2, y: (sp.y + ep.y) / 2 } - if (nx * (centroid.x - mid.x) + ny * (centroid.y - mid.y) > 0) { nx = -nx; ny = -ny } + + // 방향 결정 로직 제거 - 항상 바깥으로 확장 + // if (nx * (centroid.x - mid.x) + ny * (centroid.y - mid.y) > 0) { nx = -nx; ny = -ny } + return { sp: { x: sp.x + nx * offset, y: sp.y + ny * offset }, ep: { x: ep.x + nx * offset, y: ep.y + ny * offset } @@ -446,40 +450,40 @@ export const skeletonBuilder = (roofId, canvas, textMode) => { }) // 중복 좌표 및 일직선 위의 불필요한 점 제거 (L자 확장 시 사각형으로 단순화) - const simplifyPolygon = (pts) => { - let result = [...pts] - - // L자형 보호를 위해 최소 4개 점 유지 - if (result.length <= 4) return result - - let changed = true - while (changed) { - changed = false - for (let i = result.length - 1; i >= 0; i--) { - const next = result[(i + 1) % result.length] - if (Math.abs(result[i].x - next.x) < 1.0 && Math.abs(result[i].y - next.y) < 1.0) { - result.splice(i, 1) - changed = true - } - } - // 최소 4개 점 유지 확인 - if (result.length <= 4) break - - for (let i = result.length - 1; i >= 0 && result.length > 3; i--) { - const prev = result[(i - 1 + result.length) % result.length] - const curr = result[i] - const next = result[(i + 1) % result.length] - const cross = (curr.x - prev.x) * (next.y - prev.y) - (curr.y - prev.y) * (next.x - prev.x) - // 임계값 증가로 과도한 단순화 방지 - if (Math.abs(cross) < 20) { - result.splice(i, 1) - changed = true - } - } - } - return result - } - changRoofLinePoints = simplifyPolygon(changRoofLinePoints) + // const simplifyPolygon = (pts) => { + // let result = [...pts] + + // // 복잡한 형태 보호를 위해 최소 6개 점 유지 + // if (result.length <= 6) return result + + // let changed = true + // while (changed) { + // changed = false + // for (let i = result.length - 1; i >= 0; i--) { + // const next = result[(i + 1) % result.length] + // if (Math.abs(result[i].x - next.x) < 1.0 && Math.abs(result[i].y - next.y) < 1.0) { + // result.splice(i, 1) + // changed = true + // } + // } + // // 최소 6개 점 유지 확인 + // if (result.length <= 6) break + + // for (let i = result.length - 1; i >= 0 && result.length > 3; i--) { + // const prev = result[(i - 1 + result.length) % result.length] + // const curr = result[i] + // const next = result[(i + 1) % result.length] + // const cross = (curr.x - prev.x) * (next.y - prev.y) - (curr.y - prev.y) * (next.x - prev.x) + // // 복잡한 형태 보호를 위해 임계값 대폭 증가 + // if (Math.abs(cross) < 50) { + // result.splice(i, 1) + // changed = true + // } + // } + // } + // return result + // } + // changRoofLinePoints = simplifyPolygon(changRoofLinePoints) let roofLineContactPoints = [...changRoofLinePoints] From 3fdd9411e4822ecd39838ca3eb9738f9f2a46e4c Mon Sep 17 00:00:00 2001 From: "hyojun.choi" Date: Wed, 4 Mar 2026 14:43:28 +0900 Subject: [PATCH 3/3] =?UTF-8?q?#1511=20=E3=80=90HANASYS=20DESIGN=E3=80=91?= =?UTF-8?q?=E6=9D=B1=E8=A5=BF=E6=96=B9=E5=90=91=E3=81=AE=E3=83=A2=E3=82=B8?= =?UTF-8?q?=E3=83=A5=E3=83=BC=E3=83=AB=E9=85=8D=E7=BD=AE=E3=82=92=E8=87=AA?= =?UTF-8?q?=E5=8B=95=E3=81=A7=E8=A1=8C=E3=81=86=E3=81=A8=E3=80=81=E9=96=93?= =?UTF-8?q?=E9=9A=94=E3=81=8C=E7=8B=AD=E3=81=8F=E3=81=AA=E3=82=8B=E4=BA=8B?= =?UTF-8?q?=E8=B1=A1=20=EB=8F=99,=EC=84=9C=20=EB=B0=A9=ED=96=A5=20?= =?UTF-8?q?=EB=AA=A8=EB=93=88=20=EC=84=A4=EC=B9=98=20=EC=A0=9C=EB=8C=80?= =?UTF-8?q?=EB=A1=9C=20=EC=95=88=EB=90=98=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/hooks/module/useModuleBasicSetting.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/hooks/module/useModuleBasicSetting.js b/src/hooks/module/useModuleBasicSetting.js index c2b0398d..365ed1b0 100644 --- a/src/hooks/module/useModuleBasicSetting.js +++ b/src/hooks/module/useModuleBasicSetting.js @@ -2677,7 +2677,7 @@ export function useModuleBasicSetting(tabNum) { isInstall = true //마지막에 설치된 모듈의 Y 좌표 - installedLastHeightCoord = moduleY + width + widthMargin + installedLastHeightCoord = moduleY + width + heightMargin } else { //디버깅용 /*tempModule.set({ fill: 'transparent', stroke: 'red', strokeWidth: 1 })