Two new Math functions for you from me in 4.3, Template Min/Max of Array

Dear Community,

In 4.3 you now have available two C++ functions from me, which I gave to Epic!

These are template functions for the min and max of an array of any datatype for which the < operator is defined!

You can use my Min/Max of Array with literally any existing UE4 datatype or any datatype that you create, as long as you define operator< for your data type!

Here is my wiki on custom operators / operator overloads in UE4 C++

My functions will optionally return the index of the min/max value if you supply a pointer!

This makes using my Min/Max of Array very flexible for you to use in code, because you dont have to supply the var by reference and so you dont have to supply it at all if you dont want to know the index of the min/max value!

Here’s what Max looks like:


/**
* Max of Array
* @param	Array of templated type
* @param	Optional pointer for returning the index of the maximum element, if multiple maximum elements the first index is returned
* @return	The max value found in the array or default value if the array was empty
*/
template< class T >
static FORCEINLINE T Max(const TArray<T>& Values, int32* MaxIndex = NULL)
{
	if (Values.Num() == 0)
	{
		if (MaxIndex)
		{
			*MaxIndex = INDEX_NONE;
		}
		return **T**();
	}

	**T** CurMax = Values[0];
	int32 CurMaxIndex = 0;
	for (int32 v = 1; v < Values.Num(); ++v)
	{
		const **T** Value = Values[v];
		if (CurMax < Value)
		{
			CurMax = Value;
			CurMaxIndex = v;
		}
	}

	if (MaxIndex)
	{
		*MaxIndex = CurMaxIndex;
	}
	return CurMax;
}

**GenericPlatformMath.h **

You can find my functions in:


Public\GenericPlatform\GenericPlatformMath.h 

Sample Usage

TArray<YourVarType> MyVars;
TArray<int32> MyInts;

const YourVarType MaxValue = FMath::Max<YourVarType>(MyVars); //dont need to know the index of the max value

int32 MaxIndex;
const int32 MaxValue = FMath::Max<int32>(MyInts,&MaxIndex);

UE_LOG(YourLog,Log,TEXT("index of the max value is is %d), MaxIndex);

``
Your Data Type Only Needs the < Operator

Please note how I wrote the test for the Max of Array function!


if (CurMax < Value)

I wrote it this way so you truly only need to define the operator< for your data type to use it with my template Min/Max array functions!

:heart:

Rama

3 Likes

Realistic Use Case

Here is another realistic use case for the new functions I contributed to the Engine!

I am simply reminding you of these new tools that are at your disposable, I hope you enjoy them!

In this code below I am iterating over every one of my custom pathing volumes that I placed in the level, and I am taking the min and max radius of each one and generating a combine final set of path nodes that uses the min of the min radii and the max of the max radii


TArray<float> MinRadii;
TArray<float> MaxRadii;

//For Each pathing Volume
for(FJoyPathingVolume& Volume : C_PathVolumes)
{
  MinRadii.Add(Volume.PathSpaces.MinRadius);
  MaxRadii.Add(Volume.PathSpaces.MaxRadius);

  //For Each Pathing Space of Current Volume
  for(const FPathSpace& Each : Volume.PathSpaces.Spaces)
  {
		
    FinalSpaces.Spaces.Add(Each);
  }
}
 
//My new Min Max of TArray Functions!
FinalSpaces.MinRadius = FMath::Min<float>(MinRadii);
FinalSpaces.MaxRadius = FMath::Max<float>(MaxRadii);

More Realistic Use Cases

Sorting Through An Array of Blocking Hits

I have been using my templated min and max of array functions everywhere in my AI programming, it really speeds up my code work flow!

And I can now present you with another realistic use case that just happened!

I wrote a function to do a multi line trace and find all blocking hits for distinct actors, tracing down from the in-game cursor to the world!

I then needed to sort through the found blocking hits to find the one that was closest to being on the same z level as my player unit!

So imagine many stacked vertical layers of colliding objects, and needing to trace through them down to the colliding object that the player unit is standing on.

Here’s the code!

I used my templated min and max of array functions, now available to you in the Engine since my 4.3 pull request which was greatly facilitated by Marc Audy. (Thanks Marc!)

Specifically I used the get min of array using a float array whose indices match my original Blocking Hit array.



//This is the Cursor
//DrawPoint(CursorWorldPos,5,FColor::Black);

//Do Multi Trace
TArray<FHitResult> Hits;
VTraceMulti(
	PlayerUnit,
	CursorWorldPos,
	CursorWorldPos + CursorWorldDir  * 100000,
	Hits,
	1000 		//max blocking hits to find!
);

//Get Z Differences, want the point that is closest to the same Z level
// as the Player Unit
TArray<float> ZDiffs;
for(const FHitResult& Each : Hits)
{
  ZDiffs.Add(FMath::Abs(Each.ImpactPoint.Z - PlayerUnit->GetActorLocation().Z));
}
  
**//Get Min of Array, the focus of this thread!**
int32 Index = 0;
FMath::Min<float>(ZDiffs, &Index);
 
FVector BestImpactPoint = FVector::ZeroVector;
if(Hits.IsValidIndex(Index))
{
	BestImpactPoint = Hits[Index].ImpactPoint;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//SET!!!!
PlayerUnit->CursorWorldPosTopView = BestImpactPoint;
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~


As you can see in the code above, I needed to calculate the Z difference between the player and each and every blocking hit that my Multi Blocking hit trace function returned to me.

I created an array of floats with indices matching my Hit array, and then used my templated min of array of function to find the index of the HitResult that had the ideal Blocking Hit!

Please note my code structure above relies on the HitResult array and the float array having matching indices, if you want to use this general algorithm in your own code, make your array indices match!

If you want to sort/trim the initial data array first, you can create a pointer based array to pair up with your secondary calculation array.

Enjoy!

Rama

Another Practice Use Case: FTimespan

In this code sample I am using my template Min/Max of Array to figure out which save file in Solus was the most recent (relative to FDateTime::Now() which is the OS time of the user’s computer!)

I am not cheating or making any assumptions, I am doing the real robust analysis of comparing each save slot’s save date with current OS time!

I am getting a bunch of timespans and then finding the min index, and my Min/Max of array functions makes the code for this very succinct and easy to read!

The reason I can’t use TArray::Sort is because I need to preserve the positions of the original data, because the save slot indices are fixed.

Here again you can see how useful it is to be able to get the min index of an array of any data type that defines the operator< !

My template Min/Max functions are available to you right now in the Engine!

Enjoy!

Rama



int32 ASolusPCFileBrowser::GetMostRecentSaveSlotIndex()
{  
	//Time spans
	TArray<FTimespan> Times;
	
        //for each Save File Details, get the FTimespan since the Save Date (FDateTime) 
	for(const FSolusSaveDetails& Each : SolusSaveSlots)
	{
		Times.Add(FDateTime::Now() - Each.SaveDate);
	}
	
	int32 Index = 0;
	**FMath::Min<FTimespan>**(Times,&Index);

	return Index;
}