A cross-platform UI framework for .NET
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

116 lines
3.0 KiB

using System;
using System.Collections.Generic;
using Avalonia.Media;
using Avalonia.Media.Immutable;
using Avalonia.Platform;
using Avalonia.VisualTree;
namespace Avalonia.Rendering.SceneGraph
{
/// <summary>
/// A node in the scene graph which represents an ellipse draw.
/// </summary>
internal class EllipseNode : BrushDrawOperation
{
public EllipseNode(
Matrix transform,
IBrush? brush,
IPen? pen,
Rect rect,
IDisposable? aux = null)
: base(rect.Inflate(pen?.Thickness ?? 0), transform, aux)
{
Transform = transform;
Brush = brush?.ToImmutable();
Pen = pen?.ToImmutable();
Rect = rect;
}
/// <summary>
/// Gets the fill brush.
/// </summary>
public IBrush? Brush { get; }
/// <summary>
/// Gets the stroke pen.
/// </summary>
public ImmutablePen? Pen { get; }
/// <summary>
/// Gets the transform with which the node will be drawn.
/// </summary>
public Matrix Transform { get; }
/// <summary>
/// Gets the rect of the ellipse to draw.
/// </summary>
public Rect Rect { get; }
public bool Equals(Matrix transform, IBrush? brush, IPen? pen, Rect rect)
{
return transform == Transform &&
Equals(brush, Brush) &&
Equals(Pen, pen) &&
rect.Equals(Rect);
}
public override void Render(IDrawingContextImpl context)
{
context.Transform = Transform;
context.DrawEllipse(Brush, Pen, Rect);
}
public override bool HitTest(Point p)
{
if (!Transform.TryInvert(out Matrix inverted))
{
return false;
}
p *= inverted;
var center = Rect.Center;
var strokeThickness = Pen?.Thickness ?? 0;
var rx = Rect.Width / 2 + strokeThickness / 2;
var ry = Rect.Height / 2 + strokeThickness / 2;
var dx = p.X - center.X;
var dy = p.Y - center.Y;
if (Math.Abs(dx) > rx || Math.Abs(dy) > ry)
{
return false;
}
if (Brush != null)
{
return Contains(rx, ry);
}
else if (strokeThickness > 0)
{
bool inStroke = Contains(rx, ry);
rx = Rect.Width / 2 - strokeThickness / 2;
ry = Rect.Height / 2 - strokeThickness / 2;
bool inInner = Contains(rx, ry);
return inStroke && !inInner;
}
bool Contains(double radiusX, double radiusY)
{
var rx2 = radiusX * radiusX;
var ry2 = radiusY * radiusY;
var distance = ry2 * dx * dx + rx2 * dy * dy;
return distance <= rx2 * ry2;
}
return false;
}
}
}