1
2
3 """Pure python/pype landing zone (aka fixwin) implementation.
4
5 Not really for public consumption.
6
7 Author -- James A. Mazer (mazerj@gmail.com)
8
9 """
10
11 import sys
12 import imp
13 import math
14
15 from pype import *
16
17 import filebox
18
20 """
21 Circular Landing zone detector -- this is sort of like a FixWin,
22 but all done in pype (vs comedi_server subproc). A landing
23 zone is circular region located at (x,y) with a radius of size
24 pixels. Once the eyes enter the landing zone, a counter is
25 started. If the eyes are still in the landing zone after fixtime,
26 then it's considered a landing event the .inside() method returns
27 one.
28
29 This depends on the .inside() method being in some sort of
30 tight loop and called over and over again until something
31 happens, otherwise you might miss exit/entry events..
32
33 Eyes must stay inside the zone for fixtime_ms before it's
34 considered a fixation insize the zone. Use fixtime_ms=0 if
35 you want to accept pass throughs w/o fixations.
36
37 """
38
39 - def __init__(self, x, y, size, fixtime, app):
40 self.app = app
41 self.icon = None
42 self.x, self.y, self.size = x, y, size
43 self.size2 = size**2
44 self.fixtime = fixtime
45 self.entered_at = None
46
49
50 - def inside(self, t=None, x=None, y=None):
51 """
52 If you have multiple landing zones, you can sit in a loop, use
53 app.eye_txy() to query time and eye position ONCE, and then apply
54 it to multiple landing zones by passing in (x,y) values
55
56 """
57 if t is None:
58 (t, x, y) = self.app.eye_txy()
59 if ((self.x-x)**2 + (self.y-y)**2) < self.size2:
60 if self.entered_at is None:
61 self.entered_at = t
62 if (t - self.entered_at) >= self.fixtime:
63 return 1
64 return 0
65 else:
66 self.entered_at = None
67 return 0
68
69 - def draw(self, color='grey', dash=None, text=None):
70 self.clear()
71 self.icon = self.app.udpy.icon(self.x, self.y,
72 2*self.size, 2*self.size*self.vbias,
73 color=color, type=2, dash=dash)
74
76 if self.icon:
77 self.app.udpy.icon(self.icon)
78 self.icon = None
79
81 """
82 Sector-style Landing zone detector -- landing zone is defined
83 as an angular sector of an annular zone around a fixation
84 spot (xo, yo). Annular sector runs from inner_pix to outer_pix
85 and has an angular subtense of angle_deg +- subtense_deg.
86
87 Eyes must stay inside the zone for fixtime_ms before it's
88 considered a fixation insize the zone. Use fixtime_ms=0 if
89 you want to accept pass throughs w/o fixations.
90
91 See LandingZone for additional details about usage.
92
93 """
94
95 - def __init__(self, xo, yo,
96 inner_pix, outer_pix, angle_deg, subtense_deg,
97 fixtime_ms, app):
98 self.app = app
99 self.icon = None
100 self.xo, self.yo = xo, yo
101 self.inner = inner_pix
102 self.outer = outer_pix
103 self.angle = math.pi * angle_deg / 180.0
104 self.subtense = math.pi * subtense_deg / 180.0
105 self.fixtime = fixtime_ms
106 self.entered_at = None
107
110
111 - def inside(self, t=None, x=None, y=None):
112 """
113 If you have multiple landing zones, you can sit in a loop, use
114 app.eye_txy() to query time and eye position ONCE, and then apply
115 it to multiple landing zones by passing in (x,y) values
116
117 """
118 if t is None:
119 (t, x, y) = self.app.eye_txy()
120
121 x, y = x - self.xo, y - self.yo
122 r = (x**2 + y**2)**0.5
123 if (r > self.inner) and (r < self.outer):
124 d = abs(math.pi * math.atan2(y, x) - self.angle)
125 if d > pi:
126 d = (2 * math.pi) - d
127 if d < self.subtense:
128
129 if self.entered_at is None:
130 self.entered_at = t
131 if (t - self.entered_at) >= self.fixtime:
132 return 1
133 return 0
134 else:
135 self.entered_at = None
136 return 0
137
138 - def draw(self, color='grey', dash=None, text=None):
139 x = self.xo + (self.inner+self.outer)/2.0 + math.cos(self.angle)
140 y = self.xo + (self.inner+self.outer)/2.0 + math.sin(self.angle)
141 self.clear()
142 self.icon = self.app.udpy.icon(x, y,
143 self.outer-self.inter,
144 self.outer-self.inter,
145 color=color, type=1, dash=dash)
146
148 if self.icon:
149 self.app.udpy.icon(self.icon)
150 self.icon = None
151
152 if __name__ == '__main__':
153 sys.stderr.write('%s should never be loaded as main.\n' % __file__)
154 sys.exit(1)
155