///|
pub struct Window {
priv x0 : Int32
priv y0 : Int32
priv x1 : Int32
priv y1 : Int32
} derive(Debug, Eq)
///|
pub extend Window with @debug.Debug::{to_repr}
///|
pub extend Window with Eq::{equal, not_equal}
///|
pub fn Window::new(
x0 : Int32,
y0 : Int32,
x1 : Int32,
y1 : Int32,
) -> Window raise ExrError {
let w = x1.to_int64() - x0.to_int64() + 1L
let h = y1.to_int64() - y0.to_int64() + 1L
if w <= 0L || h <= 0L || w > 2147483647L || h > 2147483647L {
raise Invalid("empty or overflowing window", 0)
}
{ x0, y0, x1, y1, }
}
///|
pub fn Window::bounds(self : Window) -> (Int32, Int32, Int32, Int32) {
(self.x0, self.y0, self.x1, self.y1)
}
///|
pub fn Window::width(self : Window) -> Int32 {
(self.x1.to_int64() - self.x0.to_int64() + 1L).to_int()
}
///|
pub fn Window::height(self : Window) -> Int32 {
(self.y1.to_int64() - self.y0.to_int64() + 1L).to_int()
}
///|
pub fn Window::pixels(self : Window) -> Int32 raise ExrError {
mul(self.width(), self.height())
}
///|
pub fn Window::contains(self : Window, x : Int32, y : Int32) -> Bool {
x >= self.x0 && x <= self.x1 && y >= self.y0 && y <= self.y1
}
///|
pub fn Window::intersection(self : Window, other : Window) -> Window? {
let x0 = imax(self.x0, other.x0)
let y0 = imax(self.y0, other.y0)
let x1 = imin(self.x1, other.x1)
let y1 = imin(self.y1, other.y1)
if x0 > x1 || y0 > y1 {
None
} else {
Some({ x0, y0, x1, y1, })
}
}
///|
fn Window::offset(self : Window, x : Int32, y : Int32) -> Int32 raise ExrError {
if !self.contains(x, y) {
raise Invalid("coordinate outside data window", 0)
}
add(mul(y - self.y0, self.width()), x - self.x0)
}
///|
fn read_window(bytes : Bytes) -> Window raise ExrError {
if bytes.length() != 16 {
raise Invalid("box2i length", 0)
}
let r = reader(bytes)
Window::new(r.i32(), r.i32(), r.i32(), r.i32())
}
///|
fn window_bytes(box : Window) -> Bytes {
let s = sink()
s.i32(box.x0)
s.i32(box.y0)
s.i32(box.x1)
s.i32(box.y1)
s.finish()
}
///|
test "inclusive windows retain negative coordinates and intersection" {
let a = Window::new(-3, -2, 2, 1)
assert_eq(a.width(), 6)
assert_eq(a.height(), 4)
assert_eq(a.pixels(), 24)
assert_eq(a.offset(2, 1), 23)
assert_eq(
a.intersection(Window::new(1, 0, 8, 5)),
Some(Window::new(1, 0, 2, 1)),
)
assert_eq(a.intersection(Window::new(3, 0, 8, 5)), None)
assert_eq(read_window(window_bytes(a)), a)
}
///|
test "window dimensions and linear indices reject overflow" {
assert_true(
try {
ignore(Window::new(-2147483648, 0, 2147483647, 0))
false
} catch {
_ => true
},
)
assert_true(
try {
ignore(Window::new(2, 0, 1, 0))
false
} catch {
_ => true
},
)
assert_true(
try {
ignore(Window::new(0, 0, 99999, 99999).pixels())
false
} catch {
_ => true
},
)
let singleton = Window::new(2147483647, -2147483648, 2147483647, -2147483648)
assert_eq(singleton.pixels(), 1)
assert_eq(singleton.offset(2147483647, -2147483648), 0)
}