innerLines 수정 시 분할 안되는 현상 수정
This commit is contained in:
parent
777f85f5b6
commit
e14ed81db4
@ -1543,6 +1543,121 @@ export const usePolygon = () => {
|
||||
}
|
||||
}
|
||||
|
||||
// [MOVED-DIVIDER 2026-06-17] 내부 분할선(예: A타입 중앙 3868)을 옮기면 경계선만 새 위치로 재분할되고
|
||||
// 스켈레톤 hip 은 옛 위치에서 만나, 옮긴 보조선 끝점이 hip 에 노드로 안 붙어 분할이 안 되고 면이
|
||||
// 겹쳐 생긴다(ROOF-FACE-DIAG: 거의 동일한 면 2개). 해결:
|
||||
// (1) 내부 보조선 끝점이 hip 몸통 위(strict)에 있으면 그 hip 을 끝점에서 split → 보조선이 연결됨.
|
||||
// (2) split 이 일어난 경우에만, 옛 접합점이 degree-2 공선(共線) 잉여 노드가 되면 merge → 옛 분할점 제거.
|
||||
// 게이트: 실제 split 이 일어난 경우(=내부분할선 이동)에만 (2) 수행 → 외곽선 띠(SUPERSEDED) 케이스는 불변.
|
||||
{
|
||||
const innerAux = allLines.filter((l) => l.name === 'auxiliaryLine')
|
||||
const isInner = (l) => l.name === 'hip' || l.name === 'ridge'
|
||||
const EPS = 2
|
||||
const mkSeg = (proto, sp, ep) => ({
|
||||
name: proto.name,
|
||||
lineName: proto.lineName,
|
||||
attributes: { ...proto.attributes },
|
||||
startPoint: { x: sp.x, y: sp.y },
|
||||
endPoint: { x: ep.x, y: ep.y },
|
||||
x1: sp.x,
|
||||
y1: sp.y,
|
||||
x2: ep.x,
|
||||
y2: ep.y,
|
||||
})
|
||||
const onBodyStrict = (L, P) => {
|
||||
const ax = L.startPoint.x,
|
||||
ay = L.startPoint.y
|
||||
const dx = L.endPoint.x - ax,
|
||||
dy = L.endPoint.y - ay
|
||||
const lenSq = dx * dx + dy * dy
|
||||
if (lenSq < 1) return false
|
||||
const t = ((P.x - ax) * dx + (P.y - ay) * dy) / lenSq
|
||||
if (t <= 0.03 || t >= 0.97) return false
|
||||
const px = ax + t * dx,
|
||||
py = ay + t * dy
|
||||
return (P.x - px) ** 2 + (P.y - py) ** 2 < EPS * EPS
|
||||
}
|
||||
if (innerAux.length > 0) {
|
||||
const auxPts = []
|
||||
innerAux.forEach((a) => {
|
||||
auxPts.push(a.startPoint, a.endPoint)
|
||||
})
|
||||
// (1) 내부선을 보조선 끝점에서 split
|
||||
let didSplit = false
|
||||
const afterSplit = []
|
||||
allLines.forEach((L) => {
|
||||
if (!isInner(L)) {
|
||||
afterSplit.push(L)
|
||||
return
|
||||
}
|
||||
const ax = L.startPoint.x,
|
||||
ay = L.startPoint.y
|
||||
const dx = L.endPoint.x - ax,
|
||||
dy = L.endPoint.y - ay
|
||||
const lenSq = dx * dx + dy * dy || 1
|
||||
const tOf = (P) => ((P.x - ax) * dx + (P.y - ay) * dy) / lenSq
|
||||
const cuts = [...new Map(auxPts.filter((P) => onBodyStrict(L, P)).map((P) => [Math.round(tOf(P) * 1000), P])).values()].sort(
|
||||
(p, q) => tOf(p) - tOf(q),
|
||||
)
|
||||
if (cuts.length === 0) {
|
||||
afterSplit.push(L)
|
||||
return
|
||||
}
|
||||
didSplit = true
|
||||
let cur = L.startPoint
|
||||
cuts.forEach((P) => {
|
||||
afterSplit.push(mkSeg(L, cur, P))
|
||||
cur = P
|
||||
})
|
||||
afterSplit.push(mkSeg(L, cur, L.endPoint))
|
||||
})
|
||||
if (didSplit) {
|
||||
let work = afterSplit
|
||||
const key = (p) => `${Math.round(p.x)},${Math.round(p.y)}`
|
||||
// (2) degree-2 공선 내부선 접합점 merge (잉여 옛 분할점 제거)
|
||||
let merged = true
|
||||
let guard = 0
|
||||
while (merged && guard++ < 200) {
|
||||
merged = false
|
||||
const incident = {}
|
||||
work.forEach((L) => {
|
||||
;[L.startPoint, L.endPoint].forEach((p) => {
|
||||
;(incident[key(p)] || (incident[key(p)] = [])).push(L)
|
||||
})
|
||||
})
|
||||
for (const k in incident) {
|
||||
const inc = incident[k]
|
||||
if (inc.length !== 2) continue
|
||||
const [la, lb] = inc
|
||||
if (la === lb || !isInner(la) || !isInner(lb)) continue
|
||||
const [kx, ky] = k.split(',').map(Number)
|
||||
const farA = Math.abs(la.startPoint.x - kx) < 1 && Math.abs(la.startPoint.y - ky) < 1 ? la.endPoint : la.startPoint
|
||||
const farB = Math.abs(lb.startPoint.x - kx) < 1 && Math.abs(lb.startPoint.y - ky) < 1 ? lb.endPoint : lb.startPoint
|
||||
const cross = (kx - farA.x) * (farB.y - ky) - (ky - farA.y) * (farB.x - kx)
|
||||
const norm = Math.hypot(kx - farA.x, ky - farA.y) * Math.hypot(farB.x - kx, farB.y - ky)
|
||||
if (norm < 1 || Math.abs(cross) / norm > 0.02) continue
|
||||
work = work.filter((L) => L !== la && L !== lb)
|
||||
work.push(mkSeg(la, farA, farB))
|
||||
merged = true
|
||||
break
|
||||
}
|
||||
}
|
||||
// 동일 좌표 변 중복 제거
|
||||
work = work.filter(
|
||||
(line, idx, self) =>
|
||||
idx ===
|
||||
self.findIndex(
|
||||
(o) =>
|
||||
(isSamePoint(o.startPoint, line.startPoint) && isSamePoint(o.endPoint, line.endPoint)) ||
|
||||
(isSamePoint(o.startPoint, line.endPoint) && isSamePoint(o.endPoint, line.startPoint)),
|
||||
),
|
||||
)
|
||||
logger.log(`[MOVED-DIVIDER] 내부 분할선 이동 감지 — hip 재분할 적용 (allLines ${allLines.length}→${work.length})`)
|
||||
allLines = work
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 나눠서 중복 제거된 roof return
|
||||
let newRoofs = getSplitRoofsPoints(allLines)
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user