diff --git a/src/components/Roof2.jsx b/src/components/Roof2.jsx index d5e511aa..d9b10e3e 100644 --- a/src/components/Roof2.jsx +++ b/src/components/Roof2.jsx @@ -38,6 +38,7 @@ export default function Roof2() { zoomOut, zoom, togglePolygonLine, + handleOuterlinesTest, handleOuterlinesTest2, applyTemplateB, makeRoofPatternPolygon, diff --git a/src/hooks/useMode.js b/src/hooks/useMode.js index 504b8e2d..15de0ef3 100644 --- a/src/hooks/useMode.js +++ b/src/hooks/useMode.js @@ -874,10 +874,17 @@ export function useMode() { /** *벽 지붕 외곽선 생성 */ - const handleOuterlinesTest = (polygon, offset = 71) => { - var offsetPoints = [] + const handleOuterlinesTest = (offsetInputX, offsetInputY = 0) => { + const polygon = drawWallPolygon() - debugger + let offsetPoints = [] + const originalMax = 71 + const transformedMax = 100 + + offsetInputY = offsetInputY !== 0 ? offsetInputY : offsetInputX + + const offsetX = (offsetInputX / transformedMax) * originalMax * 2 + const offsetY = (offsetInputY / transformedMax) * originalMax * 2 const sortedIndex = getStartIndex(polygon.lines) let tmpArraySorted = rearrangeArray(polygon.lines, sortedIndex) @@ -930,17 +937,14 @@ export function useMode() { // 오프셋 적용 var offsetPoint = { - x1: current.x + unitNormal.x * offset, - y1: current.y + unitNormal.y * offset, + x1: current.x + unitNormal.x * offsetX, + y1: current.y + unitNormal.y * offsetY, } offsetPoints.push(offsetPoint) } - const roof = makePolygon(offsetPoints) - setRoof(roof) - - return roof + makePolygon(offsetPoints) } /** @@ -1059,6 +1063,8 @@ export function useMode() { } else if (polygon.lines.length === 6) { //6각형 handleOuterLineTemplateA6Points(polygon) + } else if (polygon.lines.length === 8) { + handleOuterLineTemplateA8Points(polygon) } } @@ -1875,6 +1881,214 @@ export function useMode() { canvas.renderAll() } + const handleOuterLineTemplateA8Points = (polygon, offsetInputX = 50, offsetInputY = 20) => { + let offsetPoints = [] + + const originalMax = 71 + const transformedMax = 100 + + let lines = [] //내각라인 + let outLines = [] //아웃라인 + let halfLength = 0 //선길이 + + const dashedCenterLineOpt = { + stroke: 'black', + strokeWidth: 4, + property: 'centerLine', + strokeDashArray: [5, 5], + fontSize: 14, + } + + const centerLineOpt = { + stroke: 'blue', + strokeWidth: 5, + property: 'bigHoriCenter', + fontSize: 14, + } + + // 폴리곤의 각 변을 선으로 생성 + for (let i = 0; i < polygon.points.length; i++) { + const start = polygon.points[i] + const end = polygon.points[(i + 1) % polygon.points.length] // 다음 점, 마지막 점의 경우 첫 점으로 + + const color = i % 2 === 0 ? '#A0D468' : 'skyblue' + + const line = new QLine([start.x, start.y, end.x, end.y], { + stroke: color, + strokeWidth: 2, + property: 'normal', + fontSize: 14, + }) + + // 선을 배열에 추가 + lines.push(line) + canvas.add(line) + } + + offsetInputY = offsetInputY !== 0 ? offsetInputY : offsetInputX + + const sortedIndex = getStartIndex(polygon.lines) + let tmpArraySorted = rearrangeArray(polygon.lines, sortedIndex) + + if (tmpArraySorted[0].direction === 'right') { + //시계방향 + tmpArraySorted = tmpArraySorted.reverse() //그럼 배열을 거꾸로 만들어서 무조건 반시계방향으로 배열 보정 + } + + setSortedArray(tmpArraySorted) //recoil에 넣음 + + const points = tmpArraySorted.map((line) => ({ + x: line.x1, + y: line.y1, + })) + + // 외적을 계산하는 함수 + function crossProduct(p1, p2, p3) { + const dx1 = p2.x - p1.x + const dy1 = p2.y - p1.y + const dx2 = p3.x - p2.x + const dy2 = p3.y - p2.y + return dx1 * dy2 - dy1 * dx2 + } + + let concaveIndices = [] //볼록한 부분 인덱스 배열 + let concavePointIndices = [] //오목한 부분 인덱스 배열 + + // 오목한 부분 찾기 + function findConcavePointIndices(points) { + let concaveIndices = [] + for (let i = 0; i < points.length; i++) { + const p1 = points[i] + const p2 = points[(i + 1) % points.length] + const p3 = points[(i + 2) % points.length] + const cross = crossProduct(p1, p2, p3) + if (cross < 0) { + concaveIndices.push((i + 1) % points.length) + } else { + concavePointIndices.push((i + 1) % points.length) + } + } + return concaveIndices + } + + // 오목한 부분 인덱스 찾기 + concaveIndices = findConcavePointIndices(points) //오목한 부분을 제외한 인덱스 + const concavePoints = concaveIndices.map((index) => points[index]) + + for (var i = 0; i < points.length; i++) { + var prev = points[(i - 1 + points.length) % points.length] + var current = points[i] + var next = points[(i + 1) % points.length] + + // 두 벡터 계산 (prev -> current, current -> next) + var vector1 = { x: current.x - prev.x, y: current.y - prev.y } + var vector2 = { x: next.x - current.x, y: next.y - current.y } + + // 벡터의 길이 계산 + var length1 = Math.sqrt(vector1.x * vector1.x + vector1.y * vector1.y) + var length2 = Math.sqrt(vector2.x * vector2.x + vector2.y * vector2.y) + + // 벡터를 단위 벡터로 정규화 + var unitVector1 = { x: vector1.x / length1, y: vector1.y / length1 } + var unitVector2 = { x: vector2.x / length2, y: vector2.y / length2 } + + // 법선 벡터 계산 (왼쪽 방향) + var normal1 = { x: -unitVector1.y, y: unitVector1.x } + var normal2 = { x: -unitVector2.y, y: unitVector2.x } + + // 법선 벡터 평균 계산 + var averageNormal = { + x: (normal1.x + normal2.x) / 2, + y: (normal1.y + normal2.y) / 2, + } + + // 평균 법선 벡터를 단위 벡터로 정규화 + var lengthNormal = Math.sqrt(averageNormal.x * averageNormal.x + averageNormal.y * averageNormal.y) + var unitNormal = { + x: averageNormal.x / lengthNormal, + y: averageNormal.y / lengthNormal, + } + + let offsetX + let offsetY + + if (concavePointIndices[0] === i || concavePointIndices[1] === i) { + // 인덱스가 배열이랑 같으면 + if ((concavePointIndices[0] === 4 && concavePointIndices[1] === 5) || (concavePointIndices[0] === 2 && concavePointIndices[1] === 3)) { + offsetX = 1 + offsetY = (offsetInputY / transformedMax) * originalMax * 2 + } else { + offsetX = (offsetInputX / transformedMax) * originalMax * 2 + offsetY = 1 + } + } else { + offsetX = (offsetInputX / transformedMax) * originalMax * 2 + offsetY = (offsetInputY / transformedMax) * originalMax * 2 + } + + // 오프셋 적용 + var offsetPoint = { + x1: current.x + unitNormal.x * offsetX, + y1: current.y + unitNormal.y * offsetY, + } + + offsetPoints.push(offsetPoint) + } + + const outlinePolygon = makePolygon(offsetPoints) + + // 아웃라인 폴리곤의 각 변을 선으로 생성 + for (let i = 0; i < outlinePolygon.points.length; i++) { + const start = outlinePolygon.points[i] + const end = outlinePolygon.points[(i + 1) % outlinePolygon.points.length] // 다음 점, 마지막 점의 경우 첫 점으로 + + const line = new QLine([start.x, start.y, end.x, end.y], { + stroke: 'blue', + strokeWidth: 2, + property: 'normal', + fontSize: 14, + }) + + // 선을 배열에 추가 + outLines.push(line) + canvas.add(line) + } + + canvas?.remove(outlinePolygon) //임시 폴리곤을 삭제 + canvas?.remove(outLines[concavePointIndices[0]]) //가운데 제외되는 선을 지운다 + + //라인들을 좌측에서 -> 우측으로 그리는거처럼 데이터 보정 + outLines.forEach((outline, index) => { + let minX, minY, maxX, maxY + if (outline.x2 < outline.x1 || outline.y2 < outline.y1) { + outLines[index].x1 = outline.x2 + outLines[index].y1 = outline.y2 + outLines[index].x2 = outline.x1 + outLines[index].y2 = outline.y1 + outLines[index].line.x1 = minX + outLines[index].line.y1 = minY + outLines[index].line.x2 = maxX + outLines[index].line.y2 = maxY + } + }) + + // for (let i = 0; i < outLines.length; i++) { + // if (!i % 2 === 0) { + // if (i === concavePointIndices[0] - 1 || i === concavePointIndices[1] + 1) { + // //배열 3번이나 5번일때 + // } else { + // } + // } + // } + + let parallelLines = concavePointIndices[0] + 4 //들어간선에 무조건 평행하는 선 찾기 + if (parallelLines > outLines.length) { + parallelLines = outLines[concavePointIndices[0] + 4 - outLines.length - 1] + } + + canvas.renderAll() + } + /** * 템플릿 B 적용 */ @@ -2371,6 +2585,7 @@ export function useMode() { zoomOut, zoom, togglePolygonLine, + handleOuterlinesTest, handleOuterlinesTest2, makeRoofPatternPolygon, }