use {
Buffer2d,
Rect,
Packer,
};
pub struct GuillotinePacker<B: Buffer2d> {
buf: B,
free_areas: Vec<Rect>,
margin: u32,
}
impl<B: Buffer2d> GuillotinePacker<B> {
fn find_free_area(&self, w: u32, h: u32) -> Option<(usize, Rect)> {
let mut index = None;
let mut min_area = None;
let mut rect = Rect::new(0, 0, 0, 0);
for i in range(0, self.free_areas.len()) {
let ref area = self.free_areas[i];
let a = area.area();
if w <= area.w && h <= area.h {
if min_area.is_none() || a < min_area.unwrap() {
index = Some(i);
min_area = Some(a);
rect.x = area.x;
rect.y = area.y;
rect.w = w;
rect.h = h;
}
} else if h <= area.w && w <= area.h {
if min_area.is_none() || a < min_area.unwrap() {
index = Some(i);
min_area = Some(a);
rect.x = area.x;
rect.y = area.y;
rect.w = h;
rect.h = w;
}
}
}
match index {
Some(i) => {
Some((i, rect))
},
_ => {
None
},
}
}
fn split(&mut self, index: usize, rect: &Rect) {
let area = self.free_areas.remove(index);
if area.w < area.h {
self.free_areas.push(Rect {
x: area.x + rect.w,
y: area.y,
w: area.w - rect.w,
h: rect.h,
});
self.free_areas.push(Rect {
x: area.x,
y: area.y + rect.h,
w: area.w,
h: area.h - rect.h,
});
}
else {
self.free_areas.push(Rect {
x: area.x,
y: area.y + rect.h,
w: rect.w,
h: area.h - rect.h,
});
self.free_areas.push(Rect {
x: area.x + rect.w,
y: area.y,
w: area.w - rect.w,
h: area.h,
});
}
}
}
impl<B: Buffer2d> Packer for GuillotinePacker<B> {
type Buffer = B;
fn new(buf: B) -> GuillotinePacker<B> {
let (width, height) = buf.dimensions();
let mut free_areas = Vec::new();
free_areas.push(Rect {
x: 0,
y: 0,
w: width,
h: height,
});
GuillotinePacker {
buf: buf,
free_areas: free_areas,
margin: 0,
}
}
fn pack<O: Buffer2d<Pixel=B::Pixel>>(&mut self, buf: &O) -> Option<Rect> {
let (mut width, mut height) = buf.dimensions();
width += self.margin;
height += self.margin;
match self.find_free_area(width, height) {
Some((i, mut rect)) => {
if width == rect.w {
self.buf.patch(rect.x, rect.y, buf);
} else {
self.buf.patch_rotated(rect.x, rect.y, buf);
}
self.split(i, &rect);
rect.w -= self.margin;
rect.h -= self.margin;
Some(rect)
},
_ => {
None
},
}
}
fn buf(&self) -> &B {
&self.buf
}
fn into_buf(self) -> B {
self.buf
}
fn set_margin(&mut self, val: u32) {
self.margin = val;
}
}