xref: /webtrees/app/Services/ChartService.php (revision 39ca88ba08cefcfcaf891abfcf748f9c808eb326)
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
52*39ca88baSGreg Roach            $family = $ancestors[$sosa_stradonitz_number]->primaryChildFamily();
53aca28033SGreg Roach
54aca28033SGreg Roach            if ($family instanceof Family) {
55*39ca88baSGreg Roach                if ($family->husband() instanceof Individual) {
56*39ca88baSGreg Roach                    $ancestors[$sosa_stradonitz_number * 2] = $family->husband();
57aca28033SGreg Roach                    $queue[] = $sosa_stradonitz_number * 2;
58aca28033SGreg Roach                }
59aca28033SGreg Roach
60*39ca88baSGreg Roach                if ($family->wife() instanceof Individual) {
61*39ca88baSGreg Roach                    $ancestors[$sosa_stradonitz_number * 2 + 1] = $family->wife();
62aca28033SGreg Roach                    $queue[] = $sosa_stradonitz_number * 2 + 1;
63aca28033SGreg Roach                }
64aca28033SGreg Roach            }
65aca28033SGreg Roach        }
66aca28033SGreg Roach
67aca28033SGreg Roach        return new Collection($ancestors);
68aca28033SGreg Roach    }
69b8e79c89SGreg Roach
70b8e79c89SGreg Roach    /**
71b8e79c89SGreg Roach     * Find the descendants of an individual.
72b8e79c89SGreg Roach     *
73b8e79c89SGreg Roach     * @param Individual $individual  Start with this individual
74b8e79c89SGreg Roach     * @param int        $generations Fetch this number of generations
75b8e79c89SGreg Roach     *
76b8e79c89SGreg Roach     * @return Collection|Individual[]
77b8e79c89SGreg Roach     */
78b8e79c89SGreg Roach    public function descendants(Individual $individual, int $generations): Collection
79b8e79c89SGreg Roach    {
80b8e79c89SGreg Roach        $descendants = new Collection([$individual]);
81b8e79c89SGreg Roach
82b8e79c89SGreg Roach        if ($generations > 0) {
83*39ca88baSGreg Roach            foreach ($individual->spouseFamilies() as $family) {
84*39ca88baSGreg Roach                foreach ($family->children() as $child) {
85b8e79c89SGreg Roach                    $descendants = $descendants->merge($this->descendants($child, $generations - 1));
86b8e79c89SGreg Roach                }
87b8e79c89SGreg Roach            }
88b8e79c89SGreg Roach        }
89b8e79c89SGreg Roach
90b8e79c89SGreg Roach        return $descendants;
91b8e79c89SGreg Roach    }
92b8e79c89SGreg Roach
93b8e79c89SGreg Roach    /**
94b8e79c89SGreg Roach     * Find the descendants of an individual.
95b8e79c89SGreg Roach     *
96b8e79c89SGreg Roach     * @param Individual $individual  Start with this individual
97b8e79c89SGreg Roach     * @param int        $generations Fetch this number of generations
98b8e79c89SGreg Roach     *
99b8e79c89SGreg Roach     * @return Collection|Family[]
100b8e79c89SGreg Roach     */
101b8e79c89SGreg Roach    public function descendantFamilies(Individual $individual, int $generations): Collection
102b8e79c89SGreg Roach    {
103*39ca88baSGreg Roach        $descendants = new Collection($individual->spouseFamilies());
104b8e79c89SGreg Roach
105b8e79c89SGreg Roach        if ($generations > 0) {
106b8e79c89SGreg Roach            foreach ($descendants as $family) {
107*39ca88baSGreg Roach                foreach ($family->children() as $child) {
108b8e79c89SGreg Roach                    $descendants = $descendants->merge($this->descendantFamilies($child, $generations - 1));
109b8e79c89SGreg Roach                }
110b8e79c89SGreg Roach            }
111b8e79c89SGreg Roach        }
112b8e79c89SGreg Roach
113b8e79c89SGreg Roach        return $descendants;
114b8e79c89SGreg Roach    }
115aca28033SGreg Roach}
116