|
using System;
using System.Collections.Generic;
using CoreGraphics;
using Microsoft.Maui.Controls.Shapes;
using Microsoft.Maui.Graphics;
using ObjCRuntime;
using Geometry = Microsoft.Maui.Controls.Shapes.Geometry;
#if __MOBILE__
namespace Microsoft.Maui.Controls.Compatibility.Platform.iOS
#else
namespace Microsoft.Maui.Controls.Compatibility.Platform.MacOS
#endif
{
public static class GeometryExtensions
{
public static PathData ToCGPath(this Geometry geometry, Transform renderTransform = null)
{
PathData pathData = new PathData
{
Data = new CGPath()
};
CGAffineTransform transform;
if (renderTransform == null)
transform = CGAffineTransform.MakeIdentity();
else
transform = renderTransform.ToCGAffineTransform();
if (geometry is LineGeometry)
{
LineGeometry lineGeometry = geometry as LineGeometry;
pathData.Data.MoveToPoint(transform, lineGeometry.StartPoint.ToPointF());
pathData.Data.AddLineToPoint(transform, lineGeometry.EndPoint.ToPointF());
}
else if (geometry is RectangleGeometry)
{
var rect = (geometry as RectangleGeometry).Rect;
pathData.Data.AddRect(transform, new CGRect(rect.X, rect.Y, rect.Width, rect.Height));
}
else if (geometry is EllipseGeometry)
{
EllipseGeometry ellipseGeometry = geometry as EllipseGeometry;
CGRect rect = new CGRect(
ellipseGeometry.Center.X - ellipseGeometry.RadiusX,
ellipseGeometry.Center.Y - ellipseGeometry.RadiusY,
ellipseGeometry.RadiusX * 2,
ellipseGeometry.RadiusY * 2);
pathData.Data.AddEllipseInRect(transform, rect);
}
else if (geometry is GeometryGroup)
{
GeometryGroup geometryGroup = geometry as GeometryGroup;
pathData.IsNonzeroFillRule = geometryGroup.FillRule == FillRule.Nonzero;
foreach (Geometry child in geometryGroup.Children)
{
PathData pathChild = child.ToCGPath(renderTransform);
pathData.Data.AddPath(pathChild.Data);
}
}
else if (geometry is PathGeometry)
{
PathGeometry pathGeometry = geometry as PathGeometry;
pathData.IsNonzeroFillRule = pathGeometry.FillRule == FillRule.Nonzero;
foreach (PathFigure pathFigure in pathGeometry.Figures)
{
pathData.Data.MoveToPoint(transform, pathFigure.StartPoint.ToPointF());
Point lastPoint = pathFigure.StartPoint;
foreach (PathSegment pathSegment in pathFigure.Segments)
{
// LineSegment
if (pathSegment is LineSegment)
{
LineSegment lineSegment = pathSegment as LineSegment;
pathData.Data.AddLineToPoint(transform, lineSegment.Point.ToPointF());
lastPoint = lineSegment.Point;
}
// PolyLineSegment
else if (pathSegment is PolyLineSegment)
{
PolyLineSegment polylineSegment = pathSegment as PolyLineSegment;
PointCollection points = polylineSegment.Points;
for (int i = 0; i < points.Count; i++)
pathData.Data.AddLineToPoint(transform, points[i].ToPointF());
lastPoint = points.Count > 0 ? points[points.Count - 1] : Point.Zero;
}
// BezierSegment
if (pathSegment is BezierSegment)
{
BezierSegment bezierSegment = pathSegment as BezierSegment;
pathData.Data.AddCurveToPoint(
transform,
bezierSegment.Point1.ToPointF(),
bezierSegment.Point2.ToPointF(),
bezierSegment.Point3.ToPointF());
lastPoint = bezierSegment.Point3;
}
// PolyBezierSegment
else if (pathSegment is PolyBezierSegment)
{
PolyBezierSegment polyBezierSegment = pathSegment as PolyBezierSegment;
PointCollection points = polyBezierSegment.Points;
if (points.Count >= 3)
{
for (int i = 0; i < points.Count; i += 3)
{
pathData.Data.AddCurveToPoint(
transform,
points[i].ToPointF(),
points[i + 1].ToPointF(),
points[i + 2].ToPointF());
}
}
lastPoint = points.Count > 0 ? points[points.Count - 1] : Point.Zero;
}
// QuadraticBezierSegment
if (pathSegment is QuadraticBezierSegment)
{
QuadraticBezierSegment bezierSegment = pathSegment as QuadraticBezierSegment;
pathData.Data.AddQuadCurveToPoint(
transform,
new nfloat(bezierSegment.Point1.X),
new nfloat(bezierSegment.Point1.Y),
new nfloat(bezierSegment.Point2.X),
new nfloat(bezierSegment.Point2.Y));
lastPoint = bezierSegment.Point2;
}
// PolyQuadraticBezierSegment
else if (pathSegment is PolyQuadraticBezierSegment)
{
PolyQuadraticBezierSegment polyBezierSegment = pathSegment as PolyQuadraticBezierSegment;
PointCollection points = polyBezierSegment.Points;
if (points.Count >= 2)
{
for (int i = 0; i < points.Count; i += 2)
{
pathData.Data.AddQuadCurveToPoint(
transform,
new nfloat(points[i + 0].X),
new nfloat(points[i + 0].Y),
new nfloat(points[i + 1].X),
new nfloat(points[i + 1].Y));
}
}
lastPoint = points.Count > 0 ? points[points.Count - 1] : Point.Zero;
}
// ArcSegment
else if (pathSegment is ArcSegment)
{
ArcSegment arcSegment = pathSegment as ArcSegment;
List<Point> points = new List<Point>();
GeometryHelper.FlattenArc(
points,
lastPoint,
arcSegment.Point,
arcSegment.Size.Width,
arcSegment.Size.Height,
arcSegment.RotationAngle,
arcSegment.IsLargeArc,
arcSegment.SweepDirection == SweepDirection.CounterClockwise,
1);
CGPoint[] cgpoints = new CGPoint[points.Count];
for (int i = 0; i < points.Count; i++)
cgpoints[i] = transform.TransformPoint(points[i].ToPointF());
pathData.Data.AddLines(cgpoints);
lastPoint = points.Count > 0 ? points[points.Count - 1] : Point.Zero;
}
}
if (pathFigure.IsClosed)
pathData.Data.CloseSubpath();
}
}
return pathData;
}
}
}
|