Advent of code 2019/10
Ajax Direct

Answer 245ms

Part 1 : 292 Part 2 : 317
$grid = grid($input);
$pos  = $grid->searchAll("#");

// ==================================================
// > PART 1
// ==================================================
$directions = [];
foreach ($pos as $p) {
    $station = xy($p);
    foreach ($pos as $target) {
        if ($p == $target) continue;
        $directions[(string) $station][] = implode(";", $station->getVector($target)[0]);
    }
}
// Maximum number of unique directions from each asteroid
$visibles = set($directions)->map(fn ($v) => count(array_unique($v)));
$solution_1 = $visibles->max();

// ==================================================
// > PART 2
// ==================================================
$station = xy(explode(";", $visibles->search($solution_1)));
$targets = [];

// Make list of each asteroid in each possible direction
foreach ($pos as $target) {
    if ($target == $station->xy) continue;
    $direction = $station->getVector($target);
    $deg = rad2deg(atan2($direction[0][1], $direction[0][0]));
    // Just offset by 90 to start north, the clockwise and the -Y counter eachothers
    $deg = fmod($deg + 90 + 360, 360);

    $targets[$deg * 1000][$direction[1]] = $target;
}
// Fix order by numeric index, because PHP
$targets = array_map(function ($angle) {
    ksort($angle);
    return array_values($angle);
}, $targets);
ksort($targets);

$order = [];
while ($targets) foreach ($targets as $a=>$t) {
    $order[] = array_shift($targets[$a]);
    if (empty($targets[$a])) unset($targets[$a]);
}
$solution_2 = $order[199][0] * 100 + $order[199][1];