Files
Nexus/2023/scripts/rigging_tools/ngskintools2/api/influence_names.py
2025-11-24 08:27:50 +08:00

118 lines
3.2 KiB
Python

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]