From 3967581b99ae5beea4df0b15a5bc58ccd3e50524 Mon Sep 17 00:00:00 2001 From: Cha Date: Fri, 21 Nov 2025 01:00:45 +0900 Subject: [PATCH] =?UTF-8?q?=EC=A7=91=EC=B6=94=EA=B0=80=EC=9E=91=EC=97=854?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/util/skeleton-utils.js | 154 +++++++++++++++++++++++++++++++++---- 1 file changed, 137 insertions(+), 17 deletions(-) diff --git a/src/util/skeleton-utils.js b/src/util/skeleton-utils.js index 010706ea..41f5e75c 100644 --- a/src/util/skeleton-utils.js +++ b/src/util/skeleton-utils.js @@ -596,9 +596,10 @@ const createInnerLinesFromSkeleton = (roofId, canvas, skeleton, textMode) => { }) + //wall.lines 는 기본 벽 라인 //wall.baseLine은 움직인라인 - + const movedLines = [] wall.lines.forEach((wallLine, index) => { console.log("wallLine:::::", wallLine, index) let p1,p2,p3, p4 @@ -614,32 +615,137 @@ const createInnerLinesFromSkeleton = (roofId, canvas, skeleton, textMode) => { const wallLineEndPoint = {x:wallLine.x2, y:wallLine.y2} const moveLine = wall.baseLines[index] //이동한 wall 존재여부 (초기 wall line = base line) + +// // 사용자가 라인을 드래그하기 시작할 때 +// baseLine.on('moving', () => { +// baseLine.attributes.isUserMoved = true +// }) +// 판별할 때 +// const movedLines = wall.baseLines +// .map((line, index) => ({ index, line })) +// .filter(({ line }) => line.attributes.isUserMoved) - let testLine = new QLine([moveLine.x1, moveLine.y1, moveLine.x2, moveLine.y2], { + +// Then in your code: + + if (!moveLine?.attributes?.originPoint) return + + const { originPoint } = moveLine.attributes + const moved = + (Math.abs(moveLine.x1 - originPoint.x1) > 0.1 || + Math.abs(moveLine.y1 - originPoint.y1) > 0.1 )||( + Math.abs(moveLine.x2 - originPoint.x2) > 0.1 || + Math.abs(moveLine.y2 - originPoint.y2) > 0.1) + + if (moved) { + + let testLine = new QLine([moveLine.x1, moveLine.y1, moveLine.x2, moveLine.y2], { stroke: 'yellow', strokeWidth: 10, property: 'normal', fontSize: 14, }); -// Then in your code: - if (doLinesIntersect(moveLine, wallLine)) { - // Lines intersect, don't add the test line - if (testLine) { - canvas.remove(testLine); - canvas.renderAll(); - } - } else { - // Lines don't intersect, safe to add test line - if (testLine) { - canvas.remove(testLine); - } + canvas.add(testLine) + canvas.renderAll() - - canvas.add(testLine); - canvas.renderAll(); + const getPolygonOrientation = baseLines => { + if (!baseLines?.length) return 0 + + const area2 = baseLines.reduce((sum, line) => { + const x1 = line.get('x1') + const y1 = line.get('y1') + const x2 = line.get('x2') + const y2 = line.get('y2') + return sum + (x2 - x1) * (y2 + y1) // shoelace 변형 + }, 0) + + return Math.sign(area2) // +1: CCW, -1: CW, 0: 불명 } + const lineOrientation = (line, polygonOrientation) => { + const x1 = line.get('x1') + const y1 = line.get('y1') + const x2 = line.get('x2') + const y2 = line.get('y2') + const cross = (x2 - x1) * (y2 + y1) // shoelace 기여 + const sameDirection = Math.sign(cross) === polygonOrientation + return sameDirection ? 'up' : 'down' + } + + const polygonOrientation = getPolygonOrientation(wall.baseLines) + + + movedLines.push({ + index, + wallLine, + moveLine, + coords: { + x1: moveLine.get('x1'), + y1: moveLine.get('y1'), + x2: moveLine.get('x2'), + y2: moveLine.get('y2'), + }, + orientation: getOrientation(moveLine), // 'vertical' / 'horizontal' / ... + direction: lineOrientation(moveLine, polygonOrientation), // 'up = right' or 'down = left' + }) + // 기존 로직도 이어서 실행 + console.log("moveLine", movedLines) + + + movedLines.forEach(({ index, moveLine, wallLine }) => { + console.log(`사용자가 움직인 선 index: ${index}, wallLineId: ${wallLine.id}`) + // 여기에서만 보조선, 텍스트, highlight 등 수행 + }) + + const EPS = 0.1 + + const shareEndpoint = (a, b, eps = 0.1) => { + const same = (ax, ay, bx, by) => Math.hypot(ax - bx, ay - by) < eps + return ( + same(a.x1, a.y1, b.x1, b.y1) || + same(a.x1, a.y1, b.x2, b.y2) || + same(a.x2, a.y2, b.x1, b.y1) || + same(a.x2, a.y2, b.x2, b.y2) + ) + } + + const angleBetween = a => b => { + const va = { x: a.x2 - a.x1, y: a.y2 - a.y1 } + const vb = { x: b.x2 - b.x1, y: b.y2 - b.y1 } + const dot = va.x * vb.x + va.y * vb.y + const mag = Math.hypot(va.x, va.y) * Math.hypot(vb.x, vb.y) + return Math.acos(Math.min(Math.max(dot / mag, -1), 1)) * 180 / Math.PI + } + + const rightAngles = [] + movedLines.forEach((a, i) => { + movedLines.slice(i + 1).forEach(b => { + if (!shareEndpoint(a.coords, b.coords)) return + const angle = angleBetween(a.coords)(b.coords) + if (Math.abs(angle - 90) < 2) rightAngles.push({ a, b, angle }) + }) + }) + + if(rightAngles.length > 0){ + let testLine = new QLine([rightAngles[0].x1, rightAngles[0].y1, rightAngles[0].x2, rightAngles[0].y2], { + stroke: 'yellow', + strokeWidth: 10, + property: 'normal', + fontSize: 14, + }); + canvas.add(testLine) + canvas.renderAll() + } + + + + } +// movedLines => [{ line: moveLineObj, index }, ...] : 이동된 것만 담김 + +if (moved) { + +} @@ -3465,3 +3571,17 @@ function doLinesIntersect(line1, line2) { // If uA and uB are between 0-1, lines are colliding return (uA >= 0 && uA <= 1 && uB >= 0 && uB <= 1); } + +const getOrientation = (line, eps = 0.1) => { + const x1 = line.get('x1') + const y1 = line.get('y1') + const x2 = line.get('x2') + const y2 = line.get('y2') + const dx = Math.abs(x2 - x1) + const dy = Math.abs(y2 - y1) + + if (dx < eps && dy >= eps) return 'vertical' + if (dy < eps && dx >= eps) return 'horizontal' + if (dx < eps && dy < eps) return 'point' + return 'diagonal' +}