diff --git a/src/util/skeleton-utils.js b/src/util/skeleton-utils.js index e525171b..9faa1671 100644 --- a/src/util/skeleton-utils.js +++ b/src/util/skeleton-utils.js @@ -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();