chaos/scripts/chaos.js

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--;
}
}
};