Akash Deodhar
Akash Deodhar

Reputation: 70

snap markers to nearest polyline point Google Maps flutter

I am writing a simple bus tracking app for my university shuttles. I have plotted out the bus GPS as navigation arrows along with the route on the map. Now as the actual GPS coordinate is a little of from the real location of bus than the plotted route, it is slightly off the road. Is there any way or method that I can call to snap these markers to the polyline nearest point in google maps flutter plugin? I just wanted to know if there is anything already in place that I am missing. I would be willing to write the custom nearest neighbor logic if necessary. Thanks!

enter image description here

enter image description here

Upvotes: 3

Views: 1450

Answers (1)

rajesh dabhi
rajesh dabhi

Reputation: 114

I have done using locationIndexOnPath, computeDistanceBetween, computeHeading.

Step 1. add this function to get nearest polyline segment index based on you current location. pass your polyline coordinates list and current location. below function return index of given polyline coordinates list.

int getEdgeIndex(List<mt.LatLng> _coordinates, mt.LatLng currentLocation) {
    final int edgeIndex1 = mt.PolygonUtil.locationIndexOnPath(
        currentLocation, _coordinates, true,
        tolerance: 1);

    final int edgeIndex2 = mt.PolygonUtil.locationIndexOnPath(
        currentLocation, _coordinates, true,
        tolerance: 2);

    final int edgeIndex6 = mt.PolygonUtil.locationIndexOnPath(
        currentLocation, _coordinates, true,
        tolerance: 6);

    final int edgeIndex10 = mt.PolygonUtil.locationIndexOnPath(
        currentLocation, _coordinates, true,
        tolerance: 10);

    final int edgeIndex15 = mt.PolygonUtil.locationIndexOnPath(
        currentLocation, _coordinates, true,
        tolerance: 15);

    int finalIndex = -1;

    if (edgeIndex1 >= 0) {
      finalIndex = edgeIndex1;
    } else if (edgeIndex2 >= 0) {
      finalIndex = edgeIndex2;
    } else if (edgeIndex6 >= 0) {
      finalIndex = edgeIndex6;
    } else if (edgeIndex10 >= 0) {
      finalIndex = edgeIndex10;
    } else if (edgeIndex15 >= 0) {
      finalIndex = edgeIndex15;
    }

    print(
        "getEdgeIndex: index : $edgeIndex1, $edgeIndex2, $edgeIndex6, $edgeIndex10, $edgeIndex15, $finalIndex");
    return finalIndex;
  }

Step 2. Now add this function to get snap LatLag to snap you current marker in centre of polyline route.

Map<String, dynamic> getSnapLatLng(LatLng currentLocation) {
    final currentLocationMT =
        mt.LatLng(currentLocation.latitude, currentLocation.longitude);

    if (coordinatesMT.isEmpty) {
      for (LatLng latLng in coordinates) {
        coordinatesMT.add(mt.LatLng(latLng.latitude, latLng.longitude));
      }
    }

    final int finalIndex = getEdgeIndex(coordinatesMT, currentLocationMT);

    if (finalIndex >= 0) {
      final snappedLatLng2 = (finalIndex < coordinatesMT.length - 1)
          ? coordinatesMT[finalIndex + 1]
          : currentLocationMT;
      final snappedLatLng = coordinatesMT[finalIndex];

      final distanceM2 = mt.SphericalUtil.computeDistanceBetween(
          snappedLatLng, currentLocationMT);

      double heading = mt.SphericalUtil.computeHeading(
        snappedLatLng2,
        snappedLatLng,
      );

      final extrapolated =
          mt.SphericalUtil.computeOffset(snappedLatLng, -distanceM2, heading);

      print(
          "snapToPolyline:distanceM  $distanceM2, $heading, $finalIndex, ${coordinatesMT.length}");

      return {
        "index": finalIndex,
        "latLng": LatLng(extrapolated.latitude, extrapolated.longitude)
      };
    }

    return {"index": finalIndex, "latLng": currentLocation};
  }

NOTE: I have used https://pub.dev/packages/maps_toolkit this package for locationIndexOnPath, computeDistanceBetween, computeHeading.

Upvotes: 3

Related Questions