Jamba C++ API  4.4.0
Lerp.h
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2018-2019 pongasoft
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License"); you may not
5  * use this file except in compliance with the License. You may obtain a copy of
6  * the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12  * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13  * License for the specific language governing permissions and limitations under
14  * the License.
15  *
16  * @author Yan Pujante
17  */
18 #pragma once
19 
20 #include "Misc.h"
21 
22 namespace pongasoft::Utils {
23 
30 template <typename TFloat, typename X, typename Y>
31 class Lerp
32 {
33 public:
34  Lerp(X iX1, Y iY1, X iX2, Y iY2) :
35  fA((static_cast<TFloat>(iY1 - iY2)) / (static_cast<TFloat>(iX1 - iX2))),
36  fB(static_cast<TFloat>(iY1) - fA * static_cast<TFloat>(iX1)) {}
37 
41  Lerp(Y iY0, Y iY1) : fA(static_cast<TFloat>(iY1 - iY0)), fB(static_cast<TFloat>(iY0)) {};
42 
43  inline Y computeY(X iX) const
44  {
45  return static_cast<Y>((static_cast<TFloat>(iX) * fA) + fB);
46  }
47 
48  inline X computeX(Y iY) const
49  {
50  DCHECK_F(fA != 0);
51  return static_cast<X>((static_cast<TFloat>(iY) - fB) / fA);
52  }
53 
59  static inline Lerp mapRange(X iFromLow, X iFromHigh, Y iToLow, Y iToHigh)
60  {
61  return Lerp(iFromLow, iToLow, iFromHigh, iToHigh);
62  }
63 
79  static Y mapValue(X iValue, X iFromLow, X iFromHigh, Y iToLow, Y iToHigh, bool iClamp = true)
80  {
81  // if the first range is empty (computation would be dividing by 0)
82  if(iFromLow == iFromHigh)
83  return iValue <= iFromLow ? iToLow : iToHigh;
84 
85  // if the second range is empty, no need for computation
86  if(iToLow == iToHigh)
87  return iToLow;
88 
89  if(iClamp)
90  {
91  iValue = clampRange(iValue, iFromLow, iFromHigh);
92  }
93 
94  return Lerp(iFromLow, iToLow, iFromHigh, iToHigh).computeY(iValue);
95  }
96 
97 private:
98  const TFloat fA;
99  const TFloat fB;
100 };
101 
102 //------------------------------------------------------------------------
103 // SPLerp - Single Precision Lerp (float)
104 //------------------------------------------------------------------------
105 template<typename X, typename Y>
107 
108 template<typename X>
110 
111 template<typename Y>
113 
115 
118 template<typename X, typename Y>
119 static inline SPLerpXY<X, Y> mapRangeSPXY(X iFromLow, X iFromHigh, Y iToLow, Y iToHigh)
120 {
121  return SPLerpXY<X, Y>(iFromLow, iToLow, iFromHigh, iToHigh);
122 }
123 
124 template<typename Y>
125 constexpr auto mapRangeSPY = mapRangeSPXY<float, Y>;
126 
127 template<typename X>
128 constexpr auto mapRangeSPX = mapRangeSPXY<X, float>;
129 
130 constexpr auto mapRangeSP = mapRangeSPXY<float, float>;
131 
134 template<typename X, typename Y>
135 inline static Y mapValueSPXY(X iValue, X iFromLow, X iFromHigh, Y iToLow, Y iToHigh, bool iClamp = true)
136 {
137  return SPLerpXY<X, Y>::mapValue(iValue, iFromLow, iFromHigh, iToLow, iToHigh, iClamp);
138 }
139 
142 template<typename Y>
143 inline static Y mapValueSPY(float iValue, float iFromLow, float iFromHigh, Y iToLow, Y iToHigh, bool iClamp = true)
144 {
145  return SPLerpY<Y>::mapValue(iValue, iFromLow, iFromHigh, iToLow, iToHigh, iClamp);
146 }
147 
150 template<typename X>
151 inline static float mapValueSPX(X iValue, X iFromLow, X iFromHigh, float iToLow, float iToHigh, bool iClamp = true)
152 {
153  return SPLerpX<X>::mapValue(iValue, iFromLow, iFromHigh, iToLow, iToHigh, iClamp);
154 }
155 
158 inline static float mapValueSP(float iValue, float iFromLow, float iFromHigh, float iToLow, float iToHigh, bool iClamp = true)
159 {
160  return SPLerp::mapValue(iValue, iFromLow, iFromHigh, iToLow, iToHigh, iClamp);
161 }
162 
163 
164 //------------------------------------------------------------------------
165 // DPLerp - Double Precision Lerp (double)
166 //------------------------------------------------------------------------
167 template<typename X, typename Y>
169 
170 template<typename X>
172 
173 template<typename Y>
175 
177 
180 template<typename X, typename Y>
181 static inline DPLerpXY<X, Y> mapRangeDPXY(X iFromLow, X iFromHigh, Y iToLow, Y iToHigh)
182 {
183  return DPLerpXY<X, Y>(iFromLow, iToLow, iFromHigh, iToHigh);
184 }
185 
186 template<typename Y>
187 constexpr auto mapRangeDPY = mapRangeDPXY<double, Y>;
188 
189 template<typename X>
190 constexpr auto mapRangeDPX = mapRangeDPXY<X, double>;
191 
192 constexpr auto mapRangeDP = mapRangeDPXY<double, double>;
193 
196 template<typename X, typename Y>
197 inline static Y mapValueDPXY(X iValue, X iFromLow, X iFromHigh, Y iToLow, Y iToHigh, bool iClamp = true)
198 {
199  return DPLerpXY<X, Y>::mapValue(iValue, iFromLow, iFromHigh, iToLow, iToHigh, iClamp);
200 }
201 
204 template<typename Y>
205 inline static Y mapValueDPY(double iValue, double iFromLow, double iFromHigh, Y iToLow, Y iToHigh, bool iClamp = true)
206 {
207  return DPLerpY<Y>::mapValue(iValue, iFromLow, iFromHigh, iToLow, iToHigh, iClamp);
208 }
209 
212 template<typename X>
213 inline static double mapValueDPX(X iValue, X iFromLow, X iFromHigh, double iToLow, double iToHigh, bool iClamp = true)
214 {
215  return DPLerpX<X>::mapValue(iValue, iFromLow, iFromHigh, iToLow, iToHigh, iClamp);
216 }
217 
220 inline static double mapValueDP(double iValue, double iFromLow, double iFromHigh, double iToLow, double iToHigh, bool iClamp = true)
221 {
222  return DPLerp::mapValue(iValue, iFromLow, iFromHigh, iToLow, iToHigh, iClamp);
223 }
224 
228 template<typename T>
229 struct Range
230 {
233  using value_type = T;
234 
235  // Empty constructor (no range)
236  Range() = default;
237 
238  // Single value range
239  explicit Range(T iValue) noexcept : fFrom{iValue}, fTo{iValue} {}
240 
241  // Constructor
242  Range(T iFrom, T iTo) : fFrom{iFrom}, fTo{iTo} {}
243 
244  // return true if the range is a single value (aka degenerate range)
245  bool isSingleValue() const { return fFrom == fTo; }
246 
257  bool contains(T iValue) const
258  {
259  if(fFrom < fTo)
260  return iValue >= fFrom && iValue <= fTo;
261  else
262  return iValue <= fFrom && iValue >= fTo;
263  }
264 
270  T clamp(T iValue) const
271  {
272  return Utils::clampRange(iValue, fFrom, fTo);
273  }
274 
283  template<typename U, typename TLerp = DPLerpXY<T, U>>
284  inline U mapValue(T iValue, Range<U> const &iRange, bool iClampToRange = true) const
285  {
286  return TLerp::mapValue(iValue, fFrom, fTo, iRange.fFrom, iRange.fTo, iClampToRange);
287  }
288 
295  template<typename U, typename TLerp = DPLerpXY<T, U>>
296  inline Range<U> mapRange(Range<U> const &iRange) const
297  {
298  // obviously *this* range is already clamped...
299  return mapSubRange<U,TLerp>(*this, iRange, true);
300  }
301 
310  template<typename U, typename TLerp = DPLerpXY<T, U>>
311  inline Range<U> mapSubRange(Range<T> const &iSubRange, Range<U> const &iRange, bool iClampToRange = true) const
312  {
314  return Range<U>{mapValue<U,TLerp>(iSubRange.fFrom, iRange, iClampToRange),
315  mapValue<U,TLerp>(iSubRange.fTo, iRange, iClampToRange)};
316  }
317 
321  template<typename U>
322  inline Range<U> cast() const
323  {
324  return Range<U>{static_cast<U>(fFrom), static_cast<U>(fTo)};
325  }
326 
327  // operator==
328  bool operator==(const Range &rhs) const
329  {
330  return fFrom == rhs.fFrom && fTo == rhs.fTo;
331  }
332 
333  // operator!=
334  bool operator!=(const Range &rhs) const
335  {
336  return !(rhs == *this);
337  }
338 
339 public:
340  T fFrom{};
341  T fTo{};
342 };
343 
344 }
T clamp(T iValue) const
Clamp the value to this range.
Definition: Lerp.h:270
static SPLerpXY< X, Y > mapRangeSPXY(X iFromLow, X iFromHigh, Y iToLow, Y iToHigh)
Convenient shortcut for single precision.
Definition: Lerp.h:119
Defines a range of values.
Definition: Lerp.h:229
static Y mapValue(X iValue, X iFromLow, X iFromHigh, Y iToLow, Y iToHigh, bool iClamp=true)
Inspired by the map function in Processing language, another way to look at Lerp is to map a range of...
Definition: Lerp.h:79
static double mapValueDP(double iValue, double iFromLow, double iFromHigh, double iToLow, double iToHigh, bool iClamp=true)
Convenient shortcut for single precision.
Definition: Lerp.h:220
T fTo
Definition: Lerp.h:341
bool operator!=(const Range &rhs) const
Definition: Lerp.h:334
bool operator==(const Range &rhs) const
Definition: Lerp.h:328
static Lerp mapRange(X iFromLow, X iFromHigh, Y iToLow, Y iToHigh)
Inspired by the map function in Processing language, another way to look at Lerp is to map a range of...
Definition: Lerp.h:59
Definition: CircularBuffer.h:25
static DPLerpXY< X, Y > mapRangeDPXY(X iFromLow, X iFromHigh, Y iToLow, Y iToHigh)
Convenient shortcut for double precision.
Definition: Lerp.h:181
bool isSingleValue() const
Definition: Lerp.h:245
static T clampRange(const U &iValue, const T &iFrom, const T &iTo)
Make sure that the value remains within its bounds.
Definition: Misc.h:44
constexpr auto mapRangeSPY
Definition: Lerp.h:125
Lerp(Y iY0, Y iY1)
Shortcut for when x=0 => iY0 and x=1.0 => iY1.
Definition: Lerp.h:41
static float mapValueSP(float iValue, float iFromLow, float iFromHigh, float iToLow, float iToHigh, bool iClamp=true)
Convenient shortcut for single precision.
Definition: Lerp.h:158
Range< U > cast() const
Cast this range to another one.
Definition: Lerp.h:322
static double mapValueDPX(X iValue, X iFromLow, X iFromHigh, double iToLow, double iToHigh, bool iClamp=true)
Convenient shortcut for single precision.
Definition: Lerp.h:213
Range< U > mapSubRange(Range< T > const &iSubRange, Range< U > const &iRange, bool iClampToRange=true) const
Map a sub range of this range to the other range.
Definition: Lerp.h:311
const TFloat fA
Definition: Lerp.h:98
constexpr auto mapRangeSP
Definition: Lerp.h:130
static Y mapValueDPXY(X iValue, X iFromLow, X iFromHigh, Y iToLow, Y iToHigh, bool iClamp=true)
Convenient shortcut for single precision.
Definition: Lerp.h:197
constexpr auto mapRangeDP
Definition: Lerp.h:192
CCoord value_type
Gives access to the type of elements in the range.
Definition: Lerp.h:233
Util class to compute linear interpolation.
Definition: Lerp.h:31
bool contains(T iValue) const
This method assumes that fFrom and fTo are part of the range or another way to put it:
Definition: Lerp.h:257
static Y mapValueDPY(double iValue, double iFromLow, double iFromHigh, Y iToLow, Y iToHigh, bool iClamp=true)
Convenient shortcut for single precision.
Definition: Lerp.h:205
T fFrom
Definition: Lerp.h:340
static Y mapValueSPXY(X iValue, X iFromLow, X iFromHigh, Y iToLow, Y iToHigh, bool iClamp=true)
Convenient shortcut for single precision.
Definition: Lerp.h:135
constexpr auto mapRangeSPX
Definition: Lerp.h:128
Lerp(X iX1, Y iY1, X iX2, Y iY2)
Definition: Lerp.h:34
static float mapValueSPX(X iValue, X iFromLow, X iFromHigh, float iToLow, float iToHigh, bool iClamp=true)
Convenient shortcut for single precision.
Definition: Lerp.h:151
Range(T iFrom, T iTo)
Definition: Lerp.h:242
Range(T iValue) noexcept
Definition: Lerp.h:239
U mapValue(T iValue, Range< U > const &iRange, bool iClampToRange=true) const
Map the value from this range into the provide range.
Definition: Lerp.h:284
Y computeY(X iX) const
Definition: Lerp.h:43
X computeX(Y iY) const
Definition: Lerp.h:48
static Y mapValueSPY(float iValue, float iFromLow, float iFromHigh, Y iToLow, Y iToHigh, bool iClamp=true)
Convenient shortcut for single precision.
Definition: Lerp.h:143
Range< U > mapRange(Range< U > const &iRange) const
Map this range to the other range.
Definition: Lerp.h:296
constexpr auto mapRangeDPX
Definition: Lerp.h:190
const TFloat fB
Definition: Lerp.h:99
constexpr auto mapRangeDPY
Definition: Lerp.h:187