// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using System;
namespace SixLabors.ImageSharp.Drawing.Processing {
///
/// The base class for pens that can apply a pattern to a line with a set brush and thickness
///
///
/// The pattern will be in to the form of
///
/// new float[]{ 1f, 2f, 0.5f}
///
/// this will be converted into a pattern that is 3.5 times longer that the width with 3 sections.
///
/// - Section 1 will be width long (making a square) and will be filled by the brush.
/// - Section 2 will be width * 2 long and will be empty.
/// - Section 3 will be width/2 long and will be filled.
///
/// The pattern will immediately repeat without gap.
///
public abstract class Pen : IEquatable
{
private readonly float[] pattern;
///
/// Initializes a new instance of the class.
///
/// The brush used to fill the stroke outline.
protected Pen(Brush strokeFill)
: this(strokeFill, 1)
{
}
///
/// Initializes a new instance of the class.
///
/// The brush used to fill the stroke outline.
/// The stroke width in the path's local coordinate space before any drawing transform is applied.
protected Pen(Brush strokeFill, float strokeWidth)
: this(strokeFill, strokeWidth, Pens.EmptyPattern)
{
}
///
/// Initializes a new instance of the class.
///
/// The brush used to fill the stroke outline.
/// The stroke width in the path's local coordinate space before any drawing transform is applied.
/// The stroke pattern.
protected Pen(Brush strokeFill, float strokeWidth, float[] strokePattern)
{
Guard.NotNull(strokeFill, nameof(strokeFill));
Guard.MustBeGreaterThan(strokeWidth, 0, nameof(strokeWidth));
Guard.NotNull(strokePattern, nameof(strokePattern));
this.StrokeFill = strokeFill;
this.StrokeWidth = strokeWidth;
this.pattern = strokePattern;
this.StrokeOptions = new StrokeOptions();
}
///
/// Initializes a new instance of the class.
///
/// The pen options.
protected Pen(PenOptions options)
{
this.StrokeFill = options.StrokeFill;
this.StrokeWidth = options.StrokeWidth;
this.pattern = options.StrokePattern;
this.StrokeOptions = options.StrokeOptions ?? new StrokeOptions();
}
///
public Brush StrokeFill { get; }
///
public float StrokeWidth { get; }
///
public ReadOnlyMemory StrokePattern => this.pattern;
///
public StrokeOptions StrokeOptions { get; }
///
/// Applies the styling from the pen to a path and generate a new path with the final vector.
///
/// The source path
/// The with the pen styling applied.
public IPath GeneratePath(IPath path)
=> this.GeneratePath(path, this.StrokeWidth);
///
/// Applies the styling from the pen to a path and generate a new path with the final vector.
///
/// The source path
/// The stroke width in the path's local coordinate space before any drawing transform is applied.
/// The with the pen styling applied.
public abstract IPath GeneratePath(IPath path, float strokeWidth);
///
public virtual bool Equals(Pen? other)
=> other != null
&& this.StrokeWidth == other.StrokeWidth
&& this.StrokeFill.Equals(other.StrokeFill)
&& this.StrokeOptions.Equals(other.StrokeOptions)
&& this.StrokePattern.Span.SequenceEqual(other.StrokePattern.Span);
///
public override bool Equals(object? obj) => this.Equals(obj as Pen);
///
public override int GetHashCode()
=> HashCode.Combine(this.StrokeWidth, this.StrokeFill, this.StrokeOptions, this.pattern);
}
}