1
2cdef class BooleanSelector(SelectorObject):
3
4    def __init__(self, dobj):
5        # Note that this has a different API than the other selector objects,
6        # so will not work as a traditional data selector.
7        if not hasattr(dobj.dobj1, "selector"):
8            self.sel1 = dobj.dobj1
9        else:
10            self.sel1 = dobj.dobj1.selector
11        if not hasattr(dobj.dobj2, "selector"):
12            self.sel2 = dobj.dobj2
13        else:
14            self.sel2 = dobj.dobj2.selector
15
16cdef class BooleanANDSelector(BooleanSelector):
17    cdef int select_bbox(self, np.float64_t left_edge[3],
18                               np.float64_t right_edge[3]) nogil:
19        cdef int rv1 = self.sel1.select_bbox(left_edge, right_edge)
20        if rv1 == 0: return 0
21        cdef int rv2 = self.sel2.select_bbox(left_edge, right_edge)
22        if rv2 == 0: return 0
23        return 1
24
25    cdef int select_bbox_edge(self, np.float64_t left_edge[3],
26                              np.float64_t right_edge[3]) nogil:
27        cdef int rv1 = self.sel1.select_bbox_edge(left_edge, right_edge)
28        if rv1 == 0: return 0
29        cdef int rv2 = self.sel2.select_bbox_edge(left_edge, right_edge)
30        if rv2 == 0: return 0
31        return max(rv1, rv2)
32
33    cdef int select_grid(self, np.float64_t left_edge[3],
34                         np.float64_t right_edge[3], np.int32_t level,
35                         Oct *o = NULL) nogil:
36        cdef int rv1 = self.sel1.select_grid(left_edge, right_edge, level, o)
37        if rv1 == 0: return 0
38        cdef int rv2 = self.sel2.select_grid(left_edge, right_edge, level, o)
39        if rv2 == 0: return 0
40        return 1
41
42    cdef int select_cell(self, np.float64_t pos[3], np.float64_t dds[3]) nogil:
43        cdef int rv1 = self.sel1.select_cell(pos, dds)
44        if rv1 == 0: return 0
45        cdef int rv2 = self.sel2.select_cell(pos, dds)
46        if rv2 == 0: return 0
47        return 1
48
49    cdef int select_point(self, np.float64_t pos[3]) nogil:
50        cdef int rv1 = self.sel1.select_point(pos)
51        if rv1 == 0: return 0
52        cdef int rv2 = self.sel2.select_point(pos)
53        if rv2 == 0: return 0
54        return 1
55
56    cdef int select_sphere(self, np.float64_t pos[3], np.float64_t radius) nogil:
57        cdef int rv1 = self.sel1.select_sphere(pos, radius)
58        if rv1 == 0: return 0
59        cdef int rv2 = self.sel2.select_sphere(pos, radius)
60        if rv2 == 0: return 0
61        return 1
62
63    def _hash_vals(self):
64        return (self.sel1._hash_vals() +
65                ("and",) +
66                self.sel2._hash_vals())
67
68cdef class BooleanORSelector(BooleanSelector):
69    cdef int select_bbox(self, np.float64_t left_edge[3],
70                               np.float64_t right_edge[3]) nogil:
71        cdef int rv1 = self.sel1.select_bbox(left_edge, right_edge)
72        if rv1 == 1: return 1
73        cdef int rv2 = self.sel2.select_bbox(left_edge, right_edge)
74        if rv2 == 1: return 1
75        return 0
76
77    cdef int select_bbox_edge(self, np.float64_t left_edge[3],
78                              np.float64_t right_edge[3]) nogil:
79        cdef int rv1 = self.sel1.select_bbox_edge(left_edge, right_edge)
80        if rv1 == 1: return 1
81        cdef int rv2 = self.sel2.select_bbox_edge(left_edge, right_edge)
82        if rv2 == 1: return 1
83        return max(rv1, rv2)
84
85    cdef int select_grid(self, np.float64_t left_edge[3],
86                         np.float64_t right_edge[3], np.int32_t level,
87                         Oct *o = NULL) nogil:
88        cdef int rv1 = self.sel1.select_grid(left_edge, right_edge, level, o)
89        if rv1 == 1: return 1
90        cdef int rv2 = self.sel2.select_grid(left_edge, right_edge, level, o)
91        if rv2 == 1: return 1
92        if (rv1 == 2) or (rv2 == 2): return 2
93        return 0
94
95    cdef int select_cell(self, np.float64_t pos[3], np.float64_t dds[3]) nogil:
96        cdef int rv1 = self.sel1.select_cell(pos, dds)
97        if rv1 == 1: return 1
98        cdef int rv2 = self.sel2.select_cell(pos, dds)
99        if rv2 == 1: return 1
100        return 0
101
102    cdef int select_point(self, np.float64_t pos[3]) nogil:
103        cdef int rv1 = self.sel1.select_point(pos)
104        if rv1 == 1: return 1
105        cdef int rv2 = self.sel2.select_point(pos)
106        if rv2 == 1: return 1
107        return 0
108
109    cdef int select_sphere(self, np.float64_t pos[3], np.float64_t radius) nogil:
110        cdef int rv1 = self.sel1.select_sphere(pos, radius)
111        if rv1 == 1: return 1
112        cdef int rv2 = self.sel2.select_sphere(pos, radius)
113        if rv2 == 1: return 1
114        return 0
115
116    def _hash_vals(self):
117        return (self.sel1._hash_vals() +
118                ("or",) +
119                self.sel2._hash_vals())
120
121cdef class BooleanNOTSelector(BooleanSelector):
122    cdef int select_bbox(self, np.float64_t left_edge[3],
123                               np.float64_t right_edge[3]) nogil:
124        # We always return True here, because we don't have a "fully included"
125        # check anywhere else.
126        return 1
127
128    cdef int select_bbox_edge(self, np.float64_t left_edge[3],
129                              np.float64_t right_edge[3]) nogil:
130        cdef int rv1 = self.sel1.select_bbox_edge(left_edge, right_edge)
131        if rv1 == 0: return 1
132        elif rv1 == 1: return 0
133        return 2
134
135    cdef int select_grid(self, np.float64_t left_edge[3],
136                         np.float64_t right_edge[3], np.int32_t level,
137                         Oct *o = NULL) nogil:
138        return 1
139
140    cdef int select_cell(self, np.float64_t pos[3], np.float64_t dds[3]) nogil:
141        cdef int rv1 = self.sel1.select_cell(pos, dds)
142        if rv1 == 0: return 1
143        return 0
144
145    cdef int select_point(self, np.float64_t pos[3]) nogil:
146        cdef int rv1 = self.sel1.select_point(pos)
147        if rv1 == 0: return 1
148        return 0
149
150    cdef int select_sphere(self, np.float64_t pos[3], np.float64_t radius) nogil:
151        cdef int rv1 = self.sel1.select_sphere(pos, radius)
152        if rv1 == 0: return 1
153        return 0
154
155    def _hash_vals(self):
156        return (self.sel1._hash_vals() +
157                ("not",))
158
159cdef class BooleanXORSelector(BooleanSelector):
160
161    cdef int select_bbox(self, np.float64_t left_edge[3],
162                               np.float64_t right_edge[3]) nogil:
163        # We always return True here, because we don't have a "fully included"
164        # check anywhere else.
165        return 1
166
167    cdef int select_bbox_edge(self, np.float64_t left_edge[3],
168                              np.float64_t right_edge[3]) nogil:
169        # Return 2 in cases where one or both selectors partially overlap since
170        # part of the bounding box could satisfy the condition unless the
171        # selectors are identical.
172        cdef int rv1 = self.sel1.select_bbox_edge(left_edge, right_edge)
173        cdef int rv2 = self.sel2.select_bbox_edge(left_edge, right_edge)
174        if rv1 == rv2:
175            if rv1 == 2:
176                # If not identical, part of the bbox will be touched by one
177                # selector and not the other.
178                # if self.sel1 == self.sel2: return 0  # requires gil
179                return 2
180            return 0
181        if rv1 == 0: return rv2
182        if rv2 == 0: return rv1
183        return 2  # part of bbox only touched by selector fully covering bbox
184
185    cdef int select_grid(self, np.float64_t left_edge[3],
186                         np.float64_t right_edge[3], np.int32_t level,
187                         Oct *o = NULL) nogil:
188        return 1
189
190    cdef int select_cell(self, np.float64_t pos[3], np.float64_t dds[3]) nogil:
191        cdef int rv1 = self.sel1.select_cell(pos, dds)
192        cdef int rv2 = self.sel2.select_cell(pos, dds)
193        if rv1 == rv2: return 0
194        return 1
195
196    cdef int select_point(self, np.float64_t pos[3]) nogil:
197        cdef int rv1 = self.sel1.select_point(pos)
198        cdef int rv2 = self.sel2.select_point(pos)
199        if rv1 == rv2: return 0
200        return 1
201
202    cdef int select_sphere(self, np.float64_t pos[3], np.float64_t radius) nogil:
203        cdef int rv1 = self.sel1.select_sphere(pos, radius)
204        cdef int rv2 = self.sel2.select_sphere(pos, radius)
205        if rv1 == rv2: return 0
206        return 1
207
208    def _hash_vals(self):
209        return (self.sel1._hash_vals() +
210                ("xor",) +
211                self.sel2._hash_vals())
212
213cdef class BooleanNEGSelector(BooleanSelector):
214
215    cdef int select_bbox(self, np.float64_t left_edge[3],
216                         np.float64_t right_edge[3]) nogil:
217        # We always return True here, because we don't have a "fully included"
218        # check anywhere else.
219        return self.sel1.select_bbox(left_edge, right_edge)
220
221    cdef int select_bbox_edge(self, np.float64_t left_edge[3],
222                              np.float64_t right_edge[3]) nogil:
223        cdef int rv1 = self.sel1.select_bbox_edge(left_edge, right_edge)
224        if rv1 == 0: return 0
225        cdef int rv2 = self.sel2.select_bbox_edge(left_edge, right_edge)
226        if rv2 == 1:
227            return 0
228        elif rv2 == 0:
229            return rv1
230        # If sel2 is partial, then sel1 - sel2 will be partial as long
231        # as sel1 != sel2
232        # if self.sel1 == self.sel2: return 0  # requires gil
233        return 2
234
235    cdef int select_grid(self, np.float64_t left_edge[3],
236                         np.float64_t right_edge[3], np.int32_t level,
237                         Oct *o = NULL) nogil:
238        return self.sel1.select_grid(left_edge, right_edge, level, o)
239
240    cdef int select_cell(self, np.float64_t pos[3], np.float64_t dds[3]) nogil:
241        cdef int rv1 = self.sel1.select_cell(pos, dds)
242        if rv1 == 0: return 0
243        cdef int rv2 = self.sel2.select_cell(pos, dds)
244        if rv2 == 1: return 0
245        return 1
246
247    cdef int select_point(self, np.float64_t pos[3]) nogil:
248        cdef int rv1 = self.sel1.select_point(pos)
249        if rv1 == 0: return 0
250        cdef int rv2 = self.sel2.select_point(pos)
251        if rv2 == 1: return 0
252        return 1
253
254    cdef int select_sphere(self, np.float64_t pos[3], np.float64_t radius) nogil:
255        cdef int rv1 = self.sel1.select_sphere(pos, radius)
256        if rv1 == 0: return 0
257        cdef int rv2 = self.sel2.select_sphere(pos, radius)
258        if rv2 == 1: return 0
259        return 1
260
261    def _hash_vals(self):
262        return (self.sel1._hash_vals() +
263                ("neg",) +
264                self.sel2._hash_vals())
265
266cdef class ChainedBooleanSelector(SelectorObject):
267    cdef int n_obj
268    cdef np.ndarray selectors
269    def __init__(self, dobj):
270        # These are data objects, not selectors
271        self.n_obj = len(dobj.data_objects)
272        self.selectors = np.empty(self.n_obj, dtype="object")
273        for i in range(self.n_obj):
274            self.selectors[i] = dobj.data_objects[i].selector
275
276cdef class ChainedBooleanANDSelector(ChainedBooleanSelector):
277    @cython.cdivision(True)
278    @cython.boundscheck(False)
279    @cython.wraparound(False)
280    cdef int select_bbox(self, np.float64_t left_edge[3],
281                         np.float64_t right_edge[3]) nogil:
282        with gil:
283            for i in range(self.n_obj):
284                if (<SelectorObject>self.selectors[i]).select_bbox(
285                        left_edge, right_edge) == 0:
286                    return 0
287        return 1
288
289    @cython.cdivision(True)
290    @cython.boundscheck(False)
291    @cython.wraparound(False)
292    cdef int select_bbox_edge(self, np.float64_t left_edge[3],
293                              np.float64_t right_edge[3]) nogil:
294        cdef int selected = 1
295        cdef int ret
296        with gil:
297            for i in range(self.n_obj):
298                ret = (<SelectorObject>self.selectors[i]).select_bbox_edge(
299                    left_edge, right_edge)
300                if ret == 0:
301                    return 0
302                elif ret == 2:
303                    selected = 2
304        return selected
305
306    @cython.cdivision(True)
307    @cython.boundscheck(False)
308    @cython.wraparound(False)
309    cdef int select_grid(self, np.float64_t left_edge[3],
310                         np.float64_t right_edge[3], np.int32_t level,
311                         Oct *o = NULL) nogil:
312        with gil:
313            for i in range(self.n_obj):
314                if (<SelectorObject>self.selectors[i]).select_grid(
315                        left_edge, right_edge, level, o) == 0:
316                    return 0
317        return 1
318
319    @cython.cdivision(True)
320    @cython.boundscheck(False)
321    @cython.wraparound(False)
322    cdef int select_cell(self, np.float64_t pos[3], np.float64_t dds[3]) nogil:
323        with gil:
324            for i in range(self.n_obj):
325                if (<SelectorObject>self.selectors[i]).select_cell(
326                        pos, dds) == 0:
327                    return 0
328        return 1
329
330    @cython.cdivision(True)
331    @cython.boundscheck(False)
332    @cython.wraparound(False)
333    cdef int select_point(self, np.float64_t pos[3]) nogil:
334        with gil:
335            for i in range(self.n_obj):
336                if (<SelectorObject>self.selectors[i]).select_point(pos) == 0:
337                    return 0
338        return 1
339
340    @cython.cdivision(True)
341    @cython.boundscheck(False)
342    @cython.wraparound(False)
343    cdef int select_sphere(self, np.float64_t pos[3], np.float64_t radius) nogil:
344        with gil:
345            for i in range(self.n_obj):
346                if (<SelectorObject>self.selectors[i]).select_sphere(
347                        pos, radius) == 0:
348                    return 0
349        return 1
350
351    def _hash_vals(self):
352        v = ("chained_and",)
353        for s in self.selectors:
354            v += s._hash_vals()
355        return v
356
357intersection_selector = ChainedBooleanANDSelector
358
359cdef class ChainedBooleanORSelector(ChainedBooleanSelector):
360    @cython.cdivision(True)
361    @cython.boundscheck(False)
362    @cython.wraparound(False)
363    cdef int select_bbox(self, np.float64_t left_edge[3],
364                         np.float64_t right_edge[3]) nogil:
365        with gil:
366            for i in range(self.n_obj):
367                if (<SelectorObject>self.selectors[i]).select_bbox(
368                        left_edge, right_edge) == 1:
369                    return 1
370        return 0
371
372    @cython.cdivision(True)
373    @cython.boundscheck(False)
374    @cython.wraparound(False)
375    cdef int select_bbox_edge(self, np.float64_t left_edge[3],
376                         np.float64_t right_edge[3]) nogil:
377        cdef int selected = 0
378        cdef int ret
379        with gil:
380            for i in range(self.n_obj):
381                ret = (<SelectorObject>self.selectors[i]).select_bbox_edge(
382                    left_edge, right_edge)
383                if ret == 1:
384                    return 1
385                elif ret == 2:
386                    selected = 2
387        return selected
388
389    @cython.cdivision(True)
390    @cython.boundscheck(False)
391    @cython.wraparound(False)
392    cdef int select_grid(self, np.float64_t left_edge[3],
393                         np.float64_t right_edge[3], np.int32_t level,
394                         Oct *o = NULL) nogil:
395        with gil:
396            for i in range(self.n_obj):
397                if (<SelectorObject>self.selectors[i]).select_grid(
398                        left_edge, right_edge, level, o) == 1:
399                    return 1
400        return 0
401
402    @cython.cdivision(True)
403    @cython.boundscheck(False)
404    @cython.wraparound(False)
405    cdef int select_cell(self, np.float64_t pos[3], np.float64_t dds[3]) nogil:
406        with gil:
407            for i in range(self.n_obj):
408                if (<SelectorObject>self.selectors[i]).select_cell(
409                        pos, dds) == 1:
410                    return 1
411        return 0
412
413    @cython.cdivision(True)
414    @cython.boundscheck(False)
415    @cython.wraparound(False)
416    cdef int select_point(self, np.float64_t pos[3]) nogil:
417        with gil:
418            for i in range(self.n_obj):
419                if (<SelectorObject>self.selectors[i]).select_point(pos) == 1:
420                    return 1
421        return 0
422
423    @cython.cdivision(True)
424    @cython.boundscheck(False)
425    @cython.wraparound(False)
426    cdef int select_sphere(self, np.float64_t pos[3], np.float64_t radius) nogil:
427        with gil:
428            for i in range(self.n_obj):
429                if (<SelectorObject>self.selectors[i]).select_sphere(
430                        pos, radius) == 1:
431                    return 1
432        return 0
433
434    def _hash_vals(self):
435        v = ("chained_or",)
436        for s in self.selectors:
437            v += s._hash_vals()
438        return v
439
440union_selector = ChainedBooleanORSelector
441