Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit bf2dbb4
Showing
13 changed files
with
6,663 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
bower_components | ||
node_modules | ||
*.log | ||
.DS_Store | ||
bundle.js |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
bower_components | ||
node_modules | ||
*.log | ||
.DS_Store | ||
.npmignore | ||
LICENSE.md |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
The MIT License (MIT) | ||
Copyright (c) 2017 Matt DesLauriers | ||
|
||
Permission is hereby granted, free of charge, to any person obtaining a copy | ||
of this software and associated documentation files (the "Software"), to deal | ||
in the Software without restriction, including without limitation the rights | ||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
copies of the Software, and to permit persons to whom the Software is | ||
furnished to do so, subject to the following conditions: | ||
|
||
The above copyright notice and this permission notice shall be included in all | ||
copies or substantial portions of the Software. | ||
|
||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | ||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | ||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. | ||
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, | ||
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR | ||
OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE | ||
OR OTHER DEALINGS IN THE SOFTWARE. | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,107 @@ | ||
# pack-spheres | ||
|
||
Brute force circle/sphere packing in 2D or 3D. | ||
|
||
<img src="demos/2d.png" width="25%" /> | ||
<img src="demos/2d-circle.png" width="25%" /> | ||
<img src="demos/3d.png" width="25%" /> | ||
|
||
See [./demos](./demos) for examples. | ||
|
||
```js | ||
const pack = require('pack-spheres'); | ||
|
||
const circles = pack({ | ||
dimensions: 2, | ||
packAttempts: 500, | ||
maxCount: 1000, | ||
minRadius: 0.05, | ||
maxRadius: 0.5, | ||
padding: 0.0025 | ||
}); | ||
|
||
console.log('Got %d circles', circles.length); | ||
console.log(circles[0].position, circles[0].radius); | ||
``` | ||
|
||
Returns an array of objects with normalized values between `-1.0` and `1.0`, but the algorithm works on arbitrary units (for example, you could use pixels instead). | ||
|
||
```js | ||
[ | ||
{ | ||
position: [ x, y, z ], | ||
radius: Number | ||
}, | ||
... | ||
] | ||
``` | ||
|
||
If you specify `{ dimensions: 2 }`, the `position` will only contain `[ x, y ]`. | ||
|
||
## Install | ||
|
||
Use [npm](https://npmjs.com/) to install. | ||
|
||
```sh | ||
npm install pack-spheres --save | ||
``` | ||
|
||
## Usage | ||
|
||
#### `spheres = pack([opt])` | ||
|
||
Packs 3D spheres (default) or 2D circles with the given options: | ||
|
||
- `dimensions` — Can either be 3 (default) for spheres, or 2 for circles | ||
- `bounds` — The normalized bounding box from `-1.0` to `1.0` that spheres are randomly generated within and clip to, default 1.0 | ||
- `packAttempts` — Number of attempts per sphere to pack within the space, default 500 | ||
- `maxCount` — The max number of total spheres that will be packed, default 1000 (note: you may not always reach the maxCount if all spheres could not be packed) | ||
- `minRadius` — A number or [generator function](#generator-functions) that specifies the min (starting) radius for placed spheres (default 0.01) | ||
- `maxRadius` — A number or [generator function](#generator-functions) that specifies the max radius a sphere will grow to (default 0.5) | ||
- `maxGrowthSteps` — A number or[ generator function](#generator-functions) that specifies the max number of steps a sphere will grow before stopping (default Infinity) | ||
- `padding` — A number or [generator function](#generator-functions) that specifies the padding around this sphere (default 0) | ||
|
||
## Override Functions | ||
|
||
You can pass in override functions to change the behaviour: | ||
|
||
- `random` — A function that returns a 0..1 random value used by the default `sample` function, defaults to `Math.random()` | ||
- `sample` — A function that returns a 2D or 3D vector for where a new sphere should be placed | ||
- `outside` — A function that takes in a sphere's `(position, radius, padding)` and returns `true` if the sphere is considered to be "outside" of your virtual bounding region. Defaults to a bounding cube/box | ||
|
||
```js | ||
// Some utility for randomness | ||
const Random = require('canvas-sketch-util/random'); | ||
|
||
// Generate circles in a 2D unit circle | ||
const bounds = 1; | ||
const shapes = pack({ | ||
bounds, | ||
// Generate a random point inside a 2D circle | ||
sample: () => Random.insideCircle(bounds), | ||
// See if mag(pos - center) >= bounds | ||
outside: (position, radius) => { | ||
const length = Math.sqrt( | ||
position[0] * position[0] + position[1] * position[1] | ||
); | ||
return length + radius >= bounds; | ||
} | ||
}); | ||
``` | ||
|
||
## Generator Functions | ||
|
||
Instead of having all spheres start with, say, a fixed `minRadius`, you can pass a function that will get used for each new sphere being placed: | ||
|
||
```js | ||
// Some utility for randomness | ||
const Random = require('canvas-sketch-util/random'); | ||
|
||
const spheres = pack({ | ||
minRadius: () => Random.range(0, 0.5) | ||
}); | ||
``` | ||
|
||
## License | ||
|
||
MIT, see [LICENSE.md](http://github.com/mattdesl/pack-spheres/blob/master/LICENSE.md) for details. |
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
const canvasSketch = require("canvas-sketch"); | ||
const Random = require("canvas-sketch-util/random"); | ||
const pack = require(".."); | ||
|
||
const settings = { | ||
dimensions: [1024, 1024] | ||
}; | ||
|
||
const sketch = ({ width, height }) => { | ||
const size = Math.min(width, height); | ||
const margin = width * 0.1; | ||
const scale = 0.5 * size - margin; | ||
|
||
const bounds = 1; | ||
const shapes = pack({ | ||
bounds, | ||
sample: () => Random.insideCircle(bounds), | ||
outside: (position, radius) => { | ||
// See if length of circle + radius | ||
// exceeds the bounds | ||
const length = Math.sqrt( | ||
position[0] * position[0] + position[1] * position[1] | ||
); | ||
return length + radius >= bounds; | ||
}, | ||
maxCount: 2500, | ||
dimensions: 2, | ||
minRadius: 0.015, | ||
maxRadius: 0.25, | ||
padding: 0.0025 | ||
}); | ||
|
||
return ({ context, width, height }) => { | ||
// Clear background | ||
context.fillStyle = "white"; | ||
context.fillRect(0, 0, width, height); | ||
|
||
// Centered origin point | ||
context.translate(width / 2, height / 2); | ||
// Scale from -1..1 to -scale..scale | ||
context.scale(scale, scale); | ||
|
||
shapes.forEach(shape => { | ||
context.beginPath(); | ||
context.arc( | ||
shape.position[0], | ||
shape.position[1], | ||
shape.radius, | ||
0, | ||
Math.PI * 2 | ||
); | ||
context.fillStyle = "black"; | ||
context.fill(); | ||
}); | ||
}; | ||
}; | ||
|
||
canvasSketch(sketch, settings); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
const canvasSketch = require("canvas-sketch"); | ||
const pack = require(".."); | ||
|
||
const settings = { | ||
dimensions: [1024, 1024] | ||
}; | ||
|
||
const sketch = ({ width, height }) => { | ||
const size = Math.min(width, height); | ||
const margin = width * 0.1; | ||
const scale = 0.5 * size - margin; | ||
|
||
const shapes = pack({ | ||
dimensions: 2, | ||
padding: 0.0025 | ||
}); | ||
|
||
return ({ context, width, height }) => { | ||
// Clear background | ||
context.fillStyle = "white"; | ||
context.fillRect(0, 0, width, height); | ||
|
||
// Centered origin point | ||
context.translate(width / 2, height / 2); | ||
// Scale from -1..1 to -scale..scale | ||
context.scale(scale, scale); | ||
|
||
shapes.forEach(shape => { | ||
context.beginPath(); | ||
context.arc( | ||
shape.position[0], | ||
shape.position[1], | ||
shape.radius, | ||
0, | ||
Math.PI * 2 | ||
); | ||
context.fillStyle = "black"; | ||
context.fill(); | ||
}); | ||
}; | ||
}; | ||
|
||
canvasSketch(sketch, settings); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,87 @@ | ||
// Ensure ThreeJS is in global scope for the 'examples/' | ||
global.THREE = require("three"); | ||
|
||
// Include any additional ThreeJS examples below | ||
require("three/examples/js/controls/OrbitControls"); | ||
|
||
const pack = require(".."); | ||
const canvasSketch = require("canvas-sketch"); | ||
|
||
const settings = { | ||
dimensions: [512, 512], | ||
// Make the loop animated | ||
animate: true, | ||
// Get a WebGL canvas rather than 2D | ||
context: "webgl" | ||
}; | ||
|
||
const sketch = ({ context }) => { | ||
// Create a renderer | ||
const renderer = new THREE.WebGLRenderer({ | ||
canvas: context.canvas | ||
}); | ||
|
||
// WebGL background color | ||
renderer.setClearColor("#000", 1); | ||
|
||
// Setup a camera | ||
const camera = new THREE.PerspectiveCamera(50, 1, 0.01, 100); | ||
camera.position.set(2, 2, -4); | ||
camera.lookAt(new THREE.Vector3()); | ||
|
||
// Setup camera controller | ||
const controls = new THREE.OrbitControls(camera, context.canvas); | ||
|
||
// Setup your scene | ||
const scene = new THREE.Scene(); | ||
|
||
// Setup a geometry | ||
const geometry = new THREE.SphereGeometry(1, 32, 16); | ||
|
||
// Setup a material | ||
const material = new THREE.MeshNormalMaterial(); | ||
|
||
// Generate spheres with default params (3D) | ||
const spheres = pack(); | ||
|
||
// Setup meshes with geometry + material | ||
const meshes = spheres.map(sphere => { | ||
const mesh = new THREE.Mesh(geometry, material); | ||
mesh.position.fromArray(sphere.position); | ||
mesh.scale.setScalar(sphere.radius); | ||
return mesh; | ||
}); | ||
|
||
// Add to scene | ||
meshes.forEach(m => scene.add(m)); | ||
|
||
// visualize bounding cube | ||
scene.add( | ||
new THREE.Box3Helper( | ||
new THREE.Box3(new THREE.Vector3(-1, -1, -1), new THREE.Vector3(1, 1, 1)) | ||
) | ||
); | ||
|
||
// draw each frame | ||
return { | ||
// Handle resize events here | ||
resize({ pixelRatio, viewportWidth, viewportHeight }) { | ||
renderer.setPixelRatio(pixelRatio); | ||
renderer.setSize(viewportWidth, viewportHeight, false); | ||
camera.aspect = viewportWidth / viewportHeight; | ||
camera.updateProjectionMatrix(); | ||
}, | ||
// Update & render your scene here | ||
render({ time }) { | ||
controls.update(); | ||
renderer.render(scene, camera); | ||
}, | ||
// Dispose of events & renderer for cleaner hot-reloading | ||
unload() { | ||
controls.dispose(); | ||
renderer.dispose(); | ||
} | ||
}; | ||
}; | ||
|
||
canvasSketch(sketch, settings); |
Oops, something went wrong.