UNPKG

@woosh/meep-engine

Version:

Pure JavaScript game engine. Fully featured and production ready.

141 lines (106 loc) 3.48 kB
import { clamp } from "../../../../../core/math/clamp.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 maxD */ export function computeSignedDistanceField_Chamfer(source, distanceField, emptyValue, d1, d2, 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; function getS(x, y) { x = clamp(x, 0, maxX); y = clamp(y, 0, maxY); const index = x + y * width; return sourceData[index]; } function getD(x, y) { x = clamp(x, 0, maxX); y = clamp(y, 0, maxY); const index = x + y * width; return distanceFieldData[index]; } function setD(x, y, v) { x = clamp(x, 0, maxX); y = clamp(y, 0, maxY); const index = x + y * width; distanceFieldData[index] = min2(v, maxD); } let x, y; //initialize distance field for (y = 0; y < height; y++) { for (x = 0; x < width; x++) { if ( getS(x - 1, y) !== getS(x, y) || getS(x + 1, y) !== getS(x, y) || getS(x, y - 1) !== getS(x, y) || getS(x, y + 1) !== getS(x, y) ) { setD(x, y, 0); } else { setD(x, y, 255); } } } //first pass (forward) for (y = 0; y < height; y++) { for (x = 0; x < width; x++) { const v = getD(x, y); const v0 = getD(x - 1, y - 1) + d2; if (v0 < v) { setD(x, y, v0); } const v1 = getD(x, y - 1) + d1; if (v1 < v) { setD(x, y, v1); } const v2 = getD(x + 1, y - 1) + d2; if (v2 < v) { setD(x, y, v2); } const v3 = getD(x - 1, y) + d1; if (v3 < v) { setD(x, y, v3); } } } //second pass (backward) for (y = maxY; y >= 0; y--) { for (x = maxX; x >= 0; x--) { const v = getD(x, y); const v0 = getD(x + 1, y) + d1; if (v0 < v) { setD(x, y, v0); } const v1 = getD(x - 1, y + 1) + d2; if (v1 < v) { setD(x, y, v1); } const v2 = getD(x, y + 1) + d1; if (v2 < v) { setD(x, y, v2); } const v3 = getD(x + 1, y + 1) + d2; if (v3 < v) { setD(x, y, v3); } } } //indicate inside & outside for (y = 0; y < height; y++) { for (x = 0; x < width; x++) { if (getS(x, y) !== emptyValue) { //inside setD(x, y, -getD(x, y)); } } } }