equalize method
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;
}