UNPKG

@woosh/meep-engine

Version:

Pure JavaScript game engine. Fully featured and production ready.

150 lines (113 loc) 3.95 kB
import { assert } from "../../../../../core/assert.js"; import { max2 } from "../../../../../core/math/max2.js"; import { min2 } from "../../../../../core/math/min2.js"; /** * algorithm proposed by Borgefors, Chamfer distance [J. ACM 15 (1968) 600, Comput. Vis. Graph. Image Process. 34 (1986) 344], h * @param {Sampler2D} source * @param {Sampler2D} distanceField * @param {number} emptyValue * @param {number} d1 distance between two adjacent pixels in either x or y direction * @param {number} d2 distance between two diagonally adjacent pixels * @param {number} maxD highest value that distance field can hold */ export function computeUnsignedDistanceField_Chamfer( source, distanceField, emptyValue, d1, d2, maxD ) { assert.defined(source, 'source'); assert.defined(distanceField, 'distanceField'); assert.isNumber(emptyValue, 'emptyValue'); assert.isNumber(d1, 'd1'); assert.isNumber(d2, 'd2'); assert.isNumber(maxD, 'maxD'); const sourceData = source.data; const distanceFieldData = distanceField.data; const width = source.width; const height = source.height; const maxX = width - 1; const maxY = height - 1; let x, y, i, v; //initialize distance field const dataSize = height * width; for (i = 0; i < dataSize; i++) { if (sourceData[i] !== emptyValue) { distanceFieldData[i] = 0; } else { distanceFieldData[i] = maxD; } } //first pass (forward) for (y = 0; y < height; y++) { const y_m1 = max2(y - 1, 0); const y_w = y * width; const y_m1_w = y_m1 * width; for (x = 0; x < width; x++) { i = y_w + x; v = distanceFieldData[i]; const x_m1 = max2(x - 1, 0); const x_p1 = min2(x + 1, maxX); const v0_i = x_m1 + y_m1_w; const v0 = distanceFieldData[v0_i] + d2; if (v0 < v) { distanceFieldData[i] = v0; v = v0; } const v1_i = x + y_m1_w; const v1 = distanceFieldData[v1_i] + d1; if (v1 < v) { distanceFieldData[i] = v1; v = v1; } const v2_i = x_p1 + y_m1_w; const v2 = distanceFieldData[v2_i] + d2; if (v2 < v) { distanceFieldData[i] = v2; v = v2; } const v3_i = x_m1 + y_w; const v3 = distanceFieldData[v3_i] + d1; if (v3 < v) { distanceFieldData[i] = v3; } } } //second pass (backward) for (y = maxY; y >= 0; y--) { const y_w = y * width; const y_p1 = min2(y + 1, maxY); const y_p1_w = y_p1 * width; for (x = maxX; x >= 0; x--) { const x_p1 = min2(x + 1, maxX); const x_m1 = max2(x - 1, 0); i = y_w + x; v = distanceFieldData[i]; const v0_i = x_p1 + y_w; const v0 = distanceFieldData[v0_i] + d1; if (v0 < v) { distanceFieldData[i] = v0; v = v0; } const v1_i = x_m1 + y_p1_w; const v1 = distanceFieldData[v1_i] + d2; if (v1 < v) { distanceFieldData[i] = v1; v = v1; } const v2_i = x + y_p1_w; const v2 = distanceFieldData[v2_i] + d1; if (v2 < v) { distanceFieldData[i] = v2; v = v2; } const v3_i = x_p1 + y_p1_w; const v3 = distanceFieldData[v3_i] + d2; if (v3 < v) { distanceFieldData[i] = v3; } } } }