Files
UnrealEngine/Engine/Source/Runtime/Slate/Private/Framework/FInvertiblePiecewiseLinearFunction.cpp
2025-05-18 13:04:45 +08:00

130 lines
2.8 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#include "Framework/FInvertiblePiecewiseLinearFunction.h"
FInvertiblePointSlopeFunction::FInvertiblePointSlopeFunction(FVector2f Point, float Slope)
: Point(Point)
, Slope(Slope)
{}
float FInvertiblePointSlopeFunction::SolveForY(float X) const
{
const float M = Slope;
const float B = Point.Y - (M * Point.X);
// y = m*x + b
return M * X + B;
}
float FInvertiblePointSlopeFunction::SolveForX(float Y) const
{
const float M = 1 / Slope;
const float B = Point.X - (M * Point.Y);
// x = m*y + b
return M * Y + B;
}
FInvertiblePiecewiseLinearFunction::FInvertiblePiecewiseLinearFunction()
: SubFunctions{{{0.f,0.f}, 1.f}}
{}
FInvertiblePiecewiseLinearFunction::FInvertiblePiecewiseLinearFunction(const TArray<FVector2f>& FixedPoints)
{
if (FixedPoints.Num() <= 1)
{
SubFunctions.Emplace(FVector2f{0.f,0.f}, 1.f);
return;
}
float PrevSlope = 0;
for(int32 Index = 0; (Index + 1) < FixedPoints.Num(); ++Index)
{
const FVector2f& Begin = FixedPoints[Index];
const FVector2f& End = FixedPoints[Index + 1];
// duplicate points are allowed but ignored
if(Begin == End)
{
continue;
}
// for invertibility, both x and y must be increasing
check(Begin.X <= End.X && Begin.Y <= End.Y);
const float Slope = (End.Y - Begin.Y) / (End.X - Begin.X);
// Only add a subfunction if it changes the slope
if (PrevSlope != Slope)
{
SubFunctions.Emplace(Begin, Slope);
}
PrevSlope = Slope;
}
}
float FInvertiblePiecewiseLinearFunction::SolveForY(float X) const
{
return FindSubFunctionAtX(X).SolveForY(X);
}
float FInvertiblePiecewiseLinearFunction::SolveForX(float Y) const
{
return FindSubFunctionAtY(Y).SolveForX(Y);
}
const FInvertiblePiecewiseLinearFunction::SubFunction& FInvertiblePiecewiseLinearFunction::FindSubFunctionAtX(float X) const
{
if(X < SubFunctions[0].Point.X)
{
return SubFunctions[0];
}
int32 Start = 0;
int32 End = SubFunctions.Num() - 1;
// Binary search for a subFunction with the correct bounds
while (Start <= End)
{
const int Mid = (Start + End) / 2;
// If K is found
if (SubFunctions[Mid].Point.X == X)
{
return SubFunctions[Mid];
}
else if (SubFunctions[Mid].Point.X < X)
{
Start = Mid + 1;
}
else
{
End = Mid - 1;
}
}
return SubFunctions[End];
}
const FInvertiblePiecewiseLinearFunction::SubFunction& FInvertiblePiecewiseLinearFunction::FindSubFunctionAtY(float Y) const
{
if(Y < SubFunctions[0].Point.Y)
{
return SubFunctions[0];
}
int Start = 0;
int End = SubFunctions.Num() - 1;
// Binary search for a subFunction with the correct bounds
while (Start <= End) {
const int Mid = (Start + End) / 2;
// If K is found
if (SubFunctions[Mid].Point.Y == Y)
return SubFunctions[Mid];
else if (SubFunctions[Mid].Point.Y < Y)
Start = Mid + 1;
else
End = Mid - 1;
}
return SubFunctions[End];
}