src/volume/EdgeIterator.js
import { Vector3 } from "three";
import { layout } from "sparse-octree";
import { Edge } from "./Edge";
/**
* An edge.
*
* @type {Edge}
* @private
*/
const edge = new Edge();
/**
* A vector.
*
* @type {Vector3}
* @private
*/
const offsetA = new Vector3();
/**
* A vector.
*
* @type {Vector3}
* @private
*/
const offsetB = new Vector3();
/**
* An edge iterator.
*
* @implements {Iterator}
* @implements {Iterable}
*/
export class EdgeIterator {
/**
* Constructs a new edge iterator.
*
* @param {EdgeData} edgeData - A set of edge data.
* @param {Vector3} cellPosition - The position of the data cell.
* @param {Number} cellSize - The size of the data cell.
* @param {Number} [c=0] - The dimension index to start at.
* @param {Number} [d=3] - The dimension limit.
*/
constructor(edgeData, cellPosition, cellSize, c = 0, d = 3) {
/**
* The edge data.
*
* @type {EdgeData}
* @private
*/
this.edgeData = edgeData;
/**
* The data cell position.
*
* @type {Vector3}
* @private
*/
this.cellPosition = cellPosition;
/**
* The data cell size.
*
* @type {Number}
* @private
*/
this.cellSize = cellSize;
/**
* The edges.
*
* @type {Uint32Array[]}
* @private
*/
this.indices = null;
/**
* The Zero Crossings.
*
* @type {Float32Array[]}
* @private
*/
this.zeroCrossings = null;
/**
* The intersection normals.
*
* @type {Float32Array[]}
* @private
*/
this.normals = null;
/**
* The axes of the existing edges.
*
* @type {Uint8Array[]}
* @private
*/
this.axes = null;
/**
* The amount of edges for each internal set of edges (X -> Y -> Z).
*
* @type {Number[]}
*/
this.lengths = null;
/**
* An iterator result.
*
* @type {IteratorResult}
* @private
*/
this.result = {
value: null,
done: false
};
/**
* The initial dimension index.
*
* @type {Number}
* @private
*/
this.initialC = c;
/**
* The current dimension index.
*
* @type {Number}
* @private
*/
this.c = c;
/**
* The initial dimension limit.
*
* @type {Number}
* @private
*/
this.initialD = d;
/**
* The dimension limit.
*
* @type {Number}
* @private
*/
this.d = d;
/**
* The current iteration index.
*
* @type {Number}
* @private
*/
this.i = 0;
/**
* The current iteration limit.
*
* @type {Number}
* @private
*/
this.l = 0;
this.reset();
}
/**
* Resets this iterator.
*
* @return {EdgeIterator} This iterator.
*/
reset() {
const edgeData = this.edgeData;
const indices = [];
const zeroCrossings = [];
const normals = [];
const axes = [];
const lengths = [];
let a, c, d, l;
this.i = 0;
this.c = 0;
this.d = 0;
// Create a collection of edges without empty arrays.
for(c = this.initialC, a = 4 >> c, d = this.initialD; c < d; ++c, a >>= 1) {
l = edgeData.indices[c].length;
if(l > 0) {
indices.push(edgeData.indices[c]);
zeroCrossings.push(edgeData.zeroCrossings[c]);
normals.push(edgeData.normals[c]);
axes.push(layout[a]);
lengths.push(l);
++this.d;
}
}
this.l = (lengths.length > 0) ? lengths[0] : 0;
this.indices = indices;
this.zeroCrossings = zeroCrossings;
this.normals = normals;
this.axes = axes;
this.lengths = lengths;
this.result.value = null;
this.result.done = false;
return this;
}
/**
* Iterates over the edges.
*
* @return {IteratorResult} The next edge.
*/
next() {
const s = this.cellSize;
const n = this.edgeData.resolution;
const m = n + 1;
const mm = m * m;
const result = this.result;
const base = this.cellPosition;
let axis, index;
let x, y, z;
let c, i;
// Has the end been reached?
if(this.i === this.l) {
// Move on to the next set of edges (X -> Y -> Z).
this.l = (++this.c < this.d) ? this.lengths[this.c] : 0;
this.i = 0;
}
// Are there any edges left?
if(this.i < this.l) {
c = this.c;
i = this.i;
axis = this.axes[c];
// Each edge is uniquely described by its starting grid point index.
index = this.indices[c][i];
edge.index = index;
// Calculate the local grid coordinates from the one-dimensional index.
x = index % m;
y = Math.trunc((index % mm) / m);
z = Math.trunc(index / mm);
edge.coordinates.set(x, y, z);
offsetA.set(
x * s / n,
y * s / n,
z * s / n
);
offsetB.set(
(x + axis[0]) * s / n,
(y + axis[1]) * s / n,
(z + axis[2]) * s / n
);
edge.a.addVectors(base, offsetA);
edge.b.addVectors(base, offsetB);
edge.t = this.zeroCrossings[c][i];
edge.n.fromArray(this.normals[c], i * 3);
result.value = edge;
++this.i;
} else {
// There are no more edges left.
result.value = null;
result.done = true;
}
return result;
}
/**
* Called when this iterator will no longer be run to completion.
*
* @param {Object} value - An interator result value.
* @return {IteratorResult} - A premature completion result.
*/
return(value) {
this.result.value = value;
this.result.done = true;
return this.result;
}
/**
* Returns this iterator.
*
* @return {EdteIterator} An iterator.
*/
[Symbol.iterator]() {
return this;
}
}