start work on better packing algorithm, start with scan
This commit is contained in:
parent
d9ca08f685
commit
cc26b98909
@ -7,7 +7,7 @@ GIT
|
||||
PATH
|
||||
remote: .
|
||||
specs:
|
||||
compass (0.11.1.d9e4054)
|
||||
compass (0.11.1.d9ca08f)
|
||||
chunky_png (~> 1.1)
|
||||
fssm (>= 0.2.7)
|
||||
sass (~> 3.1)
|
||||
@ -50,7 +50,7 @@ GEM
|
||||
autotest-fsevent (0.2.5)
|
||||
sys-uname
|
||||
builder (2.1.2)
|
||||
chunky_png (1.1.1)
|
||||
chunky_png (1.2.0)
|
||||
compass-validator (3.0.0)
|
||||
css_parser (1.0.1)
|
||||
cucumber (0.9.4)
|
||||
|
18
lib/compass/sass_extensions/sprites/image_group.rb
Normal file
18
lib/compass/sass_extensions/sprites/image_group.rb
Normal file
@ -0,0 +1,18 @@
|
||||
module Compass
|
||||
module SassExtensions
|
||||
module Sprites
|
||||
class ImageGroup
|
||||
attr_reader :images
|
||||
|
||||
def initialize(images = [])
|
||||
@images = images
|
||||
end
|
||||
|
||||
def best_fitting_rows
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -1,8 +1,13 @@
|
||||
require 'forwardable'
|
||||
|
||||
module Compass
|
||||
module SassExtensions
|
||||
module Sprites
|
||||
class ImageRow
|
||||
extend Forwardable
|
||||
|
||||
attr_reader :images, :max_width
|
||||
def_delegators :@images, :last, :delete, :empty?, :length
|
||||
|
||||
def initialize(max_width)
|
||||
@images = []
|
||||
@ -10,16 +15,13 @@ module Compass
|
||||
end
|
||||
|
||||
def add(image)
|
||||
unless image.is_a?(Compass::SassExtensions::Sprites::Image)
|
||||
raise ArgumentError, "Must be a SpriteImage"
|
||||
end
|
||||
if (images.inject(0) {|sum, img| sum + img.width} + image.width) > max_width
|
||||
return false
|
||||
end
|
||||
return false if !will_fit?(image)
|
||||
@images << image
|
||||
true
|
||||
end
|
||||
|
||||
alias :<< :add
|
||||
|
||||
def height
|
||||
images.map(&:height).max
|
||||
end
|
||||
@ -28,6 +30,17 @@ module Compass
|
||||
images.map(&:width).max
|
||||
end
|
||||
|
||||
def total_width
|
||||
images.inject(0) {|sum, img| sum + img.width }
|
||||
end
|
||||
|
||||
def efficiency
|
||||
1 - (total_width.to_f / max_width.to_f)
|
||||
end
|
||||
|
||||
def will_fit?(image)
|
||||
(total_width + image.width) <= max_width
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
81
lib/compass/sass_extensions/sprites/row_fitter.rb
Normal file
81
lib/compass/sass_extensions/sprites/row_fitter.rb
Normal file
@ -0,0 +1,81 @@
|
||||
require 'forwardable'
|
||||
|
||||
module Compass
|
||||
module SassExtensions
|
||||
module Sprites
|
||||
class RowFitter
|
||||
extend Forwardable
|
||||
|
||||
attr_reader :images, :rows
|
||||
def_delegators :rows, :[]
|
||||
def initialize(images)
|
||||
@images = images
|
||||
@rows = []
|
||||
end
|
||||
|
||||
def fit!(style = :scan)
|
||||
send("#{style}_fit")
|
||||
end
|
||||
|
||||
def width
|
||||
@width ||= @images.collect(&:width).max
|
||||
end
|
||||
|
||||
def efficiency
|
||||
@rows.inject(0) { |sum, row| sum += row.efficiency } ** @rows.length
|
||||
end
|
||||
|
||||
private
|
||||
def new_row(image = nil)
|
||||
row = Compass::SassExtensions::Sprites::ImageRow.new(width)
|
||||
row.add(image) if image
|
||||
row
|
||||
end
|
||||
|
||||
def fast_fit
|
||||
row = new_row
|
||||
@images.each do |image|
|
||||
if !row.add(image)
|
||||
@rows << row
|
||||
row = new_row(image)
|
||||
end
|
||||
end
|
||||
|
||||
@rows << row
|
||||
end
|
||||
|
||||
def scan_fit
|
||||
fast_fit
|
||||
|
||||
moved_images = []
|
||||
|
||||
begin
|
||||
removed = false
|
||||
|
||||
catch :done do
|
||||
@rows.each do |row|
|
||||
(@rows - [ row ]).each do |other_row|
|
||||
other_row.images.each do |image|
|
||||
if !moved_images.include?(image)
|
||||
if row.will_fit?(image)
|
||||
other_row.delete(image)
|
||||
row << image
|
||||
|
||||
@rows.delete(other_row) if other_row.empty?
|
||||
removed = true
|
||||
|
||||
moved_images << image
|
||||
throw :done
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end while removed
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
7
test.watchr
Normal file
7
test.watchr
Normal file
@ -0,0 +1,7 @@
|
||||
watch('test/(.*)_test\.rb') { |m| test(m[0]) }
|
||||
watch('lib/compass/sass_extensions/sprites/image_group.rb') { test('test/units/sprites/image_group_test.rb') }
|
||||
watch('lib/compass/sass_extensions/sprites/row_fitter.rb') { test('test/units/sprites/row_fitter_test.rb') }
|
||||
|
||||
def test(file = nil)
|
||||
system %{ruby -I"lib:test" #{file}}.tap { |o| puts o }
|
||||
end
|
@ -21,7 +21,7 @@ require 'rubygems' if need_gems
|
||||
require 'compass'
|
||||
|
||||
require 'test/unit'
|
||||
|
||||
require 'mocha'
|
||||
|
||||
%w(command_line diff io rails test_case).each do |helper|
|
||||
require "helpers/#{helper}"
|
||||
|
9
test/units/sprites/image_group_test.rb
Normal file
9
test/units/sprites/image_group_test.rb
Normal file
@ -0,0 +1,9 @@
|
||||
require 'test_helper'
|
||||
require 'compass/sass_extensions/sprites/image_group'
|
||||
|
||||
class ImageGroupTest < Test::Unit::TestCase
|
||||
def setup
|
||||
end
|
||||
|
||||
end
|
||||
|
@ -49,4 +49,8 @@ class ImageRowTest < Test::Unit::TestCase
|
||||
assert_equal 40, @image_row.height
|
||||
end
|
||||
|
||||
it "should have an efficiency rating" do
|
||||
populate_row
|
||||
assert_equal 1 - (580.0 / 1000.0), @image_row.efficiency
|
||||
end
|
||||
end
|
82
test/units/sprites/row_fitter_test.rb
Normal file
82
test/units/sprites/row_fitter_test.rb
Normal file
@ -0,0 +1,82 @@
|
||||
require 'test_helper'
|
||||
require 'compass/sass_extensions/sprites/row_fitter'
|
||||
|
||||
class RowFitterTest < Test::Unit::TestCase
|
||||
def setup
|
||||
end
|
||||
|
||||
def row_fitter(images = nil)
|
||||
@row_fitter ||= Compass::SassExtensions::Sprites::RowFitter.new(images)
|
||||
end
|
||||
|
||||
def teardown
|
||||
@row_fitter = nil
|
||||
end
|
||||
|
||||
def create_images(dims)
|
||||
dims.collect { |width, height| stub(:width => width, :height => height) }
|
||||
end
|
||||
|
||||
def basic_dims
|
||||
[
|
||||
[ 100, 10 ],
|
||||
[ 80, 10 ],
|
||||
[ 50, 10 ],
|
||||
[ 20, 10 ],
|
||||
[ 35, 10 ]
|
||||
]
|
||||
end
|
||||
|
||||
it 'should use the fast placement algorithm' do
|
||||
images = create_images(basic_dims)
|
||||
|
||||
row_fitter(images)
|
||||
assert_equal 100, row_fitter.width
|
||||
|
||||
row_fitter.fit!(:fast)
|
||||
|
||||
assert_equal 4, row_fitter.rows.length
|
||||
|
||||
assert_equal [ images[0] ], row_fitter[0].images
|
||||
assert_equal [ images[1] ], row_fitter[1].images
|
||||
assert_equal [ images[2], images[3] ], row_fitter[2].images
|
||||
assert_equal [ images[4] ], row_fitter[3].images
|
||||
end
|
||||
|
||||
it 'should use the scan placement algorithm' do
|
||||
images = create_images(basic_dims)
|
||||
|
||||
row_fitter(images)
|
||||
|
||||
row_fitter.fit!(:scan)
|
||||
|
||||
assert_equal 3, row_fitter.rows.length
|
||||
|
||||
assert_equal [ images[0] ], row_fitter[0].images
|
||||
assert_equal [ images[1], images[3] ], row_fitter[1].images
|
||||
assert_equal [ images[2], images[4] ], row_fitter[2].images
|
||||
end
|
||||
|
||||
it 'should use the scan placement algorithm and get images from the front' do
|
||||
images = create_images(
|
||||
[
|
||||
[ 100, 10 ],
|
||||
[ 35, 10 ],
|
||||
[ 80, 10 ],
|
||||
[ 50, 10 ],
|
||||
[ 20, 10 ],
|
||||
]
|
||||
)
|
||||
|
||||
row_fitter(images)
|
||||
|
||||
row_fitter.fit!(:scan)
|
||||
|
||||
assert_equal 3, row_fitter.rows.length
|
||||
|
||||
assert_equal [ images[0] ], row_fitter[0].images
|
||||
assert_equal [ images[1], images[3] ], row_fitter[1].images
|
||||
assert_equal [ images[2], images[4] ], row_fitter[2].images
|
||||
end
|
||||
end
|
||||
|
Loading…
Reference in New Issue
Block a user