This commit is contained in:
yscha 2025-11-29 15:52:48 +09:00
parent fc6bf3a01d
commit 0718bf052f

View File

@ -2,14 +2,9 @@ import { LINE_TYPE, POLYGON_TYPE } from '@/common/common'
import { SkeletonBuilder } from '@/lib/skeletons' import { SkeletonBuilder } from '@/lib/skeletons'
import { calcLineActualSize, calcLinePlaneSize, toGeoJSON } from '@/util/qpolygon-utils' import { calcLineActualSize, calcLinePlaneSize, toGeoJSON } from '@/util/qpolygon-utils'
import { QLine } from '@/components/fabric/QLine' 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 Big from 'big.js'
import { line } from 'framer-motion/m'
import { QPolygon } from '@/components/fabric/QPolygon' 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 roof = canvas?.getObjects().find((object) => object.id === roofId)
let wall = canvas.getObjects().find((obj) => obj.name === POLYGON_TYPE.WALL && obj.attributes.roofId === roofId) let wall = canvas.getObjects().find((obj) => obj.name === POLYGON_TYPE.WALL && obj.attributes.roofId === roofId)
let skeletonLines = [] let skeletonLines = []
let findPoints = [];
const processedInnerEdges = new Set() const processedInnerEdges = new Set()
@ -764,6 +760,7 @@ if(roof.moveUpDown??0 > 0) {
//wall.baseLine은 움직인라인 //wall.baseLine은 움직인라인
const movedLines = [] const movedLines = []
sortedWallLines.forEach((wallLine, index) => { sortedWallLines.forEach((wallLine, index) => {
@ -840,67 +837,34 @@ if(roof.moveUpDown??0 > 0) {
return line return line
} }
getAddLine(roofLine.startPoint, roofLine.endPoint) getAddLine(roofLine.startPoint, roofLine.endPoint, )
newPStart = { x: roofLine.x1, y: roofLine.y1 } newPStart = { x: roofLine.x1, y: roofLine.y1 }
newPEnd = { x: roofLine.x2, y: roofLine.y2 } newPEnd = { x: roofLine.x2, y: roofLine.y2 }
// Usage in your code: const getInnerLines = (lines, point) => {
// 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()
//두 포인트가 변경된 라인인 //두 포인트가 변경된 라인인
if (fullyMoved) { if (fullyMoved) {
//반시계방향향 //반시계방향향
console.log("moveFully:::::::::::::", wallBaseLine, newPStart, newPEnd) console.log("moveFully:::::::::::::", wallBaseLine, newPStart, newPEnd)
if (getOrientation(roofLine) === 'vertical') { if (getOrientation(roofLine) === 'vertical') {
//왼쪽 부터 roofLine, wallBaseLine //왼쪽 부터 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; newPStart.y = wallBaseLine.y1;
getAddLine({ x: newPEnd.x, y: wallBaseLine.y1 }, { x: wallBaseLine.x1, 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) { } else if (wallBaseLine.y2 <= newPEnd.y && newPEnd.y <= wallBaseLine.y1 && wallBaseLine.y1 <= newPStart.y) {
newPEnd.y = wallBaseLine.y2; newPEnd.y = wallBaseLine.y2;
getAddLine({ x: newPEnd.x, y: wallBaseLine.y2 }, { x: wallBaseLine.x2, 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; newPEnd.y = wallBaseLine.y2;
getAddLine({ x: newPEnd.x, y: wallBaseLine.y2 }, { x: wallBaseLine.x2, 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) { } else if (wallBaseLine.y1 <= newPStart.y && newPStart.y <= wallBaseLine.y2 && wallBaseLine.y2 <= newPEnd.y) {
newPStart.y = wallBaseLine.y1; newPStart.y = wallBaseLine.y1;
@ -923,13 +887,19 @@ if(roof.moveUpDown??0 > 0) {
} else if (getOrientation(roofLine) === 'horizontal') { } 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; 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) { //아래오르쪽 getAddLine({ x: wallBaseLine.x1, y: newPEnd.y }, { x: wallBaseLine.x1, y: wallBaseLine.y1 }, )
newPEnd.x = wallBaseLine.x2; //추가 라인?
getAddLine({ x: wallBaseLine.x2, y: newPEnd.y }, { x: wallBaseLine.x2, y: wallBaseLine.y2 }) 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) { //위 오른쪽 } else if (newPStart.x <= wallBaseLine.x1 && wallBaseLine.x1 <= newPEnd.x && newPEnd.x <= wallBaseLine.x2) { //위 오른쪽
newPEnd.x = wallBaseLine.x2; newPEnd.x = wallBaseLine.x2;
getAddLine({ x: wallBaseLine.x2, y: newPEnd.y }, { x: wallBaseLine.x2, y: wallBaseLine.y2 }) 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; newPStart.x = wallBaseLine.x1;
getAddLine({ x: wallBaseLine.x1, y: newPEnd.y }, { x: wallBaseLine.x1, y: wallBaseLine.y1 }) 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; newPEnd.x = wallBaseLine.x2;
getAddLine({ x: wallBaseLine.x2, y: newPEnd.y }, { x: wallBaseLine.x2, y: wallBaseLine.y2 }) getAddLine({ x: wallBaseLine.x2, y: newPEnd.y }, { x: wallBaseLine.x2, y: wallBaseLine.y2 })
newPStart.x = wallBaseLine.x1; newPStart.x = wallBaseLine.x1;
getAddLine({ x: wallBaseLine.x1, y: newPEnd.y }, { x: wallBaseLine.x1, y: wallBaseLine.y1 }) 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) { // 아래가운데 } else if (wallBaseLine.x1 <= newPStart.x && newPStart.x <= newPEnd.x && newPEnd.x <= wallBaseLine.x2) { // 아래가운데
newPEnd.x = wallBaseLine.x1; newPEnd.x = wallBaseLine.x1;
getAddLine({ x: wallBaseLine.x1, y: newPEnd.y }, { x: wallBaseLine.x1, y: wallBaseLine.y1 }) 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 } newPStart = { y: roofLine.y1, x: roofLine.x1 }
newPEnd = { y: roofLine.y2, x: (isCross) ? currentRoofLine.x1 : wallBaseLine.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 } //수직라인 접점까지지 //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 } newPStart = { x: roofLine.x1, y: roofLine.y1 }
newPEnd = { x: roofLine.x2, y: (isCross) ? currentRoofLine.y2 : wallBaseLine.y2 } 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 }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 } 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 } newPStart = { y: roofLine.y1, x: roofLine.x1 }
newPEnd = { y: roofLine.y2, x: (isCross) ? currentRoofLine.x2 : wallBaseLine.x2 } 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 } // newPStart = { x: roofLine.x2, y: roofLine.y2 }
@ -1136,12 +1119,21 @@ if(roof.moveUpDown??0 > 0) {
//polygon 만들기 //polygon 만들기
console.log("innerLines:::::", innerLines) console.log("innerLines:::::", innerLines)
console.log("movedLines", movedLines) console.log("movedLines", movedLines)
// console.log("updateLines:::::", updateLines)
} }
// --- 사용 예시 --- // --- 사용 예시 ---
// const polygons = findConnectedLines(movedLines, innerLines, canvas, roofId, roof); // const polygons = findConnectedLines(movedLines, innerLines, canvas, roofId, roof);
// console.log("polygon", polygons); // console.log("polygon", polygons);
// canvas.renderAll // 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 - 허용 오차 * @param {number} epsilon - 허용 오차
* @returns {boolean} * @returns {boolean}
*/ */
function isPointOnLineSegment(point, lineStart, lineEnd, epsilon = 0.1) { // function isPointOnLineSegment(point, lineStart, lineEnd, epsilon = 0.1) {
const dx = lineEnd.x - lineStart.x; // const dx = lineEnd.x - lineStart.x;
const dy = lineEnd.y - lineStart.y; // const dy = lineEnd.y - lineStart.y;
const length = Math.sqrt(dx * dx + dy * dy); // const length = Math.sqrt(dx * dx + dy * dy);
//
if (length === 0) { // if (length === 0) {
// 선분의 길이가 0이면 시작점과의 거리만 확인 // // 선분의 길이가 0이면 시작점과의 거리만 확인
return Math.abs(point.x - lineStart.x) < epsilon && Math.abs(point.y - lineStart.y) < epsilon; // 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 toPoint = { x: point.x - lineStart.x, y: point.y - lineStart.y };
//
// 선분 방향으로의 투영 길이 // // 선분 방향으로의 투영 길이
const t = (toPoint.x * dx + toPoint.y * dy) / (length * length); // const t = (toPoint.x * dx + toPoint.y * dy) / (length * length);
//
// t가 0과 1 사이에 있어야 선분 위에 있음 // // t가 0과 1 사이에 있어야 선분 위에 있음
if (t < 0 || t > 1) { // if (t < 0 || t > 1) {
return false; // return false;
} // }
//
// 선분 위의 가장 가까운 점 // // 선분 위의 가장 가까운 점
const closestPoint = { // const closestPoint = {
x: lineStart.x + t * dx, // x: lineStart.x + t * dx,
y: lineStart.y + t * dy // y: lineStart.y + t * dy
}; // };
//
// 점과 가장 가까운 점 사이의 거리 // // 점과 가장 가까운 점 사이의 거리
const dist = Math.sqrt( // const dist = Math.sqrt(
Math.pow(point.x - closestPoint.x, 2) + // Math.pow(point.x - closestPoint.x, 2) +
Math.pow(point.y - closestPoint.y, 2) // Math.pow(point.y - closestPoint.y, 2)
); // );
//
return dist < epsilon; // return dist < epsilon;
} // }
// selectLine과 baseLines 비교하여 방향 찾기 // selectLine과 baseLines 비교하여 방향 찾기
function findLineDirection(selectLine, baseLines) { function findLineDirection(selectLine, baseLines) {
@ -3787,3 +3779,95 @@ function adjustLinePoints({ roofLine, currentRoofLine, wallBaseLine, origin, mov
return { newPStart, newPEnd }; 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;
}