임시
This commit is contained in:
parent
ee0517a952
commit
89a6787aee
@ -29,6 +29,8 @@ import { QcastContext } from '@/app/QcastProvider'
|
|||||||
import { usePlan } from '@/hooks/usePlan'
|
import { usePlan } from '@/hooks/usePlan'
|
||||||
import { roofsState } from '@/store/roofAtom'
|
import { roofsState } from '@/store/roofAtom'
|
||||||
import { useText } from '@/hooks/useText'
|
import { useText } from '@/hooks/useText'
|
||||||
|
import { processEaveHelpLines } from '@/util/skeleton-utils'
|
||||||
|
import { QLine } from '@/components/fabric/QLine'
|
||||||
|
|
||||||
export function useRoofAllocationSetting(id) {
|
export function useRoofAllocationSetting(id) {
|
||||||
const canvas = useRecoilValue(canvasState)
|
const canvas = useRecoilValue(canvasState)
|
||||||
@ -404,6 +406,56 @@ export function useRoofAllocationSetting(id) {
|
|||||||
const wallLines = canvas.getObjects().filter((obj) => obj.name === POLYGON_TYPE.WALL)
|
const wallLines = canvas.getObjects().filter((obj) => obj.name === POLYGON_TYPE.WALL)
|
||||||
roofBases.forEach((roofBase) => {
|
roofBases.forEach((roofBase) => {
|
||||||
try {
|
try {
|
||||||
|
|
||||||
|
const roofEaveHelpLines = canvas.getObjects().filter(obj =>
|
||||||
|
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));
|
||||||
|
roofBase.lines = [...roofBase.lines, ...newEaveLines];
|
||||||
|
} else {
|
||||||
|
roofBase.lines = [...roofEaveHelpLines];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (!roofBase.innerLines) {
|
||||||
|
roofBase.innerLines = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add only eaveHelpLines that belong to this roofBase
|
||||||
|
// const baseEaveHelpLines = roofEaveHelpLines.filter(line => line.roofId === roofBase.id);
|
||||||
|
// roofBase.innerLines = [...new Set([...roofBase.innerLines, ...baseEaveHelpLines])];
|
||||||
|
|
||||||
if (roofBase.separatePolygon.length > 0) {
|
if (roofBase.separatePolygon.length > 0) {
|
||||||
splitPolygonWithSeparate(roofBase.separatePolygon)
|
splitPolygonWithSeparate(roofBase.separatePolygon)
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@ -437,6 +437,55 @@ const createInnerLinesFromSkeleton = (roofId, canvas, skeleton, textMode) => {
|
|||||||
|
|
||||||
const processedInnerEdges = new Set()
|
const processedInnerEdges = new Set()
|
||||||
|
|
||||||
|
const textElements = {};
|
||||||
|
|
||||||
|
const coordinateText = (line) => {
|
||||||
|
// Generate a stable ID for this line
|
||||||
|
const lineKey = `${line.x1},${line.y1},${line.x2},${line.y2}`;
|
||||||
|
|
||||||
|
// Remove existing text elements for this line
|
||||||
|
if (textElements[lineKey]) {
|
||||||
|
textElements[lineKey].forEach(text => {
|
||||||
|
if (canvas.getObjects().includes(text)) {
|
||||||
|
canvas.remove(text);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create start point text
|
||||||
|
const startText = new fabric.Text(`(${Math.round(line.x1)}, ${Math.round(line.y1)})`, {
|
||||||
|
left: line.x1 + 5,
|
||||||
|
top: line.y1 - 20,
|
||||||
|
fontSize: 10,
|
||||||
|
fill: 'green',
|
||||||
|
fontFamily: 'Arial',
|
||||||
|
selectable: false,
|
||||||
|
hasControls: false,
|
||||||
|
hasBorders: false
|
||||||
|
});
|
||||||
|
|
||||||
|
// Create end point text
|
||||||
|
const endText = new fabric.Text(`(${Math.round(line.x2)}, ${Math.round(line.y2)})`, {
|
||||||
|
left: line.x2 + 5,
|
||||||
|
top: line.y2 - 20,
|
||||||
|
fontSize: 10,
|
||||||
|
fill: 'orange',
|
||||||
|
fontFamily: 'Arial',
|
||||||
|
selectable: false,
|
||||||
|
hasControls: false,
|
||||||
|
hasBorders: false
|
||||||
|
});
|
||||||
|
|
||||||
|
// Add to canvas
|
||||||
|
canvas.add(startText, endText);
|
||||||
|
|
||||||
|
// Store references
|
||||||
|
textElements[lineKey] = [startText, endText];
|
||||||
|
|
||||||
|
// Bring lines to front
|
||||||
|
canvas.bringToFront(startText);
|
||||||
|
canvas.bringToFront(endText);
|
||||||
|
};
|
||||||
// 1. 모든 Edge를 순회하며 기본 스켈레톤 선(용마루)을 수집합니다.
|
// 1. 모든 Edge를 순회하며 기본 스켈레톤 선(용마루)을 수집합니다.
|
||||||
|
|
||||||
skeleton.Edges.forEach((edgeResult, index) => {
|
skeleton.Edges.forEach((edgeResult, index) => {
|
||||||
@ -556,10 +605,9 @@ const createInnerLinesFromSkeleton = (roofId, canvas, skeleton, textMode) => {
|
|||||||
lineName: (sktLine.attributes.isOuterEdge)?'roofLine': attributes.type,
|
lineName: (sktLine.attributes.isOuterEdge)?'roofLine': attributes.type,
|
||||||
selectable:(!sktLine.attributes.isOuterEdge),
|
selectable:(!sktLine.attributes.isOuterEdge),
|
||||||
visible: (!sktLine.attributes.isOuterEdge),
|
visible: (!sktLine.attributes.isOuterEdge),
|
||||||
lineNo: (sktLine.attributes.isOuterEdge)? skIndex:0,//그려지는 외곽라인의 순서를 찾아서...
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
coordinateText(skeletonLine)
|
||||||
canvas.add(skeletonLine);
|
canvas.add(skeletonLine);
|
||||||
skeletonLine.bringToFront();
|
skeletonLine.bringToFront();
|
||||||
existingLines.add(lineKey); // 추가된 라인을 추적
|
existingLines.add(lineKey); // 추가된 라인을 추적
|
||||||
@ -588,22 +636,22 @@ const createInnerLinesFromSkeleton = (roofId, canvas, skeleton, textMode) => {
|
|||||||
canvas.renderAll();
|
canvas.renderAll();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if(roof.moveUpDown??0 > 0) {
|
||||||
|
|
||||||
// 같은 라인이 없으므로 새 다각형 라인 생성
|
// 같은 라인이 없으므로 새 다각형 라인 생성
|
||||||
//라인 편집
|
//라인 편집
|
||||||
// let i = 0
|
// let i = 0
|
||||||
const currentRoofLines = canvas.getObjects().filter((obj) => obj.lineName === 'roofLine' && obj.attributes.roofId === roofId)
|
const currentRoofLines = canvas.getObjects().filter((obj) => obj.lineName === 'roofLine' && obj.attributes.roofId === roofId)
|
||||||
let roofLineRects = canvas.getObjects().filter((obj) => obj.name === 'roofLineRect' && obj.roofId === roofId)
|
let roofLineRects = canvas.getObjects().filter((obj) => obj.name === 'roofLineRect' && obj.roofId === roofId)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
roofLineRects.forEach((roofLineRect) => {
|
roofLineRects.forEach((roofLineRect) => {
|
||||||
canvas.remove(roofLineRect)
|
canvas.remove(roofLineRect)
|
||||||
canvas.renderAll()
|
canvas.renderAll()
|
||||||
})
|
})
|
||||||
|
|
||||||
let helpLines = canvas.getObjects().filter((obj) => obj.lineName === 'helpLine' && obj.roofId === roofId)
|
let helpLines = canvas.getObjects().filter((obj) => obj.lineName === 'helpLine' && obj.roofId === roofId)
|
||||||
helpLines.forEach((helpLine) => {
|
helpLines.forEach((helpLine) => {
|
||||||
canvas.remove(helpLine)
|
canvas.remove(helpLine)
|
||||||
canvas.renderAll()
|
canvas.renderAll()
|
||||||
})
|
})
|
||||||
@ -637,29 +685,81 @@ const createInnerLinesFromSkeleton = (roofId, canvas, skeleton, textMode) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// function sortCurrentRoofLines(lines) {
|
// function sortCurrentRoofLines(lines) {
|
||||||
// return [...lines].sort((a, b) => {
|
// return [...lines].sort((a, b) => {
|
||||||
// const aX = a.x1 ?? a.get('x1')
|
// const aX = a.x1 ?? a.get('x1')
|
||||||
// const aY = a.y1 ?? a.get('y1')
|
// const aY = a.y1 ?? a.get('y1')
|
||||||
// const bX = b.x1 ?? b.get('x1')
|
// const bX = b.x1 ?? b.get('x1')
|
||||||
// const bY = b.y1 ?? b.get('y1')
|
// const bY = b.y1 ?? b.get('y1')
|
||||||
|
|
||||||
// if (aX !== bX) return aX - bX
|
// if (aX !== bX) return aX - bX
|
||||||
// return aY - bY
|
// return aY - bY
|
||||||
// })
|
// })
|
||||||
// }
|
// }
|
||||||
|
|
||||||
|
|
||||||
// 각 라인 집합 정렬
|
// 각 라인 집합 정렬
|
||||||
|
|
||||||
|
// roofLines의 방향에 맞춰 currentRoofLines의 방향을 조정
|
||||||
|
const alignLineDirection = (sourceLines, targetLines) => {
|
||||||
|
return sourceLines.map(sourceLine => {
|
||||||
|
// 가장 가까운 targetLine 찾기
|
||||||
|
const nearestTarget = targetLines.reduce((nearest, targetLine) => {
|
||||||
|
const sourceCenter = {
|
||||||
|
x: (sourceLine.x1 + sourceLine.x2) / 2,
|
||||||
|
y: (sourceLine.y1 + sourceLine.y2) / 2
|
||||||
|
};
|
||||||
|
const targetCenter = {
|
||||||
|
x: (targetLine.x1 + targetLine.x2) / 2,
|
||||||
|
y: (targetLine.y1 + targetLine.y2) / 2
|
||||||
|
};
|
||||||
|
const distance = Math.hypot(
|
||||||
|
sourceCenter.x - targetCenter.x,
|
||||||
|
sourceCenter.y - targetCenter.y
|
||||||
|
);
|
||||||
|
|
||||||
|
return !nearest || distance < nearest.distance
|
||||||
|
? { line: targetLine, distance }
|
||||||
|
: nearest;
|
||||||
|
}, null)?.line;
|
||||||
|
|
||||||
|
if (!nearestTarget) return sourceLine;
|
||||||
|
|
||||||
|
// 방향이 반대인지 확인 (벡터 내적을 사용)
|
||||||
|
const sourceVec = {
|
||||||
|
x: sourceLine.x2 - sourceLine.x1,
|
||||||
|
y: sourceLine.y2 - sourceLine.y1
|
||||||
|
};
|
||||||
|
const targetVec = {
|
||||||
|
x: nearestTarget.x2 - nearestTarget.x1,
|
||||||
|
y: nearestTarget.y2 - nearestTarget.y1
|
||||||
|
};
|
||||||
|
|
||||||
|
const dotProduct = sourceVec.x * targetVec.x + sourceVec.y * targetVec.y;
|
||||||
|
|
||||||
|
// 내적이 음수이면 방향이 반대이므로 뒤집기
|
||||||
|
if (dotProduct < 0) {
|
||||||
|
return {
|
||||||
|
...sourceLine,
|
||||||
|
x1: sourceLine.x2,
|
||||||
|
y1: sourceLine.y2,
|
||||||
|
x2: sourceLine.x1,
|
||||||
|
y2: sourceLine.y1
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return sourceLine;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
const sortedWallLines = sortCurrentRoofLines(wall.lines);
|
const sortedWallLines = sortCurrentRoofLines(wall.lines);
|
||||||
const sortedCurrentRoofLines = sortCurrentRoofLines(currentRoofLines);
|
// roofLines의 방향에 맞춰 currentRoofLines 조정 후 정렬
|
||||||
|
const alignedCurrentRoofLines = alignLineDirection(currentRoofLines, roofLines);
|
||||||
|
const sortedCurrentRoofLines = sortCurrentRoofLines(alignedCurrentRoofLines);
|
||||||
const sortedRoofLines = sortCurrentRoofLines(roofLines);
|
const sortedRoofLines = sortCurrentRoofLines(roofLines);
|
||||||
const sortedWallBaseLines = sortCurrentRoofLines(wall.baseLines);
|
const sortedWallBaseLines = sortCurrentRoofLines(wall.baseLines);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//wall.lines 는 기본 벽 라인
|
//wall.lines 는 기본 벽 라인
|
||||||
//wall.baseLine은 움직인라인
|
//wall.baseLine은 움직인라인
|
||||||
const movedLines = []
|
const movedLines = []
|
||||||
@ -672,6 +772,23 @@ const createInnerLinesFromSkeleton = (roofId, canvas, skeleton, textMode) => {
|
|||||||
const moveLine = sortedWallBaseLines[index]
|
const moveLine = sortedWallBaseLines[index]
|
||||||
const wallBaseLine = sortedWallBaseLines[index]
|
const wallBaseLine = sortedWallBaseLines[index]
|
||||||
|
|
||||||
|
console.log('=== Line Coordinates ===');
|
||||||
|
console.table({
|
||||||
|
'Point' : ['X', 'Y'],
|
||||||
|
'roofLine' : [roofLine.x1, roofLine.y1],
|
||||||
|
'currentRoofLine': [currentRoofLine.x1, currentRoofLine.y1],
|
||||||
|
'moveLine' : [moveLine.x1, moveLine.y1],
|
||||||
|
'wallBaseLine' : [wallBaseLine.x1, wallBaseLine.y1]
|
||||||
|
});
|
||||||
|
console.log('End Points:');
|
||||||
|
console.table({
|
||||||
|
'Point' : ['X', 'Y'],
|
||||||
|
'roofLine' : [roofLine.x2, roofLine.y2],
|
||||||
|
'currentRoofLine': [currentRoofLine.x2, currentRoofLine.y2],
|
||||||
|
'moveLine' : [moveLine.x2, moveLine.y2],
|
||||||
|
'wallBaseLine' : [wallBaseLine.x2, wallBaseLine.y2]
|
||||||
|
});
|
||||||
|
|
||||||
const origin = moveLine.attributes?.originPoint
|
const origin = moveLine.attributes?.originPoint
|
||||||
if (!origin) return
|
if (!origin) return
|
||||||
|
|
||||||
@ -698,184 +815,160 @@ const createInnerLinesFromSkeleton = (roofId, canvas, skeleton, textMode) => {
|
|||||||
fontSize : roof.fontSize,
|
fontSize : roof.fontSize,
|
||||||
stroke : stroke,
|
stroke : stroke,
|
||||||
strokeWidth: 4,
|
strokeWidth: 4,
|
||||||
name : 'helpLine',
|
name : 'eaveHelpLine',
|
||||||
lineName : 'helpLine',
|
lineName : 'eaveHelpLine',
|
||||||
selectable : true,
|
selectable : true,
|
||||||
visible : true,
|
visible : true,
|
||||||
roofId : roofId,
|
roofId : roofId,
|
||||||
attributes : {
|
attributes : {
|
||||||
type: 'helpLine'
|
type: 'eaveHelpLine'
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
coordinateText(line)
|
||||||
const coordinateText = new fabric.Text(`(${Math.round(line.x1)}, ${Math.round(line.y1)})`, {
|
|
||||||
left: line.x1 + 5, // 좌표점에서 약간 오른쪽으로 이동
|
|
||||||
top: line.y1 - 20, // 좌표점에서 약간 위로 이동
|
|
||||||
fontSize: 13,
|
|
||||||
fill: 'red',
|
|
||||||
fontFamily: 'Arial',
|
|
||||||
selectable: true,
|
|
||||||
lockMovementX: false,
|
|
||||||
lockMovementY: false,
|
|
||||||
lockRotation: true,
|
|
||||||
lockScalingX: true,
|
|
||||||
lockScalingY: true,
|
|
||||||
name: 'lengthText'
|
|
||||||
})
|
|
||||||
|
|
||||||
canvas?.add(coordinateText)
|
|
||||||
|
|
||||||
canvas.add(line)
|
canvas.add(line)
|
||||||
canvas.renderAll();
|
canvas.renderAll();
|
||||||
return line
|
return line
|
||||||
}
|
}
|
||||||
|
|
||||||
//두 포인트가 변경된 라인인
|
//두 포인트가 변경된 라인인
|
||||||
if (fullyMoved) {
|
if (fullyMoved) {
|
||||||
//반시계방향향
|
//반시계방향향
|
||||||
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 }
|
||||||
|
|
||||||
console.log("moveFully:::::::::::::", wallBaseLine, newPStart, newPEnd)
|
console.log("moveFully:::::::::::::", wallBaseLine, newPStart, newPEnd)
|
||||||
|
|
||||||
if(getOrientation(roofLine) === 'vertical'){
|
if (getOrientation(roofLine) === 'vertical') {
|
||||||
|
|
||||||
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) {
|
||||||
newPStart.y = wallBaseLine.y1;
|
|
||||||
getAddLine({x:newPEnd.x, y:wallBaseLine.y1}, {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){
|
|
||||||
newPEnd.y = wallBaseLine.y2;
|
|
||||||
getAddLine({x:newPEnd.x, y:wallBaseLine.y2}, {x: wallBaseLine.x2, y:wallBaseLine.y2 })
|
|
||||||
} else if(wallBaseLine.y1 <= newPStart.y && newPStart.y <= wallBaseLine.y2 && wallBaseLine.y2 <= newPEnd.y){
|
|
||||||
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 })
|
||||||
} else if(wallBaseLine.y2 <= newPEnd.y && newPStart.y <= wallBaseLine.y1 ) { // 위가운데
|
} 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 })
|
||||||
newPStart.y = wallBaseLine.y1;
|
} else if (newPStart.y <= wallBaseLine.y1 && wallBaseLine.y1 <= newPEnd.y && newPEnd.y <= wallBaseLine.y2) {
|
||||||
getAddLine({x:newPEnd.x, y:wallBaseLine.y1}, {x: wallBaseLine.x1, y:wallBaseLine.y1 })
|
newPEnd.y = wallBaseLine.y2;
|
||||||
} else if(wallBaseLine.y1 <= newPStart.y && newPEnd.y <= wallBaseLine.y2 ) { // 아래가운데
|
getAddLine({ x: newPEnd.x, y: wallBaseLine.y2 }, { x: wallBaseLine.x2, y: wallBaseLine.y2 })
|
||||||
newPEnd.y = wallBaseLine.y1;
|
} else if (wallBaseLine.y1 <= newPStart.y && newPStart.y <= wallBaseLine.y2 && wallBaseLine.y2 <= newPEnd.y) {
|
||||||
getAddLine({x:newPEnd.x, y:wallBaseLine.y1}, {x: wallBaseLine.x1, y:wallBaseLine.y1 })
|
newPStart.y = wallBaseLine.y1;
|
||||||
newPStart.y = wallBaseLine.y2;
|
getAddLine({ x: newPEnd.x, y: wallBaseLine.y1 }, { x: wallBaseLine.x1, y: wallBaseLine.y1 })
|
||||||
getAddLine({x:newPStart.x, y:wallBaseLine.y2}, {x: wallBaseLine.x2, y:wallBaseLine.y2 })
|
} else if (wallBaseLine.y2 <= newPEnd.y && newPStart.y <= wallBaseLine.y1) { // 위가운데
|
||||||
}
|
newPEnd.y = wallBaseLine.y2;
|
||||||
|
getAddLine({ x: newPEnd.x, y: wallBaseLine.y2 }, { x: wallBaseLine.x2, y: wallBaseLine.y2 })
|
||||||
|
newPStart.y = wallBaseLine.y1;
|
||||||
}else if(getOrientation(roofLine) === 'horizontal') {
|
getAddLine({ x: newPEnd.x, y: wallBaseLine.y1 }, { x: wallBaseLine.x1, y: wallBaseLine.y1 })
|
||||||
|
} else if (wallBaseLine.y1 <= newPStart.y && newPEnd.y <= wallBaseLine.y2) { // 아래가운데
|
||||||
|
newPEnd.y = wallBaseLine.y1;
|
||||||
|
getAddLine({ x: newPEnd.x, y: wallBaseLine.y1 }, { x: wallBaseLine.x1, y: wallBaseLine.y1 })
|
||||||
|
newPStart.y = wallBaseLine.y2;
|
||||||
|
getAddLine({ x: newPStart.x, y: wallBaseLine.y2 }, { x: wallBaseLine.x2, y: wallBaseLine.y2 })
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
if(newPEnd.x <= wallBaseLine.x2 && wallBaseLine.x2 <= newPStart.x && newPStart.x <= wallBaseLine.x1){ //위 왼쪽
|
} else if (getOrientation(roofLine) === 'horizontal') {
|
||||||
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})
|
|
||||||
|
|
||||||
} 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})
|
|
||||||
|
|
||||||
} else if(wallBaseLine.x1 <= newPStart.x && newPStart.x <= wallBaseLine.x2 && wallBaseLine.x2 <= newPEnd.x){ //아래 왼쪽
|
if (newPEnd.x <= wallBaseLine.x2 && wallBaseLine.x2 <= newPStart.x && newPStart.x <= wallBaseLine.x1) { //위 왼쪽
|
||||||
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 <= wallBaseLine.x1 && wallBaseLine.x1 <= newPStart.x) { //아래오르쪽
|
||||||
|
newPEnd.x = wallBaseLine.x2;
|
||||||
|
getAddLine({ x: wallBaseLine.x2, y: newPEnd.y }, { x: wallBaseLine.x2, y: wallBaseLine.y2 })
|
||||||
|
|
||||||
} else if(wallBaseLine.x2 <= newPEnd.x && newPEnd.x <= newPStart.x && newPStart.x <= wallBaseLine.x1 ) { // 위가운데
|
} 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 })
|
||||||
|
|
||||||
newPEnd.x = wallBaseLine.x2;
|
} else if (wallBaseLine.x1 <= newPStart.x && newPStart.x <= wallBaseLine.x2 && wallBaseLine.x2 <= newPEnd.x) { //아래 왼쪽
|
||||||
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})
|
|
||||||
|
|
||||||
} else if(wallBaseLine.x1 <= newPStart.x &&newPStart.x <= newPEnd.x&&newPEnd.x <= wallBaseLine.x2 ) { // 아래가운데
|
} else if (wallBaseLine.x2 <= newPEnd.x && newPEnd.x <= newPStart.x && newPStart.x <= wallBaseLine.x1) { // 위가운데
|
||||||
newPEnd.x = wallBaseLine.x1;
|
|
||||||
getAddLine({x:wallBaseLine.x1, y:newPEnd.y}, {x:wallBaseLine.x1, y: wallBaseLine.y1})
|
newPEnd.x = wallBaseLine.x2;
|
||||||
newPStart.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;
|
||||||
|
getAddLine({ x: wallBaseLine.x1, y: newPEnd.y }, { 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 })
|
||||||
|
newPStart.x = wallBaseLine.x2;
|
||||||
|
getAddLine({ x: wallBaseLine.x2, y: newPEnd.y }, { x: wallBaseLine.x2, y: wallBaseLine.y2 })
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
getAddLine(newPStart, newPEnd, 'red')
|
||||||
getAddLine(newPStart, newPEnd)
|
movedLines.push({ index, newPStart, newPEnd })
|
||||||
movedLines.push({ index, newPStart, newPEnd })
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
else if(movedStart) { //end 변경경
|
|
||||||
|
|
||||||
|
|
||||||
newPStart = {x:roofLine.x1, y:roofLine.y1}
|
|
||||||
|
|
||||||
if(getOrientation(roofLine) === 'vertical'){
|
} else if (movedStart) { //end 변경경
|
||||||
|
|
||||||
let isCross = false
|
|
||||||
if(Math.abs(currentRoofLine.x2 - roofLine.x1) < 0.1 || Math.abs(currentRoofLine.x1 - roofLine.x2) < 0.1){
|
newPStart = { x: roofLine.x1, y: roofLine.y1 }
|
||||||
|
|
||||||
|
if (getOrientation(roofLine) === 'vertical') {
|
||||||
|
|
||||||
|
let isCross = false
|
||||||
|
if (Math.abs(currentRoofLine.x2 - roofLine.x1) < 0.1 || Math.abs(currentRoofLine.x1 - roofLine.x2) < 0.1) {
|
||||||
isCross = true;
|
isCross = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
newPEnd = {x:roofLine.x1, y:(isCross)? currentRoofLine.y2:origin.y1}
|
newPEnd = { x: roofLine.x1, y: (isCross) ? currentRoofLine.y1 : origin.y1 }
|
||||||
|
|
||||||
}else if(getOrientation(roofLine) === 'horizontal') {
|
} else if (getOrientation(roofLine) === 'horizontal') {
|
||||||
|
|
||||||
let isCross = false
|
let isCross = false
|
||||||
if(Math.abs(currentRoofLine.y1 - roofLine.y2) < 0.1 || Math.abs(currentRoofLine.y2 - roofLine.y1) < 0.1){
|
if (Math.abs(currentRoofLine.y1 - roofLine.y2) < 0.1 || Math.abs(currentRoofLine.y2 - roofLine.y1) < 0.1) {
|
||||||
isCross = true;
|
isCross = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
newPEnd = { x: (isCross) ? currentRoofLine.x1 : origin.x1, y: roofLine.y1 } //수직라인 접점까지지
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
newPEnd = {x:(isCross)? currentRoofLine.x2:origin.x1, y:roofLine.y1} //수직라인 접점까지지
|
movedLines.push({ index, newPStart, newPEnd })
|
||||||
|
console.log("moveStart:::::::::::::", origin, newPStart, newPEnd)
|
||||||
|
getAddLine(newPStart, newPEnd, 'red')
|
||||||
|
|
||||||
|
|
||||||
|
} else if (movedEnd) { //start변경
|
||||||
|
|
||||||
|
//반시계방향
|
||||||
|
newPStart = { x: roofLine.x2, y: roofLine.y2 }
|
||||||
|
|
||||||
|
if (getOrientation(roofLine) === 'vertical') {
|
||||||
|
|
||||||
|
let isCross = false
|
||||||
|
if (Math.abs(currentRoofLine.x2 - roofLine.x1) < 0.1 || Math.abs(currentRoofLine.x1 - roofLine.x2) < 0.1) {
|
||||||
|
isCross = true;
|
||||||
|
}
|
||||||
|
newPEnd = { x: roofLine.x2, y: (isCross) ? currentRoofLine.y2 : origin.y2 } //수직라인 접점까지지
|
||||||
|
|
||||||
|
} else if (getOrientation(roofLine) === 'horizontal') {
|
||||||
|
|
||||||
|
let isCross = false
|
||||||
|
if (Math.abs(currentRoofLine.y2 - roofLine.y1) < 0.1 || Math.abs(currentRoofLine.y1 - roofLine.y2) < 0.1) {
|
||||||
|
isCross = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
newPEnd = { x: (isCross) ? currentRoofLine.x2 : origin.x2, y: roofLine.y2 } //수직라인 접점까지지
|
||||||
|
|
||||||
|
}
|
||||||
|
console.log("movedEnd:::::::::::::", origin, newPStart, newPEnd)
|
||||||
|
getAddLine(newPStart, newPEnd, 'orange')
|
||||||
|
movedLines.push({ index, newPStart, newPEnd })
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
movedLines.push({ index, newPStart, newPEnd })
|
canvas.renderAll()
|
||||||
console.log("moveStart:::::::::::::", origin, newPStart, newPEnd)
|
|
||||||
getAddLine(newPStart, newPEnd)
|
|
||||||
|
|
||||||
|
|
||||||
}else if(movedEnd) { //start변경
|
});
|
||||||
|
|
||||||
//반시계방향
|
|
||||||
newPStart = {x:roofLine.x2, y:roofLine.y2}
|
|
||||||
|
|
||||||
if(getOrientation(roofLine) === 'vertical'){
|
|
||||||
|
|
||||||
let isCross = false
|
|
||||||
if(Math.abs(currentRoofLine.x2 - roofLine.x1) < 0.1 || Math.abs(currentRoofLine.x1 - roofLine.x2) < 0.1){
|
|
||||||
isCross = true;
|
|
||||||
}
|
|
||||||
newPEnd = {x:roofLine.x2, y:(isCross)? currentRoofLine.y1:origin.y2} //수직라인 접점까지지
|
|
||||||
|
|
||||||
}else if(getOrientation(roofLine) === 'horizontal') {
|
|
||||||
|
|
||||||
let isCross = false
|
|
||||||
if(Math.abs(currentRoofLine.y2 - roofLine.y1) < 0.1 || Math.abs(currentRoofLine.y1 - roofLine.y2) < 0.1){
|
|
||||||
isCross = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
newPEnd = {x:(isCross)? currentRoofLine.x1:origin.x2, y:roofLine.y2} //수직라인 접점까지지
|
|
||||||
|
|
||||||
}
|
|
||||||
console.log("movedEnd:::::::::::::", origin, newPStart, newPEnd)
|
|
||||||
getAddLine(newPStart, newPEnd)
|
|
||||||
movedLines.push({ index, newPStart, newPEnd })
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
canvas.renderAll()
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
//polygon 만들기
|
//polygon 만들기
|
||||||
console.log("innerLines:::::", innerLines)
|
console.log("innerLines:::::", innerLines)
|
||||||
console.log("movedLines", movedLines)
|
console.log("movedLines", movedLines)
|
||||||
|
}
|
||||||
// --- 사용 예시 ---
|
// --- 사용 예시 ---
|
||||||
// const polygons = findConnectedLines(movedLines, innerLines, canvas, roofId, roof);
|
// const polygons = findConnectedLines(movedLines, innerLines, canvas, roofId, roof);
|
||||||
// console.log("polygon", polygons);
|
// console.log("polygon", polygons);
|
||||||
@ -886,18 +979,18 @@ console.log("movedLines", movedLines)
|
|||||||
let p1,p2,p3, p4
|
let p1,p2,p3, p4
|
||||||
let idx = 0;
|
let idx = 0;
|
||||||
let isMoveLine = false;
|
let isMoveLine = false;
|
||||||
|
|
||||||
if (wallLine.startPoint.x !== wallLine.x1) wallLine.startPoint.x = wallLine.x1
|
if (wallLine.startPoint.x !== wallLine.x1) wallLine.startPoint.x = wallLine.x1
|
||||||
if (wallLine.startPoint.y !== wallLine.y1) wallLine.startPoint.y = wallLine.y1
|
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.x !== wallLine.x2) wallLine.endPoint.x = wallLine.x2
|
||||||
if (wallLine.endPoint.y !== wallLine.y2) wallLine.endPoint.y = wallLine.y2
|
if (wallLine.endPoint.y !== wallLine.y2) wallLine.endPoint.y = wallLine.y2
|
||||||
|
|
||||||
const wallLineStartPoint = {x:wallLine.x1, y:wallLine.y1}
|
const wallLineStartPoint = {x:wallLine.x1, y:wallLine.y1}
|
||||||
const wallLineEndPoint = {x:wallLine.x2, y:wallLine.y2}
|
const wallLineEndPoint = {x:wallLine.x2, y:wallLine.y2}
|
||||||
const moveLine = wall.baseLines[index] //이동한 wall 존재여부 (초기 wall line = base line)
|
const moveLine = wall.baseLines[index] //이동한 wall 존재여부 (초기 wall line = base line)
|
||||||
|
|
||||||
if(index === 2){
|
if(index === 2){
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// // 사용자가 라인을 드래그하기 시작할 때
|
// // 사용자가 라인을 드래그하기 시작할 때
|
||||||
@ -910,13 +1003,13 @@ console.log("movedLines", movedLines)
|
|||||||
// .map((line, index) => ({ index, line }))
|
// .map((line, index) => ({ index, line }))
|
||||||
// .filter(({ line }) => line.attributes.isUserMoved)
|
// .filter(({ line }) => line.attributes.isUserMoved)
|
||||||
|
|
||||||
|
|
||||||
// Then in your code:
|
// Then in your code:
|
||||||
|
|
||||||
if (!moveLine?.attributes?.originPoint) return
|
if (!moveLine?.attributes?.originPoint) return
|
||||||
|
|
||||||
const { originPoint } = moveLine.attributes
|
const { originPoint } = moveLine.attributes
|
||||||
const moved =
|
const moved =
|
||||||
(Math.abs(moveLine.x1 - originPoint.x1) > 0.1 ||
|
(Math.abs(moveLine.x1 - originPoint.x1) > 0.1 ||
|
||||||
Math.abs(moveLine.y1 - originPoint.y1) > 0.1 )||(
|
Math.abs(moveLine.y1 - originPoint.y1) > 0.1 )||(
|
||||||
Math.abs(moveLine.x2 - originPoint.x2) > 0.1 ||
|
Math.abs(moveLine.x2 - originPoint.x2) > 0.1 ||
|
||||||
@ -938,7 +1031,7 @@ console.log("movedLines", movedLines)
|
|||||||
|
|
||||||
const getPolygonOrientation = baseLines => {
|
const getPolygonOrientation = baseLines => {
|
||||||
if (!baseLines?.length) return 0
|
if (!baseLines?.length) return 0
|
||||||
|
|
||||||
const area2 = baseLines.reduce((sum, line) => {
|
const area2 = baseLines.reduce((sum, line) => {
|
||||||
const x1 = line.get('x1')
|
const x1 = line.get('x1')
|
||||||
const y1 = line.get('y1')
|
const y1 = line.get('y1')
|
||||||
@ -946,10 +1039,10 @@ console.log("movedLines", movedLines)
|
|||||||
const y2 = line.get('y2')
|
const y2 = line.get('y2')
|
||||||
return sum + (x2 - x1) * (y2 + y1) // shoelace 변형
|
return sum + (x2 - x1) * (y2 + y1) // shoelace 변형
|
||||||
}, 0)
|
}, 0)
|
||||||
|
|
||||||
return Math.sign(area2) // +1: CCW, -1: CW, 0: 불명
|
return Math.sign(area2) // +1: CCW, -1: CW, 0: 불명
|
||||||
}
|
}
|
||||||
|
|
||||||
const lineOrientation = (line, polygonOrientation) => {
|
const lineOrientation = (line, polygonOrientation) => {
|
||||||
const x1 = line.get('x1')
|
const x1 = line.get('x1')
|
||||||
const y1 = line.get('y1')
|
const y1 = line.get('y1')
|
||||||
@ -978,7 +1071,7 @@ console.log("movedLines", movedLines)
|
|||||||
})
|
})
|
||||||
// 기존 로직도 이어서 실행
|
// 기존 로직도 이어서 실행
|
||||||
console.log("moveLine", movedLines)
|
console.log("moveLine", movedLines)
|
||||||
|
|
||||||
|
|
||||||
movedLines.forEach(({ index, moveLine, wallLine }) => {
|
movedLines.forEach(({ index, moveLine, wallLine }) => {
|
||||||
console.log(`사용자가 움직인 선 index: ${index}, wallLineId: ${wallLine.id}`)
|
console.log(`사용자가 움직인 선 index: ${index}, wallLineId: ${wallLine.id}`)
|
||||||
@ -996,7 +1089,7 @@ console.log("movedLines", movedLines)
|
|||||||
same(a.x2, a.y2, b.x2, b.y2)
|
same(a.x2, a.y2, b.x2, b.y2)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
const angleBetween = a => b => {
|
const angleBetween = a => b => {
|
||||||
const va = { x: a.x2 - a.x1, y: a.y2 - a.y1 }
|
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 vb = { x: b.x2 - b.x1, y: b.y2 - b.y1 }
|
||||||
@ -1004,7 +1097,7 @@ console.log("movedLines", movedLines)
|
|||||||
const mag = Math.hypot(va.x, va.y) * Math.hypot(vb.x, 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
|
return Math.acos(Math.min(Math.max(dot / mag, -1), 1)) * 180 / Math.PI
|
||||||
}
|
}
|
||||||
|
|
||||||
const rightAngles = []
|
const rightAngles = []
|
||||||
movedLines.forEach((a, i) => {
|
movedLines.forEach((a, i) => {
|
||||||
movedLines.slice(i + 1).forEach(b => {
|
movedLines.slice(i + 1).forEach(b => {
|
||||||
@ -1024,14 +1117,14 @@ console.log("movedLines", movedLines)
|
|||||||
canvas.add(testLine)
|
canvas.add(testLine)
|
||||||
canvas.renderAll()
|
canvas.renderAll()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
// movedLines => [{ line: moveLineObj, index }, ...] : 이동된 것만 담김
|
// movedLines => [{ line: moveLineObj, index }, ...] : 이동된 것만 담김
|
||||||
|
|
||||||
if (moved) {
|
if (moved) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -3987,3 +4080,49 @@ function findConnectedLines(aLines, bLines, canvas, roofId, roof) {
|
|||||||
return results;
|
return results;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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 mergedVertical = mergeLines(verticalLines, 'vertical');
|
||||||
|
const mergedHorizontal = mergeLines(horizontalLines, 'horizontal');
|
||||||
|
|
||||||
|
return [...mergedVertical, ...mergedHorizontal];
|
||||||
|
};
|
||||||
|
|
||||||
|
const mergeLines = (lines, direction) => {
|
||||||
|
if (lines.length < 2) return lines;
|
||||||
|
|
||||||
|
// 방향에 따라 정렬
|
||||||
|
lines.sort((a, b) => {
|
||||||
|
const aPos = direction === 'vertical' ? a.y1 : a.x1;
|
||||||
|
const bPos = direction === 'vertical' ? b.y1 : b.x1;
|
||||||
|
return aPos - bPos;
|
||||||
|
});
|
||||||
|
|
||||||
|
const merged = [];
|
||||||
|
let current = { ...lines[0] };
|
||||||
|
|
||||||
|
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) {
|
||||||
|
// 라인 병합
|
||||||
|
current.y2 = Math.max(current.y2, line.y2);
|
||||||
|
current.x2 = direction === 'vertical' ? current.x1 : current.x2;
|
||||||
|
} else {
|
||||||
|
merged.push(current);
|
||||||
|
current = { ...line };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
merged.push(current);
|
||||||
|
return merged;
|
||||||
|
};
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user