OK, celui-ci m'a donné du fil à retordre. Je pense que c’est plutôt bien, même si les résultats ne sont pas aussi artistiques que d’autres. C'est l'affaire avec le hasard. Certaines images intermédiaires semblent peut-être meilleures, mais je voulais vraiment avoir un algorithme pleinement fonctionnel avec des diagrammes de voronoï.
Modifier:
Ceci est un exemple de l'algorithme final. L'image est fondamentalement la superposition de trois diagrammes de voronoï, un pour chaque composante de couleur (rouge, vert, bleu).
Code
non golfé, version commentée à la fin
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];
}
Il m'a fallu beaucoup d'efforts, alors j'ai envie de partager les résultats à différentes étapes, et il y en a de bonnes (incorrectes) à montrer.
Première étape: placer quelques points au hasard, avec x=y
Je l'ai converti en jpeg parce que le png original était trop lourd pour upload ( >2MB
), je parie que c'est bien plus de 50 nuances de gris!
Deuxièmement: avoir une meilleure coordonnée y
Je ne pouvais pas se permettre d'avoir une autre table de coordonnées générées au hasard pour l' y
axe, donc je besoin d' un moyen simple d'obtenir « au hasard » les dans le moins de caractères possible. Je suis allé en utilisant les x
coordonnées d'un autre point de la table, en faisant un bitwise AND
sur l'index du point.
3ème: je ne m'en souviens pas mais ça commence à bien
Mais à cette époque, j’avais dépassé les 140 personnages, j’avais donc besoin de beaucoup jouer au golf.
4ème: lignes de balayage
Je plaisante, ce n'est pas voulu, mais plutôt cool, il me semble.
Toujours en train de réduire la taille de l'algorithme, je suis fier de présenter:
Édition StarFox
Voronoï instagram
5ème: augmenter le nombre de points
J'ai maintenant un morceau de code de travail, passons donc de 25 à 60 points.
C'est difficile à voir à partir d'une seule image, mais les points sont presque tous situés dans la même y
plage. Bien sûr, je n'ai pas changé l'opération bitwise, &42
c'est bien mieux:
Et nous sommes au même point que la toute première image de ce post. Expliquons maintenant le code pour les rares qui seraient intéressés.
Ungolfed et expliqué le code
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];
}
Merci d'avoir lu jusqu'ici.