// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using System;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.Primitives;
namespace SixLabors.ImageSharp.Processing
{
///
/// A radial gradient brush, defined by center point and radius.
///
public sealed class RadialGradientBrush : GradientBrush
{
private readonly PointF center;
private readonly float radius;
///
/// The center of the circular gradient and 0 for the color stops.
/// The radius of the circular gradient and 1 for the color stops.
/// Defines how the colors in the gradient are repeated.
/// the color stops as defined in base class.
public RadialGradientBrush(
PointF center,
float radius,
GradientRepetitionMode repetitionMode,
params ColorStop[] colorStops)
: base(repetitionMode, colorStops)
{
this.center = center;
this.radius = radius;
}
///
public override BrushApplicator CreateApplicator(
Configuration configuration,
GraphicsOptions options,
ImageFrame source,
RectangleF region) =>
new RadialGradientBrushApplicator(
configuration,
options,
source,
this.center,
this.radius,
this.ColorStops,
this.RepetitionMode);
///
private sealed class RadialGradientBrushApplicator : GradientBrushApplicator
where TPixel : struct, IPixel
{
private readonly PointF center;
private readonly float radius;
///
/// Initializes a new instance of the class.
///
/// The configuration instance to use when performing operations.
/// The graphics options.
/// The target image.
/// Center point of the gradient.
/// Radius of the gradient.
/// Definition of colors.
/// How the colors are repeated beyond the first gradient.
public RadialGradientBrushApplicator(
Configuration configuration,
GraphicsOptions options,
ImageFrame target,
PointF center,
float radius,
ColorStop[] colorStops,
GradientRepetitionMode repetitionMode)
: base(configuration, options, target, colorStops, repetitionMode)
{
this.center = center;
this.radius = radius;
}
///
/// As this is a circular gradient, the position on the gradient is based on
/// the distance of the point to the center.
///
/// The X coordinate of the target pixel.
/// The Y coordinate of the target pixel.
/// the position on the color gradient.
protected override float PositionOnGradient(float x, float y)
{
// TODO: Can this not use Vector2 distance?
float distance = MathF.Sqrt(MathF.Pow(this.center.X - x, 2) + MathF.Pow(this.center.Y - y, 2));
return distance / this.radius;
}
internal override void Apply(Span scanline, int x, int y)
{
// TODO: each row is symmetric across center, so we can calculate half of it and mirror it to improve performance.
base.Apply(scanline, x, y);
}
}
}
}