Skip to content

Add a constrained parameter to map_range() #2

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 6 commits into from
Apr 14, 2021
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
56 changes: 44 additions & 12 deletions adafruit_simplemath.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,22 +24,49 @@


def map_range(
x: float, in_min: float, in_max: float, out_min: float, out_max: float
x: float,
in_min: float,
in_max: float,
out_min: float,
out_max: float,
constrained: bool = True,
) -> float:
"""
Maps a number from one range to another. Somewhat similar to the Arduino ``map()`` function,
but returns a floating point result, and constrains the output value to be between
``out_min`` and ``out_max``.
If ``in_min`` is greater than ``in_max`` or ``out_min`` is greater than ``out_max``,
the corresponding range is reversed, allowing, for example, mapping a range of 0-10 to 50-0.
Maps a number from one range to another. Somewhat similar to the Arduino
:attr:`map()` function, but returns a floating point result, and
optionally constrains the output value to be between :attr:`out_min` and
:attr:`out_max`. If :attr:`in_min` is greater than :attr:`in_max` or
:attr:`out_min` is greater than :attr:`out_max`, the corresponding range
is reversed, allowing, for example, mapping a range of 0-10 to 50-0.

.. code-block::

from adafruit_simplemath import map_range

percent = 23
screen_width = 320 # or board.DISPLAY.width
x = map_range(percent, 0, 100, 0, screen_width - 1)
print("X position", percent, "% from the left of screen is", x)

celsius = 20
fahrenheit = map_range(celsius, 0, 100, 32, 212, constrained=False)
print(celsius, "degress Celsius =", fahrenheit, "degrees Fahrenheit")

celsius = -20
fahrenheit = map_range(celsius, 0, 100, 32, 212, False)
print(celsius, "degress Celsius =", fahrenheit, "degrees Fahrenheit")

:param float x: Value to convert
:param float in_min: Start value of input range.
:param float in_max: End value of input range.
:param float out_min: Start value of output range.
:param float out_max: End value of output range.
:param bool constrained: Whether the output value should be constrained
between :attr:`out_min` and :attr:`out_max`. Defaults to `True`.
:return: Returns value mapped to new range.
:rtype: float
"""
# pylint: disable=too-many-arguments
in_range = in_max - in_min
in_delta = x - in_min
if in_range != 0:
Expand All @@ -50,19 +77,24 @@ def map_range(
mapped = 0.5
mapped *= out_max - out_min
mapped += out_min

if not constrained:
return mapped
if out_min <= out_max:
return max(min(mapped, out_max), out_min)
return min(max(mapped, out_max), out_min)


def constrain(x: float, out_min: float, out_max: float) -> float:
"""Constrains ``x`` to be within the inclusive range [``out_min``, ``out_max``].
Sometimes called ``clip`` or ``clamp`` in other libraries.
``out_min`` should be less than or equal to ``out_max``.
If ``x`` is less than ``out_min``, return ``out_min``.
If ``x`` is greater than ``out_max``, return ``out_max``.
Otherwise just return ``x``.
"""Constrains :attr:`x` to be within the inclusive range
[:attr:`out_min`, :attr:`out_max`]. Sometimes called :attr:`clip` or
:attr:`clamp` in other libraries. :attr:`out_min` should be less than or
equal to :attr:`out_max`.
If :attr:`x` is less than :attr:`out_min`, return :attr:`out_min`.
If :attr:`x` is greater than :attr:`out_max`, return :attr:`out_max`.
Otherwise just return :attr:`x`.

:param float x: Value to constrain
:param float out_min: Lower bound of output range.
:param float out_max: Upper bound of output range.
:return: Returns value constrained to given range.
Expand Down
44 changes: 40 additions & 4 deletions examples/simplemath_simpletest.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,46 @@

from adafruit_simplemath import map_range, constrain

print("map_range() examples")
# Map, say, a sensor value, from a range of 0-255 to 0-1023.
print(map_range(30, 0, 255, 0, 1023))
sensor_input_value = 30
sensor_converted_value = map_range(sensor_input_value, 0, 255, 0, 1023)
print(
"Sensor input value:",
sensor_input_value,
"Converted value:",
sensor_converted_value,
)

percent = 23
screen_width = 320 # or board.DISPLAY.width
x = map_range(percent, 0, 100, 0, screen_width - 1)
print("X position", percent, "% from the left of screen is", x)

celsius = 20
fahrenheit = map_range(celsius, 0, 100, 32, 212, constrained=False)
print(celsius, "degress Celsius =", fahrenheit, "degrees Fahrenheit")

celsius = -20
fahrenheit = map_range(celsius, 0, 100, 32, 212, False)
print(celsius, "degress Celsius =", fahrenheit, "degrees Fahrenheit")

print("constrain() examples")
# Constrain a value to a range.
print(constrain(0, 1, 3)) # prints 1
print(constrain(4, 1, 3)) # prints 3
print(constrain(2, 2, 3)) # prints 2
def constrain_example(value, min_value, max_value):
constrained_value = constrain(value, min_value, max_value)
print(
"Constrain",
value,
"between [",
min_value,
"and",
max_value,
"] gives",
constrained_value,
)


constrain_example(0, 1, 3) # expects 1
constrain_example(4, 1, 3) # expects 3
constrain_example(2, 2, 3) # expects 2
3 changes: 3 additions & 0 deletions tests/map_range_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,6 @@ def test_map_range():
assert map_range(1, 10, 0, 0, 5) == 4.5
assert map_range(1, 0, 10, 10, 0) == 9.0
assert map_range(10, 1, 10, 1, 20) == 20.0
assert map_range(392, 32, 212, 0, 100) == 100.0
assert map_range(392, 32, 212, 0, 100, constrained=True) == 100.0
assert map_range(392, 32, 212, 0, 100, constrained=False) == 200.0