mgear-dev / mgear4

mGear v.4.x.x (python 3 ready) https://mgear4.readthedocs.io
MIT License
259 stars 91 forks source link

MirrorController.get_opposite_control method Bug #392

Open thirstydevil opened 4 months ago

thirstydevil commented 4 months ago

The method to replace the side string isn't very safe and produces bugs.

target_name = node.name().replace(side_l, side_r)

For example, input node of "fore_quad_leg_l_fk1" will produce "fore_quad_reg_r_fk1" where the name "leg" has been changed to "reg"

I have a more robust fix at the cost of speed, but it could be cached.

    @staticmethod
    def get_opposite_control_fallback(node):
        import difflib
        mgear.log(f"Using : MirrorController.get_opposite_control_fallback method for node : {node}")

        root = node.longName().split("|")[0]
        # This guard may be overkill but the guide might be in the scene or some straggling shapes
        controls = [n for n in pm.ls(type="transform") if
                    n.longName().startswith(root) and hasattr(n, "side_label")]

        side = node.attr("side_label").get()

        filtered_controls = []
        if side == "L":
            filtered_controls = [n.shortName() for n in controls if n.attr("side_label").get() == "R"]

        elif side == "R":
            filtered_controls = [n.shortName() for n in controls if n.attr("side_label").get() == "L"]

        closest = difflib.get_close_matches(node.shortName(), filtered_controls)
        if closest:
            return pm.PyNode(closest[0])

    @staticmethod
    def get_opposite_control(node):
        side_l = node.attr("L_custom_side_label").get()
        side_r = node.attr("R_custom_side_label").get()
        side = node.attr("side_label").get()

        target_name = None
        if side == "L":
            target_name = node.name().replace(side_l, side_r)
        elif side == "R":
            target_name = node.name().replace(side_r, side_l)

        if target_name and pm.objExists(target_name):
            return pm.PyNode(target_name)
        else:
            return MirrorController.get_opposite_control_fallback(node)