JSPM

@thi.ng/poisson

1.0.15
  • ESM via JSPM
  • ES Module Entrypoint
  • Export Map
  • Keywords
  • License
  • Repository URL
  • TypeScript Types
  • README
  • Created
  • Published
  • Downloads 77
  • Score
    100M100P100Q88785F
  • License Apache-2.0

nD Poisson-disc sampling w/ support for spatial density functions and custom PRNGs

Package Exports

  • @thi.ng/poisson

This package does not declare an exports field, so the exports above have been automatically detected and optimized by JSPM instead. If any package subpath is missing, it is recommended to post an issue to the original package (@thi.ng/poisson) to support the "exports" field. If that is not possible, create a JSPM override to customize the exports field for this package.

Readme

poisson

npm version npm downloads Twitter Follow

This project is part of the @thi.ng/umbrella monorepo.

About

example screenshot

nD Poisson disk sampling with support for variable spatial density, custom PRNGs (via @thi.ng/random's IRandom interface & implementations) and customizable quality settings.

Currently uses a k-D tree implementation to speed up the sampling process, but will be refactored to support other, alternative spatial indexing mechanisms...

Status

STABLE - used in production

Installation

yarn add @thi.ng/poisson
// ES module
<script type="module" src="https://unpkg.com/@thi.ng/poisson?module" crossorigin></script>

// UMD
<script src="https://unpkg.com/@thi.ng/poisson/lib/index.umd.js" crossorigin></script>

Package sizes (gzipped, pre-treeshake): ESM: 337 bytes / CJS: 391 bytes / UMD: 501 bytes

Dependencies

Usage examples

Several demos in this repo's /examples directory are using this package.

A selection:

Screenshot Description Live demo Source
Poisson-disk shape-aware sampling, Voronoi & Minimum Spanning Tree visualization Demo Source

API

Generated API docs

The package provides a single function samplePoisson() and the following options to customize the sampling process:

interface PoissonOpts {
    /**
     * Point generator function. Responsible for producing a new
     * candidate point within user defined bounds using provided RNG.
     */
    points: PointGenerator;
    /**
     * Density field function. Called for each new sample point created
     * by point generator and should return the exclusion radius for
     * given point location. If this option is given as number, uses
     * this value to create a uniform distance field.
     */
    density: DensityFunction | number;
    /**
     * Spatial indexing implementation. Currently only KdTree from
     * thi.ng/geom-accel package is supported and must be
     * pre-initialized to given dimensions. Furthermore, pre-seeding the
     * tree allows already indexed points to participate in the sampling
     * process and act as exclusion zones.
     */
    accel: KdTree<ReadonlyVec, any>;
    /**
     * Max number of samples to produce.
     */
    max: number;
    /**
     * Step distance for the random walk each failed candidate point is
     * undergoing. This distance should be adjusted depending on overall
     * sampling area/bounds. Default: 1
     */
    jitter?: number;
    /**
     * Number of random walk steps performed before giving up on a
     * candidate point. Default: 5
     */
    iter?: number;
    /**
     * Number of allowed failed continuous candidate points before
     * stopping entire sampling process. Increasing this value improves
     * overall quality, especially in dense regions with small radii.
     * Default: 500
     */
    quality?: number;
    /**
     * Random number generator instance. Default thi.ng/random/SYSTEM
     * (aka Math.random)
     */
    rnd?: IRandom;
}

example output

import { samplePoisson } from "@thi.ng/poisson";

import { asSvg, svgDoc, circle } from "@thi.ng/geom";
import { KdTree } from "@thi.ng/geom-accel";
import { fit01 } from "@thi.ng/math";
import { dist2, randMinMax2 } from "@thi.ng/vectors";

accel = new KdTree(2);

pts = samplePoisson({
    accel,
    points: () => randMinMax2(null, [0, 0], [500, 500]),
    density: (p) => fit01(Math.pow(Math.max(dist2(p, [250, 250]) / 250, 0), 2), 2, 10),
    iter: 5,
    max: 8000,
    quality: 500
});

// use thi.ng/geom to visualize results
// each circle's radius is set to distance to its nearest neighbor
circles = pts.map((p) => circle(p, dist2(p, accel.selectKeys(p, 2, 40)[1]) / 2));

document.body.innerHTML = asSvg(svgDoc({ fill: "none", stroke: "red" }, ...circles));

Authors

Karsten Schmidt

License

© 2016 - 2020 Karsten Schmidt // Apache Software License 2.0