This commit is contained in:
ysCha 2025-11-26 19:06:20 +09:00
parent 89a6787aee
commit e20892188a
2 changed files with 118 additions and 710 deletions

View File

@ -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];

View File

@ -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
}
};
}
}