| File: ArcFlattener.cs | Web Access |
| Project: src\src\Graphics\src\Graphics\Graphics.csproj (Microsoft.Maui.Graphics) |
using System; namespace Microsoft.Maui.Graphics { internal class ArcFlattener { private float _cx; private float _cy; private float _diameter; private float _radius; private float _fx; private float _fy; private float _sweep; private float _startAngle; private PointF _startPoint; public ArcFlattener( float x, float y, float width, float height, float startAngle, float endAngle, bool clockwise) { _startAngle = startAngle; _cx = x + (width / 2); _cy = y + (height / 2); _diameter = Math.Max(width, height); _radius = _diameter / 2; _fx = width / _diameter; _fy = height / _diameter; _sweep = Math.Abs(endAngle - startAngle); if (clockwise) _sweep *= -1; _startPoint = GetPointOnArc(0); } private PointF GetPointOnArc( float percentage) { var angle = _startAngle + (_sweep * percentage); while (angle >= 360) angle -= 360; angle *= -1; var radians = (float)GeometryUtil.DegreesToRadians(angle); var point = GetPointAtAngle(0, 0, _radius, radians); point.X = _cx + (point.X * _fx); point.Y = _cy + (point.Y * _fy); return point; } private static PointF GetPointAtAngle( float x, float y, float distance, float radians) { var x2 = x + (Math.Cos(radians) * distance); var y2 = y + (Math.Sin(radians) * distance); return new PointF((float)x2, (float)y2); } private static PointF GetCenter(PointF point1, PointF point2) { var x = (point1.X + point2.X) / 2; var y = (point1.Y + point2.Y) / 2; return new PointF(x, y); } public PathF CreateFlattenedPath( float flatness = .5f) { var found = false; var n = 1; PointF? endPoint = null; while ((!found) && (n < 1024)) { var candidate = 1f / (float)n; var midPointOnArc = GetPointOnArc(candidate / 2); if (endPoint == null) endPoint = GetPointOnArc(candidate); var midPointOnLine = GetCenter(_startPoint, (PointF)endPoint); if (GeometryUtil.GetDistance(midPointOnArc.X, midPointOnArc.Y, midPointOnLine.X, midPointOnLine.Y) <= flatness) { found = true; n = n << 1; } else { endPoint = midPointOnArc; n++; } } var path = new PathF(); path.MoveTo(_startPoint); float step = 1f / n; float percentage = 0; for (var i = 1; i < n; i++) { percentage += step; var point = GetPointOnArc(percentage); path.LineTo(point); } path.LineTo(GetPointOnArc(1)); return path; } } }