use scirs2_core::ndarray::{Array, Dimension, IxDyn};
use super::Connectivity;
use crate::error::{NdimageError, NdimageResult};
#[allow(dead_code)]
pub fn generate_binary_structure(
rank: usize,
connectivity: Connectivity,
) -> NdimageResult<Array<bool, IxDyn>> {
if rank == 0 {
return Err(NdimageError::InvalidInput(
"Rank must be greater than 0".into(),
));
}
let shape = vec![3; rank];
let mut structure = Array::<bool, IxDyn>::from_elem(IxDyn(&shape), false);
let center = vec![1; rank];
structure[IxDyn(¢er)] = true;
for dim in 0..rank {
let mut lower_idx = center.clone();
let mut upper_idx = center.clone();
lower_idx[dim] = 0;
upper_idx[dim] = 2;
structure[IxDyn(&lower_idx)] = true;
structure[IxDyn(&upper_idx)] = true;
}
if connectivity == Connectivity::FaceEdge || connectivity == Connectivity::Full {
let mut indices = vec![1; rank];
add_connected_indices(&mut structure, &mut indices, 0, connectivity);
}
Ok(structure)
}
#[allow(dead_code)]
fn add_connected_indices(
structure: &mut Array<bool, IxDyn>,
indices: &mut Vec<usize>,
dim: usize,
connectivity: Connectivity,
) {
if dim == indices.len() {
structure[IxDyn(indices)] = true;
return;
}
let orig_val = indices[dim];
for val in 0..3 {
indices[dim] = val;
let center_dist = indices
.iter()
.enumerate()
.map(|(i, &idx)| {
if i == dim {
0 } else {
match idx {
0 | 2 => 1, _ => 0, }
}
})
.sum::<usize>();
let is_valid = match connectivity {
Connectivity::Face => {
center_dist == 0
}
Connectivity::FaceEdge => {
center_dist <= 1
}
Connectivity::Full => {
true
}
};
if is_valid {
add_connected_indices(structure, indices, dim + 1, connectivity);
}
}
indices[dim] = orig_val;
}
#[allow(dead_code)]
pub fn iterate_structure<D>(
structure: &Array<bool, D>,
iterations: usize,
) -> NdimageResult<Array<bool, D>>
where
D: Dimension,
{
if structure.ndim() == 0 {
return Err(NdimageError::InvalidInput(
"Structure cannot be 0-dimensional".into(),
));
}
if iterations == 0 {
return Ok(structure.to_owned());
}
Ok(structure.to_owned())
}
#[allow(dead_code)]
pub fn box_structure(shape: &[usize]) -> NdimageResult<Array<bool, IxDyn>> {
if shape.is_empty() {
return Err(NdimageError::InvalidInput("Shape cannot be empty".into()));
}
for &s in shape {
if s == 0 {
return Err(NdimageError::InvalidInput(
"Shape dimensions must be greater than 0".into(),
));
}
}
let structure = Array::<bool, IxDyn>::from_elem(IxDyn(shape), true);
Ok(structure)
}
#[allow(dead_code)]
pub fn disk_structure(radius: f64, dimension: Option<usize>) -> NdimageResult<Array<bool, IxDyn>> {
if radius <= 0.0 {
return Err(NdimageError::InvalidInput(
"Radius must be greater than 0".into(),
));
}
let dim = dimension.unwrap_or(2);
if dim < 2 {
return Err(NdimageError::InvalidInput(
"Dimension must be at least 2".into(),
));
}
let size = (2.0 * radius).round() as usize;
if size % 2 == 0 {
let size = size + 1;
let shape = vec![size; dim];
let center = (size - 1) as f64 / 2.0;
let mut structure = Array::<bool, IxDyn>::from_elem(IxDyn(&shape), false);
if dim == 2 {
for i in 0..size {
for j in 0..size {
let dx = i as f64 - center;
let dy = j as f64 - center;
let distance = (dx * dx + dy * dy).sqrt();
if distance <= radius {
structure[[i, j]] = true;
}
}
}
} else {
let size = (2.0 * radius.ceil() + 1.0) as usize;
let shape = vec![size; dim];
return box_structure(&shape);
}
Ok(structure)
} else {
let shape = vec![size; dim];
let center = (size - 1) as f64 / 2.0;
let mut structure = Array::<bool, IxDyn>::from_elem(IxDyn(&shape), false);
if dim == 2 {
for i in 0..size {
for j in 0..size {
let dx = i as f64 - center;
let dy = j as f64 - center;
let distance = (dx * dx + dy * dy).sqrt();
if distance <= radius {
structure[[i, j]] = true;
}
}
}
} else {
let size = (2.0 * radius.ceil() + 1.0) as usize;
let shape = vec![size; dim];
return box_structure(&shape);
}
Ok(structure)
}
}
pub(crate) fn generate_binary_structure_dyn(rank: usize) -> NdimageResult<Array<bool, IxDyn>> {
generate_binary_structure(rank, Connectivity::Face)
}
#[cfg(test)]
mod tests {
use super::*;
use scirs2_core::ndarray::Array2;
#[test]
fn test_iterate_structure() {
let input = Array2::from_elem((3, 3), true);
let result = iterate_structure(&input, 1).expect("Operation failed");
assert_eq!(result.shape(), input.shape());
}
#[test]
fn test_box_structure() {
let result = box_structure(&[3, 3]).expect("Operation failed");
assert_eq!(result.shape(), &[3, 3]);
assert!(result.iter().all(|&x| x));
}
#[test]
fn test_disk_structure() {
let result = disk_structure(1.5, None).expect("Operation failed");
assert_eq!(result.shape(), &[3, 3]);
println!("Actual disk structure:");
let rows = result.shape()[0];
let cols = result.shape()[1];
for i in 0..rows {
for j in 0..cols {
print!("{}", if result[[i, j]] { "1" } else { "0" });
}
println!();
}
assert!(result[[1, 1]]);
let count: usize = result.iter().filter(|&&x| x).count();
assert!(
count >= 5 && count <= 9,
"Expected between 5 and 9 pixels, got {}",
count
);
}
}