用于生成不重复的,间隔开的RGB颜色值的算法
问题描述:
我想要一个静态方法,该方法每当调用时都会返回一个尚未出现的颜色值,并且不会与上次返回的颜色太接近(即return new Color(last_value += 10)
不会这样做)。它也应该不是随机的,所以每次启动应用程序时,返回颜色的顺序都是相同的。用于生成不重复的,间隔开的RGB颜色值的算法
冒出我的头一件事,就是循环与原始数步数组,像这样:
private static HashMap<Integer, Boolean> used = new HashMap<>();
private static int[] values = new int[0xfffff]; // 1/16th of possible colors
private static int current = 0, jump = values.length/7;
public static Color getColour(){
int value = values[current];
used.put(current, true);
current += jump;
current %= values.length;
//have some check here if all colors were used
while (used.containsKey(current)){
current++;
current%=values.length;
}
return new Color(value);
}
但我不喜欢它,因为颜色将接近每其他来自一些电话回来。
答
生成非重复随机样序列的一个好方法是使用LFSR。
/**
* Linear feedback shift register
*
* Taps can be found at: See http://www.xilinx.com/support/documentation/application_notes/xapp052.pdf See http://mathoverflow.net/questions/46961/how-are-taps-proven-to-work-for-lfsrs/46983#46983 See
* http://www.newwaveinstruments.com/resources/articles/m_sequence_linear_feedback_shift_register_lfsr.htm See http://www.yikes.com/~ptolemy/lfsr_web/index.htm See
* http://seanerikoconnor.freeservers.com/Mathematics/AbstractAlgebra/PrimitivePolynomials/overview.html
*
* @author OldCurmudgeon
*/
public class LFSR implements Iterable<BigInteger> {
// Bit pattern for taps.
private final BigInteger taps;
// Where to start (and end).
private final BigInteger start;
// The poly must be primitive to span the full sequence.
public LFSR(BigInteger primitivePoly, BigInteger start) {
// Where to start from (and stop).
this.start = start.equals(BigInteger.ZERO) ? BigInteger.ONE : start;
// Knock off the 2^0 coefficient of the polynomial for the TAP.
this.taps = primitivePoly.shiftRight(1);
}
public LFSR(BigInteger primitivePoly) {
this(primitivePoly, BigInteger.ONE);
}
// Constructor from an array of taps.
public LFSR(int[] taps) {
this(asPoly(taps));
}
private static BigInteger asPoly(int[] taps) {
// Build the BigInteger.
BigInteger primitive = BigInteger.ZERO;
for (int bit : taps) {
primitive = primitive.or(BigInteger.ONE.shiftLeft(bit));
}
return primitive;
}
@Override
public Iterator<BigInteger> iterator() {
return new LFSRIterator(start);
}
private class LFSRIterator implements Iterator<BigInteger> {
// The last one we returned.
private BigInteger last = null;
// The next one to return.
private BigInteger next = null;
public LFSRIterator(BigInteger start) {
// Do not return the seed.
last = start;
}
@Override
public boolean hasNext() {
if (next == null) {
/*
* Uses the Galois form.
*
* Shift last right one.
*
* If the bit shifted out was a 1 - xor with the tap mask.
*/
boolean shiftedOutA1 = last.testBit(0);
// Shift right.
next = last.shiftRight(1);
if (shiftedOutA1) {
// Tap!
next = next.xor(taps);
}
// Never give them `start` again.
if (next.equals(start)) {
// Could set a finished flag here too.
next = null;
}
}
return next != null;
}
@Override
public BigInteger next() {
// Remember this one.
last = hasNext() ? next : null;
// Don't deliver it again.
next = null;
return last;
}
@Override
public void remove() {
throw new UnsupportedOperationException("Not supported.");
}
@Override
public String toString() {
return LFSR.this.toString()
+ "[" + (last != null ? last.toString(16) : "")
+ "-" + (next != null ? next.toString(16) : "") + "]";
}
}
@Override
public String toString() {
return "(" + taps.toString(32) + ")-" + start.toString(32);
}
}
现在您只需要一个8+8+8=24
分接值。
使用它很简单。
public void test() {
// Sample 24-bit tap found on page 5 of
// http://www.xilinx.com/support/documentation/application_notes/xapp052.pdf
int[] taps = new int[]{24, 23, 22, 17};
LFSR lfsr = new LFSR(taps);
int count = 100;
for (BigInteger i : lfsr) {
System.out.println("Colour: " + new Color(i.intValue()));
if (--count <= 0) {
break;
}
}
}
特色的LFSR的:
- 它将重复 - 但直到所有可能的位模式已经产生(除
0
)。 - 生成的数字在统计上是一个很好的随机数。
- 每次都会生成相同的序列(如果需要不同的序列,请选择不同的
tap
)。
达到你需要我建议你添加一个过滤器和丢弃任何过于接近(由标准)前一个的间距。
您如何准确定义RGB配色方案的接近度? – svs
为什么你不需要随机颜色?我认为在某些时候你必须使用随机的。 – Priyamal
@svs好吧,只要看一眼就可以区分出不同的颜色,同时它也是宽大的装饰板,所以它并不是所有的东西,例如,红。 –