| 1 |  |  | <?php | 
            
                                                                                                            
                            
            
                                    
            
            
                | 2 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 3 |  |  | namespace Hexogen\KDTree; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 4 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 5 |  |  | class FileTreePersister implements TreePersisterInterface | 
            
                                                                                                            
                            
            
                                    
            
            
                | 6 |  |  | { | 
            
                                                                                                            
                            
            
                                    
            
            
                | 7 |  |  |     /** | 
            
                                                                                                            
                            
            
                                    
            
            
                | 8 |  |  |      * @var string path to the file | 
            
                                                                                                            
                            
            
                                    
            
            
                | 9 |  |  |      */ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 10 |  |  |     private $path; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 11 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 12 |  |  |     /** | 
            
                                                                                                            
                            
            
                                    
            
            
                | 13 |  |  |      * @var resource file handler | 
            
                                                                                                            
                            
            
                                    
            
            
                | 14 |  |  |      */ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 15 |  |  |     private $handler; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 16 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 17 |  |  |     /** | 
            
                                                                                                            
                            
            
                                    
            
            
                | 18 |  |  |      * @var int | 
            
                                                                                                            
                            
            
                                    
            
            
                | 19 |  |  |      */ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 20 |  |  |     private $dimensions; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 21 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 22 |  |  |     /** | 
            
                                                                                                            
                            
            
                                    
            
            
                | 23 |  |  |      * @var int | 
            
                                                                                                            
                            
            
                                    
            
            
                | 24 |  |  |      */ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 25 |  |  |     private $nodeMemorySize; | 
            
                                                                                                            
                                                                
            
                                    
            
            
                | 26 |  |  |  | 
            
                                                                        
                            
            
                                    
            
            
                | 27 | 3 |  |     public function __construct(string $path) | 
            
                                                                        
                            
            
                                    
            
            
                | 28 |  |  |     { | 
            
                                                                        
                            
            
                                    
            
            
                | 29 | 3 |  |         $this->path = $path; | 
            
                                                                        
                            
            
                                    
            
            
                | 30 | 3 |  |     } | 
            
                                                                                                            
                            
            
                                    
            
            
                | 31 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 32 |  |  |     /** | 
            
                                                                                                            
                            
            
                                    
            
            
                | 33 |  |  |      * @param KDTreeInterface $tree | 
            
                                                                                                            
                            
            
                                    
            
            
                | 34 |  |  |      * @param string $identifier that identifies persisted tree(may be a filename, database name etc.) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 35 |  |  |      * @return mixed | 
            
                                                                                                            
                            
            
                                    
            
            
                | 36 |  |  |      */ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 37 | 3 |  |     public function convert(KDTreeInterface $tree, string $identifier) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 38 |  |  |     { | 
            
                                                                                                            
                            
            
                                    
            
            
                | 39 | 3 |  |         $this->initTree($identifier); | 
            
                                                                                                            
                            
            
                                    
            
            
                | 40 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 41 | 3 |  |         $this->dimensions = $tree->getDimensionCount(); | 
            
                                                                                                            
                            
            
                                    
            
            
                | 42 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 43 | 3 |  |         $this->calculateNodeSize(); | 
            
                                                                                                            
                            
            
                                    
            
            
                | 44 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 45 | 3 |  |         $this->specifyNumberOfDimensions(); | 
            
                                                                                                            
                            
            
                                    
            
            
                | 46 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 47 | 3 |  |         $this->specifyNumberOfItems($tree); | 
            
                                                                                                            
                            
            
                                    
            
            
                | 48 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 49 | 3 |  |         $upperBound = $tree->getMaxBoundary(); | 
            
                                                                                                            
                            
            
                                    
            
            
                | 50 | 3 |  |         $this->writeCoordinate($upperBound); | 
            
                                                                                                            
                            
            
                                    
            
            
                | 51 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 52 | 3 |  |         $lowerBound = $tree->getMinBoundary(); | 
            
                                                                                                            
                            
            
                                    
            
            
                | 53 | 3 |  |         $this->writeCoordinate($lowerBound); | 
            
                                                                                                            
                            
            
                                    
            
            
                | 54 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 55 | 3 |  |         $this->writeNode($tree->getRoot()); | 
            
                                                                                                            
                            
            
                                    
            
            
                | 56 | 3 |  |         fclose($this->handler); | 
            
                                                                                                            
                            
            
                                    
            
            
                | 57 | 3 |  |     } | 
            
                                                                                                            
                            
            
                                    
            
            
                | 58 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 59 |  |  |     /** | 
            
                                                                                                            
                            
            
                                    
            
            
                | 60 |  |  |      * @param NodeInterface $node | 
            
                                                                                                            
                            
            
                                    
            
            
                | 61 |  |  |      */ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 62 | 3 |  |     private function writeNode(NodeInterface $node) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 63 |  |  |     { | 
            
                                                                                                            
                            
            
                                    
            
            
                | 64 | 3 |  |         $position = ftell($this->handler); | 
            
                                                                                                            
                            
            
                                    
            
            
                | 65 | 3 |  |         $item = $node->getItem(); | 
            
                                                                                                            
                            
            
                                    
            
            
                | 66 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 67 | 3 |  |         $this->writeItemId($item); | 
            
                                                                                                            
                            
            
                                    
            
            
                | 68 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 69 | 3 |  |         $dataChunk = pack('V', 0); // left position currently unknown so it equal 0/null | 
            
                                                                                                            
                            
            
                                    
            
            
                | 70 | 3 |  |         fwrite($this->handler, $dataChunk); | 
            
                                                                                                            
                            
            
                                    
            
            
                | 71 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 72 | 3 |  |         $rightNode = $node->getRight(); | 
            
                                                                                                            
                            
            
                                    
            
            
                | 73 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 74 | 3 |  |         $rightPosition = 0; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 75 | 3 |  |         if ($rightNode) { | 
            
                                                                                                            
                            
            
                                    
            
            
                | 76 | 3 |  |             $rightPosition = $position + $this->nodeMemorySize; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 77 |  |  |         } | 
            
                                                                                                            
                            
            
                                    
            
            
                | 78 | 3 |  |         $dataChunk = pack('V', $rightPosition); | 
            
                                                                                                            
                            
            
                                    
            
            
                | 79 | 3 |  |         fwrite($this->handler, $dataChunk); | 
            
                                                                                                            
                            
            
                                    
            
            
                | 80 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 81 | 3 |  |         $this->saveItemCoordinate($item); | 
            
                                                                                                            
                            
            
                                    
            
            
                | 82 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 83 | 3 |  |         if ($rightNode) { | 
            
                                                                                                            
                            
            
                                    
            
            
                | 84 | 3 |  |             $this->writeNode($rightNode); | 
            
                                                                                                            
                            
            
                                    
            
            
                | 85 |  |  |         } | 
            
                                                                                                            
                            
            
                                    
            
            
                | 86 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 87 | 3 |  |         $leftNode = $node->getLeft(); | 
            
                                                                                                            
                            
            
                                    
            
            
                | 88 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 89 | 3 |  |         if ($leftNode == null) { | 
            
                                                                                                            
                            
            
                                    
            
            
                | 90 | 3 |  |             return; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 91 |  |  |         } | 
            
                                                                                                            
                            
            
                                    
            
            
                | 92 | 3 |  |         $this->persistLeftLink($position); | 
            
                                                                                                            
                            
            
                                    
            
            
                | 93 | 3 |  |         $this->writeNode($leftNode); | 
            
                                                                                                            
                            
            
                                    
            
            
                | 94 | 3 |  |     } | 
            
                                                                                                            
                            
            
                                    
            
            
                | 95 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 96 |  |  |     /** | 
            
                                                                                                            
                            
            
                                    
            
            
                | 97 |  |  |      * @param array $coordinate | 
            
                                                                                                            
                            
            
                                    
            
            
                | 98 |  |  |      */ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 99 | 3 |  |     private function writeCoordinate(array $coordinate) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 100 |  |  |     { | 
            
                                                                                                            
                            
            
                                    
            
            
                | 101 | 3 |  |         $dataChunk = pack('d'.$this->dimensions, ...$coordinate); | 
            
                                                                                                            
                            
            
                                    
            
            
                | 102 | 3 |  |         fwrite($this->handler, $dataChunk); | 
            
                                                                                                            
                            
            
                                    
            
            
                | 103 | 3 |  |     } | 
            
                                                                                                            
                            
            
                                    
            
            
                | 104 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 105 |  |  |     /** | 
            
                                                                                                            
                            
            
                                    
            
            
                | 106 |  |  |      * @param string $identifier | 
            
                                                                                                            
                            
            
                                    
            
            
                | 107 |  |  |      */ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 108 | 3 |  |     private function initTree(string $identifier) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 109 |  |  |     { | 
            
                                                                                                            
                            
            
                                    
            
            
                | 110 | 3 |  |         $this->handler = fopen($this->path . '/' . $identifier, 'wb'); | 
            
                                                                                                            
                            
            
                                    
            
            
                | 111 | 3 |  |     } | 
            
                                                                                                            
                            
            
                                    
            
            
                | 112 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 113 |  |  |     /** | 
            
                                                                                                            
                            
            
                                    
            
            
                | 114 |  |  |      * Calculate memory size in file needed for single node | 
            
                                                                                                            
                            
            
                                    
            
            
                | 115 |  |  |      */ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 116 | 3 |  |     private function calculateNodeSize() | 
            
                                                                                                            
                            
            
                                    
            
            
                | 117 |  |  |     { | 
            
                                                                                                            
                            
            
                                    
            
            
                | 118 | 3 |  |         $this->nodeMemorySize = $this->dimensions * 8 + 3 * 4; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 119 | 3 |  |     } | 
            
                                                                                                            
                            
            
                                    
            
            
                | 120 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 121 |  |  |     /** | 
            
                                                                                                            
                            
            
                                    
            
            
                | 122 |  |  |      * Specify number of dimensions according to file format | 
            
                                                                                                            
                            
            
                                    
            
            
                | 123 |  |  |      */ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 124 | 3 |  |     private function specifyNumberOfDimensions() | 
            
                                                                                                            
                            
            
                                    
            
            
                | 125 |  |  |     { | 
            
                                                                                                            
                            
            
                                    
            
            
                | 126 | 3 |  |         $dataChunk = pack('V', $this->dimensions); | 
            
                                                                                                            
                            
            
                                    
            
            
                | 127 | 3 |  |         fwrite($this->handler, $dataChunk); | 
            
                                                                                                            
                            
            
                                    
            
            
                | 128 | 3 |  |     } | 
            
                                                                                                            
                            
            
                                    
            
            
                | 129 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 130 |  |  |     /** | 
            
                                                                                                            
                            
            
                                    
            
            
                | 131 |  |  |      * @param KDTreeInterface $tree | 
            
                                                                                                            
                            
            
                                    
            
            
                | 132 |  |  |      */ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 133 | 3 |  |     private function specifyNumberOfItems(KDTreeInterface $tree) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 134 |  |  |     { | 
            
                                                                                                            
                            
            
                                    
            
            
                | 135 | 3 |  |         $itemCount = $tree->getItemCount(); | 
            
                                                                                                            
                            
            
                                    
            
            
                | 136 | 3 |  |         $dataChunk = pack('V', $itemCount); | 
            
                                                                                                            
                            
            
                                    
            
            
                | 137 | 3 |  |         fwrite($this->handler, $dataChunk); | 
            
                                                                                                            
                            
            
                                    
            
            
                | 138 | 3 |  |     } | 
            
                                                                                                            
                            
            
                                    
            
            
                | 139 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 140 |  |  |     /** | 
            
                                                                                                            
                            
            
                                    
            
            
                | 141 |  |  |      * @param $item | 
            
                                                                                                            
                            
            
                                    
            
            
                | 142 |  |  |      */ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 143 | 3 |  |     private function saveItemCoordinate(ItemInterface $item) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 144 |  |  |     { | 
            
                                                                                                            
                            
            
                                    
            
            
                | 145 | 3 |  |         $coordinate = []; | 
            
                                                                                                            
                            
            
                                    
            
            
                | 146 | 3 |  |         for ($i = 0; $i < $this->dimensions; $i++) { | 
            
                                                                                                            
                            
            
                                    
            
            
                | 147 | 3 |  |             $coordinate[] = $item->getNthDimension($i); | 
            
                                                                                                            
                            
            
                                    
            
            
                | 148 |  |  |         } | 
            
                                                                                                            
                            
            
                                    
            
            
                | 149 | 3 |  |         $this->writeCoordinate($coordinate); | 
            
                                                                                                            
                            
            
                                    
            
            
                | 150 | 3 |  |     } | 
            
                                                                                                            
                            
            
                                    
            
            
                | 151 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 152 |  |  |     /** | 
            
                                                                                                            
                            
            
                                    
            
            
                | 153 |  |  |      * Persist current position before writing left node | 
            
                                                                                                            
                            
            
                                    
            
            
                | 154 |  |  |      * @param $position | 
            
                                                                                                            
                            
            
                                    
            
            
                | 155 |  |  |      */ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 156 | 3 |  |     private function persistLeftLink($position) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 157 |  |  |     { | 
            
                                                                                                            
                            
            
                                    
            
            
                | 158 | 3 |  |         $leftPosition = ftell($this->handler); | 
            
                                                                                                            
                            
            
                                    
            
            
                | 159 | 3 |  |         fseek($this->handler, $position + 4); | 
            
                                                                                                            
                            
            
                                    
            
            
                | 160 | 3 |  |         $dataChunk = pack('V', $leftPosition); | 
            
                                                                                                            
                            
            
                                    
            
            
                | 161 | 3 |  |         fwrite($this->handler, $dataChunk); | 
            
                                                                                                            
                            
            
                                    
            
            
                | 162 | 3 |  |         fseek($this->handler, $leftPosition); | 
            
                                                                                                            
                            
            
                                    
            
            
                | 163 | 3 |  |     } | 
            
                                                                                                            
                            
            
                                    
            
            
                | 164 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 165 |  |  |     /** | 
            
                                                                                                            
                            
            
                                    
            
            
                | 166 |  |  |      * @param $item | 
            
                                                                                                            
                            
            
                                    
            
            
                | 167 |  |  |      */ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 168 | 3 |  |     private function writeItemId(ItemInterface $item) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 169 |  |  |     { | 
            
                                                                                                            
                            
            
                                    
            
            
                | 170 | 3 |  |         $itemId = $item->getId(); | 
            
                                                                                                            
                            
            
                                    
            
            
                | 171 | 3 |  |         $dataChunk = pack('V', $itemId); | 
            
                                                                                                            
                            
            
                                    
            
            
                | 172 | 3 |  |         fwrite($this->handler, $dataChunk); | 
            
                                                                                                            
                            
            
                                    
            
            
                | 173 | 3 |  |     } | 
            
                                                                                                            
                                                                
            
                                    
            
            
                | 174 |  |  | } | 
            
                                                        
            
                                    
            
            
                | 175 |  |  |  |