USplineComponent::GetInputKeyAtDistanceAlongSpline is wrong

GetInputKeyAtDistanceAlongSpline doesn’t do what its name implies it would.
If I understand it well the second function shows that this TimeMultiplier thing should not be there at all. Distance → SplineInputKey conversion can be done via SplineCurves.ReparamTable.Eval(Distance, 0.0f).
Sad thing that it is not possible from outside.

float USplineComponent::GetInputKeyAtDistanceAlongSpline(float Distance) const
{
	const int32 NumPoints = SplineCurves.Position.Points.Num();

	if (NumPoints < 2)
	{
		return 0.0f;
	}

	const float TimeMultiplier = Duration / (bClosedLoop ? NumPoints : (NumPoints - 1.0f));
	return SplineCurves.ReparamTable.Eval(Distance, 0.0f) * TimeMultiplier;
}


FVector USplineComponent::GetLocationAtDistanceAlongSpline(float Distance, ESplineCoordinateSpace::Type CoordinateSpace) const
{
	const float Param = SplineCurves.ReparamTable.Eval(Distance, 0.0f);
	return GetLocationAtSplineInputKey(Param, CoordinateSpace);
}

Also, a FindDistanceClosestToWorldLocation() function would be the thing almost everyone needs.

Edit: I tried to calculate the input key simply by a division outside. It works if the duration is 1.0f, and if it is not a closed spline.
I can’t really check the value of duration because there isn’t any getter function for that.
I don’t even know what it is (I just checked with a breakpoint, it was 1.0).

Thanks,

Hey ,

Can you explain to me if this is a actual bug with the Unreal Engine, as in it is either breaking a portion of, as in a crash or assert?

I don’t fully understand what it is you are trying to describe.

Please break this down and explain it more:

If I understand it well the second function shows that this TimeMultiplier thing should not be there at all. Distance → SplineInputKey conversion can be done via SplineCurves.ReparamTable.Eval(Distance, 0.0f). Sad thing that it is not possible from outside.

It does not lead to crash (or not directly). Sorry if I wasn’t clear enough, I’ll try to explain it.

The function USplineComponent::GetInputKeyAtDistanceAlongSpline simply does not do what it says it does.

It should convert “Distance” values to “InputKey” values.

The second function (which works as it is intended) does the conversion because the input is Distance. It just converts it to InputKey, and then uses another function which expects InputKey. I just pasted it here to show that even if I miss something, I am sure that between the two function, one must be wrong.

Because the first says that in order to get InputKey from Distance Eval has to be called and the result has to be multiplied with “TimeMultiplier”.
According to the second the TimeMultiplier part should not be there.

According to my tests the second is correct.
As a temp. fix I can modify the GetInputKeyAtDistanceAlongSpline() return value outside, but that does not work in all case, because some part of TimeMultiplier is simply not accessible.

Can you show me the tests that show that the GetInputKeyAtDistanceAlongSpline function is incorrect?

Thanks.

Well, the easiest example I can come up with: create a spline.

First call the function GetLocationAtDistanceAlongSpline() for a distance value > 0, maybe spline length is the best.

After that call GetInputKeyAtDistanceAlongSpline() for the same distance, and use the return value to call GetLocationAtSplineInputKey().

The two locations are different.

My actual example I had trouble with is pretty complicated - I use the function to calculate the distance value for the closest spline point from a given world location. I can get the inputkey value, I have to calculate the distance from that, I use logarithmic search to get the distance.

However as the inputkey goes from the beginning of the spline until the end, the calculated distance does not go between 0 and SplineLength, it covers a smaller segment. Multiplying the return value of GetInputKeyAtDistanceAlongSpline() with NumPoints-1 fixes it (as long as the duration is 1.0f and the spline is not closed).

I am not sure I understand the issue.

GetInputKeyAtDistanceAlongSpline is going to get you the result of the Duration of the Spline, based on the distance. As an example:

GetInputKeyAtDistanceAlongSpline( GetSplineLength( ) / 2 ) where Duration is 3, will give you 1.5f.

GetInputKeyAtDistanceAlongSpline( GetSplineLength( ) / 2 ) where Duration is 30, will give you 15.f.

Using this result as an argument for GetLocationAtDistanceAlongSpline( ) will of course be different than the direct ( Length / 2 ) because the result is based on the Duration of the Spline and not a literal distance.

Please correct me if I am wrong.

Thanks.

“GetInputKeyAtDistanceAlongSpline is going to get you the result of the Duration of the Spline, based on the distance.”

As in, if the length is 200 and the Duration is 1.0 and you use half the length (100) to get the input key, it will be 0.5 as 100 is going to be 50% of the total length. It’s returning the percentage of duration that the distance being passed in represents as a whole length of the Spline.

Is that the issue being reported? The function name is using InputKey when it doesn’t return the InputKey?

Thanks.

“GetInputKeyAtDistanceAlongSpline is going to get you the result of the Duration of the Spline, based on the distance.”

You mean the time?
Why doesn’t it called GetTimeAtDistanceAlongSpline() then?
In the function name the word “InputKey” is used, which is not the same.

Yes, that’s my point.

Maybe it’s not a “bug”, but we can call it anything - if the function name implies something and the return value is different, that’s something I would call a problem.

Thanks for your time, and sorry for not being clear enough from the beginning.

Hey ,

To begin, thank you for submitting a bug report, however at this time we believe that the issue you are describing is not actually a bug with the Unreal Engine, and so we are not able to take any further action on this.

Secondly, I understand that the function name is a bit confusing given that the normal representation of a InputKey in the Viewport is a whole value, such as 1.0, 2.0, or 3.0. What this function is designed to do is give you a InputKey that is based on the start and end point of the Spline, based on the Duration of the spline. This still constitutes a InputKey, it just doesn’t directly follow the same structure as the visual appearance of them. It instead uses a 0.0 to 1.0 scale as it is only using the start and end points to do the calculation.

It appears that you have a good understanding of what is going on and have a work around that will suit your project well. If you would like to update the function and put a pull request, you can do so by visiting the Epic GitHub starting page, here:

[][1]

[1]:

Hi ,
I do not concur. When a function uses Duration to calculate the result its signature has the suffix “AtTime”. This funcion uses Duration and has not that suffix and there is no alternative to get and input key from distance indepently from Duration.

Take a look at the comment, no mention to duration is given…

/** Given a distance along the length of this spline, return the corresponding input key at that point */
UFUNCTION(BlueprintCallable, Category=Spline)
float GetInputKeyAtDistanceAlongSpline(float Distance) const;

…but in all “AtTime” funcions duration is mentioned. For example:

/** Given a time from 0 to the spline duration, return a unit direction vector of the spline tangent there. */
UFUNCTION(BlueprintCallable, Category=Spline)
FVector GetDirectionAtTime(float Time, ESplineCoordinateSpace::Type CoordinateSpace, bool bUseConstantVelocity = false) const;

The expected would be to deprecate this function and add two more, one Duration dependent and the other independent, I think.

Regards,

.

The function name is misleading and causes problems. Every other function with “InputKey” returns (or expects to receive in order to return proper results) values from 0.0f to number of keys so input key is NOT a 0.0f - 1.0f range. It is 0.5f between the 0 index point and 1 index point, then 1.5f between the 1 index point and 2 index point etc. For a spline with 4 points total, the input key is a range from 0.0f - 3.0f.

My fix was to set the duration to the number of points (keeping in mind closed loops). This makes Time and InputKey functions equivalent, but that is not ok for every use case. The change required to make it less confusing is really small, literally modify the existing function to return input key as used in other functions and add GetTimeAtDistanceAlongSpline which does exactly what the current GetInputKeyAtDistanceAlongSpline does. That avoids rename, which may be painful and change a lot of files.

Do you not see the issue? Does it need to be explained in a better detail? Pull request isn’t really an option, you rarely merge them into the engine.

This is still an issue as of 4.24 and should at the very least be documented that it does not follow the naming conventions in USplineComponent and returns a Time rather than InputKey.

I made a pull request with a fix years ago, it ended up in the pull request hell.
I just stopped bothering, it’s just too much effort to get anything fixed.

Stating that the function name is a bit confusing still makes me laugh after 3.5 years.

It is already December 2022 and UE5.1 is released, this confusing still remains.

1 Like