123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138 |
- using Newtonsoft.Json;
- using NUnit.Framework;
- using System;
- using System.Collections.Generic;
- using System.Net.Sockets;
- using UnityEngine;
- using UnityEngine.InputSystem;
- /* 本文件用于控制手势的采集和比对
- * 也包含导出和导入手势的功能
- */
- 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; // 采样率
- private Vector2 prePointLoc = new Vector2(0, 0); // 第一个点
- private Vector2 curPointLoc = new Vector2(0, 0); // 第二个点
- private float timer = 0f;
- public bool isRecording;
- private float interval;
- private float lengthTorrence = 0.25f; // 允许的长度误差
- public GestureManager()
- {
- interval = (float)1 / sampleRate;
- }
- 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;
- var data = JsonConvert.DeserializeObject<Dictionary<string, object>>(json);
- this.sampleRate = int.Parse(data["sampleRate"].ToString());
- gesturePointOffsetList.Clear();
- GesturePointOffset[] pointOffsets = JsonConvert.DeserializeObject<GesturePointOffset[]>(data["gesturePointOffsetList"].ToString());
- foreach (var point in pointOffsets)
- {
- gesturePointOffsetList.Add(point);
- }
- }
- // 添加一个运动轨迹
- public void Record()
- {
- Vector2 pointLoc = Pointer.current.position.ReadValue();
- if (isRecording)
- {
- if (gesturePointOffsetList.Count == 0)
- {
- prePointLoc = pointLoc;
- curPointLoc = pointLoc;
- GesturePointOffset gesturePointMovement = new GesturePointOffset(0, 0);
- gesturePointOffsetList.Add(gesturePointMovement);
- return;
- }
- else
- {
- //Debug.Log("interval:" + interval.ToString());
- timer += Time.deltaTime;
- if (timer >= interval)
- {
- timer = 0f;
- curPointLoc = pointLoc;
- float distance = Vector2.Distance(prePointLoc, curPointLoc);
- 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;
- }
- }
- }
- }
- public float CompareGesture(GestureManager anotherGesture)
- {
- float score = 0f;
- if (this.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);
- 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 distanceScore = 0f;
- if (distanceMin == 0)
- {
- distanceScore = 1f;
- }
- else
- {
- distanceScore = distanceMin / distanceMax;
- }
- float angleDitance1 = angleMax - angleMin;
- float angleDitance2 = 360 - angleDitance1;
- float angleScore = 1 - (Mathf.Min(angleDitance1, angleDitance2) / 180);
- score = score * (i / (i + 1f)) + (distanceScore + angleScore) / 2 * (1f / (i + 1));
- }
- // 如果长度超过公差范围,就要考虑调整score
- if ((maxGesturePoints / minGesturePoints) > (1f+ lengthTorrence))
- {
- int deltaGesturePoints = Mathf.RoundToInt(maxGesturePoints - minGesturePoints * (1f + lengthTorrence));
- score = score * (minGesturePoints / (minGesturePoints + deltaGesturePoints));
- }
- return score;
- }
- public void ResetGesture()
- {
- this.gesturePointOffsetList.Clear();
- }
- }
|