/// <summary> /// Dispatch updates to trackers which have just been created. /// </summary> /// <param name="lPairs">The list trackers to create.</param> private void createNew(List <SpatioTemporalInput> lInputs) { // Create new trackers for each input. foreach (SpatioTemporalInput pInput in lInputs) { // Create new, insert input and then append. SpatioTemporalTracker pTracker = new SpatioTemporalTracker(this.DefaultSmoothSize, ++this.iNextID); pTracker.consumeInput(pInput); pTracker.eTrackerState = TrackerState.Discover; lTrackers.Add(pTracker); // Raise the event. //if (this.OnStart != null) // this.OnStart(this, pTracker); } }
/// <summary> /// Enqueue a 'ContactType.Start' event. /// </summary> /// <param name="pSource">The SpatioTemporalClassifier which was the source.</param> /// <param name="pTracker">The reference to the SpatioTemporalTracker responsible for tracking this input.</param> private void handleInputClassifier_OnStart(SpatioTemporalClassifier pSource, SpatioTemporalTracker pTracker) { // Enqueue a contact removed event. lFrame.Enqueue(new WiiContact(pTracker.ID, ContactType.Start, new System.Windows.Point(pTracker.Position.X, pTracker.Position.Y), ScreenSize, pSource, pTracker)); }
/// <summary> /// Construct a new WiiContact. /// </summary> /// <param name="iID">The unique session ID for this input.</param> /// <param name="eContactType">The type of contact.</param> /// <param name="tPosition">The position which generated the contact.</param> /// <param name="tNormalPosition">The maximum width/height so that we can generate a normalised position.</param> /// <param name="pClassifier">The classifer responsible for the history</param> /// <param name="pTracker">The tracker within the classifer responsible for the direct history.</param> public WiiContact(ulong iID, ContactType eContactType, Point tPosition, Vector tScreenSize, SpatioTemporalClassifier pClassifier, SpatioTemporalTracker pTracker) { this.Classifier = pClassifier; this.Tracker = pTracker; this.ID = iID; this.Type = eContactType; this.Position = tPosition; this.NormalPosition = new Point(tPosition.X / tScreenSize.X, tPosition.Y / tScreenSize.Y); this.Size = new Vector(1, 1); }
/// <summary> /// Construct a new process pair. This will invoke 'getClassificationRanking' on the tracker. /// </summary> /// <param name="pTracker">The tracker to pair.</param> /// <param name="pInput">The input to pair.</param> public ProcessPair(SpatioTemporalTracker pTracker, SpatioTemporalInput pInput) { this.pInput = pInput; this.pTracker = pTracker; this.fRanking = pTracker.getClassificationRanking(this.pInput); }
/// <summary> /// This is called to process a 'frame' of inputs which will be ranked against eachother before being dispatched /// to the appropriate existing inputs, removing old ones or generating new ones. /// </summary> /// <param name="tInputs">The array of inputs which we want to process as a frame.</param> public void processFrame(List <SpatioTemporalInput> lInputs) { // Check we have data. if (lInputs.Count + lTrackers.Count == 0) { return; } #region Ugly (but fairly quick) duplicate tracker removal. // Loop over an exclusive half-diagonal of a number square! :-) Ahh the memories! bool bPossible = true; bool bFound = false; while (bPossible) { // Check for a collision! for (int i = 0; i < lTrackers.Count; ++i) { // Flag that we have not found a collision on this loop round. bFound = false; for (int j = i + 1; j < lTrackers.Count; ++j) { // Test the trackers are in very close range of eachother (i.e. overlapping and stealing inputs!). if ((lTrackers[i].Position - lTrackers[j].Position).Length < this.DuplicateDistance) { // They are too close - set one to be dead! SpatioTemporalTracker pRemove = lTrackers[i]; // Remove it. this.lTrackers.Remove(pRemove); pRemove.eTrackerState = TrackerState.Destroy; bFound = true; // Raise the event. if (pRemove.StrongLock) { if (this.OnEnd != null) { this.OnEnd(this, pRemove); } } } } // If we found a collision we have removed it from the list and this need to check again. if (bFound) { break; } } // So we got this far and had no collisions. bPossible = bFound; } #endregion #region Process and Sort the table of all possible trackers. // Build the big table of trackers-inputs-distances. List <ProcessPair> lTable = new List <ProcessPair>(lInputs.Count * lTrackers.Count); foreach (SpatioTemporalTracker pTracker in lTrackers) { foreach (SpatioTemporalInput pInput in lInputs) { // Only add it to to the table if it will not be rejected out of hand. ProcessPair pPair = new ProcessPair(pTracker, pInput); //if (pPair.fRanking < pTracker.PredictionScale) lTable.Add(pPair); } } // Sort the above table based on the distance rankings. lTable.Sort(); #endregion #region Strip duplicate pairs from the tracker ranking table based on 'best' selections. // Remove duplicate tracker entries from the table whilst saving the best pairs in their own table. List <ProcessPair> lBest = new List <ProcessPair>(); foreach (ProcessPair pPair in lTable) { // Does the table of best matches already contain this tracker? bool bContains = false; for (int i = 0; i < lBest.Count; ++i) { if (lBest[i].pTracker == pPair.pTracker) { bContains = true; break; } } // If it doesn't then add it. if (!bContains) { lBest.Add(pPair); } } #endregion #region Build a list of remove candidates. // Create an array which contains old trackers to be removed. List <SpatioTemporalTracker> lRemove = new List <SpatioTemporalTracker>(); foreach (SpatioTemporalTracker pTracker in lTrackers) { // Does the table of best matches already contain this input? bool bContains = false; for (int i = 0; i < lBest.Count; ++i) { if (lBest[i].pTracker == pTracker) { bContains = true; break; } } // If it doesn't then add it. if (!bContains) { lRemove.Add(pTracker); } } #endregion #region Build a list of create candidates. // Create an array which contains new trackers to be created. List <SpatioTemporalInput> lCreate = new List <SpatioTemporalInput>(); foreach (SpatioTemporalInput pInput in lInputs) { // Does the table of best matches already contain this input? bool bContains = false; for (int i = 0; i < lBest.Count; ++i) { if (lBest[i].pInput == pInput) { bContains = true; break; } } // If it doesn't then add it. if (!bContains) { lCreate.Add(pInput); } } #endregion // So now we need to dispatch some more processing. // Update the best matches. this.dispatchUpdates(lBest); // Remove the old. this.removeOld(lRemove); // Create the new. this.createNew(lCreate); }