Imports System.Windows
Imports System.Windows.Controls
Imports System.Windows.Media
Imports System.Windows.Shapes

Imports Microsoft.kinect

''' <summary>
''' Interaction logic for SkeletonViewer.xaml
''' </summary>
''' <remarks></remarks>
Public Class SkeletonViewer
#Region "メンバー変数"
    Private ReadOnly _SkeletonBrushes() As Brush = New Brush() {Brushes.Black,
                                                                Brushes.Crimson,
                                                                Brushes.Indigo,
                                                                Brushes.DodgerBlue,
                                                                Brushes.Purple,
                                                                Brushes.Pink}
    Private _FrameSkeletons() As Skeleton
#End Region

#Region "コンストラクタ"
    Sub New()

        ' この呼び出しはデザイナーで必要です。
        InitializeComponent()

        ' InitializeComponent() 呼び出しの後で初期化を追加します。

    End Sub
#End Region


#Region "メソッド"
    Private Sub KinectDevice_SkeletonFrameReady(sender As Object, e As SkeletonFrameReadyEventArgs)
        SkeletonsPanel.Children.Clear()
        JointInfoPanel.Children.Clear()

        Using frame As SkeletonFrame = e.OpenSkeletonFrame()
            If frame IsNot Nothing Then
                If Me.IsEnabled Then
                    frame.CopySkeletonDataTo(Me._FrameSkeletons)

                    For i As Integer = 0 To Me._FrameSkeletons.Length - 1
                        DrawSkeleton(Me._FrameSkeletons(i), Me._SkeletonBrushes(i))

                        TrackJoint(Me._FrameSkeletons(i).Joints(JointType.HandLeft),
                                   Me._SkeletonBrushes(i))
                        TrackJoint(Me._FrameSkeletons(i).Joints(JointType.HandRight),
                                   Me._SkeletonBrushes(i))
                        '必要があれば、すべての関節を追跡可能
                    Next
                End If
            End If
        End Using
    End Sub


    Private Sub DrawSkeleton(_skeleton As Skeleton, _brush As Brush)
        If _skeleton IsNot Nothing AndAlso _skeleton.TrackingState = SkeletonTrackingState.Tracked Then
            ' 9章 
            Dim figure As Polyline
            For Each _jointType As JointType In [Enum].GetValues(GetType(JointType))
                figure = CreateFigure(_skeleton,
                                      _brush,
                                      New JointType() {_skeleton.BoneOrientations(_jointType).StartJoint,
                                                       _skeleton.BoneOrientations(_jointType).EndJoint
                                                      })
                SkeletonsPanel.Children.Add(figure)
            Next
        End If
    End Sub

    Private Function CreateFigure(_skeleton As Skeleton, _brush As Brush, joints() As JointType) As Polyline
        Dim figure As Polyline = New Polyline()

        Figure.StrokeThickness = 18
        Figure.Stroke = _brush

        For i As Integer = 0 To joints.Length - 1
            figure.Points.Add(GetJointPoint(_skeleton.Joints(joints(i))))
        Next
        Return figure
    End Function

    Private Function GetJointPoint(_joint As Joint) As Point
        Dim _point As DepthImagePoint = Me.KinectDevice.MapSkeletonPointToDepth(_joint.Position,
                                                                               Me.KinectDevice.DepthStream.Format)
        _point.X *= Fix(Me.LayoutRoot.ActualWidth / KinectDevice.DepthStream.FrameWidth)
        _point.Y *= Fix(Me.LayoutRoot.ActualHeight / KinectDevice.DepthStream.FrameHeight)

        Return New Point(_point.X, _point.Y)
    End Function

    Private Sub TrackJoint(_joint As Joint, _brush As Brush)
        If _joint.TrackingState <> JointTrackingState.NotTracked Then
            Dim container As Canvas = New Canvas
            Dim jointPoint As Point = GetJointPoint(_joint)
            Dim z As Double = _joint.Position.Z

            Dim element As Ellipse = New Ellipse
            element.Height = 15
            element.Width = 15
            element.Fill = _brush
            Canvas.SetLeft(element, 0 - (element.Width / 2))
            Canvas.SetTop(element, 0 - (element.Height / 2))
            container.Children.Add(element)

            Dim positionText As TextBlock = New TextBlock
            positionText.Text = String.Format("<{0:0.00}, {1:0.00}, {2:0.00}>",
                                              jointPoint.X,
                                              jointPoint.Y,
                                              z)
            positionText.Foreground = _brush
            positionText.FontSize = 24
            positionText.Measure(New Size(Double.PositiveInfinity, Double.PositiveInfinity))
            Canvas.SetLeft(positionText, 35)
            Canvas.SetTop(positionText, 15)
            container.Children.Add(positionText)

            Canvas.SetLeft(container, jointPoint.X)
            Canvas.SetTop(container, jointPoint.Y)

            JointInfoPanel.Children.Add(container)
        End If
    End Sub
#End Region


#Region "プロパティ"
#Region "KinectDevice"
    Protected Const KinectDevicePropertyName As String = "KinectDevice"
    Public Shared ReadOnly KinectDeviceProperty As DependencyProperty = DependencyProperty.Register(KinectDevicePropertyName,
                                                                                                     GetType(KinectSensor),
                                                                                                     GetType(SkeletonViewer),
                                                                                                     New PropertyMetadata(Nothing,
                                                                                                                         AddressOf KinectDeviceChanged))


    Private Shared Sub KinectDeviceChanged(owner As DependencyObject, e As DependencyPropertyChangedEventArgs)
        Dim viewer As SkeletonViewer = CType(owner, SkeletonViewer)

        If e.OldValue IsNot Nothing Then
            RemoveHandler CType(e.OldValue, KinectSensor).SkeletonFrameReady, AddressOf viewer.KinectDevice_SkeletonFrameReady
            viewer._FrameSkeletons = Nothing
        End If

        If e.NewValue IsNot Nothing Then
            viewer.KinectDevice = CType(e.NewValue, KinectSensor)
            AddHandler viewer.KinectDevice.SkeletonFrameReady, AddressOf viewer.KinectDevice_SkeletonFrameReady
            ReDim viewer._FrameSkeletons(viewer.KinectDevice.SkeletonStream.FrameSkeletonArrayLength - 1)
        End If
    End Sub

    Public Property KinectDevice As KinectSensor
        Get
            Return CType(GetValue(KinectDeviceProperty), KinectSensor)
        End Get
        Set(value As KinectSensor)
            SetValue(KinectDeviceProperty, value)
        End Set
    End Property
#End Region
#End Region
End Class