GestureController.cs 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596
  1. using Newtonsoft.Json;
  2. using NUnit.Framework;
  3. using System.Collections.Generic;
  4. using System.Net.Sockets;
  5. using UnityEngine;
  6. /* 本文件用于控制手势的采集和比对
  7. * 也包含导出和导入手势的功能
  8. */
  9. public class GestureController
  10. {
  11. // Start is called once before the first execution of Update after the MonoBehaviour is created
  12. private List<GesturePointOffset> gesturePointOffsetList = new List<GesturePointOffset>();
  13. public int sampleRate { private set; get; } = 10; // 采样率
  14. private Vector2 prePointLoc = new Vector2(0, 0); // 第一个点
  15. private Vector2 curPointLoc = new Vector2(0, 0); // 第二个点
  16. public string ExportToJson()
  17. {
  18. string json = string.Empty;
  19. if (gesturePointOffsetList.Count / 2 <= sampleRate) { return json; }
  20. json = JsonConvert.SerializeObject(this);
  21. return json;
  22. }
  23. public void ImportFromJson(string json)
  24. {
  25. var data = JsonConvert.DeserializeObject<Dictionary<string, string>>(json);
  26. this.sampleRate = int.Parse(data["sample_rate"]);
  27. gesturePointOffsetList.Clear();
  28. GesturePointOffset[] pointOffsets = JsonConvert.DeserializeObject<GesturePointOffset[]>(data["points"]);
  29. foreach (var point in pointOffsets)
  30. {
  31. gesturePointOffsetList.Add(point);
  32. }
  33. }
  34. // 添加一个运动轨迹
  35. public void AddGesturePoint(Vector2 pointLoc)
  36. {
  37. if (gesturePointOffsetList.Count == 0)
  38. {
  39. prePointLoc = pointLoc;
  40. curPointLoc = pointLoc;
  41. GesturePointOffset gesturePointMovement = new GesturePointOffset(0, 0);
  42. gesturePointOffsetList.Add(gesturePointMovement);
  43. return;
  44. }
  45. else
  46. {
  47. curPointLoc = pointLoc;
  48. float distance = Vector2.Distance(prePointLoc, curPointLoc);
  49. float angle = Vector2.Angle(prePointLoc, curPointLoc);
  50. GesturePointOffset gesturePointMovement = new GesturePointOffset(distance, angle);
  51. gesturePointOffsetList.Add(gesturePointMovement);
  52. prePointLoc = curPointLoc;
  53. }
  54. }
  55. public float CompareGesture(GestureController anotherGesture)
  56. {
  57. float score = 0f;
  58. if (this.sampleRate != anotherGesture.sampleRate)
  59. {
  60. Debug.Log("Sample rate not match");
  61. return -1f;
  62. }
  63. int maxGesturePoints = Mathf.Max(this.gesturePointOffsetList.Count, anotherGesture.gesturePointOffsetList.Count);
  64. int minGesturePoints = Mathf.Min(this.gesturePointOffsetList.Count, anotherGesture.gesturePointOffsetList.Count);
  65. for (int i = 0; i < minGesturePoints; i++)
  66. {
  67. float ditanceMin = Mathf.Min(this.gesturePointOffsetList[i].distance - anotherGesture.gesturePointOffsetList[i].distance);
  68. float ditanceMax = Mathf.Max(this.gesturePointOffsetList[i].distance - anotherGesture.gesturePointOffsetList[i].distance);
  69. float distanceScore = ditanceMin / ditanceMax;
  70. float angleMin = Mathf.Min(this.gesturePointOffsetList[i].angle - anotherGesture.gesturePointOffsetList[i].angle);
  71. float angleMax = Mathf.Max(this.gesturePointOffsetList[i].angle - anotherGesture.gesturePointOffsetList[i].angle);
  72. float angleDitance1 = angleMax - angleMin;
  73. float angleDitance2 = 360 - angleDitance1;
  74. float angleScore = 1 - (Mathf.Min(angleDitance1, angleDitance2) / 180);
  75. score = score * (i / (i + 1)) + (distanceScore + angleScore) / 2 * (1f / (i + 1));
  76. }
  77. // 如果长度超过20%,就要考虑调整score
  78. if ((maxGesturePoints / minGesturePoints) > 1.2f)
  79. {
  80. int deltaGesturePoints = Mathf.RoundToInt(maxGesturePoints - minGesturePoints * 1.2f);
  81. score = score * (minGesturePoints / (minGesturePoints + deltaGesturePoints));
  82. }
  83. return score;
  84. }
  85. }