Repository: godotengine/godot
File: scene/resources/animation.cpp (C++)

Code before:
		double v0 = a0 / (t1.time - t0.time);
		double v1 = a1 / (t2.time - t1.time);
		// Avoid zero div but check equality.
		if (abs(v0 - v1) < p_allowed_precision_error) {
			return true;
		} else if (abs(v0) < p_allowed_precision_error || abs(v1) < p_allowed_precision_error) {
			return false;
		}
		double ratio = v0 < v1 ? v0 / v1 : v1 / v0;
		if (ratio >= 1.0 - p_allowed_velocity_err) {
			return true;
		}
	}
	return false;
}

void Animation::_position_track_optimize(int p_idx, real_t p_allowed_velocity_err, real_t p_allowed_angular_err, real_t p_allowed_precision_error) {
	ERR_FAIL_INDEX(p_idx, tracks.size());
	ERR_FAIL_COND(tracks[p_idx]->type != TYPE_POSITION_3D);
	PositionTrack *tt = static_cast<PositionTrack *>(tracks[p_idx]);
	int i = 0;
	while (i < tt->positions.size() - 2) {
		TKey<Vector3> t0 = tt->positions[i];
		TKey<Vector3> t1 = tt->positions[i + 1];
		TKey<Vector3> t2 = tt->positions[i + 2];
		bool erase = _vector3_track_optimize_key(t0, t1, t2, p_allowed_velocity_err, p_allowed_angular_err, p_allowed_precision_error, track_get_interpolation_type(i) == Animation::INTERPOLATION_NEAREST);
		if (erase) {
			tt->positions.remove_at(i + 1);
		} else {
			i++;
		}
	}

	if (tt->positions.size() == 2) {
		if ((tt->positions[0].value - tt->positions[1].value).length() < p_allowed_precision_error) {
			tt->positions.remove_at(1);
		}
	}
}

void Animation::_rotation_track_optimize(int p_idx, real_t p_allowed_velocity_err, real_t p_allowed_angular_err, real_t p_allowed_precision_error) {
	ERR_FAIL_INDEX(p_idx, tracks.size());
	ERR_FAIL_COND(tracks[p_idx]->type != TYPE_ROTATION_3D);
	RotationTrack *rt = static_cast<RotationTrack *>(tracks[p_idx]);
	int i = 0;
	while (i < rt->rotations.size() - 2) {
		TKey<Quaternion> t0 = rt->rotations[i];
		TKey<Quaternion> t1 = rt->rotations[i + 1];
		TKey<Quaternion> t2 = rt->rotations[i + 2];
		bool erase = _quaternion_track_optimize_key(t0, t1, t2, p_allowed_velocity_err, p_allowed_angular_err, p_allowed_precision_error, track_get_interpolation_type(i) == Animation::INTERPOLATION_NEAREST);
		if (erase) {

Review comment (bug):
A closer look at the code reveals that `i` is a mistake as it is the key index. The correct variable for the track index is `p_idx`, so which should be:
```cpp
void Animation::_position_track_optimize(int p_idx, real_t p_allowed_velocity_err, real_t p_allowed_angular_err, real_t p_allowed_precision_error) {
	ERR_FAIL_INDEX(p_idx, tracks.size());
	ERR_FAIL_COND(tracks[p_idx]->type != TYPE_POSITION_3D);
	PositionTrack *tt = static_cast<PositionTrack *>(tracks[p_idx]);

	int i = 0;
	bool is_nearest = tracks[p_idx]->interpolation == INTERPOLATION_NEAREST;
	while (i < tt->positions.size() - 2) {
		TKey<Vector3> t0 = tt->positions[i];
		TKey<Vector3> t1 = tt->positions[i + 1];
		TKey<Vector3> t2 = tt->positions[i + 2];
		bool erase = _vector3_track_optimize_key(t0, t1, t2, p_allowed_velocity_err, p_allowed_angular_err, p_allowed_precision_error, is_nearest);
```
Please make the same correction elsewhere.

By the way, in the case of Cubic, it should not be optimized, so we could do a quicker return like:
```cpp
void Animation::_position_track_optimize(int p_idx, real_t p_allowed_velocity_err, real_t p_allowed_angular_err, real_t p_allowed_precision_error) {
	ERR_FAIL_INDEX(p_idx, tracks.size());
	ERR_FAIL_COND(tracks[p_idx]->type != TYPE_POSITION_3D);
	bool is_nearest = false;
	if (tracks[p_idx]->interpolation == INTERPOLATION_NEAREST) {
		is_nearest = true;
	} else if (tracks[p_idx]->interpolation != INTERPOLATION_LINEAR) {
		return;
	}
	PositionTrack *tt = static_cast<PositionTrack *>(tracks[p_idx]);

	int i = 0;
	while (i < tt->positions.size() - 2) {
		TKey<Vector3> t0 = tt->positions[i];
		TKey<Vector3> t1 = tt->positions[i + 1];
		TKey<Vector3> t2 = tt->positions[i + 2];
		bool erase = _vector3_track_optimize_key(t0, t1, t2, p_allowed_velocity_err, p_allowed_angular_err, p_allowed_precision_error, is_nearest);
```
Then value track should take account of `INTERPOLATION_LINEAR_ANGLE`.
```cpp
void Animation::_value_track_optimize(int p_idx, real_t p_allowed_velocity_err, real_t p_allowed_angular_err, real_t p_allowed_precision_error) {
	ERR_FAIL_INDEX(p_idx, tracks.size());
	ERR_FAIL_COND(tracks[p_idx]->type != TYPE_VALUE);
	bool is_nearest = false;
	if (tracks[p_idx]->interpolation == INTERPOLATION_NEAREST) {
		is_nearest = true;
	} else if (tracks[p_idx]->interpolation != INTERPOLATION_LINEAR && tracks[p_idx]->interpolation != INTERPOLATION_LINEAR_ANGLE) {
		return;
	}
```

Code after:
		double v0 = a0 / (t1.time - t0.time);
		double v1 = a1 / (t2.time - t1.time);
		// Avoid zero div but check equality.
		if (abs(v0 - v1) < p_allowed_precision_error) {
			return true;
		} else if (abs(v0) < p_allowed_precision_error || abs(v1) < p_allowed_precision_error) {
			return false;
		}
		double ratio = v0 < v1 ? v0 / v1 : v1 / v0;
		if (ratio >= 1.0 - p_allowed_velocity_err) {
			return true;
		}
	}
	return false;
}

void Animation::_position_track_optimize(int p_idx, real_t p_allowed_velocity_err, real_t p_allowed_angular_err, real_t p_allowed_precision_error) {
	ERR_FAIL_INDEX(p_idx, tracks.size());
	ERR_FAIL_COND(tracks[p_idx]->type != TYPE_POSITION_3D);
	bool is_nearest = false;
	if (tracks[p_idx]->interpolation == INTERPOLATION_NEAREST) {
		is_nearest = true;
	} else if (tracks[p_idx]->interpolation != INTERPOLATION_LINEAR) {
		return;
	}
	PositionTrack *tt = static_cast<PositionTrack *>(tracks[p_idx]);
	int i = 0;
	while (i < tt->positions.size() - 2) {
		TKey<Vector3> t0 = tt->positions[i];
		TKey<Vector3> t1 = tt->positions[i + 1];
		TKey<Vector3> t2 = tt->positions[i + 2];
		bool erase = _vector3_track_optimize_key(t0, t1, t2, p_allowed_velocity_err, p_allowed_angular_err, p_allowed_precision_error, is_nearest);
		if (erase) {
			tt->positions.remove_at(i + 1);
		} else {
			i++;
		}
	}

	if (tt->positions.size() == 2) {
		if ((tt->positions[0].value - tt->positions[1].value).length() < p_allowed_precision_error) {
			tt->positions.remove_at(1);
		}
	}
}

void Animation::_rotation_track_optimize(int p_idx, real_t p_allowed_velocity_err, real_t p_allowed_angular_err, real_t p_allowed_precision_error) {
	ERR_FAIL_INDEX(p_idx, tracks.size());
	ERR_FAIL_COND(tracks[p_idx]->type != TYPE_ROTATION_3D);
	bool is_nearest = false;
	if (tracks[p_idx]->interpolation == INTERPOLATION_NEAREST) {