/// <summary>
        /// Spawn an asteroid field.
        /// </summary>
        /// <param name="_numberOfAsteroids">The number of asteroids in the field.</param>
        /// <param name="_altitude">The maximum altitude AGL of the field, minimum altitude AGL is 50m.</param>
        /// <param name="_radius">The radius of the field from the spawn point.</param>
        /// <param name="_geoCoords">The spawn point (centre) of the field.</param>
        public void SpawnField(int numberOfAsteroids, float altitude, float radius, Vector2d geoCoords)
        {
            altitude *= 100f;  // Convert to m.
            radius   *= 1000f; // Convert to m.
            Debug.Log($"[BDArmory.Asteroids]: Spawning asteroid field with {numberOfAsteroids} asteroids with height {altitude}m and radius {radius / 1000f}km at coordinate ({geoCoords.x:F4}, {geoCoords.y:F4}).");
            BDACompetitionMode.Instance.competitionStatus.Add("Spawning Asteroid Field, please be patient.");

            var spawnPoint   = FlightGlobals.currentMainBody.GetWorldSurfacePosition(geoCoords.x, geoCoords.y, altitude);
            var upDirection  = (spawnPoint - FlightGlobals.currentMainBody.transform.position).normalized;
            var refDirection = Math.Abs(Vector3.Dot(Vector3.up, upDirection)) < 0.71f ? Vector3.up : Vector3.forward; // Avoid that the reference direction is colinear with the local surface normal.

            asteroids = new Vessel[numberOfAsteroids];
            for (int i = 0; i < asteroids.Length; ++i)
            {
                var direction = Vector3.ProjectOnPlane(Quaternion.AngleAxis((float)RNG.NextDouble() * 360f, upDirection) * refDirection, upDirection).normalized;
                var x         = (float)RNG.NextDouble();
                var distance  = Mathf.Sqrt(1f - x) * radius;
                var height    = RNG.NextDouble() * (altitude - 50f) + 50f;
                var position  = spawnPoint + direction * distance;
                position += (height - Misc.Misc.GetRadarAltitudeAtPos(position, false)) * upDirection;
                var asteroid = AsteroidUtils.SpawnAsteroid(position);
                if (asteroid != null)
                {
                    asteroids[i] = asteroid;
                }
            }
            UpdateAsteroidNames();

            floatingCoroutine = StartCoroutine(Float());
            StartCoroutine(CleanOutAsteroids());
        }
        /// <summary>
        /// Replace an asteroid at position i in the pool.
        /// </summary>
        /// <param name="i"></param>
        void ReplacePooledAsteroid(int i)
        {
            if (BDArmorySettings.DRAW_DEBUG_LABELS)
            {
                Debug.Log($"[BDArmory.Asteroids]: Replacing asteroid at position {i}.");
            }
            var asteroid = AsteroidUtils.SpawnAsteroid(FlightGlobals.currentMainBody.GetWorldSurfacePosition(geoCoords.x, geoCoords.y, altitude + 10000));

            if (asteroid != null)
            {
                StartCoroutine(CleanAsteroid(asteroid));
                asteroidPool[i] = asteroid;
            }
        }
        /// <summary>
        /// Strip out various modules from the asteroids as they make excessive amounts of GC allocations.
        /// Then set up the initial asteroid rotations.
        /// </summary>
        IEnumerator CleanOutAsteroids()
        {
            var wait = new WaitForFixedUpdate();

            while (asteroids.Any(a => a != null && (a.packed || !a.loaded)))
            {
                yield return(wait);
            }
            for (int i = 0; i < asteroids.Length; ++i)
            {
                if (asteroids[i] == null)
                {
                    continue;
                }
                AsteroidUtils.CleanOutAsteroid(asteroids[i]);
            }

            yield return(InitialRotation());
        }
        /// <summary>
        /// Add a number of asteroids to the pool.
        /// </summary>
        /// <param name="count"></param>
        void AddAsteroidsToPool(int count)
        {
            Debug.Log($"[BDArmory.Asteroids]: Increasing asteroid pool size to {asteroidPool.Count + count}.");
            spawnPoint  = FlightGlobals.currentMainBody.GetWorldSurfacePosition(geoCoords.x, geoCoords.y, altitude);
            upDirection = (spawnPoint - FlightGlobals.currentMainBody.transform.position).normalized;
            var refDirection = Math.Abs(Vector3d.Dot(Vector3.up, upDirection)) < 0.71f ? Vector3d.up : Vector3d.forward; // Avoid that the reference direction is colinear with the local surface normal.

            for (int i = 0; i < count; ++i)
            {
                var direction = Vector3.ProjectOnPlane(Quaternion.AngleAxis(i / 60f * 360f, upDirection) * refDirection, upDirection).normalized; // 60 asteroids per layer of the spiral (approx. 100m apart).
                var position  = spawnPoint + (1e4f + 1e2f * i / 60) * upDirection + 1e3f * direction;                                             // 100m altitude difference per layer of the spiral.
                var asteroid  = AsteroidUtils.SpawnAsteroid(position);
                if (asteroid != null)
                {
                    StartCoroutine(CleanAsteroid(asteroid));
                    asteroidPool.Add(asteroid);
                }
            }
            UpdatePooledAsteroidNames();
        }
        /// <summary>
        /// Wait until the collider bounds have been generated, then remove various modules from the asteroid for performance reasons.
        /// </summary>
        /// <param name="asteroid">The asteroid to clean.</param>
        IEnumerator CleanAsteroid(Vessel asteroid)
        {
            ++cleaningInProgress;
            var wait = new WaitForFixedUpdate();

            asteroid.gameObject.SetActive(true);
            var startTime = Time.time;

            while (asteroid != null && Time.time - startTime < 10 && (asteroid.packed || !asteroid.loaded || asteroid.rootPart.GetColliderBounds().Length < 2))
            {
                yield return(wait);
            }
            if (asteroid != null)
            {
                if (Time.time - startTime >= 10)
                {
                    Debug.LogWarning($"[BDArmory.Asteroids]: Timed out waiting for colliders on {asteroid.vesselName} to be generated.");
                }
                AsteroidUtils.CleanOutAsteroid(asteroid);
                asteroid.gameObject.SetActive(false);
            }
            --cleaningInProgress;
        }