Skip to content
Open
Show file tree
Hide file tree
Changes from all 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
19 changes: 8 additions & 11 deletions crates/processing_pyo3/mewnala/__init__.py
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
from .mewnala import *

# re-export the native submodules as submodules of this module, if they exist
# this allows users to import from `mewnala.math` and `mewnala.color`
# if they exist, without needing to know about the internal structure of the native module
import sys as _sys
from . import mewnala as _native
for _name in ("math", "color"):
_sub = getattr(_native, _name, None)
if _sub is not None:
_sys.modules[f"{__name__}.{_name}"] = _sub

_color = getattr(_native, "color", None)
if _color is not None:
_sys.modules[f"{__name__}.color"] = _color

from . import math # noqa: E402 (Python submodule, extends native math)
from .math import * # noqa: E402,F401,F403

# global var handling. for wildcard import of our module, we copy into globals, otherwise
# we dispatch to get attr and call the underlying getter method
# we dispatch to get attr and call the underlying getter method

_DYNAMIC_GRAPHICS_ATTRS = (
"width",
Expand Down Expand Up @@ -69,6 +69,3 @@ def __getattr__(name):

def __dir__():
return sorted(set(list(globals().keys()) + list(_DYNAMIC)))


del _sys, _name, _sub
69 changes: 69 additions & 0 deletions crates/processing_pyo3/mewnala/math.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
"""Processing math methods and vector/quaternion types."""
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This PR implements the following functions from Processing4:

sin(), cos(), tan(), asin(), acos(), atan(), atan2(), sqrt(), exp(), log(), ceil(), floor(), degrees(), radians(), sq(), pow(), constrain(), lerp(), norm(), map(), mag(), dist()

It's currently missing:

from .mewnala import math as _native_math
from math import (
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do all of these methods behave like their Processing equivalent?

sin, cos, tan,
asin, acos, atan, atan2,
sqrt, exp, log,
ceil, floor,
degrees, radians,
)

Vec2 = _native_math.Vec2
Vec3 = _native_math.Vec3
Vec4 = _native_math.Vec4
Quat = _native_math.Quat
VecIter = _native_math.PyVecIter
vec2 = _native_math.vec2
vec3 = _native_math.vec3
vec4 = _native_math.vec4
quat = _native_math.quat


def sq(x):
return x * x


def pow(base, exponent):
return base ** exponent


def constrain(value, low, high):
if value < low:
return low
if value > high:
return high
return value


def lerp(start, stop, amt):
return start + (stop - start) * amt


def norm(value, start, stop):
return (value - start) / (stop - start)


def remap(value, start1, stop1, start2, stop2):
Copy link
Copy Markdown

@SableRaf SableRaf Apr 25, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not a blocker but we could potentially add the optional 6th argument from p5.js's version of the map() function: map(value, start1, stop1, start2, stop2, [withinBounds]) where withinBounds is a boolean which (if true) makes the function constrain the return value to the newly mapped range.

return start2 + (stop2 - start2) * ((value - start1) / (stop1 - start1))


def mag(*args):
if len(args) == 2:
a, b = args
return sqrt(a * a + b * b)
if len(args) == 3:
a, b, c = args
return sqrt(a * a + b * b + c * c)
raise TypeError(f"mag() takes 2 or 3 arguments ({len(args)} given)")


def dist(*args):
if len(args) == 4:
x1, y1, x2, y2 = args
dx, dy = x2 - x1, y2 - y1
return sqrt(dx * dx + dy * dy)
if len(args) == 6:
x1, y1, z1, x2, y2, z2 = args
dx, dy, dz = x2 - x1, y2 - y1, z2 - z1
return sqrt(dx * dx + dy * dy + dz * dz)
raise TypeError(f"dist() takes 4 or 6 arguments ({len(args)} given)")
Loading