edges 0.8.1

a library for getting the edges of objects in images with transparency
Documentation
#[cfg(feature = "parallel")]
use rayon::prelude::*;

use super::Neighbors;
use crate::UVec2;
use Direction::{East, North, Northeast, Northwest, South, Southeast, Southwest, West};

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Direction {
    North,
    South,
    East,
    West,

    Northeast,
    Northwest,
    Southeast,
    Southwest,
}

impl Direction {
    pub fn find_in(self, current: UVec2, points: &[UVec2]) -> Option<UVec2> {
        #[cfg(not(feature = "parallel"))]
        let iter = points.iter();
        #[cfg(feature = "parallel")]
        let iter = points.par_iter();
        match self {
            Direction::North => iter
                .filter(|p| p.x == current.x && p.y > current.y)
                .min_by_key(|p| p.y),
            Direction::South => iter
                .filter(|p| p.x == current.x && p.y < current.y)
                .max_by_key(|p| p.y),
            Direction::East => iter
                .filter(|p| p.y == current.y && p.x > current.x)
                .min_by_key(|p| p.x),
            Direction::West => iter
                .filter(|p| p.y == current.y && p.x < current.x)
                .max_by_key(|p| p.x),
            Direction::Northeast => iter
                .filter(|p| {
                    p.cmpgt(current).all() && p.y.abs_diff(current.y) == p.x.abs_diff(current.x)
                })
                .min_by_key(|p| p.y),
            Direction::Northwest => iter
                .filter(|p| {
                    (p.x < current.x && p.y > current.y)
                        && p.y.abs_diff(current.y) == p.x.abs_diff(current.x)
                })
                .min_by_key(|p| p.y),
            Direction::Southeast => iter
                .filter(|p| {
                    (p.x > current.x && p.y < current.y)
                        && p.y.abs_diff(current.y) == p.x.abs_diff(current.x)
                })
                .max_by_key(|p| p.y),
            Direction::Southwest => iter
                .filter(|p| {
                    p.cmplt(current).all() && p.y.abs_diff(current.y) == p.x.abs_diff(current.x)
                })
                .max_by_key(|p| p.y),
        }
        .copied()
    }

    #[inline]
    pub fn reverse(self) -> Self {
        match self {
            North => South,
            South => North,
            East => West,
            West => East,
            Northeast => Southwest,
            Northwest => Southeast,
            Southeast => Northwest,
            Southwest => Northeast,
        }
    }

    #[allow(clippy::too_many_lines)]
    pub fn next_direction(previous_direction: Option<Self>, neighbors: Neighbors) -> Self {
        match neighbors.bits() {
            140 | 136 | 132 | 128 => Some(North),
            64..=67 => Some(South),
            42 | 40 | 34 | 32 => Some(East),
            21 | 20 | 17 | 16 => Some(West),
            8 => Some(Northeast),
            4 => Some(Northwest),
            2 => Some(Southeast),
            1 => Some(Southwest),

            239
            | 238
            | 235
            | 234
            | 223
            | 221
            | 215
            | 213
            | 188..=207
            | 127
            | 123
            | 119
            | 115
            | 48..=63
            | 9
            | 6 => previous_direction,

            80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 254 => match previous_direction {
                Some(North) => Some(West),
                Some(East) => Some(South),
                _ => None,
            },
            96 | 97 | 98 | 99 | 104 | 105 | 106 | 107 | 253 => match previous_direction {
                Some(North) => Some(East),
                Some(West) => Some(South),
                _ => None,
            },
            144 | 145 | 148 | 149 | 152 | 153 | 156 | 157 | 251 => match previous_direction {
                Some(South) => Some(West),
                Some(East) => Some(North),
                _ => None,
            },
            160 | 162 | 164 | 166 | 168 | 170 | 172 | 174 | 247 => match previous_direction {
                Some(South) => Some(East),
                Some(West) => Some(North),
                _ => None,
            },

            18 | 19 | 22 | 23 => match previous_direction {
                Some(Northwest) => Some(West),
                Some(East) => Some(Southeast),
                _ => None,
            },
            24 | 25 | 28 | 29 => match previous_direction {
                Some(East) => Some(Northeast),
                Some(Southwest) => Some(West),
                _ => None,
            },
            33 | 35 | 41 | 43 => match previous_direction {
                Some(West) => Some(Southwest),
                Some(Northeast) => Some(East),
                _ => None,
            },
            36 | 38 | 44 | 46 => match previous_direction {
                Some(West) => Some(Northwest),
                Some(Southeast) => Some(East),
                _ => None,
            },
            68..=71 => match previous_direction {
                Some(North) => Some(Northwest),
                Some(Southeast) => Some(South),
                _ => None,
            },
            72..=75 => match previous_direction {
                Some(North) => Some(Northeast),
                Some(Southwest) => Some(South),
                _ => None,
            },
            129 | 133 | 137 | 141 => match previous_direction {
                Some(South) => Some(Southwest),
                Some(Northeast) => Some(North),
                _ => None,
            },
            130 | 134 | 138 | 142 => match previous_direction {
                Some(South) => Some(Southeast),
                Some(Northwest) => Some(North),
                _ => None,
            },

            3 => match previous_direction {
                Some(Northeast) => Some(Southeast),
                Some(Northwest) => Some(Southwest),
                _ => None,
            },
            5 => match previous_direction {
                Some(Northeast) => Some(Northwest),
                Some(Southeast) => Some(Southwest),
                _ => None,
            },
            10 => match previous_direction {
                Some(Northwest) => Some(Northeast),
                Some(Southwest) => Some(Southeast),
                _ => None,
            },
            12 => match previous_direction {
                Some(Southeast) => Some(Northeast),
                Some(Southwest) => Some(Northwest),
                _ => None,
            },

            7 => match previous_direction {
                Some(Northeast) => Some(Southeast),
                Some(Northwest) => Some(Northwest),
                Some(Southeast) => Some(Southwest),
                _ => None,
            },
            11 => match previous_direction {
                Some(Northeast) => Some(Southeast),
                Some(Northwest) => Some(Northeast),
                Some(Southwest) => Some(Southwest),
                _ => None,
            },
            13 => match previous_direction {
                Some(Northeast) => Some(Northeast),
                Some(Southeast) => Some(Southwest),
                Some(Southwest) => Some(Northwest),
                _ => None,
            },
            14 => match previous_direction {
                Some(Northwest) => Some(Northeast),
                Some(Southeast) => Some(Southeast),
                Some(Southwest) => Some(Northwest),
                _ => None,
            },

            112..=114 | 116..=118 | 120..=122 | 124..=126 | 252 => match previous_direction {
                Some(North) => Some(East),
                Some(East) => Some(South),
                Some(West) => Some(West),
                _ => None,
            },
            176..=187 | 243 => match previous_direction {
                Some(South) => Some(West),
                Some(East) => Some(East),
                Some(West) => Some(North),
                _ => None,
            },
            208..=212 | 214 | 216..=220 | 222 | 250 => match previous_direction {
                Some(North) => Some(North),
                Some(South) => Some(West),
                Some(East) => Some(South),
                _ => None,
            },
            224..=233 | 237 | 236 | 245 => match previous_direction {
                Some(North) => Some(East),
                Some(South) => Some(South),
                Some(West) => Some(North),
                _ => None,
            },

            88..=95 => match previous_direction {
                Some(North) => Some(Northeast),
                Some(East) => Some(South),
                Some(Southwest) => Some(West),
                _ => None,
            },
            100..=103 | 108..=111 => match previous_direction {
                Some(North) => Some(East),
                Some(West) => Some(Northwest),
                Some(Southeast) => Some(South),
                _ => None,
            },
            146 | 147 | 150 | 151 | 154 | 155 | 158 | 159 => match previous_direction {
                Some(South) => Some(West),
                Some(East) => Some(Southeast),
                Some(Northwest) => Some(North),
                _ => None,
            },
            161 | 163 | 165 | 167 | 169 | 171 | 173 | 175 => match previous_direction {
                Some(South) => Some(Southwest),
                Some(West) => Some(North),
                Some(Northeast) => Some(East),
                _ => None,
            },

            26 | 27 | 30 | 31 => match previous_direction {
                Some(East) => Some(Southeast),
                Some(Northwest) => Some(Northeast),
                Some(Southwest) => Some(West),
                _ => None,
            },
            37 | 39 | 45 | 47 => match previous_direction {
                Some(West) => Some(Northwest),
                Some(Northeast) => Some(East),
                Some(Southeast) => Some(Southwest),
                _ => None,
            },
            76..=79 => match previous_direction {
                Some(North) => Some(Northeast),
                Some(Southeast) => Some(South),
                Some(Southwest) => Some(Northwest),
                _ => None,
            },
            131 | 135 | 139 | 143 => match previous_direction {
                Some(South) => Some(Southwest),
                Some(Northeast) => Some(Southeast),
                Some(Northwest) => Some(North),
                _ => None,
            },

            240 | 241 | 242 | 244 | 246 | 248 | 249 => match previous_direction {
                Some(North) => Some(East),
                Some(South) => Some(West),
                Some(East) => Some(South),
                Some(West) => Some(North),
                _ => None,
            },
            15 => match previous_direction {
                Some(Northeast) => Some(Southeast),
                Some(Northwest) => Some(Northeast),
                Some(Southeast) => Some(Southwest),
                Some(Southwest) => Some(Northwest),
                _ => None,
            },
            0 | 255 => unreachable!(),
        }
        .unwrap_or({
            if neighbors.contains(Neighbors::NORTH) {
                North
            } else if neighbors.contains(Neighbors::SOUTH) {
                South
            } else if neighbors.contains(Neighbors::EAST) {
                East
            } else if neighbors.contains(Neighbors::WEST) {
                West
            } else if neighbors.contains(Neighbors::NORTHEAST) {
                Northeast
            } else if neighbors.contains(Neighbors::NORTHWEST) {
                Northwest
            } else if neighbors.contains(Neighbors::SOUTHEAST) {
                Southeast
            } else if neighbors.contains(Neighbors::SOUTHWEST) {
                Southwest
            } else {
                unreachable!()
            }
        })
    }
}