|
@@ -8,6 +8,7 @@ using Drawie.Backend.Core.Vector;
|
|
using Drawie.Numerics;
|
|
using Drawie.Numerics;
|
|
|
|
|
|
namespace ChunkyImageLib.Operations;
|
|
namespace ChunkyImageLib.Operations;
|
|
|
|
+
|
|
internal class EllipseOperation : IMirroredDrawOperation
|
|
internal class EllipseOperation : IMirroredDrawOperation
|
|
{
|
|
{
|
|
public bool IgnoreEmptyChunks => false;
|
|
public bool IgnoreEmptyChunks => false;
|
|
@@ -21,14 +22,15 @@ internal class EllipseOperation : IMirroredDrawOperation
|
|
private bool init = false;
|
|
private bool init = false;
|
|
private VectorPath? outerPath;
|
|
private VectorPath? outerPath;
|
|
private VectorPath? innerPath;
|
|
private VectorPath? innerPath;
|
|
-
|
|
|
|
|
|
+
|
|
private VectorPath? ellipseOutline;
|
|
private VectorPath? ellipseOutline;
|
|
private VecF[]? ellipse;
|
|
private VecF[]? ellipse;
|
|
private VecF[]? ellipseFill;
|
|
private VecF[]? ellipseFill;
|
|
private RectI? ellipseFillRect;
|
|
private RectI? ellipseFillRect;
|
|
private bool antialiased;
|
|
private bool antialiased;
|
|
|
|
|
|
- public EllipseOperation(RectD location, Paintable strokePaintable, Paintable fillPaintable, float strokeWidth, double rotationRad,
|
|
|
|
|
|
+ public EllipseOperation(RectD location, Paintable strokePaintable, Paintable fillPaintable, float strokeWidth,
|
|
|
|
+ double rotationRad,
|
|
bool antiAliased, Paint? paint = null)
|
|
bool antiAliased, Paint? paint = null)
|
|
{
|
|
{
|
|
this.location = location;
|
|
this.location = location;
|
|
@@ -92,7 +94,7 @@ internal class EllipseOperation : IMirroredDrawOperation
|
|
|
|
|
|
if (antialiased)
|
|
if (antialiased)
|
|
{
|
|
{
|
|
- DrawAntiAliased(surf);
|
|
|
|
|
|
+ DrawAntiAliased(surf);
|
|
}
|
|
}
|
|
else
|
|
else
|
|
{
|
|
{
|
|
@@ -109,22 +111,26 @@ internal class EllipseOperation : IMirroredDrawOperation
|
|
{
|
|
{
|
|
if (Math.Abs(rotation) < 0.001 && strokeWidth > 0)
|
|
if (Math.Abs(rotation) < 0.001 && strokeWidth > 0)
|
|
{
|
|
{
|
|
|
|
+ RectD rect = (RectD)ellipseFillRect!.Value;
|
|
|
|
+ fillPaintable.Bounds = location;
|
|
if (fillPaintable.AnythingVisible || paint.BlendMode != BlendMode.SrcOver)
|
|
if (fillPaintable.AnythingVisible || paint.BlendMode != BlendMode.SrcOver)
|
|
{
|
|
{
|
|
paint.SetPaintable(fillPaintable);
|
|
paint.SetPaintable(fillPaintable);
|
|
surf.Canvas.DrawPoints(PointMode.Lines, ellipseFill!, paint);
|
|
surf.Canvas.DrawPoints(PointMode.Lines, ellipseFill!, paint);
|
|
- surf.Canvas.DrawRect((RectD)ellipseFillRect!.Value, paint);
|
|
|
|
|
|
+ surf.Canvas.DrawRect(rect, paint);
|
|
}
|
|
}
|
|
-
|
|
|
|
|
|
+
|
|
paint.SetPaintable(strokeWidth <= 0 ? fillPaintable : strokePaintable);
|
|
paint.SetPaintable(strokeWidth <= 0 ? fillPaintable : strokePaintable);
|
|
paint.StrokeWidth = 1f;
|
|
paint.StrokeWidth = 1f;
|
|
surf.Canvas.DrawPoints(PointMode.Points, ellipse!, paint);
|
|
surf.Canvas.DrawPoints(PointMode.Points, ellipse!, paint);
|
|
|
|
+
|
|
|
|
+ fillPaintable.Bounds = null;
|
|
}
|
|
}
|
|
else
|
|
else
|
|
{
|
|
{
|
|
surf.Canvas.Save();
|
|
surf.Canvas.Save();
|
|
surf.Canvas.RotateRadians((float)rotation, (float)location.Center.X, (float)location.Center.Y);
|
|
surf.Canvas.RotateRadians((float)rotation, (float)location.Center.X, (float)location.Center.Y);
|
|
-
|
|
|
|
|
|
+
|
|
if (fillPaintable.AnythingVisible || paint.BlendMode != BlendMode.SrcOver)
|
|
if (fillPaintable.AnythingVisible || paint.BlendMode != BlendMode.SrcOver)
|
|
{
|
|
{
|
|
paint.SetPaintable(fillPaintable);
|
|
paint.SetPaintable(fillPaintable);
|
|
@@ -151,14 +157,15 @@ internal class EllipseOperation : IMirroredDrawOperation
|
|
surf.Canvas.Save();
|
|
surf.Canvas.Save();
|
|
surf.Canvas.RotateRadians((float)rotation, (float)location.Center.X, (float)location.Center.Y);
|
|
surf.Canvas.RotateRadians((float)rotation, (float)location.Center.X, (float)location.Center.Y);
|
|
surf.Canvas.ClipPath(innerPath!);
|
|
surf.Canvas.ClipPath(innerPath!);
|
|
- surf.Canvas.DrawPaintable(fillPaintable, paint.BlendMode);
|
|
|
|
|
|
+ surf.Canvas.DrawPaintable(fillPaintable, paint.BlendMode, location);
|
|
surf.Canvas.Restore();
|
|
surf.Canvas.Restore();
|
|
}
|
|
}
|
|
|
|
+
|
|
surf.Canvas.Save();
|
|
surf.Canvas.Save();
|
|
surf.Canvas.RotateRadians((float)rotation, (float)location.Center.X, (float)location.Center.Y);
|
|
surf.Canvas.RotateRadians((float)rotation, (float)location.Center.X, (float)location.Center.Y);
|
|
surf.Canvas.ClipPath(outerPath!);
|
|
surf.Canvas.ClipPath(outerPath!);
|
|
surf.Canvas.ClipPath(innerPath!, ClipOperation.Difference);
|
|
surf.Canvas.ClipPath(innerPath!, ClipOperation.Difference);
|
|
- surf.Canvas.DrawPaintable(strokePaintable, paint.BlendMode);
|
|
|
|
|
|
+ surf.Canvas.DrawPaintable(strokePaintable, paint.BlendMode, location);
|
|
surf.Canvas.Restore();
|
|
surf.Canvas.Restore();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
@@ -167,24 +174,24 @@ internal class EllipseOperation : IMirroredDrawOperation
|
|
{
|
|
{
|
|
surf.Canvas.Save();
|
|
surf.Canvas.Save();
|
|
surf.Canvas.RotateRadians((float)rotation, (float)location.Center.X, (float)location.Center.Y);
|
|
surf.Canvas.RotateRadians((float)rotation, (float)location.Center.X, (float)location.Center.Y);
|
|
-
|
|
|
|
|
|
+
|
|
paint.IsAntiAliased = false;
|
|
paint.IsAntiAliased = false;
|
|
paint.SetPaintable(fillPaintable);
|
|
paint.SetPaintable(fillPaintable);
|
|
paint.Style = PaintStyle.Fill;
|
|
paint.Style = PaintStyle.Fill;
|
|
-
|
|
|
|
|
|
+
|
|
RectD fillRect = ((RectD)location).Inflate(-strokeWidth / 2f);
|
|
RectD fillRect = ((RectD)location).Inflate(-strokeWidth / 2f);
|
|
-
|
|
|
|
|
|
+
|
|
surf.Canvas.DrawOval(fillRect.Center, fillRect.Size / 2f, paint);
|
|
surf.Canvas.DrawOval(fillRect.Center, fillRect.Size / 2f, paint);
|
|
|
|
|
|
paint.IsAntiAliased = true;
|
|
paint.IsAntiAliased = true;
|
|
paint.SetPaintable(strokeWidth <= 0 ? fillPaintable : strokePaintable);
|
|
paint.SetPaintable(strokeWidth <= 0 ? fillPaintable : strokePaintable);
|
|
paint.Style = PaintStyle.Stroke;
|
|
paint.Style = PaintStyle.Stroke;
|
|
paint.StrokeWidth = strokeWidth <= 0 ? 1f : strokeWidth;
|
|
paint.StrokeWidth = strokeWidth <= 0 ? 1f : strokeWidth;
|
|
-
|
|
|
|
|
|
+
|
|
RectD strokeRect = ((RectD)location).Inflate((-strokeWidth / 2f));
|
|
RectD strokeRect = ((RectD)location).Inflate((-strokeWidth / 2f));
|
|
-
|
|
|
|
|
|
+
|
|
surf.Canvas.DrawOval(strokeRect.Center, strokeRect.Size / 2f, paint);
|
|
surf.Canvas.DrawOval(strokeRect.Center, strokeRect.Size / 2f, paint);
|
|
-
|
|
|
|
|
|
+
|
|
surf.Canvas.Restore();
|
|
surf.Canvas.Restore();
|
|
}
|
|
}
|
|
|
|
|
|
@@ -193,14 +200,15 @@ internal class EllipseOperation : IMirroredDrawOperation
|
|
ShapeCorners corners = new((RectD)location);
|
|
ShapeCorners corners = new((RectD)location);
|
|
corners = corners.AsRotated(rotation, (VecD)location.Center);
|
|
corners = corners.AsRotated(rotation, (VecD)location.Center);
|
|
RectI bounds = (RectI)corners.AABBBounds.RoundOutwards();
|
|
RectI bounds = (RectI)corners.AABBBounds.RoundOutwards();
|
|
-
|
|
|
|
|
|
+
|
|
var chunks = OperationHelper.FindChunksTouchingRectangle(bounds, ChunkyImage.FullChunkSize);
|
|
var chunks = OperationHelper.FindChunksTouchingRectangle(bounds, ChunkyImage.FullChunkSize);
|
|
if (!fillPaintable?.AnythingVisible ?? false)
|
|
if (!fillPaintable?.AnythingVisible ?? false)
|
|
{
|
|
{
|
|
- chunks.ExceptWith(OperationHelper.FindChunksFullyInsideEllipse
|
|
|
|
- (location.Center, location.Width / 2.0 - strokeWidth * 2, location.Height / 2.0 - strokeWidth * 2, ChunkyImage.FullChunkSize, rotation));
|
|
|
|
|
|
+ chunks.ExceptWith(OperationHelper.FindChunksFullyInsideEllipse
|
|
|
|
+ (location.Center, location.Width / 2.0 - strokeWidth * 2, location.Height / 2.0 - strokeWidth * 2,
|
|
|
|
+ ChunkyImage.FullChunkSize, rotation));
|
|
}
|
|
}
|
|
-
|
|
|
|
|
|
+
|
|
return new AffectedArea(chunks, bounds);
|
|
return new AffectedArea(chunks, bounds);
|
|
}
|
|
}
|
|
|
|
|
|
@@ -226,7 +234,8 @@ internal class EllipseOperation : IMirroredDrawOperation
|
|
((IPositionPaintable)finalStrokePaintable).Position = newLocation.Center;
|
|
((IPositionPaintable)finalStrokePaintable).Position = newLocation.Center;
|
|
}
|
|
}
|
|
|
|
|
|
- return new EllipseOperation(newLocation, finalStrokePaintable, finalFillPaintable, strokeWidth, rotation, antialiased, paint);
|
|
|
|
|
|
+ return new EllipseOperation(newLocation, finalStrokePaintable, finalFillPaintable, strokeWidth, rotation,
|
|
|
|
+ antialiased, paint);
|
|
}
|
|
}
|
|
|
|
|
|
public void Dispose()
|
|
public void Dispose()
|