1#[cfg(not(feature = "std"))]
23#[allow(unused_imports)]
24use crate::compat::*;
25use crate::error::{OxiGdalError, Result};
26
27#[derive(Debug, Clone, PartialEq, Eq)]
44pub struct Mask {
45 width: usize,
47 height: usize,
49 data: Vec<u64>,
52}
53
54impl Mask {
57 #[inline]
59 fn words_for(pixel_count: usize) -> usize {
60 pixel_count.saturating_add(63) / 64
61 }
62
63 #[inline]
65 fn coords(i: usize) -> (usize, u32) {
66 (i / 64, (i % 64) as u32)
67 }
68
69 fn clear_tail_bits(&mut self) {
73 let pixel_count = self.width * self.height;
74 let tail = pixel_count % 64;
75 if tail != 0
76 && let Some(last) = self.data.last_mut()
77 {
78 *last &= (1u64 << tail).wrapping_sub(1);
80 }
81 }
82
83 #[inline]
85 fn check_dims(&self, other: &Mask) -> Result<()> {
86 if self.width != other.width || self.height != other.height {
87 Err(OxiGdalError::InvalidParameter {
88 parameter: "other",
89 message: format!(
90 "Mask dimension mismatch: self={}×{}, other={}×{}",
91 self.width, self.height, other.width, other.height
92 ),
93 })
94 } else {
95 Ok(())
96 }
97 }
98}
99
100impl Mask {
103 #[must_use]
107 pub fn new(width: usize, height: usize) -> Self {
108 let words = Self::words_for(width * height);
109 Self {
110 width,
111 height,
112 data: vec![0u64; words],
113 }
114 }
115
116 #[must_use]
121 pub fn new_filled(width: usize, height: usize) -> Self {
122 let mut mask = Self {
123 width,
124 height,
125 data: vec![!0u64; Self::words_for(width * height)],
126 };
127 mask.clear_tail_bits();
128 mask
129 }
130
131 pub fn from_slice(width: usize, height: usize, values: &[bool]) -> Result<Self> {
141 let pixel_count = width * height;
142 if values.len() != pixel_count {
143 return Err(OxiGdalError::InvalidParameter {
144 parameter: "values",
145 message: format!(
146 "Slice length {} does not match {}×{} = {} pixels",
147 values.len(),
148 width,
149 height,
150 pixel_count
151 ),
152 });
153 }
154 let mut mask = Self::new(width, height);
155 for (i, &v) in values.iter().enumerate() {
156 if v {
157 let (word, bit) = Self::coords(i);
158 mask.data[word] |= 1u64 << bit;
159 }
160 }
161 Ok(mask)
164 }
165}
166
167impl Mask {
170 #[must_use]
172 #[inline]
173 pub const fn width(&self) -> usize {
174 self.width
175 }
176
177 #[must_use]
179 #[inline]
180 pub const fn height(&self) -> usize {
181 self.height
182 }
183
184 #[must_use]
186 #[inline]
187 pub fn pixel_count(&self) -> usize {
188 self.width * self.height
189 }
190
191 #[must_use]
200 pub fn get(&self, x: usize, y: usize) -> bool {
201 debug_assert!(
202 x < self.width,
203 "x={} out of bounds (width={})",
204 x,
205 self.width
206 );
207 debug_assert!(
208 y < self.height,
209 "y={} out of bounds (height={})",
210 y,
211 self.height
212 );
213 let i = y * self.width + x;
214 let (word, bit) = Self::coords(i);
215 if word < self.data.len() {
216 (self.data[word] >> bit) & 1 == 1
217 } else {
218 false
219 }
220 }
221
222 pub fn set(&mut self, x: usize, y: usize, value: bool) {
230 debug_assert!(
231 x < self.width,
232 "x={} out of bounds (width={})",
233 x,
234 self.width
235 );
236 debug_assert!(
237 y < self.height,
238 "y={} out of bounds (height={})",
239 y,
240 self.height
241 );
242 let i = y * self.width + x;
243 let (word, bit) = Self::coords(i);
244 if word < self.data.len() {
245 if value {
246 self.data[word] |= 1u64 << bit;
247 } else {
248 self.data[word] &= !(1u64 << bit);
249 }
250 }
251 }
252}
253
254impl Mask {
257 pub fn fill(&mut self, value: bool) {
261 let fill_word = if value { !0u64 } else { 0u64 };
262 for w in &mut self.data {
263 *w = fill_word;
264 }
265 if value {
266 self.clear_tail_bits();
267 }
268 }
269
270 pub fn fill_rect(&mut self, x: usize, y: usize, w: usize, h: usize, value: bool) {
275 let x_end = (x + w).min(self.width);
277 let y_end = (y + h).min(self.height);
278 for row in y..y_end {
279 for col in x..x_end {
280 self.set(col, row, value);
281 }
282 }
283 }
286}
287
288impl Mask {
291 pub fn and_assign(&mut self, other: &Mask) -> Result<()> {
297 self.check_dims(other)?;
298 for (a, b) in self.data.iter_mut().zip(other.data.iter()) {
299 *a &= b;
300 }
301 Ok(())
302 }
303
304 pub fn or_assign(&mut self, other: &Mask) -> Result<()> {
310 self.check_dims(other)?;
311 for (a, b) in self.data.iter_mut().zip(other.data.iter()) {
312 *a |= b;
313 }
314 Ok(())
317 }
318
319 pub fn not_in_place(&mut self) {
323 for w in &mut self.data {
324 *w = !*w;
325 }
326 self.clear_tail_bits();
327 }
328
329 pub fn xor_assign(&mut self, other: &Mask) -> Result<()> {
335 self.check_dims(other)?;
336 for (a, b) in self.data.iter_mut().zip(other.data.iter()) {
337 *a ^= b;
338 }
339 Ok(())
341 }
342
343 pub fn and(&self, other: &Mask) -> Result<Mask> {
349 self.check_dims(other)?;
350 let data: Vec<u64> = self
351 .data
352 .iter()
353 .zip(other.data.iter())
354 .map(|(a, b)| a & b)
355 .collect();
356 Ok(Mask {
357 width: self.width,
358 height: self.height,
359 data,
360 })
361 }
362
363 pub fn or(&self, other: &Mask) -> Result<Mask> {
369 self.check_dims(other)?;
370 let data: Vec<u64> = self
371 .data
372 .iter()
373 .zip(other.data.iter())
374 .map(|(a, b)| a | b)
375 .collect();
376 Ok(Mask {
377 width: self.width,
378 height: self.height,
379 data,
380 })
381 }
382
383 #[must_use]
387 pub fn not(&self) -> Mask {
388 let mut result = Mask {
389 width: self.width,
390 height: self.height,
391 data: self.data.iter().map(|w| !w).collect(),
392 };
393 result.clear_tail_bits();
394 result
395 }
396}
397
398impl Mask {
401 #[must_use]
403 pub fn count_set(&self) -> usize {
404 self.data.iter().map(|w| w.count_ones() as usize).sum()
405 }
406
407 #[must_use]
409 pub fn count_unset(&self) -> usize {
410 self.pixel_count() - self.count_set()
411 }
412
413 #[must_use]
415 pub fn all_set(&self) -> bool {
416 self.count_set() == self.pixel_count()
417 }
418
419 #[must_use]
421 pub fn all_unset(&self) -> bool {
422 self.data.iter().all(|&w| w == 0)
423 }
424
425 #[must_use]
427 pub fn any_set(&self) -> bool {
428 self.data.iter().any(|&w| w != 0)
429 }
430}
431
432impl Mask {
435 pub fn set_positions(&self) -> impl Iterator<Item = (usize, usize)> + '_ {
440 SetPositions {
441 mask: self,
442 word_idx: 0,
443 current_word: self.data.first().copied().unwrap_or(0),
444 pixel_base: 0,
445 }
446 }
447}
448
449struct SetPositions<'a> {
451 mask: &'a Mask,
452 word_idx: usize,
454 current_word: u64,
456 pixel_base: usize,
458}
459
460impl<'a> Iterator for SetPositions<'a> {
461 type Item = (usize, usize);
462
463 fn next(&mut self) -> Option<Self::Item> {
464 loop {
465 if self.current_word != 0 {
466 let bit = self.current_word.trailing_zeros() as usize;
468 self.current_word &= self.current_word - 1;
470 let i = self.pixel_base + bit;
471 if i < self.mask.pixel_count() {
472 let x = i % self.mask.width;
473 let y = i / self.mask.width;
474 return Some((x, y));
475 }
476 continue;
478 }
479 self.word_idx += 1;
481 if self.word_idx >= self.mask.data.len() {
482 return None;
483 }
484 self.pixel_base = self.word_idx * 64;
485 self.current_word = self.mask.data[self.word_idx];
486 }
487 }
488}
489
490impl Mask {
493 pub fn from_nodata_f32(data: &[f32], width: usize, height: usize, nodata: f32) -> Result<Self> {
503 let pixel_count = width * height;
504 if data.len() != pixel_count {
505 return Err(OxiGdalError::InvalidParameter {
506 parameter: "data",
507 message: format!(
508 "Slice length {} ≠ {}×{} = {} pixels",
509 data.len(),
510 width,
511 height,
512 pixel_count
513 ),
514 });
515 }
516 let nodata_is_nan = nodata.is_nan();
517 let mut mask = Self::new(width, height);
518 for (i, &v) in data.iter().enumerate() {
519 let is_nodata = if nodata_is_nan {
520 v.is_nan()
521 } else {
522 v == nodata
523 };
524 if is_nodata {
525 let (word, bit) = Self::coords(i);
526 mask.data[word] |= 1u64 << bit;
527 }
528 }
529 Ok(mask)
530 }
531
532 pub fn from_nodata_f64(data: &[f64], width: usize, height: usize, nodata: f64) -> Result<Self> {
542 let pixel_count = width * height;
543 if data.len() != pixel_count {
544 return Err(OxiGdalError::InvalidParameter {
545 parameter: "data",
546 message: format!(
547 "Slice length {} ≠ {}×{} = {} pixels",
548 data.len(),
549 width,
550 height,
551 pixel_count
552 ),
553 });
554 }
555 let nodata_is_nan = nodata.is_nan();
556 let mut mask = Self::new(width, height);
557 for (i, &v) in data.iter().enumerate() {
558 let is_nodata = if nodata_is_nan {
559 v.is_nan()
560 } else {
561 v == nodata
562 };
563 if is_nodata {
564 let (word, bit) = Self::coords(i);
565 mask.data[word] |= 1u64 << bit;
566 }
567 }
568 Ok(mask)
569 }
570
571 pub fn from_nodata_i32(data: &[i32], width: usize, height: usize, nodata: i32) -> Result<Self> {
580 let pixel_count = width * height;
581 if data.len() != pixel_count {
582 return Err(OxiGdalError::InvalidParameter {
583 parameter: "data",
584 message: format!(
585 "Slice length {} ≠ {}×{} = {} pixels",
586 data.len(),
587 width,
588 height,
589 pixel_count
590 ),
591 });
592 }
593 let mut mask = Self::new(width, height);
594 for (i, &v) in data.iter().enumerate() {
595 if v == nodata {
596 let (word, bit) = Self::coords(i);
597 mask.data[word] |= 1u64 << bit;
598 }
599 }
600 Ok(mask)
601 }
602
603 pub fn from_nodata_u8(data: &[u8], width: usize, height: usize, nodata: u8) -> Result<Self> {
612 let pixel_count = width * height;
613 if data.len() != pixel_count {
614 return Err(OxiGdalError::InvalidParameter {
615 parameter: "data",
616 message: format!(
617 "Slice length {} ≠ {}×{} = {} pixels",
618 data.len(),
619 width,
620 height,
621 pixel_count
622 ),
623 });
624 }
625 let mut mask = Self::new(width, height);
626 for (i, &v) in data.iter().enumerate() {
627 if v == nodata {
628 let (word, bit) = Self::coords(i);
629 mask.data[word] |= 1u64 << bit;
630 }
631 }
632 Ok(mask)
633 }
634}
635
636impl Mask {
639 #[must_use]
644 pub fn to_bool_vec(&self) -> Vec<bool> {
645 let n = self.pixel_count();
646 let mut out = Vec::with_capacity(n);
647 for i in 0..n {
648 let (word, bit) = Self::coords(i);
649 out.push((self.data[word] >> bit) & 1 == 1);
650 }
651 out
652 }
653}
654
655impl Mask {
658 pub fn apply_to_f32(&self, data: &mut [f32], nodata_value: f32) {
664 let n = self.pixel_count().min(data.len());
665 for (i, elem) in data.iter_mut().enumerate().take(n) {
666 let (word, bit) = Self::coords(i);
667 if word < self.data.len() && (self.data[word] >> bit) & 1 == 1 {
668 *elem = nodata_value;
669 }
670 }
671 }
672
673 pub fn apply_to_f64(&self, data: &mut [f64], nodata_value: f64) {
677 let n = self.pixel_count().min(data.len());
678 for (i, elem) in data.iter_mut().enumerate().take(n) {
679 let (word, bit) = Self::coords(i);
680 if word < self.data.len() && (self.data[word] >> bit) & 1 == 1 {
681 *elem = nodata_value;
682 }
683 }
684 }
685
686 pub fn apply_to_u8(&self, data: &mut [u8], nodata_value: u8) {
690 let n = self.pixel_count().min(data.len());
691 for (i, elem) in data.iter_mut().enumerate().take(n) {
692 let (word, bit) = Self::coords(i);
693 if word < self.data.len() && (self.data[word] >> bit) & 1 == 1 {
694 *elem = nodata_value;
695 }
696 }
697 }
698
699 pub fn apply_to_i32(&self, data: &mut [i32], nodata_value: i32) {
703 let n = self.pixel_count().min(data.len());
704 for (i, elem) in data.iter_mut().enumerate().take(n) {
705 let (word, bit) = Self::coords(i);
706 if word < self.data.len() && (self.data[word] >> bit) & 1 == 1 {
707 *elem = nodata_value;
708 }
709 }
710 }
711}
712
713#[cfg(test)]
716mod tests {
717 #![allow(clippy::expect_used)]
718
719 use super::*;
720
721 #[test]
724 fn test_mask_basic_set_get() {
725 let mut mask = Mask::new(8, 8);
726 for y in 0..8 {
728 for x in 0..8 {
729 assert!(!mask.get(x, y), "({x},{y}) should be unset");
730 }
731 }
732 mask.set(0, 0, true);
733 mask.set(7, 7, true);
734 mask.set(3, 5, true);
735 assert!(mask.get(0, 0));
736 assert!(mask.get(7, 7));
737 assert!(mask.get(3, 5));
738 assert!(!mask.get(1, 1));
739 assert_eq!(mask.count_set(), 3);
740 }
741
742 #[test]
743 fn test_mask_fill_true() {
744 let mut mask = Mask::new(10, 10);
745 mask.fill(true);
746 assert_eq!(mask.count_set(), 100);
747 assert_eq!(mask.count_unset(), 0);
748 }
749
750 #[test]
751 fn test_mask_fill_false() {
752 let mut mask = Mask::new_filled(5, 5);
753 mask.fill(false);
754 assert_eq!(mask.count_set(), 0);
755 assert!(mask.all_unset());
756 }
757
758 #[test]
759 fn test_mask_fill_rect() {
760 let mut mask = Mask::new(10, 10);
761 mask.fill_rect(2, 2, 3, 3, true);
763 assert_eq!(mask.count_set(), 9);
764 for dy in 0..3 {
766 for dx in 0..3 {
767 assert!(mask.get(2 + dx, 2 + dy));
768 }
769 }
770 assert!(!mask.get(1, 2));
772 assert!(!mask.get(5, 5));
773 }
774
775 #[test]
778 fn test_mask_and_or_not() {
779 let mut a = Mask::new(4, 4); a.set(0, 0, true);
781 a.set(1, 1, true);
782
783 let mut b = Mask::new(4, 4); b.set(1, 1, true);
785 b.set(2, 2, true);
786
787 let and = a.and(&b).expect("and should succeed");
789 assert_eq!(and.count_set(), 1);
790 assert!(and.get(1, 1));
791
792 let or = a.or(&b).expect("or should succeed");
794 assert_eq!(or.count_set(), 3);
795
796 let not_a = a.not();
798 assert_eq!(not_a.count_set(), 14);
799 assert!(!not_a.get(0, 0));
800 assert!(!not_a.get(1, 1));
801 assert!(not_a.get(0, 1));
802 }
803
804 #[test]
805 fn test_mask_dimension_mismatch_err() {
806 let mut a = Mask::new(4, 4);
807 let b = Mask::new(4, 5);
808 assert!(a.and_assign(&b).is_err());
809 assert!(a.or_assign(&b).is_err());
810 assert!(a.xor_assign(&b).is_err());
811 assert!(a.and(&b).is_err());
812 assert!(a.or(&b).is_err());
813 }
814
815 #[test]
818 fn test_mask_from_slice_roundtrip() {
819 let values: Vec<bool> = (0..20usize).map(|i| i % 3 == 0).collect();
820 let mask = Mask::from_slice(4, 5, &values).expect("from_slice");
821 let back = mask.to_bool_vec();
822 assert_eq!(back, values);
823 }
824
825 #[test]
826 fn test_mask_from_slice_length_err() {
827 assert!(Mask::from_slice(4, 4, &[true; 10]).is_err());
829 }
830
831 #[test]
834 fn test_mask_from_nodata_f32() {
835 let nodata = -9999.0f32;
836 let data = vec![1.0f32, nodata, f32::NAN, 3.0, nodata];
837 let mask = Mask::from_nodata_f32(&data, 5, 1, nodata).expect("from_nodata_f32");
838 assert!(!mask.get(0, 0));
841 assert!(mask.get(1, 0));
842 assert!(!mask.get(2, 0)); assert!(!mask.get(3, 0));
844 assert!(mask.get(4, 0));
845 assert_eq!(mask.count_set(), 2);
846 }
847
848 #[test]
849 fn test_mask_from_nodata_f32_nan_nodata() {
850 let data = vec![1.0f32, f32::NAN, 2.0, f32::NAN];
852 let mask = Mask::from_nodata_f32(&data, 4, 1, f32::NAN).expect("from_nodata_f32 NaN");
853 assert!(!mask.get(0, 0));
854 assert!(mask.get(1, 0));
855 assert!(!mask.get(2, 0));
856 assert!(mask.get(3, 0));
857 }
858
859 #[test]
860 fn test_mask_from_nodata_u8_zero() {
861 let data: Vec<u8> = vec![0, 1, 0, 5, 0];
862 let mask = Mask::from_nodata_u8(&data, 5, 1, 0).expect("from_nodata_u8");
863 assert!(mask.get(0, 0));
864 assert!(!mask.get(1, 0));
865 assert!(mask.get(2, 0));
866 assert!(!mask.get(3, 0));
867 assert!(mask.get(4, 0));
868 assert_eq!(mask.count_set(), 3);
869 }
870
871 #[test]
874 fn test_mask_apply_to_f32() {
875 let mut mask = Mask::new(4, 1);
876 mask.set(1, 0, true);
877 mask.set(3, 0, true);
878 let mut data = vec![1.0f32, 2.0, 3.0, 4.0];
879 mask.apply_to_f32(&mut data, -9999.0);
880 assert!((data[0] - 1.0).abs() < 1e-7);
881 assert!((data[1] - (-9999.0)).abs() < 1e-1);
882 assert!((data[2] - 3.0).abs() < 1e-7);
883 assert!((data[3] - (-9999.0)).abs() < 1e-1);
884 }
885
886 #[test]
887 fn test_mask_apply_to_u8() {
888 let mut mask = Mask::new(3, 1);
889 mask.set(0, 0, true);
890 mask.set(2, 0, true);
891 let mut data: Vec<u8> = vec![10, 20, 30];
892 mask.apply_to_u8(&mut data, 0);
893 assert_eq!(data, vec![0, 20, 0]);
894 }
895
896 #[test]
899 fn test_mask_count_set_checkerboard() {
900 let values: Vec<bool> = (0..64usize).map(|i| i % 2 == 0).collect();
902 let mask = Mask::from_slice(8, 8, &values).expect("from_slice");
903 assert_eq!(mask.count_set(), 32);
904 assert_eq!(mask.count_unset(), 32);
905 }
906
907 #[test]
910 fn test_mask_set_positions_iterator() {
911 let mut mask = Mask::new(5, 5);
912 let positions = [(1usize, 0usize), (4, 2), (0, 4)];
913 for &(x, y) in &positions {
914 mask.set(x, y, true);
915 }
916 let mut collected: Vec<(usize, usize)> = mask.set_positions().collect();
917 collected.sort_unstable();
918 let mut expected = positions.to_vec();
919 expected.sort_unstable();
920 assert_eq!(collected, expected);
921 }
922
923 #[test]
926 fn test_mask_all_set_all_unset() {
927 let empty = Mask::new(0, 0);
928 assert!(empty.all_set());
930 assert!(empty.all_unset());
931
932 let zeros = Mask::new(10, 10);
933 assert!(zeros.all_unset());
934 assert!(!zeros.all_set());
935
936 let ones = Mask::new_filled(10, 10);
937 assert!(ones.all_set());
938 assert!(!ones.all_unset());
939 }
940
941 #[test]
944 fn test_mask_large_width_crosses_word_boundary() {
945 let mut mask = Mask::new(65, 1);
947 mask.set(63, 0, true); mask.set(64, 0, true); assert!(mask.get(63, 0));
950 assert!(mask.get(64, 0));
951 assert!(!mask.get(0, 0));
952 assert_eq!(mask.count_set(), 2);
953 }
954
955 #[test]
958 fn test_mask_single_pixel() {
959 let mut mask = Mask::new(1, 1);
960 assert!(!mask.get(0, 0));
961 assert!(mask.all_unset());
962 mask.set(0, 0, true);
963 assert!(mask.get(0, 0));
964 assert!(mask.all_set());
965 assert_eq!(mask.count_set(), 1);
966 mask.not_in_place();
967 assert!(!mask.get(0, 0));
968 assert!(mask.all_unset());
969 }
970
971 #[test]
974 fn test_mask_xor_self_is_zero() {
975 let mut mask = Mask::new(6, 6);
976 mask.fill_rect(0, 0, 3, 3, true);
977 let clone = mask.clone();
978 mask.xor_assign(&clone).expect("xor_assign");
979 assert!(mask.all_unset());
980 }
981
982 #[test]
985 fn test_mask_new_filled_all_set() {
986 let mask = Mask::new_filled(9, 7); assert_eq!(mask.pixel_count(), 63);
989 assert_eq!(mask.count_set(), 63);
990 assert!(mask.all_set());
991 }
992
993 #[test]
994 fn test_mask_not_in_place_tail_invariant() {
995 let mut mask = Mask::new(9, 7); mask.not_in_place(); assert_eq!(mask.count_set(), 63);
998 mask.not_in_place(); assert_eq!(mask.count_set(), 0);
1000 }
1001
1002 #[test]
1005 fn test_mask_or_idempotent() {
1006 let mut a = Mask::new(4, 4);
1007 a.fill_rect(0, 0, 2, 2, true);
1008 let b = a.clone();
1009 a.or_assign(&b).expect("or_assign");
1010 assert_eq!(a.count_set(), 4);
1011 }
1012
1013 #[test]
1016 fn test_mask_to_bool_vec_roundtrip() {
1017 let mask = Mask::new_filled(5, 3);
1018 let bv = mask.to_bool_vec();
1019 assert_eq!(bv.len(), 15);
1020 assert!(bv.iter().all(|&b| b));
1021 }
1022}