Как автоматически генерировать N "разных" цветов?
Я написал два метода ниже, чтобы автоматически выбрать N различных цветов. Он работает, определяя кусочно-линейную функцию на кубе RGB. Преимущество этого - вы также можете получить прогрессивный масштаб, если это то, что вы хотите, но когда N станет большим, цвета могут начать выглядеть похожими. Я могу представить себе равномерное разделение куба RGB на решетку, а затем на рисование точек. Кто-нибудь знает какие-либо другие методы? Я исключаю определение списка, а затем просто еду через него. Я также должен сказать, что мне не все равно, если они сталкиваются или не выглядят красиво, они просто должны быть визуально различны.
public static List<Color> pick(int num) {
List<Color> colors = new ArrayList<Color>();
if (num < 2)
return colors;
float dx = 1.0f / (float) (num - 1);
for (int i = 0; i < num; i++) {
colors.add(get(i * dx));
}
return colors;
}
public static Color get(float x) {
float r = 0.0f;
float g = 0.0f;
float b = 1.0f;
if (x >= 0.0f && x < 0.2f) {
x = x / 0.2f;
r = 0.0f;
g = x;
b = 1.0f;
} else if (x >= 0.2f && x < 0.4f) {
x = (x - 0.2f) / 0.2f;
r = 0.0f;
g = 1.0f;
b = 1.0f - x;
} else if (x >= 0.4f && x < 0.6f) {
x = (x - 0.4f) / 0.2f;
r = x;
g = 1.0f;
b = 0.0f;
} else if (x >= 0.6f && x < 0.8f) {
x = (x - 0.6f) / 0.2f;
r = 1.0f;
g = 1.0f - x;
b = 0.0f;
} else if (x >= 0.8f && x <= 1.0f) {
x = (x - 0.8f) / 0.2f;
r = 1.0f;
g = 0.0f;
b = x;
}
return new Color(r, g, b);
}
Ответы
Ответ 1
Вы можете использовать цветную модель HSL, чтобы создать свои цвета.
Если все, что вам нужно, это разные оттенки (скорее всего) и небольшие вариации на легкость или насыщенность, вы можете распределить оттенки следующим образом:
// assumes hue [0, 360), saturation [0, 100), lightness [0, 100)
for(i = 0; i < 360; i += 360 / num_colors) {
HSLColor c;
c.hue = i;
c.saturation = 90 + randf() * 10;
c.lightness = 50 + randf() * 10;
addColor(c);
}
Ответ 2
Эти вопросы появляются в нескольких обсуждениях SO:
Предлагаются различные решения, но ни один из них не является оптимальным. К счастью, наука приходит на помощь
Произвольный N
Последние 2 будут бесплатными через большинство университетских библиотек/прокси.
N конечна и относительно мала
В этом случае можно было бы найти решение списка. Очень интересная статья в теме доступна свободно:
Существует несколько списков цветов:
- Список Boynton из 11 цветов, которые почти никогда не смущаются (доступно в первой статье предыдущего раздела)
- Kelly 22 цвета максимальной контрастности (доступно в приведенной выше статье)
Я также столкнулся с this Палитра ученика MIT.
Наконец, следующие ссылки могут быть полезны при преобразовании между различными системами/координатами цвета (например, некоторые цвета в статьях не указаны в RGB):
Для списка Келли и Бойнтона я уже сделал преобразование в RGB (за исключением белого и черного, что должно быть очевидно). Некоторый код С#:
public static ReadOnlyCollection<Color> KellysMaxContrastSet
{
get { return _kellysMaxContrastSet.AsReadOnly(); }
}
private static readonly List<Color> _kellysMaxContrastSet = new List<Color>
{
UIntToColor(0xFFFFB300), //Vivid Yellow
UIntToColor(0xFF803E75), //Strong Purple
UIntToColor(0xFFFF6800), //Vivid Orange
UIntToColor(0xFFA6BDD7), //Very Light Blue
UIntToColor(0xFFC10020), //Vivid Red
UIntToColor(0xFFCEA262), //Grayish Yellow
UIntToColor(0xFF817066), //Medium Gray
//The following will not be good for people with defective color vision
UIntToColor(0xFF007D34), //Vivid Green
UIntToColor(0xFFF6768E), //Strong Purplish Pink
UIntToColor(0xFF00538A), //Strong Blue
UIntToColor(0xFFFF7A5C), //Strong Yellowish Pink
UIntToColor(0xFF53377A), //Strong Violet
UIntToColor(0xFFFF8E00), //Vivid Orange Yellow
UIntToColor(0xFFB32851), //Strong Purplish Red
UIntToColor(0xFFF4C800), //Vivid Greenish Yellow
UIntToColor(0xFF7F180D), //Strong Reddish Brown
UIntToColor(0xFF93AA00), //Vivid Yellowish Green
UIntToColor(0xFF593315), //Deep Yellowish Brown
UIntToColor(0xFFF13A13), //Vivid Reddish Orange
UIntToColor(0xFF232C16), //Dark Olive Green
};
public static ReadOnlyCollection<Color> BoyntonOptimized
{
get { return _boyntonOptimized.AsReadOnly(); }
}
private static readonly List<Color> _boyntonOptimized = new List<Color>
{
Color.FromArgb(0, 0, 255), //Blue
Color.FromArgb(255, 0, 0), //Red
Color.FromArgb(0, 255, 0), //Green
Color.FromArgb(255, 255, 0), //Yellow
Color.FromArgb(255, 0, 255), //Magenta
Color.FromArgb(255, 128, 128), //Pink
Color.FromArgb(128, 128, 128), //Gray
Color.FromArgb(128, 0, 0), //Brown
Color.FromArgb(255, 128, 0), //Orange
};
static public Color UIntToColor(uint color)
{
var a = (byte)(color >> 24);
var r = (byte)(color >> 16);
var g = (byte)(color >> 8);
var b = (byte)(color >> 0);
return Color.FromArgb(a, r, g, b);
}
И вот значения RGB в шестнадцатеричных и 8-битных представлениях для канала:
kelly_colors_hex = [
0xFFB300, # Vivid Yellow
0x803E75, # Strong Purple
0xFF6800, # Vivid Orange
0xA6BDD7, # Very Light Blue
0xC10020, # Vivid Red
0xCEA262, # Grayish Yellow
0x817066, # Medium Gray
# The following don't work well for people with defective color vision
0x007D34, # Vivid Green
0xF6768E, # Strong Purplish Pink
0x00538A, # Strong Blue
0xFF7A5C, # Strong Yellowish Pink
0x53377A, # Strong Violet
0xFF8E00, # Vivid Orange Yellow
0xB32851, # Strong Purplish Red
0xF4C800, # Vivid Greenish Yellow
0x7F180D, # Strong Reddish Brown
0x93AA00, # Vivid Yellowish Green
0x593315, # Deep Yellowish Brown
0xF13A13, # Vivid Reddish Orange
0x232C16, # Dark Olive Green
]
kelly_colors = dict(vivid_yellow=(255, 179, 0),
strong_purple=(128, 62, 117),
vivid_orange=(255, 104, 0),
very_light_blue=(166, 189, 215),
vivid_red=(193, 0, 32),
grayish_yellow=(206, 162, 98),
medium_gray=(129, 112, 102),
# these aren't good for people with defective color vision:
vivid_green=(0, 125, 52),
strong_purplish_pink=(246, 118, 142),
strong_blue=(0, 83, 138),
strong_yellowish_pink=(255, 122, 92),
strong_violet=(83, 55, 122),
vivid_orange_yellow=(255, 142, 0),
strong_purplish_red=(179, 40, 81),
vivid_greenish_yellow=(244, 200, 0),
strong_reddish_brown=(127, 24, 13),
vivid_yellowish_green=(147, 170, 0),
deep_yellowish_brown=(89, 51, 21),
vivid_reddish_orange=(241, 58, 19),
dark_olive_green=(35, 44, 22))
Для всех разработчиков Java, вот цвета JavaFX:
// Don't forget to import javafx.scene.paint.Color;
private static final Color[] KELLY_COLORS = {
Color.web("0xFFB300"), // Vivid Yellow
Color.web("0x803E75"), // Strong Purple
Color.web("0xFF6800"), // Vivid Orange
Color.web("0xA6BDD7"), // Very Light Blue
Color.web("0xC10020"), // Vivid Red
Color.web("0xCEA262"), // Grayish Yellow
Color.web("0x817066"), // Medium Gray
Color.web("0x007D34"), // Vivid Green
Color.web("0xF6768E"), // Strong Purplish Pink
Color.web("0x00538A"), // Strong Blue
Color.web("0xFF7A5C"), // Strong Yellowish Pink
Color.web("0x53377A"), // Strong Violet
Color.web("0xFF8E00"), // Vivid Orange Yellow
Color.web("0xB32851"), // Strong Purplish Red
Color.web("0xF4C800"), // Vivid Greenish Yellow
Color.web("0x7F180D"), // Strong Reddish Brown
Color.web("0x93AA00"), // Vivid Yellowish Green
Color.web("0x593315"), // Deep Yellowish Brown
Color.web("0xF13A13"), // Vivid Reddish Orange
Color.web("0x232C16"), // Dark Olive Green
};
ниже представлены несортированные цвета келли в соответствии с приведенным выше порядком.
![unsorted kelly colors]()
Ниже приведены отсортированные цвета келли в соответствии с оттенками (обратите внимание, что некоторые желтые цвета не очень контрастируют)
![отсортированные цвета келли]()
Ответ 3
Вот идея. Представьте себе цилиндр HSV
![HSV_cylinder.jpg]()
Определите верхний и нижний пределы, которые вы хотите для яркости и насыщенности. Это определяет квадратное поперечное сечение в пространстве.
Теперь разброс N точек случайно в этом пространстве.
Затем примените на них итеративный алгоритм отталкивания либо для фиксированного числа итераций, либо до тех пор, пока точки не стабилизируются.
Теперь у вас должно быть N точек, представляющих N цветов, которые могут быть как можно более различны в интересующем вас цветовом пространстве.
Уго
Ответ 4
Как и Ури Коэн, но вместо этого генератор. Начнем с использования цветов, расположенных далеко друг от друга. Детерминированный.
Образец, оставшиеся цвета сначала:
![sample]()
#!/usr/bin/env python3.3
import colorsys
import itertools
from fractions import Fraction
def zenos_dichotomy():
"""
http://en.wikipedia.org/wiki/1/2_%2B_1/4_%2B_1/8_%2B_1/16_%2B_%C2%B7_%C2%B7_%C2%B7
"""
for k in itertools.count():
yield Fraction(1,2**k)
def getfracs():
"""
[Fraction(0, 1), Fraction(1, 2), Fraction(1, 4), Fraction(3, 4), Fraction(1, 8), Fraction(3, 8), Fraction(5, 8), Fraction(7, 8), Fraction(1, 16), Fraction(3, 16), ...]
[0.0, 0.5, 0.25, 0.75, 0.125, 0.375, 0.625, 0.875, 0.0625, 0.1875, ...]
"""
yield 0
for k in zenos_dichotomy():
i = k.denominator # [1,2,4,8,16,...]
for j in range(1,i,2):
yield Fraction(j,i)
bias = lambda x: (math.sqrt(x/3)/Fraction(2,3)+Fraction(1,3))/Fraction(6,5) # can be used for the v in hsv to map linear values 0..1 to something that looks equidistant
def genhsv(h):
for s in [Fraction(6,10)]: # optionally use range
for v in [Fraction(8,10),Fraction(5,10)]: # could use range too
yield (h, s, v) # use bias for v here if you use range
genrgb = lambda x: colorsys.hsv_to_rgb(*x)
flatten = itertools.chain.from_iterable
gethsvs = lambda: flatten(map(genhsv,getfracs()))
getrgbs = lambda: map(genrgb, gethsvs())
def genhtml(x):
uint8tuple = map(lambda y: int(y*255), x)
return "rgb({},{},{})".format(*uint8tuple)
gethtmlcolors = lambda: map(genhtml, getrgbs())
if __name__ == "__main__":
print(list(itertools.islice(gethtmlcolors(), 100)))
Ответ 5
Для будущих поколений я добавляю здесь принятый ответ на Python.
import numpy as np
import colorsys
def _get_colors(num_colors):
colors=[]
for i in np.arange(0., 360., 360. / num_colors):
hue = i/360.
lightness = (50 + np.random.rand() * 10)/100.
saturation = (90 + np.random.rand() * 10)/100.
colors.append(colorsys.hls_to_rgb(hue, lightness, saturation))
return colors
Ответ 6
Кажется, что все пропустили существование очень полезного цветового пространства YUV, которое было предназначено для восприятия различий цвета в визуальной системе человека. Расстояния в ЮВ представляют собой различия в восприятии человека. Мне понадобилась эта функциональность для MagicCube4D, которая реализует 4-мерные кубики Рубика и неограниченное количество других 4D извилистых головоломок с произвольным количеством лиц.
Мое решение начинается с выбора случайных точек в YUV, а затем итеративного разбиения ближайших двух точек и только преобразования в RGB при возврате результата. Метод O (n ^ 3), но это не имеет значения для небольших чисел или единиц, которые могут быть кэшированы. Это, безусловно, может быть сделано более эффективно, но результаты кажутся превосходными.
Функция допускает дополнительную спецификацию порогов яркости, чтобы не создавать цвета, при которых ни один компонент не будет ярче или темнее заданных количеств. IE, возможно, вам не нужны значения, близкие к черным или белым. Это полезно, когда результирующие цвета будут использоваться в качестве базовых цветов, которые затем затенены через освещение, слоирование, прозрачность и т.д. И должны по-прежнему отличаться от их базовых цветов.
import java.awt.Color;
import java.util.Random;
/**
* Contains a method to generate N visually distinct colors and helper methods.
*
* @author Melinda Green
*/
public class ColorUtils {
private ColorUtils() {} // To disallow instantiation.
private final static float
U_OFF = .436f,
V_OFF = .615f;
private static final long RAND_SEED = 0;
private static Random rand = new Random(RAND_SEED);
/*
* Returns an array of ncolors RGB triplets such that each is as unique from the rest as possible
* and each color has at least one component greater than minComponent and one less than maxComponent.
* Use min == 1 and max == 0 to include the full RGB color range.
*
* Warning: O N^2 algorithm blows up fast for more than 100 colors.
*/
public static Color[] generateVisuallyDistinctColors(int ncolors, float minComponent, float maxComponent) {
rand.setSeed(RAND_SEED); // So that we get consistent results for each combination of inputs
float[][] yuv = new float[ncolors][3];
// initialize array with random colors
for(int got = 0; got < ncolors;) {
System.arraycopy(randYUVinRGBRange(minComponent, maxComponent), 0, yuv[got++], 0, 3);
}
// continually break up the worst-fit color pair until we get tired of searching
for(int c = 0; c < ncolors * 1000; c++) {
float worst = 8888;
int worstID = 0;
for(int i = 1; i < yuv.length; i++) {
for(int j = 0; j < i; j++) {
float dist = sqrdist(yuv[i], yuv[j]);
if(dist < worst) {
worst = dist;
worstID = i;
}
}
}
float[] best = randYUVBetterThan(worst, minComponent, maxComponent, yuv);
if(best == null)
break;
else
yuv[worstID] = best;
}
Color[] rgbs = new Color[yuv.length];
for(int i = 0; i < yuv.length; i++) {
float[] rgb = new float[3];
yuv2rgb(yuv[i][0], yuv[i][1], yuv[i][2], rgb);
rgbs[i] = new Color(rgb[0], rgb[1], rgb[2]);
//System.out.println(rgb[i][0] + "\t" + rgb[i][1] + "\t" + rgb[i][2]);
}
return rgbs;
}
public static void hsv2rgb(float h, float s, float v, float[] rgb) {
// H is given on [0->6] or -1. S and V are given on [0->1].
// RGB are each returned on [0->1].
float m, n, f;
int i;
float[] hsv = new float[3];
hsv[0] = h;
hsv[1] = s;
hsv[2] = v;
System.out.println("H: " + h + " S: " + s + " V:" + v);
if(hsv[0] == -1) {
rgb[0] = rgb[1] = rgb[2] = hsv[2];
return;
}
i = (int) (Math.floor(hsv[0]));
f = hsv[0] - i;
if(i % 2 == 0)
f = 1 - f; // if i is even
m = hsv[2] * (1 - hsv[1]);
n = hsv[2] * (1 - hsv[1] * f);
switch(i) {
case 6:
case 0:
rgb[0] = hsv[2];
rgb[1] = n;
rgb[2] = m;
break;
case 1:
rgb[0] = n;
rgb[1] = hsv[2];
rgb[2] = m;
break;
case 2:
rgb[0] = m;
rgb[1] = hsv[2];
rgb[2] = n;
break;
case 3:
rgb[0] = m;
rgb[1] = n;
rgb[2] = hsv[2];
break;
case 4:
rgb[0] = n;
rgb[1] = m;
rgb[2] = hsv[2];
break;
case 5:
rgb[0] = hsv[2];
rgb[1] = m;
rgb[2] = n;
break;
}
}
// From http://en.wikipedia.org/wiki/YUV#Mathematical_derivations_and_formulas
public static void yuv2rgb(float y, float u, float v, float[] rgb) {
rgb[0] = 1 * y + 0 * u + 1.13983f * v;
rgb[1] = 1 * y + -.39465f * u + -.58060f * v;
rgb[2] = 1 * y + 2.03211f * u + 0 * v;
}
public static void rgb2yuv(float r, float g, float b, float[] yuv) {
yuv[0] = .299f * r + .587f * g + .114f * b;
yuv[1] = -.14713f * r + -.28886f * g + .436f * b;
yuv[2] = .615f * r + -.51499f * g + -.10001f * b;
}
private static float[] randYUVinRGBRange(float minComponent, float maxComponent) {
while(true) {
float y = rand.nextFloat(); // * YFRAC + 1-YFRAC);
float u = rand.nextFloat() * 2 * U_OFF - U_OFF;
float v = rand.nextFloat() * 2 * V_OFF - V_OFF;
float[] rgb = new float[3];
yuv2rgb(y, u, v, rgb);
float r = rgb[0], g = rgb[1], b = rgb[2];
if(0 <= r && r <= 1 &&
0 <= g && g <= 1 &&
0 <= b && b <= 1 &&
(r > minComponent || g > minComponent || b > minComponent) && // don't want all dark components
(r < maxComponent || g < maxComponent || b < maxComponent)) // don't want all light components
return new float[]{y, u, v};
}
}
private static float sqrdist(float[] a, float[] b) {
float sum = 0;
for(int i = 0; i < a.length; i++) {
float diff = a[i] - b[i];
sum += diff * diff;
}
return sum;
}
private static double worstFit(Color[] colors) {
float worst = 8888;
float[] a = new float[3], b = new float[3];
for(int i = 1; i < colors.length; i++) {
colors[i].getColorComponents(a);
for(int j = 0; j < i; j++) {
colors[j].getColorComponents(b);
float dist = sqrdist(a, b);
if(dist < worst) {
worst = dist;
}
}
}
return Math.sqrt(worst);
}
private static float[] randYUVBetterThan(float bestDistSqrd, float minComponent, float maxComponent, float[][] in) {
for(int attempt = 1; attempt < 100 * in.length; attempt++) {
float[] candidate = randYUVinRGBRange(minComponent, maxComponent);
boolean good = true;
for(int i = 0; i < in.length; i++)
if(sqrdist(candidate, in[i]) < bestDistSqrd)
good = false;
if(good)
return candidate;
}
return null; // after a bunch of passes, couldn't find a candidate that beat the best.
}
/**
* Simple example program.
*/
public static void main(String[] args) {
final int ncolors = 10;
Color[] colors = generateVisuallyDistinctColors(ncolors, .8f, .3f);
for(int i = 0; i < colors.length; i++) {
System.out.println(colors[i].toString());
}
System.out.println("Worst fit color = " + worstFit(colors));
}
}
Ответ 7
Вот решение для управления вашей "отдельной" проблемой, которая полностью раздута:
Создайте единичную сферу и нанесите на нее очки с отталкивающими зарядами. Запустите систему частиц, пока они больше не перемещаются (или дельта "достаточно мала" ). В этот момент каждая из точек находится как можно дальше друг от друга. Преобразуйте (x, y, z) в rgb.
Я упоминаю это, потому что для некоторых классов проблем этот тип решения может работать лучше, чем грубая сила.
Я изначально увидел этот подход здесь для тесселяции сферы.
Опять же, наиболее очевидные решения по пересечению пространства HSL или пространства RGB, вероятно, будут работать нормально.
Ответ 8
Я бы попытался исправить насыщенность и просветление до максимума и сосредоточиться только на оттенке. Как я вижу, H может идти от 0 до 255, а затем обертывается. Теперь, если вам нужны два контрастных цвета, вы должны взять противоположные стороны этого кольца, то есть 0 и 128. Если вы хотите 4 цвета, вы должны отделить их на 1/4 от 256 длины круга, то есть 0, 64, 128, 192. И, конечно, поскольку другие предложили, когда вам нужны N цветов, вы можете просто отделить их на 256/N.
Что я хотел бы добавить к этой идее, так это использовать обратное представление двоичного числа для формирования этой последовательности. Посмотрите на это:
0 = 00000000 after reversal is 00000000 = 0
1 = 00000001 after reversal is 10000000 = 128
2 = 00000010 after reversal is 01000000 = 64
3 = 00000011 after reversal is 11000000 = 192
...
таким образом, если вам нужно N разных цветов, вы можете просто взять первые N чисел, отменить их, и вы получите как можно больше удаленных точек (для N - мощность двух), в то же время сохраняя, что каждый префикс последовательности отличается много.
Это была важная цель в моем случае использования, поскольку у меня была диаграмма, в которой цвета были отсортированы по площади, покрытой этим цветом. Я хотел, чтобы самые большие области диаграммы имели большой контраст, и я был в порядке с небольшими областями, чтобы иметь цвета, похожие на те, что были в первой десятке, так как для читателя было очевидно, что один из них просто наблюдает за областью.
Ответ 9
Если N достаточно велико, вы получите похожие цвета. Их так много в мире.
Почему бы не просто равномерно распределить их по спектру, например:
IEnumerable<Color> CreateUniqueColors(int nColors)
{
int subdivision = (int)Math.Floor(Math.Pow(nColors, 1/3d));
for(int r = 0; r < 255; r += subdivision)
for(int g = 0; g < 255; g += subdivision)
for(int b = 0; b < 255; b += subdivision)
yield return Color.FromArgb(r, g, b);
}
Если вы хотите смешать последовательность, чтобы похожие цвета не были рядом друг с другом, вы могли бы перетасовать полученный список.
Как я это понимаю?
Ответ 10
Это тривиально в MATLAB (есть команда hsv):
cmap = hsv(number_of_colors)
Ответ 11
Я написал пакет для R, называемый qualpalr, который специально разработан для этой цели. Я рекомендую вам посмотреть vignette, чтобы узнать, как это работает, но я попытаюсь обобщить основные моменты.
qualpalr принимает спецификацию цветов в цветовом пространстве HSL (который был описан ранее в этом потоке), проецирует его на цвет стандарта DIN99d пространство (которое воспринимается единообразно) и найдите n
, которые максимизируют минимальное расстояние между любыми ними.
# Create a palette of 4 colors of hues from 0 to 360, saturations between
# 0.1 and 0.5, and lightness from 0.6 to 0.85
pal <- qualpal(n = 4, list(h = c(0, 360), s = c(0.1, 0.5), l = c(0.6, 0.85)))
# Look at the colors in hex format
pal$hex
#> [1] "#6F75CE" "#CC6B76" "#CAC16A" "#76D0D0"
# Create a palette using one of the predefined color subspaces
pal2 <- qualpal(n = 4, colorspace = "pretty")
# Distance matrix of the DIN99d color differences
pal2$de_DIN99d
#> #69A3CC #6ECC6E #CA6BC4
#> 6ECC6E 22
#> CA6BC4 21 30
#> CD976B 24 21 21
plot(pal2)
![введите описание изображения здесь]()
Ответ 12
Я думаю, что этот простой рекурсивный алгоритм дополняет принятый ответ, чтобы генерировать различные значения оттенков. Я сделал это для hsv, но может быть использован и для других цветовых пространств.
Он генерирует оттенки в циклах как можно более раздельно друг для друга в каждом цикле.
/**
* 1st cycle: 0, 120, 240
* 2nd cycle (+60): 60, 180, 300
* 3th cycle (+30): 30, 150, 270, 90, 210, 330
* 4th cycle (+15): 15, 135, 255, 75, 195, 315, 45, 165, 285, 105, 225, 345
*/
public static float recursiveHue(int n) {
// if 3: alternates red, green, blue variations
float firstCycle = 3;
// First cycle
if (n < firstCycle) {
return n * 360f / firstCycle;
}
// Each cycle has as much values as all previous cycles summed (powers of 2)
else {
// floor of log base 2
int numCycles = (int)Math.floor(Math.log(n / firstCycle) / Math.log(2));
// divDown stores the larger power of 2 that is still lower than n
int divDown = (int)(firstCycle * Math.pow(2, numCycles));
// same hues than previous cycle, but summing an offset (half than previous cycle)
return recursiveHue(n % divDown) + 180f / divDown;
}
}
Мне здесь не удалось найти такой алгоритм. Надеюсь, это поможет, это мой первый пост здесь.