Skip to content

Commit

Permalink
fix(morton): fix tree coord conversion fns, add tests
Browse files Browse the repository at this point in the history
  • Loading branch information
postspectacular committed Apr 9, 2020
1 parent a6ec36a commit 9a23fa2
Show file tree
Hide file tree
Showing 2 changed files with 47 additions and 16 deletions.
41 changes: 28 additions & 13 deletions packages/morton/src/tree.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,51 +6,66 @@ export const treeToMorton = (t: number[], dim: number) => {
let l = t.length;
dim = 1 << dim;
while (--l >= 0) {
m += t[l] * Math.pow(dim, n);
m += (t[l] - 1) * Math.pow(dim, n);
n++;
}
return m;
return m + 1;
};

export const mortonToTree = (m: number, dim: number) => {
const t: number[] = [];
dim = 1 << dim;
while (true) {
const d = Math.floor(m / dim);
t.unshift(m % dim);
if (!d) break;
m--;
const d = ((m / dim) | 0) + 1;
const r = (m % dim) + 1;
t.unshift(r);
if (d === 1) break;
m = d;
}
return t;
};

/**
* Inverse operation of {@link cartesianToTree}. Takes vector of nD quad
* tree coordinates and converts them back to cartesian.
*
* @param t - tree coords
* @param dim - dimensionality
*/
export const treeToCartesian = (t: number[], dim: number) => {
const c: number[] = [];
for (let i = 0, x = t[0]; i < dim; i++) {
c[i] = (x >>> i) & 1;
for (let i = 0, x = t[0] - 1; i < dim; i++) {
c[i] = ((x >>> i) & 1) + 1;
}
if (t.length < 2) return c;
const cn = treeToCartesian(t.slice(1), 2);
const cn = treeToCartesian(t.slice(1), dim);
const m = 1 << (t.length - 1);
const res: number[] = new Array(dim);
for (let i = 0; i < dim; i++) {
res[i] = m * c[i] + cn[i];
res[i] = m * (c[i] - 1) + cn[i];
}
return res;
};

/**
* Takes a vector of positive integer coordinates and returns vector of
* nD quad tree coordinates.
*
* @param v
*/
export const cartesianToTree = (v: number[]) => {
const $ = (v: number[], half: number): number[] => {
const t = v.reduce((t, x, i) => t + (1 << i) * <any>(x >= half), 0);
const t = v.reduce((t, x, i) => t + (1 << i) * <any>(x > half), 1);
return half > 1
? [
t,
...$(
v.map((x) => x % half),
v.map((x) => ((x - 1) % half) + 1),
half >>> 1
)
),
]
: [t];
};
return $(v, Math.max(2, ceilPow2(Math.max(...v) + 1)) >> 1);
return $(v, Math.max(2, ceilPow2(Math.max(...v))) >>> 1);
};
22 changes: 19 additions & 3 deletions packages/morton/test/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,22 @@
// import * as assert from "assert";
// import * as m from "../src/index";
import * as assert from "assert";
import {
cartesianToTree,
treeToCartesian,
treeToMorton,
mortonToTree,
} from "../src/index";

describe("morton", () => {
it("tests pending");
it("tree <> cartesian3 fuzz", function () {
this.timeout(10000);
const M = 1 << 11;
const $ = () => (1 + Math.random() * M) | 0;
for (let i = 0; i < 1e5; i++) {
const p = [$(), $(), $()];
const tree = cartesianToTree(p);
const morton = treeToMorton(tree, 3);
assert.deepEqual(mortonToTree(morton, 3), tree, "m2t");
assert.deepEqual(treeToCartesian(tree, 3), p, "t2c");
}
});
});

0 comments on commit 9a23fa2

Please sign in to comment.