fix(align V1): GREEN 게이트 강화 — 4개 center 모두 요구 (측정 BV 게이트와 정렬)

증상: 정렬 OK 직후 측정 시 ch3 미검출로 BV SKIP. 정렬은 통과했는데
      측정에서 "No center channels" 가 자주 발생.

원인: 정렬 GREEN 게이트는 depths.size >= 2 만 요구 (2~3 center 채널
      만으로도 CV/lr 통과 시 OK). 반면 측정 BV 게이트는
      effectiveCenterWalls >= 4 필요. 정렬 OK 직후 ch3 가 borderline
      이면 측정 단계에서 빠질 확률 높음.

수정: PlacementGuideView.computePlacementGuide() 의 GREEN 게이트를
      depths.size < 4 로 강화 (측정 게이트와 동일). 4개 모두
      잡힐 때만 CV/lr 평가로 진입.
      빠진 채널 위치별 hint 분기:
        - 2개 이상 missing → 일반 "adjust position"
        - ch3 missing → 'Slide up slightly ↑' (사센서 너무 낮음)
        - ch0 missing → 'Slide down slightly ↓' (센서 너무 높음)
        - ch1/ch2 missing → generic 미세 조정
      phase 는 GREEN→VERTICAL 로 회귀 (기존 < 2 분기와 동일).

효과: 정렬 OK 가 4-channel 안정 검출 필요 → 그 다음 measurement
      에서 ch3 미검출로 BV SKIP 거의 사라짐.

트레이드오프: 정렬 단계가 다소 까다로워짐 (작은 방광/borderline
              ch3 사용자 좌절 가능). 필요 시 사용자별 relax 조정.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
2026-06-17 18:10:25 +09:00
parent ac6013e373
commit 8c07809d58
@@ -1812,6 +1812,7 @@ private fun computePlacementGuide(
val centerCh = hw.centerCh val centerCh = hw.centerCh
val depths = mutableListOf<Double>() val depths = mutableListOf<Double>()
val missingCenters = mutableListOf<Int>()
for (localIdx in centerCh.indices) { for (localIdx in centerCh.indices) {
val ch = centerCh[localIdx] val ch = centerCh[localIdx]
val w = if (ch < walls.size) walls[ch] else null val w = if (ch < walls.size) walls[ch] else null
@@ -1819,12 +1820,28 @@ private fun computePlacementGuide(
val rawDepth = (offset + w.second * dps) - (offset + w.first * dps) val rawDepth = (offset + w.second * dps) - (offset + w.first * dps)
val theta = degAll[ch] * Math.PI / 180.0 val theta = degAll[ch] * Math.PI / 180.0
val corrected = rawDepth * kotlin.math.cos(theta) val corrected = rawDepth * kotlin.math.cos(theta)
if (corrected > 0) depths.add(corrected) if (corrected > 0) depths.add(corrected) else missingCenters.add(ch)
} else {
missingCenters.add(ch)
} }
} }
if (depths.size < 2) { // 측정 단계 BV 게이트와 정렬 (effectiveCenterWalls >= 4) — 4개 center 모두
return PlacementGuideResult("Start over from above the pubic bone", "arrow.up", 10, // 잡혀야만 GREEN 통과. 정렬 OK 직후 측정 시 ch3 missing 으로 BV SKIP 되던 케이스 차단.
if (depths.size < 4) {
val pubicMissing = 3 in missingCenters // ch3 = 치골 쪽 (bottom of sensor)
val navelMissing = 0 in missingCenters // ch0 = 배꼽 쪽 (top of sensor)
val (hint, icon) = when {
missingCenters.size >= 2 ->
Pair("Adjust position — multiple channels missing", "arrow.up")
pubicMissing ->
Pair("Slide up slightly ↑ (ch3 missing)", "arrow.up")
navelMissing ->
Pair("Slide down slightly ↓ (ch0 missing)", "arrow.down")
else ->
Pair("Adjust position slightly — center channel missing", "arrow.up")
}
return PlacementGuideResult(hint, icon, 30,
phase = PlacementPhase.GREEN, nextPhase = PlacementPhase.VERTICAL) phase = PlacementPhase.GREEN, nextPhase = PlacementPhase.VERTICAL)
} }