diff --git a/src/hooks/roofcover/useRoofAllocationSetting.js b/src/hooks/roofcover/useRoofAllocationSetting.js index ae26d4d7..5704b383 100644 --- a/src/hooks/roofcover/useRoofAllocationSetting.js +++ b/src/hooks/roofcover/useRoofAllocationSetting.js @@ -411,37 +411,14 @@ export function useRoofAllocationSetting(id) { obj.name === 'eaveHelpLine' && obj.roofId === roofBase.id ); - const mergedEaveLines = processEaveHelpLines(roofEaveHelpLines); // 기존 라인 제거 roofEaveHelpLines.forEach(line => canvas.remove(line)); - mergedEaveLines.forEach(line => { - const newLine = new QLine([line.x1, line.y1, line.x2, line.y2], { - // 필요한 속성들 유지 - parentId : roofBase.id, - fontSize : 10, - stroke : 'blue', - strokeWidth: 4, - name : 'eaveHelpLine', - lineName : 'eaveHelpLine', - selectable : true, - visible : true, - roofId : roofBase.id, - attributes : { - type: 'eaveHelpLine' - } - // 기타 속성들... - }); - canvas.add(newLine); - }); - - canvas.renderAll(); - if (roofBase.lines) { // Filter out any eaveHelpLines that are already in lines to avoid duplicates const existingEaveLineIds = new Set(roofBase.lines.map(line => line.id)); - const newEaveLines = mergedEaveLines.filter(line => !existingEaveLineIds.has(line.id)); + const newEaveLines = roofEaveHelpLines.filter(line => !existingEaveLineIds.has(line.id)); roofBase.lines = [...roofBase.lines, ...newEaveLines]; } else { roofBase.lines = [...roofEaveHelpLines]; diff --git a/src/util/skeleton-utils.js b/src/util/skeleton-utils.js index 56984fbf..92c92d55 100644 --- a/src/util/skeleton-utils.js +++ b/src/util/skeleton-utils.js @@ -810,6 +810,11 @@ if(roof.moveUpDown??0 > 0) { //현재 roof는 무조건 시계방향 const getAddLine = (p1, p2, stroke = '#1083E3') => { + movedLines.push({ index, p1, p2 }) + +// Usage: + let mergeLines = mergeMovedLines(movedLines); + console.log("mergeLines:::::::", mergeLines); const line = new QLine([p1.x, p1.y, p2.x, p2.y], { parentId : roof.id, fontSize : roof.fontSize, @@ -898,7 +903,7 @@ if(roof.moveUpDown??0 > 0) { } } getAddLine(newPStart, newPEnd, 'red') - movedLines.push({ index, newPStart, newPEnd }) + } else if (movedStart) { //end 변경경 @@ -926,7 +931,7 @@ if(roof.moveUpDown??0 > 0) { } - movedLines.push({ index, newPStart, newPEnd }) + //movedLines.push({ index, newPStart, newPEnd }) console.log("moveStart:::::::::::::", origin, newPStart, newPEnd) getAddLine(newPStart, newPEnd, 'red') @@ -956,7 +961,7 @@ if(roof.moveUpDown??0 > 0) { } console.log("movedEnd:::::::::::::", origin, newPStart, newPEnd) getAddLine(newPStart, newPEnd, 'orange') - movedLines.push({ index, newPStart, newPEnd }) + //movedLines.push({ index, newPStart, newPEnd }) } @@ -975,679 +980,6 @@ if(roof.moveUpDown??0 > 0) { // canvas.renderAll return innerLines; } -/* - let p1,p2,p3, p4 - let idx = 0; - let isMoveLine = false; - - if (wallLine.startPoint.x !== wallLine.x1) wallLine.startPoint.x = wallLine.x1 - if (wallLine.startPoint.y !== wallLine.y1) wallLine.startPoint.y = wallLine.y1 - if (wallLine.endPoint.x !== wallLine.x2) wallLine.endPoint.x = wallLine.x2 - if (wallLine.endPoint.y !== wallLine.y2) wallLine.endPoint.y = wallLine.y2 - - const wallLineStartPoint = {x:wallLine.x1, y:wallLine.y1} - const wallLineEndPoint = {x:wallLine.x2, y:wallLine.y2} - const moveLine = wall.baseLines[index] //이동한 wall 존재여부 (초기 wall line = base line) - - if(index === 2){ - - } - -// // 사용자가 라인을 드래그하기 시작할 때 -// baseLine.on('moving', () => { -// baseLine.attributes.isUserMoved = true -// }) - -// 판별할 때 -// const movedLines = wall.baseLines -// .map((line, index) => ({ index, line })) -// .filter(({ line }) => line.attributes.isUserMoved) - - -// 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) { - - const p1moveLine = findClosestRoofLine(moveLine.startPoint, currentRoofLines) - const p2moveLine = findClosestRoofLine(moveLine.endPoint, currentRoofLines) - const p1RoofLine = findClosestRoofLine(currentRoofLine.startPoint,roof.lines) - const p2RoofLine = findClosestRoofLine(currentRoofLine.endPoint,roof.lines) - - const p1wallLine = findClosestRoofLine(wallLineStartPoint,wall.lines) - const p2wallLine = findClosestRoofLine(wallLineEndPoint,wall.lines) - - - - - - 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) { - -} - - - - if(isMoveLine){ - //wallLine 의 index는 맨 왼쪽 부터 0으로 변경 - - const roofIndex = (wallLine.idx === 0)? wall.lines.length : wallLine.idx //(0-6, 1-1, 2-2, 3-3 - - - - const roofLines = canvas.getObjects().filter(obj => obj.name === 'roof' && obj.id === roofId).map(obj => obj.lines).flat(); - const roofLine = roofLines[roofIndex-1]; - - const currentRoofLines = canvas - .getObjects() - .filter((obj) => obj.lineName === 'roofLine' && obj.parentId === roofId) - - const currentRoofLine = findClosestParallelLine(roofLine, currentRoofLines); - - const testLine2 = new QLine([roofLine.x1, roofLine.y1, roofLine.x2, roofLine.y2], { - stroke: 'red', - strokeWidth: 10, - property: 'normal', - fontSize: 14, - }) - - - const testLine3 = new QLine([currentRoofLine.x1, currentRoofLine.y1, currentRoofLine.x2, currentRoofLine.y2], { - stroke: 'blue', - strokeWidth: 10, - property: 'normal', - fontSize: 14, - }) - //canvas.add(testLine2); - canvas.add(testLine); - //canvas.add(testLine3); - canvas.renderAll() - - - - - - //roof 접점 - const p1RoofLine = findClosestRoofLine(wallLineStartPoint,roof.lines) - const p2RoofLine = findClosestRoofLine(wallLineEndPoint,roof.lines) - //wall 접점 - const p1wallLine = findClosestRoofLine(wallLineStartPoint,wall.lines) - const p2wallLine = findClosestRoofLine(wallLineEndPoint,wall.lines) - //move 접점 - - //wall move 접점 - const p1outerLine = findClosestRoofLine(wallLineStartPoint, currentRoofLines) - const p2outerLine = findClosestRoofLine(wallLineEndPoint, currentRoofLines) - - - // console.log("p1RoofLineV",p1RoofLine) - // console.log("p2RoofLineV",p2RoofLine) - // console.log("p1wallLineV",p1wallLine) - // console.log("p2wallLineV",p2wallLine) - // console.log("p1moveLineV",p1moveLine) - // console.log("p2moveLineV",p2moveLine) - // console.log("p1outerLine",p1outerLine) - // console.log("p2outerLine",p2outerLine) - // const outerLines= canvas.getObjects().filter((obj) => obj.name === 'outerLine' && obj.attributes.roofId === roofId) - // const outerLine = outerLines[index] - // canvas.remove(outerLine) - // canvas.renderAll() - if(Math.abs(p1moveLine.distance - p1outerLine.distance) < 0.1){ - return - } - - // Calculate vectors from moveLine endpoints to wall line - const v1 = {x: wallLine.x1 - moveLine.x1, y: wallLine.y1 - moveLine.y1}; - const v2 = {x: wallLine.x2 - moveLine.x1, y: wallLine.y2 - moveLine.y1}; - const v3 = {x: wallLine.x1 - moveLine.x2, y: wallLine.y1 - moveLine.y2}; - const v4 = {x: wallLine.x2 - moveLine.x2, y: wallLine.y2 - moveLine.y2}; - - // Calculate dot products - const dot1 = v1.x * v2.x + v1.y * v2.y; // For start point - const dot2 = v3.x * v4.x + v3.y * v4.y; // For end point - - const angles = []; - // Check right angles with tolerance - if (Math.abs(dot1) < 0.1) { - angles.push({ - wall: wall, - endpoint: 'start', - point: {x: moveLine.x1, y: moveLine.y1} - }); - } - if (Math.abs(dot2) < 0.1) { - angles.push({ - wall: wall, - endpoint: 'end', - point: {x: moveLine.x2, y: moveLine.y2} - }); - } - - console.log("angels::::::::", angles) - - // currentOuterLines.forEach((line) => { - // line.set('stroke', 'green') // 원하는 색으로 변경 - // }) - // - // if (currentOuterLines.length > 0) { - // canvas.requestRenderAll() - // } - // const candidates = canvas.getObjects().filter((obj) => obj.roofId === roofId) - // console.log('candidates', candidates.map((obj) => obj.lineName)) - - const addHelpLine = (roofLine, wallLine, outerLineA, outerLineB = null) => { - //반시계방향 - const roofLineStartPoint = {x:roofLine.x1, y:roofLine.y1} - const roofLineEndPoint = {x:roofLine.x2, y:roofLine.y2} - const wallLineStartPoint = {x:wallLine.x1, y:wallLine.y1} - const wallLineEndPoint = {x:wallLine.x2, y:wallLine.y2} - const isVertical = wallLineStartPoint.x === wallLineEndPoint.x; - - let newP1, newP2, newP3, newP4; - if(isVertical){ - newP1 = roofLineStartPoint - newP3 = wallLineStartPoint - newP2 = {x:newP1.x, y: newP3.y} - newP4 = {x:Math.abs(outerLineA?.intersectionPoint.y - newP1.y) < 0.1 ? outerLineA?.intersectionPoint.x : newP3.x, y:newP1.y} - }else{ - newP1 = roofLineStartPoint - newP3 = wallLineStartPoint - newP2 = {x:newP3.x, y: newP1.y} - newP4 = {x:newP1.x, y: (Math.abs(outerLineA?.intersectionPoint.x - newP1.x) < 0.1) ? outerLineA?.intersectionPoint.y : newP3.y} - - } - return {newP1, newP2, newP3, newP4} - - }; - - const addHelpLine2 = (roofLine, wallLine, outerLineA, outerLineB=null) => { - //반시계방향 - const roofLineStartPoint = {x:roofLine.x1, y:roofLine.y1} - const roofLineEndPoint = {x:roofLine.x2, y:roofLine.y2} - const wallLineStartPoint = {x:wallLine.x1, y:wallLine.y1} - const wallLineEndPoint = {x:wallLine.x2, y:wallLine.y2} - const isVertical = wallLineStartPoint.x === wallLineEndPoint.x; - - let newP1, newP2, newP3, newP4; - if(isVertical){ - newP1 = roofLineEndPoint - newP3 = wallLineEndPoint - newP2 = {x:newP1.x, y: newP3.y} - newP4 = {x:Math.abs(outerLineB?.intersectionPoint.y - newP1.y) < 0.1 ? outerLineB?.intersectionPoint.x : newP3.x, y:newP1.y} - }else{ - newP1 = roofLineEndPoint - newP3 = wallLineEndPoint - newP2 = {x:newP3.x, y: newP1.y} - newP4 = {x:newP1.x, y: (Math.abs(outerLineB?.intersectionPoint.x - newP1.x) < 0.1) ? outerLineB?.intersectionPoint.y : newP3.y} - - } - return {newP1, newP2, newP3, newP4} - - }; - - const addHelpLineBottom = (roofLine, wallLine, moveLine, outerLine, target) => { - //반시계방향 - const roofLinePoint = (target === 'S') ? {x:roofLine.x1, y:roofLine.y1} : {x:roofLine.x2, y:roofLine.y2} - const moveLinePoint = (target === 'S') ? {x:moveLine.x1, y:moveLine.y1} : {x:moveLine.x2, y:moveLine.y2} - - let newP1, newP2, newP3, newP4; - - newP1 = roofLinePoint - newP3 = moveLinePoint - newP2 = {x:newP3.x, y: newP1.y} - newP4 = {x:newP1.x, y: (Math.abs(outerLine?.intersectionPoint.x - newP1.x) < 0.1) ? outerLine?.intersectionPoint.y : newP3.y} - - return {newP1, newP2, newP3, newP4} - - }; - - const addHelpLineTop = (roofLine, wallLine, moveLine, outerLine, target) => { - //반시계방향 - const roofLinePoint = (target === 'S') ? {x:roofLine.x1, y:roofLine.y1} : {x:roofLine.x2, y:roofLine.y2} - const moveLinePoint = (target === 'S') ? {x:moveLine.x1, y:moveLine.y1} : {x:moveLine.x2, y:moveLine.y2} - - let newP1, newP2, newP3, newP4; - - newP1 = roofLinePoint - newP3 = moveLinePoint - newP2 = {x:newP3.x, y: newP1.y} - newP4 = {x:newP1.x, y: (Math.abs(outerLine?.intersectionPoint.x - newP1.x) < 0.1) ? outerLine?.intersectionPoint.y : newP3.y} - - return {newP1, newP2, newP3, newP4} - - }; - - const addHelpLineLeft = (roofLine, wallLine, moveLine, outerLine, target) => { - //반시계방향 - const roofLinePoint = (target === 'S') ? {x:roofLine.x1, y:roofLine.y1} : {x:roofLine.x2, y:roofLine.y2} - const moveLinePoint = (target === 'S') ? {x:moveLine.x1, y:moveLine.y1} : {x:moveLine.x2, y:moveLine.y2} - - let newP1, newP2, newP3, newP4; - - newP1 = roofLinePoint - newP3 = moveLinePoint - newP2 = {x:newP1.x, y: newP3.y} - newP4 = {x:Math.abs(outerLine?.intersectionPoint.y - newP1.y) < 0.1 ? outerLine?.intersectionPoint.x : newP3.x, y:newP1.y} - - return {newP1, newP2, newP3, newP4} - - }; - - const addHelpLineRight = (roofLine, wallLine, moveLine, outerLine, target) => { - //반시계방향 - const roofLinePoint = (target === 'S') ? {x:roofLine.x1, y:roofLine.y1} : {x:roofLine.x2, y:roofLine.y2} - const moveLinePoint = (target === 'S') ? {x:moveLine.x1, y:moveLine.y1} : {x:moveLine.x2, y:moveLine.y2} - - let newP1, newP2, newP3, newP4; - - newP1 = roofLinePoint - newP3 = moveLinePoint - newP2 = {x:newP1.x, y: newP3.y} - newP4 = {x:Math.abs(outerLine?.intersectionPoint.y - newP1.y) < 0.1 ? outerLine?.intersectionPoint.x : newP3.x, y:newP1.y} - - return {newP1, newP2, newP3, newP4} - - }; - - let isPolygon; - - // Calculate the movement direction - const dx1 = wallLine.x1 - moveLine.x1; - const dy1 = wallLine.y1 - moveLine.y1; - const dx2 = wallLine.x2 - moveLine.x2; - const dy2 = wallLine.y2 - moveLine.y2; - - // Determine movement direction - let moveDirection = 'none'; - -// Check if it's a vertical wall line (x coordinates are equal) - if (Math.abs(wallLine.x1 - wallLine.x2) < 0.1) { - // For vertical lines, check x movement - if (dx1 > 0 || dx2 > 0) { - moveDirection = 'left'; - } else if (dx1 < 0 || dx2 < 0) { - moveDirection = 'right'; - } - } - // Check if it's a horizontal wall line (y coordinates are equal) - else if (Math.abs(wallLine.y1 - wallLine.y2) < 0.1) { - // For horizontal lines, check y movement - if (dy1 > 0 || dy2 > 0) { - moveDirection = 'top'; - } else if (dy1 < 0 || dy2 < 0) { - moveDirection = 'bottom'; - } - } - console.log(`Wall line moved ${moveDirection}`); - - - let changeLine - switch (moveDirection) { - case 'left': - // Handle left movement - if(p1moveLine.distance > p2moveLine.distance) { - changeLine = addHelpLineLeft(roofLine, wallLine, moveLine, p1moveLine, 'S') - - console.log('p1moveLine.distance', p1moveLine.distance); - }else{ - changeLine = addHelpLineLeft(roofLine, wallLine, moveLine, p2moveLine, 'E') - console.log('p2moveLine.distance', p2moveLine.distance); - } - - p1 = changeLine.newP1 - p2 = changeLine.newP2 - p3 = changeLine.newP3 - p4 = changeLine.newP4 - - canvas.remove(p1outerLine.line) - canvas.remove(p2outerLine.line) - - isPolygon = true - // const testLine2 = new QLine([wallLine.x1, wallLine.y1, wallLine.x2, wallLine.y2], { - // stroke: 'red', - // strokeWidth: 10, - // property: 'normal', - // fontSize: 14, - // }) - // const testLine = new QLine([moveLine.x1, moveLine.y1, moveLine.x2, moveLine.y2], { - // stroke: 'yellow', - // strokeWidth: 10, - // property: 'normal', - // fontSize: 14, - // }) - // canvas.add(testLine2); - // canvas.add(testLine); - // canvas.renderAll() - - break; - case 'right': - - if(p1moveLine.distance > p2moveLine.distance) { - changeLine = addHelpLineRight(roofLine, wallLine, moveLine, p1moveLine, 'S') - - console.log('p1moveLine.distance', p1moveLine.distance); - }else{ - changeLine = addHelpLineRight(roofLine, wallLine, moveLine, p2moveLine, 'E') - console.log('p2moveLine.distance', p2moveLine.distance); - } - - p1 = changeLine.newP1 - p2 = changeLine.newP2 - p3 = changeLine.newP3 - p4 = changeLine.newP4 - - canvas.remove(p1outerLine.line) - canvas.remove(p2outerLine.line) - - isPolygon = true - break; - case 'top': - // Handle upward movement - if(p1moveLine.distance > p2moveLine.distance) { - changeLine = addHelpLineTop(roofLine, wallLine, moveLine, p1moveLine, 'S') - console.log('p1moveLine.distance', p1moveLine.distance); - }else{ - changeLine = addHelpLineTop(roofLine, wallLine, moveLine, p2moveLine, 'E') - console.log('p2moveLine.distance', p2moveLine.distance); - } - - p1 = changeLine.newP1 - p2 = changeLine.newP2 - p3 = changeLine.newP3 - p4 = changeLine.newP4 - - canvas.remove(p1outerLine.line) - canvas.remove(p2outerLine.line) - - isPolygon = true - break; - case 'bottom': - // Handle downward movement - if(p1moveLine.distance > p2moveLine.distance) { - changeLine = addHelpLineBottom(roofLine, wallLine, moveLine, p1moveLine, 'S') - console.log('p1moveLine.distance', p1moveLine.distance); - }else{ - changeLine = addHelpLineBottom(roofLine, wallLine, moveLine, p2moveLine, 'E') - console.log('p2moveLine.distance', p2moveLine.distance); - } - - p1 = changeLine.newP1 - p2 = changeLine.newP2 - p3 = changeLine.newP3 - p4 = changeLine.newP4 - - canvas.remove(p1outerLine.line) - canvas.remove(p2outerLine.line) - - isPolygon = true - break; - - default: - // No movement or movement is too small to detect - isPolygon = false - break; - } - - console.log(`Wall line moved ${moveDirection}`); - - -/* - if(p1wallLine.distance > 0 && p2wallLine.distance === 0) { - - console.log("왼쪽 수평 / 오른쪽 수직") - const changeLine = addHelpLine(roofLine, wallLine, p1outerLine, p2outerLine) - - p1 = changeLine.newP1 - p2 = changeLine.newP2 - p3 = changeLine.newP3 - p4 = changeLine.newP4 - - canvas.remove(p1outerLine.line) - canvas.remove(p2outerLine.line) - - isPolygon = true - - - }else if(p2wallLine.distance > 0 && p1wallLine.distance === 0) { - console.log("오른쪽 수평 / 왼쪽 수직") - const changeLine = addHelpLine2(roofLine, wallLine, p1outerLine, p2outerLine) - - p1 = changeLine.newP1 - p2 = changeLine.newP2 - p3 = changeLine.newP3 - p4 = changeLine.newP4 - - canvas.remove(p1outerLine.line) - canvas.remove(p2outerLine.line) - isPolygon = true - }else if(p1wallLine.distance > 0 && p2wallLine.distance > 0) { - - if(p1wallLine.distance > p2wallLine.distance){ - const changeLine = addHelpLine(roofLine, wallLine, p1outerLine, p2outerLine) - console.log("1왼쪽 수평 / 1오른쪽 수직") - console.log("1p1wallLine.distance", p1wallLine.distance); - - p1 = changeLine.newP1 - p2 = changeLine.newP2 - p3 = changeLine.newP3 - p4 = changeLine.newP4 - }else{ - const changeLine = addHelpLine2(roofLine, wallLine, p1outerLine, p2outerLine) - console.log("1오른쪽 수평 / 1왼쪽 수직") - console.log("1p2wallLine.distance", p2wallLine.distance); - p1 = changeLine.newP1 - p2 = changeLine.newP2 - p3 = changeLine.newP3 - p4 = changeLine.newP4 - } - isPolygon = true - - }else { - console.log("p1wallLine.distance", p1wallLine.distance); - console.log("p2wallLine.distance", p2wallLine.distance); - - isPolygon = false - } - - // //targetLines를 p1, p2 로 바꾸고 싶다.. - // const editLine = (targetLines, p1, p2) => { - // targetLines.forEach((line) => { - // line.set({ - // x1: p1.x, - // y1: p1.y, - // x2: p2.x, - // y2: p2.y, - // }) - // - // // QLine은 startPoint/endPoint도 쓰므로 같이 갱신 - // if (line.startPoint) { - // line.startPoint.x = p1.x - // line.startPoint.y = p1.y - // } - // if (line.endPoint) { - // line.endPoint.x = p2.x - // line.endPoint.y = p2.y - // } - // - // // originPoint 같은 커스텀 속성을 쓰면 여기도 맞춰줌 - // if (line.attributes?.originPoint) { - // line.attributes.originPoint = { x1: p1.x, y1: p1.y, x2: p2.x, y2: p2.y } - // } - // }) - // - // - // - // canvas.requestRenderAll() - // // 1) 고유 ID로 찾기 - // const lineToUpdate = targetLines.find((line) => line.id === someLineId) - // if (lineToUpdate) { //특정라인인 - // lineToUpdate.set({ - // x1: newP1.x, - // y1: newP1.y, - // x2: newP2.x, - // y2: newP2.y, - // }) - // lineToUpdate.startPoint.x = newP1.x - // lineToUpdate.startPoint.y = newP1.y - // lineToUpdate.endPoint.x = newP2.x - // lineToUpdate.endPoint.y = newP2.y - // canvas.requestRenderAll() - // } - // - // } - - */ - - // const drawPolygon = (p1,p2,p3,p4) => { - // const rect = new QPolygon([p1, p2, p3, p4], { - // type: POLYGON_TYPE.ROOF, - // fill: 'transparent', - // stroke: 'black', - // strokeWidth: 3, - // selectable: false, - // evented: false, - // name: 'roofLineRect', - // roofId: roofId, - // }) - // canvas.add(rect) - // canvas.renderAll() - // } - // if(isPolygon){ - // drawPolygon( p1,p2,p3, p4) - // } - - // const wallLine = wall.baseLines[roofLine.idx - 1]; - - - // if(p1RoofLine.distance > p2RoofLine.distance){ - // p1 = p2RoofLine.line.endPoint //loofLine.startPoint - // p3 = p2RoofLine.line.endPoint //wallLine.startPoint - // p2 = { x: p1.x, y: p3.y } //x고정, y변동 - // p4 = { x: p3.x, y: p1.y } //x변동 y고정 - // }else{ - // p1 = loofLine.startPoint //loofLine.startPoint - // p3 = wallLine.startPoint //wallLine.startPoint - // p2 = { x: p3.x, y: p1.y } //x고정, y변동 - // p4 = { x: p1.x, y: p3.y } //x변동 y고정 - // } - - - //wallLine이 baseLine의 위 또는 오른쪽에 있을때 - - - // let outerLines = canvas.getObjects().filter((obj) => obj.name === 'outerLine' && obj.attributes.roofId === roofId) - // outerLines.forEach((outerLine) => { - // canvas.remove(outerLine) - // canvas.renderAll() - // }); - - - -// } -// }); -// return innerLines; -// } /** * EAVES(처마) Edge를 처리하여 내부 스켈레톤 선을 추가합니다. @@ -4083,21 +3415,26 @@ function findConnectedLines(aLines, bLines, canvas, roofId, roof) { export const processEaveHelpLines = (lines) => { if (!lines || lines.length === 0) return []; - // 수직/수평 라인 분류 - const verticalLines = lines.filter(line => line.x1 === line.x2); - const horizontalLines = lines.filter(line => line.y1 === line.y2); + // 수직/수평 라인 분류 (부동소수점 오차 고려) + const verticalLines = lines.filter(line => Math.abs(line.x1 - line.x2) < 0.1); + const horizontalLines = lines.filter(line => Math.abs(line.y1 - line.y2) < 0.1); - // 라인 정렬 및 병합 + // 라인 병합 (더 엄격한 조건으로) const mergedVertical = mergeLines(verticalLines, 'vertical'); const mergedHorizontal = mergeLines(horizontalLines, 'horizontal'); + // 결과 확인용 로그 + console.log('Original lines:', lines.length); + console.log('Merged vertical:', mergedVertical.length); + console.log('Merged horizontal:', mergedHorizontal.length); + return [...mergedVertical, ...mergedHorizontal]; }; const mergeLines = (lines, direction) => { - if (lines.length < 2) return lines; + if (!lines || lines.length < 2) return lines || []; - // 방향에 따라 정렬 + // 방향에 따라 정렬 (수직: y1 기준, 수평: x1 기준) lines.sort((a, b) => { const aPos = direction === 'vertical' ? a.y1 : a.x1; const bPos = direction === 'vertical' ? b.y1 : b.x1; @@ -4109,11 +3446,18 @@ const mergeLines = (lines, direction) => { for (let i = 1; i < lines.length; i++) { const line = lines[i]; - const isConnected = direction === 'vertical' - ? current.y2 >= line.y1 - 1 - : current.x2 >= line.x1 - 1; - if (isConnected) { + // 같은 선상에 있는지 확인 (부동소수점 오차 고려) + const isSameLine = direction === 'vertical' + ? Math.abs(current.x1 - line.x1) < 0.1 + : Math.abs(current.y1 - line.y1) < 0.1; + + // 연결 가능한지 확인 (약간의 겹침 허용) + const isConnected = direction === 'vertical' + ? current.y2 + 0.1 >= line.y1 // 약간의 오차 허용 + : current.x2 + 0.1 >= line.x1; + + if (isSameLine && isConnected) { // 라인 병합 current.y2 = Math.max(current.y2, line.y2); current.x2 = direction === 'vertical' ? current.x1 : current.x2; @@ -4123,6 +3467,93 @@ const mergeLines = (lines, direction) => { } } merged.push(current); + + // 병합 결과 로그 + console.log(`Merged ${direction} lines:`, merged); + return merged; }; +function mergeMovedLines(movedLines) { + if (!movedLines || movedLines.length < 2) return movedLines; + + const result = [...movedLines]; // Start with all original lines + const processed = new Set(); + + // First pass: find and merge connected lines + for (let i = 0; i < result.length; i++) { + if (processed.has(i)) continue; + + for (let j = i + 1; j < result.length; j++) { + if (processed.has(j)) continue; + + const line1 = result[i]; + const line2 = result[j]; + + // Skip if lines are not the same type (vertical/horizontal) + const line1Type = getLineType(line1); + const line2Type = getLineType(line2); + if (line1Type !== line2Type) continue; + + if (areLinesConnected(line1, line2, line1Type)) { + // Merge the lines + const merged = mergeTwoLines(line1, line2, line1Type); + + // Replace the first line with merged result + result[i] = merged; + // Mark the second line for removal + processed.add(j); + } + } + } + + // Remove processed lines and keep the order + return result.filter((_, index) => !processed.has(index)); +} + +function getLineType(line) { + if (Math.abs(line.p1.x - line.p2.x) < 0.1) return 'vertical'; + if (Math.abs(line.p1.y - line.p2.y) < 0.1) return 'horizontal'; + return 'other'; +} + +function areLinesConnected(line1, line2, type) { + if (type === 'vertical') { + // For vertical lines, check if x coordinates are the same and y ranges overlap + return Math.abs(line1.p1.x - line2.p1.x) < 0.1 && + Math.min(line1.p2.y, line2.p2.y) >= Math.max(line1.p1.y, line2.p1.y) - 0.1; + } else if (type === 'horizontal') { + // For horizontal lines, check if y coordinates are the same and x ranges overlap + return Math.abs(line1.p1.y - line2.p1.y) < 0.1 && + Math.min(line1.p2.x, line2.p2.x) >= Math.max(line1.p1.x, line2.p1.x) - 0.1; + } + return false; +} + +function mergeTwoLines(line1, line2, type) { + if (type === 'vertical') { + return { + ...line1, // Preserve original properties + p1: { + x: line1.p1.x, + y: Math.min(line1.p1.y, line1.p2.y, line2.p1.y, line2.p2.y) + }, + p2: { + x: line1.p1.x, + y: Math.max(line1.p1.y, line1.p2.y, line2.p1.y, line2.p2.y) + } + }; + } else { // horizontal + return { + ...line1, // Preserve original properties + p1: { + x: Math.min(line1.p1.x, line1.p2.x, line2.p1.x, line2.p2.x), + y: line1.p1.y + }, + p2: { + x: Math.max(line1.p1.x, line1.p2.x, line2.p1.x, line2.p2.x), + y: line1.p1.y + } + }; + } +} \ No newline at end of file