Source code for base_functions

"""Basic NodeCalculator functions.

This is an extension that is loaded by default.

The main difference to the base_operators is that functions rely on operators!
They combine existing operators to create more complex setups.
"""
from node_calculator.core import noca_op
from node_calculator.core import Op

# Any Maya plugin that should be loaded for the NodeCalculator
REQUIRED_EXTENSION_PLUGINS = []


# Dict of all available operations: used node-type, inputs, outputs, etc.
EXTENSION_OPERATORS = {}


[docs]@noca_op def soft_approach(attr_a, fade_in_range=0.5, target_value=1): """Follow attr_a, but approach the target_value slowly. Note: Only works for 1D inputs! Args: attr_a (NcNode or NcAttrs or str or int or float): Value or attr fade_in_range (NcNode or NcAttrs or str or int or float): Value or attr. This defines a range over which the target_value will be approached. Before the attr_a is within this range the output of this and the attr_a will be equal. Defaults to 0.5. target_value (NcNode or NcAttrs or str or int or float): Value or attr. This is the value that will be approached slowly. Defaults to 1. Returns: NcNode: Instance with node and output-attr. Example: :: in_attr = Node("pCube.tx") Op.soft_approach(in_attr, fade_in_range=2, target_value=5) # Starting at the value 3 (because 5-2=3), the output of this # will slowly approach the target_value 5. """ start_val = target_value - fade_in_range exponent = ((start_val) - attr_a) / fade_in_range soft_approach_value = target_value - fade_in_range * Op.exp(exponent) is_range_valid_condition = Op.condition( fade_in_range > 0, soft_approach_value, target_value, ) is_in_range_condition = Op.condition( attr_a > start_val, is_range_valid_condition, attr_a, ) return is_in_range_condition
[docs]@noca_op def sin(attr_a): """Sine of attr_a. Note: Only works for 1D inputs! The idea how to set this up with native Maya nodes is from Chad Vernon: https://www.chadvernon.com/blog/trig-maya/ Args: attr_a (NcNode or NcAttrs or str or int or float): Value or attr Returns: NcNode: Instance with node and output-attr. Example: :: in_attr = Node("pCube.tx") Op.sin(in_attr) """ sine = Op.euler_to_quat(attr_a * 2).outputQuatX return sine
[docs]@noca_op def cos(attr_a): """Cosine of attr_a. Note: Only works for 1D inputs! The idea how to set this up with native Maya nodes is from Chad Vernon: https://www.chadvernon.com/blog/trig-maya/ Args: attr_a (NcNode or NcAttrs or str or int or float): Value or attr Returns: NcNode: Instance with node and output-attr. Example: :: in_attr = Node("pCube.tx") Op.cos(in_attr) """ cosine = Op.euler_to_quat(attr_a * 2).outputQuatW return cosine
[docs]@noca_op def tan(attr_a): """Tangent of attr_a. Note: Only works for 1D inputs! The idea how to set this up with native Maya nodes is from Chad Vernon: https://www.chadvernon.com/blog/trig-maya/ Args: attr_a (NcNode or NcAttrs or str or int or float): Value or attr Returns: NcNode: Instance with node and output-attr. Example: :: in_attr = Node("pCube.tx") Op.tan(in_attr) """ sine = Op.sin(attr_a) cosine = Op.cos(attr_a) tangent = sine / cosine divide_by_zero_safety = Op.condition(cosine == 0, 0, tangent) return divide_by_zero_safety
[docs]@noca_op def asin(attr_a): """Arcsine of attr_a. Note: Only works for 1D inputs! Args: attr_a (NcNode or NcAttrs or str or int or float): Value or attr Returns: NcNode: Instance with node and output-attr. Example: :: in_attr = Node("pCube.tx") Op.asin(in_attr) """ x_vector_component = Op.sqrt(1 - attr_a ** 2) angle_between = Op.angle_between( (x_vector_component, 0, 0), (x_vector_component, attr_a, 0), ) right_angle_cond = Op.condition(x_vector_component == 0, 90, angle_between) sign_cond = Op.condition(attr_a >= 0, right_angle_cond, -right_angle_cond) return sign_cond
[docs]@noca_op def acos(attr_a): """Arccosine of attr_a. Note: Only works for 1D inputs! Args: attr_a (NcNode or NcAttrs or str or int or float): Value or attr Returns: NcNode: Instance with node and output-attr. Example: :: in_attr = Node("pCube.tx") Op.acos(in_attr) """ y_vector_component = Op.sqrt(1 - attr_a ** 2) angle_between = Op.angle_between( (attr_a, 0, 0), (attr_a, y_vector_component, 0), ) right_angle_cond = Op.condition(attr_a == 0, 90, angle_between) flip_cond = Op.condition( attr_a < 0, 180 - right_angle_cond, right_angle_cond ) return flip_cond
[docs]@noca_op def atan(attr_a): """Arctangent of attr_a, which calculates only quadrant 1 and 4. Note: Only works for 1D inputs! Args: attr_a (NcNode or NcAttrs or str or int or float): Value or attr Returns: NcNode: Instance with node and output-attr. Example: :: in_attr = Node("pCube.tx") Op.atan(in_attr) """ angle_between = Op.angle_between( (1, 0, 0), (1, attr_a, 0), ) sign_cond = Op.condition(attr_a < 0, -angle_between, angle_between) return sign_cond
[docs]@noca_op def atan2(attr_a, attr_b): """Arctangent2 of attr_b/attr_a, which calculates all four quadrants. Note: The arguments mimic the behaviour of math.atan2(y, x)! Make sure you pass them in the right order. Args: attr_a (NcNode or NcAttrs or str or int or float): Value or attr attr_b (NcNode or NcAttrs or str or int or float): Value or attr Returns: NcNode: Instance with node and output-attr. Example: :: x = Node("pCube.tx") y = Node("pCube.ty") Op.atan2(y, x) """ # Measure the angle between a vector constructed out of given values. angle_between = Op.angle_between( (attr_b, 0, 0), (attr_b, attr_a, 0), ) # Change the angle, depending on the quadrant it lies in. quadrant_1_and_4_cond = Op.condition( attr_a > 0, angle_between, -angle_between, ) quadrant_2_and_3_cond = Op.condition( attr_a > 0, 180 - angle_between, -180 + angle_between, ) quadrant_cond = Op.condition( attr_b > 0, quadrant_1_and_4_cond, quadrant_2_and_3_cond, ) # Take care of special case where attr_b is zero & would result in angle=0. right_angle_cond = Op.condition( attr_b == 0, Op.condition(attr_a < 0, -90, 90), quadrant_cond, ) return right_angle_cond