//------------------------------------------------------------------------------
// Title: Dance Like Me
// Name: Camille Jacobson
// This program utilizes code from the "SkeletonBasics-WPF" application from the
// Kinect for Windows Developer Toolkit v1.8.0. which was developed by Microsoft.
// I used the basic structure of the program (a WPF application in C# with a xaml file for a UI)
// and the code to process the skeleton from the Kinect. I then took this code and built
// Dance Like Me off of it by adding functionality and creating a way for users to store and
// see dance moves with the skeleton.
// I noted in the documentation where functions that were written by Microsoft stayed the same,
// I had modified, and the ones I wrote on my own. (NOTE: The SkeletonBasics-WPF application
// only had about 350 lines of code to begin with that I then reduced and reused within this program.
// I also worked somewhat with the xaml file that accompanied the SkeletonBasics-WPF app. I tried to eliminate
// what I felt useless, but found that there were certain elements that, in order for the program to run, I
// had to keep. The xaml file is also documented.
//------------------------------------------------------------------------------
namespace Microsoft.Samples.Kinect.SkeletonBasics
{
using System.Collections.Generic;
using System.IO;
using System.Windows;
using System.Windows.Media;
using Microsoft.Kinect;
using System.Windows.Threading;
using System;
using System.Windows.Controls;
public partial class MainWindow : Window
{
//The following variables (labeled with a "summary" tag) were created by
//Microsoft in the SkeletonBasics application. I used these throughout
//I did modify the JointThickness and the BodyCenterThickness
///
/// Width of output drawing
///
private const float RenderWidth = 640.0f;
///
/// Height of our output drawing
///
private const float RenderHeight = 480.0f;
///
/// Thickness of drawn joint lines
///
private const double JointThickness = 5;
///
/// Thickness of body center ellipse
///
private const double BodyCenterThickness = 15;
///
/// Thickness of clip edge rectangles
///
private const double ClipBoundsThickness = 10;
///
/// Brush used to draw skeleton center point
///
private readonly Brush centerPointBrush = Brushes.Blue;
///
/// Brush used for drawing joints that are currently tracked
///
private readonly Brush trackedJointBrush = new SolidColorBrush(Color.FromArgb(255, 68, 192, 68));
///
/// Brush used for drawing joints that are currently inferred
///
private readonly Brush inferredJointBrush = Brushes.Yellow;
///
/// Pen used for drawing bones that are currently tracked
///
private readonly Pen trackedBonePen = new Pen(Brushes.Purple, 6);
///
/// Pen used for drawing bones that are currently inferred
///
private readonly Pen inferredBonePen = new Pen(Brushes.Gray, 1);
//Now, the following variables are mine
//These are all brushes that determine the color of the skeleton - depends on the button you clicked
//The Brush objects are not used outside of creating the Pens. The pens are used in drawBone().
//I used a Hex to RGB color converter to get the specific color that matched each button, so they
// resemble each other: https://www.rapidtables.com/convert/color/hex-to-rgb.html
//In Bust A Move, the skeleton turns purple when recording
private static Brush moveBrush = new SolidColorBrush(Color.FromArgb(255, 189, 44, 231));
private readonly Pen movePen = new Pen(moveBrush, 6);
//In Bust A Move, the skeleton starts as orange
private readonly Pen allInPen = new Pen(Brushes.Orange, 6);
//In Freestyle, the skeleton is red
private static Brush freestyleBrush = new SolidColorBrush(Color.FromArgb(255, 232, 43, 43));
private readonly Pen freestylePen = new Pen(freestyleBrush, 6);
//In Routines, the skeleton is green
private static Brush routineBrush = new SolidColorBrush(Color.FromArgb(255, 98, 215, 14));
private readonly Pen routinePen = new Pen(routineBrush, 6);
//In PartnerUp, the skeleton is blue
private static Brush partnerUpBrush = new SolidColorBrush(Color.FromArgb(255, 15, 190, 255));
private readonly Pen partnerUpPen = new Pen(partnerUpBrush, 6);
//These variables were also created by Microsoft
///
/// Active Kinect sensor
///
private KinectSensor sensor;
///
/// Drawing group for skeleton rendering output
///
private DrawingGroup drawingGroup;
///
/// Drawing image that we will display
///
private DrawingImage imageSource;
//The following code is used to generate the path for this file
/*Code to get a general file came from the following pages (as well as assistance from Dr. McVey):
* https://www.c-sharpcorner.com/UploadFile/370e35/basedirectory-vs-currentdirectory-in-C-Sharp/
* https://stackoverflow.com/questions/14899422/how-to-navigate-a-few-folders-up
* */
private static string filePathLong = AppDomain.CurrentDomain.BaseDirectory;
private static string filePathShort = System.IO.Path.GetFullPath(System.IO.Path.Combine(filePathLong, @"..\..\")); //steps back from .exe location
///
/// Initializes a new instance of the MainWindow class.
/// This function was created by Microsoft
///
public MainWindow()
{
InitializeComponent();
}
///
/// Draws indicators to show which edges are clipping skeleton data - Created by Microsoft
/// Camille Jacobson added in-line documentation on this function
///
/// skeleton to draw clipping information for
/// drawing context to draw to
/// 2/19/2019 as of this day, this method has NOT been modified
/// 4/10/2019 as of this day, this method has STILL NOT been modified. I do not plan on
/// changing Microsoft's detection, just when, during execution, we detect when a skeleton goes out of bounds
private static void RenderClippedEdges(Skeleton skeleton, DrawingContext drawingContext)
{
if (skeleton.ClippedEdges.HasFlag(FrameEdges.Bottom)) //Bottom edge of screen
{
drawingContext.DrawRectangle(
Brushes.Red,
null,
new Rect(0, RenderHeight - ClipBoundsThickness, RenderWidth, ClipBoundsThickness));
}
if (skeleton.ClippedEdges.HasFlag(FrameEdges.Top)) //Top edge of screen
{
drawingContext.DrawRectangle(
Brushes.Red,
null,
new Rect(0, 0, RenderWidth, ClipBoundsThickness));
}
if (skeleton.ClippedEdges.HasFlag(FrameEdges.Left)) //Left edge of screen
{
drawingContext.DrawRectangle(
Brushes.Red,
null,
new Rect(0, 0, ClipBoundsThickness, RenderHeight));
}
if (skeleton.ClippedEdges.HasFlag(FrameEdges.Right)) //Right edge of screen
{
drawingContext.DrawRectangle(
Brushes.Red,
null,
new Rect(RenderWidth - ClipBoundsThickness, 0, ClipBoundsThickness, RenderHeight));
}
}
//bools that keep track of which page I am on
//Once you click on a button, it is noted that you are in that page
private bool inFreestyle = false;
private bool inMove = false;
private bool inHomeScreen = false;
private bool inRoutines = false;
private bool inPartnerUp = false;
///
/// Event handler for "Freestyle" button on home page.
/// Disables and hides the home screen, changes inHomeScreen to false
///
///
///
private void FreestyleOnClick(object sender, RoutedEventArgs e)
{
this.HomeButtons.Visibility = Visibility.Collapsed;
this.HomeButtons.IsEnabled = false;
this.FreestyleGrid.Visibility = Visibility.Visible;
this.FreestyleGrid.IsEnabled = true;
this.ImageViewbox.Visibility = Visibility.Collapsed;
inHomeScreen = false;
}
///
/// On the FreestyleGrid, there's a button to start tracking the skeleton.
/// Once clicked, a skeleton can be drawn to the screen. A back button appears for
/// when users want to return to the Home Screen
///
///
///
private void StartFreestyleBtnClick(object sender, RoutedEventArgs e)
{
inFreestyle = true;
this.ImageViewbox.Visibility = Visibility.Visible;
this.FreestyleGrid.Visibility = Visibility.Collapsed;
this.FreestyleGrid.IsEnabled = false;
this.BackButton.Visibility = Visibility.Visible;
this.BackButton.IsEnabled = true;
}
///
/// Event handler for the back button used in the various modes of the game.
/// Returns user to Home Screen and flips every page bool to false except inHomeScreen
///
///
///
private void BackBtnClicked(object sender, RoutedEventArgs e)
{
if (this.InstructionsGrid.Visibility == Visibility.Visible) //Collapses instruction screen
{
this.InstructionsGrid.Visibility = Visibility.Collapsed;
}
this.BackButton.Visibility = Visibility.Collapsed;
this.BackButton.IsEnabled = false;
this.HomeButtons.Visibility = Visibility.Visible;
this.HomeButtons.IsEnabled = true;
this.ImageViewbox.Visibility = Visibility.Visible;
inFreestyle = false;
inRoutines = false;
inMove = false;
inPartnerUp = false;
inHomeScreen = true;
}
///
/// Event handler for "Bust A Move" button on home page
/// Disables and hides home screen and makes instruction grid appear
///
///
///
private void MoveOnClick(object sender, RoutedEventArgs e)
{
this.HomeButtons.Visibility = Visibility.Collapsed;
this.HomeButtons.IsEnabled = false;
this.InstructionsGrid.Visibility = Visibility.Visible;
this.ImageViewbox.Visibility = Visibility.Collapsed;
}
///
/// Start button for Bust A Move. Changes bool for inMove to true and inHomeScreen to false.
/// Shows the 5 initializing buttons to start a dance move recording.
///
///
///
private void StartBtnClick(object sender, RoutedEventArgs e)
{
inMove = true;
inHomeScreen = false;
this.RightHandButton.Visibility = Visibility.Visible;
this.LeftHandButton.Visibility = Visibility.Visible;
this.LeftFootButton.Visibility = Visibility.Visible;
this.RightFootButton.Visibility = Visibility.Visible;
this.HeadButton.Visibility = Visibility.Visible;
this.InstructionsGrid.Visibility = Visibility.Collapsed;
this.ImageViewbox.Visibility = Visibility.Visible;
}
///
/// Once a dance move is done being recorded, a notification screen pops up for user benefit.
/// This event handler is for the "Okay!" button and returns the user to the Home Screen
///
///
///
private void ReturnBtnClick(object sender, RoutedEventArgs e)
{
inMove = false;
this.BustMoveGrid.Visibility = Visibility.Collapsed;
this.BustMoveGrid.IsEnabled = false;
this.HomeButtons.Visibility = Visibility.Visible;
this.HomeButtons.IsEnabled = true;
this.ImageViewbox.Visibility = Visibility.Visible;
}
///
/// This event handler is for the end screen for Routines/PartnerUp for when
/// a dance routine is completed before a user kills the routine via the back button.
///
///
///
private void EndRoutineBtnClick(object sender, RoutedEventArgs e)
{
inRoutines = false;
inMove1 = false;
inMove2 = false;
inMove3 = false;
inPartnerUp = false;
this.RoutineGrid.Visibility = Visibility.Collapsed;
this.RoutineGrid.IsEnabled = false;
this.HomeButtons.Visibility = Visibility.Visible;
this.HomeButtons.IsEnabled = true;
this.ImageViewbox.Visibility = Visibility.Visible;
this.BackButton.Visibility = Visibility.Collapsed;
this.BackButton.IsEnabled = false;
}
//The following variables are utilized in RotuineOnClick, dtClockTime, PartnerUpOnClick, and
//PartnerUp's respective timer handler
private static SkeletonPoint[,] routine1;
private static SkeletonPoint[,] routine2;
private static SkeletonPoint[,] routine3;
private Brush drawBrushTest = Brushes.Goldenrod;
private static int move1, move2, move3;
private static int lineCount1, lineCount2, lineCount3;
private static DispatcherTimer dtClockTime;
///
/// So, this function is the event handler for when a user clicks the Routines button.
/// In this function, 3 dance moves are randomly selected and those dance moves are pulled in from
/// the SavedMoves folder and placed into their respective 2D arrays (routine1, routine2, or routine3).
/// A timer (dtClockTime) is also started in this function and given the event handler: dtClockTime_Tick
/// This event handler is called every 10 milliseconds
///
///
///
private void RoutineOnClick(object sender, RoutedEventArgs e)
{
/* The following random number generated is taken from the following source:
* https://www.c-sharpcorner.com/article/generating-random-number-and-string-in-C-Sharp/
*/
Random rnd = new Random(); //Random number generator
inRoutines = true;
this.HomeButtons.Visibility = Visibility.Collapsed; //Clears out HomeScreen
this.HomeButtons.IsEnabled = false;
this.BackButton.IsEnabled = true; //Brings in the back button
this.BackButton.Visibility = Visibility.Visible;
int moveAmount = System.IO.Directory.GetDirectories(System.IO.Path.Combine(filePathShort, "SavedMoves")).Length;
moveAmount++; //incremented because the random generator goes between the range of x to y-1
inHomeScreen = false;
//the following is the list of random dance moves - as a programmer decision, the computer
//could potentially select the same three moves in a row. I will not prevent this.
move1 = rnd.Next(1, moveAmount);
move2 = rnd.Next(1, moveAmount);
move3 = rnd.Next(1, moveAmount);
//Array of file names within saved moves - order matters!
string[] fileNames = {"HipCenter.txt", "ShoulderCenter.txt", "Head.txt", "ShoulderLeft.txt", "ElbowLeft.txt",
"WristLeft.txt", "ShoulderRight.txt", "ElbowRight.txt", "WristRight.txt", "KneeLeft.txt",
"AnkleLeft.txt", "KneeRight.txt", "AnkleRight.txt" };
//setting up the timer
dtClockTime = new DispatcherTimer();
dtClockTime.Interval = new TimeSpan(0, 0, 0, 0, 10);//Yup, tick every 10 milliseconds. This reduced the seuizure-like effect of the redrawing
dtClockTime.Tick += dtClockTime_Tick;
//setting up to read from the files for each dance move
string line;
SkeletonPoint pos = new SkeletonPoint();
Joint joint = new Joint();
int lineCounter = 0;
totalArrayCount = 0;
intervalCount = 0;
string originalFolder = System.IO.Path.Combine(filePathShort, "SavedMoves");
string subDirectory1 = System.IO.Path.Combine(originalFolder,move1.ToString()); //sub-directory for each dance move
string subDirectory2 = System.IO.Path.Combine(originalFolder, move2.ToString());
string subDirectory3 = System.IO.Path.Combine(originalFolder, move3.ToString());
lineCount1 = getLineCount(move1); //gets line count for each dance move
lineCount2 = getLineCount(move2);
lineCount3 = getLineCount(move3);
routine1 = new SkeletonPoint[13, lineCount1]; //initialize routine arrays
routine2 = new SkeletonPoint[13, lineCount2];
routine3 = new SkeletonPoint[13, lineCount3];
inMove1 = true; //starting in Move1
inMove2 = false;
inMove3 = false;
string generalSubDirectory = subDirectory1;
//this for loop will get every 2D array ready to be drawn to the screen
for (int i=0; i<3; i++) //3 = number of selected dance moves
{
if (i == 1) //changing the directory if the move changes
{
generalSubDirectory = subDirectory2;
}
if (i == 2)
{
generalSubDirectory = subDirectory3;
}
for(int j=0; j<13; j++) //goes through the file of each joint and assigns the joint position to a spot in the array
{
lineCounter = 0;
using (System.IO.StreamReader file = new System.IO.StreamReader(System.IO.Path.Combine(generalSubDirectory, fileNames[j])))
{
while ((line = file.ReadLine()) != null)
{
string[] nums = line.Split(' '); //splits each line and gets it ready to be a Position
pos.X = (float)System.Convert.ToDouble(nums[0]); //X Coordinate
pos.Y = (float)System.Convert.ToDouble(nums[1]); //Y Coordinate
pos.Z = (float)System.Convert.ToDouble(nums[2]); //Z Coordinate
joint.Position = pos;
if (i == 0) //depending on the routine you're focusing on, change the array
{
routine1[j, lineCounter] = pos;
}
else if (i == 1)
{
routine2[j, lineCounter] = pos;
}
else
{
routine3[j, lineCounter] = pos;
}
lineCounter++;
}
file.Close();
}
}
}
dtClockTime.Start();
}
private static int totalArrayCount = 0;
private static int intervalCount = 0;
private static bool inMove1;
private static bool inMove2;
private static bool inMove3;
///
/// This is the event handler for dtClockTime. Every time the timer ticks (every 10 milliseconds), a new skeleton is drawn (and,
/// actually, the same skeleton is drawn 5 times due to the playback speed). This function draws those skeletons.
///
///
///
/// For reference, here's how the skeleton appears and explains why the lines are drawn the way they were:
/// 2
/// |
/// 3___1 ___6
/// | | |
/// 4 | 7
/// | | |
/// 5 0 8
/// | |
/// | |
/// 9 11
/// | |
/// | |
/// 10 12
/// I would've LOVED to condense the repetitive lines down, but I could not becuase of this skeleton
private void dtClockTime_Tick(object sender, EventArgs e)
{
Brush drawBrush = Brushes.White;
using (DrawingContext drawingCon = this.drawingGroup.Append())
{
if (!inHomeScreen && inRoutines) //Guarantees that these skeletons won't be drawn anywhere except in Routines
{
if (inMove1)
{
//Draws ellipses for all 13 joints
for (int i = 0; i < 13; i++)
{
drawingCon.DrawEllipse(drawBrush, null, this.SkeletonPointToScreen(routine1[i, totalArrayCount]), JointThickness, JointThickness);
}
//lines connecting the ellipses
drawingCon.DrawLine(routinePen, SkeletonPointToScreen(routine1[1, totalArrayCount]), SkeletonPointToScreen(routine1[0, totalArrayCount]));
drawingCon.DrawLine(routinePen, SkeletonPointToScreen(routine1[1, totalArrayCount]), SkeletonPointToScreen(routine1[6, totalArrayCount]));
drawingCon.DrawLine(routinePen, SkeletonPointToScreen(routine1[2, totalArrayCount]), SkeletonPointToScreen(routine1[1, totalArrayCount]));
drawingCon.DrawLine(routinePen, SkeletonPointToScreen(routine1[3, totalArrayCount]), SkeletonPointToScreen(routine1[1, totalArrayCount]));
drawingCon.DrawLine(routinePen, SkeletonPointToScreen(routine1[4, totalArrayCount]), SkeletonPointToScreen(routine1[3, totalArrayCount]));
drawingCon.DrawLine(routinePen, SkeletonPointToScreen(routine1[5, totalArrayCount]), SkeletonPointToScreen(routine1[4, totalArrayCount]));
drawingCon.DrawLine(routinePen, SkeletonPointToScreen(routine1[7, totalArrayCount]), SkeletonPointToScreen(routine1[6, totalArrayCount]));
drawingCon.DrawLine(routinePen, SkeletonPointToScreen(routine1[8, totalArrayCount]), SkeletonPointToScreen(routine1[7, totalArrayCount]));
drawingCon.DrawLine(routinePen, SkeletonPointToScreen(routine1[0, totalArrayCount]), SkeletonPointToScreen(routine1[9, totalArrayCount]));
drawingCon.DrawLine(routinePen, SkeletonPointToScreen(routine1[9, totalArrayCount]), SkeletonPointToScreen(routine1[10, totalArrayCount]));
drawingCon.DrawLine(routinePen, SkeletonPointToScreen(routine1[0, totalArrayCount]), SkeletonPointToScreen(routine1[11, totalArrayCount]));
drawingCon.DrawLine(routinePen, SkeletonPointToScreen(routine1[11, totalArrayCount]), SkeletonPointToScreen(routine1[12, totalArrayCount]));
if (totalArrayCount == (lineCount1 - 10)) //if you make it to the end of the dance move, go the the next
{
totalArrayCount = 0;
inMove1 = false;
inMove2 = true;
}
}
if (inMove2)
{
//ellipses
for (int i = 0; i < 13; i++)
{
drawingCon.DrawEllipse(drawBrush, null, this.SkeletonPointToScreen(routine2[i, totalArrayCount]), JointThickness, JointThickness);
}
//lines connecting the ellipses
drawingCon.DrawLine(routinePen, SkeletonPointToScreen(routine2[1, totalArrayCount]), SkeletonPointToScreen(routine2[0, totalArrayCount]));
drawingCon.DrawLine(routinePen, SkeletonPointToScreen(routine2[1, totalArrayCount]), SkeletonPointToScreen(routine2[6, totalArrayCount]));
drawingCon.DrawLine(routinePen, SkeletonPointToScreen(routine2[2, totalArrayCount]), SkeletonPointToScreen(routine2[1, totalArrayCount]));
drawingCon.DrawLine(routinePen, SkeletonPointToScreen(routine2[3, totalArrayCount]), SkeletonPointToScreen(routine2[1, totalArrayCount]));
drawingCon.DrawLine(routinePen, SkeletonPointToScreen(routine2[4, totalArrayCount]), SkeletonPointToScreen(routine2[3, totalArrayCount]));
drawingCon.DrawLine(routinePen, SkeletonPointToScreen(routine2[5, totalArrayCount]), SkeletonPointToScreen(routine2[4, totalArrayCount]));
drawingCon.DrawLine(routinePen, SkeletonPointToScreen(routine2[7, totalArrayCount]), SkeletonPointToScreen(routine2[6, totalArrayCount]));
drawingCon.DrawLine(routinePen, SkeletonPointToScreen(routine2[8, totalArrayCount]), SkeletonPointToScreen(routine2[7, totalArrayCount]));
drawingCon.DrawLine(routinePen, SkeletonPointToScreen(routine2[0, totalArrayCount]), SkeletonPointToScreen(routine2[9, totalArrayCount]));
drawingCon.DrawLine(routinePen, SkeletonPointToScreen(routine2[9, totalArrayCount]), SkeletonPointToScreen(routine2[10, totalArrayCount]));
drawingCon.DrawLine(routinePen, SkeletonPointToScreen(routine2[0, totalArrayCount]), SkeletonPointToScreen(routine2[11, totalArrayCount]));
drawingCon.DrawLine(routinePen, SkeletonPointToScreen(routine2[11, totalArrayCount]), SkeletonPointToScreen(routine2[12, totalArrayCount]));
if (totalArrayCount == (lineCount2 - 10)) //if Move2 is done, go to Move3
{
totalArrayCount = 0;
inMove2 = false;
inMove3 = true;
}
}
if (inMove3)
{
//ellipses
for (int i = 0; i < 13; i++)
{
drawingCon.DrawEllipse(drawBrush, null, this.SkeletonPointToScreen(routine3[i, totalArrayCount]), JointThickness, JointThickness);
}
//lines connecting the ellipses
drawingCon.DrawLine(routinePen, SkeletonPointToScreen(routine3[1, totalArrayCount]), SkeletonPointToScreen(routine3[0, totalArrayCount]));
drawingCon.DrawLine(routinePen, SkeletonPointToScreen(routine3[1, totalArrayCount]), SkeletonPointToScreen(routine3[6, totalArrayCount]));
drawingCon.DrawLine(routinePen, SkeletonPointToScreen(routine3[2, totalArrayCount]), SkeletonPointToScreen(routine3[1, totalArrayCount]));
drawingCon.DrawLine(routinePen, SkeletonPointToScreen(routine3[3, totalArrayCount]), SkeletonPointToScreen(routine3[1, totalArrayCount]));
drawingCon.DrawLine(routinePen, SkeletonPointToScreen(routine3[4, totalArrayCount]), SkeletonPointToScreen(routine3[3, totalArrayCount]));
drawingCon.DrawLine(routinePen, SkeletonPointToScreen(routine3[5, totalArrayCount]), SkeletonPointToScreen(routine3[4, totalArrayCount]));
drawingCon.DrawLine(routinePen, SkeletonPointToScreen(routine3[7, totalArrayCount]), SkeletonPointToScreen(routine3[6, totalArrayCount]));
drawingCon.DrawLine(routinePen, SkeletonPointToScreen(routine3[8, totalArrayCount]), SkeletonPointToScreen(routine3[7, totalArrayCount]));
drawingCon.DrawLine(routinePen, SkeletonPointToScreen(routine3[0, totalArrayCount]), SkeletonPointToScreen(routine3[9, totalArrayCount]));
drawingCon.DrawLine(routinePen, SkeletonPointToScreen(routine3[9, totalArrayCount]), SkeletonPointToScreen(routine3[10, totalArrayCount]));
drawingCon.DrawLine(routinePen, SkeletonPointToScreen(routine3[0, totalArrayCount]), SkeletonPointToScreen(routine3[11, totalArrayCount]));
drawingCon.DrawLine(routinePen, SkeletonPointToScreen(routine3[11, totalArrayCount]), SkeletonPointToScreen(routine3[12, totalArrayCount]));
if (totalArrayCount == (lineCount3 - 10)) //if Move3 is done, the whole routine is done
{
totalArrayCount = 0;
inMove3 = false;
this.RoutineGrid.IsEnabled = true;
this.RoutineGrid.Visibility = Visibility.Visible;
this.ImageViewbox.Visibility = Visibility.Collapsed;
dtClockTime.Stop();
}
}
}
}
//intervalCount is used to reduce the strobe-light effect of redrawing skeletons at the speeds they were obtained at
//intervalCount is responsible for the same skeleton being drawn 5 times to a screen before moving on
if (intervalCount ==5)
{
totalArrayCount++; //We don't move onto the next position until intervalCount hits 5
intervalCount = 0;
}
else
{
intervalCount++;
}
}
///
/// This function iterates through a file for a given move and reports the number of lines in a file
///
/// Send the number of the dance move
/// Returns the total line count
private int getLineCount(int moveNumber)
{
int lineCounter = 0;
string line;
string originalFolder = System.IO.Path.Combine(filePathShort, "SavedMoves");
string subDirectory1 = System.IO.Path.Combine(originalFolder, moveNumber.ToString());
using (System.IO.StreamReader file = new System.IO.StreamReader(System.IO.Path.Combine(subDirectory1, "Head.txt")))
{
while ((line = file.ReadLine()) != null)
{
lineCounter++; //gets the amount of lines in one file, which will be the same amount for all files for this move
}
file.Close();
}
return lineCounter;
}
//partnerUp1 and partnerUpA are partners and so on
private static SkeletonPoint[,] partnerUp1;
private static SkeletonPoint[,] partnerUp2;
private static SkeletonPoint[,] partnerUp3;
private static SkeletonPoint[,] partnerUpA;
private static SkeletonPoint[,] partnerUpB;
private static SkeletonPoint[,] partnerUpC;
private static DispatcherTimer dtClockTimePartner;
///
/// Similar to RoutineOnClick, this function is generating the dance routine for PartnerUp
///
///
///
private void PartnerBtnClick(object sender, RoutedEventArgs e)
{
Random rnd = new Random();
inPartnerUp = true;
this.HomeButtons.Visibility = Visibility.Collapsed;
this.HomeButtons.IsEnabled = false;
this.BackButton.IsEnabled = true;
this.BackButton.Visibility = Visibility.Visible;
int moveAmount = System.IO.Directory.GetDirectories(System.IO.Path.Combine(filePathShort, "SavedMoves")).Length;
moveAmount++; //incremented because the random generator goes between the range of x to y-1
inHomeScreen = false;
//the following is the list of random dance moves - as a programmer decision, the computer
//could potentially select the same three moves in a row. I will not prevent this.
move1 = rnd.Next(1, moveAmount);
move2 = rnd.Next(1, moveAmount);
move3 = rnd.Next(1, moveAmount);
//Array of file names within saved moves - Order matters!
//Note: There's two arrays because the 2 skeletons will be mirrored, so the order varies slightly
string[] fileNames = {"HipCenter.txt", "ShoulderCenter.txt", "Head.txt", "ShoulderLeft.txt", "ElbowLeft.txt",
"WristLeft.txt", "ShoulderRight.txt", "ElbowRight.txt", "WristRight.txt", "KneeLeft.txt",
"AnkleLeft.txt", "KneeRight.txt", "AnkleRight.txt" };
string[] fileNamesForRightPartner = {"HipCenter.txt", "ShoulderCenter.txt", "Head.txt", "ShoulderRight.txt", "ElbowRight.txt",
"WristRight.txt", "ShoulderLeft.txt", "ElbowLeft.txt", "WristLeft.txt", "KneeRight.txt",
"AnkleRight.txt", "KneeLeft.txt", "AnkleLeft.txt" };
dtClockTimePartner = new DispatcherTimer();
dtClockTimePartner.Interval = new TimeSpan(0, 0, 0, 0, 10);
dtClockTimePartner.Tick += dtClockTime_TickPartner;
string line;
SkeletonPoint pos = new SkeletonPoint();
Joint joint = new Joint();
int lineCounter = 0;
arrayIndex = 0;
intervalArrayIndex = 0;
string originalFolder = System.IO.Path.Combine(filePathShort, "SavedMoves");
string subDirectory1 = System.IO.Path.Combine(originalFolder, move1.ToString());
string subDirectory2 = System.IO.Path.Combine(originalFolder, move2.ToString());
string subDirectory3 = System.IO.Path.Combine(originalFolder, move3.ToString());
lineCount1 = getLineCount(move1);
lineCount2 = getLineCount(move2);
lineCount3 = getLineCount(move3);
//6 2D arrays to account for the 6 total skeletons
partnerUp1 = new SkeletonPoint[13, lineCount1];
partnerUp2 = new SkeletonPoint[13, lineCount2];
partnerUp3 = new SkeletonPoint[13, lineCount3];
partnerUpA = new SkeletonPoint[13, lineCount1];
partnerUpB = new SkeletonPoint[13, lineCount2];
partnerUpC = new SkeletonPoint[13, lineCount3];
inMove1 = true;
inMove2 = false;
inMove3 = false;
string generalSubDirectory = subDirectory1;
for (int i = 0; i < 3; i++)
{
if (i == 1)
{
generalSubDirectory = subDirectory2;
}
if (i == 2)
{
generalSubDirectory = subDirectory3;
}
for (int j = 0; j < 13; j++)
{
lineCounter = 0;
//accounts for the left skeleton
using (System.IO.StreamReader file = new System.IO.StreamReader(System.IO.Path.Combine(generalSubDirectory, fileNames[j])))
{
while ((line = file.ReadLine()) != null)
{
string[] nums = line.Split(' ');
pos.X = (float)System.Convert.ToDouble(nums[0]);
pos.Y = (float)System.Convert.ToDouble(nums[1]);
pos.Z = (float)System.Convert.ToDouble(nums[2]);
joint.Position = pos;
pos.X = (float)(pos.X - 0.50); //accounts for shifting the skeleton leftwards on screen
if (i == 0)
{
partnerUp1[j, lineCounter] = pos;
}
else if (i == 1)
{
partnerUp2[j, lineCounter] = pos;
}
else
{
partnerUp3[j, lineCounter] = pos;
}
lineCounter++;
}
file.Close();
}
lineCounter = 0;
//accounts for the right skeleton
using (System.IO.StreamReader file = new System.IO.StreamReader(System.IO.Path.Combine(generalSubDirectory, fileNamesForRightPartner[j])))
{
while ((line = file.ReadLine()) != null)
{
string[] nums = line.Split(' ');
pos.X = (float)System.Convert.ToDouble(nums[0]);
pos.Y = (float)System.Convert.ToDouble(nums[1]);
pos.Z = (float)System.Convert.ToDouble(nums[2]);
joint.Position = pos;
pos.X = (float)((pos.X * -1) + 0.5); //flips the x coordinate for mirror effect and shifts it right
if (i == 0)
{
partnerUpA[j, lineCounter] = pos;
}
else if (i == 1)
{
partnerUpB[j, lineCounter] = pos;
}
else
{
partnerUpC[j, lineCounter] = pos;
}
lineCounter++;
}
file.Close();
}
}
}
dtClockTimePartner.Start();
}
///
/// Similar to dtClockTime_Tick, except to draw both partners for PartnerUp
///
///
///
///
private static int arrayIndex=0;
private static int intervalArrayIndex = 0;
private void dtClockTime_TickPartner(object sender, EventArgs e)
{
Brush drawBrush = Brushes.GreenYellow;
using (DrawingContext drawingCon = this.drawingGroup.Append())
{
if (!inHomeScreen && inPartnerUp)
{
if (inMove1)
{
//ellipses
for (int i = 0; i < 13; i++)
{
drawingCon.DrawEllipse(drawBrush, null, this.SkeletonPointToScreen(partnerUp1[i, arrayIndex]), JointThickness, JointThickness);
drawingCon.DrawEllipse(drawBrush, null, this.SkeletonPointToScreen(partnerUpA[i, arrayIndex]), JointThickness, JointThickness);
}
//lines connecting the ellipses
drawingCon.DrawLine(partnerUpPen, SkeletonPointToScreen(partnerUp1[1, arrayIndex]), SkeletonPointToScreen(partnerUp1[0, arrayIndex]));
drawingCon.DrawLine(partnerUpPen, SkeletonPointToScreen(partnerUp1[1, arrayIndex]), SkeletonPointToScreen(partnerUp1[6, arrayIndex]));
drawingCon.DrawLine(partnerUpPen, SkeletonPointToScreen(partnerUp1[2, arrayIndex]), SkeletonPointToScreen(partnerUp1[1, arrayIndex]));
drawingCon.DrawLine(partnerUpPen, SkeletonPointToScreen(partnerUp1[3, arrayIndex]), SkeletonPointToScreen(partnerUp1[1, arrayIndex]));
drawingCon.DrawLine(partnerUpPen, SkeletonPointToScreen(partnerUp1[4, arrayIndex]), SkeletonPointToScreen(partnerUp1[3, arrayIndex]));
drawingCon.DrawLine(partnerUpPen, SkeletonPointToScreen(partnerUp1[5, arrayIndex]), SkeletonPointToScreen(partnerUp1[4, arrayIndex]));
drawingCon.DrawLine(partnerUpPen, SkeletonPointToScreen(partnerUp1[7, arrayIndex]), SkeletonPointToScreen(partnerUp1[6, arrayIndex]));
drawingCon.DrawLine(partnerUpPen, SkeletonPointToScreen(partnerUp1[8, arrayIndex]), SkeletonPointToScreen(partnerUp1[7, arrayIndex]));
drawingCon.DrawLine(partnerUpPen, SkeletonPointToScreen(partnerUp1[0, arrayIndex]), SkeletonPointToScreen(partnerUp1[9, arrayIndex]));
drawingCon.DrawLine(partnerUpPen, SkeletonPointToScreen(partnerUp1[9, arrayIndex]), SkeletonPointToScreen(partnerUp1[10, arrayIndex]));
drawingCon.DrawLine(partnerUpPen, SkeletonPointToScreen(partnerUp1[0, arrayIndex]), SkeletonPointToScreen(partnerUp1[11, arrayIndex]));
drawingCon.DrawLine(partnerUpPen, SkeletonPointToScreen(partnerUp1[11, arrayIndex]), SkeletonPointToScreen(partnerUp1[12, arrayIndex]));
//lines connecting the ellipses
drawingCon.DrawLine(partnerUpPen, SkeletonPointToScreen(partnerUpA[1, arrayIndex]), SkeletonPointToScreen(partnerUpA[0, arrayIndex]));
drawingCon.DrawLine(partnerUpPen, SkeletonPointToScreen(partnerUpA[1, arrayIndex]), SkeletonPointToScreen(partnerUpA[6, arrayIndex]));
drawingCon.DrawLine(partnerUpPen, SkeletonPointToScreen(partnerUpA[2, arrayIndex]), SkeletonPointToScreen(partnerUpA[1, arrayIndex]));
drawingCon.DrawLine(partnerUpPen, SkeletonPointToScreen(partnerUpA[3, arrayIndex]), SkeletonPointToScreen(partnerUpA[1, arrayIndex]));
drawingCon.DrawLine(partnerUpPen, SkeletonPointToScreen(partnerUpA[4, arrayIndex]), SkeletonPointToScreen(partnerUpA[3, arrayIndex]));
drawingCon.DrawLine(partnerUpPen, SkeletonPointToScreen(partnerUpA[5, arrayIndex]), SkeletonPointToScreen(partnerUpA[4, arrayIndex]));
drawingCon.DrawLine(partnerUpPen, SkeletonPointToScreen(partnerUpA[7, arrayIndex]), SkeletonPointToScreen(partnerUpA[6, arrayIndex]));
drawingCon.DrawLine(partnerUpPen, SkeletonPointToScreen(partnerUpA[8, arrayIndex]), SkeletonPointToScreen(partnerUpA[7, arrayIndex]));
drawingCon.DrawLine(partnerUpPen, SkeletonPointToScreen(partnerUpA[0, arrayIndex]), SkeletonPointToScreen(partnerUpA[9, arrayIndex]));
drawingCon.DrawLine(partnerUpPen, SkeletonPointToScreen(partnerUpA[9, arrayIndex]), SkeletonPointToScreen(partnerUpA[10, arrayIndex]));
drawingCon.DrawLine(partnerUpPen, SkeletonPointToScreen(partnerUpA[0, arrayIndex]), SkeletonPointToScreen(partnerUpA[11, arrayIndex]));
drawingCon.DrawLine(partnerUpPen, SkeletonPointToScreen(partnerUpA[11, arrayIndex]), SkeletonPointToScreen(partnerUpA[12, arrayIndex]));
if (arrayIndex == (lineCount1 - 10))
{
arrayIndex = 0;
inMove1 = false;
inMove2 = true;
}
}
if (inMove2)
{
//ellipses
for (int i = 0; i < 13; i++)
{
drawingCon.DrawEllipse(drawBrush, null, this.SkeletonPointToScreen(partnerUp2[i, arrayIndex]), JointThickness, JointThickness);
drawingCon.DrawEllipse(drawBrush, null, this.SkeletonPointToScreen(partnerUpB[i, arrayIndex]), JointThickness, JointThickness);
}
//lines connecting the ellipses
drawingCon.DrawLine(partnerUpPen, SkeletonPointToScreen(partnerUp2[1, arrayIndex]), SkeletonPointToScreen(partnerUp2[0, arrayIndex]));
drawingCon.DrawLine(partnerUpPen, SkeletonPointToScreen(partnerUp2[1, arrayIndex]), SkeletonPointToScreen(partnerUp2[6, arrayIndex]));
drawingCon.DrawLine(partnerUpPen, SkeletonPointToScreen(partnerUp2[2, arrayIndex]), SkeletonPointToScreen(partnerUp2[1, arrayIndex]));
drawingCon.DrawLine(partnerUpPen, SkeletonPointToScreen(partnerUp2[3, arrayIndex]), SkeletonPointToScreen(partnerUp2[1, arrayIndex]));
drawingCon.DrawLine(partnerUpPen, SkeletonPointToScreen(partnerUp2[4, arrayIndex]), SkeletonPointToScreen(partnerUp2[3, arrayIndex]));
drawingCon.DrawLine(partnerUpPen, SkeletonPointToScreen(partnerUp2[5, arrayIndex]), SkeletonPointToScreen(partnerUp2[4, arrayIndex]));
drawingCon.DrawLine(partnerUpPen, SkeletonPointToScreen(partnerUp2[7, arrayIndex]), SkeletonPointToScreen(partnerUp2[6, arrayIndex]));
drawingCon.DrawLine(partnerUpPen, SkeletonPointToScreen(partnerUp2[8, arrayIndex]), SkeletonPointToScreen(partnerUp2[7, arrayIndex]));
drawingCon.DrawLine(partnerUpPen, SkeletonPointToScreen(partnerUp2[0, arrayIndex]), SkeletonPointToScreen(partnerUp2[9, arrayIndex]));
drawingCon.DrawLine(partnerUpPen, SkeletonPointToScreen(partnerUp2[9, arrayIndex]), SkeletonPointToScreen(partnerUp2[10, arrayIndex]));
drawingCon.DrawLine(partnerUpPen, SkeletonPointToScreen(partnerUp2[0, arrayIndex]), SkeletonPointToScreen(partnerUp2[11, arrayIndex]));
drawingCon.DrawLine(partnerUpPen, SkeletonPointToScreen(partnerUp2[11, arrayIndex]), SkeletonPointToScreen(partnerUp2[12, arrayIndex]));
//lines connecting the ellipses
drawingCon.DrawLine(partnerUpPen, SkeletonPointToScreen(partnerUpB[1, arrayIndex]), SkeletonPointToScreen(partnerUpB[0, arrayIndex]));
drawingCon.DrawLine(partnerUpPen, SkeletonPointToScreen(partnerUpB[1, arrayIndex]), SkeletonPointToScreen(partnerUpB[6, arrayIndex]));
drawingCon.DrawLine(partnerUpPen, SkeletonPointToScreen(partnerUpB[2, arrayIndex]), SkeletonPointToScreen(partnerUpB[1, arrayIndex]));
drawingCon.DrawLine(partnerUpPen, SkeletonPointToScreen(partnerUpB[3, arrayIndex]), SkeletonPointToScreen(partnerUpB[1, arrayIndex]));
drawingCon.DrawLine(partnerUpPen, SkeletonPointToScreen(partnerUpB[4, arrayIndex]), SkeletonPointToScreen(partnerUpB[3, arrayIndex]));
drawingCon.DrawLine(partnerUpPen, SkeletonPointToScreen(partnerUpB[5, arrayIndex]), SkeletonPointToScreen(partnerUpB[4, arrayIndex]));
drawingCon.DrawLine(partnerUpPen, SkeletonPointToScreen(partnerUpB[7, arrayIndex]), SkeletonPointToScreen(partnerUpB[6, arrayIndex]));
drawingCon.DrawLine(partnerUpPen, SkeletonPointToScreen(partnerUpB[8, arrayIndex]), SkeletonPointToScreen(partnerUpB[7, arrayIndex]));
drawingCon.DrawLine(partnerUpPen, SkeletonPointToScreen(partnerUpB[0, arrayIndex]), SkeletonPointToScreen(partnerUpB[9, arrayIndex]));
drawingCon.DrawLine(partnerUpPen, SkeletonPointToScreen(partnerUpB[9, arrayIndex]), SkeletonPointToScreen(partnerUpB[10, arrayIndex]));
drawingCon.DrawLine(partnerUpPen, SkeletonPointToScreen(partnerUpB[0, arrayIndex]), SkeletonPointToScreen(partnerUpB[11, arrayIndex]));
drawingCon.DrawLine(partnerUpPen, SkeletonPointToScreen(partnerUpB[11, arrayIndex]), SkeletonPointToScreen(partnerUpB[12, arrayIndex]));
if (arrayIndex == (lineCount2 - 10))
{
arrayIndex = 0;
inMove2 = false;
inMove3 = true;
}
}
if (inMove3)
{
//ellipses
for (int i = 0; i < 13; i++)
{
drawingCon.DrawEllipse(drawBrush, null, this.SkeletonPointToScreen(partnerUp3[i, arrayIndex]), JointThickness, JointThickness);
drawingCon.DrawEllipse(drawBrush, null, this.SkeletonPointToScreen(partnerUpC[i, arrayIndex]), JointThickness, JointThickness);
}
//lines connecting the ellipses
drawingCon.DrawLine(partnerUpPen, SkeletonPointToScreen(partnerUp3[1, arrayIndex]), SkeletonPointToScreen(partnerUp3[0, arrayIndex]));
drawingCon.DrawLine(partnerUpPen, SkeletonPointToScreen(partnerUp3[1, arrayIndex]), SkeletonPointToScreen(partnerUp3[6, arrayIndex]));
drawingCon.DrawLine(partnerUpPen, SkeletonPointToScreen(partnerUp3[2, arrayIndex]), SkeletonPointToScreen(partnerUp3[1, arrayIndex]));
drawingCon.DrawLine(partnerUpPen, SkeletonPointToScreen(partnerUp3[3, arrayIndex]), SkeletonPointToScreen(partnerUp3[1, arrayIndex]));
drawingCon.DrawLine(partnerUpPen, SkeletonPointToScreen(partnerUp3[4, arrayIndex]), SkeletonPointToScreen(partnerUp3[3, arrayIndex]));
drawingCon.DrawLine(partnerUpPen, SkeletonPointToScreen(partnerUp3[5, arrayIndex]), SkeletonPointToScreen(partnerUp3[4, arrayIndex]));
drawingCon.DrawLine(partnerUpPen, SkeletonPointToScreen(partnerUp3[7, arrayIndex]), SkeletonPointToScreen(partnerUp3[6, arrayIndex]));
drawingCon.DrawLine(partnerUpPen, SkeletonPointToScreen(partnerUp3[8, arrayIndex]), SkeletonPointToScreen(partnerUp3[7, arrayIndex]));
drawingCon.DrawLine(partnerUpPen, SkeletonPointToScreen(partnerUp3[0, arrayIndex]), SkeletonPointToScreen(partnerUp3[9, arrayIndex]));
drawingCon.DrawLine(partnerUpPen, SkeletonPointToScreen(partnerUp3[9, arrayIndex]), SkeletonPointToScreen(partnerUp3[10, arrayIndex]));
drawingCon.DrawLine(partnerUpPen, SkeletonPointToScreen(partnerUp3[0, arrayIndex]), SkeletonPointToScreen(partnerUp3[11, arrayIndex]));
drawingCon.DrawLine(partnerUpPen, SkeletonPointToScreen(partnerUp3[11, arrayIndex]), SkeletonPointToScreen(partnerUp3[12, arrayIndex]));
//lines connecting the ellipses
drawingCon.DrawLine(partnerUpPen, SkeletonPointToScreen(partnerUpC[1, arrayIndex]), SkeletonPointToScreen(partnerUpC[0, arrayIndex]));
drawingCon.DrawLine(partnerUpPen, SkeletonPointToScreen(partnerUpC[1, arrayIndex]), SkeletonPointToScreen(partnerUpC[6, arrayIndex]));
drawingCon.DrawLine(partnerUpPen, SkeletonPointToScreen(partnerUpC[2, arrayIndex]), SkeletonPointToScreen(partnerUpC[1, arrayIndex]));
drawingCon.DrawLine(partnerUpPen, SkeletonPointToScreen(partnerUpC[3, arrayIndex]), SkeletonPointToScreen(partnerUpC[1, arrayIndex]));
drawingCon.DrawLine(partnerUpPen, SkeletonPointToScreen(partnerUpC[4, arrayIndex]), SkeletonPointToScreen(partnerUpC[3, arrayIndex]));
drawingCon.DrawLine(partnerUpPen, SkeletonPointToScreen(partnerUpC[5, arrayIndex]), SkeletonPointToScreen(partnerUpC[4, arrayIndex]));
drawingCon.DrawLine(partnerUpPen, SkeletonPointToScreen(partnerUpC[7, arrayIndex]), SkeletonPointToScreen(partnerUpC[6, arrayIndex]));
drawingCon.DrawLine(partnerUpPen, SkeletonPointToScreen(partnerUpC[8, arrayIndex]), SkeletonPointToScreen(partnerUpC[7, arrayIndex]));
drawingCon.DrawLine(partnerUpPen, SkeletonPointToScreen(partnerUpC[0, arrayIndex]), SkeletonPointToScreen(partnerUpC[9, arrayIndex]));
drawingCon.DrawLine(partnerUpPen, SkeletonPointToScreen(partnerUpC[9, arrayIndex]), SkeletonPointToScreen(partnerUpC[10, arrayIndex]));
drawingCon.DrawLine(partnerUpPen, SkeletonPointToScreen(partnerUpC[0, arrayIndex]), SkeletonPointToScreen(partnerUpC[11, arrayIndex]));
drawingCon.DrawLine(partnerUpPen, SkeletonPointToScreen(partnerUpC[11, arrayIndex]), SkeletonPointToScreen(partnerUpC[12, arrayIndex]));
if (arrayIndex == (lineCount3 - 10))
{
arrayIndex = 0;
inMove3 = false;
this.RoutineGrid.IsEnabled = true;
this.RoutineGrid.Visibility = Visibility.Visible;
this.ImageViewbox.Visibility = Visibility.Collapsed;
this.EndRoutineBtn.Background = partnerUpBrush;
dtClockTimePartner.Stop();
}
}
}
}
if (intervalArrayIndex == 5)
{
arrayIndex++;
intervalArrayIndex = 0;
}
else
{
intervalArrayIndex++;
}
}
//list of all of the joints I will NOT be tracking
private List excludedJoints = new List();
///
/// Execute startup tasks
///
/// object sending the event
/// event arguments
/// 2/19/2019 as of this date, this function has not been modified
/// 3/4/2019 as of this date, this function HAS been modified to include adding joints to ecludedJoints()
/// 4/11/2019 as of this date, this function has been modified to include an error message if the Kinect is unplugged
/// when the application is run AND an event handler was added to the KinectSensor Status, so if the Kinect's status
/// changes during runtime, the program closes (such as if it's unplugged during execution)
private void WindowLoaded(object sender, RoutedEventArgs e)
{
// Create the DrawingGroup will be used for drawing
this.drawingGroup = new DrawingGroup();
// Create an ImageSource that can be used in our image control
this.imageSource = new DrawingImage(this.drawingGroup);
// Display the drawing using the ImageSource
Image.Source = this.imageSource;
//Sets up the excludedJoints list, which are all the joints that will not be drawn
//This will keep these joints from being drawn
excludedJoints.Add(JointType.FootLeft);
excludedJoints.Add(JointType.FootRight);
excludedJoints.Add(JointType.Spine);
excludedJoints.Add(JointType.HandLeft);
excludedJoints.Add(JointType.HandRight);
excludedJoints.Add(JointType.HipLeft);
excludedJoints.Add(JointType.HipRight);
// Look through all sensors and start the first connected one.
// This requires that a Kinect is connected at the time of app startup.
foreach (var potentialSensor in KinectSensor.KinectSensors)
{
if (potentialSensor.Status == KinectStatus.Connected)
{
this.sensor = potentialSensor;
break;
}
}
//Event handler added to detect if the status of the sensor changes during runtime
KinectSensor.KinectSensors.StatusChanged += KinectSensors_StatusChanged;
if (null != this.sensor)
{
// Turns on the skeleton stream to receive skeleton frames
this.sensor.SkeletonStream.Enable();
// Adds an event handler to be called whenever there is new color frame data
this.sensor.SkeletonFrameReady += this.SensorSkeletonFrameReady;
// Starts the sensor
try
{
this.sensor.Start();
}
catch (IOException)
{
this.sensor = null;
}
}
if (null == this.sensor) //if the sensor is NOT detected
{
this.ErrorGrid.Visibility = Visibility.Visible;
this.HomeButtons.Visibility = Visibility.Collapsed;
this.HomeButtons.IsEnabled = false;
}
}
///
/// Built-in event handler for the KinectSensor status to throw an exception if
/// the status of the Kinect changes during runtime
/// Added by Camille Jacobson
///
///
///
private void KinectSensors_StatusChanged(object sender, StatusChangedEventArgs e)
{
throw new NotImplementedException();
}
///
/// Execute shutdown tasks
///
/// object sending the event
/// event arguments
/// 2/19/2019 as of this date, this function has not been modified
private void WindowClosing(object sender, System.ComponentModel.CancelEventArgs e)
{
if (null != this.sensor)
{
this.sensor.Stop();
}
}
///
/// Event handler for Kinect sensor's SkeletonFrameReady event
///
/// object sending the event
/// event arguments
/// What I Have Changed As of 2/19/2019:
/// -Added a new Skeleton object (skeleton)
/// -Called drawOwnSkel with that new Skeleton object
/// -Added a second condition to "if" statement in the "foreach" loop
/// to check for "inFreestyle"
///What I Changed As of 4/11/2019
///- Moved the call to RenderClippedEdges() to prevent these from being detected once a user steps out of bounds
///when the skeleton is even being drawn to screen (since skeletons are still being detected despite not being drawn)
private void SensorSkeletonFrameReady(object sender, SkeletonFrameReadyEventArgs e)
{
Skeleton[] skeletons = new Skeleton[0];
using (SkeletonFrame skeletonFrame = e.OpenSkeletonFrame())
{
if (skeletonFrame != null)
{
skeletons = new Skeleton[skeletonFrame.SkeletonArrayLength];
skeletonFrame.CopySkeletonDataTo(skeletons);
}
}
using (DrawingContext dc = this.drawingGroup.Open())
{
// Draw a transparent background to set the render size
dc.DrawRectangle(Brushes.Black, null, new Rect(0.0, 0.0, RenderWidth, RenderHeight));
if (skeletons.Length != 0)
{
foreach (Skeleton skel in skeletons)
{
if (skel.TrackingState == SkeletonTrackingState.Tracked && (inFreestyle == true || inMove == true))
{
RenderClippedEdges(skel, dc);
this.DrawBonesAndJoints(skel, dc);
}
else if (skel.TrackingState == SkeletonTrackingState.PositionOnly)
{
dc.DrawEllipse(
this.centerPointBrush,
null,
this.SkeletonPointToScreen(skel.Position),
BodyCenterThickness,
BodyCenterThickness);
}
}
}
// prevent drawing outside of the render area
this.drawingGroup.ClipGeometry = new RectangleGeometry(new Rect(0.0, 0.0, RenderWidth, RenderHeight));
}
}
//These variables are used for Bust A Move and InitializeMoveMaking()
private bool allIn = false;
private bool leftWIn = false;
private bool rightWIn = false;
private bool leftFIn = false;
private bool rightFIn = false;
private bool headIn = false;
///
/// Draws a skeleton's bones and joints (Included by Microsoft, modified by Camille Jacobson)
///
/// skeleton to draw
/// drawing context to draw to
/// What I Have Changed As of 2/19/2019:
/// -Commented out hand drawings
/// -Tested code at end of function
/// What I Have Changed As of 4/14/2019
/// -Eliminated calls to DrawBone() that would've drawn excludedJoints
/// -Eliminated calls to DrawEllipse() that would've drawn excludedJoints
/// -Added a check to see if inMove so that it can call InitializeMoveMaking()
/// every time a skeleton is drawn
private void DrawBonesAndJoints(Skeleton skeleton, DrawingContext drawingContext)
{
// Torso
this.DrawBone(skeleton, drawingContext, JointType.Head, JointType.ShoulderCenter);
this.DrawBone(skeleton, drawingContext, JointType.ShoulderCenter, JointType.ShoulderLeft);
this.DrawBone(skeleton, drawingContext, JointType.ShoulderCenter, JointType.ShoulderRight);
this.DrawBone(skeleton, drawingContext, JointType.ShoulderCenter, JointType.HipCenter);
// Left Arm
this.DrawBone(skeleton, drawingContext, JointType.ShoulderLeft, JointType.ElbowLeft);
this.DrawBone(skeleton, drawingContext, JointType.ElbowLeft, JointType.WristLeft);
// Right Arm
this.DrawBone(skeleton, drawingContext, JointType.ShoulderRight, JointType.ElbowRight);
this.DrawBone(skeleton, drawingContext, JointType.ElbowRight, JointType.WristRight);
// Left Leg
this.DrawBone(skeleton, drawingContext, JointType.HipCenter, JointType.KneeLeft);
this.DrawBone(skeleton, drawingContext, JointType.KneeLeft, JointType.AnkleLeft);
// Right Leg
this.DrawBone(skeleton, drawingContext, JointType.HipCenter, JointType.KneeRight);
this.DrawBone(skeleton, drawingContext, JointType.KneeRight, JointType.AnkleRight);
// Render Joints
foreach (Joint joint in skeleton.Joints)
{
Brush drawBrush = null;
if (joint.TrackingState == JointTrackingState.Tracked)
{
foreach(JointType jointType in excludedJoints)
{
if (!excludedJoints.Contains(joint.JointType))
{
drawBrush = this.trackedJointBrush;
}
}
}
//Inferred joints are the Kinect guessing where that joint is if it cannot immediately tell
//I allow joints to still be drawn in this way as a guide to the user as to why their movements might
// look odd on the playback
else if (joint.TrackingState == JointTrackingState.Inferred)
{
foreach (JointType jointType in excludedJoints)
{
if (!excludedJoints.Contains(joint.JointType))
{
drawBrush = this.inferredJointBrush;
}
}
}
if (drawBrush != null)
{
drawingContext.DrawEllipse(drawBrush, null, this.SkeletonPointToScreen(joint.Position), JointThickness, JointThickness);
}
}
// if inMove, test to see if the skeleton is lined up with the correct circles
if (inMove)
{
InitializeMoveMaking(skeleton, drawingContext);
}
}
private int MoveCount;
///
/// Writes the data stored in each list in the array skelPoints
/// to its respective file.
/// NOTE: The file names are matched up with the order in which the JointType is enumerated, so
/// files and their respective list in the array match up.
///
/// Array of lists for each tracked JointType in the skeleton
///
private void WritingJointsToFile(List[] skelPoints, DrawingContext drawingContext)
{
/*Code for creating directories and files found on:
* https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/file-system/how-to-create-a-file-or-folder
* */
MoveCount = System.IO.Directory.GetDirectories(System.IO.Path.Combine(filePathShort, "SavedMoves")).Length;
MoveCount++;
string originalFolder = System.IO.Path.Combine(filePathShort, "SavedMoves");
string newSubDirectory = System.IO.Path.Combine(originalFolder, MoveCount.ToString());
string savedDirectory = System.IO.Path.Combine(System.IO.Path.Combine(filePathShort, "SavedMoves"),MoveCount.ToString());
System.IO.Directory.CreateDirectory(newSubDirectory);
string[] fileNames = {"HipCenter.txt", "ShoulderCenter.txt", "Head.txt", "ShoulderLeft.txt", "ElbowLeft.txt",
"WristLeft.txt", "ShoulderRight.txt", "ElbowRight.txt", "WristRight.txt", "KneeLeft.txt",
"AnkleLeft.txt", "KneeRight.txt", "AnkleRight.txt" };
newSubDirectory = savedDirectory;
for (int j=0; j<13; j++)
{
using (System.IO.StreamWriter file = new System.IO.StreamWriter(System.IO.Path.Combine(savedDirectory, fileNames[j]), true))
{
foreach (SkeletonPoint skelPoint in skelPoints[j])
{
file.WriteLine(skelPoint.X + " " + skelPoint.Y + " " + skelPoint.Z + " ");
}
}
newSubDirectory = savedDirectory;
}
//get rid of the 5 circles and set up the message telling the user their dance move was recorded
this.LeftHandButton.Visibility = Visibility.Collapsed;
this.LeftHandButton.IsEnabled = false;
this.RightHandButton.Visibility = Visibility.Collapsed;
this.RightHandButton.IsEnabled = false;
this.RightFootButton.Visibility = Visibility.Collapsed;
this.RightFootButton.IsEnabled = false;
this.HeadButton.Visibility = Visibility.Collapsed;
this.HeadButton.IsEnabled = false;
this.LeftFootButton.Visibility = Visibility.Collapsed;
this.LeftFootButton.IsEnabled = false;
this.BustMoveGrid.Visibility = Visibility.Visible;
this.BustMoveGrid.IsEnabled = true;
this.ImageViewbox.Visibility = Visibility.Collapsed;
}
private static int activatedCount = 0;
private static int frameCount = 0;
//Lists of Positions of each JointType, will be filled in InitializeMoveMaking()
private static List leftWristPoints = new List();
private static List rightWristPoints = new List();
private static List hipCenterPoints = new List();
private static List headPoints = new List();
private static List leftAnklePoints = new List();
private static List rightAnklePoints = new List();
private static List leftElbowPoints = new List();
private static List rightElbowPoints = new List();
private static List leftShoulderPoints = new List();
private static List rightShoulderPoints = new List();
private static List shoulderCenterPoints = new List();
private static List leftKneePoints = new List();
private static List rightKneePoints = new List();
private static List[] allPoints = new List[13];
///
/// This function checks to see if a user is standing in the correct spot for the correct amount of time.
/// If they are, the data for each joint is recorded (10 frames per second) and stored in a List.
/// These lists are then placed in the List Array allPoints to be written to files in WritingJointsToFile()
///
/// Skeleton object that is sent in to begin tracking the movements of the user
///
private void InitializeMoveMaking(Skeleton skeleton, DrawingContext drawingContext)
{
Joint leftWrist = skeleton.Joints[JointType.WristLeft];
Joint rightWrist = skeleton.Joints[JointType.WristRight];
Joint hipCenter = skeleton.Joints[JointType.HipCenter];
Joint leftKnee = skeleton.Joints[JointType.KneeLeft];
Joint rightKnee = skeleton.Joints[JointType.KneeRight];
Joint leftAnkle = skeleton.Joints[JointType.AnkleLeft];
Joint rightAnkle = skeleton.Joints[JointType.AnkleRight];
Joint shoulderCenter = skeleton.Joints[JointType.ShoulderCenter];
Joint head = skeleton.Joints[JointType.Head];
Joint leftShoulder = skeleton.Joints[JointType.ShoulderLeft];
Joint leftElbow = skeleton.Joints[JointType.ElbowLeft];
Joint rightShoulder = skeleton.Joints[JointType.ShoulderRight];
Joint rightElbow = skeleton.Joints[JointType.ElbowRight];
//checking to see if the correct body parts are in the correct coordinate ranges for the circles
leftWIn = LockedInPlace(leftWrist);
rightWIn = LockedInPlace(rightWrist);
headIn = LockedInPlace(head);
leftFIn = LockedInPlace(leftAnkle);
rightFIn = LockedInPlace(rightAnkle);
//if EVERYTHING is in order, start tracking how many frames (so, how long) they are in that position
//If they leave the "locking in" position before a dance starts, they need to start over with trying to lock in
//They need to be there for 2 seconds (60 frames) to start
if (leftWIn && rightWIn && headIn && leftFIn && rightFIn) //If EVERYTHING is in place, start counting
{
activatedCount++;
if (activatedCount >= 60) //if they have stood in position for at least 2 seconds
{
activatedCount = 0;
if (allIn) //if they are done dancing and standing in the initial position, stop recording data and get ready to write to files
{
allIn = false;
allPoints[0] = hipCenterPoints;
allPoints[1] = shoulderCenterPoints;
allPoints[2] = headPoints;
allPoints[3] = leftShoulderPoints;
allPoints[4] = leftElbowPoints;
allPoints[5] = leftWristPoints;
allPoints[6] = rightShoulderPoints;
allPoints[7] = rightElbowPoints;
allPoints[8] = rightWristPoints;
allPoints[9] = leftKneePoints;
allPoints[10] = leftAnklePoints;
allPoints[11] = rightKneePoints;
allPoints[12] = rightAnklePoints;
WritingJointsToFile(allPoints, drawingContext);
return;
}
else //if they in initial position to start the dance, then they are marked as all in and dance moves start being recorded
{
allIn = true;
this.RightHandButton.Fill = Brushes.Lime;
this.RightHandButton.Opacity = 1d;
this.LeftHandButton.Fill = Brushes.Lime;
this.LeftHandButton.Opacity = 1d;
this.HeadButton.Fill = Brushes.Lime;
this.HeadButton.Opacity = 1d;
this.LeftFootButton.Fill = Brushes.Lime;
this.LeftFootButton.Opacity = 1d;
this.RightFootButton.Fill = Brushes.Lime;
this.RightFootButton.Opacity = 1d;
}
}
}
else //else if not in initial position, start activatedCount over
{
activatedCount = 0;
}
if (allIn) //for when you are no longer in the circles and now recording
{
frameCount++;
if (frameCount == 3) //counting every 3rd frame and recording it
{
hipCenterPoints.Add(hipCenter.Position);
shoulderCenterPoints.Add(shoulderCenter.Position);
headPoints.Add(head.Position);
leftShoulderPoints.Add(leftShoulder.Position);
leftElbowPoints.Add(leftElbow.Position);
leftWristPoints.Add(leftWrist.Position);
rightShoulderPoints.Add(rightShoulder.Position);
rightElbowPoints.Add(rightElbow.Position);
rightWristPoints.Add(rightWrist.Position);
leftKneePoints.Add(leftKnee.Position);
leftAnklePoints.Add(leftAnkle.Position);
rightKneePoints.Add(rightKnee.Position);
rightAnklePoints.Add(rightAnkle.Position);
frameCount = 0;
}
}
}
///
/// This function exists to improve the functionality of InitializeMoveMaking() and adding modularity
/// to this program. This function checks to see if the correct joints are in the correct place
/// (relative to their circles).
/// The function takes a Joint object and verifies that it is the correct type before checking it against
/// the correct location of the "lock in" circles.
///
/// This parameter allows for the function to be applied to all 5 joints that are being checked.
/// This function returns true or false depending on whether the joints are lined up with the circles.
/// These values are then stored in the corresponding bool variables: leftWIn, rightWIn, headIn, leftFIn, rightFIn
/// based on how InitializeMoveMaking() calls this function for each joint
/// NOTE: A user has to be between 1.9 and 2.5 meters for this
private bool LockedInPlace(Joint joint)
{
//handling the Left Wrist
Brush circleFillTeal = new SolidColorBrush(Color.FromArgb(255, 52, 218, 185));
if (joint.JointType == JointType.WristLeft)
{
if((joint.Position.X < -0.15 && joint.Position.X > -0.45) && (joint.Position.Y < 0.23 && joint.Position.Y > -0.05) && (joint.Position.Z < 2.5 && joint.Position.Z > 1.9))
{
this.LeftHandButton.Fill = Brushes.LightGray;
this.LeftHandButton.Opacity = .50d;
return true;
}
else
{
if (allIn)
{
this.LeftHandButton.Fill = Brushes.Lime;
this.LeftHandButton.Opacity = 1d;
}
else
{
this.LeftHandButton.Fill = circleFillTeal;
this.LeftHandButton.Opacity = 1d;
}
return false;
}
}
// handling the Right Wrist
else if (joint.JointType == JointType.WristRight)
{
if ((joint.Position.X > 0.20 && joint.Position.X < 0.36) && (joint.Position.Y < 0.23 && joint.Position.Y > -0.05) && (joint.Position.Z < 2.5 && joint.Position.Z > 1.9))
{
this.RightHandButton.Fill = Brushes.LightGray;
this.RightHandButton.Opacity = .50d;
return true;
}
else
{
if (allIn)
{
this.RightHandButton.Fill = Brushes.Lime;
this.RightHandButton.Opacity = 1d;
}
else
{
this.RightHandButton.Fill = circleFillTeal;
this.RightHandButton.Opacity = 1d;
}
return false;
}
}
//handling the Head
else if (joint.JointType == JointType.Head)
{
if ((joint.Position.X < 0.06 && joint.Position.X > -0.06) && (joint.Position.Y < 1.0 && joint.Position.Y > 0.60) && (joint.Position.Z < 2.5 && joint.Position.Z > 1.9))
{
this.HeadButton.Fill = Brushes.LightGray;
this.HeadButton.Opacity = .50d;
return true;
}
else
{
if (allIn)
{
this.HeadButton.Fill = Brushes.Lime;
this.HeadButton.Opacity = 1d;
}
else
{
this.HeadButton.Fill = circleFillTeal;
this.HeadButton.Opacity = 1d;
}
return false;
}
}
//handling the Left Ankle
else if(joint.JointType == JointType.AnkleLeft)
{
if ((joint.Position.X < -0.14 && joint.Position.X > -0.40) && (joint.Position.Y < -.52 && joint.Position.Y > -.73) && (joint.Position.Z < 2.5 && joint.Position.Z > 1.9))
{
this.LeftFootButton.Fill = Brushes.LightGray;
this.LeftFootButton.Opacity = .50d;
return true;
}
else
{
if (allIn)
{
this.LeftFootButton.Fill = Brushes.Lime;
this.LeftFootButton.Opacity = 1d;
}
else
{
this.LeftFootButton.Fill = circleFillTeal;
this.LeftFootButton.Opacity = 1d;
}
return false;
}
}
//handline the Right Ankle
else if (joint.JointType == JointType.AnkleRight)
{
if ((joint.Position.X < 0.25 && joint.Position.X > 0.07) && (joint.Position.Y < -.52 && joint.Position.Y > -0.73) && (joint.Position.Z < 2.5 && joint.Position.Z > 1.9))
{
this.RightFootButton.Fill = Brushes.LightGray;
this.RightFootButton.Opacity = .50d;
return true;
}
else
{
if (allIn)
{
this.RightFootButton.Fill = Brushes.Lime;
this.RightFootButton.Opacity = 1d;
}
else
{
this.RightFootButton.Fill = circleFillTeal;
this.RightFootButton.Opacity = 1d;
}
return false;
}
}
return false;
}
///
/// Maps a SkeletonPoint to lie within our render space and converts to Point
/// Created by Microsoft
///
/// point to map
/// mapped point
/// 2/19/2019 as of this date, this function has not been modified, even the documentation
private Point SkeletonPointToScreen(SkeletonPoint skelpoint)
{
// Convert point to depth space.
// We are not using depth directly, but we do want the points in our 640x480 output resolution.
DepthImagePoint depthPoint = this.sensor.CoordinateMapper.MapSkeletonPointToDepthPoint(skelpoint, DepthImageFormat.Resolution640x480Fps30);
return new Point(depthPoint.X, depthPoint.Y);
}
///
/// Draws a bone line between two joints
///
/// skeleton to draw bones from
/// drawing context to draw to
/// joint to start drawing from
/// joint to end drawing at
/// 2/19/2019 as of this date, this function has not been modified
/// 4/14/2019 as of this date, I added checks for inFreestyle and inMove to change
/// the color of the skeleton being drawn in those modes. I maintained the idea of the inferred
/// joints to allow the user to understand how their movements may be deemed eratic (since the program
/// is guessing where some joints are)
private void DrawBone(Skeleton skeleton, DrawingContext drawingContext, JointType jointType0, JointType jointType1)
{
Joint joint0 = skeleton.Joints[jointType0];
Joint joint1 = skeleton.Joints[jointType1];
// If we can't find either of these joints, exit
if (joint0.TrackingState == JointTrackingState.NotTracked ||
joint1.TrackingState == JointTrackingState.NotTracked)
{
return;
}
// Don't draw if both points are inferred
if (joint0.TrackingState == JointTrackingState.Inferred &&
joint1.TrackingState == JointTrackingState.Inferred)
{
return;
}
// We assume all drawn bones are inferred unless BOTH joints are tracked
Pen drawPen = this.inferredBonePen;
if (joint0.TrackingState == JointTrackingState.Tracked && joint1.TrackingState == JointTrackingState.Tracked)
{
if (inMove)
{
if (!allIn)
{
drawPen = this.allInPen;
}
else
{
drawPen = this.movePen;
}
}
else if (inFreestyle)
{
drawPen = this.freestylePen;
}
}
drawingContext.DrawLine(drawPen, this.SkeletonPointToScreen(joint0.Position), this.SkeletonPointToScreen(joint1.Position));
}
}
}