@woosh/meep-engine
Version:
Pure JavaScript game engine. Fully featured and production ready.
150 lines (113 loc) • 3.95 kB
JavaScript
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;
}
}
}
}