From aeb0ccff90bbb6655dab2ad08b1a70d859dc25f8 Mon Sep 17 00:00:00 2001
From: Nelsson Huotari <unelsson@gmail.com>
Date: Mon, 4 Nov 2019 12:16:08 +0200
Subject: [PATCH 1/3] Allow selecting cell edges everywhere

---
 apps/opencs/view/render/terrainshapemode.cpp | 23 ++++++++++++++++----
 apps/opencs/view/render/terrainshapemode.hpp |  3 +++
 2 files changed, 22 insertions(+), 4 deletions(-)

diff --git a/apps/opencs/view/render/terrainshapemode.cpp b/apps/opencs/view/render/terrainshapemode.cpp
index af97e4d8f7..d7b4684d6b 100644
--- a/apps/opencs/view/render/terrainshapemode.cpp
+++ b/apps/opencs/view/render/terrainshapemode.cpp
@@ -1038,6 +1038,21 @@ bool CSVRender::TerrainShapeMode::isInCellSelection(int globalSelectionX, int gl
     return false;
 }
 
+void CSVRender::TerrainShapeMode::handleSelection(int globalSelectionX, int globalSelectionY, std::vector<std::pair<int, int>>* selections)
+{
+    if (isInCellSelection(globalSelectionX, globalSelectionY)) selections->emplace_back(globalSelectionX, globalSelectionY);
+    else
+    {
+        int moduloX = globalSelectionX % (ESM::Land::LAND_SIZE - 1);
+        int moduloY = globalSelectionY % (ESM::Land::LAND_SIZE - 1);
+        bool xIsAtCellBorder = moduloX == 0;
+        bool yIsAtCellBorder = moduloY == 0;
+        if (isInCellSelection(globalSelectionX - 1, globalSelectionY) && xIsAtCellBorder && !yIsAtCellBorder) selections->emplace_back(globalSelectionX, globalSelectionY);
+        if (isInCellSelection(globalSelectionX, globalSelectionY - 1) && !xIsAtCellBorder && yIsAtCellBorder) selections->emplace_back(globalSelectionX, globalSelectionY);
+        if (isInCellSelection(globalSelectionX - 1, globalSelectionY - 1) && xIsAtCellBorder && yIsAtCellBorder) selections->emplace_back(globalSelectionX, globalSelectionY);
+    }
+}
+
 void CSVRender::TerrainShapeMode::selectTerrainShapes(const std::pair<int, int>& vertexCoords, unsigned char selectMode, bool dragOperation)
 {
     int r = mBrushSize / 2;
@@ -1045,7 +1060,7 @@ void CSVRender::TerrainShapeMode::selectTerrainShapes(const std::pair<int, int>&
 
     if (mBrushShape == CSVWidget::BrushShape_Point)
     {
-        if (isInCellSelection(vertexCoords.first, vertexCoords.second)) selections.emplace_back(vertexCoords.first, vertexCoords.second);
+        handleSelection(vertexCoords.first, vertexCoords.second, &selections);
     }
 
     if (mBrushShape == CSVWidget::BrushShape_Square)
@@ -1054,7 +1069,7 @@ void CSVRender::TerrainShapeMode::selectTerrainShapes(const std::pair<int, int>&
         {
             for(int j = vertexCoords.second - r; j <= vertexCoords.second + r; ++j)
             {
-                if (isInCellSelection(i, j)) selections.emplace_back(i, j);
+                handleSelection(i, j, &selections);
             }
         }
     }
@@ -1068,7 +1083,7 @@ void CSVRender::TerrainShapeMode::selectTerrainShapes(const std::pair<int, int>&
                 int distanceX = abs(i - vertexCoords.first);
                 int distanceY = abs(j - vertexCoords.second);
                 int distance = std::round(sqrt(pow(distanceX, 2)+pow(distanceY, 2)));
-                if (isInCellSelection(i, j) && distance <= r) selections.emplace_back(i, j);
+                if (distance <= r) handleSelection(i, j, &selections);
             }
         }
     }
@@ -1081,7 +1096,7 @@ void CSVRender::TerrainShapeMode::selectTerrainShapes(const std::pair<int, int>&
             {
                 std::pair<int, int> localVertexCoords (vertexCoords.first + value.first, vertexCoords.second + value.second);
                 std::string cellId (CSMWorld::CellCoordinates::vertexGlobalToCellId(localVertexCoords));
-                if (isInCellSelection(localVertexCoords.first, localVertexCoords.second)) selections.emplace_back(localVertexCoords);
+                handleSelection(localVertexCoords.first, localVertexCoords.second, &selections);
             }
         }
     }
diff --git a/apps/opencs/view/render/terrainshapemode.hpp b/apps/opencs/view/render/terrainshapemode.hpp
index 605827c9e4..ce2ea5465e 100644
--- a/apps/opencs/view/render/terrainshapemode.hpp
+++ b/apps/opencs/view/render/terrainshapemode.hpp
@@ -134,6 +134,9 @@ namespace CSVRender
             /// Check if global selection coordinate belongs to cell in view
             bool isInCellSelection(int globalSelectionX, int globalSelectionY);
 
+            /// Select vertex at global selection coordinate
+            void handleSelection(int globalSelectionX, int globalSelectionY, std::vector<std::pair<int, int>>* selections);
+
             /// Handle brush mechanics for terrain shape selection
             void selectTerrainShapes (const std::pair<int, int>& vertexCoords, unsigned char selectMode, bool dragOperation);
 

From 45d43045eb0032c970e620bdaa3f882378f158c2 Mon Sep 17 00:00:00 2001
From: Nelsson Huotari <unelsson@gmail.com>
Date: Mon, 4 Nov 2019 12:29:37 +0200
Subject: [PATCH 2/3] Remove unused std::string

---
 apps/opencs/view/render/terrainshapemode.cpp | 1 -
 1 file changed, 1 deletion(-)

diff --git a/apps/opencs/view/render/terrainshapemode.cpp b/apps/opencs/view/render/terrainshapemode.cpp
index d7b4684d6b..ee6492a87d 100644
--- a/apps/opencs/view/render/terrainshapemode.cpp
+++ b/apps/opencs/view/render/terrainshapemode.cpp
@@ -1095,7 +1095,6 @@ void CSVRender::TerrainShapeMode::selectTerrainShapes(const std::pair<int, int>&
             for(auto const& value: mCustomBrushShape)
             {
                 std::pair<int, int> localVertexCoords (vertexCoords.first + value.first, vertexCoords.second + value.second);
-                std::string cellId (CSMWorld::CellCoordinates::vertexGlobalToCellId(localVertexCoords));
                 handleSelection(localVertexCoords.first, localVertexCoords.second, &selections);
             }
         }

From 120583f443f5cec487f235dd2c07b0892d2ecf27 Mon Sep 17 00:00:00 2001
From: Nelsson Huotari <unelsson@gmail.com>
Date: Thu, 14 Nov 2019 11:28:49 +0200
Subject: [PATCH 3/3] optimize isInCellSelection calls

---
 apps/opencs/view/render/terrainshapemode.cpp | 13 ++++++++++---
 1 file changed, 10 insertions(+), 3 deletions(-)

diff --git a/apps/opencs/view/render/terrainshapemode.cpp b/apps/opencs/view/render/terrainshapemode.cpp
index ee6492a87d..e73887615c 100644
--- a/apps/opencs/view/render/terrainshapemode.cpp
+++ b/apps/opencs/view/render/terrainshapemode.cpp
@@ -1047,9 +1047,16 @@ void CSVRender::TerrainShapeMode::handleSelection(int globalSelectionX, int glob
         int moduloY = globalSelectionY % (ESM::Land::LAND_SIZE - 1);
         bool xIsAtCellBorder = moduloX == 0;
         bool yIsAtCellBorder = moduloY == 0;
-        if (isInCellSelection(globalSelectionX - 1, globalSelectionY) && xIsAtCellBorder && !yIsAtCellBorder) selections->emplace_back(globalSelectionX, globalSelectionY);
-        if (isInCellSelection(globalSelectionX, globalSelectionY - 1) && !xIsAtCellBorder && yIsAtCellBorder) selections->emplace_back(globalSelectionX, globalSelectionY);
-        if (isInCellSelection(globalSelectionX - 1, globalSelectionY - 1) && xIsAtCellBorder && yIsAtCellBorder) selections->emplace_back(globalSelectionX, globalSelectionY);
+        if (!xIsAtCellBorder && !yIsAtCellBorder)
+            return;
+        int selectionX = globalSelectionX;
+        int selectionY = globalSelectionY;
+        if (xIsAtCellBorder)
+            selectionX--;
+        if (yIsAtCellBorder)
+            selectionY--;
+        if (isInCellSelection(selectionX, selectionY))
+            selections->emplace_back(globalSelectionX, globalSelectionY);
     }
 }