GestureManager.cs 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138
  1. using Newtonsoft.Json;
  2. using NUnit.Framework;
  3. using System;
  4. using System.Collections.Generic;
  5. using System.Net.Sockets;
  6. using UnityEngine;
  7. using UnityEngine.InputSystem;
  8. /* 本文件用于控制手势的采集和比对
  9. * 也包含导出和导入手势的功能
  10. */
  11. public class GestureManager
  12. {
  13. // Start is called once before the first execution of Update after the MonoBehaviour is created
  14. public List<GesturePointOffset> gesturePointOffsetList { set; get; } = new List<GesturePointOffset>();
  15. public int sampleRate { set; get; } = 10; // 采样率
  16. private Vector2 prePointLoc = new Vector2(0, 0); // 第一个点
  17. private Vector2 curPointLoc = new Vector2(0, 0); // 第二个点
  18. private float timer = 0f;
  19. public bool isRecording;
  20. private float interval;
  21. private float lengthTorrence = 0.25f; // 允许的长度误差
  22. public GestureManager()
  23. {
  24. interval = (float)1 / sampleRate;
  25. }
  26. public string ExportToJson()
  27. {
  28. string json = string.Empty;
  29. if (gesturePointOffsetList.Count / 2 <= sampleRate) { return json; }
  30. json = JsonConvert.SerializeObject(this);
  31. return json;
  32. }
  33. public void ImportFromJson(string json)
  34. {
  35. this.isRecording = false;
  36. var data = JsonConvert.DeserializeObject<Dictionary<string, object>>(json);
  37. this.sampleRate = int.Parse(data["sampleRate"].ToString());
  38. gesturePointOffsetList.Clear();
  39. GesturePointOffset[] pointOffsets = JsonConvert.DeserializeObject<GesturePointOffset[]>(data["gesturePointOffsetList"].ToString());
  40. foreach (var point in pointOffsets)
  41. {
  42. gesturePointOffsetList.Add(point);
  43. }
  44. }
  45. // 添加一个运动轨迹
  46. public void Record()
  47. {
  48. Vector2 pointLoc = Pointer.current.position.ReadValue();
  49. if (isRecording)
  50. {
  51. if (gesturePointOffsetList.Count == 0)
  52. {
  53. prePointLoc = pointLoc;
  54. curPointLoc = pointLoc;
  55. GesturePointOffset gesturePointMovement = new GesturePointOffset(0, 0);
  56. gesturePointOffsetList.Add(gesturePointMovement);
  57. return;
  58. }
  59. else
  60. {
  61. //Debug.Log("interval:" + interval.ToString());
  62. timer += Time.deltaTime;
  63. if (timer >= interval)
  64. {
  65. timer = 0f;
  66. curPointLoc = pointLoc;
  67. float distance = Vector2.Distance(prePointLoc, curPointLoc);
  68. float angle = Vector2.Angle(prePointLoc, curPointLoc);
  69. GesturePointOffset gesturePointMovement = new GesturePointOffset(distance, angle);
  70. if (distance * angle != 0)
  71. {
  72. gesturePointOffsetList.Add(gesturePointMovement);
  73. Debug.Log("log time:" + DateTime.Now.ToString());
  74. }
  75. prePointLoc = curPointLoc;
  76. }
  77. }
  78. }
  79. }
  80. public float CompareGesture(GestureManager anotherGesture)
  81. {
  82. float score = 0f;
  83. if (this.sampleRate != anotherGesture.sampleRate)
  84. {
  85. Debug.Log("Sample rate not match");
  86. return -1f;
  87. }
  88. int maxGesturePoints = Mathf.Max(this.gesturePointOffsetList.Count, anotherGesture.gesturePointOffsetList.Count);
  89. int minGesturePoints = Mathf.Min(this.gesturePointOffsetList.Count, anotherGesture.gesturePointOffsetList.Count);
  90. for (int i = 0; i < minGesturePoints; i++)
  91. {
  92. float distanceMin = Mathf.Min(this.gesturePointOffsetList[i].distance - anotherGesture.gesturePointOffsetList[i].distance);
  93. float distanceMax = Mathf.Max(this.gesturePointOffsetList[i].distance - anotherGesture.gesturePointOffsetList[i].distance);
  94. float angleMin = Mathf.Min(this.gesturePointOffsetList[i].angle - anotherGesture.gesturePointOffsetList[i].angle);
  95. float angleMax = Mathf.Max(this.gesturePointOffsetList[i].angle - anotherGesture.gesturePointOffsetList[i].angle);
  96. float distanceScore = 0f;
  97. if (distanceMin == 0)
  98. {
  99. distanceScore = 1f;
  100. }
  101. else
  102. {
  103. distanceScore = distanceMin / distanceMax;
  104. }
  105. float angleDitance1 = angleMax - angleMin;
  106. float angleDitance2 = 360 - angleDitance1;
  107. float angleScore = 1 - (Mathf.Min(angleDitance1, angleDitance2) / 180);
  108. score = score * (i / (i + 1f)) + (distanceScore + angleScore) / 2 * (1f / (i + 1));
  109. }
  110. // 如果长度超过公差范围,就要考虑调整score
  111. if ((maxGesturePoints / minGesturePoints) > (1f+ lengthTorrence))
  112. {
  113. int deltaGesturePoints = Mathf.RoundToInt(maxGesturePoints - minGesturePoints * (1f + lengthTorrence));
  114. score = score * (minGesturePoints / (minGesturePoints + deltaGesturePoints));
  115. }
  116. return score;
  117. }
  118. public void ResetGesture()
  119. {
  120. this.gesturePointOffsetList.Clear();
  121. }
  122. }