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
use num::{PrimInt, Float, NumCast};
#[cfg(any(test, feature = "arbitrary"))]
use quickcheck::{Arbitrary, Gen};
use nalgebra::{Vector2, BaseFloat};
use partition::{Partition, Subdivide};
#[derive(Copy, Clone, Debug, PartialEq, Hash, Eq)]
pub struct UnitQuad {
scale: u8,
offset: (u32, u32),
}
impl UnitQuad {
pub fn new(scale: u8, offset: (u32, u32)) -> UnitQuad {
assert!(scale < 32);
let max_offset = 2.pow(scale as u32);
assert!(offset.0 < max_offset && offset.1 < max_offset);
UnitQuad { scale: scale, offset: offset }
}
pub fn scale(&self) -> u8 { self.scale }
pub fn offset(&self) -> (u32, u32) { self.offset }
pub fn coordinate<T: BaseFloat + NumCast + Float>(&self, coord: (T, T)) -> Vector2<T> {
let (u, v) = coord;
let width: T = self.width();
Vector2::new(
width * (<T as NumCast>::from(self.offset.0).unwrap() + u),
width * (<T as NumCast>::from(self.offset.1).unwrap() + v),
)
}
pub fn center<T: BaseFloat + NumCast + Float>(&self) -> Vector2<T> {
let half = NumCast::from(0.5).unwrap();
self.coordinate((half, half))
}
pub fn width<T: BaseFloat + NumCast + Float>(&self) -> T {
Float::powi(<T as NumCast>::from(0.5).unwrap(), self.scale as i32)
}
}
impl Subdivide for UnitQuad {
fn subdivide(&self) -> Vec<UnitQuad> {
[(0, 0), (0, 1), (1, 0), (1, 1)]
.iter()
.map(|&(di, dj)| {
let (i, j) = self.offset;
UnitQuad::new(self.scale + 1, (i * 2 + di, j * 2 + dj))
})
.collect()
}
}
impl<T: BaseFloat + NumCast + Float> Partition<Vector2<T>> for UnitQuad
{
fn contains(&self, elem: &Vector2<T>) -> bool {
let width: T = self.width();
let offset = Vector2::new(
width * NumCast::from(self.offset.0).unwrap(),
width * NumCast::from(self.offset.1).unwrap(),
);
(offset.x < elem.x) && (elem.x < offset.x + width) &&
(offset.y < elem.y) && (elem.y < offset.y + width)
}
}
#[cfg(any(test, feature = "arbitrary"))]
impl Arbitrary for UnitQuad {
fn arbitrary<G: Gen>(g: &mut G) -> UnitQuad {
use std::cmp;
use rand::Rng;
let scale: u8 = {
let max_scale = cmp::min(31, g.size()) as u8;
g.gen_range(0, max_scale)
};
let max_offset = 2.pow(scale as u32);
UnitQuad::new(scale, (
g.gen_range(0, max_offset),
g.gen_range(0, max_offset),
))
}
}
#[cfg(test)]
mod test {
pub use nalgebra::Vector2;
pub use super::*;
use quickcheck::{quickcheck, TestResult};
use partition::Partition;
partition_quickcheck!(unitquad_vec2_f32, UnitQuad, Vector2<f32>);
partition_quickcheck!(unitquad_vec2_f64, UnitQuad, Vector2<f64>);
#[test]
fn unitquad_base_contains_region() {
fn check(v: Vector2<f64>) -> TestResult {
if v.x < 0.0 || v.x >= 1.0 || v.y < 0.0 || v.y >= 1.0 {
TestResult::discard()
} else {
TestResult::from_bool(UnitQuad::new(0, (0, 0)).contains(&v))
}
}
quickcheck(check as fn(Vector2<f64>) -> TestResult);
}
}