1aca28033SGreg Roach<?php 2aca28033SGreg Roach/** 3aca28033SGreg Roach * webtrees: online genealogy 4aca28033SGreg Roach * Copyright (C) 2019 webtrees development team 5aca28033SGreg Roach * This program is free software: you can redistribute it and/or modify 6aca28033SGreg Roach * it under the terms of the GNU General Public License as published by 7aca28033SGreg Roach * the Free Software Foundation, either version 3 of the License, or 8aca28033SGreg Roach * (at your option) any later version. 9aca28033SGreg Roach * This program is distributed in the hope that it will be useful, 10aca28033SGreg Roach * but WITHOUT ANY WARRANTY; without even the implied warranty of 11aca28033SGreg Roach * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12aca28033SGreg Roach * GNU General Public License for more details. 13aca28033SGreg Roach * You should have received a copy of the GNU General Public License 14aca28033SGreg Roach * along with this program. If not, see <http://www.gnu.org/licenses/>. 15aca28033SGreg Roach */ 16aca28033SGreg Roachdeclare(strict_types=1); 17aca28033SGreg Roach 18aca28033SGreg Roachnamespace Fisharebest\Webtrees\Services; 19aca28033SGreg Roach 20aca28033SGreg Roachuse Fisharebest\Webtrees\Family; 21aca28033SGreg Roachuse Fisharebest\Webtrees\Individual; 22aca28033SGreg Roachuse Illuminate\Support\Collection; 23aca28033SGreg Roach 24aca28033SGreg Roach/** 25aca28033SGreg Roach * Find ancestors, descendants, cousins, etc for drawing charts. 26aca28033SGreg Roach */ 27aca28033SGreg Roachclass ChartService 28aca28033SGreg Roach{ 29aca28033SGreg Roach /** 30aca28033SGreg Roach * Find the ancestors of an individual, indexed by their Sosa-Stradonitz number. 31aca28033SGreg Roach * 32aca28033SGreg Roach * @param Individual $individual Start with this individual 33aca28033SGreg Roach * @param int $generations Fetch this number of generations 34aca28033SGreg Roach * 35aca28033SGreg Roach * @return Collection|Individual[] 36aca28033SGreg Roach */ 37aca28033SGreg Roach public function sosaStradonitzAncestors(Individual $individual, int $generations): Collection 38aca28033SGreg Roach { 39aca28033SGreg Roach $ancestors = [1 => $individual]; 40aca28033SGreg Roach 41aca28033SGreg Roach $queue = [1]; 42aca28033SGreg Roach 43aca28033SGreg Roach $max = 2 ** ($generations - 1); 44aca28033SGreg Roach 45aca28033SGreg Roach while (!empty($queue)) { 46aca28033SGreg Roach $sosa_stradonitz_number = array_shift($queue); 47aca28033SGreg Roach 48aca28033SGreg Roach if ($sosa_stradonitz_number >= $max) { 49aca28033SGreg Roach break; 50aca28033SGreg Roach } 51aca28033SGreg Roach 52aca28033SGreg Roach $family = $ancestors[$sosa_stradonitz_number]->getPrimaryChildFamily(); 53aca28033SGreg Roach 54aca28033SGreg Roach if ($family instanceof Family) { 55aca28033SGreg Roach if ($family->getHusband() instanceof Individual) { 56aca28033SGreg Roach $ancestors[$sosa_stradonitz_number * 2] = $family->getHusband(); 57aca28033SGreg Roach $queue[] = $sosa_stradonitz_number * 2; 58aca28033SGreg Roach } 59aca28033SGreg Roach 60aca28033SGreg Roach if ($family->getWife() instanceof Individual) { 61aca28033SGreg Roach $ancestors[$sosa_stradonitz_number * 2 + 1] = $family->getWife(); 62aca28033SGreg Roach $queue[] = $sosa_stradonitz_number * 2 + 1; 63aca28033SGreg Roach } 64aca28033SGreg Roach } 65aca28033SGreg Roach } 66aca28033SGreg Roach 67aca28033SGreg Roach return new Collection($ancestors); 68aca28033SGreg Roach } 69*b8e79c89SGreg Roach 70*b8e79c89SGreg Roach /** 71*b8e79c89SGreg Roach * Find the descendants of an individual. 72*b8e79c89SGreg Roach * 73*b8e79c89SGreg Roach * @param Individual $individual Start with this individual 74*b8e79c89SGreg Roach * @param int $generations Fetch this number of generations 75*b8e79c89SGreg Roach * 76*b8e79c89SGreg Roach * @return Collection|Individual[] 77*b8e79c89SGreg Roach */ 78*b8e79c89SGreg Roach public function descendants(Individual $individual, int $generations): Collection 79*b8e79c89SGreg Roach { 80*b8e79c89SGreg Roach $descendants = new Collection([$individual]); 81*b8e79c89SGreg Roach 82*b8e79c89SGreg Roach if ($generations > 0) { 83*b8e79c89SGreg Roach foreach ($individual->getSpouseFamilies() as $family) { 84*b8e79c89SGreg Roach foreach ($family->getChildren() as $child) { 85*b8e79c89SGreg Roach $descendants = $descendants->merge($this->descendants($child, $generations - 1)); 86*b8e79c89SGreg Roach } 87*b8e79c89SGreg Roach } 88*b8e79c89SGreg Roach } 89*b8e79c89SGreg Roach 90*b8e79c89SGreg Roach return $descendants; 91*b8e79c89SGreg Roach } 92*b8e79c89SGreg Roach 93*b8e79c89SGreg Roach /** 94*b8e79c89SGreg Roach * Find the descendants of an individual. 95*b8e79c89SGreg Roach * 96*b8e79c89SGreg Roach * @param Individual $individual Start with this individual 97*b8e79c89SGreg Roach * @param int $generations Fetch this number of generations 98*b8e79c89SGreg Roach * 99*b8e79c89SGreg Roach * @return Collection|Family[] 100*b8e79c89SGreg Roach */ 101*b8e79c89SGreg Roach public function descendantFamilies(Individual $individual, int $generations): Collection 102*b8e79c89SGreg Roach { 103*b8e79c89SGreg Roach $descendants = new Collection($individual->getSpouseFamilies()); 104*b8e79c89SGreg Roach 105*b8e79c89SGreg Roach if ($generations > 0) { 106*b8e79c89SGreg Roach foreach ($descendants as $family) { 107*b8e79c89SGreg Roach foreach ($family->getChildren() as $child) { 108*b8e79c89SGreg Roach $descendants = $descendants->merge($this->descendantFamilies($child, $generations - 1)); 109*b8e79c89SGreg Roach } 110*b8e79c89SGreg Roach } 111*b8e79c89SGreg Roach } 112*b8e79c89SGreg Roach 113*b8e79c89SGreg Roach return $descendants; 114*b8e79c89SGreg Roach } 115aca28033SGreg Roach} 116