86 lines
2.6 KiB
JavaScript
86 lines
2.6 KiB
JavaScript
'use strict';
|
|
|
|
import { getRandomNumber, getColor } from './utils';
|
|
|
|
/**
|
|
* Calculate the position of a regular polygon's vertices
|
|
* inside a 2 x 2 squared centered on the origin
|
|
*
|
|
* @param {number} count Vertices amount
|
|
* @return {Array<Array>} Array of points representing the vertices
|
|
*/
|
|
export const createRegularVertices = count => {
|
|
const step = 2 * Math.PI / count;
|
|
const initial = -Math.atan(Math.sin(step) / (Math.cos(step) - 1));
|
|
const result = [];
|
|
|
|
for (let i = 0; i < count; i += 1) {
|
|
let current = step * i + initial;
|
|
|
|
result.push([Math.cos(current), Math.sin(current)]);
|
|
}
|
|
|
|
return result;
|
|
};
|
|
|
|
/**
|
|
* Scale the vertices so that they fit in given bounding rectangle
|
|
*
|
|
* @param {number} width Bounding rectangle width
|
|
* @param {number} height Bounding rectangle height
|
|
* @param {Array<Array>} vertices Vertices to scale
|
|
* @return {Array<Array>} Scaled vertices
|
|
*/
|
|
export const scaleVertices = (width, height, vertices) => {
|
|
const centerX = Math.floor(width / 2);
|
|
const centerY = Math.floor(height / 2);
|
|
const radius = Math.min(centerX, centerY);
|
|
|
|
return vertices.map(vertex => ([
|
|
vertex[0] * radius + centerX,
|
|
vertex[1] * radius + centerY
|
|
]));
|
|
};
|
|
|
|
/**
|
|
* Apply the chaos game algorithm in a polygon
|
|
* of given vertices, with given fraction
|
|
*
|
|
* @param {ImageData} image Image to write on Data to amend
|
|
* @param {number} fraction Fraction to use
|
|
* @param {Array} vertices List of vertices of the bounding polygon
|
|
* @return {null}
|
|
*/
|
|
export const applyChaos = (image, fraction, vertices) => {
|
|
const count = vertices.length, imageWidth = image.width;
|
|
|
|
// now we apply the chaos algorithm:
|
|
// for any point, the next point is a `fraction` of the
|
|
// distance between it and a random vertex
|
|
let point = vertices[0];
|
|
let iterations = Math.floor(500 * imageWidth * fraction);
|
|
let drop = Math.floor(iterations / 200);
|
|
|
|
while (iterations--) {
|
|
const vertexNumber = getRandomNumber(0, count);
|
|
const vertex = vertices[vertexNumber], color = getColor(vertexNumber);
|
|
|
|
point = [
|
|
Math.floor((point[0] - vertex[0]) * fraction + vertex[0]),
|
|
Math.floor((point[1] - vertex[1]) * fraction + vertex[1])
|
|
];
|
|
|
|
// skip the first 1000 points
|
|
if (drop === 0) {
|
|
const i = (point[1] * imageWidth + point[0]) * 4;
|
|
|
|
image.data[i] = color[0];
|
|
image.data[i + 1] = color[1];
|
|
image.data[i + 2] = color[2];
|
|
image.data[i + 3] = 255;
|
|
} else {
|
|
drop--;
|
|
}
|
|
}
|
|
};
|