members, function ($member) { return ($member instanceof Way) and ('outer' === $member->role) ; }); } public function getOuterWaysStartingWith(Point $point, ?Way $exclude = null): array { return array_filter($this->members, function ($member) use ($point, $exclude) { return ($member instanceof Way) and ('outer' === $member->role) and $point->isSame($member->getFirstPoint()) and ( is_null($exclude) or !$member->isSame($exclude) ) ; }); } public function getOuterWaysStopingWith(Point $point, ?Way $exclude = null): array { return array_filter($this->members, function ($member) use ($point, $exclude) { return ($member instanceof Way) and ('outer' === $member->role) and $point->isSame($member->getLastPoint()) and ( is_null($exclude) or !$member->isSame($exclude) ) ; }); } public function getOrderedOuterWays(): array { $orderedWays = []; $ways = $this->getOuterWays(); $currentWay = reset($ways); $veryFirstPoint = $currentWay->getFirstPoint(); $isDone = false; while (!$isDone) { $orderedWays[] = $currentWay; $nextWays = $this->getOuterWaysStartingWith($currentWay->getLastPoint(), $currentWay); assert(count($nextWays) <= 1); if (1 === count($nextWays)) { $nextWay = reset($nextWays); if ($veryFirstPoint->isSame($nextWay->getFirstPoint())) { break; } $currentWay = $nextWay; continue; } else { $nextWays = $this->getOuterWaysStopingWith($currentWay->getLastPoint(), $currentWay); assert(count($nextWays) <= 1); if (1 === count($nextWays)) { $nextWay = reset($nextWays); $nextWay->reversePoints(); if ($veryFirstPoint->isSame($nextWay->getFirstPoint())) { break; } $currentWay = $nextWay; continue; } else { $isDone = true; } } } return $orderedWays; } }