Merge branch 'dev' of https://git.hanasys.jp/qcast3/qcast-front into dev
This commit is contained in:
commit
960d31ffdd
@ -319,7 +319,7 @@ const createInnerLinesFromSkeleton = (skeleton, baseLines, roof, canvas, textMod
|
|||||||
|
|
||||||
const innerLines = []
|
const innerLines = []
|
||||||
const processedInnerEdges = new Set()
|
const processedInnerEdges = new Set()
|
||||||
const rawLines = []
|
const skeletonLines = []
|
||||||
|
|
||||||
// 1. 기본 skeleton에서 모든 내부 선분 수집
|
// 1. 기본 skeleton에서 모든 내부 선분 수집
|
||||||
//edge 순서와 baseLines 순서가 같을수가 없다.
|
//edge 순서와 baseLines 순서가 같을수가 없다.
|
||||||
@ -330,37 +330,17 @@ const createInnerLinesFromSkeleton = (skeleton, baseLines, roof, canvas, textMod
|
|||||||
//오른쪽 하단에서 시작하면 그 지점에서부터 시계 방향으로 진행합니다.
|
//오른쪽 하단에서 시작하면 그 지점에서부터 시계 방향으로 진행합니다.
|
||||||
//edgeIndex 대신에 실제 baseLines 선택라인을 찾아야 한다.
|
//edgeIndex 대신에 실제 baseLines 선택라인을 찾아야 한다.
|
||||||
const edgeResult = skeleton.Edges[edgeIndex]
|
const edgeResult = skeleton.Edges[edgeIndex]
|
||||||
|
console.log(edgeResult)
|
||||||
// 방향을 고려하지 않고 같은 라인인지 확인하는 함수
|
// 방향을 고려하지 않고 같은 라인인지 확인하는 함수
|
||||||
|
|
||||||
let edgeType = 'eaves'
|
let edgeType = 'eaves'
|
||||||
let baseLineIndex = 0
|
let baseLineIndex = 0
|
||||||
|
|
||||||
processEavesEdge(edgeResult, baseLines, rawLines, processedInnerEdges, edgeIndex, baseLineIndex)
|
processEavesEdge(edgeResult, baseLines, skeletonLines, processedInnerEdges)
|
||||||
// // ✅ Edge 타입별 처리 분기
|
|
||||||
// switch (edgeType) {
|
|
||||||
// case 'eaves':
|
|
||||||
// processEavesEdge(edgeResult, baseLines, rawLines, processedInnerEdges, edgeIndex, baseLineIndex)
|
|
||||||
// break
|
|
||||||
//
|
|
||||||
// case 'wall':
|
|
||||||
// processWallEdge(edgeResult, baseLines, rawLines, processedInnerEdges, edgeIndex)
|
|
||||||
// break
|
|
||||||
//
|
|
||||||
// case 'gable':
|
|
||||||
// processGableEdge(edgeResult, baseLines, rawLines, processedInnerEdges, edgeIndex, baseLineIndex)
|
|
||||||
// break
|
|
||||||
//
|
|
||||||
// default:
|
|
||||||
// console.warn(`알 수 없는 edge 타입: ${edgeType}`)
|
|
||||||
// processEavesEdge(edgeResult, baseLines, rawLines, processedInnerEdges, edgeIndex, baseLineIndex)
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for (let baseLineIndex = 0; baseLineIndex < baseLines.length; baseLineIndex++) {
|
|
||||||
|
|
||||||
if (baseLines[baseLineIndex].attributes.type === 'gable') {
|
|
||||||
// 일다 그려서 rawLines를 만들어
|
|
||||||
for (let edgeIndex = 0; edgeIndex < skeleton.Edges.length; edgeIndex++) {
|
for (let edgeIndex = 0; edgeIndex < skeleton.Edges.length; edgeIndex++) {
|
||||||
|
|
||||||
const edgeResult = skeleton.Edges[edgeIndex]
|
const edgeResult = skeleton.Edges[edgeIndex]
|
||||||
@ -369,24 +349,33 @@ const createInnerLinesFromSkeleton = (skeleton, baseLines, roof, canvas, textMod
|
|||||||
const endX = edgeResult.Edge.End.X
|
const endX = edgeResult.Edge.End.X
|
||||||
const endY = edgeResult.Edge.End.Y
|
const endY = edgeResult.Edge.End.Y
|
||||||
|
|
||||||
//외벽선 동일 라인이면
|
|
||||||
|
//외벽선 라인과 같은 edgeResult를 찾는다
|
||||||
|
for (let baseLineIndex = 0; baseLineIndex < baseLines.length; baseLineIndex++) {
|
||||||
|
|
||||||
|
if (baseLines[baseLineIndex].attributes.type === 'gable') {
|
||||||
|
// 일다 그려서 skeletonLines를 만들어
|
||||||
|
//외벽선 동일 라인이면
|
||||||
if (isSameLine(startX, startY, endX, endY, baseLines[baseLineIndex])) {
|
if (isSameLine(startX, startY, endX, endY, baseLines[baseLineIndex])) {
|
||||||
processGableEdge(edgeResult, baseLines, rawLines, processedInnerEdges, edgeIndex, baseLineIndex) //
|
processGableEdge(edgeResult, baseLines, skeletonLines, processedInnerEdges, edgeIndex, baseLineIndex) //
|
||||||
break // 매칭되는 라인을 찾았으므로 루프 종료
|
break // 매칭되는 라인을 찾았으므로 루프 종료
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log(`처리된 rawLines: ${rawLines.length}개`)
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(`처리된 skeletonLines: ${skeletonLines.length}개`)
|
||||||
|
|
||||||
// 2. 겹치는 선분 병합
|
// 2. 겹치는 선분 병합
|
||||||
// const mergedLines = mergeCollinearLines(rawLines)
|
// const mergedLines = mergeCollinearLines(skeletonLines)
|
||||||
// console.log('mergedLines', mergedLines)
|
// console.log('mergedLines', mergedLines)
|
||||||
// 3. QLine 객체로 변환
|
// 3. QLine 객체로 변환
|
||||||
for (const line of rawLines) {
|
for (const line of skeletonLines) {
|
||||||
const { p1, p2, attributes, lineStyle } = line
|
const { p1, p2, attributes, lineStyle } = line
|
||||||
const innerLine = new QLine([p1.x, p1.y, p2.x, p2.y], {
|
const innerLine = new QLine([p1.x, p1.y, p2.x, p2.y], {
|
||||||
parentId: roof.id,
|
parentId: roof.id,
|
||||||
@ -409,10 +398,13 @@ const createInnerLinesFromSkeleton = (skeleton, baseLines, roof, canvas, textMod
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ✅ EAVES (처마) 처리 - 기본 skeleton 모두 사용
|
// ✅ EAVES (처마) 처리 - 기본 skeleton 모두 사용
|
||||||
function processEavesEdge(edgeResult, baseLines, rawLines, processedInnerEdges) {
|
function processEavesEdge(edgeResult, baseLines, skeletonLines, processedInnerEdges) {
|
||||||
console.log(`processEavesEdge::`, rawLines)
|
console.log(`processEavesEdge::`, skeletonLines)
|
||||||
|
const begin = edgeResult.Edge.Begin
|
||||||
|
const end = edgeResult.Edge.End
|
||||||
|
|
||||||
// 내부 선분 수집 (스케레톤은 다각형)
|
|
||||||
|
//내부 선분 수집 (스케레톤은 다각형)
|
||||||
const polygonPoints = edgeResult.Polygon.map((p) => ({ x: p.X, y: p.Y }))
|
const polygonPoints = edgeResult.Polygon.map((p) => ({ x: p.X, y: p.Y }))
|
||||||
|
|
||||||
for (let i = 0; i < polygonPoints.length; i++) {
|
for (let i = 0; i < polygonPoints.length; i++) {
|
||||||
@ -421,14 +413,14 @@ function processEavesEdge(edgeResult, baseLines, rawLines, processedInnerEdges)
|
|||||||
const p2 = polygonPoints[(i + 1) % polygonPoints.length]
|
const p2 = polygonPoints[(i + 1) % polygonPoints.length]
|
||||||
|
|
||||||
// 외벽선 제외 후 추가
|
// 외벽선 제외 후 추가
|
||||||
if (!isOuterEdge(p1, p2, baseLines)) {
|
if(begin !== edgeResult.Polygon[i] && end !== edgeResult.Polygon[i] ) {
|
||||||
addRawLine(rawLines, processedInnerEdges, p1, p2, 'RIDGE', '#FF0000', 3)
|
addRawLine(skeletonLines, processedInnerEdges, p1, p2, 'RIDGE', '#FF0000', 3)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ✅ WALL (벽) 처리 - 선분 개수 최소화
|
// ✅ WALL (벽) 처리 - 선분 개수 최소화
|
||||||
function processWallEdge(edgeResult, baseLines, rawLines, processedInnerEdges, edgeIndex) {
|
function processWallEdge(edgeResult, baseLines, skeletonLines, processedInnerEdges, edgeIndex) {
|
||||||
console.log(`WALL Edge ${edgeIndex}: 내부 선분 최소화`)
|
console.log(`WALL Edge ${edgeIndex}: 내부 선분 최소화`)
|
||||||
|
|
||||||
const polygonPoints = edgeResult.Polygon.map((p) => ({ x: p.X, y: p.Y }))
|
const polygonPoints = edgeResult.Polygon.map((p) => ({ x: p.X, y: p.Y }))
|
||||||
@ -444,7 +436,7 @@ function processWallEdge(edgeResult, baseLines, rawLines, processedInnerEdges, e
|
|||||||
|
|
||||||
if (lineLength > 10) {
|
if (lineLength > 10) {
|
||||||
// 최소 길이 조건
|
// 최소 길이 조건
|
||||||
addRawLine(rawLines, processedInnerEdges, p1, p2, 'HIP', '#000000', 2)
|
addRawLine(skeletonLines, processedInnerEdges, p1, p2, 'HIP', '#000000', 2)
|
||||||
} else {
|
} else {
|
||||||
console.log(`WALL: 짧은 선분 제거 (길이: ${lineLength.toFixed(1)})`)
|
console.log(`WALL: 짧은 선분 제거 (길이: ${lineLength.toFixed(1)})`)
|
||||||
}
|
}
|
||||||
@ -453,7 +445,7 @@ function processWallEdge(edgeResult, baseLines, rawLines, processedInnerEdges, e
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ✅ GABLE (케라바) 처리 - 직선 생성, 다른 선분 제거
|
// ✅ GABLE (케라바) 처리 - 직선 생성, 다른 선분 제거
|
||||||
function processGableEdge(edgeResult, baseLines, rawLines, processedInnerEdges, edgeIndex, baseLineIndex) {
|
function processGableEdge(edgeResult, baseLines, skeletonLines, processedInnerEdges, edgeIndex, baseLineIndex) {
|
||||||
console.log(`GABLE Edge ${edgeResult}: 직선 skeleton 생성`)
|
console.log(`GABLE Edge ${edgeResult}: 직선 skeleton 생성`)
|
||||||
const diagonalLine = []; //대각선 라인
|
const diagonalLine = []; //대각선 라인
|
||||||
|
|
||||||
@ -463,7 +455,6 @@ function processGableEdge(edgeResult, baseLines, rawLines, processedInnerEdges,
|
|||||||
|
|
||||||
// 1. 기존 복잡한 skeleton 선분들 무시
|
// 1. 기존 복잡한 skeleton 선분들 무시
|
||||||
// 2. GABLE edge에 수직인 직선 생성
|
// 2. GABLE edge에 수직인 직선 생성
|
||||||
|
|
||||||
const sourceEdge = edgeResult.Edge
|
const sourceEdge = edgeResult.Edge
|
||||||
const gableStart = { x: sourceEdge.Begin.X, y: sourceEdge.Begin.Y }
|
const gableStart = { x: sourceEdge.Begin.X, y: sourceEdge.Begin.Y }
|
||||||
const gableEnd = { x: sourceEdge.End.X, y: sourceEdge.End.Y }
|
const gableEnd = { x: sourceEdge.End.X, y: sourceEdge.End.Y }
|
||||||
@ -486,10 +477,10 @@ function processGableEdge(edgeResult, baseLines, rawLines, processedInnerEdges,
|
|||||||
// })
|
// })
|
||||||
// }
|
// }
|
||||||
//
|
//
|
||||||
// // 폴리곤 중심점 (대략적)
|
// 폴리곤 중심점 (대략적)
|
||||||
// const centerX = polygonPoints.reduce((sum, p) => sum + p.x, 0) / polygonPoints.length
|
const centerX = polygonPoints.reduce((sum, p) => sum + p.x, 0) / polygonPoints.length
|
||||||
// const centerY = polygonPoints.reduce((sum, p) => sum + p.y, 0) / polygonPoints.length
|
const centerY = polygonPoints.reduce((sum, p) => sum + p.y, 0) / polygonPoints.length
|
||||||
// const polygonCenter = { x: centerX, y: centerY }
|
const polygonCenter = { x: centerX, y: centerY }
|
||||||
//
|
//
|
||||||
// // 허용 오차
|
// // 허용 오차
|
||||||
// const colinearityTolerance = 0.1
|
// const colinearityTolerance = 0.1
|
||||||
@ -530,15 +521,114 @@ function processGableEdge(edgeResult, baseLines, rawLines, processedInnerEdges,
|
|||||||
|
|
||||||
const selectBaseLine = baseLines[baseLineIndex];
|
const selectBaseLine = baseLines[baseLineIndex];
|
||||||
console.log('selectBaseLine:', selectBaseLine);
|
console.log('selectBaseLine:', selectBaseLine);
|
||||||
console.log('rawLines:', rawLines)
|
console.log('skeletonLines:', skeletonLines)
|
||||||
//selectBaseLine 과 같은 edgeResult.ed
|
|
||||||
|
// selectBaseLine의 중간 좌표 계산
|
||||||
|
const midPoint = {
|
||||||
|
x: (selectBaseLine.x1 + selectBaseLine.x2) / 2,
|
||||||
|
y: (selectBaseLine.y1 + selectBaseLine.y2) / 2
|
||||||
|
};
|
||||||
|
console.log('midPoint of selectBaseLine:', midPoint);
|
||||||
|
|
||||||
// 대각선 보정(fallback) 제거: 항상 수평/수직 내부 용마루만 생성
|
// 대각선 보정(fallback) 제거: 항상 수평/수직 내부 용마루만 생성
|
||||||
|
const edgePoints = edgeResult.Polygon.map(p => ({ x: p.X, y: p.Y }));
|
||||||
|
|
||||||
for (let i = rawLines.length - 1; i >= 0; i--) {
|
//제거
|
||||||
const line = rawLines[i];
|
for (let i = skeletonLines.length - 1; i >= 0; i--) {
|
||||||
|
const line = skeletonLines[i];
|
||||||
console.log('line:', line)
|
console.log('line:', line)
|
||||||
console.log('line.attributes.type:', line.attributes.type)
|
console.log('line.attributes.type:', line.attributes.type)
|
||||||
|
|
||||||
|
const linePoints = [line.p1, line.p2];
|
||||||
|
|
||||||
|
// Check if both points of the line are in the edgePoints
|
||||||
|
const isEdgeLine = linePoints.every(point =>
|
||||||
|
edgePoints.some(ep =>
|
||||||
|
Math.abs(ep.x - point.x) < 0.001 &&
|
||||||
|
Math.abs(ep.y - point.y) < 0.001
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
if (isEdgeLine) {
|
||||||
|
skeletonLines.splice(i, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//확장
|
||||||
|
// Extend lines that have endpoints in edgePoints to intersect with selectBaseLine
|
||||||
|
// Find diagonal lines (not horizontal or vertical)
|
||||||
|
// Extend lines that have endpoints in edgePoints
|
||||||
|
|
||||||
|
for (let i = 0; i < skeletonLines.length; i++) {
|
||||||
|
const line = skeletonLines[i];
|
||||||
|
const p1 = line.p1;
|
||||||
|
const p2 = line.p2;
|
||||||
|
const lineP1 = { x: line.p1.x, y: line.p1.y };
|
||||||
|
const lineP2 = { x: line.p2.x, y: line.p2.y };
|
||||||
|
|
||||||
|
let hasP1 = false;
|
||||||
|
let hasP2 = false;
|
||||||
|
console.log('edgeResult.Edge::',edgeResult.Edge)
|
||||||
|
|
||||||
|
const lineInfo = findMatchingLinePoints(line, edgeResult.Polygon);
|
||||||
|
console.log(lineInfo);
|
||||||
|
|
||||||
|
//대각선
|
||||||
|
//직선(마루)
|
||||||
|
if(lineInfo.hasMatch) {
|
||||||
|
if (lineInfo.matches[0].type === 'diagonal') {
|
||||||
|
|
||||||
|
const intersection2 = getLineIntersectionParametric(lineP1, lineP2, gableStart, gableEnd);
|
||||||
|
console.log('intersection2:', intersection2);
|
||||||
|
if (lineInfo.matches[0].linePoint === 'p1') {
|
||||||
|
|
||||||
|
|
||||||
|
skeletonLines[i].p1 = { ...skeletonLines[i].p1, x: intersection2.x, y: intersection2.y };
|
||||||
|
} else {
|
||||||
|
|
||||||
|
skeletonLines[i].p2 = { ...skeletonLines[i].p2, x: intersection2.x, y: intersection2.y };
|
||||||
|
}
|
||||||
|
|
||||||
|
} else if (lineInfo.matches[0].type === 'horizontal') {
|
||||||
|
if (lineInfo.matches[0].linePoint === 'p1') {
|
||||||
|
skeletonLines[i].p1 = { ...skeletonLines[i].p1, x: edgeResult.Edge.Begin.X };
|
||||||
|
} else {
|
||||||
|
skeletonLines[i].p2 = { ...skeletonLines[i].p2, x: edgeResult.Edge.Begin.X };
|
||||||
|
}
|
||||||
|
|
||||||
|
} else if (lineInfo.matches[0].type === 'vertical') {
|
||||||
|
if (lineInfo.matches[0].linePoint === 'p1') {
|
||||||
|
skeletonLines[i].p1 = { ...skeletonLines[i].p1, y: edgeResult.Edge.Begin.Y };
|
||||||
|
} else {
|
||||||
|
skeletonLines[i].p2 = { ...skeletonLines[i].p2, y: edgeResult.Edge.Begin.Y };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// for (const polyPoint of edgeResult.Polygon) {
|
||||||
|
//
|
||||||
|
// if (polyPoint.X === lineP1.x && polyPoint.Y === lineP1.y) {
|
||||||
|
// const extendedPoint1 = getExtensionIntersection(lineP2.x, lineP2.y, lineP1.x, lineP1.y, edgeResult.Edge.Begin.X, edgeResult.Edge.Begin.Y, edgeResult.Edge.End.X,edgeResult.Edge.End.Y);
|
||||||
|
// console.log('extendedPoint1:', extendedPoint1);
|
||||||
|
//
|
||||||
|
// skeletonLines[i].p1 = { ...skeletonLines[i].p1, x: extendedPoint1.x, y: extendedPoint1.Y };
|
||||||
|
// //skeletonLines[i].p2 = { ...skeletonLines[i].p2, x: edgeResult.Edge.Begin.X};
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// if (polyPoint.X === lineP2.x && polyPoint.Y === lineP2.y) {
|
||||||
|
// const extendedPoint2 = getExtensionIntersection(lineP1.x, lineP1.y,lineP2.x, lineP2.y, edgeResult.Edge.Begin.X, edgeResult.Edge.Begin.Y, edgeResult.Edge.End.X,edgeResult.Edge.End.Y);
|
||||||
|
// console.log('extendedPoint2:', extendedPoint2);
|
||||||
|
//
|
||||||
|
// skeletonLines[i].p1 = { ...skeletonLines[i].p1, x: extendedPoint2.x, y: extendedPoint2.Y };
|
||||||
|
// //skeletonLines[i].p2 = { ...skeletonLines[i].p2, y: edgeResult.Edge.Begin.Y };
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
if (line.attributes.type === LINE_TYPE.SUBLINE.HIP || line.attributes.type === 'HIP') {
|
if (line.attributes.type === LINE_TYPE.SUBLINE.HIP || line.attributes.type === 'HIP') {
|
||||||
|
|
||||||
// 선택한 기준선 을 중심으로 대각선 삭제
|
// 선택한 기준선 을 중심으로 대각선 삭제
|
||||||
@ -556,19 +646,32 @@ function processGableEdge(edgeResult, baseLines, rawLines, processedInnerEdges,
|
|||||||
const sharesEndPoint = pointsEqual(edgeEnd, lineStart) || pointsEqual(edgeEnd, lineEnd);
|
const sharesEndPoint = pointsEqual(edgeEnd, lineStart) || pointsEqual(edgeEnd, lineEnd);
|
||||||
|
|
||||||
if (sharesStartPoint || sharesEndPoint) {
|
if (sharesStartPoint || sharesEndPoint) {
|
||||||
rawLines.splice(i, 1);
|
skeletonLines.splice(i, 1);
|
||||||
// ridge extension logic can go here
|
// ridge extension logic can go here
|
||||||
|
//gableMidpoint까지 확장
|
||||||
|
|
||||||
|
}else{
|
||||||
|
//선택한 baseLine 연장(edgeResult.Polygon 의 좌표와 동일한 좌표를 찾아서 연장)
|
||||||
|
for (const polyPoint of edgeResult.Polygon) {
|
||||||
|
if (Math.abs(polyPoint.X - lineEnd.x) < 0.1 && Math.abs(polyPoint.Y - lineEnd.y) < 0.1) {
|
||||||
|
// 연장 로직
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}else if (line.attributes.type === LINE_TYPE.SUBLINE.RIDGE || line.attributes.type === 'RIDGE') {
|
}else if (line.attributes.type === LINE_TYPE.SUBLINE.RIDGE || line.attributes.type === 'RIDGE') {
|
||||||
//마루일때
|
//마루일때
|
||||||
|
|
||||||
if(edgeResult.Polygon.length > 3){
|
|
||||||
const lineP1 = { x: line.p1.x, y: line.p1.y };
|
const lineP1 = { x: line.p1.x, y: line.p1.y };
|
||||||
const lineP2 = { x: line.p2.x, y: line.p2.y };
|
const lineP2 = { x: line.p2.x, y: line.p2.y };
|
||||||
|
const extensionLine= {
|
||||||
|
maxX:'',
|
||||||
|
minX:'',
|
||||||
|
maxY:'',
|
||||||
|
minY:'',
|
||||||
|
}
|
||||||
|
|
||||||
|
if(edgeResult.Polygon.length > 3){
|
||||||
|
|
||||||
let hasP1 = false;
|
let hasP1 = false;
|
||||||
let hasP2 = false;
|
let hasP2 = false;
|
||||||
|
|
||||||
@ -585,18 +688,74 @@ function processGableEdge(edgeResult, baseLines, rawLines, processedInnerEdges,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (hasP1 && hasP2) {
|
if (hasP1 && hasP2) {
|
||||||
rawLines.splice(i, 1);
|
skeletonLines.splice(i, 1);
|
||||||
|
//양쪽 대각선이 있으면 서로 만난다.
|
||||||
|
for (const polyPoint of edgeResult.Polygon) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//가운데 연장선을 추가
|
||||||
|
skeletonLines.push({
|
||||||
|
p1: {x: midPoint.x, y: midPoint.y},
|
||||||
|
p2: {x: centerX, y: centerY},
|
||||||
|
attributes: {
|
||||||
|
type: LINE_TYPE.SUBLINE.RIDGE,
|
||||||
|
planeSize: calcLinePlaneSize({ x1: midPoint.x, y1: midPoint.y, x2: centerX, y2: centerY }),
|
||||||
|
isRidge: true,
|
||||||
|
},
|
||||||
|
lineStyle: {
|
||||||
|
color: '#FF0000',
|
||||||
|
width: 2
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}else{
|
||||||
|
console.log("mpoint",gableMidpoint)
|
||||||
|
console.log("midPoint", midPoint)
|
||||||
|
console.log("lineP1",lineP1)
|
||||||
|
console.log("lineP2",lineP2)
|
||||||
|
//gableMidpoint까지 확장 (x or y 동일)
|
||||||
|
//가로일때 gableMidPoint.y 동일
|
||||||
|
// Extend horizontal lines to gable midpoint
|
||||||
|
//
|
||||||
|
if (Math.abs(lineP1.y - lineP2.y) < 0.3) { // 가로 라인
|
||||||
|
const extension = getExtensionLine(midPoint, lineP1, lineP2);
|
||||||
|
if (extension) { // null 체크 추가
|
||||||
|
if (extension.isStartExtension) {
|
||||||
|
skeletonLines[i].p1 = { ...skeletonLines[i].p1, x: extension.extensionPoint.x };
|
||||||
|
} else {
|
||||||
|
skeletonLines[i].p2 = { ...skeletonLines[i].p2, x: extension.extensionPoint.x };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else { // 세로 라인
|
||||||
|
const extension = getExtensionLine(midPoint, lineP1, lineP2);
|
||||||
|
if (extension) { // null 체크 추가
|
||||||
|
if (extension.isStartExtension) {
|
||||||
|
skeletonLines[i].p1 = { ...skeletonLines[i].p1, y: extension.extensionPoint.y };
|
||||||
|
} else {
|
||||||
|
skeletonLines[i].p2 = { ...skeletonLines[i].p2, y: extension.extensionPoint.y };
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log('result rawLines:', rawLines)
|
console.log('result skeletonLines:', skeletonLines)
|
||||||
}
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// addRawLine(
|
// addRawLine(
|
||||||
// rawLines,
|
// skeletonLines,
|
||||||
// processedInnerEdges,
|
// processedInnerEdges,
|
||||||
// gableMidpoint,
|
// gableMidpoint,
|
||||||
// polygonCenter,
|
// polygonCenter,
|
||||||
@ -626,7 +785,7 @@ function isOuterEdge(p1, p2, baseLines) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
function addRawLine(rawLines, processedInnerEdges, p1, p2, lineType, color, width) {
|
function addRawLine(skeletonLines, processedInnerEdges, p1, p2, lineType, color, width) {
|
||||||
const edgeKey = [`${p1.x.toFixed(1)},${p1.y.toFixed(1)}`, `${p2.x.toFixed(1)},${p2.y.toFixed(1)}`].sort().join('|')
|
const edgeKey = [`${p1.x.toFixed(1)},${p1.y.toFixed(1)}`, `${p2.x.toFixed(1)},${p2.y.toFixed(1)}`].sort().join('|')
|
||||||
|
|
||||||
if (processedInnerEdges.has(edgeKey)) return
|
if (processedInnerEdges.has(edgeKey)) return
|
||||||
@ -651,7 +810,7 @@ function addRawLine(rawLines, processedInnerEdges, p1, p2, lineType, color, widt
|
|||||||
// 대각선일 때 lineType을 HIP로 지정
|
// 대각선일 때 lineType을 HIP로 지정
|
||||||
const normalizedType = isDiagonal ? LINE_TYPE.SUBLINE.HIP : inputNormalizedType
|
const normalizedType = isDiagonal ? LINE_TYPE.SUBLINE.HIP : inputNormalizedType
|
||||||
|
|
||||||
rawLines.push({
|
skeletonLines.push({
|
||||||
p1: p1,
|
p1: p1,
|
||||||
p2: p2,
|
p2: p2,
|
||||||
attributes: {
|
attributes: {
|
||||||
@ -1618,3 +1777,333 @@ const isSameLine = (edgeStartX, edgeStartY, edgeEndX, edgeEndY, baseLine) => {
|
|||||||
|
|
||||||
return clockwiseMatch || counterClockwiseMatch
|
return clockwiseMatch || counterClockwiseMatch
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 중간점과 선분의 끝점을 비교하여 연장선(extensionLine)을 결정합니다.
|
||||||
|
* @param {Object} midPoint - 중간점 좌표 {x, y}
|
||||||
|
* @param {Object} lineP1 - 선분의 첫 번째 끝점 {x, y}
|
||||||
|
* @param {Object} lineP2 - 선분의 두 번째 끝점 {x, y}
|
||||||
|
* @returns {Object|null} - 연장선 설정 또는 null (연장 불필요 시)
|
||||||
|
*/
|
||||||
|
function getExtensionLine(midPoint, lineP1, lineP2) {
|
||||||
|
// 선분의 방향 계산
|
||||||
|
const isHorizontal = Math.abs(lineP1.y - lineP2.y) < 0.3; // y 좌표가 거의 같으면 수평선
|
||||||
|
const isVertical = Math.abs(lineP1.x - lineP2.x) < 0.3; // x 좌표가 거의 같으면 수직선
|
||||||
|
|
||||||
|
if (isHorizontal) {
|
||||||
|
// 수평선인 경우 - y 좌표가 midPoint와 같은지 확인
|
||||||
|
if (Math.abs(lineP1.y - midPoint.y) > 0.3) {
|
||||||
|
return null; // y 좌표가 다르면 연장하지 않음
|
||||||
|
}
|
||||||
|
|
||||||
|
// 중간점이 선분의 왼쪽에 있는 경우
|
||||||
|
if (midPoint.x < Math.min(lineP1.x, lineP2.x)) {
|
||||||
|
return {
|
||||||
|
isHorizontal: true,
|
||||||
|
isStartExtension: lineP1.x < lineP2.x,
|
||||||
|
extensionPoint: { ...midPoint, y: lineP1.y }
|
||||||
|
};
|
||||||
|
}
|
||||||
|
// 중간점이 선분의 오른쪽에 있는 경우
|
||||||
|
else if (midPoint.x > Math.max(lineP1.x, lineP2.x)) {
|
||||||
|
return {
|
||||||
|
isHorizontal: true,
|
||||||
|
isStartExtension: lineP1.x > lineP2.x,
|
||||||
|
extensionPoint: { ...midPoint, y: lineP1.y }
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (isVertical) {
|
||||||
|
// 수직선인 경우 - x 좌표가 midPoint와 같은지 확인
|
||||||
|
if (Math.abs(lineP1.x - midPoint.x) > 0.3) {
|
||||||
|
return null; // x 좌표가 다르면 연장하지 않음
|
||||||
|
}
|
||||||
|
|
||||||
|
// 중간점이 선분의 위에 있는 경우
|
||||||
|
if (midPoint.y < Math.min(lineP1.y, lineP2.y)) {
|
||||||
|
return {
|
||||||
|
isHorizontal: false,
|
||||||
|
isStartExtension: lineP1.y < lineP2.y,
|
||||||
|
extensionPoint: { ...midPoint, x: lineP1.x }
|
||||||
|
};
|
||||||
|
}
|
||||||
|
// 중간점이 선분의 아래에 있는 경우
|
||||||
|
else if (midPoint.y > Math.max(lineP1.y, lineP2.y)) {
|
||||||
|
return {
|
||||||
|
isHorizontal: false,
|
||||||
|
isStartExtension: lineP1.y > lineP2.y,
|
||||||
|
extensionPoint: { ...midPoint, x: lineP1.x }
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 기본값 반환 (연장 불필요)
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
function convertToClockwise(points) {
|
||||||
|
// 1. 다각형의 면적 계산 (시계/반시계 방향 판단용)
|
||||||
|
let area = 0;
|
||||||
|
const n = points.length;
|
||||||
|
|
||||||
|
for (let i = 0; i < n; i++) {
|
||||||
|
const j = (i + 1) % n;
|
||||||
|
area += (points[j].X - points[i].X) * (points[j].Y + points[i].Y);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. 반시계방향이면 배열을 뒤집어 시계방향으로 변환
|
||||||
|
if (area < 0) {
|
||||||
|
return [...points].reverse();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. 이미 시계방향이면 그대로 반환
|
||||||
|
return [...points];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* skeletonLines에서 특정 점(polyPoint)을 지나는 라인을 찾는 함수
|
||||||
|
* @param {Array} skeletonLines - 검색할 라인 배열
|
||||||
|
* @param {Object} polyPoint - 검색할 점 {X, Y}
|
||||||
|
* @returns {Array} - 일치하는 라인 배열
|
||||||
|
*/
|
||||||
|
function findLinesPassingPoint(skeletonLines, polyPoint) {
|
||||||
|
return skeletonLines.filter(line => {
|
||||||
|
// 라인의 시작점이나 끝점이 polyPoint와 일치하는지 확인
|
||||||
|
const isP1Match = (Math.abs(line.p1.x - polyPoint.X) < 0.001 &&
|
||||||
|
Math.abs(line.p1.y - polyPoint.Y) < 0.001);
|
||||||
|
const isP2Match = (Math.abs(line.p2.x - polyPoint.X) < 0.001 &&
|
||||||
|
Math.abs(line.p2.y - polyPoint.Y) < 0.001);
|
||||||
|
|
||||||
|
return isP1Match || isP2Match;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// 두 선분의 교차점을 찾는 함수
|
||||||
|
// 두 선분의 교차점을 찾는 함수 (개선된 버전)
|
||||||
|
function findIntersection(p1, p2, p3, p4) {
|
||||||
|
// 선분1: p1 -> p2
|
||||||
|
// 선분2: p3 -> p4
|
||||||
|
|
||||||
|
// 선분 방향 벡터
|
||||||
|
const d1x = p2.x - p1.x;
|
||||||
|
const d1y = p2.y - p1.y;
|
||||||
|
const d2x = p4.x - p3.x;
|
||||||
|
const d2y = p4.y - p3.y;
|
||||||
|
|
||||||
|
// 분모 계산
|
||||||
|
const denominator = d1x * d2y - d1y * d2x;
|
||||||
|
|
||||||
|
// 평행한 경우 (또는 매우 가까운 경우)
|
||||||
|
// if (Math.abs(denominator) < 0.0001) {
|
||||||
|
// return null;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// 매개변수 t와 u 계산
|
||||||
|
const t = ((p3.x - p1.x) * d2y - (p3.y - p1.y) * d2x) / denominator;
|
||||||
|
const u = ((p3.x - p1.x) * d1y - (p3.y - p1.y) * d1x) / denominator;
|
||||||
|
|
||||||
|
// 두 선분이 교차하는지 확인 (0 <= t <= 1, 0 <= u <= 1)
|
||||||
|
if (t >= -0.001 && t <= 1.001 && u >= -0.001 && u <= 1.001) {
|
||||||
|
// 교차점 계산
|
||||||
|
const x = p1.x + t * d1x;
|
||||||
|
const y = p1.y + t * d1y;
|
||||||
|
return { x, y };
|
||||||
|
}
|
||||||
|
|
||||||
|
// 교차하지 않는 경우
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* edgePoints와 skeletonLines의 교차점을 찾는 함수
|
||||||
|
* @param {Array<{x: number, y: number}>} edgePoints - 엣지 포인트 배열
|
||||||
|
* @param {Array} skeletonLines - 원시 라인 배열 (각 라인은 p1, p2 속성을 가짐)
|
||||||
|
* @returns {Array<{x: number, y: number, line: Object}>} 교차점과 해당 라인 정보 배열
|
||||||
|
*/
|
||||||
|
function findIntersectionsWithEdgePoints(edgePoints, skeletonLines) {
|
||||||
|
const intersections = [];
|
||||||
|
|
||||||
|
// edgePoints를 순회하며 각 점을 지나는 라인 찾기
|
||||||
|
for (let i = 0; i < edgePoints.length; i++) {
|
||||||
|
const point = edgePoints[i];
|
||||||
|
const nextPoint = edgePoints[(i + 1) % edgePoints.length];
|
||||||
|
|
||||||
|
// 현재 엣지 선분
|
||||||
|
const edgeLine = {
|
||||||
|
x1: point.x, y1: point.y,
|
||||||
|
x2: nextPoint.x, y2: nextPoint.y
|
||||||
|
};
|
||||||
|
|
||||||
|
// 모든 skeletonLines와의 교차점 검사
|
||||||
|
for (const rawLine of skeletonLines) {
|
||||||
|
// rawLine은 p1, p2 속성을 가짐
|
||||||
|
const rawLineObj = {
|
||||||
|
x1: rawLine.p1.x, y1: rawLine.p1.y,
|
||||||
|
x2: rawLine.p2.x, y2: rawLine.p2.y
|
||||||
|
};
|
||||||
|
|
||||||
|
// 선분 교차 검사
|
||||||
|
const intersection = findIntersection(
|
||||||
|
edgeLine.x1, edgeLine.y1, edgeLine.x2, edgeLine.y2,
|
||||||
|
rawLineObj.x1, rawLineObj.y1, rawLineObj.x2, rawLineObj.y2
|
||||||
|
);
|
||||||
|
|
||||||
|
if (intersection) {
|
||||||
|
intersections.push({
|
||||||
|
x: intersection.x,
|
||||||
|
y: intersection.y,
|
||||||
|
edgeIndex: i,
|
||||||
|
line: rawLine
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return intersections;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Helper function to extend a line to intersect with polygon edges
|
||||||
|
function extendLineToIntersections(p1, p2, polygonPoints) {
|
||||||
|
let intersections = [];
|
||||||
|
const line = { p1, p2 };
|
||||||
|
|
||||||
|
// Check intersection with each polygon edge
|
||||||
|
for (let i = 0; i < polygonPoints.length; i++) {
|
||||||
|
const edgeP1 = polygonPoints[i];
|
||||||
|
const edgeP2 = polygonPoints[(i + 1) % polygonPoints.length];
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if (intersections.length < 2) return null;
|
||||||
|
|
||||||
|
// Sort by distance from p1
|
||||||
|
intersections.sort((a, b) => a.distance - b.distance);
|
||||||
|
|
||||||
|
// Return the two farthest intersection points
|
||||||
|
return {
|
||||||
|
p1: { x: intersections[0].x, y: intersections[0].y },
|
||||||
|
p2: {
|
||||||
|
x: intersections[intersections.length - 1].x,
|
||||||
|
y: intersections[intersections.length - 1].y
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function getExtensionIntersection(
|
||||||
|
startX, startY, // 대각선 시작점
|
||||||
|
currentX, currentY, // 대각선 현재 위치
|
||||||
|
lineStartX, lineStartY, // 연장할 선의 시작점
|
||||||
|
lineEndX, lineEndY // 연장할 선의 끝점
|
||||||
|
) {
|
||||||
|
// 대각선 방향 벡터
|
||||||
|
const dx = currentX - startX;
|
||||||
|
const dy = currentY - startY;
|
||||||
|
|
||||||
|
// 연장할 선의 기울기
|
||||||
|
const m = (lineEndY - lineStartY) / (lineEndX - lineStartX);
|
||||||
|
|
||||||
|
// 매개변수 t 방정식에서 t를 구하기 위한 식 전개
|
||||||
|
// 대각선의 parametric 방정식: x = startX + t*dx, y = startY + t*dy
|
||||||
|
// 연장할 선 방정식: y = m * (x - lineStartX) + lineStartY
|
||||||
|
// 이를 대입해 t 구함
|
||||||
|
const numerator = m * (lineStartX - startX) + startY - lineStartY;
|
||||||
|
const denominator = dy - m * dx;
|
||||||
|
|
||||||
|
if (denominator === 0) {
|
||||||
|
// 평행하거나 일치하여 교점 없음
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const t = numerator / denominator;
|
||||||
|
|
||||||
|
const intersectX = startX + t * dx;
|
||||||
|
const intersectY = startY + t * dy;
|
||||||
|
|
||||||
|
return { x: intersectX, y: intersectY };
|
||||||
|
}
|
||||||
|
|
||||||
|
function findMatchingLinePoints(Aline, APolygon, epsilon = 1e-10) {
|
||||||
|
const { p1, p2 } = Aline;
|
||||||
|
const matches = [];
|
||||||
|
|
||||||
|
// 선의 방향 판단
|
||||||
|
function getLineDirection(point1, point2, epsilon = 1e-10) {
|
||||||
|
const deltaX = Math.abs(point1.x - point2.x);
|
||||||
|
const deltaY = Math.abs(point1.y - point2.y);
|
||||||
|
|
||||||
|
if (deltaX < epsilon && deltaY < epsilon) {
|
||||||
|
return {
|
||||||
|
type: 'point',
|
||||||
|
description: '점 (두 좌표가 동일)'
|
||||||
|
};
|
||||||
|
} else if (deltaX < epsilon) {
|
||||||
|
return {
|
||||||
|
type: 'vertical',
|
||||||
|
description: '수직선 (세로)'
|
||||||
|
};
|
||||||
|
} else if (deltaY < epsilon) {
|
||||||
|
return {
|
||||||
|
type: 'horizontal',
|
||||||
|
description: '수평선 (가로)'
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
return {
|
||||||
|
type: 'diagonal',
|
||||||
|
description: '대각선'
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 선의 방향 정보 계산
|
||||||
|
const lineDirection = getLineDirection(p1, p2, epsilon);
|
||||||
|
|
||||||
|
APolygon.forEach((point, index) => {
|
||||||
|
// p1과 비교
|
||||||
|
if (Math.abs(p1.x - point.X) < epsilon && Math.abs(p1.y - point.Y) < epsilon) {
|
||||||
|
matches.push({
|
||||||
|
linePoint: 'p1',
|
||||||
|
polygonIndex: index,
|
||||||
|
coordinates: { x: point.X, y: point.Y },
|
||||||
|
lineDirection: lineDirection,
|
||||||
|
type: lineDirection.type
|
||||||
|
});
|
||||||
|
}
|
||||||
|
// p2와 비교
|
||||||
|
if (Math.abs(p2.x - point.X) < epsilon && Math.abs(p2.y - point.Y) < epsilon) {
|
||||||
|
matches.push({
|
||||||
|
linePoint: 'p2',
|
||||||
|
polygonIndex: index,
|
||||||
|
coordinates: { x: point.X, y: point.Y },
|
||||||
|
lineDirection: lineDirection,
|
||||||
|
type: lineDirection.type
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
hasMatch: matches.length > 0,
|
||||||
|
lineDirection: lineDirection,
|
||||||
|
matches: matches
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function getLineIntersectionParametric(p1, p2, p3, p4) {
|
||||||
|
const d1 = { x: p2.x - p1.x, y: p2.y - p1.y }; // 첫번째 직선 방향벡터
|
||||||
|
const d2 = { x: p4.x - p3.x, y: p4.y - p3.y }; // 두번째 직선 방향벡터
|
||||||
|
|
||||||
|
// 평행선 체크 (외적이 0이면 평행)
|
||||||
|
const cross = d1.x * d2.y - d1.y * d2.x;
|
||||||
|
if (Math.abs(cross) < Number.EPSILON) {
|
||||||
|
return null; // 평행선
|
||||||
|
}
|
||||||
|
|
||||||
|
// 매개변수 t 계산
|
||||||
|
const dx = p3.x - p1.x;
|
||||||
|
const dy = p3.y - p1.y;
|
||||||
|
const t = (dx * d2.y - dy * d2.x) / cross;
|
||||||
|
|
||||||
|
// 교점: p1 + t * d1
|
||||||
|
return {
|
||||||
|
x: p1.x + t * d1.x,
|
||||||
|
y: p1.y + t * d1.y
|
||||||
|
};
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user