Anatomy of Radial Gradient Brush

WPF(Windows Presentation Foundation) and XPS (Open XML Paper Specification) supports five types of brushes. They are solid color brush, linear gradient brush, radial gradient brush, image brush, and visual brush. This posting will discuss the 'shape' of radial gradient brushes.

The shape of a WPF/XPS radial gradient brush is defined by three attributes:

  • Center
  • GradientOrigin
  • Radius

Here is a simple radial gradient brush in XAML:

<RadialGradientBrush SpreadMethod="Repeat" Center="0.5,0.5" RadiusX="0.2" RadiusY="0.2" GradientOrigin="0.5,0.5">
<RadialGradientBrush.GradientStops>
<GradientStopCollection>
<GradientStop Color="blue" Offset="1" />
<GradientStop Color="yellow" Offset="0" />
</GradientStopCollection>
</RadialGradientBrush.GradientStops>
</RadialGradientBrush>

 

The best way to understand a radial gradient brush is to look it using a series of paramterized ellipses, with parameter t.

The brush originates at GradientOrigin, with t= 0, color from GradientStopCollection at offset 0, and radius (0, 0).

When t = 1, it complets its first cycle. The ellipses is centered around Center, with t = 1, color from GradientStopCollections at offset 1, and radisu (RadiusX, RadiusY).

Here is the generic formulas for a radial gradient brush's ellipses:

Center:   GradientOrigin (1 - t) + Center * t

Radius:  (RadiusX * t, RadiusY * t)

Color:     GradientStopCollection[t mod 1]

The centers for these ellipses move along the straight line from GradientOrigin to Center. After the first cycle is completed, they continue to move along the line.

Radii are simply increasing proportionally with t.

Color is a periodical function of t. But you also need to consider SpreadMethod to make it right.

GradientOrigin

Normally, center and origin are the same point. These ellipses are then cocentric curves. But when origin is moving away from center, they can become quite interesting.

If we move GradientOrigin from (0.5, 0.5) to (0.4, 0.5), this is what we get:

<RadialGradientBrush SpreadMethod="Repeat" Center="0.5,0.5" RadiusX="0.2" RadiusY="0.2" GradientOrigin="0.4,0.5">
<RadialGradientBrush.GradientStops>
<GradientStopCollection>
<GradientStop Color="blue" Offset="1" />
<GradientStop Color="yellow" Offset="0" />
</GradientStopCollection>
</RadialGradientBrush.GradientStops>
</RadialGradientBrush>

If we further move GradientOrigin from (0.4, 0.5) to (0.3, 0.5), something drastic happens:

<RadialGradientBrush SpreadMethod="Repeat" Center="0.5,0.5" RadiusX="0.2" RadiusY="0.2" GradientOrigin="0.3,0.5">
<RadialGradientBrush.GradientStops>
<GradientStopCollection>
<GradientStop Color="blue" Offset="1" />
<GradientStop Color="yellow" Offset="0" />
</GradientStopCollection>
</RadialGradientBrush.GradientStops>
</RadialGradientBrush>

Instead of having gradual changing ellipses filling the whole plane, only half of the plane is filled with ellipses; the other is filled with color at gradient stop 1. This breaking change happens when the distance between center and origin points equals radius.

If we move the origin further away, the ellipses fill an even smaller (triangular) shape:

<RadialGradientBrush SpreadMethod="Repeat" Center="0.5,0.5" RadiusX="0.2" RadiusY="0.2" GradientOrigin="0.2,0.5">
<RadialGradientBrush.GradientStops>
<GradientStopCollection>
<GradientStop Color="blue" Offset="1" />
<GradientStop Color="yellow" Offset="0" />
</GradientStopCollection>
</RadialGradientBrush.GradientStops>
</RadialGradientBrush>

The angle of the triangle can be calculated using:

2* arctan(radius / distance(center,origin))