Ark Server API (ASA) - Wiki
Loading...
Searching...
No Matches
RandomStream.h
Go to the documentation of this file.
1// Copyright Epic Games, Inc. All Rights Reserved.
2
3#pragma once
4
5#include "CoreTypes.h"
6#include "Math/Box.h"
7#include "Math/UnrealMathUtility.h"
8#include "Math/Vector.h"
9#include "Math/Matrix.h"
10#include "Math/RotationMatrix.h"
11#include "Math/Transform.h"
12#include "HAL/PlatformTime.h"
13
14/**
15 * Implements a thread-safe SRand based RNG.
16 *
17 * Very bad quality in the lower bits. Don't use the modulus (%) operator.
18 */
20{
21 friend struct Z_Construct_UScriptStruct_FRandomStream_Statics;
22
23public:
24
25 /**
26 * Default constructor.
27 *
28 * The seed should be set prior to use.
29 */
31 : InitialSeed(0)
32 , Seed(0)
33 { }
34
35 /**
36 * Creates and initializes a new random stream from the specified seed value.
37 *
38 * @param InSeed The seed value.
39 */
40 FRandomStream( int32 InSeed )
41 {
42 Initialize(InSeed);
43 }
44
45 /**
46 * Creates and initializes a new random stream from the specified name.
47 *
48 * @note If NAME_None is provided, the stream will be seeded using the current time.
49 * @param InName The name value from which the stream will be initialized.
50 */
52 {
53 Initialize(InName);
54 }
55
56public:
57
58 /**
59 * Initializes this random stream with the specified seed value.
60 *
61 * @param InSeed The seed value.
62 */
63 void Initialize( int32 InSeed )
64 {
65 InitialSeed = InSeed;
66 Seed = uint32(InSeed);
67 }
68
69 /**
70 * Initializes this random stream using the specified name.
71 *
72 * @note If NAME_None is provided, the stream will be seeded using the current time.
73 * @param InName The name value from which the stream will be initialized.
74 */
75 void Initialize( FName InName )
76 {
77 if (InName != NAME_None)
78 {
80 }
81 else
82 {
84 }
85
86 Seed = uint32(InitialSeed);
87 }
88
89 /**
90 * Resets this random stream to the initial seed value.
91 */
92 void Reset() const
93 {
94 Seed = uint32(InitialSeed);
95 }
96
97 int32 GetInitialSeed() const
98 {
99 return InitialSeed;
100 }
101
102 /**
103 * Generates a new random seed.
104 */
106 {
107 Initialize(FMath::Rand());
108 }
109
110 /**
111 * Returns a random float number in the range [0, 1).
112 *
113 * @return Random number.
114 */
115 float GetFraction() const
116 {
118
119 float Result;
120
121 *(uint32*)&Result = 0x3F800000U | (Seed >> 9);
122
123 return Result - 1.0f;
124 }
125
126 /**
127 * Returns a random number between 0 and MAXUINT.
128 *
129 * @return Random number.
130 */
131 uint32 GetUnsignedInt() const
132 {
134
135 return Seed;
136 }
137
138 /**
139 * Returns a random vector of unit size.
140 *
141 * @return Random unit vector.
142 */
143 FVector GetUnitVector() const
144 {
145 FVector Result;
146 FVector::FReal L;
147
148 do
149 {
150 // Check random vectors in the unit sphere so result is statistically uniform.
151 Result.X = GetFraction() * 2.f - 1.f;
152 Result.Y = GetFraction() * 2.f - 1.f;
153 Result.Z = GetFraction() * 2.f - 1.f;
154 L = Result.SizeSquared();
155 }
156 while(L > 1.f || L < UE_KINDA_SMALL_NUMBER);
157
158 return Result.GetUnsafeNormal();
159 }
160
161 /**
162 * Gets the current seed.
163 *
164 * @return Current seed.
165 */
166 int32 GetCurrentSeed() const
167 {
168 return int32(Seed);
169 }
170
171 /**
172 * Mirrors the random number API in FMath
173 *
174 * @return Random number.
175 */
176 FORCEINLINE float FRand() const
177 {
178 return GetFraction();
179 }
180
181 /**
182 * Helper function for rand implementations.
183 *
184 * @return A random number in [0..A)
185 */
186 FORCEINLINE int32 RandHelper( int32 A ) const
187 {
188 // GetFraction guarantees a result in the [0,1) range.
189 return ((A > 0) ? FMath::TruncToInt(GetFraction() * float(A)) : 0);
190 }
191
192 /**
193 * Helper function for rand implementations.
194 *
195 * @return A random number >= Min and <= Max
196 */
197 FORCEINLINE int32 RandRange( int32 Min, int32 Max ) const
198 {
199 const int32 Range = (Max - Min) + 1;
200
201 return Min + RandHelper(Range);
202 }
203
204 /**
205 * Helper function for rand implementations.
206 *
207 * @return A random number >= Min and <= Max
208 */
210 {
211 return InMin + (InMax - InMin) * FRand();
212 }
213
214 /**
215 * Returns a random vector of unit size.
216 *
217 * @return Random unit vector.
218 */
219 FORCEINLINE FVector VRand() const
220 {
221 return GetUnitVector();
222 }
223
224 FORCEINLINE FVector RandPointInBox(const FBox& Box) const
225 {
226 return FVector( FRandRange(Box.Min.X, Box.Max.X),
227 FRandRange(Box.Min.Y, Box.Max.Y),
228 FRandRange(Box.Min.Z, Box.Max.Z) );
229 }
230
231 /**
232 * Returns a random unit vector, uniformly distributed, within the specified cone.
233 *
234 * @param Dir The center direction of the cone
235 * @param ConeHalfAngleRad Half-angle of cone, in radians.
236 * @return Normalized vector within the specified cone.
237 */
238 FORCEINLINE FVector VRandCone( FVector const& Dir, float ConeHalfAngleRad ) const
239 {
240 if (ConeHalfAngleRad > 0.f)
241 {
242 float const RandU = FRand();
243 float const RandV = FRand();
244
245 // Get spherical coords that have an even distribution over the unit sphere
246 // Method described at http://mathworld.wolfram.com/SpherePointPicking.html
247 float Theta = 2.f * UE_PI * RandU;
248 float Phi = FMath::Acos((2.f * RandV) - 1.f);
249
250 // restrict phi to [0, ConeHalfAngleRad]
251 // this gives an even distribution of points on the surface of the cone
252 // centered at the origin, pointing upward (z), with the desired angle
253 Phi = FMath::Fmod(Phi, ConeHalfAngleRad);
254
255 // get axes we need to rotate around
256 FMatrix const DirMat = FRotationMatrix(Dir.Rotation());
257 // note the axis translation, since we want the variation to be around X
258 FVector const DirZ = DirMat.GetUnitAxis( EAxis::X );
259 FVector const DirY = DirMat.GetUnitAxis( EAxis::Y );
260
261 FVector Result = Dir.RotateAngleAxis(Phi * 180.f / UE_PI, DirY);
262 Result = Result.RotateAngleAxis(Theta * 180.f / UE_PI, DirZ);
263
264 // ensure it's a unit vector (might not have been passed in that way)
265 Result = Result.GetSafeNormal();
266
267 return Result;
268 }
269 else
270 {
271 return Dir.GetSafeNormal();
272 }
273 }
274
275 /**
276 * Returns a random unit vector, uniformly distributed, within the specified cone.
277 *
278 * @param Dir The center direction of the cone
279 * @param HorizontalConeHalfAngleRad Horizontal half-angle of cone, in radians.
280 * @param VerticalConeHalfAngleRad Vertical half-angle of cone, in radians.
281 * @return Normalized vector within the specified cone.
282 */
283 FORCEINLINE FVector VRandCone( FVector const& Dir, float HorizontalConeHalfAngleRad, float VerticalConeHalfAngleRad ) const
284 {
285 if ( (VerticalConeHalfAngleRad > 0.f) && (HorizontalConeHalfAngleRad > 0.f) )
286 {
287 float const RandU = FRand();
288 float const RandV = FRand();
289
290 // Get spherical coords that have an even distribution over the unit sphere
291 // Method described at http://mathworld.wolfram.com/SpherePointPicking.html
292 float Theta = 2.f * UE_PI * RandU;
293 float Phi = FMath::Acos((2.f * RandV) - 1.f);
294
295 // restrict phi to [0, ConeHalfAngleRad]
296 // where ConeHalfAngleRad is now a function of Theta
297 // (specifically, radius of an ellipse as a function of angle)
298 // function is ellipse function (x/a)^2 + (y/b)^2 = 1, converted to polar coords
299 float ConeHalfAngleRad = FMath::Square(FMath::Cos(Theta) / VerticalConeHalfAngleRad) + FMath::Square(FMath::Sin(Theta) / HorizontalConeHalfAngleRad);
300 ConeHalfAngleRad = FMath::Sqrt(1.f / ConeHalfAngleRad);
301
302 // clamp to make a cone instead of a sphere
303 Phi = FMath::Fmod(Phi, ConeHalfAngleRad);
304
305 // get axes we need to rotate around
306 FMatrix const DirMat = FRotationMatrix(Dir.Rotation());
307 // note the axis translation, since we want the variation to be around X
308 FVector const DirZ = DirMat.GetUnitAxis( EAxis::X );
309 FVector const DirY = DirMat.GetUnitAxis( EAxis::Y );
310
311 FVector Result = Dir.RotateAngleAxis(Phi * 180.f / UE_PI, DirY);
312 Result = Result.RotateAngleAxis(Theta * 180.f / UE_PI, DirZ);
313
314 // ensure it's a unit vector (might not have been passed in that way)
315 Result = Result.GetSafeNormal();
316
317 return Result;
318 }
319 else
320 {
321 return Dir.GetSafeNormal();
322 }
323 }
324
325 /**
326 * Get a textual representation of the RandomStream.
327 *
328 * @return Text describing the RandomStream.
329 */
331 {
332 return FString::Printf(TEXT("FRandomStream(InitialSeed=%i, Seed=%u)"), InitialSeed, Seed);
333 }
334
335protected:
336
337 /**
338 * Mutates the current seed into the next seed.
339 */
340 void MutateSeed() const
341 {
342 Seed = (Seed * 196314165U) + 907633515U;
343 }
344
345private:
346
347 // Holds the initial seed.
349
350 // Holds the current seed. This should be an uint32 so that any shift to obtain top bits
351 // is a logical shift, rather than an arithmetic shift (which smears down the negative bit).
352 mutable uint32 Seed;
353};
#define TEXT(x)
Definition Platform.h:1108
#define FORCEINLINE
Definition Platform.h:644
#define UE_PI
#define UE_KINDA_SMALL_NUMBER
FWindowsPlatformTime FPlatformTime
FString ToString() const
Definition NameTypes.h:662
FORCEINLINE bool operator!=(EName Ename) const
Definition NameTypes.h:1668
friend FORCEINLINE uint32 GetTypeHash(const FString &S)
int32 GetCurrentSeed() const
void Reset() const
FORCEINLINE FVector VRand() const
void GenerateNewSeed()
uint32 GetUnsignedInt() const
void MutateSeed() const
FORCEINLINE FVector VRandCone(FVector const &Dir, float HorizontalConeHalfAngleRad, float VerticalConeHalfAngleRad) const
FRandomStream(int32 InSeed)
void Initialize(int32 InSeed)
FVector GetUnitVector() const
FString ToString() const
void Initialize(FName InName)
int32 GetInitialSeed() const
FRandomStream(FName InName)
FORCEINLINE FVector VRandCone(FVector const &Dir, float ConeHalfAngleRad) const
FORCEINLINE int32 RandHelper(int32 A) const
float GetFraction() const
FORCEINLINE FVector::FReal FRandRange(FVector::FReal InMin, FVector::FReal InMax) const
FORCEINLINE float FRand() const
FORCEINLINE FVector RandPointInBox(const FBox &Box) const
FORCEINLINE int32 RandRange(int32 Min, int32 Max) const
static FORCEINLINE uint32 Cycles()