dev #457
@ -754,6 +754,7 @@ const createInnerLinesFromSkeleton = (roofId, canvas, skeleton, textMode) => {
|
|||||||
const sortedCurrentRoofLines = sortCurrentRoofLines(alignedCurrentRoofLines);
|
const sortedCurrentRoofLines = sortCurrentRoofLines(alignedCurrentRoofLines);
|
||||||
const sortedRoofLines = sortCurrentRoofLines(roofLines);
|
const sortedRoofLines = sortCurrentRoofLines(roofLines);
|
||||||
const sortedWallBaseLines = sortCurrentRoofLines(wall.baseLines);
|
const sortedWallBaseLines = sortCurrentRoofLines(wall.baseLines);
|
||||||
|
const sortedBaseLines = sortBaseLinesByWallLines(wall.baseLines, wallLines);
|
||||||
|
|
||||||
|
|
||||||
//wall.lines 는 기본 벽 라인
|
//wall.lines 는 기본 벽 라인
|
||||||
@ -772,8 +773,8 @@ const createInnerLinesFromSkeleton = (roofId, canvas, skeleton, textMode) => {
|
|||||||
|
|
||||||
const roofLine = roofLines[index];
|
const roofLine = roofLines[index];
|
||||||
const currentRoofLine = currentRoofLines[index];
|
const currentRoofLine = currentRoofLines[index];
|
||||||
const moveLine = wall.baseLines[index]
|
const moveLine = sortedBaseLines[index]
|
||||||
const wallBaseLine = wall.baseLines[index]
|
const wallBaseLine = sortedBaseLines[index]
|
||||||
|
|
||||||
//roofline 외곽선 설정
|
//roofline 외곽선 설정
|
||||||
|
|
||||||
@ -861,14 +862,13 @@ const createInnerLinesFromSkeleton = (roofId, canvas, skeleton, textMode) => {
|
|||||||
//두 포인트가 변경된 라인인
|
//두 포인트가 변경된 라인인
|
||||||
if (fullyMoved ) {
|
if (fullyMoved ) {
|
||||||
//반시계방향향
|
//반시계방향향
|
||||||
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') {
|
||||||
|
|
||||||
if (['left', 'right'].includes(mLine.position)) {
|
if (['left', 'right'].includes(mLine.position)) {
|
||||||
if(wallLine.x1 === wallBaseLine.x1) {
|
if(Math.abs(wallLine.x1 - wallBaseLine.x1) < 0.1 || Math.abs(wallLine.x2 - wallBaseLine.x2) < 0.1) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
const positionType =
|
const positionType =
|
||||||
@ -876,7 +876,7 @@ const createInnerLinesFromSkeleton = (roofId, canvas, skeleton, textMode) => {
|
|||||||
(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, wall.baseLines)
|
let isStartEnd = findInteriorPoint(wallBaseLine, sortedBaseLines)
|
||||||
let sPoint, ePoint;
|
let sPoint, ePoint;
|
||||||
if(condition === 'left_in') {
|
if(condition === 'left_in') {
|
||||||
isIn = true
|
isIn = true
|
||||||
@ -1014,6 +1014,7 @@ const createInnerLinesFromSkeleton = (roofId, canvas, skeleton, textMode) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
findPoints.push({ y: newPStart.y, x: newPEnd.x, position: 'left_out_end' });
|
||||||
}
|
}
|
||||||
}else if(condition === 'right_in') {
|
}else if(condition === 'right_in') {
|
||||||
if (isStartEnd.start ) {
|
if (isStartEnd.start ) {
|
||||||
@ -1165,7 +1166,7 @@ const createInnerLinesFromSkeleton = (roofId, canvas, skeleton, textMode) => {
|
|||||||
} else if (getOrientation(roofLine) === 'horizontal') { //red
|
} else if (getOrientation(roofLine) === 'horizontal') { //red
|
||||||
|
|
||||||
if (['top', 'bottom'].includes(mLine.position)) {
|
if (['top', 'bottom'].includes(mLine.position)) {
|
||||||
if(Math.abs(wallLine.y1 - wallBaseLine.y1) < 0.1) {
|
if(Math.abs(wallLine.y1 - wallBaseLine.y1) < 0.1 || Math.abs(wallLine.y2 - wallBaseLine.y2) < 0.1) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
const positionType =
|
const positionType =
|
||||||
@ -1174,7 +1175,7 @@ const createInnerLinesFromSkeleton = (roofId, canvas, skeleton, textMode) => {
|
|||||||
? 'in' : 'out';
|
? 'in' : 'out';
|
||||||
|
|
||||||
const condition = `${mLine.position}_${positionType}`;
|
const condition = `${mLine.position}_${positionType}`;
|
||||||
let isStartEnd = findInteriorPoint(wallBaseLine, wall.baseLines)
|
let isStartEnd = findInteriorPoint(wallBaseLine, sortedBaseLines)
|
||||||
|
|
||||||
let sPoint, ePoint;
|
let sPoint, ePoint;
|
||||||
|
|
||||||
@ -1401,15 +1402,15 @@ const createInnerLinesFromSkeleton = (roofId, canvas, skeleton, textMode) => {
|
|||||||
const eLineX = Big(bStartX).minus(wallLine.x2).abs().toNumber()
|
const eLineX = Big(bStartX).minus(wallLine.x2).abs().toNumber()
|
||||||
newPEnd.x = aStartX
|
newPEnd.x = aStartX
|
||||||
newPStart.x = Big(roofLine.x1).plus(eLineX).toNumber()
|
newPStart.x = Big(roofLine.x1).plus(eLineX).toNumber()
|
||||||
let idx = (0 > index - 1)?roofLines.length:index
|
let idx = (roofLines.length < index + 1)?0:index
|
||||||
const newLine = roofLines[idx-1];
|
const newLine = roofLines[idx + 1];
|
||||||
|
|
||||||
if(Math.abs(wallBaseLine.x2 - wallLine.x2) < 0.1) {
|
if(Math.abs(wallBaseLine.x2 - wallLine.x2) < 0.1) {
|
||||||
if(inLine){
|
if(inLine){
|
||||||
if(inLine.y2 < inLine.y1 ) {
|
if(inLine.y2 < inLine.y1 ) {
|
||||||
getAddLine({ x: bStartX, y: wallLine.y1 }, { x: inLine.x2, y: inLine.y2 }, 'pink')
|
getAddLine({ x: bStartX, y: wallLine.y1 }, { x: inLine.x2, y: inLine.y2 }, 'pink')
|
||||||
}else{
|
}else{
|
||||||
getAddLine({ x: inLine.x2, y: inLine.y2 }, { x: bStartX, y: wallLine.y1 }, 'pink')
|
getAddLine({ x: inLine.x1, y: inLine.y1 }, { x: bStartX, y: wallLine.y1 }, 'pink')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
getAddLine({ x: bStartX, y: wallLine.y1 }, { x: roofLine.x2, y: wallLine.y2 }, 'magenta')
|
getAddLine({ x: bStartX, y: wallLine.y1 }, { x: roofLine.x2, y: wallLine.y2 }, 'magenta')
|
||||||
@ -3136,7 +3137,7 @@ function updateAndAddLine(innerLines, targetPoint) {
|
|||||||
isUpdatingStart = true;
|
isUpdatingStart = true;
|
||||||
}
|
}
|
||||||
}else if(targetPoint.position === "top_out_end"){
|
}else if(targetPoint.position === "top_out_end"){
|
||||||
if(foundLine.y2 > foundLine.y1){
|
if(foundLine.y2 >= foundLine.y1){
|
||||||
isUpdatingStart = true;
|
isUpdatingStart = true;
|
||||||
}
|
}
|
||||||
}else if(targetPoint.position === "bottom_out_start"){
|
}else if(targetPoint.position === "bottom_out_start"){
|
||||||
@ -3317,4 +3318,82 @@ function findInteriorPoint(line, polygonLines) {
|
|||||||
start: startIsValley,
|
start: startIsValley,
|
||||||
end: endIsValley
|
end: endIsValley
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* baseLines의 순서를 wallLines의 순서와 일치시킵니다.
|
||||||
|
* 각 wallLine에 대해 가장 가깝고 평행한 baseLine을 찾아 정렬된 배열을 반환합니다.
|
||||||
|
*
|
||||||
|
* @param {Array} baseLines - 정렬할 원본 baseLine 배열
|
||||||
|
* @param {Array} wallLines - 기준이 되는 wallLine 배열
|
||||||
|
* @returns {Array} wallLines 순서에 맞춰 정렬된 baseLines
|
||||||
|
*/
|
||||||
|
export const sortBaseLinesByWallLines = (baseLines, wallLines) => {
|
||||||
|
if (!baseLines || !wallLines || baseLines.length === 0 || wallLines.length === 0) {
|
||||||
|
return baseLines;
|
||||||
|
}
|
||||||
|
|
||||||
|
const sortedBaseLines = [];
|
||||||
|
const usedIndices = new Set(); // 이미 매칭된 baseLine 인덱스를 추적
|
||||||
|
|
||||||
|
wallLines.forEach((wallLine) => {
|
||||||
|
let bestMatchIndex = -1;
|
||||||
|
let minDistance = Infinity;
|
||||||
|
|
||||||
|
// wallLine의 중점 계산
|
||||||
|
const wMidX = (wallLine.x1 + wallLine.x2) / 2;
|
||||||
|
const wMidY = (wallLine.y1 + wallLine.y2) / 2;
|
||||||
|
|
||||||
|
// wallLine의 방향 벡터 (평행 확인용)
|
||||||
|
const wDx = wallLine.x2 - wallLine.x1;
|
||||||
|
const wDy = wallLine.y2 - wallLine.y1;
|
||||||
|
const wLen = Math.hypot(wDx, wDy);
|
||||||
|
|
||||||
|
baseLines.forEach((baseLine, index) => {
|
||||||
|
// 이미 매칭된 라인은 건너뜀 (1:1 매칭)
|
||||||
|
if (usedIndices.has(index)) return;
|
||||||
|
|
||||||
|
// baseLine의 중점 계산
|
||||||
|
const bMidX = (baseLine.x1 + baseLine.x2) / 2;
|
||||||
|
const bMidY = (baseLine.y1 + baseLine.y2) / 2;
|
||||||
|
|
||||||
|
// 두 라인의 중점 사이 거리 계산
|
||||||
|
const dist = Math.hypot(wMidX - bMidX, wMidY - bMidY);
|
||||||
|
|
||||||
|
// 평행 여부 확인 (내적 사용)
|
||||||
|
const bDx = baseLine.x2 - baseLine.x1;
|
||||||
|
const bDy = baseLine.y2 - baseLine.y1;
|
||||||
|
const bLen = Math.hypot(bDx, bDy);
|
||||||
|
|
||||||
|
if (wLen > 0 && bLen > 0) {
|
||||||
|
// 단위 벡터 내적값 (-1 ~ 1)
|
||||||
|
const dot = (wDx * bDx + wDy * bDy) / (wLen * bLen);
|
||||||
|
|
||||||
|
// 내적의 절대값이 1에 가까우면 평행 (약 10도 오차 허용)
|
||||||
|
if (Math.abs(Math.abs(dot) - 1) < 0.1) {
|
||||||
|
if (dist < minDistance) {
|
||||||
|
minDistance = dist;
|
||||||
|
bestMatchIndex = index;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (bestMatchIndex !== -1) {
|
||||||
|
sortedBaseLines.push(baseLines[bestMatchIndex]);
|
||||||
|
usedIndices.add(bestMatchIndex);
|
||||||
|
} else {
|
||||||
|
// 매칭되는 라인을 찾지 못한 경우, 아직 사용되지 않은 첫 번째 라인을 할당 (Fallback)
|
||||||
|
const unusedIndex = baseLines.findIndex((_, idx) => !usedIndices.has(idx));
|
||||||
|
if (unusedIndex !== -1) {
|
||||||
|
sortedBaseLines.push(baseLines[unusedIndex]);
|
||||||
|
usedIndices.add(unusedIndex);
|
||||||
|
} else {
|
||||||
|
// 더 이상 남은 라인이 없으면 null 또는 기존 라인 중 하나(에러 방지)
|
||||||
|
sortedBaseLines.push(baseLines[0]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return sortedBaseLines;
|
||||||
|
};
|
||||||
Loading…
x
Reference in New Issue
Block a user