-
Notifications
You must be signed in to change notification settings - Fork 0
/
ColorGenerator.cs
120 lines (97 loc) · 4.66 KB
/
ColorGenerator.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
using System;
using System.Collections.Generic;
using System.Drawing;
namespace Peddler {
/// <summary>
/// A generator for <see cref="Color" /> values, with configurable
/// consideration for whether or not the the "alpha" channel is included
/// as part of the <see cref="Color" />.
/// </summary>
public sealed class ColorGenerator : IDistinctGenerator<Color> {
/// <inheritdoc />
public IEqualityComparer<Color> EqualityComparer { get; }
private bool useAlpha { get; }
private int mask { get; }
private Int64Generator colorGenerator { get; }
/// <summary>
/// Instantiates a <see cref="ColorGenerator" /> that has an equal liklihood of
/// of emiting any color that can be represented using the <see cref="Color" />
/// class provided with .NET Standard.
/// </summary>
/// <param name="useAlpha">
/// Controls whether or not the alpha channel is considered. If set to
/// <c>true</c> the alpha channel for each generate color will vary in value
/// from 0 to 255. If <c>false</c>, the alpha channel will be full opacity
/// (255) for all colors generated by the <see cref="ColorGenerator" />.
/// </param>
public ColorGenerator(bool useAlpha = false) {
this.useAlpha = useAlpha;
if (useAlpha) {
this.mask = unchecked((int)0xFFFFFFFF);
} else {
this.mask = unchecked((int)0x00FFFFFF);
}
this.EqualityComparer = new ColorEqualityComparer(this.mask);
// This needs to be using Int64 in order to generate values that
// are 0 <-> 0xFFFFFFFF (Full Opacity White). The Int32Generator
// can only generate values between 0 <-> (0xFFFFFFFE) because
// the upper bounder is exclusive.
this.colorGenerator = new Int64Generator(0L, ((long)(uint)mask) + 1L);
}
/// <summary>
/// Generates a random <see cref="Color" /> with arbitrary red, green, and blue
/// values that range from 0 to 255.
/// </summary>
/// <remarks>
/// If the "useAlpha" constructor parameter was set to <c>true</c>, then the alpha
/// channel will also range from 0 to 255. However, if it was set to <c>false</c>,
/// then the alpha channel will always be set to 255 for full opacity.
/// </remarks>
public Color Next() {
var value = unchecked((int)this.colorGenerator.Next());
if (!this.useAlpha) {
value |= unchecked((int)0xFF000000); // Make full opacity
}
return Color.FromArgb(value);
}
/// <summary>
/// Generates a distinct <see cref="Color" /> with regard to red, green, blue
/// and, potentially, alpha channels.
/// </summary>
/// <remarks>
/// <para>
/// If this <see cref="ColorGenerator" /> was created WITHOUT regard for the
/// alpha channel (the "useAlpha" constructor parameter was set to <c>false</c>),
/// then the alpha of the generated color will always be 255, and one or more of
/// the provided red, green, or blue values will be distinct from the red, green,
/// or blue values provided via the <paramref name="color" /> parameter.
/// </para>
/// <para>
/// if this <see cref="ColorGenerator" /> was created WITH regard for the
/// alpha channel (the "useAlpha" constructor parameter set to <c>true</c>), then
/// one or more of the red, green, blue, and alpha channels will be distinct from
/// those that are defined in the <paramref name="color" /> parameter.
/// </para>
/// </remarks>
public Color NextDistinct(Color color) {
var input = (color.ToArgb() & this.mask);
var value = unchecked((int)this.colorGenerator.NextDistinct(input));
if (!this.useAlpha) {
value |= unchecked((int)0xFF000000); // Make full opacity
}
return Color.FromArgb(value);
}
private class ColorEqualityComparer : EqualityComparer<Color> {
private int mask { get; }
public ColorEqualityComparer(int mask) {
this.mask = mask;
}
public override int GetHashCode(Color color) {
return color.ToArgb() & this.mask;
}
public override bool Equals(Color x, Color y) {
return (x.ToArgb() & this.mask) == (y.ToArgb() & this.mask);
}
}
}
}