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