UNPKG

atum

Version:

A Procedural Graph Based Javascript Library

201 lines (183 loc) 7.26 kB
/** * This module is used to create different point distributions that can be * turned into different tile sets when made into a graph format. There are * various different distributions that can be used to create interesting * tile patterns when turned into a voronoi diagram. * * @tutorial Point-Distributions * * @class PointDistribution */ "use strict"; import Poisson from "poisson-disk-sample"; import Vector from "../geometry/Vector"; import Rectangle from "../geometry/Rectangle"; import Rand from "./Rand"; /** * Creates a random distribution of points in a particular bounding box * with a particular average distance between points. * * @export * @param {Rectangle} bbox The bounding box to create the points in * @param {number} d Average distance between points * @param {number} [seed=null] If specified use a local seed for creating the point * distribution. Otherwise, use the current global seed for generation * @returns {Vector[]} The list of randomly distributed points * @memberof PointDistribution */ export function random(bbox, d, seed = null) { const rng = seed ? new Rand(seed) : Rand; const nPoints = bbox.area / (d * d); let points = []; for (let i = 0; i < nPoints; i++) { points.push(rng.vector(bbox)); } return points; } /** * Creates a square grid like distribution of points in a particular bounding * box with a particular distance between points. * * @export * @param {Rectangle} bbox The bounding box to create the points in * @param {number} d Average distance between points * @returns {Vector[]} The list of randomly distributed points * @memberof PointDistribution */ export function square(bbox, d) { const dx = d / 2; const dy = dx; let points = []; for (let y = 0; y < bbox.height; y += d) { for (let x = 0; x < bbox.width; x += d) { points.push(new Vector(dx + x, dy + y)); } } return points; } /** * Creates a uniform hexagonal distribution of points in a particular bounding * box with a particular distance between points. The hexagons can also be * specified to have a particular width or height as well as creating hexagons * that have "pointy" tops or "flat" tops. By default it makes flat tops. * * @export * @param {Rectangle} bbox The bounding box to create the points in * @param {number} d Average distance between points * @param {boolean} [flatTop=true] Create hecagons with flat tops by default. * Otherwise go with the pointy top hexagons. * @param {number} w The width of the hexagon tiles * @param {number} h The height of the hexagon tiles * @returns {Vector[]} The list of randomly distributed points * @memberof PointDistribution */ export function hexagon(bbox, d, flatTop = true, w, h) { // Need to allow for the change of height and width // Running into "Uncaught Voronoi.closeCells() > this makes no sense!" const dx = d / 2; const dy = dx; let points = []; const altitude = Math.sqrt(3) / 2 * d; var N = Math.sqrt(bbox.area / (d * d)); for (let y = 0; y < N; y++) { for (let x = 0; x < N; x++) { points.push(new Vector((0.5 + x) / N * bbox.width, (0.25 + 0.5 * x % 2 + y) / N * bbox.height)); // points.push(new Vector((y % 2) * dx + x * d + dx, y * d + dy)); // Pointy Top // points.push(new Vector(x * d, (x % 2) * dx + y * d)); // Flat Top } } return points; } /** * Creates a blue noise distribution of points in a particular bounding box * with a particular average distance between points. This is done by * creating a grid system and picking a random point in each grid. This has * the effect of creating a less random distribution of points. The second * parameter m determins the spacing between points in the grid. This ensures * that no two points are in the same grid. * * @summary Create a jittered grid based random blue noise point distribution. * * @export * @param {Rectangle} bbox The bounding box to create the points in * @param {number} d Average distance between points * @param {number} [seed=null] If specified use a local seed for creating the point * distribution. Otherwise, use the current global seed for generation * @param {number} [m=0] Maximum distance away from the edge of the grid that a * point can be placed. This acts to increase the padding between points. * This makes the noise less random. This number must be smaller than d. * @returns {Vector[]} The list of randomly distributed points * @memberof PointDistribution */ export function jitteredGrid(bbox, d, seed = null, m = 0) { const rng = seed ? new Rand(seed) : Rand; let points = []; let pointBox; for (let y = 0; y < bbox.height - d; y += d) { for (let x = 0; x < bbox.width - d; x += d) { // Local bbox for the point to generate in const boxPos = new Vector(x - d + m, y - d + m); pointBox = new Rectangle(boxPos, x - m, y - m); points.push(rng.vector(pointBox)); } } return points; } /** * Creates a poisson, or blue noise distribution of points in a particular * bounding box with a particular average distance between points. This is * done by using poisson disk sampling which tries to create points so that the * distance between neighbors is as close to a fixed number (the distance d) * as possible. This algorithm is implemented using the poisson dart throwing * algorithm. * * @summary Create a blue noise distribution of points using poisson disk * sampling. * * @export * @param {Rectangle} bbox The bounding box to create the points in * @param {number} d Average distance between points * @returns {Vector[]} The list of randomly distributed points * * @see {@link https://www.jasondavies.com/poisson-disc/} * @see {@link https://github.com/jeffrey-hearn/poisson-disk-sample} * @memberof PointDistribution */ export function poisson(bbox, d) { var sampler = new Poisson(bbox.width, bbox.height, d, d); var solution = sampler.sampleUntilSolution(); var points = solution.map(point => new Vector(point)); return points; } /** * Creates a blue noise distribution of points in a particular bounding box * with a particular average distance between points. This is done by using * recursive wang tiles to create this distribution of points. * * @summary Not Implemented Yet * * @export * @param {Rectangle} bbox The bounding box to create the points in * @param {number} d Average distance between points * @returns {Vector[]} The list of randomly distributed points * @memberof PointDistribution */ export function recursiveWang(bbox, d) { throw "Error: Not Implemented"; } /** * Creates a circular distribution of points in a particular bounding box * with a particular average distance between points. * * @summary Not Implemented Yet * * @export * @param {Rectangle} bbox The bounding box to create the points in * @param {number} d Average distance between points * @returns {Vector[]} The list of randomly distributed points * @memberof PointDistribution */ export function circular(bbox, d) { throw "Error: Not Implemented"; }