. */ declare(strict_types=1); namespace Fisharebest\Webtrees\Services; use Fisharebest\Webtrees\Family; use Fisharebest\Webtrees\Individual; use Illuminate\Support\Collection; /** * Find ancestors, descendants, cousins, etc for drawing charts. */ class ChartService { /** * Find the ancestors of an individual, indexed by their Sosa-Stradonitz number. * * @param Individual $individual Start with this individual * @param int $generations Fetch this number of generations * * @return Collection|Individual[] */ public function sosaStradonitzAncestors(Individual $individual, int $generations): Collection { $ancestors = [1 => $individual]; $queue = [1]; $max = 2 ** ($generations - 1); while (!empty($queue)) { $sosa_stradonitz_number = array_shift($queue); if ($sosa_stradonitz_number >= $max) { break; } $family = $ancestors[$sosa_stradonitz_number]->getPrimaryChildFamily(); if ($family instanceof Family) { if ($family->getHusband() instanceof Individual) { $ancestors[$sosa_stradonitz_number * 2] = $family->getHusband(); $queue[] = $sosa_stradonitz_number * 2; } if ($family->getWife() instanceof Individual) { $ancestors[$sosa_stradonitz_number * 2 + 1] = $family->getWife(); $queue[] = $sosa_stradonitz_number * 2 + 1; } } } return new Collection($ancestors); } /** * Find the descendants of an individual. * * @param Individual $individual Start with this individual * @param int $generations Fetch this number of generations * * @return Collection|Individual[] */ public function descendants(Individual $individual, int $generations): Collection { $descendants = new Collection([$individual]); if ($generations > 0) { foreach ($individual->getSpouseFamilies() as $family) { foreach ($family->getChildren() as $child) { $descendants = $descendants->merge($this->descendants($child, $generations - 1)); } } } return $descendants; } /** * Find the descendants of an individual. * * @param Individual $individual Start with this individual * @param int $generations Fetch this number of generations * * @return Collection|Family[] */ public function descendantFamilies(Individual $individual, int $generations): Collection { $descendants = new Collection($individual->getSpouseFamilies()); if ($generations > 0) { foreach ($descendants as $family) { foreach ($family->getChildren() as $child) { $descendants = $descendants->merge($this->descendantFamilies($child, $generations - 1)); } } } return $descendants; } }