Ark Server API (ASA) - Wiki
Loading...
Searching...
No Matches
Sphere.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/MathFwd.h"
7#include "Math/Matrix.h"
8#include "Math/Transform.h"
9#include "Math/UnrealMathUtility.h"
10#include "Math/Vector.h"
11#include "Math/Vector4.h"
12#include "Misc/AssertionMacros.h"
13#include "Misc/LargeWorldCoordinates.h"
14#include "Serialization/Archive.h"
15#include "Serialization/StructuredArchiveAdapters.h"
16#include "Templates/IsUECoreType.h"
17#include "Templates/UnrealTypeTraits.h"
18#include "UObject/ObjectVersion.h"
19
20/**
21 * Implements a basic sphere.
22 */
23namespace UE {
24namespace Math {
25template <typename T> struct TMatrix;
26
27template<typename T>
28struct TSphere
29{
30public:
31 using FReal = T;
32
33 /** The sphere's center point. */
34 TVector<T> Center;
35
36 /** The sphere's radius. */
37 T W;
38
39
40 /** Default constructor (no initialization). */
41 TSphere() { }
42
43 /**
44 * Creates and initializes a new sphere.
45 *
46 * @param int32 Passing int32 sets up zeroed sphere.
47 */
48 TSphere(int32)
49 : Center(0.0f, 0.0f, 0.0f)
50 , W(0)
51 { }
52
53 /**
54 * Creates and initializes a new sphere with the specified parameters.
55 *
56 * @param InV Center of sphere.
57 * @param InW Radius of sphere.
58 */
59 TSphere(TVector<T> InV, T InW)
60 : Center(InV)
61 , W(InW)
62 { }
63
64 /**
65 * Constructor.
66 *
67 * @param EForceInit Force Init Enum.
68 */
69 explicit FORCEINLINE TSphere(EForceInit)
70 : Center(ForceInit)
71 , W(0.0f)
72 { }
73
74 /**
75 * Constructor.
76 *
77 * @param Points Pointer to list of points this sphere must contain.
78 * @param Count How many points are in the list.
79 */
80 TSphere(const TVector<T>* Points, int32 Count);
81
82
83 /**
84 * Constructor.
85 *
86 * @param Spheres Pointer to list of spheres this sphere must contain.
87 * @param Count How many points are in the list.
88 */
89 TSphere(const TSphere<T>* Spheres, int32 Count);
90
91 // Conversion from other variant type.
92 template<typename FArg, TEMPLATE_REQUIRES(!std::is_same_v<T, FArg>)>
93 explicit TSphere(const TSphere<FArg>& From) : TSphere<T>(TVector<T>(From.Center), T(From.W)) {}
94
95 /**
96 * Check whether two spheres are the same within specified tolerance.
97 *
98 * @param Sphere The other sphere.
99 * @param Tolerance Error Tolerance.
100 * @return true if spheres are equal within specified tolerance, otherwise false.
101 */
102 bool Equals(const TSphere<T>& Sphere, T Tolerance = UE_KINDA_SMALL_NUMBER) const
103 {
104 return Center.Equals(Sphere.Center, Tolerance) && FMath::Abs(W - Sphere.W) <= Tolerance;
105 }
106
107 /**
108 * Compares two spheres for equality.
109 *
110 * @param Other The other sphere to compare with.
111 * @return true if the spheres are equal, false otherwise.
112 */
113 bool operator==(const TSphere<T>& Other) const
114 {
115 return Center == Other.Center && W == Other.W;
116 }
117
118 /**
119 * Compares two spheres for inequality.
120 *
121 * @param Other The other sphere to compare with.
122 * @return true if the spheres are not equal, false otherwise.
123 */
124 bool operator!=(const TSphere<T>& Other) const
125 {
126 return !(*this == Other);
127 }
128
129 /**
130 * Gets the result of addition to this bounding volume.
131 *
132 * @param Other The other volume to add to this.
133 * @return A new bounding volume.
134 */
135 TSphere<T> operator+(const TSphere<T>& Other) const
136 {
137 return TSphere<T>(*this) += Other;
138 }
139
140 /**
141 * Adds to this sphere to include a new bounding volume.
142 *
143 * @param Other the bounding volume to increase the bounding volume to.
144 * @return Reference to this bounding volume after resizing to include the other bounding volume.
145 */
146 TSphere<T>& operator+=(const TSphere<T>& Other);
147
148 /**
149 * Check whether sphere is inside of another.
150 *
151 * @param Other The other sphere.
152 * @param Tolerance Error Tolerance.
153 * @return true if sphere is inside another, otherwise false.
154 */
155 bool IsInside(const TSphere<T>& Other, T Tolerance = UE_KINDA_SMALL_NUMBER) const
156 {
157 if (W > Other.W + Tolerance)
158 {
159 return false;
160 }
161
162 return (Center - Other.Center).SizeSquared() <= FMath::Square(Other.W + Tolerance - W);
163 }
164
165 /**
166 * Checks whether the given location is inside this sphere.
167 *
168 * @param In The location to test for inside the bounding volume.
169 * @return true if location is inside this volume.
170 */
171 bool IsInside(const FVector& In, T Tolerance = UE_KINDA_SMALL_NUMBER) const
172 {
173 return (Center - In).SizeSquared() <= FMath::Square(W + Tolerance);
174 }
175
176 /**
177 * Test whether this sphere intersects another.
178 *
179 * @param Other The other sphere.
180 * @param Tolerance Error tolerance.
181 * @return true if spheres intersect, false otherwise.
182 */
183 FORCEINLINE bool Intersects(const TSphere<T>& Other, T Tolerance = UE_KINDA_SMALL_NUMBER) const
184 {
185 return (Center - Other.Center).SizeSquared() <= FMath::Square(FMath::Max(0.f, Other.W + W + Tolerance));
186 }
187
188 /**
189 * Get result of Transforming sphere by Matrix.
190 *
191 * @param M Matrix to transform by.
192 * @return Result of transformation.
193 */
194 TSphere<T> TransformBy(const TMatrix<T>& M) const;
195
196 /**
197 * Get result of Transforming sphere with Transform.
198 *
199 * @param M Transform information.
200 * @return Result of transformation.
201 */
202 TSphere<T> TransformBy(const FTransform& M) const;
203
204 /**
205 * Get volume of the current sphere
206 *
207 * @return Volume (in Unreal units).
208 */
209 T GetVolume() const
210 {
211 return (4.f / 3.f) * UE_PI * (W * W * W);
212 }
213
214 /**
215 * Get a textual representation of the sphere.
216 *
217 * @return Text describing the sphere.
218 */
219 FString ToString() const
220 {
221 return FString::Printf(TEXT("Center=(%s), Radius=(%s)"), *Center.ToString(), *W.ToString());
222 }
223
224 // Note: TSphere is usually written via binary serialization. This function exists for SerializeFromMismatchedTag conversion usage.
225 bool Serialize(FArchive& Ar)
226 {
227 Ar << *this;
228 return true;
229 }
230
231 bool SerializeFromMismatchedTag(FName StructTag, FArchive& Ar);
232
233};
234
235/**
236 * Serializes the given sphere from or into the specified archive.
237 *
238 * @param Ar The archive to serialize from or into.
239 * @param Sphere The sphere to serialize.
240 * @return The archive.
241 */
242
243inline FArchive& operator<<(FArchive& Ar, TSphere<float>& Sphere)
244{
245 Ar << Sphere.Center << Sphere.W;
246 return Ar;
247}
248
249/**
250 * Serializes the given sphere from or into the specified archive.
251 *
252 * @param Ar The archive to serialize from or into.
253 * @param Sphere The sphere to serialize.
254 * @return The archive.
255 */
256
257inline FArchive& operator<<(FArchive& Ar, TSphere<double>& Sphere)
258{
259 Ar << Sphere.Center;
260
261 if (Ar.UEVer() >= EUnrealEngineObjectUE5Version::LARGE_WORLD_COORDINATES)
262 {
263 Ar << Sphere.W;
264 }
265 else
266 {
267 checkf(Ar.IsLoading(), TEXT("float -> double conversion applied outside of load!"));
268 // Stored as floats, so serialize float and copy.
269 float SW;
270 Ar << SW;
271 Sphere.W = (double)SW;
272 }
273
274 return Ar;
275}
276
277template<typename T>
278TSphere<T> TSphere<T>::TransformBy(const TMatrix<T>& M) const
279{
280 TSphere<T> Result;
281
282 FVector4 TransformedCenter = M.TransformPosition(this->Center);
283 Result.Center = TVector<T>(TransformedCenter.X, TransformedCenter.Y, TransformedCenter.Z);
284
285 const TVector<T> XAxis(M.M[0][0], M.M[0][1], M.M[0][2]);
286 const TVector<T> YAxis(M.M[1][0], M.M[1][1], M.M[1][2]);
287 const TVector<T> ZAxis(M.M[2][0], M.M[2][1], M.M[2][2]);
288
289 Result.W = FMath::Sqrt(FMath::Max(XAxis | XAxis, FMath::Max(YAxis | YAxis, ZAxis | ZAxis))) * W;
290
291 return Result;
292}
293
294
295template<typename T>
296TSphere<T> TSphere<T>::TransformBy(const FTransform& M) const
297{
298 TSphere<T> Result;
299
300 Result.Center = M.TransformPosition(this->Center);
301 Result.W = M.GetMaximumAxisScale() * W;
302
303 return Result;
304}
305
306template<typename T>
307TSphere<T>& TSphere<T>::operator+=(const TSphere<T>& Other)
308{
309 if (W == 0.f)
310 {
311 *this = Other;
312 return *this;
313 }
314
315 TVector<T> ToOther = Other.Center - Center;
316 T DistSqr = ToOther.SizeSquared();
317
318 if (FMath::Square(W - Other.W) + UE_KINDA_SMALL_NUMBER >= DistSqr)
319 {
320 // Pick the smaller
321 if (W < Other.W)
322 {
323 *this = Other;
324 }
325 }
326 else
327 {
328 T Dist = FMath::Sqrt(DistSqr);
329
330 TSphere<T> NewSphere;
331 NewSphere.W = (Dist + Other.W + W) * 0.5f;
332 NewSphere.Center = Center;
333
334 if (Dist > UE_SMALL_NUMBER)
335 {
336 NewSphere.Center += ToOther * ((NewSphere.W - W) / Dist);
337 }
338
339 // make sure both are inside afterwards
340 checkSlow(Other.IsInside(NewSphere, 1.f));
341 checkSlow(IsInside(NewSphere, 1.f));
342
343 *this = NewSphere;
344 }
345
346 return *this;
347}
348
349// Forward declarations for complex constructors.
350template<> TSphere<float>::TSphere(const TVector<float>* Points, int32 Count);
351template<> TSphere<double>::TSphere(const TVector<double>* Points, int32 Count);
352template<> TSphere<float>::TSphere(const TSphere<float>* Spheres, int32 Count);
353template<> TSphere<double>::TSphere(const TSphere<double>* Spheres, int32 Count);
354
355} // namespace Math
356} // namespace UE
357
358
360
361template<> struct TCanBulkSerialize<FSphere3f> { enum { Value = true }; };
362template<> struct TIsPODType<FSphere3f> { enum { Value = true }; };
363template<> struct TIsUECoreVariant<FSphere3f> { enum { Value = true }; };
364
365template<> struct TCanBulkSerialize<FSphere3d> { enum { Value = true }; };
366template<> struct TIsPODType<FSphere3d> { enum { Value = true }; };
367template<> struct TIsUECoreVariant<FSphere3d> { enum { Value = true }; };
368
369template<>
370inline bool FSphere3f::SerializeFromMismatchedTag(FName StructTag, FArchive& Ar)
371{
372 return UE_SERIALIZE_VARIANT_FROM_MISMATCHED_TAG(Ar, Sphere, Sphere3f, Sphere3d);
373}
374
375template<>
376inline bool FSphere3d::SerializeFromMismatchedTag(FName StructTag, FArchive& Ar)
377{
378 return UE_SERIALIZE_VARIANT_FROM_MISMATCHED_TAG(Ar, Sphere, Sphere3d, Sphere3f);
379}
380
381
382/* FMath inline functions
383 *****************************************************************************/
384
385/**
386* Computes minimal bounding sphere encompassing given cone
387*/
388template<typename FReal>
389FORCEINLINE UE::Math::TSphere<FReal> FMath::ComputeBoundingSphereForCone(UE::Math::TVector<FReal> const& ConeOrigin, UE::Math::TVector<FReal> const& ConeDirection, FReal ConeRadius, FReal CosConeAngle, FReal SinConeAngle)
390{
391 // Based on: https://bartwronski.com/2017/04/13/cull-that-cone/
392 const FReal COS_PI_OVER_4 = 0.70710678118f; // Cos(Pi/4); // LWC_TODO: precision improvement possible here
393 if (CosConeAngle < COS_PI_OVER_4)
394 {
395 return UE::Math::TSphere<FReal>(ConeOrigin + ConeDirection * ConeRadius * CosConeAngle, ConeRadius * SinConeAngle);
396 }
397 else
398 {
399 const FReal BoundingRadius = ConeRadius / (2.0f * CosConeAngle);
400 return UE::Math::TSphere<FReal>(ConeOrigin + ConeDirection * BoundingRadius, BoundingRadius);
401 }
402}
#define checkSlow(expr)
#define checkf(expr, format,...)
#define UE_DECLARE_LWC_TYPE(...)
#define UE_SERIALIZE_VARIANT_FROM_MISMATCHED_TAG(AR_OR_SLOT, ALIAS, TYPE, ALT_TYPE)
#define TEXT(x)
Definition Platform.h:1108
#define FORCEINLINE
Definition Platform.h:644
#define UE_PI
#define UE_SMALL_NUMBER
#define UE_KINDA_SMALL_NUMBER
#define TEMPLATE_REQUIRES(...)