UNPKG

@woosh/meep-engine

Version:

Pure JavaScript game engine. Fully featured and production ready.

148 lines (120 loc) 4.08 kB
import { query_vertex_is_boundary } from "../query/query_vertex_is_boundary.js"; import { collapseEdge, partialEdgeCollapse } from "./collapseEdge.js"; import { computeEdgeCollapseCost } from "./computeEdgeCollapseCost.js"; export class EdgeCollapseCandidate { constructor() { /** * * @type {TopoEdge|null} */ this.edge = null; /** * * @type {TopoVertex|null} */ this.victim_vertex = null; /** * * @type {TopoVertex|null} */ this.target_vertex = null; /** * * @type {number} */ this.cost = 0; /** * Debug value, used to track how many times the edge was updated * @type {number} */ this.version = 0; /** * Collapsed victim point belonged to the border * @type {boolean} * @private */ this.__border_collapse = false; } /** * * @returns {boolean} */ isBorderCollapse() { return this.__border_collapse; } validate() { if (!this.edge.containsBothVertices(this.victim_vertex, this.target_vertex)) { return false; } return true; } /** * * @param {TopoMesh} mesh * @param {Map<number, Quadratic3>} vertex_quadratics */ collapse(mesh, vertex_quadratics) { // if (!this.validate()) { // throw new Error("Invalid state"); // } const v_from = this.victim_vertex; const v_to = this.target_vertex; if (v_from === v_to) { // degenerate partialEdgeCollapse(mesh, this.edge, v_from, v_to); } else { if (query_vertex_is_boundary(v_from)) { this.__border_collapse = true; } collapseEdge(mesh, this.edge, v_from, v_to); // accumulate error from removed vertex to the remaining one const q_from = vertex_quadratics.get(v_from.index); const q_to = vertex_quadratics.get(v_to.index); q_to.add(q_from); } } /** * Compute cost of collapse as well as which vertex should be the victim * @param {Map<number, Quadratic3>} vertex_quadratics * @param {Set<number>} restricted_vertices * @returns {boolean} */ update(vertex_quadratics, restricted_vertices) { this.version++; const edge = this.edge; const v0 = edge.v0; const v1 = edge.v1; const v0_restricted = restricted_vertices.has(v0.index); const v1_restricted = restricted_vertices.has(v1.index); if (v0_restricted) { if (v1_restricted) { return false; } else { this.victim_vertex = v1; this.target_vertex = v0; this.cost = computeEdgeCollapseCost(v1, v0, edge, vertex_quadratics); } } else { if (v1_restricted) { this.victim_vertex = v0; this.target_vertex = v1; this.cost = computeEdgeCollapseCost(v0, v1, edge, vertex_quadratics); } else { // unrestricted const cost_forward = computeEdgeCollapseCost(v0, v1, edge, vertex_quadratics); const cost_backward = computeEdgeCollapseCost(v1, v0, edge, vertex_quadratics); // pick minimum cost collapse if (cost_forward > cost_backward) { this.victim_vertex = v1; this.target_vertex = v0; this.cost = cost_backward; } else { this.victim_vertex = v0; this.target_vertex = v1; this.cost = cost_forward; } } } return true; } }