11# SPDX-FileCopyrightText: Copyright (c) 2021 Dan Halbert for Adafruit Industries LLC
2+ # SPDX-FileCopyrightText: 2021 James Carr
23#
34# SPDX-License-Identifier: MIT
45"""
89Math utility functions
910
1011
11- * Author(s): Adafruit Industries
12+ * Author(s): Dan Halbert, James Carr
1213
1314Implementation Notes
1415--------------------
2425
2526
2627def map_range (
27- x : float ,
28- in_min : float ,
29- in_max : float ,
30- out_min : float ,
31- out_max : float ,
32- constrained : bool = True ,
28+ x : float , in_min : float , in_max : float , out_min : float , out_max : float
3329) -> float :
3430 """
3531 Maps a number from one range to another. Somewhat similar to the Arduino
3632 :attr:`map()` function, but returns a floating point result, and
37- optionally constrains the output value to be between :attr:`out_min` and
33+ constrains the output value to be between :attr:`out_min` and
3834 :attr:`out_max`. If :attr:`in_min` is greater than :attr:`in_max` or
3935 :attr:`out_min` is greater than :attr:`out_max`, the corresponding range
4036 is reversed, allowing, for example, mapping a range of 0-10 to 50-0.
4137
38+ See also :py:func:`unconstrained_map_range`
39+
4240 .. code-block::
4341
4442 from adafruit_simplemath import map_range
@@ -48,25 +46,61 @@ def map_range(
4846 x = map_range(percent, 0, 100, 0, screen_width - 1)
4947 print("X position", percent, "% from the left of screen is", x)
5048
51- celsius = 20
52- fahrenheit = map_range(celsius, 0, 100, 32, 212, constrained=False)
53- print(celsius, "degress Celsius =", fahrenheit, "degrees Fahrenheit")
49+ :param float x: Value to convert
50+ :param float in_min: Start value of input range.
51+ :param float in_max: End value of input range.
52+ :param float out_min: Start value of output range.
53+ :param float out_max: End value of output range.
54+ :return: Returns value mapped to new range.
55+ :rtype: float
56+ """
57+ # in_range = in_max - in_min
58+ # in_delta = x - in_min
59+ # if in_range != 0:
60+ # mapped = in_delta / in_range
61+ # elif in_delta != 0:
62+ # mapped = in_delta
63+ # else:
64+ # mapped = 0.5
65+ # mapped *= out_max - out_min
66+ # mapped += out_min
67+
68+ mapped = unconstrained_map_range (x , in_min , in_max , out_min , out_max )
69+
70+ if out_min <= out_max :
71+ return max (min (mapped , out_max ), out_min )
72+ return min (max (mapped , out_max ), out_min )
73+
74+
75+ def unconstrained_map_range (
76+ x : float , in_min : float , in_max : float , out_min : float , out_max : float
77+ ) -> float :
78+ """
79+ Maps a number from one range to another. Somewhat similar to the Arduino
80+ :attr:`map()` function, but returns a floating point result, and
81+ does not constrain the output value to be between :attr:`out_min` and
82+ :attr:`out_max`. If :attr:`in_min` is greater than :attr:`in_max` or
83+ :attr:`out_min` is greater than :attr:`out_max`, the corresponding range
84+ is reversed, allowing, for example, mapping a range of 0-10 to 50-0.
85+
86+ See also :py:func:`map_range`
87+
88+ .. code-block::
89+
90+ from adafruit_simplemath import unconstrained_map_range
5491
5592 celsius = -20
56- fahrenheit = map_range (celsius, 0, 100, 32, 212, False )
93+ fahrenheit = unconstrained_map_range (celsius, 0, 100, 32, 212)
5794 print(celsius, "degress Celsius =", fahrenheit, "degrees Fahrenheit")
5895
5996 :param float x: Value to convert
6097 :param float in_min: Start value of input range.
6198 :param float in_max: End value of input range.
6299 :param float out_min: Start value of output range.
63100 :param float out_max: End value of output range.
64- :param bool constrained: Whether the output value should be constrained
65- between :attr:`out_min` and :attr:`out_max`. Defaults to `True`.
66101 :return: Returns value mapped to new range.
67102 :rtype: float
68103 """
69- # pylint: disable=too-many-arguments
70104 in_range = in_max - in_min
71105 in_delta = x - in_min
72106 if in_range != 0 :
@@ -78,11 +112,7 @@ def map_range(
78112 mapped *= out_max - out_min
79113 mapped += out_min
80114
81- if not constrained :
82- return mapped
83- if out_min <= out_max :
84- return max (min (mapped , out_max ), out_min )
85- return min (max (mapped , out_max ), out_min )
115+ return mapped
86116
87117
88118def constrain (x : float , out_min : float , out_max : float ) -> float :
@@ -93,11 +123,14 @@ def constrain(x: float, out_min: float, out_max: float) -> float:
93123 If :attr:`x` is less than :attr:`out_min`, return :attr:`out_min`.
94124 If :attr:`x` is greater than :attr:`out_max`, return :attr:`out_max`.
95125 Otherwise just return :attr:`x`.
126+ If :attr:`max_value` is less than :attr:`min_value`, they will be swapped.
96127
97128 :param float x: Value to constrain
98129 :param float out_min: Lower bound of output range.
99130 :param float out_max: Upper bound of output range.
100131 :return: Returns value constrained to given range.
101132 :rtype: float
102133 """
103- return max (out_min , min (x , out_max ))
134+ if out_min <= out_max :
135+ return max (min (x , out_max ), out_min )
136+ return min (max (x , out_max ), out_min )
0 commit comments