-
Notifications
You must be signed in to change notification settings - Fork 3
/
index.js
144 lines (129 loc) · 3.11 KB
/
index.js
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
'use strict';
const Jimp = require('jimp');
const util = require('util');
const width = 256;
const height = 256;
const numIterations = 2000;
let maxHeight = 0;
let minHeight = 0;
const colorRamp = [
[0,0,100],
[0,0,100],
[0,0,100],
[0,0,100],
[0,0,100],
[0,0,100],
[0,0,155],
[0,0,170],
[0,0,180],
[0,0,255],
[0,0,255],
[0,0,255],
[0,0,255],
[0,127,127],
[0,255,0],
[42,255,0],
[85,255,0],
[127,255,0],
[170,255,0],
[212,255,0],
[255,255,0],
[246,226,0],
[238,197,0],
[230,168,0],
[222,139,0],
[214,110,0],
[206,81,0],
[214,110,42],
[222,139,85],
[230,168,127],
[238,197,170],
[246,226,212],
[255,255,255],
];
async function generateImage() {
const heightData = new Array(width * height).fill(0);
for (let i = 0; i < numIterations; i++) {
shiftSide(heightData);
// if ([10, 50, 100, 500, 1000, 2000].includes(i + 1)) {
// findMaxMinHeight(heightData);
// await saveImage(heightDataToColorBuffer(heightData), (i + 1) + '_iterations.png');
// }
}
findMaxMinHeight(heightData);
return heightDataToColorBuffer(heightData);
}
function findMaxMinHeight(heightData) {
heightData.forEach((h) => {
if (h > maxHeight) {
maxHeight = h;
}
if (h < minHeight) {
minHeight = h;
}
});
}
function heightDataToColorBuffer(heightData) {
const colorData = [];
for (let i = 0; i < height; i++) {
for (let k = 0; k < width; k++) {
let currentHeight = heightData[k + i * width];
let colorIndex = Math.floor(normalize(currentHeight, minHeight, maxHeight) * (colorRamp.length - 1));
colorData.push(...colorRamp[colorIndex]);
}
}
return Buffer.from(colorData);
}
function normalize(num, min, max) {
return (num - min) / (max - min);
}
// generate random line by picking 2 random points
// go through all points and raise/lower them depending
// on which side of the line segment they lie on
function shiftSide(heightData) {
const x1 = getRandomInt(0, width - 1);
const y1 = getRandomInt(0, height - 1);
const x2 = getRandomInt(0, width - 1);
const y2 = getRandomInt(0, height - 1);
for (let y = 0; y < height; y++) {
const stride = y * width;
for (let x = 0; x < width; x++) {
const d = pointSide(x, y, x1, y1, x2, y2);
const i = x + stride;
if (d > 0) {
heightData[i] ++;
} else if (d < 0) {
heightData[i] --;
}
}
}
}
// min, max inclusive
function getRandomInt(min, max) {
min = Math.ceil(min);
max = Math.floor(max);
return Math.floor(Math.random() * (max - min + 1)) + min;
}
// https://math.stackexchange.com/a/274728/49923
function pointSide(x, y, x1, y1, x2, y2) {
return ((x - x1) * (y2 - y1)) - ((y - y1) * (x2 - x1));
}
// save buffer to file, buffer is rgb data
const saveImage = util.promisify(function (buffer, filename, callback) {
new Jimp({ data: buffer, width: width, height: height }, (err, image) => {
if (err) {
return callback(err);
}
image.write(filename, callback)
});
});
(async () => {
try {
const now = Date.now();
const buffer = await generateImage();
await saveImage(buffer, 'test.png');
console.log(numIterations + ' iterations took ' + (Date.now() - now) + ' ms');
} catch (e) {
console.error(e);
}
})();