forked from mitxela/plotterfun
-
Notifications
You must be signed in to change notification settings - Fork 0
/
jaggy.js
138 lines (107 loc) · 4.35 KB
/
jaggy.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
/**
* Algorithm by Tim Koop https://github.com/tkoop
*/
importScripts('helpers.js')
postMessage(['sliders', defaultControls.concat([
{ label: 'Seed', value: 50, min: 0, max: 100, step: 1 },
])]);
// Thanks to https://gist.github.com/blixt/f17b47c62508be59987b
function createRandFunction(seedString) {
let seed = parseInt(seedString) % 2147483647
if (seed <= 0) seed += 2147483646;
let next = function() {
return seed = seed * 16807 % 2147483647;
};
let rand = function() {
// We know that result of next() will be 1 to 2147483646 (inclusive).
return (next() - 1) / 2147483646;
};
return rand
}
// These three functions thanks to https://stackoverflow.com/a/1501725/650004
function sqr(x) {
return x * x
}
function dist2(v, w) {
return sqr(v[0] - w[0]) + sqr(v[1] - w[1])
}
function distToSegmentSquared(p, v, w) {
var l2 = dist2(v, w);
if (l2 == 0) return dist2(p, v);
var t = ((p[0] - v[0]) * (w[0] - v[0]) + (p[1] - v[1]) * (w[1] - v[1])) / l2;
t = Math.max(0, Math.min(1, t));
return dist2(p, [v[0] + t * (w[0] - v[0]), v[1] + t * (w[1] - v[1]) ]);
}
/* This function returns the index into loop of the closest line segment to the point. The line segment is
defined as the line segment from one point (i) to the next (i+1). It returns the index to the first point.
*/
function findIndexOfClosestLineToPoint(loop, point) {
var closestIndex = 0
var closestDistance = distToSegmentSquared(point, loop[0], loop[1])
for(var i=1; i<loop.length-1; i++) {
var p1 = loop[i]
var p2 = loop[i+1]
var distance = distToSegmentSquared(point, p1, p2)
if (distance < closestDistance) {
closestDistance = distance
closestIndex = i
}
}
return closestIndex
}
onmessage = async function (e) {
const [config, pixData] = e.data;
// Image processor (gets a value for the current pixel)
const getPixel = pixelProcessor(config, pixData)
// Our points. Not the final list given back.
let points = [];
// We will use a random number generater that can take a seed, so that all dots are the same
// when changing line directions
let dotRand = createRandFunction("" + config.Seed);
for (let y = 0; y < config.height - 1; y += 1) {
for (let x = 0; x <= config.width - 1; x += 1) {
// Get the current pixels 'value'
pixelval = getPixel(x, y);
// We will place a dot here, randomly, with a darker value more likely to be placed
p = pixelval / 255.0 // convert pixel darkness to a probablilty (p)
p = p * p * p * 0.1 // p value is still too high, so we turn it down to something that looks about right
if (p > dotRand()) {
points.push([x, y]);
}
}
}
let totalPoints = points.length
let everyPercent = Math.ceil(totalPoints / 100)
let everyRedraw = Math.ceil(totalPoints / 10)
// This loop is an ordered array of points
let loop = [];
let randomPointIndex = parseInt(dotRand() * points.length);
loop.push(points[randomPointIndex]);
points.splice(randomPointIndex, 1);
randomPointIndex = parseInt(dotRand() * points.length);
loop.push(points[randomPointIndex]);
points.splice(randomPointIndex, 1);
randomPointIndex = parseInt(dotRand() * points.length);
loop.push(points[randomPointIndex]);
points.splice(randomPointIndex, 1);
loop.push(loop[0]);
// loop is now a triangle, with four points. The first and last are the same point.
while(points.length > 0) {
randomPointIndex = parseInt(dotRand() * points.length)
let point = points[randomPointIndex]
// points.splice(randomPointIndex, 1)
// The following two lines act like the above splice, but maybe faster
points[randomPointIndex] = points[points.length-1]
points.length = points.length - 1
let indexOfClosestLineToPoint = findIndexOfClosestLineToPoint(loop, point)
loop.splice(indexOfClosestLineToPoint + 1, 0, point)
if (points.length % everyPercent == 0) {
postMessage(['msg', ((totalPoints - points.length) * 100 / totalPoints).toFixed(0) + "%"]);
}
if (points.length % everyRedraw == 0) {
postLines(loop);
}
}
postMessage(['msg', '']);
postLines(loop);
}