# Path: robot_designer_plugin/operators/helpers.py
# def _mat3_to_vec_roll(mat):
#     """
#     Function to convert a 3x3 rotation matrix to a rotation axis and a roll angle along this axis
#     Python port of the C function defined in armature.c
# 
#     Thanks to blenderartists.org user vida_vida
# 
#     :param mat:
#     :return:
#     """
#     from ..properties.globals import global_properties
# 
#     vec = mat.col[1] * global_properties.bone_length.get(bpy.context.scene)
#     vecmat = _vec_roll_to_mat3(mat.col[1], 0)
#     vecmatinv = vecmat.inverted()
#     rollmat = vecmatinv @ mat
#     roll = math.atan2(rollmat[0][2], rollmat[2][2])
#     return vec, roll
# 
# class ModelSelected(Condition):
#     @staticmethod
#     def check():
#         """
#         :ref:`condition` that assures the armature is selected.
# 
#         :return: True if the condition is met, else false. String with error message.
#         """
#         if bpy.context.active_object:
#             return (
#                 bpy.context.active_object.type == "ARMATURE",
#                 "Model not selected and active.",
#             )
#         else:
#             return False, "No model selected"
# 
# class SingleSegmentSelected(Condition):
#     @staticmethod
#     def check():
#         """
#         :ref:`condition` that assures that a single mesh object (i.e., two selected objects where exactly one is a mesh).
# 
#         :return: True if the condition is met, else false. String with error message.
#         """
#         if bpy.context.active_bone:
#             selected_segments = [
#                 i for i in bpy.context.active_object.data.bones if i.select
#             ]
#             return len(selected_segments) == 1, "Single Segment must be selected"
#         else:
#             return False, "No Object Selected"
# 
# class PoseMode(Condition):
#     @staticmethod
#     def check():
#         """
#         :term:`condition` that assures that the :term:`pose mode` is selected.
#         """
#         if bpy.context.object:
#             return bpy.context.object.mode == "POSE", "Must be in Pose Mode"
#         else:
#             return True, ""
# 
# class AtLeastOneSegmentSelected(Condition):
#     @staticmethod
#     def check():
#         """
#         :ref:`condition` that assures that at least one bone of the active object is selected
# 
#         :return: True if the condition is met, else false. String with error message.
#         """
#         if bpy.context.active_bone:
#             selected_segments = [
#                 i for i in bpy.context.active_object.data.bones if i.select
#             ]
#             return len(selected_segments) >= 1, "At least one segment must be selected"
#         else:
#             return False, "No Object Selected"
# 
# class NotEditMode(Condition):
#     @staticmethod
#     def check():
#         """
#         :term:`condition` that assures that the :term:`edit mode` is *not* selected.
#         """
#         if bpy.context.object:
#             return bpy.context.object.mode != "EDIT", "Must not be in Edit Mode"
#         else:
#             return True, ""


from math import degrees, radians
from bpy.props import StringProperty, BoolProperty
from .rigid_bodies import *
from .helpers import (
    _mat3_to_vec_roll,
    ModelSelected,
    SingleSegmentSelected,
    PoseMode,
    AtLeastOneSegmentSelected,
    NotEditMode,
)
import bpy
        SelectSegment.run(segment_name=self.segment_name)

        if (
            not bpy.data.armatures[armature_data_name]
            .bones[segment_name]
            .RobotDesigner.RD_Bone
        ):
            self.logger.info("Not updated (not a RD segment): {}".format(segment_name))
            return {"FINISHED"}

        bone = bpy.data.armatures[armature_data_name].bones[segment_name]

        # Transforms as per RD spec.
        matrix, joint_matrix = bone.RobotDesigner.getTransform()

        bpy.ops.object.mode_set(mode="EDIT", toggle=False)

        editbone = bpy.data.armatures[armature_data_name].edit_bones[
            bpy.data.armatures[armature_data_name].bones[segment_name].name
        ]
        editbone.use_inherit_rotation = True

        # Express desired matrix in frame of the Armature
        if editbone.parent is not None:
            transform = editbone.parent.matrix.copy()
            matrix = transform @ matrix

        # Adjust bone properties to match RD transform specs.
        # Try to move it around rigidly. Keep length.
        pos = matrix.to_translation()

# Path: robot_designer_plugin/operators/helpers.py
# def _mat3_to_vec_roll(mat):
#     """
#     Function to convert a 3x3 rotation matrix to a rotation axis and a roll angle along this axis
#     Python port of the C function defined in armature.c
# 
#     Thanks to blenderartists.org user vida_vida
# 
#     :param mat:
#     :return:
#     """
#     from ..properties.globals import global_properties
# 
#     vec = mat.col[1] * global_properties.bone_length.get(bpy.context.scene)
#     vecmat = _vec_roll_to_mat3(mat.col[1], 0)
#     vecmatinv = vecmat.inverted()
#     rollmat = vecmatinv @ mat
#     roll = math.atan2(rollmat[0][2], rollmat[2][2])
#     return vec, roll
# 
# class ModelSelected(Condition):
#     @staticmethod
#     def check():
#         """
#         :ref:`condition` that assures the armature is selected.
# 
#         :return: True if the condition is met, else false. String with error message.
#         """
#         if bpy.context.active_object:
#             return (
#                 bpy.context.active_object.type == "ARMATURE",
#                 "Model not selected and active.",
#             )
#         else:
#             return False, "No model selected"
# 
# class SingleSegmentSelected(Condition):
#     @staticmethod
#     def check():
#         """
#         :ref:`condition` that assures that a single mesh object (i.e., two selected objects where exactly one is a mesh).
# 
#         :return: True if the condition is met, else false. String with error message.
#         """
#         if bpy.context.active_bone:
#             selected_segments = [
#                 i for i in bpy.context.active_object.data.bones if i.select
#             ]
#             return len(selected_segments) == 1, "Single Segment must be selected"
#         else:
#             return False, "No Object Selected"
# 
# class PoseMode(Condition):
#     @staticmethod
#     def check():
#         """
#         :term:`condition` that assures that the :term:`pose mode` is selected.
#         """
#         if bpy.context.object:
#             return bpy.context.object.mode == "POSE", "Must be in Pose Mode"
#         else:
#             return True, ""
# 
# class AtLeastOneSegmentSelected(Condition):
#     @staticmethod
#     def check():
#         """
#         :ref:`condition` that assures that at least one bone of the active object is selected
# 
#         :return: True if the condition is met, else false. String with error message.
#         """
#         if bpy.context.active_bone:
#             selected_segments = [
#                 i for i in bpy.context.active_object.data.bones if i.select
#             ]
#             return len(selected_segments) >= 1, "At least one segment must be selected"
#         else:
#             return False, "No Object Selected"
# 
# class NotEditMode(Condition):
#     @staticmethod
#     def check():
#         """
#         :term:`condition` that assures that the :term:`edit mode` is *not* selected.
#         """
#         if bpy.context.object:
#             return bpy.context.object.mode != "EDIT", "Must not be in Edit Mode"
#         else:
#             return True, ""


# Path: robot_designer_plugin/operators/segments.py
from math import degrees, radians
from bpy.props import StringProperty, BoolProperty
from .rigid_bodies import *
from .helpers import (
    _mat3_to_vec_roll,
    ModelSelected,
    SingleSegmentSelected,
    PoseMode,
    AtLeastOneSegmentSelected,
    NotEditMode,
)
import bpy

        SelectSegment.run(segment_name=self.segment_name)

        if (
            not bpy.data.armatures[armature_data_name]
            .bones[segment_name]
            .RobotDesigner.RD_Bone
        ):
            self.logger.info("Not updated (not a RD segment): {}".format(segment_name))
            return {"FINISHED"}

        bone = bpy.data.armatures[armature_data_name].bones[segment_name]

        # Transforms as per RD spec.
        matrix, joint_matrix = bone.RobotDesigner.getTransform()

        bpy.ops.object.mode_set(mode="EDIT", toggle=False)

        editbone = bpy.data.armatures[armature_data_name].edit_bones[
            bpy.data.armatures[armature_data_name].bones[segment_name].name
        ]
        editbone.use_inherit_rotation = True

        # Express desired matrix in frame of the Armature
        if editbone.parent is not None:
            transform = editbone.parent.matrix.copy()
            matrix = transform @ matrix

        # Adjust bone properties to match RD transform specs.
        # Try to move it around rigidly. Keep length.
        pos = matrix.to_translation()

        axis, roll = _mat3_to_vec_roll(matrix.to_3x3())