OK, este me hizo pasar un mal rato. Sin embargo, creo que es bastante bueno, incluso si los resultados no son tan artísticos como otros. Ese es el trato con la aleatoriedad. Tal vez algunas imágenes intermedias se vean mejor, pero realmente quería tener un algoritmo completamente funcional con diagramas voronoi.
Editar:
Este es un ejemplo del algoritmo final. La imagen es básicamente la superposición de tres diagramas voronoi, uno para cada componente de color (rojo, verde, azul).
Código
versión no comentada y comentada al final
unsigned short red_fn(int i, int j){
int t[64],k=0,l,e,d=2e7;srand(time(0));while(k<64){t[k]=rand()%DIM;if((e=_sq(i-t[k])+_sq(j-t[42&k++]))<d)d=e,l=k;}return t[l];
}
unsigned short green_fn(int i, int j){
static int t[64];int k=0,l,e,d=2e7;while(k<64){if(!t[k])t[k]=rand()%DIM;if((e=_sq(i-t[k])+_sq(j-t[42&k++]))<d)d=e,l=k;}return t[l];
}
unsigned short blue_fn(int i, int j){
static int t[64];int k=0,l,e,d=2e7;while(k<64){if(!t[k])t[k]=rand()%DIM;if((e=_sq(i-t[k])+_sq(j-t[42&k++]))<d)d=e,l=k;}return t[l];
}
Me tomó muchos esfuerzos, así que tengo ganas de compartir los resultados en diferentes etapas, y hay algunos buenos (incorrectos) para mostrar.
Primer paso: coloque algunos puntos al azar, con x=y
Lo he convertido a jpeg porque el png original era demasiado pesado para cargar ( >2MB
), ¡apuesto a que son más de 50 tonos de gris!
Segundo: tener una mejor coordenada y
No podía permitirme tener otra tabla de coordenadas generada aleatoriamente para el y
eje, por lo que necesitaba una forma simple de obtener las " aleatorias " en la menor cantidad de caracteres posible. Fui a usar la x
coordenada de otro punto en la tabla, haciendo un bit AND
a bit en el índice del punto.
3 °: no recuerdo pero se está poniendo bien
Pero en este momento tenía más de 140 caracteres, así que necesitaba jugar golf bastante.
4to: líneas de escaneo
Es broma, esto no es deseable, pero me parece genial.
Aún trabajando para reducir el tamaño del algoritmo, me enorgullece presentar:
Edición StarFox
Voronoi instagram
5to: aumentar el número de puntos
Ahora tengo un código funcional, así que pasemos de 25 a 60 puntos.
Eso es difícil de ver desde una sola imagen, pero los puntos están casi todos ubicados en el mismo y
rango. Por supuesto, no cambié la operación bit a bit, &42
es mucho mejor:
Y aquí estamos, en el mismo punto que la primera imagen de esta publicación. Ahora expliquemos el código para los raros que estarían interesados.
Código sin golf y explicado
unsigned short red_fn(int i, int j)
{
int t[64], // table of 64 points's x coordinate
k = 0, // used for loops
l, // retains the index of the nearest point
e, // for intermediary results
d = 2e7; // d is the minimum distance to the (i,j) pixel encoutnered so far
// it is initially set to 2e7=2'000'000 to be greater than the maximum distance 1024²
srand(time(0)); // seed for random based on time of run
// if the run overlaps two seconds, a split will be observed on the red diagram but that is
// the better compromise I found
while(k < 64) // for every point
{
t[k] = rand() % DIM; // assign it a random x coordinate in [0, 1023] range
// this is done at each call unfortunately because static keyword and srand(...)
// were mutually exclusive, lenght-wise
if (
(e= // assign the distance between pixel (i,j) and point of index k
_sq(i - t[k]) // first part of the euclidian distance
+
_sq(j - t[42 & k++]) // second part, but this is the trick to have "" random "" y coordinates
// instead of having another table to generate and look at, this uses the x coordinate of another point
// 42 is 101010 in binary, which is a better pattern to apply a & on; it doesn't use all the table
// I could have used 42^k to have a bijection k <-> 42^k but this creates a very visible pattern splitting the image at the diagonal
// this also post-increments k for the while loop
) < d // chekcs if the distance we just calculated is lower than the minimal one we knew
)
// { // if that is the case
d=e, // update the minimal distance
l=k; // retain the index of the point for this distance
// the comma ',' here is a trick to have multiple expressions in a single statement
// and therefore avoiding the curly braces for the if
// }
}
return t[l]; // finally, return the x coordinate of the nearest point
// wait, what ? well, the different areas around points need to have a
// "" random "" color too, and this does the trick without adding any variables
}
// The general idea is the same so I will only comment the differences from green_fn
unsigned short green_fn(int i, int j)
{
static int t[64]; // we don't need to bother a srand() call, so we can have these points
// static and generate their coordinates only once without adding too much characters
// in C++, objects with static storage are initialized to 0
// the table is therefore filled with 60 zeros
// see http://stackoverflow.com/a/201116/1119972
int k = 0, l, e, d = 2e7;
while(k<64)
{
if( !t[k] ) // this checks if the value at index k is equal to 0 or not
// the negation of 0 will cast to true, and any other number to false
t[k] = rand() % DIM; // assign it a random x coordinate
// the following is identical to red_fn
if((e=_sq(i-t[k])+_sq(j-t[42&k++]))<d)
d=e,l=k;
}
return t[l];
}
Gracias por leer hasta ahora.