region: add tagged regions
This commit is contained in:
parent
0872a1251d
commit
6243278f5f
6 changed files with 1087 additions and 99 deletions
|
|
@ -1,6 +1,7 @@
|
|||
#![allow(
|
||||
clippy::mem_replace_with_default,
|
||||
clippy::comparison_chain,
|
||||
clippy::collapsible_else_if,
|
||||
clippy::needless_lifetimes
|
||||
)]
|
||||
|
||||
|
|
|
|||
|
|
@ -5,31 +5,72 @@ use {
|
|||
std::fmt::{Debug, Formatter},
|
||||
};
|
||||
|
||||
pub trait Tag: Copy + Eq + Ord + Debug + Default + Sized {
|
||||
const IS_SIGNIFICANT: bool;
|
||||
|
||||
fn constrain(self) -> Self;
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Debug, Default)]
|
||||
pub struct NoTag;
|
||||
|
||||
impl Tag for NoTag {
|
||||
const IS_SIGNIFICANT: bool = false;
|
||||
|
||||
#[inline(always)]
|
||||
fn constrain(self) -> Self {
|
||||
Self
|
||||
}
|
||||
}
|
||||
|
||||
impl Tag for u32 {
|
||||
const IS_SIGNIFICANT: bool = true;
|
||||
|
||||
#[inline(always)]
|
||||
fn constrain(self) -> Self {
|
||||
self & 1
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Eq, PartialEq, Default)]
|
||||
pub struct RectRaw {
|
||||
pub struct RectRaw<T = NoTag>
|
||||
where
|
||||
T: Tag,
|
||||
{
|
||||
pub x1: i32,
|
||||
pub y1: i32,
|
||||
pub x2: i32,
|
||||
pub y2: i32,
|
||||
pub tag: T,
|
||||
}
|
||||
|
||||
impl Debug for RectRaw {
|
||||
impl<T> Debug for RectRaw<T>
|
||||
where
|
||||
T: Tag,
|
||||
{
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||
f.debug_struct("Rect")
|
||||
let mut debug = f.debug_struct("Rect");
|
||||
debug
|
||||
.field("x1", &self.x1)
|
||||
.field("y1", &self.y1)
|
||||
.field("x2", &self.x2)
|
||||
.field("y2", &self.y2)
|
||||
.field("width", &(self.x2 - self.x1))
|
||||
.field("height", &(self.y2 - self.y1))
|
||||
.finish()
|
||||
.field("height", &(self.y2 - self.y1));
|
||||
if T::IS_SIGNIFICANT {
|
||||
debug.field("tag", &self.tag);
|
||||
}
|
||||
debug.finish()
|
||||
}
|
||||
}
|
||||
|
||||
impl RectRaw {
|
||||
impl<T> RectRaw<T>
|
||||
where
|
||||
T: Tag,
|
||||
{
|
||||
fn is_empty(&self) -> bool {
|
||||
self.x1 == self.x2 || self.y1 == self.y2
|
||||
}
|
||||
}
|
||||
|
||||
type Container = SmallVec<[RectRaw; 1]>;
|
||||
type Container<T = NoTag> = SmallVec<[RectRaw<T>; 1]>;
|
||||
|
|
|
|||
|
|
@ -1,44 +1,64 @@
|
|||
use {
|
||||
crate::{
|
||||
rect::{Container, RectRaw},
|
||||
rect::{Container, NoTag, RectRaw, Tag},
|
||||
windows::WindowsExt,
|
||||
},
|
||||
std::{cmp::Ordering, collections::BinaryHeap, mem, ops::Deref},
|
||||
std::{cmp::Ordering, collections::BinaryHeap, marker::PhantomData, mem, ops::Deref},
|
||||
};
|
||||
|
||||
pub fn union(left: &Container, right: &Container) -> Container {
|
||||
op::<Union>(left, right)
|
||||
op::<_, _, _, Union>(left, right)
|
||||
}
|
||||
|
||||
pub fn subtract(left: &Container, right: &Container) -> Container {
|
||||
op::<Subtract>(left, right)
|
||||
op::<_, _, _, Subtract>(left, right)
|
||||
}
|
||||
|
||||
struct Bands<'a> {
|
||||
rects: &'a [RectRaw],
|
||||
pub fn intersect(left: &Container, right: &Container) -> Container {
|
||||
op::<_, _, _, Intersect<NoTag>>(left, right)
|
||||
}
|
||||
|
||||
pub fn intersect_tagged(left: &Container<u32>, right: &Container) -> Container<u32> {
|
||||
op::<_, _, _, Intersect<u32>>(left, right)
|
||||
}
|
||||
|
||||
struct Bands<'a, T>
|
||||
where
|
||||
T: Tag,
|
||||
{
|
||||
rects: &'a [RectRaw<T>],
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
struct Band<'a> {
|
||||
rects: &'a [RectRaw],
|
||||
struct Band<'a, T>
|
||||
where
|
||||
T: Tag,
|
||||
{
|
||||
rects: &'a [RectRaw<T>],
|
||||
y1: i32,
|
||||
y2: i32,
|
||||
}
|
||||
|
||||
impl<'a> Band<'a> {
|
||||
fn can_merge_with(&self, next: &Band) -> bool {
|
||||
impl<'a, T> Band<'a, T>
|
||||
where
|
||||
T: Tag,
|
||||
{
|
||||
fn can_merge_with(&self, next: &Band<'_, T>) -> bool {
|
||||
next.rects.len() == self.rects.len()
|
||||
&& next.y1 == self.y2
|
||||
&& next
|
||||
.rects
|
||||
.iter()
|
||||
.zip(self.rects.iter())
|
||||
.all(|(a, b)| (a.x1, a.x2) == (b.x1, b.x2))
|
||||
.all(|(a, b)| (a.x1, a.x2, a.tag) == (b.x1, b.x2, b.tag))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Iterator for Bands<'a> {
|
||||
type Item = Band<'a>;
|
||||
impl<'a, T> Iterator for Bands<'a, T>
|
||||
where
|
||||
T: Tag,
|
||||
{
|
||||
type Item = Band<'a, T>;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
if self.rects.is_empty() {
|
||||
|
|
@ -62,7 +82,10 @@ impl<'a> Iterator for Bands<'a> {
|
|||
}
|
||||
|
||||
#[inline]
|
||||
pub fn extents(a: &[RectRaw]) -> RectRaw {
|
||||
pub fn extents<T>(a: &[RectRaw<T>]) -> RectRaw
|
||||
where
|
||||
T: Tag,
|
||||
{
|
||||
let mut a = a.iter();
|
||||
let mut res = match a.next() {
|
||||
Some(a) => *a,
|
||||
|
|
@ -74,10 +97,21 @@ pub fn extents(a: &[RectRaw]) -> RectRaw {
|
|||
res.x2 = res.x2.max(a.x2);
|
||||
res.y2 = res.y2.max(a.y2);
|
||||
}
|
||||
res
|
||||
RectRaw {
|
||||
x1: res.x1,
|
||||
y1: res.y1,
|
||||
x2: res.x2,
|
||||
y2: res.y2,
|
||||
tag: NoTag,
|
||||
}
|
||||
}
|
||||
|
||||
fn op<O: Op>(a: &[RectRaw], b: &[RectRaw]) -> Container {
|
||||
fn op<T1, T2, T3, O: Op<T1, T2, T3>>(a: &[RectRaw<T2>], b: &[RectRaw<T3>]) -> Container<T1>
|
||||
where
|
||||
T1: Tag,
|
||||
T2: Tag,
|
||||
T3: Tag,
|
||||
{
|
||||
let mut res = Container::new();
|
||||
|
||||
let mut prev_band_y2 = 0;
|
||||
|
|
@ -100,7 +134,7 @@ fn op<O: Op>(a: &[RectRaw], b: &[RectRaw]) -> Container {
|
|||
}
|
||||
|
||||
macro_rules! append_nonoverlapping {
|
||||
($append_opt:expr, $a:expr, $a_opt:expr, $a_bands:expr, $b:expr) => {{
|
||||
($append_opt:expr, $map:ident, $a:expr, $a_opt:expr, $a_bands:expr, $b:expr) => {{
|
||||
if $append_opt {
|
||||
let y2 = $a.y2.min($b.y1);
|
||||
cur_band_start = res.len();
|
||||
|
|
@ -111,6 +145,7 @@ fn op<O: Op>(a: &[RectRaw], b: &[RectRaw]) -> Container {
|
|||
y1: $a.y1,
|
||||
x2: rect.x2,
|
||||
y2,
|
||||
tag: O::$map(rect.tag),
|
||||
});
|
||||
}
|
||||
fixup_new_band!($a.y1, y2);
|
||||
|
|
@ -125,9 +160,9 @@ fn op<O: Op>(a: &[RectRaw], b: &[RectRaw]) -> Container {
|
|||
|
||||
while let (Some(a), Some(b)) = (&mut a_opt, &mut b_opt) {
|
||||
if a.y1 < b.y1 {
|
||||
append_nonoverlapping!(O::APPEND_NON_A, a, a_opt, a_bands, b);
|
||||
append_nonoverlapping!(O::APPEND_NON_A, map_t2_to_t1, a, a_opt, a_bands, b);
|
||||
} else if b.y1 < a.y1 {
|
||||
append_nonoverlapping!(O::APPEND_NON_B, b, b_opt, b_bands, a);
|
||||
append_nonoverlapping!(O::APPEND_NON_B, map_t3_to_t1, b, b_opt, b_bands, a);
|
||||
} else {
|
||||
let y2 = a.y2.min(b.y2);
|
||||
cur_band_start = res.len();
|
||||
|
|
@ -149,7 +184,7 @@ fn op<O: Op>(a: &[RectRaw], b: &[RectRaw]) -> Container {
|
|||
}
|
||||
|
||||
macro_rules! push_trailing {
|
||||
($a_opt:expr, $a_bands:expr) => {{
|
||||
($a_opt:expr, $a_bands:expr, $map:ident) => {{
|
||||
while let Some(a) = $a_opt {
|
||||
cur_band_start = res.len();
|
||||
res.reserve(a.rects.len());
|
||||
|
|
@ -159,6 +194,7 @@ fn op<O: Op>(a: &[RectRaw], b: &[RectRaw]) -> Container {
|
|||
y1: a.y1,
|
||||
x2: rect.x2,
|
||||
y2: a.y2,
|
||||
tag: O::$map(rect.tag),
|
||||
});
|
||||
}
|
||||
fixup_new_band!(a.y1, a.y2);
|
||||
|
|
@ -168,25 +204,28 @@ fn op<O: Op>(a: &[RectRaw], b: &[RectRaw]) -> Container {
|
|||
}
|
||||
|
||||
if O::APPEND_NON_A {
|
||||
push_trailing!(a_opt, a_bands);
|
||||
push_trailing!(a_opt, a_bands, map_t2_to_t1);
|
||||
}
|
||||
|
||||
if O::APPEND_NON_B {
|
||||
push_trailing!(b_opt, b_bands);
|
||||
push_trailing!(b_opt, b_bands, map_t3_to_t1);
|
||||
}
|
||||
|
||||
res.shrink_to_fit();
|
||||
res
|
||||
}
|
||||
|
||||
fn coalesce(new: &mut Container, a: usize, b: usize, y2: i32) -> bool {
|
||||
fn coalesce<T>(new: &mut Container<T>, a: usize, b: usize, y2: i32) -> bool
|
||||
where
|
||||
T: Tag,
|
||||
{
|
||||
if new.len() - b != b - a {
|
||||
return false;
|
||||
}
|
||||
let slice_a = &new[a..b];
|
||||
let slice_b = &new[b..];
|
||||
for (a, b) in slice_a.iter().zip(slice_b.iter()) {
|
||||
if (a.x1, a.x2) != (b.x1, b.x2) {
|
||||
if (a.x1, a.x2, a.tag) != (b.x1, b.x2, b.tag) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
@ -197,16 +236,25 @@ fn coalesce(new: &mut Container, a: usize, b: usize, y2: i32) -> bool {
|
|||
true
|
||||
}
|
||||
|
||||
trait Op {
|
||||
trait Op<T1, T2, T3>
|
||||
where
|
||||
T1: Tag,
|
||||
T2: Tag,
|
||||
T3: Tag,
|
||||
{
|
||||
const APPEND_NON_A: bool;
|
||||
const APPEND_NON_B: bool;
|
||||
|
||||
fn handle_band(new: &mut Container, a: &[RectRaw], b: &[RectRaw], y1: i32, y2: i32);
|
||||
fn handle_band(new: &mut Container<T1>, a: &[RectRaw<T2>], b: &[RectRaw<T3>], y1: i32, y2: i32);
|
||||
|
||||
fn map_t2_to_t1(tag: T2) -> T1;
|
||||
|
||||
fn map_t3_to_t1(tag: T3) -> T1;
|
||||
}
|
||||
|
||||
struct Union;
|
||||
|
||||
impl Op for Union {
|
||||
impl Op<NoTag, NoTag, NoTag> for Union {
|
||||
const APPEND_NON_A: bool = true;
|
||||
const APPEND_NON_B: bool = true;
|
||||
|
||||
|
|
@ -216,7 +264,13 @@ impl Op for Union {
|
|||
|
||||
macro_rules! push {
|
||||
() => {
|
||||
new.push(RectRaw { x1, y1, x2, y2 });
|
||||
new.push(RectRaw {
|
||||
x1,
|
||||
y1,
|
||||
x2,
|
||||
y2,
|
||||
tag: NoTag,
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
|
|
@ -272,11 +326,21 @@ impl Op for Union {
|
|||
|
||||
push!();
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn map_t2_to_t1(_tag: NoTag) -> NoTag {
|
||||
NoTag
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn map_t3_to_t1(_tag: NoTag) -> NoTag {
|
||||
NoTag
|
||||
}
|
||||
}
|
||||
|
||||
struct Subtract;
|
||||
|
||||
impl Op for Subtract {
|
||||
impl Op<NoTag, NoTag, NoTag> for Subtract {
|
||||
const APPEND_NON_A: bool = true;
|
||||
const APPEND_NON_B: bool = false;
|
||||
|
||||
|
|
@ -291,6 +355,7 @@ impl Op for Subtract {
|
|||
y1,
|
||||
x2: $x2,
|
||||
y2,
|
||||
tag: NoTag,
|
||||
});
|
||||
};
|
||||
}
|
||||
|
|
@ -337,33 +402,145 @@ impl Op for Subtract {
|
|||
pull!();
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn map_t2_to_t1(_tag: NoTag) -> NoTag {
|
||||
NoTag
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn map_t3_to_t1(_tag: NoTag) -> NoTag {
|
||||
NoTag
|
||||
}
|
||||
}
|
||||
|
||||
struct Intersect<T>(PhantomData<T>);
|
||||
|
||||
impl<T> Op<T, T, NoTag> for Intersect<T>
|
||||
where
|
||||
T: Tag,
|
||||
{
|
||||
const APPEND_NON_A: bool = false;
|
||||
const APPEND_NON_B: bool = false;
|
||||
|
||||
fn handle_band(new: &mut Container<T>, a: &[RectRaw<T>], b: &[RectRaw], y1: i32, y2: i32) {
|
||||
let mut x1;
|
||||
let mut x2;
|
||||
let mut tag;
|
||||
|
||||
macro_rules! push {
|
||||
($x2:expr) => {
|
||||
new.push(RectRaw {
|
||||
x1,
|
||||
y1,
|
||||
x2: $x2,
|
||||
y2,
|
||||
tag,
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
let mut a_iter = a.iter();
|
||||
let mut b_iter = b.iter();
|
||||
|
||||
macro_rules! pull {
|
||||
() => {
|
||||
match a_iter.next() {
|
||||
Some(n) => {
|
||||
x1 = n.x1;
|
||||
x2 = n.x2;
|
||||
tag = n.tag;
|
||||
}
|
||||
_ => return,
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
pull!();
|
||||
|
||||
let mut b_opt = b_iter.next();
|
||||
|
||||
while let Some(b) = b_opt {
|
||||
if b.x2 <= x1 {
|
||||
b_opt = b_iter.next();
|
||||
} else if b.x1 >= x2 {
|
||||
pull!();
|
||||
} else {
|
||||
x1 = x1.max(b.x1);
|
||||
if x2 <= b.x2 {
|
||||
push!(x2);
|
||||
pull!();
|
||||
} else {
|
||||
push!(b.x2);
|
||||
b_opt = b_iter.next();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn map_t2_to_t1(_tag: T) -> T {
|
||||
unreachable!()
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn map_t3_to_t1(_tag: NoTag) -> T {
|
||||
unreachable!()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn rects_to_bands(rects_tmp: &[RectRaw]) -> Container {
|
||||
rects_to_bands_(rects_tmp)
|
||||
}
|
||||
|
||||
pub fn rects_to_bands_tagged(rects_tmp: &[RectRaw<u32>]) -> Container<u32> {
|
||||
rects_to_bands_(rects_tmp)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn rects_to_bands_<T>(rects_tmp: &[RectRaw<T>]) -> Container<T>
|
||||
where
|
||||
T: Tag,
|
||||
{
|
||||
#[derive(Copy, Clone)]
|
||||
struct W(RectRaw);
|
||||
impl Eq for W {}
|
||||
impl PartialEq<Self> for W {
|
||||
struct W<T>(RectRaw<T>)
|
||||
where
|
||||
T: Tag;
|
||||
impl<T> Eq for W<T> where T: Tag {}
|
||||
impl<T> PartialEq<Self> for W<T>
|
||||
where
|
||||
T: Tag,
|
||||
{
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.0 == other.0
|
||||
}
|
||||
}
|
||||
impl PartialOrd<Self> for W {
|
||||
impl<T> PartialOrd<Self> for W<T>
|
||||
where
|
||||
T: Tag,
|
||||
{
|
||||
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
|
||||
Some(self.cmp(other))
|
||||
}
|
||||
}
|
||||
impl Ord for W {
|
||||
impl<T> Ord for W<T>
|
||||
where
|
||||
T: Tag,
|
||||
{
|
||||
fn cmp(&self, other: &Self) -> Ordering {
|
||||
self.0
|
||||
.y1
|
||||
.cmp(&other.0.y1)
|
||||
.then_with(|| self.0.x1.cmp(&other.0.x1))
|
||||
.then_with(|| self.0.tag.cmp(&other.0.tag))
|
||||
.reverse()
|
||||
}
|
||||
}
|
||||
impl Deref for W {
|
||||
type Target = RectRaw;
|
||||
impl<T> Deref for W<T>
|
||||
where
|
||||
T: Tag,
|
||||
{
|
||||
type Target = RectRaw<T>;
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.0
|
||||
}
|
||||
|
|
@ -411,17 +588,60 @@ pub fn rects_to_bands(rects_tmp: &[RectRaw]) -> Container {
|
|||
check_rect!(rect);
|
||||
let mut x1 = rect.x1;
|
||||
let mut x2 = rect.x2;
|
||||
let mut tag: T = rect.tag;
|
||||
while let Some(mut rect) = rects.peek().copied() {
|
||||
check_rect!(rect);
|
||||
if rect.x1 > x2 {
|
||||
res.push(RectRaw { x1, x2, y1, y2 });
|
||||
if rect.x1 > x2 || (rect.tag != tag && rect.x1 == x2) {
|
||||
res.push(RectRaw {
|
||||
x1,
|
||||
x2,
|
||||
y1,
|
||||
y2,
|
||||
tag: tag.constrain(),
|
||||
});
|
||||
x1 = rect.x1;
|
||||
x2 = rect.x2;
|
||||
tag = rect.tag;
|
||||
} else {
|
||||
x2 = x2.max(rect.x2);
|
||||
if rect.tag == tag {
|
||||
x2 = x2.max(rect.x2);
|
||||
} else if rect.tag > tag {
|
||||
if rect.x2 > x2 {
|
||||
rect.0.x1 = x2;
|
||||
rect.0.y1 = y1;
|
||||
rect.0.y2 = y2;
|
||||
rects.push(rect);
|
||||
}
|
||||
} else {
|
||||
if x2 > rect.x2 {
|
||||
rects.push(W(RectRaw {
|
||||
x1: rect.x2,
|
||||
y1,
|
||||
x2,
|
||||
y2,
|
||||
tag,
|
||||
}));
|
||||
}
|
||||
res.push(RectRaw {
|
||||
x1,
|
||||
y1,
|
||||
x2: rect.x1,
|
||||
y2,
|
||||
tag: tag.constrain(),
|
||||
});
|
||||
x1 = rect.x1;
|
||||
x2 = rect.x2;
|
||||
tag = rect.tag;
|
||||
}
|
||||
}
|
||||
}
|
||||
res.push(RectRaw { x1, x2, y1, y2 });
|
||||
res.push(RectRaw {
|
||||
x1,
|
||||
x2,
|
||||
y1,
|
||||
y2,
|
||||
tag: tag.constrain(),
|
||||
});
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
|
|
|||
136
src/rect.rs
136
src/rect.rs
|
|
@ -5,20 +5,26 @@ mod tests;
|
|||
|
||||
pub use region::{DamageQueue, RegionBuilder};
|
||||
use {
|
||||
jay_algorithms::rect::RectRaw,
|
||||
jay_algorithms::rect::{NoTag, RectRaw, Tag},
|
||||
smallvec::SmallVec,
|
||||
std::fmt::{Debug, Formatter},
|
||||
};
|
||||
|
||||
#[derive(Copy, Clone, Eq, PartialEq, Default)]
|
||||
#[repr(transparent)]
|
||||
pub struct Rect {
|
||||
raw: RectRaw,
|
||||
pub struct Rect<T = NoTag>
|
||||
where
|
||||
T: Tag,
|
||||
{
|
||||
raw: RectRaw<T>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Eq, PartialEq, Debug, Default)]
|
||||
pub struct Region {
|
||||
rects: SmallVec<[RectRaw; 1]>,
|
||||
pub struct Region<T = NoTag>
|
||||
where
|
||||
T: Tag,
|
||||
{
|
||||
rects: SmallVec<[RectRaw<T>; 1]>,
|
||||
extents: Rect,
|
||||
}
|
||||
|
||||
|
|
@ -50,6 +56,23 @@ impl RectOverflow {
|
|||
}
|
||||
}
|
||||
|
||||
impl<T> Rect<T>
|
||||
where
|
||||
T: Tag,
|
||||
{
|
||||
pub fn untag(&self) -> Rect {
|
||||
Rect {
|
||||
raw: RectRaw {
|
||||
x1: self.raw.x1,
|
||||
y1: self.raw.y1,
|
||||
x2: self.raw.x2,
|
||||
y2: self.raw.y2,
|
||||
tag: NoTag,
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Rect {
|
||||
pub fn new_empty(x: i32, y: i32) -> Self {
|
||||
Self {
|
||||
|
|
@ -58,6 +81,7 @@ impl Rect {
|
|||
y1: y,
|
||||
x2: x,
|
||||
y2: y,
|
||||
tag: NoTag,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
|
@ -67,7 +91,13 @@ impl Rect {
|
|||
return None;
|
||||
}
|
||||
Some(Self {
|
||||
raw: RectRaw { x1, y1, x2, y2 },
|
||||
raw: RectRaw {
|
||||
x1,
|
||||
y1,
|
||||
x2,
|
||||
y2,
|
||||
tag: NoTag,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
|
|
@ -76,10 +106,16 @@ impl Rect {
|
|||
Self::new(x1, y1, x2, y2).unwrap()
|
||||
}
|
||||
|
||||
#[expect(dead_code)]
|
||||
#[cfg_attr(not(test), expect(dead_code))]
|
||||
fn new_unchecked_danger(x1: i32, y1: i32, x2: i32, y2: i32) -> Self {
|
||||
Self {
|
||||
raw: RectRaw { x1, y1, x2, y2 },
|
||||
raw: RectRaw {
|
||||
x1,
|
||||
y1,
|
||||
x2,
|
||||
y2,
|
||||
tag: NoTag,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -102,6 +138,58 @@ impl Rect {
|
|||
y1: self.raw.y1.min(other.raw.y1),
|
||||
x2: self.raw.x2.max(other.raw.x2),
|
||||
y2: self.raw.y2.max(other.raw.y2),
|
||||
tag: NoTag,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
pub fn intersect(&self, other: Self) -> Self {
|
||||
let x1 = self.raw.x1.max(other.raw.x1);
|
||||
let y1 = self.raw.y1.max(other.raw.y1);
|
||||
let x2 = self.raw.x2.min(other.raw.x2).max(x1);
|
||||
let y2 = self.raw.y2.min(other.raw.y2).max(y1);
|
||||
Self {
|
||||
raw: RectRaw {
|
||||
x1,
|
||||
y1,
|
||||
x2,
|
||||
y2,
|
||||
tag: NoTag,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
pub fn with_size(&self, width: i32, height: i32) -> Option<Self> {
|
||||
Self::new_sized(self.raw.x1, self.raw.y1, width, height)
|
||||
}
|
||||
|
||||
#[expect(dead_code)]
|
||||
pub fn with_tag(&self, tag: u32) -> Rect<u32> {
|
||||
Rect {
|
||||
raw: RectRaw {
|
||||
x1: self.raw.x1,
|
||||
y1: self.raw.y1,
|
||||
x2: self.raw.x2,
|
||||
y2: self.raw.y2,
|
||||
tag,
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Rect<T>
|
||||
where
|
||||
T: Tag,
|
||||
{
|
||||
#[cfg_attr(not(test), expect(dead_code))]
|
||||
fn new_unchecked_danger_tagged(x1: i32, y1: i32, x2: i32, y2: i32, tag: T) -> Self {
|
||||
Self {
|
||||
raw: RectRaw {
|
||||
x1,
|
||||
y1,
|
||||
x2,
|
||||
y2,
|
||||
tag,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
|
@ -113,16 +201,6 @@ impl Rect {
|
|||
&& other.raw.y1 < self.raw.y2
|
||||
}
|
||||
|
||||
pub fn intersect(&self, other: Self) -> Self {
|
||||
let x1 = self.raw.x1.max(other.raw.x1);
|
||||
let y1 = self.raw.y1.max(other.raw.y1);
|
||||
let x2 = self.raw.x2.min(other.raw.x2).max(x1);
|
||||
let y2 = self.raw.y2.min(other.raw.y2).max(y1);
|
||||
Self {
|
||||
raw: RectRaw { x1, y1, x2, y2 },
|
||||
}
|
||||
}
|
||||
|
||||
pub fn contains(&self, x: i32, y: i32) -> bool {
|
||||
self.raw.x1 <= x && self.raw.y1 <= y && self.raw.x2 > x && self.raw.y2 > y
|
||||
}
|
||||
|
|
@ -144,14 +222,20 @@ impl Rect {
|
|||
}
|
||||
|
||||
#[expect(dead_code)]
|
||||
pub fn contains_rect(&self, rect: &Self) -> bool {
|
||||
pub fn contains_rect<U>(&self, rect: &Rect<U>) -> bool
|
||||
where
|
||||
U: Tag,
|
||||
{
|
||||
self.raw.x1 <= rect.raw.x1
|
||||
&& self.raw.y1 <= rect.raw.x1
|
||||
&& rect.raw.x2 <= self.raw.x2
|
||||
&& rect.raw.y2 <= self.raw.y2
|
||||
}
|
||||
|
||||
pub fn get_overflow(&self, child: &Self) -> RectOverflow {
|
||||
pub fn get_overflow<U>(&self, child: &Rect<U>) -> RectOverflow
|
||||
where
|
||||
U: Tag,
|
||||
{
|
||||
RectOverflow {
|
||||
left: self.raw.x1 - child.raw.x1,
|
||||
right: child.raw.x2 - self.raw.x2,
|
||||
|
|
@ -177,6 +261,7 @@ impl Rect {
|
|||
y1: 0,
|
||||
x2: self.raw.x2 - self.raw.x1,
|
||||
y2: self.raw.y2 - self.raw.y1,
|
||||
tag: self.raw.tag,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
|
@ -188,6 +273,7 @@ impl Rect {
|
|||
y1: self.raw.y1.saturating_add(dy),
|
||||
x2: self.raw.x2.saturating_add(dx),
|
||||
y2: self.raw.y2.saturating_add(dy),
|
||||
tag: self.raw.tag,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
|
@ -199,14 +285,11 @@ impl Rect {
|
|||
y1,
|
||||
x2: x1 + self.raw.x2 - self.raw.x1,
|
||||
y2: y1 + self.raw.y2 - self.raw.y1,
|
||||
tag: self.raw.tag,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
pub fn with_size(&self, width: i32, height: i32) -> Option<Self> {
|
||||
Self::new_sized(self.raw.x1, self.raw.y1, width, height)
|
||||
}
|
||||
|
||||
pub fn translate(&self, x: i32, y: i32) -> (i32, i32) {
|
||||
(x.wrapping_sub(self.raw.x1), y.wrapping_sub(self.raw.y1))
|
||||
}
|
||||
|
|
@ -253,4 +336,9 @@ impl Rect {
|
|||
self.raw.y1 + self.height() / 2,
|
||||
)
|
||||
}
|
||||
|
||||
#[expect(dead_code)]
|
||||
pub fn tag(&self) -> T {
|
||||
self.raw.tag
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,8 +7,11 @@ use {
|
|||
},
|
||||
},
|
||||
jay_algorithms::rect::{
|
||||
RectRaw,
|
||||
region::{extents, rects_to_bands, subtract, union},
|
||||
RectRaw, Tag,
|
||||
region::{
|
||||
extents, intersect, intersect_tagged, rects_to_bands, rects_to_bands_tagged, subtract,
|
||||
union,
|
||||
},
|
||||
},
|
||||
smallvec::SmallVec,
|
||||
std::{
|
||||
|
|
@ -29,19 +32,6 @@ thread_local! {
|
|||
}
|
||||
|
||||
impl Region {
|
||||
pub fn new(rect: Rect) -> Rc<Self> {
|
||||
Rc::new(Self::new2(rect))
|
||||
}
|
||||
|
||||
pub fn new2(rect: Rect) -> Self {
|
||||
let mut rects = SmallVec::new();
|
||||
rects.push(rect.raw);
|
||||
Self {
|
||||
rects,
|
||||
extents: rect,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn empty() -> Rc<Self> {
|
||||
EMPTY.with(|e| e.clone())
|
||||
}
|
||||
|
|
@ -96,13 +86,82 @@ impl Region {
|
|||
})
|
||||
}
|
||||
|
||||
#[cfg_attr(not(test), expect(dead_code))]
|
||||
pub fn intersect(&self, other: &Region) -> Self {
|
||||
if self.is_empty() || other.is_empty() {
|
||||
return Self::default();
|
||||
}
|
||||
let rects = intersect(&self.rects, &other.rects);
|
||||
Self {
|
||||
extents: Rect {
|
||||
raw: extents(&rects),
|
||||
},
|
||||
rects,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Region<u32> {
|
||||
#[cfg_attr(not(test), expect(dead_code))]
|
||||
pub fn from_rects_tagged(rects: &[Rect<u32>]) -> Self {
|
||||
if rects.is_empty() {
|
||||
return Self::default();
|
||||
}
|
||||
if rects.len() == 1 {
|
||||
let mut rect = rects[0];
|
||||
rect.raw.tag = rect.raw.tag.constrain();
|
||||
return Self::new2(rect);
|
||||
}
|
||||
let rects = rects_to_bands_tagged(unsafe {
|
||||
mem::transmute::<&[Rect<u32>], &[RectRaw<u32>]>(rects)
|
||||
});
|
||||
Self {
|
||||
extents: Rect {
|
||||
raw: extents(&rects),
|
||||
},
|
||||
rects,
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg_attr(not(test), expect(dead_code))]
|
||||
pub fn intersect_tagged(&self, other: &Region) -> Self {
|
||||
if self.is_empty() || other.is_empty() {
|
||||
return Self::default();
|
||||
}
|
||||
let rects = intersect_tagged(&self.rects, &other.rects);
|
||||
Self {
|
||||
extents: Rect {
|
||||
raw: extents(&rects),
|
||||
},
|
||||
rects,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Region<T>
|
||||
where
|
||||
T: Tag,
|
||||
{
|
||||
pub fn new(rect: Rect<T>) -> Rc<Self> {
|
||||
Rc::new(Self::new2(rect))
|
||||
}
|
||||
|
||||
pub fn new2(rect: Rect<T>) -> Self {
|
||||
let mut rects = SmallVec::new();
|
||||
rects.push(rect.raw);
|
||||
Self {
|
||||
rects,
|
||||
extents: rect.untag(),
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg_attr(not(feature = "it"), expect(dead_code))]
|
||||
pub fn extents(&self) -> Rect {
|
||||
self.extents
|
||||
}
|
||||
|
||||
pub fn rects(&self) -> &[Rect] {
|
||||
unsafe { mem::transmute::<&[RectRaw], &[Rect]>(&self.rects[..]) }
|
||||
pub fn rects(&self) -> &[Rect<T>] {
|
||||
unsafe { mem::transmute::<&[RectRaw<T>], &[Rect<T>]>(&self.rects[..]) }
|
||||
}
|
||||
|
||||
pub fn contains(&self, x: i32, y: i32) -> bool {
|
||||
|
|
@ -118,11 +177,14 @@ impl Region {
|
|||
}
|
||||
}
|
||||
|
||||
impl Deref for Region {
|
||||
type Target = [Rect];
|
||||
impl<T> Deref for Region<T>
|
||||
where
|
||||
T: Tag,
|
||||
{
|
||||
type Target = [Rect<T>];
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
unsafe { mem::transmute::<&[RectRaw], _>(&self.rects) }
|
||||
unsafe { mem::transmute::<&[RectRaw<T>], _>(&self.rects) }
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
use {
|
||||
crate::rect::{Rect, Region},
|
||||
jay_algorithms::rect::RectRaw,
|
||||
jay_algorithms::rect::{NoTag, RectRaw},
|
||||
};
|
||||
|
||||
#[test]
|
||||
|
|
@ -43,25 +43,29 @@ fn subtract1() {
|
|||
x1: 0,
|
||||
y1: 0,
|
||||
x2: 20,
|
||||
y2: 5
|
||||
y2: 5,
|
||||
tag: NoTag,
|
||||
},
|
||||
RectRaw {
|
||||
x1: 0,
|
||||
y1: 5,
|
||||
x2: 5,
|
||||
y2: 15
|
||||
y2: 15,
|
||||
tag: NoTag,
|
||||
},
|
||||
RectRaw {
|
||||
x1: 15,
|
||||
y1: 5,
|
||||
x2: 20,
|
||||
y2: 15
|
||||
y2: 15,
|
||||
tag: NoTag,
|
||||
},
|
||||
RectRaw {
|
||||
x1: 0,
|
||||
y1: 15,
|
||||
x2: 20,
|
||||
y2: 20
|
||||
y2: 20,
|
||||
tag: NoTag,
|
||||
},
|
||||
]
|
||||
);
|
||||
|
|
@ -83,19 +87,22 @@ fn rects_to_bands() {
|
|||
x1: 0,
|
||||
y1: 0,
|
||||
x2: 30,
|
||||
y2: 5
|
||||
y2: 5,
|
||||
tag: NoTag,
|
||||
},
|
||||
RectRaw {
|
||||
x1: 0,
|
||||
y1: 5,
|
||||
x2: 50,
|
||||
y2: 10
|
||||
y2: 10,
|
||||
tag: NoTag,
|
||||
},
|
||||
RectRaw {
|
||||
x1: 30,
|
||||
y1: 10,
|
||||
x2: 50,
|
||||
y2: 15
|
||||
y2: 15,
|
||||
tag: NoTag,
|
||||
},
|
||||
]
|
||||
);
|
||||
|
|
@ -111,3 +118,572 @@ fn rects_to_bands2() {
|
|||
// println!("{:#?}", r.rects);
|
||||
assert_eq!(&r.rects[..], &[Rect::new(0, 0, 10, 20).unwrap().raw,]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn rects_to_bands_tagged1() {
|
||||
let rects = [
|
||||
Rect::new_unchecked_danger_tagged(0, 0, 200, 200, 1),
|
||||
Rect::new_unchecked_danger_tagged(50, 50, 150, 150, 0),
|
||||
];
|
||||
let r = Region::from_rects_tagged(&rects[..]);
|
||||
assert_eq!(
|
||||
&r.rects[..],
|
||||
&[
|
||||
RectRaw {
|
||||
x1: 0,
|
||||
y1: 0,
|
||||
x2: 200,
|
||||
y2: 50,
|
||||
tag: 1,
|
||||
},
|
||||
RectRaw {
|
||||
x1: 0,
|
||||
y1: 50,
|
||||
x2: 50,
|
||||
y2: 150,
|
||||
tag: 1,
|
||||
},
|
||||
RectRaw {
|
||||
x1: 50,
|
||||
y1: 50,
|
||||
x2: 150,
|
||||
y2: 150,
|
||||
tag: 0,
|
||||
},
|
||||
RectRaw {
|
||||
x1: 150,
|
||||
y1: 50,
|
||||
x2: 200,
|
||||
y2: 150,
|
||||
tag: 1,
|
||||
},
|
||||
RectRaw {
|
||||
x1: 0,
|
||||
y1: 150,
|
||||
x2: 200,
|
||||
y2: 200,
|
||||
tag: 1,
|
||||
},
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn rects_to_bands_tagged2() {
|
||||
let rects = [
|
||||
Rect::new_unchecked_danger_tagged(0, 0, 200, 200, 1),
|
||||
Rect::new_unchecked_danger_tagged(50, 50, 150, 150, 0),
|
||||
Rect::new_unchecked_danger_tagged(60, 60, 140, 140, 2),
|
||||
];
|
||||
let r = Region::from_rects_tagged(&rects[..]);
|
||||
assert_eq!(
|
||||
&r.rects[..],
|
||||
&[
|
||||
RectRaw {
|
||||
x1: 0,
|
||||
y1: 0,
|
||||
x2: 200,
|
||||
y2: 50,
|
||||
tag: 1,
|
||||
},
|
||||
RectRaw {
|
||||
x1: 0,
|
||||
y1: 50,
|
||||
x2: 50,
|
||||
y2: 150,
|
||||
tag: 1,
|
||||
},
|
||||
RectRaw {
|
||||
x1: 50,
|
||||
y1: 50,
|
||||
x2: 150,
|
||||
y2: 150,
|
||||
tag: 0,
|
||||
},
|
||||
RectRaw {
|
||||
x1: 150,
|
||||
y1: 50,
|
||||
x2: 200,
|
||||
y2: 150,
|
||||
tag: 1,
|
||||
},
|
||||
RectRaw {
|
||||
x1: 0,
|
||||
y1: 150,
|
||||
x2: 200,
|
||||
y2: 200,
|
||||
tag: 1,
|
||||
},
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn rects_to_bands_tagged3() {
|
||||
let rects = [
|
||||
Rect::new_unchecked_danger_tagged(0, 0, 200, 200, 2),
|
||||
Rect::new_unchecked_danger_tagged(50, 50, 150, 150, 1),
|
||||
Rect::new_unchecked_danger_tagged(60, 60, 140, 140, 0),
|
||||
];
|
||||
let r = Region::from_rects_tagged(&rects[..]);
|
||||
assert_eq!(
|
||||
&r.rects[..],
|
||||
&[
|
||||
RectRaw {
|
||||
x1: 0,
|
||||
y1: 0,
|
||||
x2: 200,
|
||||
y2: 50,
|
||||
tag: 0,
|
||||
},
|
||||
RectRaw {
|
||||
x1: 0,
|
||||
y1: 50,
|
||||
x2: 50,
|
||||
y2: 60,
|
||||
tag: 0,
|
||||
},
|
||||
RectRaw {
|
||||
x1: 50,
|
||||
y1: 50,
|
||||
x2: 150,
|
||||
y2: 60,
|
||||
tag: 1,
|
||||
},
|
||||
RectRaw {
|
||||
x1: 150,
|
||||
y1: 50,
|
||||
x2: 200,
|
||||
y2: 60,
|
||||
tag: 0,
|
||||
},
|
||||
RectRaw {
|
||||
x1: 0,
|
||||
y1: 60,
|
||||
x2: 50,
|
||||
y2: 140,
|
||||
tag: 0,
|
||||
},
|
||||
RectRaw {
|
||||
x1: 50,
|
||||
y1: 60,
|
||||
x2: 60,
|
||||
y2: 140,
|
||||
tag: 1,
|
||||
},
|
||||
RectRaw {
|
||||
x1: 60,
|
||||
y1: 60,
|
||||
x2: 140,
|
||||
y2: 140,
|
||||
tag: 0,
|
||||
},
|
||||
RectRaw {
|
||||
x1: 140,
|
||||
y1: 60,
|
||||
x2: 150,
|
||||
y2: 140,
|
||||
tag: 1,
|
||||
},
|
||||
RectRaw {
|
||||
x1: 150,
|
||||
y1: 60,
|
||||
x2: 200,
|
||||
y2: 140,
|
||||
tag: 0,
|
||||
},
|
||||
RectRaw {
|
||||
x1: 0,
|
||||
y1: 140,
|
||||
x2: 50,
|
||||
y2: 150,
|
||||
tag: 0,
|
||||
},
|
||||
RectRaw {
|
||||
x1: 50,
|
||||
y1: 140,
|
||||
x2: 150,
|
||||
y2: 150,
|
||||
tag: 1,
|
||||
},
|
||||
RectRaw {
|
||||
x1: 150,
|
||||
y1: 140,
|
||||
x2: 200,
|
||||
y2: 150,
|
||||
tag: 0,
|
||||
},
|
||||
RectRaw {
|
||||
x1: 0,
|
||||
y1: 150,
|
||||
x2: 200,
|
||||
y2: 200,
|
||||
tag: 0,
|
||||
},
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn rects_to_bands_tagged4() {
|
||||
let rects = [
|
||||
Rect::new_unchecked_danger_tagged(0, 0, 100, 100, 1),
|
||||
Rect::new_unchecked_danger_tagged(100, 0, 200, 200, 0),
|
||||
];
|
||||
let r = Region::from_rects_tagged(&rects[..]);
|
||||
assert_eq!(
|
||||
&r.rects[..],
|
||||
&[
|
||||
RectRaw {
|
||||
x1: 0,
|
||||
y1: 0,
|
||||
x2: 100,
|
||||
y2: 100,
|
||||
tag: 1,
|
||||
},
|
||||
RectRaw {
|
||||
x1: 100,
|
||||
y1: 0,
|
||||
x2: 200,
|
||||
y2: 100,
|
||||
tag: 0,
|
||||
},
|
||||
RectRaw {
|
||||
x1: 100,
|
||||
y1: 100,
|
||||
x2: 200,
|
||||
y2: 200,
|
||||
tag: 0,
|
||||
},
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn rects_to_bands_tagged5() {
|
||||
let rects = [
|
||||
Rect::new_unchecked_danger_tagged(0, 0, 200, 100, 1),
|
||||
Rect::new_unchecked_danger_tagged(100, 0, 200, 100, 0),
|
||||
];
|
||||
let r = Region::from_rects_tagged(&rects[..]);
|
||||
assert_eq!(
|
||||
&r.rects[..],
|
||||
&[
|
||||
RectRaw {
|
||||
x1: 0,
|
||||
y1: 0,
|
||||
x2: 100,
|
||||
y2: 100,
|
||||
tag: 1,
|
||||
},
|
||||
RectRaw {
|
||||
x1: 100,
|
||||
y1: 0,
|
||||
x2: 200,
|
||||
y2: 100,
|
||||
tag: 0,
|
||||
},
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn rects_to_bands_tagged6() {
|
||||
let rects = [
|
||||
Rect::new_unchecked_danger_tagged(0, 0, 200, 100, 1),
|
||||
Rect::new_unchecked_danger_tagged(100, 0, 300, 100, 0),
|
||||
];
|
||||
let r = Region::from_rects_tagged(&rects[..]);
|
||||
assert_eq!(
|
||||
&r.rects[..],
|
||||
&[
|
||||
RectRaw {
|
||||
x1: 0,
|
||||
y1: 0,
|
||||
x2: 100,
|
||||
y2: 100,
|
||||
tag: 1,
|
||||
},
|
||||
RectRaw {
|
||||
x1: 100,
|
||||
y1: 0,
|
||||
x2: 300,
|
||||
y2: 100,
|
||||
tag: 0,
|
||||
},
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn rects_to_bands_tagged7() {
|
||||
let rects = [
|
||||
Rect::new_unchecked_danger_tagged(0, 0, 200, 100, 0),
|
||||
Rect::new_unchecked_danger_tagged(100, 0, 300, 200, 1),
|
||||
];
|
||||
let r = Region::from_rects_tagged(&rects[..]);
|
||||
assert_eq!(
|
||||
&r.rects[..],
|
||||
&[
|
||||
RectRaw {
|
||||
x1: 0,
|
||||
y1: 0,
|
||||
x2: 200,
|
||||
y2: 100,
|
||||
tag: 0,
|
||||
},
|
||||
RectRaw {
|
||||
x1: 200,
|
||||
y1: 0,
|
||||
x2: 300,
|
||||
y2: 100,
|
||||
tag: 1,
|
||||
},
|
||||
RectRaw {
|
||||
x1: 100,
|
||||
y1: 100,
|
||||
x2: 300,
|
||||
y2: 200,
|
||||
tag: 1,
|
||||
},
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn rects_to_bands_tagged8() {
|
||||
let rects = [
|
||||
Rect::new_unchecked_danger_tagged(0, 0, 100, 100, 1),
|
||||
Rect::new_unchecked_danger_tagged(100, 0, 200, 100, 0),
|
||||
];
|
||||
let r = Region::from_rects_tagged(&rects[..]);
|
||||
assert_eq!(
|
||||
&r.rects[..],
|
||||
&[
|
||||
RectRaw {
|
||||
x1: 0,
|
||||
y1: 0,
|
||||
x2: 100,
|
||||
y2: 100,
|
||||
tag: 1,
|
||||
},
|
||||
RectRaw {
|
||||
x1: 100,
|
||||
y1: 0,
|
||||
x2: 200,
|
||||
y2: 100,
|
||||
tag: 0,
|
||||
},
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn rects_to_bands_tagged9() {
|
||||
let rects = [
|
||||
Rect::new_unchecked_danger_tagged(0, 0, 100, 100, 1),
|
||||
Rect::new_unchecked_danger_tagged(100, 0, 200, 100, 1),
|
||||
];
|
||||
let r = Region::from_rects_tagged(&rects[..]);
|
||||
assert_eq!(
|
||||
&r.rects[..],
|
||||
&[RectRaw {
|
||||
x1: 0,
|
||||
y1: 0,
|
||||
x2: 200,
|
||||
y2: 100,
|
||||
tag: 1,
|
||||
},],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn rects_to_bands_tagged10() {
|
||||
let rects = [
|
||||
Rect::new_unchecked_danger_tagged(0, 0, 100, 100, 1),
|
||||
Rect::new_unchecked_danger_tagged(0, 100, 100, 200, 1),
|
||||
];
|
||||
let r = Region::from_rects_tagged(&rects[..]);
|
||||
assert_eq!(
|
||||
&r.rects[..],
|
||||
&[RectRaw {
|
||||
x1: 0,
|
||||
y1: 0,
|
||||
x2: 100,
|
||||
y2: 200,
|
||||
tag: 1,
|
||||
},],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn rects_to_bands_tagged11() {
|
||||
let rects = [Rect::new_unchecked_danger_tagged(0, 0, 100, 100, 11)];
|
||||
let r = Region::from_rects_tagged(&rects[..]);
|
||||
assert_eq!(
|
||||
&r.rects[..],
|
||||
&[RectRaw {
|
||||
x1: 0,
|
||||
y1: 0,
|
||||
x2: 100,
|
||||
y2: 100,
|
||||
tag: 1,
|
||||
},],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn rects_to_bands_tagged12() {
|
||||
let rects = [
|
||||
Rect::new_unchecked_danger_tagged(0, 0, 100, 100, 11),
|
||||
Rect::new_unchecked_danger_tagged(200, 0, 300, 100, 10),
|
||||
];
|
||||
let r = Region::from_rects_tagged(&rects[..]);
|
||||
assert_eq!(
|
||||
&r.rects[..],
|
||||
&[
|
||||
RectRaw {
|
||||
x1: 0,
|
||||
y1: 0,
|
||||
x2: 100,
|
||||
y2: 100,
|
||||
tag: 1,
|
||||
},
|
||||
RectRaw {
|
||||
x1: 200,
|
||||
y1: 0,
|
||||
x2: 300,
|
||||
y2: 100,
|
||||
tag: 0,
|
||||
},
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn rects_to_bands_tagged13() {
|
||||
let rects = [
|
||||
Rect::new_unchecked_danger_tagged(0, 0, 100, 100, 1),
|
||||
Rect::new_unchecked_danger_tagged(0, 100, 100, 200, 0),
|
||||
];
|
||||
let r = Region::from_rects_tagged(&rects[..]);
|
||||
assert_eq!(
|
||||
&r.rects[..],
|
||||
&[
|
||||
RectRaw {
|
||||
x1: 0,
|
||||
y1: 0,
|
||||
x2: 100,
|
||||
y2: 100,
|
||||
tag: 1,
|
||||
},
|
||||
RectRaw {
|
||||
x1: 0,
|
||||
y1: 100,
|
||||
x2: 100,
|
||||
y2: 200,
|
||||
tag: 0,
|
||||
},
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn rects_to_bands_tagged14() {
|
||||
let rects = [
|
||||
Rect::new_unchecked_danger_tagged(0, 0, 100, 100, 1),
|
||||
Rect::new_unchecked_danger_tagged(0, 0, 100, 100, 0),
|
||||
];
|
||||
let r = Region::from_rects_tagged(&rects[..]);
|
||||
assert_eq!(
|
||||
&r.rects[..],
|
||||
&[RectRaw {
|
||||
x1: 0,
|
||||
y1: 0,
|
||||
x2: 100,
|
||||
y2: 100,
|
||||
tag: 0,
|
||||
},],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn intersect1() {
|
||||
let rects = [Rect::new_unchecked_danger_tagged(0, 0, 100, 100, 0)];
|
||||
let r1 = Region::from_rects_tagged(&rects[..]);
|
||||
let rects = [Rect::new_unchecked_danger(100, 100, 200, 200)];
|
||||
let r2 = Region::from_rects2(&rects[..]);
|
||||
let r3 = r1.intersect_tagged(&r2);
|
||||
assert_eq!(&r3.rects[..], &[],);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn intersect2() {
|
||||
let rects = [Rect::new_unchecked_danger_tagged(0, 0, 200, 200, 0)];
|
||||
let r1 = Region::from_rects_tagged(&rects[..]);
|
||||
let rects = [Rect::new_unchecked_danger(50, 50, 150, 150)];
|
||||
let r2 = Region::from_rects2(&rects[..]);
|
||||
let r3 = r1.intersect_tagged(&r2);
|
||||
assert_eq!(
|
||||
&r3.rects[..],
|
||||
&[RectRaw {
|
||||
x1: 50,
|
||||
y1: 50,
|
||||
x2: 150,
|
||||
y2: 150,
|
||||
tag: 0,
|
||||
}],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn intersect3() {
|
||||
macro_rules! t {
|
||||
($l:expr, $r:expr, $t:expr) => {
|
||||
Rect::new_unchecked_danger_tagged($l, 0, $r, 1, $t)
|
||||
};
|
||||
}
|
||||
macro_rules! u {
|
||||
($l:expr, $r:expr) => {
|
||||
Rect::new_unchecked_danger($l, 0, $r, 1)
|
||||
};
|
||||
}
|
||||
macro_rules! r {
|
||||
($l:expr, $r:expr, $t:expr) => {
|
||||
RectRaw {
|
||||
x1: $l,
|
||||
y1: 0,
|
||||
x2: $r,
|
||||
y2: 1,
|
||||
tag: $t,
|
||||
}
|
||||
};
|
||||
}
|
||||
let rects = [
|
||||
t!(0, 100, 0),
|
||||
t!(110, 130, 1),
|
||||
t!(140, 160, 2),
|
||||
t!(170, 180, 0),
|
||||
];
|
||||
let r1 = Region::from_rects_tagged(&rects[..]);
|
||||
let rects = [
|
||||
u!(10, 20),
|
||||
u!(50, 60),
|
||||
u!(70, 100),
|
||||
u!(120, 150),
|
||||
u!(170, 180),
|
||||
];
|
||||
let r2 = Region::from_rects2(&rects[..]);
|
||||
let r3 = r1.intersect_tagged(&r2);
|
||||
assert_eq!(
|
||||
&r3.rects[..],
|
||||
&[
|
||||
r!(10, 20, 0),
|
||||
r!(50, 60, 0),
|
||||
r!(70, 100, 0),
|
||||
r!(120, 130, 1),
|
||||
r!(140, 150, 0),
|
||||
r!(170, 180, 0),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue