UDocumentation UE5.7 10.02.2026 (Source)
API documentation for Unreal Engine 5.7
MovieScenePiecewiseCurveUtils.inl
Go to the documentation of this file.
1// Copyright Epic Games, Inc. All Rights Reserved.
2
3#pragma once
4
5#include "Containers/Array.h"
6#include "MovieSceneFwd.h"
9#include "Curves/RichCurve.h"
11
12struct FFrameTime;
13
15{
16
17
18template<typename PiecewiseDataType>
20{
21 using namespace UE::MovieScene;
22
23 const int32 NumPieces = PiecewiseData.NumPieces();
24 const FFrameNumber FiniteSplineStart = PiecewiseData.GetFiniteStart();
25 const FFrameNumber FiniteSplineEnd = PiecewiseData.GetFiniteEnd();
26
27 check(NumPieces > 0 &&
28 StartTime >= FiniteSplineStart && StartTime <= FiniteSplineEnd &&
29 EndTime >= FiniteSplineStart && EndTime <= FiniteSplineEnd
30 );
31
32 // Start at the first key that is less than or equal to the start time (upper bound finds first key >, then we subtract 1)
33 const int32 StartIndex = PiecewiseData.GetIndexOfPieceByTime(StartTime);
34
36
37 for (int32 PieceIndex = StartIndex; PieceIndex >= 0 && PieceIndex < NumPieces; ++PieceIndex)
38 {
40
41 if (Interp.GetRange().Start > EndTime)
42 {
43 break;
44 }
45
46 FFrameTime EvalTime1 = Interp.GetRange().Clamp(StartTime);
47 FFrameTime EvalTime2 = Interp.GetRange().Clamp(EndTime);
48 Extents.Combine(Interp.ComputeExtents(EvalTime1, EvalTime2));
49 }
50
51 return Extents;
52}
53
54template<typename PiecewiseDataType>
56{
57 using namespace UE::MovieScene;
58 using namespace UE::MovieScene::Interpolation;
59
60 if (!ensure(StartTime <= EndTime))
61 {
62 return FInterpolationExtents{ 0, 0, 0, 0 };
63 }
64
65 check(StartTime <= EndTime);
66
67 const int32 NumPieces = PiecewiseData.NumPieces();
68
69 if (NumPieces == 0)
70 {
72 if (PiecewiseData.HasDefaultValue())
73 {
74 Extents.AddPoint(PiecewiseData.GetDefaultValue(), StartTime);
75 Extents.AddPoint(PiecewiseData.GetDefaultValue(), EndTime);
76 }
77
78 return Extents;
79 }
80
83
85
86 // Deal with linear pre-post extrapolation
87 if (PiecewiseData.GetPreExtrapolation() == RCCE_Linear && StartTime.FrameNumber.Value < FiniteSplineStart)
88 {
90 const int32 Min = StartTime.FrameNumber.Value;
91 const int32 Max = FMath::Min(FirstKeyTime, EndTime.FrameNumber.Value);
92
93 const double MinPreExtrap = PiecewiseData.PreExtrapolate(Min);
94 const double MaxPreExtrap = PiecewiseData.PreExtrapolate(Max);
95
96 FinalExtents.AddPoint(MinPreExtrap, Min);
97 FinalExtents.AddPoint(MaxPreExtrap, Max);
98
99 if (EndTime.FrameNumber.Value <= FirstKeyTime)
100 {
101 return FinalExtents;
102 }
103
104 // Clamp to the valid range
105 StartTime = FiniteSplineStart;
106 }
107
108 if (PiecewiseData.GetPostExtrapolation() == RCCE_Linear && EndTime.FrameNumber.Value > FiniteSplineEnd)
109 {
110 const int32 LastKeyTime = FiniteSplineEnd.Value;
111 const int32 Min = FMath::Max(LastKeyTime, StartTime.FrameNumber.Value);
112 const int32 Max = EndTime.FrameNumber.Value;
113
114 const double MinPostExtrap = PiecewiseData.PostExtrapolate(Min);
115 const double MaxPostExtrap = PiecewiseData.PostExtrapolate(Max);
116
117 FinalExtents.AddPoint(MinPostExtrap, Min);
118 FinalExtents.AddPoint(MaxPostExtrap, Max);
119
120 if (StartTime.FrameNumber.Value >= LastKeyTime)
121 {
122 return FinalExtents;
123 }
124
125 // Clamp to the valid range
126 EndTime = FiniteSplineEnd;
127 }
128
131
132 const double StartValue = PiecewiseData.GetStartingValue();
133 const double EndValue = PiecewiseData.GetEndingValue();
134
135 // Deal with offset cycles and oscillation on the start frame
136 if (StartTime < FFrameTime(FiniteSplineStart))
137 {
138 switch (PiecewiseData.GetPreExtrapolation())
139 {
140 case RCCE_Linear: StartCycled.CycleCount = 0; break;
141 case RCCE_Cycle: break;
142 case RCCE_CycleWithOffset: StartCycled.ComputePreValueOffset(StartValue, EndValue); break;
143 case RCCE_Oscillate: StartCycled.Oscillate(FiniteSplineStart.Value, FiniteSplineEnd.Value); break;
144 case RCCE_Constant: StartCycled.Time = FiniteSplineStart; StartCycled.CycleCount = 0; break;
145 case RCCE_None: StartCycled.Time = FiniteSplineStart; StartCycled.CycleCount = 0; break;
146 }
147 }
148 else if (StartTime > FFrameTime(FiniteSplineEnd))
149 {
150 switch (PiecewiseData.GetPostExtrapolation())
151 {
152 case RCCE_Linear: StartCycled.CycleCount = 0; break;
153 case RCCE_Cycle: break;
154 case RCCE_CycleWithOffset: StartCycled.ComputePostValueOffset(StartValue, EndValue); break;
155 case RCCE_Oscillate: StartCycled.Oscillate(FiniteSplineStart.Value, FiniteSplineEnd.Value); break;
156 case RCCE_Constant: StartCycled.Time = FiniteSplineEnd; StartCycled.CycleCount = 0; break;
157 case RCCE_None: StartCycled.Time = FiniteSplineEnd; StartCycled.CycleCount = 0; break;
158 }
159 }
160
161 // Deal with offset cycles and oscillation on the end frame
162 if (EndTime < FFrameTime(FiniteSplineStart))
163 {
164 switch (PiecewiseData.GetPreExtrapolation())
165 {
166 case RCCE_Linear: EndCycled.CycleCount = 0; break;
167 case RCCE_Cycle: break;
168 case RCCE_CycleWithOffset: EndCycled.ComputePreValueOffset(StartValue, EndValue); break;
169 case RCCE_Oscillate: EndCycled.Oscillate(FiniteSplineStart.Value, FiniteSplineEnd.Value); break;
170 case RCCE_Constant: EndCycled.Time = FiniteSplineStart; EndCycled.CycleCount = 0; break;
171 case RCCE_None: EndCycled.Time = FiniteSplineStart; EndCycled.CycleCount = 0; break;
172 }
173 }
174 else if (EndTime > FFrameTime(FiniteSplineEnd))
175 {
176 switch (PiecewiseData.GetPostExtrapolation())
177 {
178 case RCCE_Linear: EndCycled.CycleCount = 0; break;
179 case RCCE_Cycle: break;
180 case RCCE_CycleWithOffset: EndCycled.ComputePostValueOffset(StartValue, EndValue); break;
181 case RCCE_Oscillate: EndCycled.Oscillate(FiniteSplineStart.Value, FiniteSplineEnd.Value); break;
182 case RCCE_Constant: EndCycled.Time = FiniteSplineEnd; EndCycled.CycleCount = 0; break;
183 case RCCE_None: EndCycled.Time = FiniteSplineEnd; EndCycled.CycleCount = 0; break;
184 }
185 }
186
187 if (StartCycled.CycleCount != EndCycled.CycleCount)
188 {
189 const double OffsetPerCycle = (EndValue - StartValue);
191
194 StartCycled.bMirrorCurve ? FiniteSplineStart : StartCycled.Time,
195 StartCycled.bMirrorCurve ? StartCycled.Time : FiniteSplineEnd);
196
198 StartCycleExtents.MaxValue += StartCycled.ValueOffset;
199 StartCycleExtents.MinValueTime += StartCycled.CycleCount * CycleDuration;
200 StartCycleExtents.MaxValueTime += StartCycled.CycleCount * CycleDuration;
201
204 EndCycled.bMirrorCurve ? EndCycled.Time : FiniteSplineStart,
205 EndCycled.bMirrorCurve ? FiniteSplineEnd : EndCycled.Time);
206
207 EndCycleExtents.MinValue += EndCycled.ValueOffset;
208 EndCycleExtents.MaxValue += EndCycled.ValueOffset;
209 EndCycleExtents.MinValueTime += EndCycled.CycleCount * CycleDuration;
210 EndCycleExtents.MaxValueTime += EndCycled.CycleCount * CycleDuration;
211
214
215 if (EndCycled.CycleCount - StartCycled.CycleCount > 1)
216 {
217 const bool bHasPreExtrapCycles = PiecewiseData.GetPreExtrapolation() == RCCE_CycleWithOffset && StartCycled.CycleCount < 0;
218 const bool bHasPostExtrapCycles = PiecewiseData.GetPostExtrapolation() == RCCE_CycleWithOffset && EndCycled.CycleCount > 0;
219
220 const int32 NumFullPreExtrapCycles = bHasPreExtrapCycles ? -(StartCycled.CycleCount - FMath::Min(EndCycled.CycleCount, 0))-1 : 0;
221 const int32 NumFullPostExtrapCycles = bHasPostExtrapCycles ? (EndCycled.CycleCount - FMath::Max(StartCycled.CycleCount, 0))-1 : 0;
222
224
226 {
232 PostExtents.AddPoint(
235
236 PreExtents.AddPoint(
239 PreExtents.AddPoint(
242
243 FullExtents.Combine(PreExtents);
244 FullExtents.Combine(PostExtents);
245 }
246
247 FinalExtents.Combine(FullExtents);
248 }
249 }
250 else if (EndCycled.Time == StartCycled.Time)
251 {
252 double Value = 0.0;
253
255 {
256 Value = PiecewiseData.PreExtrapolate(StartCycled.Time);
257 }
258 else if (StartCycled.Time >= FiniteSplineEnd)
259 {
260 Value = PiecewiseData.PostExtrapolate(StartCycled.Time);
261 }
262 else
263 {
264 PiecewiseData.GetPieceByTime(StartCycled.Time).Evaluate(StartCycled.Time, Value);
265 }
266
267 FInterpolationExtents Extents;
268 Extents.AddPoint(Value, StartTime);
269 return Extents;
270 }
271 else
272 {
273 // Within the same cycle is easy - just compute the extents between the two bounds, and offset by the oscillation amount
276 StartCycled.bMirrorCurve ? EndCycled.Time : StartCycled.Time,
277 StartCycled.bMirrorCurve ? StartCycled.Time : EndCycled.Time);
278
279 Extents.MinValue += StartCycled.ValueOffset;
280 Extents.MaxValue += StartCycled.ValueOffset;
281
282 FinalExtents.Combine(Extents);
283 }
284
285 return FinalExtents;
286}
287
288} // namespace UE::MovieScene::Interpolation
#define check(expr)
Definition AssertionMacros.h:314
#define ensure( InExpression)
Definition AssertionMacros.h:464
FPlatformTypes::int32 int32
A 32-bit signed integer.
Definition Platform.h:1125
UE_FORCEINLINE_HINT TSharedRef< CastToType, Mode > StaticCastSharedRef(TSharedRef< CastFromType, Mode > const &InSharedRef)
Definition SharedPointer.h:127
Definition MovieSceneCurveChannelImpl.h:17
UE::MovieScene::Interpolation::FInterpolationExtents ComputeExtentsWithinBounds(const PiecewiseDataType &PiecewiseData, FFrameTime StartTime, FFrameTime EndTime)
Definition MovieScenePiecewiseCurveUtils.inl:19
UE::MovieScene::Interpolation::FInterpolationExtents ComputePiecewiseExtents(const PiecewiseDataType &PiecewiseData, FFrameTime StartTime, FFrameTime EndTime)
Definition MovieScenePiecewiseCurveUtils.inl:55
Definition ConstraintsManager.h:14
FCycleParams CycleTime(FFrameNumber MinFrame, FFrameNumber MaxFrame, FFrameTime InTime)
Definition MovieSceneCurveChannelImpl.cpp:91
Definition FrameNumber.h:18
int32 Value
Definition FrameNumber.h:77
Definition FrameTime.h:16
FFrameNumber FrameNumber
Definition FrameTime.h:98
Definition MovieSceneChannel.h:60
Definition MovieSceneInterpolation.h:460
Definition MovieSceneInterpolation.h:98
MOVIESCENE_API void AddPoint(double Value, FFrameTime Time)
Definition MovieSceneInterpolation.cpp:15
MOVIESCENE_API void Combine(const FInterpolationExtents &Other)
Definition MovieSceneInterpolation.cpp:29
double MaxValue
Definition MovieSceneInterpolation.h:100
double MinValue
Definition MovieSceneInterpolation.h:99