@woosh/meep-engine
Version:
Pure JavaScript game engine. Fully featured and production ready.
308 lines (245 loc) • 6.75 kB
JavaScript
import { assert } from "../../../../assert.js";
import { array_push_if_unique } from "../../../../collection/array/array_push_if_unique.js";
import { array_remove_first } from "../../../../collection/array/array_remove_first.js";
import { v3_distance } from "../../../vec3/v3_distance.js";
import { query_vertex_in_edge } from "../query/query_vertex_in_edge.js";
let vertex_index_counter = 0;
export class TopoVertex {
/**
* Identification number, expected to be unique within a given topology
* @type {number}
*/
index = vertex_index_counter++;
/**
*
* @type {TopoEdge[]}
*/
edges = [];
/**
*
* @type {TopoTriangle[]}
*/
faces = [];
/**
*
* @type {number}
*/
x = 0;
/**
*
* @type {number}
*/
y = 0;
/**
*
* @type {number}
*/
z = 0;
get 0() {
return this.x;
}
get 1() {
return this.y;
}
get 2() {
return this.z;
}
/**
* Estimate of this object's size in RAM, in bytes
* @return {number}
*/
get byteSize() {
return 80 + 6 * 4 + 8 + this.edges.length * 8 + 10 + this.faces.length * 8 + 10;
}
/**
*
* @param {TopoVertex} other
*/
copy(other) {
this.x = other.x;
this.y = other.y;
this.z = other.z;
this.index = other.index;
this.faces = other.faces.slice();
this.edges = other.edges.slice();
}
/**
* @returns {TopoVertex}
*/
clone() {
const r = new TopoVertex();
r.copy(this);
return r;
}
/**
*
* @param {function(reason:string)} error_consumer
* @return {boolean}
*/
validate(error_consumer) {
let valid = true;
const faces = this.faces;
const face_count = faces.length;
for (let i = 0; i < face_count; i++) {
const face = faces[i];
if (!face.containsVertex(this)) {
error_consumer(`Missing back-link from face[${i}]`);
valid = false;
}
}
const edges = this.edges;
const edge_count = edges.length;
for (let i = 0; i < edge_count; i++) {
const edge = edges[i];
if (!query_vertex_in_edge(edge, this)) {
error_consumer(`Missing back-link from edge[${i}]`);
valid = false;
}
}
return valid;
}
/**
*
* @param {TopoVertex} other
* @return {number}
*/
distanceTo(other) {
return v3_distance(
this.x,
this.y,
this.z,
other.x,
other.y,
other.z
);
}
/**
*
* @param {TopoTriangle} f
*/
addFace(f) {
assert.equal(f.isTopoFace, true, "f.isTopoFace !== true");
assert.arrayHasNo(this.faces, f, 'already contains face');
this.faces.push(f);
}
/**
*
* @param {TopoTriangle} e
* @return {boolean}
*/
addUniqueFace(e) {
assert.equal(e.isTopoFace, true, "e.isTopoFace !== true");
return array_push_if_unique(this.faces, e);
}
/**
*
* @param {TopoTriangle} face
* @return {boolean}
*/
containsFace(face) {
assert.equal(face.isTopoFace, true, "face.isTopoFace !== true");
return this.faces.indexOf(face) !== -1;
}
/**
*
* @param {TopoTriangle} f
*/
removeFace(f) {
assert.equal(f.isTopoFace, true, "f.isTopoFace !== true");
array_remove_first(this.faces, f);
assert.arrayHasNo(this.faces, f, 'found an instance of removed face');
}
/**
*
* @param {TopoEdge} e
*/
addEdge(e) {
assert.defined(e, 'e');
assert.equal(e.isTopoEdge, true, "e.isTopoEdge !== true");
assert.arrayHasNo(this.edges, e, 'already contains edge');
this.edges.push(e);
}
/**
*
* @param {TopoEdge} e
* @return {boolean}
*/
addUniqueEdge(e) {
assert.defined(e, 'e');
assert.equal(e.isTopoEdge, true, "e.isTopoEdge !== true");
return array_push_if_unique(this.edges, e);
}
/**
*
* @param {TopoEdge} victim
* @param {TopoEdge} replacement
*/
replaceEdge(victim, replacement) {
assert.equal(victim.isTopoEdge, true, "victim.isTopoEdge !== true");
assert.equal(replacement.isTopoEdge, true, "replacement.isTopoEdge !== true");
const edges = this.edges;
const victim_index = edges.indexOf(victim);
assert.greaterThanOrEqual(victim_index, 0, 'victim not found');
assert.arrayHasNo(edges, replacement, 'edges already contain replacement');
edges[victim_index] = replacement;
}
/**
*
* @param {TopoEdge} edge
* @returns {boolean}
*/
containsEdge(edge) {
assert.equal(edge.isTopoEdge, true, "edge.isTopoEdge !== true");
return this.edges.indexOf(edge) !== -1;
}
/**
*
* @param {TopoEdge} e
* @returns {boolean}
*/
removeEdge(e) {
assert.equal(e.isTopoEdge, true, "e.isTopoEdge !== true");
const r = array_remove_first(this.edges, e);
assert.arrayHasNo(this.edges, e, 'found an instance of removed edge');
assert.arrayHasNo(this.edges, undefined, 'found an instance of undefined');
return r;
}
/**
*
* @param {TopoVertex[]} result
* @param {number} result_offset
* @returns {number}
*/
computeNeighbourVertices(result, result_offset) {
let additions = 0;
const edges = this.edges;
const edge_count = edges.length;
for (let i = 0; i < edge_count; i++) {
const edge = edges[i];
const neighbour = edge.getOtherVertex(this);
// TODO dedupe
result[result_offset + additions] = neighbour;
additions++;
}
return additions;
}
/**
*
* @param {number} x
* @param {number} y
* @param {number} z
* @return {TopoVertex}
*/
static from(x, y, z) {
const r = new TopoVertex();
r.x = x;
r.y = y;
r.z = z;
return r;
}
}
/**
* @readonly
* @type {boolean}
*/
TopoVertex.prototype.isTopoVertex = true;