Calculate distance between current location and Polyline Data in Flutter
Consider a River that goes in length of many kilometers. Now, if I ask you how do you detect whether the user is standing close to the river, what would be your answer?
Breakdown
Now, let's break down our problem into parts. If we need to calculate the distance between two locations, we can use the Haversine Formula to manually calculate the distance or the GeoLocator dependency, which has a built-in function to calculate the distance in units between two points.
But what if we have one location point but the other is a array of location points. How do we calculate whether the provided location point is closer to any of the location points provided. To do that, we need to understand polyline concept.
Polyline
A polyline is a series of connected line segments on a map. It's essentially a path drawn between multiple points. This is commonly used to visualize routes, trails, or any other linear data on a map.
So, a polyline is a line drawn between two latitude-longitude points. A route from point A to point B will have 'n' number of location points and therefore 'n' number of polylines, where 'n' depends on the number of straight lines needed to reach the destination.
Approach
We take pairs of location points and draw polyline between them. And then take the target location point and find a projected location point that falls right on the polyline. Then we will calculate the distance between target location point and the projected point.
Consider the following example. Let us take the first two location points (L0, L1) in the given array and draw polyline between them. We have the target location (current location) somewhere in the top of the polyline.
We can now draw a line from the target location point, perpendicular (or shortest distance) to the polyline to find the projected point that touches the polyline. Now we have the projected point location and target point location. We can easily calculate distance between these two using geolocator.
Code
Taken in consideration that you have already included geo_locator dependency in your package. Lets create two data classes named 'line_segment.dart' and 'location_info.dart'
class LineSegment {
final LocationInfo start;
final LocationInfo end;
LineSegment(this.start, this.end);
}
class LocationInfo {
final double latitude;
final double longitude;
LocationInfo({required this.latitude, this.longitude});
}
Now, lets create a helper class named 'location_service.dart' with the following function added. The function will take two parameters. One is the user location called point and another is a LineSegment parameter which contains start and end lat long. The function will draw a line between start and end positions and project another line to reach the previously drawn line. This projection will happen in such a way to find the shortest path to reach the previously drawn line. The function will then return the co-ordinates of the projected point.
class LocationService {
LocationInfo _projectPointOnLineSegment(
LocationInfo point, LineSegment lineSegment) {
// Vector from line segment start to point
final v = LocationInfo(
latitude: point.latitude - lineSegment.start.latitude,
longitude: point.longitude - lineSegment.start.longitude);
// Vector representing the line segment
final w = LocationInfo(
latitude: lineSegment.end.latitude - lineSegment.start.latitude,
longitude: lineSegment.end.longitude - lineSegment.start.longitude);
// Calculate the projection parameter
final wLengthSquared = w.latitude * w.latitude + w.longitude * w.longitude;
final wDotV = w.latitude * v.latitude + w.longitude * v.longitude;
final t = wDotV / wLengthSquared;
// Clamp t to the range [0, 1] to ensure the projected point is on the line segment
final tClamped = t.clamp(0.0, 1.0);
// Calculate the projected point
final projectedPoint = LocationInfo(
latitude: lineSegment.start.latitude + tClamped * w.latitude,
longitude: lineSegment.start.longitude + tClamped * w.longitude,
);
return projectedPoint;
}
}
Now that we have found out the co-ordinates of a projected point, we can easily calculate the distance between projected point and the user's current location using geo_locator. Add the following functions inside 'location_service.dart'
double calculateDistanceToRoad(
LineSegment lineSegment, LocationInfo currentLoc) {
// finds the co-ordinates of projected point
LocationInfo projectLoc =
_projectPointOnLineSegment(currentLoc, lineSegment);
// Calculate distance between current location and projection point
final distanceToProjection =
calculateDistanceInMeters(currentLoc, projectLoc);
}
double calculateDistanceInMeters(LocationInfo startDes, LocationInfo endDes) {
return _geoLocator.distanceBetween(startDes.latitude, startDes.longitude,
endDes.latitude, endDes.longitude);
}
If you have a use case where you have a large list of polyline points, and want to detect whether the user is in a certain distance from the entire route, you can loop through each co-ordinate pairs to find the distance from user location and validate whether the calculated distance is less than the desired radius.
Thank you for reading!
Subscribe to my newsletter
Read articles from Vignesh Marimuthu directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by