로직변경1

This commit is contained in:
ysCha 2025-12-04 19:10:02 +09:00
parent 3663636b5d
commit 3cbfbbd0b3

View File

@ -453,7 +453,7 @@ const createInnerLinesFromSkeleton = (roofId, canvas, skeleton, textMode) => {
left: line.x1 + 5,
top: line.y1 - 20,
fontSize: 10,
fill: 'green',
fill: 'magenta',
fontFamily: 'Arial',
selectable: false,
hasControls: false,
@ -813,12 +813,12 @@ if((roof.moveUpDown??0 > 0) ) {
//현재 roof는 무조건 시계방향
const getAddLine = (p1, p2, stroke = '#1083E3') => {
const getAddLine = (p1, p2, stroke = '') => {
movedLines.push({ index, p1, p2 })
// Usage:
let mergeLines = mergeMovedLines(movedLines);
console.log("mergeLines:::::::", mergeLines);
//console.log("mergeLines:::::::", mergeLines);
const line = new QLine([p1.x, p1.y, p2.x, p2.y], {
parentId : roof.id,
fontSize : roof.fontSize,
@ -855,6 +855,7 @@ if((roof.moveUpDown??0 > 0) ) {
if (fullyMoved ) {
//반시계방향향
console.log("moveFully:::::::::::::", wallBaseLine, newPStart, newPEnd)
console.log("moveFully:::::::::::::", roofLine.direction)
const mLine = getSelectLinePosition(wall, wallBaseLine)
if (getOrientation(roofLine) === 'vertical') {
@ -864,26 +865,68 @@ if((roof.moveUpDown??0 > 0) ) {
(mLine.position === 'right' && wallLine.x1 > wallBaseLine.x1)
? 'in' : 'out';
const condition = `${mLine.position}_${positionType}`;
let isStartEnd = findInteriorPoint(wallBaseLine, sortedWallBaseLines)
let sPoint, ePoint;
switch (condition) {
case 'left_in':
isIn = true
newPEnd.y = wallBaseLine.y2;
getAddLine({ x: newPEnd.x, y: wallBaseLine.y2 }, { x: wallBaseLine.x2, y: wallBaseLine.y2 })
findPoints.push({ x: wallBaseLine.x2, y: wallBaseLine.y2 });
break;
if (isStartEnd.start ) {
const moveDist = Big(wallBaseLine.x1).minus(wallLine.x1).abs().toNumber()
sPoint = {x: wallBaseLine.x1, y: wallBaseLine.y1};
newPEnd.y = wallBaseLine.y2;
newPStart.x = wallBaseLine.x2
getAddLine({ x: newPEnd.x, y: newPEnd.y }, { x: sPoint.x, y: sPoint.y }, 'blue')
findPoints.push({ x: sPoint.x, y: sPoint.y });
const newPointX = Big(roofLine.x1).plus(moveDist).toNumber()
getAddLine({ x: roofLine.x1, y: roofLine.y1 }, { x: newPointX, y: roofLine.y1 }, 'orange')
}else if(isStartEnd.end) {
newPStart.y = roofLine.y1;
newPStart.x = roofLine.x1;
const moveDist = Big(wallBaseLine.x2).minus(wallLine.x2).abs().toNumber()
ePoint = {x: wallBaseLine.x2, y: wallBaseLine.y2};
newPEnd.y = wallBaseLine.y2
findPoints.push({ x: ePoint.x, y: ePoint.y });
const newPointX = Big(roofLine.x1).plus(moveDist).toNumber()
const pDist = Big(wallLine.x1).minus(roofLine.x1).abs().toNumber()
const pLineY = Big(roofLine.y2).minus(0).abs().toNumber()
getAddLine({ x: newPEnd.x, y: newPEnd.y }, { x: ePoint.x, y: ePoint.y }, 'blue')
getAddLine({ x: roofLine.x1, y: roofLine.y1 }, { x: newPointX, y: roofLine.y1 }, 'orange')
if(Math.abs(wallBaseLine.y2 - wallLine.y2) < 0.1) {
getAddLine({ x: roofLine.x1, y: pLineY }, { x: newPointX, y: pLineY }, 'green')
getAddLine({ x: newPointX, y: pLineY }, { x: ePoint.x, y: ePoint.y }, 'pink')
}
}
break;
case 'left_out':
const moveX = Math.abs(wallBaseLine.x1 - wallLine.x1)
const aStartY = Math.abs(newPEnd.y + moveX)
const bStartY = Math.abs(wallLine.y2 + moveX)
findPoints.push({ x: newPEnd.x, y: aStartY });
const inLine = findLineContainingPoint(innerLines, { x: newPEnd.x, y: aStartY })
// console.log("startLines:::::::", inLine);
getAddLine({ x: wallLine.x1, y: roofLine.y2 }, { x: wallLine.x1, y: bStartY })
getAddLine({ x: wallLine.x2, y: bStartY }, { x: inLine.x2, y: inLine.y2 }, 'pink')
const eLineY = Math.abs(bStartY - wallLine.y2)
newPStart.y += eLineY
newPEnd.y = aStartY
if(isStartEnd.start){
const moveX = Math.abs(wallBaseLine.x1 - wallLine.x1)
const aStartY = Math.abs(newPEnd.y + moveX)
const bStartY = Math.abs(wallLine.y2 + moveX)
findPoints.push({ x: newPEnd.x, y: aStartY });
const inLine = findLineContainingPoint(innerLines, { x: newPEnd.x, y: aStartY })
// console.log("startLines:::::::", inLine);
getAddLine({ x: wallLine.x1, y: roofLine.y2 }, { x: wallLine.x1, y: bStartY })
getAddLine({ x: wallLine.x2, y: bStartY }, { x: inLine.x2, y: inLine.y2 }, 'pink')
const eLineY = Math.abs(bStartY - wallLine.y2)
newPStart.y += eLineY
newPEnd.y = aStartY
}else if(isStartEnd.end){
}
break;
case 'right_in':
newPEnd.y = wallBaseLine.y2;
@ -972,17 +1015,34 @@ if((roof.moveUpDown??0 > 0) ) {
const condition = `${mLine.position}_${positionType}`;
let isStartEnd = findInteriorPoint(wallBaseLine, sortedWallBaseLines)
let sPoint, ePoint;
switch (condition) {
case 'top_in':
console.log("findInteriorPoint result:::::::", isStartEnd);
let sPoint, ePoint;
if (isStartEnd.start ) {
const moveDist = Big(wallLine.y1).minus(wallBaseLine.y1).abs().toNumber()
sPoint = {x: wallBaseLine.x1, y: wallBaseLine.y1};
newPStart.x = wallBaseLine.x1;
getAddLine({ x: newPStart.x, y: newPStart.y }, { x: sPoint.x, y: sPoint.y })
const newPointY = Big(roofLine.y2).plus(moveDist).toNumber()
const pDist = Big(wallLine.y2).minus(roofLine.y2).abs().toNumber()
const pLineX = Big(roofLine.x1).minus(0).abs().toNumber()
getAddLine({ x: newPStart.x, y: newPStart.y }, { x: sPoint.x, y: sPoint.y }, 'blue')
findPoints.push({ x: sPoint.x, y: sPoint.y });
if(Math.abs(wallBaseLine.x1 - wallLine.x1) < 0.1) {
getAddLine({ x: pLineX, y: roofLine.y2 }, { x: pLineX, y: newPointY }, 'green')
getAddLine({ x: pLineX, y: newPointY }, { x: sPoint.x, y: sPoint.y }, 'pink')
}
//getAddLine({ x: roofLine.x2, y: roofLine.y2 }, { x: roofLine.x2, y: newPointY }, 'orange')
}
if(isStartEnd.end){
@ -994,7 +1054,6 @@ if((roof.moveUpDown??0 > 0) ) {
break;
case 'top_out':
console.log("findInteriorPoint result:::::::", isStartEnd);
const moveY = Math.abs(wallLine.y1 - wallBaseLine.y1)
@ -1015,9 +1074,46 @@ if((roof.moveUpDown??0 > 0) ) {
break;
case 'bottom_in':
if (isStartEnd.start ) {
const moveDist = Big(wallLine.y1).minus(wallBaseLine.y1).abs().toNumber()
sPoint = {x: wallBaseLine.x1, y: wallBaseLine.y1};
newPStart.x = wallBaseLine.x1;
getAddLine({ x: newPStart.x, y: newPStart.y }, { x: sPoint.x, y: sPoint.y })
findPoints.push({ x: sPoint.x, y: sPoint.y });
const newPointY = Big(roofLine.y2).minus(moveDist).abs().toNumber()
//getAddLine({ x: roofLine.x2, y: roofLine.y2 }, { x: roofLine.x2, y: newPointY }, 'orange')
}
if(isStartEnd.end){
const moveDist = Big(wallLine.y2).minus(wallBaseLine.y2).abs().toNumber()
sPoint = {x: wallBaseLine.x1, y: wallBaseLine.y1};
newPStart.x = wallBaseLine.x1;
getAddLine({ x: newPStart.x, y: newPStart.y }, { x: sPoint.x, y: sPoint.y })
findPoints.push({ x: sPoint.x, y: sPoint.y });
const newPointY = Big(roofLine.y1).minus(moveDist).abs().toNumber()
//getAddLine({ x: roofLine.x1, y: roofLine.y1 }, { x: roofLine.x1, y: newPointY }, 'orange')
}
break;
case 'bottom_out':
// console.log("findInteriorPoint result:::::::", isStartEnd);
//
// const moveY = Math.abs(wallLine.y1 - wallBaseLine.y1)
// const dist = Math.abs(roofLine.y1 - wallLine.y1)
// const aStartX = Math.abs(newPStart.x + moveY)
// const bStartX = Math.abs(wallLine.x1 + moveY)
//
// //newPStart.x += moveX
// //wallLine.x1 += moveX
// findPoints.push({ x: aStartX, y: newPEnd.y });
// const inLine = findLineContainingPoint(innerLines, { x: aStartX, y: newPEnd.y })
// console.log("startLines:::::::", inLine);
// getAddLine({ x: bStartX, y: wallLine.y1 }, { x: roofLine.x1, y: wallLine.y1 })
// getAddLine({ x: bStartX, y: wallLine.y2 }, { x: inLine.x2, y: inLine.y2 }, 'pink')
// const eLineX = Math.abs(bStartX - wallLine.x1)
// newPEnd.x += eLineX
// newPStart.x = aStartX
break;
}
}
@ -1095,72 +1191,115 @@ if((roof.moveUpDown??0 > 0) ) {
}
getAddLine(newPStart, newPEnd, 'red')
}
/*
} else if (movedStart ) { //end 변경경
} /* else if (movedStart ) { //end 변경경
if (getOrientation(roofLine) === 'vertical') { //green 수직
if (getOrientation(roofLine) === 'vertical') { //brown 수직
const mLine = getSelectLinePosition(wall, wallBaseLine)
if (['left', 'right'].includes(mLine.position)) {
const positionType =
(mLine.position === 'left' && wallLine.x1 <= wallBaseLine.x1) ||
(mLine.position === 'right' && wallLine.x1 >= wallBaseLine.x1)
? 'in' : 'out';
const condition = `${mLine.position}_${positionType}`;
let isStartEnd = findInteriorPoint(wallBaseLine, sortedWallBaseLines)
let sPoint, ePoint;
let isCross = false
if (Math.abs(currentRoofLine?.x2 - roofLine.x1) < 0.1 || Math.abs(currentRoofLine?.x1 - roofLine.x2) < 0.1) {
isCross = true;
}
switch (condition) {
case 'left_in':
if(isStartEnd.start){
}else if(isStartEnd.end){
newPStart = { x: roofLine.x1, y: (isCross) ? currentRoofLine.y1 : wallBaseLine.y1 }
newPEnd ={ x: roofLine.x2, y: roofLine.y2 }
}else {
newPStart = { x: roofLine.x1, y: roofLine.y1 }
newPEnd = { x: roofLine.x2, y: (isCross) ? currentRoofLine?.y1 : wallBaseLine.y1 }
}
break;
case 'left_out':
break;
case 'right_in':
newPStart = { x: roofLine.x1, y: (isCross) ? currentRoofLine?.y1 : wallBaseLine.y1 }
newPEnd ={ x: roofLine.x2, y: roofLine.y2 }
//대각선 라인을 보조라인으로 그린다.
if(isCross){
getAddLine({ x: wallBaseLine.x1, y: wallBaseLine.y1 }, { x: roofLine.x1, y: currentRoofLine?.y1 }, 'purple')
}
break;
case 'right_out':
break;
}
}
if(mLine.position === 'left') isIn = true
if(mLine.position === 'right') isOut = true
let isCross = false
if (Math.abs(currentRoofLine?.x2 - roofLine.x1) < 0.1 || Math.abs(currentRoofLine?.x1 - roofLine.x2) < 0.1) {
isCross = true;
}
if(newPStart.y <= wallBaseLine.y1 && wallBaseLine.y1 < wallBaseLine.y2 && wallBaseLine.y2 < newPEnd.y){//in bottom left
if(isIn){
newPStart = { x: roofLine.x1, y: roofLine.y1 }
newPEnd = { x: roofLine.x2, y: (isCross) ? currentRoofLine?.y1 : wallBaseLine.y1 }
}
// if(isIn){
// newPStart = { x: roofLine.x1, y: roofLine.y1 }
// newPEnd = { x: roofLine.x2, y: (isCross) ? currentRoofLine?.y1 : wallBaseLine.y1 }
// }
}else if(newPEnd.y <= wallBaseLine.y2 && wallBaseLine.y2 < wallBaseLine.y1 && wallBaseLine.y1 <= newPStart.y){ //하단 오른쪽v
newPStart = { x: roofLine.x1, y: roofLine.y1 }
newPEnd = { x: roofLine.x2, y: (isCross) ? currentRoofLine?.y1 : wallBaseLine.y1 }
// newPStart = { x: roofLine.x1, y: roofLine.y1 }
// newPEnd = { x: roofLine.x2, y: (isCross) ? currentRoofLine?.y1 : wallBaseLine.y1 }
}else if(newPEnd.y <= wallBaseLine.y2 && wallBaseLine.y2 <= newPStart.y && newPStart.y <= wallBaseLine.y1) { //top right
newPStart = { x: roofLine.x1, y: (isCross) ? currentRoofLine?.y1 : wallBaseLine.y1 }
newPEnd ={ x: roofLine.x2, y: roofLine.y2 }
//대각선 라인을 보조라인으로 그린다.
if(isCross){
getAddLine({ x: wallBaseLine.x1, y: wallBaseLine.y1 }, { x: roofLine.x1, y: currentRoofLine?.y1 }, 'yellow')
}
// newPStart = { x: roofLine.x1, y: (isCross) ? currentRoofLine?.y1 : wallBaseLine.y1 }
// newPEnd ={ x: roofLine.x2, y: roofLine.y2 }
//
// //대각선 라인을 보조라인으로 그린다.
// if(isCross){
// getAddLine({ x: wallBaseLine.x1, y: wallBaseLine.y1 }, { x: roofLine.x1, y: currentRoofLine?.y1 }, 'purple')
// }
}else if(newPStart.y <= wallBaseLine.y1 && wallBaseLine.y1 <= newPEnd.y && newPEnd.y <= wallBaseLine.y2) {//상단 오르쪽
newPStart = { x: roofLine.x1, y: roofLine.y1 }
newPEnd = { x: roofLine.x2, y: (isCross) ? currentRoofLine.y1 : wallBaseLine.y1 }
// newPStart = { x: roofLine.x1, y: roofLine.y1 }
// newPEnd = { x: roofLine.x2, y: (isCross) ? currentRoofLine.y1 : wallBaseLine.y1 }
}else if(wallBaseLine.y1 <= newPStart.y && newPStart.y <= wallBaseLine.y2 && wallBaseLine.y2 <= newPEnd.y) { // out bottom left //bottom left
if(isIn){
newPStart = { x: roofLine.x1, y: (isCross) ? currentRoofLine.y1 : wallBaseLine.y1 }
newPEnd = { x: roofLine.x2, y: roofLine.y2 }
//대각선 라인을 보조라인으로 그린다.
if(isCross){
getAddLine( { x: wallBaseLine.x1, y: wallBaseLine.y1 }, { x: roofLine.x1, y: currentRoofLine.y1 }, 'yellow')
}
}else if(isOut){
}
// if(isIn){
// newPStart = { x: roofLine.x1, y: (isCross) ? currentRoofLine.y1 : wallBaseLine.y1 }
// newPEnd = { x: roofLine.x2, y: roofLine.y2 }
//
// //대각선 라인을 보조라인으로 그린다.
// if(isCross){
// getAddLine( { x: wallBaseLine.x1, y: wallBaseLine.y1 }, { x: roofLine.x1, y: currentRoofLine.y1 }, 'purple')
// }
// }else if(isOut){
//
// }
}else if (wallBaseLine.y2 <= newPEnd.y && newPEnd.y <= wallBaseLine.y1 && wallBaseLine.y1 <= newPStart.y) { //하단 왼쪽
newPStart = { x: roofLine.x1, y: (isCross) ? currentRoofLine.y1 : wallBaseLine.y1 }
newPEnd ={ x: roofLine.x2, y: roofLine.y2 }
// newPStart = { x: roofLine.x1, y: (isCross) ? currentRoofLine.y1 : wallBaseLine.y1 }
// newPEnd ={ x: roofLine.x2, y: roofLine.y2 }
}
} else if (getOrientation(roofLine) === 'horizontal') { //green 수평
} else if (getOrientation(roofLine) === 'horizontal') { //magenta 수평
const mLine = getSelectLinePosition(wall, wallBaseLine)
@ -1193,7 +1332,7 @@ if((roof.moveUpDown??0 > 0) ) {
//대각선 라인을 보조라인으로 그린다.
if(isCross){
getAddLine({ x: currentRoofLine.x1, y: roofLine.y1 }, { x: wallBaseLine.x1, y: wallBaseLine.y1 }, 'yellow')
getAddLine({ x: currentRoofLine.x1, y: roofLine.y1 }, { x: wallBaseLine.x1, y: wallBaseLine.y1 }, 'purple')
}
}else if(isOut){
@ -1213,7 +1352,7 @@ if((roof.moveUpDown??0 > 0) ) {
//대각선 라인을 보조라인으로 그린다.
if(isCross){
getAddLine({ x: wallBaseLine.x1, y: wallBaseLine.y1 },{ x: currentRoofLine.x1, y: roofLine.y1 }, 'yellow')
getAddLine({ x: wallBaseLine.x1, y: wallBaseLine.y1 },{ x: currentRoofLine.x1, y: roofLine.y1 }, 'purple')
}
}else if (wallBaseLine.x2 <= newPEnd.x && newPEnd.x <= wallBaseLine.x1 && wallBaseLine.x1 <= newPStart.x) { //right / top
@ -1229,7 +1368,7 @@ if((roof.moveUpDown??0 > 0) ) {
//newPEnd = { x: (isCross) ? currentRoofLine.x1 : origin.x1, y: roofLine.y1 } //수직라인 접점까지지
}
getAddLine(newPStart, newPEnd, 'green')
getAddLine(newPStart, newPEnd, 'magenta')
//movedLines.push({ index, newPStart, newPEnd })
//console.log("moveStart:::::::::::::", origin, newPStart, newPEnd)
@ -1239,68 +1378,115 @@ if((roof.moveUpDown??0 > 0) ) {
if (getOrientation(roofLine) === 'vertical') { //수직 오렌지
const mLine = getSelectLinePosition(wall, wallBaseLine)
if(mLine.position === 'left') isIn = true
if(mLine.position === 'right') isOut = true
let isCross = false
if (Math.abs(currentRoofLine.x2 - roofLine.x1) < 0.1 || Math.abs(currentRoofLine.x1 - roofLine.x2) < 0.1) {
isCross = true;
const mLine = getSelectLinePosition(wall, wallBaseLine)
if (['left', 'right'].includes(mLine.position)) {
const positionType =
(mLine.position === 'left' && wallLine.x1 <= wallBaseLine.x1) ||
(mLine.position === 'right' && wallLine.x1 >= wallBaseLine.x1)
? 'in' : 'out';
const condition = `${mLine.position}_${positionType}`;
let isStartEnd = findInteriorPoint(wallBaseLine, sortedWallBaseLines)
let sPoint, ePoint;
let isCross = false
if (Math.abs(currentRoofLine.x2 - roofLine.x1) < 0.1 || Math.abs(currentRoofLine.x1 - roofLine.x2) < 0.1) {
isCross = true;
}
switch (condition) {
case 'left_in':
newPStart = { x: roofLine.x1, y: roofLine.y1 }
newPEnd = { x: roofLine.x2, y: (isCross) ? currentRoofLine.y2 : wallBaseLine.y2 }
//대각선 라인을 보조라인으로 그린다.
if (isCross) {
getAddLine({ x: roofLine.x2, y: currentRoofLine.y2 }, {
x: wallBaseLine.x2,
y: wallBaseLine.y2
}, 'purple')
}
break;
case 'left_out':
break;
case 'right_in':
newPStart = { x: roofLine.x1, y: (isCross) ? currentRoofLine.y2 : wallBaseLine.y2 }
newPEnd = { x: roofLine.x2, y: roofLine.y2 }
break;
case 'right_out':
break;
}
}
// const mLine = getSelectLinePosition(wall, wallBaseLine)
// if(mLine.position === 'left') isIn = true
// if(mLine.position === 'right') isOut = true
if(newPStart.y <= wallBaseLine.y1 && wallBaseLine.y1 < wallBaseLine.y2 && wallBaseLine.y2 < newPEnd.y){//out top left
if(isIn) {
newPStart = { x: roofLine.x1, y: (isCross) ? currentRoofLine.y2 : wallBaseLine.y2 }
newPEnd = { x: roofLine.x2, y: roofLine.y2 }
}else if(isOut) {
newPStart = { x: roofLine.x1, y: roofLine.y1 }
newPEnd = { x: roofLine.x2, y: wallLine.y2 }
}
// if(isIn) {
// newPStart = { x: roofLine.x1, y: (isCross) ? currentRoofLine.y2 : wallBaseLine.y2 }
// newPEnd = { x: roofLine.x2, y: roofLine.y2 }
// }else if(isOut) {
//
// newPStart = { x: roofLine.x1, y: roofLine.y1 }
// newPEnd = { x: roofLine.x2, y: wallLine.y2 }
//
// }
}else if(newPEnd.y <= wallBaseLine.y2 && wallBaseLine.y2 < wallBaseLine.y1 && wallBaseLine.y1 <= newPStart.y){ //top /right
newPStart = { x: roofLine.x1, y: (isCross) ? currentRoofLine.y2 : wallBaseLine.y2 }
newPEnd = { x: roofLine.x2, y: roofLine.y2 }
// newPStart = { x: roofLine.x1, y: (isCross) ? currentRoofLine.y2 : wallBaseLine.y2 }
// newPEnd = { x: roofLine.x2, y: roofLine.y2 }
}else if(newPEnd.y <= wallBaseLine.y2 && wallBaseLine.y2 <= newPStart.y && newPStart.y <= wallBaseLine.y1) { //top / left
newPStart = { x: roofLine.x1, y: (isCross) ? currentRoofLine.y2 : wallBaseLine.y2 }
newPEnd ={ x: roofLine.x2, y: roofLine.y2 }
// newPStart = { x: roofLine.x1, y: (isCross) ? currentRoofLine.y2 : wallBaseLine.y2 }
// newPEnd ={ x: roofLine.x2, y: roofLine.y2 }
}else if(newPStart.y <= wallBaseLine.y1 && wallBaseLine.y1 <= newPEnd.y && newPEnd.y <= wallBaseLine.y2) {//in top left/
if(isIn) {
newPStart = { x: roofLine.x1, y: roofLine.y1 }
newPEnd = { x: roofLine.x2, y: (isCross) ? currentRoofLine.y2 : wallBaseLine.y2 }
//대각선 라인을 보조라인으로 그린다.
if (isCross) {
getAddLine({ x: roofLine.x2, y: currentRoofLine.y2 }, {
x: wallBaseLine.x2,
y: wallBaseLine.y2
}, 'yellow')
}
}
// if(isIn) {
// newPStart = { x: roofLine.x1, y: roofLine.y1 }
// newPEnd = { x: roofLine.x2, y: (isCross) ? currentRoofLine.y2 : wallBaseLine.y2 }
//
// //대각선 라인을 보조라인으로 그린다.
// if (isCross) {
// getAddLine({ x: roofLine.x2, y: currentRoofLine.y2 }, {
// x: wallBaseLine.x2,
// y: wallBaseLine.y2
// }, 'purple')
// }
// }
}else if(wallBaseLine.y1 <= newPStart.y && newPStart.y <= wallBaseLine.y2 && wallBaseLine.y2 <= newPEnd.y) { //하단 오른쪽v
newPStart = { x: roofLine.x1, y: (isCross) ? currentRoofLine.y1 : wallBaseLine.y1 }
newPEnd = { x: roofLine.x2, y: roofLine.y2 }
// newPStart = { x: roofLine.x1, y: (isCross) ? currentRoofLine.y1 : wallBaseLine.y1 }
// newPEnd = { x: roofLine.x2, y: roofLine.y2 }
}else if (wallBaseLine.y2 <= newPEnd.y && newPEnd.y <= wallBaseLine.y1 && wallBaseLine.y1 <= newPStart.y) { //bottom right
newPStart = { x: roofLine.x1, y: roofLine.y1 }
newPEnd = { x: roofLine.x2, y: (isCross) ? currentRoofLine.y2 : wallBaseLine.y2 }
//대각선 라인을 보조라인으로 그린다.
if(isCross){
getAddLine({ x: roofLine.x2, y: currentRoofLine.y2 }, { x: wallBaseLine.x2, y: wallBaseLine.y2 }, 'yellow')
}
// newPStart = { x: roofLine.x1, y: roofLine.y1 }
// newPEnd = { x: roofLine.x2, y: (isCross) ? currentRoofLine.y2 : wallBaseLine.y2 }
//
// //대각선 라인을 보조라인으로 그린다.
// if(isCross){
// getAddLine({ x: roofLine.x2, y: currentRoofLine.y2 }, { x: wallBaseLine.x2, y: wallBaseLine.y2 }, 'purple')
// }
}
@ -1340,7 +1526,7 @@ if((roof.moveUpDown??0 > 0) ) {
//대각선 라인을 보조라인으로 그린다.
if(isCross){
getAddLine({ x: currentRoofLine.x2, y: roofLine.y2 }, { x:wallBaseLine.x2 , y: wallBaseLine.y2 }, 'yellow')
getAddLine({ x: currentRoofLine.x2, y: roofLine.y2 }, { x:wallBaseLine.x2 , y: wallBaseLine.y2 }, 'purple')
}
@ -1356,7 +1542,7 @@ if((roof.moveUpDown??0 > 0) ) {
newPEnd = { y: roofLine.y2, x: (isCross) ? currentRoofLine.x2 : wallBaseLine.x2 }
//대각선 라인을 보조라인으로 그린다.
if(isCross){
getAddLine({ x: currentRoofLine.x2, y: roofLine.y2 }, { x:wallBaseLine.x2 , y: wallBaseLine.y2 }, 'yellow')
getAddLine({ x: currentRoofLine.x2, y: roofLine.y2 }, { x:wallBaseLine.x2 , y: wallBaseLine.y2 }, 'purple')
}
}else if(isOut){
// newPEnd = { x: roofLine.x2, y: roofLine.y2 }
@ -4256,42 +4442,99 @@ function PointBasedOnBaseLength(x1, y1, x2, y2) {
* @param {Array} polygonLines - 폴리곤을 구성하는 선분들의 배열
* @returns {Object} - { start: boolean, end: boolean } 시작점과 끝점의 내부 여부
*/
function findInteriorPoint(line, polygonLines) {
const { x1, y1, x2, y2 } = line;
// function findInteriorPoint(line, polygonLines) {
// const { x1, y1, x2, y2 } = line;
//
// // 선분의 방향 벡터
// const dx = x2 - x1;
// const dy = y2 - y1;
//
// // 수직 벡터 (왼쪽으로 90도 회전)
// const perpX = -dy;
// const perpY = dx;
//
// // 정규화
// const length = Math.sqrt(perpX * perpX + perpY * perpY);
// const nx = perpX / length;
// const ny = perpY / length;
//
// // 오프셋 계산 (선분 길이의 1% 또는 최소 0.1)
// const lineLength = Math.sqrt(dx*dx + dy*dy);
// const offset = Math.max(0.1, lineLength * 0.01);
//
// // 시작점에서 수직 방향으로 약간 떨어진 점
// const testPoint = {
// x: x1 + nx * offset,
// y: y1 + ny * offset
// };
//
// // 반대 방향 점 추가 확인 (라인이 중앙에 있는 경우를 위해)
// const testPoint2 = {
// x: x1 - nx * offset,
// y: y1 - ny * offset
// };
//
// // 이 점이 폴리곤 내부에 있는지 확인
// const isInside = isPointInPolygon(testPoint, polygonLines);
// const isInside2 = isPointInPolygon(testPoint2, polygonLines);
//
// // 라인이 폴리곤 내부에 완전히 포함된 경우 (중앙) -> 양쪽 다 true
// if (isInside && isInside2) {
// return {
// start: true,
// end: true
// };
// }
//
// // 시작점이 내부를 향하는지 여부
// return {
// start: isInside,
// // 끝점 방향은 시작점과 반대
// end: !isInside
// };
// }
// 선분의 방향 벡터
const dx = x2 - x1;
const dy = y2 - y1;
// 수직 벡터 (왼쪽으로 90도 회전)
const perpX = -dy;
const perpY = dx;
// 정규화
const length = Math.sqrt(perpX * perpX + perpY * perpY);
const nx = perpX / length;
const ny = perpY / length;
// 오프셋 계산 (선분 길이의 1% 또는 최소 0.1)
const lineLength = Math.sqrt(dx*dx + dy*dy);
const offset = Math.max(0.1, lineLength * 0.01);
// 시작점에서 수직 방향으로 약간 떨어진 점
const testPoint = {
x: x1 + nx * offset,
y: y1 + ny * offset
/**
* 레이저(Ray) 폴리곤의 다른 선분과 교차하는지 확인하는 헬퍼 함수
* @param {Object} origin - 레이저 시작점 {x, y}
* @param {Object} dir - 레이저 방향 벡터 {x, y} (정규화됨)
* @param {Array} lines - 검사할 선분들
* @param {Object} excludeLine - 자기 자신 라인 (제외)
*/
function checkRayIntersection(origin, dir, lines, excludeLine) {
// 레이저를 아주 멀리까지 쏘아봅니다 (도면 크기에 따라 조절, 충분히 큰 값)
const rayLength = 100000;
const rayEnd = {
x: origin.x + dir.x * rayLength,
y: origin.y + dir.y * rayLength
};
// 이 점이 폴리곤 내부에 있는지 확인
const isInside = isPointInPolygon(testPoint, polygonLines);
for (const line of lines) {
// 자기 자신은 검사 제외
if (line === excludeLine) continue;
// 좌표 기반 비교로도 자기 자신 체크 (객체 참조가 다를 수 있으므로)
if (Math.abs(line.x1 - excludeLine.x1) < 0.1 && Math.abs(line.y1 - excludeLine.y1) < 0.1 &&
Math.abs(line.x2 - excludeLine.x2) < 0.1 && Math.abs(line.y2 - excludeLine.y2) < 0.1) continue;
// 시작점이 내부를 향하는지 여부
return {
start: isInside,
// 끝점 방향은 시작점과 반대
end: !isInside
};
const lineStart = { x: line.x1, y: line.y1 };
const lineEnd = { x: line.x2, y: line.y2 };
// 선분 교차 검사
const intersect = getLineIntersection(origin, rayEnd, lineStart, lineEnd);
if (intersect) {
// 교차점이 시작점(origin)과 너무 가까우면(코너 등) 무시하고,
// 확실히 전방에 있는 경우만 인정
const dist = Math.hypot(intersect.x - origin.x, intersect.y - origin.y);
if (dist > 1.0) { // 1.0 정도의 여유를 둠
return true; // 부딪힘! (빨간 라인 후보)
}
}
}
return false; // 허공! (파란 라인 후보)
}
// 점이 선분의 어느 쪽에 있는지 확인
function isPointInDirection(line, point) {
const {x1, y1, x2, y2} = line;
@ -4379,3 +4622,91 @@ function isPointOnLineSegment2(point, lineStart, lineEnd, tolerance = 0.1) {
return isOnSegment;
}
/**
* (p1 -> p2 -> p3) 방향성을 계산합니다. (2D 외적)
* 반시계 방향(CCW)으로 그려진 폴리곤(Y축 Down) 기준:
* - 결과 > 0 : 오른쪽 (Right Turn) -> 골짜기 (Valley/Reflex Vertex)
* - 결과 < 0 : 왼쪽 (Left Turn) -> 외곽 모서리 (Convex Vertex)
* - 결과 = 0 : 직선
*/
function getTurnDirection(p1, p2, p3) {
// 벡터 a: p1 -> p2
// 벡터 b: p2 -> p3
const val = (p2.x - p1.x) * (p3.y - p2.y) - (p2.y - p1.y) * (p3.x - p2.x);
return val;
}
/**
* 현재 (point) 기준으로 연결된 이전 라인과 다음 라인을 찾아 골짜기 여부 판단
*/
function isValleyVertex(targetPoint, connectedLine, allLines, isStartVertex) {
const tolerance = 0.1;
// 1. 연결된 '다른' 라인을 찾습니다.
// isStartVertex가 true면 : 이 점으로 '들어오는' 라인(Previous Line)을 찾아야 함
// isStartVertex가 false면 : 이 점에서 '나가는' 라인(Next Line)을 찾아야 함
let neighborLine = null;
if (isStartVertex) {
// targetPoint가 Start이므로, 어떤 라인의 End가 targetPoint와 같아야 함 (Previous Line)
neighborLine = allLines.find(l =>
l !== connectedLine &&
isSamePoint(l.endPoint || {x:l.x2, y:l.y2}, targetPoint, tolerance)
);
} else {
// targetPoint가 End이므로, 어떤 라인의 Start가 targetPoint와 같아야 함 (Next Line)
neighborLine = allLines.find(l =>
l !== connectedLine &&
isSamePoint(l.startPoint || {x:l.x1, y:l.y1}, targetPoint, tolerance)
);
}
// 연결된 라인을 못 찾았거나 끊겨있으면 판단 불가 (일단 false)
if (!neighborLine) return false;
// 2. 세 점을 구성하여 회전 방향(Turn) 계산
// 순서: PrevLine.Start -> [TargetVertex] -> NextLine.End
let p1, p2, p3;
if (isStartVertex) {
// neighbor(Prev) -> connected(Current)
p1 = neighborLine.startPoint || {x: neighborLine.x1, y: neighborLine.y1};
p2 = targetPoint; // 접점
p3 = connectedLine.endPoint || {x: connectedLine.x2, y: connectedLine.y2};
} else {
// connected(Current) -> neighbor(Next)
p1 = connectedLine.startPoint || {x: connectedLine.x1, y: connectedLine.y1};
p2 = targetPoint; // 접점
p3 = neighborLine.endPoint || {x: neighborLine.x2, y: neighborLine.y2};
}
// 3. 외적 계산 (Y축이 아래로 증가하는 캔버스 좌표계 + CCW 진행 기준)
// 값이 양수(+)면 오른쪽 턴 = 골짜기
const crossProduct = getTurnDirection(p1, p2, p3);
return crossProduct > 0;
}
function findInteriorPoint(line, polygonLines) {
const { x1, y1, x2, y2 } = line;
// line 객체 포맷 통일
const currentLine = {
...line,
startPoint: { x: x1, y: y1 },
endPoint: { x: x2, y: y2 }
};
// 1. 시작점이 골짜기인지 확인 (들어오는 라인과 나가는 라인의 각도)
const startIsValley = isValleyVertex(currentLine.startPoint, currentLine, polygonLines, true);
// 2. 끝점이 골짜기인지 확인
const endIsValley = isValleyVertex(currentLine.endPoint, currentLine, polygonLines, false);
return {
start: startIsValley,
end: endIsValley
};
}