From 6c8a3cb50b8974d85cf730312eca900b431ccdcd Mon Sep 17 00:00:00 2001 From: biwa <6475593+biwa@users.noreply.github.com> Date: Mon, 5 Apr 2021 19:15:14 +0200 Subject: [PATCH] Visual Mode: things inside self-referencing sectors are now displayed at the correct height --- Source/Core/Map/Sector.cs | 15 ++++++--- Source/Core/Map/Thing.cs | 37 ++++++++++++++++++--- Source/Core/VisualModes/VisualBlockMap.cs | 40 ++++++++++++++++++----- 3 files changed, 75 insertions(+), 17 deletions(-) diff --git a/Source/Core/Map/Sector.cs b/Source/Core/Map/Sector.cs index 8047f5d64..7ad3d227e 100755 --- a/Source/Core/Map/Sector.cs +++ b/Source/Core/Map/Sector.cs @@ -546,6 +546,9 @@ namespace CodeImp.DoomBuilder.Map // This checks if the given point is inside the sector polygon // See: http://paulbourke.net/geometry/polygonmesh/index.html#insidepoly + // This checks for the linedefs instead of the sidedefs, since self-referencing sectors + // will never result in an odd number of intersections when using sidedefs, since both + // sidedefs of the outer linedef belong to the same sector public bool Intersect(Vector2D p) { return Intersect(p, true); } public bool Intersect(Vector2D p, bool countontopastrue) { @@ -554,13 +557,17 @@ namespace CodeImp.DoomBuilder.Map uint c = 0; Vector2D v1, v2; + HashSet<Linedef> linedefs = new HashSet<Linedef>(sidedefs.Count); + + foreach (Sidedef sd in sidedefs) + linedefs.Add(sd.Line); - // Go for all sidedefs - foreach(Sidedef sd in sidedefs) + // Go for all linedefs + foreach(Linedef ld in linedefs) { // Get vertices - v1 = sd.Line.Start.Position; - v2 = sd.Line.End.Position; + v1 = ld.Start.Position; + v2 = ld.End.Position; //mxd. On top of a vertex? if(p == v1 || p == v2) return countontopastrue; diff --git a/Source/Core/Map/Thing.cs b/Source/Core/Map/Thing.cs index 23e44224c..7105fb4cd 100755 --- a/Source/Core/Map/Thing.cs +++ b/Source/Core/Map/Thing.cs @@ -273,19 +273,46 @@ namespace CodeImp.DoomBuilder.Map public void DetermineSector(BlockMap<BlockEntry> blockmap) { BlockEntry be = blockmap.GetBlockAt(pos); + List<Sector> sectors = new List<Sector>(1); foreach (Sector s in be.Sectors) if (s.Intersect(pos)) - { - sector = s; - return; - } + sectors.Add(s); + + if(sectors.Count == 0) + { + sector = null; + } + if (sectors.Count == 1) + { + sector = sectors[0]; + } + else + { + // Having multiple intersections indicates that there are self-referencing sectors in this spot. + // In this case we have to check which side of the nearest linedef pos is on, and then use that sector + HashSet<Linedef> linedefs = new HashSet<Linedef>(sectors[0].Sidedefs.Count * sectors.Count); + + foreach (Sector s in sectors) + foreach (Sidedef sd in s.Sidedefs) + linedefs.Add(sd.Line); + + Linedef nearest = MapSet.NearestLinedef(linedefs, pos); + double d = nearest.SideOfLine(pos); + + if (d <= 0.0 && nearest.Front != null) + sector = nearest.Front.Sector; + else if (nearest.Back != null) + sector = nearest.Back.Sector; + else + sector = null; + } } // This determines which sector the thing is in and links it public void DetermineSector(VisualBlockMap blockmap) { - sector = blockmap.GetSectorAt(pos); + sector = blockmap.GetSectorAt(pos); } // This translates the flags into UDMF fields diff --git a/Source/Core/VisualModes/VisualBlockMap.cs b/Source/Core/VisualModes/VisualBlockMap.cs index 9a985921a..5a4c9641b 100755 --- a/Source/Core/VisualModes/VisualBlockMap.cs +++ b/Source/Core/VisualModes/VisualBlockMap.cs @@ -76,16 +76,40 @@ namespace CodeImp.DoomBuilder.VisualModes public Sector GetSectorAt(Vector2D pos) { - foreach (VisualBlockEntry e in GetBlocks(pos)) - { + List<Sector> sectors = new List<Sector>(1); + + foreach (VisualBlockEntry e in GetBlocks(pos)) foreach (Sector s in e.Sectors) - { if (s.Intersect(pos)) - { - return s; - } - } - } + sectors.Add(s); + + if (sectors.Count == 0) + { + return null; + } + else if (sectors.Count == 1) + { + return sectors[0]; + } + else + { + // Having multiple intersections indicates that there are self-referencing sectors in this spot. + // In this case we have to check which side of the nearest linedef pos is on, and then use that sector + HashSet<Linedef> linedefs = new HashSet<Linedef>(sectors[0].Sidedefs.Count * sectors.Count); + + foreach (Sector s in sectors) + foreach (Sidedef sd in s.Sidedefs) + linedefs.Add(sd.Line); + + Linedef nearest = MapSet.NearestLinedef(linedefs, pos); + double d = nearest.SideOfLine(pos); + + if (d <= 0.0 && nearest.Front != null) + return nearest.Front.Sector; + else if (nearest.Back != null) + return nearest.Back.Sector; + } + return null; } -- GitLab