Skip to content

Commit 0b00489

Browse files
Fixed crash caused by ConstantVelocityInterpolator creating PathInterpolator with an invalid path. (#6367)
* Fixed crash caused by ConstantVelocityInterpolator creating PathInterpolator with an invalid path. * CHANGELOG
1 parent b0fca53 commit 0b00489

File tree

3 files changed

+58
-23
lines changed

3 files changed

+58
-23
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ Mapbox welcomes participation and contributions from everyone.
1616
- Replaced `ViewStyleCustomization.defaultMarkerAnnotationOptions` with `ViewStyleCustomization.defaultDestinationMarkerAnnotationOptions`. [#6365](https://github.com/mapbox/mapbox-navigation-android/pull/6365)
1717
- Fixed the issue with incorrect geometry indices for `RouteLeg#incidents` and `RouteLeg#closures` after refresh. [#6364](https://github.com/mapbox/mapbox-navigation-android/pull/6364)
1818
- Introduced `NavigationViewListener#onMapClicked` to inform when a map was clicked, but the event was not processed by `NavigationView`. [#6360](https://github.com/mapbox/mapbox-navigation-android/pull/6360)
19+
- Fixed crash caused by `ConstantVelocityInterpolator` creating `PathInterpolator` with an invalid path. [#6367](https://github.com/mapbox/mapbox-navigation-android/pull/6367)
1920

2021
## Mapbox Navigation SDK 2.9.0-alpha.2 - 16 September, 2022
2122
### Changelog

libnavui-maps/src/main/java/com/mapbox/navigation/ui/maps/internal/location/ConstantVelocityInterpolator.kt

Lines changed: 23 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -20,22 +20,16 @@ class ConstantVelocityInterpolator(
2020
val distances = mutableListOf<Double>()
2121
var total = 0.0
2222
keyPoints.fold(startPoint) { prevPoint, point ->
23-
val d = distanceTo(prevPoint, point)
24-
distances.add(d)
25-
total += d
23+
val d = distance(prevPoint, point)
24+
if (0.0 < d) {
25+
distances.add(d)
26+
total += d
27+
}
2628
point
2729
}
2830

2931
innerInterpolator = if (0 < total) {
30-
val path = Path()
31-
val step = 1.0f / keyPoints.size
32-
var pathTime = 0.0
33-
keyPoints.forEachIndexed { index, _ ->
34-
// simplified from (distances[index] / velocity) where (velocity = total / duration) and duration = 1.0
35-
val deltaTime = distances[index] / total
36-
pathTime += deltaTime
37-
path.lineTo(pathTime.toFloat(), step * (index + 1))
38-
}
32+
val path = timingPath(distances, total)
3933
PathInterpolator(path)
4034
} else {
4135
TimeInterpolator { it }
@@ -45,7 +39,23 @@ class ConstantVelocityInterpolator(
4539
override fun getInterpolation(input: Float): Float =
4640
innerInterpolator.getInterpolation(input)
4741

48-
private fun distanceTo(p1: Point, p2: Point): Double {
42+
private fun distance(p1: Point, p2: Point): Double {
4943
return hypot(p2.latitude() - p1.latitude(), p2.longitude() - p1.longitude())
5044
}
45+
46+
private fun timingPath(distances: List<Double>, total: Double): Path {
47+
val path = Path()
48+
val step = 1.0f / distances.size
49+
var pathTime = 0.0f
50+
// NOTE: The Path must start at (0,0) and end at (1,1)
51+
// To avoid PathInterpolator IllegalArgException, we ignore last keypoint distance value
52+
// and manually add line to (1,1).
53+
for (i in 0..distances.size - 2) {
54+
val deltaTime = distances[i] / total
55+
pathTime += deltaTime.toFloat()
56+
path.lineTo(pathTime, (step * (i + 1)))
57+
}
58+
path.lineTo(1f, 1f)
59+
return path
60+
}
5161
}

libnavui-maps/src/test/java/com/mapbox/navigation/ui/maps/internal/location/ConstantVelocityInterpolatorTest.kt

Lines changed: 34 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,24 @@ class ConstantVelocityInterpolatorTest {
2929
}
3030
}
3131

32+
@Test
33+
fun `should not use keypoints that are at ZERO distance from previous point`() {
34+
val p0 = Point.fromLngLat(0.0, 0.0)
35+
val keyPoints = arrayOf(
36+
Point.fromLngLat(0.5, 0.5),
37+
Point.fromLngLat(0.5, 0.5),
38+
Point.fromLngLat(1.0, 1.0),
39+
)
40+
41+
val sut = ConstantVelocityInterpolator(p0, keyPoints)
42+
43+
val path = calculatePathValues(p0, *keyPoints)
44+
assertEquals(keyPoints.size - 1, path.size)
45+
path.forEach { (outTime, inTime) ->
46+
assertEquals(outTime, sut.getInterpolation(inTime))
47+
}
48+
}
49+
3250
@Test
3351
fun `should use linear interpolation for key points at zero distance`() {
3452
val p0 = Point.fromLngLat(1.0, 1.0)
@@ -58,18 +76,18 @@ class ConstantVelocityInterpolatorTest {
5876
val distances = mutableListOf<Double>()
5977
var totalDistance = 0.0
6078
points.fold(p0) { a, b ->
61-
val d = sqrt(
62-
(b.latitude() - a.latitude()).pow(2.0) +
63-
(b.longitude() - a.longitude()).pow(2.0)
64-
)
65-
distances.add(d)
66-
totalDistance += d
79+
val d = distance(a, b)
80+
if (0 < d) {
81+
distances.add(d)
82+
totalDistance += d
83+
}
6784
b
6885
}
69-
val timeStep = 1.0f / points.size
70-
var pathTime = 0.0
86+
87+
val timeStep = 1.0f / distances.size
7188
val velocities = mutableListOf<Double>()
72-
val path = mutableListOf<Pair<Float, Float>>()
89+
val path = mutableListOf<Pair<Float, Float>>() // animationTime to scaledTime
90+
var pathTime = 0.0
7391
distances.forEachIndexed { i, d ->
7492
val dt = d / totalDistance
7593
velocities.add(d / dt)
@@ -78,10 +96,16 @@ class ConstantVelocityInterpolatorTest {
7896
}
7997

8098
// verify constant velocity
81-
for (i in 1 until points.size) {
99+
for (i in 1 until distances.size) {
82100
assertEquals(velocities[i - 1], velocities[i], 0.0001)
83101
}
84102

85103
return path
86104
}
105+
106+
private fun distance(a: Point, b: Point) =
107+
sqrt(
108+
(b.latitude() - a.latitude()).pow(2.0) +
109+
(b.longitude() - a.longitude()).pow(2.0)
110+
)
87111
}

0 commit comments

Comments
 (0)