From 2101d30d98546fe8729b4118f6d07fe8ebb3d656 Mon Sep 17 00:00:00 2001 From: "hyojun.choi" Date: Wed, 1 Apr 2026 17:11:58 +0900 Subject: [PATCH 1/2] =?UTF-8?q?1830=20=EB=AA=A8=EB=93=88=20=EC=84=A4?= =?UTF-8?q?=EC=B9=98=EC=98=81=EC=97=AD=20=EB=8C=80=EA=B0=81=20=EC=9E=88?= =?UTF-8?q?=EB=8A=94=20=ED=98=84=EC=83=81=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 | 48 ++++++++++++++++++++++++++++++++++++++------ 1 file changed, 42 insertions(+), 6 deletions(-) diff --git a/src/hooks/useMode.js b/src/hooks/useMode.js index 8492042a..d014b25f 100644 --- a/src/hooks/useMode.js +++ b/src/hooks/useMode.js @@ -1756,6 +1756,11 @@ export function useMode() { offsetEdges.push(createOffsetEdge(edge, dx, dy)) }) + // 폴리곤의 감김 방향(signed area)을 구한다 + const signedArea = bevelJoin + ? polygon.edges.reduce((sum, edge) => sum + (edge.vertex1.x * edge.vertex2.y - edge.vertex2.x * edge.vertex1.y), 0) + : 0 + const vertices = [] offsetEdges.forEach((thisEdge, i) => { @@ -1765,9 +1770,22 @@ export function useMode() { if (!vertex.isIntersectionOutside || !bevelJoin) { vertices.push({ x: vertex.x, y: vertex.y }) } else { - // 둔각 + bevelJoin: offset edge 끝점 사용 - vertices.push({ x: prevEdge.vertex2.x, y: prevEdge.vertex2.y }) - vertices.push({ x: thisEdge.vertex1.x, y: thisEdge.vertex1.y }) + // 꼭짓점의 볼록/오목 판별 (cross product와 signed area 비교) + const origPrev = polygon.edges[(i + polygon.edges.length - 1) % polygon.edges.length] + const origThis = polygon.edges[i] + const cross = + (origPrev.vertex2.x - origPrev.vertex1.x) * (origThis.vertex2.y - origThis.vertex1.y) - + (origPrev.vertex2.y - origPrev.vertex1.y) * (origThis.vertex2.x - origThis.vertex1.x) + const isConvex = cross * signedArea > 0 + + if (isConvex) { + // 볼록 꼭짓점: bevel 적용 (offset edge 끝점 사용) + vertices.push({ x: prevEdge.vertex2.x, y: prevEdge.vertex2.y }) + vertices.push({ x: thisEdge.vertex1.x, y: thisEdge.vertex1.y }) + } else { + // 오목 꼭짓점: 교차점 사용 (90도 유지) + vertices.push({ x: vertex.x, y: vertex.y }) + } } } }) @@ -1795,6 +1813,11 @@ export function useMode() { offsetEdges.push(createOffsetEdge(edge, dx, dy)) }) + // 폴리곤의 감김 방향(signed area)을 구한다 + const signedArea = bevelJoin + ? polygon.edges.reduce((sum, edge) => sum + (edge.vertex1.x * edge.vertex2.y - edge.vertex2.x * edge.vertex1.y), 0) + : 0 + const vertices = [] offsetEdges.forEach((thisEdge, i) => { @@ -1804,9 +1827,22 @@ export function useMode() { if (!vertex.isIntersectionOutside || !bevelJoin) { vertices.push({ x: vertex.x, y: vertex.y }) } else { - // 둔각 + bevelJoin: offset edge 끝점 사용 - vertices.push({ x: prevEdge.vertex2.x, y: prevEdge.vertex2.y }) - vertices.push({ x: thisEdge.vertex1.x, y: thisEdge.vertex1.y }) + // 꼭짓점의 볼록/오목 판별 (cross product와 signed area 비교) + const origPrev = polygon.edges[(i + polygon.edges.length - 1) % polygon.edges.length] + const origThis = polygon.edges[i] + const cross = + (origPrev.vertex2.x - origPrev.vertex1.x) * (origThis.vertex2.y - origThis.vertex1.y) - + (origPrev.vertex2.y - origPrev.vertex1.y) * (origThis.vertex2.x - origThis.vertex1.x) + const isConvex = cross * signedArea > 0 + + if (isConvex) { + // 볼록 꼭짓점: bevel 적용 (offset edge 끝점 사용) + vertices.push({ x: prevEdge.vertex2.x, y: prevEdge.vertex2.y }) + vertices.push({ x: thisEdge.vertex1.x, y: thisEdge.vertex1.y }) + } else { + // 오목 꼭짓점: 교차점 사용 (90도 유지) + vertices.push({ x: vertex.x, y: vertex.y }) + } } } }) -- 2.47.2 From 13f10fd18eb5e9464c9e6b578367b22b978742e3 Mon Sep 17 00:00:00 2001 From: ysCha Date: Wed, 1 Apr 2026 17:48:25 +0900 Subject: [PATCH 2/2] =?UTF-8?q?Revert=20"=EC=88=98=EB=8F=99=20=EB=B0=B0?= =?UTF-8?q?=EC=B9=98=20=EC=8B=9C=20=EC=9E=90=EB=8F=99=20=EB=AC=BC=EB=96=BC?= =?UTF-8?q?=EC=84=B8=20=EB=B0=B0=EC=B9=98=20=ED=95=9C=EB=8B=A4=EB=A1=9C=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 This reverts commit b1c35376da012c1b685f7b58a0b14b3ffddf5425. --- src/components/floor-plan/modal/basic/BasicSetting.jsx | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/src/components/floor-plan/modal/basic/BasicSetting.jsx b/src/components/floor-plan/modal/basic/BasicSetting.jsx index 04dbbcb0..983492bf 100644 --- a/src/components/floor-plan/modal/basic/BasicSetting.jsx +++ b/src/components/floor-plan/modal/basic/BasicSetting.jsx @@ -17,7 +17,6 @@ import { currentCanvasPlanState, isManualModuleLayoutSetupState, isManualModuleSetupState, - moduleSetupOptionState, toggleManualSetupModeState, } from '@/store/canvasAtom' import { loginUserStore } from '@/store/commonAtom' @@ -48,7 +47,6 @@ export default function BasicSetting({ id, pos = { x: 50, y: 230 } }) { const [checkedModules, setCheckedModules] = useRecoilState(checkedModuleState) const [roofs, setRoofs] = useState(addedRoofs) const [manualSetupMode, setManualSetupMode] = useRecoilState(toggleManualSetupModeState) - const [moduleSetupOption, setModuleSetupOption] = useRecoilState(moduleSetupOptionState) const [layoutSetup, setLayoutSetup] = useState([{}]) const { selectedModules, @@ -213,12 +211,8 @@ export default function BasicSetting({ id, pos = { x: 50, y: 230 } }) { } const handleManualModuleSetup = () => { - const nextManual = !isManualModuleSetup - setManualSetupMode(`manualSetup_${nextManual}`) - setIsManualModuleSetup(nextManual) - if (nextManual) { - setModuleSetupOption((prev) => ({ ...prev, isChidori: true })) - } + setManualSetupMode(`manualSetup_${!isManualModuleSetup}`) + setIsManualModuleSetup(!isManualModuleSetup) } const handleManualModuleLayoutSetup = () => { -- 2.47.2