Fix illegal circle arc with center out of polygon

This commit is contained in:
OliBomby 2023-12-07 00:57:29 +01:00
parent 89859b85b7
commit a2ec75d824
1 changed files with 29 additions and 10 deletions

View File

@ -379,37 +379,56 @@ private Vector2[] tryCircleArc(List<Vector2> segment)
double loss = 0; double loss = 0;
Vector2? lastPoint = null; Vector2? lastPoint = null;
Vector2? lastVec = null; Vector2? lastVec = null;
Vector2? lastVec2 = null;
int? lastDir = null; int? lastDir = null;
int? lastDir2 = null;
double totalWinding = 0; double totalWinding = 0;
// Loop through the points and check if they are not too far away from the circular arc. // 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. // Also make sure it curves monotonically in one direction and at most one loop is done.
foreach (var point in points) 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 (lastPoint.HasValue)
{
var vec = point - lastPoint.Value;
if (lastVec.HasValue) if (lastVec.HasValue)
{ {
double dot = Vector2.Dot(vec, lastVec.Value);
double det = lastVec.Value.X * vec.Y - lastVec.Value.Y * vec.X; double det = lastVec.Value.X * vec.Y - lastVec.Value.Y * vec.X;
double angle = Math.Atan2(det, dot); int dir = Math.Sign(det);
int dir = Math.Sign(angle);
if (dir == 0) if (dir == 0)
continue; continue;
if (lastDir.HasValue && dir != lastDir) if (lastDir.HasValue && dir != lastDir)
return null; // Curvature changed, like in an S-shape return null; // Circle center is not inside the polygon
totalWinding += Math.Abs(angle);
lastDir = dir; lastDir = dir;
} }
lastVec = vec; lastVec = vec;
if (lastPoint.HasValue)
{
var vec2 = point - lastPoint.Value;
if (lastVec2.HasValue)
{
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 dir2 = Math.Sign(angle);
if (dir2 == 0)
continue;
if (lastDir2.HasValue && dir2 != lastDir2)
return null; // Curvature changed, like in an S-shape
totalWinding += Math.Abs(angle);
lastDir2 = dir2;
}
lastVec2 = vec2;
} }
lastPoint = point; lastPoint = point;