~ubuntu-branches/debian/jessie/python-expyriment/jessie

« back to all changes in this revision

Viewing changes to expyriment/stimuli/extras/_lcdsymbol.py

  • Committer: Package Import Robot
  • Author(s): Oliver Lindemann
  • Date: 2014-03-26 14:35:33 UTC
  • Revision ID: package-import@ubuntu.com-20140326143533-w5emkoy0zq64ybfn
Tags: upstream-0.7.0+git34-g55a4e7e
ImportĀ upstreamĀ versionĀ 0.7.0+git34-g55a4e7e

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#!/usr/bin/env python
 
2
 
 
3
"""
 
4
A LCD symbol.
 
5
 
 
6
This module contains a class implementing a LCD symbol.
 
7
 
 
8
"""
 
9
 
 
10
__author__ = 'Florian Krause <florian@expyriment.org>, \
 
11
Oliver Lindemann <oliver@expyriment.org>'
 
12
__version__ = '0.7.0'
 
13
__revision__ = '55a4e7e'
 
14
__date__ = 'Wed Mar 26 14:33:37 2014 +0100'
 
15
 
 
16
 
 
17
import math
 
18
import copy
 
19
 
 
20
import pygame
 
21
 
 
22
import defaults
 
23
import expyriment
 
24
from expyriment.stimuli._visual import Visual
 
25
from expyriment.stimuli.extras._polygondot import PolygonDot
 
26
 
 
27
 
 
28
class LcdSymbol(Visual):
 
29
    """A LCD symbol class.
 
30
 
 
31
    IDs for points and line ::
 
32
 
 
33
    Point=      Lines =
 
34
    0---1         X-0-X
 
35
    |   |         1   2
 
36
    2---3         X-3-X
 
37
    |   |         4   5
 
38
    4---5         X-6-X
 
39
 
 
40
    Valid shapes are:
 
41
        '0','1','2','3','4','5','6','7','8','9'
 
42
        'A','C','E','F','U','H','L','P','h'
 
43
 
 
44
    """
 
45
 
 
46
    _shapes = {"0":(0, 1, 2, 4, 5, 6),
 
47
              "1":(2, 5),
 
48
              "2":(0, 2, 3, 4, 6),
 
49
              "3":(0, 2, 3, 5, 6),
 
50
              "4":(1, 2, 3, 5),
 
51
              "5":(0, 1, 3, 5, 6),
 
52
              "6":(0, 1, 3, 4, 5, 6),
 
53
              "7":(0, 2 , 5),
 
54
              "8":(0, 1, 2 , 3 , 4 , 5 , 6),
 
55
              "9":(0, 1 , 2 , 3 , 5, 6),
 
56
              "A":(0, 1, 2, 3, 4, 5),
 
57
              "C":(0, 1, 4, 6),
 
58
              "E":(0, 1, 3, 4, 6),
 
59
              "F":(0, 1, 3, 4),
 
60
              "U":(1, 4, 6, 5, 2),
 
61
              "H":(1, 2, 3, 4, 5),
 
62
              "L":(1, 4, 6),
 
63
              "P":(0, 1, 2, 3, 4),
 
64
              "h":(1, 3, 4, 5)
 
65
              }
 
66
 
 
67
    _lines = ((0, 1), (0, 2), (1, 3), (2, 3), (2, 4), (3, 5), (4, 5))
 
68
 
 
69
    def __init__(self, shape, position=None, size=None, colour=None,
 
70
                 inactive_colour=None, background_colour=None,
 
71
                 line_width=None, gap=None, simple_lines=None):
 
72
        """Create a LCD symbol.
 
73
 
 
74
        Parameters
 
75
        ----------
 
76
        shape : list
 
77
            shape to show
 
78
        position : (int, int), optional
 
79
            position to show the symbol
 
80
        size : (int, int)
 
81
            size of the LCD symbol
 
82
        colour : (int, int, int), optional
 
83
            LCD symbol colour
 
84
        inactive_colour : (int, int, int), optional
 
85
            colour of inactive lines
 
86
        background_colour : (int, int, int), optional
 
87
        line_width : int, optional
 
88
            width of the lines
 
89
        gap :int, optional
 
90
            gap between lines
 
91
        simple_lines : bool, optional
 
92
            use simple lines
 
93
 
 
94
        """
 
95
 
 
96
        Visual.__init__(self, position)
 
97
        if shape in self._shapes:
 
98
            self._shape = self._shapes[shape]
 
99
        else:
 
100
            self._shape = shape
 
101
        if size is not None:
 
102
            self._width = size[0]
 
103
            self._height = size[1]
 
104
        else:
 
105
            size = defaults.lcdsymbol_size
 
106
            if size is None:
 
107
                try:
 
108
                    size = expyriment._active_exp.screen.surface.get_size()
 
109
                except:
 
110
                    raise RuntimeError("Could not get size of screen!")
 
111
            self._width = size[0]
 
112
            self._height = size[1]
 
113
        if colour is None:
 
114
            colour = defaults.lcdsymbol_colour
 
115
        if colour is not None:
 
116
            self._colour = colour
 
117
        else:
 
118
            self._colour = expyriment._active_exp.foreground_colour
 
119
        if inactive_colour is not None:
 
120
            self._inactive_colour = inactive_colour
 
121
        else:
 
122
            self._inactive_colour = \
 
123
                    defaults.lcdsymbol_inactive_colour
 
124
        if background_colour is not None:
 
125
            self._background_colour = background_colour
 
126
        else:
 
127
            self._background_colour = \
 
128
                    defaults.lcdsymbol_background_colour
 
129
        if line_width is not None:
 
130
            self._line_width = line_width
 
131
        else:
 
132
            self._line_width = defaults.lcdsymbol_line_width
 
133
        if gap is not None:
 
134
            self._gap = gap
 
135
        else:
 
136
            self._gap = defaults.lcdsymbol_gap
 
137
        if simple_lines is not None:
 
138
            self._simple_lines = simple_lines
 
139
        else:
 
140
            self._simple_lines = defaults.lcdsymbol_simple_lines
 
141
 
 
142
        x = int(self.line_width / 2.0) + 1
 
143
        self._points = (PolygonDot(radius=0, position=(x, x)),
 
144
                        PolygonDot(radius=0, position=(self._width - x, x)), \
 
145
                        PolygonDot(radius=0,
 
146
                            position=(x, math.floor(self._height / 2))), \
 
147
                        PolygonDot(radius=0,
 
148
                            position=(self._width - x,
 
149
                                      math.floor(self._height / 2))), \
 
150
                        PolygonDot(radius=0, position=(x, self._height - x)), \
 
151
                        PolygonDot(radius=0,
 
152
                            position=(self._width - x, self._height - x)))
 
153
        expyriment.stimuli._stimulus.Stimulus._id_counter -= 6
 
154
 
 
155
    _getter_exception_message = "Cannot set {0} if surface exists!"
 
156
 
 
157
    @property
 
158
    def shape(self):
 
159
        """Getter for shape."""
 
160
 
 
161
        return self._shape
 
162
 
 
163
    @shape.setter
 
164
    def shape(self, value):
 
165
        """Setter for shape."""
 
166
 
 
167
        if self.has_surface:
 
168
                raise AttributeError(
 
169
                    LcdSymbol._getter_exception_message.format("shape"))
 
170
        else:
 
171
            if value in self.shapes:
 
172
                self._shape = self.shapes[value]
 
173
            else:
 
174
                self._shape = value
 
175
 
 
176
    @property
 
177
    def size(self):
 
178
        """Getter for size."""
 
179
 
 
180
        return (self._width, self._height)
 
181
 
 
182
    @size.setter
 
183
    def size(self, value):
 
184
        """Setter for size."""
 
185
 
 
186
        if self.has_surface:
 
187
                raise AttributeError(
 
188
                    LcdSymbol._getter_exception_message.format("shape"))
 
189
        else:
 
190
            self._width = value[0]
 
191
            self._height = value[1]
 
192
            self._points = (PolygonDot(radius=0, position=(0, 0)),
 
193
                           PolygonDot(radius=0, position=(self._width, 0)),
 
194
                           PolygonDot(radisu=0,
 
195
                               position=(0, math.floor(self._height / 2))),
 
196
                           PolygonDot(radius=0, position=(self._width,
 
197
                                         math.floor(self._height / 2))),
 
198
                           PolygonDot(radius=0, position=(0, self._height)),
 
199
                           PolygonDot(radius=0, position=(self._width, self._height)))
 
200
            expyriment.stimuli._stimulus.Stimulus._id_counter -= 6
 
201
 
 
202
    @property
 
203
    def colour(self):
 
204
        """Getter for colour."""
 
205
 
 
206
        return self._colour
 
207
 
 
208
    @colour.setter
 
209
    def colour(self, value):
 
210
        """Setter for colour."""
 
211
 
 
212
        if self.has_surface:
 
213
                raise AttributeError(
 
214
                    LcdSymbol._getter_exception_message.format("colour"))
 
215
        else:
 
216
            self._colour = value
 
217
 
 
218
    @property
 
219
    def inactive_colour(self):
 
220
        """Getter for inactive_colour."""
 
221
 
 
222
        return self._inactive_colour
 
223
 
 
224
    @inactive_colour.setter
 
225
    def inactive_colour(self, value):
 
226
        """Setter for inactive_colour."""
 
227
 
 
228
        if self.has_surface:
 
229
                raise AttributeError(
 
230
                    LcdSymbol._getter_exception_message.format(
 
231
                        "inactive_colour"))
 
232
        else:
 
233
            self._inactive_colour = value
 
234
 
 
235
    @property
 
236
    def background_colour(self):
 
237
        """Getter for background_colour."""
 
238
 
 
239
        return self._background_colour
 
240
 
 
241
    @background_colour.setter
 
242
    def background_colour(self, value):
 
243
        """Setter for background_colour."""
 
244
 
 
245
        if self.has_surface:
 
246
                raise AttributeError(
 
247
                    LcdSymbol._getter_exception_message.format(
 
248
                        "background_colour"))
 
249
        else:
 
250
            self._background_colour = value
 
251
 
 
252
    @property
 
253
    def line_width(self):
 
254
        """Getter for line_width."""
 
255
 
 
256
        return self._line_width
 
257
 
 
258
    @line_width.setter
 
259
    def line_width(self, value):
 
260
        """Setter for line_width."""
 
261
 
 
262
        if self.has_surface:
 
263
                raise AttributeError(
 
264
                    LcdSymbol._getter_exception_message.format("line_width"))
 
265
        else:
 
266
            self._line_width = value
 
267
 
 
268
    @property
 
269
    def gap(self):
 
270
        """Getter for gap."""
 
271
 
 
272
        return self._gap
 
273
 
 
274
    @gap.setter
 
275
    def gap(self, value):
 
276
        """Setter for gap."""
 
277
 
 
278
        if self.has_surface:
 
279
                raise AttributeError(
 
280
                    LcdSymbol._getter_exception_message.format("gap"))
 
281
        else:
 
282
            self._gap = value
 
283
 
 
284
    @property
 
285
    def simple_lines(self):
 
286
        """Getter for simple_lines."""
 
287
 
 
288
        return self._simple_lines
 
289
 
 
290
    @simple_lines.setter
 
291
    def simple_lines(self, value):
 
292
        """Setter for simple_lines."""
 
293
 
 
294
        if self.has_surface:
 
295
                raise AttributeError(
 
296
                    LcdSymbol._getter_exception_message.format(
 
297
                        "simple_lines"))
 
298
        else:
 
299
            self._simple_lines = value
 
300
 
 
301
    @property
 
302
    def points(self):
 
303
        """Getter for points."""
 
304
 
 
305
        return self._points
 
306
 
 
307
    def _create_surface(self):
 
308
        """Create the surface of the stimulus."""
 
309
 
 
310
        surface = pygame.surface.Surface((self._width, self._height),
 
311
                                        pygame.SRCALPHA).convert_alpha()
 
312
        if self.background_colour is not None:
 
313
            surface.fill(self.background_colour)
 
314
        if self.inactive_colour is not None:
 
315
            #draw background
 
316
            for x in self._shapes["8"]:
 
317
                moved_poly = []
 
318
                for p in self.get_line_polygon(x):
 
319
                    moved_poly.append((p[0], p[1]))
 
320
                pygame.draw.polygon(surface, self.inactive_colour,
 
321
                                    moved_poly, 0)
 
322
        if len(self._shape) > 0:
 
323
            for x in self._shape:
 
324
                moved_poly = []
 
325
                for p in self.get_line_polygon(x):
 
326
                    moved_poly.append((p[0], p[1]))
 
327
                pygame.draw.polygon(surface, self.colour, moved_poly, 0)
 
328
        return surface
 
329
 
 
330
    def get_line_points(self, idx):
 
331
        """Return point tuple including start and end point of a line.
 
332
 
 
333
        Parameters
 
334
        ----------
 
335
        idx : int
 
336
            index of the line
 
337
 
 
338
        Returns
 
339
        -------
 
340
        points : ((int, int), (int,int))
 
341
            point tuple including start and end point of a line
 
342
 
 
343
        """
 
344
 
 
345
        if idx == 0 or idx == 3 or idx == 6 : # horizontal line
 
346
            p1 = copy.copy(self.points[self._lines[idx][0]])
 
347
            p2 = copy.copy(self.points[self._lines[idx][1]])
 
348
            p1.position[0] = p1.position[0] + self.gap
 
349
            p2.position[0] = p2.position[0] - self.gap
 
350
            return (p1.position, p2.position)
 
351
        elif idx == 1 or idx == 2 or idx == 4 or idx == 5: # vertical line
 
352
            p1 = copy.copy(self.points[self._lines[idx][0]])
 
353
            p2 = copy.copy(self.points[self._lines[idx][1]])
 
354
            p1.position[1] = p1.position[1] + self.gap
 
355
            p2.position[1] = p2.position[1] - self.gap
 
356
            return (p1.position, p2.position)
 
357
        else:
 
358
            return ()
 
359
 
 
360
    def get_line_polygon(self, idx):
 
361
        """Return point list describing the line as polygon.
 
362
 
 
363
        Parameters
 
364
        ----------
 
365
        idx : int
 
366
            index of the line (int)
 
367
 
 
368
        Returns
 
369
        -------
 
370
        point : list of tuple
 
371
        """
 
372
 
 
373
        if idx == 0 or idx == 3 or idx == 6 : # horizontal line
 
374
            return self._line_to_polygon(self.points[self._lines[idx][0]], \
 
375
                                     self.points[self._lines[idx][1]], True)
 
376
        elif idx == 1 or idx == 2 or idx == 4 or idx == 5: # vertical line
 
377
            return self._line_to_polygon(self.points[self._lines[idx][0]], \
 
378
                                     self.points[self._lines[idx][1]], False)
 
379
        else:
 
380
            return ()
 
381
 
 
382
    def _line_to_polygon(self, start, end, horizontal):
 
383
        """Convert a line defined by start and end points to a polygon.
 
384
 
 
385
        Parameters
 
386
        ----------
 
387
        start : int
 
388
            start point
 
389
        end : int
 
390
            end point
 
391
        horizontal : bool
 
392
            True or False
 
393
 
 
394
        """
 
395
 
 
396
        w2 = math.floor((self.line_width - 1) / 2)
 
397
        if w2 <= 0:
 
398
            w2 = 1
 
399
        poly = []
 
400
        poly.append(copy.copy(start.position))
 
401
        p = PolygonDot(radius=0, position=(0, 0))
 
402
        expyriment.stimuli._stimulus.Stimulus._id_counter -= 1
 
403
        if horizontal:
 
404
            p.position[0] = start.position[0] + self.gap
 
405
            p.position[1] = start.position[1] - w2
 
406
            poly.append(copy.copy(p.position))
 
407
            p.position[0] = end.position[0] - self.gap
 
408
            poly.append(copy.copy(p.position))
 
409
            poly.append(copy.copy(end.position))
 
410
            p.position[0] = end.position[0] - self.gap
 
411
            p.position[1] = end.position[1] + w2
 
412
            poly.append(copy.copy(p.position))
 
413
            p.position[0] = start.position[0] + self.gap
 
414
            poly.append(copy.copy(p.position))
 
415
        else:
 
416
            p.position[0] = start.position[0] + w2
 
417
            p.position[1] = start.position[1] + self.gap
 
418
            poly.append(copy.copy(p.position))
 
419
            p.position[1] = end.position[1] - self.gap
 
420
            poly.append(copy.copy(p.position))
 
421
            poly.append(copy.copy(end.position))
 
422
            p.position[0] = end.position[0] - w2
 
423
            p.position[1] = end.position[1] - self.gap
 
424
            poly.append(copy.copy(p.position))
 
425
            p.position[1] = start.position[1] + self.gap
 
426
            poly.append(copy.copy(p.position))
 
427
 
 
428
        if self.simple_lines:
 
429
            poly.pop(3)
 
430
            poly.pop(0)
 
431
 
 
432
        return tuple(poly)
 
433
 
 
434
 
 
435
if __name__ == "__main__":
 
436
    from expyriment import control
 
437
    control.set_develop_mode(True)
 
438
    defaults.event_logging = 0
 
439
    exp = control.initialize()
 
440
    lcdsymbol = LcdSymbol("A", size=(100, 100))
 
441
    lcdsymbol.present()
 
442
    exp.clock.wait(1000)