space = $space; $this->points = new SplObjectStorage(); } public function getPoints(): array { $points = []; foreach ($this->points as $point) { if ($point->label === null) { $points[] = $point->toArray(); } else { $points[$point->label] = $point->toArray(); } } return $points; } public function toArray(): array { return [ 'centroid' => parent::toArray(), 'points' => $this->getPoints(), ]; } public function attach(Point $point): Point { if ($point instanceof self) { throw new LogicException('Cannot attach a cluster to another'); } $this->points->attach($point); return $point; } public function detach(Point $point): Point { $this->points->detach($point); return $point; } public function attachAll(SplObjectStorage $points): void { $this->points->addAll($points); } public function detachAll(SplObjectStorage $points): void { $this->points->removeAll($points); } public function updateCentroid(): void { $count = count($this->points); if ($count === 0) { return; } $centroid = $this->space->newPoint(array_fill(0, $this->dimension, 0)); foreach ($this->points as $point) { for ($n = 0; $n < $this->dimension; ++$n) { $centroid->coordinates[$n] += $point->coordinates[$n]; } } for ($n = 0; $n < $this->dimension; ++$n) { $this->coordinates[$n] = $centroid->coordinates[$n] / $count; } } /** * @return Point[]|SplObjectStorage */ public function getIterator() { return $this->points; } public function count(): int { return count($this->points); } public function setCoordinates(array $newCoordinates): void { $this->coordinates = $newCoordinates; } }