Skip to content

Instantly share code, notes, and snippets.

@RemyPorter
Last active May 29, 2021 16:33
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save RemyPorter/b6021b690d9c5af7648ef9d9e5ce92c1 to your computer and use it in GitHub Desktop.
Save RemyPorter/b6021b690d9c5af7648ef9d9e5ce92c1 to your computer and use it in GitHub Desktop.
A Markov Chain-based glyph generator
/**
A markov-chain based glyph generator. Given sequences of points as a corpus, this will create a markov chain based on those points.
Then, by sampling the chain, we can generate entirely new glyphs that weren't in our original dataset.
Press "r" to generate a new frame. Press "s" to save the frame to a file (with a random UUID as its name).
Requires the PostFx library: https://github.com/cansik/processing-postfx/
*/
import java.util.*;
import static java.util.UUID.randomUUID;
import ch.bildspur.postfx.builder.*;
import ch.bildspur.postfx.pass.*;
import ch.bildspur.postfx.*;
/**
Generic MarkovChain class. This is a very lazy implementation.
There is a key for each unique item. Each key has an arraylist of items
which were seen to follow it.
*/
class MarkovChain<T> extends HashMap<T, ArrayList<T>> {
//safety wrapper to ensure we always have data for every key
ArrayList<T> get(Object key) {
if (!this.containsKey(key)) {
this.put((T)key, new ArrayList<T>());
}
return super.get(key);
}
//populate the chain with a corpus
void analyze(List<T> sequence) {
for (int i = 1; i < sequence.size(); i++) {
T item = sequence.get(i-1);
this.get(item).add(sequence.get(i));
}
}
T getRandomKey() {
T[] keys = (T[])this.keySet().toArray();
int r = (int)random(keys.length);
return keys[r];
}
T getRandomFollower(T key) {
ArrayList<T> entry = get(key);
return entry.get((int)random(entry.size()));
}
//Generate a new sequence of len items
ArrayList<T> generate(int len) {
ArrayList<T> res = new ArrayList<T>();
T start = this.getRandomKey();
res.add(start);
for (int i = 1; i < len; i++) {
try {
start = getRandomFollower(start);
res.add(start);
} catch (IndexOutOfBoundsException ex) {
start = this.getRandomKey();
res.add(start);
}
}
return res;
}
}
/** POINT LISTS - my input dataset **/
PVector[] square = {
new PVector(0,0),
new PVector(1,0),
new PVector(1,1),
new PVector(0,1),
new PVector(0,0)
};
PVector[] buildSinus(int n) {
PVector[] res = new PVector[n];
for (int i = 0; i < n; i++) {
float x = i / n;
PVector p = new PVector(x, sin(x*2*PI));
res[i] = p;
}
return res;
}
PVector[] triangle = {
new PVector(0,0),
new PVector(0,1),
new PVector(1,0),
new PVector(0,0)
};
PVector[] sinusPath = buildSinus(10);
PVector[] snowflake = {
new PVector(0, 0.25),
new PVector(0.25, 0.5),
new PVector(0, 0.75),
new PVector(0.25, 0.75),
new PVector(0.5, 1),
new PVector(0.75, 0.75),
new PVector(1,0.75),
new PVector(0.75,0.5),
new PVector(1., 0.25),
new PVector(0.75, 0.25),
new PVector(0.5, 0),
new PVector(0.25, 0.25),
new PVector(0, 0.25)
};
PVector[] c = {
new PVector(0,0),
new PVector(0,1),
new PVector(1,1),
new PVector(1,0.75),
new PVector(0.25,0.75),
new PVector(0.25, 0.25),
new PVector(1., 0.25),
new PVector(1, 0),
new PVector(0, 0)
};
PVector[] a = {
new PVector(0, 1),
new PVector(0.25, 0.5),
new PVector(0.75, 0.5),
new PVector(1, 1),
new PVector(0.5, 0),
new PVector(0, 1)
};
PVector[] l = {
new PVector(0, 0),
new PVector(0, 1),
new PVector(1, 1),
new PVector(1, 0.75),
new PVector(0.25, 0.75),
new PVector(0.25, 0),
new PVector(0, 0)
};
PVector[] t = {
new PVector(0, 0),
new PVector(1, 0),
new PVector(1, 0.25),
new PVector(0.75, 0.25),
new PVector(0.75, 1),
new PVector(0.25, 1),
new PVector(0.25, 0.25),
new PVector(0, 0.25),
new PVector(0, 0)
};
PVector[] o = {
new PVector(0, 0),
new PVector(0, 1),
new PVector(0.75, 1),
new PVector(0.75, 0),
new PVector(0, 0)
};
PVector[] sev = {
new PVector(0,0),
new PVector(0, 0.25),
new PVector(0.75, 0.25),
new PVector(0, 0.75),
new PVector(0, 1),
new PVector(1, 0),
new PVector(0, 0)
};
PVector[] bx = {
new PVector(0, 0),
new PVector(0, 0.5),
new PVector(0.75, 0.5),
new PVector(0.75, 0.75),
new PVector(1, 0.75),
new PVector(1, 0),
new PVector(0, 0)
};
PVector[] tup = {
new PVector(0, 1),
new PVector(1, 1),
new PVector(1, 0.5),
new PVector(0, 1)
};
/** END POINT LISTS **/
PVector[][] chains = {
bx, sev, t, l, a, c, square, o, triangle, sinusPath, snowflake, tup
};
MarkovChain<PVector> s = new MarkovChain<PVector>();
PostFX fx;
void setup() {
fullScreen(P3D);
//populate the markov chain out of our input dataset
for (int i = 0; i < chains.length; i++) {
s.analyze(Arrays.asList(chains[i]));
}
background(0);
frameRate(10);
fill(#00FF00);
noStroke();
fx = new PostFX(this);
}
boolean redraw = true;
void draw() {
if (!redraw) return;
clear();
for (int x = 0; x < width + 20; x += 20) {
for (int y = 0; y < height + 20; y += 20) {
ArrayList<PVector> gen = s.generate(10);
pushMatrix();
translate(x, y);
scale(15);
beginShape();
for (PVector p : gen) {
vertex(p.x, p.y);
}
endShape(CLOSE);
popMatrix();
}
}
fx.render()
.sobel()
.brightPass(0.25)
.pixelate(width/2.75)
.bloom(0.5, 20, 40)
.vignette(0.75, 0.25)
.noise(0.25, 0.25)
.compose();
redraw = false;
//save("sample.png");
}
void keyPressed() {
if (key == 'r') {
redraw = true;
}
else if (key == 's') {
save(randomUUID().toString() + ".png");
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment