public InternalToken IdentifyCluster(Cluster cluster) { //Start Stop Watch for statistics Stopwatch sw = Stopwatch.StartNew(); InternalToken token = null; //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 int[] furthestPointIndexes = FindTwoFurthestPoints(clusterPoints.Values.ToArray()); //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(); if(FindOriginIndex(furthestPointIndexes, originAndDataIndexes, clusterPoints, ref orderedIndexes)) { //Origin Marker Identified and stored in orderedIndexes[0] if (DistinguishAxisVectors(furthestPointIndexes, clusterPoints, ref orderedIndexes)) { //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); meanSquaredTokenReferenceSystem = TokenUtils.MeanSquareOrthogonalReferenceSystem(markers[orderedIndexes[0]], markers[orderedIndexes[1]], markers[orderedIndexes[2]], TokenManager.CurrentTokenType.DistanceOriginAxisMarkersPX); //Create Token token = new InternalToken(cluster.Hash, markers); token.SetMeanSquareReferenceSystem(meanSquaredTokenReferenceSystem); } else throw (new TokenAxisNotDistinguishedException("Could not Distinguish Axis")); } else { //throw (new NoOrthogonalVectorsFoundException("Could not find Orthogonal Vectors")); //No orthogonal vectors found thus no origin, failed identification //For the moment return null, in case consider doing second iteration on second maximum sw.Stop(); TokenStatistics.Instance.SetTokenIdentificationTime(sw.ElapsedMilliseconds); return token; } sw.Stop(); TokenStatistics.Instance.SetTokenIdentificationTime(sw.ElapsedMilliseconds); return token; }
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 OnInputsUpdateEventHandler(object sender, InputUpdateEventArgs e) { String clusterHash; ResetClustersBuffers(); 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 } 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); } } 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) { UpdateClusters(); CheckClustersUpdated(); if (IdentifiedClustersCancelled.Count > 0) OnClustersCancelled(new ClusterUpdateEventArgs("Moved cluster request", IdentifiedClustersCancelled.Values.ToList())); if (IdentifiedClustersMoved.Count > 0) OnClustersMoved(new ClusterUpdateEventArgs("Moved cluster request", IdentifiedClustersMoved)); if (ClustersToIdentify.Count > 0) OnClusterToIdentify(new ClusterUpdateEventArgs("Identification request", ClustersToIdentify)); //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); } } } } }
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); }
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(); }
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.Hash; _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.Hash = ClusterUtils.GetPointsHash(_pointsIds.ToArray<int>()); // } // else newCluster = new Cluster(InternalTouches.List[touchId]); } UpdateCentroid(); return new Cluster[] { this ,newCluster }; }