73 lines
3 KiB
C#
73 lines
3 KiB
C#
using Avalonia;
|
|
using Avalonia.Media;
|
|
using SimpleDrawing;
|
|
|
|
namespace Shapes.Shapes;
|
|
|
|
public sealed class Triangle : Shape
|
|
{
|
|
private const int SideLengthMin = 10;
|
|
private const int SideLengthMax = 150;
|
|
|
|
public Triangle(Point position, Point scale,
|
|
double? lineThickness = null, IBrush? lineColor = null, IBrush? fillColor = null)
|
|
: base(position, new Point(Math.Clamp(scale.X, SideLengthMin, SideLengthMax),
|
|
Math.Clamp(scale.Y, SideLengthMin, SideLengthMax)),
|
|
lineThickness, lineColor, fillColor)
|
|
{
|
|
// Clamp the scale values directly in the base ctor
|
|
}
|
|
|
|
public override bool DrawSelf(Point position = default, Point scale = default,
|
|
double? lineThickness = null, IBrush? lineColor = null, IBrush? fillColor = null)
|
|
{
|
|
if (position == default)
|
|
{
|
|
position = Position;
|
|
}
|
|
if (scale == default)
|
|
{
|
|
scale = Scale;
|
|
}
|
|
double lineThicknessUsed = lineThickness ?? LineThickness ?? DefaultLineThickness;
|
|
IBrush? lineColorUsed = lineColor ?? LineColor;
|
|
IBrush? fillColorUsed = fillColor ?? FillColor;
|
|
|
|
var vertices = CalculateTriangleVertices(position, scale.X);
|
|
return LeoCanvas.DrawPolygonByPath(vertices, lineThicknessUsed, lineColorUsed, fillColorUsed);
|
|
}
|
|
|
|
public override bool PointInShape(Point mousePoint)
|
|
{
|
|
var vertices = CalculateTriangleVertices(Position, Scale.X);
|
|
return IsPointInTriangle(mousePoint, vertices[0], vertices[1], vertices[2]);
|
|
}
|
|
|
|
private static Point[] CalculateTriangleVertices(Point center, double sideLength)
|
|
{
|
|
double height = sideLength * Math.Sqrt(3) / 2;
|
|
double yOffset = height / 3;
|
|
|
|
var vertices = new Point[3];
|
|
vertices[0] = new Point(center.X, center.Y - height + yOffset);
|
|
vertices[1] = new Point(center.X - sideLength / 2, center.Y + yOffset);
|
|
vertices[2] = new Point(center.X + sideLength / 2, center.Y + yOffset);
|
|
|
|
return vertices;
|
|
}
|
|
|
|
// Ripped from https://stackoverflow.com/questions/2049582/how-to-determine-if-a-point-is-in-a-2d-triangle
|
|
// very nice & self written code :)
|
|
// Double is used instead of float to avoid casting. Unfortunately, float isn't supported in Avalonia.Base.Point
|
|
// Double is worse in performance than float, if you don't need high precision and run it in a loop like GameDev
|
|
private static bool IsPointInTriangle(Point p, Point a, Point b, Point c)
|
|
{
|
|
double d = (b.Y - c.Y) * (a.X - c.X) + (c.X - b.X) * (a.Y - c.Y);
|
|
|
|
double alpha = ((b.Y - c.Y) * (p.X - c.X) + (c.X - b.X) * (p.Y - c.Y)) / d;
|
|
double beta = ((c.Y - a.Y) * (p.X - c.X) + (a.X - c.X) * (p.Y - c.Y)) / d;
|
|
double gamma = 1 - alpha - beta;
|
|
|
|
return alpha >= 0 && beta >= 0 && gamma >= 0;
|
|
}
|
|
}
|