Update
This commit is contained in:
117
2023/scripts/rigging_tools/ngskintools2/api/influence_names.py
Normal file
117
2023/scripts/rigging_tools/ngskintools2/api/influence_names.py
Normal file
@@ -0,0 +1,117 @@
|
||||
import re
|
||||
|
||||
from ngSkinTools2.api.python_compatibility import Object
|
||||
from ngSkinTools2.signal import Signal
|
||||
|
||||
|
||||
class InfluenceNameFilter(Object):
|
||||
"""
|
||||
simple helper object to match against filter strings;
|
||||
accepts filter as a string, breaks it down into lowercase tokens, and
|
||||
matches values in non-case sensitive way
|
||||
|
||||
e.g. filter "leg arm spines" matches "leg", "left_leg",
|
||||
"R_arm", but does not match "spine"
|
||||
|
||||
in a special case of empty filter, returns true for isMatch
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
self.matchers = []
|
||||
self.changed = Signal("filter changed")
|
||||
self.currentFilterString = ""
|
||||
|
||||
def set_filter_string(self, filter_string):
|
||||
if self.currentFilterString == filter_string:
|
||||
# avoid emitting change events if there's no change
|
||||
return
|
||||
self.currentFilterString = filter_string
|
||||
|
||||
def create_pattern(expression):
|
||||
expression = "".join([char for char in expression if char.lower() in "abcdefghijklmnopqrstuvwxyz0123456789_*"])
|
||||
expression = expression.replace("*", ".*")
|
||||
return re.compile(expression, re.I)
|
||||
|
||||
self.matchers = [create_pattern(i.strip()) for i in filter_string.split() if i.strip() != '']
|
||||
self.changed.emit()
|
||||
return self
|
||||
|
||||
def short_name(self, name):
|
||||
try:
|
||||
return name[name.rindex("|") + 1 :]
|
||||
except Exception as err:
|
||||
return name
|
||||
|
||||
def is_match(self, value):
|
||||
if len(self.matchers) == 0:
|
||||
return True
|
||||
|
||||
value = self.short_name(str(value).lower())
|
||||
for pattern in self.matchers:
|
||||
if pattern.search(value) is not None:
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
|
||||
def short_name(name, min_len=0):
|
||||
"""
|
||||
|
||||
:param str name:
|
||||
:param int min_len:
|
||||
"""
|
||||
idx = name.rfind("|", None, len(name) - min_len - 1)
|
||||
if idx < 0:
|
||||
return name
|
||||
return name[idx + 1 :]
|
||||
|
||||
|
||||
class IndexedName(object):
|
||||
def __init__(self, path):
|
||||
self.path = path
|
||||
self.name = short_name(path)
|
||||
|
||||
def extend_short_name(self):
|
||||
self.name = short_name(self.path, len(self.name))
|
||||
|
||||
|
||||
def extend_unique_names(items, from_item):
|
||||
"""
|
||||
|
||||
:param int from_item:
|
||||
:param list[IndexedName] items:
|
||||
"""
|
||||
|
||||
if from_item >= len(items) - 1:
|
||||
return
|
||||
|
||||
curr = items[from_item]
|
||||
needs_more_iterations = True
|
||||
while needs_more_iterations:
|
||||
needs_more_iterations = False
|
||||
curr_name = curr.name
|
||||
|
||||
for item in items[from_item + 1 :]:
|
||||
if item.name == curr_name:
|
||||
if not needs_more_iterations:
|
||||
curr.extend_short_name()
|
||||
item.extend_short_name()
|
||||
needs_more_iterations = True
|
||||
|
||||
|
||||
def unique_names(name_list):
|
||||
"""
|
||||
returns a list of shortened names without duplicates. e.g ["|a|b", "|a|b|c", "b|b"] will become ["a|b", "c", "b|b"]
|
||||
:param name_list:
|
||||
:return:
|
||||
"""
|
||||
|
||||
# assign index to each name to later restore the original order
|
||||
indexed_names = [IndexedName(i) for i in name_list]
|
||||
|
||||
sorted_by_reveresed_name = sorted(indexed_names, key=lambda x: x.path[::-1])
|
||||
|
||||
for i, _ in enumerate(sorted_by_reveresed_name):
|
||||
extend_unique_names(sorted_by_reveresed_name, i)
|
||||
|
||||
return [i.name for i in indexed_names]
|
||||
Reference in New Issue
Block a user