Files
f7cloud_client/apps/photos/vendor/hexogen/kdtree/src/FSTreePersister.php
T
2026-03-05 13:40:40 +00:00

184 lines
4.4 KiB
PHP

<?php
namespace Hexogen\KDTree;
use Hexogen\KDTree\Interfaces\ItemInterface;
use Hexogen\KDTree\Interfaces\KDTreeInterface;
use Hexogen\KDTree\Interfaces\NodeInterface;
use Hexogen\KDTree\Interfaces\TreePersisterInterface;
class FSTreePersister implements TreePersisterInterface
{
/**
* @var string path to the file
*/
private $path;
/**
* @var resource file handler
*/
private $handler;
/**
* @var int
*/
private $dimensions;
/**
* @var int
*/
private $nodeMemorySize;
public function __construct(string $path)
{
$this->path = $path;
}
/**
* @api
* @param KDTreeInterface $tree
* @param string $identifier that identifies persisted tree(may be a filename, database name etc.)
* @return mixed
*/
public function convert(KDTreeInterface $tree, string $identifier)
{
$this->initTree($identifier);
$this->dimensions = $tree->getDimensionCount();
$this->calculateNodeSize();
$this->specifyNumberOfDimensions();
$this->specifyNumberOfItems($tree);
$upperBound = $tree->getMaxBoundary();
$this->writeCoordinate($upperBound);
$lowerBound = $tree->getMinBoundary();
$this->writeCoordinate($lowerBound);
$root = $tree->getRoot();
if ($root) {
$this->writeNode($root);
}
fclose($this->handler);
}
/**
* @param NodeInterface $node
*/
private function writeNode(NodeInterface $node)
{
$position = ftell($this->handler);
$item = $node->getItem();
$this->writeItemId($item);
$dataChunk = pack('V', 0); // left position currently unknown so it equal 0/null
fwrite($this->handler, $dataChunk);
$rightNode = $node->getRight();
$rightPosition = 0;
if ($rightNode) {
$rightPosition = $position + $this->nodeMemorySize;
}
$dataChunk = pack('V', $rightPosition);
fwrite($this->handler, $dataChunk);
$this->saveItemCoordinate($item);
if ($rightNode) {
$this->writeNode($rightNode);
}
$leftNode = $node->getLeft();
if ($leftNode == null) {
return;
}
$this->persistLeftLink($position);
$this->writeNode($leftNode);
}
/**
* @param array $coordinate
*/
private function writeCoordinate(array $coordinate)
{
$dataChunk = pack('d'.$this->dimensions, ...$coordinate);
fwrite($this->handler, $dataChunk);
}
/**
* @param string $identifier
*/
private function initTree(string $identifier)
{
$this->handler = fopen($this->path . '/' . $identifier, 'wb');
}
/**
* Calculate memory size in file needed for single node
*/
private function calculateNodeSize()
{
$this->nodeMemorySize = 3 * FSKDTree::INT_LENGTH + $this->dimensions * FSKDTree::FLOAT_LENGTH;
}
/**
* Specify number of dimensions according to file format
*/
private function specifyNumberOfDimensions()
{
$dataChunk = pack('V', $this->dimensions);
fwrite($this->handler, $dataChunk);
}
/**
* @param KDTreeInterface $tree
*/
private function specifyNumberOfItems(KDTreeInterface $tree)
{
$itemCount = $tree->getItemCount();
$dataChunk = pack('V', $itemCount);
fwrite($this->handler, $dataChunk);
}
/**
* @param $item
*/
private function saveItemCoordinate(ItemInterface $item)
{
$coordinate = [];
for ($i = 0; $i < $this->dimensions; $i++) {
$coordinate[] = $item->getNthDimension($i);
}
$this->writeCoordinate($coordinate);
}
/**
* Persist current position before writing left node
* @param int $position
*/
private function persistLeftLink(int $position)
{
$leftPosition = ftell($this->handler);
fseek($this->handler, $position + FSKDTree::INT_LENGTH);
$dataChunk = pack('V', $leftPosition);
fwrite($this->handler, $dataChunk);
fseek($this->handler, $leftPosition);
}
/**
* @param $item
*/
private function writeItemId(ItemInterface $item)
{
$itemId = $item->getId();
$dataChunk = pack('V', $itemId);
fwrite($this->handler, $dataChunk);
}
}