equalize method

Path<LatLng> equalize(
  1. double distanceInMeterPerTime, {
  2. bool smoothPath = true,
})

Splits the path into even sections.

The section size is defined with distanceInMeterPerTime. distanceInMeterPerTime means that the original size on the given path will stay the same but the created section could be smaller because of the "linear distance"

However - if you follow the steps in a given time then the distance from point to point (over time) is correct. (Almost - because of the curves generate with CatmullRomSpline2D

final Path path = new Path.from(zigzag);

If smoothPath is turned on than the minimum of 3 coordinates is required otherwise we need two

Implementation

Path equalize(final double distanceInMeterPerTime,
    {final bool smoothPath = true}) {
  if (distanceInMeterPerTime <= 0) {
    throw ArgumentError.value(distanceInMeterPerTime,
        'distanceInMeterPerTime', 'Distance must be greater than 0');
  }
  if (!((smoothPath && _coordinates.length >= 3) ||
      (!smoothPath && _coordinates.length >= 2))) {
    throw ArgumentError.value(smoothPath, 'smoothPath',
        'At least ${smoothPath ? 3 : 2} coordinates are needed to create the steps in between');
  }

  // If we "smooth" the path every second step becomes a spline - so every other step
  // becomes a "Keyframe". A step on the given path
  final stepDistance = smoothPath
      ? distanceInMeterPerTime * 2.0
      : distanceInMeterPerTime.toDouble();

  final baseLength = distance;
  if (baseLength < stepDistance) {
    throw ArgumentError(
        'Path distance must be at least ${stepDistance}mn (step distance) but was $baseLength');
  }

  if (stepDistance > baseLength / 2) {
    print(
        'Warning: Equalizing the path (L: $baseLength) with a key-frame distance of $stepDistance leads to'
        'weired results. Turn of path smooting.');
  }

  // no steps possible - so return an empty path
  if (baseLength == stepDistance) {
    return Path.from([_coordinates.first, _coordinates.last]);
  }

  final tempCoordinates = List<T>.from(_coordinates);
  final path = Path();

  var remainingSteps = 0.0;
  double bearing;

  path.add(tempCoordinates.first);
  var baseStep = tempCoordinates.first;

  for (var index = 0; index < coordinates.length - 1; index++) {
    final distance =
        _distance(tempCoordinates[index], tempCoordinates[index + 1]);

    // Remember the direction
    bearing =
        _distance.bearing(tempCoordinates[index], tempCoordinates[index + 1]);

    if (remainingSteps <= distance ||
        (stepDistance - remainingSteps) <= distance) {
      // First step position
      var firstStepPos = stepDistance - remainingSteps;

      final steps = ((distance - firstStepPos) / stepDistance) + 1;

      final fullSteps = steps.toInt();
      remainingSteps =
          round(fullSteps > 0 ? steps % fullSteps : steps, decimals: 6) *
              stepDistance;

      baseStep = tempCoordinates[index];

      for (var stepCounter = 0; stepCounter < fullSteps; stepCounter++) {
        // Add step on the given path
        // Intermediate step is necessary to stay type-safe
        final tempStep = _distance.offset(baseStep, firstStepPos, bearing);
        final nextStep =
            _latLngFactory(tempStep.latitude, tempStep.longitude);
        path.add(nextStep);
        firstStepPos += stepDistance;

        if (smoothPath) {
          // Now - split it
          CatmullRomSpline2D<double> spline;

          if (path.nrOfCoordinates == 3) {
            spline = _createSpline(path[0], path[0], path[1], path[2]);

            // Insert new point between 0 and 1
            path.coordinates.insert(1, _pointToLatLng(spline.percentage(50)));
          } else if (path.nrOfCoordinates > 3) {
            final baseIndex = path.nrOfCoordinates - 1;
            spline = _createSpline(path[baseIndex - 3], path[baseIndex - 2],
                path[baseIndex - 1], path[baseIndex]);

            // Insert new point at last position - 2 (pushes the next 2 items down)
            path.coordinates
                .insert(baseIndex - 1, _pointToLatLng(spline.percentage(50)));
          }
        }
      }
    } else {
      remainingSteps += distance;
    }
  }

  // If last step is on the same position as the last generated step
  // then don't add the last base step.
  if (baseStep.round() != tempCoordinates.last.round() &&
      baseStep.round() != tempCoordinates.first.round() &&
      round(_distance(baseStep, tempCoordinates.last)) > 1) {
    path.add(tempCoordinates.last);
  }

  if (smoothPath) {
    // Last Spline between the last 4 elements
    var baseIndex = path.nrOfCoordinates - 1;
    if (baseIndex > 3) {
      final spline = _createSpline(path[baseIndex - 3], path[baseIndex - 2],
          path[baseIndex - 1], path[baseIndex - 0]);

      path.coordinates
          .insert(baseIndex - 1, _pointToLatLng(spline.percentage(50)));
    }

    // Check if there is a remaining gap between the last two elements - close it
    // Could be because of reminder from path divisions
    baseIndex = path.nrOfCoordinates - 1;
    if (_distance(path[baseIndex - 1], path[baseIndex]) >= stepDistance) {
      final spline = _createSpline(path[baseIndex - 1], path[baseIndex - 1],
          path[baseIndex - 0], path[baseIndex - 0]);

      path.coordinates
          .insert(baseIndex, _pointToLatLng(spline.percentage(50)));
    }
  }

  // Make sure we have no duplicates!
  // _removeDuplicates();
  return path;
}