. */ 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 */ public function sosaStradonitzAncestors(Individual $individual, int $generations): Collection { $ancestors = [1 => $individual]; $queue = [1]; $max = 2 ** ($generations - 1); while ($queue !== []) { $sosa_stradonitz_number = array_shift($queue); if ($sosa_stradonitz_number >= $max) { break; } $family = $ancestors[$sosa_stradonitz_number]->childFamilies()->first(); if ($family instanceof Family) { if ($family->husband() instanceof Individual) { $ancestors[$sosa_stradonitz_number * 2] = $family->husband(); $queue[] = $sosa_stradonitz_number * 2; } if ($family->wife() instanceof Individual) { $ancestors[$sosa_stradonitz_number * 2 + 1] = $family->wife(); $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 */ public function descendants(Individual $individual, int $generations): Collection { $descendants = new Collection([$individual]); if ($generations > 0) { foreach ($individual->spouseFamilies() as $family) { foreach ($family->children() 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 */ public function descendantFamilies(Individual $individual, int $generations): Collection { $descendants = new Collection($individual->spouseFamilies()); if ($generations > 0) { foreach ($descendants as $family) { foreach ($family->children() as $child) { $descendants = $descendants->merge($this->descendantFamilies($child, $generations - 1)); } } } return $descendants; } }