This commit is contained in:
2025-04-17 04:52:48 +08:00
commit 9985b73dc1
3708 changed files with 2387532 additions and 0 deletions

View File

@ -0,0 +1,4 @@
# Sphinx build info version 1
# This file hashes the configuration used when building these files. When it is not found, a full rebuild will be done.
config: 770bdf94db77f7f7445532076e8cf9ff
tags: 645f666f9bcd5a90fca523b33c5a78b7

Binary file not shown.

After

Width:  |  Height:  |  Size: 66 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 45 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 58 KiB

View File

@ -0,0 +1,11 @@
API
-----------------------------
pose\_wrangler.v2.main
+++++++++++++++++++++++++++++
.. autoclass:: pose_wrangler.v2.main.UERBFAPI
:members:
:undoc-members:
:show-inheritance:
:member-order: bysource

View File

@ -0,0 +1,23 @@
Extensions
=========================================
You can now create custom extensions for PoseWrangler so you can introduce new features without having to edit the
core code base.
Custom extensions can be created by inheriting from the following class:
.. autoclass:: pose_wrangler.v2.model.base_extension.PoseWranglerExtension
:members:
:undoc-members:
:show-inheritance:
:member-order: bysource
When PoseWrangler loads up, it will automatically detect and load any classes that inherit from ``PoseWranglerExtension``
on startup.
.. note::
To make sure that your extension loads, please make sure that it is imported before you start PoseWrangler.
Example extensions can be found under ``pose_wrangler.v2.extensions``

View File

@ -0,0 +1,61 @@
.. Pose Wrangler documentation master file, created by
sphinx-quickstart on Thu May 12 15:11:40 2022.
You can adapt this file completely to your liking, but it should at least
contain the root `toctree` directive.
Pose Wrangler Documentation
=========================================
.. toctree::
:maxdepth: 2
:caption: Contents:
overview
upgrading
mirror_mapping
extensions
api
Overview
===================================
PoseWrangler is a tool for interfacing with Epic's MayaUERBFPlugin. The plugin is distributed by Epic Games and installed via Quixel Bridge.
Versions
-------------------------------
1.0.0:
+++++++++++++++++++++++++++
- Supports legacy scenes created with the UE4RBFSolverNode
- Supports Maya 2018-2022
- Provides upgrade workflow to migrate to V2
2.0.0:
+++++++++++++++++++++++++++
- Supports scenes created with the UERBFSolverNode
- Multiple Driver Support
- Initial blendshape support (WIP)
- Supports Maya 2018-2022
- Support for custom mirror mappings to allow for rigs with naming conventions that deviate from the default UE5 conventions
- Fully automatable via Python and MayaPy
- Serialization/deserialization to dictionary or JSON file
- Support for custom extensions and context menu actions
Contributors
----------------------------
- Chris Evans
- Judd Simantov
- David Corral
- Borna Berc
- Chris Theodosius
Indices and tables
==================
* :ref:`genindex`
* :ref:`modindex`
* :ref:`search`

View File

@ -0,0 +1,59 @@
Mirror Mapping
=========================================
Mirror mapping enables Pose Wrangler to support custom skeletons when mirroring RBF solvers and poses.
Below is the mirror mapping for characters following the MetaHuman naming conventions:
.. code-block:: JSON
{
"solver_expression": "(?P<prefix>[a-zA-Z0-9]+)?(?P<side>_[lr]{1}_)(?P<suffix>[a-zA-Z0-9_]+)",
"transform_expression": "(?P<prefix>[a-zA-Z0-9_]+)?(?P<side>_[lr]{1}_)(?P<suffix>[a-zA-Z0-9_]+)",
"left": {
"solver_syntax": "_l_",
"transform_syntax": "_l_"
},
"right": {
"solver_syntax": "_r_",
"transform_syntax": "_r_"
}
}
.. list-table:: Title
:widths: 25 50
:header-rows: 1
* - Key
- Definition
* - solver_expression
- A regular expression used to match against the solver node name
* - transform_expression
- A regular expression used to match against the transform (joint) node name
* - left
- dictionary containing the expected match for the solver_expression and |br| transform_expression
* - right
- dictionary containing the expected match for the solver_expression and |br| transform_expression
.. note::
As an example if we wanted to mirror a solver called ``calf_l_UERBFSolver`` we first try to match the name
of the solver against the ``solver_expression``. If the match fails, you'll see an error appear in the output
log that the solver name doesn't match the settings defined in mirror mapping.
If the match succeeds, it will then iterate through the groups in the matchdict to determine if one of the groups
matches the ``solver_syntax`` for the left hand side. If it does, it will replace it with the right and vice versa.
In this case, we will end up with a matchdict that looks something like this: |br|
``{"prefix": "calf", "side": "_l_", "suffix": "UERBFSolver"}`` |br|
The mapping will iterate through this dictionary and attempt to match each value against the ``solver_syntax`` of
the ``left`` and ``right`` group defined in mirror mapping. If it matches the ``left`` group it will replace the
``side`` value with the ``solver_syntax`` specified in the ``right`` group resulting in the following dictionary: |br|
``{"prefix": "calf", "side": "_r_", "suffix": "UERBFSolver"}`` |br|
The same thing then happens for the drivers and driven transforms associated with the solver, using ``transform_expression``
and ``transform_syntax`` in place of the solver.
.. |br| raw:: html
<br>

View File

@ -0,0 +1,78 @@
2.0.0 Overview
=========================================
Version 2.0.0 is a refactor of the original Pose Wrangler. The goal of this version has been to separate the UI
logic from the backend, enabling users to automate RBF setup via Python and create custom extensions to add new
functionality.
UI Overview
-------------------------------
.. image:: /images/overview.png
:width: 800
:alt: UI Overview
1) Solver View
++++++++++++++++++++++++++++++++++++++++++++
Here is where you can find a list of all the RBF solvers currently available in the scene and can edit, create, delete
or mirror solvers.
In order to make changes to the poses, drivers or driven transforms/blendshapes you need to toggle a solver into `edit`
mode via the `Edit Selected Solver` button.
.. note::
Only one solver can be edited at a single time.
2) Pose View
++++++++++++++++++++++++++++++++++++++++++++
Here you can find a list of all the poses. In order to make any changes to the poses, you need to edit the corresponding solver.
.. warning::
Most of these are self-explanatory, but is it worth noting that `Mute Pose` will enable and disable the pose on the
solver via the `targetEnable` attribute. This means that if the RBF solver node is set to use `automatic radius`
then the radius will be calculated without the influence of the muted poses.
3) Driver View
++++++++++++++++++++++++++++++++++++++++++++
2.0.0 supports multiple drivers. Here you can add/remove driver transforms.
4) Driven Transforms / Blendshape View
++++++++++++++++++++++++++++++++++++++++++++
Here you can add/remove driven transforms and create/add blendshapes.
.. note::
The blendshape workflow is currently a work in progress and may change in the future.
5) Extensions and Settings View
++++++++++++++++++++++++++++++++++++++++++++
Pose Wrangler now supports writing custom extensions for the tool that can be embedded into the UI here.
`Core Extensions` are default extensions that ship with Pose Wrangler. `Pose Exporter` is an example of a custom
extension used by the MetaHuman team. For more information on how these extensions work and how to create your own,
please refer to the :doc:`extensions` page.
You can also change the mirror mapping, which will allow you to specify a custom mapping if your skeleton does not
match the default MetaHuman skeleton and the mirror solver/pose functionality is causing unexpected results.
6) Top Menu
++++++++++++++++++++++++++++++++++++++++++++
Here you can import/export RBF solvers to/from a JSON file, change the theme and view the help.
7) Output Log
++++++++++++++++++++++++++++++++++++++++++++
Displays debug, info, warning and error messages.

View File

@ -0,0 +1,20 @@
Upgrading to 2.0.0
========================================
When you load up Pose Wrangler with a scene that contains `UE4RBFSolverNode` you will be greeted with the new legacy
version of PoseWrangler. This version is almost identical with the version previously available via GitHub, with the
addition of the log window and the upgrade button.
If you have the new version of the plugin available you will be presented with an option to upgrade your scene at the
top of the Pose Wrangler window. Pressing this button will execute an upgrade script that will replace all the
`UE4RBFSolverNode` with `UERBFSolverNode` and clean up old/redundant nodes left lingering in the scene.
.. image:: /images/upgrade.png
:width: 800
:alt: UI Overview
If the upgrade is successful you will be presented with the new tool window.
.. image:: /images/v2.png
:width: 800
:alt: UI Overview

View File

@ -0,0 +1,906 @@
/*
* basic.css
* ~~~~~~~~~
*
* Sphinx stylesheet -- basic theme.
*
* :copyright: Copyright 2007-2022 by the Sphinx team, see AUTHORS.
* :license: BSD, see LICENSE for details.
*
*/
/* -- main layout ----------------------------------------------------------- */
div.clearer {
clear: both;
}
div.section::after {
display: block;
content: '';
clear: left;
}
/* -- relbar ---------------------------------------------------------------- */
div.related {
width: 100%;
font-size: 90%;
}
div.related h3 {
display: none;
}
div.related ul {
margin: 0;
padding: 0 0 0 10px;
list-style: none;
}
div.related li {
display: inline;
}
div.related li.right {
float: right;
margin-right: 5px;
}
/* -- sidebar --------------------------------------------------------------- */
div.sphinxsidebarwrapper {
padding: 10px 5px 0 10px;
}
div.sphinxsidebar {
float: left;
width: 230px;
margin-left: -100%;
font-size: 90%;
word-wrap: break-word;
overflow-wrap : break-word;
}
div.sphinxsidebar ul {
list-style: none;
}
div.sphinxsidebar ul ul,
div.sphinxsidebar ul.want-points {
margin-left: 20px;
list-style: square;
}
div.sphinxsidebar ul ul {
margin-top: 0;
margin-bottom: 0;
}
div.sphinxsidebar form {
margin-top: 10px;
}
div.sphinxsidebar input {
border: 1px solid #98dbcc;
font-family: sans-serif;
font-size: 1em;
}
div.sphinxsidebar #searchbox form.search {
overflow: hidden;
}
div.sphinxsidebar #searchbox input[type="text"] {
float: left;
width: 80%;
padding: 0.25em;
box-sizing: border-box;
}
div.sphinxsidebar #searchbox input[type="submit"] {
float: left;
width: 20%;
border-left: none;
padding: 0.25em;
box-sizing: border-box;
}
img {
border: 0;
max-width: 100%;
}
/* -- search page ----------------------------------------------------------- */
ul.search {
margin: 10px 0 0 20px;
padding: 0;
}
ul.search li {
padding: 5px 0 5px 20px;
background-image: url(file.png);
background-repeat: no-repeat;
background-position: 0 7px;
}
ul.search li a {
font-weight: bold;
}
ul.search li p.context {
color: #888;
margin: 2px 0 0 30px;
text-align: left;
}
ul.keywordmatches li.goodmatch a {
font-weight: bold;
}
/* -- index page ------------------------------------------------------------ */
table.contentstable {
width: 90%;
margin-left: auto;
margin-right: auto;
}
table.contentstable p.biglink {
line-height: 150%;
}
a.biglink {
font-size: 1.3em;
}
span.linkdescr {
font-style: italic;
padding-top: 5px;
font-size: 90%;
}
/* -- general index --------------------------------------------------------- */
table.indextable {
width: 100%;
}
table.indextable td {
text-align: left;
vertical-align: top;
}
table.indextable ul {
margin-top: 0;
margin-bottom: 0;
list-style-type: none;
}
table.indextable > tbody > tr > td > ul {
padding-left: 0em;
}
table.indextable tr.pcap {
height: 10px;
}
table.indextable tr.cap {
margin-top: 10px;
background-color: #f2f2f2;
}
img.toggler {
margin-right: 3px;
margin-top: 3px;
cursor: pointer;
}
div.modindex-jumpbox {
border-top: 1px solid #ddd;
border-bottom: 1px solid #ddd;
margin: 1em 0 1em 0;
padding: 0.4em;
}
div.genindex-jumpbox {
border-top: 1px solid #ddd;
border-bottom: 1px solid #ddd;
margin: 1em 0 1em 0;
padding: 0.4em;
}
/* -- domain module index --------------------------------------------------- */
table.modindextable td {
padding: 2px;
border-collapse: collapse;
}
/* -- general body styles --------------------------------------------------- */
div.body {
min-width: 450px;
max-width: 800px;
}
div.body p, div.body dd, div.body li, div.body blockquote {
-moz-hyphens: auto;
-ms-hyphens: auto;
-webkit-hyphens: auto;
hyphens: auto;
}
a.headerlink {
visibility: hidden;
}
a.brackets:before,
span.brackets > a:before{
content: "[";
}
a.brackets:after,
span.brackets > a:after {
content: "]";
}
h1:hover > a.headerlink,
h2:hover > a.headerlink,
h3:hover > a.headerlink,
h4:hover > a.headerlink,
h5:hover > a.headerlink,
h6:hover > a.headerlink,
dt:hover > a.headerlink,
caption:hover > a.headerlink,
p.caption:hover > a.headerlink,
div.code-block-caption:hover > a.headerlink {
visibility: visible;
}
div.body p.caption {
text-align: inherit;
}
div.body td {
text-align: left;
}
.first {
margin-top: 0 !important;
}
p.rubric {
margin-top: 30px;
font-weight: bold;
}
img.align-left, figure.align-left, .figure.align-left, object.align-left {
clear: left;
float: left;
margin-right: 1em;
}
img.align-right, figure.align-right, .figure.align-right, object.align-right {
clear: right;
float: right;
margin-left: 1em;
}
img.align-center, figure.align-center, .figure.align-center, object.align-center {
display: block;
margin-left: auto;
margin-right: auto;
}
img.align-default, figure.align-default, .figure.align-default {
display: block;
margin-left: auto;
margin-right: auto;
}
.align-left {
text-align: left;
}
.align-center {
text-align: center;
}
.align-default {
text-align: center;
}
.align-right {
text-align: right;
}
/* -- sidebars -------------------------------------------------------------- */
div.sidebar,
aside.sidebar {
margin: 0 0 0.5em 1em;
border: 1px solid #ddb;
padding: 7px;
background-color: #ffe;
width: 40%;
float: right;
clear: right;
overflow-x: auto;
}
p.sidebar-title {
font-weight: bold;
}
div.admonition, div.topic, blockquote {
clear: left;
}
/* -- topics ---------------------------------------------------------------- */
div.topic {
border: 1px solid #ccc;
padding: 7px;
margin: 10px 0 10px 0;
}
p.topic-title {
font-size: 1.1em;
font-weight: bold;
margin-top: 10px;
}
/* -- admonitions ----------------------------------------------------------- */
div.admonition {
margin-top: 10px;
margin-bottom: 10px;
padding: 7px;
}
div.admonition dt {
font-weight: bold;
}
p.admonition-title {
margin: 0px 10px 5px 0px;
font-weight: bold;
}
div.body p.centered {
text-align: center;
margin-top: 25px;
}
/* -- content of sidebars/topics/admonitions -------------------------------- */
div.sidebar > :last-child,
aside.sidebar > :last-child,
div.topic > :last-child,
div.admonition > :last-child {
margin-bottom: 0;
}
div.sidebar::after,
aside.sidebar::after,
div.topic::after,
div.admonition::after,
blockquote::after {
display: block;
content: '';
clear: both;
}
/* -- tables ---------------------------------------------------------------- */
table.docutils {
margin-top: 10px;
margin-bottom: 10px;
border: 0;
border-collapse: collapse;
}
table.align-center {
margin-left: auto;
margin-right: auto;
}
table.align-default {
margin-left: auto;
margin-right: auto;
}
table caption span.caption-number {
font-style: italic;
}
table caption span.caption-text {
}
table.docutils td, table.docutils th {
padding: 1px 8px 1px 5px;
border-top: 0;
border-left: 0;
border-right: 0;
border-bottom: 1px solid #aaa;
}
table.footnote td, table.footnote th {
border: 0 !important;
}
th {
text-align: left;
padding-right: 5px;
}
table.citation {
border-left: solid 1px gray;
margin-left: 1px;
}
table.citation td {
border-bottom: none;
}
th > :first-child,
td > :first-child {
margin-top: 0px;
}
th > :last-child,
td > :last-child {
margin-bottom: 0px;
}
/* -- figures --------------------------------------------------------------- */
div.figure, figure {
margin: 0.5em;
padding: 0.5em;
}
div.figure p.caption, figcaption {
padding: 0.3em;
}
div.figure p.caption span.caption-number,
figcaption span.caption-number {
font-style: italic;
}
div.figure p.caption span.caption-text,
figcaption span.caption-text {
}
/* -- field list styles ----------------------------------------------------- */
table.field-list td, table.field-list th {
border: 0 !important;
}
.field-list ul {
margin: 0;
padding-left: 1em;
}
.field-list p {
margin: 0;
}
.field-name {
-moz-hyphens: manual;
-ms-hyphens: manual;
-webkit-hyphens: manual;
hyphens: manual;
}
/* -- hlist styles ---------------------------------------------------------- */
table.hlist {
margin: 1em 0;
}
table.hlist td {
vertical-align: top;
}
/* -- object description styles --------------------------------------------- */
.sig {
font-family: 'Consolas', 'Menlo', 'DejaVu Sans Mono', 'Bitstream Vera Sans Mono', monospace;
}
.sig-name, code.descname {
background-color: transparent;
font-weight: bold;
}
.sig-name {
font-size: 1.1em;
}
code.descname {
font-size: 1.2em;
}
.sig-prename, code.descclassname {
background-color: transparent;
}
.optional {
font-size: 1.3em;
}
.sig-paren {
font-size: larger;
}
.sig-param.n {
font-style: italic;
}
/* C++ specific styling */
.sig-inline.c-texpr,
.sig-inline.cpp-texpr {
font-family: unset;
}
.sig.c .k, .sig.c .kt,
.sig.cpp .k, .sig.cpp .kt {
color: #0033B3;
}
.sig.c .m,
.sig.cpp .m {
color: #1750EB;
}
.sig.c .s, .sig.c .sc,
.sig.cpp .s, .sig.cpp .sc {
color: #067D17;
}
/* -- other body styles ----------------------------------------------------- */
ol.arabic {
list-style: decimal;
}
ol.loweralpha {
list-style: lower-alpha;
}
ol.upperalpha {
list-style: upper-alpha;
}
ol.lowerroman {
list-style: lower-roman;
}
ol.upperroman {
list-style: upper-roman;
}
:not(li) > ol > li:first-child > :first-child,
:not(li) > ul > li:first-child > :first-child {
margin-top: 0px;
}
:not(li) > ol > li:last-child > :last-child,
:not(li) > ul > li:last-child > :last-child {
margin-bottom: 0px;
}
ol.simple ol p,
ol.simple ul p,
ul.simple ol p,
ul.simple ul p {
margin-top: 0;
}
ol.simple > li:not(:first-child) > p,
ul.simple > li:not(:first-child) > p {
margin-top: 0;
}
ol.simple p,
ul.simple p {
margin-bottom: 0;
}
dl.footnote > dt,
dl.citation > dt {
float: left;
margin-right: 0.5em;
}
dl.footnote > dd,
dl.citation > dd {
margin-bottom: 0em;
}
dl.footnote > dd:after,
dl.citation > dd:after {
content: "";
clear: both;
}
dl.field-list {
display: grid;
grid-template-columns: fit-content(30%) auto;
}
dl.field-list > dt {
font-weight: bold;
word-break: break-word;
padding-left: 0.5em;
padding-right: 5px;
}
dl.field-list > dt:after {
content: ":";
}
dl.field-list > dd {
padding-left: 0.5em;
margin-top: 0em;
margin-left: 0em;
margin-bottom: 0em;
}
dl {
margin-bottom: 15px;
}
dd > :first-child {
margin-top: 0px;
}
dd ul, dd table {
margin-bottom: 10px;
}
dd {
margin-top: 3px;
margin-bottom: 10px;
margin-left: 30px;
}
dl > dd:last-child,
dl > dd:last-child > :last-child {
margin-bottom: 0;
}
dt:target, span.highlighted {
background-color: #fbe54e;
}
rect.highlighted {
fill: #fbe54e;
}
dl.glossary dt {
font-weight: bold;
font-size: 1.1em;
}
.versionmodified {
font-style: italic;
}
.system-message {
background-color: #fda;
padding: 5px;
border: 3px solid red;
}
.footnote:target {
background-color: #ffa;
}
.line-block {
display: block;
margin-top: 1em;
margin-bottom: 1em;
}
.line-block .line-block {
margin-top: 0;
margin-bottom: 0;
margin-left: 1.5em;
}
.guilabel, .menuselection {
font-family: sans-serif;
}
.accelerator {
text-decoration: underline;
}
.classifier {
font-style: oblique;
}
.classifier:before {
font-style: normal;
margin: 0 0.5em;
content: ":";
display: inline-block;
}
abbr, acronym {
border-bottom: dotted 1px;
cursor: help;
}
/* -- code displays --------------------------------------------------------- */
pre {
overflow: auto;
overflow-y: hidden; /* fixes display issues on Chrome browsers */
}
pre, div[class*="highlight-"] {
clear: both;
}
span.pre {
-moz-hyphens: none;
-ms-hyphens: none;
-webkit-hyphens: none;
hyphens: none;
white-space: nowrap;
}
div[class*="highlight-"] {
margin: 1em 0;
}
td.linenos pre {
border: 0;
background-color: transparent;
color: #aaa;
}
table.highlighttable {
display: block;
}
table.highlighttable tbody {
display: block;
}
table.highlighttable tr {
display: flex;
}
table.highlighttable td {
margin: 0;
padding: 0;
}
table.highlighttable td.linenos {
padding-right: 0.5em;
}
table.highlighttable td.code {
flex: 1;
overflow: hidden;
}
.highlight .hll {
display: block;
}
div.highlight pre,
table.highlighttable pre {
margin: 0;
}
div.code-block-caption + div {
margin-top: 0;
}
div.code-block-caption {
margin-top: 1em;
padding: 2px 5px;
font-size: small;
}
div.code-block-caption code {
background-color: transparent;
}
table.highlighttable td.linenos,
span.linenos,
div.highlight span.gp { /* gp: Generic.Prompt */
user-select: none;
-webkit-user-select: text; /* Safari fallback only */
-webkit-user-select: none; /* Chrome/Safari */
-moz-user-select: none; /* Firefox */
-ms-user-select: none; /* IE10+ */
}
div.code-block-caption span.caption-number {
padding: 0.1em 0.3em;
font-style: italic;
}
div.code-block-caption span.caption-text {
}
div.literal-block-wrapper {
margin: 1em 0;
}
code.xref, a code {
background-color: transparent;
font-weight: bold;
}
h1 code, h2 code, h3 code, h4 code, h5 code, h6 code {
background-color: transparent;
}
.viewcode-link {
float: right;
}
.viewcode-back {
float: right;
font-family: sans-serif;
}
div.viewcode-block:target {
margin: -1px -10px;
padding: 0 10px;
}
/* -- math display ---------------------------------------------------------- */
img.math {
vertical-align: middle;
}
div.body div.math p {
text-align: center;
}
span.eqno {
float: right;
}
span.eqno a.headerlink {
position: absolute;
z-index: 1;
}
div.math:hover a.headerlink {
visibility: visible;
}
/* -- printout stylesheet --------------------------------------------------- */
@media print({
div.document,
div.documentwrapper,
div.bodywrapper {
margin: 0 !important;
width: 100%;
}
div.sphinxsidebar,
div.related,
div.footer,
#top-link {
display: none;
}
}

View File

@ -0,0 +1 @@
.fa:before{-webkit-font-smoothing:antialiased}.clearfix{*zoom:1}.clearfix:after,.clearfix:before{display:table;content:""}.clearfix:after{clear:both}@font-face{font-family:FontAwesome;font-style:normal;font-weight:400;src:url(fonts/fontawesome-webfont.eot?674f50d287a8c48dc19ba404d20fe713?#iefix) format("embedded-opentype"),url(fonts/fontawesome-webfont.woff2?af7ae505a9eed503f8b8e6982036873e) format("woff2"),url(fonts/fontawesome-webfont.woff?fee66e712a8a08eef5805a46892932ad) format("woff"),url(fonts/fontawesome-webfont.ttf?b06871f281fee6b241d60582ae9369b9) format("truetype"),url(fonts/fontawesome-webfont.svg?912ec66d7572ff821749319396470bde#FontAwesome) format("svg")}.fa:before{font-family:FontAwesome;font-style:normal;font-weight:400;line-height:1}.fa:before,a .fa{text-decoration:inherit}.fa:before,a .fa,li .fa{display:inline-block}li .fa-large:before{width:1.875em}ul.fas{list-style-type:none;margin-left:2em;text-indent:-.8em}ul.fas li .fa{width:.8em}ul.fas li .fa-large:before{vertical-align:baseline}.fa-book:before,.icon-book:before{content:"\f02d"}.fa-caret-down:before,.icon-caret-down:before{content:"\f0d7"}.fa-caret-up:before,.icon-caret-up:before{content:"\f0d8"}.fa-caret-left:before,.icon-caret-left:before{content:"\f0d9"}.fa-caret-right:before,.icon-caret-right:before{content:"\f0da"}.rst-versions{position:fixed;bottom:0;left:0;width:300px;color:#fcfcfc;background:#1f1d1d;font-family:Lato,proxima-nova,Helvetica Neue,Arial,sans-serif;z-index:400}.rst-versions a{color:#2980b9;text-decoration:none}.rst-versions .rst-badge-small{display:none}.rst-versions .rst-current-version{padding:12px;background-color:#272525;display:block;text-align:right;font-size:90%;cursor:pointer;color:#27ae60}.rst-versions .rst-current-version:after{clear:both;content:"";display:block}.rst-versions .rst-current-version .fa{color:#fcfcfc}.rst-versions .rst-current-version .fa-book,.rst-versions .rst-current-version .icon-book{float:left}.rst-versions .rst-current-version.rst-out-of-date{background-color:#e74c3c;color:#fff}.rst-versions .rst-current-version.rst-active-old-version{background-color:#f1c40f;color:#000}.rst-versions.shift-up{height:auto;max-height:100%;overflow-y:scroll}.rst-versions.shift-up .rst-other-versions{display:block}.rst-versions .rst-other-versions{font-size:90%;padding:12px;color:grey;display:none}.rst-versions .rst-other-versions hr{display:block;height:1px;border:0;margin:20px 0;padding:0;border-top:1px solid #413d3d}.rst-versions .rst-other-versions dd{display:inline-block;margin:0}.rst-versions .rst-other-versions dd a{display:inline-block;padding:6px;color:#fcfcfc}.rst-versions.rst-badge{width:auto;bottom:20px;right:20px;left:auto;border:none;max-width:300px;max-height:90%}.rst-versions.rst-badge .fa-book,.rst-versions.rst-badge .icon-book{float:none;line-height:30px}.rst-versions.rst-badge.shift-up .rst-current-version{text-align:right}.rst-versions.rst-badge.shift-up .rst-current-version .fa-book,.rst-versions.rst-badge.shift-up .rst-current-version .icon-book{float:left}.rst-versions.rst-badge>.rst-current-version{width:auto;height:30px;line-height:30px;padding:0 6px;display:block;text-align:center}@media screen and (max-width:768px){.rst-versions{width:85%;display:none}.rst-versions.shift{display:block}}

File diff suppressed because it is too large Load Diff

After

Width:  |  Height:  |  Size: 434 KiB

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,358 @@
/*
* doctools.js
* ~~~~~~~~~~~
*
* Sphinx JavaScript utilities for all documentation.
*
* :copyright: Copyright 2007-2022 by the Sphinx team, see AUTHORS.
* :license: BSD, see LICENSE for details.
*
*/
/**
* select a different prefix for underscore
*/
$u = _.noConflict();
/**
* make the code below compatible with browsers without
* an installed firebug like debugger
if (!window.console || !console.firebug) {
var names = ["log", "debug", "info", "warn", "error", "assert", "dir",
"dirxml", "group", "groupEnd", "time", "timeEnd", "count", "trace",
"profile", "profileEnd"];
window.console = {};
for (var i = 0; i < names.length; ++i)
window.console[names[i]] = function() {};
}
*/
/**
* small helper function to urldecode strings
*
* See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/decodeURIComponent#Decoding_query_parameters_from_a_URL
*/
jQuery.urldecode = function(x) {
if (!x) {
return x
}
return decodeURIComponent(x.replace(/\+/g, ' '));
};
/**
* small helper function to urlencode strings
*/
jQuery.urlencode = encodeURIComponent;
/**
* This function returns the parsed url parameters of the
* current request. Multiple values per key are supported,
* it will always return arrays of strings for the value parts.
*/
jQuery.getQueryParameters = function(s) {
if (typeof s === 'undefined')
s = document.location.search;
var parts = s.substr(s.indexOf('?') + 1).split('&');
var result = {};
for (var i = 0; i < parts.length; i++) {
var tmp = parts[i].split('=', 2);
var key = jQuery.urldecode(tmp[0]);
var value = jQuery.urldecode(tmp[1]);
if (key in result)
result[key].push(value);
else
result[key] = [value];
}
return result;
};
/**
* highlight a given string on a jquery object by wrapping it in
* span elements with the given class name.
*/
jQuery.fn.highlightText = function(text, className) {
function highlight(node, addItems) {
if (node.nodeType === 3) {
var val = node.nodeValue;
var pos = val.toLowerCase().indexOf(text);
if (pos >= 0 &&
!jQuery(node.parentNode).hasClass(className) &&
!jQuery(node.parentNode).hasClass("nohighlight")) {
var span;
var isInSVG = jQuery(node).closest("body, svg, foreignObject").is("svg");
if (isInSVG) {
span = document.createElementNS("http://www.w3.org/2000/svg", "tspan");
} else {
span = document.createElement("span");
span.className = className;
}
span.appendChild(document.createTextNode(val.substr(pos, text.length)));
node.parentNode.insertBefore(span, node.parentNode.insertBefore(
document.createTextNode(val.substr(pos + text.length)),
node.nextSibling));
node.nodeValue = val.substr(0, pos);
if (isInSVG) {
var rect = document.createElementNS("http://www.w3.org/2000/svg", "rect");
var bbox = node.parentElement.getBBox();
rect.x.baseVal.value = bbox.x;
rect.y.baseVal.value = bbox.y;
rect.width.baseVal.value = bbox.width;
rect.height.baseVal.value = bbox.height;
rect.setAttribute('class', className);
addItems.push({
"parent": node.parentNode,
"target": rect});
}
}
}
else if (!jQuery(node).is("button, select, textarea")) {
jQuery.each(node.childNodes, function() {
highlight(this, addItems);
});
}
}
var addItems = [];
var result = this.each(function() {
highlight(this, addItems);
});
for (var i = 0; i < addItems.length; ++i) {
jQuery(addItems[i].parent).before(addItems[i].target);
}
return result;
};
/*
* backward compatibility for jQuery.browser
* This will be supported until firefox bug is fixed.
*/
if (!jQuery.browser) {
jQuery.uaMatch = function(ua) {
ua = ua.toLowerCase();
var match = /(chrome)[ \/]([\w.]+)/.exec(ua) ||
/(webkit)[ \/]([\w.]+)/.exec(ua) ||
/(opera)(?:.*version|)[ \/]([\w.]+)/.exec(ua) ||
/(msie) ([\w.]+)/.exec(ua) ||
ua.indexOf("compatible") < 0 && /(mozilla)(?:.*? rv:([\w.]+)|)/.exec(ua) ||
[];
return {
browser: match[ 1 ] || "",
version: match[ 2 ] || "0"
};
};
jQuery.browser = {};
jQuery.browser[jQuery.uaMatch(navigator.userAgent).browser] = true;
}
/**
* Small JavaScript module for the documentation.
*/
var Documentation = {
init : function() {
this.fixFirefoxAnchorBug();
this.highlightSearchWords();
this.initIndexTable();
this.initOnKeyListeners();
},
/**
* i18n support
*/
TRANSLATIONS : {},
PLURAL_EXPR : function(n) { return n === 1 ? 0 : 1; },
LOCALE : 'unknown',
// gettext and ngettext don't access this so that the functions
// can safely bound to a different name (_ = Documentation.gettext)
gettext : function(string) {
var translated = Documentation.TRANSLATIONS[string];
if (typeof translated === 'undefined')
return string;
return (typeof translated === 'string') ? translated : translated[0];
},
ngettext : function(singular, plural, n) {
var translated = Documentation.TRANSLATIONS[singular];
if (typeof translated === 'undefined')
return (n == 1) ? singular : plural;
return translated[Documentation.PLURALEXPR(n)];
},
addTranslations : function(catalog) {
for (var key in catalog.messages)
this.TRANSLATIONS[key] = catalog.messages[key];
this.PLURAL_EXPR = new Function('n', 'return +(' + catalog.plural_expr + ')');
this.LOCALE = catalog.locale;
},
/**
* add context elements like header anchor links
*/
addContextElements : function() {
$('div[id] > :header:first').each(function() {
$('<a class="headerlink">\u00B6</a>').
attr('href', '#' + this.id).
attr('title', _('Permalink to this headline')).
appendTo(this);
});
$('dt[id]').each(function() {
$('<a class="headerlink">\u00B6</a>').
attr('href', '#' + this.id).
attr('title', _('Permalink to this definition')).
appendTo(this);
});
},
/**
* workaround a firefox stupidity
* see: https://bugzilla.mozilla.org/show_bug.cgi?id=645075
*/
fixFirefoxAnchorBug : function() {
if (document.location.hash && $.browser.mozilla)
window.setTimeout(function() {
document.location.href += '';
}, 10);
},
/**
* highlight the search words provided in the url in the text
*/
highlightSearchWords : function() {
var params = $.getQueryParameters();
var terms = (params.highlight) ? params.highlight[0].split(/\s+/) : [];
if (terms.length) {
var body = $('div.body');
if (!body.length) {
body = $('body');
}
window.setTimeout(function() {
$.each(terms, function() {
body.highlightText(this.toLowerCase(), 'highlighted');
});
}, 10);
$('<p class="highlight-link"><a href="javascript:Documentation.' +
'hideSearchWords()">' + _('Hide Search Matches') + '</a></p>')
.appendTo($('#searchbox'));
}
},
/**
* init the domain index toggle buttons
*/
initIndexTable : function() {
var togglers = $('img.toggler').click(function() {
var src = $(this).attr('src');
var idnum = $(this).attr('id').substr(7);
$('tr.cg-' + idnum).toggle();
if (src.substr(-9) === 'minus.png')
$(this).attr('src', src.substr(0, src.length-9) + 'plus.png');
else
$(this).attr('src', src.substr(0, src.length-8) + 'minus.png');
}).css('display', '');
if (DOCUMENTATION_OPTIONS.COLLAPSE_INDEX) {
togglers.click();
}
},
/**
* helper function to hide the search marks again
*/
hideSearchWords : function() {
$('#searchbox .highlight-link').fadeOut(300);
$('span.highlighted').removeClass('highlighted');
var url = new URL(window.location);
url.searchParams.delete('highlight');
window.history.replaceState({}, '', url);
},
/**
* helper function to focus on search bar
*/
focusSearchBar : function() {
$('input[name=q]').first().focus();
},
/**
* make the url absolute
*/
makeURL : function(relativeURL) {
return DOCUMENTATION_OPTIONS.URL_ROOT + '/' + relativeURL;
},
/**
* get the current relative url
*/
getCurrentURL : function() {
var path = document.location.pathname;
var parts = path.split(/\//);
$.each(DOCUMENTATION_OPTIONS.URL_ROOT.split(/\//), function() {
if (this === '..')
parts.pop();
});
var url = parts.join('/');
return path.substring(url.lastIndexOf('/') + 1, path.length - 1);
},
initOnKeyListeners: function() {
// only install a listener if it is really needed
if (!DOCUMENTATION_OPTIONS.NAVIGATION_WITH_KEYS &&
!DOCUMENTATION_OPTIONS.ENABLE_SEARCH_SHORTCUTS)
return;
$(document).keydown(function(event) {
var activeElementType = document.activeElement.tagName;
// don't navigate when in search box, textarea, dropdown or button
if (activeElementType !== 'TEXTAREA' && activeElementType !== 'INPUT' && activeElementType !== 'SELECT'
&& activeElementType !== 'BUTTON') {
if (event.altKey || event.ctrlKey || event.metaKey)
return;
if (!event.shiftKey) {
switch (event.key) {
case 'ArrowLeft':
if (!DOCUMENTATION_OPTIONS.NAVIGATION_WITH_KEYS)
break;
var prevHref = $('link[rel="prev"]').prop('href');
if (prevHref) {
window.location.href = prevHref;
return false;
}
break;
case 'ArrowRight':
if (!DOCUMENTATION_OPTIONS.NAVIGATION_WITH_KEYS)
break;
var nextHref = $('link[rel="next"]').prop('href');
if (nextHref) {
window.location.href = nextHref;
return false;
}
break;
case 'Escape':
if (!DOCUMENTATION_OPTIONS.ENABLE_SEARCH_SHORTCUTS)
break;
Documentation.hideSearchWords();
return false;
}
}
// some keyboard layouts may need Shift to get /
switch (event.key) {
case '/':
if (!DOCUMENTATION_OPTIONS.ENABLE_SEARCH_SHORTCUTS)
break;
Documentation.focusSearchBar();
return false;
}
}
});
}
};
// quick alias for translations
_ = Documentation.gettext;
$(document).ready(function() {
Documentation.init();
});

View File

@ -0,0 +1,14 @@
var DOCUMENTATION_OPTIONS = {
URL_ROOT: document.getElementById("documentation_options").getAttribute('data-url_root'),
VERSION: '2.0.0',
LANGUAGE: 'None',
COLLAPSE_INDEX: false,
BUILDER: 'html',
FILE_SUFFIX: '.html',
LINK_SUFFIX: '.html',
HAS_SOURCE: true,
SOURCELINK_SUFFIX: '.txt',
NAVIGATION_WITH_KEYS: false,
SHOW_SEARCH_SUMMARY: true,
ENABLE_SEARCH_SHORTCUTS: true,
};

Binary file not shown.

After

Width:  |  Height:  |  Size: 286 B

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1 @@
!function(e){var t={};function r(n){if(t[n])return t[n].exports;var o=t[n]={i:n,l:!1,exports:{}};return e[n].call(o.exports,o,o.exports,r),o.l=!0,o.exports}r.m=e,r.c=t,r.d=function(e,t,n){r.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:n})},r.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},r.t=function(e,t){if(1&t&&(e=r(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var n=Object.create(null);if(r.r(n),Object.defineProperty(n,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var o in e)r.d(n,o,function(t){return e[t]}.bind(null,o));return n},r.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return r.d(t,"a",t),t},r.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},r.p="",r(r.s=4)}({4:function(e,t,r){}});

View File

@ -0,0 +1,4 @@
/**
* @preserve HTML5 Shiv 3.7.3-pre | @afarkas @jdalton @jon_neal @rem | MIT/GPL2 Licensed
*/
!function(a,b){function c(a,b){var c=a.createElement("p"),d=a.getElementsByTagName("head")[0]||a.documentElement;return c.innerHTML="x<style>"+b+"</style>",d.insertBefore(c.lastChild,d.firstChild)}function d(){var a=y.elements;return"string"==typeof a?a.split(" "):a}function e(a,b){var c=y.elements;"string"!=typeof c&&(c=c.join(" ")),"string"!=typeof a&&(a=a.join(" ")),y.elements=c+" "+a,j(b)}function f(a){var b=x[a[v]];return b||(b={},w++,a[v]=w,x[w]=b),b}function g(a,c,d){if(c||(c=b),q)return c.createElement(a);d||(d=f(c));var e;return e=d.cache[a]?d.cache[a].cloneNode():u.test(a)?(d.cache[a]=d.createElem(a)).cloneNode():d.createElem(a),!e.canHaveChildren||t.test(a)||e.tagUrn?e:d.frag.appendChild(e)}function h(a,c){if(a||(a=b),q)return a.createDocumentFragment();c=c||f(a);for(var e=c.frag.cloneNode(),g=0,h=d(),i=h.length;i>g;g++)e.createElement(h[g]);return e}function i(a,b){b.cache||(b.cache={},b.createElem=a.createElement,b.createFrag=a.createDocumentFragment,b.frag=b.createFrag()),a.createElement=function(c){return y.shivMethods?g(c,a,b):b.createElem(c)},a.createDocumentFragment=Function("h,f","return function(){var n=f.cloneNode(),c=n.createElement;h.shivMethods&&("+d().join().replace(/[\w\-:]+/g,function(a){return b.createElem(a),b.frag.createElement(a),'c("'+a+'")'})+");return n}")(y,b.frag)}function j(a){a||(a=b);var d=f(a);return!y.shivCSS||p||d.hasCSS||(d.hasCSS=!!c(a,"article,aside,dialog,figcaption,figure,footer,header,hgroup,main,nav,section{display:block}mark{background:#FF0;color:#000}template{display:none}")),q||i(a,d),a}function k(a){for(var b,c=a.getElementsByTagName("*"),e=c.length,f=RegExp("^(?:"+d().join("|")+")$","i"),g=[];e--;)b=c[e],f.test(b.nodeName)&&g.push(b.applyElement(l(b)));return g}function l(a){for(var b,c=a.attributes,d=c.length,e=a.ownerDocument.createElement(A+":"+a.nodeName);d--;)b=c[d],b.specified&&e.setAttribute(b.nodeName,b.nodeValue);return e.style.cssText=a.style.cssText,e}function m(a){for(var b,c=a.split("{"),e=c.length,f=RegExp("(^|[\\s,>+~])("+d().join("|")+")(?=[[\\s,>+~#.:]|$)","gi"),g="$1"+A+"\\:$2";e--;)b=c[e]=c[e].split("}"),b[b.length-1]=b[b.length-1].replace(f,g),c[e]=b.join("}");return c.join("{")}function n(a){for(var b=a.length;b--;)a[b].removeNode()}function o(a){function b(){clearTimeout(g._removeSheetTimer),d&&d.removeNode(!0),d=null}var d,e,g=f(a),h=a.namespaces,i=a.parentWindow;return!B||a.printShived?a:("undefined"==typeof h[A]&&h.add(A),i.attachEvent("onbeforeprint",function(){b();for(var f,g,h,i=a.styleSheets,j=[],l=i.length,n=Array(l);l--;)n[l]=i[l];for(;h=n.pop();)if(!h.disabled&&z.test(h.media)){try{f=h.imports,g=f.length}catch(o){g=0}for(l=0;g>l;l++)n.push(f[l]);try{j.push(h.cssText)}catch(o){}}j=m(j.reverse().join("")),e=k(a),d=c(a,j)}),i.attachEvent("onafterprint",function(){n(e),clearTimeout(g._removeSheetTimer),g._removeSheetTimer=setTimeout(b,500)}),a.printShived=!0,a)}var p,q,r="3.7.3",s=a.html5||{},t=/^<|^(?:button|map|select|textarea|object|iframe|option|optgroup)$/i,u=/^(?:a|b|code|div|fieldset|h1|h2|h3|h4|h5|h6|i|label|li|ol|p|q|span|strong|style|table|tbody|td|th|tr|ul)$/i,v="_html5shiv",w=0,x={};!function(){try{var a=b.createElement("a");a.innerHTML="<xyz></xyz>",p="hidden"in a,q=1==a.childNodes.length||function(){b.createElement("a");var a=b.createDocumentFragment();return"undefined"==typeof a.cloneNode||"undefined"==typeof a.createDocumentFragment||"undefined"==typeof a.createElement}()}catch(c){p=!0,q=!0}}();var y={elements:s.elements||"abbr article aside audio bdi canvas data datalist details dialog figcaption figure footer header hgroup main mark meter nav output picture progress section summary template time video",version:r,shivCSS:s.shivCSS!==!1,supportsUnknownElements:q,shivMethods:s.shivMethods!==!1,type:"default",shivDocument:j,createElement:g,createDocumentFragment:h,addElements:e};a.html5=y,j(b);var z=/^$|\b(?:all|print)\b/,A="html5shiv",B=!q&&function(){var c=b.documentElement;return!("undefined"==typeof b.namespaces||"undefined"==typeof b.parentWindow||"undefined"==typeof c.applyElement||"undefined"==typeof c.removeNode||"undefined"==typeof a.attachEvent)}();y.type+=" print",y.shivPrint=o,o(b),"object"==typeof module&&module.exports&&(module.exports=y)}("undefined"!=typeof window?window:this,document);

View File

@ -0,0 +1,4 @@
/**
* @preserve HTML5 Shiv 3.7.3 | @afarkas @jdalton @jon_neal @rem | MIT/GPL2 Licensed
*/
!function(a,b){function c(a,b){var c=a.createElement("p"),d=a.getElementsByTagName("head")[0]||a.documentElement;return c.innerHTML="x<style>"+b+"</style>",d.insertBefore(c.lastChild,d.firstChild)}function d(){var a=t.elements;return"string"==typeof a?a.split(" "):a}function e(a,b){var c=t.elements;"string"!=typeof c&&(c=c.join(" ")),"string"!=typeof a&&(a=a.join(" ")),t.elements=c+" "+a,j(b)}function f(a){var b=s[a[q]];return b||(b={},r++,a[q]=r,s[r]=b),b}function g(a,c,d){if(c||(c=b),l)return c.createElement(a);d||(d=f(c));var e;return e=d.cache[a]?d.cache[a].cloneNode():p.test(a)?(d.cache[a]=d.createElem(a)).cloneNode():d.createElem(a),!e.canHaveChildren||o.test(a)||e.tagUrn?e:d.frag.appendChild(e)}function h(a,c){if(a||(a=b),l)return a.createDocumentFragment();c=c||f(a);for(var e=c.frag.cloneNode(),g=0,h=d(),i=h.length;i>g;g++)e.createElement(h[g]);return e}function i(a,b){b.cache||(b.cache={},b.createElem=a.createElement,b.createFrag=a.createDocumentFragment,b.frag=b.createFrag()),a.createElement=function(c){return t.shivMethods?g(c,a,b):b.createElem(c)},a.createDocumentFragment=Function("h,f","return function(){var n=f.cloneNode(),c=n.createElement;h.shivMethods&&("+d().join().replace(/[\w\-:]+/g,function(a){return b.createElem(a),b.frag.createElement(a),'c("'+a+'")'})+");return n}")(t,b.frag)}function j(a){a||(a=b);var d=f(a);return!t.shivCSS||k||d.hasCSS||(d.hasCSS=!!c(a,"article,aside,dialog,figcaption,figure,footer,header,hgroup,main,nav,section{display:block}mark{background:#FF0;color:#000}template{display:none}")),l||i(a,d),a}var k,l,m="3.7.3-pre",n=a.html5||{},o=/^<|^(?:button|map|select|textarea|object|iframe|option|optgroup)$/i,p=/^(?:a|b|code|div|fieldset|h1|h2|h3|h4|h5|h6|i|label|li|ol|p|q|span|strong|style|table|tbody|td|th|tr|ul)$/i,q="_html5shiv",r=0,s={};!function(){try{var a=b.createElement("a");a.innerHTML="<xyz></xyz>",k="hidden"in a,l=1==a.childNodes.length||function(){b.createElement("a");var a=b.createDocumentFragment();return"undefined"==typeof a.cloneNode||"undefined"==typeof a.createDocumentFragment||"undefined"==typeof a.createElement}()}catch(c){k=!0,l=!0}}();var t={elements:n.elements||"abbr article aside audio bdi canvas data datalist details dialog figcaption figure footer header hgroup main mark meter nav output picture progress section summary template time video",version:m,shivCSS:n.shivCSS!==!1,supportsUnknownElements:l,shivMethods:n.shivMethods!==!1,type:"default",shivDocument:j,createElement:g,createDocumentFragment:h,addElements:e};a.html5=t,j(b),"object"==typeof module&&module.exports&&(module.exports=t)}("undefined"!=typeof window?window:this,document);

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,297 @@
/*
* language_data.js
* ~~~~~~~~~~~~~~~~
*
* This script contains the language-specific data used by searchtools.js,
* namely the list of stopwords, stemmer, scorer and splitter.
*
* :copyright: Copyright 2007-2022 by the Sphinx team, see AUTHORS.
* :license: BSD, see LICENSE for details.
*
*/
var stopwords = ["a","and","are","as","at","be","but","by","for","if","in","into","is","it","near","no","not","of","on","or","such","that","the","their","then","there","these","they","this","to","was","will","with"];
/* Non-minified version is copied as a separate JS file, is available */
/**
* Porter Stemmer
*/
var Stemmer = function() {
var step2list = {
ational: 'ate',
tional: 'tion',
enci: 'ence',
anci: 'ance',
izer: 'ize',
bli: 'ble',
alli: 'al',
entli: 'ent',
eli: 'e',
ousli: 'ous',
ization: 'ize',
ation: 'ate',
ator: 'ate',
alism: 'al',
iveness: 'ive',
fulness: 'ful',
ousness: 'ous',
aliti: 'al',
iviti: 'ive',
biliti: 'ble',
logi: 'log'
};
var step3list = {
icate: 'ic',
ative: '',
alize: 'al',
iciti: 'ic',
ical: 'ic',
ful: '',
ness: ''
};
var c = "[^aeiou]"; // consonant
var v = "[aeiouy]"; // vowel
var C = c + "[^aeiouy]*"; // consonant sequence
var V = v + "[aeiou]*"; // vowel sequence
var mgr0 = "^(" + C + ")?" + V + C; // [C]VC... is m>0
var meq1 = "^(" + C + ")?" + V + C + "(" + V + ")?$"; // [C]VC[V] is m=1
var mgr1 = "^(" + C + ")?" + V + C + V + C; // [C]VCVC... is m>1
var s_v = "^(" + C + ")?" + v; // vowel in stem
this.stemWord = function (w) {
var stem;
var suffix;
var firstch;
var origword = w;
if (w.length < 3)
return w;
var re;
var re2;
var re3;
var re4;
firstch = w.substr(0,1);
if (firstch == "y")
w = firstch.toUpperCase() + w.substr(1);
// Step 1a
re = /^(.+?)(ss|i)es$/;
re2 = /^(.+?)([^s])s$/;
if (re.test(w))
w = w.replace(re,"$1$2");
else if (re2.test(w))
w = w.replace(re2,"$1$2");
// Step 1b
re = /^(.+?)eed$/;
re2 = /^(.+?)(ed|ing)$/;
if (re.test(w)) {
var fp = re.exec(w);
re = new RegExp(mgr0);
if (re.test(fp[1])) {
re = /.$/;
w = w.replace(re,"");
}
}
else if (re2.test(w)) {
var fp = re2.exec(w);
stem = fp[1];
re2 = new RegExp(s_v);
if (re2.test(stem)) {
w = stem;
re2 = /(at|bl|iz)$/;
re3 = new RegExp("([^aeiouylsz])\\1$");
re4 = new RegExp("^" + C + v + "[^aeiouwxy]$");
if (re2.test(w))
w = w + "e";
else if (re3.test(w)) {
re = /.$/;
w = w.replace(re,"");
}
else if (re4.test(w))
w = w + "e";
}
}
// Step 1c
re = /^(.+?)y$/;
if (re.test(w)) {
var fp = re.exec(w);
stem = fp[1];
re = new RegExp(s_v);
if (re.test(stem))
w = stem + "i";
}
// Step 2
re = /^(.+?)(ational|tional|enci|anci|izer|bli|alli|entli|eli|ousli|ization|ation|ator|alism|iveness|fulness|ousness|aliti|iviti|biliti|logi)$/;
if (re.test(w)) {
var fp = re.exec(w);
stem = fp[1];
suffix = fp[2];
re = new RegExp(mgr0);
if (re.test(stem))
w = stem + step2list[suffix];
}
// Step 3
re = /^(.+?)(icate|ative|alize|iciti|ical|ful|ness)$/;
if (re.test(w)) {
var fp = re.exec(w);
stem = fp[1];
suffix = fp[2];
re = new RegExp(mgr0);
if (re.test(stem))
w = stem + step3list[suffix];
}
// Step 4
re = /^(.+?)(al|ance|ence|er|ic|able|ible|ant|ement|ment|ent|ou|ism|ate|iti|ous|ive|ize)$/;
re2 = /^(.+?)(s|t)(ion)$/;
if (re.test(w)) {
var fp = re.exec(w);
stem = fp[1];
re = new RegExp(mgr1);
if (re.test(stem))
w = stem;
}
else if (re2.test(w)) {
var fp = re2.exec(w);
stem = fp[1] + fp[2];
re2 = new RegExp(mgr1);
if (re2.test(stem))
w = stem;
}
// Step 5
re = /^(.+?)e$/;
if (re.test(w)) {
var fp = re.exec(w);
stem = fp[1];
re = new RegExp(mgr1);
re2 = new RegExp(meq1);
re3 = new RegExp("^" + C + v + "[^aeiouwxy]$");
if (re.test(stem) || (re2.test(stem) && !(re3.test(stem))))
w = stem;
}
re = /ll$/;
re2 = new RegExp(mgr1);
if (re.test(w) && re2.test(w)) {
re = /.$/;
w = w.replace(re,"");
}
// and turn initial Y back to y
if (firstch == "y")
w = firstch.toLowerCase() + w.substr(1);
return w;
}
}
var splitChars = (function() {
var result = {};
var singles = [96, 180, 187, 191, 215, 247, 749, 885, 903, 907, 909, 930, 1014, 1648,
1748, 1809, 2416, 2473, 2481, 2526, 2601, 2609, 2612, 2615, 2653, 2702,
2706, 2729, 2737, 2740, 2857, 2865, 2868, 2910, 2928, 2948, 2961, 2971,
2973, 3085, 3089, 3113, 3124, 3213, 3217, 3241, 3252, 3295, 3341, 3345,
3369, 3506, 3516, 3633, 3715, 3721, 3736, 3744, 3748, 3750, 3756, 3761,
3781, 3912, 4239, 4347, 4681, 4695, 4697, 4745, 4785, 4799, 4801, 4823,
4881, 5760, 5901, 5997, 6313, 7405, 8024, 8026, 8028, 8030, 8117, 8125,
8133, 8181, 8468, 8485, 8487, 8489, 8494, 8527, 11311, 11359, 11687, 11695,
11703, 11711, 11719, 11727, 11735, 12448, 12539, 43010, 43014, 43019, 43587,
43696, 43713, 64286, 64297, 64311, 64317, 64319, 64322, 64325, 65141];
var i, j, start, end;
for (i = 0; i < singles.length; i++) {
result[singles[i]] = true;
}
var ranges = [[0, 47], [58, 64], [91, 94], [123, 169], [171, 177], [182, 184], [706, 709],
[722, 735], [741, 747], [751, 879], [888, 889], [894, 901], [1154, 1161],
[1318, 1328], [1367, 1368], [1370, 1376], [1416, 1487], [1515, 1519], [1523, 1568],
[1611, 1631], [1642, 1645], [1750, 1764], [1767, 1773], [1789, 1790], [1792, 1807],
[1840, 1868], [1958, 1968], [1970, 1983], [2027, 2035], [2038, 2041], [2043, 2047],
[2070, 2073], [2075, 2083], [2085, 2087], [2089, 2307], [2362, 2364], [2366, 2383],
[2385, 2391], [2402, 2405], [2419, 2424], [2432, 2436], [2445, 2446], [2449, 2450],
[2483, 2485], [2490, 2492], [2494, 2509], [2511, 2523], [2530, 2533], [2546, 2547],
[2554, 2564], [2571, 2574], [2577, 2578], [2618, 2648], [2655, 2661], [2672, 2673],
[2677, 2692], [2746, 2748], [2750, 2767], [2769, 2783], [2786, 2789], [2800, 2820],
[2829, 2830], [2833, 2834], [2874, 2876], [2878, 2907], [2914, 2917], [2930, 2946],
[2955, 2957], [2966, 2968], [2976, 2978], [2981, 2983], [2987, 2989], [3002, 3023],
[3025, 3045], [3059, 3076], [3130, 3132], [3134, 3159], [3162, 3167], [3170, 3173],
[3184, 3191], [3199, 3204], [3258, 3260], [3262, 3293], [3298, 3301], [3312, 3332],
[3386, 3388], [3390, 3423], [3426, 3429], [3446, 3449], [3456, 3460], [3479, 3481],
[3518, 3519], [3527, 3584], [3636, 3647], [3655, 3663], [3674, 3712], [3717, 3718],
[3723, 3724], [3726, 3731], [3752, 3753], [3764, 3772], [3774, 3775], [3783, 3791],
[3802, 3803], [3806, 3839], [3841, 3871], [3892, 3903], [3949, 3975], [3980, 4095],
[4139, 4158], [4170, 4175], [4182, 4185], [4190, 4192], [4194, 4196], [4199, 4205],
[4209, 4212], [4226, 4237], [4250, 4255], [4294, 4303], [4349, 4351], [4686, 4687],
[4702, 4703], [4750, 4751], [4790, 4791], [4806, 4807], [4886, 4887], [4955, 4968],
[4989, 4991], [5008, 5023], [5109, 5120], [5741, 5742], [5787, 5791], [5867, 5869],
[5873, 5887], [5906, 5919], [5938, 5951], [5970, 5983], [6001, 6015], [6068, 6102],
[6104, 6107], [6109, 6111], [6122, 6127], [6138, 6159], [6170, 6175], [6264, 6271],
[6315, 6319], [6390, 6399], [6429, 6469], [6510, 6511], [6517, 6527], [6572, 6592],
[6600, 6607], [6619, 6655], [6679, 6687], [6741, 6783], [6794, 6799], [6810, 6822],
[6824, 6916], [6964, 6980], [6988, 6991], [7002, 7042], [7073, 7085], [7098, 7167],
[7204, 7231], [7242, 7244], [7294, 7400], [7410, 7423], [7616, 7679], [7958, 7959],
[7966, 7967], [8006, 8007], [8014, 8015], [8062, 8063], [8127, 8129], [8141, 8143],
[8148, 8149], [8156, 8159], [8173, 8177], [8189, 8303], [8306, 8307], [8314, 8318],
[8330, 8335], [8341, 8449], [8451, 8454], [8456, 8457], [8470, 8472], [8478, 8483],
[8506, 8507], [8512, 8516], [8522, 8525], [8586, 9311], [9372, 9449], [9472, 10101],
[10132, 11263], [11493, 11498], [11503, 11516], [11518, 11519], [11558, 11567],
[11622, 11630], [11632, 11647], [11671, 11679], [11743, 11822], [11824, 12292],
[12296, 12320], [12330, 12336], [12342, 12343], [12349, 12352], [12439, 12444],
[12544, 12548], [12590, 12592], [12687, 12689], [12694, 12703], [12728, 12783],
[12800, 12831], [12842, 12880], [12896, 12927], [12938, 12976], [12992, 13311],
[19894, 19967], [40908, 40959], [42125, 42191], [42238, 42239], [42509, 42511],
[42540, 42559], [42592, 42593], [42607, 42622], [42648, 42655], [42736, 42774],
[42784, 42785], [42889, 42890], [42893, 43002], [43043, 43055], [43062, 43071],
[43124, 43137], [43188, 43215], [43226, 43249], [43256, 43258], [43260, 43263],
[43302, 43311], [43335, 43359], [43389, 43395], [43443, 43470], [43482, 43519],
[43561, 43583], [43596, 43599], [43610, 43615], [43639, 43641], [43643, 43647],
[43698, 43700], [43703, 43704], [43710, 43711], [43715, 43738], [43742, 43967],
[44003, 44015], [44026, 44031], [55204, 55215], [55239, 55242], [55292, 55295],
[57344, 63743], [64046, 64047], [64110, 64111], [64218, 64255], [64263, 64274],
[64280, 64284], [64434, 64466], [64830, 64847], [64912, 64913], [64968, 65007],
[65020, 65135], [65277, 65295], [65306, 65312], [65339, 65344], [65371, 65381],
[65471, 65473], [65480, 65481], [65488, 65489], [65496, 65497]];
for (i = 0; i < ranges.length; i++) {
start = ranges[i][0];
end = ranges[i][1];
for (j = start; j <= end; j++) {
result[j] = true;
}
}
return result;
})();
function splitQuery(query) {
var result = [];
var start = -1;
for (var i = 0; i < query.length; i++) {
if (splitChars[query.charCodeAt(i)]) {
if (start !== -1) {
result.push(query.slice(start, i));
start = -1;
}
} else if (start === -1) {
start = i;
}
}
if (start !== -1) {
result.push(query.slice(start));
}
return result;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 90 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 90 B

View File

@ -0,0 +1,74 @@
pre { line-height: 125%; }
td.linenos .normal { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; }
span.linenos { color: inherit; background-color: transparent; padding-left: 5px; padding-right: 5px; }
td.linenos .special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; }
span.linenos.special { color: #000000; background-color: #ffffc0; padding-left: 5px; padding-right: 5px; }
.highlight .hll { background-color: #ffffcc }
.highlight { background: #f8f8f8; }
.highlight .c { color: #3D7B7B; font-style: italic } /* Comment */
.highlight .err { border: 1px solid #FF0000 } /* Error */
.highlight .k { color: #008000; font-weight: bold } /* Keyword */
.highlight .o { color: #666666 } /* Operator */
.highlight .ch { color: #3D7B7B; font-style: italic } /* Comment.Hashbang */
.highlight .cm { color: #3D7B7B; font-style: italic } /* Comment.Multiline */
.highlight .cp { color: #9C6500 } /* Comment.Preproc */
.highlight .cpf { color: #3D7B7B; font-style: italic } /* Comment.PreprocFile */
.highlight .c1 { color: #3D7B7B; font-style: italic } /* Comment.Single */
.highlight .cs { color: #3D7B7B; font-style: italic } /* Comment.Special */
.highlight .gd { color: #A00000 } /* Generic.Deleted */
.highlight .ge { font-style: italic } /* Generic.Emph */
.highlight .gr { color: #E40000 } /* Generic.Error */
.highlight .gh { color: #000080; font-weight: bold } /* Generic.Heading */
.highlight .gi { color: #008400 } /* Generic.Inserted */
.highlight .go { color: #717171 } /* Generic.Output */
.highlight .gp { color: #000080; font-weight: bold } /* Generic.Prompt */
.highlight .gs { font-weight: bold } /* Generic.Strong */
.highlight .gu { color: #800080; font-weight: bold } /* Generic.Subheading */
.highlight .gt { color: #0044DD } /* Generic.Traceback */
.highlight .kc { color: #008000; font-weight: bold } /* Keyword.Constant */
.highlight .kd { color: #008000; font-weight: bold } /* Keyword.Declaration */
.highlight .kn { color: #008000; font-weight: bold } /* Keyword.Namespace */
.highlight .kp { color: #008000 } /* Keyword.Pseudo */
.highlight .kr { color: #008000; font-weight: bold } /* Keyword.Reserved */
.highlight .kt { color: #B00040 } /* Keyword.Type */
.highlight .m { color: #666666 } /* Literal.Number */
.highlight .s { color: #BA2121 } /* Literal.String */
.highlight .na { color: #687822 } /* Name.Attribute */
.highlight .nb { color: #008000 } /* Name.Builtin */
.highlight .nc { color: #0000FF; font-weight: bold } /* Name.Class */
.highlight .no { color: #880000 } /* Name.Constant */
.highlight .nd { color: #AA22FF } /* Name.Decorator */
.highlight .ni { color: #717171; font-weight: bold } /* Name.Entity */
.highlight .ne { color: #CB3F38; font-weight: bold } /* Name.Exception */
.highlight .nf { color: #0000FF } /* Name.Function */
.highlight .nl { color: #767600 } /* Name.Label */
.highlight .nn { color: #0000FF; font-weight: bold } /* Name.Namespace */
.highlight .nt { color: #008000; font-weight: bold } /* Name.Tag */
.highlight .nv { color: #19177C } /* Name.Variable */
.highlight .ow { color: #AA22FF; font-weight: bold } /* Operator.Word */
.highlight .w { color: #bbbbbb } /* Text.Whitespace */
.highlight .mb { color: #666666 } /* Literal.Number.Bin */
.highlight .mf { color: #666666 } /* Literal.Number.Float */
.highlight .mh { color: #666666 } /* Literal.Number.Hex */
.highlight .mi { color: #666666 } /* Literal.Number.Integer */
.highlight .mo { color: #666666 } /* Literal.Number.Oct */
.highlight .sa { color: #BA2121 } /* Literal.String.Affix */
.highlight .sb { color: #BA2121 } /* Literal.String.Backtick */
.highlight .sc { color: #BA2121 } /* Literal.String.Char */
.highlight .dl { color: #BA2121 } /* Literal.String.Delimiter */
.highlight .sd { color: #BA2121; font-style: italic } /* Literal.String.Doc */
.highlight .s2 { color: #BA2121 } /* Literal.String.Double */
.highlight .se { color: #AA5D1F; font-weight: bold } /* Literal.String.Escape */
.highlight .sh { color: #BA2121 } /* Literal.String.Heredoc */
.highlight .si { color: #A45A77; font-weight: bold } /* Literal.String.Interpol */
.highlight .sx { color: #008000 } /* Literal.String.Other */
.highlight .sr { color: #A45A77 } /* Literal.String.Regex */
.highlight .s1 { color: #BA2121 } /* Literal.String.Single */
.highlight .ss { color: #19177C } /* Literal.String.Symbol */
.highlight .bp { color: #008000 } /* Name.Builtin.Pseudo */
.highlight .fm { color: #0000FF } /* Name.Function.Magic */
.highlight .vc { color: #19177C } /* Name.Variable.Class */
.highlight .vg { color: #19177C } /* Name.Variable.Global */
.highlight .vi { color: #19177C } /* Name.Variable.Instance */
.highlight .vm { color: #19177C } /* Name.Variable.Magic */
.highlight .il { color: #666666 } /* Literal.Number.Integer.Long */

View File

@ -0,0 +1,525 @@
/*
* searchtools.js
* ~~~~~~~~~~~~~~~~
*
* Sphinx JavaScript utilities for the full-text search.
*
* :copyright: Copyright 2007-2022 by the Sphinx team, see AUTHORS.
* :license: BSD, see LICENSE for details.
*
*/
if (!Scorer) {
/**
* Simple result scoring code.
*/
var Scorer = {
// Implement the following function to further tweak the score for each result
// The function takes a result array [filename, title, anchor, descr, score]
// and returns the new score.
/*
score: function(result) {
return result[4];
},
*/
// query matches the full name of an object
objNameMatch: 11,
// or matches in the last dotted part of the object name
objPartialMatch: 6,
// Additive scores depending on the priority of the object
objPrio: {0: 15, // used to be importantResults
1: 5, // used to be objectResults
2: -5}, // used to be unimportantResults
// Used when the priority is not in the mapping.
objPrioDefault: 0,
// query found in title
title: 15,
partialTitle: 7,
// query found in terms
term: 5,
partialTerm: 2
};
}
if (!splitQuery) {
function splitQuery(query) {
return query.split(/\s+/);
}
}
/**
* Search Module
*/
var Search = {
_index : null,
_queued_query : null,
_pulse_status : -1,
htmlToText : function(htmlString) {
var virtualDocument = document.implementation.createHTMLDocument('virtual');
var htmlElement = $(htmlString, virtualDocument);
htmlElement.find('.headerlink').remove();
docContent = htmlElement.find('[role=main]')[0];
if(docContent === undefined) {
console.warn("Content block not found. Sphinx search tries to obtain it " +
"via '[role=main]'. Could you check your theme or template.");
return "";
}
return docContent.textContent || docContent.innerText;
},
init : function() {
var params = $.getQueryParameters();
if (params.q) {
var query = params.q[0];
$('input[name="q"]')[0].value = query;
this.performSearch(query);
}
},
loadIndex : function(url) {
$.ajax({type: "GET", url: url, data: null,
dataType: "script", cache: true,
complete: function(jqxhr, textstatus) {
if (textstatus != "success") {
document.getElementById("searchindexloader").src = url;
}
}});
},
setIndex : function(index) {
var q;
this._index = index;
if ((q = this._queued_query) !== null) {
this._queued_query = null;
Search.query(q);
}
},
hasIndex : function() {
return this._index !== null;
},
deferQuery : function(query) {
this._queued_query = query;
},
stopPulse : function() {
this._pulse_status = 0;
},
startPulse : function() {
if (this._pulse_status >= 0)
return;
function pulse() {
var i;
Search._pulse_status = (Search._pulse_status + 1) % 4;
var dotString = '';
for (i = 0; i < Search._pulse_status; i++)
dotString += '.';
Search.dots.text(dotString);
if (Search._pulse_status > -1)
window.setTimeout(pulse, 500);
}
pulse();
},
/**
* perform a search for something (or wait until index is loaded)
*/
performSearch : function(query) {
// create the required interface elements
this.out = $('#search-results');
this.title = $('<h2>' + _('Searching') + '</h2>').appendTo(this.out);
this.dots = $('<span></span>').appendTo(this.title);
this.status = $('<p class="search-summary">&nbsp;</p>').appendTo(this.out);
this.output = $('<ul class="search"/>').appendTo(this.out);
$('#search-progress').text(_('Preparing search...'));
this.startPulse();
// index already loaded, the browser was quick!
if (this.hasIndex())
this.query(query);
else
this.deferQuery(query);
},
/**
* execute search (requires search index to be loaded)
*/
query : function(query) {
var i;
// stem the searchterms and add them to the correct list
var stemmer = new Stemmer();
var searchterms = [];
var excluded = [];
var hlterms = [];
var tmp = splitQuery(query);
var objectterms = [];
for (i = 0; i < tmp.length; i++) {
if (tmp[i] !== "") {
objectterms.push(tmp[i].toLowerCase());
}
if ($u.indexOf(stopwords, tmp[i].toLowerCase()) != -1 || tmp[i] === "") {
// skip this "word"
continue;
}
// stem the word
var word = stemmer.stemWord(tmp[i].toLowerCase());
var toAppend;
// select the correct list
if (word[0] == '-') {
toAppend = excluded;
word = word.substr(1);
}
else {
toAppend = searchterms;
hlterms.push(tmp[i].toLowerCase());
}
// only add if not already in the list
if (!$u.contains(toAppend, word))
toAppend.push(word);
}
var highlightstring = '?highlight=' + $.urlencode(hlterms.join(" "));
// console.debug('SEARCH: searching for:');
// console.info('required: ', searchterms);
// console.info('excluded: ', excluded);
// prepare search
var terms = this._index.terms;
var titleterms = this._index.titleterms;
// array of [filename, title, anchor, descr, score]
var results = [];
$('#search-progress').empty();
// lookup as object
for (i = 0; i < objectterms.length; i++) {
var others = [].concat(objectterms.slice(0, i),
objectterms.slice(i+1, objectterms.length));
results = results.concat(this.performObjectSearch(objectterms[i], others));
}
// lookup as search terms in fulltext
results = results.concat(this.performTermsSearch(searchterms, excluded, terms, titleterms));
// let the scorer override scores with a custom scoring function
if (Scorer.score) {
for (i = 0; i < results.length; i++)
results[i][4] = Scorer.score(results[i]);
}
// now sort the results by score (in opposite order of appearance, since the
// display function below uses pop() to retrieve items) and then
// alphabetically
results.sort(function(a, b) {
var left = a[4];
var right = b[4];
if (left > right) {
return 1;
} else if (left < right) {
return -1;
} else {
// same score: sort alphabetically
left = a[1].toLowerCase();
right = b[1].toLowerCase();
return (left > right) ? -1 : ((left < right) ? 1 : 0);
}
});
// for debugging
//Search.lastresults = results.slice(); // a copy
//console.info('search results:', Search.lastresults);
// print(the results
var resultCount = results.length;
function displayNextItem() {
// results left, load the summary and display it
if (results.length) {
var item = results.pop();
var listItem = $('<li></li>');
var requestUrl = "";
var linkUrl = "";
if (DOCUMENTATION_OPTIONS.BUILDER === 'dirhtml') {
// dirhtml builder
var dirname = item[0] + '/';
if (dirname.match(/\/index\/$/)) {
dirname = dirname.substring(0, dirname.length-6);
} else if (dirname == 'index/') {
dirname = '';
}
requestUrl = DOCUMENTATION_OPTIONS.URL_ROOT + dirname;
linkUrl = requestUrl;
} else {
// normal html builders
requestUrl = DOCUMENTATION_OPTIONS.URL_ROOT + item[0] + DOCUMENTATION_OPTIONS.FILE_SUFFIX;
linkUrl = item[0] + DOCUMENTATION_OPTIONS.LINK_SUFFIX;
}
listItem.append($('<a/>').attr('href',
linkUrl +
highlightstring + item[2]).html(item[1]));
if (item[3]) {
listItem.append($('<span> (' + item[3] + ')</span>'));
Search.output.append(listItem);
setTimeout(function() {
displayNextItem();
}, 5);
} else if (DOCUMENTATION_OPTIONS.SHOW_SEARCH_SUMMARY) {
$.ajax({url: requestUrl,
dataType: "text",
complete: function(jqxhr, textstatus) {
var data = jqxhr.responseText;
if (data !== '' && data !== undefined) {
var summary = Search.makeSearchSummary(data, searchterms, hlterms);
if (summary) {
listItem.append(summary);
}
}
Search.output.append(listItem);
setTimeout(function() {
displayNextItem();
}, 5);
}});
} else {
// just display title
Search.output.append(listItem);
setTimeout(function() {
displayNextItem();
}, 5);
}
}
// search finished, update title and status message
else {
Search.stopPulse();
Search.title.text(_('Search Results'));
if (!resultCount)
Search.status.text(_('Your search did not match any documents. Please make sure that all words are spelled correctly and that you\'ve selected enough categories.'));
else
Search.status.text(_('Search finished, found %s page(s) matching the search query.').replace('%s', resultCount));
Search.status.fadeIn(500);
}
}
displayNextItem();
},
/**
* search for object names
*/
performObjectSearch : function(object, otherterms) {
var filenames = this._index.filenames;
var docnames = this._index.docnames;
var objects = this._index.objects;
var objnames = this._index.objnames;
var titles = this._index.titles;
var i;
var results = [];
for (var prefix in objects) {
for (var iMatch = 0; iMatch != objects[prefix].length; ++iMatch) {
var match = objects[prefix][iMatch];
var name = match[4];
var fullname = (prefix ? prefix + '.' : '') + name;
var fullnameLower = fullname.toLowerCase()
if (fullnameLower.indexOf(object) > -1) {
var score = 0;
var parts = fullnameLower.split('.');
// check for different match types: exact matches of full name or
// "last name" (i.e. last dotted part)
if (fullnameLower == object || parts[parts.length - 1] == object) {
score += Scorer.objNameMatch;
// matches in last name
} else if (parts[parts.length - 1].indexOf(object) > -1) {
score += Scorer.objPartialMatch;
}
var objname = objnames[match[1]][2];
var title = titles[match[0]];
// If more than one term searched for, we require other words to be
// found in the name/title/description
if (otherterms.length > 0) {
var haystack = (prefix + ' ' + name + ' ' +
objname + ' ' + title).toLowerCase();
var allfound = true;
for (i = 0; i < otherterms.length; i++) {
if (haystack.indexOf(otherterms[i]) == -1) {
allfound = false;
break;
}
}
if (!allfound) {
continue;
}
}
var descr = objname + _(', in ') + title;
var anchor = match[3];
if (anchor === '')
anchor = fullname;
else if (anchor == '-')
anchor = objnames[match[1]][1] + '-' + fullname;
// add custom score for some objects according to scorer
if (Scorer.objPrio.hasOwnProperty(match[2])) {
score += Scorer.objPrio[match[2]];
} else {
score += Scorer.objPrioDefault;
}
results.push([docnames[match[0]], fullname, '#'+anchor, descr, score, filenames[match[0]]]);
}
}
}
return results;
},
/**
* See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions
*/
escapeRegExp : function(string) {
return string.replace(/[.*+\-?^${}()|[\]\\]/g, '\\$&'); // $& means the whole matched string
},
/**
* search for full-text terms in the index
*/
performTermsSearch : function(searchterms, excluded, terms, titleterms) {
var docnames = this._index.docnames;
var filenames = this._index.filenames;
var titles = this._index.titles;
var i, j, file;
var fileMap = {};
var scoreMap = {};
var results = [];
// perform the search on the required terms
for (i = 0; i < searchterms.length; i++) {
var word = searchterms[i];
var files = [];
var _o = [
{files: terms[word], score: Scorer.term},
{files: titleterms[word], score: Scorer.title}
];
// add support for partial matches
if (word.length > 2) {
var word_regex = this.escapeRegExp(word);
for (var w in terms) {
if (w.match(word_regex) && !terms[word]) {
_o.push({files: terms[w], score: Scorer.partialTerm})
}
}
for (var w in titleterms) {
if (w.match(word_regex) && !titleterms[word]) {
_o.push({files: titleterms[w], score: Scorer.partialTitle})
}
}
}
// no match but word was a required one
if ($u.every(_o, function(o){return o.files === undefined;})) {
break;
}
// found search word in contents
$u.each(_o, function(o) {
var _files = o.files;
if (_files === undefined)
return
if (_files.length === undefined)
_files = [_files];
files = files.concat(_files);
// set score for the word in each file to Scorer.term
for (j = 0; j < _files.length; j++) {
file = _files[j];
if (!(file in scoreMap))
scoreMap[file] = {};
scoreMap[file][word] = o.score;
}
});
// create the mapping
for (j = 0; j < files.length; j++) {
file = files[j];
if (file in fileMap && fileMap[file].indexOf(word) === -1)
fileMap[file].push(word);
else
fileMap[file] = [word];
}
}
// now check if the files don't contain excluded terms
for (file in fileMap) {
var valid = true;
// check if all requirements are matched
var filteredTermCount = // as search terms with length < 3 are discarded: ignore
searchterms.filter(function(term){return term.length > 2}).length
if (
fileMap[file].length != searchterms.length &&
fileMap[file].length != filteredTermCount
) continue;
// ensure that none of the excluded terms is in the search result
for (i = 0; i < excluded.length; i++) {
if (terms[excluded[i]] == file ||
titleterms[excluded[i]] == file ||
$u.contains(terms[excluded[i]] || [], file) ||
$u.contains(titleterms[excluded[i]] || [], file)) {
valid = false;
break;
}
}
// if we have still a valid result we can add it to the result list
if (valid) {
// select one (max) score for the file.
// for better ranking, we should calculate ranking by using words statistics like basic tf-idf...
var score = $u.max($u.map(fileMap[file], function(w){return scoreMap[file][w]}));
results.push([docnames[file], titles[file], '', null, score, filenames[file]]);
}
}
return results;
},
/**
* helper function to return a node containing the
* search summary for a given text. keywords is a list
* of stemmed words, hlwords is the list of normal, unstemmed
* words. the first one is used to find the occurrence, the
* latter for highlighting it.
*/
makeSearchSummary : function(htmlText, keywords, hlwords) {
var text = Search.htmlToText(htmlText);
if (text == "") {
return null;
}
var textLower = text.toLowerCase();
var start = 0;
$.each(keywords, function() {
var i = textLower.indexOf(this.toLowerCase());
if (i > -1)
start = i;
});
start = Math.max(start - 120, 0);
var excerpt = ((start > 0) ? '...' : '') +
$.trim(text.substr(start, 240)) +
((start + 240 - text.length) ? '...' : '');
var rv = $('<p class="context"></p>').text(excerpt);
$.each(hlwords, function() {
rv = rv.highlightText(this, 'highlighted');
});
return rv;
}
};
$(document).ready(function() {
Search.init();
});

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,648 @@
<!DOCTYPE html>
<html class="writer-html5" lang="en" >
<head>
<meta charset="utf-8" /><meta name="generator" content="Docutils 0.17.1: http://docutils.sourceforge.net/" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>API &mdash; Pose Wrangler 2.0.0 documentation</title>
<link rel="stylesheet" href="_static/pygments.css" type="text/css" />
<link rel="stylesheet" href="_static/css/theme.css" type="text/css" />
<!--[if lt IE 9]>
<script src="_static/js/html5shiv.min.js"></script>
<![endif]-->
<script data-url_root="./" id="documentation_options" src="_static/documentation_options.js"></script>
<script src="_static/jquery.js"></script>
<script src="_static/underscore.js"></script>
<script src="_static/doctools.js"></script>
<script src="_static/js/theme.js"></script>
<link rel="index" title="Index" href="genindex.html" />
<link rel="search" title="Search" href="search.html" />
<link rel="prev" title="Extensions" href="extensions.html" />
</head>
<body class="wy-body-for-nav">
<div class="wy-grid-for-nav">
<nav data-toggle="wy-nav-shift" class="wy-nav-side">
<div class="wy-side-scroll">
<div class="wy-side-nav-search" >
<a href="index.html" class="icon icon-home"> Pose Wrangler
</a>
<div role="search">
<form id="rtd-search-form" class="wy-form" action="search.html" method="get">
<input type="text" name="q" placeholder="Search docs" />
<input type="hidden" name="check_keywords" value="yes" />
<input type="hidden" name="area" value="default" />
</form>
</div>
</div><div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="Navigation menu">
<p class="caption" role="heading"><span class="caption-text">Contents:</span></p>
<ul class="current">
<li class="toctree-l1"><a class="reference internal" href="overview.html">2.0.0 Overview</a></li>
<li class="toctree-l1"><a class="reference internal" href="upgrading.html">Upgrading to 2.0.0</a></li>
<li class="toctree-l1"><a class="reference internal" href="mirror_mapping.html">Mirror Mapping</a></li>
<li class="toctree-l1"><a class="reference internal" href="extensions.html">Extensions</a></li>
<li class="toctree-l1 current"><a class="current reference internal" href="#">API</a><ul>
<li class="toctree-l2"><a class="reference internal" href="#pose-wrangler-v2-main">pose_wrangler.v2.main</a></li>
</ul>
</li>
</ul>
</div>
</div>
</nav>
<section data-toggle="wy-nav-shift" class="wy-nav-content-wrap"><nav class="wy-nav-top" aria-label="Mobile navigation menu" >
<i data-toggle="wy-nav-top" class="fa fa-bars"></i>
<a href="index.html">Pose Wrangler</a>
</nav>
<div class="wy-nav-content">
<div class="rst-content">
<div role="navigation" aria-label="Page navigation">
<ul class="wy-breadcrumbs">
<li><a href="index.html" class="icon icon-home"></a> &raquo;</li>
<li>API</li>
<li class="wy-breadcrumbs-aside">
<a href="_sources/api.rst.txt" rel="nofollow"> View page source</a>
</li>
</ul>
<hr/>
</div>
<div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article">
<div itemprop="articleBody">
<section id="api">
<h1>API<a class="headerlink" href="#api" title="Permalink to this headline"></a></h1>
<section id="pose-wrangler-v2-main">
<h2>pose_wrangler.v2.main<a class="headerlink" href="#pose-wrangler-v2-main" title="Permalink to this headline"></a></h2>
<dl class="py class">
<dt class="sig sig-object py" id="pose_wrangler.v2.main.UERBFAPI">
<em class="property"><span class="pre">class</span><span class="w"> </span></em><span class="sig-prename descclassname"><span class="pre">pose_wrangler.v2.main.</span></span><span class="sig-name descname"><span class="pre">UERBFAPI</span></span><span class="sig-paren">(</span><em class="sig-param"><span class="n"><span class="pre">view</span></span><span class="o"><span class="pre">=</span></span><span class="default_value"><span class="pre">False</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">parent</span></span><span class="o"><span class="pre">=</span></span><span class="default_value"><span class="pre">None</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">file_path</span></span><span class="o"><span class="pre">=</span></span><span class="default_value"><span class="pre">None</span></span></em><span class="sig-paren">)</span><a class="headerlink" href="#pose_wrangler.v2.main.UERBFAPI" title="Permalink to this definition"></a></dt>
<dd><p>Bases: <code class="xref py py-class docutils literal notranslate"><span class="pre">pose_wrangler.model.api.RBFAPI</span></code></p>
<p>Main entry point for interacting with the UERBFSolverNode and UEPoseBlenderNode</p>
<div class="doctest highlight-default notranslate"><div class="highlight"><pre><span></span><span class="gp">&gt;&gt;&gt; </span><span class="kn">from</span> <span class="nn">pose_wrangler.v2</span> <span class="kn">import</span> <span class="n">main</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">rbf_api</span> <span class="o">=</span> <span class="n">main</span><span class="o">.</span><span class="n">UERBFAPI</span><span class="p">(</span><span class="n">view</span><span class="o">=</span><span class="kc">False</span><span class="p">)</span>
<span class="gp">&gt;&gt;&gt; </span><span class="n">rbf_api</span><span class="o">.</span><span class="n">create_rbf_solver</span><span class="p">(</span><span class="n">solver_name</span><span class="o">=</span><span class="s2">&quot;ExampleSolver&quot;</span><span class="p">,</span> <span class="n">drivers</span><span class="o">=</span><span class="p">[</span><span class="s1">&#39;leg_l&#39;</span><span class="p">])</span>
</pre></div>
</div>
<dl class="py attribute">
<dt class="sig sig-object py" id="pose_wrangler.v2.main.UERBFAPI.VERSION">
<span class="sig-name descname"><span class="pre">VERSION</span></span><em class="property"><span class="w"> </span><span class="p"><span class="pre">=</span></span><span class="w"> </span><span class="pre">'2.0.0'</span></em><a class="headerlink" href="#pose_wrangler.v2.main.UERBFAPI.VERSION" title="Permalink to this definition"></a></dt>
<dd></dd></dl>
<dl class="py property">
<dt class="sig sig-object py" id="pose_wrangler.v2.main.UERBFAPI.extensions">
<em class="property"><span class="pre">property</span><span class="w"> </span></em><span class="sig-name descname"><span class="pre">extensions</span></span><a class="headerlink" href="#pose_wrangler.v2.main.UERBFAPI.extensions" title="Permalink to this definition"></a></dt>
<dd><dl class="field-list simple">
<dt class="field-odd">Returns</dt>
<dd class="field-odd"><p>list of pose wrangler extensions currently loaded</p>
</dd>
<dt class="field-even">Return type</dt>
<dd class="field-even"><p>list[<a class="reference internal" href="extensions.html#pose_wrangler.v2.model.base_extension.PoseWranglerExtension" title="pose_wrangler.v2.model.base_extension.PoseWranglerExtension">pose_wrangler.v2.model.base_extension.PoseWranglerExtension</a>]</p>
</dd>
</dl>
</dd></dl>
<dl class="py property">
<dt class="sig sig-object py" id="pose_wrangler.v2.main.UERBFAPI.view">
<em class="property"><span class="pre">property</span><span class="w"> </span></em><span class="sig-name descname"><span class="pre">view</span></span><a class="headerlink" href="#pose_wrangler.v2.main.UERBFAPI.view" title="Permalink to this definition"></a></dt>
<dd><dl class="field-list simple">
<dt class="field-odd">Returns</dt>
<dd class="field-odd"><p>reference to the ui QWidget</p>
</dd>
<dt class="field-even">Return type</dt>
<dd class="field-even"><p>QtWidgets.QWidget or None</p>
</dd>
</dl>
</dd></dl>
<dl class="py property">
<dt class="sig sig-object py" id="pose_wrangler.v2.main.UERBFAPI.current_solver">
<em class="property"><span class="pre">property</span><span class="w"> </span></em><span class="sig-name descname"><span class="pre">current_solver</span></span><a class="headerlink" href="#pose_wrangler.v2.main.UERBFAPI.current_solver" title="Permalink to this definition"></a></dt>
<dd><dl class="field-list simple">
<dt class="field-odd">Returns</dt>
<dd class="field-odd"><p>reference to the current solver</p>
</dd>
<dt class="field-even">Return type</dt>
<dd class="field-even"><p>api.RBFNode or None</p>
</dd>
</dl>
</dd></dl>
<dl class="py property">
<dt class="sig sig-object py" id="pose_wrangler.v2.main.UERBFAPI.mirror_mapping">
<em class="property"><span class="pre">property</span><span class="w"> </span></em><span class="sig-name descname"><span class="pre">mirror_mapping</span></span><a class="headerlink" href="#pose_wrangler.v2.main.UERBFAPI.mirror_mapping" title="Permalink to this definition"></a></dt>
<dd><dl class="field-list simple">
<dt class="field-odd">Returns</dt>
<dd class="field-odd"><p>reference to the currently loaded mirror mapping</p>
</dd>
<dt class="field-even">Return type</dt>
<dd class="field-even"><p>mirror_mapping.MirrorMapping object</p>
</dd>
</dl>
</dd></dl>
<dl class="py property">
<dt class="sig sig-object py" id="pose_wrangler.v2.main.UERBFAPI.rbf_solvers">
<em class="property"><span class="pre">property</span><span class="w"> </span></em><span class="sig-name descname"><span class="pre">rbf_solvers</span></span><a class="headerlink" href="#pose_wrangler.v2.main.UERBFAPI.rbf_solvers" title="Permalink to this definition"></a></dt>
<dd><dl class="field-list simple">
<dt class="field-odd">Returns</dt>
<dd class="field-odd"><p>list of rbf solvers in the scene</p>
</dd>
<dt class="field-even">Return type</dt>
<dd class="field-even"><p>list</p>
</dd>
</dl>
</dd></dl>
<dl class="py method">
<dt class="sig sig-object py" id="pose_wrangler.v2.main.UERBFAPI.create_rbf_solver">
<span class="sig-name descname"><span class="pre">create_rbf_solver</span></span><span class="sig-paren">(</span><em class="sig-param"><span class="n"><span class="pre">solver_name</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">drivers</span></span><span class="o"><span class="pre">=</span></span><span class="default_value"><span class="pre">None</span></span></em><span class="sig-paren">)</span><a class="headerlink" href="#pose_wrangler.v2.main.UERBFAPI.create_rbf_solver" title="Permalink to this definition"></a></dt>
<dd><p>Create an rbf solver node with the given name and the specified driver transforms</p>
<dl class="field-list simple">
<dt class="field-odd">Parameters</dt>
<dd class="field-odd"><ul class="simple">
<li><p><strong>solver_name</strong> (<em>str</em>) name of the solver node</p></li>
<li><p><strong>drivers</strong> (<em>list</em>) list of driver transform node names</p></li>
</ul>
</dd>
<dt class="field-even">Returns</dt>
<dd class="field-even"><p>RBFNode ref</p>
</dd>
<dt class="field-odd">Return type</dt>
<dd class="field-odd"><p>api.RBFNode</p>
</dd>
</dl>
</dd></dl>
<dl class="py method">
<dt class="sig sig-object py" id="pose_wrangler.v2.main.UERBFAPI.delete_rbf_solver">
<span class="sig-name descname"><span class="pre">delete_rbf_solver</span></span><span class="sig-paren">(</span><em class="sig-param"><span class="n"><span class="pre">solver</span></span><span class="o"><span class="pre">=</span></span><span class="default_value"><span class="pre">None</span></span></em><span class="sig-paren">)</span><a class="headerlink" href="#pose_wrangler.v2.main.UERBFAPI.delete_rbf_solver" title="Permalink to this definition"></a></dt>
<dd><p>Delete the specified solver</p>
<dl class="field-list simple">
<dt class="field-odd">Parameters</dt>
<dd class="field-odd"><p><strong>solver</strong> (<em>api.RBFNode</em>) solver reference</p>
</dd>
</dl>
</dd></dl>
<dl class="py method">
<dt class="sig sig-object py" id="pose_wrangler.v2.main.UERBFAPI.edit_solver">
<span class="sig-name descname"><span class="pre">edit_solver</span></span><span class="sig-paren">(</span><em class="sig-param"><span class="n"><span class="pre">edit</span></span><span class="o"><span class="pre">=</span></span><span class="default_value"><span class="pre">True</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">solver</span></span><span class="o"><span class="pre">=</span></span><span class="default_value"><span class="pre">None</span></span></em><span class="sig-paren">)</span><a class="headerlink" href="#pose_wrangler.v2.main.UERBFAPI.edit_solver" title="Permalink to this definition"></a></dt>
<dd><p>Edit or finish editing the specified solver. Enables pose creation/driven node changes via the ui</p>
<dl class="field-list simple">
<dt class="field-odd">Parameters</dt>
<dd class="field-odd"><ul class="simple">
<li><p><strong>edit</strong> (<em>bool</em>) set edit mode on or off</p></li>
<li><p><strong>solver</strong> (<em>api.RBFNode</em>) solver reference</p></li>
</ul>
</dd>
</dl>
</dd></dl>
<dl class="py method">
<dt class="sig sig-object py" id="pose_wrangler.v2.main.UERBFAPI.mirror_rbf_solver">
<span class="sig-name descname"><span class="pre">mirror_rbf_solver</span></span><span class="sig-paren">(</span><em class="sig-param"><span class="n"><span class="pre">solver</span></span><span class="o"><span class="pre">=</span></span><span class="default_value"><span class="pre">None</span></span></em><span class="sig-paren">)</span><a class="headerlink" href="#pose_wrangler.v2.main.UERBFAPI.mirror_rbf_solver" title="Permalink to this definition"></a></dt>
<dd><p>Mirror the current solver</p>
<dl class="field-list simple">
<dt class="field-odd">Parameters</dt>
<dd class="field-odd"><p><strong>solver</strong> (<em>api.RBFNode</em>) solver reference</p>
</dd>
<dt class="field-even">Returns</dt>
<dd class="field-even"><p>mirrored solver reference</p>
</dd>
<dt class="field-odd">Return type</dt>
<dd class="field-odd"><p>api.RBFNode</p>
</dd>
</dl>
</dd></dl>
<dl class="py method">
<dt class="sig sig-object py" id="pose_wrangler.v2.main.UERBFAPI.get_rbf_solver_by_name">
<span class="sig-name descname"><span class="pre">get_rbf_solver_by_name</span></span><span class="sig-paren">(</span><em class="sig-param"><span class="n"><span class="pre">solver_name</span></span></em><span class="sig-paren">)</span><a class="headerlink" href="#pose_wrangler.v2.main.UERBFAPI.get_rbf_solver_by_name" title="Permalink to this definition"></a></dt>
<dd><p>Searches the scene for an rbf solver with the given name. Case insensitive</p>
<dl class="field-list simple">
<dt class="field-odd">Parameters</dt>
<dd class="field-odd"><p><strong>solver_name</strong> (<em>str</em>) Solver node name</p>
</dd>
<dt class="field-even">Returns</dt>
<dd class="field-even"><p>found node or None</p>
</dd>
<dt class="field-odd">Return type</dt>
<dd class="field-odd"><p>api.RBFNode or None</p>
</dd>
</dl>
</dd></dl>
<dl class="py method">
<dt class="sig sig-object py" id="pose_wrangler.v2.main.UERBFAPI.add_drivers">
<span class="sig-name descname"><span class="pre">add_drivers</span></span><span class="sig-paren">(</span><em class="sig-param"><span class="n"><span class="pre">drivers</span></span><span class="o"><span class="pre">=</span></span><span class="default_value"><span class="pre">None</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">solver</span></span><span class="o"><span class="pre">=</span></span><span class="default_value"><span class="pre">None</span></span></em><span class="sig-paren">)</span><a class="headerlink" href="#pose_wrangler.v2.main.UERBFAPI.add_drivers" title="Permalink to this definition"></a></dt>
<dd><p>Add the specified drivers to the specified solver</p>
<dl class="field-list simple">
<dt class="field-odd">Parameters</dt>
<dd class="field-odd"><ul class="simple">
<li><p><strong>drivers</strong> (<em>list</em>) list of transform nodes</p></li>
<li><p><strong>solver</strong> (<em>api.RBFNode</em>) solver reference</p></li>
</ul>
</dd>
</dl>
</dd></dl>
<dl class="py method">
<dt class="sig sig-object py" id="pose_wrangler.v2.main.UERBFAPI.remove_drivers">
<span class="sig-name descname"><span class="pre">remove_drivers</span></span><span class="sig-paren">(</span><em class="sig-param"><span class="n"><span class="pre">drivers</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">solver</span></span><span class="o"><span class="pre">=</span></span><span class="default_value"><span class="pre">None</span></span></em><span class="sig-paren">)</span><a class="headerlink" href="#pose_wrangler.v2.main.UERBFAPI.remove_drivers" title="Permalink to this definition"></a></dt>
<dd><p>Remove the specified drivers from the specified solver</p>
<dl class="field-list simple">
<dt class="field-odd">Parameters</dt>
<dd class="field-odd"><ul class="simple">
<li><p><strong>drivers</strong> (<em>list</em>) list of driver transform nodes</p></li>
<li><p><strong>solver</strong> (<em>api.RBFNode</em>) solver reference</p></li>
</ul>
</dd>
</dl>
</dd></dl>
<dl class="py method">
<dt class="sig sig-object py" id="pose_wrangler.v2.main.UERBFAPI.add_driven_transforms">
<span class="sig-name descname"><span class="pre">add_driven_transforms</span></span><span class="sig-paren">(</span><em class="sig-param"><span class="n"><span class="pre">driven_nodes</span></span><span class="o"><span class="pre">=</span></span><span class="default_value"><span class="pre">None</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">solver</span></span><span class="o"><span class="pre">=</span></span><span class="default_value"><span class="pre">None</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">edit</span></span><span class="o"><span class="pre">=</span></span><span class="default_value"><span class="pre">False</span></span></em><span class="sig-paren">)</span><a class="headerlink" href="#pose_wrangler.v2.main.UERBFAPI.add_driven_transforms" title="Permalink to this definition"></a></dt>
<dd><p>Add driven transforms to the specified solver</p>
<dl class="field-list simple">
<dt class="field-odd">Parameters</dt>
<dd class="field-odd"><ul class="simple">
<li><p><strong>driven_nodes</strong> (<em>list</em>) list of transform nodes</p></li>
<li><p><strong>solver</strong> (<em>api.RBFNode</em>) solver reference</p></li>
<li><p><strong>edit</strong> (<em>bool</em>) should this transform not be connected to the pose blender output upon creation</p></li>
</ul>
</dd>
</dl>
</dd></dl>
<dl class="py method">
<dt class="sig sig-object py" id="pose_wrangler.v2.main.UERBFAPI.remove_driven">
<span class="sig-name descname"><span class="pre">remove_driven</span></span><span class="sig-paren">(</span><em class="sig-param"><span class="n"><span class="pre">driven_nodes</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">solver</span></span><span class="o"><span class="pre">=</span></span><span class="default_value"><span class="pre">None</span></span></em><span class="sig-paren">)</span><a class="headerlink" href="#pose_wrangler.v2.main.UERBFAPI.remove_driven" title="Permalink to this definition"></a></dt>
<dd><p>Remove driven transforms from the specified solver</p>
<dl class="field-list simple">
<dt class="field-odd">Parameters</dt>
<dd class="field-odd"><ul class="simple">
<li><p><strong>driven_nodes</strong> (<em>list</em>) list of transform nodes</p></li>
<li><p><strong>solver</strong> (<em>api.RBFNode</em>) solver reference</p></li>
</ul>
</dd>
</dl>
</dd></dl>
<dl class="py method">
<dt class="sig sig-object py" id="pose_wrangler.v2.main.UERBFAPI.add_blendshape">
<span class="sig-name descname"><span class="pre">add_blendshape</span></span><span class="sig-paren">(</span><em class="sig-param"><span class="n"><span class="pre">pose_name</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">mesh_name</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">base_mesh</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">solver</span></span><span class="o"><span class="pre">=</span></span><span class="default_value"><span class="pre">None</span></span></em><span class="sig-paren">)</span><a class="headerlink" href="#pose_wrangler.v2.main.UERBFAPI.add_blendshape" title="Permalink to this definition"></a></dt>
<dd><p>Add an existing blendshape for the current pose</p>
<dl class="field-list simple">
<dt class="field-odd">Parameters</dt>
<dd class="field-odd"><ul class="simple">
<li><p><strong>pose_name</strong> (<em>str</em>) name of the pose the blendshape is associated with</p></li>
<li><p><strong>mesh_name</strong> (<em>str</em>) name of the existing blendshape mesh</p></li>
<li><p><strong>base_mesh</strong> (<em>str</em>) name of the mesh the blendshape mesh is derived from</p></li>
<li><p><strong>solver</strong> (<em>api.RBFNode</em>) solver reference</p></li>
</ul>
</dd>
</dl>
</dd></dl>
<dl class="py method">
<dt class="sig sig-object py" id="pose_wrangler.v2.main.UERBFAPI.create_blendshape">
<span class="sig-name descname"><span class="pre">create_blendshape</span></span><span class="sig-paren">(</span><em class="sig-param"><span class="n"><span class="pre">pose_name</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">mesh_name</span></span><span class="o"><span class="pre">=</span></span><span class="default_value"><span class="pre">None</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">edit</span></span><span class="o"><span class="pre">=</span></span><span class="default_value"><span class="pre">False</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">solver</span></span><span class="o"><span class="pre">=</span></span><span class="default_value"><span class="pre">None</span></span></em><span class="sig-paren">)</span><a class="headerlink" href="#pose_wrangler.v2.main.UERBFAPI.create_blendshape" title="Permalink to this definition"></a></dt>
<dd><p>Create a new blendshape for the given pose and mesh</p>
<dl class="field-list simple">
<dt class="field-odd">Parameters</dt>
<dd class="field-odd"><ul class="simple">
<li><p><strong>pose_name</strong> (<em>str</em>) name of the pose to create this blendshape for</p></li>
<li><p><strong>mesh_name</strong> (<em>str</em>) name of the mesh to create the blendshape from</p></li>
<li><p><strong>edit</strong> (<em>bool</em>) should this blendshape be edited straight away</p></li>
<li><p><strong>solver</strong> (<em>api.RBFNode</em>) solver reference</p></li>
</ul>
</dd>
<dt class="field-even">Returns</dt>
<dd class="field-even"><p>name of the newly created blendshape mesh</p>
</dd>
<dt class="field-odd">Return type</dt>
<dd class="field-odd"><p>str</p>
</dd>
</dl>
</dd></dl>
<dl class="py method">
<dt class="sig sig-object py" id="pose_wrangler.v2.main.UERBFAPI.delete_blendshape">
<span class="sig-name descname"><span class="pre">delete_blendshape</span></span><span class="sig-paren">(</span><em class="sig-param"><span class="n"><span class="pre">pose_name</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">solver</span></span><span class="o"><span class="pre">=</span></span><span class="default_value"><span class="pre">None</span></span></em><span class="sig-paren">)</span><a class="headerlink" href="#pose_wrangler.v2.main.UERBFAPI.delete_blendshape" title="Permalink to this definition"></a></dt>
<dd><p>Delete the blendshape associated with the specified pose</p>
<dl class="field-list simple">
<dt class="field-odd">Parameters</dt>
<dd class="field-odd"><ul class="simple">
<li><p><strong>pose_name</strong> (<em>str</em>) name of the pose to delete blendshapes for</p></li>
<li><p><strong>solver</strong> (<em>api.RBFNode</em>) solver reference</p></li>
</ul>
</dd>
</dl>
</dd></dl>
<dl class="py method">
<dt class="sig sig-object py" id="pose_wrangler.v2.main.UERBFAPI.edit_blendshape">
<span class="sig-name descname"><span class="pre">edit_blendshape</span></span><span class="sig-paren">(</span><em class="sig-param"><span class="n"><span class="pre">pose_name</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">edit</span></span><span class="o"><span class="pre">=</span></span><span class="default_value"><span class="pre">True</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">solver</span></span><span class="o"><span class="pre">=</span></span><span class="default_value"><span class="pre">None</span></span></em><span class="sig-paren">)</span><a class="headerlink" href="#pose_wrangler.v2.main.UERBFAPI.edit_blendshape" title="Permalink to this definition"></a></dt>
<dd><p>Edit or finish editing the blendshape associated with the specified pose name</p>
<dl class="field-list simple">
<dt class="field-odd">Parameters</dt>
<dd class="field-odd"><ul class="simple">
<li><p><strong>pose_name</strong> (<em>str</em>) name of the pose the blendshape is associated with</p></li>
<li><p><strong>edit</strong> (<em>bool</em>) True = enable editing, False = finish editing</p></li>
<li><p><strong>solver</strong> (<em>api.RBFNode</em>) solver reference</p></li>
</ul>
</dd>
</dl>
</dd></dl>
<dl class="py method">
<dt class="sig sig-object py" id="pose_wrangler.v2.main.UERBFAPI.isolate_blendshape">
<span class="sig-name descname"><span class="pre">isolate_blendshape</span></span><span class="sig-paren">(</span><em class="sig-param"><span class="n"><span class="pre">pose_name</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">isolate</span></span><span class="o"><span class="pre">=</span></span><span class="default_value"><span class="pre">True</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">solver</span></span><span class="o"><span class="pre">=</span></span><span class="default_value"><span class="pre">None</span></span></em><span class="sig-paren">)</span><a class="headerlink" href="#pose_wrangler.v2.main.UERBFAPI.isolate_blendshape" title="Permalink to this definition"></a></dt>
<dd><p>Isolate the blendshape associated with the specified pose name, disabling all other blendshapes.</p>
<dl class="field-list simple">
<dt class="field-odd">Parameters</dt>
<dd class="field-odd"><ul class="simple">
<li><p><strong>pose_name</strong> (<em>str</em>) name of the pose the blendshape is associated with</p></li>
<li><p><strong>isolate</strong> (<em>bool</em>) True = isolate the blendshape, False = reconnect all disconnected blendshapes</p></li>
<li><p><strong>solver</strong> (<em>api.RBFNode</em>) solver reference</p></li>
</ul>
</dd>
</dl>
</dd></dl>
<dl class="py method">
<dt class="sig sig-object py" id="pose_wrangler.v2.main.UERBFAPI.create_pose">
<span class="sig-name descname"><span class="pre">create_pose</span></span><span class="sig-paren">(</span><em class="sig-param"><span class="n"><span class="pre">pose_name</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">solver</span></span><span class="o"><span class="pre">=</span></span><span class="default_value"><span class="pre">None</span></span></em><span class="sig-paren">)</span><a class="headerlink" href="#pose_wrangler.v2.main.UERBFAPI.create_pose" title="Permalink to this definition"></a></dt>
<dd><p>Create a new pose for the specified solver</p>
<dl class="field-list simple">
<dt class="field-odd">Parameters</dt>
<dd class="field-odd"><ul class="simple">
<li><p><strong>pose_name</strong> (<em>str</em>) name of the new pose</p></li>
<li><p><strong>solver</strong> (<em>api.RBFNode</em>) solver reference</p></li>
</ul>
</dd>
</dl>
</dd></dl>
<dl class="py method">
<dt class="sig sig-object py" id="pose_wrangler.v2.main.UERBFAPI.delete_pose">
<span class="sig-name descname"><span class="pre">delete_pose</span></span><span class="sig-paren">(</span><em class="sig-param"><span class="n"><span class="pre">pose_name</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">solver</span></span><span class="o"><span class="pre">=</span></span><span class="default_value"><span class="pre">None</span></span></em><span class="sig-paren">)</span><a class="headerlink" href="#pose_wrangler.v2.main.UERBFAPI.delete_pose" title="Permalink to this definition"></a></dt>
<dd><p>Remove a pose from the given solver</p>
<dl class="field-list simple">
<dt class="field-odd">Parameters</dt>
<dd class="field-odd"><ul class="simple">
<li><p><strong>pose_name</strong> (<em>str</em>) name of the pose to remove</p></li>
<li><p><strong>solver</strong> (<em>api.RBFNode</em>) solver reference</p></li>
</ul>
</dd>
</dl>
</dd></dl>
<dl class="py method">
<dt class="sig sig-object py" id="pose_wrangler.v2.main.UERBFAPI.go_to_pose">
<span class="sig-name descname"><span class="pre">go_to_pose</span></span><span class="sig-paren">(</span><em class="sig-param"><span class="n"><span class="pre">pose_name</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">solver</span></span><span class="o"><span class="pre">=</span></span><span class="default_value"><span class="pre">None</span></span></em><span class="sig-paren">)</span><a class="headerlink" href="#pose_wrangler.v2.main.UERBFAPI.go_to_pose" title="Permalink to this definition"></a></dt>
<dd><p>Move the driver/driven transforms to the given pose</p>
<dl class="field-list simple">
<dt class="field-odd">Parameters</dt>
<dd class="field-odd"><ul class="simple">
<li><p><strong>pose_name</strong> (<em>str</em>) name of the pose</p></li>
<li><p><strong>solver</strong> (<em>api.RBFNode</em>) solver reference</p></li>
</ul>
</dd>
</dl>
</dd></dl>
<dl class="py method">
<dt class="sig sig-object py" id="pose_wrangler.v2.main.UERBFAPI.mirror_pose">
<span class="sig-name descname"><span class="pre">mirror_pose</span></span><span class="sig-paren">(</span><em class="sig-param"><span class="n"><span class="pre">pose_name</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">solver</span></span><span class="o"><span class="pre">=</span></span><span class="default_value"><span class="pre">None</span></span></em><span class="sig-paren">)</span><a class="headerlink" href="#pose_wrangler.v2.main.UERBFAPI.mirror_pose" title="Permalink to this definition"></a></dt>
<dd><p>Mirror a pose to the mirror of the current solver</p>
<dl class="field-list simple">
<dt class="field-odd">Parameters</dt>
<dd class="field-odd"><ul class="simple">
<li><p><strong>pose_name</strong> (<em>str</em>) name of the pose</p></li>
<li><p><strong>solver</strong> (<em>api.RBFNode</em>) solver reference</p></li>
</ul>
</dd>
</dl>
</dd></dl>
<dl class="py method">
<dt class="sig sig-object py" id="pose_wrangler.v2.main.UERBFAPI.mute_pose">
<span class="sig-name descname"><span class="pre">mute_pose</span></span><span class="sig-paren">(</span><em class="sig-param"><span class="n"><span class="pre">pose_name</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">mute</span></span><span class="o"><span class="pre">=</span></span><span class="default_value"><span class="pre">True</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">solver</span></span><span class="o"><span class="pre">=</span></span><span class="default_value"><span class="pre">None</span></span></em><span class="sig-paren">)</span><a class="headerlink" href="#pose_wrangler.v2.main.UERBFAPI.mute_pose" title="Permalink to this definition"></a></dt>
<dd><p>Mute or unmute the specified pose, removing all influences of the pose from the solver.
NOTE: This will affect the solver radius if automatic radius is enabled.</p>
<dl class="field-list simple">
<dt class="field-odd">Parameters</dt>
<dd class="field-odd"><ul class="simple">
<li><p><strong>pose_name</strong> (<em>str</em>) name of the pose</p></li>
<li><p><strong>mute</strong> (<em>bool</em>) mute or unmute the pose</p></li>
<li><p><strong>solver</strong> (<em>api.RBFNode</em>) solver reference</p></li>
</ul>
</dd>
</dl>
</dd></dl>
<dl class="py method">
<dt class="sig sig-object py" id="pose_wrangler.v2.main.UERBFAPI.rename_pose">
<span class="sig-name descname"><span class="pre">rename_pose</span></span><span class="sig-paren">(</span><em class="sig-param"><span class="n"><span class="pre">pose_name</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">new_pose_name</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">solver</span></span><span class="o"><span class="pre">=</span></span><span class="default_value"><span class="pre">None</span></span></em><span class="sig-paren">)</span><a class="headerlink" href="#pose_wrangler.v2.main.UERBFAPI.rename_pose" title="Permalink to this definition"></a></dt>
<dd><p>Rename a pose on the given solver</p>
<dl class="field-list simple">
<dt class="field-odd">Parameters</dt>
<dd class="field-odd"><ul class="simple">
<li><p><strong>pose_name</strong> (<em>str</em>) name of the pose</p></li>
<li><p><strong>new_pose_name</strong> (<em>str</em>) new name of the pose</p></li>
<li><p><strong>solver</strong> (<em>api.RBFNode</em>) solver reference</p></li>
</ul>
</dd>
</dl>
</dd></dl>
<dl class="py method">
<dt class="sig sig-object py" id="pose_wrangler.v2.main.UERBFAPI.update_pose">
<span class="sig-name descname"><span class="pre">update_pose</span></span><span class="sig-paren">(</span><em class="sig-param"><span class="n"><span class="pre">pose_name</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">solver</span></span><span class="o"><span class="pre">=</span></span><span class="default_value"><span class="pre">None</span></span></em><span class="sig-paren">)</span><a class="headerlink" href="#pose_wrangler.v2.main.UERBFAPI.update_pose" title="Permalink to this definition"></a></dt>
<dd><p>Update the pose for the given solver</p>
<dl class="field-list simple">
<dt class="field-odd">Parameters</dt>
<dd class="field-odd"><ul class="simple">
<li><p><strong>pose_name</strong> (<em>str</em>) name of the pose to update</p></li>
<li><p><strong>solver</strong> (<em>api.RBFNode</em>) solver reference</p></li>
</ul>
</dd>
</dl>
</dd></dl>
<dl class="py method">
<dt class="sig sig-object py" id="pose_wrangler.v2.main.UERBFAPI.deserialize_from_file">
<span class="sig-name descname"><span class="pre">deserialize_from_file</span></span><span class="sig-paren">(</span><em class="sig-param"><span class="n"><span class="pre">file_path</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">solver_names</span></span><span class="o"><span class="pre">=</span></span><span class="default_value"><span class="pre">None</span></span></em><span class="sig-paren">)</span><a class="headerlink" href="#pose_wrangler.v2.main.UERBFAPI.deserialize_from_file" title="Permalink to this definition"></a></dt>
<dd><p>Deserialize solvers from a specific file.</p>
<dl class="field-list simple">
<dt class="field-odd">Parameters</dt>
<dd class="field-odd"><p><strong>file_path</strong> (<em>str</em>) json file to load</p>
</dd>
</dl>
</dd></dl>
<dl class="py method">
<dt class="sig sig-object py" id="pose_wrangler.v2.main.UERBFAPI.serialize_to_file">
<span class="sig-name descname"><span class="pre">serialize_to_file</span></span><span class="sig-paren">(</span><em class="sig-param"><span class="n"><span class="pre">file_path</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">solvers</span></span><span class="o"><span class="pre">=</span></span><span class="default_value"><span class="pre">None</span></span></em><span class="sig-paren">)</span><a class="headerlink" href="#pose_wrangler.v2.main.UERBFAPI.serialize_to_file" title="Permalink to this definition"></a></dt>
<dd><p>Serialize the specified solvers to a file</p>
<dl class="field-list simple">
<dt class="field-odd">Parameters</dt>
<dd class="field-odd"><ul class="simple">
<li><p><strong>file_path</strong> (<em>str</em>) json file to serialize</p></li>
<li><p><strong>solvers</strong> (<em>list</em>) list of api.RBFNode to serialize</p></li>
</ul>
</dd>
</dl>
</dd></dl>
<dl class="py method">
<dt class="sig sig-object py" id="pose_wrangler.v2.main.UERBFAPI.deserialize">
<span class="sig-name descname"><span class="pre">deserialize</span></span><span class="sig-paren">(</span><em class="sig-param"><span class="n"><span class="pre">data</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">solver_names</span></span><span class="o"><span class="pre">=</span></span><span class="default_value"><span class="pre">None</span></span></em><span class="sig-paren">)</span><a class="headerlink" href="#pose_wrangler.v2.main.UERBFAPI.deserialize" title="Permalink to this definition"></a></dt>
<dd><p>Deserialize and load the solvers from the data specified</p>
<dl class="field-list simple">
<dt class="field-odd">Parameters</dt>
<dd class="field-odd"><ul class="simple">
<li><p><strong>data</strong> (<em>dict</em>) serialized solver data</p></li>
<li><p><strong>solver_names</strong> (<em>list</em><em>, </em><em>optional</em>) list of solver names to load from the data</p></li>
</ul>
</dd>
</dl>
</dd></dl>
<dl class="py method">
<dt class="sig sig-object py" id="pose_wrangler.v2.main.UERBFAPI.serialize">
<span class="sig-name descname"><span class="pre">serialize</span></span><span class="sig-paren">(</span><em class="sig-param"><span class="n"><span class="pre">solvers</span></span><span class="o"><span class="pre">=</span></span><span class="default_value"><span class="pre">None</span></span></em><span class="sig-paren">)</span><a class="headerlink" href="#pose_wrangler.v2.main.UERBFAPI.serialize" title="Permalink to this definition"></a></dt>
<dd><p>Serialize the specified solvers</p>
<dl class="field-list simple">
<dt class="field-odd">Parameters</dt>
<dd class="field-odd"><p><strong>solvers</strong> (<em>list</em>) list of api.RBFNode to serialize</p>
</dd>
<dt class="field-even">Returns</dt>
<dd class="field-even"><p>serialized solver data</p>
</dd>
<dt class="field-odd">Return type</dt>
<dd class="field-odd"><p>dict</p>
</dd>
</dl>
</dd></dl>
<dl class="py method">
<dt class="sig sig-object py" id="pose_wrangler.v2.main.UERBFAPI.load">
<span class="sig-name descname"><span class="pre">load</span></span><span class="sig-paren">(</span><span class="sig-paren">)</span><a class="headerlink" href="#pose_wrangler.v2.main.UERBFAPI.load" title="Permalink to this definition"></a></dt>
<dd><p>Load the default pose wrangler settings</p>
</dd></dl>
<dl class="py method">
<dt class="sig sig-object py" id="pose_wrangler.v2.main.UERBFAPI.get_context">
<span class="sig-name descname"><span class="pre">get_context</span></span><span class="sig-paren">(</span><span class="sig-paren">)</span><a class="headerlink" href="#pose_wrangler.v2.main.UERBFAPI.get_context" title="Permalink to this definition"></a></dt>
<dd><p>Get the current solver context</p>
<dl class="field-list simple">
<dt class="field-odd">Returns</dt>
<dd class="field-odd"><p>pose wrangler context containing the current solver and all rbf solvers</p>
</dd>
<dt class="field-even">Return type</dt>
<dd class="field-even"><p>context.PoseWranglerContext</p>
</dd>
</dl>
</dd></dl>
<dl class="py method">
<dt class="sig sig-object py" id="pose_wrangler.v2.main.UERBFAPI.get_ui_context">
<span class="sig-name descname"><span class="pre">get_ui_context</span></span><span class="sig-paren">(</span><span class="sig-paren">)</span><a class="headerlink" href="#pose_wrangler.v2.main.UERBFAPI.get_ui_context" title="Permalink to this definition"></a></dt>
<dd><p>If the ui is available, return the ui context</p>
<dl class="field-list simple">
<dt class="field-odd">Returns</dt>
<dd class="field-odd"><p>ui context containing the current state of the ui</p>
</dd>
<dt class="field-even">Return type</dt>
<dd class="field-even"><p>ui_context.PoseWranglerUIContext or None</p>
</dd>
</dl>
</dd></dl>
<dl class="py method">
<dt class="sig sig-object py" id="pose_wrangler.v2.main.UERBFAPI.get_extension_by_type">
<span class="sig-name descname"><span class="pre">get_extension_by_type</span></span><span class="sig-paren">(</span><em class="sig-param"><span class="n"><span class="pre">class_ref</span></span></em><span class="sig-paren">)</span><a class="headerlink" href="#pose_wrangler.v2.main.UERBFAPI.get_extension_by_type" title="Permalink to this definition"></a></dt>
<dd><p>Get a reference to one of the loaded extensions from a class type</p>
<dl class="field-list simple">
<dt class="field-odd">Parameters</dt>
<dd class="field-odd"><p><strong>class_ref</strong> (<a class="reference internal" href="extensions.html#pose_wrangler.v2.model.base_extension.PoseWranglerExtension" title="pose_wrangler.v2.model.base_extension.PoseWranglerExtension"><em>base_extension.PoseWranglerExtension</em></a>) reference to an extension class</p>
</dd>
<dt class="field-even">Returns</dt>
<dd class="field-even"><p>reference to a loaded extension if one is loaded</p>
</dd>
<dt class="field-odd">Return type</dt>
<dd class="field-odd"><p>base_extension.PoseWranglerExtension instance or None</p>
</dd>
</dl>
</dd></dl>
<dl class="py method">
<dt class="sig sig-object py" id="pose_wrangler.v2.main.UERBFAPI.set_mirror_mapping">
<span class="sig-name descname"><span class="pre">set_mirror_mapping</span></span><span class="sig-paren">(</span><em class="sig-param"><span class="n"><span class="pre">path</span></span><span class="o"><span class="pre">=</span></span><span class="default_value"><span class="pre">None</span></span></em><span class="sig-paren">)</span><a class="headerlink" href="#pose_wrangler.v2.main.UERBFAPI.set_mirror_mapping" title="Permalink to this definition"></a></dt>
<dd><p>Set the mirror mapping from a file</p>
<dl class="field-list simple">
<dt class="field-odd">Parameters</dt>
<dd class="field-odd"><p><strong>path</strong> (<em>str</em>) path to json mirror mapping file</p>
</dd>
</dl>
</dd></dl>
<dl class="py method">
<dt class="sig sig-object py" id="pose_wrangler.v2.main.UERBFAPI.get_solver_edit_status">
<span class="sig-name descname"><span class="pre">get_solver_edit_status</span></span><span class="sig-paren">(</span><em class="sig-param"><span class="n"><span class="pre">solver</span></span></em><span class="sig-paren">)</span><a class="headerlink" href="#pose_wrangler.v2.main.UERBFAPI.get_solver_edit_status" title="Permalink to this definition"></a></dt>
<dd><p>Check if the current solver is in Edit mode</p>
<dl class="field-list simple">
<dt class="field-odd">Parameters</dt>
<dd class="field-odd"><p><strong>solver</strong> (<em>api.RBFNode</em>) solver reference</p>
</dd>
<dt class="field-even">Returns</dt>
<dd class="field-even"><p>True = in edit mode, False = not in edit mode</p>
</dd>
<dt class="field-odd">Return type</dt>
<dd class="field-odd"><p>bool</p>
</dd>
</dl>
</dd></dl>
</dd></dl>
</section>
</section>
</div>
</div>
<footer><div class="rst-footer-buttons" role="navigation" aria-label="Footer">
<a href="extensions.html" class="btn btn-neutral float-left" title="Extensions" accesskey="p" rel="prev"><span class="fa fa-arrow-circle-left" aria-hidden="true"></span> Previous</a>
</div>
<hr/>
<div role="contentinfo">
<p>&#169; Copyright 2022, Epic Games.</p>
</div>
Built with <a href="https://www.sphinx-doc.org/">Sphinx</a> using a
<a href="https://github.com/readthedocs/sphinx_rtd_theme">theme</a>
provided by <a href="https://readthedocs.org">Read the Docs</a>.
</footer>
</div>
</div>
</section>
</div>
<script>
jQuery(function () {
SphinxRtdTheme.Navigation.enable(true);
});
</script>
</body>
</html>

View File

@ -0,0 +1,176 @@
<!DOCTYPE html>
<html class="writer-html5" lang="en" >
<head>
<meta charset="utf-8" /><meta name="generator" content="Docutils 0.17.1: http://docutils.sourceforge.net/" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Extensions &mdash; Pose Wrangler 2.0.0 documentation</title>
<link rel="stylesheet" href="_static/pygments.css" type="text/css" />
<link rel="stylesheet" href="_static/css/theme.css" type="text/css" />
<!--[if lt IE 9]>
<script src="_static/js/html5shiv.min.js"></script>
<![endif]-->
<script data-url_root="./" id="documentation_options" src="_static/documentation_options.js"></script>
<script src="_static/jquery.js"></script>
<script src="_static/underscore.js"></script>
<script src="_static/doctools.js"></script>
<script src="_static/js/theme.js"></script>
<link rel="index" title="Index" href="genindex.html" />
<link rel="search" title="Search" href="search.html" />
<link rel="next" title="API" href="api.html" />
<link rel="prev" title="Mirror Mapping" href="mirror_mapping.html" />
</head>
<body class="wy-body-for-nav">
<div class="wy-grid-for-nav">
<nav data-toggle="wy-nav-shift" class="wy-nav-side">
<div class="wy-side-scroll">
<div class="wy-side-nav-search" >
<a href="index.html" class="icon icon-home"> Pose Wrangler
</a>
<div role="search">
<form id="rtd-search-form" class="wy-form" action="search.html" method="get">
<input type="text" name="q" placeholder="Search docs" />
<input type="hidden" name="check_keywords" value="yes" />
<input type="hidden" name="area" value="default" />
</form>
</div>
</div><div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="Navigation menu">
<p class="caption" role="heading"><span class="caption-text">Contents:</span></p>
<ul class="current">
<li class="toctree-l1"><a class="reference internal" href="overview.html">2.0.0 Overview</a></li>
<li class="toctree-l1"><a class="reference internal" href="upgrading.html">Upgrading to 2.0.0</a></li>
<li class="toctree-l1"><a class="reference internal" href="mirror_mapping.html">Mirror Mapping</a></li>
<li class="toctree-l1 current"><a class="current reference internal" href="#">Extensions</a></li>
<li class="toctree-l1"><a class="reference internal" href="api.html">API</a></li>
</ul>
</div>
</div>
</nav>
<section data-toggle="wy-nav-shift" class="wy-nav-content-wrap"><nav class="wy-nav-top" aria-label="Mobile navigation menu" >
<i data-toggle="wy-nav-top" class="fa fa-bars"></i>
<a href="index.html">Pose Wrangler</a>
</nav>
<div class="wy-nav-content">
<div class="rst-content">
<div role="navigation" aria-label="Page navigation">
<ul class="wy-breadcrumbs">
<li><a href="index.html" class="icon icon-home"></a> &raquo;</li>
<li>Extensions</li>
<li class="wy-breadcrumbs-aside">
<a href="_sources/extensions.rst.txt" rel="nofollow"> View page source</a>
</li>
</ul>
<hr/>
</div>
<div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article">
<div itemprop="articleBody">
<section id="extensions">
<h1>Extensions<a class="headerlink" href="#extensions" title="Permalink to this headline"></a></h1>
<p>You can now create custom extensions for PoseWrangler so you can introduce new features without having to edit the
core code base.</p>
<p>Custom extensions can be created by inheriting from the following class:</p>
<dl class="py class">
<dt class="sig sig-object py" id="pose_wrangler.v2.model.base_extension.PoseWranglerExtension">
<em class="property"><span class="pre">class</span><span class="w"> </span></em><span class="sig-prename descclassname"><span class="pre">pose_wrangler.v2.model.base_extension.</span></span><span class="sig-name descname"><span class="pre">PoseWranglerExtension</span></span><span class="sig-paren">(</span><em class="sig-param"><span class="n"><span class="pre">display_view</span></span><span class="o"><span class="pre">=</span></span><span class="default_value"><span class="pre">False</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">api</span></span><span class="o"><span class="pre">=</span></span><span class="default_value"><span class="pre">None</span></span></em><span class="sig-paren">)</span><a class="headerlink" href="#pose_wrangler.v2.model.base_extension.PoseWranglerExtension" title="Permalink to this definition"></a></dt>
<dd><p>Bases: <code class="xref py py-class docutils literal notranslate"><span class="pre">object</span></code></p>
<p>Base class for extending pose wrangler with custom utilities that can be dynamically added to the UI</p>
<dl class="py property">
<dt class="sig sig-object py" id="pose_wrangler.v2.model.base_extension.PoseWranglerExtension.api">
<em class="property"><span class="pre">property</span><span class="w"> </span></em><span class="sig-name descname"><span class="pre">api</span></span><a class="headerlink" href="#pose_wrangler.v2.model.base_extension.PoseWranglerExtension.api" title="Permalink to this definition"></a></dt>
<dd><p>Get the current API</p>
<dl class="field-list simple">
<dt class="field-odd">Returns</dt>
<dd class="field-odd"><p>Reference to the main API interface</p>
</dd>
<dt class="field-even">Return type</dt>
<dd class="field-even"><p><a class="reference internal" href="api.html#pose_wrangler.v2.main.UERBFAPI" title="pose_wrangler.v2.main.UERBFAPI">pose_wrangler.v2.main.UERBFAPI</a></p>
</dd>
</dl>
</dd></dl>
<dl class="py property">
<dt class="sig sig-object py" id="pose_wrangler.v2.model.base_extension.PoseWranglerExtension.view">
<em class="property"><span class="pre">property</span><span class="w"> </span></em><span class="sig-name descname"><span class="pre">view</span></span><a class="headerlink" href="#pose_wrangler.v2.model.base_extension.PoseWranglerExtension.view" title="Permalink to this definition"></a></dt>
<dd><p>Get the current view widget. This should be overridden by custom extensions if you wish to embed a UI for this
extension into the main PoseWrangler UI</p>
<dl class="field-list simple">
<dt class="field-odd">Returns</dt>
<dd class="field-odd"><p>Reference to the PySide widget associated with this extension</p>
</dd>
<dt class="field-even">Return type</dt>
<dd class="field-even"><p>QWidget or None</p>
</dd>
</dl>
</dd></dl>
<dl class="py method">
<dt class="sig sig-object py" id="pose_wrangler.v2.model.base_extension.PoseWranglerExtension.execute">
<span class="sig-name descname"><span class="pre">execute</span></span><span class="sig-paren">(</span><em class="sig-param"><span class="n"><span class="pre">context</span></span><span class="o"><span class="pre">=</span></span><span class="default_value"><span class="pre">None</span></span></em>, <em class="sig-param"><span class="o"><span class="pre">**</span></span><span class="n"><span class="pre">kwargs</span></span></em><span class="sig-paren">)</span><a class="headerlink" href="#pose_wrangler.v2.model.base_extension.PoseWranglerExtension.execute" title="Permalink to this definition"></a></dt>
<dd><p>Generic entrypoint for executing the extension</p>
<dl class="field-list simple">
<dt class="field-odd">Param</dt>
<dd class="field-odd"><p>context: pose wrangler context containing current solver and all solvers</p>
</dd>
</dl>
</dd></dl>
<dl class="py method">
<dt class="sig sig-object py" id="pose_wrangler.v2.model.base_extension.PoseWranglerExtension.on_context_changed">
<span class="sig-name descname"><span class="pre">on_context_changed</span></span><span class="sig-paren">(</span><em class="sig-param"><span class="n"><span class="pre">new_context</span></span></em><span class="sig-paren">)</span><a class="headerlink" href="#pose_wrangler.v2.model.base_extension.PoseWranglerExtension.on_context_changed" title="Permalink to this definition"></a></dt>
<dd><p>Context event called when the current solver is set via the API</p>
<dl class="field-list simple">
<dt class="field-odd">Parameters</dt>
<dd class="field-odd"><p><strong>new_context</strong> (<em>pose_wrangler.v2.model.context.PoseWranglerContext</em><em> or </em><em>None</em>) pose wrangler context containing current solver and all solvers</p>
</dd>
</dl>
</dd></dl>
</dd></dl>
<p>When PoseWrangler loads up, it will automatically detect and load any classes that inherit from <code class="docutils literal notranslate"><span class="pre">PoseWranglerExtension</span></code>
on startup.</p>
<div class="admonition note">
<p class="admonition-title">Note</p>
<p>To make sure that your extension loads, please make sure that it is imported before you start PoseWrangler.</p>
</div>
<p>Example extensions can be found under <code class="docutils literal notranslate"><span class="pre">pose_wrangler.v2.extensions</span></code></p>
</section>
</div>
</div>
<footer><div class="rst-footer-buttons" role="navigation" aria-label="Footer">
<a href="mirror_mapping.html" class="btn btn-neutral float-left" title="Mirror Mapping" accesskey="p" rel="prev"><span class="fa fa-arrow-circle-left" aria-hidden="true"></span> Previous</a>
<a href="api.html" class="btn btn-neutral float-right" title="API" accesskey="n" rel="next">Next <span class="fa fa-arrow-circle-right" aria-hidden="true"></span></a>
</div>
<hr/>
<div role="contentinfo">
<p>&#169; Copyright 2022, Epic Games.</p>
</div>
Built with <a href="https://www.sphinx-doc.org/">Sphinx</a> using a
<a href="https://github.com/readthedocs/sphinx_rtd_theme">theme</a>
provided by <a href="https://readthedocs.org">Read the Docs</a>.
</footer>
</div>
</div>
</section>
</div>
<script>
jQuery(function () {
SphinxRtdTheme.Navigation.enable(true);
});
</script>
</body>
</html>

View File

@ -0,0 +1,310 @@
<!DOCTYPE html>
<html class="writer-html5" lang="en" >
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Index &mdash; Pose Wrangler 2.0.0 documentation</title>
<link rel="stylesheet" href="_static/pygments.css" type="text/css" />
<link rel="stylesheet" href="_static/css/theme.css" type="text/css" />
<!--[if lt IE 9]>
<script src="_static/js/html5shiv.min.js"></script>
<![endif]-->
<script data-url_root="./" id="documentation_options" src="_static/documentation_options.js"></script>
<script src="_static/jquery.js"></script>
<script src="_static/underscore.js"></script>
<script src="_static/doctools.js"></script>
<script src="_static/js/theme.js"></script>
<link rel="index" title="Index" href="#" />
<link rel="search" title="Search" href="search.html" />
</head>
<body class="wy-body-for-nav">
<div class="wy-grid-for-nav">
<nav data-toggle="wy-nav-shift" class="wy-nav-side">
<div class="wy-side-scroll">
<div class="wy-side-nav-search" >
<a href="index.html" class="icon icon-home"> Pose Wrangler
</a>
<div role="search">
<form id="rtd-search-form" class="wy-form" action="search.html" method="get">
<input type="text" name="q" placeholder="Search docs" />
<input type="hidden" name="check_keywords" value="yes" />
<input type="hidden" name="area" value="default" />
</form>
</div>
</div><div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="Navigation menu">
<p class="caption" role="heading"><span class="caption-text">Contents:</span></p>
<ul>
<li class="toctree-l1"><a class="reference internal" href="overview.html">2.0.0 Overview</a></li>
<li class="toctree-l1"><a class="reference internal" href="upgrading.html">Upgrading to 2.0.0</a></li>
<li class="toctree-l1"><a class="reference internal" href="mirror_mapping.html">Mirror Mapping</a></li>
<li class="toctree-l1"><a class="reference internal" href="extensions.html">Extensions</a></li>
<li class="toctree-l1"><a class="reference internal" href="api.html">API</a></li>
</ul>
</div>
</div>
</nav>
<section data-toggle="wy-nav-shift" class="wy-nav-content-wrap"><nav class="wy-nav-top" aria-label="Mobile navigation menu" >
<i data-toggle="wy-nav-top" class="fa fa-bars"></i>
<a href="index.html">Pose Wrangler</a>
</nav>
<div class="wy-nav-content">
<div class="rst-content">
<div role="navigation" aria-label="Page navigation">
<ul class="wy-breadcrumbs">
<li><a href="index.html" class="icon icon-home"></a> &raquo;</li>
<li>Index</li>
<li class="wy-breadcrumbs-aside">
</li>
</ul>
<hr/>
</div>
<div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article">
<div itemprop="articleBody">
<h1 id="index">Index</h1>
<div class="genindex-jumpbox">
<a href="#A"><strong>A</strong></a>
| <a href="#C"><strong>C</strong></a>
| <a href="#D"><strong>D</strong></a>
| <a href="#E"><strong>E</strong></a>
| <a href="#G"><strong>G</strong></a>
| <a href="#I"><strong>I</strong></a>
| <a href="#L"><strong>L</strong></a>
| <a href="#M"><strong>M</strong></a>
| <a href="#O"><strong>O</strong></a>
| <a href="#P"><strong>P</strong></a>
| <a href="#R"><strong>R</strong></a>
| <a href="#S"><strong>S</strong></a>
| <a href="#U"><strong>U</strong></a>
| <a href="#V"><strong>V</strong></a>
</div>
<h2 id="A">A</h2>
<table style="width: 100%" class="indextable genindextable"><tr>
<td style="width: 33%; vertical-align: top;"><ul>
<li><a href="api.html#pose_wrangler.v2.main.UERBFAPI.add_blendshape">add_blendshape() (pose_wrangler.v2.main.UERBFAPI method)</a>
</li>
<li><a href="api.html#pose_wrangler.v2.main.UERBFAPI.add_driven_transforms">add_driven_transforms() (pose_wrangler.v2.main.UERBFAPI method)</a>
</li>
</ul></td>
<td style="width: 33%; vertical-align: top;"><ul>
<li><a href="api.html#pose_wrangler.v2.main.UERBFAPI.add_drivers">add_drivers() (pose_wrangler.v2.main.UERBFAPI method)</a>
</li>
<li><a href="extensions.html#pose_wrangler.v2.model.base_extension.PoseWranglerExtension.api">api (pose_wrangler.v2.model.base_extension.PoseWranglerExtension property)</a>
</li>
</ul></td>
</tr></table>
<h2 id="C">C</h2>
<table style="width: 100%" class="indextable genindextable"><tr>
<td style="width: 33%; vertical-align: top;"><ul>
<li><a href="api.html#pose_wrangler.v2.main.UERBFAPI.create_blendshape">create_blendshape() (pose_wrangler.v2.main.UERBFAPI method)</a>
</li>
<li><a href="api.html#pose_wrangler.v2.main.UERBFAPI.create_pose">create_pose() (pose_wrangler.v2.main.UERBFAPI method)</a>
</li>
</ul></td>
<td style="width: 33%; vertical-align: top;"><ul>
<li><a href="api.html#pose_wrangler.v2.main.UERBFAPI.create_rbf_solver">create_rbf_solver() (pose_wrangler.v2.main.UERBFAPI method)</a>
</li>
<li><a href="api.html#pose_wrangler.v2.main.UERBFAPI.current_solver">current_solver (pose_wrangler.v2.main.UERBFAPI property)</a>
</li>
</ul></td>
</tr></table>
<h2 id="D">D</h2>
<table style="width: 100%" class="indextable genindextable"><tr>
<td style="width: 33%; vertical-align: top;"><ul>
<li><a href="api.html#pose_wrangler.v2.main.UERBFAPI.delete_blendshape">delete_blendshape() (pose_wrangler.v2.main.UERBFAPI method)</a>
</li>
<li><a href="api.html#pose_wrangler.v2.main.UERBFAPI.delete_pose">delete_pose() (pose_wrangler.v2.main.UERBFAPI method)</a>
</li>
</ul></td>
<td style="width: 33%; vertical-align: top;"><ul>
<li><a href="api.html#pose_wrangler.v2.main.UERBFAPI.delete_rbf_solver">delete_rbf_solver() (pose_wrangler.v2.main.UERBFAPI method)</a>
</li>
<li><a href="api.html#pose_wrangler.v2.main.UERBFAPI.deserialize">deserialize() (pose_wrangler.v2.main.UERBFAPI method)</a>
</li>
<li><a href="api.html#pose_wrangler.v2.main.UERBFAPI.deserialize_from_file">deserialize_from_file() (pose_wrangler.v2.main.UERBFAPI method)</a>
</li>
</ul></td>
</tr></table>
<h2 id="E">E</h2>
<table style="width: 100%" class="indextable genindextable"><tr>
<td style="width: 33%; vertical-align: top;"><ul>
<li><a href="api.html#pose_wrangler.v2.main.UERBFAPI.edit_blendshape">edit_blendshape() (pose_wrangler.v2.main.UERBFAPI method)</a>
</li>
<li><a href="api.html#pose_wrangler.v2.main.UERBFAPI.edit_solver">edit_solver() (pose_wrangler.v2.main.UERBFAPI method)</a>
</li>
</ul></td>
<td style="width: 33%; vertical-align: top;"><ul>
<li><a href="extensions.html#pose_wrangler.v2.model.base_extension.PoseWranglerExtension.execute">execute() (pose_wrangler.v2.model.base_extension.PoseWranglerExtension method)</a>
</li>
<li><a href="api.html#pose_wrangler.v2.main.UERBFAPI.extensions">extensions (pose_wrangler.v2.main.UERBFAPI property)</a>
</li>
</ul></td>
</tr></table>
<h2 id="G">G</h2>
<table style="width: 100%" class="indextable genindextable"><tr>
<td style="width: 33%; vertical-align: top;"><ul>
<li><a href="api.html#pose_wrangler.v2.main.UERBFAPI.get_context">get_context() (pose_wrangler.v2.main.UERBFAPI method)</a>
</li>
<li><a href="api.html#pose_wrangler.v2.main.UERBFAPI.get_extension_by_type">get_extension_by_type() (pose_wrangler.v2.main.UERBFAPI method)</a>
</li>
<li><a href="api.html#pose_wrangler.v2.main.UERBFAPI.get_rbf_solver_by_name">get_rbf_solver_by_name() (pose_wrangler.v2.main.UERBFAPI method)</a>
</li>
</ul></td>
<td style="width: 33%; vertical-align: top;"><ul>
<li><a href="api.html#pose_wrangler.v2.main.UERBFAPI.get_solver_edit_status">get_solver_edit_status() (pose_wrangler.v2.main.UERBFAPI method)</a>
</li>
<li><a href="api.html#pose_wrangler.v2.main.UERBFAPI.get_ui_context">get_ui_context() (pose_wrangler.v2.main.UERBFAPI method)</a>
</li>
<li><a href="api.html#pose_wrangler.v2.main.UERBFAPI.go_to_pose">go_to_pose() (pose_wrangler.v2.main.UERBFAPI method)</a>
</li>
</ul></td>
</tr></table>
<h2 id="I">I</h2>
<table style="width: 100%" class="indextable genindextable"><tr>
<td style="width: 33%; vertical-align: top;"><ul>
<li><a href="api.html#pose_wrangler.v2.main.UERBFAPI.isolate_blendshape">isolate_blendshape() (pose_wrangler.v2.main.UERBFAPI method)</a>
</li>
</ul></td>
</tr></table>
<h2 id="L">L</h2>
<table style="width: 100%" class="indextable genindextable"><tr>
<td style="width: 33%; vertical-align: top;"><ul>
<li><a href="api.html#pose_wrangler.v2.main.UERBFAPI.load">load() (pose_wrangler.v2.main.UERBFAPI method)</a>
</li>
</ul></td>
</tr></table>
<h2 id="M">M</h2>
<table style="width: 100%" class="indextable genindextable"><tr>
<td style="width: 33%; vertical-align: top;"><ul>
<li><a href="api.html#pose_wrangler.v2.main.UERBFAPI.mirror_mapping">mirror_mapping (pose_wrangler.v2.main.UERBFAPI property)</a>
</li>
<li><a href="api.html#pose_wrangler.v2.main.UERBFAPI.mirror_pose">mirror_pose() (pose_wrangler.v2.main.UERBFAPI method)</a>
</li>
</ul></td>
<td style="width: 33%; vertical-align: top;"><ul>
<li><a href="api.html#pose_wrangler.v2.main.UERBFAPI.mirror_rbf_solver">mirror_rbf_solver() (pose_wrangler.v2.main.UERBFAPI method)</a>
</li>
<li><a href="api.html#pose_wrangler.v2.main.UERBFAPI.mute_pose">mute_pose() (pose_wrangler.v2.main.UERBFAPI method)</a>
</li>
</ul></td>
</tr></table>
<h2 id="O">O</h2>
<table style="width: 100%" class="indextable genindextable"><tr>
<td style="width: 33%; vertical-align: top;"><ul>
<li><a href="extensions.html#pose_wrangler.v2.model.base_extension.PoseWranglerExtension.on_context_changed">on_context_changed() (pose_wrangler.v2.model.base_extension.PoseWranglerExtension method)</a>
</li>
</ul></td>
</tr></table>
<h2 id="P">P</h2>
<table style="width: 100%" class="indextable genindextable"><tr>
<td style="width: 33%; vertical-align: top;"><ul>
<li><a href="extensions.html#pose_wrangler.v2.model.base_extension.PoseWranglerExtension">PoseWranglerExtension (class in pose_wrangler.v2.model.base_extension)</a>
</li>
</ul></td>
</tr></table>
<h2 id="R">R</h2>
<table style="width: 100%" class="indextable genindextable"><tr>
<td style="width: 33%; vertical-align: top;"><ul>
<li><a href="api.html#pose_wrangler.v2.main.UERBFAPI.rbf_solvers">rbf_solvers (pose_wrangler.v2.main.UERBFAPI property)</a>
</li>
<li><a href="api.html#pose_wrangler.v2.main.UERBFAPI.remove_driven">remove_driven() (pose_wrangler.v2.main.UERBFAPI method)</a>
</li>
</ul></td>
<td style="width: 33%; vertical-align: top;"><ul>
<li><a href="api.html#pose_wrangler.v2.main.UERBFAPI.remove_drivers">remove_drivers() (pose_wrangler.v2.main.UERBFAPI method)</a>
</li>
<li><a href="api.html#pose_wrangler.v2.main.UERBFAPI.rename_pose">rename_pose() (pose_wrangler.v2.main.UERBFAPI method)</a>
</li>
</ul></td>
</tr></table>
<h2 id="S">S</h2>
<table style="width: 100%" class="indextable genindextable"><tr>
<td style="width: 33%; vertical-align: top;"><ul>
<li><a href="api.html#pose_wrangler.v2.main.UERBFAPI.serialize">serialize() (pose_wrangler.v2.main.UERBFAPI method)</a>
</li>
</ul></td>
<td style="width: 33%; vertical-align: top;"><ul>
<li><a href="api.html#pose_wrangler.v2.main.UERBFAPI.serialize_to_file">serialize_to_file() (pose_wrangler.v2.main.UERBFAPI method)</a>
</li>
<li><a href="api.html#pose_wrangler.v2.main.UERBFAPI.set_mirror_mapping">set_mirror_mapping() (pose_wrangler.v2.main.UERBFAPI method)</a>
</li>
</ul></td>
</tr></table>
<h2 id="U">U</h2>
<table style="width: 100%" class="indextable genindextable"><tr>
<td style="width: 33%; vertical-align: top;"><ul>
<li><a href="api.html#pose_wrangler.v2.main.UERBFAPI">UERBFAPI (class in pose_wrangler.v2.main)</a>
</li>
</ul></td>
<td style="width: 33%; vertical-align: top;"><ul>
<li><a href="api.html#pose_wrangler.v2.main.UERBFAPI.update_pose">update_pose() (pose_wrangler.v2.main.UERBFAPI method)</a>
</li>
</ul></td>
</tr></table>
<h2 id="V">V</h2>
<table style="width: 100%" class="indextable genindextable"><tr>
<td style="width: 33%; vertical-align: top;"><ul>
<li><a href="api.html#pose_wrangler.v2.main.UERBFAPI.VERSION">VERSION (pose_wrangler.v2.main.UERBFAPI attribute)</a>
</li>
</ul></td>
<td style="width: 33%; vertical-align: top;"><ul>
<li><a href="api.html#pose_wrangler.v2.main.UERBFAPI.view">view (pose_wrangler.v2.main.UERBFAPI property)</a>
<ul>
<li><a href="extensions.html#pose_wrangler.v2.model.base_extension.PoseWranglerExtension.view">(pose_wrangler.v2.model.base_extension.PoseWranglerExtension property)</a>
</li>
</ul></li>
</ul></td>
</tr></table>
</div>
</div>
<footer>
<hr/>
<div role="contentinfo">
<p>&#169; Copyright 2022, Epic Games.</p>
</div>
Built with <a href="https://www.sphinx-doc.org/">Sphinx</a> using a
<a href="https://github.com/readthedocs/sphinx_rtd_theme">theme</a>
provided by <a href="https://readthedocs.org">Read the Docs</a>.
</footer>
</div>
</div>
</section>
</div>
<script>
jQuery(function () {
SphinxRtdTheme.Navigation.enable(true);
});
</script>
</body>
</html>

View File

@ -0,0 +1,168 @@
<!DOCTYPE html>
<html class="writer-html5" lang="en" >
<head>
<meta charset="utf-8" /><meta name="generator" content="Docutils 0.17.1: http://docutils.sourceforge.net/" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Pose Wrangler Documentation &mdash; Pose Wrangler 2.0.0 documentation</title>
<link rel="stylesheet" href="_static/pygments.css" type="text/css" />
<link rel="stylesheet" href="_static/css/theme.css" type="text/css" />
<!--[if lt IE 9]>
<script src="_static/js/html5shiv.min.js"></script>
<![endif]-->
<script data-url_root="./" id="documentation_options" src="_static/documentation_options.js"></script>
<script src="_static/jquery.js"></script>
<script src="_static/underscore.js"></script>
<script src="_static/doctools.js"></script>
<script src="_static/js/theme.js"></script>
<link rel="index" title="Index" href="genindex.html" />
<link rel="search" title="Search" href="search.html" />
<link rel="next" title="2.0.0 Overview" href="overview.html" />
</head>
<body class="wy-body-for-nav">
<div class="wy-grid-for-nav">
<nav data-toggle="wy-nav-shift" class="wy-nav-side">
<div class="wy-side-scroll">
<div class="wy-side-nav-search" >
<a href="#" class="icon icon-home"> Pose Wrangler
</a>
<div role="search">
<form id="rtd-search-form" class="wy-form" action="search.html" method="get">
<input type="text" name="q" placeholder="Search docs" />
<input type="hidden" name="check_keywords" value="yes" />
<input type="hidden" name="area" value="default" />
</form>
</div>
</div><div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="Navigation menu">
<p class="caption" role="heading"><span class="caption-text">Contents:</span></p>
<ul>
<li class="toctree-l1"><a class="reference internal" href="overview.html">2.0.0 Overview</a></li>
<li class="toctree-l1"><a class="reference internal" href="upgrading.html">Upgrading to 2.0.0</a></li>
<li class="toctree-l1"><a class="reference internal" href="mirror_mapping.html">Mirror Mapping</a></li>
<li class="toctree-l1"><a class="reference internal" href="extensions.html">Extensions</a></li>
<li class="toctree-l1"><a class="reference internal" href="api.html">API</a></li>
</ul>
</div>
</div>
</nav>
<section data-toggle="wy-nav-shift" class="wy-nav-content-wrap"><nav class="wy-nav-top" aria-label="Mobile navigation menu" >
<i data-toggle="wy-nav-top" class="fa fa-bars"></i>
<a href="#">Pose Wrangler</a>
</nav>
<div class="wy-nav-content">
<div class="rst-content">
<div role="navigation" aria-label="Page navigation">
<ul class="wy-breadcrumbs">
<li><a href="#" class="icon icon-home"></a> &raquo;</li>
<li>Pose Wrangler Documentation</li>
<li class="wy-breadcrumbs-aside">
<a href="_sources/index.rst.txt" rel="nofollow"> View page source</a>
</li>
</ul>
<hr/>
</div>
<div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article">
<div itemprop="articleBody">
<section id="pose-wrangler-documentation">
<h1>Pose Wrangler Documentation<a class="headerlink" href="#pose-wrangler-documentation" title="Permalink to this headline"></a></h1>
<div class="toctree-wrapper compound">
<p class="caption" role="heading"><span class="caption-text">Contents:</span></p>
<ul>
<li class="toctree-l1"><a class="reference internal" href="overview.html">2.0.0 Overview</a><ul>
<li class="toctree-l2"><a class="reference internal" href="overview.html#ui-overview">UI Overview</a></li>
</ul>
</li>
<li class="toctree-l1"><a class="reference internal" href="upgrading.html">Upgrading to 2.0.0</a></li>
<li class="toctree-l1"><a class="reference internal" href="mirror_mapping.html">Mirror Mapping</a></li>
<li class="toctree-l1"><a class="reference internal" href="extensions.html">Extensions</a></li>
<li class="toctree-l1"><a class="reference internal" href="api.html">API</a><ul>
<li class="toctree-l2"><a class="reference internal" href="api.html#pose-wrangler-v2-main">pose_wrangler.v2.main</a></li>
</ul>
</li>
</ul>
</div>
</section>
<section id="overview">
<h1>Overview<a class="headerlink" href="#overview" title="Permalink to this headline"></a></h1>
<p>PoseWrangler is a tool for interfacing with Epics MayaUERBFPlugin. The plugin is distributed by Epic Games and installed via Quixel Bridge.</p>
<section id="versions">
<h2>Versions<a class="headerlink" href="#versions" title="Permalink to this headline"></a></h2>
<section id="id1">
<h3>1.0.0:<a class="headerlink" href="#id1" title="Permalink to this headline"></a></h3>
<ul class="simple">
<li><p>Supports legacy scenes created with the UE4RBFSolverNode</p></li>
<li><p>Supports Maya 2018-2022</p></li>
<li><p>Provides upgrade workflow to migrate to V2</p></li>
</ul>
</section>
<section id="id2">
<h3>2.0.0:<a class="headerlink" href="#id2" title="Permalink to this headline"></a></h3>
<ul class="simple">
<li><p>Supports scenes created with the UERBFSolverNode</p></li>
<li><p>Multiple Driver Support</p></li>
<li><p>Initial blendshape support (WIP)</p></li>
<li><p>Supports Maya 2018-2022</p></li>
<li><p>Support for custom mirror mappings to allow for rigs with naming conventions that deviate from the default UE5 conventions</p></li>
<li><p>Fully automatable via Python and MayaPy</p></li>
<li><p>Serialization/deserialization to dictionary or JSON file</p></li>
<li><p>Support for custom extensions and context menu actions</p></li>
</ul>
</section>
</section>
<section id="contributors">
<h2>Contributors<a class="headerlink" href="#contributors" title="Permalink to this headline"></a></h2>
<ul class="simple">
<li><p>Chris Evans</p></li>
<li><p>Judd Simantov</p></li>
<li><p>David Corral</p></li>
<li><p>Borna Berc</p></li>
<li><p>Chris Theodosius</p></li>
</ul>
</section>
</section>
<section id="indices-and-tables">
<h1>Indices and tables<a class="headerlink" href="#indices-and-tables" title="Permalink to this headline"></a></h1>
<ul class="simple">
<li><p><a class="reference internal" href="genindex.html"><span class="std std-ref">Index</span></a></p></li>
<li><p><a class="reference internal" href="py-modindex.html"><span class="std std-ref">Module Index</span></a></p></li>
<li><p><a class="reference internal" href="search.html"><span class="std std-ref">Search Page</span></a></p></li>
</ul>
</section>
</div>
</div>
<footer><div class="rst-footer-buttons" role="navigation" aria-label="Footer">
<a href="overview.html" class="btn btn-neutral float-right" title="2.0.0 Overview" accesskey="n" rel="next">Next <span class="fa fa-arrow-circle-right" aria-hidden="true"></span></a>
</div>
<hr/>
<div role="contentinfo">
<p>&#169; Copyright 2022, Epic Games.</p>
</div>
Built with <a href="https://www.sphinx-doc.org/">Sphinx</a> using a
<a href="https://github.com/readthedocs/sphinx_rtd_theme">theme</a>
provided by <a href="https://readthedocs.org">Read the Docs</a>.
</footer>
</div>
</div>
</section>
</div>
<script>
jQuery(function () {
SphinxRtdTheme.Navigation.enable(true);
});
</script>
</body>
</html>

View File

@ -0,0 +1,168 @@
<!DOCTYPE html>
<html class="writer-html5" lang="en" >
<head>
<meta charset="utf-8" /><meta name="generator" content="Docutils 0.17.1: http://docutils.sourceforge.net/" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Mirror Mapping &mdash; Pose Wrangler 2.0.0 documentation</title>
<link rel="stylesheet" href="_static/pygments.css" type="text/css" />
<link rel="stylesheet" href="_static/css/theme.css" type="text/css" />
<!--[if lt IE 9]>
<script src="_static/js/html5shiv.min.js"></script>
<![endif]-->
<script data-url_root="./" id="documentation_options" src="_static/documentation_options.js"></script>
<script src="_static/jquery.js"></script>
<script src="_static/underscore.js"></script>
<script src="_static/doctools.js"></script>
<script src="_static/js/theme.js"></script>
<link rel="index" title="Index" href="genindex.html" />
<link rel="search" title="Search" href="search.html" />
<link rel="next" title="Extensions" href="extensions.html" />
<link rel="prev" title="Upgrading to 2.0.0" href="upgrading.html" />
</head>
<body class="wy-body-for-nav">
<div class="wy-grid-for-nav">
<nav data-toggle="wy-nav-shift" class="wy-nav-side">
<div class="wy-side-scroll">
<div class="wy-side-nav-search" >
<a href="index.html" class="icon icon-home"> Pose Wrangler
</a>
<div role="search">
<form id="rtd-search-form" class="wy-form" action="search.html" method="get">
<input type="text" name="q" placeholder="Search docs" />
<input type="hidden" name="check_keywords" value="yes" />
<input type="hidden" name="area" value="default" />
</form>
</div>
</div><div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="Navigation menu">
<p class="caption" role="heading"><span class="caption-text">Contents:</span></p>
<ul class="current">
<li class="toctree-l1"><a class="reference internal" href="overview.html">2.0.0 Overview</a></li>
<li class="toctree-l1"><a class="reference internal" href="upgrading.html">Upgrading to 2.0.0</a></li>
<li class="toctree-l1 current"><a class="current reference internal" href="#">Mirror Mapping</a></li>
<li class="toctree-l1"><a class="reference internal" href="extensions.html">Extensions</a></li>
<li class="toctree-l1"><a class="reference internal" href="api.html">API</a></li>
</ul>
</div>
</div>
</nav>
<section data-toggle="wy-nav-shift" class="wy-nav-content-wrap"><nav class="wy-nav-top" aria-label="Mobile navigation menu" >
<i data-toggle="wy-nav-top" class="fa fa-bars"></i>
<a href="index.html">Pose Wrangler</a>
</nav>
<div class="wy-nav-content">
<div class="rst-content">
<div role="navigation" aria-label="Page navigation">
<ul class="wy-breadcrumbs">
<li><a href="index.html" class="icon icon-home"></a> &raquo;</li>
<li>Mirror Mapping</li>
<li class="wy-breadcrumbs-aside">
<a href="_sources/mirror_mapping.rst.txt" rel="nofollow"> View page source</a>
</li>
</ul>
<hr/>
</div>
<div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article">
<div itemprop="articleBody">
<section id="mirror-mapping">
<h1>Mirror Mapping<a class="headerlink" href="#mirror-mapping" title="Permalink to this headline"></a></h1>
<p>Mirror mapping enables Pose Wrangler to support custom skeletons when mirroring RBF solvers and poses.</p>
<p>Below is the mirror mapping for characters following the MetaHuman naming conventions:</p>
<blockquote>
<div><div class="highlight-JSON notranslate"><div class="highlight"><pre><span></span><span class="p">{</span><span class="w"></span>
<span class="w"> </span><span class="nt">&quot;solver_expression&quot;</span><span class="p">:</span><span class="w"> </span><span class="s2">&quot;(?P&lt;prefix&gt;[a-zA-Z0-9]+)?(?P&lt;side&gt;_[lr]{1}_)(?P&lt;suffix&gt;[a-zA-Z0-9_]+)&quot;</span><span class="p">,</span><span class="w"></span>
<span class="w"> </span><span class="nt">&quot;transform_expression&quot;</span><span class="p">:</span><span class="w"> </span><span class="s2">&quot;(?P&lt;prefix&gt;[a-zA-Z0-9_]+)?(?P&lt;side&gt;_[lr]{1}_)(?P&lt;suffix&gt;[a-zA-Z0-9_]+)&quot;</span><span class="p">,</span><span class="w"></span>
<span class="w"> </span><span class="nt">&quot;left&quot;</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w"> </span><span class="nt">&quot;solver_syntax&quot;</span><span class="p">:</span><span class="w"> </span><span class="s2">&quot;_l_&quot;</span><span class="p">,</span><span class="w"></span>
<span class="w"> </span><span class="nt">&quot;transform_syntax&quot;</span><span class="p">:</span><span class="w"> </span><span class="s2">&quot;_l_&quot;</span><span class="w"></span>
<span class="w"> </span><span class="p">},</span><span class="w"></span>
<span class="w"> </span><span class="nt">&quot;right&quot;</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w"></span>
<span class="w"> </span><span class="nt">&quot;solver_syntax&quot;</span><span class="p">:</span><span class="w"> </span><span class="s2">&quot;_r_&quot;</span><span class="p">,</span><span class="w"></span>
<span class="w"> </span><span class="nt">&quot;transform_syntax&quot;</span><span class="p">:</span><span class="w"> </span><span class="s2">&quot;_r_&quot;</span><span class="w"></span>
<span class="w"> </span><span class="p">}</span><span class="w"></span>
<span class="p">}</span><span class="w"></span>
</pre></div>
</div>
</div></blockquote>
<table class="colwidths-given docutils align-default" id="id1">
<caption><span class="caption-text">Title</span><a class="headerlink" href="#id1" title="Permalink to this table"></a></caption>
<colgroup>
<col style="width: 33%" />
<col style="width: 67%" />
</colgroup>
<thead>
<tr class="row-odd"><th class="head"><p>Key</p></th>
<th class="head"><p>Definition</p></th>
</tr>
</thead>
<tbody>
<tr class="row-even"><td><p>solver_expression</p></td>
<td><p>A regular expression used to match against the solver node name</p></td>
</tr>
<tr class="row-odd"><td><p>transform_expression</p></td>
<td><p>A regular expression used to match against the transform (joint) node name</p></td>
</tr>
<tr class="row-even"><td><p>left</p></td>
<td><p>dictionary containing the expected match for the solver_expression and <br> transform_expression</p></td>
</tr>
<tr class="row-odd"><td><p>right</p></td>
<td><p>dictionary containing the expected match for the solver_expression and <br> transform_expression</p></td>
</tr>
</tbody>
</table>
<div class="admonition note">
<p class="admonition-title">Note</p>
<p>As an example if we wanted to mirror a solver called <code class="docutils literal notranslate"><span class="pre">calf_l_UERBFSolver</span></code> we first try to match the name
of the solver against the <code class="docutils literal notranslate"><span class="pre">solver_expression</span></code>. If the match fails, youll see an error appear in the output
log that the solver name doesnt match the settings defined in mirror mapping.</p>
<p>If the match succeeds, it will then iterate through the groups in the matchdict to determine if one of the groups
matches the <code class="docutils literal notranslate"><span class="pre">solver_syntax</span></code> for the left hand side. If it does, it will replace it with the right and vice versa.</p>
<p>In this case, we will end up with a matchdict that looks something like this: <br>
<code class="docutils literal notranslate"><span class="pre">{&quot;prefix&quot;:</span> <span class="pre">&quot;calf&quot;,</span> <span class="pre">&quot;side&quot;:</span> <span class="pre">&quot;_l_&quot;,</span> <span class="pre">&quot;suffix&quot;:</span> <span class="pre">&quot;UERBFSolver&quot;}</span></code> <br>
The mapping will iterate through this dictionary and attempt to match each value against the <code class="docutils literal notranslate"><span class="pre">solver_syntax</span></code> of
the <code class="docutils literal notranslate"><span class="pre">left</span></code> and <code class="docutils literal notranslate"><span class="pre">right</span></code> group defined in mirror mapping. If it matches the <code class="docutils literal notranslate"><span class="pre">left</span></code> group it will replace the
<code class="docutils literal notranslate"><span class="pre">side</span></code> value with the <code class="docutils literal notranslate"><span class="pre">solver_syntax</span></code> specified in the <code class="docutils literal notranslate"><span class="pre">right</span></code> group resulting in the following dictionary: <br>
<code class="docutils literal notranslate"><span class="pre">{&quot;prefix&quot;:</span> <span class="pre">&quot;calf&quot;,</span> <span class="pre">&quot;side&quot;:</span> <span class="pre">&quot;_r_&quot;,</span> <span class="pre">&quot;suffix&quot;:</span> <span class="pre">&quot;UERBFSolver&quot;}</span></code> <br></p>
<p>The same thing then happens for the drivers and driven transforms associated with the solver, using <code class="docutils literal notranslate"><span class="pre">transform_expression</span></code>
and <code class="docutils literal notranslate"><span class="pre">transform_syntax</span></code> in place of the solver.</p>
</div>
</section>
</div>
</div>
<footer><div class="rst-footer-buttons" role="navigation" aria-label="Footer">
<a href="upgrading.html" class="btn btn-neutral float-left" title="Upgrading to 2.0.0" accesskey="p" rel="prev"><span class="fa fa-arrow-circle-left" aria-hidden="true"></span> Previous</a>
<a href="extensions.html" class="btn btn-neutral float-right" title="Extensions" accesskey="n" rel="next">Next <span class="fa fa-arrow-circle-right" aria-hidden="true"></span></a>
</div>
<hr/>
<div role="contentinfo">
<p>&#169; Copyright 2022, Epic Games.</p>
</div>
Built with <a href="https://www.sphinx-doc.org/">Sphinx</a> using a
<a href="https://github.com/readthedocs/sphinx_rtd_theme">theme</a>
provided by <a href="https://readthedocs.org">Read the Docs</a>.
</footer>
</div>
</div>
</section>
</div>
<script>
jQuery(function () {
SphinxRtdTheme.Navigation.enable(true);
});
</script>
</body>
</html>

View File

@ -0,0 +1,7 @@
# Sphinx inventory version 2
# Project: Pose Wrangler
# Version:
# The remainder of this file is compressed using zlib.
<EFBFBD>Mo<EFBFBD>0 <0C><><EFBFBD><02>k<EFBFBD><6B><EFBFBD><EFBFBD>6,rh<1B><>vd<><64><05> <0B><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>"<22>v<EFBFBD>`C,<2C>fP<66>C<EFBFBD>5EI+ <0B><><10>p0<70><30><EFBFBD><14><><EFBFBD>}<7D><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><06><><EFBFBD><EFBFBD><EFBFBD>Z<EFBFBD><11><><EFBFBD> <09><><0E>
<EFBFBD>װ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>m<EFBFBD><EFBFBD>‰s<C289>U<EFBFBD><55><11>R\q<>ԶDC p<><70>30԰=H켓<48>)#l><3E><>g<EFBFBD><06><>%<25><>H<EFBFBD>+<2B>a<EFBFBD><1D><><EFBFBD><EFBFBD><EFBFBD>'uƀt<13>6J<36>q<EFBFBD><71>
<1C>(<28><>J<><04>`<60>0<EFBFBD><30>/X<><58>wF <09>c|>

View File

@ -0,0 +1,177 @@
<!DOCTYPE html>
<html class="writer-html5" lang="en" >
<head>
<meta charset="utf-8" /><meta name="generator" content="Docutils 0.17.1: http://docutils.sourceforge.net/" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>2.0.0 Overview &mdash; Pose Wrangler 2.0.0 documentation</title>
<link rel="stylesheet" href="_static/pygments.css" type="text/css" />
<link rel="stylesheet" href="_static/css/theme.css" type="text/css" />
<!--[if lt IE 9]>
<script src="_static/js/html5shiv.min.js"></script>
<![endif]-->
<script data-url_root="./" id="documentation_options" src="_static/documentation_options.js"></script>
<script src="_static/jquery.js"></script>
<script src="_static/underscore.js"></script>
<script src="_static/doctools.js"></script>
<script src="_static/js/theme.js"></script>
<link rel="index" title="Index" href="genindex.html" />
<link rel="search" title="Search" href="search.html" />
<link rel="next" title="Upgrading to 2.0.0" href="upgrading.html" />
<link rel="prev" title="Pose Wrangler Documentation" href="index.html" />
</head>
<body class="wy-body-for-nav">
<div class="wy-grid-for-nav">
<nav data-toggle="wy-nav-shift" class="wy-nav-side">
<div class="wy-side-scroll">
<div class="wy-side-nav-search" >
<a href="index.html" class="icon icon-home"> Pose Wrangler
</a>
<div role="search">
<form id="rtd-search-form" class="wy-form" action="search.html" method="get">
<input type="text" name="q" placeholder="Search docs" />
<input type="hidden" name="check_keywords" value="yes" />
<input type="hidden" name="area" value="default" />
</form>
</div>
</div><div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="Navigation menu">
<p class="caption" role="heading"><span class="caption-text">Contents:</span></p>
<ul class="current">
<li class="toctree-l1 current"><a class="current reference internal" href="#">2.0.0 Overview</a><ul>
<li class="toctree-l2"><a class="reference internal" href="#ui-overview">UI Overview</a><ul>
<li class="toctree-l3"><a class="reference internal" href="#solver-view">1) Solver View</a></li>
<li class="toctree-l3"><a class="reference internal" href="#pose-view">2) Pose View</a></li>
<li class="toctree-l3"><a class="reference internal" href="#driver-view">3) Driver View</a></li>
<li class="toctree-l3"><a class="reference internal" href="#driven-transforms-blendshape-view">4) Driven Transforms / Blendshape View</a></li>
<li class="toctree-l3"><a class="reference internal" href="#extensions-and-settings-view">5) Extensions and Settings View</a></li>
<li class="toctree-l3"><a class="reference internal" href="#top-menu">6) Top Menu</a></li>
<li class="toctree-l3"><a class="reference internal" href="#output-log">7) Output Log</a></li>
</ul>
</li>
</ul>
</li>
<li class="toctree-l1"><a class="reference internal" href="upgrading.html">Upgrading to 2.0.0</a></li>
<li class="toctree-l1"><a class="reference internal" href="mirror_mapping.html">Mirror Mapping</a></li>
<li class="toctree-l1"><a class="reference internal" href="extensions.html">Extensions</a></li>
<li class="toctree-l1"><a class="reference internal" href="api.html">API</a></li>
</ul>
</div>
</div>
</nav>
<section data-toggle="wy-nav-shift" class="wy-nav-content-wrap"><nav class="wy-nav-top" aria-label="Mobile navigation menu" >
<i data-toggle="wy-nav-top" class="fa fa-bars"></i>
<a href="index.html">Pose Wrangler</a>
</nav>
<div class="wy-nav-content">
<div class="rst-content">
<div role="navigation" aria-label="Page navigation">
<ul class="wy-breadcrumbs">
<li><a href="index.html" class="icon icon-home"></a> &raquo;</li>
<li>2.0.0 Overview</li>
<li class="wy-breadcrumbs-aside">
<a href="_sources/overview.rst.txt" rel="nofollow"> View page source</a>
</li>
</ul>
<hr/>
</div>
<div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article">
<div itemprop="articleBody">
<section id="overview">
<h1>2.0.0 Overview<a class="headerlink" href="#overview" title="Permalink to this headline"></a></h1>
<p>Version 2.0.0 is a refactor of the original Pose Wrangler. The goal of this version has been to separate the UI
logic from the backend, enabling users to automate RBF setup via Python and create custom extensions to add new
functionality.</p>
<section id="ui-overview">
<h2>UI Overview<a class="headerlink" href="#ui-overview" title="Permalink to this headline"></a></h2>
<a class="reference internal image-reference" href="_images/overview.png"><img alt="UI Overview" src="_images/overview.png" style="width: 800px;" /></a>
<section id="solver-view">
<h3>1) Solver View<a class="headerlink" href="#solver-view" title="Permalink to this headline"></a></h3>
<p>Here is where you can find a list of all the RBF solvers currently available in the scene and can edit, create, delete
or mirror solvers.</p>
<p>In order to make changes to the poses, drivers or driven transforms/blendshapes you need to toggle a solver into <cite>edit</cite>
mode via the <cite>Edit Selected Solver</cite> button.</p>
<div class="admonition note">
<p class="admonition-title">Note</p>
<p>Only one solver can be edited at a single time.</p>
</div>
</section>
<section id="pose-view">
<h3>2) Pose View<a class="headerlink" href="#pose-view" title="Permalink to this headline"></a></h3>
<p>Here you can find a list of all the poses. In order to make any changes to the poses, you need to edit the corresponding solver.</p>
<div class="admonition warning">
<p class="admonition-title">Warning</p>
<p>Most of these are self-explanatory, but is it worth noting that <cite>Mute Pose</cite> will enable and disable the pose on the
solver via the <cite>targetEnable</cite> attribute. This means that if the RBF solver node is set to use <cite>automatic radius</cite>
then the radius will be calculated without the influence of the muted poses.</p>
</div>
</section>
<section id="driver-view">
<h3>3) Driver View<a class="headerlink" href="#driver-view" title="Permalink to this headline"></a></h3>
<p>2.0.0 supports multiple drivers. Here you can add/remove driver transforms.</p>
</section>
<section id="driven-transforms-blendshape-view">
<h3>4) Driven Transforms / Blendshape View<a class="headerlink" href="#driven-transforms-blendshape-view" title="Permalink to this headline"></a></h3>
<p>Here you can add/remove driven transforms and create/add blendshapes.</p>
<div class="admonition note">
<p class="admonition-title">Note</p>
<p>The blendshape workflow is currently a work in progress and may change in the future.</p>
</div>
</section>
<section id="extensions-and-settings-view">
<h3>5) Extensions and Settings View<a class="headerlink" href="#extensions-and-settings-view" title="Permalink to this headline"></a></h3>
<p>Pose Wrangler now supports writing custom extensions for the tool that can be embedded into the UI here.
<cite>Core Extensions</cite> are default extensions that ship with Pose Wrangler. <cite>Pose Exporter</cite> is an example of a custom
extension used by the MetaHuman team. For more information on how these extensions work and how to create your own,
please refer to the <a class="reference internal" href="extensions.html"><span class="doc">Extensions</span></a> page.</p>
<p>You can also change the mirror mapping, which will allow you to specify a custom mapping if your skeleton does not
match the default MetaHuman skeleton and the mirror solver/pose functionality is causing unexpected results.</p>
</section>
<section id="top-menu">
<h3>6) Top Menu<a class="headerlink" href="#top-menu" title="Permalink to this headline"></a></h3>
<p>Here you can import/export RBF solvers to/from a JSON file, change the theme and view the help.</p>
</section>
<section id="output-log">
<h3>7) Output Log<a class="headerlink" href="#output-log" title="Permalink to this headline"></a></h3>
<p>Displays debug, info, warning and error messages.</p>
</section>
</section>
</section>
</div>
</div>
<footer><div class="rst-footer-buttons" role="navigation" aria-label="Footer">
<a href="index.html" class="btn btn-neutral float-left" title="Pose Wrangler Documentation" accesskey="p" rel="prev"><span class="fa fa-arrow-circle-left" aria-hidden="true"></span> Previous</a>
<a href="upgrading.html" class="btn btn-neutral float-right" title="Upgrading to 2.0.0" accesskey="n" rel="next">Next <span class="fa fa-arrow-circle-right" aria-hidden="true"></span></a>
</div>
<hr/>
<div role="contentinfo">
<p>&#169; Copyright 2022, Epic Games.</p>
</div>
Built with <a href="https://www.sphinx-doc.org/">Sphinx</a> using a
<a href="https://github.com/readthedocs/sphinx_rtd_theme">theme</a>
provided by <a href="https://readthedocs.org">Read the Docs</a>.
</footer>
</div>
</div>
</section>
</div>
<script>
jQuery(function () {
SphinxRtdTheme.Navigation.enable(true);
});
</script>
</body>
</html>

View File

@ -0,0 +1,119 @@
<!DOCTYPE html>
<html class="writer-html5" lang="en" >
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Search &mdash; Pose Wrangler 2.0.0 documentation</title>
<link rel="stylesheet" href="_static/pygments.css" type="text/css" />
<link rel="stylesheet" href="_static/css/theme.css" type="text/css" />
<!--[if lt IE 9]>
<script src="_static/js/html5shiv.min.js"></script>
<![endif]-->
<script data-url_root="./" id="documentation_options" src="_static/documentation_options.js"></script>
<script src="_static/jquery.js"></script>
<script src="_static/underscore.js"></script>
<script src="_static/doctools.js"></script>
<script src="_static/js/theme.js"></script>
<script src="_static/searchtools.js"></script>
<script src="_static/language_data.js"></script>
<link rel="index" title="Index" href="genindex.html" />
<link rel="search" title="Search" href="#" />
</head>
<body class="wy-body-for-nav">
<div class="wy-grid-for-nav">
<nav data-toggle="wy-nav-shift" class="wy-nav-side">
<div class="wy-side-scroll">
<div class="wy-side-nav-search" >
<a href="index.html" class="icon icon-home"> Pose Wrangler
</a>
<div role="search">
<form id="rtd-search-form" class="wy-form" action="#" method="get">
<input type="text" name="q" placeholder="Search docs" />
<input type="hidden" name="check_keywords" value="yes" />
<input type="hidden" name="area" value="default" />
</form>
</div>
</div><div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="Navigation menu">
<p class="caption" role="heading"><span class="caption-text">Contents:</span></p>
<ul>
<li class="toctree-l1"><a class="reference internal" href="overview.html">2.0.0 Overview</a></li>
<li class="toctree-l1"><a class="reference internal" href="upgrading.html">Upgrading to 2.0.0</a></li>
<li class="toctree-l1"><a class="reference internal" href="mirror_mapping.html">Mirror Mapping</a></li>
<li class="toctree-l1"><a class="reference internal" href="extensions.html">Extensions</a></li>
<li class="toctree-l1"><a class="reference internal" href="api.html">API</a></li>
</ul>
</div>
</div>
</nav>
<section data-toggle="wy-nav-shift" class="wy-nav-content-wrap"><nav class="wy-nav-top" aria-label="Mobile navigation menu" >
<i data-toggle="wy-nav-top" class="fa fa-bars"></i>
<a href="index.html">Pose Wrangler</a>
</nav>
<div class="wy-nav-content">
<div class="rst-content">
<div role="navigation" aria-label="Page navigation">
<ul class="wy-breadcrumbs">
<li><a href="index.html" class="icon icon-home"></a> &raquo;</li>
<li>Search</li>
<li class="wy-breadcrumbs-aside">
</li>
</ul>
<hr/>
</div>
<div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article">
<div itemprop="articleBody">
<noscript>
<div id="fallback" class="admonition warning">
<p class="last">
Please activate JavaScript to enable the search functionality.
</p>
</div>
</noscript>
<div id="search-results">
</div>
</div>
</div>
<footer>
<hr/>
<div role="contentinfo">
<p>&#169; Copyright 2022, Epic Games.</p>
</div>
Built with <a href="https://www.sphinx-doc.org/">Sphinx</a> using a
<a href="https://github.com/readthedocs/sphinx_rtd_theme">theme</a>
provided by <a href="https://readthedocs.org">Read the Docs</a>.
</footer>
</div>
</div>
</section>
</div>
<script>
jQuery(function () {
SphinxRtdTheme.Navigation.enable(true);
});
</script>
<script>
jQuery(function() { Search.loadIndex("searchindex.js"); });
</script>
<script id="searchindexloader"></script>
</body>
</html>

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,117 @@
<!DOCTYPE html>
<html class="writer-html5" lang="en" >
<head>
<meta charset="utf-8" /><meta name="generator" content="Docutils 0.17.1: http://docutils.sourceforge.net/" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Upgrading to 2.0.0 &mdash; Pose Wrangler 2.0.0 documentation</title>
<link rel="stylesheet" href="_static/pygments.css" type="text/css" />
<link rel="stylesheet" href="_static/css/theme.css" type="text/css" />
<!--[if lt IE 9]>
<script src="_static/js/html5shiv.min.js"></script>
<![endif]-->
<script data-url_root="./" id="documentation_options" src="_static/documentation_options.js"></script>
<script src="_static/jquery.js"></script>
<script src="_static/underscore.js"></script>
<script src="_static/doctools.js"></script>
<script src="_static/js/theme.js"></script>
<link rel="index" title="Index" href="genindex.html" />
<link rel="search" title="Search" href="search.html" />
<link rel="next" title="Mirror Mapping" href="mirror_mapping.html" />
<link rel="prev" title="2.0.0 Overview" href="overview.html" />
</head>
<body class="wy-body-for-nav">
<div class="wy-grid-for-nav">
<nav data-toggle="wy-nav-shift" class="wy-nav-side">
<div class="wy-side-scroll">
<div class="wy-side-nav-search" >
<a href="index.html" class="icon icon-home"> Pose Wrangler
</a>
<div role="search">
<form id="rtd-search-form" class="wy-form" action="search.html" method="get">
<input type="text" name="q" placeholder="Search docs" />
<input type="hidden" name="check_keywords" value="yes" />
<input type="hidden" name="area" value="default" />
</form>
</div>
</div><div class="wy-menu wy-menu-vertical" data-spy="affix" role="navigation" aria-label="Navigation menu">
<p class="caption" role="heading"><span class="caption-text">Contents:</span></p>
<ul class="current">
<li class="toctree-l1"><a class="reference internal" href="overview.html">2.0.0 Overview</a></li>
<li class="toctree-l1 current"><a class="current reference internal" href="#">Upgrading to 2.0.0</a></li>
<li class="toctree-l1"><a class="reference internal" href="mirror_mapping.html">Mirror Mapping</a></li>
<li class="toctree-l1"><a class="reference internal" href="extensions.html">Extensions</a></li>
<li class="toctree-l1"><a class="reference internal" href="api.html">API</a></li>
</ul>
</div>
</div>
</nav>
<section data-toggle="wy-nav-shift" class="wy-nav-content-wrap"><nav class="wy-nav-top" aria-label="Mobile navigation menu" >
<i data-toggle="wy-nav-top" class="fa fa-bars"></i>
<a href="index.html">Pose Wrangler</a>
</nav>
<div class="wy-nav-content">
<div class="rst-content">
<div role="navigation" aria-label="Page navigation">
<ul class="wy-breadcrumbs">
<li><a href="index.html" class="icon icon-home"></a> &raquo;</li>
<li>Upgrading to 2.0.0</li>
<li class="wy-breadcrumbs-aside">
<a href="_sources/upgrading.rst.txt" rel="nofollow"> View page source</a>
</li>
</ul>
<hr/>
</div>
<div role="main" class="document" itemscope="itemscope" itemtype="http://schema.org/Article">
<div itemprop="articleBody">
<section id="upgrading-to-2-0-0">
<h1>Upgrading to 2.0.0<a class="headerlink" href="#upgrading-to-2-0-0" title="Permalink to this headline"></a></h1>
<p>When you load up Pose Wrangler with a scene that contains <cite>UE4RBFSolverNode</cite> you will be greeted with the new legacy
version of PoseWrangler. This version is almost identical with the version previously available via GitHub, with the
addition of the log window and the upgrade button.</p>
<p>If you have the new version of the plugin available you will be presented with an option to upgrade your scene at the
top of the Pose Wrangler window. Pressing this button will execute an upgrade script that will replace all the
<cite>UE4RBFSolverNode</cite> with <cite>UERBFSolverNode</cite> and clean up old/redundant nodes left lingering in the scene.</p>
<a class="reference internal image-reference" href="_images/upgrade.png"><img alt="UI Overview" src="_images/upgrade.png" style="width: 800px;" /></a>
<p>If the upgrade is successful you will be presented with the new tool window.</p>
<a class="reference internal image-reference" href="_images/v2.png"><img alt="UI Overview" src="_images/v2.png" style="width: 800px;" /></a>
</section>
</div>
</div>
<footer><div class="rst-footer-buttons" role="navigation" aria-label="Footer">
<a href="overview.html" class="btn btn-neutral float-left" title="2.0.0 Overview" accesskey="p" rel="prev"><span class="fa fa-arrow-circle-left" aria-hidden="true"></span> Previous</a>
<a href="mirror_mapping.html" class="btn btn-neutral float-right" title="Mirror Mapping" accesskey="n" rel="next">Next <span class="fa fa-arrow-circle-right" aria-hidden="true"></span></a>
</div>
<hr/>
<div role="contentinfo">
<p>&#169; Copyright 2022, Epic Games.</p>
</div>
Built with <a href="https://www.sphinx-doc.org/">Sphinx</a> using a
<a href="https://github.com/readthedocs/sphinx_rtd_theme">theme</a>
provided by <a href="https://readthedocs.org">Read the Docs</a>.
</footer>
</div>
</div>
</section>
</div>
<script>
jQuery(function () {
SphinxRtdTheme.Navigation.enable(true);
});
</script>
</body>
</html>

View File

@ -0,0 +1,7 @@
# Copyright Epic Games, Inc. All Rights Reserved.
import logging
# Grab the pose wrangler log
LOG = logging.getLogger("EpicGames.PoseWrangler")
# Set the logging level
LOG.setLevel(logging.DEBUG)

View File

@ -0,0 +1,30 @@
# Copyright Epic Games, Inc. All Rights Reserved.
import os
from epic_pose_wrangler.log import LOG
from epic_pose_wrangler.model.plugin_manager import PluginManager
class PoseWrangler(object):
"""
Main entrypoint for interacting with PoseWrangler. Will handle loading the correct version of the tool based on the
available version of the plugin
"""
def __init__(self, view=True):
# Get the current version of the tool
self._api = PluginManager.get_pose_wrangler(view=view, parent=self)
@property
def api(self):
return self._api
def upgrade(self, file_path=None, delete_file=False):
"""
Restart pose_wrangler with the specified serialized solver data file
:param file_path :type str: path to serialized json data
:param delete_file :type bool: should the file be deleted once the upgrade has completed?
"""
LOG.info("Rebooting PoseWrangler")
self._api = PluginManager.get_pose_wrangler(view=self._api.view, parent=self, file_path=file_path)
if delete_file:
os.remove(file_path)

View File

@ -0,0 +1,13 @@
# Copyright Epic Games, Inc. All Rights Reserved.
class RBFAPI(object):
"""
Base class for creating RBF API classes
"""
UPGRADE_AVAILABLE = False
VERSION = "0.0.0"
def __init__(self, view=False, parent=None, file_path=None):
super(RBFAPI, self).__init__()
self._view = view
self._parent = parent
self._file_path = file_path

View File

@ -0,0 +1,37 @@
# Copyright Epic Games, Inc. All Rights Reserved.
from epic_pose_wrangler.log import LOG
class PoseWranglerException(Exception):
"""
Base Exception for PoseWrangler related errors
"""
def __init__(self, message):
super(PoseWranglerException, self).__init__(message)
# Log the message as an error
LOG.error(message)
class InvalidPoseWranglerPlugin(PoseWranglerException, RuntimeError):
"""
Exception raised when no valid plugins could be loaded
"""
class PoseWranglerSettingsError(PoseWranglerException):
"""
Raised when a setting is invalid
"""
class InvalidMirrorMapping(PoseWranglerSettingsError):
"""
Raised when the mirror mapping is incorrect
"""
class PoseWranglerIOError(PoseWranglerException):
"""
Raised when issues with serialization/deserialization arise
"""
class PoseWranglerFunctionalityNotImplemented(PoseWranglerException):
"""
Raised when pose wrangler functionality hasn't been implemented yet
"""

View File

@ -0,0 +1,125 @@
# Copyright Epic Games, Inc. All Rights Reserved.
"""
Example Mapping (MetaHuman)
{
# Regular expression to validate that the solver follows the correct naming convention for mirroring
"solver_expression": "(?P<prefix>[a-zA-Z0-9]+)?(?P<side>_[lr]{1}_)(?P<suffix>[a-zA-Z0-9]+)",
# Regular expression to validate that the joint follows the correct naming convention for mirroring
"transform_expression": "(?P<prefix>[a-zA-Z0-9]+)?(?P<side>_[lr]{1}_)(?P<suffix>[a-zA-Z0-9]+)",
"left": {
# Left side syntax for the solver
"solver_syntax": "_l_",
# Left side syntax for the joint
"transform_syntax": "_l_"
},
"right": {
# Right side syntax for the solver
"solver_syntax": "_r_",
# Right side syntax for the joint
"transform_syntax": "_r_"
}
}
"""
import json
import os
from epic_pose_wrangler.log import LOG
class MirrorMapping(object):
"""
Class for managing mirror settings
"""
LEFT = "left"
RIGHT = "right"
def __init__(self, file_path=None, source_side="left"):
# Make a list of valid mappings that should exist in the mirror mapping file
self._valid_mappings = [MirrorMapping.LEFT, MirrorMapping.RIGHT]
# If no file path is specified, use the MetaHuman config as the fallback
if file_path is None:
LOG.debug("No mirror mapping specified, using default MetaHuman conventions")
file_path = os.path.join(
os.path.dirname(os.path.dirname(__file__)),
'resources',
'mirror_mappings',
'metahuman.json'
)
self._file_path = file_path
# Load the json mapping data
with open(file_path, 'r') as f:
self._mapping_data = json.loads(f.read())
# Set the solver expression from the file
self._solver_expression = self._mapping_data['solver_expression']
# Set the transform expression from the file
self._transform_expression = self._mapping_data['transform_expression']
# Set the source side and create defaults
self._source_side = source_side
self._source_mapping_data = {}
self._source_solver_syntax = ""
self._source_transform_syntax = ""
self._target_mapping_data = {}
self._target_solver_syntax = ""
self._target_transform_syntax = ""
# Set the source side property to trigger the default values to be updated
self.source_side = source_side
@property
def file_path(self):
return self._file_path
@property
def solver_expression(self):
return self._solver_expression
@property
def transform_expression(self):
return self._transform_expression
@property
def source_side(self):
return self._source_side
@source_side.setter
def source_side(self, side):
"""
Sets the source side and updates the source/target values accordingly
:param side: MirrorMapping.LEFT or MirrorMapping.RIGHT
"""
if side not in self._valid_mappings:
raise ValueError("Invalid side specified, options are: {}".format(", ".join(self._valid_mappings)))
self._source_side = side
self._source_mapping_data = self._mapping_data[self._source_side]
self._source_solver_syntax = self._source_mapping_data['solver_syntax']
self._source_transform_syntax = self._source_mapping_data['transform_syntax']
self._target_mapping_data = self._mapping_data[
MirrorMapping.RIGHT if self._source_side == MirrorMapping.LEFT else MirrorMapping.LEFT]
self._target_solver_syntax = self._target_mapping_data['solver_syntax']
self._target_transform_syntax = self._target_mapping_data['transform_syntax']
@property
def source_solver_syntax(self):
return self._source_solver_syntax
@property
def source_transform_syntax(self):
return self._source_transform_syntax
@property
def target_solver_syntax(self):
return self._target_solver_syntax
@property
def target_transform_syntax(self):
return self._target_transform_syntax
def swap_sides(self):
"""
Swap the source side to the opposite of the current side.
"""
new_target = MirrorMapping.LEFT if self.source_side == MirrorMapping.RIGHT else MirrorMapping.RIGHT
self.source_side = new_target

View File

@ -0,0 +1,110 @@
# Copyright Epic Games, Inc. All Rights Reserved.
from collections import OrderedDict
from maya import cmds
from epic_pose_wrangler.log import LOG
from epic_pose_wrangler.model import exceptions
class PluginManager:
"""
Class for loading latest available plugin and managing pose_wrangler versions
"""
# The name of the recommended solver
RECOMMENDED_SOLVER = "UERBFSolverNode"
# Empty list to keep track of the loaded solver nodes
LOADED_NODES = []
# Generate an ordered manifest of known plugin name variants with the newest plugins
__PLUGIN_VERSIONS = OrderedDict(
{
"MayaUERBFPlugin_{}".format(cmds.about(version=True)): "UERBFSolverNode",
"MayaUERBFPlugin{}".format(cmds.about(version=True)): "UERBFSolverNode",
"MayaUERBFPlugin": "UERBFSolverNode",
"MayaUE4RBFPlugin_{}".format(cmds.about(version=True)): "UE4RBFSolverNode",
"MayaUE4RBFPlugin{}".format(cmds.about(version=True)): "UE4RBFSolverNode",
"MayaUE4RBFPlugin": "UE4RBFSolverNode"}
)
@staticmethod
def load_plugin():
"""
Load any valid RBF plugins
:return :type list: node names loaded
"""
PluginManager.LOADED_NODES = []
# Iterate through all of the valid plugin versions and attempt to load
for plugin_name, solver_name in PluginManager.__PLUGIN_VERSIONS.items():
# If the plugin is already loaded, add the solver name to the list of loaded nodes
if cmds.pluginInfo(plugin_name, q=True, loaded=True) and solver_name not in PluginManager.LOADED_NODES:
PluginManager.LOADED_NODES.append(solver_name)
else:
try:
# Attempt to load the plugin
cmds.loadPlugin(plugin_name)
# If the solver name is not already in the list, add it
if solver_name not in PluginManager.LOADED_NODES:
PluginManager.LOADED_NODES.append(solver_name)
# Ignore errors
except RuntimeError as e:
pass
# If we have no loaded nodes no plugin loaded correctly
if not PluginManager.LOADED_NODES:
raise exceptions.InvalidPoseWranglerPlugin("Unable to load valid RBF plugin version.")
return PluginManager.LOADED_NODES
@staticmethod
def is_scene_using_recommended_solver():
"""
Scan the current scene to find which version of the solver is being used
:return :type bool: is the recommended solver being used for all RBF nodes
"""
solvers = []
# Get a list of the solver names
for solver_node_name in list(PluginManager.__PLUGIN_VERSIONS.values()):
if solver_node_name not in solvers:
solvers.append(solver_node_name)
# Iterate through the solver names
for solver_node_name in solvers:
# Check if any solvers exist in the scene of the specified type and check if the solver name is the
# recommended name. If we have old solvers in the scene, we aren't using the latest version.
if cmds.ls(type=solver_node_name) and solver_node_name != PluginManager.RECOMMENDED_SOLVER:
return False
return True
@staticmethod
def get_pose_wrangler(view=True, parent=None, file_path=None):
"""
Get the correct version of the pose wrangler tool depending on the available plugins and nodes in the scene
:param view :type bool: Should we be displaying a UI to the user?
:param parent :type main.PoseWrangler: reference to the main entry point for the tool, used for
restarting/upgrading the tool
:param file_path :type str: (optional) path to a json file containing serialized solver data
:return :type object: reference to the currently loaded version of pose wrangler
"""
# Load the RBF plugin
loaded_nodes = PluginManager.load_plugin()
# If the recommended solver is not loaded, fall back to the original pose wrangler implementation
if PluginManager.RECOMMENDED_SOLVER not in loaded_nodes:
LOG.warning("You are currently using an outdated plugin. Certain functionality may be limited.")
from epic_pose_wrangler.v1 import main
return main.UE4RBFAPI(view=view, parent=parent)
# Bool to keep track of importing the newest api version
import_failed = False
# Check if the scene uses the latest solver
if PluginManager.is_scene_using_recommended_solver():
# Try and import the latest tool version
try:
from epic_pose_wrangler.v2 import main
return main.UERBFAPI(view=view, parent=parent, file_path=file_path)
except ImportError as e:
LOG.error("Unable to import API v2, falling back to API v1 - {exception}".format(exception=e))
import_failed = True
# Fall back to API v1
from epic_pose_wrangler.v1 import main
# If the recommended solver is available but finds old nodes in the scene and imports correctly, provide
# the option to upgrade to the latest version
if not import_failed:
main.UE4RBFAPI.UPGRADE_AVAILABLE = True
return main.UE4RBFAPI(view=view, parent=parent)

View File

@ -0,0 +1,47 @@
import os
from Qt import QtCore
from epic_pose_wrangler.log import LOG
from epic_pose_wrangler.model import exceptions
class SettingsManager(object):
"""
Settings Manager for reading/writing to PoseWrangler settings ini file
"""
QSETTINGS = None
def __init__(self):
# Initialize the QSettings
QtCore.QSettings.setPath(QtCore.QSettings.IniFormat, QtCore.QSettings.UserScope, os.environ['LOCALAPPDATA'])
# Store the QSettings
self.__class__.QSETTINGS = QtCore.QSettings(
QtCore.QSettings.IniFormat,
QtCore.QSettings.UserScope,
"Epic Games",
"PoseWrangler"
)
self.__class__.QSETTINGS.setFallbacksEnabled(False)
LOG.debug("Successfully initialized SettingsManager")
@classmethod
def get_setting(cls, name):
"""
Get the setting with the specified name
:param name :type str: setting name
:return :type str or None: setting value
"""
# If the settings haven't been initialized, raise exception
if cls.QSETTINGS is None:
raise exceptions.PoseWranglerSettingsError("Unable to load settings, "
"{cls} must be initialized first".format(cls=cls))
return cls.QSETTINGS.value(name, None)
@classmethod
def set_setting(cls, name, value):
"""
Add/Overwrite the setting with the specified name and value
:param name :type str: setting name
:param value :type any: setting value
"""
cls.QSETTINGS.setValue(name, value)

View File

@ -0,0 +1,201 @@
import sys
import inspect
import maya
import maya.OpenMaya as OpenMaya
import maya.OpenMayaMPx as OpenMayaMPx
import maya.cmds as cmds
from pymel.core.windows import Callback, CallbackWithArgs
StreamTypesPerSubjectType = {
"Prop": ["Root Only", "Full Hierarchy"],
"Character": ["Root Only", "Full Hierarchy"],
"Camera": ["Root Only", "Full Hierarchy", "Camera"],
"Light": ["Root Only", "Full Hierarchy", "Light"],
}
def OnRemoveSubject(SubjectPath):
cmds.LiveLinkRemoveSubject(SubjectPath)
RefreshSubjects()
def CreateSubjectTable():
cmds.rowColumnLayout("SubjectLayout", numberOfColumns=5, columnWidth=[(1, 20), (2,80), (3, 100), (4, 180), (5, 120)], columnOffset=[(1, 'right', 5), (2, 'right', 10), (4, 'left', 10)], parent="SubjectWrapperLayout")
cmds.text(label="")
cmds.text(label="Subject Type", font="boldLabelFont", align="left")
cmds.text(label="Subject Name", font="boldLabelFont", align="left")
cmds.text(label="DAG Path", font="boldLabelFont", align="left")
cmds.text(label="Stream Type", font="boldLabelFont", align="left")
cmds.rowColumnLayout("SubjectLayout", edit=True, rowOffset=(1, "bottom", 10))
#Populate subjects list from c++
def PopulateSubjects():
SubjectNames = cmds.LiveLinkSubjectNames()
SubjectPaths = cmds.LiveLinkSubjectPaths()
SubjectTypes = cmds.LiveLinkSubjectTypes()
SubjectRoles = cmds.LiveLinkSubjectRoles()
if SubjectPaths is not None:
RowCounter = 0
for (SubjectName, SubjectPath, SubjectType, SubjectRole) in zip(SubjectNames, SubjectPaths, SubjectTypes, SubjectRoles):
cmds.button(label="-", height=21, command=Callback(OnRemoveSubject, SubjectPath), parent="SubjectLayout")
cmds.text(label=SubjectType, height=21, align="left", parent="SubjectLayout")
cmds.textField(text=SubjectName, height=21, changeCommand=CallbackWithArgs(cmds.LiveLinkChangeSubjectName, SubjectPath), parent="SubjectLayout")
cmds.text(label=SubjectPath, align="left", height=21, parent="SubjectLayout")
LayoutName = "ColumnLayoutRow_" + str(RowCounter) # adding a trailing index makes the name unique which is required by the api
cmds.columnLayout(LayoutName, parent="SubjectLayout")
cmds.optionMenu("SubjectTypeMenu", parent=LayoutName, height=21, changeCommand=CallbackWithArgs(cmds.LiveLinkChangeSubjectStreamType, SubjectPath))
for StreamType in StreamTypesPerSubjectType[SubjectType]:
cmds.menuItem(label=StreamType)
StreamTypeIndex = StreamTypesPerSubjectType[SubjectType].index(SubjectRole) + 1 # menu items are 1-indexed
cmds.optionMenu("SubjectTypeMenu", edit=True, select=StreamTypeIndex)
RowCounter += 1
def ClearSubjects():
if (cmds.window(MayaLiveLinkUI.WindowName , exists=True)):
cmds.deleteUI("SubjectLayout")
#Refresh subjects list
def RefreshSubjects():
if (cmds.window(MayaLiveLinkUI.WindowName , exists=True)):
cmds.deleteUI("SubjectLayout")
CreateSubjectTable()
PopulateSubjects()
#Connection UI Colours
ConnectionActiveColour = [0.71, 0.9, 0.1]
ConnectionInactiveColour = [1.0, 0.4, 0.4]
ConnectionColourMap = {
True : ConnectionActiveColour,
False: ConnectionInactiveColour
}
#Base class for command (common creator method + allows for automatic register/unregister)
class LiveLinkCommand(OpenMayaMPx.MPxCommand):
def __init__(self):
OpenMayaMPx.MPxCommand.__init__(self)
@classmethod
def Creator(Cls):
return OpenMayaMPx.asMPxPtr( Cls() )
# Is supplied object a live link command
def IsLiveLinkCommand(InCls):
return inspect.isclass(InCls) and issubclass(InCls, LiveLinkCommand) and InCls != LiveLinkCommand
# Given a list of strings of names return all the live link commands listed
def GetLiveLinkCommandsFromModule(ModuleItems):
EvalItems = (eval(Item) for Item in ModuleItems)
return [Command for Command in EvalItems if IsLiveLinkCommand(Command) ]
# Command to create the Live Link UI
class MayaLiveLinkUI(LiveLinkCommand):
WindowName = "MayaLiveLinkUI"
Title = "Maya Live Link UI"
WindowSize = (500, 300)
def __init__(self):
LiveLinkCommand.__init__(self)
# Invoked when the command is run.
def doIt(self,argList):
if (cmds.window(self.WindowName , exists=True)):
cmds.deleteUI(self.WindowName)
window = cmds.window( self.WindowName, title=self.Title, widthHeight=(self.WindowSize[0], self.WindowSize[1]) )
#Get current connection status
ConnectionText, ConnectedState = cmds.LiveLinkConnectionStatus()
cmds.columnLayout( "mainColumn", adjustableColumn=True )
cmds.rowLayout("HeaderRow", numberOfColumns=3, adjustableColumn=1, parent = "mainColumn")
cmds.text(label="Unreal Engine Live Link", align="left")
cmds.text(label="Connection:")
cmds.text("ConnectionStatusUI", label=ConnectionText, align="center", backgroundColor=ConnectionColourMap[ConnectedState], width=150)
cmds.separator(h=20, style="none", parent="mainColumn")
cmds.columnLayout("SubjectWrapperLayout", parent="mainColumn") # just used as a container that will survive refreshing, so the following controls stay in their correct place
CreateSubjectTable()
PopulateSubjects()
cmds.separator(h=20, style="none", parent="mainColumn")
cmds.button( label='Add Selection', parent = "mainColumn", command=self.AddSelection)
cmds.showWindow( self.WindowName )
def AddSelection(self, *args):
cmds.LiveLinkAddSelection()
RefreshSubjects()
# Command to Refresh the subject UI
class MayaLiveLinkRefreshUI(LiveLinkCommand):
def __init__(self):
LiveLinkCommand.__init__(self)
# Invoked when the command is run.
def doIt(self,argList):
RefreshSubjects()
class MayaLiveLinkClearUI(LiveLinkCommand):
def __init__(self):
LiveLinkCommand.__init__(self)
def doIt(self, argList):
ClearSubjects()
CreateSubjectTable()
# Command to Refresh the connection UI
class MayaLiveLinkRefreshConnectionUI(LiveLinkCommand):
def __init__(self):
LiveLinkCommand.__init__(self)
# Invoked when the command is run.
def doIt(self,argList):
if (cmds.window(MayaLiveLinkUI.WindowName , exists=True)):
#Get current connection status
ConnectionText, ConnectedState = cmds.LiveLinkConnectionStatus()
cmds.text("ConnectionStatusUI", edit=True, label=ConnectionText, backgroundColor=ConnectionColourMap[ConnectedState])
class MayaLiveLinkGetActiveCamera(LiveLinkCommand):
def __init__(self):
LiveLinkCommand.__init__(self)
# Invoked when the command is run.
def doIt(self,argList):
self.clearResult()
try:
c = cmds.getPanel(wf=1)
cam = cmds.modelPanel(c, q=True, camera=True)
except:
pass
else:
self.setResult(cam)
#Grab commands declared
Commands = GetLiveLinkCommandsFromModule(dir())
#Initialize the script plug-in
def initializePlugin(mobject):
mplugin = OpenMayaMPx.MFnPlugin(mobject)
print("LiveLink:"
for Command in Commands:
try:
print("\tRegistering Command '%s'"%Command.__name__
mplugin.registerCommand( Command.__name__, Command.Creator )
except:
sys.stderr.write( "Failed to register command: %s\n" % Command.__name__ )
raise
# Uninitialize the script plug-in
def uninitializePlugin(mobject):
mplugin = OpenMayaMPx.MFnPlugin(mobject)
for Command in Commands:
try:
mplugin.deregisterCommand( Command.__name__ )
except:
sys.stderr.write( "Failed to unregister command: %s\n" % Command.__name__ )

View File

@ -0,0 +1,201 @@
import sys
import inspect
import maya
import maya.OpenMaya as OpenMaya
import maya.OpenMayaMPx as OpenMayaMPx
import maya.cmds as cmds
from pymel.core.windows import Callback, CallbackWithArgs
StreamTypesPerSubjectType = {
"Prop": ["Root Only", "Full Hierarchy"],
"Character": ["Root Only", "Full Hierarchy"],
"Camera": ["Root Only", "Full Hierarchy", "Camera"],
"Light": ["Root Only", "Full Hierarchy", "Light"],
}
def OnRemoveSubject(SubjectPath):
cmds.LiveLinkRemoveSubject(SubjectPath)
RefreshSubjects()
def CreateSubjectTable():
cmds.rowColumnLayout("SubjectLayout", numberOfColumns=5, columnWidth=[(1, 20), (2,80), (3, 100), (4, 180), (5, 120)], columnOffset=[(1, 'right', 5), (2, 'right', 10), (4, 'left', 10)], parent="SubjectWrapperLayout")
cmds.text(label="")
cmds.text(label="Subject Type", font="boldLabelFont", align="left")
cmds.text(label="Subject Name", font="boldLabelFont", align="left")
cmds.text(label="DAG Path", font="boldLabelFont", align="left")
cmds.text(label="Stream Type", font="boldLabelFont", align="left")
cmds.rowColumnLayout("SubjectLayout", edit=True, rowOffset=(1, "bottom", 10))
#Populate subjects list from c++
def PopulateSubjects():
SubjectNames = cmds.LiveLinkSubjectNames()
SubjectPaths = cmds.LiveLinkSubjectPaths()
SubjectTypes = cmds.LiveLinkSubjectTypes()
SubjectRoles = cmds.LiveLinkSubjectRoles()
if SubjectPaths is not None:
RowCounter = 0
for (SubjectName, SubjectPath, SubjectType, SubjectRole) in zip(SubjectNames, SubjectPaths, SubjectTypes, SubjectRoles):
cmds.button(label="-", height=21, command=Callback(OnRemoveSubject, SubjectPath), parent="SubjectLayout")
cmds.text(label=SubjectType, height=21, align="left", parent="SubjectLayout")
cmds.textField(text=SubjectName, height=21, changeCommand=CallbackWithArgs(cmds.LiveLinkChangeSubjectName, SubjectPath), parent="SubjectLayout")
cmds.text(label=SubjectPath, align="left", height=21, parent="SubjectLayout")
LayoutName = "ColumnLayoutRow_" + str(RowCounter) # adding a trailing index makes the name unique which is required by the api
cmds.columnLayout(LayoutName, parent="SubjectLayout")
cmds.optionMenu("SubjectTypeMenu", parent=LayoutName, height=21, changeCommand=CallbackWithArgs(cmds.LiveLinkChangeSubjectStreamType, SubjectPath))
for StreamType in StreamTypesPerSubjectType[SubjectType]:
cmds.menuItem(label=StreamType)
StreamTypeIndex = StreamTypesPerSubjectType[SubjectType].index(SubjectRole) + 1 # menu items are 1-indexed
cmds.optionMenu("SubjectTypeMenu", edit=True, select=StreamTypeIndex)
RowCounter += 1
def ClearSubjects():
if (cmds.window(MayaLiveLinkUI.WindowName , exists=True)):
cmds.deleteUI("SubjectLayout")
#Refresh subjects list
def RefreshSubjects():
if (cmds.window(MayaLiveLinkUI.WindowName , exists=True)):
cmds.deleteUI("SubjectLayout")
CreateSubjectTable()
PopulateSubjects()
#Connection UI Colours
ConnectionActiveColour = [0.71, 0.9, 0.1]
ConnectionInactiveColour = [1.0, 0.4, 0.4]
ConnectionColourMap = {
True : ConnectionActiveColour,
False: ConnectionInactiveColour
}
#Base class for command (common creator method + allows for automatic register/unregister)
class LiveLinkCommand(OpenMayaMPx.MPxCommand):
def __init__(self):
OpenMayaMPx.MPxCommand.__init__(self)
@classmethod
def Creator(Cls):
return OpenMayaMPx.asMPxPtr( Cls() )
# Is supplied object a live link command
def IsLiveLinkCommand(InCls):
return inspect.isclass(InCls) and issubclass(InCls, LiveLinkCommand) and InCls != LiveLinkCommand
# Given a list of strings of names return all the live link commands listed
def GetLiveLinkCommandsFromModule(ModuleItems):
EvalItems = (eval(Item) for Item in ModuleItems)
return [Command for Command in EvalItems if IsLiveLinkCommand(Command) ]
# Command to create the Live Link UI
class MayaLiveLinkUI(LiveLinkCommand):
WindowName = "MayaLiveLinkUI"
Title = "Maya Live Link UI"
WindowSize = (500, 300)
def __init__(self):
LiveLinkCommand.__init__(self)
# Invoked when the command is run.
def doIt(self,argList):
if (cmds.window(self.WindowName , exists=True)):
cmds.deleteUI(self.WindowName)
window = cmds.window( self.WindowName, title=self.Title, widthHeight=(self.WindowSize[0], self.WindowSize[1]) )
#Get current connection status
ConnectionText, ConnectedState = cmds.LiveLinkConnectionStatus()
cmds.columnLayout( "mainColumn", adjustableColumn=True )
cmds.rowLayout("HeaderRow", numberOfColumns=3, adjustableColumn=1, parent = "mainColumn")
cmds.text(label="Unreal Engine Live Link", align="left")
cmds.text(label="Connection:")
cmds.text("ConnectionStatusUI", label=ConnectionText, align="center", backgroundColor=ConnectionColourMap[ConnectedState], width=150)
cmds.separator(h=20, style="none", parent="mainColumn")
cmds.columnLayout("SubjectWrapperLayout", parent="mainColumn") # just used as a container that will survive refreshing, so the following controls stay in their correct place
CreateSubjectTable()
PopulateSubjects()
cmds.separator(h=20, style="none", parent="mainColumn")
cmds.button( label='Add Selection', parent = "mainColumn", command=self.AddSelection)
cmds.showWindow( self.WindowName )
def AddSelection(self, *args):
cmds.LiveLinkAddSelection()
RefreshSubjects()
# Command to Refresh the subject UI
class MayaLiveLinkRefreshUI(LiveLinkCommand):
def __init__(self):
LiveLinkCommand.__init__(self)
# Invoked when the command is run.
def doIt(self,argList):
RefreshSubjects()
class MayaLiveLinkClearUI(LiveLinkCommand):
def __init__(self):
LiveLinkCommand.__init__(self)
def doIt(self, argList):
ClearSubjects()
CreateSubjectTable()
# Command to Refresh the connection UI
class MayaLiveLinkRefreshConnectionUI(LiveLinkCommand):
def __init__(self):
LiveLinkCommand.__init__(self)
# Invoked when the command is run.
def doIt(self,argList):
if (cmds.window(MayaLiveLinkUI.WindowName , exists=True)):
#Get current connection status
ConnectionText, ConnectedState = cmds.LiveLinkConnectionStatus()
cmds.text("ConnectionStatusUI", edit=True, label=ConnectionText, backgroundColor=ConnectionColourMap[ConnectedState])
class MayaLiveLinkGetActiveCamera(LiveLinkCommand):
def __init__(self):
LiveLinkCommand.__init__(self)
# Invoked when the command is run.
def doIt(self,argList):
self.clearResult()
try:
c = cmds.getPanel(wf=1)
cam = cmds.modelPanel(c, q=True, camera=True)
except:
pass
else:
self.setResult(cam)
#Grab commands declared
Commands = GetLiveLinkCommandsFromModule(dir())
#Initialize the script plug-in
def initializePlugin(mobject):
mplugin = OpenMayaMPx.MFnPlugin(mobject)
print("LiveLink:"
for Command in Commands:
try:
print("\tRegistering Command '%s'"%Command.__name__
mplugin.registerCommand( Command.__name__, Command.Creator )
except:
sys.stderr.write( "Failed to register command: %s\n" % Command.__name__ )
raise
# Uninitialize the script plug-in
def uninitializePlugin(mobject):
mplugin = OpenMayaMPx.MFnPlugin(mobject)
for Command in Commands:
try:
mplugin.deregisterCommand( Command.__name__ )
except:
sys.stderr.write( "Failed to unregister command: %s\n" % Command.__name__ )

View File

@ -0,0 +1,201 @@
import sys
import inspect
import maya
import maya.OpenMaya as OpenMaya
import maya.OpenMayaMPx as OpenMayaMPx
import maya.cmds as cmds
from pymel.core.windows import Callback, CallbackWithArgs
StreamTypesPerSubjectType = {
"Prop": ["Root Only", "Full Hierarchy"],
"Character": ["Root Only", "Full Hierarchy"],
"Camera": ["Root Only", "Full Hierarchy", "Camera"],
"Light": ["Root Only", "Full Hierarchy", "Light"],
}
def OnRemoveSubject(SubjectPath):
cmds.LiveLinkRemoveSubject(SubjectPath)
RefreshSubjects()
def CreateSubjectTable():
cmds.rowColumnLayout("SubjectLayout", numberOfColumns=5, columnWidth=[(1, 20), (2,80), (3, 100), (4, 180), (5, 120)], columnOffset=[(1, 'right', 5), (2, 'right', 10), (4, 'left', 10)], parent="SubjectWrapperLayout")
cmds.text(label="")
cmds.text(label="Subject Type", font="boldLabelFont", align="left")
cmds.text(label="Subject Name", font="boldLabelFont", align="left")
cmds.text(label="DAG Path", font="boldLabelFont", align="left")
cmds.text(label="Stream Type", font="boldLabelFont", align="left")
cmds.rowColumnLayout("SubjectLayout", edit=True, rowOffset=(1, "bottom", 10))
#Populate subjects list from c++
def PopulateSubjects():
SubjectNames = cmds.LiveLinkSubjectNames()
SubjectPaths = cmds.LiveLinkSubjectPaths()
SubjectTypes = cmds.LiveLinkSubjectTypes()
SubjectRoles = cmds.LiveLinkSubjectRoles()
if SubjectPaths is not None:
RowCounter = 0
for (SubjectName, SubjectPath, SubjectType, SubjectRole) in zip(SubjectNames, SubjectPaths, SubjectTypes, SubjectRoles):
cmds.button(label="-", height=21, command=Callback(OnRemoveSubject, SubjectPath), parent="SubjectLayout")
cmds.text(label=SubjectType, height=21, align="left", parent="SubjectLayout")
cmds.textField(text=SubjectName, height=21, changeCommand=CallbackWithArgs(cmds.LiveLinkChangeSubjectName, SubjectPath), parent="SubjectLayout")
cmds.text(label=SubjectPath, align="left", height=21, parent="SubjectLayout")
LayoutName = "ColumnLayoutRow_" + str(RowCounter) # adding a trailing index makes the name unique which is required by the api
cmds.columnLayout(LayoutName, parent="SubjectLayout")
cmds.optionMenu("SubjectTypeMenu", parent=LayoutName, height=21, changeCommand=CallbackWithArgs(cmds.LiveLinkChangeSubjectStreamType, SubjectPath))
for StreamType in StreamTypesPerSubjectType[SubjectType]:
cmds.menuItem(label=StreamType)
StreamTypeIndex = StreamTypesPerSubjectType[SubjectType].index(SubjectRole) + 1 # menu items are 1-indexed
cmds.optionMenu("SubjectTypeMenu", edit=True, select=StreamTypeIndex)
RowCounter += 1
def ClearSubjects():
if (cmds.window(MayaLiveLinkUI.WindowName , exists=True)):
cmds.deleteUI("SubjectLayout")
#Refresh subjects list
def RefreshSubjects():
if (cmds.window(MayaLiveLinkUI.WindowName , exists=True)):
cmds.deleteUI("SubjectLayout")
CreateSubjectTable()
PopulateSubjects()
#Connection UI Colours
ConnectionActiveColour = [0.71, 0.9, 0.1]
ConnectionInactiveColour = [1.0, 0.4, 0.4]
ConnectionColourMap = {
True : ConnectionActiveColour,
False: ConnectionInactiveColour
}
#Base class for command (common creator method + allows for automatic register/unregister)
class LiveLinkCommand(OpenMayaMPx.MPxCommand):
def __init__(self):
OpenMayaMPx.MPxCommand.__init__(self)
@classmethod
def Creator(Cls):
return OpenMayaMPx.asMPxPtr( Cls() )
# Is supplied object a live link command
def IsLiveLinkCommand(InCls):
return inspect.isclass(InCls) and issubclass(InCls, LiveLinkCommand) and InCls != LiveLinkCommand
# Given a list of strings of names return all the live link commands listed
def GetLiveLinkCommandsFromModule(ModuleItems):
EvalItems = (eval(Item) for Item in ModuleItems)
return [Command for Command in EvalItems if IsLiveLinkCommand(Command) ]
# Command to create the Live Link UI
class MayaLiveLinkUI(LiveLinkCommand):
WindowName = "MayaLiveLinkUI"
Title = "Maya Live Link UI"
WindowSize = (500, 300)
def __init__(self):
LiveLinkCommand.__init__(self)
# Invoked when the command is run.
def doIt(self,argList):
if (cmds.window(self.WindowName , exists=True)):
cmds.deleteUI(self.WindowName)
window = cmds.window( self.WindowName, title=self.Title, widthHeight=(self.WindowSize[0], self.WindowSize[1]) )
#Get current connection status
ConnectionText, ConnectedState = cmds.LiveLinkConnectionStatus()
cmds.columnLayout( "mainColumn", adjustableColumn=True )
cmds.rowLayout("HeaderRow", numberOfColumns=3, adjustableColumn=1, parent = "mainColumn")
cmds.text(label="Unreal Engine Live Link", align="left")
cmds.text(label="Connection:")
cmds.text("ConnectionStatusUI", label=ConnectionText, align="center", backgroundColor=ConnectionColourMap[ConnectedState], width=150)
cmds.separator(h=20, style="none", parent="mainColumn")
cmds.columnLayout("SubjectWrapperLayout", parent="mainColumn") # just used as a container that will survive refreshing, so the following controls stay in their correct place
CreateSubjectTable()
PopulateSubjects()
cmds.separator(h=20, style="none", parent="mainColumn")
cmds.button( label='Add Selection', parent = "mainColumn", command=self.AddSelection)
cmds.showWindow( self.WindowName )
def AddSelection(self, *args):
cmds.LiveLinkAddSelection()
RefreshSubjects()
# Command to Refresh the subject UI
class MayaLiveLinkRefreshUI(LiveLinkCommand):
def __init__(self):
LiveLinkCommand.__init__(self)
# Invoked when the command is run.
def doIt(self,argList):
RefreshSubjects()
class MayaLiveLinkClearUI(LiveLinkCommand):
def __init__(self):
LiveLinkCommand.__init__(self)
def doIt(self, argList):
ClearSubjects()
CreateSubjectTable()
# Command to Refresh the connection UI
class MayaLiveLinkRefreshConnectionUI(LiveLinkCommand):
def __init__(self):
LiveLinkCommand.__init__(self)
# Invoked when the command is run.
def doIt(self,argList):
if (cmds.window(MayaLiveLinkUI.WindowName , exists=True)):
#Get current connection status
ConnectionText, ConnectedState = cmds.LiveLinkConnectionStatus()
cmds.text("ConnectionStatusUI", edit=True, label=ConnectionText, backgroundColor=ConnectionColourMap[ConnectedState])
class MayaLiveLinkGetActiveCamera(LiveLinkCommand):
def __init__(self):
LiveLinkCommand.__init__(self)
# Invoked when the command is run.
def doIt(self,argList):
self.clearResult()
try:
c = cmds.getPanel(wf=1)
cam = cmds.modelPanel(c, q=True, camera=True)
except:
pass
else:
self.setResult(cam)
#Grab commands declared
Commands = GetLiveLinkCommandsFromModule(dir())
#Initialize the script plug-in
def initializePlugin(mobject):
mplugin = OpenMayaMPx.MFnPlugin(mobject)
print("LiveLink:"
for Command in Commands:
try:
print("\tRegistering Command '%s'"%Command.__name__
mplugin.registerCommand( Command.__name__, Command.Creator )
except:
sys.stderr.write( "Failed to register command: %s\n" % Command.__name__ )
raise
# Uninitialize the script plug-in
def uninitializePlugin(mobject):
mplugin = OpenMayaMPx.MFnPlugin(mobject)
for Command in Commands:
try:
mplugin.deregisterCommand( Command.__name__ )
except:
sys.stderr.write( "Failed to unregister command: %s\n" % Command.__name__ )

View File

@ -0,0 +1,203 @@
from __future__ import print_function
import sys
import inspect
import maya
import maya.OpenMaya as OpenMaya
import maya.OpenMayaMPx as OpenMayaMPx
import maya.cmds as cmds
from pymel.core.windows import Callback, CallbackWithArgs
StreamTypesPerSubjectType = {
"Prop": ["Root Only", "Full Hierarchy"],
"Character": ["Root Only", "Full Hierarchy"],
"Camera": ["Root Only", "Full Hierarchy", "Camera"],
"Light": ["Root Only", "Full Hierarchy", "Light"],
}
def OnRemoveSubject(SubjectPath):
cmds.LiveLinkRemoveSubject(SubjectPath)
RefreshSubjects()
def CreateSubjectTable():
cmds.rowColumnLayout("SubjectLayout", numberOfColumns=5, columnWidth=[(1, 20), (2,80), (3, 100), (4, 180), (5, 120)], columnOffset=[(1, 'right', 5), (2, 'right', 10), (4, 'left', 10)], parent="SubjectWrapperLayout")
cmds.text(label="")
cmds.text(label="Subject Type", font="boldLabelFont", align="left")
cmds.text(label="Subject Name", font="boldLabelFont", align="left")
cmds.text(label="DAG Path", font="boldLabelFont", align="left")
cmds.text(label="Stream Type", font="boldLabelFont", align="left")
cmds.rowColumnLayout("SubjectLayout", edit=True, rowOffset=(1, "bottom", 10))
#Populate subjects list from c++
def PopulateSubjects():
SubjectNames = cmds.LiveLinkSubjectNames()
SubjectPaths = cmds.LiveLinkSubjectPaths()
SubjectTypes = cmds.LiveLinkSubjectTypes()
SubjectRoles = cmds.LiveLinkSubjectRoles()
if SubjectPaths is not None:
RowCounter = 0
for (SubjectName, SubjectPath, SubjectType, SubjectRole) in zip(SubjectNames, SubjectPaths, SubjectTypes, SubjectRoles):
cmds.button(label="-", height=21, command=Callback(OnRemoveSubject, SubjectPath), parent="SubjectLayout")
cmds.text(label=SubjectType, height=21, align="left", parent="SubjectLayout")
cmds.textField(text=SubjectName, height=21, changeCommand=CallbackWithArgs(cmds.LiveLinkChangeSubjectName, SubjectPath), parent="SubjectLayout")
cmds.text(label=SubjectPath, align="left", height=21, parent="SubjectLayout")
LayoutName = "ColumnLayoutRow_" + str(RowCounter) # adding a trailing index makes the name unique which is required by the api
cmds.columnLayout(LayoutName, parent="SubjectLayout")
cmds.optionMenu("SubjectTypeMenu", parent=LayoutName, height=21, changeCommand=CallbackWithArgs(cmds.LiveLinkChangeSubjectStreamType, SubjectPath))
for StreamType in StreamTypesPerSubjectType[SubjectType]:
cmds.menuItem(label=StreamType)
StreamTypeIndex = StreamTypesPerSubjectType[SubjectType].index(SubjectRole) + 1 # menu items are 1-indexed
cmds.optionMenu("SubjectTypeMenu", edit=True, select=StreamTypeIndex)
RowCounter += 1
def ClearSubjects():
if (cmds.window(MayaLiveLinkUI.WindowName , exists=True)):
cmds.deleteUI("SubjectLayout")
#Refresh subjects list
def RefreshSubjects():
if (cmds.window(MayaLiveLinkUI.WindowName , exists=True)):
cmds.deleteUI("SubjectLayout")
CreateSubjectTable()
PopulateSubjects()
#Connection UI Colours
ConnectionActiveColour = [0.71, 0.9, 0.1]
ConnectionInactiveColour = [1.0, 0.4, 0.4]
ConnectionColourMap = {
True : ConnectionActiveColour,
False: ConnectionInactiveColour
}
#Base class for command (common creator method + allows for automatic register/unregister)
class LiveLinkCommand(OpenMayaMPx.MPxCommand):
def __init__(self):
OpenMayaMPx.MPxCommand.__init__(self)
@classmethod
def Creator(Cls):
return OpenMayaMPx.asMPxPtr( Cls() )
# Is supplied object a live link command
def IsLiveLinkCommand(InCls):
return inspect.isclass(InCls) and issubclass(InCls, LiveLinkCommand) and InCls != LiveLinkCommand
# Given a list of strings of names return all the live link commands listed
def GetLiveLinkCommandsFromModule(ModuleItems):
EvalItems = (eval(Item) for Item in ModuleItems)
return [Command for Command in EvalItems if IsLiveLinkCommand(Command) ]
# Command to create the Live Link UI
class MayaLiveLinkUI(LiveLinkCommand):
WindowName = "MayaLiveLinkUI"
Title = "Maya Live Link UI"
WindowSize = (500, 300)
def __init__(self):
LiveLinkCommand.__init__(self)
# Invoked when the command is run.
def doIt(self,argList):
if (cmds.window(self.WindowName , exists=True)):
cmds.deleteUI(self.WindowName)
window = cmds.window( self.WindowName, title=self.Title, widthHeight=(self.WindowSize[0], self.WindowSize[1]) )
#Get current connection status
ConnectionText, ConnectedState = cmds.LiveLinkConnectionStatus()
cmds.columnLayout( "mainColumn", adjustableColumn=True )
cmds.rowLayout("HeaderRow", numberOfColumns=3, adjustableColumn=1, parent = "mainColumn")
cmds.text(label="Unreal Engine Live Link", align="left")
cmds.text(label="Connection:")
cmds.text("ConnectionStatusUI", label=ConnectionText, align="center", backgroundColor=ConnectionColourMap[ConnectedState], width=150)
cmds.separator(h=20, style="none", parent="mainColumn")
cmds.columnLayout("SubjectWrapperLayout", parent="mainColumn") # just used as a container that will survive refreshing, so the following controls stay in their correct place
CreateSubjectTable()
PopulateSubjects()
cmds.separator(h=20, style="none", parent="mainColumn")
cmds.button( label='Add Selection', parent = "mainColumn", command=self.AddSelection)
cmds.showWindow( self.WindowName )
def AddSelection(self, *args):
cmds.LiveLinkAddSelection()
RefreshSubjects()
# Command to Refresh the subject UI
class MayaLiveLinkRefreshUI(LiveLinkCommand):
def __init__(self):
LiveLinkCommand.__init__(self)
# Invoked when the command is run.
def doIt(self,argList):
RefreshSubjects()
class MayaLiveLinkClearUI(LiveLinkCommand):
def __init__(self):
LiveLinkCommand.__init__(self)
def doIt(self, argList):
ClearSubjects()
CreateSubjectTable()
# Command to Refresh the connection UI
class MayaLiveLinkRefreshConnectionUI(LiveLinkCommand):
def __init__(self):
LiveLinkCommand.__init__(self)
# Invoked when the command is run.
def doIt(self,argList):
if (cmds.window(MayaLiveLinkUI.WindowName , exists=True)):
#Get current connection status
ConnectionText, ConnectedState = cmds.LiveLinkConnectionStatus()
cmds.text("ConnectionStatusUI", edit=True, label=ConnectionText, backgroundColor=ConnectionColourMap[ConnectedState])
class MayaLiveLinkGetActiveCamera(LiveLinkCommand):
def __init__(self):
LiveLinkCommand.__init__(self)
# Invoked when the command is run.
def doIt(self,argList):
self.clearResult()
try:
c = cmds.getPanel(wf=1)
cam = cmds.modelPanel(c, q=True, camera=True)
except:
pass
else:
self.setResult(cam)
#Grab commands declared
Commands = GetLiveLinkCommandsFromModule(dir())
#Initialize the script plug-in
def initializePlugin(mobject):
mplugin = OpenMayaMPx.MFnPlugin(mobject)
print("LiveLink:")
for Command in Commands:
try:
print("\tRegistering Command '%s'"%Command.__name__)
mplugin.registerCommand( Command.__name__, Command.Creator )
except:
sys.stderr.write( "Failed to register command: %s\n" % Command.__name__ )
raise
# Uninitialize the script plug-in
def uninitializePlugin(mobject):
mplugin = OpenMayaMPx.MFnPlugin(mobject)
for Command in Commands:
try:
mplugin.deregisterCommand( Command.__name__ )
except:
sys.stderr.write( "Failed to unregister command: %s\n" % Command.__name__ )

Some files were not shown because too many files have changed in this diff Show More