Ark Server API (ASA) - Wiki
Loading...
Searching...
No Matches
InterpCurve.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 "Misc/AssertionMacros.h"
7#include "Containers/Array.h"
8#include "Math/UnrealMathUtility.h"
9#include "Math/Color.h"
10#include "Math/Vector2D.h"
11#include "Math/Vector.h"
12#include "Math/Quat.h"
13#include "Math/TwoVectors.h"
14#include "Math/InterpCurvePoint.h"
15
16/**
17 * Template for interpolation curves.
18 *
19 * @see FInterpCurvePoint
20 * @todo Docs: FInterpCurve needs template and function documentation
21 */
22template<class T>
24{
25public:
26
27 /** Holds the collection of interpolation points. */
29
30 /** Specify whether the curve is looped or not */
32
33 /** Specify the offset from the last point's input key corresponding to the loop point */
35
36public:
37
38 /** Default constructor. */
40 : bIsLooped(false)
41 , LoopKeyOffset(0.f)
42 {
43 }
44
45public:
46
47 /**
48 * Adds a new keypoint to the InterpCurve with the supplied In and Out value.
49 *
50 * @param InVal
51 * @param OutVal
52 * @return The index of the new key.
53 */
54 int32 AddPoint( const float InVal, const T &OutVal );
55
56 /**
57 * Moves a keypoint to a new In value.
58 *
59 * This may change the index of the keypoint, so the new key index is returned.
60 *
61 * @param PointIndex
62 * @param NewInVal
63 * @return
64 */
65 int32 MovePoint( int32 PointIndex, float NewInVal );
66
67 /** Clears all keypoints from InterpCurve. */
68 void Reset();
69
70 /** Set loop key for curve */
71 void SetLoopKey( float InLoopKey );
72
73 /** Clear loop key for curve */
74 void ClearLoopKey();
75
76 /**
77 * Evaluate the output for an arbitary input value.
78 * For inputs outside the range of the keys, the first/last key value is assumed.
79 */
80 T Eval( const float InVal, const T& Default = T(ForceInit) ) const;
81
82 /**
83 * Evaluate the derivative at a point on the curve.
84 */
85 T EvalDerivative( const float InVal, const T& Default = T(ForceInit) ) const;
86
87 /**
88 * Evaluate the second derivative at a point on the curve.
89 */
90 T EvalSecondDerivative( const float InVal, const T& Default = T(ForceInit) ) const;
91
92 /**
93 * Find the nearest point on spline to the given point.
94 *
95 * @param PointInSpace - the given point
96 * @param OutDistanceSq - output - the squared distance between the given point and the closest found point.
97 * @return The key (the 't' parameter) of the nearest point.
98 */
99 float InaccurateFindNearest( const T &PointInSpace, float& OutDistanceSq ) const;
100
101 /**
102 * Find the nearest point on spline to the given point.
103 *
104 * @param PointInSpace - the given point
105 * @param OutDistanceSq - output - the squared distance between the given point and the closest found point.
106 * @param OutSegment - output - the nearest segment to the given point.
107 * @return The key (the 't' parameter) of the nearest point.
108 */
109 float InaccurateFindNearest( const T &PointInSpace, float& OutDistanceSq, float& OutSegment ) const;
110
111 /**
112 * Find the nearest point (to the given point) on segment between Points[PtIdx] and Points[PtIdx+1]
113 *
114 * @param PointInSpace - the given point
115 * @return The key (the 't' parameter) of the found point.
116 */
117 float InaccurateFindNearestOnSegment( const T &PointInSpace, int32 PtIdx, float& OutSquaredDistance ) const;
118
119 /** Automatically set the tangents on the curve based on surrounding points */
120 void AutoSetTangents(float Tension = 0.0f, bool bStationaryEndpoints = true);
121
122 /** Calculate the min/max out value that can be returned by this InterpCurve. */
123 void CalcBounds(T& OutMin, T& OutMax, const T& Default = T(ForceInit)) const;
124
125public:
126
127 /**
128 * Serializes the interp curve.
129 *
130 * @param Ar Reference to the serialization archive.
131 * @param Curve Reference to the interp curve being serialized.
132 *
133 * @return Reference to the Archive after serialization.
134 */
135 friend FArchive& operator<<( FArchive& Ar, FInterpCurve& Curve )
136 {
137 // NOTE: This is not used often for FInterpCurves. Most of the time these are serialized
138 // as inline struct properties in UnClass.cpp!
139
140 Ar << Curve.Points;
142 {
143 Ar << Curve.bIsLooped;
145 }
146
147 return Ar;
148 }
149
150 /**
151 * Compare equality of two FInterpCurves
152 */
153 friend bool operator==(const FInterpCurve& Curve1, const FInterpCurve& Curve2)
154 {
155 return (Curve1.Points == Curve2.Points &&
158 }
159
160 /**
161 * Compare inequality of two FInterpCurves
162 */
163 friend bool operator!=(const FInterpCurve& Curve1, const FInterpCurve& Curve2)
164 {
165 return !(Curve1 == Curve2);
166 }
167
168 /**
169 * Finds the lower index of the two points whose input values bound the supplied input value.
170 */
171 int32 GetPointIndexForInputValue(const float InValue) const;
172};
173
174
175/* FInterpCurve inline functions
176 *****************************************************************************/
177
178template< class T >
179int32 FInterpCurve<T>::AddPoint( const float InVal, const T &OutVal )
180{
181 int32 i=0; for( i=0; i<Points.Num() && Points[i].InVal < InVal; i++);
182 Points.InsertUninitialized(i);
183 Points[i] = FInterpCurvePoint< T >(InVal, OutVal);
184 return i;
185}
186
187
188template< class T >
189int32 FInterpCurve<T>::MovePoint( int32 PointIndex, float NewInVal )
190{
191 if( PointIndex < 0 || PointIndex >= Points.Num() )
192 return PointIndex;
193
194 const T OutVal = Points[PointIndex].OutVal;
195 const EInterpCurveMode Mode = Points[PointIndex].InterpMode;
196 const T ArriveTan = Points[PointIndex].ArriveTangent;
197 const T LeaveTan = Points[PointIndex].LeaveTangent;
198
199 Points.RemoveAt(PointIndex);
200
201 const int32 NewPointIndex = AddPoint( NewInVal, OutVal );
202 Points[NewPointIndex].InterpMode = Mode;
203 Points[NewPointIndex].ArriveTangent = ArriveTan;
204 Points[NewPointIndex].LeaveTangent = LeaveTan;
205
206 return NewPointIndex;
207}
208
209
210template< class T >
212{
213 Points.Empty();
214}
215
216
217template <class T>
218void FInterpCurve<T>::SetLoopKey(float InLoopKey)
219{
220 // Can't set a loop key if there are no points
221 if (Points.Num() == 0)
222 {
223 bIsLooped = false;
224 return;
225 }
226
227 const float LastInKey = Points.Last().InVal;
228 if (InLoopKey > LastInKey)
229 {
230 // Calculate loop key offset from the input key of the final point
231 bIsLooped = true;
232 LoopKeyOffset = InLoopKey - LastInKey;
233 }
234 else
235 {
236 // Specified a loop key lower than the final point; turn off looping.
237 bIsLooped = false;
238 }
239}
240
241
242template <class T>
244{
245 bIsLooped = false;
246}
247
248
249template< class T >
250int32 FInterpCurve<T>::GetPointIndexForInputValue(const float InValue) const
251{
252 const int32 NumPoints = Points.Num();
253 const int32 LastPoint = NumPoints - 1;
254
255 check(NumPoints > 0);
256
257 if (InValue < Points[0].InVal)
258 {
259 return -1;
260 }
261
262 if (InValue >= Points[LastPoint].InVal)
263 {
264 return LastPoint;
265 }
266
267 int32 MinIndex = 0;
268 int32 MaxIndex = NumPoints;
269
270 while (MaxIndex - MinIndex > 1)
271 {
272 int32 MidIndex = (MinIndex + MaxIndex) / 2;
273
274 if (Points[MidIndex].InVal <= InValue)
275 {
276 MinIndex = MidIndex;
277 }
278 else
279 {
280 MaxIndex = MidIndex;
281 }
282 }
283
284 return MinIndex;
285}
286
287
288template< class T >
289T FInterpCurve<T>::Eval(const float InVal, const T& Default) const
290{
291 const int32 NumPoints = Points.Num();
292 const int32 LastPoint = NumPoints - 1;
293
294 // If no point in curve, return the Default value we passed in.
295 if (NumPoints == 0)
296 {
297 return Default;
298 }
299
300 // Binary search to find index of lower bound of input value
301 const int32 Index = GetPointIndexForInputValue(InVal);
302
303 // If before the first point, return its value
304 if (Index == -1)
305 {
306 return Points[0].OutVal;
307 }
308
309 // If on or beyond the last point, return its value.
310 if (Index == LastPoint)
311 {
312 if (!bIsLooped)
313 {
314 return Points[LastPoint].OutVal;
315 }
316 else if (InVal >= Points[LastPoint].InVal + LoopKeyOffset)
317 {
318 // Looped spline: last point is the same as the first point
319 return Points[0].OutVal;
320 }
321 }
322
323 // Somewhere within curve range - interpolate.
324 check(Index >= 0 && ((bIsLooped && Index < NumPoints) || (!bIsLooped && Index < LastPoint)));
325 const bool bLoopSegment = (bIsLooped && Index == LastPoint);
326 const int32 NextIndex = bLoopSegment ? 0 : (Index + 1);
327
328 const auto& PrevPoint = Points[Index];
329 const auto& NextPoint = Points[NextIndex];
330
331 const float Diff = bLoopSegment ? LoopKeyOffset : (NextPoint.InVal - PrevPoint.InVal);
332
333 if (Diff > 0.0f && PrevPoint.InterpMode != CIM_Constant)
334 {
335 const float Alpha = (InVal - PrevPoint.InVal) / Diff;
336 check(Alpha >= 0.0f && Alpha <= 1.0f);
337
338 if (PrevPoint.InterpMode == CIM_Linear)
339 {
340 return FMath::Lerp(PrevPoint.OutVal, NextPoint.OutVal, Alpha);
341 }
342 else
343 {
344 return FMath::CubicInterp(PrevPoint.OutVal, PrevPoint.LeaveTangent * Diff, NextPoint.OutVal, NextPoint.ArriveTangent * Diff, Alpha);
345 }
346 }
347 else
348 {
349 return Points[Index].OutVal;
350 }
351}
352
353
354template< class T >
355T FInterpCurve<T>::EvalDerivative(const float InVal, const T& Default) const
356{
357 const int32 NumPoints = Points.Num();
358 const int32 LastPoint = NumPoints - 1;
359
360 // If no point in curve, return the Default value we passed in.
361 if (NumPoints == 0)
362 {
363 return Default;
364 }
365
366 // Binary search to find index of lower bound of input value
367 const int32 Index = GetPointIndexForInputValue(InVal);
368
369 // If before the first point, return its tangent value
370 if (Index == -1)
371 {
372 return Points[0].LeaveTangent;
373 }
374
375 // If on or beyond the last point, return its tangent value.
376 if (Index == LastPoint)
377 {
378 if (!bIsLooped)
379 {
380 return Points[LastPoint].ArriveTangent;
381 }
382 else if (InVal >= Points[LastPoint].InVal + LoopKeyOffset)
383 {
384 // Looped spline: last point is the same as the first point
385 return Points[0].ArriveTangent;
386 }
387 }
388
389 // Somewhere within curve range - interpolate.
390 check(Index >= 0 && ((bIsLooped && Index < NumPoints) || (!bIsLooped && Index < LastPoint)));
391 const bool bLoopSegment = (bIsLooped && Index == LastPoint);
392 const int32 NextIndex = bLoopSegment ? 0 : (Index + 1);
393
394 const auto& PrevPoint = Points[Index];
395 const auto& NextPoint = Points[NextIndex];
396
397 const float Diff = bLoopSegment ? LoopKeyOffset : (NextPoint.InVal - PrevPoint.InVal);
398
399 if (Diff > 0.0f && PrevPoint.InterpMode != CIM_Constant)
400 {
401 if (PrevPoint.InterpMode == CIM_Linear)
402 {
403 return (NextPoint.OutVal - PrevPoint.OutVal) / Diff;
404 }
405 else
406 {
407 const float Alpha = (InVal - PrevPoint.InVal) / Diff;
408 check(Alpha >= 0.0f && Alpha <= 1.0f);
409
410 return FMath::CubicInterpDerivative(PrevPoint.OutVal, PrevPoint.LeaveTangent * Diff, NextPoint.OutVal, NextPoint.ArriveTangent * Diff, Alpha) / Diff;
411 }
412 }
413 else
414 {
415 // Derivative of a constant is zero
416 return T(ForceInit);
417 }
418}
419
420
421template< class T >
422T FInterpCurve<T>::EvalSecondDerivative(const float InVal, const T& Default) const
423{
424 const int32 NumPoints = Points.Num();
425 const int32 LastPoint = NumPoints - 1;
426
427 // If no point in curve, return the Default value we passed in.
428 if (NumPoints == 0)
429 {
430 return Default;
431 }
432
433 // Binary search to find index of lower bound of input value
434 const int32 Index = GetPointIndexForInputValue(InVal);
435
436 // If before the first point, return 0
437 if (Index == -1)
438 {
439 return T(ForceInit);
440 }
441
442 // If on or beyond the last point, return 0
443 if (Index == LastPoint)
444 {
445 if (!bIsLooped || (InVal >= Points[LastPoint].InVal + LoopKeyOffset))
446 {
447 return T(ForceInit);
448 }
449 }
450
451 // Somewhere within curve range - interpolate.
452 check(Index >= 0 && ((bIsLooped && Index < NumPoints) || (!bIsLooped && Index < LastPoint)));
453 const bool bLoopSegment = (bIsLooped && Index == LastPoint);
454 const int32 NextIndex = bLoopSegment ? 0 : (Index + 1);
455
456 const auto& PrevPoint = Points[Index];
457 const auto& NextPoint = Points[NextIndex];
458
459 const float Diff = bLoopSegment ? LoopKeyOffset : (NextPoint.InVal - PrevPoint.InVal);
460
461 if (Diff > 0.0f && PrevPoint.InterpMode != CIM_Constant)
462 {
463 if (PrevPoint.InterpMode == CIM_Linear)
464 {
465 // No change in tangent, return 0.
466 return T(ForceInit);
467 }
468 else
469 {
470 const float Alpha = (InVal - PrevPoint.InVal) / Diff;
471 check(Alpha >= 0.0f && Alpha <= 1.0f);
472
473 return FMath::CubicInterpSecondDerivative(PrevPoint.OutVal, PrevPoint.LeaveTangent * Diff, NextPoint.OutVal, NextPoint.ArriveTangent * Diff, Alpha) / (Diff * Diff);
474 }
475 }
476 else
477 {
478 // Second derivative of a constant is zero
479 return T(ForceInit);
480 }
481}
482
483
484template< class T >
485float FInterpCurve<T>::InaccurateFindNearest(const T &PointInSpace, float& OutDistanceSq) const // LWC_TODO: Precision loss
486{
487 float OutSegment;
488 return InaccurateFindNearest(PointInSpace, OutDistanceSq, OutSegment);
489}
490
491template< class T >
492float FInterpCurve<T>::InaccurateFindNearest(const T &PointInSpace, float& OutDistanceSq, float& OutSegment) const // LWC_TODO: Precision loss
493{
494 const int32 NumPoints = Points.Num();
495 const int32 NumSegments = bIsLooped ? NumPoints : NumPoints - 1;
496
497 if (NumPoints > 1)
498 {
499 float BestDistanceSq;
500 float BestResult = InaccurateFindNearestOnSegment(PointInSpace, 0, BestDistanceSq);
501 float BestSegment = 0;
502 for (int32 Segment = 1; Segment < NumSegments; ++Segment)
503 {
504 float LocalDistanceSq;
505 float LocalResult = InaccurateFindNearestOnSegment(PointInSpace, Segment, LocalDistanceSq);
506 if (LocalDistanceSq < BestDistanceSq)
507 {
508 BestDistanceSq = LocalDistanceSq;
509 BestResult = LocalResult;
510 BestSegment = (float)Segment;
511 }
512 }
513 OutDistanceSq = BestDistanceSq;
514 OutSegment = BestSegment;
515 return BestResult;
516 }
517
518 if (NumPoints == 1)
519 {
520 OutDistanceSq = static_cast<float>((PointInSpace - Points[0].OutVal).SizeSquared());
521 OutSegment = 0;
522 return Points[0].InVal;
523 }
524
525 return 0.0f;
526}
527
528
529template< class T >
530float FInterpCurve<T>::InaccurateFindNearestOnSegment(const T& PointInSpace, int32 PtIdx, float& OutSquaredDistance) const // LWC_TODO: Precision loss
531{
532 const int32 NumPoints = Points.Num();
533 const int32 LastPoint = NumPoints - 1;
534 const int32 NextPtIdx = (bIsLooped && PtIdx == LastPoint) ? 0 : (PtIdx + 1);
535 check(PtIdx >= 0 && ((bIsLooped && PtIdx < NumPoints) || (!bIsLooped && PtIdx < LastPoint)));
536
537 const float NextInVal = (bIsLooped && PtIdx == LastPoint) ? (Points[LastPoint].InVal + LoopKeyOffset) : Points[NextPtIdx].InVal;
538
539 if (CIM_Constant == Points[PtIdx].InterpMode)
540 {
541 const float Distance1 = static_cast<float>((Points[PtIdx].OutVal - PointInSpace).SizeSquared());
542 const float Distance2 = static_cast<float>((Points[NextPtIdx].OutVal - PointInSpace).SizeSquared());
543 if (Distance1 < Distance2)
544 {
545 OutSquaredDistance = Distance1;
546 return Points[PtIdx].InVal;
547 }
548 OutSquaredDistance = Distance2;
549 return NextInVal;
550 }
551
552 const float Diff = NextInVal - Points[PtIdx].InVal;
553 if (CIM_Linear == Points[PtIdx].InterpMode)
554 {
555 // like in function: FMath::ClosestPointOnLine
556 const float A = static_cast<float>((Points[PtIdx].OutVal - PointInSpace) | (Points[NextPtIdx].OutVal - Points[PtIdx].OutVal));
557 const float B = static_cast<float>((Points[NextPtIdx].OutVal - Points[PtIdx].OutVal).SizeSquared());
558 const float V = FMath::Clamp(-A / B, 0.f, 1.f);
559 OutSquaredDistance = static_cast<float>((FMath::Lerp(Points[PtIdx].OutVal, Points[NextPtIdx].OutVal, V) - PointInSpace).SizeSquared());
560 return V * Diff + Points[PtIdx].InVal;
561 }
562
563 {
564 const int32 PointsChecked = 3;
565 const int32 IterationNum = 3;
566 const float Scale = 0.75;
567
568 // Newton's methods is repeated 3 times, starting with t = 0, 0.5, 1.
569 float ValuesT[PointsChecked];
570 ValuesT[0] = 0.0f;
571 ValuesT[1] = 0.5f;
572 ValuesT[2] = 1.0f;
573
574 T InitialPoints[PointsChecked];
575 InitialPoints[0] = Points[PtIdx].OutVal;
576 InitialPoints[1] = FMath::CubicInterp(Points[PtIdx].OutVal, Points[PtIdx].LeaveTangent * Diff, Points[NextPtIdx].OutVal, Points[NextPtIdx].ArriveTangent * Diff, ValuesT[1]);
577 InitialPoints[2] = Points[NextPtIdx].OutVal;
578
579 float DistancesSq[PointsChecked];
580
581 for (int32 point = 0; point < PointsChecked; ++point)
582 {
583 //Algorithm explanation: http://permalink.gmane.org/gmane.games.devel.sweng/8285
584 T FoundPoint = InitialPoints[point];
585 float LastMove = 1.0f;
586 for (int32 iter = 0; iter < IterationNum; ++iter)
587 {
588 const T LastBestTangent = FMath::CubicInterpDerivative(Points[PtIdx].OutVal, Points[PtIdx].LeaveTangent * Diff, Points[NextPtIdx].OutVal, Points[NextPtIdx].ArriveTangent * Diff, ValuesT[point]);
589 const T Delta = (PointInSpace - FoundPoint);
590 float Move = static_cast<float>((LastBestTangent | Delta) / LastBestTangent.SizeSquared());
591 Move = FMath::Clamp(Move, -LastMove*Scale, LastMove*Scale);
592 ValuesT[point] += Move;
593 ValuesT[point] = FMath::Clamp(ValuesT[point], 0.0f, 1.0f);
594 LastMove = FMath::Abs(Move);
595 FoundPoint = FMath::CubicInterp(Points[PtIdx].OutVal, Points[PtIdx].LeaveTangent * Diff, Points[NextPtIdx].OutVal, Points[NextPtIdx].ArriveTangent * Diff, ValuesT[point]);
596 }
597 DistancesSq[point] = static_cast<float>((FoundPoint - PointInSpace).SizeSquared());
598 ValuesT[point] = ValuesT[point] * Diff + Points[PtIdx].InVal;
599 }
600
601 if (DistancesSq[0] <= DistancesSq[1] && DistancesSq[0] <= DistancesSq[2])
602 {
603 OutSquaredDistance = DistancesSq[0];
604 return ValuesT[0];
605 }
606 if (DistancesSq[1] <= DistancesSq[2])
607 {
608 OutSquaredDistance = DistancesSq[1];
609 return ValuesT[1];
610 }
611 OutSquaredDistance = DistancesSq[2];
612 return ValuesT[2];
613 }
614}
615
616
617template< class T >
618void FInterpCurve<T>::AutoSetTangents(float Tension, bool bStationaryEndpoints)
619{
620 const int32 NumPoints = Points.Num();
621 const int32 LastPoint = NumPoints - 1;
622
623 // Iterate over all points in this InterpCurve
624 for (int32 PointIndex = 0; PointIndex < NumPoints; PointIndex++)
625 {
626 const int32 PrevIndex = (PointIndex == 0) ? (bIsLooped ? LastPoint : 0) : (PointIndex - 1);
627 const int32 NextIndex = (PointIndex == LastPoint) ? (bIsLooped ? 0 : LastPoint) : (PointIndex + 1);
628
629 auto& ThisPoint = Points[PointIndex];
630 const auto& PrevPoint = Points[PrevIndex];
631 const auto& NextPoint = Points[NextIndex];
632
633 if (ThisPoint.InterpMode == CIM_CurveAuto || ThisPoint.InterpMode == CIM_CurveAutoClamped)
634 {
635 if (bStationaryEndpoints && (PointIndex == 0 || (PointIndex == LastPoint && !bIsLooped)))
636 {
637 // Start and end points get zero tangents if bStationaryEndpoints is true
638 ThisPoint.ArriveTangent = T(ForceInit);
639 ThisPoint.LeaveTangent = T(ForceInit);
640 }
641 else if (PrevPoint.IsCurveKey())
642 {
643 const bool bWantClamping = (ThisPoint.InterpMode == CIM_CurveAutoClamped);
644 T Tangent;
645
646 const float PrevTime = (bIsLooped && PointIndex == 0) ? (ThisPoint.InVal - LoopKeyOffset) : PrevPoint.InVal;
647 const float NextTime = (bIsLooped && PointIndex == LastPoint) ? (ThisPoint.InVal + LoopKeyOffset) : NextPoint.InVal;
648
649 ComputeCurveTangent(
650 PrevTime, // Previous time
651 PrevPoint.OutVal, // Previous point
652 ThisPoint.InVal, // Current time
653 ThisPoint.OutVal, // Current point
654 NextTime, // Next time
655 NextPoint.OutVal, // Next point
656 Tension, // Tension
657 bWantClamping, // Want clamping?
658 Tangent); // Out
659
660 ThisPoint.ArriveTangent = Tangent;
661 ThisPoint.LeaveTangent = Tangent;
662 }
663 else
664 {
665 // Following on from a line or constant; set curve tangent equal to that so there are no discontinuities
666 ThisPoint.ArriveTangent = PrevPoint.ArriveTangent;
667 ThisPoint.LeaveTangent = PrevPoint.LeaveTangent;
668 }
669 }
670 else if (ThisPoint.InterpMode == CIM_Linear)
671 {
672 T Tangent = NextPoint.OutVal - ThisPoint.OutVal;
673 ThisPoint.ArriveTangent = Tangent;
674 ThisPoint.LeaveTangent = Tangent;
675 }
676 else if (ThisPoint.InterpMode == CIM_Constant)
677 {
678 ThisPoint.ArriveTangent = T(ForceInit);
679 ThisPoint.LeaveTangent = T(ForceInit);
680 }
681 }
682}
683
684
685template< class T >
686void FInterpCurve<T>::CalcBounds(T& OutMin, T& OutMax, const T& Default) const
687{
688 const int32 NumPoints = Points.Num();
689
690 if (NumPoints == 0)
691 {
692 OutMin = Default;
693 OutMax = Default;
694 }
695 else if (NumPoints == 1)
696 {
697 OutMin = Points[0].OutVal;
698 OutMax = Points[0].OutVal;
699 }
700 else
701 {
702 OutMin = Points[0].OutVal;
703 OutMax = Points[0].OutVal;
704
705 const int32 NumSegments = bIsLooped ? NumPoints : (NumPoints - 1);
706
707 for (int32 Index = 0; Index < NumSegments; Index++)
708 {
709 const int32 NextIndex = (Index == NumPoints - 1) ? 0 : (Index + 1);
710 CurveFindIntervalBounds(Points[Index], Points[NextIndex], OutMin, OutMax, 0.0f);
711 }
712 }
713}
714
715
716
717/* Common type definitions
718 *****************************************************************************/
719
720#define DEFINE_INTERPCURVE_WRAPPER_STRUCT(Name, ElementType)
721 struct Name : FInterpCurve<ElementType>
722 {
723 private:
724 typedef FInterpCurve<ElementType> Super;
725
726 public:
727 Name()
728 : Super()
729 {
730 }
731
732 Name(const Super& Other)
733 : Super( Other )
734 {
735 }
736 };
737
738 template <>
739 struct TIsBitwiseConstructible<Name, FInterpCurve<ElementType>>
740 {
741 enum { Value = true };
742 };
743
744 template <>
745 struct TIsBitwiseConstructible<FInterpCurve<ElementType>, Name>
746 {
747 enum { Value = true };
748 };
749
750DEFINE_INTERPCURVE_WRAPPER_STRUCT(FInterpCurveFloat, float)
751DEFINE_INTERPCURVE_WRAPPER_STRUCT(FInterpCurveVector2D, FVector2D)
752DEFINE_INTERPCURVE_WRAPPER_STRUCT(FInterpCurveVector, FVector)
753DEFINE_INTERPCURVE_WRAPPER_STRUCT(FInterpCurveQuat, FQuat)
754DEFINE_INTERPCURVE_WRAPPER_STRUCT(FInterpCurveTwoVectors, FTwoVectors)
755DEFINE_INTERPCURVE_WRAPPER_STRUCT(FInterpCurveLinearColor, FLinearColor)
#define check(expr)
@ ForceInit
#define DEFINE_INTERPCURVE_WRAPPER_STRUCT(Name, ElementType)
void SetLoopKey(float InLoopKey)
void ClearLoopKey()
int32 GetPointIndexForInputValue(const float InValue) const
void CalcBounds(T &OutMin, T &OutMax, const T &Default=T(ForceInit)) const
float InaccurateFindNearest(const T &PointInSpace, float &OutDistanceSq) const
T Eval(const float InVal, const T &Default=T(ForceInit)) const
float LoopKeyOffset
Definition InterpCurve.h:34
friend bool operator==(const FInterpCurve &Curve1, const FInterpCurve &Curve2)
friend bool operator!=(const FInterpCurve &Curve1, const FInterpCurve &Curve2)
TArray< FInterpCurvePoint< T > > Points
Definition InterpCurve.h:28
float InaccurateFindNearest(const T &PointInSpace, float &OutDistanceSq, float &OutSegment) const
T EvalDerivative(const float InVal, const T &Default=T(ForceInit)) const
T EvalSecondDerivative(const float InVal, const T &Default=T(ForceInit)) const
float InaccurateFindNearestOnSegment(const T &PointInSpace, int32 PtIdx, float &OutSquaredDistance) const
int32 MovePoint(int32 PointIndex, float NewInVal)
int32 AddPoint(const float InVal, const T &OutVal)
void AutoSetTangents(float Tension=0.0f, bool bStationaryEndpoints=true)