From 7e29ba30998a2013cbf9ab005bd9df4073adac07 Mon Sep 17 00:00:00 2001
From: biwa <6475593+biwa@users.noreply.github.com>
Date: Mon, 14 Aug 2023 23:00:42 +0200
Subject: [PATCH] 3D Floor Mode: fixed an issue where new control sectors could
 not be created if any sector's bounding box completely encompassed the
 Control Sector Area

---
 .../Plugins/3DFloorMode/ControlSectorArea.cs  | 107 +++++++++++++-----
 1 file changed, 81 insertions(+), 26 deletions(-)

diff --git a/Source/Plugins/3DFloorMode/ControlSectorArea.cs b/Source/Plugins/3DFloorMode/ControlSectorArea.cs
index 5d1f5e260..ceaf8a4ff 100644
--- a/Source/Plugins/3DFloorMode/ControlSectorArea.cs
+++ b/Source/Plugins/3DFloorMode/ControlSectorArea.cs
@@ -317,14 +317,15 @@ namespace CodeImp.DoomBuilder.ThreeDFloorMode
 					List<BlockEntry> blocks = blockmap.GetLineBlocks(
 						new Vector2D(x + 1, y - 1),
 						new Vector2D(x + gridsize - 1, y - gridsize + 1)
-					);
-
-					// The way our blockmap is built and queried we will always get exactly one block
-					if (blocks[0].Sectors.Count == 0)
-					{
-						positions.Add(new Vector2D(x + margin, y - margin));
-						numsectors--;
-					}
+					);
+
+					// The way our blockmap is built and queried we will always get exactly one block
+					// Try the next position of the current one is occupied by another sector
+					if (blocks[0].Sectors.Any(s => SectorInNewControlSectorSpace(x, y, s)))
+						continue;
+
+					positions.Add(new Vector2D(x + margin, y - margin));
+					numsectors--;
 
 					if (numsectors == 0)
 						return positions;
@@ -354,30 +355,84 @@ namespace CodeImp.DoomBuilder.ThreeDFloorMode
 					List<BlockEntry> blocks = blockmap.GetLineBlocks(
 						new Vector2D(x + 1, y - 1),
 						new Vector2D(x + gridsize - 1, y - gridsize + 1)
-					);
-
-					// The way our blockmap is built and queried we will always get exactly one block
-					if (blocks[0].Sectors.Count == 0)
-					{
-						Point p = new Point(x + margin, y - margin);
-
-						dv.Add(SectorVertex(p.X, p.Y));
-						dv.Add(SectorVertex(p.X + BuilderPlug.Me.ControlSectorArea.SectorSize, p.Y));
-						dv.Add(SectorVertex(p.X + BuilderPlug.Me.ControlSectorArea.SectorSize, p.Y - BuilderPlug.Me.ControlSectorArea.SectorSize));
-						dv.Add(SectorVertex(p.X, p.Y - BuilderPlug.Me.ControlSectorArea.SectorSize));
-						dv.Add(SectorVertex(p.X, p.Y));
-
-						numsectors--;
-
-						if (numsectors == 0)
-							return dv;
-					}
+					);
+
+					// The way our blockmap is built and queried we will always get exactly one block
+					// Try the next position of the current one is occupied by another sector
+					if (blocks[0].Sectors.Any(s => SectorInNewControlSectorSpace(x, y, s)))
+						continue;
+
+					Point p = new Point(x + margin, y - margin);
+
+					dv.Add(SectorVertex(p.X, p.Y));
+					dv.Add(SectorVertex(p.X + BuilderPlug.Me.ControlSectorArea.SectorSize, p.Y));
+					dv.Add(SectorVertex(p.X + BuilderPlug.Me.ControlSectorArea.SectorSize, p.Y - BuilderPlug.Me.ControlSectorArea.SectorSize));
+					dv.Add(SectorVertex(p.X, p.Y - BuilderPlug.Me.ControlSectorArea.SectorSize));
+					dv.Add(SectorVertex(p.X, p.Y));
+
+					numsectors--;
+
+					if (numsectors == 0)
+						return dv;
 				}
 			}
 
 			throw new NoSpaceInCSAException("No space left for control sectors");
 		}
 
+		/// <summary>
+		/// Checks if the given sector and position for the new control sector intersect in any way.
+		/// </summary>
+		/// <param name="x">Leftmost X position of the new control sector space</param>
+		/// <param name="y">Topmost Y position of the new control sector space</param>
+		/// <param name="sector">The sector to check against</param>
+		/// <returns>true if there's an intersection, false if there isn't</returns>
+		private bool SectorInNewControlSectorSpace(int x, int y, Sector sector)
+		{
+			RectangleF rect = new RectangleF(x + 1, y - 1, gridsize - 2, gridsize - 2);
+			HashSet<Vertex> sectorvertices = new HashSet<Vertex>();
+
+			// Any of the sector's sidedef's linedef's vertices inside the new control sector's space?
+			foreach (Sidedef sd in sector.Sidedefs)
+			{
+				sectorvertices.Add(sd.Line.Start);
+				sectorvertices.Add(sd.Line.End);
+			}
+
+			foreach (Vertex v in sectorvertices)
+				if (rect.Contains((float)v.Position.x, (float)v.Position.y))
+					return true;
+
+			// Any of the new vertex positions in the sector?
+			Vector2D[] points = new Vector2D[]
+			{
+				new Vector2D(x + 1, y - 1),
+				new Vector2D(x + gridsize - 1, y - 1),
+				new Vector2D(x + gridsize - 1, y + gridsize + 1),
+				new Vector2D(x + 1, y + gridsize + 1)
+			};
+
+			foreach (Vector2D v in points)
+				if (sector.Intersect(v))
+					return true;
+
+			// Any of the new lines and the sector's lines overlapping?
+			Line2D[] lines = new Line2D[]
+			{
+				new Line2D(points[0], points[1]),
+				new Line2D(points[1], points[2]),
+				new Line2D(points[2], points[3]),
+				new Line2D(points[3], points[0])
+			};
+
+			foreach (Sidedef sd in sector.Sidedefs)
+				foreach (Line2D line in lines)
+					if (Line2D.GetIntersection(sd.Line.Line, line))
+						return true;
+
+			return false;
+		}
+
 		public bool Inside(float x, float y)
 		{
 			return Inside(new Vector2D(x, y));
-- 
GitLab