Skip to content

Commit

Permalink
feat(grid-iterators): add point transforms & global options
Browse files Browse the repository at this point in the history
BREAKING CHANGE: update function signatures, switch to using options object as arg

- add `GridIterOpts` interface
- add `PointTransform` and implementations:
- add flipX/Y/XY, swapXY transforms
- update most iterators to use new options
  • Loading branch information
postspectacular committed Dec 20, 2022
1 parent 9b2361d commit 1861154
Show file tree
Hide file tree
Showing 19 changed files with 202 additions and 114 deletions.
6 changes: 6 additions & 0 deletions packages/grid-iterators/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,9 @@
".": {
"default": "./index.js"
},
"./api": {
"default": "./api.js"
},
"./circle": {
"default": "./circle.js"
},
Expand Down Expand Up @@ -131,6 +134,9 @@
"./spiral": {
"default": "./spiral.js"
},
"./transforms": {
"default": "./transforms.js"
},
"./zcurve": {
"default": "./zcurve.js"
},
Expand Down
26 changes: 26 additions & 0 deletions packages/grid-iterators/src/api.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import type { FnU2 } from "@thi.ng/api";

/**
* Higher order point coordinate transformation function. First is called with
* grid resolution (cols,rows), then returns a function which is applied to each
* generated grid coordinate.
*/
export type PointTransform = FnU2<number, FnU2<number, [number, number]>>;

export interface GridIterOpts {
/**
* Number of grid columns
*/
cols: number;
/**
* Number of grid rows, by default same as columns.
*/
rows?: number;
/**
* Point coordinate transformation function, e.g. to mirror iteration order
* along X or Y. See {@link flipX}, {@link flipY}, {@link flipXY} etc.
*
* @defaultValue {@link ident}
*/
tx?: PointTransform;
}
14 changes: 7 additions & 7 deletions packages/grid-iterators/src/column-ends.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
import { asInt } from "@thi.ng/api/typedarray";
import type { GridIterOpts } from "./api.js";
import { __opts } from "./utils.js";

/**
* Filtered version of {@link columns2d}, only including end points of
* each column.
*
* @param cols -
* @param rows -
* @param opts -
*/
export function* columnEnds2d(cols: number, rows = cols) {
[cols, rows] = asInt(cols, rows);
export function* columnEnds2d(opts: GridIterOpts) {
let { cols, rows, tx } = __opts(opts);
rows--;
for (let x = 0; x < cols; x++) {
yield [x, 0];
yield [x, rows];
yield tx(x, 0);
yield tx(x, rows);
}
}
14 changes: 8 additions & 6 deletions packages/grid-iterators/src/columns.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
import { range2d } from "@thi.ng/transducers/range2d";
import { map } from "@thi.ng/transducers/map";
import { swapxy } from "./utils.js";
import { range2d } from "@thi.ng/transducers/range2d";
import type { GridIterOpts } from "./api.js";
import { __opts } from "./utils.js";

/**
* Yields sequence of 2D grid coordinates in column-major order.
*
* @param cols -
* @param rows -
* @param opts -
*/
export const columns2d = (cols: number, rows = cols) =>
map(swapxy, range2d(rows | 0, cols | 0));
export const columns2d = (opts: GridIterOpts) => {
const { cols, rows, tx } = __opts(opts);
return map((p) => tx(p[1], p[0]), range2d(rows | 0, cols | 0));
};
14 changes: 7 additions & 7 deletions packages/grid-iterators/src/diagonal-ends.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { asInt } from "@thi.ng/api/typedarray";
import type { GridIterOpts } from "./api.js";
import { diagonal2d } from "./diagonal.js";
import { __opts } from "./utils.js";

/**
* Filtered version of {@link diagonal2d}, only including end points of
Expand All @@ -9,19 +10,18 @@ import { diagonal2d } from "./diagonal.js";
* @remarks
* `cols` and `rows` MUST be both >= 2.
*
* @param cols -
* @param rows -
* @param opts -
*/
export function* diagonalEnds2d(cols: number, rows = cols) {
[cols, rows] = asInt(cols, rows);
export function* diagonalEnds2d(opts: GridIterOpts) {
const { cols, rows, tx } = __opts(opts);
const num = cols * rows - 1;
const maxX = cols - 1;
const maxY = rows - 1;
let i = 0;
for (let p of diagonal2d(cols, rows)) {
for (let p of diagonal2d({ cols, rows })) {
if (i > 0 && i < num) {
const [x, y] = p;
if (x === 0 || x === maxX || y === 0 || y === maxY) yield p;
if (x === 0 || x === maxX || y === 0 || y === maxY) yield tx(x, y);
}
i++;
}
Expand Down
12 changes: 6 additions & 6 deletions packages/grid-iterators/src/diagonal.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { asInt } from "@thi.ng/api/typedarray";
import type { GridIterOpts } from "./api.js";
import { __opts } from "./utils.js";

/**
* Yields sequence of 2D grid coordinates in diagonal order starting at [0,0]
Expand All @@ -8,14 +9,13 @@ import { asInt } from "@thi.ng/api/typedarray";
* Ported & modified from original Java code by Christopher Kulla.
* https://sourceforge.net/p/sunflow/code/HEAD/tree/trunk/src/org/sunflow/core/bucket/DiagonalBucketOrder.java
*
* @param cols -
* @param rows -
* @param opts -
*/
export function* diagonal2d(cols: number, rows = cols) {
[cols, rows] = asInt(cols, rows);
export function* diagonal2d(opts: GridIterOpts) {
const { cols, rows, tx } = __opts(opts);
const num = cols * rows - 1;
for (let x = 0, y = 0, nx = 1, ny = 0, i = 0; i <= num; i++) {
yield [x, y];
yield tx(x, y);
if (i != num) {
do {
if (y === ny) {
Expand Down
12 changes: 6 additions & 6 deletions packages/grid-iterators/src/hilbert.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { asInt } from "@thi.ng/api/typedarray";
import type { GridIterOpts } from "./api.js";
import { __opts } from "./utils.js";

/**
* Yields sequence of 2D grid coordinates along 2D Hilbert curve using given
Expand All @@ -7,11 +8,10 @@ import { asInt } from "@thi.ng/api/typedarray";
* Ported & modified from original Java code by Christopher Kulla.
* https://sourceforge.net/p/sunflow/code/HEAD/tree/trunk/src/org/sunflow/core/bucket/HilbertBucketOrder.java
*
* @param cols -
* @param rows -
* @param opts -
*/
export function* hilbert2d(cols: number, rows = cols) {
[cols, rows] = asInt(cols, rows);
export function* hilbert2d(opts: GridIterOpts) {
const { cols, rows, tx } = __opts(opts);
let hIndex = 0; // hilbert curve index
let hOrder = 0; // hilbert curve order
// fit to number of buckets
Expand Down Expand Up @@ -62,6 +62,6 @@ export function* hilbert2d(cols: number, rows = cols) {
(hx >= cols || hy >= rows || hx < 0 || hy < 0) &&
hIndex < numBuckets
);
yield [hx, hy];
yield tx(hx, hy);
}
}
1 change: 1 addition & 0 deletions packages/grid-iterators/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ export * from "./random.js";
export * from "./row-ends.js";
export * from "./rows.js";
export * from "./spiral.js";
export * from "./transforms.js";
export * from "./zcurve.js";
export * from "./zigzag-columns.js";
export * from "./zigzag-diagonal.js";
Expand Down
49 changes: 31 additions & 18 deletions packages/grid-iterators/src/interleave.ts
Original file line number Diff line number Diff line change
@@ -1,45 +1,58 @@
import { range2d } from "@thi.ng/transducers/range2d";
import { map } from "@thi.ng/transducers/map";
import { swapxy } from "./utils.js";
import { range2d } from "@thi.ng/transducers/range2d";
import type { GridIterOpts } from "./api.js";
import { __opts } from "./utils.js";

interface InterleaveOpts extends GridIterOpts {
/**
* Row or column stride.
*
* @defaultValue 2
*/
step?: number;
}

/**
* Yields 2D grid coordinates in the order of interleaved columns with
* configurable `step` size (default: 2). I.e. returns columns in this
* order:
* configurable `step` size (default: 2).
*
* @remarks
* Returns columns in this order:
*
* - 0, step, 2 * step, 3 * step...
* - 1, 2 * step + 1, 3 * step + 1...
* - etc.
*
* {@link interleaveRows2d}
* Also see {@link interleaveRows2d}.
*
* @param cols -
* @param rows -
* @param step - column stride
* @param opts -
*/
export function* interleaveColumns2d(cols: number, rows = cols, step = 2) {
export function* interleaveColumns2d(opts: InterleaveOpts) {
const { cols, rows, tx } = __opts(opts);
const step = (opts.step != null ? opts.step : 2) | 0;
for (let j = 0; j < step; j++) {
yield* map(swapxy, range2d(0, rows | 0, j, cols | 0, 1, step | 0));
yield* map((p) => tx(p[1], p[0]), range2d(0, rows, j, cols, 1, step));
}
}

/**
* Similar to {@link interleaveColumns2d}, but yields 2D grid coordinates in
* the order of interleaved rows with configurable `step` size (default:
* 2). I.e. returns rows in this order:
* 2).
*
* @remarks
* Returns rows in this order:
*
* - 0, step, 2 * step, 3 * step...
* - 1, 2 * step + 1, 3 * step + 1...
* - etc.
*
* {@link interleaveColumns2d}
*
* @param cols -
* @param rows -
* @param step - row stride
* @param opts -
*/
export function* interleaveRows2d(cols: number, rows = cols, step = 2) {
export function* interleaveRows2d(opts: InterleaveOpts) {
const { cols, rows, tx } = __opts(opts);
const step = (opts.step != null ? opts.step : 2) | 0;
for (let j = 0; j < step; j++) {
yield* range2d(0, cols | 0, j, rows | 0, 1, step | 0);
yield* map((p) => tx(p[0], p[1]), range2d(0, cols, j, rows, 1, step));
}
}
23 changes: 16 additions & 7 deletions packages/grid-iterators/src/random.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,18 @@
import { asInt } from "@thi.ng/api/typedarray";
import { shuffle } from "@thi.ng/arrays/shuffle";
import type { IRandom } from "@thi.ng/random";
import { SYSTEM } from "@thi.ng/random/system";
import { range } from "@thi.ng/transducers/range";
import type { GridIterOpts } from "./api.js";
import { __opts } from "./utils.js";

interface Random2DOpts extends GridIterOpts {
/**
* PRNG instance to use
*
* @defaultValue `SYSTEM`
*/
rnd?: IRandom;
}

/**
* Yields 2D grid coordinates in random order w/ support for optional
Expand All @@ -11,13 +21,12 @@ import { range } from "@thi.ng/transducers/range";
* [`SYSTEM`](https://docs.thi.ng/umbrella/random/variables/SYSTEM.html) aka
* `Math.random`).
*
* @param cols -
* @param rows -
* @param rnd - PRNG
* @param opts -
*/
export function* random2d(cols: number, rows = cols, rnd: IRandom = SYSTEM) {
[cols, rows] = asInt(cols, rows);
export function* random2d(opts: Random2DOpts) {
const { cols, rows, tx } = __opts(opts);
const rnd = opts.rnd || SYSTEM;
for (let i of shuffle([...range(cols * rows)], undefined, rnd)) {
yield [i % cols, (i / cols) | 0];
yield tx(i % cols, (i / cols) | 0);
}
}
14 changes: 7 additions & 7 deletions packages/grid-iterators/src/row-ends.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
import { asInt } from "@thi.ng/api/typedarray";
import type { GridIterOpts } from "./api.js";
import { __opts } from "./utils.js";

/**
* Filtered version of {@link rows2d}, only including end points of
* each row.
*
* @param cols -
* @param rows -
* @param opts -
*/
export function* rowEnds2d(cols: number, rows = cols) {
[cols, rows] = asInt(cols, rows);
export function* rowEnds2d(opts: GridIterOpts) {
let { cols, rows, tx } = __opts(opts);
cols--;
for (let y = 0; y < rows; y++) {
yield [0, y];
yield [cols, y];
yield tx(0, y);
yield tx(cols, y);
}
}
12 changes: 8 additions & 4 deletions packages/grid-iterators/src/rows.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
import { map } from "@thi.ng/transducers/map";
import { range2d } from "@thi.ng/transducers/range2d";
import type { GridIterOpts } from "./api.js";
import { __opts } from "./utils.js";

/**
* Yields sequence of 2D grid coordinates in row-major order. Same as
* [`range2d()`](https://docs.thi.ng/umbrella/transducers/functions/range2d.html).
*
* @param cols -
* @param rows -
* @param opts -
*/
export const rows2d = (cols: number, rows = cols) =>
range2d(cols | 0, rows | 0);
export const rows2d = (opts: GridIterOpts) => {
const { cols, rows, tx } = __opts(opts);
return map((p) => tx(p[0], p[1]), range2d(cols, rows));
};
12 changes: 6 additions & 6 deletions packages/grid-iterators/src/spiral.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { asInt } from "@thi.ng/api/typedarray";
import type { GridIterOpts } from "./api";
import { __opts } from "./utils.js";

/**
* Yields sequence of 2D grid coordinates in outward spiral order starting from
Expand All @@ -7,11 +8,10 @@ import { asInt } from "@thi.ng/api/typedarray";
* Ported & modified from original Java code by Christopher Kulla.
* https://sourceforge.net/p/sunflow/code/HEAD/tree/trunk/src/org/sunflow/core/bucket/SpiralBucketOrder.java
*
* @param cols -
* @param rows -
* @param opts -
*/
export function* spiral2d(cols: number, rows = cols) {
[cols, rows] = asInt(cols, rows);
export function* spiral2d(opts: GridIterOpts) {
const { cols, rows, tx } = __opts(opts);
const num = cols * rows;
const center = (Math.min(cols, rows) - 1) >> 1;
for (let i = 0; i < num; i++) {
Expand Down Expand Up @@ -42,6 +42,6 @@ export function* spiral2d(cols: number, rows = cols) {
by = -m2;
}
}
yield [bx + center, by + center];
yield tx(bx + center, by + center);
}
}

0 comments on commit 1861154

Please sign in to comment.