From 00703e013c947f4bccac526a63785667155e2d17 Mon Sep 17 00:00:00 2001 From: n0tst3v3 Date: Wed, 19 Aug 2026 04:01:30 -0600 Subject: [PATCH] fix(live): restore the moving navigation pin, aimed at the signal gradient --- .../btlogger/LiveRangeFinderActivity.java | 31 +++++++++++++------ 1 file changed, 22 insertions(+), 9 deletions(-) diff --git a/app/src/main/java/com/wytehat/btlogger/LiveRangeFinderActivity.java b/app/src/main/java/com/wytehat/btlogger/LiveRangeFinderActivity.java index 82acc87..3504f53 100644 --- a/app/src/main/java/com/wytehat/btlogger/LiveRangeFinderActivity.java +++ b/app/src/main/java/com/wytehat/btlogger/LiveRangeFinderActivity.java @@ -61,6 +61,8 @@ public class LiveRangeFinderActivity extends Activity implements LocationListene private float heading; /** Magnetic-to-true north correction for the current position. */ private float declination; + /** Last bearing the signal gradient produced; NaN until one is solved. */ + private float lastGradientBearing = Float.NaN; /** Smoothed compass azimuth, kept in sin/cos form to survive the 0/360 wrap. */ private float headingSin, headingCos; private boolean headingPrimed; @@ -516,6 +518,8 @@ public class LiveRangeFinderActivity extends Activity implements LocationListene } SpatialGradientEngine.Estimate estimate = spatial.consensusEstimate(); if (estimate != null) { + if (!Float.isNaN(estimate.gradientBearing)) + lastGradientBearing = estimate.gradientBearing; estimateText.setText(String.format(Locale.US, "%s • %d stations • ±%.1f m • %.0f°", estimate.preliminary ? "Estimate" : "Solved", @@ -527,6 +531,8 @@ public class LiveRangeFinderActivity extends Activity implements LocationListene } else { SpatialGradientEngine.Estimate hint = spatial.preliminaryEstimate(); if (hint != null) { + if (!Float.isNaN(hint.gradientBearing)) + lastGradientBearing = hint.gradientBearing; js(String.format(Locale.US, "updateEstimate(%.7f,%.7f,%.1f,%.1f,true)", hint.latitude, hint.longitude, hint.confidenceMeters, hint.gradientBearing)); js(String.format(Locale.US, "updateGradient(%.1f,'%s')", hint.gradientBearing, state)); @@ -545,16 +551,23 @@ public class LiveRangeFinderActivity extends Activity implements LocationListene * is what this used to do - just parks the pin wherever the user points, * so the arrow always appears to aim at it and it is useless for walking. */ + /** + * Projects the item pin the estimated distance ahead so there is always + * something to walk toward, and it moves as the range estimate changes. + * + * It aims at the last bearing the signal gradient produced, so it holds + * a real direction instead of swinging around with the compass; only + * before any gradient exists does it fall back to the phone's heading. + */ private void showFallbackPin(Location phone, float direction, double distance) { - if (target != null && target.hasLocation) { - js(String.format(Locale.US, "updateEstimate(%.7f,%.7f,%.1f,%.1f,true)", - target.latitude, target.longitude, - Math.max(1.5, target.accuracy), direction)); - } else { - js(String.format(Locale.US, "updateEstimate(%.7f,%.7f,%.1f,%.1f,true)", - phone.getLatitude(), phone.getLongitude(), - Math.max(1.5, distance), direction)); - } + float bearing = Float.isNaN(lastGradientBearing) ? direction : lastGradientBearing; + double projected = Math.max(1.5, Math.min(20.0, distance)); + double radians = Math.toRadians(bearing); + double latitude = phone.getLatitude() + Math.cos(radians) * projected / 111319.49; + double cosine = Math.max(0.2, Math.cos(Math.toRadians(phone.getLatitude()))); + double longitude = phone.getLongitude() + Math.sin(radians) * projected / (111319.49 * cosine); + js(String.format(Locale.US, "updateEstimate(%.7f,%.7f,%.1f,%.1f,true)", + latitude, longitude, Math.max(1.5, distance), bearing)); } private String sector(float bearing) {