OK, dieser hat mir eine harte Zeit bereitet. Ich finde es aber ziemlich schön, auch wenn die Ergebnisse nicht so kunstvoll sind wie bei einigen anderen. Das ist der Deal mit Zufälligkeit. Vielleicht sehen einige Zwischenbilder besser aus, aber ich wollte unbedingt einen voll funktionsfähigen Algorithmus mit Voronoi-Diagrammen haben.
Bearbeiten:
Dies ist ein Beispiel für den endgültigen Algorithmus. Das Bild ist im Grunde genommen die Überlagerung von drei Voronoi-Diagrammen, eines für jede Farbkomponente (rot, grün, blau).
Code
ungolfed, kommentierte Version am Ende
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];
}
Es hat mich sehr viel Mühe gekostet, daher möchte ich die Ergebnisse in verschiedenen Phasen teilen, und es gibt nette (falsche), die ich zeigen kann.
Erster Schritt: Einige Punkte nach dem Zufallsprinzip setzen lassen, mit x=y
Ich habe es in JPEG konvertiert, weil das ursprüngliche PNG zu schwer für das Hochladen war ( >2MB
), ich wette, das sind weit mehr als 50 Graustufen!
Zweitens: Haben Sie eine bessere y-Koordinate
Ich konnte es mir nicht leisten, eine andere zufällig generierte Koordinatentabelle für die y
Achse zu erstellen. Daher brauchte ich eine einfache Methode, um " zufällige " Koordinaten mit so wenigen Zeichen wie möglich zu erhalten. Ich ging für die Verwendung des x
in der Tabelle von einem anderen Punkt koordinieren, um eine bitweise tut AND
auf dem Index des Punktes.
3. Ich erinnere mich nicht, aber es wird schön
Aber zu dieser Zeit war ich weit über 140 Zeichen, so dass ich es ziemlich viel Golf spielen musste.
Viertens: Scanlines
Nur ein Scherz, das ist nicht erwünscht, aber irgendwie cool.
Ich arbeite immer noch an der Verkleinerung des Algorithmus und bin stolz darauf, Folgendes präsentieren zu können:
StarFox Edition
Voronoi instagram
5. Erhöhen Sie die Anzahl der Punkte
Ich habe jetzt ein funktionierendes Stück Code, gehen wir also von 25 auf 60 Punkte.
Das ist auf nur einem Bild schwer zu erkennen, aber die Punkte befinden sich fast alle im selben y
Bereich. Natürlich habe ich die bitweise Operation nicht geändert, &42
ist viel besser:
Und hier sind wir am selben Punkt wie das allererste Bild aus diesem Beitrag. Lassen Sie uns nun den Code für die seltenen erklären, die interessiert wären.
Ungolfed und erklärt 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];
}
Vielen Dank fürs Lesen.