mmSolver.utils#

The utils sub-package.

AnimCurve#

Animation curve (animCurve) utilities.

Note

Any function names ending with _apione or _apitwo depicts the Python Maya API version used in that function, and the returned types. Be careful not to mix API function values, otherwise it will all end in tears.

mmSolver.utils.animcurve.create_anim_curve_node_apione(times, values, node_attr=None, tangent_in_type=<MyCustomMock id='140422749236752'>, tangent_out_type=<MyCustomMock id='140422749236816'>, anim_type=<MyCustomMock id='140422749236624'>, undo_cache=None)#

Create an animCurve using Maya API (one).

Parameters:
  • times (tuple or list) – Time values for the animCurve

  • values (tuple or list) – Values for the animCurve.

  • node_attr (str) – The ‘plug’ to connect the animCurve to.

  • tangent_in_type (maya.OpenMayaAnim.MFnAnimCurve.kTangent*) – The “in” tangent type for keyframes.

  • tangent_out_type (maya.OpenMayaAnim.MFnAnimCurve.kTangent*) – The “out” tangent type for keyframes.

  • anim_type (maya.OpenMayaAnim.MFnAnimCurve.kAnimCurve*) – The type of animation curve node.

  • undo_cache (maya.OpenMayaAnim.MAnimCurveChange) – The Maya AnimCurve Undo Cache data structure or None if no undo is required.

Returns:

MFnAnimCurve object attached to a newly created animation curve.

Return type:

maya.OpenMaya.MFnAnimCurve

mmSolver.utils.animcurve.create_anim_curve_node(*args, **kwargs)#
mmSolver.utils.animcurve.get_anim_curves_from_nodes(nodes_or_plugs, attrs=None)#

Get all animCurve nodes connected to the given nodes.

Parameters:

nodes_or_plugs ([str, ..]) – List of nodes (or plugs) to query animation curves.

Returns:

List of animation nodes. List may be empty if no animCurves were found.

Return type:

[str, ..]

mmSolver.utils.animcurve.euler_filter_plug(node_name, attr_name)#

Perform Euler filter for the given node attribute.

mmSolver.utils.animcurve.euler_filter_value(prev_value, value)#

Perform a ‘Euler Filter’ on the given rotation values.

The filter will ensure that each sequential rotation value will be with-in +/-360 degrees of the previous value.

Each axis (X, Y and Z) must be filtered individuality.

Note

This function is called recursively when a rotation is more/less than 360 degrees.

Parameters:
  • prev_value (float) – The rotation value on the previous frame.

  • value (float) – The current rotation value.

Returns:

A new filter rotation value.

Return type:

float

Camera#

Camera related functions.

mmSolver.utils.camera.get_camera(node)#

Get both transform and shape node of a camera.

Parameters:

node (str) – Part of the camera node, must be either a transform or shape node.

Returns:

Two nodes in a tuple, transform then shape node.

Return type:

(str, str) or (None, None)

mmSolver.utils.camera.is_startup_cam(node)#

Return True if the given camera node is a ‘startupCamera’.

A startup camera is a camera; ‘persp’, ‘side’, ‘top’, ‘front’, etc.

Return type:

bool

mmSolver.utils.camera.is_not_startup_cam(node)#

Return True if the given camera node is NOT a ‘startupCamera’.

A startup camera is a camera; ‘persp’, ‘side’, ‘top’, ‘front’, etc.

Return type:

bool

mmSolver.utils.camera.get_image_plane_shapes_from_camera(cam_tfm, cam_shp)#

Get the list of image plane shape nodes connected to the given camera.

Parameters:
  • cam_tfm (str) – Camera transform node.

  • cam_shp (str) – Camera shape node.

Returns:

The list of image shape nodes, may be an empty list.

Return type:

[str, ..]

Config#

Configuration for querying and setting configuration values and files.

Tools may need to have config files to read from and write. This module is a unified module for working with these configuration files.

All configuration files are expected to be JSON formatted.

By default, without any keyword arguments, configuration files are searched for in the ‘MMSOLVER_CONFIG_PATH’ environment variable, but this may be overridden using “get_dirs”, or “get_config” function arguments.

By default the following paths are searched (in order, top-down):

  • ${HOME}/.mmSolver (Linux)

  • %APPDATA%/mmSolver (Windows)

  • ${MMSOLVER_LOCATION}/config (Linux and Windows)

This allows both a default fallback, and a user specified path. Additionally, studios may modify the ‘.mod’ file to provide an intermediate studio or project location.

mmSolver.utils.config.get_dirs(envvar)#

Get a list of directories to look in for config files.

Parameters:

envvar (str or None) – The environment variable to query for a list of directories.

Returns:

List of config directories.

mmSolver.utils.config.find_path(file_name, search_paths)#

Search though a list of defined paths for the config file name given.

If an absolute file path is given, it is verified and returned.

Parameters:
  • file_name (str) – File name to find.

  • search_paths (list of str) – The directories to search for the file.

Returns:

Full config file name, or None.

Return type:

str or None

mmSolver.utils.config.read_data(file_path)#

Read configuration file and return the data embedded.

Parameters:

file_path (str) – The absolute file path to a config file.

Returns:

Dictionary, list or None, depending what the given file contains.

Return type:

dict, list or None

mmSolver.utils.config.write_data(data, file_path, human_readable=True)#

Write the given configuration data to a file.

Parameters:
  • data (dict or list) – Configuration data to write. The data should be plain-old-(Python)data types, like lists, float, int, string and dict.

  • file_path (str) – A valid absolute file path.

mmSolver.utils.config.exists(data, key)#

Does the key exist in data?

Parameters:
  • data (dict) – The name of the config file, or an absolute file path.

  • key (str) – Hierarchy of keys separated by forward slash to search for in the config. For example ‘data[arg1][arg2][arg3]’.

Returns:

Boolean, does the ‘key’ exist in the ‘data’?

Return type:

bool

mmSolver.utils.config.get_value(data, key, default_value=None)#

Get a value from the config data.

If the config data value does not exist, or one of the argument (keys) does not exist, ‘default_value’ is returned.

>>> data = read_data('/path/to/config.json')
>>> x = get_value(data, 'key')
>>> y = get_value(data, 'key/subkey')
>>> z = get_value(data, 'key/subkey/subsubkey')
Parameters:
  • data (dict) – The configuration data, as a Python dict (plain-old-data).

  • key (str) – Hierarchy of keys separated by forward slash to search for in the config. For example ‘data[arg1][arg2][arg3]’.

  • default_value (any type) – The value returned when the config file or key doesn’t exist.

Returns:

The value type in the key - it could be any type..

mmSolver.utils.config.set_value(data, key, value)#

Set a value in the given configuration data.

Parameters:
  • data (dict) – The data to set the value on to.

  • key (str) – Where to set the value in data

  • value (any) – The value to set.

Returns:

A copy of the configuration data with the modification made.

Return type:

dict or list

class mmSolver.utils.config.Config(file_path)#

A configuration file in mmSolver, to read, write, query and edit configuration files.

Config will save a new file, if the given file_name is valid.

This is an example use:

>>> file_path = "/absolute/path/to/file.json"
>>> config = Config(file_path)
>>> config.file_path
/absolute/path/to/file.json
>>> config.read()  # Read the file, fails if the file does not exist.
>>> config.exists("my_option_name")
False
>>> config.get_value("my_option_name")
None
>>> config.set_value("my_option_name", 42)
>>> config.exists("my_option_name")
True
>>> config.get_value("my_option_name")
42
>>> config.write()
get_autoread()#
set_autoread(value)#

Set auto-read value.

By default, auto-read is True.

If auto-read is True, Config will read a config file automatically, without the need to call “read()” explicitly.

Parameters:

value (bool) – The value to set.

get_autowrite()#
set_autowrite(value)#

Set auto-write value.

By default, auto-write is False.

If auto-write is True, Config will write a config file automatically, when the Config object is destructed by Python. Otherwise, the user must call “write()” (which is generally recommended anyway).

Parameters:

value (bool) – The value to set.

get_file_path()#
set_file_path(value)#

Set the file path for the Config.

Setting the file path will automatically invalidate the Config and force a re-read of the config file when a value is next requested.

Note

If the new file path is the same as the old file path, the Config will not be invalidated. Only if the file path changes will the Config be invalidated. To re-read the file, use the Config.read() method.

Parameters:

value (str) – The value to set.

read()#

Read the file_path contents.

write(human_readable=True)#

Write the contents of this object to the file_path.

exists(key)#

Does the key exist in this config file?

get_value(key, default_value=None)#

Get a value from the Config file.

If no key exists, returns the default_value.

set_value(key, value)#

Set the key/value in the Config file.

property autoread#
property autowrite#
property file_path#
mmSolver.utils.config.get_config(file_name, search=None)#

Read a config file as a Config class object.

>>> get_config("myConfigFile.json")
<mmSolver.utils.config.Config object at 0x0000016993BF5160>
>>> get_config("/path/to/config/file.json")
<mmSolver.utils.config.Config object at 0x0000016993BF5748>
>>> get_config("non_existant_file.json")
None
Parameters:
  • file_name (str) – The name of the config file, or an absolute file path.

  • search (str or [str, ..] or None) – An environment variable to parse for search paths, or a list of given search directory paths, or if set to None, use the default environment variable for mmSolver.

Returns:

Config object, or None if the file is not found.

Return type:

Config or None

mmSolver.utils.config.get_home_dir_path(*args)#

Get the default home directory configuration directory.

The path returned will be operating system dependent.

Note

The path returned may not exist! It is up to the user to check and create files/directories as needed.

Parameters:

args ([str, ..]) – A list of string arguments to be joined to the returned path.

Returns:

An absolute path to a config directory that may or may not exist.

Return type:

str

Config Maya#

Configuration module for getting/setting config data inside Maya.

There are many places to store and read data from in Maya.

  • A Maya node

  • The Maya scene file.

  • The Python shared variables.

  • The Maya preferences.

Each type of storage can be considered to have a different life-time.

The levels are (in ascending order):

  • Maya Node

  • Maya Scene

  • Maya Session

  • Maya Preferences

mmSolver.utils.configmaya.get_node_option(node_name, attr_name, default=None)#

Get value from an node attribute.

Parameters:
  • node_name (str) – Node to get value from. Node must exist before running function!

  • attr_name (str) – The name of the attribute to get value from.

  • default (any) – Value to be returned if the value does not exist.

Returns:

A value from the node.

Return type:

bool, float, int or str

mmSolver.utils.configmaya.set_node_option(node_name, attr_name, value, add_attr=None)#

Set value onto a node.attr path.

Parameters:
  • node_name (str) – Node to store value on.

  • attr_name (str) – Attribute name to store value with.

  • value (bool, float, int or str) – The value to store.

  • add_attr (bool) – Add attribute to the given node, if the attribute does not already exist.

Return type:

None

mmSolver.utils.configmaya.get_node_option_structure(node_name, attr_name)#

Get data structure from a node attribute.

Parameters:
  • node_name (str) – Node to get data from.

  • attr_name (str) – The name of the attribute to get data from.

Returns:

Arbitrary Plain-Old-Data data structures, can be a list or dictionary.

Return type:

dict or list or None

mmSolver.utils.configmaya.set_node_option_structure(node_name, attr_name, data_struct, add_attr=None)#

Set arbitrary Plain-Old-Data onto a node.attr path.

Parameters:
  • node_name (str) – Node to store data on.

  • attr_name (str) – Attribute name to store data with.

  • data_struct (dict or list) – The data to store.

  • add_attr (bool) – Add attribute to the given node, if the attribute does not already exist.

Return type:

None

mmSolver.utils.configmaya.get_scene_option(name, default=None)#

Get a value from the scene.

Parameters:
  • name (str) – Get the option with this name.

  • default (any) – Value to be returned if the value does not exist.

Returns:

The value of the scene option, or ‘default’ if the ‘name’ does not exist.

Return type:

any

mmSolver.utils.configmaya.set_scene_option(name, value, add_attr=None)#

Set a value in the scene.

Parameters:
  • name (str) – Set the option with this name.

  • value (any) – Value to set.

  • add_attr (bool) – Add attribute to the scene, if the attribute does not already exist.

Return type:

None

mmSolver.utils.configmaya.get_preference_option(name, default=None)#

Get a Maya preference from Maya (optionVar).

Parameters:
  • name (str) – Name key to get from Maya preferences.

  • default (any) – If the preference option is not found, return this value.

Returns:

The value found under ‘name’, or the ‘default’ value.

Return type:

int, float or str

mmSolver.utils.configmaya.set_preference_option(name, value)#

Set a Maya preference to Maya (optionVar).

Parameters:
  • name (str) – Name key to set to Maya preferences.

  • value (int, float or str) – Value to set.

mmSolver.utils.configmaya.save_preference_options()#

Write all Maya preferences to disk.

Convert Types#

Conversion functions between various types, for fundamental Python types.

mmSolver.utils.converttypes.stringToBoolean(value)#

Convert a string into a boolean value, using list of ‘TRUE_WORDS’

mmSolver.utils.converttypes.booleanToString(value)#

Convert boolean value to a string.

mmSolver.utils.converttypes.stringToIntList(value)#

Convert a string of integer ranges to a list of integers.

value = ‘1001-1101’ value = ‘1001,1002,1003-1005,1010-1012’

Parameters:

value (str) – The string value to convert.

Returns:

List of integer numbers parsed from the string.

Return type:

[int, ..]

mmSolver.utils.converttypes.intListToString(value)#

Convert a list of integers to a string.

mmSolver.utils.converttypes.stringToInteger(value)#

Event#

Event registry and triggers for python functions.

The event system modelled is a ‘publish/subscribe’ pattern. https://en.wikipedia.org/wiki/Publish%E2%80%93subscribe_pattern

This module does not use any external python dependencies, but does rely on Maya’s in-built ‘maya.utils.executeDeferred()’ function.

This event system automatically combines multiple functions with single objects into a function that is run once with multiple arguments. The reason for this, is to reduce function calls and improve performance when operating on many arguments at once.

Example usage:

>>> import mmSolver.utils.event as event_utils
>>> def my_function(**kwargs):
...     print(kwargs)
...
>>> event_utils.add_function_to_event('my_event', my_function, deferred=True)
>>> event_utils.trigger_event('my_event', number=42)
>>>
{'number': 42}
>>> for i in range(3):
...     event_utils.trigger_event('my_event', number=i)
...
>>>
{'number': [0, 1, 2]}
class mmSolver.utils.event.BlockedEvents(event_names_to_block)#

A context manager used to stop events from being triggered.

Example usage:

>>> event_name = 'my_event'
>>> with event_utils.BlockedEvents([event_name]):
...    # do stuff, and don't trigger events named 'my_event'.
...    pass
mmSolver.utils.event.trigger_event(event_name, **kwargs)#

Inform the event-driven system that ‘event_name’ has occurred.

Note

It is possible the event will not be triggered if the user has called for it to be blocked. Do not assume the event will always be triggered.

mmSolver.utils.event.add_function_to_event(event_name, func, deferred=True)#

Image Sequence#

mmSolver.utils.imageseq.expand_image_sequence_path(image_sequence_path, format_style)#

Kalman Filter#

Basic 1-dimensional Kalman filter.

https://towardsdatascience.com/kalman-filters-a-step-by-step-implementation-guide-in-python-91e7e123b968

class mmSolver.utils.kalmanfilter.State(value, mean, variance)#
property mean#

Alias for field number 1

property value#

Alias for field number 0

property variance#

Alias for field number 2

mmSolver.utils.kalmanfilter.update(state_a, state_b)#

Update the variance and mean.

Parameters:
  • state_a (State) – First state.

  • state_b (State) – Second state.

Returns:

New state.

Return type:

State

mmSolver.utils.kalmanfilter.predict(state_a, state_b)#

Predict the next state, based on two gaussian distribution states.

Parameters:
  • state_a (State) – First state.

  • state_b (State) – Second state.

Returns:

New state, combined of both first and second states.

Return type:

State

Line Intersect#

Utility functions for 3D line intersection (for triangulating 3D points).

# Example usage
import mmSolver.utils.lineintersect as tri_utils
cam_tfm = '|camera1'
mkr_node = '|camera1|markerGroup1|marker1_MKR'
first_frm_num = 1001
last_frm_num = 1101
first_pnt, first_dir = tri_utils.get_point_and_direction(
    cam_tfm,
    mkr_node,
    first_frm_num
)
last_pnt, last_dir = tri_utils.get_point_and_direction(
    cam_tfm,
    mkr_node,
    last_frm_num
)
a_pnt, b_pnt = tri_utils.calculate_approx_intersection_point_between_two_3d_lines(
    first_pnt, first_dir,
    last_pnt, last_dir
)
pnt = OpenMaya.MPoint(
    (a_pnt.x + b_pnt.x) * 0.5,
    (a_pnt.y + b_pnt.y) * 0.5,
    (a_pnt.z + b_pnt.z) * 0.5
)
# Use 'pnt' as the 'intersection' point of the two lines.
mmSolver.utils.lineintersect.get_point_and_direction(camera_node, point_node, frame)#

Get the direction of the camera toward a given point.

The values returned are in world-space.

Note

This function changes the current maya scene time to the frame argument. It is the user’s responsibility to ensure the frame is maintained before/after the tool using this function is finished.

Parameters:
  • camera_node (str) – Camera transform node.

  • point_node (str) – Transform node to aim at.

  • frame (int) – The frame to query at.

Returns:

Point and direction from camera to point.

Return type:

(OpenMaya.MPoint, OpenMaya.MVector)

mmSolver.utils.lineintersect.camera_to_point_direction(camera_node, point, frame)#

Get the direction of the camera toward a given point.

Note

This function changes the current maya scene time to the frame argument. It is the user’s responsibility to ensure the frame is maintained before/after the tool using this function is finished.

Parameters:
  • camera_node (str) – Camera transform node.

  • point (OpenMaya.MPoint) – A point to get the direction of. Assumed to be in world space.

  • frame (int) – The frame to query at.

Returns:

The direction from the camera to the point.

Return type:

OpenMaya.MVector

mmSolver.utils.lineintersect.calculate_approx_intersection_point_between_two_3d_lines(a_pnt, a_dir, b_pnt, b_dir, eps=None)#

Calculate approximate intersection between two lines in 3D.

http://paulbourke.net/geometry/pointlineplane/ http://paulbourke.net/geometry/pointlineplane/lineline.c

Parameters:
  • a_pnt (MPoint) – Point A.

  • a_dir (MVector) – Direction A.

  • b_pnt (MPoint) – Point B

  • b_dir (MVector) – Direction B.

  • eps (float) – Direction B.

Returns:

Two points to define the closest line intersection.

Return type:

(MPoint, MPoint)

Load File#

Provides a base interface for marker import plug-ins.

exception mmSolver.utils.loadfile.excep.ParserWarning#

Raised when a format parser needs to warn about non-error conditions.

exception mmSolver.utils.loadfile.excep.ParserError#

Raised when a format parser cannot continue.

Provides a base interface for marker import plug-ins.

mmSolver.utils.loadfile.floatutils.float_is_equal(x, y)#

Check the two float numbers match.

Returns:

True or False, if float is equal or not.

Return type:

bool

mmSolver.utils.loadfile.floatutils.get_closest_frame(frame, value)#

Get the closest frame in the dictionary value.

Parameters:
  • frame – An int for the frame to look up.

  • value – A dict with keys as the frames to look up.

Returns the closest frame in the dict value.

A manager class for registering new marker file formats.

class mmSolver.utils.loadfile.formatmanager.FormatManager#
register_format(class_obj)#
get_formats()#

Provides a base interface for marker import plug-ins.

class mmSolver.utils.loadfile.keyframedata.KeyframeData(data=None)#

Keyframe data, used to store animated or static data.

Note: Static data is just a single keyframe of data, or multiple keyframes with the same value.

get_start_frame()#
get_end_frame()#
get_length()#
get_raw_data()#

Gives access of the underlying data structure to the user.

This is so that the user can query the data then give it to the __init__ of a new class.

get_value(frame)#

Get the key value at frame. frame is an integer.

get_keyframe_values()#
get_times()#

Get all times, should be first half of get_keyframe_values.

get_values()#

Get all values, should be second half of get_keyframe_values.

get_times_and_values()#

Get all times, should be first half of get_keyframe_values.

set_value(frame, value)#

Set the ‘value’, at ‘frame’.

simplify_data()#

Tries to convert the keyframe data into static if all values are the same.

Provides a base interface for marker import plug-ins.

class mmSolver.utils.loadfile.loader.LoaderBase#

Base class for all format loaders.

name = None#
file_exts = None#
args = None#
abstract parse(file_path, **kwargs)#

Parse the given file path.

Inherit from LoaderBase and override this method.

Raises:
  • ParserError – When the parser encounters an error related to parsing.

  • OSError – When there is a problem with reading or accessing the given file.

Returns:

Tuple of FileInfo and List of MarkerData.

Return type:

(FileInfo, [MarkerData, …])

Load Marker#

Provides a base interface for marker import plug-ins.

class mmSolver.utils.loadmarker.fileinfo.FileInfo(marker_distorted, marker_undistorted, bundle_positions, camera_field_of_view)#
property bundle_positions#

Alias for field number 2

property camera_field_of_view#

Alias for field number 3

property marker_distorted#

Alias for field number 0

property marker_undistorted#

Alias for field number 1

mmSolver.utils.loadmarker.fileinfo.create_file_info(marker_distorted=None, marker_undistorted=None, bundle_positions=None, camera_field_of_view=None)#

Create the type of contents available in the file format.

File reading and parsing utilities.

mmSolver.utils.loadmarker.fileutils.get_file_path_format(text, read_func)#

Look up the Format from the file path.

Parameters:

text – File path text.

Returns:

Format for the file path, or None if not found.

Return type:

None or Format

mmSolver.utils.loadmarker.fileutils.is_valid_file_path(text, read_func)#

Is the given text a file path we can load as a marker?

Parameters:

text (str) – A possible file path string.

Returns:

File path validity.

Return type:

bool

mmSolver.utils.loadmarker.fileutils.get_file_info(file_path, read_func)#

Get the file path information.

Parameters:

file_path (str) – The marker file path to get info for.

Returns:

The file info.

Return type:

FileInfo

mmSolver.utils.loadmarker.fileutils.get_file_info_strings(file_path, read_func)#

Get the file path information, as user-readable strings.

Parameters:

file_path (str) – The marker file path to get info for.

Returns:

Dictionary of various information about the given file path.

Return type:

dict

mmSolver.utils.loadmarker.fileutils.get_file_filter()#

Construct a string to be given to QFileDialog as a file filter.

Returns:

String of file filters, separated by ‘;;’ characters.

Return type:

str

A manager class for registering new marker file formats.

mmSolver.utils.loadmarker.formatmanager.get_format_manager()#

Provides a base interface for marker import plug-ins.

class mmSolver.utils.loadmarker.markerdata.MarkerData#
get_name()#
set_name(value)#
get_id()#
set_id(value)#
get_group_name()#
set_group_name(value)#
get_color()#
set_color(value)#
get_x()#
set_x(value)#
get_y()#
set_y(value)#
get_enable()#
set_enable(value)#
get_weight()#
set_weight(value)#
get_bundle_x()#
set_bundle_x(value)#
get_bundle_y()#
set_bundle_y(value)#
get_bundle_z()#
set_bundle_z(value)#
get_bundle_lock_x()#
set_bundle_lock_x(value)#
get_bundle_lock_y()#
set_bundle_lock_y(value)#
get_bundle_lock_z()#
set_bundle_lock_z(value)#
property name#
property id#
property x#
property y#
property enable#
property weight#
property group_name#
property color#
property bundle_x#
property bundle_y#
property bundle_z#
property bundle_lock_x#
property bundle_lock_y#
property bundle_lock_z#

Formats#

File Formats for loadmarker tool.

This file is used to automatically load all formats so the user doesn’t need to import each format individually.

The .txt format from PFTrack / PFMatchIt.

The position coordinate (-0.5, -0.5) is the lower-left. The position coordinate (width - 0.5, height - 0.5) is the upper-right.

This format is resolution dependent!

The data block looks like this:

"trackerName"   # Tracker name.
int     # Clip number. First number is 1, then 2, etc.
int     # Number of frames
int float float float  # Frame, X position, Y position, residual

Or another variation:

"trackerName"   # Tracker name.
"cameraName"    # Camera name
int     # Number of frames
int float float float float  # Frame, X position, Y position, residual

Each block of data is separated by whitespace (usually a blank line).

Optionally, each line of tracker frame and position may also have a Z-Depth value, like this:

"trackerName"   # Tracker name.
int     # Clip number.
int     # Number of frames
int float float float float  # Frame, X position, Y position, residual, z-depth

Simple file with 1 2D track and 1 frame of data:

"MyFeature1"
1
1
1 1920.000 1080.000 0.000
class mmSolver.utils.loadmarker.formats.pftrack2dt.LoaderPFTrack2DT#
name = 'PFTrack 2D Tracks (*.2dt / *.txt)'#
file_exts = ['.2dt', '.txt']#
args = [('image_width', None), ('image_height', None)]#
parse(file_path, **kwargs)#

Parse the file path as a PFTrack .2dt/.txt file.

Parameters:
  • file_path (str) – File path to parse.

  • kwargs – expected to contain ‘image_width’ and ‘image_height’.

Returns:

List of MarkerData.

Reads a Matchmover rz2 file.

class mmSolver.utils.loadmarker.formats.rz2.LoaderRZ2#
name = 'MatchMover TrackPoints (*.rz2)'#
file_exts = ['.rz2']#
args = []#
parse(file_path, **kwargs)#

Parse the given file path.

Inherit from LoaderBase and override this method.

Raises:
  • ParserError – When the parser encounters an error related to parsing.

  • OSError – When there is a problem with reading or accessing the given file.

Returns:

Tuple of FileInfo and List of MarkerData.

Return type:

(FileInfo, [MarkerData, …])

The .txt format from the 3DEqualizer 2D Points exporter.

The position coordinate (0.0, 0.0) is the lower-left. The position coordinate (width, height) is the upper-right.

This format is resolution dependent!

The file format looks like this:

int     # Number of track points in the file
string  # Name of point
int     # Color of the point
int     # Number of frames
int float float  # Frame, X position, Y position

Simple file with 1 2D track and 1 frame of data:

1
My Point Name
0
1
1 1920.0 1080.0
class mmSolver.utils.loadmarker.formats.tdetxt.Loader3DETXT#
name = '3DEqualizer Track Points (*.txt)'#
file_exts = ['.txt']#
args = [('image_width', None), ('image_height', None)]#
parse(file_path, **kwargs)#

Parse the file path as a 3DEqualizer .txt file.

Parameters:
  • file_path (str) – File path to parse.

  • kwargs – expected to contain ‘image_width’ and ‘image_height’.

Returns:

List of MarkerData.

The .uv format has two versions; v1 ASCII format and v2 JSON format.

The v1 ASCII format is derived from the 3DEqualizer 2D Points exporter.

The UV coordinate (0.0, 0.0) is the lower-left. The UV coordinate (1.0, 1.0) is the upper-right.

The ASCII file format looks like this:

int     # Number of track points in the file
string  # Name of point
int     # Number of frames
int float float float  # Frame, U coord, V coord, Point Weight

Simple ASCII v1 file with 1 2D track and 1 frame of data:

1
My Point Name
1
1 0.0 1.0 1.0

The JSON format takes the shape of a dictionary. The dictionary looks like this, format version 2:

{
    'version': int,
    'num_points': int,
    'is_undistorted': bool,
    'points': {
        'name': str,
        'id': int,  # or None
        'set_name': str,
        'per_frame': [
            {
                'frame': int,
                'pos': (float, float),  # assumed to be undistorted.
                'weight': float
            }
        ]
    }
}

Format version 3:

{
    'version': int,
    'num_points': int,
    'is_undistorted': None,  # Deprecated
    'points': {
        'name': str,
        'id': int,  # or None
        'set_name': str,
        'per_frame': [
            {
                'frame': int,
                'pos_dist': (float, float),
                'pos': (float, float),
                'weight': float
            },
        ],
        '3d': {
            'x': float, # or None
            'y': float, # or None
            'z': float, # or None
            'x_lock': bool, # or None
            'y_lock': bool, # or None
            'z_lock': bool  # or None
        }
    }
}

Format version 4:

{
    'version': int,
    'num_points': int,
    'is_undistorted': None,  # Deprecated
    'points': {
        'name': str,
        'id': int,  # or None
        'set_name': str,
        'per_frame': [
            {
                'frame': int,
                'pos_dist': (float, float),
                'pos': (float, float),
                'weight': float
            },
        ],
        '3d': {
            'x': float, # or None
            'y': float, # or None
            'z': float, # or None
            'x_lock': bool, # or None
            'y_lock': bool, # or None
            'z_lock': bool  # or None
        }
    },
    'camera': {
        'resolution': (int, int),
        'film_back_cm': (float, float),
        'lens_center_offset_cm': (float, float),
        'per_frame': [
            {
                'frame': int,
                'focal_length_cm': float,
            },
        ],
    }
}
mmSolver.utils.loadmarker.formats.uvtrack.determine_format_version(file_path)#

Work out the format version by reading the ‘file_path’.

returns: The format version, must be one of

constants.UV_TRACK_FORMAT_VERSION_LIST

mmSolver.utils.loadmarker.formats.uvtrack.parse_v1(file_path, **kwargs)#

Parse the UV file format or 3DEqualizer .txt format.

Parameters:

file_path

Returns:

mmSolver.utils.loadmarker.formats.uvtrack.parse_v2(file_path, **kwargs)#

Parse the UV file format, using JSON.

Parameters:

file_path (str) – File path to read.

Returns:

List of MarkerData objects.

mmSolver.utils.loadmarker.formats.uvtrack.parse_v3(file_path, **kwargs)#

Parse the UV file format, using JSON.

Accepts the keyword ‘undistorted’.

Parameters:

file_path (str) – File path to read.

Returns:

List of MarkerData objects.

mmSolver.utils.loadmarker.formats.uvtrack.parse_v4(file_path, **kwargs)#

Parse the UV file format, using JSON.

Accepts the keyword ‘undistorted’, ‘overscan_x’ and ‘overscan_y’.

Parameters:

file_path (str) – File path to read.

Returns:

List of MarkerData objects.

class mmSolver.utils.loadmarker.formats.uvtrack.LoaderUVTrack#
name = 'UV Track Points (*.uv)'#
file_exts = ['.uv']#
args = ['undistorted', 'with_3d_pos']#
parse(file_path, **kwargs)#

Decodes a file path into a list of MarkerData.

Parameters:
  • file_path (str) – The file path to parse.

  • kwargs – The keyword ‘undistorted’ is used by UV_TRACK_FORMAT_VERSION_3 formats. ‘with_3d_pos’ can be used to use the (3D) bundle positions or not.

Returns:

List of MarkerData

Node#

Utilities built around Maya nodes and node paths.

mmSolver.utils.node.get_node_full_path(*args, **kwargs)#
mmSolver.utils.node.node_is_referenced(node)#

Is the node given referenced (from a referenced file)?

Parameters:

node – Node to query.

Returns:

True or False, is it referenced?

Return type:

bool

mmSolver.utils.node.set_attr(plug, value, relock=False)#

Set a numeric attribute to a value.

Optionally unlocks and re-locks the plugs.

Parameters:
  • plug – Node.Attr to set.

  • value – The ne value to set.

  • relock – If the plug was already locked, should we set the new value, then re-lock afterward?

Returns:

mmSolver.utils.node.get_long_name(node)#

Given a valid node path, get the ‘full path’ node name, or None if invalid.

note::

DG nodes do not have a ‘full path’ as they do not have hierarchy and will always have unique node names.

Parameters:

node (str) – Maya DG or DAG node path.

Returns:

Full path node name.

Return type:

None or str

mmSolver.utils.node.get_node_parents(node)#

Get all the parents above the given node.

Parameters:

node (str) – Valid Maya DAG node path.

Returns:

The parent nodes of node, in order from node upwards.

Return type:

[str, ..]

mmSolver.utils.node.sort_nodes_by_depth(nodes, reverse=False)#

Sort nodes by depth, shallow nodes first.

Parameters:
  • nodes ([str, ..]) – List of Maya DAG node paths.

  • reverse (bool) – Reverses the list of nodes.

Returns:

List of sorted nodes.

Return type:

[str, ..]

mmSolver.utils.node.get_as_selection_list_apione(paths)#

Get a Maya API selection list with the given valid Maya node paths.

Parameters:

paths (list of str) – List of Maya node paths.

Returns:

MSelectionList with valid nodes added to list.

Return type:

OpenMaya1.MSelectionList

mmSolver.utils.node.get_as_dag_path_apione(node_str)#

Convert the given Maya node path into a MDagPath object.

Parameters:

node_str (str) – Maya node path to be converted.

Returns:

MDagPath API object or None if the ‘node_str’ is invalid.

Type:

MDagPath or None

mmSolver.utils.node.get_as_object_apione(node_str)#

Convert the given Maya node path into a MObject object.

Parameters:

node_str (str) – Maya node path to be converted.

Returns:

MObject API object or None, if conversion failed.

Return type:

MObject or None

mmSolver.utils.node.get_as_plug_apione(node_attr)#

Convert the given ‘node.attr’ path into a MPlug object.

Parameters:

node_attr (str) – Node attribute string in format ‘node.attr’.

Returns:

MPlug object or None if conversion failed.

Type:

MPlug or None

mmSolver.utils.node.get_dag_path_shapes_below_apione(dag)#

Get the MDagPath shape nodes under the given MDagPath.

Note

The given ‘dag’ MDagPath is not modified during this function.

Parameters:

dag (maya.OpenMaya.MDagPath) – The DAG path to get shape nodes from.

Returns:

Return type:

[maya.OpenMaya.MDagPath, ..]

mmSolver.utils.node.get_as_selection_list_apitwo(node_names)#
mmSolver.utils.node.get_as_object_apitwo(node_name)#
mmSolver.utils.node.get_as_dag_path_apitwo(node_name)#
mmSolver.utils.node.get_as_plug_apitwo(node_attr)#
mmSolver.utils.node.get_as_selection_list(*args, **kwargs)#
mmSolver.utils.node.get_as_dag_path(*args, **kwargs)#
mmSolver.utils.node.get_as_object(*args, **kwargs)#
mmSolver.utils.node.get_as_plug(*args, **kwargs)#
mmSolver.utils.node.get_camera_above_node(node)#

Get the first camera transform and shape node above the node.

Parameters:

node (str or unicode) – The node name to check above for a camera.

Returns:

Tuple of camera transform and shape nodes, or (None, None)

Return type:

(str, str) or (None, None)

mmSolver.utils.node.get_all_parent_nodes(node)#

Get the parent nodes above the given node.

Parameters:

node (str) – The node name to get the parents of.

Returns:

List of parent nodes, in order of deepest to shallowest. Nodes unparented into world will have empty lists returned.

Return type:

[str, ..]

mmSolver.utils.node.get_node_wire_colour_rgb(node)#

Get the current wireframe colour (0.0 to 1.0) of the node.

The ‘node’ is assumed to a DAG node (capable of having a wireframe colour).

Parameters:

node (str) – Maya node path to get wireframe colour from.

Returns:

Tuple of red, green and blue.

Return type:

(float, float, float)

mmSolver.utils.node.set_node_wire_colour_rgb(node, rgb)#

Change the wireframe colour (0.0 to 1.0) of the node.

The ‘node’ is assumed to a DAG node (capable of having a wireframe colour set).

Parameters:
  • node (str) – Maya DAG node path.

  • rgb (tuple) – Colour as R, G, B; Or None to reset to default colour.

Return type:

None

mmSolver.utils.node.get_node_draw_override_enabled(node)#

Get the current draw override enabled value of the node.

The ‘node’ is assumed to a DAG node (capable of having an draw override).

Parameters:

node (str) – Maya node path to get value from.

Return type:

bool

mmSolver.utils.node.set_node_draw_override_enabled(node, value)#

Set the draw override enabled value of a node.

The ‘node’ is assumed to a DAG node (capable of having an draw override).

Parameters:

node (str) – Maya DAG node path.

Return type:

None

mmSolver.utils.node.get_node_draw_override_colour_rgba(node)#

Get the draw current override colour (0.0 to 1.0) of the node.

The ‘node’ is assumed to a DAG node (capable of having a override colour).

Parameters:

node (str) – Maya node path to get override colour from.

Returns:

Tuple of red, green, blue and alpha.

Return type:

(float, float, float, float)

mmSolver.utils.node.set_node_draw_override_colour_rgba(node, rgba)#

Change the draw override colour (0.0 to 1.0) of the node.

The ‘node’ is assumed to a DAG node (capable of having a colour set).

Parameters:
  • node (str) – Maya DAG node path.

  • rgba (tuple) – Colour as R, G, B, A; Or None to reset to default colour.

Return type:

None

mmSolver.utils.node.attribute_exists(attr, node)#

Check if an attribute exists on the given node.

This is a Python equivalent of the MEL command ‘attributeExists’.

Parameters:
  • attr (str) – Attribute name to check for existence.

  • node (str) – The node to look for the attribute.

Returns:

A boolean, if the attribute exists or not.

Return type:

bool

Node Affects#

Query DG relationship information.

Use the Maya DG graph structure to determine the sparsity structure, a relation of cause and effect; which attributes affect which markers.

Answer this question: ‘for each marker, determine which attributes can affect it’s bundle.’

Detect inputs and outputs for marker-bundle relationships. For each marker, get the bundle, then find all the attributes that affect the bundle (and it’s parent nodes). If the bundle cannot be affected by any attribute in the solver, print a warning and remove it from the solve list.

This relationship building will be the basis for the mmSolver residual/parameter block creation. Note we do not need to worry about time in our relationship building, connections cannot be made at different times (and if they did, that would be stupid). This relationship building could mean we only need to measure a limited number of bundles, hence improving performance.

There are special cases for detecting inputs/outputs between markers and attributes.

  • Any transform node/attribute above the marker in the DAG that affects the world transform.

  • Cameras; transform attributes and focal length will affect all markers

mmSolver.utils.nodeaffects.find_plugs_affecting_transform(tfm_node, cam_tfm)#

Find plugs that affect the world-matrix transform of the node.

The ‘cam_tfm’ argument is for nodes that may be impacted by the screen-space matrix that views the ‘tfm_node’.

Parameters:
  • tfm_node (str) – The input node to query.

  • cam_tfm (str or None) – The camera that should be considered (optional).

Returns:

An unordered list of Maya attributes in ‘node.attr’ string format.

Return type:

[str, ..]

mmSolver.utils.nodeaffects.find_marker_attr_mapping_raw(mkr_list, attr_list)#

Get a mapping of markers to attributes, as a matrix.

Parameters:
  • mkr_list ([(str, str, str), ..]) – Tuple of marker node, bundle node and camera shape node in a list; each list of nodes represent a single Marker relationship and will be considered in mapping.

  • attr_list ([str, ..]) – Maya attributes to consider in mapping, in the familiar ‘node.attr’ string representation.

Returns:

Boolean matrix of size ‘markers x attrs’. Matrix index is ‘mapping[marker_index][attr_index]’, based on the index of the mkr_cam_node_frm_list and attr_list given.

Return type:

[[bool, .. ]]

mmSolver.utils.nodeaffects.sort_into_hierarchy_groups(mkr_list, attr_list)#

Create blocks of Markers and Attributes, sorted by hierarchy.

This will allow us to solve top-level objects (ie, root level) first, before solving children. This will ensure we minimise the base before attempting to solve the children.

Python Compatibility#

Provide Python 2.7 vs 3.x compatibility without using any third-party packages (like ‘six’ for example).

Raytrace#

Raytracing functions.

mmSolver.utils.raytrace.closest_intersect(source, direction, mesh_nodes, test_both_directions=False, max_dist=None, tolerance=None, use_smooth_mesh=None)#

Get the closest intersection point on meshes given a source point and direction

Parameters:
  • source ([float, float, float]) – Origin point of the ray projection.

  • direction ([float, float, float]) – The direction the ray will travel.

  • mesh_nodes ([str, ..]) – Mesh nodes

  • test_both_directions (bool) – testing ray direction both sides; default is False.

  • max_dist (float) – The maximum distance the ray will travel before stopping; default is RAYTRACE_MAX_DIST.

  • tolerance (float) – The minimum ray trace tolerance; default is RAYTRACE_EPSILON.

  • use_smooth_mesh (bool) – Use smooth preview mesh for intersection.

Returns:

The closest world space intersection, over all mesh nodes given, or None if no point was found

Return type:

maya.OpenMaya.MFloatPoint or None

mmSolver.utils.raytrace.closest_intersect_with_normal(source, direction, mesh_nodes, test_both_directions=False, max_dist=None, tolerance=None, use_smooth_mesh=None)#

Get the closest intersection point and normal on meshes given a source point and direction

Parameters:
  • source ([float, float, float]) – Origin point of the ray projection.

  • direction ([float, float, float]) – The direction the ray will travel.

  • mesh_nodes ([str, ..]) – Mesh nodes

  • test_both_directions (bool) – testing ray direction both sides; default is False.

  • max_dist (float) – The maximum distance the ray will travel before stopping; default is RAYTRACE_MAX_DIST.

  • tolerance (float) – The minimum ray trace tolerance; default is RAYTRACE_EPSILON.

  • use_smooth_mesh (bool) – Use smooth preview mesh for intersection.

Returns:

The closest world space intersection, over all mesh nodes given, return a tuple of the point and normal, or (None, None), if no point was found.

Return type:

(maya.OpenMaya.MFloatPoint, maya.OpenMaya.MVector) or None

Re-Project#

Re-Projection utilities - converting a 3D transform into a 2D point.

mmSolver.utils.reproject.get_camera_direction_to_world_position(camera_node, world_position)#

Get the direction of the camera toward a given world space position.

The direction vector is normalised.

The camera position is evaluated at the current frame only.

Parameters:
  • camera_node (str) – Camera transform node.

  • world_position ((float, float, float)) – World position; X, Y and Z values.

Returns:

Direction from camera to point.

Return type:

(float, float, float)

mmSolver.utils.reproject.get_camera_direction_to_point(camera_node, point_node)#

Get the direction of the camera toward a given point.

The direction vector is normalised.

The camera position is evaluated at the current frame only.

Parameters:
  • camera_node (str) – Camera transform node.

  • point_node (str) – Transform node to aim at.

Returns:

Direction from camera to point.

Return type:

(float, float, float)

mmSolver.utils.reproject.create_reprojection_on_camera(cam_tfm, cam_shp)#

Create a mmReprojection node, then connect it up as needed.

mmSolver.utils.reproject.find_reprojection_nodes(cam_tfm, cam_shp)#

Find all the reprojection nodes on the camera.

mmSolver.utils.reproject.remove_reprojection_from_camera(cam_tfm, cam_shp)#

Find the mmReprojection node and delete it.

mmSolver.utils.reproject.reset_pan_zoom(cam_tfm, cam_shp)#

Reset the Pan/Zoom camera settings.

Parameters:
  • cam_tfm (str) – Camera transform node

  • cam_shp (str) – Camera shape node.

Return type:

None

mmSolver.utils.reproject.connect_transform_to_reprojection(tfm, reproj)#

Connect ‘tfm’ to the reprojection node, ‘reproj’.

Parameters:
  • tfm (str) – Transform node name to be connected.

  • reproj (str) – The re-projection node.

Rivet#

The ‘rivet.mel technique’ for creating rivets.

‘rivet.mel’ was written by Michael Bazhutkin in 2001. https://www.highend3d.com/maya/script/rivet-button-for-maya

This method uses polygon edges converted into NURBS curves, then placing a point at the average of two different NURBS curves.

class mmSolver.utils.rivet.meshtwoedge.RivetMeshTwoEdge(rivet_transform, rivet_shape, constraint_node, loft_node, point_on_surface_info_node, curve_from_mesh_edge_a_node, curve_from_mesh_edge_b_node)#
property constraint_node#

Alias for field number 2

property curve_from_mesh_edge_a_node#

Alias for field number 5

property curve_from_mesh_edge_b_node#

Alias for field number 6

property loft_node#

Alias for field number 3

property point_on_surface_info_node#

Alias for field number 4

property rivet_shape#

Alias for field number 1

property rivet_transform#

Alias for field number 0

mmSolver.utils.rivet.meshtwoedge.create(mesh_shape, edge_a, edge_b, name=None)#

Create a Rivet position between two edges.

Parameters:
  • mesh_shape (str) – Mesh shape node.

  • edge_a (str) – First edge component path.

  • edge_b (str) – Second edge component path.

Returns:

A rivet object containing names to all the nodes.

Return type:

RivetMeshTwoEdge

Query the Nearest Point On a Mesh surface.

class mmSolver.utils.rivet.nearestpointonmesh.NearestPointData(position, normal, coords, face_index)#
property coords#

Alias for field number 2

property face_index#

Alias for field number 3

property normal#

Alias for field number 1

property position#

Alias for field number 0

mmSolver.utils.rivet.nearestpointonmesh.get_nearest_point_on_mesh(mesh_shape, in_position)#

Get data on the mesh surface, for the nearest position to ‘in_position’.

Create a Rivet using a Point-On-Poly Constraint.

class mmSolver.utils.rivet.pointonpoly.PointOnPolyConstraintNode(node)#
get_node()#
get_attr_name_target_u()#
get_attr_name_target_v()#
get_attr_name_target_weight()#
class mmSolver.utils.rivet.pointonpoly.RivetPointOnPoly(rivet_transform, rivet_shape, point_on_poly_constraint)#
property point_on_poly_constraint#

Alias for field number 2

property rivet_shape#

Alias for field number 1

property rivet_transform#

Alias for field number 0

mmSolver.utils.rivet.pointonpoly.create(mesh_transform, mesh_shape, name=None, parent=None, as_locator=None, uv_coordinate=None, in_position=None)#

Create a Point-on-Poly Rivet.

Parameters:
  • name (None or str) – Name of the Rivet to create.

  • parent (None or str) – The parent node of the newly created Rivet.

  • as_locator (bool) – Should the Point-on-Poly Rivet be created as a locator, or just a transform? By default it a locator.

  • uv_coordinate (None or (float, float)) – The default UV Coordinate of the newly created Rivet.

  • in_position (None or (float, float, float)) – The world-space position of the created Rivet, if None, fall back to the default uv_coordinate.

Returns:

Rivet data structure containing all nodes for rivet.

Return type:

RivetPointOnPoly

Selection#

Selection utilities.

mmSolver.utils.selection.filter_mesh_vertex_selection(selection)#
mmSolver.utils.selection.filter_mesh_edge_selection(selection)#
mmSolver.utils.selection.filter_mesh_face_selection(selection)#
mmSolver.utils.selection.get_mesh_vertex_selection()#
mmSolver.utils.selection.get_mesh_edge_selection()#
mmSolver.utils.selection.get_mesh_face_selection()#
mmSolver.utils.selection.get_soft_selection_weights(only_shape_node=None)#

Get the currently ‘soft’ selected components.

Soft selection may return a list for multiple different nodes.

If ‘only_shape_node’ is given, then soft selections on only that node will be returned, all else will be ignored.

Returns:

List of object mappings of soft selection vertex index to weights, or an empty list.

Return type:

[] or [{int: float}, ..]

Smooth#

Generic data smoothing.

This module is software agnostic and should not rely on any thirdparty software, however if numpy is available, an numpy-accelerated code-path will be used.

Smoothing functions supported:

  • Average

  • Gaussian (blur smoothing)

  • Fourier (frequency smoothing)

Example usage:

import mmSolver.utils.smooth as smooth
import mmSolver.utils.constant as const
data = [1.0, 0.0, 2.0, 0.0, 20000.0]
width = 2.0
new_data = smooth.smooth(const.SMOOTH_TYPE_AVERAGE, data, width)
mmSolver.utils.smooth.smooth(smooth_type, value_array, width)#

Run a Smoothing function, of any type, just pass a ‘smooth type’ in.

Parameters:
  • smooth_type (SMOOTH_TYPE_*) – Type of smoothing operation.

  • value_array ([float, ..]) – Input data to smooth.

  • width (float) – The width to smooth over. Values above 1.0 will perform smoothing. 1.0 or below has no effect.

Returns:

Smoothed copy of ‘value_array’, using the ‘smooth_type’, given.

Return type:

[float, ..]

mmSolver.utils.smooth.average_smooth(value_array, width)#

Average Smooth Function

Note

Uses standard python functions only.

Parameters:
  • value_array ([float, ..]) – Input data to smooth.

  • width (float) – The width to smooth over. Values above 1.0 will perform smoothing. 1.0 or below has no effect.

Returns:

Smoothed copy of ‘value_array’.

Return type:

[float, ..]

mmSolver.utils.smooth.gaussian_smooth(value_array, width)#

Gaussian Smooth Function.

Note

Uses standard python functions only.

Parameters:
  • value_array ([float, ..]) – Input data to smooth.

  • width (float) – The width to smooth over. Values above 1.0 will perform smoothing. 1.0 or below has no effect.

Returns:

Smoothed copy of ‘value_array’.

Return type:

[float, ..]

mmSolver.utils.smooth.fourier_smooth(value_array, width, filtr=None)#

Fourier Smooth Function.

Parameters:
  • value_array ([float, ..]) – Input data to smooth.

  • width (float) – The width to smooth over. Values above 1.0 will perform smoothing. 1.0 or below has no effect.

  • filtr (str) – Type of frequency-space smoothing filter, ‘gaussian’, ‘triangle’ or ‘box’. Default filter is ‘gaussian’.

Returns:

Smoothed copy of ‘value_array’.

Sort#

Sorting utilities.

mmSolver.utils.sort.sort_strings_with_digits(items)#

Sort the given iterable in the way that humans expect.

For example, using the built-in Python ‘sorted’ function without extra arguments sorts:

>>> x = ['a1', 'a2', 'a10']
>>> sorted(x)
['a1', 'a10', 'a2']

This function will correctly sort the numbers on the ends of the letters as a human would expect:

>>> x = ['a1', 'a2', 'a10']
>>> sort_strings_with_digits(x)
['a1', 'a2', 'a10']

Helpful function from: https://stackoverflow.com/questions/2669059/how-to-sort-alpha-numeric-set-in-python

Time#

Time related utilities.

class mmSolver.utils.time.FrameRange(start, end)#
property end#

Alias for field number 1

property start#

Alias for field number 0

mmSolver.utils.time.get_maya_timeline_range_inner()#

Get the Maya frame range (inner bar).

Returns:

Start frame and end frame as FrameRange tuple.

Return type:

FrameRange or (int, int)

mmSolver.utils.time.get_maya_timeline_range_outer()#

Get the Maya frame range (outer bar).

Returns:

Start frame and end frame as FrameRange tuple.

Return type:

FrameRange or (int, int)

mmSolver.utils.time.get_keyframe_times_for_node_attrs(nodes, attrs)#

Query keyframe times on each node attribute (sparse keys)

Parameters:
  • nodes ([str, ..]) – Nodes to query from.

  • attrs ([str, ..]) – Attributes to query keyframes from.

Returns:

{str: [int, ..]}

mmSolver.utils.time.get_frame_range(frame_range_mode, start_frame=None, end_frame=None)#

Get the FrameRange from the mode and start/end frame numbers.

Parameters:
  • frame_range_mode (mmSolver.utils.constant.FRAME_RANGE_MODE_*_VALUE) – The mode or type of frame range to get. For example we can get the current inner or outer timeline defined in the Maya scene.

  • start_frame (int or None) – If the frame_range_mode is set to FRAME_RANGE_MODE_CUSTOM_VALUE, this argument defines the exact start_frame to use. This argument is not used for any other frame_range_mode and can be left as None.

  • end_frame (int or None) – If the frame_range_mode is set to FRAME_RANGE_MODE_CUSTOM_VALUE, this argument defines the exact end_frame to use. This argument is not used for any other frame_range_mode and can be left as None.

Return type:

FrameRange

mmSolver.utils.time.convert_frame_range_to_frame_list(frame_range)#

Convert a FrameRange to a list of integer frame numbers.

Parameters:

frame_range (FrameRange) – The frame range to convert to a list.

Return type:

[int, …] or []

Tools#

Utilities for Tools to help develop and standardise inside mmSolver.

mmSolver.utils.tools.tool_context(use_undo_chunk=None, undo_chunk_name=None, restore_current_frame=None, pre_update_frame=None, post_update_frame=None, use_dg_evaluation_mode=None, disable_viewport=None, disable_viewport_mode=None)#

Create a temporary tool context.

If arguments are not given, the most stable and performant path is used. Arguments are used to remove ambiguity and force specific behaviour, and should therefore only be used when sure it is appropriate in your specific usage. The context is allowed to change default values dynamically, for example based on Maya version used or if a GUI is available.

Example usage:

>>> with tool_context() as tool_ctx:
...     # do something with Maya
...     maya.cmds.createNode('transform')
Parameters:
  • use_undo_chunk (bool or None) – Treat the commands inside this context as a single “chunk” of operations. This makes undo’ing faster, so we don’t need to undo many small changes.

  • undo_chunk_name (str or None) – The name of the undo chunk. This is displayed to the user in the Script Editor when undo’ing. This name is expected to be unique each time. Using the date/time or a UUID for this name may be helpful.

  • restore_current_frame (bool or None) – Keep track of the current frame at the start of the context, then restore to the correct frame number at the end of the context.

  • pre_update_frame (bool or None) – Before starting the context functions, make sure the current frame is updated to help trigger Maya to evaluate.

  • post_update_frame (bool or None) – After finishing the context functions tell Maya to update the frame number to help trigger Maya evaluate attributes and nodes. NOTE: This function only works if restore_current_frame is True.

  • use_dg_evaluation_mode (bool or None) – Changes Maya’s Evaluation mode to DG mode for the duration of the context then reset to whatever preference the user has (in the “Settings/Preferences” window). Using DG Evaluation can dramatically speed up evaluation across time for many tools in mmSolver (as tested on Maya 2017).

  • disable_viewport (bool or None) – Turn off the Viewport inside the context function, and enable it once the context finishes. This can be used to dramatically speed up functions that cause the Maya viewport to update many times.

  • disable_viewport_mode (mmSolver.utils.constant.DISABLE_VIEWPORT_MODE_*_VALUE) – Use the given technique to disable and re-enable the Maya viewport (using the “disable_viewport” flag).

Returns:

Yields (returns) a unique context hash id.

Transform#

Transform utilities, for querying, setting and manipulating transform nodes and matrices.

Features:

  • Store a Maya Transform node as a Python object, irrespective of DAG path names.

  • A Matrix Cache object used to query a Transform Matrix across time.

  • Common functions for querying transforms using Maya Python API 2.

mmSolver.utils.transform.create_dg_context_apitwo(frame)#

Create a Maya DG Context for querying values at time.

Parameters:

frame (None or float or int) – The frame value for the DG Context. This is the time/frame value that will be queried with this DG context.

Returns:

Time DG Context to query at.

Return type:

maya.api.OpenMaya.MDGContext

mmSolver.utils.transform.get_matrix_from_plug_apitwo(plug, ctx)#

Get a matrix plug value at a given DG (time) context.

http://chrisdevito.blogspot.com/2013/04/getting-dat-matrix-maya-python-api-20.html

Parameters:
  • plug (maya.api.OpenMaya.MPlug) – The node.attribute to query.

  • ctx (maya.api.OpenMaya.MDGContext) – Time DG Context to query at.

Returns:

The 4x4 matrix value at the given DG context.

Return type:

maya.api.OpenMaya.MMatrix

mmSolver.utils.transform.get_double_from_plug_apitwo(plug, ctx)#

Get a double plug value at a given DG (time) context.

Parameters:
  • plug (maya.api.OpenMaya.MPlug) – The node.attribute to query.

  • ctx (maya.api.OpenMaya.MDGContext) – Time DG Context to query at.

Returns:

The floating point value at the given DG context.

Return type:

float

mmSolver.utils.transform.get_parent_inverse_matrix_apitwo(node, ctx)#

Get the matrix value of attribute ‘parentInverseMatrix[0]’ at a given DG Context.

Parameters:
  • node (str) – Node path to query values on.

  • ctx (maya.api.OpenMaya.MDGContext) – The (time) context to query the attribute at.

Returns:

The 4x4 matrix value at the given DG context.

Return type:

maya.api.OpenMaya.MMatrix

mmSolver.utils.transform.get_world_matrix_apitwo(node, ctx)#

Get the matrix value of attribute ‘worldMatrix[0]’ at a given DG Context.

Parameters:
  • node (str) – Node path to query values on.

  • ctx (maya.api.OpenMaya.MDGContext) – The (time) context to query the attribute at.

Returns:

The 4x4 matrix value at the given DG context.

Return type:

maya.api.OpenMaya.MMatrix

mmSolver.utils.transform.detect_rotate_pivot_non_zero(tfm_node)#

Given a TransformNode, determine if the node has a non-zero rotate pivot.

Return type:

bool

class mmSolver.utils.transform.TransformNode(node=None)#

Represents a Maya Transform node, and the data associated.

This object store a reference to Maya node, even if the node is renamed or re-parented.

>>> a = TransformNode(node='myNode')
>>> node = a.get_node()
>>> node_uuid = a.get_node_uuid()
>>> tfm_node_parents = a.get_parents()
>>> b = TransformNode()
>>> b.set_node('myNode')
get_node()#

Get the transform node.

Returns:

The transform node name or None

Return type:

None or str or unicode

get_node_uuid()#

The Maya node’s UUID.

Returns:

The node UUID.

Return type:

str

set_node(node)#

Set the underlying Maya node that this object will operate on.

Parameters:

node (str) – Node to set to.

get_parent()#

Get the node directly above the current node.

Returns:

Transform node or None, if the node is parented to world.

Return type:

TransformNode or None

get_parents()#

Get the nodes above the current node.

Returns:

Transform nodes or empty list.

Return type:

[TransformNode, ..]

class mmSolver.utils.transform.TransformMatrixCache#

Hold a list of matrix node/values to be queried and stored in the object.

>>> tfm_node = TransformNode(node='myNode')
>>> times = list(range(1001, 1101))
>>> tfm_matrix_cache = TransformMatrixCache()
>>> tfm_matrix_cache.add_node(tfm_node, times)
>>> tfm_matrix_cache.process()
>>> tfm_matrix_cache.get_node_attr_matrix(tfm_node, times)
clear()#

Clear all the cached values, nodes, attributes and times.

add_node(tfm_node, times)#

Add a TransformNode and set of times to evaluate.

Parameters:
  • tfm_node (TransformNode) – The transform node.

  • times ([int, ..]) – List of times to evaluate.

Return type:

None

add_node_attr(tfm_node, attr_name, times)#

Add a TransformNode / attribute name and set of times to evaluate.

Parameters:
  • tfm_node (TransformNode or str) – The transform node or the Maya UUID of the node.

  • attr_name (str) – The attribute name to add.

  • times ([int, ..]) – List of times to evaluate.

Return type:

None

get_nodes()#

Get all the nodes in the cache.

Returns:

List of node names inside the cache.

Return type:

[str, ..]

process(eval_mode=None)#

Evaluate all the node attributes at times.

Parameters:

eval_mode (mmSolver.utils.constant.EVAL_MODE_*) – What type of evaluation method to use?

Return type:

None

get_attrs_for_node(tfm_node)#

Get the list of attribute names for the node in the cache.

This function allows us to detect if a node is stored with pivot point or not.

Parameters:

tfm_node (TransformNode or str) – The node to look into the cache with.

Returns:

List of attribute names in the cache for this node.

Return type:

[str, ..]

get_node_attr(tfm_node, attr_name, times)#

Get the node attribute matrix data, at given times

Parameters:
  • tfm_node (TransformNode or str) – The transform node to query.

  • attr_name (str) – Name of the attribute (previously added to the cache).

  • times ([int, ..]) – The list of times to query from the cache.

Returns:

List of MMatrix objects for each time requested. If no cached value exists, None is returned in that list entry.

Return type:

[maya.api.OpenMaya.MMatrix or None, ..]

get_node_attr_matrix(tfm_node, attr_name, times)#

Get the node attribute matrix data, at given times

Parameters:
  • tfm_node (TransformNode or str) – The transform node to query.

  • attr_name (str) – Name of the attribute (previously added to the cache).

  • times ([int, ..]) – The list of times to query from the cache.

Returns:

List of MMatrix objects for each time requested. If no cached value exists, None is returned in that list entry.

Return type:

[maya.api.OpenMaya.MMatrix or None, ..]

mmSolver.utils.transform.get_transform_matrix_list(tfm_matrix_cache, times, src_tfm_node, rotate_order=None, eval_mode=None)#

Get the transform values, as raw MTransformationMatrix.

This function does not modify the original node in any way.

src_tfm_node is used to look-up into the cache for values.

Parameters:
  • tfm_matrix_cache (TransformMatrixCache) – A cache holding queried matrix values.

  • times ([int or float, ...]) – The times to set transforms values on.

  • src_tfm_node (TransformNode) – Source node to get cached transform values from.

  • rotate_order (str) – The rotation order to set on the dst_node, or use the existing rotation on the dst_node if rotate_order is None.

Return type:

[maya.api.OpenMaya.MTransformationMatrix, ..]

mmSolver.utils.transform.decompose_matrix(tfm_matrix, prv_rot)#

Decompose a MTransformationMatrix into transform attributes.

Note

It is assumed the given matrix is already re-ordered into the desired rotation order.

Parameters:
  • tfm_matrix (maya.api.OpenMaya.MTransformationMatrix) – Transform matrix to be decomposed.

  • prv_rot ((float, float, float) or None) – The previous rotation values (on the previous frame).

Returns:

Tuple of 9 values: TX, TY, TZ, RX, RY, RZ, SX, SY and SZ.

Return type:

(float, float, float, float, float, float, float, float, float)

mmSolver.utils.transform.set_transform_values(tfm_matrix_cache, times, src_tfm_node, dst_tfm_node, rotate_order=None, delete_static_anim_curves=False, eval_mode=None)#

Set transform node values on a destination node at times, using previously evaluated cached values.

src_tfm_node is used to look-up into the cache for values. dst_tfm_node is the node that will have values set on it. It is possible to have src_tfm_node and dst_tfm_node reference the same Maya node, or even the same TransformNode object.

Note

The function assumes the given destination node has no locked attributes.

Parameters:
  • tfm_matrix_cache (TransformMatrixCache) – A cache holding queried matrix values.

  • times ([int or float, ...]) – The times to set transforms values on.

  • src_tfm_node (TransformNode) – Source node to get cached transform values from.

  • dst_tfm_node (TransformNode) – Destination node set transform values on.

  • rotate_order (str) – The rotation order to set on the dst_node, or use the existing rotation on the dst_node if rotate_order is None.

  • delete_static_anim_curves (bool) – If an animation curve is static, it will be deleted.

  • eval_mode (mmSolver.utils.constant.EVAL_MODE_*) – What type of evaluation method to use?

Return type:

None

Undo#

Undo related tools.

mmSolver.utils.undo.wrap_as_undo_chunk(func)#

Undo/Redo Chunk Decorator.

Puts the wrapped ‘func’ into a single Maya Undo action. If ‘func’ raises and exception, we close the chunk.

mmSolver.utils.undo.undo_chunk_context(name=None)#

Create an undo chunk, using a context manager.

Example usage: >>> with undo_chunk_context() as chunk_name: … # do something with Maya … maya.cmds.createNode(‘transform’)

Parameters:

name (str or None) – A string to use as the unique undo chunk name, or None to generate a random UUID.

Returns:

Yields (returns) the name of the undo chunk.

mmSolver.utils.undo.no_undo_context()#

All statements inside the ‘with’ block will not be added to the Undo stack.

Example usage: >>> with no_undo_context(): … # do something with Maya, not recorded in undo stack … maya.cmds.createNode(‘transform’)

Returns:

Yields (returns)

Viewport#

Utilities for setting and querying viewport related information.

mmSolver.utils.viewport.viewport1_turn_off()#

Turn off Maya UI.

mmSolver.utils.viewport.viewport1_turn_on()#

Turn on Maya UI.

mmSolver.utils.viewport.viewport2_turn_off()#

Turn off Viewport 2.

..note:: This is not supported below Maya 2017.

mmSolver.utils.viewport.viewport2_turn_on()#

Turn on Viewport 2.

..note:: This is not supported below Maya 2017.

mmSolver.utils.viewport.viewport_turn_off(mode=None)#

Turn off Viewport.

Parameters:

mode (mmSolver.utils.constant.DISABLE_VIEWPORT_MODE_*_VALUE) – Set the value to force a specific disable/enable method.

Note

By default mode=None will automatically switch to the fastest implementation based on the version Maya.

mmSolver.utils.viewport.viewport_turn_on(mode=None)#

Turn on the Viewport.

Parameters:

mode (mmSolver.utils.constant.DISABLE_VIEWPORT_MODE_*_VALUE) – Set the value to force a specific disable/enable method.

Note

By default mode=None will automatically switch to the fastest implementation based on the version Maya.

mmSolver.utils.viewport.set_viewport2_active_state(value)#

Set Viewport 2 activation state.

..note:: This is not supported below Maya 2017.

Parameters:

value (bool) – Set activation of the state.

mmSolver.utils.viewport.get_viewport2_active_state()#

Query the Viewport 2 active state.

..note:: This is not supported below Maya 2017.

Return type:

bool

mmSolver.utils.viewport.get_active_model_panel()#

Get the active model panel.

Return type:

str or None

mmSolver.utils.viewport.get_active_model_editor()#

Get the active model editor.

Return type:

str or None

mmSolver.utils.viewport.get_viewport_camera(model_editor)#

Get the camera from the model editor.

Parameters:

model_editor (str) – The viewport model editor to get the camera from.

Returns:

Camera transform and camera shape nodes.

Return type:

(str, str) or (None, None)

mmSolver.utils.viewport.get_all_model_panels()#

Return a list of all Maya model panels.

mmSolver.utils.viewport.get_model_editor_renderer_device_name(model_editor)#

Get the Renderer Device Name from the Model Editor.

Query for the name of the draw API used by the Viewport 2.0 renderer for a 3d modeling viewport. The possible return values are “VirtualDeviceGL” if Maya is set to use OpenGL for Viewport 2.0 or “VirtualDeviceDx11” if Maya is set to use DirectX for Viewport 2.0. If the renderer for the 3d modeling viewport is not Viewport 2.0, an empty string will be returned.

Return type:

str

mmSolver.utils.viewport.get_model_panel_renderer_device_name(model_panel)#

Get the Renderer Device Name from the Model Panel.

Query for the name of the draw API used by the Viewport 2.0 renderer for a 3d modeling viewport. The possible return values are “VirtualDeviceGL” if Maya is set to use OpenGL for Viewport 2.0 or “VirtualDeviceDx11” if Maya is set to use DirectX for Viewport 2.0. If the renderer for the 3d modeling viewport is not Viewport 2.0, an empty string will be returned.

Return type:

str

mmSolver.utils.viewport.get_currently_using_viewport2()#

Detect the currently used Viewport renderer devices, are we using Viewport 2?

Return type:

bool

mmSolver.utils.viewport.get_isolated_nodes(model_panel)#

Return nodes that are being isolated for ‘model_panel’.

mmSolver.utils.viewport.set_isolated_nodes(model_panel, nodes, enable)#

Override the isolate objects on ‘model_panel’.

With an empty list, this function clears the ‘model_panel’s isolate object list.

mmSolver.utils.viewport.get_selection_highlight(model_panel)#

Query the display of selection highlighting.

Parameters:

model_panel (str) – Model panel name to set visibility.

Returns:

True, if the selection highlighting is enable in the model panel/editor.

Return type:

bool

mmSolver.utils.viewport.set_selection_highlight(model_panel, value)#

Query the display of selection highlighting.

Parameters:
  • model_panel (str) – Model panel name to set visibility.

  • value (bool) – Enable or disable selection highlighting?

mmSolver.utils.viewport.get_grid_visibility(model_panel)#

Query the grids visibility in given model panel.

mmSolver.utils.viewport.set_grid_visibility(model_panel, value)#

Set the visibility of grids nodes in the given model panel.

mmSolver.utils.viewport.get_image_plane_visibility(model_panel)#

Query the image plane visibility in given model panel.

mmSolver.utils.viewport.set_image_plane_visibility(model_panel, value)#

Set the visibility of imagePlane nodes in the given model panel.

mmSolver.utils.viewport.get_camera_visibility(model_panel)#

Query the camera visibility in given model panel.

mmSolver.utils.viewport.set_camera_visibility(model_panel, value)#

Set the visibility of camera nodes in the given model panel.

mmSolver.utils.viewport.get_mesh_visibility(model_panel)#

Query the mesh visibility in given model panel.

mmSolver.utils.viewport.set_mesh_visibility(model_panel, value)#

Set the visibility of mesh nodes in the given model panel.

mmSolver.utils.viewport.get_subdiv_visibility(model_panel)#

Query the subdiv visibility in given model panel.

mmSolver.utils.viewport.set_subdiv_visibility(model_panel, value)#

Set the visibility of subdiv nodes in the given model panel.

mmSolver.utils.viewport.get_nurbs_curve_visibility(model_panel)#

Query the NURBS Curve visibility in given model panel.

mmSolver.utils.viewport.set_nurbs_curve_visibility(model_panel, value)#

Set the visibility of NURBS Curve nodes in the given model panel.

mmSolver.utils.viewport.get_nurbs_surface_visibility(model_panel)#

Query the NURBS surface visibility in given model panel.

mmSolver.utils.viewport.set_nurbs_surface_visibility(model_panel, value)#

Set the visibility of NURBS surface nodes in the given model panel.

mmSolver.utils.viewport.get_locator_visibility(model_panel)#

Query the locators visibility in given model panel.

mmSolver.utils.viewport.set_locator_visibility(model_panel, value)#

Set the visibility of locators nodes in the given model panel.

mmSolver.utils.viewport.get_plane_visibility(model_panel)#

Query the plane visibility in given model panel.

mmSolver.utils.viewport.set_plane_visibility(model_panel, value)#

Set the visibility of plane nodes in the given model panel.

mmSolver.utils.viewport.get_light_visibility(model_panel)#

Query the lights visibility in given model panel.

mmSolver.utils.viewport.set_light_visibility(model_panel, value)#

Set the visibility of lights nodes in the given model panel.

mmSolver.utils.viewport.get_joint_visibility(model_panel)#

Query the joints visibility in given model panel.

mmSolver.utils.viewport.set_joint_visibility(model_panel, value)#

Set the visibility of joints nodes in the given model panel.

mmSolver.utils.viewport.get_deformer_visibility(model_panel)#

Query the deformers visibility in given model panel.

mmSolver.utils.viewport.set_deformer_visibility(model_panel, value)#

Set the visibility of deformers nodes in the given model panel.

mmSolver.utils.viewport.get_ik_handle_visibility(model_panel)#

Query the ikHandles visibility in given model panel.

mmSolver.utils.viewport.set_ik_handle_visibility(model_panel, value)#

Set the visibility of ikHandles nodes in the given model panel.

mmSolver.utils.viewport.get_dynamic_visibility(model_panel)#

Query the dynamics visibility in given model panel.

mmSolver.utils.viewport.set_dynamic_visibility(model_panel, value)#

Set the visibility of dynamics nodes in the given model panel.

mmSolver.utils.viewport.get_fluid_visibility(model_panel)#

Query the fluids visibility in given model panel.

mmSolver.utils.viewport.set_fluid_visibility(model_panel, value)#

Set the visibility of fluids nodes in the given model panel.

mmSolver.utils.viewport.get_hair_system_visibility(model_panel)#

Query the hairSystems visibility in given model panel.

mmSolver.utils.viewport.set_hair_system_visibility(model_panel, value)#

Set the visibility of hairSystems nodes in the given model panel.

mmSolver.utils.viewport.get_follicle_visibility(model_panel)#

Query the follicles visibility in given model panel.

mmSolver.utils.viewport.set_follicle_visibility(model_panel, value)#

Set the visibility of follicles nodes in the given model panel.

mmSolver.utils.viewport.get_ncloth_visibility(model_panel)#

Query the nCloths visibility in given model panel.

mmSolver.utils.viewport.set_ncloth_visibility(model_panel, value)#

Set the visibility of nCloths nodes in the given model panel.

mmSolver.utils.viewport.get_nparticle_visibility(model_panel)#

Query the nParticles visibility in given model panel.

mmSolver.utils.viewport.set_nparticle_visibility(model_panel, value)#

Set the visibility of nParticles nodes in the given model panel.

mmSolver.utils.viewport.get_nrigid_visibility(model_panel)#

Query the nRigids visibility in given model panel.

mmSolver.utils.viewport.set_nrigid_visibility(model_panel, value)#

Set the visibility of nRigids nodes in the given model panel.

mmSolver.utils.viewport.get_texture_visibility(model_panel)#

Query the textures visibility in given model panel.

mmSolver.utils.viewport.set_texture_visibility(model_panel, value)#

Set the visibility of textures nodes in the given model panel.

mmSolver.utils.viewport.get_stroke_visibility(model_panel)#

Query the strokes visibility in given model panel.

mmSolver.utils.viewport.set_stroke_visibility(model_panel, value)#

Set the visibility of strokes nodes in the given model panel.

mmSolver.utils.viewport.get_node_type_visibility(model_panel, node_type)#

Query the visibility of ‘node_type’ in the given model panel.

Parameters:
  • model_panel (str) – Model panel name to set visibility.

  • node_type (str) – Node type to get visibility for.

Returns:

The visibility of the given node type.

Return type:

bool

mmSolver.utils.viewport.set_node_type_visibility(model_panel, node_type, value)#

Set the visibility of ‘node_type’ nodes in the given model panel.

Parameters:
  • model_panel (str) – Model panel name to set visibility.

  • node_type (str) – Node type to set visibility for.

  • value (bool) – Visibility of node type.

Constant#

Constant values for utilities.

constant.SMOOTH_TYPE_AVERAGE = 'average'#
constant.SMOOTH_TYPE_GAUSSIAN = 'gaussian'#
constant.SMOOTH_TYPE_FOURIER = 'fourier'#
constant.SMOOTH_TYPES = ['average', 'gaussian', 'fourier']#
constant.RAYTRACE_MAX_DIST = 9999999999.0#
constant.RAYTRACE_EPSILON = 0.0001#
constant.CONFIG_PATH_VAR_NAME = 'MMSOLVER_CONFIG_PATH'#
constant.CONFIG_HOME_DIR_PATH = {'Darwin': '${HOME}/.mmSolver/', 'Linux': '${HOME}/.mmSolver/', 'Windows': '${APPDATA}/mmSolver/'}#
constant.SCENE_DATA_NODE = 'MM_SOLVER_SCENE_DATA'#
constant.SCENE_DATA_ATTR = 'data'#
constant.ROTATE_ORDER_STR_LIST = ['xyz', 'yzx', 'zxy', 'xzy', 'yxz', 'zyx']#
constant.ROTATE_ORDER_INDEX_TO_STR = {0: 'xyz', 1: 'yzx', 2: 'zxy', 3: 'xzy', 4: 'yxz', 5: 'zyx'}#
constant.ROTATE_ORDER_STR_TO_INDEX = {'xyz': 0, 'xzy': 3, 'yxz': 4, 'yzx': 1, 'zxy': 2, 'zyx': 5}#