private bool TryFindLocationOutsideForestInternal(Vector3D? desiredLocationSize, out Vector3D location, Predicate<AreaData> predicate = null)
        {
            Vector3D desiredHalfSize = desiredLocationSize.HasValue ? desiredLocationSize.Value * 0.5f : Vector3D.Zero;
            desiredHalfSize.Y = 0;

            if (m_highLevelBoxes.Count == 0)
            {
                // no forest on the map, generate starting point
                bool valid = false;
                while (m_initialForestLocations.Count > 0 && !valid)
                {
                    var potentialTreePosition = m_initialForestLocations.Dequeue();
                    valid = true;
                    BoundingBoxD itemBox = new BoundingBoxD(potentialTreePosition, potentialTreePosition);
                    itemBox.Inflate(desiredHalfSize);

                    var entities = MyEntities.GetEntitiesInAABB(ref itemBox);
                    foreach (var entity in entities)
                    {
                        if (entity is MyEnvironmentItems)
                            continue;
                        if (entity is MyVoxelBase)
                            continue;
                        var entityBox = entity.PositionComp.WorldAABB;
                        var containment = entityBox.Intersects(itemBox);
                        if (containment)
                        {
                            valid = false;
                            break;
                        }
                    }
                    entities.Clear();

                    if (valid)
                    {
                        Vector3D end = potentialTreePosition;
                        end.Y -= 20;
                        if (RaycastForExactPosition(potentialTreePosition, end, out location))
                        {
                            d_foundEnlargingPoints.Add(location);
                            return true;
                        }
                        else
                        {
                            valid = false;
                        }
                    }
                }

                location = Vector3D.Zero;
                return false;
            }
            else
            {
                if (!TryGetRandomAreas(m_tmpAreas))
                {
                    location = Vector3D.Zero;
                    return false;
                }

                int areaIdx = 0;
                int randomStartIdx = MyUtils.GetRandomInt(m_tmpAreas.Count);
                while (areaIdx < m_tmpAreas.Count)
                {
                    var spawnArea = m_tmpAreas[randomStartIdx];
                    randomStartIdx = (randomStartIdx + 1) % m_tmpAreas.Count;
                    areaIdx++;

                    if (!spawnArea.IsValid || spawnArea.IsFull)
                        continue;

                    if (predicate != null && !predicate(spawnArea.GetAreaData()))
                    {
                        spawnArea.IsFull = true;
                        continue;
                    }

                    var spawnBox = spawnArea.ForestBox;
                    var forestBox = spawnArea.ForestBox;
                    spawnBox = forestBox.Inflate(desiredHalfSize);
                    spawnBox.Inflate(new Vector3D(0.2, 0, 0.2)); // inflate for some minimum size

                    MyBBSetSampler setSampler = new MyBBSetSampler(spawnBox.Min, spawnBox.Max);
                    setSampler.SubtractBB(ref forestBox);
                    RefineSampler(spawnArea, ref spawnBox, ref desiredHalfSize, setSampler);

                    if (!setSampler.Valid)
                        continue;

                    Vector3D exactLocation;
                    Vector3D samplePosition = setSampler.Sample();
                    if (TryGetExactLocation(spawnArea, samplePosition, 40, out exactLocation))
                    {
                        location = exactLocation;
                        d_foundEnlargingPoints.Add(exactLocation);
                        m_tmpAreas.Clear();
                        return true;
                    }
                    else
                    {
                        location = Vector3D.Zero;
                        m_tmpAreas.Clear();
                        return false;
                    }
                }
            }

            location = Vector3D.Zero;
            m_tmpAreas.Clear();
            return false;
        }
        private void FindForestInitialCandidate()
        {
            BoundingBoxD groundBox = m_ground.PositionComp.WorldAABB;
            Vector3D boxSize = groundBox.Size;
            boxSize *= 0.1f;
            groundBox.Inflate(-boxSize);
            MyBBSetSampler sampler = new MyBBSetSampler(groundBox.Min, groundBox.Max);

            bool posIsValid = true;
            Vector3D worldPos = default(Vector3D);
            int counter = 0;
            do
            {
                // find random position for starting 
                worldPos = sampler.Sample();
                var worldPosProjected = worldPos;
                worldPosProjected.Y = 0.5f;
                posIsValid = true;
                counter++;
                Vector3D areaCheck = new Vector3D(20, 20, 20);
                foreach (var enqueued in m_initialForestLocations)
                {
                    // only interested in XZ plane
                    BoundingBoxD tmp = new BoundingBoxD(enqueued - areaCheck, enqueued + areaCheck);
                    tmp.Min.Y = 0;
                    tmp.Max.Y = 1;

                    if (tmp.Contains(worldPosProjected) == ContainmentType.Contains)
                    {
                        posIsValid = false;
                        break;
                    }
                }
            } while (!posIsValid && counter != 10);

            if (!posIsValid)
            {
                // could not find any position
                return;
            }

            var lineStart = new Vector3D(worldPos.X, groundBox.Max.Y, worldPos.Z);
            var lineEnd = new Vector3D(worldPos.X, groundBox.Min.Y, worldPos.Z);
            LineD line = new LineD(lineStart, lineEnd);
            VRage.Game.Models.MyIntersectionResultLineTriangleEx? result = null;
            var correctGroundDefinition = MyDefinitionManager.Static.GetVoxelMaterialDefinition("Grass");
            var materialId = correctGroundDefinition.Index;

            if (m_ground.GetIntersectionWithLine(ref line, out result, VRage.Game.Components.IntersectionFlags.DIRECT_TRIANGLES))
            {
                Vector3D intersectionPoint = result.Value.IntersectionPointInWorldSpace;
                Vector3I voxelCoord, minRead, maxRead;
                MyVoxelCoordSystems.WorldPositionToVoxelCoord(m_ground.PositionLeftBottomCorner, ref intersectionPoint, out voxelCoord);
                minRead = voxelCoord - Vector3I.One;
                maxRead = voxelCoord + Vector3I.One;
                m_ground.Storage.ReadRange(m_voxelCache, MyStorageDataTypeFlags.Material, 0, ref minRead, ref maxRead);

                var minLocal = Vector3I.Zero;
                var maxLocal = Vector3I.One * 2;
                var it = new Vector3I_RangeIterator(ref minLocal, ref maxLocal);
                while (it.IsValid())
                {
                    var vec = it.Current;
                    var material = m_voxelCache.Material(ref vec);
                    if (material == materialId)
                    {
                        // found a location
                        var desired = voxelCoord - Vector3I.One + vec;
                        Vector3D desiredWorldPosition = default(Vector3D);
                        MyVoxelCoordSystems.VoxelCoordToWorldPosition(m_ground.PositionLeftBottomCorner, ref desired, out desiredWorldPosition);
                        m_initialForestLocations.Enqueue(desiredWorldPosition);
                        break;
                    }

                    it.MoveNext();
                }
            }
        }
        private bool TryFindLocationInsideForestInternal(Vector3D? desiredLocationSize, out Vector3D location, Predicate<AreaData> predicate = null)
        {
            if (!TryGetRandomAreas(m_tmpAreas))
            {
                location = Vector3D.Zero;
                return false;
            }

            Vector3D desiredHalfSize = desiredLocationSize.HasValue ? desiredLocationSize.Value * 0.5f : Vector3D.Zero;
            desiredHalfSize.Y = 0;

            int areaIdx = 0;
            int randomStartIdx = MyUtils.GetRandomInt(m_tmpAreas.Count);
            while (areaIdx < m_tmpAreas.Count)
            {
                var spawnArea = m_tmpAreas[randomStartIdx];
                randomStartIdx = (randomStartIdx + 1) % m_tmpAreas.Count;
                areaIdx++;

                if (!spawnArea.IsValid || spawnArea.IsFull)
                    continue;

                if (predicate != null && !predicate(spawnArea.GetAreaData()))
                {
                    spawnArea.IsFull = true;
                    continue;
                }

                var spawnBox = spawnArea.ForestBox;
                MyBBSetSampler setSampler = new MyBBSetSampler(spawnBox.Min, spawnBox.Max);

                RefineSampler(spawnArea, ref spawnBox, ref desiredHalfSize, setSampler);

                if (!setSampler.Valid)
                    continue;

                Vector3D exactLocation;
                if (TryGetExactLocation(spawnArea, setSampler.Sample(), 10, out exactLocation))
                {
                    location = exactLocation;
                    d_foundEnrichingPoints.Add(exactLocation);
                    m_tmpAreas.Clear();

                    if (SelectedArea != null)
                        SelectedArea(spawnArea.ProxyId);

                    return true;
                }
            }

            location = Vector3D.Zero;
            m_tmpAreas.Clear();
            return false;
        }