집추가작업2

This commit is contained in:
Cha 2025-11-17 00:53:43 +09:00
parent eb25b161c0
commit 1ded78a54c

View File

@ -2,13 +2,14 @@ import { LINE_TYPE, POLYGON_TYPE } from '@/common/common'
import { SkeletonBuilder } from '@/lib/skeletons'
import { calcLineActualSize, calcLinePlaneSize, toGeoJSON } from '@/util/qpolygon-utils'
import { QLine } from '@/components/fabric/QLine'
import { getDegreeByChon } from '@/util/canvas-util'
import { findClosestLineToPoint, findOrthogonalPoint, getDegreeByChon } from '@/util/canvas-util'
import Big from 'big.js'
import { line } from 'framer-motion/m'
import { QPolygon } from '@/components/fabric/QPolygon'
import { point } from '@turf/turf'
import { add } from 'mathjs'
import { add, forEach } from 'mathjs'
import wallLine from '@/components/floor-plan/modal/wallLineOffset/type/WallLine'
import * as conole from 'mathjs'
/**
* 지붕 폴리곤의 스켈레톤(중심선) 생성하고 캔버스에 그립니다.
@ -507,6 +508,8 @@ const createInnerLinesFromSkeleton = (roofId, canvas, skeleton, textMode) => {
const addLines = []
const existingLines = new Set(); // 이미 추가된 라인을 추적하기 위한 Set
const outerLines = canvas.getObjects().filter((obj) => obj.name === 'outerLine' && obj.attributes.roofId === roofId)
const baseLines = canvas.getObjects().filter((obj) => obj.name === 'baseLine' && obj.parentId === roofId)
skeletonLines.forEach(sktLine => {
let { p1, p2, attributes, lineStyle } = sktLine;
@ -541,236 +544,347 @@ const createInnerLinesFromSkeleton = (roofId, canvas, skeleton, textMode) => {
roofId: roofId,
});
//skeleton 라인에서 처마선은 삭제
if(innerLine.lineName === 'outerLine'){
//line은 시계방향이다.p1 -> p2
let idx = 0;
//const orgWallLine = wall.lines
//console.log("outLine:::::", p1, p2, line)
let lineExists = false;
for (const orgLine of roof.lines) {
const sameDirection = isSamePoint(p1, orgLine.startPoint) && isSamePoint(p2, orgLine.endPoint);
const oppositeDirection = isSamePoint(p2, orgLine.startPoint) && isSamePoint(p1, orgLine.endPoint);
if (sameDirection || oppositeDirection) {
lineExists = true;
break; // 같은 라인이 발견되면 즉시 순환 종료
}
}
if (!lineExists) {
let p1Line = findClosestRoofLine(p1, roof.lines)
let p2Line = findClosestRoofLine(p2, roof.lines)
let p1wallLine = findClosestRoofLine(p1, wall.baseLines)
let p2wallLine = findClosestRoofLine(p2, wall.baseLines)
console.log("p1LineV",p1Line)
console.log("p2LineV",p2Line)
console.log("p1wallLineV",p1wallLine)
console.log("p2wallLineV",p2wallLine)
//skt는 시계방향 p1 -> p2
//와곽라인은 시계, 반시계
//
//외벽선과 접점이 없으면
if(p1Line.distance > 0 && p2Line.distance > 0) {
}
if(p1Line.distance === 0 && p2Line.distance === 0) {
return
}
console.log("p1Line.line.startPoint.x:::::",p1Line.line.startPoint)
console.log("p1Line.line.endPoint.x:::::",p1Line.line.endPoint)
console.log("p2Line.line.startPoint.x:::::",p2Line.line.startPoint)
console.log("p2Line.line.endPoint.x:::::",p2Line.line.endPoint)
console.log("p1,p2:::::",p1, p2)
if(isSamePoint(p1, p1Line.line.startPoint) || isSamePoint(p1, p1Line.line.endPoint)) {
//p1.y = p2wallLine.line.endPoint.y
return
}
if(isSamePoint(p2, p2Line.line.startPoint) || isSamePoint(p2, p2Line.line.endPoint)) {
//p2.y = p1wallLine.line.endPoint.y
return
}
if(p1Line.distance > 0 && p2Line.distance === 0 ){
console.log("수평이면 수평을 연장")
// p1.x = p1Line.line.endPoint.x
// p1.y = p1Line.line.endPoint.y
// p2.x = p1wallLine.line.endPoint.y
// p2.y =
}
if(p1Line.distance === 0 && p2Line.distance > 0 ) {
console.log("수직이면 수평을 연장")
// p1.x = p2Line.line.endPoint.x
// p1.y = p2Line.line.endPoint.y
// p2.x = p1wallLine.line.endPoint.x
// p2.y = p1.y
}
const orgP1 = { ...p1 };
const orgP2 = { ...p2 };
let p3,p4;
let roofIdx = p2Line.index
const changeLine = roof.lines[roofIdx]
const changeWallLine = wall.baseLines[roofIdx]
p1 = p2Line.line.endPoint //changeLine.startPoint
p2.x = changeWallLine.endPoint.x
p2.y = changeLine.startPoint.y
if(Math.abs(orgP2.y - changeLine.endPoint.y) < 0.1){
p2 = orgP2
}
if(p1Line.distance > p2Line.distance){
//반시계
roofIdx = p1Line.index
const changeLine2 = roof.lines[roofIdx]
const changeWallLine2 = wall.baseLines[roofIdx]
p1 = p1Line.line.endPoint.x//changeLine2.endPoint
p2.x = changeLine2.endPoint.x
p2.y = changeWallLine2.startPoint.y
if(Math.abs(orgP1.x - changeLine2.endPoint.x) < 0.1){
p2 = orgP1
}
}
if (Array.isArray(addLines)) {
// 이미 동일한 p1, p2를 가진 객체가 있는지 확인
const isDuplicate = addLines.some(line =>
(line.p1.x === p1.x && line.p1.y === p1.y &&
line.p2.x === p2.x && line.p2.y === p2.y) ||
(line.p1.x === p2.x && line.p1.y === p2.y &&
line.p2.x === p1.x && line.p2.y === p1.y)
);
if (isDuplicate) {
return; // 중복된 라인이 있으면 함수 종료
}
// 중복이 없으면 추가
addLines.push({p1, p2});
if(addLines.length === 2){
//기존 라인삭제
const existingNewLine2 = canvas.getObjects().find(obj => obj.lineName === "helpLine");
if (existingNewLine2) {
canvas.remove(existingNewLine2);
canvas.renderAll();
}
const line1 = addLines[0];
const line2 = addLines[1];
// Find the common point (the vertex of the right angle)
let commonPoint, p3, p4;
if (line1.p1.x === line2.p1.x || line1.p1.x === line2.p2.x) {
commonPoint = line1.p1;
} else {
commonPoint = line1.p2;
}
// Find the other two points
const otherPoint1 = line1.p1 === commonPoint ? line1.p2 : line1.p1;
const otherPoint2 = line2.p1 === commonPoint ? line2.p2 : line2.p1;
// Calculate the fourth point to form a rectangle
p3 = {
x: otherPoint1.x + (otherPoint2.x - commonPoint.x),
y: otherPoint1.y + (otherPoint2.y - commonPoint.y)
};
// Create the rectangle points in order (clockwise or counter-clockwise)
const rectPoints = [commonPoint, otherPoint1, p3, otherPoint2];
const rect = new QPolygon(rectPoints, {
type: POLYGON_TYPE.ROOF,
fill: 'transparent',
stroke: 'black',
strokeWidth: 2,
selectable: false,
evented: false
});
canvas.add(rect);
canvas.renderAll();
return;
}
}
const lineId = `${p1.x},${p1.y}-${p2.x},${p2.y}`;
const newLine2 = new QLine(
[p1.x, p1.y, p2.x, p2.y],
{
parentId : roof.id,
fontSize : roof.fontSize,
stroke : 'black',
strokeWidth: 2,
name : 'auxiliaryLine',
attributes : attributes,
direction : direction,
isBaseLine : sktLine.attributes.isOuterEdge,
lineName : 'helpLine',
isFixed: true,
selectable : true,
roofId : roofId,
lineId: lineId
}
);
canvas.add(newLine2);
}
//초기외곽라인?
const coordinateText = new fabric.Text(`(${Math.round(p1.x)}, ${Math.round(p1.y)})`, {
left: p1.x + 5, // 좌표점에서 약간 오른쪽으로 이동
top: p1.y - 20, // 좌표점에서 약간 위로 이동
fontSize: 13,
fill: 'red',
fontFamily: 'Arial',
selectable: true,
lockMovementX: false,
lockMovementY: false,
lockRotation: true,
lockScalingX: true,
lockScalingY: true,
name: 'lengthText'
})
canvas?.add(coordinateText)
}else{
canvas.add(innerLine);
canvas.add(innerLine);
innerLine.bringToFront();
existingLines.add(lineKey); // 추가된 라인을 추적
const coordinateText = new fabric.Text(`(${Math.round(p1.x)}, ${Math.round(p1.y)})`, {
left: p1.x + 5, // 좌표점에서 약간 오른쪽으로 이동
top: p1.y - 20, // 좌표점에서 약간 위로 이동
fontSize: 13,
fill: 'red',
fontFamily: 'Arial',
selectable: true,
lockMovementX: false,
lockMovementY: false,
lockRotation: true,
lockScalingX: true,
lockScalingY: true,
name: 'lengthText'
})
canvas?.add(coordinateText)
//skeleton 라인에서 처마선은 삭제
if(innerLine.lineName !== 'outerLine'){
}else{
// let p3, p4
// let idx = 0;
// let isMoveLine = true;
// for(const roofLine of roof.lines){
// if(isSamePoint(p1, roofLine.startPoint) || isSamePoint(p2, roofLine.endPoint)){
// console.log("outerLine1:::::", p1, p2, roofLine, idx)
// isMoveLine = false;
// break;
// }else if(isSamePoint(p1, roofLine.endPoint) || isSamePoint(p2, roofLine.startPoint)){
// console.log("outerLine2:::::", p1, p2, roofLine, idx)
// isMoveLine = false;
// break;
// }
// }
// if(isMoveLine){
// const p1RoofLine = findClosestRoofLine(p1,roof.lines)
// const p2RoofLine = findClosestRoofLine(p2,roof.lines)
// const p1wallLine = findClosestRoofLine(p1,wall.lines)
// const p2wallLine = findClosestRoofLine(p2,wall.lines)
//
// console.log("p1RoofLineV",p1RoofLine)
// console.log("p2RoofLineV",p2RoofLine)
// console.log("p1wallLineV",p1wallLine)
// console.log("p2wallLineV",p2wallLine)
//
//
// if(p1RoofLine.distance > 0 && p2RoofLine.distance === 0){
// console.log("A:::")
// // p1 = p1RoofLine.line.startPoint
// // p2 = p1RoofLine.line.endPoint
// p3 = p1wallLine.line.endPoint
// p4 = p1wallLine.line.startPoint
// }else if(p1RoofLine.distance === 0 && p2RoofLine.distance > 0){
// console.log("B:::")
// // p1 = p2RoofLine.line.startPoint
// // p2 = p2RoofLine.line.endPoint
//
// p3 = p2wallLine.line.endPoint
// p4 = p2wallLine.line.startPoint
// } else if(p1RoofLine.distance > 0 && p2RoofLine.distance > 0){
// if(p1RoofLine.distance > p2RoofLine.distance){
// console.log("C-1:::")
// p1 = p1RoofLine.line.startPoint
// p2 = p1RoofLine.line.endPoint
// p3 = p1wallLine.line.endPoint
// p4 = p1wallLine.line.startPoint
// }else{
// console.log("C-2:::")
// p1 = p2RoofLine.line.startPoint
// p2 = p2RoofLine.line.endPoint
// p3 = p2wallLine.line.endPoint
// p4 = p2wallLine.line.startPoint
// }
// }
//
//
// // 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의 위 또는 오른쪽에 있을때
// const rect = new QPolygon([p1, p2, p3, p4], {
// type: POLYGON_TYPE.ROOF,
// fill: 'transparent',
// stroke: 'red',
// strokeWidth: 2,
// selectable: false,
// evented: false,
// })
// canvas.add(rect)
// canvas.renderAll()
// }
}
// if(innerLine.lineName === 'outerLine'){
// //line은 시계방향이다.p1 -> p2
//
// let idx = 0;
// //const orgWallLine = wall.lines
// //console.log("outLine:::::", p1, p2, line)
//
// let lineExists = false;
//
// for (const orgLine of roof.lines) {
// const sameDirection = isSamePoint(p1, orgLine.startPoint) && isSamePoint(p2, orgLine.endPoint);
// const oppositeDirection = isSamePoint(p2, orgLine.startPoint) && isSamePoint(p1, orgLine.endPoint);
//
// if (sameDirection || oppositeDirection) {
// lineExists = true;
// break; // 같은 라인이 발견되면 즉시 순환 종료
// }
// }
//
// if (!lineExists) {
//
// let p1Line = findClosestRoofLine(p1, roof.lines)
// let p2Line = findClosestRoofLine(p2, roof.lines)
//
// let p1wallLine = findClosestRoofLine(p1, wall.baseLines)
// let p2wallLine = findClosestRoofLine(p2, wall.baseLines)
//
// console.log("p1LineV",p1Line)
// console.log("p2LineV",p2Line)
// console.log("p1wallLineV",p1wallLine)
// console.log("p2wallLineV",p2wallLine)
// //skt는 시계방향 p1 -> p2
// //와곽라인은 시계, 반시계
// //
//
//
// //외벽선과 접점이 없으면
// if(p1Line.distance > 0 && p2Line.distance > 0) {
//
// }
// if(p1Line.distance === 0 && p2Line.distance === 0) {
// return
// }
//
// console.log("p1Line.line.startPoint.x:::::",p1Line.line.startPoint)
// console.log("p1Line.line.endPoint.x:::::",p1Line.line.endPoint)
// console.log("p2Line.line.startPoint.x:::::",p2Line.line.startPoint)
// console.log("p2Line.line.endPoint.x:::::",p2Line.line.endPoint)
//
// console.log("p1,p2:::::",p1, p2)
//
// if(isSamePoint(p1, p1Line.line.startPoint) || isSamePoint(p1, p1Line.line.endPoint)) {
// //p1.y = p2wallLine.line.endPoint.y
// return
//
// }
// if(isSamePoint(p2, p2Line.line.startPoint) || isSamePoint(p2, p2Line.line.endPoint)) {
// //p2.y = p1wallLine.line.endPoint.y
// return
// }
//
//
// if(p1Line.distance > 0 && p2Line.distance === 0 ){
// console.log("수평이면 수평을 연장")
//
// // p1.x = p1Line.line.endPoint.x
// // p1.y = p1Line.line.endPoint.y
// // p2.x = p1wallLine.line.endPoint.y
// // p2.y =
//
//
// }
// if(p1Line.distance === 0 && p2Line.distance > 0 ) {
//
// console.log("수직이면 수평을 연장")
// // p1.x = p2Line.line.endPoint.x
// // p1.y = p2Line.line.endPoint.y
// // p2.x = p1wallLine.line.endPoint.x
// // p2.y = p1.y
//
// }
//
//
// const orgP1 = { ...p1 };
// const orgP2 = { ...p2 };
// let p3,p4;
//
// let roofIdx = p2Line.index
// const changeLine = roof.lines[roofIdx]
// const changeWallLine = wall.baseLines[roofIdx]
//
// p1 = p2Line.line.endPoint //changeLine.startPoint
// p2.x = changeWallLine.endPoint.x
// p2.y = changeLine.startPoint.y
// if(Math.abs(orgP2.y - changeLine.endPoint.y) < 0.1){
// p2 = orgP2
//
// }
//
// if(p1Line.distance > p2Line.distance){
// //반시계
// roofIdx = p1Line.index
// const changeLine2 = roof.lines[roofIdx]
// const changeWallLine2 = wall.baseLines[roofIdx]
// p1 = p1Line.line.endPoint.x//changeLine2.endPoint
// p2.x = changeLine2.endPoint.x
// p2.y = changeWallLine2.startPoint.y
// if(Math.abs(orgP1.x - changeLine2.endPoint.x) < 0.1){
// p2 = orgP1
// }
// }
//
//
// if (Array.isArray(addLines)) {
// // 이미 동일한 p1, p2를 가진 객체가 있는지 확인
// const isDuplicate = addLines.some(line =>
// (line.p1.x === p1.x && line.p1.y === p1.y &&
// line.p2.x === p2.x && line.p2.y === p2.y) ||
// (line.p1.x === p2.x && line.p1.y === p2.y &&
// line.p2.x === p1.x && line.p2.y === p1.y)
// );
//
// if (isDuplicate) {
// return; // 중복된 라인이 있으면 함수 종료
// }
//
// // 중복이 없으면 추가
// addLines.push({p1, p2});
//
//
//
// if(addLines.length === 2){
//
// //기존 라인삭제
//
// const existingNewLine2 = canvas.getObjects().find(obj => obj.lineName === "helpLine");
// if (existingNewLine2) {
// canvas.remove(existingNewLine2);
// canvas.renderAll();
// }
// const line1 = addLines[0];
// const line2 = addLines[1];
// // Find the common point (the vertex of the right angle)
// let commonPoint, p3, p4;
//
// if (line1.p1.x === line2.p1.x || line1.p1.x === line2.p2.x) {
// commonPoint = line1.p1;
// } else {
// commonPoint = line1.p2;
// }
//
// // Find the other two points
// const otherPoint1 = line1.p1 === commonPoint ? line1.p2 : line1.p1;
// const otherPoint2 = line2.p1 === commonPoint ? line2.p2 : line2.p1;
//
// // Calculate the fourth point to form a rectangle
// p3 = {
// x: otherPoint1.x + (otherPoint2.x - commonPoint.x),
// y: otherPoint1.y + (otherPoint2.y - commonPoint.y)
// };
//
// // Create the rectangle points in order (clockwise or counter-clockwise)
// const rectPoints = [commonPoint, otherPoint1, p3, otherPoint2];
//
// const rect = new QPolygon(rectPoints, {
// type: POLYGON_TYPE.ROOF,
// fill: 'transparent',
// stroke: 'black',
// strokeWidth: 2,
// selectable: false,
// evented: false
// });
// canvas.add(rect);
// canvas.renderAll();
// return;
// }
// }
//
// const lineId = `${p1.x},${p1.y}-${p2.x},${p2.y}`;
//
//
// const newLine2 = new QLine(
// [p1.x, p1.y, p2.x, p2.y],
// {
// parentId : roof.id,
// fontSize : roof.fontSize,
// stroke : 'black',
// strokeWidth: 2,
// name : 'auxiliaryLine',
// attributes : attributes,
// direction : direction,
// isBaseLine : sktLine.attributes.isOuterEdge,
// lineName : 'helpLine',
// isFixed: true,
// selectable : true,
// roofId : roofId,
// lineId: lineId
//
// }
// );
//
// canvas.add(newLine2);
// }
//
//
// //초기외곽라인?
// const coordinateText = new fabric.Text(`(${Math.round(p1.x)}, ${Math.round(p1.y)})`, {
// left: p1.x + 5, // 좌표점에서 약간 오른쪽으로 이동
// top: p1.y - 20, // 좌표점에서 약간 위로 이동
// fontSize: 13,
// fill: 'red',
// fontFamily: 'Arial',
// selectable: true,
// lockMovementX: false,
// lockMovementY: false,
// lockRotation: true,
// lockScalingX: true,
// lockScalingY: true,
// name: 'lengthText'
// })
//
// canvas?.add(coordinateText)
//
// }else{
//
// canvas.add(innerLine);
// innerLine.bringToFront();
// existingLines.add(lineKey); // 추가된 라인을 추적
// }
innerLines.push(innerLine)
canvas.renderAll();
});
@ -793,38 +907,143 @@ const createInnerLinesFromSkeleton = (roofId, canvas, skeleton, textMode) => {
// canvas.renderAll()
// });
// 같은 라인이 없으므로 새 다각형 라인 생성
//라인 편집
let outerLines = canvas.getObjects().filter((obj) => obj.name === 'outerLine' && obj.attributes.roofId === roofId)
outerLines.forEach((outerLine) => {
const wallLine = wall.baseLines[outerLine.idx - 1];
const loofLine = roof.lines[outerLine.idx - 1];
// let i = 0
//const outerLines = canvas.getObjects().filter((obj) => obj.name === 'outerLine' && obj.attributes.roofId === roofId)
let roofLineRects = canvas.getObjects().filter((obj) => obj.name === 'roofLineRect' && obj.roofId === roofId)
roofLineRects.forEach((roofLineRect) => {
canvas.remove(roofLineRect)
canvas.renderAll()
})
if(isSamePoint(wallLine.startPoint, outerLine.startPoint) ||
isSamePoint(wallLine.endPoint, outerLine.endPoint)){
wall.baseLines.forEach((wallLine, index) => {
console.log("wallLine:::::", wallLine, index)
let p1,p2,p3, p4
let idx = 0;
let isMoveLine = true;
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}
for(const outerLine of outerLines){
if(isSamePoint(outerLine.startPoint, wallLineStartPoint) || isSamePoint(outerLine.endPoint, wallLineEndPoint)){
console.log("outerLine1:::::", wallLine, idx)
isMoveLine = false;
break;
}
}
if(isMoveLine){
const roofLine = roof.lines[index];
const p1RoofLine = findClosestRoofLine(wallLineStartPoint,roof.lines)
const p2RoofLine = findClosestRoofLine(wallLineEndPoint,roof.lines)
const p1wallLine = findClosestRoofLine(wallLineStartPoint,wall.lines)
const p2wallLine = findClosestRoofLine(wallLineEndPoint,wall.lines)
console.log("p1RoofLineV",p1RoofLine)
console.log("p2RoofLineV",p2RoofLine)
console.log("p1wallLineV",p1wallLine)
console.log("p2wallLineV",p2wallLine)
// const outerLines= canvas.getObjects().filter((obj) => obj.name === 'outerLine' && obj.attributes.roofId === roofId)
// const outerLine = outerLines[index]
// canvas.remove(outerLine)
// canvas.renderAll()
if(p1RoofLine.distance > 0 && p2RoofLine.distance === 0){
console.log("A:::")
p1 = roofLine.startPoint
p2 = roofLine.endPoint
p3 = wallLine.endPoint
p4 = wallLine.startPoint
}else if(p1RoofLine.distance === 0 && p2RoofLine.distance > 0){
console.log("B:::")
p1 = roofLine.endPoint
p2 = roofLine.startPoint
p3 = wallLine.startPoint
p4 = wallLine.endPoint
} else if(p1RoofLine.distance > 0 && p2RoofLine.distance > 0){
if(p1RoofLine.distance > p2RoofLine.distance){
console.log("C-1:::")
p1 = roofLine.startPoint
p2 = roofLine.endPoint
p3 = wallLine.endPoint
p4 = wallLine.startPoint
console.log("C-1-1:::",roofLine.startPoint, wallLineStartPoint, wallLine.endPoint, wallLine.x1, wallLine.x2)
p1 = roofLine.startPoint
//wallLine.startLine은 변경된 라인이 아니라 이전 라인의 값을 가지고 있음 그래서 x1, x2 사용
p3 = wallLineStartPoint
p2.x = p3.x
p2.y = p1.y
p4.x = p1.x
p4.y = (outerLine?.startPoint.x === p1.x)?outerLine.startPoint.y:p3.y
console.log("p1,p2:::::",p1, p2, p3,p4)
}else{
console.log("C-2:::")
p1 = roofLine.endPoint
p2 = roofLine.startPoint
p3 = wallLine.startPoint
p4 = wallLine.endPoint
p1 = roofLine.endPoint
//wallLine.startLine은 변경된 라인이 아니라 이전 라인의 값을 가지고 있음 그래서 x1, x2 사용
p3 = wallLineEndPoint
p2.x = p3.x
p2.y = p1.y
p4.x = p1.x
p4.y = p3.y
}else{
const p1 = loofLine.endPoint
const p2 = wallLine.endPoint
p2.x = p1.x
const newLine2 = new QLine(
[p1.x, p1.y, p2.x, p2.y],
{
parentId : roof.id,
fontSize : roof.fontSize,
stroke : 'black',
strokeWidth: 2,
name : 'auxiliaryLine',
lineName : 'helpLine',
isFixed: true,
selectable : true,
roofId : roofId,
}
);
}
canvas.add(newLine2);
canvas.renderAll();
// 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의 위 또는 오른쪽에 있을때
const rect = new QPolygon([p1, p2, p3, p4], {
type: POLYGON_TYPE.ROOF,
fill: 'transparent',
stroke: 'red',
strokeWidth: 2,
selectable: false,
evented: false,
name: 'roofLineRect',
roofId: roofId,
})
canvas.add(rect)
canvas.renderAll()
}
});
return innerLines;
@ -2045,6 +2264,90 @@ function getLineDirection(p1, p2) {
return 'top'; // (-135 ~ -45)
}
/**
* 라인의 방향과 wall line에서 뻗어 들어가는지(내부로) 아니면 뻗어 나가는지(외부로) 판단합니다.
* @param {Object} p1 - 라인의 시작점 {x, y}
* @param {Object} p2 - 라인의 끝점 {x, y}
* @param {Object} wall - wall 객체 (checkPointInPolygon 메서드 사용 가능)
* @returns {Object} {direction: string, orientation: 'inward'|'outward'|'unknown'}
*/
function getLineDirectionWithOrientation(p1, p2, wall) {
const direction = getLineDirection(p1, p2);
if (!wall) {
return { direction, orientation: 'unknown' };
}
// 라인의 중점과 방향 벡터 계산
const midX = (p1.x + p2.x) / 2;
const midY = (p1.y + p2.y) / 2;
const dx = p2.x - p1.x;
const dy = p2.y - p1.y;
const length = Math.sqrt(dx * dx + dy * dy);
if (length === 0) {
return { direction, orientation: 'unknown' };
}
// 중점에서 라인 방향으로 약간 이동한 점이 wall 내부에 있는지 확인
const testOffset = 10;
const testPoint = {
x: midX + (dx / length) * testOffset,
y: midY + (dy / length) * testOffset
};
const isInside = checkPointInPolygon(testPoint, wall);
return {
direction,
orientation: isInside ? 'inward' : 'outward'
};
}
/**
* 점이 선분 위에 있는지 확인하는 헬퍼 함수
* @param {Object} point - 확인할 {x, y}
* @param {Object} lineStart - 선분의 시작점 {x, y}
* @param {Object} lineEnd - 선분의 끝점 {x, y}
* @param {number} epsilon - 허용 오차
* @returns {boolean}
*/
function isPointOnLineSegment(point, lineStart, lineEnd, epsilon = 0.1) {
const dx = lineEnd.x - lineStart.x;
const dy = lineEnd.y - lineStart.y;
const length = Math.sqrt(dx * dx + dy * dy);
if (length === 0) {
// 선분의 길이가 0이면 시작점과의 거리만 확인
return Math.abs(point.x - lineStart.x) < epsilon && Math.abs(point.y - lineStart.y) < epsilon;
}
// 점에서 선분의 시작점까지의 벡터
const toPoint = { x: point.x - lineStart.x, y: point.y - lineStart.y };
// 선분 방향으로의 투영 길이
const t = (toPoint.x * dx + toPoint.y * dy) / (length * length);
// t가 0과 1 사이에 있어야 선분 위에 있음
if (t < 0 || t > 1) {
return false;
}
// 선분 위의 가장 가까운 점
const closestPoint = {
x: lineStart.x + t * dx,
y: lineStart.y + t * dy
};
// 점과 가장 가까운 점 사이의 거리
const dist = Math.sqrt(
Math.pow(point.x - closestPoint.x, 2) +
Math.pow(point.y - closestPoint.y, 2)
);
return dist < epsilon;
}
// selectLine과 baseLines 비교하여 방향 찾기
function findLineDirection(selectLine, baseLines) {
for (const baseLine of baseLines) {
@ -2076,6 +2379,67 @@ function findLineDirection(selectLine, baseLines) {
return null; // 일치하는 라인이 없는 경우
}
/**
* outerLine의 방향에 따라 올바른 시작점과 끝점을 반환합니다.
* 예를 들어 왼쪽으로 진행하는 라인의 경우, x 좌표가 작은 쪽이 끝점, 쪽이 시작점입니다.
* @param {Object} outerLine - QLine 객체
* @returns {Object} {startPoint: {x, y}, endPoint: {x, y}, direction: string}
*/
function getOuterLinePointsWithDirection(outerLine) {
const direction = getLineDirection(outerLine.startPoint, outerLine.endPoint);
let startPoint, endPoint;
switch (direction) {
case 'left':
// 왼쪽으로 진행: x 좌표가 큰 쪽이 시작점, 작은 쪽이 끝점
if (outerLine.startPoint.x > outerLine.endPoint.x) {
startPoint = outerLine.startPoint;
endPoint = outerLine.endPoint;
} else {
startPoint = outerLine.endPoint;
endPoint = outerLine.startPoint;
}
break;
case 'right':
// 오른쪽으로 진행: x 좌표가 작은 쪽이 시작점, 큰 쪽이 끝점
if (outerLine.startPoint.x < outerLine.endPoint.x) {
startPoint = outerLine.startPoint;
endPoint = outerLine.endPoint;
} else {
startPoint = outerLine.endPoint;
endPoint = outerLine.startPoint;
}
break;
case 'top':
// 위로 진행: y 좌표가 큰 쪽이 시작점, 작은 쪽이 끝점
if (outerLine.startPoint.y > outerLine.endPoint.y) {
startPoint = outerLine.startPoint;
endPoint = outerLine.endPoint;
} else {
startPoint = outerLine.endPoint;
endPoint = outerLine.startPoint;
}
break;
case 'bottom':
// 아래로 진행: y 좌표가 작은 쪽이 시작점, 큰 쪽이 끝점
if (outerLine.startPoint.y < outerLine.endPoint.y) {
startPoint = outerLine.startPoint;
endPoint = outerLine.endPoint;
} else {
startPoint = outerLine.endPoint;
endPoint = outerLine.startPoint;
}
break;
default:
// 기본값: 원래대로 반환
startPoint = outerLine.startPoint;
endPoint = outerLine.endPoint;
}
return { startPoint, endPoint, direction };
}
function getLinePositionRelativeToWall(selectLine, wall) {
// wall의 경계를 가져옵니다.
const bounds = wall.getBoundingRect();