ExpressionMath (Python)

ExpressionMath is a C++/Python Library that provides access to commonly used graphics functions.

All functions listed below are pre-imported in the context of parameter expressions, so you can use them directly, for example: lerp(0.5, 1, 12)

In a Python tab or shelf script, the functions are available from the ExpressionMath module, for example: ExpressionMath.lerp(0.5, 1, 12)

Utilities

ExpressionMath.ifelse(expression, a, b)

If expression evaluates to True, return object a. Otherwise, return object b.

Warning

BOTH inputs (a and b) are evaluated, no matter what the expression evaluates to. Unfortunately. this is inherent to Python argument handling and is not fixable.

ExpressionMath.clamp(value, a, b)

Return value, clamped between the extremes a and b. It is not necessary for b > a. Mixed scalar / vector inputs are supported for all arguments.

>>> clamp(-0.5, 0.1, 0.9)
0.1
>>> clamp(-0.5, 0.9, 0.1)
0.1
>>> clamp((-0.5,0.0,0.5,1.0), 0.1, 0.9)
(0.1, 0.1, 0.5, 0.9)
ExpressionMath.lerp(mix, a, b)

Return a linear interpolation between a and b, combined using the fraction mix. mix is not clamped between [0,1]. A mix value of 0.0 returns a. Mixed scalar / vector inputs are supported for all arguments.

>>> lerp(0.0, 10, 20)
10.0
>>> lerp(0.5, 10, 20)
15.0
>>> lerp(1.5, 10, 20)
25.0
>>> lerp((0.0,0.5,1.5), 10, 20)
(10.0, 15.0, 25.0)
>>> lerp(0.5, 10, (20,30,40))
(15.0, 20.0, 25.0)
ExpressionMath.smoothstep(t)

Compute a smoothstep (ease in, ease out) version of t: [0,1]. This will clamp the output to [0,1].

Both scalar and vector input is supported.

Note

This is the ‘classic’ smoothstep: 3t**2 - 2t**3, rather Perlin [02] modified smoothstep: 6t**5 - 15t**4 + 10t**3. The two are quite similar, the differences being that Perlin’s smoothstep has zero 1st and 2nd derivatives at t=0 and t=1, and is thus generally preferred for general use.

>>> smoothstep(0.2)
0.05792
>>> smoothstep((-0.5, 0.0, 0.25, 0.5, 0.75, 1.0, 1.5))
(0.0, 0.0, 0.103515625, 0.5, 0.896484375, 1.0, 1.0)
ExpressionMath.fit(value, oldmin, oldmax, newmin, newmax)

Returns a number between newmin and newmax, which is relative to value in the range between oldmin and oldmax.

Mixed scalar / vector inputs are supported for all arguments.

>>> fit(0, -1, 1, 10, 20)
15.0
>>> fit(2, -1, 1, 10, 20)
25.0
>>> fit((-1,0.5,0.5,1), -1, 1, 10, 20)
(10.0, 17.5, 17.5, 20.0)
ExpressionMath.cfit(value, oldmin, oldmax, newmin, newmax)

Same as fit, but the result is clamped to [newmin, newmax].

Mixed scalar / vector inputs are supported for all arguments.

>>> cfit(0, -1, 1, 10, 20)
15.0
>>> cfit(2, -1, 1, 10, 20)
20.0
>>> cfit((-1,0.5,0.5,1), -1, 1, 10, 20)
(10.0, 17.5, 17.5, 20.0)
ExpressionMath.softcfit(value, oldmin, oldmax, newmin, newmax)

Same as cfit, but value is interpolates between oldmin and oldmax using smoothstep().

Mixed scalar / vector inputs are supported for all arguments.

>>> softcfit(0, -1, 1, 10, 20)
15.0
>>> softcfit(2, -1, 1, 10, 20)
20.0
>>> softcfit((-1,0.5,0.5,1), -1, 1, 10, 20)
(10.0, 18.96484375, 18.96484375, 20.0)
ExpressionMath.retime(frame, start, end, inMode, outMode)

Performs frame interpolation using specified hold mode: ‘freeze’, ‘repeat’, or ‘mirror’.

freeze

Hold the first/last frame of the sequence: 1111 1234 4444

repeat

Repeat the sequence: 1234 1234 1234

mirror

Mirror the sequence, end points are only used once: 3432 1234 3212

Note

Repeat mode may generate values outside of [start, end] at non-integer time samples (due to extrapolation).

Supports float input for {frame, start, end}. It is not necessary for start < end (though start != end).

>>> retime(110, 101, 110, 'repeat', 'repeat')
110.0
>>> retime(111, 101, 110, 'repeat', 'repeat')
101.0
>>> retime(112, 101, 110, 'repeat', 'repeat')
102.0
>>> retime(111, 101, 110, 'repeat', 'freeze')
110.0
>>> retime(112, 101, 110, 'repeat', 'freeze')
110.0
>>> retime(111, 101, 110, 'repeat', 'mirror')
109.0
>>> retime(112, 101, 110, 'repeat', 'mirror')
108.0

Noise

ExpressionMath.noise(x [,y [,z [,w]]]])

Improved Perlin noise [02], contained within the range [0,1]. The noise is generated by smoothing interpolating a set a pseudo-random gradients at regularly spaced points in space (integer lattice locations). The statistical characteristics of this call closely approximates that of PRman’s noise operator. One, two, three, and four-dimensional interpolants are provided.

>>> noise(0.0)
0.5
>>> noise(0.5)
0.40600001811981201
>>> noise(1.0)
0.5
>>> noise(0.5,0.5)
0.6901249885559082
>>> noise(0.5)
0.6901249885559082
ExpressionMath.snoise(x [,y [,z [,w]]]])

Signed equivalent of noise().

>>> snoise(0.0)
0.0
>>> snoise(0.5)
-0.18799999356269836
>>> snoise(1.0)
0.0
>>> snoise(0.5,0.5)
0.38025002181529999
ExpressionMath.randval(min, max, seedInt)

Return a random value between [min, max] using the specified seed integer. The distribution is identical to Splat’s randVal3 function.

>>> randval(0,1,0)
0.22541344799693055
>>> randval(0,1,1)
0.16124458358652066
>>> randval(0,2,1)
0.32248916717304132
>>> [randval(0,1,frame) for frame in xrange(101,103)]
[0.77299156360630683, 0.83146012384245638, 0.099642227194188679]

Hashing

ExpressionMath.stablehash(string)

Return a 32-bit signed integer hash of the specified string. This result is stable across architectures (i.e., you get the same answer on both 32- and 64-bit platforms.) This result is often useful for turning strings (such as scenegraph locations) into seedIntegers for use in randval (see above).

>>> stablehash('')
2118318316
>>> stablehash('/root/world/lights/rig/key1')
-847711557
>>> stablehash('/root/world/lights/rig/key2')
652177629

Floating Point

ExpressionMath.isinf(number)

Return whether the argument value is an infinity (positive or negative).

>>> isinf(1.0)
False
>>> isinf(float('inf'))
True
ExpressionMath.isnan(number)

Return whether the argument value is a NaN.

>>> isnan(1.0)
False
>>> isinf(float('nan'))
True
ExpressionMath.isfinite(number)

Return whether the argument value is a finite value (zero, subnormal, or normal, and not infinite or NaN).

>>> isfinite(1.0)
True
>>> isfinite(float('nan'))
False
>>> isfinite(float('inf'))
False
>>> isfinite(float('-inf'))
False