pixel_map/
pixel_map.rs

1#[cfg(feature = "serialize")]
2use serde::{Deserialize, Serialize};
3
4use super::{
5    ICircle, ILine, IsoLine, PNode, RayCast, RayCastContext, RayCastQuery, RayCastResult, Region,
6};
7use crate::isocontour::FragmentAccumulator;
8use crate::{
9    exclusive_urect, iline, to_cropped_urect, urect_points, CellFill, NeighborOrientation,
10    NodePath, RotatedIRect,
11};
12use bevy_math::{ivec2, IVec2, URect, UVec2};
13use fxhash::{FxBuildHasher, FxHasher};
14use num_traits::{NumCast, Unsigned, Zero};
15use std::collections::{HashMap, HashSet};
16use std::fmt::{Debug, Formatter};
17use std::hash::{BuildHasher, BuildHasherDefault};
18
19/// A two-dimensional map of pixels implemented by an MX quadtree.
20/// The coordinate origin is at the bottom left.
21///
22/// # Type Parameters
23///
24/// - `T`: The type of pixel data. By default, a `bool`, to denote the pixel is on or off.
25///   A more useful type could be a `Color`.
26/// - `U`: The unsigned integer type of the coordinates used to index the pixels, typically `u16` (default), or `u32`.
27#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))]
28#[derive(Clone, PartialEq)]
29pub struct PixelMap<T: Copy + PartialEq = bool, U: Unsigned + NumCast + Copy + Debug = u16> {
30    pub(crate) root: PNode<T, U>,
31    pub(crate) map_rect: URect,
32    pub(crate) pixel_size: u8,
33}
34
35impl<T: Copy + PartialEq, U: Unsigned + NumCast + Copy + Debug> PixelMap<T, U> {
36    /// Create a new [PixelMap].
37    ///
38    /// # Parameters
39    ///
40    /// - `dimensions`: The size of this [PixelMap].
41    /// - `value`: The initial value of all pixels in this [PixelMap].
42    /// - `pixel_size`: The pixel size of this [PixelMap] that is considered the smallest divisible unit.
43    ///   Must be a power of two.
44    ///
45    /// # Panics
46    ///
47    /// If `dimensions` size is not a multiple of pixel size on each axis.
48    /// If `pixel_size` is not a power of two.
49    #[inline]
50    #[must_use]
51    pub fn new(dimensions: &UVec2, value: T, pixel_size: u8) -> Self {
52        assert!(
53            dimensions.x % pixel_size as u32 == 0 && dimensions.y % pixel_size as u32 == 0,
54            "dimensions must be a multiple of pixel_size on each axis"
55        );
56        assert!(
57            pixel_size.is_power_of_two(),
58            "pixel_size must be a power of 2"
59        );
60        let region_size = next_pow2(dimensions.x.max(dimensions.y));
61        let size = U::from(region_size).unwrap();
62        let zero = U::from(0).unwrap();
63        let region = Region::new(zero, zero, size);
64        Self {
65            root: PNode::new(region, value, true),
66            map_rect: URect::from_corners(UVec2::ZERO, *dimensions),
67            pixel_size,
68        }
69    }
70
71    /// Obtain the dimensions of this [PixelMap].
72    #[inline]
73    #[must_use]
74    pub fn map_size(&self) -> UVec2 {
75        self.map_rect.size()
76    }
77
78    /// Obtain the dimensions of this [PixelMap] as a rectangle.
79    #[inline]
80    #[must_use]
81    pub fn map_rect(&self) -> URect {
82        self.map_rect
83    }
84
85    /// Obtain the pixel size of this [PixelMap]. When a node's region is of this size, it cannot
86    /// be subdivided further.
87    #[inline]
88    #[must_use]
89    pub fn pixel_size(&self) -> u8 {
90        self.pixel_size
91    }
92
93    /// Obtain the region that this [PixelMap]'s quadtree root node covers.
94    /// This value differs from `map_size` in that it the nearest power of two larger
95    /// than the map size, and it is square.
96    #[inline]
97    #[must_use]
98    pub fn region(&self) -> &Region<U> {
99        self.root.region()
100    }
101
102    /// Discard any existing pixel data and set the root node's value to that provided.
103    ///
104    /// # Parameters
105    ///
106    /// - `value`: The value to assign to the root node.
107    #[inline]
108    pub fn clear(&mut self, value: T) {
109        self.root.set_value(value);
110    }
111
112    /// Determine if this [PixelMap] is empty, which means that it has no pixel data.
113    #[inline]
114    pub fn empty(&self) -> bool {
115        self.root.is_leaf()
116    }
117
118    /// Determine if the given point is within the [PixelMap::map_size] bounds.
119    #[inline]
120    #[must_use]
121    pub fn contains(&self, point: UVec2) -> bool {
122        self.map_rect.contains(point)
123    }
124
125    /// Get the value of the pixel at the given coordinates. If the coordinates are outside the
126    /// region covered by this [PixelMap], None is returned.
127    ///
128    /// # Parameters
129    ///
130    /// - `point`: The coordinates of the pixel for which to retrieve the associated value.
131    #[inline]
132    #[must_use]
133    pub fn get_pixel<P>(&self, point: P) -> Option<&T>
134    where
135        P: Into<UVec2>,
136    {
137        let point = point.into();
138        if self.contains(point) {
139            Some(self.root.find_node(point).value())
140        } else {
141            None
142        }
143    }
144
145    /// Get the node that represents the pixel at the given coordinates. If the coordinates
146    /// are outside the region covered by this [PixelMap], None is returned.
147    ///
148    /// # Parameters
149    ///
150    /// - `point`: The coordinates of the pixel for which to retrieve the representing node.
151    #[inline]
152    #[must_use]
153    pub fn find_node<P>(&self, point: P) -> Option<&PNode<T, U>>
154    where
155        P: Into<UVec2>,
156    {
157        let point = point.into();
158        if self.contains(point) {
159            Some(self.root.find_node(point))
160        } else {
161            None
162        }
163    }
164
165    /// Get the path to the node that stores the pixel at the given point.
166    ///
167    /// # Parameters
168    ///
169    /// - `point`: The coordinates of the pixel for which to retrieve the node path.
170    ///
171    /// # Returns
172    ///
173    /// If the coordinates are outside the region covered by this [PixelMap], `None` is returned.
174    #[inline]
175    #[must_use]
176    pub fn get_path<P>(&self, point: P) -> Option<NodePath>
177    where
178        P: Into<UVec2>,
179    {
180        let point = point.into();
181        if self.contains(point) {
182            let (_, path) = self.root.node_path(point);
183            Some(path)
184        } else {
185            None
186        }
187    }
188
189    /// Set the value of the pixel at the given coordinates.
190    ///
191    /// # Parameters
192    ///
193    /// - `point`: The coordinates of the pixel for which to set the associated value.
194    ///
195    /// # Returns
196    ///
197    /// If the coordinates are outside the [PixelMap::map_rect], `false` is returned.
198    /// Otherwise, `true` is returned.
199    #[inline]
200    pub fn set_pixel<P>(&mut self, point: P, value: T) -> bool
201    where
202        P: Into<UVec2>,
203    {
204        let point = point.into();
205        if self.contains(point) {
206            self.root.set_pixel(point, self.pixel_size, value);
207            true
208        } else {
209            false
210        }
211    }
212
213    /// Set the value of all pixel coordinates yielded by the given iterator.
214    ///
215    /// # Parameters
216    ///
217    /// - `points`: An iterator that yields pixel coordinates.
218    ///
219    /// # Returns
220    ///
221    /// If any of the coordinates are inside the [PixelMap::map_rect],
222    /// `true` is returned, `false` otherwise.
223    #[inline]
224    pub fn set_pixels<I>(&mut self, points: I, value: T) -> bool
225    where
226        I: Iterator<Item = UVec2>,
227    {
228        let mut changed = false;
229        for point in points {
230            if self.set_pixel(point, value) {
231                changed = true;
232            }
233        }
234        changed
235    }
236
237    /// Set the value of the pixels within the given rectangle.
238    ///
239    /// # Parameters
240    ///
241    /// - `rect`: The rectangle in which pixels will be set to associated value.
242    /// - `value`: The value to assign to the pixels within the given rectangle.
243    ///
244    /// # Returns
245    ///
246    /// If the rectangle overlaps the [PixelMap::map_rect], `true` is returned. Otherwise, `false` is returned.
247    #[inline]
248    pub fn draw_rect(&mut self, rect: &URect, value: T) -> bool {
249        let rect = rect.intersect(self.map_rect());
250        if rect.is_empty() {
251            return false;
252        }
253        self.root.draw_rect(&rect, self.pixel_size, value);
254        true
255    }
256
257    /// Set the value of the pixels within the given rotated rectangle.
258    ///
259    /// # Parameters
260    ///
261    /// - `rrect`: The rotated rectangle in which pixels will be set to associated value.
262    /// - `value`: The value to assign to the pixels within the given rectangle.
263    ///
264    /// # Returns
265    ///
266    /// If the rectangle overlaps the [PixelMap::map_rect], `true` is returned. Otherwise, `false` is returned.
267    #[inline]
268    pub fn draw_rotated_rect(&mut self, rrect: &RotatedIRect, value: T) -> bool {
269        if rrect.rotation.is_zero() {
270            return self.draw_rect(&to_cropped_urect(&rrect.rect), value);
271        }
272        let rect = rrect.aabb().intersect(self.map_rect().as_irect());
273        if rect.is_empty() {
274            return false;
275        }
276        let inner_rect = to_cropped_urect(&rrect.inner_rect());
277        self.root.draw_rect(&inner_rect, self.pixel_size, value);
278        let inner_rect = exclusive_urect(&inner_rect);
279        for point in rrect.unsigned_pixels() {
280            if inner_rect.contains(point) {
281                continue;
282            }
283            self.set_pixel(point, value);
284        }
285        true
286    }
287
288    /// Set the value of the pixels within the given circle.
289    ///
290    /// # Parameters
291    ///
292    /// - `circle`: The circle in which pixels will be set to associated value.
293    /// - `value`: The value to assign to the pixels within the given circle.
294    ///
295    /// # Returns
296    ///
297    /// If the circle's aabb does not overlap
298    /// the region covered by this [PixelMap], false is returned. Otherwise, true is returned.
299    #[inline]
300    pub fn draw_circle(&mut self, circle: &ICircle, value: T) -> bool {
301        let aabb = to_cropped_urect(&circle.aabb());
302        let rect = aabb.intersect(self.map_rect());
303        if rect.is_empty() {
304            return false;
305        }
306        // Implementation note: Despite the aabb check, this still allows drawing circle pixels
307        // beyond the map bounds, within the quadtree region space. Fix me.
308        self.root.draw_circle(circle, self.pixel_size, value);
309        true
310    }
311
312    /// Visit all leaf nodes in this [PixelMap] in pre-order.
313    ///
314    /// # Parameters
315    ///
316    /// - `visitor`: A closure that takes a reference to a leaf node as its only parameter.
317    ///
318    /// # Returns
319    ///
320    /// The number of nodes traversed.
321    #[inline]
322    pub fn visit<F>(&self, mut visitor: F) -> u32
323    where
324        F: FnMut(&PNode<T, U>, &URect),
325    {
326        let mut traversed = 0u32;
327        self.root
328            .visit_leaves_in_rect(&self.map_rect(), &mut visitor, &mut traversed);
329        traversed
330    }
331
332    /// Visit all leaf nodes in this [PixelMap] that overlap with the given rectangle.
333    ///
334    /// # Parameters
335    ///
336    /// - `rect`: The rectangle in which contained or overlapping nodes will be visited.
337    /// - `visitor`: A closure that takes a reference to a leaf node, and a reference to a rectangle as parameters.
338    ///   This rectangle represents the intersection of the node's region and the `rect` parameter supplied to this method.
339    ///
340    /// # Returns
341    ///
342    /// The number of nodes traversed.
343    #[inline]
344    pub fn visit_in_rect<F>(&self, rect: &URect, mut visitor: F) -> u32
345    where
346        F: FnMut(&PNode<T, U>, &URect),
347    {
348        let rect = rect.intersect(self.map_rect());
349        if rect.is_empty() {
350            return 0;
351        }
352        let mut traversed = 0u32;
353        self.root
354            .visit_leaves_in_rect(&rect, &mut visitor, &mut traversed);
355        traversed
356    }
357
358    /// Visit all nodes in this [PixelMap] that overlap with the given rectangle, controlling
359    /// navigation with the visitor return value.
360    ///
361    /// # Parameters
362    ///
363    /// - `rect`: The rectangle in which contained or overlapping nodes will be visited.
364    /// - `visitor`: A closure that takes a reference to a node, and a reference to a
365    ///   rectangle as parameters. This rectangle represents the intersection of the node's
366    ///   region and the `rect` parameter supplied to this method. It returns a [CellFill]
367    ///   that denotes which child nodes should be visited.
368    ///
369    /// # Returns
370    ///
371    /// The number of nodes traversed.
372    #[inline]
373    pub fn visit_nodes_in_rect<F>(&self, rect: &URect, mut visitor: F) -> u32
374    where
375        F: FnMut(&PNode<T, U>, &URect) -> CellFill,
376    {
377        let rect = rect.intersect(self.map_rect());
378        if rect.is_empty() {
379            return 0;
380        }
381        let mut traversed = 0u32;
382        self.root
383            .visit_nodes_in_rect(&rect, &mut visitor, &mut traversed);
384        traversed
385    }
386
387    /// Determine if any of the leaf nodes within the bounds of the given rectangle match the predicate.
388    /// Node visitation short-circuits upon the first match.
389    ///
390    /// # Parameters
391    ///
392    /// - `rect`: The rectangle in which contained or overlapping nodes will be visited.
393    /// - `f`: A closure that takes a reference to a leaf node, and a reference to a rectangle as parameters.
394    ///   This rectangle represents the intersection of the node's region and the `rect` parameter supplied to this method.
395    ///   It returns `true` if the node matches the predicate, or `false` otherwise.
396    ///
397    /// # Returns
398    ///
399    /// `Some(true)` if any of the leaf nodes within the bounds of `rect` match the
400    /// predicate. Or `Some(false)` if no nodes within `rect` match the predicate.
401    /// `None` if `rect` does not overlap the region covered by this [PixelMap].
402    #[inline]
403    #[must_use]
404    pub fn any_in_rect<F>(&self, rect: &URect, mut f: F) -> Option<bool>
405    where
406        F: FnMut(&PNode<T, U>, &URect) -> bool,
407    {
408        let rect = rect.intersect(self.map_rect());
409        if rect.is_empty() {
410            return None;
411        }
412        self.root.any_leaves_in_rect(&rect, &mut f)
413    }
414
415    /// Determine if all the leaf nodes within the bounds of the given rectangle match the predicate.
416    /// Node visitation short-circuits upon the first match.
417    ///
418    /// # Parameters
419    ///
420    /// - `rect`: The rectangle in which contained or overlapping nodes will be visited.
421    /// - `f`: A closure that takes a reference to a leaf node, and a reference to a rectangle as parameters.
422    ///   This rectangle represents the intersection of the node's region and the `rect` parameter supplied to this method.
423    ///   It returns `true` if the node matches the predicate, or `false` otherwise.
424    ///
425    /// # Returns
426    ///
427    /// `Some(true)` if all of the leaf nodes within the bounds of `rect` match the
428    /// predicate. Or `Some(false)` if none or some of the nodes within `rect` match the predicate.
429    /// `None` if `rect` does not overlap the region covered by this [PixelMap].
430    #[inline]
431    #[must_use]
432    pub fn all_in_rect<F>(&self, rect: &URect, mut f: F) -> Option<bool>
433    where
434        F: FnMut(&PNode<T, U>, &URect) -> bool,
435    {
436        let rect = rect.intersect(self.map_rect());
437        if rect.is_empty() {
438            return None;
439        }
440        self.root.all_leaves_in_rect(&rect, &mut f)
441    }
442
443    /// Visit all leaf nodes in this [PixelMap] that are marked as dirty. This is useful for examining
444    /// only leaf nodes that have changed (became dirty), and to limit time spent traversing
445    /// the quadtree. Dirty status is not changed.
446    ///
447    /// # Parameters
448    ///
449    /// - `visitor`: A closure that takes a reference to a leaf node as its only parameter.
450    ///
451    /// # Returns
452    ///
453    /// The number of nodes traversed.
454    #[inline]
455    pub fn visit_dirty<F>(&self, mut visitor: F) -> u32
456    where
457        F: FnMut(&PNode<T, U>, &URect),
458    {
459        let mut traversed = 0u32;
460        if self.root.dirty() {
461            self.root
462                .visit_dirty_leaves_in_rect(&self.map_rect(), &mut visitor, &mut traversed);
463        }
464        traversed
465    }
466
467    /// Visit dirty leaf nodes in this [PixelMap] that overlap with the given rectangle.
468    /// This is useful for examining only leaf nodes that have changed (became dirty), and to
469    /// limit time spent traversing the quadtree. Dirty status is not changed.
470    ///
471    /// # Parameters
472    ///
473    /// - `rect`: The rectangle in which contained or overlapping nodes will be visited.
474    /// - `visitor`: A closure that takes a reference to a leaf node, and a reference to a rectangle as parameters.
475    ///   This rectangle represents the intersection of the node's region and the `rect` parameter supplied to this method.
476    ///
477    /// # Returns
478    ///
479    /// The number of nodes traversed.
480    #[inline]
481    pub fn visit_dirty_in_rect<F>(&self, rect: &URect, mut visitor: F) -> u32
482    where
483        F: FnMut(&PNode<T, U>, &URect),
484    {
485        let rect = rect.intersect(self.map_rect());
486        if rect.is_empty() {
487            return 0;
488        }
489        let mut traversed = 0u32;
490        if self.root.dirty() {
491            self.root
492                .visit_dirty_leaves_in_rect(&rect, &mut visitor, &mut traversed);
493        }
494        traversed
495    }
496
497    /// Determine if the root node is marked as dirty, which indicates that at least one leaf node
498    /// has changed (became dirty).
499    #[inline]
500    pub fn dirty(&self) -> bool {
501        self.root.dirty()
502    }
503
504    /// Visit all leaf nodes in this [PixelMap] that are marked as dirty, and consume
505    /// their dirty status (by modifying their dirty state to be `false`). This is useful for operating
506    /// only on leaf nodes that have changed (became dirty), and to limit time spent traversing
507    /// the quadtree.
508    ///
509    /// # Parameters
510    ///
511    /// - `visitor`: A closure that takes a reference to a leaf node as its only parameter.
512    ///
513    /// # Returns
514    ///
515    /// The number of nodes traversed.
516    #[inline]
517    pub fn drain_dirty<F>(&mut self, mut visitor: F) -> usize
518    where
519        F: FnMut(&PNode<T, U>),
520    {
521        let mut traversed = 0;
522        if self.root.dirty() {
523            self.root.drain_dirty_leaves(&mut visitor, &mut traversed);
524        }
525        traversed
526    }
527
528    /// Clear the dirty status of the root of this [PixelMap], according to a shallow or deep strategy.
529    ///
530    /// # Shallow Clear
531    ///
532    /// If dirty state is cleared in a shallow manner, the root node is marked clean, and
533    /// the dirty state at any further depth is retained. Subsequent calls to other methods that
534    /// navigate dirty nodes will not traverse any nodes, as none that are dirty are reachable
535    /// (because the root node is no longer dirty).
536    /// But, if branch `A` was dirty, [Self::clear_dirty] is called, and then branch `B` becomes dirty,
537    /// both `A` and `B` will be traversed by [Self::visit_dirty()] or [Self::drain_dirty()].
538    ///
539    /// # Deep Clear
540    ///
541    /// A deep clear traverses all dirty nodes and marks them as clean.
542    ///
543    /// # Parameters
544    ///
545    /// - `deep`: If `true`, clear the dirty status of all nodes in this [PixelMap], otherwise
546    ///   clear the dirty status of just the root node.
547    #[inline]
548    pub fn clear_dirty(&mut self, deep: bool) {
549        if deep {
550            self.drain_dirty(|_| {});
551        } else {
552            self.root.clear_dirty();
553        }
554    }
555
556    /// Obtain the points of node region corners that overlap with the given rectangle, and match
557    /// the given predicate. Calls #[Self::collect_points] internally, but takes a guess at a
558    /// reasonable capacity for the resulting HashSet.
559    ///
560    /// # Parameters
561    ///
562    /// - `rect`: The rectangle in which contained or overlapping nodes will be visited.
563    /// - `offset`: An offset to apply to returned points.
564    /// - `predicate`: A closure that takes a reference to a leaf node, and a reference to a rectangle as parameters.
565    ///   This rectangle represents the intersection of the node's region and the `rect` parameter supplied to this method.
566    ///   It returns `true` if the node matches the predicate, or `false` otherwise.
567    pub fn points<F>(
568        &self,
569        rect: &URect,
570        offset: IVec2,
571        predicate: F,
572    ) -> HashSet<IVec2, BuildHasherDefault<FxHasher>>
573    where
574        F: FnMut(&PNode<T, U>, &URect) -> bool,
575    {
576        let area = rect.width() * rect.height();
577        let mut result =
578            HashSet::with_capacity_and_hasher(area as usize / 4, FxBuildHasher::default());
579        self.collect_points(rect, offset, predicate, &mut result);
580        result
581    }
582
583    /// Collect the points of node region corners that overlap with the given rectangle, and match
584    /// the given predicate.
585    ///
586    /// # Parameters
587    ///
588    /// - `rect`: The rectangle in which contained or overlapping nodes will be visited.
589    /// - `offset`: An offset to apply to returned points.
590    /// - `predicate`: A closure that takes a reference to a leaf node, and a reference to a rectangle as parameters.
591    ///   This rectangle represents the intersection of the node's region and the `rect` parameter supplied to this method.
592    ///   It returns `true` if the node matches the predicate, or `false` otherwise.
593    /// - `hash`: A HashSet into which matching points will be inserted.
594    #[inline]
595    pub fn collect_points<F, H>(
596        &self,
597        rect: &URect,
598        offset: IVec2,
599        mut predicate: F,
600        hash: &mut HashSet<IVec2, H>,
601    ) where
602        F: FnMut(&PNode<T, U>, &URect) -> bool,
603        H: BuildHasher,
604    {
605        let rect = rect.intersect(self.map_rect());
606        if rect.is_empty() {
607            return;
608        }
609        self.visit_in_rect(&rect, |node, sub_rect| {
610            debug_assert!(!sub_rect.is_empty());
611            if predicate(node, sub_rect) {
612                for p in urect_points(sub_rect) {
613                    hash.insert(p.as_ivec2() + offset);
614                }
615            }
616        });
617    }
618
619    /// Visit all leaf nodes in this [PixelMap] for which the region overlaps with the line
620    /// defined by the [RayCastQuery].
621    ///
622    /// # Parameters
623    ///
624    /// - `query`: A [RayCastQuery] that defines the line to cast.
625    /// - `collision_check`: A closure that takes a reference to a leaf node as its only parameter.
626    ///   It returns a [RayCast] value that determines if the node represents a collision or if the
627    ///   ray should continue.
628    ///
629    /// # Returns
630    ///
631    /// A [RayCastResult] that contains the collision result and related information.
632    #[inline]
633    #[must_use]
634    pub fn ray_cast<F>(&self, query: RayCastQuery, mut collision_check: F) -> RayCastResult
635    where
636        F: FnMut(&PNode<T, U>) -> RayCast,
637    {
638        // TODO: truncate query line to map_size
639        let mut ctx = RayCastContext {
640            line_iter: query.line.pixels(),
641            traversed: 0,
642        };
643        if let Some(result) = self.root.ray_cast(&query, &mut ctx, &mut collision_check) {
644            return result;
645        }
646        RayCastResult {
647            collision_point: None,
648            distance: 0.0,
649            traversed: ctx.traversed,
650        }
651    }
652
653    /// Collect statistics by traversing the [PixelMap] quadtree.
654    ///
655    /// # Returns
656    ///
657    /// A [Stats] struct that contains information about [PixelMap]'s current state.
658    #[must_use]
659    pub fn stats(&self) -> Stats {
660        let mut stats = Stats::default();
661        self.root.visit_nodes_in_rect(
662            &self.region().into(),
663            &mut |node, _| {
664                stats.node_count += 1;
665                if node.is_leaf() {
666                    stats.leaf_count += 1;
667
668                    if node.region().is_unit(self.pixel_size) {
669                        stats.unit_count += 1;
670                    }
671                }
672                CellFill::Full
673            },
674            &mut 0,
675        );
676        stats
677    }
678
679    /// Combine another [PixelMap] with this one using a closure that decides how to combine
680    /// the values of each pixel. This [PixelMap]'s region should overlap with the other [PixelMap]'s region,
681    /// otherwise this operation has no effect.
682    ///
683    /// # Parameters
684    ///
685    /// - `other`: The other [PixelMap] to combine with this one.
686    /// - `offset`: The other [PixelMap] is sampled according to this offset vector.
687    /// - `combiner`: A closure that takes two values and returns a resulting value.
688    ///
689    /// # Examples
690    ///
691    /// This method can be used to implement boolean operations, such as union, intersection,
692    /// disjunction, etc., according to the combiner function's implementation.
693    ///
694    /// To compute the union of two [PixelMap]s:
695    /// ```
696    /// # use bevy_math::UVec2;
697    /// use pixel_map::{PixelMap, Region};
698    /// # #[derive(Copy,Clone,PartialEq)]
699    /// # enum Color { BLACK, WHITE }
700    /// # let mut pixel_map: PixelMap<Color, u16> = PixelMap::new(&UVec2::splat(128), Color::WHITE, 1);
701    /// # let mut other: PixelMap<Color, u16> = PixelMap::new(&UVec2::splat(128), Color::BLACK, 1);
702    /// // Union (OR)
703    /// pixel_map.combine(&other, (0, 0), |c1, c2| {
704    ///     if c1 == &Color::BLACK || c2 == &Color::BLACK {
705    ///         Color::BLACK
706    ///     } else {
707    ///         Color::WHITE
708    ///     }
709    /// });
710    /// ```
711    ///
712    /// Compute an intersection of two [PixelMap]s:
713    /// ```
714    /// # use bevy_math::UVec2;
715    /// use pixel_map::{PixelMap, Region};
716    /// # #[derive(Copy,Clone,PartialEq)]
717    /// # enum Color { BLACK, WHITE }
718    /// # let mut pixel_map: PixelMap<Color, u16> = PixelMap::new(&UVec2::splat(128), Color::WHITE, 1);
719    /// # let mut other: PixelMap<Color, u16> = PixelMap::new(&UVec2::splat(128), Color::BLACK, 1);
720    /// // Intersection (AND)
721    /// pixel_map.combine(&other, (0, 0), |c1, c2| {
722    ///    if c1 == &Color::BLACK && c2 == &Color::BLACK {
723    ///       Color::BLACK
724    ///   } else {
725    ///      Color::WHITE
726    ///  }
727    /// });
728    /// ```
729    pub fn combine<P, F>(&mut self, other: &Self, offset: P, combiner: F)
730    where
731        P: Into<UVec2>,
732        F: Fn(&T, &T) -> T,
733    {
734        let offset = offset.into();
735        let mut updates: Vec<(URect, T)> = Vec::new();
736        self.visit(|node, _| {
737            let mut region_rect: URect = node.region().into();
738            region_rect = URect::from_corners(region_rect.min + offset, region_rect.max + offset);
739            other.visit_in_rect(&region_rect, |other_node, sub_rect| {
740                let value = combiner(node.value(), other_node.value());
741                let sub_rect = URect::from_corners(sub_rect.min - offset, sub_rect.max - offset);
742                updates.push((sub_rect, value));
743            });
744        });
745        for (rect, value) in updates {
746            self.draw_rect(&rect, value);
747        }
748    }
749
750    /// Generate a quad mesh that contains a triangulated quad for each leaf node accepted by
751    /// the predicate function. The returned quad mesh is non-uniform in that neighboring quads
752    /// having differing sizes, according to the layout of the quadtree, will not be fully
753    /// connected via triangulation.
754    ///
755    /// # Parameters
756    ///
757    /// - `rect`: The rectangle in which contained or overlapping nodes will be visited.
758    /// - `predicate`: A closure that takes a reference to a leaf node, and a reference to a rectangle as parameters.
759    ///   This rectangle represents the intersection of the node's region and the `rect` parameter supplied to this method.
760    ///   It returns `true` if the node matches the predicate, or `false` otherwise.
761    /// - `size_estimate`: An estimated (or known) capacity of each returned vec.
762    ///
763    /// # Returns
764    ///
765    /// A tuple having a vec of unique vertex points, and a vec of triangle indices. Each element
766    /// in the index vec is a slice of each index in a triangle, in counter-clockwise winding.
767    pub fn non_uniform_quad_mesh<F>(
768        &self,
769        rect: &URect,
770        mut predicate: F,
771        size_estimate: usize,
772    ) -> (Vec<UVec2>, Vec<[u32; 3]>)
773    where
774        F: FnMut(&PNode<T, U>, &URect) -> bool,
775    {
776        let sub_rect = self.map_rect.intersect(*rect);
777        if sub_rect.is_empty() {
778            return (vec![], vec![]);
779        }
780
781        let mut vertex_map: HashMap<[u32; 2], u32, _> =
782            HashMap::with_capacity_and_hasher(size_estimate, FxBuildHasher::default());
783        let mut indices = Vec::with_capacity(size_estimate);
784
785        #[inline]
786        fn create_or_add_vertex(
787            vertex_map: &mut HashMap<[u32; 2], u32, BuildHasherDefault<FxHasher>>,
788            v: UVec2,
789        ) -> u32 {
790            let next_index = vertex_map.len() as u32;
791            *vertex_map.entry(v.into()).or_insert(next_index)
792        }
793
794        self.root.visit_leaves_in_rect(
795            &sub_rect,
796            &mut |n, sub_rect| {
797                if !predicate(n, sub_rect) {
798                    return;
799                }
800
801                let c = urect_points(sub_rect);
802                let i = [
803                    create_or_add_vertex(&mut vertex_map, c[0]),
804                    create_or_add_vertex(&mut vertex_map, c[1]),
805                    create_or_add_vertex(&mut vertex_map, c[2]),
806                    create_or_add_vertex(&mut vertex_map, c[3]),
807                ];
808
809                indices.push([i[0], i[1], i[2]]);
810                indices.push([i[0], i[2], i[3]]);
811            },
812            &mut 0,
813        );
814
815        let mut vertices = Vec::with_capacity(vertex_map.len());
816        vertices.resize(vertex_map.len(), Default::default());
817        vertex_map.into_iter().for_each(|(k, v)| {
818            vertices[v as usize] = k.into();
819        });
820
821        (vertices, indices)
822    }
823
824    /// Obtain a list of line segments that contour the shapes determined by the given
825    /// `predicate` closure. In other words, if the `predicate` returns `true`,
826    /// the node is considered to be part of the shape for which a contour is being generated.
827    ///
828    /// *Note*: This implementation is likely to change in the future which may affect the
829    /// characteristics of the returned data.
830    ///
831    /// # Parameters
832    ///
833    /// - `rect`: The rectangle in which contained or overlapping nodes will be visited.
834    /// - `predicate`: A closure that takes a reference to a leaf node,
835    ///   and a reference to the rectangle that is the effective intersection of the node's
836    ///   region and the `rect` parameter supplied to this method.
837    ///
838    /// # Returns
839    ///
840    /// A list of line segments that contour the shapes determined by the given
841    /// `predicate` closure. The number of segments returned are the minimum possible,
842    /// in that one segment does not share continuity with any other segment.
843    #[must_use]
844    pub fn contour<F>(&self, rect: &URect, mut predicate: F) -> Vec<IsoLine>
845    where
846        F: FnMut(&PNode<T, U>, &URect) -> bool,
847    {
848        let sub_rect = self.map_rect.intersect(*rect);
849        if sub_rect.is_empty() {
850            return vec![];
851        }
852
853        let mut fragments = FragmentAccumulator::new(256);
854        self.contour_segments(&sub_rect, &mut predicate, |seg| {
855            fragments.attach(*seg);
856        });
857
858        fragments.result()
859    }
860
861    fn contour_segments<F, G>(&self, rect: &URect, mut predicate: F, mut seg_handler: G)
862    where
863        F: FnMut(&PNode<T, U>, &URect) -> bool,
864        G: FnMut(&ILine),
865    {
866        self.root
867            .visit_neighbor_pairs_face(rect, &mut |or, a, a_rect, b, b_rect| {
868                match or {
869                    NeighborOrientation::Horizontal => {
870                        let (left, left_rect, right, right_rect) = (a, a_rect, b, b_rect);
871                        if predicate(left, left_rect) != predicate(right, right_rect) {
872                            // right edge of the left node
873                            let left = left.region().as_urect();
874                            let left_right_edge = iline(
875                                ivec2(left.max.x as i32, left.min.y as i32),
876                                left.max.as_ivec2(),
877                            );
878                            let left_right_edge =
879                                left_right_edge.axis_aligned_intersect_rect(&left_rect.as_irect());
880
881                            // left edge of the right node
882                            let right = right.region().as_urect();
883                            let right_left_edge = iline(
884                                right.min.as_ivec2(),
885                                ivec2(right.min.x as i32, right.max.y as i32),
886                            );
887                            let right_left_edge =
888                                right_left_edge.axis_aligned_intersect_rect(&right_rect.as_irect());
889
890                            if let (Some(left_right_edge), Some(right_left_edge)) =
891                                (left_right_edge, right_left_edge)
892                            {
893                                if let Some(common_edge) = left_right_edge.overlap(&right_left_edge)
894                                {
895                                    seg_handler(&common_edge);
896                                }
897                            }
898                        }
899                    }
900                    NeighborOrientation::Vertical => {
901                        let (bottom, bottom_rect, top, top_rect) = (a, a_rect, b, b_rect);
902                        if predicate(bottom, bottom_rect) != predicate(top, top_rect) {
903                            // top edge of the bottom node
904                            let bottom = bottom.region().as_urect();
905                            let bottom_top_edge = iline(
906                                ivec2(bottom.min.x as i32, bottom.max.y as i32),
907                                bottom.max.as_ivec2(),
908                            );
909                            let bottom_top_edge = bottom_top_edge
910                                .axis_aligned_intersect_rect(&bottom_rect.as_irect());
911
912                            // bottom edge of the top node
913                            let top = top.region().as_urect();
914                            let top_bottom_edge = iline(
915                                top.min.as_ivec2(),
916                                ivec2(top.max.x as i32, top.min.y as i32),
917                            );
918                            let top_bottom_edge =
919                                top_bottom_edge.axis_aligned_intersect_rect(&top_rect.as_irect());
920
921                            if let (Some(bottom_top_edge), Some(top_bottom_edge)) =
922                                (bottom_top_edge, top_bottom_edge)
923                            {
924                                if let Some(common_edge) = bottom_top_edge.overlap(&top_bottom_edge)
925                                {
926                                    seg_handler(&common_edge);
927                                }
928                            }
929                        }
930                    }
931                }
932            });
933    }
934}
935
936impl<T: Copy + PartialEq, U: Unsigned + NumCast + Copy + Debug> Debug for PixelMap<T, U> {
937    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
938        f.debug_struct("PixelMap")
939            .field("pixel_size", &self.pixel_size)
940            .finish()
941    }
942}
943
944/// Stores statistics about a [PixelMap].
945/// See [PixelMap::stats].
946#[cfg_attr(feature = "serialize", derive(Serialize, Deserialize))]
947#[derive(Debug, Default, Eq, PartialEq)]
948pub struct Stats {
949    /// The number of nodes in the quadtree.
950    pub node_count: usize,
951
952    /// The number of leaf nodes in the quadtree.
953    pub leaf_count: usize,
954
955    /// The number of leaf nodes in the quadtree for which the region is a unit pixel size.
956    /// The unit size is defined by the `pixel_size` parameter of the [PixelMap] constructor.
957    pub unit_count: usize,
958}
959
960#[inline]
961#[must_use]
962fn next_pow2(mut n: u32) -> u32 {
963    if n <= 2 {
964        return 2;
965    }
966    let mut count = 0;
967    if n > 0 && (n & (n - 1)) == 0 {
968        return n;
969    }
970    while n != 0 {
971        n >>= 1;
972        count += 1;
973    }
974
975    1 << count
976}
977
978#[cfg(test)]
979mod test {
980    use crate::pixel_map::next_pow2;
981    use crate::*;
982    use bevy_math::{IVec2, URect, UVec2};
983    use std::collections::HashSet;
984
985    #[test]
986    fn test_u_type_parameters() {
987        let _ = PixelMap::<bool, u8>::new(&UVec2::splat(128), false, 1);
988        let _ = PixelMap::<bool, u16>::new(&UVec2::splat(128), false, 1);
989        let _ = PixelMap::<bool, u32>::new(&UVec2::splat(128), false, 1);
990        let _ = PixelMap::<bool, u64>::new(&UVec2::splat(128), false, 1);
991        let _ = PixelMap::<bool, u128>::new(&UVec2::splat(128), false, 1);
992    }
993
994    #[test]
995    fn test_clear() {
996        let mut pm = PixelMap::<i32, u32>::new(&UVec2::splat(2), 0, 1);
997        pm.set_pixel((1, 1), 1);
998        pm.clear(2);
999        assert_eq!(pm.root.value(), &2);
1000        assert!(pm.root.is_leaf());
1001    }
1002
1003    #[test]
1004    fn test_draw_rect() {
1005        let map_size = 32;
1006        let mut pm = PixelMap::<bool, u32>::new(&UVec2::splat(map_size), false, 1);
1007
1008        for rect_width in 1..=map_size {
1009            for rect_height in 1..=map_size {
1010                pm.clear(false);
1011
1012                let rect = URect::new(0, 0, rect_width, rect_height);
1013                pm.draw_rect(&rect, true);
1014
1015                let rect = exclusive_urect(&rect);
1016                for y in 0..map_size {
1017                    for x in 0..map_size {
1018                        let p = (x, y).into();
1019                        if rect.contains(p) {
1020                            assert_eq!(
1021                                pm.get_pixel(p),
1022                                Some(&true),
1023                                "rect_width: {}, rect_height: {}, assert: {}",
1024                                rect_width,
1025                                rect_height,
1026                                p
1027                            );
1028                        } else {
1029                            assert_eq!(
1030                                pm.get_pixel(p),
1031                                Some(&false),
1032                                "rect_width: {}, rect_height: {}, assert: {}",
1033                                rect_width,
1034                                rect_height,
1035                                p
1036                            );
1037                        }
1038                    }
1039                }
1040            }
1041        }
1042    }
1043
1044    #[test]
1045    fn test_stats_with_root_node() {
1046        let pm = PixelMap::<bool, u32>::new(&UVec2::splat(2), false, 1);
1047        assert_eq!(
1048            pm.stats(),
1049            Stats {
1050                node_count: 1,
1051                leaf_count: 1,
1052                unit_count: 0,
1053            }
1054        );
1055    }
1056
1057    #[test]
1058    fn test_stats_with_children() {
1059        let mut pm = PixelMap::<bool, u32>::new(&UVec2::splat(2), false, 1);
1060        pm.set_pixel((1, 1), true);
1061        assert_eq!(
1062            pm.stats(),
1063            Stats {
1064                node_count: 5,
1065                leaf_count: 4,
1066                unit_count: 4,
1067            }
1068        );
1069    }
1070
1071    #[test]
1072    fn test_stats_with_grandchildren() {
1073        let mut pm = PixelMap::<bool, u32>::new(&UVec2::splat(4), false, 1);
1074        pm.draw_rect(&URect::new(0, 0, 2, 2), true);
1075        pm.set_pixel((0, 0), false);
1076        assert_eq!(
1077            pm.stats(),
1078            Stats {
1079                node_count: 9,
1080                leaf_count: 7,
1081                unit_count: 4,
1082            }
1083        );
1084    }
1085
1086    #[test]
1087    fn test_any_in_rect() {
1088        let mut pm = PixelMap::<bool, u32>::new(&UVec2::splat(2), false, 1);
1089
1090        assert_eq!(
1091            pm.any_in_rect(&URect::new(0, 0, 2, 2), |n, _| *n.value()),
1092            Some(false)
1093        );
1094        assert_eq!(
1095            pm.any_in_rect(&URect::new(2, 2, 4, 4), |n, _| *n.value()),
1096            None
1097        );
1098
1099        pm.set_pixel((0, 0), true);
1100
1101        assert_eq!(
1102            pm.any_in_rect(&URect::new(0, 0, 2, 2), |n, _| *n.value()),
1103            Some(true)
1104        );
1105        assert_eq!(
1106            pm.any_in_rect(&URect::new(0, 0, 2, 2), |n, _| !*n.value()),
1107            Some(true)
1108        );
1109        assert_eq!(
1110            pm.any_in_rect(&URect::new(0, 0, 1, 1), |n, _| *n.value()),
1111            Some(true)
1112        );
1113        assert_eq!(
1114            pm.any_in_rect(&URect::new(1, 1, 2, 2), |n, _| *n.value()),
1115            Some(false)
1116        );
1117    }
1118
1119    #[test]
1120    fn test_all_in_rect() {
1121        let mut pm = PixelMap::<bool, u32>::new(&UVec2::splat(2), false, 1);
1122
1123        assert_eq!(
1124            pm.all_in_rect(&URect::new(0, 0, 2, 2), |n, _| !*n.value()),
1125            Some(true)
1126        );
1127        assert_eq!(
1128            pm.all_in_rect(&URect::new(2, 2, 4, 4), |n, _| *n.value()),
1129            None
1130        );
1131
1132        pm.set_pixel((0, 0), true);
1133
1134        assert_eq!(
1135            pm.all_in_rect(&URect::new(0, 0, 2, 2), |n, _| *n.value()),
1136            Some(false)
1137        );
1138        assert_eq!(
1139            pm.all_in_rect(&URect::new(0, 0, 2, 2), |n, _| !*n.value()),
1140            Some(false)
1141        );
1142        assert_eq!(
1143            pm.all_in_rect(&URect::new(0, 0, 1, 1), |n, _| *n.value()),
1144            Some(true)
1145        );
1146        assert_eq!(
1147            pm.all_in_rect(&URect::new(1, 1, 2, 2), |n, _| *n.value()),
1148            Some(false)
1149        );
1150    }
1151
1152    #[test]
1153    #[cfg(feature = "serialize")]
1154    fn test_serialization() {
1155        let mut pm: PixelMap<bool, u32> = PixelMap::new(&UVec2::splat(2), false, 1);
1156        pm.set_pixel((0, 0), true);
1157
1158        let pmstr = ron::to_string(&pm).unwrap();
1159        let pm2: PixelMap<bool, u32> = ron::from_str(&pmstr).unwrap();
1160
1161        assert_eq!(pm.root, pm2.root);
1162        assert_eq!(pm.pixel_size, pm2.pixel_size);
1163        assert!(pm2.get_pixel((0, 0)).unwrap());
1164    }
1165
1166    #[test]
1167    fn test_next_pow2() {
1168        assert_eq!(next_pow2(0u32), 2);
1169        assert_eq!(next_pow2(1u32), 2);
1170        assert_eq!(next_pow2(2u32), 2);
1171        assert_eq!(next_pow2(3u32), 4);
1172        assert_eq!(next_pow2(4u32), 4);
1173        assert_eq!(next_pow2(5u32), 8);
1174        assert_eq!(next_pow2(17u32), 32);
1175        assert_eq!(next_pow2(32u32), 32);
1176        assert_eq!(next_pow2(33u32), 64);
1177    }
1178
1179    #[test]
1180    fn test_contour_segments_unique() {
1181        let mut pm: PixelMap<bool, u32> = PixelMap::new(&UVec2::splat(1024), false, 1);
1182        pm.draw_circle(&ICircle::new(IVec2::splat(512), 50), true);
1183
1184        let mut segments: HashSet<ILine> = HashSet::with_capacity(256);
1185        pm.contour_segments(
1186            &pm.region().as_urect(),
1187            |a, _| *a.value(),
1188            |seg| {
1189                assert!(segments.insert(*seg));
1190                assert!(segments.insert(seg.flip()));
1191            },
1192        );
1193
1194        assert_eq!(segments.len(), 728);
1195    }
1196}