using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;

namespace KinectCar
{
    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Windows;
    using Microsoft.Kinect;
    using uPLibrary.Networking.M2Mqtt;
    using System.Net;
    using uPLibrary.Networking.M2Mqtt.Messages;
    using System.Text;

    /// <summary>       
    /// MainWindow.xaml 的交互逻辑
    /// </summary>
    public partial class MainWindow : INotifyPropertyChanged
    {

        private bool open1 = false;   //右手经过点位一
        private bool open1a = false;
        private bool open2 = false;  //右手经过点位二
        private bool open2a = false;
        private bool open3 = false;  //左手经过点位一
        private bool open3a = false;
        private bool open4 = false;  //左手经过点位二
        private bool open4a = false;
        private int Count = 1;
        // 活动的 Kinect 传感器
        private KinectSensor _kinectSensor = null;
        // 坐标映射器将一种类型的点映射到另一种
        private CoordinateMapper _coordinateMapper = null;
        // 身体框架渲染器
        private BodyFrameReader _bodyFrameReader = null;
        // 颜色框架渲染器
        private ColorFrameReader _colorFrameReader = null;
        // 身体的数组
        private Body[] _bodies = null;
        // 骨骼的定义
        private List<Tuple<JointType, JointType>> _bones;
        // 追踪的每个身体的颜色列表
        private List<Pen> _bodyColors;
        // 用于体绘制输出的绘图组
        private DrawingGroup _drawingGroup;
        // 显示的绘图图像
        private DrawingImage _imageSource;
        // 显示宽度，高度（深度空间）
        private int _displayWidth, _displayHeight;
        // 绘制的手圆半径
        private const double HandSize = 30;
        // 绘制接合线的厚度
        private const double JointThickness = 3;
        // 夹边矩形的厚度
        private const double ClipBoundsThickness = 10;
        // 将相机空间点的Z值从负值夹持的常量
        private const float InferredZPositionClamp = 0.1f;
        // 用于绘制当前跟踪为闭合的手的画笔
        private readonly Brush _handClosedBrush = new SolidColorBrush(Color.FromArgb(128, 255, 0, 0));
        // 用于绘制当前跟踪为打开状态的手的画笔
        private readonly Brush _handOpenBrush = new SolidColorBrush(Color.FromArgb(128, 0, 255, 0));
        // 用于绘制当前在套索（指针）位置跟踪的手的画笔
        private readonly Brush _handLassoBrush = new SolidColorBrush(Color.FromArgb(128, 0, 0, 255));
        // 用于绘制当前跟踪的关节的画笔
        private readonly Brush _trackedJointBrush = new SolidColorBrush(Color.FromArgb(255, 68, 192, 68));
        // 用于绘制当前推断的关节的画笔     
        private readonly Brush _inferredJointBrush = Brushes.Yellow;
        // 用于绘制当前推断的骨骼的笔      
        private readonly Pen _inferredBonePen = new Pen(Brushes.Gray, 1);
        // 要显示的当前状态文本
        private string _statusText;
        // 要显示的提示文本
        private string _tipText;
        // 阈值（1/2框）（单位：米）
        private const float Threshold = 0.15f;
        // 当前状态
        private int _gesture = -1;
        // Bitmap to display
        private WriteableBitmap _colorBitmap;

        private static string MQTT_BROKER_ADDRESS = "123.207.151.92";
        // 创建客户端实例
        MqttClient _client = new MqttClient(IPAddress.Parse(MQTT_BROKER_ADDRESS), 1600, false, null, null, MqttSslProtocols.None); // 主机为IP时

        // INotifyPropertyChangedPropertyChanged 事件允许窗口控件绑定到可更改的数据
        public event PropertyChangedEventHandler PropertyChanged;

        public string StatusText
        {
            get
            {
                return _statusText;
            }

            set
            {
                if (_statusText == value) return;
                _statusText = value;
                // 通知任何绑定元素文本已更改
                PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("StatusText"));
            }
        }

        public string TipText
        {
            get
            {
                return _tipText;
            }

            set
            {
                if (_tipText == value) return;
                _tipText = value;
                // 通知任何绑定元素文本已更改
                PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("TipText"));
            }
        }

        public MainWindow()
        {
            // 目前支持一个传感器
            _kinectSensor = KinectSensor.GetDefault();
            // 获取坐标映射器
            _coordinateMapper = _kinectSensor.CoordinateMapper;
            // 获取深度（显示）范围
            var frameDescription = _kinectSensor.DepthFrameSource.FrameDescription;
            // 得到关节空间的大小
            _displayWidth = frameDescription.Width;
            _displayHeight = frameDescription.Height;
            // 打开身体框架的渲染器
            _bodyFrameReader = _kinectSensor.BodyFrameSource.OpenReader();
            // 打开颜色框架的渲染器
            _colorFrameReader = _kinectSensor.ColorFrameSource.OpenReader();
            // 设置数据回调
            if (_bodyFrameReader != null)
            {
                _bodyFrameReader.FrameArrived += Reader_FrameArrived;
            }
            if (_colorFrameReader != null)
            {
                _colorFrameReader.FrameArrived += Reader_ColorFrameArrived;
            }
            // 利用 BGRA 格式创建颜色描述来自颜色来源
            var colorFrameDescription = _kinectSensor.ColorFrameSource.CreateFrameDescription(ColorImageFormat.Bgra);
            // 创建要显示的位图
            _colorBitmap = new WriteableBitmap(colorFrameDescription.Width, colorFrameDescription.Height, 96.0, 96.0, PixelFormats.Bgr32, null);
            // 
            // populate body colors, one for each BodyIndex
            _bodyColors = new List<Pen>
            {
                new Pen(Brushes.Red, 6),
                new Pen(Brushes.Orange, 6),
                new Pen(Brushes.Green, 6),
                new Pen(Brushes.Blue, 6),
                new Pen(Brushes.Indigo, 6),
                new Pen(Brushes.Violet, 6)
            };
            // 创建将用于绘图的绘图组
            _drawingGroup = new DrawingGroup();
            // 创建可以在图像控件中使用的图像源
            _imageSource = new DrawingImage(_drawingGroup);
            // 设置 IsAvailableChanged 事件通知程序
            _kinectSensor.IsAvailableChanged += Sensor_IsAvailableChanged;
            // 打开传感器
            _kinectSensor.Open();

            // 骨骼定义为两个关节之间的线
            _bones = new List<Tuple<JointType, JointType>>
            {
                // 躯干
                new Tuple<JointType, JointType>(JointType.Head, JointType.Neck),
                new Tuple<JointType, JointType>(JointType.Neck, JointType.SpineShoulder),
                new Tuple<JointType, JointType>(JointType.SpineShoulder, JointType.SpineMid),
                new Tuple<JointType, JointType>(JointType.SpineMid, JointType.SpineBase),
                new Tuple<JointType, JointType>(JointType.SpineShoulder, JointType.ShoulderRight),
                new Tuple<JointType, JointType>(JointType.SpineShoulder, JointType.ShoulderLeft),
                new Tuple<JointType, JointType>(JointType.SpineBase, JointType.HipRight),
                new Tuple<JointType, JointType>(JointType.SpineBase, JointType.HipLeft),
                // 右臂
                new Tuple<JointType, JointType>(JointType.ShoulderRight, JointType.ElbowRight),
                new Tuple<JointType, JointType>(JointType.ElbowRight, JointType.WristRight),
                new Tuple<JointType, JointType>(JointType.WristRight, JointType.HandRight),
                new Tuple<JointType, JointType>(JointType.HandRight, JointType.HandTipRight),
                new Tuple<JointType, JointType>(JointType.WristRight, JointType.ThumbRight),
                // 左臂
                new Tuple<JointType, JointType>(JointType.ShoulderLeft, JointType.ElbowLeft),
                new Tuple<JointType, JointType>(JointType.ElbowLeft, JointType.WristLeft),
                new Tuple<JointType, JointType>(JointType.WristLeft, JointType.HandLeft),
                new Tuple<JointType, JointType>(JointType.HandLeft, JointType.HandTipLeft),
                new Tuple<JointType, JointType>(JointType.WristLeft, JointType.ThumbLeft),
                // 右腿
                new Tuple<JointType, JointType>(JointType.HipRight, JointType.KneeRight),
                new Tuple<JointType, JointType>(JointType.KneeRight, JointType.AnkleRight),
                new Tuple<JointType, JointType>(JointType.AnkleRight, JointType.FootRight),
                // 左腿
                new Tuple<JointType, JointType>(JointType.HipLeft, JointType.KneeLeft),
                new Tuple<JointType, JointType>(JointType.KneeLeft, JointType.AnkleLeft),
                new Tuple<JointType, JointType>(JointType.AnkleLeft, JointType.FootLeft)
            };

            // 设置状态文本
            StatusText = _kinectSensor.IsAvailable ? Properties.Resources.RunningStatusText : Properties.Resources.NoSensorStatusText;
            // 在这个简单的例子中使用window对象作为视图模型
            DataContext = this;
            // 初始化窗口的组件（控件）
            InitializeComponent();
        }

        private void Window_Loaded(object sender, RoutedEventArgs e)
        {
            // 注册消息接收处理事件，还可以注册消息订阅成功、取消订阅成功、与服务器断开等事件处理函数
            _client.MqttMsgPublishReceived += ClientMqttMsgPublishReceived;
            //生成客户端 ID 并连接服务器
            var clientId = Guid.NewGuid().ToString();
            _client.Connect(clientId, "yumin", "minbb.cn");
            // 订阅主题"" 消息质量为 2
            _client.Subscribe(new string[] { Const.MQTT_TOPIC_CAR }, new byte[] { MqttMsgBase.QOS_LEVEL_EXACTLY_ONCE });
            // 发布消息到主题 "wifi/car" 消息质量为 2,不保留
            _client.Publish(Const.MQTT_TOPIC_CAR, Encoding.UTF8.GetBytes("I'm C# Client."), MqttMsgBase.QOS_LEVEL_EXACTLY_ONCE, false);
        }

        private void Window_Closing(object sender, CancelEventArgs e)
        {
            if (_bodyFrameReader != null)
            {
                _bodyFrameReader.Dispose();
                _bodyFrameReader = null;
            }

            if (_colorFrameReader != null)
            {
                _colorFrameReader.Dispose();
                _colorFrameReader = null;
            }

            if (_kinectSensor != null)
            {
                _kinectSensor.Close();
                _kinectSensor = null;
            }

            _client?.Disconnect();
        }

        private void ClientMqttMsgPublishReceived(object sender, MqttMsgPublishEventArgs e)
        {
            //处理接收到的消息
            string msg = Encoding.Default.GetString(e.Message);
            Console.WriteLine("收到消息 = " + msg + "\r\n");
        }

        private void Reader_FrameArrived(object sender, BodyFrameArrivedEventArgs e)
        {
            var dataReceived = false;
            using (var bodyFrame = e.FrameReference.AcquireFrame())
            {
                if (bodyFrame != null)
                {
                    if (_bodies == null)
                    {
                        _bodies = new Body[bodyFrame.BodyCount];
                    }
                    // 第一次调用 GetAndRefreshBodyData 时，Kinect 将在数组中分配每个 Body。只要这些主体对象没有被释放并且在数组中没有设置为 null，那么这些主体对象将被重用。
                    bodyFrame.GetAndRefreshBodyData(_bodies);
                    dataReceived = true;
                }
            }
            // 所有工作
            if (dataReceived)
            {
                // 绘制
                using (var dc = _drawingGroup.Open())
                {
                    // 绘制透明背景以设置渲染大小
                    dc.DrawRectangle(Brushes.Transparent, null, new Rect(0.0, 0.0, _displayWidth, _displayHeight));
                    // 画一个透明背景设置渲染的大小（绘制矩形，透明背景）
                    //dc.DrawRectangle(new SolidColorBrush(Color.FromArgb(0, 0, 0, 0)), null, new Rect(0.0, 0.0, _displayWidth, _displayHeight));

                    var penIndex = 0;
                    foreach (var body in _bodies)
                    {
                        var drawPen = _bodyColors[penIndex++];
                        if (body.IsTracked)
                        {
                            DrawClippedEdges(body, dc);
                            IReadOnlyDictionary<JointType, Joint> joints = body.Joints;
                            // 将关节点转换为深度（显示）空间
                            var jointPoints = new Dictionary<JointType, Point>();
                            foreach (JointType jointType in joints.Keys)
                            {
                                // 有时，推断接缝的深度（z）可能显示为负值。
                                // clamp down to 0.1f to prevent coordinatemapper from returning (-Infinity, -Infinity)
                                CameraSpacePoint position = joints[jointType].Position;
                                if (position.Z < 0)
                                {
                                    position.Z = InferredZPositionClamp;
                                }
                                var depthSpacePoint = _coordinateMapper.MapCameraPointToDepthSpace(position);
                                jointPoints[jointType] = new Point(depthSpacePoint.X, depthSpacePoint.Y);
                            }
                            DrawBody(joints, jointPoints, dc, drawPen);
                            DrawHand(body.HandLeftState, jointPoints[JointType.HandLeft], dc);
                            DrawHand(body.HandRightState, jointPoints[JointType.HandRight], dc);

                            StatusText = "追踪到身体";
                            // 右手
                            Joint jointHandRight = joints[JointType.HandRight];
                            // 右肩
                            Joint jointShoulderRight = joints[JointType.ShoulderRight];
                            // 左手
                            Joint jointHandLeft = joints[JointType.HandLeft];
                            // 左肩
                            Joint jointShoulderLeft = joints[JointType.ShoulderLeft];
                            // 脊柱中
                            Joint jointSpineMid = joints[JointType.SpineBase];
                            // 头
                            Joint jointHead = joints[JointType.Head];

                            // 右手空间坐标
                            CameraSpacePoint positionHandRight = jointHandRight.Position;
                            // 左手空间坐标 
                            CameraSpacePoint positionHandLeft = jointHandLeft.Position;
                            // 脊椎中空间坐标
                            CameraSpacePoint positionSpineMid = jointSpineMid.Position;
                            // 头部空间坐标
                            CameraSpacePoint positionHead = jointHead.Position;
                            // 左肩空间坐标
                            CameraSpacePoint positionShoulderLeft = jointShoulderLeft.Position;
                            // 右肩空间坐标
                            CameraSpacePoint positionShoulderRight = jointShoulderRight.Position;

                            // 右手坐标集
                            float xHandRight = positionHandRight.X;
                            float yHandRight = positionHandRight.Y;
                            float zHandRight = positionHandRight.Z;

                            // 左手坐标集
                            float xHandLeft = positionHandLeft.X;
                            float yHandLeft = positionHandLeft.Y;
                            float ZHandLeft = positionHandLeft.Z;

                            // 脊椎中坐标集
                            float xSpineMid = positionSpineMid.X;
                            float ySpineMid = positionSpineMid.Y;
                            float ZSpineMid = positionSpineMid.Z;
                            // 追踪到所需目标。
                            if (body.HandRightState == HandState.Open && body.HandLeftState == HandState.Open)
                            {
                                TipText = "停止";
                                //Console.WriteLine("stop");
                                _client.Publish(Const.MQTT_TOPIC_CAR_CTRL, Encoding.UTF8.GetBytes("0"), MqttMsgBase.QOS_LEVEL_EXACTLY_ONCE, false);
                            }
                            //前进逻辑
                            if (Count % 2 == 1)
                            {
                                // 控制汽车逻辑
                                if (body.HandRightState == HandState.Closed && body.HandLeftState == HandState.Closed)
                                {
                                    // 角度计算
                                    var value = Math.Atan2((yHandRight - yHandLeft), (xHandRight - xHandLeft)) * 180 / Math.PI;

                                    if (20 > value && value > -20)
                                    {
                                        TipText = "前进";
                                        Console.WriteLine("go");
                                        _client.Publish(Const.MQTT_TOPIC_CAR_CTRL, Encoding.UTF8.GetBytes("8"), MqttMsgBase.QOS_LEVEL_EXACTLY_ONCE, false);

                                    }
                                    // 右高左低 
                                    if (20 < value && value < 90)
                                    {
                                        TipText = "左前方行驶";
                                        Console.WriteLine("left");
                                        _client.Publish(Const.MQTT_TOPIC_CAR_CTRL, Encoding.UTF8.GetBytes("4"), MqttMsgBase.QOS_LEVEL_EXACTLY_ONCE, false);

                                    }
                                    //  左高右低
                                    if (-90 < value && value < -20)
                                    {
                                        TipText = "右前方行驶";
                                        Console.WriteLine("rightt");
                                        _client.Publish(Const.MQTT_TOPIC_CAR_CTRL, Encoding.UTF8.GetBytes("6"), MqttMsgBase.QOS_LEVEL_EXACTLY_ONCE, false);
                                    }
                                }

                            }
                            //后退逻辑
                            if (Count % 2 == 0)
                            {
                                // 控制汽车逻辑
                                if (body.HandRightState == HandState.Closed && body.HandLeftState == HandState.Closed)
                                {

                                    var value = Math.Atan2((yHandRight - yHandLeft), (xHandRight - xHandLeft)) * 180 / Math.PI;

                                    if (20 > value && value > -20)
                                    {
                                        TipText = "后退";
                                        Console.WriteLine("brak");
                                        _client.Publish(Const.MQTT_TOPIC_CAR_CTRL, Encoding.UTF8.GetBytes("2"), MqttMsgBase.QOS_LEVEL_EXACTLY_ONCE, false);

                                    }
                                    // 右高左低 
                                    if (20 < value && value < 90)
                                    {
                                        TipText = "左方行驶";
                                        _client.Publish(Const.MQTT_TOPIC_CAR_CTRL, Encoding.UTF8.GetBytes("4"), MqttMsgBase.QOS_LEVEL_EXACTLY_ONCE, false);

                                    }
                                    // 左高右低
                                    if (-90 < value && value < -20)
                                    {
                                        TipText = "右方行驶";
                                        _client.Publish(Const.MQTT_TOPIC_CAR_CTRL, Encoding.UTF8.GetBytes("6"), MqttMsgBase.QOS_LEVEL_EXACTLY_ONCE, false);
                                    }
                                }
                            }
                            // 麦克风管理
                            if (jointHead.TrackingState == TrackingState.Tracked
                               && jointHandRight.TrackingState == TrackingState.Tracked
                               && jointShoulderLeft.TrackingState == TrackingState.Tracked
                               && jointShoulderRight.TrackingState == TrackingState.Tracked)
                            {
                                if (positionHandRight.Y > positionHead.Y)
                                {
                                    // Console.WriteLine("举过头顶");
                                    if (positionHandRight.X < positionHead.X && positionHandRight.X > positionShoulderLeft.X)
                                    {
                                        // Console.WriteLine("手在左肩和头之间");
                                        open2 = true;
                                        open2a = true;
                                    }
                                    if (positionHandRight.X > positionShoulderRight.X)
                                    {
                                        // Console.WriteLine("右手在右肩之外");
                                        open1 = true;
                                        open1a = true;
                                    }
                                }

                                if (open1 && open2)
                                {
                                    if (positionHandRight.Y < positionHead.Y)
                                    {
                                        Console.WriteLine("手势合格  ,麦克风打开.键盘输入 下键");
                                        open1 = false;
                                        open2 = false;
                                    }
                                }
                                //Console.WriteLine("X = " + positionHead.X + ", Y = " + positionHead.Y + ", Z = " + positionHead.Z);
                                //Console.WriteLine("X = " + positionHandRight.X + ", Y = " + positionHandRight.Y + ", Z = " + positionHandRight.Z);
                            }

                            //麦克风关闭
                            if (jointHead.TrackingState == TrackingState.Tracked
                                && jointHandLeft.TrackingState == TrackingState.Tracked
                                && jointShoulderLeft.TrackingState == TrackingState.Tracked
                                && jointShoulderRight.TrackingState == TrackingState.Tracked)
                            {
                                if (positionHandLeft.Y > positionHead.Y)
                                {
                                    // Console.WriteLine("举过头顶");
                                    if (positionHead.X < positionHandLeft.X && positionHandLeft.X < positionShoulderRight.X)
                                    {
                                        // Console.WriteLine("左手在右肩与头之间");
                                        open3 = true;
                                        open3a = true;
                                    }
                                    if (positionHandLeft.X < positionShoulderLeft.X)
                                    {
                                        //Console.WriteLine("左手在左肩之外");
                                        open4 = true;
                                        open4a = true;
                                    }
                                }
                                if (open3 && open4)
                                {
                                    if (positionHandLeft.Y < positionHead.Y)
                                    {
                                        Console.WriteLine("手势合格,麦克风关闭. 键盘输入 上键");
                                        open3 = false;
                                        open4 = false;
                                    }
                                }
                                //未使用功能 执行一次开启，再次重复关闭
                                if (open4 && open1)
                                {
                                    if (positionHandLeft.Y < positionHead.Y && positionHandRight.Y < positionHead.Y)
                                    {
                                        if (Count % 2 == 0)
                                        {
                                            Console.WriteLine("未知命令 执行 ");
                                            open4 = false;
                                            open1 = false;
                                            Count++;
                                        }
                                        else
                                        {
                                            Console.WriteLine("未知命令 退出");
                                            open4 = false;
                                            open1 = false;
                                            Count++;
                                        }
                                    }
                                }
                            }
                        }
                    }
                    // 防止在渲染区域之外绘制
                    _drawingGroup.ClipGeometry = new RectangleGeometry(new Rect(0.0, 0.0, _displayWidth, _displayHeight));
                }
            }
            else
            {
                StatusText = "无数据";
            }
        }

        private void Reader_ColorFrameArrived(object sender, ColorFrameArrivedEventArgs e)
        {
            // ColorFrame is IDisposable
            using (var colorFrame = e.FrameReference.AcquireFrame())
            {
                if (colorFrame != null)
                {
                    var colorFrameDescription = colorFrame.FrameDescription;
                    using (var colorBuffer = colorFrame.LockRawImageBuffer())
                    {
                        _colorBitmap.Lock();
                        // 验证数据并将新的颜色框数据写入显示位图
                        if ((colorFrameDescription.Width == _colorBitmap.PixelWidth) && (colorFrameDescription.Height == _colorBitmap.PixelHeight))
                        {
                            colorFrame.CopyConvertedFrameDataToIntPtr(_colorBitmap.BackBuffer,
                                (uint)(colorFrameDescription.Width * colorFrameDescription.Height * 4),
                                ColorImageFormat.Bgra);
                            var rect = new Int32Rect(0, 0, _colorBitmap.PixelWidth, _colorBitmap.PixelHeight);
                            _colorBitmap.AddDirtyRect(rect);
                        }
                        _colorBitmap.Unlock();
                    }
                }
            }
        }

        private void Sensor_IsAvailableChanged(object sender, IsAvailableChangedEventArgs e)
        {
            // 如果失败，设置状态文本
            StatusText = _kinectSensor.IsAvailable ? Properties.Resources.RunningStatusText : Properties.Resources.SensorNotAvailableStatusText;
        }

        /// <summary>
        /// Draws a body
        /// </summary>
        /// <param name="joints">joints to draw</param>
        /// <param name="jointPoints">translated positions of joints to draw</param>
        /// <param name="drawingContext">drawing context to draw to</param>
        /// <param name="drawingPen">specifies color to draw a specific body</param>
        private void DrawBody(IReadOnlyDictionary<JointType, Joint> joints, IDictionary<JointType, Point> jointPoints, DrawingContext drawingContext, Pen drawingPen)
        {
            // Draw the bones
            foreach (var bone in _bones)
            {
                DrawBone(joints, jointPoints, bone.Item1, bone.Item2, drawingContext, drawingPen);
            }
            // Draw the joints
            foreach (JointType jointType in joints.Keys)
            {
                Brush drawBrush = null;
                TrackingState trackingState = joints[jointType].TrackingState;
                if (trackingState == TrackingState.Tracked)
                {
                    drawBrush = _trackedJointBrush;
                }
                else if (trackingState == TrackingState.Inferred)
                {
                    drawBrush = _inferredJointBrush;
                }
                if (drawBrush != null)
                {
                    drawingContext.DrawEllipse(drawBrush, null, jointPoints[jointType], JointThickness, JointThickness);
                }
            }
        }

        /// <summary>
        /// Draws one bone of a body (joint to joint)
        /// </summary>
        /// <param name="joints">joints to draw</param>
        /// <param name="jointPoints">translated positions of joints to draw</param>
        /// <param name="jointType0">first joint of bone to draw</param>
        /// <param name="jointType1">second joint of bone to draw</param>
        /// <param name="drawingContext">drawing context to draw to</param>
        /// /// <param name="drawingPen">specifies color to draw a specific bone</param>
        private void DrawBone(IReadOnlyDictionary<JointType, Joint> joints, IDictionary<JointType, Point> jointPoints, JointType jointType0, JointType jointType1, DrawingContext drawingContext, Pen drawingPen)
        {
            Joint joint0 = joints[jointType0];
            Joint joint1 = joints[jointType1];

            // If we can't find either of these joints, exit
            if (joint0.TrackingState == TrackingState.NotTracked || joint1.TrackingState == TrackingState.NotTracked)
            {
                return;
            }

            // We assume all drawn bones are inferred unless BOTH joints are tracked
            Pen drawPen = _inferredBonePen;
            if ((joint0.TrackingState == TrackingState.Tracked) && (joint1.TrackingState == TrackingState.Tracked))
            {
                drawPen = drawingPen;
            }

            drawingContext.DrawLine(drawPen, jointPoints[jointType0], jointPoints[jointType1]);
        }

        /// <summary>
        /// Draws a hand symbol if the hand is tracked: red circle = closed, green circle = opened; blue circle = lasso
        /// </summary>
        /// <param name="handState">state of the hand</param>
        /// <param name="handPosition">position of the hand</param>
        /// <param name="drawingContext">drawing context to draw to</param>
        private void DrawHand(HandState handState, Point handPosition, DrawingContext drawingContext)
        {
            switch (handState)
            {
                case HandState.Closed:
                    drawingContext.DrawEllipse(_handClosedBrush, null, handPosition, HandSize, HandSize);
                    break;
                case HandState.Open:
                    drawingContext.DrawEllipse(_handOpenBrush, null, handPosition, HandSize, HandSize);
                    break;
                case HandState.Lasso:
                    drawingContext.DrawEllipse(_handLassoBrush, null, handPosition, HandSize, HandSize);
                    break;
            }
        }

        /// <summary>
        /// Draws indicators to show which edges are clipping body data
        /// </summary>
        /// <param name="body">body to draw clipping information for</param>
        /// <param name="drawingContext">drawing context to draw to</param>
        private void DrawClippedEdges(Body body, DrawingContext drawingContext)
        {
            FrameEdges clippedEdges = body.ClippedEdges;
            if (clippedEdges.HasFlag(FrameEdges.Bottom))
            {
                drawingContext.DrawRectangle(Brushes.Red, null,
                    new Rect(0, _displayHeight - ClipBoundsThickness, _displayWidth, ClipBoundsThickness));
            }
            if (clippedEdges.HasFlag(FrameEdges.Top))
            {
                drawingContext.DrawRectangle(Brushes.Red, null,
                    new Rect(0, 0, _displayWidth, ClipBoundsThickness));
            }
            if (clippedEdges.HasFlag(FrameEdges.Left))
            {
                drawingContext.DrawRectangle(Brushes.Red, null,
                    new Rect(0, 0, ClipBoundsThickness, _displayHeight));
            }
            if (clippedEdges.HasFlag(FrameEdges.Right))
            {
                drawingContext.DrawRectangle(Brushes.Red, null,
                    new Rect(_displayWidth - ClipBoundsThickness, 0, ClipBoundsThickness, _displayHeight));
            }
        }

        private void Window_KeyDown(object sender, KeyEventArgs e)
        {
            switch (e.Key)
            {
                case Key.Escape:
                    ToolBar.Visibility = Visibility.Visible;
                    ViewBox.Margin = new Thickness { Left = 0, Top = 32, Right = 0, Bottom = 0 };
                    WindowState = WindowState.Normal;
                    WindowStyle = WindowStyle.SingleBorderWindow;
                    break;
                case Key.Space:
                    //var bitmapImage = new BitmapImage(new Uri("I:\\图片\\background.jpg", UriKind.Absolute));
                    //_colorBitmap = new WriteableBitmap(bitmapImage);
                    //StatusText = DateTime.Now.ToLongTimeString();
                    break;
            }
        }

        private void Settings_Click(object sender, RoutedEventArgs e)
        {
            new SettingsWindow().ShowDialog();
        }

        private void FullScreen_Click(object sender, RoutedEventArgs e)
        {
            ToolBar.Visibility = Visibility.Hidden;
            ViewBox.Margin = new Thickness { Left = 0, Top = 0, Right = 0, Bottom = 0 };
            Topmost = false;
            WindowStyle = WindowStyle.None;
            WindowState = WindowState.Maximized;
        }

        public ImageSource ImageSource => _colorBitmap;

        public ImageSource BoneSource => _imageSource;
    }
}
