%PDF- %PDF-
| Direktori : /www/varak.net/nextcloud.varak.net/nextcloud/apps/photos/vendor/hexogen/kdtree/src/ |
| Current File : //www/varak.net/nextcloud.varak.net/nextcloud/apps/photos/vendor/hexogen/kdtree/src/KDTree.php |
<?php
namespace Hexogen\KDTree;
use Hexogen\KDTree\Interfaces\ItemInterface;
use Hexogen\KDTree\Interfaces\ItemListInterface;
use Hexogen\KDTree\Interfaces\KDTreeInterface;
use Hexogen\KDTree\Interfaces\NodeInterface;
class KDTree implements KDTreeInterface
{
/**
* @var NodeInterface
*/
private $root;
/**
* @var ItemInterface[]|null array of items or null after tree has been built
*/
private $items;
/**
* @var array
*/
private $maxBoundary;
/**
* @var array
*/
private $minBoundary;
/**
* @var int number of items in the tree
*/
private $length;
/**
* @var int
*/
private $dimensions;
/**
* KDTree constructor.
* @param ItemListInterface $itemList
*/
public function __construct(ItemListInterface $itemList)
{
$this->dimensions = $itemList->getDimensionCount();
$this->items = $itemList->getItems();
$this->length = count($this->items);
$this->setBoundaries($this->items);
$this->buildTree();
unset($this->items);
}
/**
* Get number of items in the tree
* @return int
*/
public function getItemCount(): int
{
return $this->length;
}
/**
* Get root node
* @return NodeInterface|null return node or null if there is no nodes in the tree
*/
public function getRoot(): ?NodeInterface
{
return $this->root;
}
/**
* Get lower boundary coordinate
* @return array
*/
public function getMinBoundary(): array
{
return $this->minBoundary;
}
/**
* Get upper boundary coordinate
* @return array
*/
public function getMaxBoundary(): array
{
return $this->maxBoundary;
}
/**
* Get number of dimensions in the tree
* @return int
*/
public function getDimensionCount(): int
{
return $this->dimensions;
}
/**
* @param int $lo
* @param int $hi
* @param int $d
* @return Node
*/
private function buildSubTree(int $lo, int $hi, int $d): Node
{
$mid = (int)(($hi - $lo) / 2) + $lo;
$item = $this->select($mid, $lo, $hi, $d);
$node = new Node($item);
$d++;
$d = $d % $this->dimensions;
if ($mid > $lo) {
$node->setLeft($this->buildSubTree($lo, $mid - 1, $d));
}
if ($mid < $hi) {
$node->setRight($this->buildSubTree($mid + 1, $hi, $d));
}
return $node;
}
private function exch(int $i, int $j)
{
$tmp = $this->items[$i];
$this->items[$i] = $this->items[$j];
$this->items[$j] = $tmp;
}
/**
* @param int $k
* @param int $lo
* @param int $hi
* @param int $d
* @return ItemInterface
*/
private function select(int $k, int $lo, int $hi, int $d)
{
while ($hi > $lo) {
$j = $this->partition($lo, $hi, $d);
if ($j > $k) {
$hi = $j - 1;
} elseif ($j < $k) {
$lo = $j + 1;
} else {
return $this->items[$k];
}
}
return $this->items[$k];
}
/**
* @param int $lo
* @param int $hi
* @param int $d
* @return int
*/
private function partition(int $lo, int $hi, int $d)
{
$i = $lo;
$j = $hi + 1;
$v = $this->items[$lo];
$val = $v->getNthDimension($d);
do {
while ($this->items[++$i]->getNthDimension($d) < $val && $i != $hi) {
}
while ($this->items[--$j]->getNthDimension($d) > $val) {
}
if ($i < $j) {
$this->exch($i, $j);
}
} while ($i < $j);
$this->exch($lo, $j);
return $j;
}
/**
* Set boundaries for given item list
* @param ItemInterface[] $items
*/
private function setBoundaries(array $items)
{
$this->maxBoundary = [];
$this->minBoundary = [];
for ($i = 0; $i < $this->dimensions; $i++) {
$this->maxBoundary[$i] = -INF;
$this->minBoundary[$i] = INF;
}
foreach ($items as $item) {
for ($i = 0; $i < $this->dimensions; $i++) {
$this->maxBoundary[$i] = max($this->maxBoundary[$i], $item->getNthDimension($i));
$this->minBoundary[$i] = min($this->minBoundary[$i], $item->getNthDimension($i));
}
}
}
/**
* Build kd tree
*/
private function buildTree()
{
if ($this->length > 0) {
$hi = $this->length - 1;
$mid = (int)($hi / 2);
$item = $this->select($mid, 0, $hi, 0);
$this->root = new Node($item);
$nextDimension = 1 % $this->dimensions;
if ($mid > 0) {
$this->root->setLeft($this->buildSubTree(0, $mid - 1, $nextDimension));
}
if ($mid < $hi) {
$this->root->setRight($this->buildSubTree($mid + 1, $hi, $nextDimension));
}
}
}
}