-
Notifications
You must be signed in to change notification settings - Fork 1
/
ParsedMagnetData.cs
155 lines (135 loc) · 4.94 KB
/
ParsedMagnetData.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
/**
* Dealing with raw magnet input from a Cardboard device
*/
public class ParsedMagnetData {
private struct MagnetMoment {
public float deltaTime;
public float yMagnitude;
public MagnetMoment(float deltaTime, float yMagnitude) {
this.deltaTime = deltaTime;
this.yMagnitude = yMagnitude;
}
}
private struct MagnetWindowState {
public float ratio;
public float delta;
}
private List<MagnetMoment> magnetWindow;
private MagnetWindowState currentMagnetWindow;
private float MAX_WINDOW_SECONDS = 0.1f;
#if UNITY_IOS
private float MAGNET_RATIO_MIN_THRESHOLD = 0.005f;
private float MAGNET_RATIO_MAX_THRESHOLD = 0.2f;
private float MAGNET_MAGNITUDE_THRESHOLD = 800.0f;
#else
private float MAGNET_RATIO_MIN_THRESHOLD = 0.03f;
private float MAGNET_RATIO_MAX_THRESHOLD = 0.2f;
private float MAGNET_MAGNITUDE_THRESHOLD = 200.0f;
#endif
private float STABLE_RATIO_THRESHOLD = 0.001f;
private float STABLE_DELTA_THRESHOLD = 2.0f;
private float windowLength = 0.0f;
enum TriggerState {
Negative,
Neutral,
Positive
};
private TriggerState triggerState = TriggerState.Neutral;
private bool isDown = false;
private bool isStable = false;
public ParsedMagnetData() {
Input.compass.enabled = true;
magnetWindow = new List<MagnetMoment>();
windowLength = 0.0f;
}
public void Update() {
TrimMagnetWindow();
AddToMagnetWindow();
currentMagnetWindow = CaptureMagnetWindow();
TriggerState newTriggerState = CheckTriggerState();
isStable = CheckStability();
if (!isStable) ResetState();
if (isStable && newTriggerState != TriggerState.Neutral && triggerState != newTriggerState) {
isDown = !isDown;
triggerState = newTriggerState;
}
}
private bool CheckStability() {
// Delta approximates how fast the device is moving relative to the magnet
// Ratio approximates how still the device is over time
if (MagnetAbsent()) return false;
else if(currentMagnetWindow.delta < STABLE_DELTA_THRESHOLD &&
currentMagnetWindow.ratio < 1f+STABLE_RATIO_THRESHOLD &&
currentMagnetWindow.ratio > 1f-STABLE_RATIO_THRESHOLD) return true;
return isStable;
}
private TriggerState CheckTriggerState() {
if (IsNegative()) return TriggerState.Negative;
if (IsPositive()) return TriggerState.Positive;
return TriggerState.Neutral;
}
private bool MagnetAbsent() {
return Input.compass.rawVector.magnitude < MAGNET_MAGNITUDE_THRESHOLD;
}
private bool IsNegative() {
return (currentMagnetWindow.ratio < 1f-MAGNET_RATIO_MIN_THRESHOLD &&
currentMagnetWindow.ratio > 1f-MAGNET_RATIO_MAX_THRESHOLD);
}
private bool IsPositive() {
return (currentMagnetWindow.ratio > 1f+MAGNET_RATIO_MIN_THRESHOLD &&
currentMagnetWindow.ratio < 1f+MAGNET_RATIO_MAX_THRESHOLD);
}
public void TrimMagnetWindow() {
while (windowLength > MAX_WINDOW_SECONDS) {
MagnetMoment moment = magnetWindow[0];
magnetWindow.RemoveAt(0);
windowLength -= moment.deltaTime;
}
}
public void AddToMagnetWindow() {
magnetWindow.Add(new MagnetMoment(Time.deltaTime, Input.compass.rawVector.magnitude));
windowLength += Time.deltaTime;
}
private MagnetWindowState CaptureMagnetWindow() {
MagnetWindowState newState = new MagnetWindowState();
int middle = magnetWindow.Count / 2;
List<MagnetMoment> firstHalf = magnetWindow.GetRange(0, middle);
List<MagnetMoment> lastHalf = magnetWindow.GetRange(middle, magnetWindow.Count - middle);
newState.ratio = Average(firstHalf) / Average(lastHalf);
newState.delta = Mathf.Abs(magnetWindow[magnetWindow.Count-1].yMagnitude - magnetWindow[0].yMagnitude);
return newState;
}
private float Average(List<MagnetMoment> moments) {
if (moments.Count == 0) return 0.0f;
float sum = 0.0f;
for (int index = 0; index < moments.Count; index++) {
sum += moments[index].yMagnitude;
}
return sum / moments.Count;
}
private bool IsMagnetGoingDown(float min, float max, float start) {
float minDelta = Mathf.Abs(min - start);
float maxDelta = Mathf.Abs(max - start);
return minDelta > maxDelta;
}
public bool IsDown() {
return triggerState != TriggerState.Neutral && isDown;
}
public bool IsUp() {
return triggerState != TriggerState.Neutral && !isDown;
}
public void ResetState() {
triggerState = TriggerState.Neutral;
isDown = false;
}
public void PrintDebug() {
Debug.Log("--- Magnetometer\nmagnitude: " + Input.compass.rawVector.magnitude +
"\nratio: " + currentMagnetWindow.ratio +
"\ndelta: " + currentMagnetWindow.delta +
"\nstable: " + isStable +
"\nstate: " + triggerState);
}
}