UNPKG

@woosh/meep-engine

Version:

Pure JavaScript game engine. Fully featured and production ready.

308 lines (245 loc) • 6.75 kB
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;