1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
use std::fmt;
use delaunator::EMPTY;

use super::{
    Voronoi,
    Point,
    iterator::NeighborSiteIterator
};

/// Represents a Voronoi cell. This is an ergonomic way to access cell details.
///
/// Use [Voronoi::cell()] or [Voronoi::iter_cells()] to obtain an instance of this type.
#[derive(Clone)]
pub struct VoronoiCell<'v> {
    site: usize,
    voronoi: &'v Voronoi
}

impl<'v> VoronoiCell<'v> {
    #[inline]
    pub (super) fn new(site: usize, voronoi: &'v Voronoi) -> Self {
        Self {
            site,
            voronoi
        }
    }

    /// Gets a reference to the position of the site associated with this cell.
    ///
    /// # Examples
    ///
    ///```
    /// use voronoice::*;
    /// let sites = vec![Point { x: 0.0, y: 0.0 }, Point { x: 0.5, y: 0.0 }, Point { x: 0.0, y: 0.5 }];
    /// let v = VoronoiBuilder::default()
    ///     .set_sites(sites.clone())
    ///     .build()
    ///     .unwrap();
    /// // the first site generated by generate_circle_sites is at the origin
    /// assert_eq!(&sites[0], v.cell(0).site_position());
    /// assert_eq!(&sites[1], v.cell(1).site_position());
    /// assert_eq!(&sites[2], v.cell(2).site_position());
    ///```
    pub fn site_position(&self) -> &Point {
        &self.voronoi.sites[self.site]
    }

    /// Gets the index associated with the site for this cell.
    #[inline]
    pub fn site(&self) -> usize {
        self.site
    }

    /// Gets a slice of indices into [Voronoi::vertices] used to index the [Point]s representing the voronoi cell vertices.
    ///
    /// Semantically these values represent the Delaunay triangles associated with this voronoi cell.
    /// The Voronoi cell vertices are the circumcenters of the associated Delaunay triangles.
    ///
    /// If this cell is on the hull of the diagram (```cell.is_on_hull() == true```), or has had one of its edges clipped, some indices will not match to
    /// Delaunay triangles, but to virtual points added during the process of hull closing and clipping. These values will still correctly index into the [Voronoi::vertices()] vector.
    pub fn triangles(&self) -> &[usize] {
        &self.voronoi.cells[self.site]
    }

    /// Gets an iterator for the vertices of this cell.
    ///
    /// Vertices are returned in sequential counter-clockwise order.
    /// Please see [Self::triangles] and [Voronoi::vertices] for additional details regarding hull closing and clipping effects on vertices.
    #[inline]
    pub fn iter_vertices(&self) -> impl Iterator<Item = &Point> + Clone {
        self.triangles().iter().map(move |&t| &self.voronoi.circumcenters[t])
    }

    /// Gets an iterator that returns the index of each site that shared an edge with this cell/site, in a counter-clockwise manner.
    ///
    /// # Example
    ///
    ///```
    /// use voronoice::*;
    /// let sites = vec![Point { x: -0.5, y: 0.0 }, Point { x: 0.5, y: 0.0 }, Point { x: 0.0, y: 0.0 }, Point { x: 0.0, y: 0.5 }, Point { x: 0.0, y: -0.5 }];
    /// let v = VoronoiBuilder::default()
    ///     .set_sites(sites.clone())
    ///     .build()
    ///     .unwrap();
    /// let neighbors: Vec<usize> = v.cell(0).iter_neighbors().collect();
    /// assert_eq!(neighbors[0], 4);
    /// assert_eq!(neighbors[1], 2);
    /// assert_eq!(neighbors[2], 3);
    ///```
    #[inline]
    pub fn iter_neighbors(&self) -> NeighborSiteIterator {
        NeighborSiteIterator::new(self.voronoi, self.site)
    }

    /// Gets an iterator that returns the shortest path on the Voronoi diagram to the destination point, starting from the current cell.
    #[inline]
    pub fn iter_path<'p>(&self, dest: Point) ->  impl Iterator<Item = usize> + 'v {
        crate::iterator::shortest_path_iter(self.voronoi, self.site, dest)
    }

    /// Returns a boolean indicating whether this cell is on the hull (edge) of the diagram.
    ///
    /// A Voronoi cell is on the hull if its associated site is on the Delaunay hull or if clipping is enabled and the cell intersects with the bounding box.
    pub fn is_on_hull(&self) -> bool {
        // if there is no half-edge associated with the left-most edge, the edge is on the hull
        let incoming_leftmost_edge = self.voronoi.site_to_incoming_leftmost_halfedge[self.site];
        self.voronoi.triangulation.halfedges[incoming_leftmost_edge] == EMPTY
            // if the cell vertex index is higher than the # of triangles/circumcenters, it means the vertex was added either because
            // it was extending a hull cell or because of clipping (agaisnt bounding box), thus the cell is on the hull
            || self.triangles().iter().any(|&t| t > self.voronoi.number_of_triangles())
    }
}

#[allow(dead_code)]
impl<'v> fmt::Debug for  VoronoiCell<'v> {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        #[derive(Debug)]
        struct Edge {
            edge: usize,
            incoming_site: usize,
            outgoing_site: usize
        }

        #[derive(Debug)]
        struct Site {
            site: usize,
            position: Point,
            is_on_hull: bool,
            leftmost_incoming_edge: Edge
        }

        #[derive(Debug)]
        struct Cellvertices {
            /// Each vertex is the circumcenter of a associated Delaunay triangle
            triangles: Vec<usize>,
            positions: Vec<Point>
        }
        let leftmost_edge = self.voronoi.site_to_incoming_leftmost_halfedge[self.site];

        f.debug_struct("VoronoiCell")
            .field("site", &Site {
                site: self.site,
                position: self.site_position().clone(),
                is_on_hull: self.is_on_hull(),
                leftmost_incoming_edge: Edge {
                    edge: leftmost_edge,
                    incoming_site: self.site,
                    outgoing_site: self.voronoi.triangulation.triangles[leftmost_edge]
                }
            })
            .field("vertices", &Cellvertices {
                triangles: self.triangles().iter().copied().collect(),
                positions: self.triangles().iter().copied().map(|t| self.voronoi.circumcenters[t].clone()).collect()
            })
            .finish()
    }
}