Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
Expand All @@ -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? {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
Loading