public Bone(string name, int index, Bone parent, RotationOrder rotationOrder, bool inheritsScale, ChannelTriplet centerPoint, ChannelTriplet endPoint, ChannelTriplet orientation, ChannelTriplet rotation, ChannelTriplet translation, ChannelTriplet scale, Channel generalScale)
    {
        if (parent == null)
        {
            if (index != 0)
            {
                throw new InvalidOperationException("root bone must be first");
            }
        }
        else if (parent.Index > index)
        {
            throw new ArgumentException("parent bones must have lower index");
        }

        Name          = name;
        Index         = index;
        Parent        = parent;
        RotationOrder = rotationOrder;
        InheritsScale = inheritsScale;
        CenterPoint   = centerPoint;
        EndPoint      = endPoint;
        Orientation   = orientation;
        Rotation      = rotation;
        Translation   = translation;
        Scale         = scale;
        GeneralScale  = generalScale;

        rotation.ExtractMinMax(out Vector3 minDegrees, out Vector3 maxDegrees);
        Vector3 minRadians = MathExtensions.DegreesToRadians(minDegrees);
        Vector3 maxRadians = MathExtensions.DegreesToRadians(maxDegrees);

        RotationConstraint = TwistSwingConstraint.MakeFromRadians(rotationOrder.TwistAxis, minRadians, maxRadians);
    }
    public void TestCenter()
    {
        var constraint = new TwistSwingConstraint(
            new TwistConstraint(-0.1f, 0.3f),
            new SwingConstraint(
                -0.2f, 0.6f,
                -0.4f, 1.0f));

        MathAssert.AreEqual(TwistSwing.MakeFromCoordinates(0.1f, 0.2f, 0.3f), constraint.Center, 1e-4f);
    }