xref: /webtrees/app/Services/ChartService.php (revision b8e79c89406e0602039fedb0df62a458bd29b350)
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