private void OnInputsUpdateEventHandler(object sender, InputUpdateEventArgs e) { Profiler.BeginSample("---ClusterManager : Clusters Update Total"); String clusterHash; ResetClustersBuffers(); Profiler.BeginSample("------ClusterManager : Cancelled Buffer"); foreach (int touchId in InternalTouches.CancelledTouchBuffer) { clusterHash = GetClusterIdFromTouchPoint(touchId); if (clusterHash != null) { //Is a cluster with more than one point if (clusters[clusterHash].PointsIds.Count > 1) { Cluster updatedCluster = clusters[clusterHash].RemovePoint(touchId); //Update Current state Clusters clusters.Remove(clusterHash); clusters.Add(updatedCluster.Hash, updatedCluster); //If State is Cancelled update CancelledCluster Buffer if (updatedCluster.State == ClusterState.Cancelled) { IdentifiedClustersCancelled.Remove(updatedCluster.CancelledClusterHash); IdentifiedClustersCancelled.Add(updatedCluster.CancelledClusterHash, updatedCluster); } } //Is a cluster with only one point else { //Update CancelledClusterBuffer Cluster cluster = clusters[clusterHash].RemovePoint(touchId); if (cluster.State == ClusterState.Cancelled) { IdentifiedClustersCancelled.Remove(cluster.CancelledClusterHash); IdentifiedClustersCancelled.Add(cluster.CancelledClusterHash, cluster); } //Remove cluster from current Clusters clusters.Remove(clusterHash); } } //Remove touch from fingers touch list } Profiler.EndSample(); Profiler.BeginSample("------ClusterManager : Moved Buffer"); foreach (int touchId in InternalTouches.MovedTouchBuffer) { clusterHash = GetClusterIdFromTouchPoint(touchId); if (clusterHash != null) { Cluster[] updatedCluster = clusters[clusterHash].UpdatePoint(touchId); clusters.Remove(clusterHash); if (updatedCluster[0].Points.Count != 0) { clusters.Add(updatedCluster[0].Hash, updatedCluster[0]); if (updatedCluster[0].State == ClusterState.Cancelled) { IdentifiedClustersCancelled.Remove(updatedCluster[0].CancelledClusterHash); IdentifiedClustersCancelled.Add(updatedCluster[0].CancelledClusterHash, updatedCluster[0]); } } //Its the case where a previous cluster gets separeted into two if (updatedCluster[1] != null) clusters.Add(updatedCluster[1].Hash, updatedCluster[1]); } else { Cluster c = new Cluster(InternalTouches.List[touchId]); clusters.Add(c.Hash, c); } } Profiler.EndSample(); foreach (int touchId in InternalTouches.BaganTouhBuffer) { Cluster cl = new Cluster(InternalTouches.List[touchId]); clusters.Add(cl.Hash, cl); } if (InternalTouches.CancelledTouchBuffer.Count > 0 || InternalTouches.MovedTouchBuffer.Count > 0 || InternalTouches.BaganTouhBuffer.Count > 0) { Profiler.BeginSample("------ClusterManager : Clusters Update"); UpdateClusters(); Profiler.EndSample(); CheckClustersUpdated(); if (ClustersToIdentify.Count > 0 || IdentifiedClustersMoved.Count > 0 || IdentifiedClustersCancelled.Count > 0) RaiseClustersUpdateEvent(new ClustersUpdateEventArgs(ClustersToIdentify, IdentifiedClustersMoved, IdentifiedClustersCancelled.Values.ToList())); //Get points which are touches and not markers InputManager.SetFingersCancelled(InternalTouches.CancelledTouchBuffer.ToArray()); foreach (Cluster c in clusters.Values) { if (c.State == ClusterState.Invalid || c.State == ClusterState.Cancelled) { //This cluster is only made of finger touch points foreach (TouchInput touch in c.Points.Values) { InputManager.AddFingerTouch(touch); } } } } Profiler.EndSample(); }
/// <summary> /// Cluster Update hierarchical algorithm /// </summary> private void UpdateClusters() { float minDist = this._clusterDistThreshold; float dist; bool minFound = false; List<Cluster> clustersList = this.clusters.Values.ToList(); int mergeCluster1Index = 0; int mergeCluster2Index = 0; Cluster r1 = new Cluster(); Cluster r2 = new Cluster(); if (clusters.Count > 1) { while (minDist <= this._clusterDistThreshold) { for (int i = 0; i < clustersList.Count; i++) { for (int j = i + 1; j < clustersList.Count; j++) { Cluster c1 = clustersList.ElementAt(i); Cluster c2 = clustersList.ElementAt(j); dist = Vector2.Distance(c1.Centroid, c2.Centroid); if (dist < minDist) { minDist = dist; mergeCluster1Index = i; mergeCluster2Index = j; r1 = clustersList[i]; r2 = clustersList[j]; minFound = true; } } } if (minFound) { minFound = false; Cluster mergedCluster = MergeClusters(clustersList.ElementAt(mergeCluster1Index), clustersList.ElementAt(mergeCluster2Index)); clustersList.Remove(r1); clustersList.Remove(r2); clustersList.Add(mergedCluster); } else minDist *= 2; } clusters = clustersList.ToDictionary(v => v.Hash, v => v); } }
private void UpdateClusterMoved(Cluster cluster) { //Update internally the token InternalToken internalToken; if (tokens.TryGetValue(cluster.Hash, out internalToken)) { internalToken.Update(cluster); tokens.Remove(cluster.Hash); tokens.Add(internalToken.HashId, internalToken); //Update Global Token InputManager.GetToken(internalToken.Id).UpdateToken(internalToken, ContinuousMeanSquare); //Add token to local buffer identifiedTokensMoved.Add(internalToken); } }
/// <summary> /// Merges 2 clusters together /// </summary> /// <param name="c1">Cluster 1</param> /// <param name="c2">Cluster 2</param> /// <returns>Merged cluster</returns> private Cluster MergeClusters(Cluster c1, Cluster c2) { if (c1.State == ClusterState.Updated || c1.State == ClusterState.Identidied) { c1.SetCancelledClusterHash(c1.Hash); c1.SetCancelledPointIds(c1.PointsIds); c1.SetState(ClusterState.Cancelled); IdentifiedClustersCancelled.Add(c1.Hash, c1); } if (c2.State == ClusterState.Updated || c2.State == ClusterState.Identidied) { c2.SetCancelledClusterHash(c2.Hash); c2.SetCancelledPointIds(c2.PointsIds); c2.SetState(ClusterState.Cancelled); IdentifiedClustersCancelled.Add(c2.Hash, c2); } List<TouchInput> allPoints = c1.Points.Values.ToList(); allPoints.AddRange(c2.Points.Values.ToList()); return new Cluster(allPoints); }
private void IdentifyCluster(Cluster cluster) { //TODO this function requires updates Profiler.BeginSample("---TokenEngine : Token Identification"); InternalToken token = TokenIdentification.Instance.IdentifyCluster(cluster); Profiler.EndSample(); if (token != null) { //Statistics tokenStatistics.TokenIdentification(true); //Calculate TokenClass Profiler.BeginSample("---TokenEngine: Class LUT"); token.ComputeTokenClass(ClassComputeRefSystem, ComputeDimension); Profiler.EndSample(); tokenStatistics.TokenClassRecognition(token.Class); //Cluster Identification was succesfull //Set Token ID token.SetTokenId(GetFirstAvailableTokenId()); tokenIds.Add(token.Id); //Add Token to internal List tokens.Add(token.HashId, token); //Add Token To Global List InputManager.AddToken(new Token(token, ContinuousMeanSquare)); //Add Token TO local buffer succesfullyIdentifiedTokens.Add(token); } else { tokenStatistics.TokenIdentification(false); //Add token to local buffer failedIdentifiedCluster.Add(cluster); } }
private void CancelCluster(Cluster cluster) { //Cancel cluster according to point //Here is very delicate because it must be considered also the possibility of not removing the token untill not all points have been removed InternalToken token; if (tokens.TryGetValue(cluster.CancelledClusterHash, out token)) { tokenIds.Remove(token.Id); InputManager.RemoveToken(token.Id); tokens.Remove(cluster.CancelledClusterHash); //Add token to local buffer identifiedTokensCancelled.Add(token); } }
public Cluster[] UpdatePoint(int touchId) { Cluster newCluster; if (Vector2.Distance(this.Centroid, InternalTouches.List[touchId].Position) < ClusterManager.Instance.ClusterDistThreshold) { //Point still in clustrer _points[touchId] = new TouchInput(touchId, InternalTouches.List[touchId].Position, TouchState.Moved); newCluster = null; if (State == ClusterState.Identidied) _state = ClusterState.Updated; } else { //Point has moved out of the cluster //Handle current Cluster //If it was just one point then we must cancel the cluster!!!!!! // if (_pointsIds.Count != 1) // { _pointsIds.Remove(touchId); _points.Remove(touchId); if (_state == ClusterState.Identidied || _state == ClusterState.Updated) { _state = ClusterState.Cancelled; _cancelledHash = this._hashId; _cancelledPointsIds.Add(touchId); } else if (State == ClusterState.Cancelled) _cancelledPointsIds.Add(touchId); else if (_pointsIds.Count == 4) _state = ClusterState.Unidentified; else _state = ClusterState.Invalid; //Update new Hash this._hashId = GetPointsHash(_pointsIds.ToArray<int>()); // } // else newCluster = new Cluster(InternalTouches.List[touchId]); } UpdateCentroid(); return new Cluster[] { this, newCluster }; }
public InternalToken IdentifyCluster(Cluster cluster) { InternalToken token = null; bool originFound, axisDistinguished; //Cluster identification Algorithm Dictionary<int, TouchInput> clusterPoints = cluster.Points; TokenMarker[] meanSquaredTokenReferenceSystem; /*Ordered indexes of markers 0 => Origin * 1 => X axis * 2 => Y axis * 3 => Data */ int[] orderedIndexes = new int[4]; //Find two furthest apart poits which reppresent the x xis and the y axis markers Profiler.BeginSample("------Token Identification : Find Two Furthest Point"); int[] furthestPointIndexes = FindTwoFurthestPoints(clusterPoints.Values.ToArray()); Profiler.EndSample(); //Gets indexes of two remaing points which reppresent origin and data marker int[] originAndDataIndexes = clusterPoints.Where(p => p.Key != furthestPointIndexes[0] && p.Key != furthestPointIndexes[1]) .Select(z => z.Key).ToArray(); Profiler.BeginSample("------Token Identification : Find Origin"); originFound = FindOriginIndex(furthestPointIndexes, originAndDataIndexes, clusterPoints, ref orderedIndexes); Profiler.EndSample(); if (originFound) { //Origin Marker Identified and stored in orderedIndexes[0] Profiler.BeginSample("------Token Identification : Distinguish Axis"); axisDistinguished = DistinguishAxisVectors(furthestPointIndexes, clusterPoints, ref orderedIndexes); Profiler.EndSample(); if (axisDistinguished) { //Axis markers have been correctly identified //Remaing point is Data Marker orderedIndexes[3] = clusterPoints.Where(p => p.Key != orderedIndexes[0] && p.Key != orderedIndexes[1] && p.Key != orderedIndexes[2]) .Select(z => z.Key).Single(); //Compute Mean Square Problem for reference System Dictionary<int, TokenMarker> markers = TokenUtils.ConvertTouchInputToMarkers(orderedIndexes, clusterPoints); Profiler.BeginSample("------Token Identification: MeanSquare Calcs"); meanSquaredTokenReferenceSystem = TokenUtils.MeanSquareOrthogonalReferenceSystem(markers[orderedIndexes[0]], markers[orderedIndexes[1]], markers[orderedIndexes[2]], TokenManager.CurrentTokenType.DistanceOriginAxisMarkersPX); Profiler.EndSample(); Profiler.BeginSample("------Token Identification: MeanSquare Calcs Maxima"); TokenMarker[] meanSquaredTokenReferenceSystemOptimized = TokenUtils.MeanSquareOrthogonalReferenceSystemOptimized(markers[orderedIndexes[0]], markers[orderedIndexes[1]], markers[orderedIndexes[2]], TokenManager.CurrentTokenType.DistanceOriginAxisMarkersPX); Profiler.EndSample(); //Create Token token = new InternalToken(cluster.Hash, markers); token.SetMeanSquareReferenceSystem(meanSquaredTokenReferenceSystem); } } else { //No orthogonal vectors found thus no origin, failed identification //For the moment return null, in case consider doing second iteration on second maximum return token; } return token; }
public void Update(Cluster cluster) { int markerId; Vector2 newPostion; foreach (KeyValuePair<int, TouchInput> entry in cluster.Points) { markerId = entry.Key; newPostion = entry.Value.Position; this.markers[markerId].UpdatePosition(newPostion); } UpdateMarkersTypeList(); UpdateTokenAxis(); UpdateAngle(); UpdatePosition(); TokenMarker[] meanSquaredTokenReferenceSystemOptimized = TokenUtils.MeanSquareOrthogonalReferenceSystemOptimized(typeMarkers[MarkerType.Origin], typeMarkers[MarkerType.XAxis], typeMarkers[MarkerType.YAxis], TokenManager.CurrentTokenType.DistanceOriginAxisMarkersPX); SetMeanSquareReferenceSystem(meanSquaredTokenReferenceSystemOptimized); }