-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathmetrics.py
148 lines (117 loc) · 4.94 KB
/
metrics.py
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
from abc import ABC
from typing import Iterator, Union, Type, List
import analysis.p_types as p_types
from analysis.itxyek_base import ITXYEK, XYPoint
from analysis.metrics_base import MetricValueUndefined, METRIC_TYPE
from analysis.physics import AngleCalc, Velocity, Acceleration
"""
When calculating angle, speed, etc. using only the last 2 points
causes huge errors at low mouse speeds,
due to pixels being chessboard-like boxes.
"""
class _EntryOrExitHandler(ABC):
MAX_EXTRA_INDEX = 5
def __init__(self, crit_index: int, all_itxyek: ITXYEK):
self.x_list = all_itxyek.x
self.y_list = all_itxyek.y
self.t_list = all_itxyek.time
self.crit_index = crit_index
self.max_index = all_itxyek.indices[-1]
def index_too_small(self) -> bool:
return self.index_total_less_than_0()
def index_too_large(self) -> bool:
return self.index_exceeds_max_array()
def index_exceeds_max_array(self) -> bool:
return self.crit_index + self.MAX_EXTRA_INDEX > self.max_index
def index_total_less_than_0(self) -> bool:
return self.crit_index - self.MAX_EXTRA_INDEX < 0
def point_n(self, extra_index) -> XYPoint:
index = self.crit_index + extra_index
return XYPoint(self.x_list[index], self.y_list[index])
class ExitHandler(_EntryOrExitHandler):
def angle(self) -> METRIC_TYPE:
if self.index_too_small():
return MetricValueUndefined
xy1 = self.point_n(-1)
xy2 = self.point_n(0)
if Velocity().distance_too_small(xy1=xy1, xy2=xy2):
xy1 = self.point_n(-4)
return AngleCalc().angle(xy1=xy1, xy2=xy2)
def velocity(self) -> METRIC_TYPE:
if self.index_too_small():
return MetricValueUndefined
xy1 = self.point_n(-1)
xy2 = self.point_n(0)
if Velocity().distance_too_small(xy1=xy1, xy2=xy2):
xy1 = self.point_n(-4)
return Velocity().v(xy1=xy1, xy2=xy2)
def acceleration(self) -> METRIC_TYPE:
if self.index_too_small():
return MetricValueUndefined
xy1 = self.point_n(-2)
xy2 = self.point_n(-1)
xy3 = self.point_n(0)
return Acceleration().a(xy1=xy1, xy2=xy2, xy3=xy3)
class EntryHandler(_EntryOrExitHandler):
def angle(self) -> METRIC_TYPE:
if self.index_too_large():
return MetricValueUndefined
xy1 = self.point_n(0)
xy2 = self.point_n(1)
if Velocity().distance_too_small(xy1=xy1, xy2=xy2):
xy2 = self.point_n(4)
return AngleCalc().angle(xy1=xy1, xy2=xy2)
def velocity(self) -> METRIC_TYPE:
if self.index_too_large():
return MetricValueUndefined
xy1 = self.point_n(0)
xy2 = self.point_n(1)
if Velocity().distance_too_small(xy1=xy1, xy2=xy2):
xy2 = self.point_n(4)
return Velocity().v(xy1=xy1, xy2=xy2)
def acceleration(self) -> METRIC_TYPE:
if self.index_too_large():
return MetricValueUndefined
xy1 = self.point_n(0)
xy2 = self.point_n(1)
xy3 = self.point_n(2)
return Acceleration().a(xy1=xy1, xy2=xy2, xy3=xy3)
ENTRY_OR_EXIT_HANDLER = Type[Union[ExitHandler, EntryHandler]]
class _MetricsCalculator:
def __init__(self, all_itxyek: ITXYEK, crit_type: p_types.EntryOrExit, crit_indices: Iterator[int]):
self.crit_indices = crit_indices
self.crit_type = crit_type
self.all_itxyek = all_itxyek
self.point_handler: ENTRY_OR_EXIT_HANDLER = self._point_handler()
def _point_handler(self):
if self.crit_type == p_types.Exit():
return ExitHandler
else:
return EntryHandler
def critical_angles(self) -> List[float]:
angles = []
for i in self.crit_indices:
handler = self.point_handler(crit_index=i, all_itxyek=self.all_itxyek)
angle = handler.angle()
angles.append(angle)
return angles
def critical_speeds(self) -> List[float]:
speeds = []
for i in self.crit_indices:
handler = self.point_handler(crit_index=i, all_itxyek=self.all_itxyek)
speed = handler.velocity()
speeds.append(speed)
return speeds
def critical_accelerations(self) -> List[float]:
accelerations = []
for i in self.crit_indices:
handler = self.point_handler(crit_index=i, all_itxyek=self.all_itxyek)
acceleration = handler.acceleration()
accelerations.append(acceleration)
return accelerations
class ExitMetricsCalc(_MetricsCalculator):
def __init__(self, all_itxyek: ITXYEK, crit_indices: Iterator[int]):
super().__init__(all_itxyek=all_itxyek, crit_type=p_types.Exit(), crit_indices=crit_indices)
class EntryMetricsCalc(_MetricsCalculator):
def __init__(self, all_itxyek: ITXYEK, crit_indices: Iterator[int]):
super().__init__(all_itxyek=all_itxyek, crit_type=p_types.Entry(), crit_indices=crit_indices)