From a2ec75d824b4bc80198a8937944ed84d7f904158 Mon Sep 17 00:00:00 2001 From: OliBomby Date: Thu, 7 Dec 2023 00:57:29 +0100 Subject: [PATCH] Fix illegal circle arc with center out of polygon --- .../Sliders/SliderPlacementBlueprint.cs | 39 ++++++++++++++----- 1 file changed, 29 insertions(+), 10 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderPlacementBlueprint.cs b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderPlacementBlueprint.cs index 5878c0e11b..e5dada19bb 100644 --- a/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderPlacementBlueprint.cs +++ b/osu.Game.Rulesets.Osu/Edit/Blueprints/Sliders/SliderPlacementBlueprint.cs @@ -379,37 +379,56 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders double loss = 0; Vector2? lastPoint = null; Vector2? lastVec = null; + Vector2? lastVec2 = null; int? lastDir = null; + int? lastDir2 = null; double totalWinding = 0; // Loop through the points and check if they are not too far away from the circular arc. // Also make sure it curves monotonically in one direction and at most one loop is done. foreach (var point in points) { - loss += Math.Pow((Vector2.Distance(point, circleArc.Centre) - circleArc.Radius) / length, 2); + var vec = point - circleArc.Centre; + loss += Math.Pow((vec.Length - circleArc.Radius) / length, 2); + + if (lastVec.HasValue) + { + double det = lastVec.Value.X * vec.Y - lastVec.Value.Y * vec.X; + int dir = Math.Sign(det); + + if (dir == 0) + continue; + + if (lastDir.HasValue && dir != lastDir) + return null; // Circle center is not inside the polygon + + lastDir = dir; + } + + lastVec = vec; if (lastPoint.HasValue) { - var vec = point - lastPoint.Value; + var vec2 = point - lastPoint.Value; - if (lastVec.HasValue) + if (lastVec2.HasValue) { - double dot = Vector2.Dot(vec, lastVec.Value); - double det = lastVec.Value.X * vec.Y - lastVec.Value.Y * vec.X; + double dot = Vector2.Dot(vec2, lastVec2.Value); + double det = lastVec2.Value.X * vec2.Y - lastVec2.Value.Y * vec2.X; double angle = Math.Atan2(det, dot); - int dir = Math.Sign(angle); + int dir2 = Math.Sign(angle); - if (dir == 0) + if (dir2 == 0) continue; - if (lastDir.HasValue && dir != lastDir) + if (lastDir2.HasValue && dir2 != lastDir2) return null; // Curvature changed, like in an S-shape totalWinding += Math.Abs(angle); - lastDir = dir; + lastDir2 = dir2; } - lastVec = vec; + lastVec2 = vec2; } lastPoint = point;