private void FreeElevation()
    {
        // Highlight.pos is center vertex
        if (Highlight.pos.x != InitialPos.x || Highlight.pos.z != InitialPos.z)
        {         // vertex -> vertex
            InitialPos = Highlight.pos;
            TargetSetHeights.Clear();
        }
        HashSet <int> indexes = new HashSet <int>();

        for (float z = Highlight.pos.z - RadiusSlider.value; z <= Highlight.pos.z + RadiusSlider.value; z++)
        {
            for (float x = Highlight.pos.x - RadiusSlider.value; x <= Highlight.pos.x + RadiusSlider.value; x++)
            {
                if (Consts.IsWithinMapBounds(x, z))
                {
                    int     idx        = Consts.PosToIndex((int)x, (int)z);
                    Vector3 currentpos = Consts.IndexToPos(idx);
                    float   dist       = Consts.Distance(currentpos, Highlight.pos);
                    if (Mathf.Round(dist) > RadiusSlider.value - 1)
                    {
                        continue;
                    }

                    float TargetSetHeight;
                    if (TargetSetHeights.ContainsKey(idx))
                    {
                        TargetSetHeight = TargetSetHeights[idx];
                    }
                    else
                    {
                        float Hdiff = Consts.SliderValue2RealHeight(HeightSlider.value) - currentpos.y;
                        TargetSetHeight = currentpos.y + Hdiff
                                          * Consts.Smoothstep(0, 1, (RadiusSlider.value - dist) / RadiusSlider.value);
                        TargetSetHeights.Add(idx, TargetSetHeight);
                    }
                    Consts.former_heights[idx] += (TargetSetHeight - currentpos.y)
                                                  * Mathf.Pow(IntensitySlider.value * 5, 2) / 10000;
                    Consts.current_heights[idx] = Consts.former_heights[idx];
                    UndoBuffer.AddVertexPair(currentpos, Consts.IndexToPos(idx));
                    indexes.Add(idx);
                }
            }
        }
        Consts.UpdateMapColliders(indexes);
        //Search for any tiles
        RaycastHit[] hits = Physics.BoxCastAll(new Vector3(Highlight.pos.x, Consts.MAX_H, Highlight.pos.z),
                                               new Vector3(RadiusSlider.value + .5f, 1, RadiusSlider.value + .5f),
                                               Vector3.down, Quaternion.identity, Consts.RAY_H, 1 << 9);
        List <GameObject> hitsList = hits.Select(hit => hit.transform.gameObject).ToList();

        Build.UpdateTiles(hitsList);
    }
    private void Smoothing()
    {
        HashSet <int> indexes = new HashSet <int>();

        for (float z = Highlight.pos.z - RadiusSlider.value; z <= Highlight.pos.z + RadiusSlider.value; z++)
        {
            for (float x = Highlight.pos.x - RadiusSlider.value; x <= Highlight.pos.x + RadiusSlider.value; x++)
            {
                if (Consts.IsWithinMapBounds(x, z))
                {
                    int     idx        = Consts.PosToIndex((int)x, (int)z);
                    Vector3 currentpos = Consts.IndexToPos(idx);
                    float   dist       = Consts.Distance(currentpos, Highlight.pos);
                    if (Mathf.Round(dist) > RadiusSlider.value - 1)
                    {
                        continue;
                    }

                    float height_sum = 0;
                    for (float xx = currentpos.x - 1; xx <= currentpos.x + 1; xx++)
                    {
                        for (float zz = currentpos.z - 1; zz <= currentpos.z + 1; zz++)
                        {
                            if (xx == currentpos.x && zz == currentpos.z)
                            {
                                continue;
                            }
                            Vector3 neighbor_pos = new Vector3(xx, 0, zz);
                            height_sum += Consts.current_heights[Consts.PosToIndex(neighbor_pos)];
                        }
                    }
                    float avg = height_sum / 8f;

                    Vector3 for_buffer = Consts.IndexToPos(idx);
                    Consts.current_heights[idx] += (avg - Consts.current_heights[idx])
                                                   * Mathf.Pow(IntensitySlider.value * 5, 2) / 10000;
                    Consts.former_heights[idx] = Consts.current_heights[idx];
                    UndoBuffer.AddVertexPair(for_buffer, Consts.IndexToPos(idx));
                    indexes.Add(idx);
                }
            }
        }
        Consts.UpdateMapColliders(indexes);
        //Search for any tiles
        RaycastHit[] hits = Physics.BoxCastAll(new Vector3(Highlight.pos.x, Consts.MAX_H, Highlight.pos.z),
                                               new Vector3(RadiusSlider.value + 1, 1, RadiusSlider.value),
                                               Vector3.down, Quaternion.identity, Consts.RAY_H, 1 << 9);
        List <GameObject> hitsList = hits.Select(hit => hit.transform.gameObject).ToList();

        Build.UpdateTiles(hitsList);
    }
    public void ApplyPath()
    {
        if (RoadMesh == null)
        {
            return;
        }
        Vector3Int    minV    = Vector3Int.RoundToInt(RoadMesh.GetComponent <MeshFilter>().mesh.bounds.min);
        Vector3Int    maxV    = Vector3Int.RoundToInt(RoadMesh.GetComponent <MeshFilter>().mesh.bounds.max);
        HashSet <int> indexes = new HashSet <int>();

        for (int x = minV.x; x <= maxV.x; x++)
        {
            for (int z = minV.z; z <= maxV.z; z++)
            {
                if (!Consts.IsWithinMapBounds(x, z))
                {
                    continue;
                }
                if (Physics.Raycast(new Vector3(x, Consts.MAX_H, z), Vector3.down, out RaycastHit hit, Consts.RAY_H, 1 << 14))
                {
                    int idx = Consts.PosToIndex(x, z);
                    indexes.Add(idx);
                    Vector3 for_buffer = Consts.IndexToPos(idx);
                    Consts.former_heights[idx]  = hit.point.y;
                    Consts.current_heights[idx] = Consts.former_heights[idx];
                    UndoBuffer.AddVertexPair(for_buffer, Consts.IndexToPos(idx));
                }
            }
        }
        Consts.UpdateMapColliders(indexes);
        //Search for any tiles
        var surr = Build.Get_surrounding_tiles(indexes);

        Build.UpdateTiles(surr);
        UndoBuffer.ApplyTerrainOperation();
        RemovePreview();
    }
    private void Amplification(int dir = 1)
    {
        // Highlight.pos is center vertex
        HashSet <int> indexes = new HashSet <int>();

        for (float z = Highlight.pos.z - RadiusSlider.value; z <= Highlight.pos.z + RadiusSlider.value; z++)
        {
            for (float x = Highlight.pos.x - RadiusSlider.value; x <= Highlight.pos.x + RadiusSlider.value; x++)
            {
                if (Consts.IsWithinMapBounds(x, z))
                {
                    int   idx        = Consts.PosToIndex((int)x, (int)z);
                    float heightdiff = Consts.current_heights[idx] - Consts.SliderValue2RealHeight(HeightSlider.value);
                    float dist       = Consts.Distance(Consts.IndexToPos(idx), Highlight.pos);
                    if (Mathf.Round(dist) > RadiusSlider.value - 1)
                    {
                        continue;
                    }
                    Vector3 for_buffer = Consts.IndexToPos(idx);
                    Consts.former_heights[idx] += dir * heightdiff * Mathf.Pow(IntensitySlider.value * 2, 2) / 20000
                                                  * Consts.Smoothstep(0, 1, (RadiusSlider.value - dist) / RadiusSlider.value);
                    Consts.current_heights[idx] = Consts.former_heights[idx];
                    UndoBuffer.AddVertexPair(for_buffer, Consts.IndexToPos(idx));
                    indexes.Add(idx);
                }
            }
        }
        Consts.UpdateMapColliders(indexes);
        //Search for any tiles
        RaycastHit[] hits = Physics.BoxCastAll(new Vector3(Highlight.pos.x, Consts.MAX_H, Highlight.pos.z),
                                               new Vector3(RadiusSlider.value + 1, 1, RadiusSlider.value),
                                               Vector3.down, Quaternion.identity, Consts.RAY_H, 1 << 9);
        List <GameObject> hitsList = hits.Select(hit => hit.transform.gameObject).ToList();

        Build.UpdateTiles(hitsList);
    }
    private void PasteSelectionOntoTerrain()
    {
        if (CopyClipboard.Count == 0)
        {
            return;
        }

        //Indexes of vertices for UpdateMapColliders()
        HashSet <int> indexes = new HashSet <int>();

        foreach (var mrk in CopyClipboard)
        {
            Vector3 pom = Highlight.pos + mrk;
            if (Consts.IsWithinMapBounds(pom))
            {
                // Update arrays of vertex heights
                int newindex = Consts.PosToIndex(pom);
                indexes.Add(newindex);
                Vector3 for_buffer = Consts.IndexToPos(newindex);
                if (pastingMode == PastingMode.fixed_height)
                {
                    Consts.current_heights[newindex] = fixed_height + mrk.y;
                    Consts.former_heights[newindex]  = fixed_height + mrk.y;
                }
                else if (pastingMode == PastingMode.addition)
                {
                    Consts.current_heights[newindex] = pom.y;
                    Consts.former_heights[newindex]  = pom.y;
                }
                UndoBuffer.AddVertexPair(for_buffer, Consts.IndexToPos(newindex));
            }
        }
        Consts.UpdateMapColliders(indexes);
        UndoBuffer.ApplyTerrainOperation();
        Build.UpdateTiles(Build.Get_surrounding_tiles(Markings, true));
    }
    private void RectangularElevation()
    {
        if (P1.x == -1)
        {
            // Get initial position and set znacznik there
            P1        = Highlight.pos;
            P1_marker = GameObject.CreatePrimitive(PrimitiveType.Cube);
            P1_marker.transform.localScale = new Vector3(.25f, 1, .25f);
            P1_marker.transform.position   = Highlight.pos;
        }
        else
        {
            // Time to get second position
            Vector3       P2      = Highlight.pos;
            Vector3       BL      = new Vector3(Mathf.Min(P1.x, P2.x), 0, Mathf.Min(P1.z, P2.z));
            Vector3       TR      = new Vector3(Mathf.Max(P1.x, P2.x), 0, Mathf.Max(P1.z, P2.z));
            HashSet <int> indexes = new HashSet <int>();
            for (float z = BL.z - (int)RadiusSlider.value; z <= TR.z + RadiusSlider.value; z++)
            {
                for (float x = BL.x - (int)RadiusSlider.value; x <= TR.x + RadiusSlider.value; x++)
                {
                    if (Consts.IsWithinMapBounds(x, z))
                    {
                        int     idx        = Consts.PosToIndex((int)x, (int)z);
                        Vector3 currentpos = Consts.IndexToPos(idx);
                        if (x >= BL.x && x <= TR.x && z >= BL.z && z <= TR.z)
                        {
                            Consts.former_heights[idx] = Consts.SliderValue2RealHeight(HeightSlider.value);
                        }
                        else
                        {
                            Vector3 Closest = GetClosestEdgeVertex(currentpos, BL, TR);
                            float   dist    = Consts.Distance(currentpos, Closest);
                            if (Mathf.Round(dist) > RadiusSlider.value - 1)
                            {
                                continue;
                            }
                            float Hdiff = Consts.SliderValue2RealHeight(HeightSlider.value) - Consts.current_heights[idx];
                            Consts.former_heights[idx] += Hdiff * Consts.Smoothstep(0, 1, (RadiusSlider.value - dist) / RadiusSlider.value);
                        }
                        Consts.current_heights[idx] = Consts.former_heights[idx];
                        UndoBuffer.AddVertexPair(currentpos, Consts.IndexToPos(idx));
                        indexes.Add(idx);
                    }
                }
            }
            Consts.UpdateMapColliders(indexes);
            Vector3 center = new Vector3(0.5f * (P1.x + P2.x), Consts.MAX_H, 0.5f * (P1.z + P2.z));
            Vector3 bounds = new Vector3(0.5f * Mathf.Abs(P1.x - P2.x) + RadiusSlider.value + .5f, 1f,
                                         0.5f * Mathf.Abs(P1.z - P2.z) + RadiusSlider.value + .5f);
            RaycastHit[] hits = Physics.BoxCastAll(center, bounds, Vector3.down, Quaternion.identity, Consts.RAY_H, 1 << 9);
            Build.UpdateTiles(hits.Select(hit => hit.transform.gameObject).ToList());
            UndoBuffer.ApplyTerrainOperation();
            RemoveIndicator();
        }

        Vector3 GetClosestEdgeVertex(Vector3 v, Vector3 LD, Vector3 PG)
        {
            Vector3 result = new Vector3();

            if (v.x < LD.x)
            {
                result.x = LD.x;
            }
            else if (v.x > PG.x)
            {
                result.x = PG.x;
            }
            else
            {
                result.x = v.x;
            }

            if (v.z < LD.z)
            {
                result.z = LD.z;
            }
            else if (v.z > PG.z)
            {
                result.z = PG.z;
            }
            else
            {
                result.z = v.z;
            }
            return(result);
        }
    }