diff --git a/src/util/skeleton-utils.js b/src/util/skeleton-utils.js index f8c91eea..52c1a8c6 100644 --- a/src/util/skeleton-utils.js +++ b/src/util/skeleton-utils.js @@ -2,14 +2,9 @@ import { LINE_TYPE, POLYGON_TYPE } from '@/common/common' import { SkeletonBuilder } from '@/lib/skeletons' import { calcLineActualSize, calcLinePlaneSize, toGeoJSON } from '@/util/qpolygon-utils' import { QLine } from '@/components/fabric/QLine' -import { findClosestLineToPoint, findOrthogonalPoint, getDegreeByChon } from '@/util/canvas-util' +import { getDegreeByChon } from '@/util/canvas-util' import Big from 'big.js' -import { line } from 'framer-motion/m' import { QPolygon } from '@/components/fabric/QPolygon' -import { point } from '@turf/turf' -import { add, forEach } from 'mathjs' -import wallLine from '@/components/floor-plan/modal/wallLineOffset/type/WallLine' -import * as conole from 'mathjs' /** * 지붕 폴리곤의 스켈레톤(중심선)을 생성하고 캔버스에 그립니다. @@ -434,6 +429,7 @@ const createInnerLinesFromSkeleton = (roofId, canvas, skeleton, textMode) => { let roof = canvas?.getObjects().find((object) => object.id === roofId) let wall = canvas.getObjects().find((obj) => obj.name === POLYGON_TYPE.WALL && obj.attributes.roofId === roofId) let skeletonLines = [] + let findPoints = []; const processedInnerEdges = new Set() @@ -764,6 +760,7 @@ if(roof.moveUpDown??0 > 0) { //wall.baseLine은 움직인라인 const movedLines = [] + sortedWallLines.forEach((wallLine, index) => { @@ -840,67 +837,34 @@ if(roof.moveUpDown??0 > 0) { return line } - getAddLine(roofLine.startPoint, roofLine.endPoint) + getAddLine(roofLine.startPoint, roofLine.endPoint, ) newPStart = { x: roofLine.x1, y: roofLine.y1 } newPEnd = { x: roofLine.x2, y: roofLine.y2 } - // Usage in your code: - // if (fullyMoved) { - // const result = adjustLinePoints({ - // roofLine, - // currentRoofLine, - // wallBaseLine, - // origin, - // moveType: 'both' // Adjust both start and end points - // }); - // newPStart = result.newPStart; - // newPEnd = result.newPEnd; - // getAddLine(newPStart, newPEnd, 'red'); - // } - // else if (movedStart) { - // const result = adjustLinePoints({ - // roofLine, - // currentRoofLine, - // wallBaseLine, - // origin, - // moveType: 'start' // Only adjust start point - // }); - // newPStart = result.newPStart; - // getAddLine(newPStart, newPEnd, 'green'); - // } - // else if (movedEnd) { - // const result = adjustLinePoints({ - // roofLine, - // currentRoofLine, - // wallBaseLine, - // origin, - // moveType: 'end' // Only adjust end point - // }); - // newPEnd = result.newPEnd; - // getAddLine(newPStart, newPEnd, 'orange'); - // } - // canvas.renderAll() + const getInnerLines = (lines, point) => { + + } + + //두 포인트가 변경된 라인인 if (fullyMoved) { //반시계방향향 - - console.log("moveFully:::::::::::::", wallBaseLine, newPStart, newPEnd) - if (getOrientation(roofLine) === 'vertical') { //왼쪽 부터 roofLine, wallBaseLine - if (newPEnd.y <= wallBaseLine.y2 && wallBaseLine.y2 <= newPStart.y && newPStart.y <= wallBaseLine.y1) { + if (newPEnd.y <= wallBaseLine.y2 && wallBaseLine.y2 <= newPStart.y && newPStart.y <= wallBaseLine.y1) { //top right newPStart.y = wallBaseLine.y1; getAddLine({ x: newPEnd.x, y: wallBaseLine.y1 }, { x: wallBaseLine.x1, y: wallBaseLine.y1 }) - + findPoints.push({ x: wallBaseLine.x1, y: wallBaseLine.y1 }); } else if (wallBaseLine.y2 <= newPEnd.y && newPEnd.y <= wallBaseLine.y1 && wallBaseLine.y1 <= newPStart.y) { newPEnd.y = wallBaseLine.y2; getAddLine({ x: newPEnd.x, y: wallBaseLine.y2 }, { x: wallBaseLine.x2, y: wallBaseLine.y2 }) - } else if (newPStart.y <= wallBaseLine.y1 && wallBaseLine.y1 <= newPEnd.y && newPEnd.y <= wallBaseLine.y2) { + } else if (newPStart.y <= wallBaseLine.y1 && wallBaseLine.y1 <= newPEnd.y && newPEnd.y <= wallBaseLine.y2) { //top left newPEnd.y = wallBaseLine.y2; getAddLine({ x: newPEnd.x, y: wallBaseLine.y2 }, { x: wallBaseLine.x2, y: wallBaseLine.y2 }) + findPoints.push({ x: wallBaseLine.x2, y: wallBaseLine.y2 }); } else if (wallBaseLine.y1 <= newPStart.y && newPStart.y <= wallBaseLine.y2 && wallBaseLine.y2 <= newPEnd.y) { newPStart.y = wallBaseLine.y1; @@ -923,13 +887,19 @@ if(roof.moveUpDown??0 > 0) { } else if (getOrientation(roofLine) === 'horizontal') { - if (newPEnd.x <= wallBaseLine.x2 && wallBaseLine.x2 <= newPStart.x && newPStart.x <= wallBaseLine.x1) { //위 왼쪽 + if (newPEnd.x <= wallBaseLine.x2 && wallBaseLine.x2 <= newPStart.x && newPStart.x <= wallBaseLine.x1) { //top left newPStart.x = wallBaseLine.x1; - getAddLine({ x: wallBaseLine.x1, y: newPEnd.y }, { x: wallBaseLine.x1, y: wallBaseLine.y1 }) - } else if (wallBaseLine.x2 <= newPEnd.x && newPEnd.x <= wallBaseLine.x1 && wallBaseLine.x1 <= newPStart.x) { //아래오르쪽 - newPEnd.x = wallBaseLine.x2; - getAddLine({ x: wallBaseLine.x2, y: newPEnd.y }, { x: wallBaseLine.x2, y: wallBaseLine.y2 }) + //추가 수직 + getAddLine({ x: wallBaseLine.x1, y: newPEnd.y }, { x: wallBaseLine.x1, y: wallBaseLine.y1 }, ) + //추가 라인? + findPoints.push({ x: wallBaseLine.x1, y: wallBaseLine.y1 }); + } else if (wallBaseLine.x2 <= newPEnd.x && newPEnd.x <= wallBaseLine.x1 && wallBaseLine.x1 <= newPStart.x) { //top right + newPEnd.x = wallBaseLine.x2; + //추가 수직 + getAddLine({ x: wallBaseLine.x2, y: newPEnd.y }, { x: wallBaseLine.x2, y: wallBaseLine.y2 }) + //추가 라인? + findPoints.push({ x: wallBaseLine.x2, y: wallBaseLine.y2 }); } else if (newPStart.x <= wallBaseLine.x1 && wallBaseLine.x1 <= newPEnd.x && newPEnd.x <= wallBaseLine.x2) { //위 오른쪽 newPEnd.x = wallBaseLine.x2; getAddLine({ x: wallBaseLine.x2, y: newPEnd.y }, { x: wallBaseLine.x2, y: wallBaseLine.y2 }) @@ -938,13 +908,15 @@ if(roof.moveUpDown??0 > 0) { newPStart.x = wallBaseLine.x1; getAddLine({ x: wallBaseLine.x1, y: newPEnd.y }, { x: wallBaseLine.x1, y: wallBaseLine.y1 }) - } else if (wallBaseLine.x2 <= newPEnd.x && newPEnd.x <= newPStart.x && newPStart.x <= wallBaseLine.x1) { // 위가운데 + } else if (wallBaseLine.x2 <= newPEnd.x && newPEnd.x <= newPStart.x && newPStart.x <= wallBaseLine.x1) { // top center newPEnd.x = wallBaseLine.x2; getAddLine({ x: wallBaseLine.x2, y: newPEnd.y }, { x: wallBaseLine.x2, y: wallBaseLine.y2 }) newPStart.x = wallBaseLine.x1; getAddLine({ x: wallBaseLine.x1, y: newPEnd.y }, { x: wallBaseLine.x1, y: wallBaseLine.y1 }) - + //추가 라인? + findPoints.push({ x: wallBaseLine.x2, y: wallBaseLine.y2 }); + findPoints.push({ x: wallBaseLine.x1, y: wallBaseLine.y1 }); } else if (wallBaseLine.x1 <= newPStart.x && newPStart.x <= newPEnd.x && newPEnd.x <= wallBaseLine.x2) { // 아래가운데 newPEnd.x = wallBaseLine.x1; getAddLine({ x: wallBaseLine.x1, y: newPEnd.y }, { x: wallBaseLine.x1, y: wallBaseLine.y1 }) @@ -1030,6 +1002,10 @@ if(roof.moveUpDown??0 > 0) { newPStart = { y: roofLine.y1, x: roofLine.x1 } newPEnd = { y: roofLine.y2, x: (isCross) ? currentRoofLine.x1 : wallBaseLine.x1 } + }else if (wallBaseLine.x2 <= newPEnd.x && newPEnd.x <= newPStart.x && newPStart.x <= wallBaseLine.x1) { //right / top + + newPStart = { y: roofLine.y1, x: (isCross) ? currentRoofLine.x1 : wallBaseLine.x1 } + newPEnd ={ y: roofLine.y2, x: roofLine.x2 } } //newPEnd = { x: (isCross) ? currentRoofLine.x1 : origin.x1, y: roofLine.y1 } //수직라인 접점까지지 @@ -1068,7 +1044,10 @@ if(roof.moveUpDown??0 > 0) { newPStart = { x: roofLine.x1, y: roofLine.y1 } newPEnd = { x: roofLine.x2, y: (isCross) ? currentRoofLine.y2 : wallBaseLine.y2 } - + //대각선 라인을 보조라인으로 그린다. + if(isCross){ + getAddLine({ x: roofLine.x2, y: currentRoofLine.y2 }, { x: roofLine.x2, y: roofLine.y2 }, 'red') + } }else if(wallBaseLine.y1 <= newPStart.y && newPStart.y <= wallBaseLine.y2 && wallBaseLine.y2 <= newPEnd.y) { //하단 오른쪽v newPStart = { x: roofLine.x1, y: (isCross) ? currentRoofLine.y1 : wallBaseLine.y1 } @@ -1116,6 +1095,10 @@ if(roof.moveUpDown??0 > 0) { newPStart = { y: roofLine.y1, x: roofLine.x1 } newPEnd = { y: roofLine.y2, x: (isCross) ? currentRoofLine.x2 : wallBaseLine.x2 } + + }else if (wallBaseLine.x2 <= newPEnd.x && newPEnd.x <= newPStart.x && newPStart.x <= wallBaseLine.x1){ //top center + newPStart = { y: roofLine.y1, x: roofLine.x1 } + newPEnd = { y: roofLine.y2, x: (isCross) ? currentRoofLine.x2 : wallBaseLine.x2 } } // newPStart = { x: roofLine.x2, y: roofLine.y2 } @@ -1136,12 +1119,21 @@ if(roof.moveUpDown??0 > 0) { //polygon 만들기 console.log("innerLines:::::", innerLines) console.log("movedLines", movedLines) + // console.log("updateLines:::::", updateLines) + } // --- 사용 예시 --- // const polygons = findConnectedLines(movedLines, innerLines, canvas, roofId, roof); // console.log("polygon", polygons); // canvas.renderAll - return innerLines; + if (findPoints.length > 0) { + // 모든 점에 대해 라인 업데이트를 누적 + return findPoints.reduce((lines, point) => { + return updateAndAddLine(lines, point); + }, [...innerLines]); + } + return innerLines; + } /** @@ -2407,41 +2399,41 @@ function getLineDirectionWithOrientation(p1, p2, wall) { * @param {number} epsilon - 허용 오차 * @returns {boolean} */ -function isPointOnLineSegment(point, lineStart, lineEnd, epsilon = 0.1) { - const dx = lineEnd.x - lineStart.x; - const dy = lineEnd.y - lineStart.y; - const length = Math.sqrt(dx * dx + dy * dy); - - if (length === 0) { - // 선분의 길이가 0이면 시작점과의 거리만 확인 - return Math.abs(point.x - lineStart.x) < epsilon && Math.abs(point.y - lineStart.y) < epsilon; - } - - // 점에서 선분의 시작점까지의 벡터 - const toPoint = { x: point.x - lineStart.x, y: point.y - lineStart.y }; - - // 선분 방향으로의 투영 길이 - const t = (toPoint.x * dx + toPoint.y * dy) / (length * length); - - // t가 0과 1 사이에 있어야 선분 위에 있음 - if (t < 0 || t > 1) { - return false; - } - - // 선분 위의 가장 가까운 점 - const closestPoint = { - x: lineStart.x + t * dx, - y: lineStart.y + t * dy - }; - - // 점과 가장 가까운 점 사이의 거리 - const dist = Math.sqrt( - Math.pow(point.x - closestPoint.x, 2) + - Math.pow(point.y - closestPoint.y, 2) - ); - - return dist < epsilon; -} +// function isPointOnLineSegment(point, lineStart, lineEnd, epsilon = 0.1) { +// const dx = lineEnd.x - lineStart.x; +// const dy = lineEnd.y - lineStart.y; +// const length = Math.sqrt(dx * dx + dy * dy); +// +// if (length === 0) { +// // 선분의 길이가 0이면 시작점과의 거리만 확인 +// return Math.abs(point.x - lineStart.x) < epsilon && Math.abs(point.y - lineStart.y) < epsilon; +// } +// +// // 점에서 선분의 시작점까지의 벡터 +// const toPoint = { x: point.x - lineStart.x, y: point.y - lineStart.y }; +// +// // 선분 방향으로의 투영 길이 +// const t = (toPoint.x * dx + toPoint.y * dy) / (length * length); +// +// // t가 0과 1 사이에 있어야 선분 위에 있음 +// if (t < 0 || t > 1) { +// return false; +// } +// +// // 선분 위의 가장 가까운 점 +// const closestPoint = { +// x: lineStart.x + t * dx, +// y: lineStart.y + t * dy +// }; +// +// // 점과 가장 가까운 점 사이의 거리 +// const dist = Math.sqrt( +// Math.pow(point.x - closestPoint.x, 2) + +// Math.pow(point.y - closestPoint.y, 2) +// ); +// +// return dist < epsilon; +// } // selectLine과 baseLines 비교하여 방향 찾기 function findLineDirection(selectLine, baseLines) { @@ -3787,3 +3779,95 @@ function adjustLinePoints({ roofLine, currentRoofLine, wallBaseLine, origin, mov return { newPStart, newPEnd }; } +/** + * 주어진 점을 포함하는 라인을 찾는 함수 + * @param {Array} lines - 검색할 라인 배열 (각 라인은 x1, y1, x2, y2 속성을 가져야 함) + * @param {Object} point - 찾고자 하는 점 {x, y} + * @param {number} [tolerance=0.1] - 점이 선분 위에 있는지 판단할 때의 허용 오차 + * @returns {Object|null} 점을 포함하는 첫 번째 라인 또는 null + */ +function findLineContainingPoint(lines, point, tolerance = 0.1) { + if (!point || !lines || !lines.length) return null; + + return lines.find(line => { + const { x1, y1, x2, y2 } = line; + return isPointOnLineSegment(point, {x: x1, y: y1}, {x: x2, y: y2}, tolerance); + }) || null; +} + +/** + * 점이 선분 위에 있는지 확인하는 함수 + * @param {Object} point - 확인할 점 {x, y} + * @param {Object} lineStart - 선분의 시작점 {x, y} + * @param {Object} lineEnd - 선분의 끝점 {x, y} + * @param {number} tolerance - 허용 오차 + * @returns {boolean} + */ +function isPointOnLineSegment(point, lineStart, lineEnd, tolerance = 0.1) { + const { x: px, y: py } = point; + const { x: x1, y: y1 } = lineStart; + const { x: x2, y: y2 } = lineEnd; + + // 선분의 길이 + const lineLength = Math.hypot(x2 - x1, y2 - y1); + + // 점에서 선분의 양 끝점까지의 거리 합 + const dist1 = Math.hypot(px - x1, py - y1); + const dist2 = Math.hypot(px - x2, py - y2); + + // 점이 선분 위에 있는지 확인 (허용 오차 범위 내에서) + return Math.abs(dist1 + dist2 - lineLength) <= tolerance; +} + +/** + * Updates a line in the innerLines array and returns the updated array + * @param {Array} innerLines - Array of line objects to update + * @param {Object} targetPoint - The point to find the line {x, y} + * @param {Object} wallBaseLine - The base line containing new coordinates + * @param {Function} getAddLine - Function to add a new line + * @returns {Array} Updated array of lines + */ +function updateAndAddLine(innerLines, targetPoint) { + + // 1. Find the line containing the target point + const foundLine = findLineContainingPoint(innerLines, targetPoint); + if (!foundLine) { + console.warn('No line found containing the target point'); + return [...innerLines]; + } + + // 2. Create a new array without the found line + const updatedLines = innerLines.filter(line => + line !== foundLine && + !(line.x1 === foundLine.x1 && + line.y1 === foundLine.y1 && + line.x2 === foundLine.x2 && + line.y2 === foundLine.y2) + ); + + const updatedLine = { + ...foundLine, + x1: targetPoint.x, + y1: targetPoint.y, + x2: foundLine.x2, + y2: foundLine.y2, + startPoint: { x: targetPoint.x, y: targetPoint.y }, + endPoint: foundLine.endPoint || { x: foundLine.x2, y: foundLine.y2 } + }; + + // 4. If it's a Fabric.js object, use set method if available + if (typeof foundLine.set === 'function') { + foundLine.set({ + x1: targetPoint.x, + y1: targetPoint.y, + x2: foundLine.x2, + y2: foundLine.y2 + }); + updatedLines.push(foundLine); + } else { + updatedLines.push(updatedLine); + } + + + return updatedLines; +} \ No newline at end of file