Simple bin packing for rectangles.
Based on the version in Haskell.
[The demo of a similar algorithm](https://observablehq.com/
BinPack a
, where a
is the type of what every rectangle is associated with (what lies in every cell). For example, it could be Color
.
{ x : Basics.Float
, y : Basics.Float
, width : Basics.Float
, height : Basics.Float
}
The bounds, top left corner and width/height.
container : Basics.Float -> Basics.Float -> BinPack a
Create an empty container with given height and width.
pack : ( { width : Basics.Float, height : Basics.Float }, a ) -> BinPack a -> Maybe (BinPack a)
Try to pack the value in a rectangle with given width and height. If the rect doesn't fit, Nothing
is returned.
carelessPack : ( { width : Basics.Float, height : Basics.Float }, a ) -> BinPack a -> BinPack a
Try to pack the value in a rectangle with given width and height. If the rectangle doesn't fit, ignore that fact and return previous condition of BinPack
.
packAll : Basics.Float -> Basics.Float -> List ( { width : Basics.Float, height : Basics.Float }, a ) -> BinPack a
Try to pack all the values with given dimensions in a BinPack
container with given width and height, ignore the item when it doesn't fit.
packAllIn : List ( { width : Basics.Float, height : Basics.Float }, a ) -> BinPack a -> BinPack a
Try to pack all the values with given dimensions in the given BinPack
container.
find : { x : Basics.Float, y : Basics.Float } -> BinPack a -> Maybe ( a, Bounds )
Try to find a value in a structure using given coordinates.
fold : (a -> b -> b) -> b -> BinPack a -> b
Fold the BinPack a
to any other type, for example:
BinPack.container 300 250
|> carelessPack ( { width = 10, height = 30 }, Color.black )
|> carelessPack ( { width = 20, height = 15 }, Color.red )
|> carelessPack ( { width = 5, height = 25 }, Color.blue )
|> fold (::) []
-- == [ Color.black, Color.red, Color.blue ]
foldWithFreeSpace : (Maybe a -> b -> b) -> b -> BinPack a -> b
Fold the BinPack
using the information about if it's a free space (Nothing
) or a node (Maybe a
).
foldGeometry : (( a, Bounds ) -> k -> k) -> k -> BinPack a -> k
Fold the structure, using both the values and their bounds:
BinPack.container 20 100
|> carelessPack ( { width = 10, height = 30 }, Color.black )
|> carelessPack ( { width = 20, height = 15 }, Color.red )
|> carelessPack ( { width = 5, height = 25 }, Color.blue )
|> carelessPack ( { width = 12, height = 25 }, Color.green )
|> foldGeometry (::) []
-- ==
-- [ ( Color.black, { x = 0, y = 0, width = 10, height = 30 } )
-- , ( Color.red, { x = 0, y = 30, width = 20, height = 15 } )
-- , ( Color.blue, { x = 10, y = 0, width = 5, height = 25 } )
-- , ( Color.green, { x = 0, y = 45, width = 12, height = 25 } )
-- ]
foldGeometryWithFreeSpace : (( Maybe a, Bounds ) -> k -> k) -> k -> BinPack a -> k
Fold with the information if it's a free space (Nothing
) or a node (Just a
), including bounds.
toList : BinPack a -> List ( a, Bounds )
Convert the structure to the list of values and their bounds
toListWithFreeSpace : BinPack a -> List ( Maybe a, Bounds )
Convert the structure to the list of values and their bounds + information if it's a free space or a node.
map : (a -> b) -> BinPack a -> BinPack b
Substitute all of the cells with different ones, using the previous ones as the source.