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