Last active
February 28, 2019 13:52
-
-
Save yfujiki/e0ed77d6578befdf80c6bdd127ad07f3 to your computer and use it in GitHub Desktop.
Calculate start/endpoints from each other
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class AnimatablePathDrawable(points: MutableList<NormalizedPoint>, context: Context) | |
: PathDrawable(points, context), ValueAnimator.AnimatorUpdateListener { | |
... | |
// The main method to be explained here. It configures startPoints/endPoints | |
private fun configureStartEndPoints(fromStartPoints: List<NormalizedPoint>, | |
toEndPoints: List<NormalizedPoint>) { | |
// The first part of the explanation above. | |
// Projecting vertices on the start/end path onto the straight line. | |
val projectedMergedPoints = projectedMergedPoints(fromStartPoints, toEndPoints) | |
// The second part of the explanation above. | |
// Mapping the points on the straight line back to the start/end paths. | |
startPoints = mapProjectedPointsIntoPath(fromStartPoints, projectedMergedPoints) | |
endPoints = mapProjectedPointsIntoPath(toEndPoints, projectedMergedPoints) | |
} | |
... | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
... | |
// Utility method to calculate the entire line length | |
// that connects the specified points. | |
private fun euclidianDistanceForPath(points: List<NormalizedPoint>): Double { | |
if (points.size < 1) { | |
return 0.0 | |
} | |
val shiftedPoints = points.slice(1 until points.size) | |
return points.zip(shiftedPoints).sumByDouble { (a, b) -> | |
sqrt(pow((b.y - a.y).toDouble(), 2.0) + pow((b.x - a.x).toDouble(), 2.0)) | |
} | |
} | |
... |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
... | |
// Generate merged points when projecting both | |
// startPoints/endPoints into 1-dimensional line of (0,1) | |
private fun projectedMergedPoints(fromStartPoints: List<NormalizedPoint>, | |
toEndPoints: List<NormalizedPoint>) | |
: List<Double> { | |
val startPathLength = euclidianDistanceForPath(fromStartPoints) | |
val endPathLength = euclidianDistanceForPath(toEndPoints) | |
var projectedMergedPoints: MutableList<Double> = mutableListOf( 0.0 ) | |
(1 until fromStartPoints.size).forEach { i -> | |
val pointsToI = (fromStartPoints.slice(0..i)).toList() | |
val normalizedDistanceToI = euclidianDistanceForPath(pointsToI) / startPathLength | |
projectedMergedPoints.add(normalizedDistanceToI) | |
} | |
(1 until toEndPoints.size).forEach { i -> | |
val pointsToI = (toEndPoints.slice(0..i)).toList() | |
val normalizedDistanceToI = euclidianDistanceForPath(pointsToI) / endPathLength | |
projectedMergedPoints.add(normalizedDistanceToI) | |
} | |
projectedMergedPoints.sort() | |
return projectedMergedPoints.toList() | |
} | |
... |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
... | |
// Generate 2-d points when mapping the projected points back onto the path. | |
private fun mapProjectedPointsIntoPath(path: List<NormalizedPoint>, | |
projectedPoints: List<Double>) | |
: List<NormalizedPoint> { | |
val entireDistance = euclidianDistanceForPath(path) | |
val distanceKeyedPoints: SortedMap<Double, NormalizedPoint> = sortedMapOf() | |
var distancesToPoints: SortedSet<Double> = sortedSetOf() | |
path.forEachIndexed { index, normalizedPoint -> | |
if (index == 0) { | |
distanceKeyedPoints[0.0] = normalizedPoint | |
distancesToPoints.add(0.0) | |
} else if (index == path.size - 1) { | |
distanceKeyedPoints[entireDistance] = normalizedPoint | |
distancesToPoints.add(entireDistance) | |
} else { | |
val pointsToIndex = (path.slice(0..index)).toList() | |
val distanceToIndex = euclidianDistanceForPath(pointsToIndex) | |
distanceKeyedPoints[distanceToIndex] = normalizedPoint | |
distancesToPoints.add(distanceToIndex) | |
} | |
} | |
var tempPoints: MutableList<NormalizedPoint> = mutableListOf() | |
projectedPoints.forEach { projectedPoint -> | |
val distanceToProjectedPoint = projectedPoint * entireDistance | |
val pointInPath = pointInPath(distanceKeyedPoints, distanceToProjectedPoint) | |
tempPoints.add(pointInPath) | |
} | |
return tempPoints.toList() | |
} | |
// When line length reaching to this point is `distanceToPoint`, | |
// then map that onto the path and figure out corresponding point. | |
// `distanceKeyedPoints.values` hold the vertices on the path. | |
// `distanceKeyedPoints.keys` hold the distance of the path to the corresponding point. | |
private fun pointInPath(distanceKeyedPoints: SortedMap<Double, NormalizedPoint>, | |
distanceToPoint: Double) | |
: NormalizedPoint { | |
var prevDistance = distanceKeyedPoints.firstKey() | |
var prevPoint = distanceKeyedPoints[prevDistance]!! | |
for ((distance, point) in distanceKeyedPoints) { | |
if (distance == distanceToPoint) { | |
return point | |
} else if ((distanceToPoint - prevDistance) * (distanceToPoint - distance) < 0) { | |
val x = (point.x - prevPoint.x) | |
* (distanceToPoint - prevDistance) | |
/ (distance - prevDistance) | |
+ prevPoint.x | |
val y = (point.y - prevPoint.y) | |
* (distanceToPoint - prevDistance) | |
/ (distance - prevDistance) | |
+ prevPoint.y | |
return NormalizedPoint(x.toFloat(), y.toFloat()) | |
} | |
prevDistance = distance | |
prevPoint = point | |
} | |
return distanceKeyedPoints[distanceKeyedPoints.lastKey()]!! | |
} | |
... |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment