/// <summary>
        /// Extract the concatenated feature vector from a skeleton
        /// </summary>
        /// <param name="s">A processed Skeleton</param>
        /// <returns>The concatenated feature vector</returns>
        public static double[] FeatureSet(Skeleton s)
        {
            SkeletonFeatureFrame sff = new SkeletonFeatureFrame(s);
            var features = new double[31];
            int nextFreeIndex = 0;

            nextFreeIndex = AddFeat(sff, SkeletonFeatureFrame.DirectionVectors.ArmLeft, features, nextFreeIndex);
            nextFreeIndex = AddFeat(sff, SkeletonFeatureFrame.DirectionVectors.ArmRight, features, nextFreeIndex);
            nextFreeIndex = AddFeat(sff, SkeletonFeatureFrame.DirectionVectors.ForeArmLeft, features, nextFreeIndex);
            nextFreeIndex = AddFeat(sff, SkeletonFeatureFrame.DirectionVectors.ForeArmLeft, features, nextFreeIndex);
            nextFreeIndex = AddFeat(sff, SkeletonFeatureFrame.DirectionVectors.HandLeft, features, nextFreeIndex);
            nextFreeIndex = AddFeat(sff, SkeletonFeatureFrame.DirectionVectors.HandRight, features, nextFreeIndex);
            nextFreeIndex = AddFeat(sff, SkeletonFeatureFrame.DirectionVectors.ShoulderBladeLeft, features, nextFreeIndex);
            nextFreeIndex = AddFeat(sff, SkeletonFeatureFrame.DirectionVectors.ShoulderBladeRight, features, nextFreeIndex);
            nextFreeIndex = AddFeat(sff, SkeletonFeatureFrame.DirectionVectors.BetweenHands, features, nextFreeIndex);

            features[nextFreeIndex++] = sff.Angle(SkeletonFeatureFrame.Angles.AngleElbowLeft);
            features[nextFreeIndex++] = sff.Angle(SkeletonFeatureFrame.Angles.AngleElbowRight);
            features[nextFreeIndex++] = sff.Angle(SkeletonFeatureFrame.Angles.AngleShoulderLeft);
            features[nextFreeIndex++] = sff.Angle(SkeletonFeatureFrame.Angles.AngleShoulderRight);

            if (nextFreeIndex != features.Length) throw new Exception("Missing features");

            return features;
        }
 private static int AddFeat(
     SkeletonFeatureFrame sff, SkeletonFeatureFrame.DirectionVectors feature,
     double[] arr, int nextFreeIndex)
 {
     Vector3D v = sff.DirectionVector(feature);
     arr[nextFreeIndex++] = v.X;
     arr[nextFreeIndex++] = v.Y;
     arr[nextFreeIndex++] = v.Z;
     return nextFreeIndex;
 }
        public void Setup()
        {
            skeleton = new Skeleton
            {
                ShoulderCenter = Vector3D.Zero,
                ShoulderLeft = Vector3D.UnitX,
                ShoulderRight = -Vector3D.UnitX
            };

            skeleton.ElbowLeft = skeleton.ShoulderLeft + 2 * Vector3D.UnitX;
            skeleton.WristLeft = skeleton.ElbowLeft + (Vector3D.UnitY);
            skeleton.PalmLeft = skeleton.WristLeft + (0.5 * Vector3D.UnitZ);

            skeleton.ElbowRight = skeleton.ShoulderRight + new Vector3D(-1.5, 0, -1.5);
            skeleton.WristRight = skeleton.ElbowRight + new Vector3D(0, 3.5, -3.5);
            skeleton.PalmRight = skeleton.WristRight + new Vector3D(-0.5, 1, -1);

            skeletonFeatureFrame = new SkeletonFeatureFrame(skeleton);
        }