// ----------------------------------------------------------------------- // // Copyright (c) Microsoft Corporation. All rights reserved. // // ----------------------------------------------------------------------- namespace Microsoft.Samples.Kinect.Webserver.Sensor { using System; using Microsoft.Kinect; /// /// Represents activity state and metrics for a single user. /// internal class UserActivityRecord { // Activity level, above which a user is considered to be in "active" state. private const double ActivityMetricThreshold = 0.1; private double activityLevel; public UserActivityRecord(SkeletonPoint position, int updateId, long timestamp) { this.ActivityLevel = 0.0; this.LastPosition = position; this.LastUpdateId = updateId; this.IsActive = false; this.StateTransitionTimestamp = timestamp; } /// /// User activity level metric being tracked. /// /// /// Value is always in [0.0, 1.0] interval. /// public double ActivityLevel { get { return this.activityLevel; } private set { this.activityLevel = Math.Max(0.0, Math.Min(1.0, value)); } } /// /// Id of last update that touched this activity record. /// public int LastUpdateId { get; private set; } /// /// True if user activity is currently larger than the activity threshold. /// public bool IsActive { get; private set; } /// /// Time when IsActive state last changed from true to false or vice versa. /// public long StateTransitionTimestamp { get; private set; } /// /// Last position where user was observed. /// public SkeletonPoint LastPosition { get; private set; } public void Update(SkeletonPoint position, int updateId, long timestamp) { // Movement magnitude gets scaled by this amount in order to get the current activity metric const double DeltaScalingFactor = 10.0; // Controls how quickly new values of the metric displace old values. 1.0 means that new values // for metric immediately replace old values, while smaller decay amounts mean that old metric // values influence the metric for a longer amount of time (i.e.: decay more slowly). const double ActivityDecay = 0.1; var delta = new SkeletonPoint { X = position.X - this.LastPosition.X, Y = position.Y - this.LastPosition.Y, Z = position.Z - this.LastPosition.Z }; double deltaLengthSquared = (delta.X * delta.X) + (delta.Y * delta.Y) + (delta.Z * delta.Z); double newMetric = DeltaScalingFactor * Math.Sqrt(deltaLengthSquared); this.ActivityLevel = ((1.0 - ActivityDecay) * this.ActivityLevel) + (ActivityDecay * newMetric); bool newIsActive = this.ActivityLevel >= ActivityMetricThreshold; if (newIsActive != this.IsActive) { this.IsActive = newIsActive; this.StateTransitionTimestamp = timestamp; } this.LastPosition = position; this.LastUpdateId = updateId; } } }