<?php
declare(strict_types=1);
namespace BinContainerPacking;
use BinContainerPacking\Handlers\IntersectionHandler;
use BinContainerPacking\Types\AxisType;
use BinContainerPacking\Types\PositionType;
use BinContainerPacking\Types\RotationCombinationType;
final class Bin implements \JsonSerializable
{
private $id;
private float $length;
private float $breadth;
private float $height;
private float $volume;
private float $weight;
private iterable $fittedItems;
private float $totalFittedVolume;
private float $totalFittedWeight;
public function __construct($id, float $length, float $height, float $breadth, float $weight)
{
$this->id = $id;
$this->length = $length;
$this->height = $height;
$this->breadth = $breadth;
$this->volume = (float)$this->length * $this->height * $this->breadth;
$this->weight = $weight;
$this->fittedItems = [];
$this->totalFittedVolume = 0;
$this->totalFittedWeight = 0;
}
public function getId()
{
return $this->id;
}
public function getLength(): float
{
return $this->length;
}
public function getHeight(): float
{
return $this->height;
}
public function getBreadth(): float
{
return $this->breadth;
}
public function getVolume(): float
{
return $this->volume;
}
public function getWeight(): float
{
return $this->weight;
}
public function getFittedItems(): iterable
{
return $this->fittedItems;
}
public function getIterableFittedItems(): \ArrayIterator
{
return new \ArrayIterator($this->fittedItems);
}
public function getTotalFittedVolume(): float
{
return $this->totalFittedVolume;
}
private function setFittedItems(Item $item): void
{
$this->fittedItems[] = $item;
$this->totalFittedVolume += $item->getVolume();
$this->totalFittedWeight += $item->getWeight();
}
public function putItems(array $items): bool
{
foreach ($items as $item) {
if (!$this->putItem($item)) {
return false;
}
}
return true;
}
public function putItem(Item $item): bool
{
$fitted = false;
$fittedItems = $this->getFittedItems();
if (count($fittedItems) === 0) {
if ($this->putItemPosition($item, PositionType::START_POSITION)) {
$fitted = true;
}
} else {
foreach (AxisType::ALL_AXIS as $axis) {
foreach ($fittedItems as $fittedItem) {
$pivot = PositionType::START_POSITION;
$dimension = $fittedItem->getDimension();
if ($axis === AxisType::LENGTH) {
$pivot = [
AxisType::LENGTH => $fittedItem->getPosition()[AxisType::LENGTH] + $dimension[AxisType::LENGTH],
AxisType::HEIGHT => $fittedItem->getPosition()[AxisType::HEIGHT],
AxisType::BREADTH => $fittedItem->getPosition()[AxisType::BREADTH]
];
} elseif ($axis === AxisType::HEIGHT) {
$pivot = [
AxisType::LENGTH => $fittedItem->getPosition()[AxisType::LENGTH],
AxisType::HEIGHT => $fittedItem->getPosition()[AxisType::HEIGHT] + $dimension[AxisType::HEIGHT],
AxisType::BREADTH => $fittedItem->getPosition()[AxisType::BREADTH]
];
} elseif ($axis === AxisType::BREADTH) {
$pivot = [
AxisType::LENGTH => $fittedItem->getPosition()[AxisType::LENGTH],
AxisType::HEIGHT => $fittedItem->getPosition()[AxisType::HEIGHT],
AxisType::BREADTH => $fittedItem->getPosition()[AxisType::BREADTH] + $dimension[AxisType::BREADTH]
];
}
if ($this->putItemPosition($item, $pivot)) {
$fitted = true;
break;
}
}
if ($fitted) {
break;
}
}
}
return $fitted;
}
private function putItemPosition(Item $item, array $position): bool
{
$fit = false;
$validItemPosition = $item->getPosition();
$item->setPosition($position);
foreach (RotationCombinationType::ALL_ROTATION_COMBINATION as $rotationType) {
$item->setRotationType($rotationType);
$dimension = $item->getDimension();
if (
$this->length < $position[AxisType::LENGTH] + $dimension[AxisType::LENGTH] ||
$this->height < $position[AxisType::HEIGHT] + $dimension[AxisType::HEIGHT] ||
$this->breadth < $position[AxisType::BREADTH] + $dimension[AxisType::BREADTH]
) {
continue;
}
$fit = true;
foreach ($this->fittedItems as $fitted_item) {
if (IntersectionHandler::isIntersected($fitted_item, $item)) {
$fit = false;
break;
}
}
if ($fit) {
if (($this->totalFittedWeight + $item->getWeight()) > $this->weight) {
return false;
}
$this->setFittedItems($item);
}
if (!$fit) {
$item->setPosition($validItemPosition);
}
return $fit;
}
if (!$fit) {
$item->setPosition($validItemPosition);
}
return $fit;
}
public function jsonSerialize(): array
{
$vars = get_object_vars($this);
return $vars;
}
}