1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24 package org.dishevelled.matrix;
25
26 import org.dishevelled.bitset.MutableBitSet;
27
28 import org.dishevelled.functor.TernaryProcedure;
29
30
31
32
33
34
35 public final class BitMatrix3D
36 {
37
38 private final MutableBitSet bitset;
39
40
41 private final long slices;
42
43
44 private final long rows;
45
46
47 private final long columns;
48
49
50 private final long size;
51
52
53
54
55
56
57
58
59
60
61
62
63 public BitMatrix3D(final long slices, final long rows, final long columns)
64 {
65 if (slices < 0)
66 {
67 throw new IllegalArgumentException("slices must be >= 0");
68 }
69 if (rows < 0)
70 {
71 throw new IllegalArgumentException("rows must be >= 0");
72 }
73 if (columns < 0)
74 {
75 throw new IllegalArgumentException("columns must be >= 0");
76 }
77 this.slices = slices;
78 this.rows = rows;
79 this.columns = columns;
80 this.size = (slices * rows * columns);
81 this.bitset = new MutableBitSet(size);
82 }
83
84
85
86
87
88
89
90 public long size()
91 {
92 return size;
93 }
94
95
96
97
98
99
100 public long slices()
101 {
102 return slices;
103 }
104
105
106
107
108
109
110 public long rows()
111 {
112 return rows;
113 }
114
115
116
117
118
119
120 public long columns()
121 {
122 return columns;
123 }
124
125
126
127
128
129
130
131 public long cardinality()
132 {
133 return bitset.cardinality();
134 }
135
136
137
138
139
140
141 public boolean isEmpty()
142 {
143 return (0 == cardinality());
144 }
145
146
147
148
149 public void clear()
150 {
151 for (long i = bitset.nextSetBit(0); i >= 0; i = bitset.nextSetBit(i + 1))
152 {
153 bitset.clear(i);
154 }
155 }
156
157
158
159
160
161
162
163
164
165
166
167
168
169 public boolean get(final long slice, final long row, final long column)
170 {
171 if (slice < 0)
172 {
173 throw new IndexOutOfBoundsException(slice + " < 0");
174 }
175 if (slice >= slices)
176 {
177 throw new IndexOutOfBoundsException(slice + " >= " + slices);
178 }
179 if (row < 0)
180 {
181 throw new IndexOutOfBoundsException(row + " < 0");
182 }
183 if (row >= rows)
184 {
185 throw new IndexOutOfBoundsException(row + " >= " + rows);
186 }
187 if (column < 0)
188 {
189 throw new IndexOutOfBoundsException(column + " < 0");
190 }
191 if (column >= columns)
192 {
193 throw new IndexOutOfBoundsException(column + " >= " + columns);
194 }
195 return getQuick(slice, row, column);
196 }
197
198
199
200
201
202
203
204
205
206 public boolean getQuick(final long slice, final long row, final long column)
207 {
208 return bitset.getQuick(index(slice, row, column));
209 }
210
211
212
213
214
215
216
217
218
219
220
221
222
223 public void set(final long slice, final long row, final long column, final boolean value)
224 {
225 if (slice < 0)
226 {
227 throw new IndexOutOfBoundsException(slice + " < 0");
228 }
229 if (slice >= slices)
230 {
231 throw new IndexOutOfBoundsException(slice + " >= " + slices);
232 }
233 if (row < 0)
234 {
235 throw new IndexOutOfBoundsException(row + " < 0");
236 }
237 if (row >= rows)
238 {
239 throw new IndexOutOfBoundsException(row + " >= " + rows);
240 }
241 if (column < 0)
242 {
243 throw new IndexOutOfBoundsException(column + " < 0");
244 }
245 if (column >= columns)
246 {
247 throw new IndexOutOfBoundsException(column + " >= " + columns);
248 }
249 setQuick(slice, row, column, value);
250 }
251
252
253
254
255
256
257
258
259
260 public void setQuick(final long slice, final long row, final long column, final boolean value)
261 {
262 long index = index(slice, row, column);
263 if (value)
264 {
265 bitset.setQuick(index);
266 }
267 else
268 {
269 bitset.clearQuick(index);
270 }
271 }
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298 public void set(final long slice0, final long row0, final long column0,
299 final long slice1, final long row1, final long column1, final boolean value)
300 {
301 if (slice0 < 0)
302 {
303 throw new IndexOutOfBoundsException(slice0 + " < 0");
304 }
305 if (slice0 >= slices)
306 {
307 throw new IndexOutOfBoundsException(slice0 + " >= " + slices);
308 }
309 if (row0 < 0)
310 {
311 throw new IndexOutOfBoundsException(row0 + " < 0");
312 }
313 if (row0 >= rows)
314 {
315 throw new IndexOutOfBoundsException(row0 + " >= " + rows);
316 }
317 if (column0 < 0)
318 {
319 throw new IndexOutOfBoundsException(column0 + " < 0");
320 }
321 if (column0 >= columns)
322 {
323 throw new IndexOutOfBoundsException(column0 + " >= " + columns);
324 }
325 if (slice1 < 0)
326 {
327 throw new IndexOutOfBoundsException(slice1 + " < 0");
328 }
329 if (slice1 > slices)
330 {
331 throw new IndexOutOfBoundsException(slice1 + " > " + slices);
332 }
333 if (row1 < 0)
334 {
335 throw new IndexOutOfBoundsException(row1 + " < 0");
336 }
337 if (row1 > rows)
338 {
339 throw new IndexOutOfBoundsException(row1 + " > " + rows);
340 }
341 if (column1 < 0)
342 {
343 throw new IndexOutOfBoundsException(column1 + " < 0");
344 }
345 if (column1 > columns)
346 {
347 throw new IndexOutOfBoundsException(column1 + " > " + columns);
348 }
349
350 for (long slice = slice0; slice < slice1; slice++)
351 {
352 for (long row = row0; row < row1; row++)
353 {
354 for (long column = column0; column < column1; column++)
355 {
356 setQuick(slice, row, column, value);
357 }
358 }
359 }
360 }
361
362
363
364
365
366
367
368
369
370
371
372
373
374 public void flip(final long slice, final long row, final long column)
375 {
376 if (slice < 0)
377 {
378 throw new IndexOutOfBoundsException(slice + " < 0");
379 }
380 if (slice >= slices)
381 {
382 throw new IndexOutOfBoundsException(slice + " >= " + slices);
383 }
384 if (row < 0)
385 {
386 throw new IndexOutOfBoundsException(row + " < 0");
387 }
388 if (row >= rows)
389 {
390 throw new IndexOutOfBoundsException(row + " >= " + rows);
391 }
392 if (column < 0)
393 {
394 throw new IndexOutOfBoundsException(column + " < 0");
395 }
396 if (column >= columns)
397 {
398 throw new IndexOutOfBoundsException(column + " >= " + columns);
399 }
400 flipQuick(slice, row, column);
401 }
402
403
404
405
406
407
408
409
410
411 public void flipQuick(final long slice, final long row, final long column)
412 {
413 bitset.flipQuick(index(slice, row, column));
414 }
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441 public void flip(final long slice0, final long row0, final long column0,
442 final long slice1, final long row1, final long column1)
443 {
444 if (slice0 < 0)
445 {
446 throw new IndexOutOfBoundsException(slice0 + " < 0");
447 }
448 if (slice0 >= slices)
449 {
450 throw new IndexOutOfBoundsException(slice0 + " >= " + slices);
451 }
452 if (row0 < 0)
453 {
454 throw new IndexOutOfBoundsException(row0 + " < 0");
455 }
456 if (row0 >= rows)
457 {
458 throw new IndexOutOfBoundsException(row0 + " >= " + rows);
459 }
460 if (column0 < 0)
461 {
462 throw new IndexOutOfBoundsException(column0 + " < 0");
463 }
464 if (column0 >= columns)
465 {
466 throw new IndexOutOfBoundsException(column0 + " >= " + columns);
467 }
468 if (slice1 < 0)
469 {
470 throw new IndexOutOfBoundsException(slice1 + " < 0");
471 }
472 if (slice1 > slices)
473 {
474 throw new IndexOutOfBoundsException(slice1 + " > " + slices);
475 }
476 if (row1 < 0)
477 {
478 throw new IndexOutOfBoundsException(row1 + " < 0");
479 }
480 if (row1 > rows)
481 {
482 throw new IndexOutOfBoundsException(row1 + " > " + rows);
483 }
484 if (column1 < 0)
485 {
486 throw new IndexOutOfBoundsException(column1 + " < 0");
487 }
488 if (column1 > columns)
489 {
490 throw new IndexOutOfBoundsException(column1 + " > " + columns);
491 }
492
493 for (long slice = slice0; slice < slice1; slice++)
494 {
495 for (long row = row0; row < row1; row++)
496 {
497 for (long column = column0; column < column1; column++)
498 {
499 flipQuick(slice, row, column);
500 }
501 }
502 }
503 }
504
505
506
507
508
509
510
511 public BitMatrix3D assign(final boolean value)
512 {
513 if (size > 0)
514 {
515 set(0, 0, 0, slices, rows, columns, value);
516 }
517 return this;
518 }
519
520
521
522
523
524
525
526
527
528
529 public boolean intersects(final BitMatrix3D other)
530 {
531 if (other == null)
532 {
533 throw new IllegalArgumentException("other must not be null");
534 }
535 if ((size != other.size()) || (slices != other.slices()) || (rows != other.rows())
536 || (columns != other.columns()))
537 {
538 throw new IllegalArgumentException("this and other must have the same dimensions");
539 }
540 return bitset.intersects(other.bitset);
541 }
542
543
544
545
546
547
548
549
550
551 public BitMatrix3D and(final BitMatrix3D other)
552 {
553 if (other == null)
554 {
555 throw new IllegalArgumentException("other must not be null");
556 }
557 if ((size != other.size()) || (slices != other.slices()) || (rows != other.rows())
558 || (columns != other.columns()))
559 {
560 throw new IllegalArgumentException("this and other must have the same dimensions");
561 }
562 bitset.and(other.bitset);
563 return this;
564
565 }
566
567
568
569
570
571
572
573
574
575 public BitMatrix3D andNot(final BitMatrix3D other)
576 {
577 if (other == null)
578 {
579 throw new IllegalArgumentException("other must not be null");
580 }
581 if ((size != other.size()) || (slices != other.slices()) || (rows != other.rows())
582 || (columns != other.columns()))
583 {
584 throw new IllegalArgumentException("this and other must have the same dimensions");
585 }
586 bitset.andNot(other.bitset);
587 return this;
588 }
589
590
591
592
593
594
595
596
597
598 public BitMatrix3D or(final BitMatrix3D other)
599 {
600 if (other == null)
601 {
602 throw new IllegalArgumentException("other must not be null");
603 }
604 if ((size != other.size()) || (slices != other.slices()) || (rows != other.rows())
605 || (columns != other.columns()))
606 {
607 throw new IllegalArgumentException("this and other must have the same dimensions");
608 }
609 bitset.or(other.bitset);
610 return this;
611 }
612
613
614
615
616
617
618
619
620
621 public BitMatrix3D xor(final BitMatrix3D other)
622 {
623 if (other == null)
624 {
625 throw new IllegalArgumentException("other must not be null");
626 }
627 if ((size != other.size()) || (slices != other.slices()) || (rows != other.rows())
628 || (columns != other.columns()))
629 {
630 throw new IllegalArgumentException("this and other must have the same dimensions");
631 }
632 bitset.xor(other.bitset);
633 return this;
634 }
635
636
637
638
639
640
641
642
643 public void forEach(final boolean value,
644 final TernaryProcedure<Long, Long, Long> procedure)
645 {
646 if (procedure == null)
647 {
648 throw new IllegalArgumentException("procedure must not be null");
649 }
650
651 for (long slice = 0; slice < slices; slice++)
652 {
653 for (long row = 0; row < rows; row++)
654 {
655 for (long column = 0; column < columns; column++)
656 {
657 if (getQuick(slice, row, column) == value)
658 {
659 procedure.run(Long.valueOf(slice), Long.valueOf(row), Long.valueOf(column));
660 }
661 }
662 }
663 }
664 }
665
666
667 public boolean equals(final Object o)
668 {
669 if (o == null)
670 {
671 return false;
672 }
673 if (!(o instanceof BitMatrix3D))
674 {
675 return false;
676 }
677
678 BitMatrix3D bm = (BitMatrix3D) o;
679
680 if ((size != bm.size()) || (slices != bm.slices()) || (rows != bm.rows()) || (columns != bm.columns()))
681 {
682 return false;
683 }
684 return bitset.equals(bm.bitset);
685 }
686
687
688 public int hashCode()
689 {
690 int hashCode = 37;
691 hashCode = 17 * hashCode + (int) (size ^ (size >>> 32));
692 hashCode = 17 * hashCode + (int) (slices ^ (slices >>> 32));
693 hashCode = 17 * hashCode + (int) (rows ^ (rows >>> 32));
694 hashCode = 17 * hashCode + (int) (columns ^ (columns >>> 32));
695 hashCode = 17 * hashCode + bitset.hashCode();
696 return hashCode;
697 }
698
699
700
701
702
703
704
705
706
707
708 private long index(final long slice, final long row, final long column)
709 {
710 return (rows * columns * slice) + (columns * row) + column;
711 }
712 }