-
Notifications
You must be signed in to change notification settings - Fork 1
/
lattice.pde
151 lines (136 loc) · 4.48 KB
/
lattice.pde
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
// Represents a recursive lattice structure. It is generated
// by layering n-pronged structures within eachother (see the
// 'fractalize' method for more information.
class Lattice {
private PGraphics buffer; /* so we don't have to draw on-screen */
private int dimension; /* prongs per iteration */
private float precision; /* base case of recursion */
private float radius; /* original prong length */
private float angle; /* ngle between prongs */
private Painter painter; /* color scheme */
// Stores parameters, calculates some helper values, and
// generates.
Lattice(int d, float p, Painter c){
painter = c;
dimension = d;
precision = p;
radius = (width+height)/6.5;
angle = 2*PI/d;
generate();
}
// Create PGraphics buffer so drawing can be done without
// displaying on screen. Recursively generate lattice in
// the center of this buffer.
private void generate(){
buffer = createGraphics(width*2, height*2);
buffer.beginDraw();
buffer.background(black);
buffer.pushMatrix();
buffer.translate(buffer.width/2, buffer.height/2);
buffer.rotate(random(2*PI));
fractalize(radius);
buffer.popMatrix();
buffer.endDraw();
}
// Place PGraphics buffer on screen.
void display(float angle){
pushMatrix();
translate(width/2, height/2);
rotate(angle);
translate(-width/2, -height/2);
display();
popMatrix();
}
void display(){
image(buffer, -width/2, -height/2, 2*width, 2*height);
}
// Draws an n-pronged structure with arms the size of <stretch>,
// half this arm length, and recurse downward, nesting prong
// structures within eachother - each with arms half the length
// of its parent.
//
// The prong structures are fitted together such that two prongs
// of each child remain in contact with two prongs of the parents
// prongs.
private void fractalize(float stretch){
if(stretch < precision){
return;
}
prongs(stretch);
buffer.pushMatrix();
for(int i = 0; i < dimension; ++i){
buffer.rotate(angle);
buffer.pushMatrix();
buffer.translate(stretch/2.0, 0);
buffer.rotate(angle);
buffer.translate(stretch/2, 0);
buffer.rotate(PI);
fractalize(stretch/2.0);
buffer.popMatrix();
}
buffer.popMatrix();
}
// Draws n-pronged structure to the PGraphics buffer. This is
// performed at each step of recursion, with lines decreasing
// length each time. <stretch> is line length.
private void prongs(float stretch){
buffer.fill(255);
buffer.ellipse(0, 0, stretch/10, stretch/10);
buffer.pushMatrix();
for(int i = 0; i < dimension; ++i){
buffer.stroke(painter.paint(stretch));
buffer.line(0, 0, stretch, 0);
// Draw some circles to make things look nicer. These four
// lines aren't really necessary - commenting them out won't
// break anything.
buffer.ellipse(-stretch, 0, stretch/10.0, stretch/10.0);
buffer.ellipse(stretch, 0, stretch/10.0, stretch/10.0);
buffer.ellipse(0, stretch, stretch/10.0, stretch/10.0);
buffer.ellipse(0, -stretch, stretch/10.0, stretch/10.0);
buffer.rotate(angle);
}
buffer.popMatrix();
}
// Crops and saves image.
void saveTo(String path){
if(!path.endsWith(".png"))
path += ".png";
cropped().save(path);
}
// Generates a cropped and padded image of the lattice
// buffer. Without this, there's a whole lot of extra
// background space. With it, saved images look nice
// and fitting to their frames.
private PImage cropped(){
int s = 60;
int lm = leftMost();
int tm = topMost();
int l = max(0, lm - s);
int t = max(0, tm - s);
return buffer.get(l, t, buffer.width - 2*l, buffer.height - 2*t);
}
// Finds location of the left-most non-black pixel on the
// lattice. This is used for auto-cropping.
private int leftMost(){
buffer.loadPixels();
for(int i = 0; i < buffer.width/2; i += 2){
for(int j = 0; j < buffer.height; j += 2){
if(buffer.pixels[i + j*buffer.width] != black)
return i;
}
}
return 0;
}
// Finds location of the highest non-black pixel on the
// lattice. This is used for auto-cropping.
private int topMost(){
buffer.loadPixels();
for(int j = 0; j < buffer.height/2; j += 2){
for(int i = 0; i < buffer.width; i += 2){
if(buffer.pixels[i + j*buffer.width] != black)
return j;
}
}
return 0;
}
}