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
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 num distanceInMeterPerTime, {
final bool smoothPath = true,
}) {
Validate.isTrue(
distanceInMeterPerTime > 0,
"Distance must be greater than 0",
);
Validate.isTrue(
(smoothPath && coordinates.length >= 3) ||
(!smoothPath && coordinates.length >= 2),
"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
double stepDistance = smoothPath
? distanceInMeterPerTime * 2.0
: distanceInMeterPerTime.toDouble();
double baseLength = distance;
Validate.isTrue(
baseLength >= stepDistance,
"Path distance must be at least ${stepDistance}m (step distance) but was $baseLength",
);
if (stepDistance > baseLength / 2) {
_logger.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]);
}
List<T> tempCoordinates = coordinates.toList();
Path path = Path();
double remainingSteps = 0.0;
double bearing;
path.add(tempCoordinates.first);
T baseStep = tempCoordinates.first;
for (int index = 0; index < coordinates.length - 1; index++) {
double distance = getDistance(
tempCoordinates[index],
tempCoordinates[index + 1],
) as double;
// Remember the direction
bearing = getDistance.bearing(
tempCoordinates[index],
tempCoordinates[index + 1],
);
if (remainingSteps <= distance ||
(stepDistance - remainingSteps) <= distance) {
// First step position
double firstStepPos = stepDistance - remainingSteps;
double steps = ((distance - firstStepPos) / stepDistance) + 1;
int fullSteps = steps.toInt();
remainingSteps = round(
fullSteps > 0 ? steps % fullSteps : steps,
decimals: 6,
) *
stepDistance;
baseStep = tempCoordinates[index];
for (int stepCounter = 0; stepCounter < fullSteps; stepCounter++) {
// Add step on the given path
// Intermediate step is necessary to stay type-safe
LatLng tempStep = getDistance.offset(baseStep, firstStepPos, bearing);
LatLng nextStep = geoPositionFactory(tempStep.lat, tempStep.lng);
path.add(nextStep);
firstStepPos += stepDistance;
if (smoothPath) {
// Now - split it
CatmullRomSpline2D<double> spline;
if (path.numCoordinates == 3) {
spline = _createSpline(path[0], path[0], path[1], path[2]);
// Insert new point between 0 and 1
path.coordinates.insert(
1,
_pointToPosition(spline.percentage(50)),
);
} else if (path.numCoordinates > 3) {
int baseIndex = path.numCoordinates - 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,
_pointToPosition(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(getDistance(baseStep, tempCoordinates.last) as double) > 1) {
path.add(tempCoordinates.last);
}
if (smoothPath) {
// Last Spline between the last 4 elements
int baseIndex = path.numCoordinates - 1;
if (baseIndex > 3) {
CatmullRomSpline2D<double> spline = _createSpline(
path[baseIndex - 3],
path[baseIndex - 2],
path[baseIndex - 1],
path[baseIndex - 0],
);
path.coordinates.insert(
baseIndex - 1,
_pointToPosition(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.numCoordinates - 1;
if (getDistance(path[baseIndex - 1], path[baseIndex]) >= stepDistance) {
CatmullRomSpline2D<double> spline = _createSpline(
path[baseIndex - 1],
path[baseIndex - 1],
path[baseIndex - 0],
path[baseIndex - 0],
);
path.coordinates.insert(
baseIndex,
_pointToPosition(spline.percentage(50)),
);
}
}
return path;
}