|
| 1 | +import operator |
| 2 | +import sys |
| 3 | +if getattr(sys, 'frozen', False): |
| 4 | + from collider import Collide2DPoly |
| 5 | +else: |
| 6 | + from kivy.garden.collider import Collide2DPoly |
| 7 | +import itertools |
| 8 | + |
| 9 | +__all__ = ('DataList', ) |
| 10 | + |
| 11 | +class DataList(list): |
| 12 | + |
| 13 | + def __init__(self, d, score_type, name, func='', previous=None, *largs, **kwargs): |
| 14 | + super(DataList, self).__init__(*largs, **kwargs) |
| 15 | + self.score_type = score_type |
| 16 | + ''' Possible score_type are xyt, xy, t, pts ''' |
| 17 | + self.previous = previous |
| 18 | + self.name = name |
| 19 | + self.func = func |
| 20 | + self.pts = [] |
| 21 | + self.d = d |
| 22 | + |
| 23 | + def compare_constant(self, value, op): |
| 24 | + if value.__class__ is not float and value.__class__ is not int: |
| 25 | + raise Exception('Invalid data type, %s, given to %s comparison operator.' %(type(value), op)) |
| 26 | + if self.score_type != 'pts': |
| 27 | + raise Exception("You can use the %s comparison operator only on pts." %op) |
| 28 | + result = DataList(self.d, 't', self.name, '%s_%f_%s' % (op, float(value), self.name)) |
| 29 | + result.pts = self.pts |
| 30 | + op = getattr(operator, op) |
| 31 | + result[:] = [op(t, value) for t in self.d['_pts']] |
| 32 | + return result |
| 33 | + def __lt__(self, val): |
| 34 | + return self.compare_constant(val, 'lt') |
| 35 | + def __le__(self, val): |
| 36 | + return self.compare_constant(val, 'le') |
| 37 | + def __gt__(self, val): |
| 38 | + return self.compare_constant(val, 'gt') |
| 39 | + def __ge__(self, val): |
| 40 | + return self.compare_constant(val, 'ge') |
| 41 | + |
| 42 | + def within_dist(self, value): |
| 43 | + if value.__class__ is not float and value.__class__ is not int: |
| 44 | + raise Exception('Invalid data type, %s, used in within_dist.' %type(value)) |
| 45 | + if self.score_type != 't': |
| 46 | + raise Exception("You can use the within_dist operator only on t score types.") |
| 47 | + result = DataList(self.d, 't', self.name, 'within_dist_%f_%s' % (float(value), self.name), self) |
| 48 | + result.pts = self.pts |
| 49 | + pts = self.d['_pts'] |
| 50 | + result[:] = [False, ] * len(self) |
| 51 | + points = [pts[i] for i in range(len(self)) if self[i]] |
| 52 | + for i in range(len(result)): |
| 53 | + if value >= 0: |
| 54 | + result[i] = any([point <= pts[i] < point + value for point in points]) |
| 55 | + else: |
| 56 | + result[i] = any([point + value < pts[i] <= point for point in points]) |
| 57 | + return result |
| 58 | + |
| 59 | + def __or__(self, other): |
| 60 | + if other.__class__ is not DataList: |
| 61 | + raise Exception('Invalid data type given to or (|).') |
| 62 | + score_types = (self.score_type, other.score_type) |
| 63 | + if 'pts' in score_types: |
| 64 | + raise Exception("You cannot 'or' pts type data.") |
| 65 | + if score_types[0] == score_types[1]: |
| 66 | + if score_types[0] != 't': |
| 67 | + raise Exception("You can only 'or' identical data types if they are both of type t.") |
| 68 | + if len(self) != len(other): |
| 69 | + raise Exception("You can only 'or' data types t if they are both of the same length.") |
| 70 | + result = DataList(self.d, self.score_type, self.name, 'or_'+other.name, self) |
| 71 | + result.pts = self.pts |
| 72 | + result.extend([self[i] or other[i] for i in range(len(self))]) |
| 73 | + return result |
| 74 | + raise Exception("You cannot 'or' a "+score_types[0]+' type with a '+score_types[1]+' type.') |
| 75 | + |
| 76 | + def __invert__(self): |
| 77 | + if self.score_type != 't': |
| 78 | + raise Exception("You can only 'invert' t type data.") |
| 79 | + result = DataList(self.d, self.score_type, self.name, 'invert_' + self.name, self) |
| 80 | + result.pts = self.pts |
| 81 | + result[:] = [not val for val in self] |
| 82 | + return result |
| 83 | + |
| 84 | + def __and__(self, other): |
| 85 | + if other.__class__ is not DataList: |
| 86 | + raise Exception('Invalid data type given to and (&).') |
| 87 | + score_types = (self.score_type, other.score_type) |
| 88 | + if 'pts' in score_types: |
| 89 | + raise Exception("You cannot 'and' pts type data.") |
| 90 | + if score_types[0] == score_types[1]: |
| 91 | + if score_types[0] != 't': |
| 92 | + raise Exception("You can only 'and' identical data types if they are both of type t.") |
| 93 | + if len(self) != len(other): |
| 94 | + raise Exception("You can only 'and' data types t if they are both of the same length.") |
| 95 | + result = DataList(self.d, self.score_type, self.name, 'and_'+other.name, self) |
| 96 | + result.pts = self.pts |
| 97 | + result.extend([self[i] and other[i] for i in range(len(self))]) |
| 98 | + return result |
| 99 | + if 't' in score_types: |
| 100 | + raise Exception("You cannot 'and' a "+score_types[0]+' type with a '+score_types[1]+' type.') |
| 101 | + a, b = self, other |
| 102 | + if score_types[0] == 'xyt': |
| 103 | + a, b = b, a |
| 104 | + collider = Collide2DPoly([p for p in itertools.chain.from_iterable(a)], cache=True) |
| 105 | + result = DataList(b.d, 't', b.name, 'and_'+a.name, b) |
| 106 | + result.pts = b.pts |
| 107 | + result.extend([b[i] in collider for i in range(len(b))]) |
| 108 | + return result |
| 109 | + |
| 110 | +# A scaler result from an operation on array |
| 111 | +class DataResult(float): |
| 112 | + |
| 113 | + def __new__(cls, previous=None, *largs, **kwargs): |
| 114 | + obj = float.__new__(cls, *largs, **kwargs) |
| 115 | + obj.previous = previous |
| 116 | + return obj |
| 117 | + |
| 118 | +def esum(data): |
| 119 | + return DataResult(data, sum(data)) |
| 120 | +def emin(data): |
| 121 | + return DataResult(data, min(data)) |
| 122 | +def emax(data): |
| 123 | + return DataResult(data, max(data)) |
| 124 | +def elen(data): |
| 125 | + return DataResult(data, len(data)) |
| 126 | + |
| 127 | +def event(data): |
| 128 | + if data.__class__ is not DataList: |
| 129 | + raise Exception('Invalid data type given to event().') |
| 130 | + if data.score_type != 't': |
| 131 | + raise Exception('Only t type channels can be given to event().') |
| 132 | + pts = data.d['_pts'] |
| 133 | + result = DataList(data.d, data.score_type, data.name, 'event', data) |
| 134 | + start = -1 |
| 135 | + for i in range(len(data)): |
| 136 | + if data[i] and start == -1: |
| 137 | + start = i |
| 138 | + if start != -1 and (i + 1 == len(data) or not data[i + 1]): |
| 139 | + result.append(pts[i] - pts[start]) |
| 140 | + result.pts.append(start) |
| 141 | + start = -1 |
| 142 | + return result |
| 143 | + |
| 144 | +def export_data(d, channels): |
| 145 | + result = [0, ] * len(channels) |
| 146 | + for i in range(len(channels)): |
| 147 | + lines = channels[i].split('\n') |
| 148 | + lines = [line for line in lines if line] |
| 149 | + exec('\n'.join(lines[:-1])) |
| 150 | + result[i] = eval(lines[-1]) |
| 151 | + return result |
0 commit comments