bounds_max_z) / 40) * 40 + 40); } /** * Layout edge south of the city. */ public static function layoutMinZ(City $city): float { return (float) (floor(((float) $city->bounds_min_z) / 40) * 40 - 40); } /** * Full airports descriptor for the world payload. * * @return array{visit: array, sites: list>} */ public static function geometry(City $city): array { return [ 'visit' => [ 'half_width' => self::VISIT_HALF_WIDTH, 'min_z' => self::VISIT_MIN_Z, 'max_z' => self::VISIT_MAX_Z, ], 'sites' => [ self::northSite(self::layoutMaxZ($city)), self::southSite(self::layoutMinZ($city)), ], ]; } /** * Large airport south of the city (+Z): east-west runway. * * @return array */ private static function northSite(float $lz): array { // lz = 160 for the shipped bounds: runway at 350, apron at 285. $standZ = $lz + 135; return [ 'id' => 'sul', 'name' => 'Aeroporto City10 Sul', 'code' => 'CTS', 'runway' => [ 'center' => [0.0, $lz + 190], 'length' => 180.0, 'width' => 18.0, 'axis' => 'x', 'designators' => ['09', '27'], ], 'taxiways' => [ ['center' => [0.0, $lz + 160], 'length' => 170.0, 'width' => 10.0, 'axis' => 'x'], ['center' => [-80.0, $lz + 175], 'length' => 30.0, 'width' => 8.0, 'axis' => 'z'], ['center' => [80.0, $lz + 175], 'length' => 30.0, 'width' => 8.0, 'axis' => 'z'], ], 'apron' => ['center' => [0.0, $lz + 125], 'size' => [170.0, 60.0]], 'terminal' => ['center' => [-45.0, $lz + 105], 'size' => [80.0, 18.0]], 'hangars' => [ ['center' => [35.0, $lz + 106], 'size' => [26.0, 20.0]], ['center' => [65.0, $lz + 106], 'size' => [26.0, 20.0]], ], 'tower' => ['center' => [10.0, $lz + 118]], 'stands' => [ [-70.0, $standZ], [-35.0, $standZ], [0.0, $standZ], [35.0, $standZ], ], 'helipad' => ['center' => [-100.0, $lz + 165], 'radius' => 8.0], ]; } /** * Regional airport north of the city (-Z): north-south runway. * * @return array */ private static function southSite(float $lz): array { // lz = -160 for the shipped bounds: runway centre at -300. $cZ = $lz - 140; return [ 'id' => 'norte', 'name' => 'Aeroporto Regional do Norte', 'code' => 'CRN', 'runway' => [ 'center' => [-50.0, $cZ], 'length' => 160.0, 'width' => 14.0, 'axis' => 'z', 'designators' => ['18', '36'], ], 'taxiways' => [ ['center' => [-30.0, $cZ], 'length' => 150.0, 'width' => 8.0, 'axis' => 'z'], // Connectors aligned with the takeoff lineup (-240) and the // landing rollout exit (-370) so taxi paths stay on pavement. ['center' => [-40.0, $lz - 80], 'length' => 20.0, 'width' => 7.0, 'axis' => 'x'], ['center' => [-40.0, $lz - 210], 'length' => 20.0, 'width' => 7.0, 'axis' => 'x'], ], 'apron' => ['center' => [15.0, $cZ], 'size' => [90.0, 140.0]], 'terminal' => ['center' => [55.0, $lz - 95], 'size' => [34.0, 14.0]], 'hangars' => [ ['center' => [55.0, $lz - 205], 'size' => [24.0, 18.0]], ], 'tower' => ['center' => [40.0, $lz - 80]], 'stands' => [ [0.0, $lz - 95], [0.0, $lz - 155], [30.0, $lz - 125], [30.0, $lz - 185], ], 'helipad' => ['center' => [75.0, $lz - 85], 'radius' => 7.0], ]; } }