From 1187f5c9f2bbfd471b1e504c98bdd1a36c32ff32 Mon Sep 17 00:00:00 2001 From: CarnifexOptimus <156172553+CarnifexOptimus@users.noreply.github.com> Date: Sun, 9 Feb 2025 20:54:08 +0100 Subject: [PATCH] hitching is forbidden --- BossMod/Util/Polygon.cs | 72 ++++++++++++++++++++--------------------- 1 file changed, 35 insertions(+), 37 deletions(-) diff --git a/BossMod/Util/Polygon.cs b/BossMod/Util/Polygon.cs index 0cf28263ae..6f99eee683 100644 --- a/BossMod/Util/Polygon.cs +++ b/BossMod/Util/Polygon.cs @@ -1,5 +1,6 @@ using Clipper2Lib; using EarcutNet; +using System.Threading; // currently we use Clipper2 library (based on Vatti algorithm) for boolean operations and Earcut.net library (earcutting) for triangulating // note: the major user of these primitives is bounds clipper; since they operate in 'local' coordinates, we use WDir everywhere (offsets from center) and call that 'relative polygons' - i'm not quite happy with that, it's not very intuitive @@ -89,50 +90,47 @@ public bool Contains(WDir p) ref var edgeBuckets = ref _edgeBuckets; if (edgeBuckets == null) { - lock (_edgeBucketLock) + var holecount = HoleStarts.Count; + ContourEdgeBuckets[] holeEdgeBuckets; + var exteriorTask = Task.Run(() => BuildEdgeBucketsForContour(Exterior)); + switch (holecount) { - // Double-check to prevent race conditions - if (_edgeBuckets == null) - { - var exteriorTask = Task.Run(() => BuildEdgeBucketsForContour(Exterior)); - var holecount = HoleStarts.Count; - ContourEdgeBuckets[] holeEdgeBuckets; - switch (holecount) + case 0: + holeEdgeBuckets = []; + break; + case 1: + holeEdgeBuckets = new ContourEdgeBuckets[1]; + holeEdgeBuckets[0] = Task.Run(() => BuildEdgeBucketsForContour(Interior(0))).Result; + break; + default: + holeEdgeBuckets = new ContourEdgeBuckets[holecount]; + var holeTasks = new Task[holecount]; + for (var i = 0; i < holecount; ++i) { - case 0: - holeEdgeBuckets = []; - break; - case 1: - holeEdgeBuckets = new ContourEdgeBuckets[1]; - holeEdgeBuckets[0] = Task.Run(() => BuildEdgeBucketsForContour(Interior(0))).Result; - break; - default: - holeEdgeBuckets = new ContourEdgeBuckets[holecount]; - var holeTasks = new Task[holecount]; - for (var i = 0; i < holecount; ++i) - { - var index = i; - holeTasks[i] = Task.Run(() => - { - holeEdgeBuckets[index] = BuildEdgeBucketsForContour(Interior(index)); - }); - } - Task.WaitAll(holeTasks); - break; + holeTasks[i] = Task.Run(() => + { + holeEdgeBuckets[i] = BuildEdgeBucketsForContour(Interior(i)); + }); } - edgeBuckets = new EdgeBuckets(exteriorTask.Result, holeEdgeBuckets); - } + Task.WaitAll(holeTasks); + break; } - } - if (!InSimplePolygon(p, edgeBuckets!.ExteriorEdgeBuckets)) - return false; + var newEdgeBuckets = new EdgeBuckets(exteriorTask.Result, holeEdgeBuckets); + var original = Interlocked.CompareExchange(ref _edgeBuckets, newEdgeBuckets, null); - for (var i = 0; i < edgeBuckets.HoleEdgeBuckets.Length; ++i) - { - if (InSimplePolygon(p, edgeBuckets.HoleEdgeBuckets[i])) - return false; + edgeBuckets = original ?? newEdgeBuckets; } + + if (!InSimplePolygon(p, edgeBuckets.ExteriorEdgeBuckets)) + return false; + var len = edgeBuckets.HoleEdgeBuckets.Length; + if (len != 0) + for (var i = 0; i < len; ++i) + { + if (InSimplePolygon(p, edgeBuckets.HoleEdgeBuckets[i])) + return false; + } return true; }