private void RemoveTrees(Terrain terrain, IOnPaint editContext, bool clearSelectedOnly)
        {
            PaintTreesDetailsContext ctx = PaintTreesDetailsContext.Create(terrain, editContext.uv);

            for (int i = 0; i < ctx.neighborTerrains.Length; ++i)
            {
                Terrain ctxTerrain = ctx.neighborTerrains[i];
                if (ctxTerrain != null)
                {
                    Vector2 ctxUV  = ctx.neighborUvs[i];
                    float   radius = 0.5f * brushSize / ctxTerrain.terrainData.size.x;

                    int treePrototype = kInvalidTree;
                    if (clearSelectedOnly && selectedTree != kInvalidTree)
                    {
                        treePrototype = PaintTreesUtils.FindTreePrototype(ctxTerrain, m_TargetTerrain, selectedTree);
                    }

                    if (!clearSelectedOnly || treePrototype != kInvalidTree)
                    {
                        TerrainPaintUtilityEditor.UpdateTerrainDataUndo(ctxTerrain.terrainData, "Terrain - Remove Trees");

                        ctxTerrain.RemoveTrees(ctxUV, radius, treePrototype);
                    }
                }
            }
        }
        private void PlaceTrees(Terrain terrain, IOnPaint editContext)
        {
            if (m_TargetTerrain == null ||
                selectedTree == kInvalidTree ||
                selectedTree >= m_TargetTerrain.terrainData.treePrototypes.Length)
            {
                return;
            }

            PaintTreesDetailsContext ctx = PaintTreesDetailsContext.Create(terrain, editContext.uv);

            int placedTreeCount = 0;

            int treePrototype = PaintTreesUtils.FindTreePrototype(terrain, m_TargetTerrain, selectedTree);

            if (treePrototype == kInvalidTree)
            {
                treePrototype = PaintTreesUtils.CopyTreePrototype(terrain, m_TargetTerrain, selectedTree);
            }

            if (PaintTreesUtils.ValidateTreePrototype(terrain, treePrototype))
            {
                // When painting single tree
                // And just clicking we always place it, so you can do overlapping trees
                Vector3 position          = new Vector3(editContext.uv.x, 0, editContext.uv.y);
                bool    checkTreeDistance = Event.current.type == EventType.MouseDrag || brushSize > 1;
                if (!checkTreeDistance || TerrainInspectorUtil.CheckTreeDistance(terrain.terrainData, position, treePrototype, spacing))
                {
                    TerrainPaintUtilityEditor.UpdateTerrainDataUndo(terrain.terrainData, "Terrain - Place Trees");

                    var instanceHeight = GetTreeHeight();
                    PaintTreesUtils.PlaceTree(terrain, treePrototype, position, GetTreeColor(), instanceHeight, GetTreeWidth(instanceHeight), GetTreeRotation());
                    ++placedTreeCount;
                }
            }

            for (int i = 0; i < ctx.neighborTerrains.Length; ++i)
            {
                Terrain ctxTerrain = ctx.neighborTerrains[i];
                if (ctxTerrain != null)
                {
                    Vector2 ctxUV = ctx.neighborUvs[i];

                    treePrototype = PaintTreesUtils.FindTreePrototype(ctxTerrain, m_TargetTerrain, selectedTree);
                    if (treePrototype == kInvalidTree)
                    {
                        treePrototype = PaintTreesUtils.CopyTreePrototype(ctxTerrain, m_TargetTerrain, selectedTree);
                    }

                    if (PaintTreesUtils.ValidateTreePrototype(ctxTerrain, treePrototype))
                    {
                        Vector3 size = TerrainInspectorUtil.GetPrototypeExtent(ctxTerrain.terrainData, treePrototype);
                        size.y = 0;
                        float treeCountOneAxis = brushSize / (size.magnitude * spacing * .5f);
                        int   treeCount        = (int)((treeCountOneAxis * treeCountOneAxis) * .5f);
                        treeCount = Mathf.Clamp(treeCount, 0, 100);
                        // Plant a bunch of trees
                        for (int j = ctxTerrain == terrain ? 1 : 0; j < treeCount && placedTreeCount < treeCount; ++j)
                        {
                            Vector2 randomOffset = 0.5f * Random.insideUnitCircle;
                            randomOffset.x *= brushSize / ctxTerrain.terrainData.size.x;
                            randomOffset.y *= brushSize / ctxTerrain.terrainData.size.z;
                            Vector3 position = new Vector3(ctxUV.x + randomOffset.x, 0, ctxUV.y + randomOffset.y);
                            if (position.x >= 0 && position.x <= 1 && position.z >= 0 && position.z <= 1 &&
                                TerrainInspectorUtil.CheckTreeDistance(ctxTerrain.terrainData, position, treePrototype, spacing * .5f))
                            {
                                TerrainPaintUtilityEditor.UpdateTerrainDataUndo(ctxTerrain.terrainData, "Terrain - Place Trees");

                                var instanceHeight = GetTreeHeight();
                                PaintTreesUtils.PlaceTree(ctxTerrain, treePrototype, position, GetTreeColor(), instanceHeight, GetTreeWidth(instanceHeight), GetTreeRotation());
                                ++placedTreeCount;
                            }
                        }
                    }
                }
            }
        }