1*3379af09SAndreas Gohr<?php 2*3379af09SAndreas Gohr 3*3379af09SAndreas Gohr/** 4*3379af09SAndreas Gohr * This file is part of PHP K-Means 5*3379af09SAndreas Gohr * 6*3379af09SAndreas Gohr * Copyright (c) 2014 Benjamin Delespierre 7*3379af09SAndreas Gohr * 8*3379af09SAndreas Gohr * Permission is hereby granted, free of charge, to any person obtaining a copy 9*3379af09SAndreas Gohr * of this software and associated documentation files (the "Software"), to deal 10*3379af09SAndreas Gohr * in the Software without restriction, including without limitation the rights 11*3379af09SAndreas Gohr * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12*3379af09SAndreas Gohr * copies of the Software, and to permit persons to whom the Software is furnished 13*3379af09SAndreas Gohr * to do so, subject to the following conditions: 14*3379af09SAndreas Gohr * 15*3379af09SAndreas Gohr * The above copyright notice and this permission notice shall be included in all 16*3379af09SAndreas Gohr * copies or substantial portions of the Software. 17*3379af09SAndreas Gohr * 18*3379af09SAndreas Gohr * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19*3379af09SAndreas Gohr * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20*3379af09SAndreas Gohr * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21*3379af09SAndreas Gohr * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22*3379af09SAndreas Gohr * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23*3379af09SAndreas Gohr * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24*3379af09SAndreas Gohr * THE SOFTWARE. 25*3379af09SAndreas Gohr */ 26*3379af09SAndreas Gohr 27*3379af09SAndreas Gohrnamespace KMeans; 28*3379af09SAndreas Gohr 29*3379af09SAndreas Gohrclass Point implements \ArrayAccess 30*3379af09SAndreas Gohr{ 31*3379af09SAndreas Gohr protected $space; 32*3379af09SAndreas Gohr protected $dimention; 33*3379af09SAndreas Gohr protected $coordinates; 34*3379af09SAndreas Gohr 35*3379af09SAndreas Gohr public function __construct(Space $space, array $coordinates) 36*3379af09SAndreas Gohr { 37*3379af09SAndreas Gohr $this->space = $space; 38*3379af09SAndreas Gohr $this->dimention = $space->getDimention(); 39*3379af09SAndreas Gohr $this->coordinates = $coordinates; 40*3379af09SAndreas Gohr } 41*3379af09SAndreas Gohr 42*3379af09SAndreas Gohr public function toArray(): array 43*3379af09SAndreas Gohr { 44*3379af09SAndreas Gohr return [ 45*3379af09SAndreas Gohr 'coordinates' => $this->coordinates, 46*3379af09SAndreas Gohr 'data' => isset($this->space[$this]) ? $this->space[$this] : null, 47*3379af09SAndreas Gohr ]; 48*3379af09SAndreas Gohr } 49*3379af09SAndreas Gohr 50*3379af09SAndreas Gohr public function getDistanceWith(self $point, bool $precise = true): float 51*3379af09SAndreas Gohr { 52*3379af09SAndreas Gohr if ($point->space !== $this->space) { 53*3379af09SAndreas Gohr throw new \LogicException("can only calculate distances from points in the same space"); 54*3379af09SAndreas Gohr } 55*3379af09SAndreas Gohr 56*3379af09SAndreas Gohr $distance = 0; 57*3379af09SAndreas Gohr for ($n = 0; $n < $this->dimention; $n++) { 58*3379af09SAndreas Gohr $difference = $this->coordinates[$n] - $point->coordinates[$n]; 59*3379af09SAndreas Gohr $distance += $difference * $difference; 60*3379af09SAndreas Gohr } 61*3379af09SAndreas Gohr 62*3379af09SAndreas Gohr return $precise ? sqrt($distance) : $distance; 63*3379af09SAndreas Gohr } 64*3379af09SAndreas Gohr 65*3379af09SAndreas Gohr public function getClosest(iterable $points): ?Point 66*3379af09SAndreas Gohr { 67*3379af09SAndreas Gohr $minDistance = PHP_INT_MAX; 68*3379af09SAndreas Gohr $minPoint = null; 69*3379af09SAndreas Gohr foreach ($points as $point) { 70*3379af09SAndreas Gohr $distance = $this->getDistanceWith($point, false); 71*3379af09SAndreas Gohr 72*3379af09SAndreas Gohr if ($distance < $minDistance) { 73*3379af09SAndreas Gohr $minDistance = $distance; 74*3379af09SAndreas Gohr $minPoint = $point; 75*3379af09SAndreas Gohr } 76*3379af09SAndreas Gohr } 77*3379af09SAndreas Gohr 78*3379af09SAndreas Gohr return $minPoint; 79*3379af09SAndreas Gohr } 80*3379af09SAndreas Gohr 81*3379af09SAndreas Gohr public function belongsTo(Space $space): bool 82*3379af09SAndreas Gohr { 83*3379af09SAndreas Gohr return $this->space === $space; 84*3379af09SAndreas Gohr } 85*3379af09SAndreas Gohr 86*3379af09SAndreas Gohr public function getSpace(): Space 87*3379af09SAndreas Gohr { 88*3379af09SAndreas Gohr return $this->space; 89*3379af09SAndreas Gohr } 90*3379af09SAndreas Gohr 91*3379af09SAndreas Gohr public function getCoordinates(): array 92*3379af09SAndreas Gohr { 93*3379af09SAndreas Gohr return $this->coordinates; 94*3379af09SAndreas Gohr } 95*3379af09SAndreas Gohr 96*3379af09SAndreas Gohr public function offsetExists($offset): bool 97*3379af09SAndreas Gohr { 98*3379af09SAndreas Gohr return isset($this->coordinates[$offset]); 99*3379af09SAndreas Gohr } 100*3379af09SAndreas Gohr 101*3379af09SAndreas Gohr public function offsetGet($offset) 102*3379af09SAndreas Gohr { 103*3379af09SAndreas Gohr return $this->coordinates[$offset]; 104*3379af09SAndreas Gohr } 105*3379af09SAndreas Gohr 106*3379af09SAndreas Gohr public function offsetSet($offset, $value): void 107*3379af09SAndreas Gohr { 108*3379af09SAndreas Gohr $this->coordinates[$offset] = $value; 109*3379af09SAndreas Gohr } 110*3379af09SAndreas Gohr 111*3379af09SAndreas Gohr public function offsetUnset($offset): void 112*3379af09SAndreas Gohr { 113*3379af09SAndreas Gohr unset($this->coordinates[$offset]); 114*3379af09SAndreas Gohr } 115*3379af09SAndreas Gohr} 116