Completed Shapes

This commit is contained in:
MarcUs7i 2025-03-16 23:18:52 +01:00
parent 1e62ef5688
commit 05b49929ba
4 changed files with 120 additions and 61 deletions

View file

@ -1,4 +1,7 @@
using System.Numerics;
using System;
using Avalonia;
using Avalonia.Media;
using SimpleDrawing;
namespace Shapes.Shapes;
@ -7,33 +10,40 @@ public sealed class Circle : Shape
private const int RadiusMin = 5;
private const int RadiusMax = 100;
public Circle(Vector2 position, Vector2 scale)
: base(position, new Vector2(
Math.Clamp(scale.X, RadiusMin, RadiusMax),
Math.Clamp(scale.Y, RadiusMin, RadiusMax)))
public Circle(Point position, Point scale,
double? lineThickness = null, IBrush? lineColor = null, IBrush? fillColor = null)
: base(position, new Point(Math.Clamp(scale.X, RadiusMin, RadiusMax),
Math.Clamp(scale.Y, RadiusMin, RadiusMax)),
lineThickness, lineColor, fillColor)
{
// Clamp the scale values directly in the base ctor
// Just clamping the size.Y as default. Not actually needed
}
public override bool DrawSelf(Vector2 position = default, Vector2 scale = default)
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;
// TODO
return false;
return LeoCanvas.DrawCircle(new Point(position.X, position.Y), scale.X,
lineThicknessUsed, lineColorUsed, fillColorUsed);
}
public override bool PointInShape(Vector2 mousePoint)
public override bool PointInShape(Point mousePoint)
{
// TODO
return false;
double distanceSquared = Math.Pow(mousePoint.X - Position.X, 2) + Math.Pow(mousePoint.Y - Position.Y, 2);
double radiusSquared = Math.Pow(Scale.X, 2);
return distanceSquared <= radiusSquared;
}
}

View file

@ -1,4 +1,5 @@
using System.Numerics;
using Avalonia;
using Avalonia.Media;
using SimpleDrawing;
namespace Shapes.Shapes;
@ -8,40 +9,46 @@ public sealed class Rectangle : Shape
private const int SideLengthMin = 10;
private const int SideLengthMax = 150;
public Rectangle(Vector2 position, Vector2 scale)
: base(position, new Vector2(
Math.Clamp(scale.X, SideLengthMin, SideLengthMax),
Math.Clamp(scale.Y, SideLengthMin, SideLengthMax)))
public Rectangle(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(Vector2 position = default, Vector2 scale = default)
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;
}
return LeoCanvas.DrawRectangle(new(position.X - scale.X/2, position.Y - scale.Y/2), new(scale.X, scale.Y));
double lineThicknessUsed = lineThickness ?? LineThickness ?? DefaultLineThickness;
IBrush? lineColorUsed = lineColor ?? LineColor;
IBrush? fillColorUsed = fillColor ?? FillColor;
var topLeft = new Point(position.X - scale.X/2, position.Y - scale.Y/2);
var bottomRight = new Point(position.X + scale.X/2, position.Y + scale.Y/2);
return LeoCanvas.DrawRectangle(topLeft, bottomRight,
lineThicknessUsed, lineColorUsed, fillColorUsed);
}
public override bool PointInShape(Vector2 mousePoint)
public override bool PointInShape(Point mousePoint)
{
float halfWidth = Scale.X / 2;
float halfHeight = Scale.Y / 2;
double halfWidth = Scale.X / 2;
double halfHeight = Scale.Y / 2;
float left = Position.X - halfWidth;
float right = Position.X + halfWidth;
float top = Position.Y - halfHeight;
float bottom = Position.Y + halfHeight;
double left = Position.X - halfWidth;
double right = Position.X + halfWidth;
double top = Position.Y - halfHeight;
double bottom = Position.Y + halfHeight;
// If point is inside shape
return mousePoint.X >= left && mousePoint.X <= right &&
mousePoint.Y >= top && mousePoint.Y <= bottom;
}

View file

@ -1,4 +1,5 @@
using System.Numerics;
using Avalonia;
using Avalonia.Media;
using SimpleDrawing;
namespace Shapes.Shapes;
@ -7,39 +8,48 @@ public sealed class Square : Shape
{
private const int SideLengthMin = 10;
private const int SideLengthMax = 120;
public Square(Vector2 position, Vector2 scale)
: base(position, new Vector2(
Math.Clamp(scale.X, SideLengthMin, SideLengthMax),
Math.Clamp(scale.Y, SideLengthMin, SideLengthMax)))
public Square(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
// Just clamping the size.Y as default. Not actually needed
}
public override bool DrawSelf(Vector2 position = default, Vector2 scale = default)
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;
return LeoCanvas.DrawRectangle(new(position.X - scale.X/2, position.Y - scale.Y/2), new(scale.X, scale.Y));
double size = scale.X;
var topLeft = new Point(position.X - size/2, position.Y - size/2);
var bottomRight = new Point(position.X + size/2, position.Y + size/2);
return LeoCanvas.DrawRectangle(topLeft, bottomRight,
lineThicknessUsed, lineColorUsed, fillColorUsed);
}
public override bool PointInShape(Vector2 mousePoint)
{
float halfWidth = Scale.X / 2;
float halfHeight = Scale.Y / 2;
float left = Position.X - halfWidth;
float right = Position.X + halfWidth;
float top = Position.Y - halfHeight;
float bottom = Position.Y + halfHeight;
public override bool PointInShape(Point mousePoint)
{
double halfWidth = Scale.X / 2;
double halfHeight = Scale.Y / 2;
double left = Position.X - halfWidth;
double right = Position.X + halfWidth;
double top = Position.Y - halfHeight;
double bottom = Position.Y + halfHeight;
// If point is inside shape
return mousePoint.X >= left && mousePoint.X <= right &&

View file

@ -1,5 +1,5 @@
using System.Numerics;
using Avalonia;
using Avalonia;
using Avalonia.Media;
using SimpleDrawing;
namespace Shapes.Shapes;
@ -9,33 +9,65 @@ public sealed class Triangle : Shape
private const int SideLengthMin = 10;
private const int SideLengthMax = 150;
public Triangle(Vector2 position, Vector2 scale)
: base(position, new Vector2(
Math.Clamp(scale.X, SideLengthMin, SideLengthMax),
Math.Clamp(scale.Y, SideLengthMin, SideLengthMax)))
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(Vector2 position = default, Vector2 scale = default)
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;
// TODO
return false;
var vertices = CalculateTriangleVertices(position, scale.X);
return LeoCanvas.DrawPolygonByPath(vertices, lineThicknessUsed, lineColorUsed, fillColorUsed);
}
public override bool PointInShape(Vector2 mousePoint)
public override bool PointInShape(Point mousePoint)
{
// TODO
return false;
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;
}
}