Skip to content

Commit ecf2279

Browse files
authored
add remap_default (issue 1157) (#1216)
New Features Added remap_default() — safely remaps numeric values between ranges, returning a provided fallback when the result would be infinite or NaN. Documentation Documented remap_default() with signature, behavior notes, and usage examples; updated remap entry to reference the safer variant. Tests Added tests covering remap_default() across types, edge cases, infinities and NaN.
1 parent 4a38717 commit ecf2279

4 files changed

Lines changed: 46 additions & 1 deletion

File tree

core/variant/variant_utility.cpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
#include "variant_utility.h"
3434

3535
#include "core/io/marshalls.h"
36+
#include "core/math/math_funcs.h"
3637
#include "core/object/ref_counted.h"
3738
#include "core/object/script_language.h"
3839
#include "core/os/os.h"
@@ -556,6 +557,15 @@ double VariantUtilityFunctions::remap(double value, double istart, double istop,
556557
return Math::remap(value, istart, istop, ostart, ostop);
557558
}
558559

560+
double VariantUtilityFunctions::remap_default(double value, double istart, double istop, double ostart, double ostop, double default_value) {
561+
double result = Math::remap(value, istart, istop, ostart, ostop);
562+
if (Math::is_finite(result)) {
563+
return result;
564+
}
565+
566+
return default_value;
567+
}
568+
559569
double VariantUtilityFunctions::smoothstep(double from, double to, double val) {
560570
return Math::smoothstep(from, to, val);
561571
}
@@ -1745,6 +1755,7 @@ void Variant::_register_variant_utility_functions() {
17451755
FUNCBINDR(lerp_angle, sarray("from", "to", "weight"), Variant::UTILITY_FUNC_TYPE_MATH);
17461756
FUNCBINDR(inverse_lerp, sarray("from", "to", "weight"), Variant::UTILITY_FUNC_TYPE_MATH);
17471757
FUNCBINDR(remap, sarray("value", "istart", "istop", "ostart", "ostop"), Variant::UTILITY_FUNC_TYPE_MATH);
1758+
FUNCBINDR(remap_default, sarray("value", "istart", "istop", "ostart", "ostop", "default_value"), Variant::UTILITY_FUNC_TYPE_MATH);
17481759

17491760
FUNCBINDR(smoothstep, sarray("from", "to", "x"), Variant::UTILITY_FUNC_TYPE_MATH);
17501761
FUNCBINDR(move_toward, sarray("from", "to", "delta"), Variant::UTILITY_FUNC_TYPE_MATH);

core/variant/variant_utility.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,7 @@ struct VariantUtilityFunctions {
9595
static double lerp_angle(double from, double to, double weight);
9696
static double inverse_lerp(double from, double to, double weight);
9797
static double remap(double value, double istart, double istop, double ostart, double ostop);
98+
static double remap_default(double value, double istart, double istop, double ostart, double ostop, double default_value);
9899
static double smoothstep(double from, double to, double val);
99100
static double move_toward(double from, double to, double delta);
100101
static double rotate_toward(double from, double to, double delta);

doc/classes/@GlobalScope.xml

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1102,7 +1102,24 @@
11021102
remap(75, 0, 100, -1, 1) # Returns 0.5
11031103
[/codeblock]
11041104
For complex use cases where multiple ranges are needed, consider using [Curve] or [Gradient] instead.
1105-
[b]Note:[/b] If [code]istart == istop[/code], the return value is undefined (most likely NaN, INF, or -INF).
1105+
[b]Note:[/b] If [code]istart == istop[/code], the return value is undefined (most likely NaN, INF, or -INF). See also [method remap_default].
1106+
</description>
1107+
</method>
1108+
<method name="remap_default" keywords="range, lerp, interpolate">
1109+
<return type="float" />
1110+
<param index="0" name="value" type="float" />
1111+
<param index="1" name="istart" type="float" />
1112+
<param index="2" name="istop" type="float" />
1113+
<param index="3" name="ostart" type="float" />
1114+
<param index="4" name="ostop" type="float" />
1115+
<param index="5" name="default_value" type="float" />
1116+
<description>
1117+
Maps a [param value] from range [code][istart, istop][/code] to [code][ostart, ostop][/code] and returns [param default_value] if [method remap] would've returned [code]INF[/code] or [code]NAN[/code]. See also [method remap], [method lerp] and [method inverse_lerp]. If [param value] is outside [code][istart, istop][/code], then the resulting value will also be outside [code][ostart, ostop][/code]. If this is not desired, use [method clamp] on the result of this function.
1118+
[codeblock]
1119+
remap_default(75, 0, 100, -1, 1, 3) # Returns 0.5
1120+
remap_default(75, 0, 0, -1, 1, 3) # Returns 3.0
1121+
[/codeblock]
1122+
For complex use cases where multiple ranges are needed, consider using [Curve] or [Gradient] instead.
11061123
</description>
11071124
</method>
11081125
<method name="rid_allocate_id">

tests/core/variant/test_variant_utility.h

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232

3333
#pragma once
3434

35+
#include "core/math/math_defs.h"
3536
#include "core/variant/variant_utility.h"
3637

3738
#include "tests/test_macros.h"
@@ -130,4 +131,19 @@ TEST_CASE("[VariantUtility] Type conversion") {
130131
}
131132
}
132133

134+
TEST_CASE_TEMPLATE("[VariantUtility] remap_default", T, float, double) {
135+
CHECK(VariantUtilityFunctions::remap_default(150.0, 100.0, 200.0, 0.0, 1000.0, -99.0) == doctest::Approx(500.0));
136+
CHECK(VariantUtilityFunctions::remap_default(250.0, 100.0, 200.0, 0.0, 1000.0, -99.0) == doctest::Approx(1500.0));
137+
CHECK(VariantUtilityFunctions::remap_default(-50.0, -100.0, 0.0, 0.0, 100.0, -99.0) == doctest::Approx(50.0));
138+
139+
CHECK(VariantUtilityFunctions::remap_default(150.0, 100.0, 100.0, 0.0, 1000.0, -99.0) == doctest::Approx(-99.0));
140+
CHECK(VariantUtilityFunctions::remap_default(100.0, 100.0, 100.0, 0.0, 1000.0, -99.0) == doctest::Approx(-99.0));
141+
142+
CHECK(VariantUtilityFunctions::remap_default(INFINITY, 100.0, 200.0, 0.0, 1000.0, -99.0) == doctest::Approx(-99.0));
143+
CHECK(VariantUtilityFunctions::remap_default(NAN, 100.0, 200.0, 0.0, 1000.0, -99.0) == doctest::Approx(-99.0));
144+
CHECK(VariantUtilityFunctions::remap_default(150.0, 100.0, 200.0, NAN, 1000.0, -99.0) == doctest::Approx(-99.0));
145+
146+
CHECK(VariantUtilityFunctions::remap_default(150.0, 100.0, INFINITY, 0.0, 1000.0, -99.0) == doctest::Approx(0.0));
147+
CHECK(VariantUtilityFunctions::remap_default(150.0, 100.0, INFINITY, 50.0, 1000.0, -99.0) == doctest::Approx(50.0));
148+
}
133149
} // namespace TestVariantUtility

0 commit comments

Comments
 (0)