Converting 8 Bit Images to 16 bit with Php ImageMagick - php

What I'm trying to do is convert an 8 bit image to a 16 bit image using php ImageMagick. With Imagick it's as easy as convert /location/image.jpg -colors 8 -depth 16 txt:-. In the PHP docs it shows that you can do it using $imagick->setImageDepth(16); but the problem is that it doesn't give you the 16 bit hex / rgb numbers.
Is there an advantage to using 16 bit when trying to extract colors from an image? If not then I'm wondering isn't the php function working?
Here is what I get from $mapColor->getColor():
Array
(
[r] => 51
[g] => 51
[b] => 51
[a] => 1
)
Array
Here is my code for getting colors:
// Create new instance
$imagick = new Imagick($image);
// Set number of colors
$numberColors = 6;
// Set colorspace
$colorSpace = Imagick::COLORSPACE_SRGB;
// Set tree depth
$treeDepth = 0;
// Set dither
$dither = false;
// Convert to 16 bit
$imagick->setImageDepth(16);
// Quantize image to number of colors
$imagick->quantizeImage($numberColors, $colorSpace, $treeDepth, $dither, false);
// Get Image Dimensions
$sizes = $imagick->getImageGeometry();
// Get image's histogram
$pixels = $imagick->getImageHistogram();
// Temp cache dimensions
$totalSize = $sizes['width'] * $sizes['height'];
// Loop through each pixel
foreach($pixels as $k => $v) {
// Get total number of color instances
$count = $v->getColorCount();
// Get colormap at pixel
$mapColor = $imagick->getImageColormapColor($k);
// Get colore
$rgbColor = $mapColor->getColor();
// Convert to RGB hex values
$red = str_pad(dechex($rgbColor['r']), 2, 0, STR_PAD_LEFT);
$green = str_pad(dechex($rgbColor['g']), 2, 0, STR_PAD_LEFT);
$blue = str_pad(dechex($rgbColor['b']), 2, 0, STR_PAD_LEFT);
// Set hexadecimal
$hex = $red.$green.$blue;
// Calculate color percentage
$percentage = (100 * $count) / $totalSize;
// Push colors into array
$colors[] = array(
'red' => $rgbColor['r'],
'green' => $rgbColor['g'],
'blue' => $rgbColor['b'],
'hex' => $hex,
'count' => $count,
'percentage' => $percentage,
);
}
print_r($colors);

Related

How to get Highest possible bit rate and dimensions of a video?

I am using a package called pascalbaljetmedia/laravel-ffmpeg
And want to create an HLS playlist for video streaming.
but first i want to check the video bit-rate or width/height to see if it's a 4k, 1080, 720 etc.
So how do i calculate the video bitrate and it's dimensions?..
Here is what i want to do after getting the video information:
$video = FFMpeg::fromDisk('videos')
->open('original_video.mp4')
->exportForHLS();
$resolutions = [];
//check if we can make 4k version
if ( ( $bitrate >= 14000 ) || ( $width >= 3840 && $height >= 2160 ) )
{
// Then it's a 4k video
// We make a 4k version of HLS
$resolutions[] = ['q' => 14000, 'size' => [ 'w' => 3840, 'h' => 2160]];
}
//check if we can make HD version
if( ( $bitrate >= 5800 ) || ( $width >= 1920 && $height >= 1080 ) )
{
// Then it's a HD video
// We make a HD version of HLS
$resolutions[] = ['q' => 5800, 'size' => [ 'w' => 1920, 'h' => 1080]];
}
//Lastly we loop through and add formarts
foreach($resolutions as $resolution){
$video->addFormat($resolution['q'], function($media) {
$media->addFilter('scale='. $resolution['size']['w].':'. $resolution['size']['h]);
});
}
$video->save('video_name.m3u8');
Any help?.
I don't use Laravel, but it looks like pascalbaljetmedia/laravel-ffmpeg is a wrapper for php-ffmpeg/php-ffmpeg, so you should be able to use FFProbe to extract this information.
$ffprobe = FFMpeg\FFProbe::create();
$video = $ffprobe->streams('original_video.mp4')->videos()->first();
$width = $video->get('width');
$height = $video->get('height');
$bitrate = $video->get('bit_rate');
Incidentally, there are a couple of typos in your line of code which should be $media->addFilter('scale=' . $resolution['size']['w'] . ':' . $resolution['size']['h']);.

Calculation of possible Solutions inside an php Array: How to improve my Algorithm?

Preamble:
This question is not about to learn PHP, nor is it code that I plan to use in a productive environment. I just want so see and learn better ways to do this work, as I did in my approach. So please only correct my code or show me better, faster or shorter solutions for doing it. The problem itself has already been solved. Thank you!
The Problem:
Some days ago a user asked a question here on SO. His problem has got my attention, because I wanted to find a way to solve his needs.
He wanted to get all possible key combinations of an PHP array, where the sum of the values is 100, or as close as possible to 100. He had given us an example array, which I will use for my examples too:
$array = array(25, 30, 50, 15, 20, 30);
For example, one result should be [2, 4, 5], because 50 + 20 + 30 is 100.
$sum = $array[2] + $array[4] + $array[5]; // = 100
I think the basic idea should be clear. Now let's take a look at my work ...
My Approach:
So this problem has got my attention as a developer. At first, I thought it would be pretty simple. Just do some addition and check the result. But then I've noticed that there some points to keep in mind ...
There are plenty of combinations to test. For the example array, there would be up to 720 (6! = 1*2*3*4*5*6 = 720) possible permutations. To get all possible combinations, I wanted to get all possible permutations of the array first.
But that was only the half truth. Because there could be double values in the array (as in your example the 30), we could not get all possible permutations of the array values, we had to get all possible permutations of the array keys instead.
So I've used the pc_permut function of the php cookbook and modified it for my needs. It will return all possible permutations in an array of keys.
/**
* gets all possible permutations of $array
* #param array $array
* #param array $permutations
* #return array
*/
function permutations($array, $permutations = array()) {
if( !empty($array) ) {
$result = array();
for( $i = count($array) - 1; $i >= 0; --$i ) {
$newItems = $array;
$newPerms = $permutations;
list($values) = array_splice($newItems, $i, 1);
array_unshift($newPerms, $values);
$result = array_merge($result, permutations($newItems, $newPerms));
}
}
else {
$result = array($permutations);
}
return $result;
}
The result of this function is a multidimensional array, containing all permutations in an ordered key array.
Array (
[0] => Array (
[0] => 0
[1] => 1
[2] => 2
[3] => 3
[4] => 4
[5] => 5
)
[1] => Array (
[0] => 1
[1] => 0
[2] => 2
[3] => 3
[4] => 4
[5] => 5
)
[...
)
So, for now I got all permutations to work with. The calculation of the possible combinations is not so hard at all. I'll just loop through the permutation, increment the sum until they've reached 100 or above and return the key combination.
But I find out that I missed one thing. As I got all possible permutations, there are even some results doubled in the list. To explain, this two results are basically the same:
[2, 4, 5]; // 50 + 20 + 30 = 100
[4, 5, 2]; // 20 + 30 + 50 = 100
I've ended up sorting the keys after calculation and use them as index in the resulting array. So it would be sure, that every combination only exists once in the result. This is my combinations function:
/**
* gets all possible key combinations of $array with a sum below or equal $maxSum
* #param array $array
* #param integer $maxSum
* #return array
*/
function combinations($array, $maxSum) {
// get all permutations of the array keys
$permutations = permutations(array_keys($array));
$combinations = array();
// loop all permutations
foreach( $permutations as $keys ) {
// create a container for each permutation to store calculation
$current = array(
"sum" => 0,
"keys" => array()
);
// now loop through the permutation keys
foreach( $keys as $key ) {
// if the addition is still between or equal $maxSum
if( $current["sum"] + $array[$key] <= $maxSum ) {
// increment the sum and add key to result
$current["sum"] += $array[$key];
$current["keys"][] = $key;
}
}
// to be sure each combination only exists once in the result
// order the keys and use them as array index
sort($current["keys"]);
$combinations[join("", $current["keys"])] = $current;
}
// remove the created key-index from array when finished
return array_values($combinations);
}
The execution is simple straight forward:
$array = array(25, 30, 50, 15, 20, 30);
print_r(combinations($array, 100));
The result is an array, containing all combinations. For our example array there are eleven possible combinations. The result looks like this:
Array (
[0] => Array (
[sum] => 90
[keys] => Array (
[0] => 0
[1] => 1
[2] => 3
[3] => 4
)
)
[1] => Array (
[sum] => 90
[keys] => Array (
[0] => 0
[1] => 2
[2] => 3
)
)
[...
Since I've written this script as an answer of the original question, I'll ask myself, if there would be another, even better way to do the work. Maybe there is a way without permutations, or a way to exclude same combinations from calculation or the resulting array. I know that I could execute the calculation directly in the permutations function too, but this would be basically the same work flow.
I would really like to get some advises, tips or improvements from you. I think here is some potential to improve the script, but I have actually no idea how to. But I'm sure it could be done more simple and straight forward ...
Thanks for your time! :)
Sorting the array leads to some possibilities: here is the one i'm thinking of:
I denote a(selectedIndexes) the element composed of all elements of selectedIndexes e.g.
a({25, 30, 30}) = (25, 30, 30)
P(n) is the set of all combinations of the indexes 1 to n and for clarity sake my arrays starts at index 1 (thus P(2)={1, 2, (1, 2)})
I'm using 2 break conditions explained in the pseudocode below. 1st one is the first element of aSorted = the allowed sum.
2nd one is the sum is too small compared to aSorted first element
selectedIndexes = {}
sum = 100
aSorted = {15, 20, 25, 30, 30, 50} //starting values for the example
//to clarify the following function
aSum = {15, 35, 60, 90}
function n(aSorted, sum, selectedIndexes){
compute aSum //precisely search in aSum for the index at which
//the elements are bigger than sum, and cut
answer = (P(count(aSum))) X a(selectedIndexes) // with X being the cartesian product
for (i=count(aSum)+1; i<=count(aSorted); i++){
newASorted = splice(aSorted, count(aSum))
// 1st break condition
if(newASorted is empty) return answer
// 2nd break condition the new sum < the first element of aSorted
if (aSorted(i)<sum && sum-aSorted(i)>=aSorted(1)){
answer += n(newASorted, sum-aSorted(i), push(selectedIndexes,
i))
}
}
return answer
}
The complexity of this algorithm feels quadratic(after a quick check it's more like of order n^log2(n)) in regard to the number of elements in the array
To make it less abstract, let's develop the example(warning i trust the example more than the pseudocode although i didn't see inaccuracies myself in the pseudocode):
n({15, 20, 25, 30, 30, 50}, 100, {}) = P(4) + n({15, 20, 25, 30, 30}, 50, {6}) + n({15, 20, 25, 30}, 70, {5})
Starting by developing the first n function of the right side of the equation
n({15, 20, 25, 30, 30}, 50, {5}) = (P(2) X {6}) + n({15, 20, 25, 30}, 20, {5, 6}) + n({15, 20, 25}, 20, {4, 6}) + n({15, 20}, 25, {3, 6})
n({15, 20, 25, 30}, 20, {5, 6}) = (P(1) X {(5, 6)}) // + n({15}, 0, {2, 5, 6}) (but 0<15) break condition 2
n({15, 20, 25}, 20, {4, 6}) = P(1) X {(4, 6)} // and break condition 2
n({15, 20}, 25, {3, 6}) = P(1) X {(3, 6)} // + n({15}, 5, {2, 3, 6}) (but 5<15) break condition 2
Now developing the second n function of the right side of the equation
n({15, 20, 25, 30}, 70, {5}) = (P(3) X {5}) + n({15, 20, 25}, 40, {4, 5})
n({15, 20, 25}, 40, {4, 5}) = (P(2) X {(4, 5)}) + n({15, 20}, 15, {3, 4, 5})
n({15, 20}, 15, {3, 4, 5}) = P(1) x {(3, 4, 5)} // + n({}, 0, {1, 3, 4, 5}) new break condition aSum is empty

More efficient way to set PHP variables over and over again

I am curious of a better way of doing the code I have below, I find it repetitive and would like to cut down on it, any suggestions?
I was trying to do something with Variable Variables but I failed at getting that to work.
So basically I have a bunch of color names that I get with $_GET[color-name-here']
The goal is to set a color's code to a new color's code. So using the URL I am able to set the code for the color red to the color code of green so red's value would become 00FF00
// Get color and color replacement values from URL
// get_value_or is ran through this code...
// isset($_GET[$key]) && !empty($_GET[$key]) ? $_GET[$key] : $default;
$red = get_value_or('red', null);
$orange = get_value_or('orange', null);
$yellow = get_value_or('yellow', null);
$green = get_value_or('green', null);
$turquoise = get_value_or('turquise', null);
$blue = get_value_or('blue', null);
$purple = get_value_or('purple', null);
$pink = get_value_or('pink', null);
$white = get_value_or('white', null);
// Define Default Color Name and Hexcode values
$colorsArray = array(
'red' => 'FF0000',
'orange' => 'FF5000',
'yellow' => 'FFF200',
'green' => '00FF00',
'turquoise' => '00F0C8',
'blue' => '0064FF',
'purple' => '9F00FF',
'pink' => 'FF0082',
'white' => 'FFFFFF'
);
// Iterate Color Array and Set New Color Values if they exist
foreach($colorsArray as $colorName => $colorCode){
// Do something to set each color Name with a New color code, if that color name has a value set
}
// Right now I am doing it manually for each color name, all 9+ like this...
//Set Reds NEW color value
if(isset($red)){
$colorsArray['red'] = $colorsArray[$red];
}
//Set oranges NEW color value
if(isset($orange)){
$colorsArray['orange'] = $colorsArray[$orange];
}
//Set yellows NEW color value
if(isset($yellow)){
$colorsArray['yellow'] = $colorsArray[$yellow];
}
So any ideas how to set all the colors with less code?
A color's code should ONLY be updated if that color has a NEW value set in the URL using $_GET variables
PS) I wasn't sure of a good title for this question, feel free to change it if you have a better one, thanks
If I were you, I would put the assignments in the loop:
$colorsArray = array(
'red' => 'FF0000',
'orange' => 'FF5000',
'yellow' => 'FFF200',
'green' => '00FF00',
'turquoise' => '00F0C8',
'blue' => '0064FF',
'purple' => '9F00FF',
'pink' => 'FF0082',
'white' => 'FFFFFF'
);
foreach ($colorsArray as $colorName => $colorCode) {
$colorsArray[$colorName] = get_value_or($colorName, $colorCode);
}
It's quite neat, but I'm not sure whether it works with your real code or not.
Edit
I updated the code because I realized that the array $color_names was unnecessary, you have them in the keys of $colorsArray.
Edit
Updated the code again because the if in the loop was unnecessary too.
You can access all global variables by using the super global $GLOBALS. So you could do this:
foreach ($colorsArray as $colorName => $colorCode) {
if (isset($GLOBALS[$colorName]) {
$colorsArray[$colorName] = $GLOBALS[$colorName];
}
}
More info about $GLOBALS.

PHP/mySQL: Import data and store in hierarchical nested set for use with jsTree

I'm using jsTree to view hierarchical data that is stored in a mySQL database as a nested set (left, right, level, etc.). This is working fine, but I need to allow users to import data by uploading a CSV file. When they do so, any existing data in the table will be removed so I don't have to worry about updating the left/right fields.
The data they will be uploading will be in this format:
"Code","Title"
"100","Unit 100"
"200","Unit 200"
"101","Task 101: This is a task"
"102","Task 102: Another task"
"201","Task 201: Yet another"
"300","Unit 300"
"301","Task 301: Another one"
Everything will be a child of a main "Group" that is a level 1 node. All of the "codes" divisible by 100 (ie. 100, 200, 300) will be level 2 (parent nodes.. children of "Group"). All others will be level 3 (child) nodes of their respective parent nodes (ie. 101 and 102 are children of 100, 201 is a child of 200, etc.)
The resulting table in mySQL should look like this:
id parent_id position left right level title
1 0 0 1 18 0 ROOT
2 1 0 2 17 1 Group
3 2 0 3 8 2 Unit 100
4 2 1 9 12 2 Unit 200
5 3 0 4 5 3 Task 101: This is a task
6 3 1 6 7 3 Task 102: Another task
7 4 0 10 11 3 Task 201: Yet another
8 2 2 13 16 2 Unit 300
9 8 0 14 15 3 Task 301: Another one
The tree would then look like this:
My question is: using PHP, what is the best method to accomplish this? I already have code in place that pulls the data contained in the uploaded CSV file and stores it in an array, but I'm not sure what the logic to convert this to a nested set should look like.
Right now, the data is stored in a 2-dimensional array called $data (in the format $data[$col][$row]):
$data[0][0] = "Code";
$data[0][1] = "100";
$data[0][2] = "200";
$data[0][3] = "101";
$data[0][4] = "102";
$data[0][5] = "201";
$data[0][6] = "300";
$data[0][7] = "301";
$data[1][0] = "Title";
$data[1][1] = "Unit 100";
$data[1][2] = "Unit 200";
$data[1][3] = "Task 101: This is a task";
$data[1][4] = "Task 102: Another task";
$data[1][5] = "Task 201: Yet another";
$data[1][6] = "Unit 300";
$data[1][7] = "Task 301: Another one";
Array ( [0] => Array ( [0] => Code [1] => 100 [2] => 200 [3] => 101 [4] => 102 [5] => 201 [6] => 300 [7] => 301 ) [1] => Array ( [0] => Title [1] => Unit 100 [2] => Unit 200 [3] => Task 101: This is a task [4] => Task 102: Another task [5] => Task 201: Yet another [6] => Unit 300 [7] => Task 301: Another one ) )
Any help would be very much appreciated. I now have the parent_id, position, and level being calculated correctly... I just need to figure out the left/right part. Here is the code I'm currently using (thanks for getting me started Matteo):
$rows = array();
// insert ROOT row
$rows[] = array(
'id' => 1,
'parent_id' => 0,
'position' => 0,
'left' => 1,
'right' => 10000, // just a guess, will need updated later
'level' => 0,
'title' => 'ROOT',
);
echo "<br>";
print_r($rows[0]);
// insert group row
$rows[] = array(
'id' => 2,
'parent_id' => 1,
'position' => 0,
'left' => 2,
'right' => 9999, // just a guess, will need updated later
'level' => 1,
'title' => 'Group',
);
echo "<br>";
print_r($rows[1]);
// next ID to be used
$id = 3;
// keep track of code => ID correspondence
$map = array();
// parse data
for ($i = 1, $c = count($data[0]); $i < $c; ++$i) {
// save ID in the map
$map[$data[0][$i]] = $id;
// initialize the current row
$row = array(
'id' => $id,
'parent_id' => 1,
'position' => 0,
'left' => 0,
'right' => 0,
'level' => 1,
'title' => $data[1][$i],
);
// if the code is multiple of 100
if ($data[0][$i] % 100 == 0) {
$row['parent_id'] = 2;
$row['level'] = 2;
$row['position'] = (floor($data[0][$i] / 100)) - 1;
} else {
// get parent id from map
$row['parent_id'] = $map[floor($data[0][$i] / 100) * 100];
$row['level'] = 3;
$row['position'] = $data[0][$i] % 100;
}
// add the row
$rows[] = $row;
++$id;
echo "<br>";
print_r($row);
}
Given your $data array, you could parse it like this:
// this will contain all the rows to be inserted in your DB
$rows = array();
// insert ROOT row
$rows[0] = array(
'id' => 1,
'parent_id' => 0,
'position' => 0,
'level' => 0,
'left' => 1,
'right' => 10000,
'title' => 'ROOT',
);
// insert group row
$rows[1] = array(
'id' => 2,
'parent_id' => 1,
'position' => 0,
'level' => 1,
'left' => 2,
'right' => 9999,
'title' => 'Group',
);
// keep trace of code => ID correspondence
$map = array();
// next ID to be used
$id = 3;
// keep father => sons relationship
$tree = array();
// keep trace of code => row index correspondence
$indexes = array();
// next row index
$index = 2;
// parse your data
for ($i = 1, $c = count($data[0]); $i < $c; ++$i) {
// current code
$code = $data[0][$i];
// save ID in the map
$map[$code] = $id;
// update the indexes map
$indexes[$code] = $index;
// prepare the current row
$row = array(
'id' => $id,
'title' => $data[1][$i],
)
// get the value of code mod 100
$mod = $code % 100;
// if the code is multiple of 100
if ($mod == 0) {
// the parent_id is 2
$row['parent_id'] = 2;
// it is level two
$row['level'] = 2;
// compute position
$row['position'] = floor($code / 100) - 1;
}
else {
// get the parent code
$parent = floor($code / 100) * 100;
// get parent id from map using parent code
$row['parent_id'] = $map[$parent];
// it is level three
$row['level'] = 3;
// save position
$row['position'] = $mod;
// save in relationship tree
$tree[$parent][] = $code;
}
// add the row
$rows[$index] = $row;
// prepare next id
++$id;
// update row index
++$index;
}
// sort the relationship tree base on the parent code (key)
ksort($tree, SORT_NUMERIC);
// next left value
$left = 3;
// now, using the relationship tree, assign left and right
foreach ($tree as $parent => $sons) {
// calculate parent left value
$parentLeft = $left;
// prepare next left value
++$left;
// to be sure that the sons are in order
sort($sons, SORT_NUMERIC);
// assign values to sons
foreach ($sons as $son) {
// index in the rows array
$index = $indexes[$son];
// set left value
$rows[$index]['left'] = $left;
// set right value
$rows[$index]['right'] = $left + 1;
// increment left value
$left += 2;
}
// calculate parent right value
$parentRight = $left;
// prepare next left value
++$left;
// index of parent in the rows array
$index = $indexes[$parent];
// set the values
$rows[$index]['left'] = $parentLeft;
$rows[$index]['right'] = $parentRight;
}
// update group row right value
$rows[1]['right'] = $left;
// prepare next left value
++$left;
// update root row right value
$rows[0]['right'] = $left;
At this point, you can insert all the rows one at a time.
EDIT: now the script should handle all the required values correctly.
I would use Doctrine2 with a Nested Set Extension. You could use a nice and convenient API and don't have to worry about the nested set implementation:
See
http://www.gediminasm.org/article/tree-nestedset-behavior-extension-for-doctrine-2
or http://wildlyinaccurate.com/simple-nested-sets-in-doctrine-2
There are several extensions on github. Actually, i don't know which one is best.
https://github.com/l3pp4rd/DoctrineExtensions
https://github.com/guilhermeblanco/Doctrine2-Hierarchical-Structural-Behavior
https://github.com/blt04/doctrine2-nestedset
List item
If your data is flat, you could parse for keywords like 'Unit' or 'Task' to arrange your elements to the needed hierarchical order.

Calculate a rough estimate for shipping box size

I'm trying to find the best way to calculate the box size needed for shipping.
I have 3 shipping containers with different sizes. I have the product's width, length, depth, and mass defined in the database.
I would like to know how to find the smallest amount of boxes needed to ship, and also the smallest dimensions of those boxes given the number of items in the cart.
My current 'idea' is to find the maximum width of the entire products array, the select a box according to it, and then split the order as needed... this doesn't seem like it would work.
My Box sizes are:
- 8 x 6 x 6 = 228 cubic inches
- 10 x 8 x 8 = 640 cubic inches
- 12.5 x 12.5 x 12.5 = 1953.125 cubic inches
A product is defined as such:
[Product] => Array
(
[STOCK_CODE] => 010003
[Product_Slug] => GABA_010003
[ItemName] => GABA
[WHOLESALE_PRICE] => 17.47
[RETAIL_PRICE] => 24.95
[Brand] =>
[ProductLine] =>
[image_name] => 705077000440
[MASS] => 0.313
[Height] => 4.625
[Width] => 2.375
[Depth] => 2.375
[cubic_inches] => 26.087890625
)
I've looked into knapsack problem, packing problem, etc and can't find a way to do this. Any help would be GREAT.
function shipping(){
$this->CartProduct->unbindModel(
array('belongsTo' => array('User'))
);
//find all cart products by current logged in user
$cartItems = $this->CartProduct->find('all', array('conditions' => array('CartProduct.user_id' => $this->Auth->user('id'))));
$i = 0;
//get the max width, height, depth
$maxHeight = 0;
$maxWidth = 0;
$maxDepth = 0;
foreach($cartItems as $c){
$cartItems[$i]['Product']['cubic_inches'] = $c['Product']['Height'] * $c['Product']['Width'] * $c['Product']['Depth'];
$cartItems[$i]['CartProduct']['total_cubic_inches'] = ($c['Product']['Height'] * $c['Product']['Width'] * $c['Product']['Depth']) * $c['CartProduct']['qty'];
if($c['Product']['Height'] > $maxHeight)
{
$maxHeight = $c['Product']['Height'];
}
if($c['Product']['Width'] > $maxWidth)
{
$maxWidth = $c['Product']['Width'];
}
if($c['Product']['Depth'] > $maxDepth)
{
$maxDepth = $c['Product']['Depth'];
}
$i++;
}
//possible containers
//8 x 6 x 6 = 228 ci
//10 x 8 x 8 = 640 ci
//12.5 x 12.5 x 12.5 = 1953.125
$possibleContainers = array(
1 => array(
'Height' => 8,
'Width' => 6,
'Depth' => 6,
'Cubic' => 228),
2 => array(
'Height' => 10,
'Width' => 8,
'Depth' => 8,
'Cubic' => 640),
3 => array(
'Height' => 12.5,
'Width' => 12.5,
'Depth' => 12.5,
'Cubic' => 1953.125)
);
$max = array(
'Height' => $maxHeight,
'Width' => $maxWidth,
'Depth' => $maxDepth,
);
pr($cartItems);
pr($possibleContainers);
die();
}
As for getting a optimal answer, that's NP-Hard... http://en.wikipedia.org/wiki/Bin_packing_problem
The greedy algorithm shown on Wikipedia, while it can be quite far off, might actually do for your case.
However as an estimate you could just sum up the volumes of the items and then apply a inefficiency factor and then use the smallest box(s) you can.
Alternately you could sort the items into decreasing volume and then see how much you can get into the current set of boxes, creating a new box when you can't fit the item in. Not sure how you would handle different box sizes though. You could also have a case where it changes the box size rather than creating a new box.
Food for thought.
Here is a low tech but possible solution:
We just ran into the same issue. I decided to take our box sizes and then give each product a percentage for how much space it took in each box size. Our products are free form and can be squished a bit so if yours are absolute in size you may need to reduce the percentages to account for products being put in the box at different angles ect... Also for us we are able to always put things in the boxes as the same angle to each other so this also helps make the below method work better.
This assumes there are 3 box sizes:
Product A
Box A = 48% (2 fit in a box)
Box B = 30% (3 fit in a box)
Box C = 12% (8 fit in a box)
Product B
Box A = 24%
Box B = 15%
Box C = 7%
Then just have your code add up those percentages for your cart items for box A, B and C ... obviously if any are below 100% everything should fit and if you start from top to bottom the first one to reach less than 100% will fit your products and be the smallest box. And if you run into any scenarios when packing that wont fit just slightly reduce the percentage you entered for that product.
For multiple box shipments you just need to decide what you want to do as for as combinations. The above works best for single box shipments but with some additional logic could easily work well for multiple box shipments.

Categories