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
GeoPath equalize(final num distanceInMeterPerTime,{ final bool smoothPath: true }) {
GValidate.isTrue(distanceInMeterPerTime > 0, "Distance must be greater than 0");
GValidate.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
final double stepDistance = smoothPath ? distanceInMeterPerTime * 2.0 : distanceInMeterPerTime.toDouble();
final double baseLength = distance.toDouble();
GValidate.isTrue(baseLength >= stepDistance,
"Path distance must be at least ${stepDistance}mn (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 new GeoPath.from([ _coordinates.first, _coordinates.last ]);
}
final List<T> tempCoordinates = new List.from(_coordinates);
final GeoPath path = new GeoPath();
double remainingSteps = 0.0;
double bearing;
path.add(tempCoordinates.first);
T baseStep = tempCoordinates.first;
for(int index = 0;index < coordinates.length - 1;index++) {
final double distance = _distance(tempCoordinates[index],tempCoordinates[index + 1]).toDouble();
// Remember the direction
bearing = _distance.bearing(tempCoordinates[index],tempCoordinates[index + 1]);
if(remainingSteps <= distance || (stepDistance - remainingSteps) <= distance) {
// First step position
double firstStepPos = stepDistance - remainingSteps;
final double steps = ((distance - firstStepPos) / stepDistance) + 1;
final 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
final GeoLatLng tempStep = _distance.offset(baseStep,firstStepPos,bearing);
final GeoLatLng 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 int 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).toDouble()) > 1) {
path.add(tempCoordinates.last);
}
if(smoothPath) {
// Last Spline between the last 4 elements
int baseIndex = path.nrOfCoordinates - 1;
if(baseIndex > 3) {
final CatmullRomSpline2D<double> 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 CatmullRomSpline2D<double> 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;
}