Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
67 changes: 67 additions & 0 deletions src/KappaDuck.Quack/Graphics/Drawing/CircleShape.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
// Copyright (c) KappaDuck.
// Licensed under the MIT license.

using KappaDuck.Quack.Geometry;

namespace KappaDuck.Quack.Graphics.Drawing;

/// <summary>
/// A circle shape, approximated by a configurable number of points.
/// </summary>
public sealed class CircleShape : Shape
{
private float _radius;
private int _pointCount;

/// <summary>
/// Creates a circle of the given radius.
/// </summary>
/// <param name="radius">The radius of the circle, in local units.</param>
/// <param name="pointCount">The number of points used to approximate the circle; more points give a smoother circle.</param>
public CircleShape(float radius, int pointCount = 30)
{
_radius = radius;
_pointCount = pointCount;
Update();
}

/// <summary>
/// Gets or sets the radius of the circle, in local units.
/// </summary>
public float Radius
{
get => _radius;
set
{
_radius = value;
Update();
}
}

/// <inheritdoc/>
public override int PointCount => _pointCount;

/// <summary>
/// Sets the number of points used to approximate the circle.
/// </summary>
/// <param name="count">The number of points; more points give a smoother circle.</param>
public void SetPointCount(int count)
{
_pointCount = count;
Update();
}

/// <inheritdoc/>
public override PointF GetPoint(int index)
{
ArgumentOutOfRangeException.ThrowIfNegative(index);
ArgumentOutOfRangeException.ThrowIfGreaterThanOrEqual(index, _pointCount);

Angle angle = Angle.FromDegrees((index * 360f / _pointCount) - 90f);

float x = _radius + (_radius * angle.Cos);
float y = _radius + (_radius * angle.Sin);

return new PointF(x, y);
}
}
62 changes: 62 additions & 0 deletions src/KappaDuck.Quack/Graphics/Drawing/ConvexShape.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
// Copyright (c) KappaDuck.
// Licensed under the MIT license.

using KappaDuck.Quack.Geometry;

namespace KappaDuck.Quack.Graphics.Drawing;

/// <summary>
/// A convex polygon shape defined by an arbitrary set of points.
/// </summary>
/// <remarks>The points must form a convex polygon; concave shapes will not fill correctly.</remarks>
public sealed class ConvexShape : Shape
{
private PointF[] _points;

/// <summary>
/// Creates a convex shape with the given number of points, all at the origin.
/// </summary>
/// <param name="pointCount">The number of points. Set each one with <see cref="SetPoint(int, PointF)"/>.</param>
public ConvexShape(int pointCount)
{
_points = new PointF[pointCount];
Update();
}

/// <summary>
/// Creates a convex shape from the given points.
/// </summary>
/// <param name="points">The points of the convex polygon, in local coordinates.</param>
public ConvexShape(ReadOnlySpan<PointF> points)
{
_points = points.ToArray();
Update();
}

/// <inheritdoc/>
public override int PointCount => _points.Length;

/// <inheritdoc/>
public override PointF GetPoint(int index) => _points[index];

/// <summary>
/// Sets the position of a single point of the shape.
/// </summary>
/// <param name="index">The index of the point, from 0 to <see cref="PointCount"/> minus one.</param>
/// <param name="point">The new position of the point, in local coordinates.</param>
public void SetPoint(int index, PointF point)
{
_points[index] = point;
Update();
}

/// <summary>
/// Replaces all points of the shape.
/// </summary>
/// <param name="points">The new points of the convex polygon, in local coordinates.</param>
public void SetPoints(ReadOnlySpan<PointF> points)
{
_points = points.ToArray();
Update();
}
}
66 changes: 66 additions & 0 deletions src/KappaDuck.Quack/Graphics/Drawing/RectangleShape.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
// Copyright (c) KappaDuck.
// Licensed under the MIT license.

using KappaDuck.Quack.Geometry;

namespace KappaDuck.Quack.Graphics.Drawing;

/// <summary>
/// A rectangle shape defined by its width and height.
/// </summary>
public sealed class RectangleShape : Shape
{
private SizeF _size;

/// <summary>
/// Creates a rectangle of the given size.
/// </summary>
/// <param name="size">The width and height of the rectangle, in local units.</param>
public RectangleShape(SizeF size)
{
_size = size;
Update();
}

/// <summary>
/// Creates a rectangle of the given position and size.
/// </summary>
/// <param name="position">The position of the rectangle, in local units.</param>
/// <param name="size">The width and height of the rectangle, in local units.</param>
public RectangleShape(PointF position, SizeF size) : this(size)
=> Position = position;

/// <summary>
/// Creates a rectangle of the given rect.
/// </summary>
/// <param name="rect">The rectangle, in local units.</param>
public RectangleShape(Rect rect) : this(rect.Position, rect.Size)
{
}

/// <summary>
/// Gets or sets the width and height of the rectangle, in local units.
/// </summary>
public SizeF Size
{
get => _size;
set
{
_size = value;
Update();
}
}

/// <inheritdoc/>
public override int PointCount { get; } = 4;

/// <inheritdoc/>
public override PointF GetPoint(int index) => index switch
{
0 => new PointF(0f, 0f),
1 => new PointF(_size.Width, 0f),
2 => new PointF(_size.Width, _size.Height),
3 => new PointF(0f, _size.Height),
_ => throw new ArgumentOutOfRangeException(nameof(index))
};
}
78 changes: 78 additions & 0 deletions src/KappaDuck.Quack/Graphics/Drawing/RegularPolygon.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
// Copyright (c) KappaDuck.
// Licensed under the MIT license.

using KappaDuck.Quack.Geometry;

namespace KappaDuck.Quack.Graphics.Drawing;

/// <summary>
/// A regular polygon shape whose points are evenly spaced around a circle.
/// </summary>
/// <remarks>Use it for triangles, pentagons, hexagons and so on; a high side count approximates a circle.</remarks>
public sealed class RegularPolygon : Shape
{
private float _radius;
private int _sideCount;

/// <summary>
/// Creates a regular polygon.
/// </summary>
/// <param name="radius">The distance from the center to each point, in local units.</param>
/// <param name="sideCount">The number of sides. Must be at least 3.</param>
/// <exception cref="ArgumentOutOfRangeException"><paramref name="sideCount"/> is less than 3.</exception>
public RegularPolygon(float radius, int sideCount)
{
ArgumentOutOfRangeException.ThrowIfLessThan(sideCount, 3);

_radius = radius;
_sideCount = sideCount;

Update();
}

/// <summary>
/// Gets or sets the distance from the center to each point, in local units.
/// </summary>
public float Radius
{
get => _radius;
set
{
_radius = value;
Update();
}
}

/// <summary>
/// Gets or sets the number of sides. Must be at least 3.
/// </summary>
/// <exception cref="ArgumentOutOfRangeException">The value is less than 3.</exception>
public int SideCount
{
get => _sideCount;
set
{
ArgumentOutOfRangeException.ThrowIfLessThan(value, 3);

_sideCount = value;
Update();
}
}

/// <inheritdoc/>
public override int PointCount => _sideCount;

/// <inheritdoc/>
public override PointF GetPoint(int index)
{
ArgumentOutOfRangeException.ThrowIfNegative(index);
ArgumentOutOfRangeException.ThrowIfGreaterThanOrEqual(index, _sideCount);

Angle angle = Angle.FromDegrees((index * 360f / _sideCount) - 90f);

float x = _radius + (_radius * angle.Cos);
float y = _radius + (_radius * angle.Sin);

return new PointF(x, y);
}
}
Loading