用于生成不重复的,间隔开的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); 
    } 

但我不喜欢它,因为颜色将接近每其他来自一些电话回来。

+0

您如何准确定义RGB配色方案的接近度? – svs

+0

为什么你不需要随机颜色?我认为在某些时候你必须使用随机的。 – Priyamal

+0

@svs好吧,只要看一眼就可以区分出不同的颜色,同时它也是宽大的装饰板,所以它并不是所有的东西,例如,红。 –

生成非重复随机样序列的一个好方法是使用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)。

达到你需要我建议你添加一个过滤器和丢弃任何过于接近(由标准)前一个的间距。