From 5f481b85eadfeb478a90153ab150fadf326fa622 Mon Sep 17 00:00:00 2001 From: oh in seong <58154638+ois0886@users.noreply.github.com> Date: Wed, 11 Nov 2026 21:14:37 +0900 Subject: [PATCH] =?UTF-8?q?=EC=97=B0=EC=86=8D=20=EB=8F=99=EC=9D=BC=20?= =?UTF-8?q?=EC=9C=84=EC=B9=98=20=ED=91=9C=EB=B3=B8=EC=9D=84=20=EB=B3=B5?= =?UTF-8?q?=EC=8A=B5=20=EB=8F=84=EB=A1=9C=20=EA=B5=AC=EA=B0=84=20=EA=B3=84?= =?UTF-8?q?=EC=82=B0=EC=97=90=EC=84=9C=20=EC=B2=98=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../map/StoredLocationRoadSuggestion.kt | 16 +++++--- .../hangil/feature/map/StoredLocationTrace.kt | 9 ++++- .../map/StoredLocationRoadSuggestionTest.kt | 40 +++++++++++++++++++ 3 files changed, 57 insertions(+), 8 deletions(-) diff --git a/feature/map/src/main/kotlin/io/github/hangillab/hangil/feature/map/StoredLocationRoadSuggestion.kt b/feature/map/src/main/kotlin/io/github/hangillab/hangil/feature/map/StoredLocationRoadSuggestion.kt index 2f54405..303536f 100644 --- a/feature/map/src/main/kotlin/io/github/hangillab/hangil/feature/map/StoredLocationRoadSuggestion.kt +++ b/feature/map/src/main/kotlin/io/github/hangillab/hangil/feature/map/StoredLocationRoadSuggestion.kt @@ -51,7 +51,7 @@ internal object StoredLocationRoadSuggestion { var last = selected for (neighbor in index - 1 downTo maxOf(0, index - NEIGHBORS_PER_SIDE)) { val previous = (input.events[neighbor].reading as? LocationUpdateReading.Sample)?.sample ?: break - if (!StoredLocationTrace.canLink(input.run, previous, last)) break + if (!StoredLocationTrace.isContinuous(input.run, previous, last)) break samples.add(previous) last = previous } @@ -60,16 +60,20 @@ internal object StoredLocationRoadSuggestion { last = selected for (neighbor in index + 1..minOf(input.events.lastIndex, index + NEIGHBORS_PER_SIDE)) { val next = (input.events[neighbor].reading as? LocationUpdateReading.Sample)?.sample ?: break - if (!StoredLocationTrace.canLink(input.run, last, next)) break + if (!StoredLocationTrace.isContinuous(input.run, last, next)) break samples.add(next) last = next } - if (samples.size < MIN_SAMPLES) return null - val span = spanMeters(samples.first(), samples.last()) + val movingSamples = + samples.filterIndexed { index, sample -> + index == 0 || samples[index - 1].let { it.latitude != sample.latitude || it.longitude != sample.longitude } + } + if (movingSamples.size < MIN_SAMPLES) return null + val span = spanMeters(movingSamples.first(), movingSamples.last()) if (!span.isFinite() || span < MIN_SPAN_METERS) return null - val nearest = nearestRoad(samples.first(), input.courseRoads) ?: return null - return if (samples.drop(1).all { nearestRoad(it, input.courseRoads) == nearest }) Match(nearest, samples) else null + val nearest = nearestRoad(movingSamples.first(), input.courseRoads) ?: return null + return if (movingSamples.drop(1).all { nearestRoad(it, input.courseRoads) == nearest }) Match(nearest, movingSamples) else null } private fun projectedSection(match: Match): Suggestion? { diff --git a/feature/map/src/main/kotlin/io/github/hangillab/hangil/feature/map/StoredLocationTrace.kt b/feature/map/src/main/kotlin/io/github/hangillab/hangil/feature/map/StoredLocationTrace.kt index fdba8fb..5175d09 100644 --- a/feature/map/src/main/kotlin/io/github/hangillab/hangil/feature/map/StoredLocationTrace.kt +++ b/feature/map/src/main/kotlin/io/github/hangillab/hangil/feature/map/StoredLocationTrace.kt @@ -44,14 +44,19 @@ internal object StoredLocationTrace { run: LocationRecordingRun, start: LocationUpdateSample, end: LocationUpdateSample, + ): Boolean = isContinuous(run, start, end) && (start.latitude != end.latitude || start.longitude != end.longitude) + + fun isContinuous( + run: LocationRecordingRun, + start: LocationUpdateSample, + end: LocationUpdateSample, ): Boolean { val startTime = start.receivedAtElapsedRealtimeMillis val endTime = end.receivedAtElapsedRealtimeMillis return startTime >= run.startedAtElapsedRealtimeMillis && (run.endedAtElapsedRealtimeMillis?.let { endTime <= it } != false) && endTime - startTime in 1 until LocationUpdateGateway.NO_UPDATE_TIMEOUT_MILLIS && - abs(start.longitude - end.longitude) < 180 && - (start.latitude != end.latitude || start.longitude != end.longitude) + abs(start.longitude - end.longitude) < 180 } fun add( diff --git a/feature/map/src/test/kotlin/io/github/hangillab/hangil/feature/map/StoredLocationRoadSuggestionTest.kt b/feature/map/src/test/kotlin/io/github/hangillab/hangil/feature/map/StoredLocationRoadSuggestionTest.kt index 928d1d4..838fa23 100644 --- a/feature/map/src/test/kotlin/io/github/hangillab/hangil/feature/map/StoredLocationRoadSuggestionTest.kt +++ b/feature/map/src/test/kotlin/io/github/hangillab/hangil/feature/map/StoredLocationRoadSuggestionTest.kt @@ -50,6 +50,46 @@ class StoredLocationRoadSuggestionTest { assertEquals(nearRoad, StoredLocationRoadSuggestion.find(captured)) } + @Test fun `stationary repeats preserve the section around either stored callback`() { + val readings = listOf(sample(0.0, 1_000), sample(0.00015, 2_000), sample(0.00015, 3_000), sample(0.00030, 4_000)) + val first = input(readings, selectedIndex = 1) + val second = input(readings, selectedIndex = 2) + val section = checkNotNull(StoredLocationRoadSuggestion.section(first, linkedReview(first))) + + assertEquals(nearRoad, StoredLocationRoadSuggestion.find(first)) + assertEquals(nearRoad, StoredLocationRoadSuggestion.find(second)) + assertEquals(CourseRoadSection(0, 1), section.publicRange) + assertEquals(section, StoredLocationRoadSuggestion.section(second, linkedReview(second))) + assertNull(StoredLocationRoadSuggestion.section(second, linkedReview(first))) + } + + @Test fun `stationary repeats cannot extend the sample window or supply a third moving position`() { + val readings = + listOf( + sample(0.0, 1_000), + sample(0.00030, 2_000), + sample(0.00030, 3_000), + sample(0.00030, 4_000), + sample(0.00060, 5_000), + ) + + assertNull(StoredLocationRoadSuggestion.find(input(readings))) + assertNull(StoredLocationRoadSuggestion.find(input(readings.dropLast(1)))) + } + + @Test fun `a timeout still breaks continuity between identical positions`() { + val timeout = LocationUpdateGateway.NO_UPDATE_TIMEOUT_MILLIS + val readings = + listOf( + sample(0.0, 1_000), + sample(0.00015, 2_000), + sample(0.00015, 2_000 + timeout), + sample(0.00030, 3_000 + timeout), + ) + + assertNull(StoredLocationRoadSuggestion.find(input(readings))) + } + @Test fun `an empty callback separates the samples and cannot be a selection`() { val (first, second, third) = movingSamples() val interrupted = listOf(first, LocationUpdateReading.Empty(1_500), second, third)