@jgphilpott/polytree
Version: 
A modern, high-performance spatial querying library designed specifically for three.js and Node.
469 lines (323 loc) • 15.4 kB
Markdown
<p align="center">
    <img width="321" height="321" src="https://raw.githubusercontent.com/jgphilpott/polytree/polytree/icon.png" alt="Polytree Icon">
</p>
<p align="center">
  <a href="https://github.com/jgphilpott/polytree/actions"><img src="https://github.com/jgphilpott/polytree/actions/workflows/nodejs.yml/badge.svg" alt="Polytree Tests"></a>
  <a href="https://badge.fury.io/js/@jgphilpott%2Fpolytree"><img src="https://badge.fury.io/js/@jgphilpott%2Fpolytree.svg" alt="npm version"></a>
  <a href="https://opensource.org/licenses/MIT"><img src="https://img.shields.io/badge/License-MIT-green.svg" alt="License: MIT"></a>
</p>
# Polytree
<details open>
<summary><h2 style="display:inline">Intro</h2></summary>
**Polytree** is a modern, high-performance spatial querying and Constructive Solid Geometry (CSG) library for JavaScript and Node.js Built on an efficient [Octree data structure](https://en.wikipedia.org/wiki/Octree), it is designed for advanced 3D modeling, mesh analysis, geometric search, and seamless integration with [three.js](https://github.com/mrdoob/three.js).
Polytree goes beyond traditional CSG libraries by providing a comprehensive suite of spatial query functions—such as closest point, distance field, intersection testing, layer slicing, and volume analysis—making it ideal for 3D printing, CAD, simulation, and mesh analysis applications.
**▶️ [View the Polytree Demo Site with GitHub Pages](https://jgphilpott.github.io/polytree)**
**📦 [View the Polytree npm Package](https://www.npmjs.com/package/@jgphilpott/polytree)**
### Features
- **Advanced Spatial Queries**: Closest point search, distance calculations, intersection testing, layer slicing, and volume analysis—optimized for mesh analysis, 3D printing, and simulation workflows.
- **Complete CSG Operations**: Union, subtraction, and intersection with full test coverage.
- **3D Printing & CAD Support**: Layer slicing, cross-section analysis, and spatial operations for manufacturing and design applications.
- **High Performance**: Octree-based spatial partitioning for fast queries and operations on large meshes.
- **Dual API**: Both synchronous and asynchronous operation modes for flexible integration.
- **Multi-Input Support**: Works directly with Three.js meshes, BufferGeometry, and Polytree instances.
- **Lightweight**: Minimal dependencies with efficient memory usage.
- **Three.js Integration**: Direct mesh-to-mesh operations and spatial queries with material preservation.
- **Well Documented**: Comprehensive API documentation and interactive examples.
- **Robust Testing**: 500+ tests ensuring reliability across edge cases.
</details>
<details open>
<summary><h2 style="display:inline">Table of Contents</h2></summary>
- [Intro](#intro)
- [Getting Started](#getting-started)
- [Usage](#usage)
    - [Utility Functions](#utility-functions)
    - [Basic CSG Operations](#basic-csg-operations)
    - [Async CSG Operations](#async-csg-operations)
    - [Async Array Operations](#async-array-operations)
    - [Spatial Query Functions](#spatial-query-functions)
    - [Advanced Polytree-to-Polytree Operations](#advanced-polytree-to-polytree-operations)
- [Performance](#performance)
- [Applications](#applications)
- [Contributing](#contributing)
</details>
<details open>
<summary><h2 style="display:inline">Getting Started</h2></summary>
### Node.js
#### Install
```bash
npm install polytree
```
#### Import
```js
import * as THREE from 'three';
import { Polytree } from 'polytree';
```
### Browser
For browser usage, use the ES module-compatible bundle:
```html
<script type="importmap">
{
    "imports": {
        "three": "./path/to/three.module.min.js",
        "polytree": "./path/to/polytree.bundle.browser.js"
    }
}
</script>
<script type="module">
import * as THREE from 'three';
import Polytree from 'polytree';
</script>
```
The browser bundle (`polytree.bundle.browser.js`) is specifically designed for ES module imports in browsers, while the main bundle (`polytree.bundle.js`) is for Node.js environments.
</details>
<details open>
<summary><h2 style="display:inline">Usage</h2></summary>
<details open>
<summary><h3 style="display:inline">Utility Functions</h3></summary>
Polytree provides utility functions for geometry analysis and calculations:
#### Surface Area Calculation
Calculate the surface area of Three.js meshes or geometries:
```js
// Calculate surface area from a mesh:
const boxGeometry = new THREE.BoxGeometry(2, 3, 4);
const boxMesh = new THREE.Mesh(boxGeometry, new THREE.MeshBasicMaterial());
const surfaceArea = Polytree.getSurface(boxMesh);
console.log(`Surface area: ${surfaceArea}`); // Output: 52
// Calculate surface area directly from geometry:
const sphereGeometry = new THREE.SphereGeometry(1);
const sphereSurfaceArea = Polytree.getSurface(sphereGeometry);
console.log(`Sphere surface area: ${sphereSurfaceArea}`); // Output: ~12.47
```
The `getSurface()` method:
- Accepts either Three.js `Mesh` objects or `BufferGeometry` objects.
- Returns the total surface area as a number.
- Works by summing the areas of all triangular faces.
- Handles both indexed and non-indexed geometries.
#### Volume Calculation
Calculate the volume of Three.js meshes or geometries:
```js
// Calculate volume from a mesh:
const boxGeometry = new THREE.BoxGeometry(2, 2, 2);
const boxMesh = new THREE.Mesh(boxGeometry, new THREE.MeshBasicMaterial());
const volume = Polytree.getVolume(boxMesh);
console.log(`Volume: ${volume}`); // Output: 8
// Calculate volume directly from geometry:
const sphereGeometry = new THREE.SphereGeometry(1);
const sphereVolume = Polytree.getVolume(sphereGeometry);
console.log(`Sphere volume: ${sphereVolume}`); // Output: ~4.19 (approx 4/3 * π)
```
The `getVolume()` method:
- Accepts either Three.js `Mesh` objects or `BufferGeometry` objects.
- Returns the total volume as a number.
- Uses the divergence theorem with signed tetrahedron volumes.
- Handles both indexed and non-indexed geometries.
- Automatically handles edge cases like empty geometries.
</details>
<details open>
<summary><h3 style="display:inline">Basic CSG Operations</h3></summary>
Polytree provides three core CSG operations that work directly with Three.js meshes:
#### Unite (Join)
Join two 3D objects into a single merged object:
```js
// Create two identical boxes.
const geometry1 = new THREE.BoxGeometry(2, 2, 2);
const geometry2 = new THREE.BoxGeometry(2, 2, 2);
const mesh1 = new THREE.Mesh(geometry1, new THREE.MeshBasicMaterial());
const mesh2 = new THREE.Mesh(geometry2, new THREE.MeshBasicMaterial());
// Offset the position of one box.
mesh1.position.set(1, 1, 1);
// Join the boxes together.
const result = await Polytree.unite(mesh1, mesh2);
scene.add(result);
```
#### Subtract (Remove)
Remove one object's volume from another:
```js
// Create a box and a sphere.
const boxGeometry = new THREE.BoxGeometry(2, 2, 2);
const sphereGeometry = new THREE.SphereGeometry(1.5);
const boxMesh = new THREE.Mesh(boxGeometry, new THREE.MeshBasicMaterial());
const sphereMesh = new THREE.Mesh(sphereGeometry, new THREE.MeshBasicMaterial());
// Remove the sphere from the box (creates a cavity).
const result = await Polytree.subtract(boxMesh, sphereMesh);
scene.add(result);
```
#### Intersect (Overlap)
Keep only the overlapping volume of two objects:
```js
// Create two overlapping spheres.
const sphere1 = new THREE.Mesh(
    new THREE.SphereGeometry(1),
    new THREE.MeshBasicMaterial()
);
const sphere2 = new THREE.Mesh(
    new THREE.SphereGeometry(1),
    new THREE.MeshBasicMaterial()
);
// Offset the position of one sphere.
sphere1.position.set(1, 0, 0);
// Keep only the overlapping volume.
const result = await Polytree.intersect(sphere1, sphere2);
scene.add(result);
```
</details>
<details>
<summary><h3 style="display:inline">Async CSG Operations</h3></summary>
For better performance in web applications, use async operations to prevent UI blocking:
```js
// Async union with Promise.
const unionPromise = Polytree.unite(mesh1, mesh2);
unionPromise.then(result => {
    scene.add(result);
});
// Async with await.
const unionResult = await Polytree.unite(mesh1, mesh2);
scene.add(unionResult);
```
</details>
<details>
<summary><h3 style="display:inline">Async Array Operations</h3></summary>
Process multiple objects efficiently:
```js
// Unite multiple objects asynchronously.
const meshArray = [mesh1, mesh2, mesh3, mesh4 ... meshX];
const polytreeArray = meshArray.map(mesh => Polytree.fromMesh(mesh));
Polytree.async.uniteArray(polytreeArray).then(result => {
    const finalMesh = Polytree.toMesh(result);
    scene.add(finalMesh);
    // Clean up.
    polytreeArray.forEach(polytree => {
        polytree.delete()
    });
    result.delete();
});
```
</details>
<details open>
<summary><h3 style="display:inline">Spatial Query Functions</h3></summary>
Polytree now includes advanced spatial query capabilities inspired by the `three-mesh-bvh` library, transforming it from a pure CSG library into a comprehensive spatial querying tool optimized for 3D printing applications.
#### Point-based Queries
Find the closest points and calculate distances for collision detection and mesh analysis:
```js
const geometry = new THREE.BoxGeometry(2, 2, 2);
const mesh = new THREE.Mesh(geometry, material);
const testPoint = new THREE.Vector3(5, 0, 0);
// Find closest point on surface - works with Mesh, BufferGeometry, or Polytree.
const closestPoint = Polytree.closestPointToPoint(mesh, testPoint);
console.log(`Closest point: (${closestPoint.x}, ${closestPoint.y}, ${closestPoint.z})`);
// Calculate distance to surface.
const distance = Polytree.distanceToPoint(mesh, testPoint);
console.log(`Distance: ${distance} units`);
```
#### Volume Analysis
Perform both exact and statistical volume calculations:
```js
// Exact volume calculation.
const exactVolume = Polytree.getVolume(mesh);
// Monte Carlo volume estimation for complex geometries.
const estimatedVolume = Polytree.estimateVolumeViaSampling(mesh, 50000);
console.log(`Exact: ${exactVolume}, Estimated: ${estimatedVolume}`);
```
#### Intersection Testing
Test intersections with bounding volumes for collision detection:
```js
// Test sphere intersection.
const sphere = new THREE.Sphere(new THREE.Vector3(0, 0, 0), 2);
const intersectsSphere = Polytree.intersectsSphere(mesh, sphere);
// Test bounding box intersection.
const box = new THREE.Box3(min, max);
const intersectsBox = Polytree.intersectsBox(mesh, box);
```
#### 3D Printing Layer Slicing
Generate layer slices for 3D printing applications:
```js
// Slice geometry into horizontal layers.
const layers = Polytree.sliceIntoLayers(
    mesh,                      // Input geometry
    0.2,                       // Layer height (0.2mm)
    -10,                       // Minimum Z
    10,                        // Maximum Z
    new THREE.Vector3(0, 0, 1) // Optional normal (default: Z-up)
);
console.log(`Generated ${layers.length} layers for 3D printing`);
// Single plane intersection for cross-section analysis.
const plane = new THREE.Plane(new THREE.Vector3(0, 0, 1), 0);
const crossSection = Polytree.intersectPlane(mesh, plane);
```
#### Advanced Spatial Operations
Custom spatial queries and triangle-based operations:
```js
// Get triangles near a specific point.
const nearbyTriangles = Polytree.getTrianglesNearPoint(mesh, point, 2.0);
// Custom spatial query with callback.
const results = Polytree.shapecast(mesh, (triangle) => {
    // Custom query logic - return true to collect triangle.
    return triangle.normal.y > 0.8; // Find upward-facing triangles.
}, (triangle) => {
    // Optional collection callback for processing results.
    return { triangle, area: triangle.getArea() };
});
```
#### Multi-Input Support
All spatial query functions accept Three.js meshes, BufferGeometry, or Polytree instances:
```js
const geometry = new THREE.BoxGeometry(2, 2, 2);
const mesh = new THREE.Mesh(geometry, material);
const polytree = Polytree.fromMesh(mesh);
// All of these work identically.
const result1 = Polytree.closestPointToPoint(mesh, testPoint);     // Mesh
const result2 = Polytree.closestPointToPoint(geometry, testPoint); // BufferGeometry
const result3 = Polytree.closestPointToPoint(polytree, testPoint); // Polytree
```
</details>
<details>
<summary><h3 style="display:inline">Advanced Polytree-to-Polytree Operations</h3></summary>
For maximum performance when chaining operations, work directly with Polytree objects:
```js
// Convert meshes to polytrees once.
const polytree1 = Polytree.fromMesh(mesh1);
const polytree2 = Polytree.fromMesh(mesh2);
const polytree3 = Polytree.fromMesh(mesh3);
// Chain operations efficiently.
const intermediate = await Polytree.unite(polytree1, polytree2);
const final = await Polytree.subtract(intermediate, polytree3);
// Convert back to mesh for rendering.
const finalMesh = Polytree.toMesh(final);
scene.add(finalMesh);
// Clean up resources.
polytree1.delete();
polytree2.delete();
polytree3.delete();
intermediate.delete();
final.delete();
```
</details>
</details>
<details open>
<summary><h2 style="display:inline">Performance</h2></summary>
Polytree is designed for high-performance CSG operations:
- **Octree Optimization**: Spatial partitioning reduces computational complexity for both CSG and spatial query operations.
- **Memory Efficient**: Smart resource management with cleanup methods and automatic temporary object disposal.
- **Unified Architecture**: CSG operations + spatial queries in one optimized library, eliminating the need for multiple tools.
- **Multi-Input Support**: Functions work directly with Three.js meshes, geometries, and Polytree instances without manual conversion.
- **Comprehensive Testing**: 500+ test cases ensuring reliability and performance across all operations.
- **Async Support**: Non-blocking operations for smooth user experiences.
- **Minimal Dependencies**: Only Three.js as a dependency for lightweight integration.
</details>
<details open>
<summary><h2 style="display:inline">Applications</h2></summary>
- **3D Modeling**: Professional-grade boolean operations for CAD applications.
- **Game Development**: Runtime mesh manipulation and procedural geometry.
- **3D Printing & Manufacturing**: Complete slicing pipeline with layer generation, support analysis, and volume calculations.
- **Collision Detection**: Fast spatial queries for physics engines and interactive applications.
- **Mesh Analysis & Repair**: Distance field calculations, closest point queries, and geometric validation.
- **Architectural Visualization**: Complex building geometry operations with spatial analysis.
- **Educational Tools**: Interactive 3D geometry learning applications with real-time feedback.
- **Integration with [Polyslice](https://github.com/jgphilpott/polyslice)**: Advanced FDM slicing workflows and manufacturing optimization.
</details>
<details open>
<summary><h2 style="display:inline">Contributing</h2></summary>
Contributions, issues, and feature requests are welcome! Please [open an issue](https://github.com/jgphilpott/polytree/issues) or submit a [pull request](https://github.com/jgphilpott/polytree/pulls).
</details>
---
**Polytree** is developed and maintained by [](https://github.com/jgphilpott).