コード例 #1
0
        private List <GroundShapeInfoInTree> FindOverlappingGroundShapes(GroundShapeInfo info)
        {
            var queryEnvelope       = MyNetTopologySuiteUtils.ToEnvelope(info.GlobalSubposition);
            var overlappingElements =
                _groundTree.Query(queryEnvelope)
                .Where(c => c.GlobalSubpositionEnvelope.Intersection(queryEnvelope).Area > 1)
                .ToList();

            return(overlappingElements);
        }
コード例 #2
0
 private ILinearRing Translate(ILinearRing input)
 {
     return(new LinearRing(
                input.Coordinates
                .Select(c => MyNetTopologySuiteUtils.ToVector2(c))
                .Select(c => _translator.TranslateToUnity(c))
                .Select(c => MyNetTopologySuiteUtils.ToCoordinate(c))
                .ToArray()
                ));
 }
コード例 #3
0
ファイル: HabitatMap.cs プロジェクト: defacto2k15/PwMgr
        public MyQuadtree <HabitatFieldInTree> QueryMap(MyRectangle queryArea)
        {
            var outTree = new MyQuadtree <HabitatFieldInTree>();

            Vector2 reoffsetStartPosition = new Vector2(queryArea.X, queryArea.Y) - _mapStartPosition;
            Vector2 reoffsetEndPosition   = new Vector2(queryArea.X + queryArea.Width, queryArea.Y + queryArea.Height)
                                            - _mapStartPosition;

            var startGridX = Mathf.FloorToInt(reoffsetStartPosition.x / _mapGridSize.x);
            var startGridY = Mathf.FloorToInt(reoffsetStartPosition.y / _mapGridSize.y);

            var endGridX = Mathf.Min(_gridCellsCount.X, Mathf.CeilToInt(reoffsetEndPosition.x / _mapGridSize.x));
            var endGridY = Mathf.Min(_gridCellsCount.Y, Mathf.CeilToInt(reoffsetEndPosition.y / _mapGridSize.y));

            if (startGridX < 0 || startGridY < 0 || endGridX > _gridCellsCount.X || endGridY > _gridCellsCount.Y)
            {
                Preconditions.Fail(
                    $"Querying area {queryArea}, makes grids query: x:{startGridX} - {endGridX} y:{startGridY}-{endGridY} which is out of size {_gridCellsCount}");
            }

            var queryEnvelope = MyNetTopologySuiteUtils.ToGeometryEnvelope(queryArea);

            for (var gridX = startGridX; gridX < endGridX; gridX++)
            {
                for (var gridY = startGridY; gridY < endGridY; gridY++)
                {
                    //todo return other structure - one that uses gridded tree in array
                    List <HabitatFieldInTree> treeElements = null;

                    treeElements = _treeArray[gridX, gridY].QueryAll().Select(c =>
                                                                              new
                    {
                        intersection = c.Field.Geometry.Intersection(queryEnvelope),
                        elem         = c
                    })
                                   .Where(c => !c.intersection.IsEmpty && !(c.intersection is ILineString))
                                   .SelectMany(c => MyNetTopologySuiteUtils.ToSinglePolygons(c.intersection).Select(
                                                   k => new HabitatFieldInTree()
                    {
                        Field = new HabitatField()
                        {
                            Geometry = k,
                            Type     = c.elem.Field.Type
                        }
                    })).ToList();

                    treeElements.ForEach(c => outTree.Add(c));
                }
            }

            return(outTree);
        }
コード例 #4
0
        private MyQuadtree <HabitatEnlargedByMarginInTree> GenerateEnlargedTree(List <HabitatField> habitatFields)
        {
            var outTree = new MyQuadtree <HabitatEnlargedByMarginInTree>();

            foreach (var field in habitatFields)
            {
                var geo         = field.Geometry;
                var enlargedGeo = MyNetTopologySuiteUtils.EnlargeByMargin(geo, _configuration.HabitatMargin);
                outTree.Add(new HabitatEnlargedByMarginInTree()
                {
                    Type = field.Type,
                    MarginedHabitatField = enlargedGeo,
                    StandardHabitatField = geo
                });
            }
            return(outTree);
        }
コード例 #5
0
ファイル: FinalVegetation.cs プロジェクト: defacto2k15/PwMgr
        private void InitializeBushObjectsDb(List <VegetationSubjectEntity> smallDb, ForgingVegetationSubjectInstanceContainerProxy forgingContainerProxy)
        {
            var repositioner = _veConfiguration.VegetationRepositioner;

            var supportedSpecies = _veConfiguration.SupportedLeadingBushSpecies;

            var speciesChanger = new VegetationSpeciesRandomChanger(_veConfiguration.SpeciesChangingList, 661); //todo!

            var filteredEntities = smallDb
                                   .Where(c => supportedSpecies.Contains(c.Detail.SpeciesEnum))
                                   .Select(c => speciesChanger.ChangeSpecies(c))
                                   .Where(c => _veConfiguration.SupportedBushSpecies.Contains(c.Detail.SpeciesEnum));
            var quadtree = new Quadtree <VegetationSubjectEntity>();

            foreach (var entity in filteredEntities)
            {
                quadtree.Insert(MyNetTopologySuiteUtils.ToPointEnvelope(entity.Position2D), entity);
            }

            var positionsProvider = new VegetationSubjectsPositionsDatabase(quadtree);

            var runtimeManagement = new VegetationRuntimeManagement(
                positionsProvider: positionsProvider,
                vegetationSubjectsChangesListener: forgingContainerProxy,
                visibleEntitiesContainer: new VegetationSubjectsVisibleEntitiesContainer(),
                configuration: _veConfiguration.BushObjectsVegetationRuntimeManagementConfiguration);

            var vegetationRuntimeManagementProxy = new VegetationRuntimeManagementProxy(runtimeManagement);

            _ultraUpdatableContainer.AddUpdatableElement(new FieldBasedUltraUpdatable()
            {
                StartCameraField = (camera) =>
                {
                    vegetationRuntimeManagementProxy.StartThreading();
                    var position = camera.Position;
                    vegetationRuntimeManagementProxy.Start(repositioner.InvMove(position));
                },
                UpdateCameraField = (camera) =>
                {
                    var position = camera.Position;
                    vegetationRuntimeManagementProxy.AddUpdate(repositioner.InvMove(position));
                    vegetationRuntimeManagementProxy.SynchronicUpdate(repositioner.InvMove(position));
                },
            });
        }
コード例 #6
0
        public List <VegetationSubjectEntity> GetEntiesFrom(IGeometry area, VegetationDetailLevel level)
        {
            var outPositions = new List <Vector2>();

            if (level == VegetationDetailLevel.FULL)
            {
                var envelope           = area.EnvelopeInternal;
                var gridPositionsStart = new IntVector2(
                    Mathf.CeilToInt((float)envelope.MinX / _configuration.PositionsGridSize.x),
                    Mathf.CeilToInt((float)envelope.MinY / _configuration.PositionsGridSize.y));

                var afterGridingLength = new Vector2(
                    (float)(envelope.MaxX - gridPositionsStart.X * _configuration.PositionsGridSize.x),
                    (float)(envelope.MaxY - gridPositionsStart.Y * _configuration.PositionsGridSize.y));

                var gridLength = new IntVector2( //ceil becouse there is point at length 0 !!
                    Mathf.CeilToInt(afterGridingLength.x / _configuration.PositionsGridSize.x),
                    Mathf.CeilToInt(afterGridingLength.y / _configuration.PositionsGridSize.y));

                for (int x = 0; x < gridLength.X; x++)
                {
                    for (int y = 0; y < gridLength.Y; y++)
                    {
                        var position = new Vector2(
                            (0.5f + (gridPositionsStart.X + x)) * _configuration.PositionsGridSize.x,
                            (0.5f + (gridPositionsStart.Y + y)) * _configuration.PositionsGridSize.y);

                        outPositions.Add(position);
                    }
                }
            }

            return(outPositions.Where(c => area.Contains(MyNetTopologySuiteUtils.ToGeometryEnvelope(
                                                             MyNetTopologySuiteUtils.ToPointEnvelope(c)))).Select(c => new VegetationSubjectEntity(
                                                                                                                      new DesignBodyLevel0Detail()
            {
                Pos2D = c,
                Radius = 0,
                Size = 0,
                SpeciesEnum = VegetationSpeciesEnum.Grass2SpotMarker
            })).ToList());
        }
コード例 #7
0
        private VegetationSubjectsPositionsDatabase CreateSamplePositionsDatabase()
        {
            var tree = new Quadtree <VegetationSubjectEntity>();

            for (int x = 0; x < 4000; x += 30)
            {
                for (int y = 0; y < 4000; y += 30)
                {
                    var newEntity = new VegetationSubjectEntity(
                        new DesignBodyLevel0Detail()
                    {
                        Pos2D       = new Vector2(x, y),
                        Radius      = 0,
                        Size        = 0,
                        SpeciesEnum = VegetationSpeciesEnum.Tree1A
                    });
                    tree.Insert(MyNetTopologySuiteUtils.ToPointEnvelope(newEntity.Position2D), newEntity);
                }
            }
            return(new VegetationSubjectsPositionsDatabase(tree));
        }
コード例 #8
0
//19.64311408996582 49.603153228759766
//        1914206496
//        180998242

//19.71388099829122, 49.648193645648
// 19.628429388931949, 49.617853376339596
        private ILinearRing ToLinearRing(List <Vector2> nodes)
        {
            var nodesAsCoordinates = nodes.Select(c => MyNetTopologySuiteUtils.ToCoordinate(c)).ToList();

            if (!nodesAsCoordinates.First().Equals(nodesAsCoordinates.Last()))
            {
                var repairedRing = nodesAsCoordinates.ToList();
                repairedRing.Add(nodesAsCoordinates.First());
                var ring = new LinearRing(repairedRing.ToArray());
                if (!ring.IsValid)
                {
                    //simple connection failed. Propably should do crectangle merging
                    var ringRect = ring.EnvelopeInternal;
                    Debug.Log("Pushing your luck. Lets hope that it is his only, 2415555 relation!");
                    //todo make better invalid circular way  repairing algorithm. Like find which two sides
                    // of enveloping rectangle would be shorted in repairing road
                    var newRingPoint = ringRect.ToMyRectangle().TopRightPoint;
                    repairedRing[repairedRing.Count - 1] = new Coordinate(newRingPoint.x, newRingPoint.y);
                    repairedRing.Add(nodesAsCoordinates.First());

                    ring = new LinearRing(repairedRing.ToArray());
                    if (!ring.IsValid)
                    {
                        var validOp = new IsValidOp(ring);
                        Debug.Log("Validation error is: " + validOp.ValidationError);
                        Debug.Log("R1 Ring is " + ring.ToString());
                        return(null);

                        //var text = ring.ToText();
                        //File.WriteAllText(@"C:\inz\wrongRing.wkt", text);
                    }
                    Preconditions.Assert(ring.IsValid, "Ring still invalid. What to do?");
                }
                return(ring);
            }
            else
            {
                return(new LinearRing(nodesAsCoordinates.ToArray()));
            }
        }
コード例 #9
0
        public static void CreateDebugHabitatField(HabitatField field, float positionMultiplier = 1000,
                                                   GameObject parentGameObject = null)
        {
            var polys = MyNetTopologySuiteUtils.ToSinglePolygons(field.Geometry);

            if (polys.Count == 1)
            {
                var poly         = polys[0];
                var exteriorRing = poly.ExteriorRing.Coordinates.Select(i => MyNetTopologySuiteUtils.ToVector2(i))
                                   .ToList();

                var rootObject = CreateRingGameObject(exteriorRing, positionMultiplier);
                if (parentGameObject != null)
                {
                    rootObject.transform.SetParent(parentGameObject.transform);
                }
                rootObject.name = field.Type.ToString();


                foreach (var interiorRing in poly.Holes)
                {
                    var ring
                        = interiorRing.Coordinates.Select(i => MyNetTopologySuiteUtils.ToVector2(i)).ToList();
                    var ringObject = CreateRingGameObject(ring, positionMultiplier);
                    ringObject.transform.SetParent(rootObject.transform);
                }
            }
            else
            {
                foreach (var habitatField in polys.Select(poly => new HabitatField()
                {
                    Geometry = poly,
                    Type = field.Type
                }))
                {
                    CreateDebugHabitatField(habitatField, positionMultiplier, parentGameObject);
                }
            }
        }
コード例 #10
0
ファイル: HabitatMap.cs プロジェクト: defacto2k15/PwMgr
        public static HabitatMap Create(
            MyRectangle areaOnMap,
            Vector2 mapGridSize,
            List <HabitatField> habitatFields,
            HabitatType defaultHabitatType,
            HabitatTypePriorityResolver priorityResolver)
        {
            var fullTree = new MyQuadtree <HabitatFieldInTree>();

            habitatFields.ForEach(c => fullTree.Add(new HabitatFieldInTree()
            {
                Field = c
            }));

            int gridXCount = Mathf.CeilToInt(areaOnMap.Width / mapGridSize.x);
            int gridYCount = Mathf.CeilToInt(areaOnMap.Height / mapGridSize.y);

            var gridTreeArray = new MyQuadtree <HabitatFieldInTree> [gridXCount, gridYCount];

            for (int gridX = 0; gridX < gridXCount; gridX++)
            {
                for (int gridY = 0; gridY < gridYCount; gridY++)
                {
                    var gridArea = new MyRectangle(
                        areaOnMap.X + gridX * mapGridSize.x,
                        areaOnMap.Y + gridY * mapGridSize.y,
                        mapGridSize.x,
                        mapGridSize.y);

                    var geometryEnvelope = MyNetTopologySuiteUtils.ToGeometryEnvelope(gridArea);
                    var fieldsInArea     = fullTree.QueryWithIntersection(geometryEnvelope);
                    //Debug.Log("U34: "+fieldsInArea.Count(c => c.Field.Type == HabitatType.Fell));
                    //if (fieldsInArea.Count(c => c.Field.Type == HabitatType.Fell) > 0 )
                    //{
                    //    Debug.Log($"J2: {StringUtils.ToString(fieldsInArea.Where(c => c.Field.Type == HabitatType.Fell).Select(c => c.Field.Geometry.AsText()))}");
                    //}

                    var fieldsInEnvelope = fieldsInArea.Select(c => new HabitatField()
                    {
                        Geometry = MySafeIntersection(c.Field.Geometry, geometryEnvelope),
                        Type     = c.Field.Type
                    }).Where(c => c.Geometry != null && !c.Geometry.IsEmpty);

                    // removal of elements one on other

                    var sortedFields = fieldsInEnvelope.OrderByDescending(c => priorityResolver.Resolve(c.Type))
                                       .ToList();
                    for (int i = 0; i < sortedFields.Count; i++)
                    {
                        var current = sortedFields[i];
                        for (int j = i + 1; j < sortedFields.Count; j++)
                        {
                            var other = sortedFields[j];
                            other.Geometry = other.Geometry.Difference(current.Geometry);
                        }
                    }
                    sortedFields = sortedFields.Where(c => !c.Geometry.IsEmpty).ToList();


                    var notUsedAreaInGrid = geometryEnvelope;
                    foreach (var cutGeometry in sortedFields.Select(c => c.Geometry))
                    {
                        notUsedAreaInGrid = notUsedAreaInGrid.Difference(cutGeometry);
                    }
                    if (!notUsedAreaInGrid.IsEmpty)
                    {
                        sortedFields.Add(
                            new HabitatField()
                        {
                            Type     = defaultHabitatType,
                            Geometry = notUsedAreaInGrid
                        }
                            );
                    }

                    var singleFieldsInTree = sortedFields.SelectMany(c => MyNetTopologySuiteUtils
                                                                     .ToSinglePolygons(c.Geometry).Select(poly => new HabitatField()
                    {
                        Geometry = poly,
                        Type     = c.Type
                    })).Select(c => new HabitatFieldInTree()
                    {
                        Field = c
                    }).ToList();
                    gridTreeArray[gridX, gridY] = MyQuadtree <HabitatFieldInTree> .CreateWithElements(singleFieldsInTree);
                }
            }
            return(new HabitatMap(
                       new Vector2(areaOnMap.X, areaOnMap.Y),
                       mapGridSize,
                       new IntVector2(gridXCount, gridYCount),
                       gridTreeArray));
        }
コード例 #11
0
        private async Task <Dictionary <HabitatType, Texture2D> > CreateHabitatTexturesDict(
            Vector2 startOffset,
            IntVector2 habitatTextureSize,
            List <HabitatFieldInTree> habitats)
        {
            var habitatTextureTemplatesDict = new Dictionary <HabitatType, MyTextureTemplate>();
            var allTypes = habitats.Select(c => c.Field.Type).Distinct();

            foreach (var type in allTypes)
            {
                //var newTex = new Texture2D(habitatTextureSize.X, habitatTextureSize.Y, TextureFormat.RGB24, false, true);
                var newTexTemplate = new MyTextureTemplate(habitatTextureSize.X, habitatTextureSize.Y,
                                                           TextureFormat.ARGB32, false, FilterMode.Bilinear)
                {
                    wrapMode = TextureWrapMode.Clamp
                };
                habitatTextureTemplatesDict[type] = newTexTemplate;
            }

            var enlargedTree = GenerateEnlargedTree(habitats.Select(c => c.Field).ToList());

            for (int x = 0; x < habitatTextureSize.X; x++)
            {
                for (int y = 0; y < habitatTextureSize.Y; y++)
                {
                    var centerPoint = new Vector2(
                        (x + 0.5f) * (_configuration.HabitatSamplingUnit),
                        (y + 0.5f) * (_configuration.HabitatSamplingUnit)
                        ) + startOffset;
                    var pointGeometry =
                        MyNetTopologySuiteUtils.ToGeometryEnvelope(MyNetTopologySuiteUtils
                                                                   .ToPointEnvelope(centerPoint));
                    var marginTouchingHabitats = enlargedTree.QueryWithIntersection(pointGeometry);

                    foreach (var texture in habitatTextureTemplatesDict.Values)
                    {
                        texture.SetPixel(x, y, new Color(0, 0, 0));
                    }

                    foreach (var habitatType in marginTouchingHabitats.Select(c => c.Type).Distinct())
                    {
                        var maxIntensityValue = 0f;
                        foreach (var habitat in marginTouchingHabitats.Where(c => c.Type == habitatType))
                        {
                            if (habitat.StandardHabitatField.Contains(pointGeometry))
                            {
                                maxIntensityValue = 1;
                            }
                            else
                            {
                                var distance = MyNetTopologySuiteUtils.Distance(pointGeometry,
                                                                                habitat.StandardHabitatField,
                                                                                _configuration.HabitatMargin);
                                maxIntensityValue =
                                    Mathf.Max(maxIntensityValue,
                                              Mathf.Clamp01(1 - (distance / _configuration.HabitatMargin)));
                            }
                        }

                        habitatTextureTemplatesDict[habitatType].SetPixel(x, y, new Color(maxIntensityValue, 0, 0));
                    }
                }
            }

            var renderedTextures =
                await TaskUtils.WhenAll(
                    habitatTextureTemplatesDict.Values
                    .Select(async(c) => await _textureConciever.ConcieveTextureAsync(c)));

            var outDict = Enumerable.Range(0, renderedTextures.Count)
                          .ToDictionary(i => habitatTextureTemplatesDict.Keys.ToList()[i], i => renderedTextures[i]);

            return(outDict);
        }
コード例 #12
0
ファイル: HeightArrayDb.cs プロジェクト: defacto2k15/PwMgr
 public bool Intersects(IGeometry geometry)
 {
     return(MyNetTopologySuiteUtils.ToGeometryEnvelope(CoordedHeightArray.Coords).Intersects(geometry));
 }
コード例 #13
0
ファイル: HeightArrayDb.cs プロジェクト: defacto2k15/PwMgr
 public Envelope CalculateEnvelope()
 {
     return(MyNetTopologySuiteUtils.ToEnvelope(CoordedHeightArray.Coords));
 }
コード例 #14
0
ファイル: FinalVegetation.cs プロジェクト: defacto2k15/PwMgr
        private void StartTreesRuntimeManagment()
        {
            var globalInstancingContainer = _initializationFields.Retrive <GlobalGpuInstancingContainer>();
            var representationContainer   = new DesignBodyRepresentationContainer();
            var instanceBucketsContainer  = new DesignBodyInstanceBucketsContainer(globalInstancingContainer);

            var quadBillboardMesh = GameObject.CreatePrimitive(PrimitiveType.Quad).GetComponent <MeshFilter>().mesh;

            IDesignBodyRepresentationInstanceCombinationProvider combinationProvider;

            if (_veConfiguration.Mode == VegetationMode.Legacy)
            {
                var gShifter        = new GTreeDetailProviderShifter(new DetailProviderRepository(), quadBillboardMesh);
                var treeFileManager = new TreeFileManager(new TreeFileManagerConfiguration()
                {
                    WritingTreeCompletedClanDirectory = _veConfiguration.TreeCompletedClanDirectiory
                });
                combinationProvider = new GDesignBodyRepresentationInstanceCombinationProvider(treeFileManager, gShifter);
            }
            else
            {
                var eVegetationShifter = new EVegetationDetailProviderShifter(
                    _veConfiguration.ShaderNames,
                    new DetailProviderRepository(), quadBillboardMesh,
                    _veConfiguration.ReferencedAssets, _materialCommonPack);
                combinationProvider = new EVegetationDesignBodyRepresentationInstanceCombinationProvider(new TreePrefabManager(), eVegetationShifter, _veConfiguration.ReferencedAssets);
            }

            foreach (var pair in _veConfiguration.ShiftingConfigurations.Where(c => _veConfiguration.SupportedVegetationSpecies.Contains(c.Key)))
            {
                var clanRepresentations = combinationProvider.CreateRepresentations(pair.Value, pair.Key);
                representationContainer.InitializeLists(clanRepresentations);
                instanceBucketsContainer.InitializeLists(clanRepresentations);
            }

            var designBodySpotUpdaterProxy = _initializationFields.Retrive <DesignBodySpotUpdaterProxy>();
            var mediatorSpotUpdater        = new ListenerCenteredMediatorDesignBodyChangesUpdater(designBodySpotUpdaterProxy);

            var rootMediator = _initializationFields.Retrive <RootMediatorSpotPositionsUpdater>();

            rootMediator.AddListener(mediatorSpotUpdater);

            var repositioner          = _veConfiguration.VegetationRepositioner;
            var forgingContainerProxy = new ForgingVegetationSubjectInstanceContainerProxy(
                new ForgingVegetationSubjectInstanceContainer(
                    new DesignBodyPortrayalForger(
                        representationContainer,
                        instanceBucketsContainer,
                        repositioner),
                    mediatorSpotUpdater//teraz napisz tak, zeby info zwrotne se spotupdatera wracalo zgodnie z multithreadingiem (szlo do innego watku!)
                    ));

            mediatorSpotUpdater.SetTargetChangesListener(new LambdaSpotPositionChangesListener(dict =>
            {
                forgingContainerProxy.AddSpotModifications(dict);
            }));

            _ultraUpdatableContainer.AddOtherThreadProxy(forgingContainerProxy);

            MyProfiler.BeginSample("Vegetation1: Loading from file");
            var baseVegetationList = VegetationDatabaseFileUtils.LoadListFromFiles(_veConfiguration.LoadingVegetationDatabaseDictionaryPath);

            MyProfiler.EndSample();

            if (_veConfiguration.GenerateTrees)
            {
                MyProfiler.BeginSample("Vegetation2: pushingToFile");
                foreach (var pair in _veConfiguration.PerRankVegetationRuntimeManagementConfigurations)
                {
                    var rank = pair.Key;
                    var managementConfiguration = pair.Value;

                    var baseRankedDb = baseVegetationList[rank];

                    var supportedSpecies = _veConfiguration.SupportedTreeSpecies;

                    var filteredEntities = baseRankedDb.Where(c => supportedSpecies.Contains(c.Detail.SpeciesEnum)).ToList();

                    var stagnantEntities    = new List <VegetationSubjectEntity>();
                    var nonStagnantEntities = new List <VegetationSubjectEntity>();

                    var nonStagnantVegetationRect = _veConfiguration.NonStagnantVegetationArea;
                    foreach (var entity in filteredEntities)
                    {
                        if (nonStagnantVegetationRect.Contains(entity.Position2D))
                        {
                            nonStagnantEntities.Add(entity);
                        }
                        else
                        {
                            stagnantEntities.Add(entity);
                        }
                    }

                    var stagnantVegetationRuntimeManagement = new StagnantVegetationRuntimeManagement(forgingContainerProxy,
                                                                                                      stagnantEntities, _veConfiguration.StagnantVegetationRuntimeManagementConfiguration);
                    var stagnantVegetationRuntimaManagementProxy = new StagnantVegetationRuntimeManagementProxy(stagnantVegetationRuntimeManagement);

                    _ultraUpdatableContainer.AddUpdatableElement(new FieldBasedUltraUpdatable()
                    {
                        StartField = () => { stagnantVegetationRuntimaManagementProxy.StartThreading(); }
                    });


                    var quadtree = new Quadtree <VegetationSubjectEntity>();
                    foreach (var entity in nonStagnantEntities)
                    {
                        quadtree.Insert(MyNetTopologySuiteUtils.ToPointEnvelope(entity.Position2D), entity);
                    }

                    var positionsProvider = new VegetationSubjectsPositionsDatabase(quadtree);

                    var runtimeManagement = new VegetationRuntimeManagement(
                        positionsProvider: positionsProvider,
                        vegetationSubjectsChangesListener: forgingContainerProxy,
                        visibleEntitiesContainer: new VegetationSubjectsVisibleEntitiesContainer(),
                        configuration: managementConfiguration);

                    var outerVegetationRuntimeManagementProxy = new VegetationRuntimeManagementProxy(runtimeManagement);

                    _ultraUpdatableContainer.AddUpdatableElement(new FieldBasedUltraUpdatable()
                    {
                        StartCameraField = (camera) =>
                        {
                            outerVegetationRuntimeManagementProxy.StartThreading();
                            var position = camera.Position;
                            outerVegetationRuntimeManagementProxy.Start(repositioner.InvMove(position));
                        },
                        UpdateCameraField = (camera) =>
                        {
                            var position = camera.Position;
                            outerVegetationRuntimeManagementProxy.AddUpdate(repositioner.InvMove(position));
                            outerVegetationRuntimeManagementProxy.SynchronicUpdate(repositioner.InvMove(position));
                        },
                    });
                }
                MyProfiler.EndSample();
            }

            if (_veConfiguration.GenerateBigBushes)
            {
                InitializeBushObjectsDb(baseVegetationList[VegetationLevelRank.Small], forgingContainerProxy);
            }
        }