in src/Avalonia.Controls.ColorPicker/ColorSpectrum/ColorSpectrum.cs [1393:1577]
private void FillPixelForRing(
double x,
double y,
double radius,
Hsv baseHsv,
ColorSpectrumComponents components,
double minHue,
double maxHue,
double minSaturation,
double maxSaturation,
double minValue,
double maxValue,
PooledList<byte> bgraMinPixelData,
PooledList<byte> bgraMiddle1PixelData,
PooledList<byte> bgraMiddle2PixelData,
PooledList<byte> bgraMiddle3PixelData,
PooledList<byte> bgraMiddle4PixelData,
PooledList<byte> bgraMaxPixelData,
List<Hsv> newHsvValues)
{
double hMin = minHue;
double hMax = maxHue;
double sMin = minSaturation / 100.0;
double sMax = maxSaturation / 100.0;
double vMin = minValue / 100.0;
double vMax = maxValue / 100.0;
double distanceFromRadius = Math.Sqrt(Math.Pow(x - radius, 2) + Math.Pow(y - radius, 2));
double xToUse = x;
double yToUse = y;
// If we're outside the ring, then we want the pixel to appear as blank.
// However, to avoid issues with rounding errors, we'll act as though this point
// is on the edge of the ring for the purposes of returning an HSL value.
// That way, hit testing on the edges will always return the correct value.
if (distanceFromRadius > radius)
{
xToUse = (radius / distanceFromRadius) * (x - radius) + radius;
yToUse = (radius / distanceFromRadius) * (y - radius) + radius;
distanceFromRadius = radius;
}
Hsv hsvMin = baseHsv;
Hsv hsvMiddle1 = baseHsv;
Hsv hsvMiddle2 = baseHsv;
Hsv hsvMiddle3 = baseHsv;
Hsv hsvMiddle4 = baseHsv;
Hsv hsvMax = baseHsv;
double r = 1 - distanceFromRadius / radius;
double theta = Math.Atan2((radius - yToUse), (radius - xToUse)) * 180.0 / Math.PI;
theta += 180.0;
theta = Math.Floor(theta);
while (theta > 360)
{
theta -= 360;
}
double thetaPercent = theta / 360;
switch (components)
{
case ColorSpectrumComponents.HueValue:
hsvMin.H = hsvMiddle1.H = hsvMiddle2.H = hsvMiddle3.H = hsvMiddle4.H = hsvMax.H = hMin + thetaPercent * (hMax - hMin);
hsvMin.V = hsvMiddle1.V = hsvMiddle2.V = hsvMiddle3.V = hsvMiddle4.V = hsvMax.V = vMin + r * (vMax - vMin);
hsvMin.S = 0;
hsvMax.S = 1;
break;
case ColorSpectrumComponents.HueSaturation:
hsvMin.H = hsvMiddle1.H = hsvMiddle2.H = hsvMiddle3.H = hsvMiddle4.H = hsvMax.H = hMin + thetaPercent * (hMax - hMin);
hsvMin.S = hsvMiddle1.S = hsvMiddle2.S = hsvMiddle3.S = hsvMiddle4.S = hsvMax.S = sMin + r * (sMax - sMin);
hsvMin.V = 0;
hsvMax.V = 1;
break;
case ColorSpectrumComponents.ValueHue:
hsvMin.V = hsvMiddle1.V = hsvMiddle2.V = hsvMiddle3.V = hsvMiddle4.V = hsvMax.V = vMin + thetaPercent * (vMax - vMin);
hsvMin.H = hsvMiddle1.H = hsvMiddle2.H = hsvMiddle3.H = hsvMiddle4.H = hsvMax.H = hMin + r * (hMax - hMin);
hsvMin.S = 0;
hsvMax.S = 1;
break;
case ColorSpectrumComponents.ValueSaturation:
hsvMin.V = hsvMiddle1.V = hsvMiddle2.V = hsvMiddle3.V = hsvMiddle4.V = hsvMax.V = vMin + thetaPercent * (vMax - vMin);
hsvMin.S = hsvMiddle1.S = hsvMiddle2.S = hsvMiddle3.S = hsvMiddle4.S = hsvMax.S = sMin + r * (sMax - sMin);
hsvMin.H = 0;
hsvMiddle1.H = 60;
hsvMiddle2.H = 120;
hsvMiddle3.H = 180;
hsvMiddle4.H = 240;
hsvMax.H = 300;
break;
case ColorSpectrumComponents.SaturationHue:
hsvMin.S = hsvMiddle1.S = hsvMiddle2.S = hsvMiddle3.S = hsvMiddle4.S = hsvMax.S = sMin + thetaPercent * (sMax - sMin);
hsvMin.H = hsvMiddle1.H = hsvMiddle2.H = hsvMiddle3.H = hsvMiddle4.H = hsvMax.H = hMin + r * (hMax - hMin);
hsvMin.V = 0;
hsvMax.V = 1;
break;
case ColorSpectrumComponents.SaturationValue:
hsvMin.S = hsvMiddle1.S = hsvMiddle2.S = hsvMiddle3.S = hsvMiddle4.S = hsvMax.S = sMin + thetaPercent * (sMax - sMin);
hsvMin.V = hsvMiddle1.V = hsvMiddle2.V = hsvMiddle3.V = hsvMiddle4.V = hsvMax.V = vMin + r * (vMax - vMin);
hsvMin.H = 0;
hsvMiddle1.H = 60;
hsvMiddle2.H = 120;
hsvMiddle3.H = 180;
hsvMiddle4.H = 240;
hsvMax.H = 300;
break;
}
// If saturation is an axis in the spectrum with hue, or value is an axis, then we want
// that axis to go from maximum at the top to minimum at the bottom,
// or maximum at the outside to minimum at the inside in the case of the ring configuration,
// so we'll invert the number before assigning the HSL value to the array.
// Otherwise, we'll have a very narrow section in the middle that actually has meaningful hue
// in the case of the ring configuration.
if (components == ColorSpectrumComponents.HueSaturation ||
components == ColorSpectrumComponents.SaturationHue)
{
hsvMin.S = sMax - hsvMin.S + sMin;
hsvMiddle1.S = sMax - hsvMiddle1.S + sMin;
hsvMiddle2.S = sMax - hsvMiddle2.S + sMin;
hsvMiddle3.S = sMax - hsvMiddle3.S + sMin;
hsvMiddle4.S = sMax - hsvMiddle4.S + sMin;
hsvMax.S = sMax - hsvMax.S + sMin;
}
else
{
hsvMin.V = vMax - hsvMin.V + vMin;
hsvMiddle1.V = vMax - hsvMiddle1.V + vMin;
hsvMiddle2.V = vMax - hsvMiddle2.V + vMin;
hsvMiddle3.V = vMax - hsvMiddle3.V + vMin;
hsvMiddle4.V = vMax - hsvMiddle4.V + vMin;
hsvMax.V = vMax - hsvMax.V + vMin;
}
newHsvValues.Add(hsvMin);
Rgb rgbMin = hsvMin.ToRgb();
bgraMinPixelData.Add((byte)Math.Round(rgbMin.B * 255)); // b
bgraMinPixelData.Add((byte)Math.Round(rgbMin.G * 255)); // g
bgraMinPixelData.Add((byte)Math.Round(rgbMin.R * 255)); // r
bgraMinPixelData.Add(255); // a
// We'll only save pixel data for the middle bitmaps if our third dimension is hue.
if (components == ColorSpectrumComponents.ValueSaturation ||
components == ColorSpectrumComponents.SaturationValue)
{
Rgb rgbMiddle1 = hsvMiddle1.ToRgb();
bgraMiddle1PixelData.Add((byte)Math.Round(rgbMiddle1.B * 255)); // b
bgraMiddle1PixelData.Add((byte)Math.Round(rgbMiddle1.G * 255)); // g
bgraMiddle1PixelData.Add((byte)Math.Round(rgbMiddle1.R * 255)); // r
bgraMiddle1PixelData.Add(255); // a
Rgb rgbMiddle2 = hsvMiddle2.ToRgb();
bgraMiddle2PixelData.Add((byte)Math.Round(rgbMiddle2.B * 255)); // b
bgraMiddle2PixelData.Add((byte)Math.Round(rgbMiddle2.G * 255)); // g
bgraMiddle2PixelData.Add((byte)Math.Round(rgbMiddle2.R * 255)); // r
bgraMiddle2PixelData.Add(255); // a
Rgb rgbMiddle3 = hsvMiddle3.ToRgb();
bgraMiddle3PixelData.Add((byte)Math.Round(rgbMiddle3.B * 255)); // b
bgraMiddle3PixelData.Add((byte)Math.Round(rgbMiddle3.G * 255)); // g
bgraMiddle3PixelData.Add((byte)Math.Round(rgbMiddle3.R * 255)); // r
bgraMiddle3PixelData.Add(255); // a
Rgb rgbMiddle4 = hsvMiddle4.ToRgb();
bgraMiddle4PixelData.Add((byte)Math.Round(rgbMiddle4.B * 255)); // b
bgraMiddle4PixelData.Add((byte)Math.Round(rgbMiddle4.G * 255)); // g
bgraMiddle4PixelData.Add((byte)Math.Round(rgbMiddle4.R * 255)); // r
bgraMiddle4PixelData.Add(255); // a
}
Rgb rgbMax = hsvMax.ToRgb();
bgraMaxPixelData.Add((byte)Math.Round(rgbMax.B * 255)); // b
bgraMaxPixelData.Add((byte)Math.Round(rgbMax.G * 255)); // g
bgraMaxPixelData.Add((byte)Math.Round(rgbMax.R * 255)); // r
bgraMaxPixelData.Add(255); // a
}