1#![allow(unsafe_code)]
4
5use core::fmt;
75
76use crate::error::{OxiGdalError, Result};
77use crate::types::{NoDataValue, RasterDataType};
78
79mod band_iterator;
80pub use band_iterator::{BandIterator, BandRef, MultiBandBuffer};
81
82mod raster_window;
83pub use raster_window::RasterWindow;
84
85pub mod mask;
86pub use mask::Mask;
87
88pub use crate::simd_buffer::{ArenaTile, TileIteratorArena};
89
90#[cfg(feature = "arrow")]
91pub mod arrow_convert;
92
93#[derive(Clone)]
95pub struct RasterBuffer {
96 data: Vec<u8>,
98 width: u64,
100 height: u64,
102 data_type: RasterDataType,
104 nodata: NoDataValue,
106}
107
108impl RasterBuffer {
109 pub fn new(
114 data: Vec<u8>,
115 width: u64,
116 height: u64,
117 data_type: RasterDataType,
118 nodata: NoDataValue,
119 ) -> Result<Self> {
120 let expected_size = width * height * data_type.size_bytes() as u64;
121 if data.len() as u64 != expected_size {
122 return Err(OxiGdalError::InvalidParameter {
123 parameter: "data",
124 message: format!(
125 "Data size mismatch: expected {} bytes for {}x{} {:?}, got {}",
126 expected_size,
127 width,
128 height,
129 data_type,
130 data.len()
131 ),
132 });
133 }
134
135 Ok(Self {
136 data,
137 width,
138 height,
139 data_type,
140 nodata,
141 })
142 }
143
144 #[must_use]
146 pub fn zeros(width: u64, height: u64, data_type: RasterDataType) -> Self {
147 let size = (width * height * data_type.size_bytes() as u64) as usize;
148 Self {
149 data: vec![0u8; size],
150 width,
151 height,
152 data_type,
153 nodata: NoDataValue::None,
154 }
155 }
156
157 #[must_use]
159 pub fn nodata_filled(
160 width: u64,
161 height: u64,
162 data_type: RasterDataType,
163 nodata: NoDataValue,
164 ) -> Self {
165 let mut buffer = Self::zeros(width, height, data_type);
166 buffer.nodata = nodata;
167
168 if let Some(value) = nodata.as_f64() {
170 buffer.fill_value(value);
171 }
172
173 buffer
174 }
175
176 pub fn fill_value(&mut self, value: f64) {
178 match self.data_type {
179 RasterDataType::UInt8 => {
180 let v = value as u8;
181 self.data.fill(v);
182 }
183 RasterDataType::Int8 => {
184 let v = value as i8;
185 self.data.fill(v as u8);
186 }
187 RasterDataType::UInt16 => {
188 let v = (value as u16).to_ne_bytes();
189 for chunk in self.data.chunks_exact_mut(2) {
190 chunk.copy_from_slice(&v);
191 }
192 }
193 RasterDataType::Int16 => {
194 let v = (value as i16).to_ne_bytes();
195 for chunk in self.data.chunks_exact_mut(2) {
196 chunk.copy_from_slice(&v);
197 }
198 }
199 RasterDataType::UInt32 => {
200 let v = (value as u32).to_ne_bytes();
201 for chunk in self.data.chunks_exact_mut(4) {
202 chunk.copy_from_slice(&v);
203 }
204 }
205 RasterDataType::Int32 => {
206 let v = (value as i32).to_ne_bytes();
207 for chunk in self.data.chunks_exact_mut(4) {
208 chunk.copy_from_slice(&v);
209 }
210 }
211 RasterDataType::Float32 => {
212 let v = (value as f32).to_ne_bytes();
213 for chunk in self.data.chunks_exact_mut(4) {
214 chunk.copy_from_slice(&v);
215 }
216 }
217 RasterDataType::Float64 => {
218 let v = value.to_ne_bytes();
219 for chunk in self.data.chunks_exact_mut(8) {
220 chunk.copy_from_slice(&v);
221 }
222 }
223 RasterDataType::UInt64 => {
224 let v = (value as u64).to_ne_bytes();
225 for chunk in self.data.chunks_exact_mut(8) {
226 chunk.copy_from_slice(&v);
227 }
228 }
229 RasterDataType::Int64 => {
230 let v = (value as i64).to_ne_bytes();
231 for chunk in self.data.chunks_exact_mut(8) {
232 chunk.copy_from_slice(&v);
233 }
234 }
235 RasterDataType::CFloat32 | RasterDataType::CFloat64 => {
236 }
239 }
240 }
241
242 #[must_use]
244 pub const fn width(&self) -> u64 {
245 self.width
246 }
247
248 #[must_use]
250 pub const fn height(&self) -> u64 {
251 self.height
252 }
253
254 #[must_use]
256 pub const fn data_type(&self) -> RasterDataType {
257 self.data_type
258 }
259
260 #[must_use]
262 pub const fn nodata(&self) -> NoDataValue {
263 self.nodata
264 }
265
266 #[must_use]
268 pub const fn pixel_count(&self) -> u64 {
269 self.width * self.height
270 }
271
272 #[must_use]
274 pub fn as_bytes(&self) -> &[u8] {
275 &self.data
276 }
277
278 pub fn as_bytes_mut(&mut self) -> &mut [u8] {
280 &mut self.data
281 }
282
283 #[must_use]
285 pub fn into_bytes(self) -> Vec<u8> {
286 self.data
287 }
288
289 pub fn from_typed_vec<T: Copy + 'static>(
300 width: usize,
301 height: usize,
302 data: Vec<T>,
303 data_type: RasterDataType,
304 ) -> Result<Self> {
305 let expected_pixels = width * height;
306 if data.len() != expected_pixels {
307 return Err(OxiGdalError::InvalidParameter {
308 parameter: "data",
309 message: format!(
310 "Data length mismatch: expected {} pixels for {}x{}, got {}",
311 expected_pixels,
312 width,
313 height,
314 data.len()
315 ),
316 });
317 }
318
319 let type_size = core::mem::size_of::<T>();
321 let expected_type_size = data_type.size_bytes();
322 if type_size != expected_type_size {
323 return Err(OxiGdalError::InvalidParameter {
324 parameter: "data_type",
325 message: format!(
326 "Type size mismatch: provided type has {} bytes, {:?} expects {} bytes",
327 type_size, data_type, expected_type_size
328 ),
329 });
330 }
331
332 let byte_data: Vec<u8> = data
333 .iter()
334 .flat_map(|v| {
335 let ptr = v as *const T as *const u8;
337 unsafe { core::slice::from_raw_parts(ptr, type_size) }.to_vec()
338 })
339 .collect();
340
341 Self::new(
342 byte_data,
343 width as u64,
344 height as u64,
345 data_type,
346 NoDataValue::None,
347 )
348 }
349
350 pub fn as_slice<T: Copy + 'static>(&self) -> Result<&[T]> {
358 let type_size = core::mem::size_of::<T>();
359 let expected_size = self.data_type.size_bytes();
360
361 if type_size != expected_size {
362 return Err(OxiGdalError::InvalidParameter {
363 parameter: "T",
364 message: format!(
365 "Type size mismatch: requested type has {} bytes, buffer contains {:?} ({} bytes)",
366 type_size, self.data_type, expected_size
367 ),
368 });
369 }
370
371 let pixel_count = (self.width * self.height) as usize;
372 let slice =
375 unsafe { core::slice::from_raw_parts(self.data.as_ptr() as *const T, pixel_count) };
376 Ok(slice)
377 }
378
379 pub fn as_slice_mut<T: Copy + 'static>(&mut self) -> Result<&mut [T]> {
387 let type_size = core::mem::size_of::<T>();
388 let expected_size = self.data_type.size_bytes();
389
390 if type_size != expected_size {
391 return Err(OxiGdalError::InvalidParameter {
392 parameter: "T",
393 message: format!(
394 "Type size mismatch: requested type has {} bytes, buffer contains {:?} ({} bytes)",
395 type_size, self.data_type, expected_size
396 ),
397 });
398 }
399
400 let pixel_count = (self.width * self.height) as usize;
401 let slice = unsafe {
404 core::slice::from_raw_parts_mut(self.data.as_mut_ptr() as *mut T, pixel_count)
405 };
406 Ok(slice)
407 }
408
409 pub fn get_pixel(&self, x: u64, y: u64) -> Result<f64> {
414 if x >= self.width || y >= self.height {
415 return Err(OxiGdalError::OutOfBounds {
416 message: format!(
417 "Pixel ({}, {}) out of bounds for {}x{} buffer",
418 x, y, self.width, self.height
419 ),
420 });
421 }
422
423 let pixel_size = self.data_type.size_bytes();
424 let offset = (y * self.width + x) as usize * pixel_size;
425
426 let value = match self.data_type {
427 RasterDataType::UInt8 => f64::from(self.data[offset]),
428 RasterDataType::Int8 => f64::from(self.data[offset] as i8),
429 RasterDataType::UInt16 => {
430 let bytes: [u8; 2] = self.data[offset..offset + 2].try_into().map_err(|_| {
431 OxiGdalError::Internal {
432 message: "Invalid slice length".to_string(),
433 }
434 })?;
435 f64::from(u16::from_ne_bytes(bytes))
436 }
437 RasterDataType::Int16 => {
438 let bytes: [u8; 2] = self.data[offset..offset + 2].try_into().map_err(|_| {
439 OxiGdalError::Internal {
440 message: "Invalid slice length".to_string(),
441 }
442 })?;
443 f64::from(i16::from_ne_bytes(bytes))
444 }
445 RasterDataType::UInt32 => {
446 let bytes: [u8; 4] = self.data[offset..offset + 4].try_into().map_err(|_| {
447 OxiGdalError::Internal {
448 message: "Invalid slice length".to_string(),
449 }
450 })?;
451 f64::from(u32::from_ne_bytes(bytes))
452 }
453 RasterDataType::Int32 => {
454 let bytes: [u8; 4] = self.data[offset..offset + 4].try_into().map_err(|_| {
455 OxiGdalError::Internal {
456 message: "Invalid slice length".to_string(),
457 }
458 })?;
459 f64::from(i32::from_ne_bytes(bytes))
460 }
461 RasterDataType::Float32 => {
462 let bytes: [u8; 4] = self.data[offset..offset + 4].try_into().map_err(|_| {
463 OxiGdalError::Internal {
464 message: "Invalid slice length".to_string(),
465 }
466 })?;
467 f64::from(f32::from_ne_bytes(bytes))
468 }
469 RasterDataType::Float64 => {
470 let bytes: [u8; 8] = self.data[offset..offset + 8].try_into().map_err(|_| {
471 OxiGdalError::Internal {
472 message: "Invalid slice length".to_string(),
473 }
474 })?;
475 f64::from_ne_bytes(bytes)
476 }
477 RasterDataType::UInt64 => {
478 let bytes: [u8; 8] = self.data[offset..offset + 8].try_into().map_err(|_| {
479 OxiGdalError::Internal {
480 message: "Invalid slice length".to_string(),
481 }
482 })?;
483 u64::from_ne_bytes(bytes) as f64
484 }
485 RasterDataType::Int64 => {
486 let bytes: [u8; 8] = self.data[offset..offset + 8].try_into().map_err(|_| {
487 OxiGdalError::Internal {
488 message: "Invalid slice length".to_string(),
489 }
490 })?;
491 i64::from_ne_bytes(bytes) as f64
492 }
493 RasterDataType::CFloat32 | RasterDataType::CFloat64 => {
494 let bytes: [u8; 4] = self.data[offset..offset + 4].try_into().map_err(|_| {
496 OxiGdalError::Internal {
497 message: "Invalid slice length".to_string(),
498 }
499 })?;
500 f64::from(f32::from_ne_bytes(bytes))
501 }
502 };
503
504 Ok(value)
505 }
506
507 pub fn set_pixel(&mut self, x: u64, y: u64, value: f64) -> Result<()> {
512 if x >= self.width || y >= self.height {
513 return Err(OxiGdalError::OutOfBounds {
514 message: format!(
515 "Pixel ({}, {}) out of bounds for {}x{} buffer",
516 x, y, self.width, self.height
517 ),
518 });
519 }
520
521 let pixel_size = self.data_type.size_bytes();
522 let offset = (y * self.width + x) as usize * pixel_size;
523
524 match self.data_type {
525 RasterDataType::UInt8 => {
526 self.data[offset] = value as u8;
527 }
528 RasterDataType::Int8 => {
529 self.data[offset] = (value as i8) as u8;
530 }
531 RasterDataType::UInt16 => {
532 let bytes = (value as u16).to_ne_bytes();
533 self.data[offset..offset + 2].copy_from_slice(&bytes);
534 }
535 RasterDataType::Int16 => {
536 let bytes = (value as i16).to_ne_bytes();
537 self.data[offset..offset + 2].copy_from_slice(&bytes);
538 }
539 RasterDataType::UInt32 => {
540 let bytes = (value as u32).to_ne_bytes();
541 self.data[offset..offset + 4].copy_from_slice(&bytes);
542 }
543 RasterDataType::Int32 => {
544 let bytes = (value as i32).to_ne_bytes();
545 self.data[offset..offset + 4].copy_from_slice(&bytes);
546 }
547 RasterDataType::Float32 => {
548 let bytes = (value as f32).to_ne_bytes();
549 self.data[offset..offset + 4].copy_from_slice(&bytes);
550 }
551 RasterDataType::Float64 => {
552 let bytes = value.to_ne_bytes();
553 self.data[offset..offset + 8].copy_from_slice(&bytes);
554 }
555 RasterDataType::UInt64 => {
556 let bytes = (value as u64).to_ne_bytes();
557 self.data[offset..offset + 8].copy_from_slice(&bytes);
558 }
559 RasterDataType::Int64 => {
560 let bytes = (value as i64).to_ne_bytes();
561 self.data[offset..offset + 8].copy_from_slice(&bytes);
562 }
563 RasterDataType::CFloat32 => {
564 let bytes = (value as f32).to_ne_bytes();
566 self.data[offset..offset + 4].copy_from_slice(&bytes);
567 }
568 RasterDataType::CFloat64 => {
569 let bytes = value.to_ne_bytes();
571 self.data[offset..offset + 8].copy_from_slice(&bytes);
572 }
573 }
574
575 Ok(())
576 }
577
578 pub fn get_u8(&self, x: u64, y: u64) -> Result<u8> {
585 self.check_bounds(x, y)?;
586 self.check_type(RasterDataType::UInt8)?;
587 let offset = (y * self.width + x) as usize;
588 Ok(self.data[offset])
589 }
590
591 pub fn get_i8(&self, x: u64, y: u64) -> Result<i8> {
596 self.check_bounds(x, y)?;
597 self.check_type(RasterDataType::Int8)?;
598 let offset = (y * self.width + x) as usize;
599 Ok(self.data[offset] as i8)
600 }
601
602 pub fn get_u16(&self, x: u64, y: u64) -> Result<u16> {
607 self.check_bounds(x, y)?;
608 self.check_type(RasterDataType::UInt16)?;
609 let offset = (y * self.width + x) as usize * 2;
610 let bytes: [u8; 2] =
611 self.data[offset..offset + 2]
612 .try_into()
613 .map_err(|_| OxiGdalError::Internal {
614 message: "Invalid slice length".to_string(),
615 })?;
616 Ok(u16::from_ne_bytes(bytes))
617 }
618
619 pub fn get_i16(&self, x: u64, y: u64) -> Result<i16> {
624 self.check_bounds(x, y)?;
625 self.check_type(RasterDataType::Int16)?;
626 let offset = (y * self.width + x) as usize * 2;
627 let bytes: [u8; 2] =
628 self.data[offset..offset + 2]
629 .try_into()
630 .map_err(|_| OxiGdalError::Internal {
631 message: "Invalid slice length".to_string(),
632 })?;
633 Ok(i16::from_ne_bytes(bytes))
634 }
635
636 pub fn get_u32(&self, x: u64, y: u64) -> Result<u32> {
641 self.check_bounds(x, y)?;
642 self.check_type(RasterDataType::UInt32)?;
643 let offset = (y * self.width + x) as usize * 4;
644 let bytes: [u8; 4] =
645 self.data[offset..offset + 4]
646 .try_into()
647 .map_err(|_| OxiGdalError::Internal {
648 message: "Invalid slice length".to_string(),
649 })?;
650 Ok(u32::from_ne_bytes(bytes))
651 }
652
653 pub fn get_i32(&self, x: u64, y: u64) -> Result<i32> {
658 self.check_bounds(x, y)?;
659 self.check_type(RasterDataType::Int32)?;
660 let offset = (y * self.width + x) as usize * 4;
661 let bytes: [u8; 4] =
662 self.data[offset..offset + 4]
663 .try_into()
664 .map_err(|_| OxiGdalError::Internal {
665 message: "Invalid slice length".to_string(),
666 })?;
667 Ok(i32::from_ne_bytes(bytes))
668 }
669
670 pub fn get_u64(&self, x: u64, y: u64) -> Result<u64> {
675 self.check_bounds(x, y)?;
676 self.check_type(RasterDataType::UInt64)?;
677 let offset = (y * self.width + x) as usize * 8;
678 let bytes: [u8; 8] =
679 self.data[offset..offset + 8]
680 .try_into()
681 .map_err(|_| OxiGdalError::Internal {
682 message: "Invalid slice length".to_string(),
683 })?;
684 Ok(u64::from_ne_bytes(bytes))
685 }
686
687 pub fn get_i64(&self, x: u64, y: u64) -> Result<i64> {
692 self.check_bounds(x, y)?;
693 self.check_type(RasterDataType::Int64)?;
694 let offset = (y * self.width + x) as usize * 8;
695 let bytes: [u8; 8] =
696 self.data[offset..offset + 8]
697 .try_into()
698 .map_err(|_| OxiGdalError::Internal {
699 message: "Invalid slice length".to_string(),
700 })?;
701 Ok(i64::from_ne_bytes(bytes))
702 }
703
704 pub fn get_f32(&self, x: u64, y: u64) -> Result<f32> {
709 self.check_bounds(x, y)?;
710 self.check_type(RasterDataType::Float32)?;
711 let offset = (y * self.width + x) as usize * 4;
712 let bytes: [u8; 4] =
713 self.data[offset..offset + 4]
714 .try_into()
715 .map_err(|_| OxiGdalError::Internal {
716 message: "Invalid slice length".to_string(),
717 })?;
718 Ok(f32::from_ne_bytes(bytes))
719 }
720
721 pub fn get_f64(&self, x: u64, y: u64) -> Result<f64> {
726 self.check_bounds(x, y)?;
727 self.check_type(RasterDataType::Float64)?;
728 let offset = (y * self.width + x) as usize * 8;
729 let bytes: [u8; 8] =
730 self.data[offset..offset + 8]
731 .try_into()
732 .map_err(|_| OxiGdalError::Internal {
733 message: "Invalid slice length".to_string(),
734 })?;
735 Ok(f64::from_ne_bytes(bytes))
736 }
737
738 pub fn set_u8(&mut self, x: u64, y: u64, value: u8) -> Result<()> {
745 self.check_bounds(x, y)?;
746 self.check_type(RasterDataType::UInt8)?;
747 let offset = (y * self.width + x) as usize;
748 self.data[offset] = value;
749 Ok(())
750 }
751
752 pub fn set_f32(&mut self, x: u64, y: u64, value: f32) -> Result<()> {
757 self.check_bounds(x, y)?;
758 self.check_type(RasterDataType::Float32)?;
759 let offset = (y * self.width + x) as usize * 4;
760 self.data[offset..offset + 4].copy_from_slice(&value.to_ne_bytes());
761 Ok(())
762 }
763
764 pub fn set_f64(&mut self, x: u64, y: u64, value: f64) -> Result<()> {
769 self.check_bounds(x, y)?;
770 self.check_type(RasterDataType::Float64)?;
771 let offset = (y * self.width + x) as usize * 8;
772 self.data[offset..offset + 8].copy_from_slice(&value.to_ne_bytes());
773 Ok(())
774 }
775
776 pub fn row_slice<T: Copy + 'static>(&self, y: u64) -> Result<&[T]> {
783 if y >= self.height {
784 return Err(OxiGdalError::OutOfBounds {
785 message: format!("Row {} out of bounds for height {}", y, self.height),
786 });
787 }
788 let type_size = core::mem::size_of::<T>();
789 let expected_size = self.data_type.size_bytes();
790 if type_size != expected_size {
791 return Err(OxiGdalError::InvalidParameter {
792 parameter: "T",
793 message: format!(
794 "Type size {} doesn't match {:?} size {}",
795 type_size, self.data_type, expected_size
796 ),
797 });
798 }
799 let row_start = (y * self.width) as usize * expected_size;
800 let row_end = row_start + self.width as usize * expected_size;
801 let slice = unsafe {
803 core::slice::from_raw_parts(
804 self.data[row_start..row_end].as_ptr() as *const T,
805 self.width as usize,
806 )
807 };
808 Ok(slice)
809 }
810
811 pub fn window(&self, x: u64, y: u64, width: u64, height: u64) -> Result<Self> {
816 if x + width > self.width || y + height > self.height {
817 return Err(OxiGdalError::OutOfBounds {
818 message: format!(
819 "Window ({},{}) {}x{} exceeds buffer {}x{}",
820 x, y, width, height, self.width, self.height
821 ),
822 });
823 }
824 let pixel_size = self.data_type.size_bytes();
825 let row_bytes = width as usize * pixel_size;
826 let mut data = Vec::with_capacity(height as usize * row_bytes);
827 for row in y..y + height {
828 let src_start = (row * self.width + x) as usize * pixel_size;
829 data.extend_from_slice(&self.data[src_start..src_start + row_bytes]);
830 }
831 Self::new(data, width, height, self.data_type, self.nodata)
832 }
833
834 fn check_bounds(&self, x: u64, y: u64) -> Result<()> {
837 if x >= self.width || y >= self.height {
838 return Err(OxiGdalError::OutOfBounds {
839 message: format!(
840 "Pixel ({}, {}) out of bounds for {}x{} buffer",
841 x, y, self.width, self.height
842 ),
843 });
844 }
845 Ok(())
846 }
847
848 fn check_type(&self, expected: RasterDataType) -> Result<()> {
849 if self.data_type != expected {
850 return Err(OxiGdalError::InvalidParameter {
851 parameter: "data_type",
852 message: format!(
853 "Buffer contains {:?} data, requested {:?}",
854 self.data_type, expected
855 ),
856 });
857 }
858 Ok(())
859 }
860
861 #[must_use]
863 pub fn is_nodata(&self, value: f64) -> bool {
864 match self.nodata.as_f64() {
865 Some(nd) => {
866 if nd.is_nan() && value.is_nan() {
867 true
868 } else {
869 (nd - value).abs() < f64::EPSILON
870 }
871 }
872 None => false,
873 }
874 }
875
876 pub fn convert_to(&self, target_type: RasterDataType) -> Result<Self> {
881 if target_type == self.data_type {
882 return Ok(self.clone());
883 }
884
885 let mut result = Self::zeros(self.width, self.height, target_type);
886 result.nodata = self.nodata;
887
888 for y in 0..self.height {
889 for x in 0..self.width {
890 let value = self.get_pixel(x, y)?;
891 result.set_pixel(x, y, value)?;
892 }
893 }
894
895 Ok(result)
896 }
897
898 pub fn compute_statistics(&self) -> Result<BufferStatistics> {
900 let mut min = f64::MAX;
901 let mut max = f64::MIN;
902 let mut sum = 0.0;
903 let mut sum_sq = 0.0;
904 let mut valid_count = 0u64;
905
906 for y in 0..self.height {
907 for x in 0..self.width {
908 let value = self.get_pixel(x, y)?;
909 if !self.is_nodata(value) && value.is_finite() {
910 min = min.min(value);
911 max = max.max(value);
912 sum += value;
913 sum_sq += value * value;
914 valid_count += 1;
915 }
916 }
917 }
918
919 if valid_count == 0 {
920 return Ok(BufferStatistics {
921 min: f64::NAN,
922 max: f64::NAN,
923 mean: f64::NAN,
924 std_dev: f64::NAN,
925 valid_count: 0,
926 histogram: None,
927 });
928 }
929
930 let mean = sum / valid_count as f64;
931 let variance = (sum_sq / valid_count as f64) - (mean * mean);
932 let std_dev = variance.sqrt();
933
934 Ok(BufferStatistics {
935 min,
936 max,
937 mean,
938 std_dev,
939 valid_count,
940 histogram: None,
941 })
942 }
943
944 pub fn compute_statistics_with_histogram(&self, bin_count: usize) -> Result<BufferStatistics> {
965 if bin_count == 0 {
966 return Err(OxiGdalError::InvalidParameter {
967 parameter: "bin_count",
968 message: "bin_count must be at least 1".to_string(),
969 });
970 }
971
972 let mut min = f64::MAX;
974 let mut max = f64::MIN;
975 let mut sum = 0.0f64;
976 let mut sum_sq = 0.0f64;
977 let mut valid_count = 0u64;
978 let total_pixels = (self.width * self.height) as usize;
980 let mut valid_values: Vec<f64> = Vec::with_capacity(total_pixels);
981
982 for y in 0..self.height {
983 for x in 0..self.width {
984 let value = self.get_pixel(x, y)?;
985 if !self.is_nodata(value) && value.is_finite() {
986 min = min.min(value);
987 max = max.max(value);
988 sum += value;
989 sum_sq += value * value;
990 valid_count += 1;
991 valid_values.push(value);
992 }
993 }
994 }
995
996 let mut bins = vec![0u64; bin_count];
998
999 if valid_count > 0 {
1000 let range = max - min;
1001 if range == 0.0 {
1002 bins[0] = valid_count;
1004 } else {
1005 for v in &valid_values {
1006 let bin_idx = (((v - min) / range) * bin_count as f64).floor() as usize;
1007 let bin_idx = bin_idx.min(bin_count - 1);
1009 bins[bin_idx] += 1;
1010 }
1011 }
1012 }
1013
1014 if valid_count == 0 {
1015 return Ok(BufferStatistics {
1016 min: f64::NAN,
1017 max: f64::NAN,
1018 mean: f64::NAN,
1019 std_dev: f64::NAN,
1020 valid_count: 0,
1021 histogram: Some(bins),
1022 });
1023 }
1024
1025 let mean = sum / valid_count as f64;
1026 let variance = (sum_sq / valid_count as f64) - (mean * mean);
1027 let std_dev = variance.max(0.0).sqrt();
1028
1029 Ok(BufferStatistics {
1030 min,
1031 max,
1032 mean,
1033 std_dev,
1034 valid_count,
1035 histogram: Some(bins),
1036 })
1037 }
1038}
1039
1040impl fmt::Debug for RasterBuffer {
1041 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1042 f.debug_struct("RasterBuffer")
1043 .field("width", &self.width)
1044 .field("height", &self.height)
1045 .field("data_type", &self.data_type)
1046 .field("nodata", &self.nodata)
1047 .field("bytes", &self.data.len())
1048 .finish()
1049 }
1050}
1051
1052#[derive(Debug, Clone, PartialEq)]
1057pub struct BufferStatistics {
1058 pub min: f64,
1060 pub max: f64,
1062 pub mean: f64,
1064 pub std_dev: f64,
1066 pub valid_count: u64,
1068 pub histogram: Option<Vec<u64>>,
1073}
1074
1075#[cfg(feature = "arrow")]
1076mod arrow_support {
1077 use arrow_array::{Array, Float64Array};
1080
1081 use super::{OxiGdalError, RasterBuffer, Result};
1082
1083 impl RasterBuffer {
1084 pub fn from_arrow_array<A: Array>(_array: &A, _width: u64, _height: u64) -> Result<Self> {
1089 Err(OxiGdalError::NotSupported {
1092 operation: "Arrow array conversion".to_string(),
1093 })
1094 }
1095
1096 pub fn to_float64_array(&self) -> Result<Float64Array> {
1098 let mut values = Vec::with_capacity(self.pixel_count() as usize);
1099 for y in 0..self.height {
1100 for x in 0..self.width {
1101 values.push(self.get_pixel(x, y)?);
1102 }
1103 }
1104 Ok(Float64Array::from(values))
1105 }
1106 }
1107}
1108
1109#[cfg(test)]
1110mod tests {
1111 #![allow(clippy::expect_used)]
1112
1113 use super::*;
1114
1115 #[test]
1116 fn test_buffer_creation() {
1117 let buffer = RasterBuffer::zeros(100, 100, RasterDataType::UInt8);
1118 assert_eq!(buffer.width(), 100);
1119 assert_eq!(buffer.height(), 100);
1120 assert_eq!(buffer.pixel_count(), 10_000);
1121 assert_eq!(buffer.as_bytes().len(), 10_000);
1122 }
1123
1124 #[test]
1125 fn test_pixel_access() {
1126 let mut buffer = RasterBuffer::zeros(10, 10, RasterDataType::Float32);
1127
1128 buffer.set_pixel(5, 5, 42.0).expect("set should work");
1129 let value = buffer.get_pixel(5, 5).expect("get should work");
1130 assert!((value - 42.0).abs() < f64::EPSILON);
1131
1132 assert!(buffer.get_pixel(100, 0).is_err());
1134 assert!(buffer.set_pixel(0, 100, 0.0).is_err());
1135 }
1136
1137 #[test]
1138 fn test_nodata() {
1139 let buffer = RasterBuffer::nodata_filled(
1140 10,
1141 10,
1142 RasterDataType::Float32,
1143 NoDataValue::Float(-9999.0),
1144 );
1145
1146 assert!(buffer.is_nodata(-9999.0));
1147 assert!(!buffer.is_nodata(0.0));
1148 }
1149
1150 #[test]
1151 fn test_statistics() {
1152 let mut buffer = RasterBuffer::zeros(10, 10, RasterDataType::Float32);
1153
1154 for y in 0..10 {
1156 for x in 0..10 {
1157 let value = (y * 10 + x) as f64;
1158 buffer.set_pixel(x, y, value).expect("set should work");
1159 }
1160 }
1161
1162 let stats = buffer.compute_statistics().expect("stats should work");
1163 assert!((stats.min - 0.0).abs() < f64::EPSILON);
1164 assert!((stats.max - 99.0).abs() < f64::EPSILON);
1165 assert!((stats.mean - 49.5).abs() < 0.01);
1166 assert_eq!(stats.valid_count, 100);
1167 }
1168
1169 #[test]
1170 fn test_data_validation() {
1171 let result = RasterBuffer::new(
1173 vec![0u8; 100],
1174 10,
1175 10,
1176 RasterDataType::UInt16, NoDataValue::None,
1178 );
1179 assert!(result.is_err());
1180
1181 let result = RasterBuffer::new(
1183 vec![0u8; 200],
1184 10,
1185 10,
1186 RasterDataType::UInt16,
1187 NoDataValue::None,
1188 );
1189 assert!(result.is_ok());
1190 }
1191
1192 #[test]
1193 fn test_typed_get_u8() {
1194 let mut buffer = RasterBuffer::zeros(10, 10, RasterDataType::UInt8);
1195 buffer.set_pixel(3, 4, 200.0).expect("set should work");
1196 assert_eq!(buffer.get_u8(3, 4).expect("get_u8"), 200);
1197 assert!(buffer.get_f32(3, 4).is_err());
1199 }
1200
1201 #[test]
1202 fn test_typed_get_i8() {
1203 let mut buffer = RasterBuffer::zeros(10, 10, RasterDataType::Int8);
1204 buffer.set_pixel(0, 0, -42.0).expect("set should work");
1205 assert_eq!(buffer.get_i8(0, 0).expect("get_i8"), -42);
1206 }
1207
1208 #[test]
1209 fn test_typed_get_u16() {
1210 let mut buffer = RasterBuffer::zeros(10, 10, RasterDataType::UInt16);
1211 buffer.set_pixel(5, 5, 60000.0).expect("set should work");
1212 assert_eq!(buffer.get_u16(5, 5).expect("get_u16"), 60000);
1213 }
1214
1215 #[test]
1216 fn test_typed_get_i16() {
1217 let mut buffer = RasterBuffer::zeros(10, 10, RasterDataType::Int16);
1218 buffer.set_pixel(2, 3, -1234.0).expect("set should work");
1219 assert_eq!(buffer.get_i16(2, 3).expect("get_i16"), -1234);
1220 }
1221
1222 #[test]
1223 fn test_typed_get_u32() {
1224 let mut buffer = RasterBuffer::zeros(10, 10, RasterDataType::UInt32);
1225 buffer.set_pixel(0, 0, 100_000.0).expect("set should work");
1226 assert_eq!(buffer.get_u32(0, 0).expect("get_u32"), 100_000);
1227 }
1228
1229 #[test]
1230 fn test_typed_get_i32() {
1231 let mut buffer = RasterBuffer::zeros(10, 10, RasterDataType::Int32);
1232 buffer.set_pixel(1, 1, -50_000.0).expect("set should work");
1233 assert_eq!(buffer.get_i32(1, 1).expect("get_i32"), -50_000);
1234 }
1235
1236 #[test]
1237 fn test_typed_get_u64() {
1238 let mut buffer = RasterBuffer::zeros(10, 10, RasterDataType::UInt64);
1239 buffer
1240 .set_pixel(0, 0, 1_000_000.0)
1241 .expect("set should work");
1242 assert_eq!(buffer.get_u64(0, 0).expect("get_u64"), 1_000_000);
1243 }
1244
1245 #[test]
1246 fn test_typed_get_i64() {
1247 let mut buffer = RasterBuffer::zeros(10, 10, RasterDataType::Int64);
1248 buffer.set_pixel(0, 0, -999_999.0).expect("set should work");
1249 assert_eq!(buffer.get_i64(0, 0).expect("get_i64"), -999_999);
1250 }
1251
1252 #[test]
1253 fn test_typed_get_f32() {
1254 let mut buffer = RasterBuffer::zeros(10, 10, RasterDataType::Float32);
1255 buffer
1256 .set_f32(7, 8, core::f32::consts::PI)
1257 .expect("set_f32 should work");
1258 let val = buffer.get_f32(7, 8).expect("get_f32");
1259 assert!((val - core::f32::consts::PI).abs() < 1e-5);
1260 }
1261
1262 #[test]
1263 fn test_typed_get_f64() {
1264 let mut buffer = RasterBuffer::zeros(10, 10, RasterDataType::Float64);
1265 buffer
1266 .set_f64(9, 9, core::f64::consts::E)
1267 .expect("set_f64 should work");
1268 let val = buffer.get_f64(9, 9).expect("get_f64");
1269 assert!((val - core::f64::consts::E).abs() < 1e-9);
1270 }
1271
1272 #[test]
1273 fn test_typed_set_u8() {
1274 let mut buffer = RasterBuffer::zeros(10, 10, RasterDataType::UInt8);
1275 buffer.set_u8(0, 0, 255).expect("set_u8 should work");
1276 assert_eq!(buffer.get_u8(0, 0).expect("get_u8"), 255);
1277 }
1278
1279 #[test]
1280 fn test_typed_out_of_bounds() {
1281 let buffer = RasterBuffer::zeros(10, 10, RasterDataType::Float32);
1282 assert!(buffer.get_f32(10, 0).is_err());
1283 assert!(buffer.get_f32(0, 10).is_err());
1284 }
1285
1286 #[test]
1287 fn test_typed_wrong_type() {
1288 let buffer = RasterBuffer::zeros(10, 10, RasterDataType::UInt8);
1289 assert!(buffer.get_f32(0, 0).is_err());
1290 assert!(buffer.get_u16(0, 0).is_err());
1291 assert!(buffer.get_i32(0, 0).is_err());
1292 assert!(buffer.get_f64(0, 0).is_err());
1293 }
1294
1295 #[test]
1296 fn test_row_slice() {
1297 let mut buffer = RasterBuffer::zeros(5, 3, RasterDataType::Float32);
1298 for x in 0..5 {
1299 buffer
1300 .set_pixel(x, 1, (x + 10) as f64)
1301 .expect("set should work");
1302 }
1303 let row: &[f32] = buffer.row_slice(1).expect("row_slice should work");
1304 assert_eq!(row.len(), 5);
1305 assert!((row[0] - 10.0).abs() < 1e-5);
1306 assert!((row[4] - 14.0).abs() < 1e-5);
1307 }
1308
1309 #[test]
1310 fn test_row_slice_out_of_bounds() {
1311 let buffer = RasterBuffer::zeros(5, 3, RasterDataType::Float32);
1312 assert!(buffer.row_slice::<f32>(3).is_err());
1313 }
1314
1315 #[test]
1316 fn test_window() {
1317 let mut buffer = RasterBuffer::zeros(10, 10, RasterDataType::UInt8);
1318 buffer.set_pixel(5, 5, 42.0).expect("set should work");
1319 buffer.set_pixel(6, 6, 99.0).expect("set should work");
1320
1321 let win = buffer.window(4, 4, 4, 4).expect("window should work");
1322 assert_eq!(win.width(), 4);
1323 assert_eq!(win.height(), 4);
1324 let val = win.get_pixel(1, 1).expect("get should work");
1326 assert!((val - 42.0).abs() < f64::EPSILON);
1327 let val = win.get_pixel(2, 2).expect("get should work");
1329 assert!((val - 99.0).abs() < f64::EPSILON);
1330 }
1331
1332 #[test]
1333 fn test_window_out_of_bounds() {
1334 let buffer = RasterBuffer::zeros(10, 10, RasterDataType::UInt8);
1335 assert!(buffer.window(8, 8, 4, 4).is_err());
1336 }
1337}