|
@@ -1,8 +1,6 @@
|
|
|
using Newtonsoft.Json;
|
|
|
-using NUnit.Framework;
|
|
|
using System;
|
|
|
using System.Collections.Generic;
|
|
|
-using System.Net.Sockets;
|
|
|
using UnityEngine;
|
|
|
using UnityEngine.InputSystem;
|
|
|
|
|
@@ -13,32 +11,38 @@ public class GestureManager
|
|
|
{
|
|
|
// Start is called once before the first execution of Update after the MonoBehaviour is created
|
|
|
public List<GesturePointOffset> gesturePointOffsetList { set; get; } = new List<GesturePointOffset>();
|
|
|
- public int sampleRate { set; get; } = 10; // 采样率
|
|
|
+ public int sampleRate { set; get; } = 20; // 采样率
|
|
|
private Vector2 prePointLoc = new Vector2(0, 0); // 第一个点
|
|
|
private Vector2 curPointLoc = new Vector2(0, 0); // 第二个点
|
|
|
- private float timer = 0f;
|
|
|
+ private float timer = 0f; // 配合interval使用
|
|
|
public bool isRecording;
|
|
|
- private float interval;
|
|
|
+ private float interval; // 采样间隔,使用采样率计算
|
|
|
private float lengthTorrence = 0.25f; // 允许的长度误差
|
|
|
+ private DateTime startTime;
|
|
|
+ private DateTime endTime;
|
|
|
+ private float duration;
|
|
|
+ private int screenWidth;
|
|
|
+ private int screenHeight;
|
|
|
|
|
|
public GestureManager()
|
|
|
{
|
|
|
- interval = (float)1 / sampleRate;
|
|
|
+ interval = 1f / sampleRate;
|
|
|
+ screenWidth = Screen.width;
|
|
|
+ screenHeight = Screen.height;
|
|
|
}
|
|
|
|
|
|
public string ExportToJson()
|
|
|
{
|
|
|
string json = string.Empty;
|
|
|
- if (gesturePointOffsetList.Count / 2 <= sampleRate) { return json; }
|
|
|
json = JsonConvert.SerializeObject(this);
|
|
|
return json;
|
|
|
}
|
|
|
|
|
|
public void ImportFromJson(string json)
|
|
|
{
|
|
|
- this.isRecording = false;
|
|
|
+ isRecording = false;
|
|
|
var data = JsonConvert.DeserializeObject<Dictionary<string, object>>(json);
|
|
|
- this.sampleRate = int.Parse(data["sampleRate"].ToString());
|
|
|
+ sampleRate = int.Parse(data["sampleRate"].ToString());
|
|
|
gesturePointOffsetList.Clear();
|
|
|
GesturePointOffset[] pointOffsets = JsonConvert.DeserializeObject<GesturePointOffset[]>(data["gesturePointOffsetList"].ToString());
|
|
|
foreach (var point in pointOffsets)
|
|
@@ -53,6 +57,13 @@ public class GestureManager
|
|
|
Vector2 pointLoc = Pointer.current.position.ReadValue();
|
|
|
if (isRecording)
|
|
|
{
|
|
|
+ // if (!IsMouseOnScreen())
|
|
|
+ // {
|
|
|
+ // StopRecording();
|
|
|
+ // Debug.Log("Mouse not on screen");
|
|
|
+ // return;
|
|
|
+ // }
|
|
|
+
|
|
|
if (gesturePointOffsetList.Count == 0)
|
|
|
{
|
|
|
prePointLoc = pointLoc;
|
|
@@ -68,16 +79,20 @@ public class GestureManager
|
|
|
if (timer >= interval)
|
|
|
{
|
|
|
timer = 0f;
|
|
|
-
|
|
|
curPointLoc = pointLoc;
|
|
|
- float distance = Vector2.Distance(prePointLoc, curPointLoc);
|
|
|
- float angle = Vector2.Angle(prePointLoc, curPointLoc);
|
|
|
+
|
|
|
+ Vector2 normalizedCurPoint = NormalizePoint(curPointLoc);
|
|
|
+ Vector2 normalizedPrePoint = NormalizePoint(prePointLoc);
|
|
|
+ float distance = Vector2.Distance(normalizedCurPoint, normalizedPrePoint);
|
|
|
+
|
|
|
+ Vector2 direction = curPointLoc - prePointLoc;
|
|
|
+ float angle = Mathf.Atan2(direction.y, direction.x) * Mathf.Rad2Deg;
|
|
|
+ // float angle = Vector2.Angle(prePointLoc, curPointLoc);
|
|
|
GesturePointOffset gesturePointMovement = new GesturePointOffset(distance, angle);
|
|
|
|
|
|
if (distance * angle != 0)
|
|
|
{
|
|
|
gesturePointOffsetList.Add(gesturePointMovement);
|
|
|
- Debug.Log("log time:" + DateTime.Now.ToString());
|
|
|
}
|
|
|
prePointLoc = curPointLoc;
|
|
|
}
|
|
@@ -88,21 +103,27 @@ public class GestureManager
|
|
|
public float CompareGesture(GestureManager anotherGesture)
|
|
|
{
|
|
|
float score = 0f;
|
|
|
- if (this.sampleRate != anotherGesture.sampleRate)
|
|
|
+ if (sampleRate != anotherGesture.sampleRate)
|
|
|
{
|
|
|
Debug.Log("Sample rate not match");
|
|
|
return -1f;
|
|
|
}
|
|
|
|
|
|
- int maxGesturePoints = Mathf.Max(this.gesturePointOffsetList.Count, anotherGesture.gesturePointOffsetList.Count);
|
|
|
- int minGesturePoints = Mathf.Min(this.gesturePointOffsetList.Count, anotherGesture.gesturePointOffsetList.Count);
|
|
|
+ if (gesturePointOffsetList.Count == 0 || anotherGesture.gesturePointOffsetList.Count == 0)
|
|
|
+ {
|
|
|
+ Debug.Log("Gesture point count is 0");
|
|
|
+ return -1f;
|
|
|
+ }
|
|
|
+
|
|
|
+ int maxGesturePoints = Mathf.Max(gesturePointOffsetList.Count, anotherGesture.gesturePointOffsetList.Count);
|
|
|
+ int minGesturePoints = Mathf.Min(gesturePointOffsetList.Count, anotherGesture.gesturePointOffsetList.Count);
|
|
|
for (int i = 0; i < minGesturePoints; i++)
|
|
|
{
|
|
|
|
|
|
- float distanceMin = Mathf.Min(this.gesturePointOffsetList[i].distance - anotherGesture.gesturePointOffsetList[i].distance);
|
|
|
- float distanceMax = Mathf.Max(this.gesturePointOffsetList[i].distance - anotherGesture.gesturePointOffsetList[i].distance);
|
|
|
- float angleMin = Mathf.Min(this.gesturePointOffsetList[i].angle - anotherGesture.gesturePointOffsetList[i].angle);
|
|
|
- float angleMax = Mathf.Max(this.gesturePointOffsetList[i].angle - anotherGesture.gesturePointOffsetList[i].angle);
|
|
|
+ float distanceMin = Mathf.Min(gesturePointOffsetList[i].distance, anotherGesture.gesturePointOffsetList[i].distance);
|
|
|
+ float distanceMax = Mathf.Max(gesturePointOffsetList[i].distance, anotherGesture.gesturePointOffsetList[i].distance);
|
|
|
+ float angleMin = Mathf.Min(gesturePointOffsetList[i].angle, anotherGesture.gesturePointOffsetList[i].angle);
|
|
|
+ float angleMax = Mathf.Max(gesturePointOffsetList[i].angle, anotherGesture.gesturePointOffsetList[i].angle);
|
|
|
|
|
|
float distanceScore = 0f;
|
|
|
if (distanceMin == 0)
|
|
@@ -122,10 +143,10 @@ public class GestureManager
|
|
|
}
|
|
|
|
|
|
// 如果长度超过公差范围,就要考虑调整score
|
|
|
- if ((maxGesturePoints / minGesturePoints) > (1f+ lengthTorrence))
|
|
|
+ if ((maxGesturePoints / minGesturePoints) > (1f + lengthTorrence))
|
|
|
{
|
|
|
int deltaGesturePoints = Mathf.RoundToInt(maxGesturePoints - minGesturePoints * (1f + lengthTorrence));
|
|
|
- score = score * (minGesturePoints / (minGesturePoints + deltaGesturePoints));
|
|
|
+ score = score * ((float)minGesturePoints / (minGesturePoints + deltaGesturePoints));
|
|
|
}
|
|
|
|
|
|
return score;
|
|
@@ -133,6 +154,64 @@ public class GestureManager
|
|
|
|
|
|
public void ResetGesture()
|
|
|
{
|
|
|
- this.gesturePointOffsetList.Clear();
|
|
|
+ gesturePointOffsetList.Clear();
|
|
|
+ }
|
|
|
+
|
|
|
+ public void StartRecording()
|
|
|
+ {
|
|
|
+ isRecording = true;
|
|
|
+ gesturePointOffsetList.Clear();
|
|
|
+ timer = 0f;
|
|
|
+ prePointLoc = Vector2.zero;
|
|
|
+ curPointLoc = Vector2.zero;
|
|
|
+ startTime = DateTime.Now;
|
|
|
+ }
|
|
|
+ public bool StopRecording()
|
|
|
+ {
|
|
|
+ isRecording = false;
|
|
|
+ endTime = DateTime.Now;
|
|
|
+ duration = (float)(endTime - startTime).TotalSeconds;
|
|
|
+ Debug.Log("gesture duration:" + duration.ToString());
|
|
|
+ Debug.Log("gesture point count:" + gesturePointOffsetList.Count.ToString());
|
|
|
+ // 如果采样过少,就不记录这个手势
|
|
|
+ if (gesturePointOffsetList.Count <= sampleRate/2)
|
|
|
+ {
|
|
|
+ Debug.Log("gesture duration too short");
|
|
|
+ gesturePointOffsetList.Clear();
|
|
|
+ }
|
|
|
+ if (gesturePointOffsetList.Count > 0)
|
|
|
+ {
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private bool IsMouseOnScreen()
|
|
|
+ {
|
|
|
+ Vector2 mousePos = Pointer.current.position.ReadValue();
|
|
|
+ return mousePos.x >= 0 && mousePos.x < Screen.width &&
|
|
|
+ mousePos.y >= 0 && mousePos.y < Screen.height;
|
|
|
+ }
|
|
|
+
|
|
|
+ private Vector2 NormalizePoint(Vector2 point)
|
|
|
+ {
|
|
|
+ float x = point.x / screenWidth;
|
|
|
+ float y = point.y / screenHeight;
|
|
|
+ return new Vector2(x, y);
|
|
|
+ }
|
|
|
+ private Vector2 DenormalizePoint(Vector2 point)
|
|
|
+ {
|
|
|
+ float x = point.x * screenWidth;
|
|
|
+ float y = point.y * screenHeight;
|
|
|
+ return new Vector2(x, y);
|
|
|
+ }
|
|
|
+
|
|
|
+ public void SetSampleRate(int rate)
|
|
|
+ {
|
|
|
+ sampleRate = rate;
|
|
|
+ interval = 1f / sampleRate;
|
|
|
}
|
|
|
}
|