One-ring neighborhood
Interactive example using Three.js and three-mesh-halfedge.
by mvgician
HTML
<script type="importmap">
{
"imports": {
"three": "https://cdn.jsdelivr.net/npm/[email protected]/build/three.module.js",
"three/addons/": "https://cdn.jsdelivr.net/npm/[email protected]/examples/jsm/",
"three-mesh-halfedge": "https://cdn.jsdelivr.net/npm/[email protected]/build/index.esm.js"
}
}
</script>
<div id="wrapper">
<button type="button" id="button">
<span class="primary">halfedge</span> = <span class="primary">halfedge</span>.<span class="secondary">twin</span>.<span class="tertiary">next</span>
</button>
</div>
CSS
body {
padding: 0;
margin: 0;
}
#wrapper {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
margin: auto;
overflow: hidden;
}
.primary{
color: #ddc000;
}
.secondary{
color: #f78e20;
}
.tertiary{
color: #e21;
}
JavaScript
import * as THREE from 'three'
import { HalfedgeDS, Vertex } from 'three-mesh-halfedge'
// renderer
const width = window.innerWidth
const height = window.innerHeight - 30 // hardcoded button height
const renderer = new THREE.WebGLRenderer({ antialias: true })
renderer.setPixelRatio(2) // smoother (and thinner) lines
renderer.setSize(width, height)
document.getElementById('wrapper').prepend(renderer.domElement)
// camera
const aspect = (width / height)
const frustum = 1.25
const camera = new THREE.OrthographicCamera(-frustum * 0.5 * aspect, frustum * 0.5 * aspect, 0.5 * frustum, -frustum * 0.5, 0.5, 20)
camera.position.z = 5
// scene
const scene = new THREE.Scene()
scene.background = new THREE.Color(0xffffff)
// utils
const dir = new THREE.Vector3()
const triangle = new THREE.Triangle()
const sphere = new THREE.SphereGeometry(0.025)
const primaryColor = 0xFFFE000
const secondaryColor = 0xF78E20
const tertiaryColor = 0xee2211
const defaultColor = 0x333333
const backgroundColor = 0x111111
// simple hexagonal mesh
const geometry = new THREE.CircleGeometry(0.5, 6)
const mesh = new THREE.Mesh(geometry, new THREE.MeshNormalMaterial())
const wireframe = new THREE.Mesh(geometry, new THREE.MeshBasicMaterial({ color: backgroundColor, wireframe: true }))
scene.add(mesh, wireframe)
// half-edge data structure
const struct = new HalfedgeDS()
struct.setFromGeometry(geometry)
// one-ring neighbor generator function
Vertex.prototype.getNeighbors = function * () {
const start = this.halfedge
let halfedge = start
do {
yield halfedge.twin.vertex
halfedge = halfedge.twin.next
} while (start !== halfedge)
return null
}
// creates a sphere centered in the position of "vertex"
function createSphere (vertex) {
const mesh = new THREE.Mesh(sphere, new THREE.MeshBasicMaterial({ color: backgroundColor }))
mesh.position.copy(vertex.position)
vertex.highlight = function (color) { mesh.material.color.setHex(color) }
scene.add(mesh)
}
// create a sphere for...