로직변경1
This commit is contained in:
parent
3663636b5d
commit
3cbfbbd0b3
@ -453,7 +453,7 @@ const createInnerLinesFromSkeleton = (roofId, canvas, skeleton, textMode) => {
|
|||||||
left: line.x1 + 5,
|
left: line.x1 + 5,
|
||||||
top: line.y1 - 20,
|
top: line.y1 - 20,
|
||||||
fontSize: 10,
|
fontSize: 10,
|
||||||
fill: 'green',
|
fill: 'magenta',
|
||||||
fontFamily: 'Arial',
|
fontFamily: 'Arial',
|
||||||
selectable: false,
|
selectable: false,
|
||||||
hasControls: false,
|
hasControls: false,
|
||||||
@ -813,12 +813,12 @@ if((roof.moveUpDown??0 > 0) ) {
|
|||||||
|
|
||||||
//현재 roof는 무조건 시계방향
|
//현재 roof는 무조건 시계방향
|
||||||
|
|
||||||
const getAddLine = (p1, p2, stroke = '#1083E3') => {
|
const getAddLine = (p1, p2, stroke = '') => {
|
||||||
movedLines.push({ index, p1, p2 })
|
movedLines.push({ index, p1, p2 })
|
||||||
|
|
||||||
// Usage:
|
// Usage:
|
||||||
let mergeLines = mergeMovedLines(movedLines);
|
let mergeLines = mergeMovedLines(movedLines);
|
||||||
console.log("mergeLines:::::::", mergeLines);
|
//console.log("mergeLines:::::::", mergeLines);
|
||||||
const line = new QLine([p1.x, p1.y, p2.x, p2.y], {
|
const line = new QLine([p1.x, p1.y, p2.x, p2.y], {
|
||||||
parentId : roof.id,
|
parentId : roof.id,
|
||||||
fontSize : roof.fontSize,
|
fontSize : roof.fontSize,
|
||||||
@ -855,6 +855,7 @@ if((roof.moveUpDown??0 > 0) ) {
|
|||||||
if (fullyMoved ) {
|
if (fullyMoved ) {
|
||||||
//반시계방향향
|
//반시계방향향
|
||||||
console.log("moveFully:::::::::::::", wallBaseLine, newPStart, newPEnd)
|
console.log("moveFully:::::::::::::", wallBaseLine, newPStart, newPEnd)
|
||||||
|
console.log("moveFully:::::::::::::", roofLine.direction)
|
||||||
const mLine = getSelectLinePosition(wall, wallBaseLine)
|
const mLine = getSelectLinePosition(wall, wallBaseLine)
|
||||||
|
|
||||||
if (getOrientation(roofLine) === 'vertical') {
|
if (getOrientation(roofLine) === 'vertical') {
|
||||||
@ -864,26 +865,68 @@ if((roof.moveUpDown??0 > 0) ) {
|
|||||||
(mLine.position === 'right' && wallLine.x1 > wallBaseLine.x1)
|
(mLine.position === 'right' && wallLine.x1 > wallBaseLine.x1)
|
||||||
? 'in' : 'out';
|
? 'in' : 'out';
|
||||||
const condition = `${mLine.position}_${positionType}`;
|
const condition = `${mLine.position}_${positionType}`;
|
||||||
|
let isStartEnd = findInteriorPoint(wallBaseLine, sortedWallBaseLines)
|
||||||
|
let sPoint, ePoint;
|
||||||
switch (condition) {
|
switch (condition) {
|
||||||
case 'left_in':
|
case 'left_in':
|
||||||
isIn = true
|
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 });
|
if (isStartEnd.start ) {
|
||||||
break;
|
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':
|
case 'left_out':
|
||||||
const moveX = Math.abs(wallBaseLine.x1 - wallLine.x1)
|
if(isStartEnd.start){
|
||||||
const aStartY = Math.abs(newPEnd.y + moveX)
|
const moveX = Math.abs(wallBaseLine.x1 - wallLine.x1)
|
||||||
const bStartY = Math.abs(wallLine.y2 + moveX)
|
const aStartY = Math.abs(newPEnd.y + moveX)
|
||||||
findPoints.push({ x: newPEnd.x, y: aStartY });
|
const bStartY = Math.abs(wallLine.y2 + moveX)
|
||||||
const inLine = findLineContainingPoint(innerLines, { x: newPEnd.x, y: aStartY })
|
findPoints.push({ x: newPEnd.x, y: aStartY });
|
||||||
// console.log("startLines:::::::", inLine);
|
const inLine = findLineContainingPoint(innerLines, { x: newPEnd.x, y: aStartY })
|
||||||
getAddLine({ x: wallLine.x1, y: roofLine.y2 }, { x: wallLine.x1, y: bStartY })
|
// console.log("startLines:::::::", inLine);
|
||||||
getAddLine({ x: wallLine.x2, y: bStartY }, { x: inLine.x2, y: inLine.y2 }, 'pink')
|
getAddLine({ x: wallLine.x1, y: roofLine.y2 }, { x: wallLine.x1, y: bStartY })
|
||||||
const eLineY = Math.abs(bStartY - wallLine.y2)
|
getAddLine({ x: wallLine.x2, y: bStartY }, { x: inLine.x2, y: inLine.y2 }, 'pink')
|
||||||
newPStart.y += eLineY
|
const eLineY = Math.abs(bStartY - wallLine.y2)
|
||||||
newPEnd.y = aStartY
|
newPStart.y += eLineY
|
||||||
|
newPEnd.y = aStartY
|
||||||
|
|
||||||
|
}else if(isStartEnd.end){
|
||||||
|
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case 'right_in':
|
case 'right_in':
|
||||||
newPEnd.y = wallBaseLine.y2;
|
newPEnd.y = wallBaseLine.y2;
|
||||||
@ -972,17 +1015,34 @@ if((roof.moveUpDown??0 > 0) ) {
|
|||||||
const condition = `${mLine.position}_${positionType}`;
|
const condition = `${mLine.position}_${positionType}`;
|
||||||
let isStartEnd = findInteriorPoint(wallBaseLine, sortedWallBaseLines)
|
let isStartEnd = findInteriorPoint(wallBaseLine, sortedWallBaseLines)
|
||||||
|
|
||||||
|
let sPoint, ePoint;
|
||||||
|
|
||||||
switch (condition) {
|
switch (condition) {
|
||||||
case 'top_in':
|
case 'top_in':
|
||||||
|
|
||||||
console.log("findInteriorPoint result:::::::", isStartEnd);
|
console.log("findInteriorPoint result:::::::", isStartEnd);
|
||||||
|
|
||||||
let sPoint, ePoint;
|
|
||||||
if (isStartEnd.start ) {
|
if (isStartEnd.start ) {
|
||||||
|
const moveDist = Big(wallLine.y1).minus(wallBaseLine.y1).abs().toNumber()
|
||||||
sPoint = {x: wallBaseLine.x1, y: wallBaseLine.y1};
|
sPoint = {x: wallBaseLine.x1, y: wallBaseLine.y1};
|
||||||
newPStart.x = wallBaseLine.x1;
|
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 });
|
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){
|
if(isStartEnd.end){
|
||||||
@ -994,7 +1054,6 @@ if((roof.moveUpDown??0 > 0) ) {
|
|||||||
|
|
||||||
break;
|
break;
|
||||||
case 'top_out':
|
case 'top_out':
|
||||||
|
|
||||||
console.log("findInteriorPoint result:::::::", isStartEnd);
|
console.log("findInteriorPoint result:::::::", isStartEnd);
|
||||||
|
|
||||||
const moveY = Math.abs(wallLine.y1 - wallBaseLine.y1)
|
const moveY = Math.abs(wallLine.y1 - wallBaseLine.y1)
|
||||||
@ -1015,9 +1074,46 @@ if((roof.moveUpDown??0 > 0) ) {
|
|||||||
break;
|
break;
|
||||||
case 'bottom_in':
|
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;
|
break;
|
||||||
case 'bottom_out':
|
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;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1095,72 +1191,115 @@ if((roof.moveUpDown??0 > 0) ) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
getAddLine(newPStart, newPEnd, 'red')
|
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)
|
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 === 'left') isIn = true
|
||||||
if(mLine.position === 'right') isOut = 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(newPStart.y <= wallBaseLine.y1 && wallBaseLine.y1 < wallBaseLine.y2 && wallBaseLine.y2 < newPEnd.y){//in bottom left
|
||||||
if(isIn){
|
// if(isIn){
|
||||||
newPStart = { x: roofLine.x1, y: roofLine.y1 }
|
// newPStart = { x: roofLine.x1, y: roofLine.y1 }
|
||||||
newPEnd = { x: roofLine.x2, y: (isCross) ? currentRoofLine?.y1 : wallBaseLine.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
|
}else if(newPEnd.y <= wallBaseLine.y2 && wallBaseLine.y2 < wallBaseLine.y1 && wallBaseLine.y1 <= newPStart.y){ //하단 오른쪽v
|
||||||
newPStart = { x: roofLine.x1, y: roofLine.y1 }
|
// newPStart = { x: roofLine.x1, y: roofLine.y1 }
|
||||||
newPEnd = { x: roofLine.x2, y: (isCross) ? currentRoofLine?.y1 : wallBaseLine.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
|
}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 }
|
// newPStart = { x: roofLine.x1, y: (isCross) ? currentRoofLine?.y1 : wallBaseLine.y1 }
|
||||||
newPEnd ={ x: roofLine.x2, y: roofLine.y2 }
|
// newPEnd ={ x: roofLine.x2, y: roofLine.y2 }
|
||||||
|
//
|
||||||
//대각선 라인을 보조라인으로 그린다.
|
// //대각선 라인을 보조라인으로 그린다.
|
||||||
if(isCross){
|
// if(isCross){
|
||||||
getAddLine({ x: wallBaseLine.x1, y: wallBaseLine.y1 }, { x: roofLine.x1, y: currentRoofLine?.y1 }, 'yellow')
|
// 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) {//상단 오르쪽
|
}else if(newPStart.y <= wallBaseLine.y1 && wallBaseLine.y1 <= newPEnd.y && newPEnd.y <= wallBaseLine.y2) {//상단 오르쪽
|
||||||
|
|
||||||
newPStart = { x: roofLine.x1, y: roofLine.y1 }
|
// newPStart = { x: roofLine.x1, y: roofLine.y1 }
|
||||||
newPEnd = { x: roofLine.x2, y: (isCross) ? currentRoofLine.y1 : wallBaseLine.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
|
}else if(wallBaseLine.y1 <= newPStart.y && newPStart.y <= wallBaseLine.y2 && wallBaseLine.y2 <= newPEnd.y) { // out bottom left //bottom left
|
||||||
if(isIn){
|
// if(isIn){
|
||||||
newPStart = { x: roofLine.x1, y: (isCross) ? currentRoofLine.y1 : wallBaseLine.y1 }
|
// newPStart = { x: roofLine.x1, y: (isCross) ? currentRoofLine.y1 : wallBaseLine.y1 }
|
||||||
newPEnd = { x: roofLine.x2, y: roofLine.y2 }
|
// newPEnd = { x: roofLine.x2, y: roofLine.y2 }
|
||||||
|
//
|
||||||
//대각선 라인을 보조라인으로 그린다.
|
// //대각선 라인을 보조라인으로 그린다.
|
||||||
if(isCross){
|
// if(isCross){
|
||||||
getAddLine( { x: wallBaseLine.x1, y: wallBaseLine.y1 }, { x: roofLine.x1, y: currentRoofLine.y1 }, 'yellow')
|
// getAddLine( { x: wallBaseLine.x1, y: wallBaseLine.y1 }, { x: roofLine.x1, y: currentRoofLine.y1 }, 'purple')
|
||||||
}
|
// }
|
||||||
}else if(isOut){
|
// }else if(isOut){
|
||||||
|
//
|
||||||
}
|
// }
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}else if (wallBaseLine.y2 <= newPEnd.y && newPEnd.y <= wallBaseLine.y1 && wallBaseLine.y1 <= newPStart.y) { //하단 왼쪽
|
}else if (wallBaseLine.y2 <= newPEnd.y && newPEnd.y <= wallBaseLine.y1 && wallBaseLine.y1 <= newPStart.y) { //하단 왼쪽
|
||||||
|
|
||||||
newPStart = { x: roofLine.x1, y: (isCross) ? currentRoofLine.y1 : wallBaseLine.y1 }
|
// newPStart = { x: roofLine.x1, y: (isCross) ? currentRoofLine.y1 : wallBaseLine.y1 }
|
||||||
newPEnd ={ x: roofLine.x2, y: roofLine.y2 }
|
// newPEnd ={ x: roofLine.x2, y: roofLine.y2 }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
} else if (getOrientation(roofLine) === 'horizontal') { //green 수평
|
} else if (getOrientation(roofLine) === 'horizontal') { //magenta 수평
|
||||||
|
|
||||||
|
|
||||||
const mLine = getSelectLinePosition(wall, wallBaseLine)
|
const mLine = getSelectLinePosition(wall, wallBaseLine)
|
||||||
@ -1193,7 +1332,7 @@ if((roof.moveUpDown??0 > 0) ) {
|
|||||||
|
|
||||||
//대각선 라인을 보조라인으로 그린다.
|
//대각선 라인을 보조라인으로 그린다.
|
||||||
if(isCross){
|
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){
|
}else if(isOut){
|
||||||
|
|
||||||
@ -1213,7 +1352,7 @@ if((roof.moveUpDown??0 > 0) ) {
|
|||||||
|
|
||||||
//대각선 라인을 보조라인으로 그린다.
|
//대각선 라인을 보조라인으로 그린다.
|
||||||
if(isCross){
|
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
|
}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 } //수직라인 접점까지지
|
//newPEnd = { x: (isCross) ? currentRoofLine.x1 : origin.x1, y: roofLine.y1 } //수직라인 접점까지지
|
||||||
}
|
}
|
||||||
|
|
||||||
getAddLine(newPStart, newPEnd, 'green')
|
getAddLine(newPStart, newPEnd, 'magenta')
|
||||||
//movedLines.push({ index, newPStart, newPEnd })
|
//movedLines.push({ index, newPStart, newPEnd })
|
||||||
//console.log("moveStart:::::::::::::", origin, newPStart, newPEnd)
|
//console.log("moveStart:::::::::::::", origin, newPStart, newPEnd)
|
||||||
|
|
||||||
@ -1239,68 +1378,115 @@ if((roof.moveUpDown??0 > 0) ) {
|
|||||||
|
|
||||||
|
|
||||||
if (getOrientation(roofLine) === 'vertical') { //수직 오렌지
|
if (getOrientation(roofLine) === 'vertical') { //수직 오렌지
|
||||||
const mLine = getSelectLinePosition(wall, wallBaseLine)
|
|
||||||
if(mLine.position === 'left') isIn = true
|
|
||||||
if(mLine.position === 'right') isOut = true
|
|
||||||
|
|
||||||
let isCross = false
|
const mLine = getSelectLinePosition(wall, wallBaseLine)
|
||||||
if (Math.abs(currentRoofLine.x2 - roofLine.x1) < 0.1 || Math.abs(currentRoofLine.x1 - roofLine.x2) < 0.1) {
|
if (['left', 'right'].includes(mLine.position)) {
|
||||||
isCross = true;
|
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(newPStart.y <= wallBaseLine.y1 && wallBaseLine.y1 < wallBaseLine.y2 && wallBaseLine.y2 < newPEnd.y){//out top left
|
||||||
|
|
||||||
if(isIn) {
|
// if(isIn) {
|
||||||
newPStart = { x: roofLine.x1, y: (isCross) ? currentRoofLine.y2 : wallBaseLine.y2 }
|
// newPStart = { x: roofLine.x1, y: (isCross) ? currentRoofLine.y2 : wallBaseLine.y2 }
|
||||||
newPEnd = { x: roofLine.x2, y: roofLine.y2 }
|
// newPEnd = { x: roofLine.x2, y: roofLine.y2 }
|
||||||
}else if(isOut) {
|
// }else if(isOut) {
|
||||||
|
//
|
||||||
newPStart = { x: roofLine.x1, y: roofLine.y1 }
|
// newPStart = { x: roofLine.x1, y: roofLine.y1 }
|
||||||
newPEnd = { x: roofLine.x2, y: wallLine.y2 }
|
// newPEnd = { x: roofLine.x2, y: wallLine.y2 }
|
||||||
|
//
|
||||||
}
|
// }
|
||||||
|
|
||||||
|
|
||||||
}else if(newPEnd.y <= wallBaseLine.y2 && wallBaseLine.y2 < wallBaseLine.y1 && wallBaseLine.y1 <= newPStart.y){ //top /right
|
}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 }
|
// newPStart = { x: roofLine.x1, y: (isCross) ? currentRoofLine.y2 : wallBaseLine.y2 }
|
||||||
newPEnd = { x: roofLine.x2, y: roofLine.y2 }
|
// newPEnd = { x: roofLine.x2, y: roofLine.y2 }
|
||||||
|
|
||||||
|
|
||||||
}else if(newPEnd.y <= wallBaseLine.y2 && wallBaseLine.y2 <= newPStart.y && newPStart.y <= wallBaseLine.y1) { //top / left
|
}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 }
|
// newPStart = { x: roofLine.x1, y: (isCross) ? currentRoofLine.y2 : wallBaseLine.y2 }
|
||||||
newPEnd ={ x: roofLine.x2, y: roofLine.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/
|
}else if(newPStart.y <= wallBaseLine.y1 && wallBaseLine.y1 <= newPEnd.y && newPEnd.y <= wallBaseLine.y2) {//in top left/
|
||||||
|
|
||||||
|
|
||||||
if(isIn) {
|
// if(isIn) {
|
||||||
newPStart = { x: roofLine.x1, y: roofLine.y1 }
|
// newPStart = { x: roofLine.x1, y: roofLine.y1 }
|
||||||
newPEnd = { x: roofLine.x2, y: (isCross) ? currentRoofLine.y2 : wallBaseLine.y2 }
|
// newPEnd = { x: roofLine.x2, y: (isCross) ? currentRoofLine.y2 : wallBaseLine.y2 }
|
||||||
|
//
|
||||||
//대각선 라인을 보조라인으로 그린다.
|
// //대각선 라인을 보조라인으로 그린다.
|
||||||
if (isCross) {
|
// if (isCross) {
|
||||||
getAddLine({ x: roofLine.x2, y: currentRoofLine.y2 }, {
|
// getAddLine({ x: roofLine.x2, y: currentRoofLine.y2 }, {
|
||||||
x: wallBaseLine.x2,
|
// x: wallBaseLine.x2,
|
||||||
y: wallBaseLine.y2
|
// y: wallBaseLine.y2
|
||||||
}, 'yellow')
|
// }, 'purple')
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
}else if(wallBaseLine.y1 <= newPStart.y && newPStart.y <= wallBaseLine.y2 && wallBaseLine.y2 <= newPEnd.y) { //하단 오른쪽v
|
}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 }
|
// newPStart = { x: roofLine.x1, y: (isCross) ? currentRoofLine.y1 : wallBaseLine.y1 }
|
||||||
newPEnd = { x: roofLine.x2, y: roofLine.y2 }
|
// newPEnd = { x: roofLine.x2, y: roofLine.y2 }
|
||||||
|
|
||||||
}else if (wallBaseLine.y2 <= newPEnd.y && newPEnd.y <= wallBaseLine.y1 && wallBaseLine.y1 <= newPStart.y) { //bottom right
|
}else if (wallBaseLine.y2 <= newPEnd.y && newPEnd.y <= wallBaseLine.y1 && wallBaseLine.y1 <= newPStart.y) { //bottom right
|
||||||
|
|
||||||
newPStart = { x: roofLine.x1, y: roofLine.y1 }
|
// newPStart = { x: roofLine.x1, y: roofLine.y1 }
|
||||||
newPEnd = { x: roofLine.x2, y: (isCross) ? currentRoofLine.y2 : wallBaseLine.y2 }
|
// newPEnd = { x: roofLine.x2, y: (isCross) ? currentRoofLine.y2 : wallBaseLine.y2 }
|
||||||
|
//
|
||||||
//대각선 라인을 보조라인으로 그린다.
|
// //대각선 라인을 보조라인으로 그린다.
|
||||||
if(isCross){
|
// if(isCross){
|
||||||
getAddLine({ x: roofLine.x2, y: currentRoofLine.y2 }, { x: wallBaseLine.x2, y: wallBaseLine.y2 }, 'yellow')
|
// 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){
|
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 }
|
newPEnd = { y: roofLine.y2, x: (isCross) ? currentRoofLine.x2 : wallBaseLine.x2 }
|
||||||
//대각선 라인을 보조라인으로 그린다.
|
//대각선 라인을 보조라인으로 그린다.
|
||||||
if(isCross){
|
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){
|
}else if(isOut){
|
||||||
// newPEnd = { x: roofLine.x2, y: roofLine.y2 }
|
// newPEnd = { x: roofLine.x2, y: roofLine.y2 }
|
||||||
@ -4256,42 +4442,99 @@ function PointBasedOnBaseLength(x1, y1, x2, y2) {
|
|||||||
* @param {Array} polygonLines - 폴리곤을 구성하는 선분들의 배열
|
* @param {Array} polygonLines - 폴리곤을 구성하는 선분들의 배열
|
||||||
* @returns {Object} - { start: boolean, end: boolean } 시작점과 끝점의 내부 여부
|
* @returns {Object} - { start: boolean, end: boolean } 시작점과 끝점의 내부 여부
|
||||||
*/
|
*/
|
||||||
function findInteriorPoint(line, polygonLines) {
|
// function findInteriorPoint(line, polygonLines) {
|
||||||
const { x1, y1, x2, y2 } = line;
|
// 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;
|
* 레이저(Ray)가 폴리곤의 다른 선분과 교차하는지 확인하는 헬퍼 함수
|
||||||
const dy = y2 - y1;
|
* @param {Object} origin - 레이저 시작점 {x, y}
|
||||||
|
* @param {Object} dir - 레이저 방향 벡터 {x, y} (정규화됨)
|
||||||
// 수직 벡터 (왼쪽으로 90도 회전)
|
* @param {Array} lines - 검사할 선분들
|
||||||
const perpX = -dy;
|
* @param {Object} excludeLine - 자기 자신 라인 (제외)
|
||||||
const perpY = dx;
|
*/
|
||||||
|
function checkRayIntersection(origin, dir, lines, excludeLine) {
|
||||||
// 정규화
|
// 레이저를 아주 멀리까지 쏘아봅니다 (도면 크기에 따라 조절, 충분히 큰 값)
|
||||||
const length = Math.sqrt(perpX * perpX + perpY * perpY);
|
const rayLength = 100000;
|
||||||
const nx = perpX / length;
|
const rayEnd = {
|
||||||
const ny = perpY / length;
|
x: origin.x + dir.x * rayLength,
|
||||||
|
y: origin.y + dir.y * rayLength
|
||||||
// 오프셋 계산 (선분 길이의 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
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// 이 점이 폴리곤 내부에 있는지 확인
|
for (const line of lines) {
|
||||||
const isInside = isPointInPolygon(testPoint, polygonLines);
|
// 자기 자신은 검사 제외
|
||||||
|
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;
|
||||||
|
|
||||||
// 시작점이 내부를 향하는지 여부
|
const lineStart = { x: line.x1, y: line.y1 };
|
||||||
return {
|
const lineEnd = { x: line.x2, y: line.y2 };
|
||||||
start: isInside,
|
|
||||||
// 끝점 방향은 시작점과 반대
|
// 선분 교차 검사
|
||||||
end: !isInside
|
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) {
|
function isPointInDirection(line, point) {
|
||||||
const {x1, y1, x2, y2} = line;
|
const {x1, y1, x2, y2} = line;
|
||||||
@ -4379,3 +4622,91 @@ function isPointOnLineSegment2(point, lineStart, lineEnd, tolerance = 0.1) {
|
|||||||
|
|
||||||
return isOnSegment;
|
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
|
||||||
|
};
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user