#[derive(Debug,Copy,Clone)]
pub struct Entry {
id: usize,
width: u32,
height: u32,
}
impl Entry {
pub fn new( id: usize, width: u32, height: u32 ) -> Entry {
Entry {
id: id,
width: width,
height: height,
}
}
}
#[derive(Debug)]
pub struct EntryWithPosition {
pub id: usize,
pub width: u32,
pub height: u32,
pub x: u32,
pub y: u32,
}
impl EntryWithPosition {
pub fn new_from_entry( entry: &Entry ) -> EntryWithPosition {
EntryWithPosition {
id: entry.id,
width: entry.width,
height: entry.height,
x: 0,
y: 0,
}
}
pub fn set_position( &mut self, x: u32, y: u32 ) {
self.x = x;
self.y = y;
}
}
#[derive(Debug)]
struct Row {
y: u32, width: u32,
height: u32,
end_x: u32, }
impl Row {
fn new( y: u32, width: u32, height: u32 ) -> Row {
Row {
y: y,
width: width,
height: height,
end_x: 0
}
}
fn would_fit( &self, w: u32, h: u32 ) -> bool {
if self.height >= h {
let available_space = self.width - self.end_x;
if available_space >= w {
true
} else {
false
}
} else {
false
}
}
}
#[derive(Debug)]
pub struct Page {
size: u32,
border: u32,
pub entries: Vec<EntryWithPosition>,
rows: Vec<Row>,
used_height: u32,
}
impl Page {
pub fn new( size: u32, border: u32 ) -> Page {
Page {
size: size,
border: border,
entries: Vec::new(),
rows: Vec::new(),
used_height: 0,
}
}
fn add_row( &mut self, height: u32 ) -> Option<usize> {
if height <= ( self.size - self.used_height ) {
let row = Row::new( self.used_height, self.size, height );
self.used_height += height;
let row_index = self.rows.len();
self.rows.push( row );
Some( row_index )
} else {
None
}
}
fn fit_entry_to_row_with_index( &mut self, entry: &Entry, row_index: usize ) -> bool {
match self.rows.get_mut( row_index ) {
None => false, Some( row ) => {
if row.would_fit( entry.width, entry.height ) {
let mut e = EntryWithPosition::new_from_entry( entry );
let x = row.end_x;
let y = row.y;
row.end_x += e.width;
e.set_position( x, y );
self.entries.push(
e
);
true
} else {
false
}
}
}
}
fn fit_entry( &mut self, entry: &Entry ) -> bool {
let h = entry.height;
if self.size < entry.width || self.size < entry.height {
false
} else {
let mut candidates = Vec::new();
for ri in 0..self.rows.len() {
let r = &self.rows[ ri ];
if r.would_fit( entry.width, entry.height ) {
if r.height < 2*entry.height { candidates.push( ri );
}
}
}
if candidates.len() > 0 {
let best_candidate_index = 0;
self.fit_entry_to_row_with_index( entry, candidates[ best_candidate_index ] )
} else {
match self.add_row( h ) {
None => false, Some( row_index ) => self.fit_entry_to_row_with_index( entry, row_index ),
}
}
}
}
}
#[derive(Debug)]
pub struct AtlasFitter {
entries: Vec< Entry >,
}
impl AtlasFitter {
pub fn new() -> AtlasFitter {
AtlasFitter {
entries: Vec::new()
}
}
pub fn add_entry( &mut self, id: usize, width: u32, height: u32 ) {
let e = Entry::new( id, width, height );
self.entries.push( e );
}
pub fn fit( &self, size: u32, border: u32 ) -> Vec<Page> {
let mut pages: Vec<Page> = Vec::new();
for e in &self.entries {
let mut did_fit = false;
for p in &mut pages {
if p.fit_entry( &e ) {
did_fit = true;
break;
}
}
if !did_fit {
let mut p = Page::new( size, border );
if !p.fit_entry( &e ) {
println!("‼️ Image doesn't fit into empty page {:?}", e );
}
pages.push( p );
}
}
pages
}
}