라인줄표시, 인덱스 재설치
This commit is contained in:
parent
26b583e2f5
commit
8fef6c9f28
@ -7,6 +7,7 @@ import * as turf from '@turf/turf'
|
|||||||
import { LINE_TYPE, POLYGON_TYPE } from '@/common/common'
|
import { LINE_TYPE, POLYGON_TYPE } from '@/common/common'
|
||||||
import Big from 'big.js'
|
import Big from 'big.js'
|
||||||
import { drawSkeletonRidgeRoof, drawSkeletonRidgeRoofFromBaseLines, verifyMoveBoundary } from '@/util/skeleton-utils'
|
import { drawSkeletonRidgeRoof, drawSkeletonRidgeRoofFromBaseLines, verifyMoveBoundary } from '@/util/skeleton-utils'
|
||||||
|
import { attachDebugLabels } from '@/util/debugLabels'
|
||||||
|
|
||||||
export const QPolygon = fabric.util.createClass(fabric.Polygon, {
|
export const QPolygon = fabric.util.createClass(fabric.Polygon, {
|
||||||
type: 'QPolygon',
|
type: 'QPolygon',
|
||||||
@ -514,6 +515,9 @@ export const QPolygon = fabric.util.createClass(fabric.Polygon, {
|
|||||||
// console.log('변별로 설정')
|
// console.log('변별로 설정')
|
||||||
drawRoofByAttribute(this.id, this.canvas, textMode)
|
drawRoofByAttribute(this.id, this.canvas, textMode)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// [DEBUG] URL ?debug=labels 일 때만 라벨 부착. 운영 빌드/평소엔 noop.
|
||||||
|
attachDebugLabels(this.canvas, this.id)
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@ -1339,24 +1339,29 @@ const createInnerLinesFromSkeleton = (roofId, canvas, skeleton, textMode, isOver
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// 각 라인 집합 정렬
|
// [정렬 정책 — 인덱스가 생명] (2026-04-27)
|
||||||
const sortWallLines = ensureCounterClockwiseLines(wallLines)
|
// 1) master = roofLines. roofLine 은 외곽(처마) 경계라 사용자 mutation 영향 없음 → 시작점 안정.
|
||||||
// wall.baseLines를 독립적으로 CCW 정렬하면 ㅗ→붕괴 등으로 꼭짓점 집합이 달라질 때
|
// 2) ensureCounterClockwiseLines 가 master 의 leftTop(min-Y → min-X) 꼭짓점에서 시작해 CCW 정렬.
|
||||||
// 시작점(min-Y-then-min-X)이 wallLines와 어긋나 배열이 shift된다.
|
// 3) wall.lines, wall.baseLines 는 raw 인덱스 1:1 페어링 유지된다는 전제로
|
||||||
// wallLines[i]와 wall.baseLines[i]는 초기 생성 시부터 raw-index 1:1 페어링이 유지되므로,
|
// master 의 sorted 순서 → 원 인덱스 → wall.lines[idx] / wall.baseLines[idx] 매핑.
|
||||||
// sortWallLines의 CCW 순서에 대응하는 원 인덱스를 복원하여 같은 순서로 wall.baseLines를 매핑한다.
|
// wall 쪽을 master 로 쓰던 구현은 OVER 흡수/usePropertiesSetting 등에서 wall.lines 가
|
||||||
|
// 재할당되며 시작점이 어긋나 페어 인덱스가 회전되던 문제(2026-04-27 ㅗ 좌측오버 케이스) 가 있어 변경.
|
||||||
const _keyOfEdge = (l) => {
|
const _keyOfEdge = (l) => {
|
||||||
const a = `${Math.round(l.x1 * 10) / 10},${Math.round(l.y1 * 10) / 10}`
|
const a = `${Math.round(l.x1 * 10) / 10},${Math.round(l.y1 * 10) / 10}`
|
||||||
const b = `${Math.round(l.x2 * 10) / 10},${Math.round(l.y2 * 10) / 10}`
|
const b = `${Math.round(l.x2 * 10) / 10},${Math.round(l.y2 * 10) / 10}`
|
||||||
return a < b ? `${a}|${b}` : `${b}|${a}`
|
return a < b ? `${a}|${b}` : `${b}|${a}`
|
||||||
}
|
}
|
||||||
const _rawIdxByKey = new Map()
|
const _rawIdxByKey = new Map()
|
||||||
wallLines.forEach((l, i) => _rawIdxByKey.set(_keyOfEdge(l), i))
|
roofLines.forEach((l, i) => _rawIdxByKey.set(_keyOfEdge(l), i))
|
||||||
const sortWallBaseLines = sortWallLines.map((sl) => {
|
const sortRoofLines = ensureCounterClockwiseLines(roofLines)
|
||||||
|
const sortWallLines = sortRoofLines.map((sl) => {
|
||||||
|
const origIdx = _rawIdxByKey.get(_keyOfEdge(sl))
|
||||||
|
return origIdx != null && wallLines[origIdx] ? wallLines[origIdx] : sl
|
||||||
|
})
|
||||||
|
const sortWallBaseLines = sortRoofLines.map((sl) => {
|
||||||
const origIdx = _rawIdxByKey.get(_keyOfEdge(sl))
|
const origIdx = _rawIdxByKey.get(_keyOfEdge(sl))
|
||||||
return origIdx != null && wall.baseLines[origIdx] ? wall.baseLines[origIdx] : sl
|
return origIdx != null && wall.baseLines[origIdx] ? wall.baseLines[origIdx] : sl
|
||||||
})
|
})
|
||||||
const sortRoofLines = ensureCounterClockwiseLines(roofLines)
|
|
||||||
|
|
||||||
// [MOVE-TRACE] 진입 스냅샷 (필요 시 주석 해제)
|
// [MOVE-TRACE] 진입 스냅샷 (필요 시 주석 해제)
|
||||||
// console.log('[MOVE-TRACE] === getMoveUpDownLine entry ===',
|
// console.log('[MOVE-TRACE] === getMoveUpDownLine entry ===',
|
||||||
@ -1596,10 +1601,11 @@ const createInnerLinesFromSkeleton = (roofId, canvas, skeleton, textMode, isOver
|
|||||||
const roofLine = sortRoofLines[index]
|
const roofLine = sortRoofLines[index]
|
||||||
const wallBaseLine = sortWallBaseLines[index]
|
const wallBaseLine = sortWallBaseLines[index]
|
||||||
|
|
||||||
// [SHOULDER-ABSORBED] wall.baseLines[k] 가 이동 흡수로 zero-length(planeSize≈0)면
|
// [SHOULDER-ABSORBED] wall.baseLines[k] 가 이동 흡수/OVER_EPS 클램핑으로 거의 zero-length 이면
|
||||||
// 해당 edge 는 흡수되어 사라진 상태. pair 생성 자체가 불필요(DIR_MISMATCH + eaveHelpLine 노이즈 유발).
|
// 해당 edge 는 흡수된 상태. pair 생성 자체가 불필요(DIR_MISMATCH + eaveHelpLine 노이즈 유발).
|
||||||
// 참고: 같은 파일 line 666 의 filter(planeSize > 0) 선례와 동일 패턴.
|
// 임계 = 10: useMovementSetting OVER_EPS=0.5 (canvas unit) 시 잔여 길이=0.5 → planeSize=5 (calcLinePlaneSize × 10).
|
||||||
if (!wallBaseLine || (wallBaseLine.attributes?.planeSize ?? Infinity) < 1) {
|
// 안전마진 두고 < 10 으로 차단. 정상 baseLine 은 보통 50+ 이므로 false positive 없음.
|
||||||
|
if (!wallBaseLine || (wallBaseLine.attributes?.planeSize ?? Infinity) < 10) {
|
||||||
console.log(`⏭️ [pair#${index}] SHOULDER_ABSORBED skip: wb=(${Math.round(wallBaseLine?.x1)},${Math.round(wallBaseLine?.y1)})→(${Math.round(wallBaseLine?.x2)},${Math.round(wallBaseLine?.y2)}) planeSize=${wallBaseLine?.attributes?.planeSize}`)
|
console.log(`⏭️ [pair#${index}] SHOULDER_ABSORBED skip: wb=(${Math.round(wallBaseLine?.x1)},${Math.round(wallBaseLine?.y1)})→(${Math.round(wallBaseLine?.x2)},${Math.round(wallBaseLine?.y2)}) planeSize=${wallBaseLine?.attributes?.planeSize}`)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user