@thi.ng/rasterize 0.1.1 → 0.3.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +37 -6
- package/README.md +77 -18
- package/api.d.ts +3 -0
- package/api.js +1 -0
- package/checks.d.ts +3 -1
- package/checks.js +3 -1
- package/circle.d.ts +2 -1
- package/circle.js +2 -2
- package/draw.d.ts +6 -1
- package/draw.js +36 -5
- package/flood-fill.d.ts +6 -15
- package/flood-fill.js +21 -31
- package/index.d.ts +4 -0
- package/index.js +4 -0
- package/line.d.ts +3 -2
- package/line.js +4 -4
- package/package.json +112 -92
- package/poly.d.ts +18 -0
- package/poly.js +67 -0
- package/polyline.d.ts +4 -0
- package/polyline.js +12 -0
- package/rect.d.ts +2 -1
- package/rect.js +25 -6
- package/shader.d.ts +20 -0
- package/shader.js +18 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,19 +1,50 @@
|
|
|
1
1
|
# Change Log
|
|
2
2
|
|
|
3
|
+
- **Last updated**: 2021-11-21T17:09:28Z
|
|
4
|
+
- **Generator**: [thi.ng/monopub](https://thi.ng/monopub)
|
|
5
|
+
|
|
3
6
|
All notable changes to this project will be documented in this file.
|
|
4
|
-
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
|
7
|
+
See [Conventional Commits](https://conventionalcommits.org/) for commit guidelines.
|
|
8
|
+
|
|
9
|
+
**Note:** Unlisted _patch_ versions only involve non-code or otherwise excluded changes
|
|
10
|
+
and/or version bumps of transitive dependencies.
|
|
11
|
+
|
|
12
|
+
## [0.3.0](https://github.com/thi-ng/umbrella/tree/@thi.ng/rasterize@0.3.0) (2021-11-17)
|
|
5
13
|
|
|
6
|
-
|
|
14
|
+
#### 🚀 Features
|
|
7
15
|
|
|
8
|
-
|
|
16
|
+
- Using workspaces for local tools ([bf7a404](https://github.com/thi-ng/umbrella/commit/bf7a404))
|
|
17
|
+
Improving the overall build ergonomics
|
|
18
|
+
- introduced a tools workspaces
|
|
19
|
+
- imported it in all needed packages/examples
|
|
20
|
+
- inclusive project root
|
|
9
21
|
|
|
22
|
+
#### ♻️ Refactoring
|
|
10
23
|
|
|
24
|
+
- testrunner to binary ([4ebbbb2](https://github.com/thi-ng/umbrella/commit/4ebbbb2))
|
|
25
|
+
this commit reverts (partly) changes made in:
|
|
26
|
+
ef346d7a8753590dc9094108a3d861a8dbd5dd2c
|
|
27
|
+
overall purpose is better testament ergonomics:
|
|
28
|
+
instead of having to pass NODE_OPTIONS with every invocation
|
|
29
|
+
having a binary to handle this for us.
|
|
11
30
|
|
|
31
|
+
## [0.2.0](https://github.com/thi-ng/umbrella/tree/@thi.ng/rasterize@0.2.0) (2021-11-10)
|
|
12
32
|
|
|
33
|
+
#### 🚀 Features
|
|
13
34
|
|
|
14
|
-
|
|
35
|
+
- major update/additions ([e6f7fb0](https://github.com/thi-ng/umbrella/commit/e6f7fb0))
|
|
36
|
+
- add new shapes (polyline, polygon)
|
|
37
|
+
- add "shader" function support for all draw fns
|
|
38
|
+
- add shader functions
|
|
39
|
+
- rename drawLineWith() => traceLine()
|
|
40
|
+
- update to new IGrid2D impls ([71ac0ca](https://github.com/thi-ng/umbrella/commit/71ac0ca))
|
|
41
|
+
- add floodFillWith() for custom fill content/procedures
|
|
42
|
+
- update/fix rect()
|
|
43
|
+
- optimize __draw2D() for primitive values
|
|
44
|
+
- add/update deps
|
|
15
45
|
|
|
46
|
+
## [0.1.0](https://github.com/thi-ng/umbrella/tree/@thi.ng/rasterize@0.1.0) (2021-11-03)
|
|
16
47
|
|
|
17
|
-
|
|
48
|
+
#### 🚀 Features
|
|
18
49
|
|
|
19
|
-
|
|
50
|
+
- import as new pkg ([585eb8d](https://github.com/thi-ng/umbrella/commit/585eb8d))
|
package/README.md
CHANGED
|
@@ -12,8 +12,10 @@ This project is part of the
|
|
|
12
12
|
- [About](#about)
|
|
13
13
|
- [Circle](#circle)
|
|
14
14
|
- [Line](#line)
|
|
15
|
+
- [Polygon / polyline](#polygon--polyline)
|
|
15
16
|
- [Rect](#rect)
|
|
16
17
|
- [Flood fill](#flood-fill)
|
|
18
|
+
- [Custom shaders](#custom-shaders)
|
|
17
19
|
- [Status](#status)
|
|
18
20
|
- [Related packages](#related-packages)
|
|
19
21
|
- [Installation](#installation)
|
|
@@ -27,40 +29,94 @@ This project is part of the
|
|
|
27
29
|
2D shape drawing & rasterization.
|
|
28
30
|
|
|
29
31
|
The functions in this package can be used with any
|
|
30
|
-
[`IGrid2D`](https://docs.thi.ng/umbrella/api/interfaces/
|
|
32
|
+
[`IGrid2D`](https://docs.thi.ng/umbrella/api/interfaces/IGrid2D.html) compatible
|
|
31
33
|
grid/image type (e.g. those provided by
|
|
32
34
|
[@thi.ng/pixel](https://github.com/thi-ng/umbrella/tree/develop/packages/pixel)
|
|
33
35
|
or
|
|
34
36
|
[@thi.ng/text-canvas](https://github.com/thi-ng/umbrella/tree/develop/packages/text-canvas)).
|
|
35
37
|
|
|
36
|
-
Currently the following functions are available
|
|
38
|
+
Currently the following functions are available. All of them support [custom
|
|
39
|
+
shader-like](#custom-shaders) functions to produce "pixel" values.
|
|
37
40
|
|
|
38
41
|
### Circle
|
|
39
42
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
+
- [`drawCircle()`](https://docs.thi.ng/umbrella/rasterize/modules.html#drawCircle):
|
|
44
|
+
Filled or outline implementation of [Bresenham's circle
|
|
45
|
+
algorithm](https://en.wikipedia.org/wiki/Midpoint_circle_algorithm), with
|
|
46
|
+
clipping.
|
|
43
47
|
|
|
44
48
|
### Line
|
|
45
49
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
[`
|
|
52
|
-
|
|
50
|
+
- [`drawLine()`](https://docs.thi.ng/umbrella/rasterize/modules.html#drawLine):
|
|
51
|
+
Implementation of [Bresenham's line
|
|
52
|
+
algorithm](https://en.wikipedia.org/wiki/Bresenham%27s_line_algorithm) with
|
|
53
|
+
pre-applied [Liang-Barsky
|
|
54
|
+
clipping](https://en.wikipedia.org/wiki/Liang%E2%80%93Barsky_algorithm)
|
|
55
|
+
- [`traceLine()`](https://docs.thi.ng/umbrella/rasterize/modules.html#traceLine):
|
|
56
|
+
Apply custom functions to trace the line
|
|
57
|
+
|
|
58
|
+
### Polygon / polyline
|
|
59
|
+
|
|
60
|
+
Filled or outline drawing of polygons (without holes):
|
|
61
|
+
|
|
62
|
+
- [`drawPolyline()`](https://docs.thi.ng/umbrella/rasterize/modules.html#drawPolyline)
|
|
63
|
+
- [`fillPoly()`](https://docs.thi.ng/umbrella/rasterize/modules.html#fillPoly)
|
|
53
64
|
|
|
54
65
|
### Rect
|
|
55
66
|
|
|
56
|
-
|
|
67
|
+
- [`drawRect()`](https://docs.thi.ng/umbrella/rasterize/modules.html#drawRect):
|
|
68
|
+
Filled or outline implementation with pre-applied clipping against the target
|
|
69
|
+
grid.
|
|
57
70
|
|
|
58
71
|
### Flood fill
|
|
59
72
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
73
|
+
- [`floodFill()`](https://docs.thi.ng/umbrella/rasterize/modules.html#floodFill):
|
|
74
|
+
Fills grid in the connected region around `x,y` with given value or shader
|
|
75
|
+
|
|
76
|
+
Also see corresponding function in
|
|
77
|
+
[@thi.ng/grid-iterators](https://docs.thi.ng/umbrella/grid-iterators/modules.html#floodFill).
|
|
78
|
+
|
|
79
|
+
## Custom shaders
|
|
80
|
+
|
|
81
|
+
Conceptually similar, but **not** to be equaled with actual WebGL fragement
|
|
82
|
+
shaders, many functions in this package support shader-like functions to produce
|
|
83
|
+
per-pixel fill/color values for each individual pixel processed. These simple
|
|
84
|
+
functions take an `x` and `y` arg (in grid-space, **not** normalized!) and
|
|
85
|
+
produce a fill value for that location. A pixel is processed at most once per
|
|
86
|
+
draw call.
|
|
87
|
+
|
|
88
|
+
The following shader functions are provided:
|
|
89
|
+
|
|
90
|
+
- [`defPattern()`](https://docs.thi.ng/umbrella/rasterize/modules.html#defPattern):
|
|
91
|
+
pattern fill (must be same format as target grid)
|
|
92
|
+
- [`defStripes()`](https://docs.thi.ng/umbrella/rasterize/modules.html#defStripes):
|
|
93
|
+
procedural stripes (configurable)
|
|
94
|
+
- [`defNoise()`](https://docs.thi.ng/umbrella/rasterize/modules.html#defNoise):
|
|
95
|
+
random noise pattern (configurable)
|
|
96
|
+
|
|
97
|
+
As an example, here's a simple custom UV gradient shader for drawing into a
|
|
98
|
+
[float RGBA](https://docs.thi.ng/umbrella/pixel/modules.html#floatBuffer)
|
|
99
|
+
buffer:
|
|
100
|
+
|
|
101
|
+
```ts
|
|
102
|
+
import type { Shader2D } from "@thi.ng/rasterize";
|
|
103
|
+
import { floatBuffer } from "@thi.ng/pixel";
|
|
104
|
+
import { drawCircle } from "@thi.ng/rasterize";
|
|
105
|
+
|
|
106
|
+
// custom gradient shader
|
|
107
|
+
const defUVGradient = (width: number, height: number): Shader2D<number[]> =>
|
|
108
|
+
(x, y) => [x/width, y/height, 0.5, 1];
|
|
109
|
+
|
|
110
|
+
const W = 256;
|
|
111
|
+
|
|
112
|
+
// create float RGBA pixel buffer
|
|
113
|
+
const img = floatBuffer(W, W);
|
|
114
|
+
|
|
115
|
+
// draw filled circle using gradient shader
|
|
116
|
+
drawCircle(img, W/2, W/2, W/2 - 4, defUVGradient(W, W), true);
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+

|
|
64
120
|
|
|
65
121
|
### Status
|
|
66
122
|
|
|
@@ -97,12 +153,15 @@ node --experimental-repl-await
|
|
|
97
153
|
> const rasterize = await import("@thi.ng/rasterize");
|
|
98
154
|
```
|
|
99
155
|
|
|
100
|
-
Package sizes (gzipped, pre-treeshake): ESM:
|
|
156
|
+
Package sizes (gzipped, pre-treeshake): ESM: 1.45 KB
|
|
101
157
|
|
|
102
158
|
## Dependencies
|
|
103
159
|
|
|
104
160
|
- [@thi.ng/api](https://github.com/thi-ng/umbrella/tree/develop/packages/api)
|
|
161
|
+
- [@thi.ng/checks](https://github.com/thi-ng/umbrella/tree/develop/packages/checks)
|
|
162
|
+
- [@thi.ng/equiv](https://github.com/thi-ng/umbrella/tree/develop/packages/equiv)
|
|
105
163
|
- [@thi.ng/grid-iterators](https://github.com/thi-ng/umbrella/tree/develop/packages/grid-iterators)
|
|
164
|
+
- [@thi.ng/random](https://github.com/thi-ng/umbrella/tree/develop/packages/random)
|
|
106
165
|
- [@thi.ng/transducers](https://github.com/thi-ng/umbrella/tree/develop/packages/transducers)
|
|
107
166
|
|
|
108
167
|
## API
|
package/api.d.ts
ADDED
package/api.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/checks.d.ts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
1
|
import type { IGrid2D } from "@thi.ng/api";
|
|
2
|
-
|
|
2
|
+
import type { Shader2D } from "./api.js";
|
|
3
|
+
export declare const isInBounds2D: ({ size }: IGrid2D<any, any>, x: number, y: number) => boolean;
|
|
4
|
+
export declare const ensureShader2D: <T>(val: T | Shader2D<T>) => Shader2D<T>;
|
|
3
5
|
//# sourceMappingURL=checks.d.ts.map
|
package/checks.js
CHANGED
|
@@ -1 +1,3 @@
|
|
|
1
|
-
|
|
1
|
+
import { isFunction } from "@thi.ng/checks/is-function";
|
|
2
|
+
export const isInBounds2D = ({ size }, x, y) => x >= 0 && x < size[0] && y >= 0 && y < size[1];
|
|
3
|
+
export const ensureShader2D = (val) => isFunction(val) ? val : () => val;
|
package/circle.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
1
|
import type { IGrid2D, TypedArray } from "@thi.ng/api";
|
|
2
|
-
|
|
2
|
+
import type { Shader2D } from "./api.js";
|
|
3
|
+
export declare const drawCircle: <T extends any[] | TypedArray, P>(grid: IGrid2D<T, P>, x: number, y: number, r: number, val: P | Shader2D<P>, fill?: boolean) => IGrid2D<T, P>;
|
|
3
4
|
//# sourceMappingURL=circle.d.ts.map
|
package/circle.js
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import { circleClipped } from "@thi.ng/grid-iterators/circle";
|
|
2
|
-
import {
|
|
3
|
-
export const drawCircle = (grid, x, y, r, val, fill = false) =>
|
|
2
|
+
import { __draw2D } from "./draw.js";
|
|
3
|
+
export const drawCircle = (grid, x, y, r, val, fill = false) => __draw2D(circleClipped(x, y, r, 0, 0, grid.size[0], grid.size[1], fill), grid, val);
|
package/draw.d.ts
CHANGED
|
@@ -1,4 +1,9 @@
|
|
|
1
1
|
import type { IGrid2D, Nullable, TypedArray } from "@thi.ng/api";
|
|
2
|
+
import type { Shader2D } from "./api.js";
|
|
2
3
|
/** @internal */
|
|
3
|
-
export declare const
|
|
4
|
+
export declare const __draw2D: <T extends any[] | TypedArray, P>(pts: Nullable<Iterable<number[]>>, grid: IGrid2D<T, P>, val: P | Shader2D<P>) => IGrid2D<T, P>;
|
|
5
|
+
/** @internal */
|
|
6
|
+
export declare const __drawSolid2D: <T extends any[] | TypedArray, P>(pts: Nullable<Iterable<number[]>>, grid: IGrid2D<T, P>, val: P) => IGrid2D<T, P>;
|
|
7
|
+
/** @internal */
|
|
8
|
+
export declare const __drawShader2D: <T extends any[] | TypedArray, P>(pts: Nullable<Iterable<number[]>>, grid: IGrid2D<T, P>, shader: Shader2D<P>) => IGrid2D<T, P>;
|
|
4
9
|
//# sourceMappingURL=draw.d.ts.map
|
package/draw.js
CHANGED
|
@@ -1,9 +1,40 @@
|
|
|
1
|
+
import { isFunction } from "@thi.ng/checks/is-function";
|
|
2
|
+
import { isPrimitive } from "@thi.ng/checks/is-primitive";
|
|
1
3
|
/** @internal */
|
|
2
|
-
export const
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
4
|
+
export const __draw2D = (pts, grid, val) => isFunction(val)
|
|
5
|
+
? __drawShader2D(pts, grid, val)
|
|
6
|
+
: __drawSolid2D(pts, grid, val);
|
|
7
|
+
/** @internal */
|
|
8
|
+
export const __drawSolid2D = (pts, grid, val) => {
|
|
9
|
+
if (!pts)
|
|
10
|
+
return grid;
|
|
11
|
+
if (isPrimitive(val)) {
|
|
12
|
+
const { data, offset, stride: [sx, sy], } = grid;
|
|
13
|
+
for (let p of pts) {
|
|
14
|
+
data[offset + p[0] * sx + p[1] * sy] = val;
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
else {
|
|
18
|
+
for (let p of pts) {
|
|
19
|
+
grid.setAtUnsafe(p[0], p[1], val);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
return grid;
|
|
23
|
+
};
|
|
24
|
+
/** @internal */
|
|
25
|
+
export const __drawShader2D = (pts, grid, shader) => {
|
|
26
|
+
if (!pts)
|
|
27
|
+
return grid;
|
|
28
|
+
if (isPrimitive(grid.getAtUnsafe(0, 0))) {
|
|
29
|
+
const { data, offset, stride: [sx, sy], } = grid;
|
|
30
|
+
for (let { 0: x, 1: y } of pts) {
|
|
31
|
+
data[offset + x * sx + y * sy] = shader(x, y);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
else {
|
|
35
|
+
for (let { 0: x, 1: y } of pts) {
|
|
36
|
+
grid.setAtUnsafe(x, y, shader(x, y));
|
|
37
|
+
}
|
|
7
38
|
}
|
|
8
39
|
return grid;
|
|
9
40
|
};
|
package/flood-fill.d.ts
CHANGED
|
@@ -1,23 +1,14 @@
|
|
|
1
1
|
import type { IGrid2D, TypedArray } from "@thi.ng/api";
|
|
2
|
+
import type { Shader2D } from "./api.js";
|
|
2
3
|
/**
|
|
3
|
-
* Fills
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
* @param img
|
|
7
|
-
* @param x
|
|
8
|
-
* @param y
|
|
9
|
-
* @param val
|
|
10
|
-
*/
|
|
11
|
-
export declare const floodFillSolid: <T extends any[] | TypedArray, P>(img: IGrid2D<T, P>, x: number, y: number, val: P) => IGrid2D<T, P>;
|
|
12
|
-
/**
|
|
13
|
-
* Fills pixel in the connected region around `x,y` with the pattern defined by
|
|
14
|
-
* given `pattern` image (must be in same format as `img`). Returns updated
|
|
15
|
-
* pixel buffer.
|
|
4
|
+
* Fills cells in the connected region around `x,y` with given value or shader
|
|
5
|
+
* function. If the latter, the shader is called for each grid coordinate and
|
|
6
|
+
* returns a fill value. Returns updated grid.
|
|
16
7
|
*
|
|
17
8
|
* @param grid
|
|
18
9
|
* @param x
|
|
19
10
|
* @param y
|
|
20
|
-
* @param
|
|
11
|
+
* @param val
|
|
21
12
|
*/
|
|
22
|
-
export declare const
|
|
13
|
+
export declare const floodFill: <T extends any[] | TypedArray, P>(grid: IGrid2D<T, P>, x: number, y: number, val: P | Shader2D<P>) => IGrid2D<T, P>;
|
|
23
14
|
//# sourceMappingURL=flood-fill.d.ts.map
|
package/flood-fill.js
CHANGED
|
@@ -1,40 +1,30 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { isIterable } from "@thi.ng/checks/is-iterable";
|
|
2
|
+
import { isPrimitive } from "@thi.ng/checks/is-primitive";
|
|
3
|
+
import { equiv } from "@thi.ng/equiv";
|
|
4
|
+
import { floodFill as $fill } from "@thi.ng/grid-iterators/flood-fill";
|
|
2
5
|
import { isInBounds2D } from "./checks.js";
|
|
3
|
-
import {
|
|
6
|
+
import { __draw2D } from "./draw.js";
|
|
4
7
|
/**
|
|
5
|
-
* Fills
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
* @param img
|
|
9
|
-
* @param x
|
|
10
|
-
* @param y
|
|
11
|
-
* @param val
|
|
12
|
-
*/
|
|
13
|
-
export const floodFillSolid = (img, x, y, val) => {
|
|
14
|
-
if (!isInBounds2D(img, x, y))
|
|
15
|
-
return img;
|
|
16
|
-
const { data, width, height, stride, rowStride } = img;
|
|
17
|
-
const srcVal = img.getAtUnsafe(x, y);
|
|
18
|
-
return draw2D(img, val, floodFill((x, y) => data[x * stride + y * rowStride] === srcVal, x, y, width, height));
|
|
19
|
-
};
|
|
20
|
-
/**
|
|
21
|
-
* Fills pixel in the connected region around `x,y` with the pattern defined by
|
|
22
|
-
* given `pattern` image (must be in same format as `img`). Returns updated
|
|
23
|
-
* pixel buffer.
|
|
8
|
+
* Fills cells in the connected region around `x,y` with given value or shader
|
|
9
|
+
* function. If the latter, the shader is called for each grid coordinate and
|
|
10
|
+
* returns a fill value. Returns updated grid.
|
|
24
11
|
*
|
|
25
12
|
* @param grid
|
|
26
13
|
* @param x
|
|
27
14
|
* @param y
|
|
28
|
-
* @param
|
|
15
|
+
* @param val
|
|
29
16
|
*/
|
|
30
|
-
export const
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
const { data
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
17
|
+
export const floodFill = (grid, x, y, val) => isInBounds2D(grid, x, y)
|
|
18
|
+
? __draw2D($fill(__pred(grid, x, y), x, y, grid.size[0], grid.size[1]), grid, val)
|
|
19
|
+
: grid;
|
|
20
|
+
const __pred = (img, x, y) => {
|
|
21
|
+
const { data, offset, stride: [stride, rowStride], } = img;
|
|
22
|
+
let srcVal = img.getAtUnsafe(x, y);
|
|
23
|
+
if (isPrimitive(srcVal)) {
|
|
24
|
+
return (x, y) => data[offset + x * stride + y * rowStride] === srcVal;
|
|
25
|
+
}
|
|
26
|
+
if (isIterable(srcVal)) {
|
|
27
|
+
srcVal = [...srcVal];
|
|
38
28
|
}
|
|
39
|
-
return
|
|
29
|
+
return (x, y) => equiv(img.getAtUnsafe(x, y), srcVal);
|
|
40
30
|
};
|
package/index.d.ts
CHANGED
|
@@ -1,6 +1,10 @@
|
|
|
1
|
+
export * from "./api.js";
|
|
1
2
|
export * from "./checks.js";
|
|
2
3
|
export * from "./circle.js";
|
|
3
4
|
export * from "./flood-fill.js";
|
|
4
5
|
export * from "./line.js";
|
|
6
|
+
export * from "./poly.js";
|
|
7
|
+
export * from "./polyline.js";
|
|
5
8
|
export * from "./rect.js";
|
|
9
|
+
export * from "./shader.js";
|
|
6
10
|
//# sourceMappingURL=index.d.ts.map
|
package/index.js
CHANGED
|
@@ -1,5 +1,9 @@
|
|
|
1
|
+
export * from "./api.js";
|
|
1
2
|
export * from "./checks.js";
|
|
2
3
|
export * from "./circle.js";
|
|
3
4
|
export * from "./flood-fill.js";
|
|
4
5
|
export * from "./line.js";
|
|
6
|
+
export * from "./poly.js";
|
|
7
|
+
export * from "./polyline.js";
|
|
5
8
|
export * from "./rect.js";
|
|
9
|
+
export * from "./shader.js";
|
package/line.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { Fn, IGrid2D, TypedArray } from "@thi.ng/api";
|
|
2
|
-
|
|
3
|
-
export declare const
|
|
2
|
+
import type { Shader2D } from "./api.js";
|
|
3
|
+
export declare const drawLine: <T extends any[] | TypedArray, P>(grid: IGrid2D<T, P>, x1: number, y1: number, x2: number, y2: number, val: P | Shader2D<P>) => IGrid2D<T, P>;
|
|
4
|
+
export declare const traceLine: (grid: IGrid2D<any, any>, x1: number, y1: number, x2: number, y2: number, fn: Fn<number[], void>) => IGrid2D<any, any>;
|
|
4
5
|
//# sourceMappingURL=line.d.ts.map
|
package/line.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { lineClipped } from "@thi.ng/grid-iterators/line";
|
|
2
|
-
import {
|
|
3
|
-
export const drawLine = (grid, x1, y1, x2, y2, val) =>
|
|
4
|
-
export const
|
|
5
|
-
const pts = lineClipped(x1, y1, x2, y2, 0, 0, grid.
|
|
2
|
+
import { __draw2D } from "./draw.js";
|
|
3
|
+
export const drawLine = (grid, x1, y1, x2, y2, val) => __draw2D(lineClipped(x1, y1, x2, y2, 0, 0, grid.size[0], grid.size[1]), grid, val);
|
|
4
|
+
export const traceLine = (grid, x1, y1, x2, y2, fn) => {
|
|
5
|
+
const pts = lineClipped(x1, y1, x2, y2, 0, 0, grid.size[0], grid.size[1]);
|
|
6
6
|
if (pts) {
|
|
7
7
|
for (let p of pts)
|
|
8
8
|
fn(p);
|
package/package.json
CHANGED
|
@@ -1,102 +1,122 @@
|
|
|
1
1
|
{
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
2
|
+
"name": "@thi.ng/rasterize",
|
|
3
|
+
"version": "0.3.2",
|
|
4
|
+
"description": "2D shape drawing & rasterization",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"module": "./index.js",
|
|
7
|
+
"typings": "./index.d.ts",
|
|
8
|
+
"sideEffects": false,
|
|
9
|
+
"repository": {
|
|
10
|
+
"type": "git",
|
|
11
|
+
"url": "https://github.com/thi-ng/umbrella.git"
|
|
12
|
+
},
|
|
13
|
+
"homepage": "https://github.com/thi-ng/umbrella/tree/master/packages/rasterize#readme",
|
|
14
|
+
"funding": [
|
|
15
|
+
{
|
|
16
|
+
"type": "github",
|
|
17
|
+
"url": "https://github.com/sponsors/postspectacular"
|
|
12
18
|
},
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
"
|
|
25
|
-
"
|
|
26
|
-
"
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
19
|
+
{
|
|
20
|
+
"type": "patreon",
|
|
21
|
+
"url": "https://patreon.com/thing_umbrella"
|
|
22
|
+
}
|
|
23
|
+
],
|
|
24
|
+
"author": "Karsten Schmidt <k+npm@thi.ng>",
|
|
25
|
+
"license": "Apache-2.0",
|
|
26
|
+
"scripts": {
|
|
27
|
+
"build": "yarn clean && tsc --declaration",
|
|
28
|
+
"clean": "rimraf '*.js' '*.d.ts' '*.map' doc",
|
|
29
|
+
"doc": "typedoc --excludePrivate --excludeInternal --out doc src/index.ts",
|
|
30
|
+
"doc:ae": "mkdir -p .ae/doc .ae/temp && api-extractor run --local --verbose",
|
|
31
|
+
"doc:readme": "yarn doc:stats && tools:readme",
|
|
32
|
+
"doc:stats": "tools:module-stats",
|
|
33
|
+
"pub": "yarn npm publish --access public",
|
|
34
|
+
"test": "testament test"
|
|
35
|
+
},
|
|
36
|
+
"dependencies": {
|
|
37
|
+
"@thi.ng/api": "^8.3.2",
|
|
38
|
+
"@thi.ng/checks": "^3.1.2",
|
|
39
|
+
"@thi.ng/equiv": "^2.1.2",
|
|
40
|
+
"@thi.ng/grid-iterators": "^2.2.2",
|
|
41
|
+
"@thi.ng/random": "^3.2.2",
|
|
42
|
+
"@thi.ng/transducers": "^8.1.2"
|
|
43
|
+
},
|
|
44
|
+
"devDependencies": {
|
|
45
|
+
"@microsoft/api-extractor": "^7.18.19",
|
|
46
|
+
"@thi.ng/testament": "^0.2.2",
|
|
47
|
+
"rimraf": "^3.0.2",
|
|
48
|
+
"tools": "^0.0.1",
|
|
49
|
+
"typedoc": "^0.22.9",
|
|
50
|
+
"typescript": "^4.5.2"
|
|
51
|
+
},
|
|
52
|
+
"keywords": [
|
|
53
|
+
"2d",
|
|
54
|
+
"bitmap",
|
|
55
|
+
"circle",
|
|
56
|
+
"clipping",
|
|
57
|
+
"draw",
|
|
58
|
+
"floodfill",
|
|
59
|
+
"grid",
|
|
60
|
+
"line",
|
|
61
|
+
"pattern",
|
|
62
|
+
"shape",
|
|
63
|
+
"rect",
|
|
64
|
+
"typescript"
|
|
65
|
+
],
|
|
66
|
+
"publishConfig": {
|
|
67
|
+
"access": "public"
|
|
68
|
+
},
|
|
69
|
+
"browser": {
|
|
70
|
+
"process": false,
|
|
71
|
+
"setTimeout": false
|
|
72
|
+
},
|
|
73
|
+
"engines": {
|
|
74
|
+
"node": ">=14"
|
|
75
|
+
},
|
|
76
|
+
"files": [
|
|
77
|
+
"*.js",
|
|
78
|
+
"*.d.ts"
|
|
79
|
+
],
|
|
80
|
+
"exports": {
|
|
81
|
+
".": {
|
|
82
|
+
"import": "./index.js"
|
|
35
83
|
},
|
|
36
|
-
"
|
|
37
|
-
|
|
38
|
-
"@thi.ng/grid-iterators": "^2.1.1",
|
|
39
|
-
"@thi.ng/transducers": "^8.0.7"
|
|
84
|
+
"./api": {
|
|
85
|
+
"import": "./api.js"
|
|
40
86
|
},
|
|
41
|
-
"
|
|
42
|
-
|
|
87
|
+
"./checks": {
|
|
88
|
+
"import": "./checks.js"
|
|
43
89
|
},
|
|
44
|
-
"
|
|
45
|
-
|
|
46
|
-
"bitmap",
|
|
47
|
-
"circle",
|
|
48
|
-
"clipping",
|
|
49
|
-
"draw",
|
|
50
|
-
"floodfill",
|
|
51
|
-
"grid",
|
|
52
|
-
"line",
|
|
53
|
-
"pattern",
|
|
54
|
-
"shape",
|
|
55
|
-
"rect",
|
|
56
|
-
"typescript"
|
|
57
|
-
],
|
|
58
|
-
"publishConfig": {
|
|
59
|
-
"access": "public"
|
|
90
|
+
"./circle": {
|
|
91
|
+
"import": "./circle.js"
|
|
60
92
|
},
|
|
61
|
-
"
|
|
62
|
-
|
|
63
|
-
"setTimeout": false
|
|
93
|
+
"./flood-fill": {
|
|
94
|
+
"import": "./flood-fill.js"
|
|
64
95
|
},
|
|
65
|
-
"
|
|
66
|
-
|
|
96
|
+
"./line": {
|
|
97
|
+
"import": "./line.js"
|
|
67
98
|
},
|
|
68
|
-
"
|
|
69
|
-
|
|
70
|
-
"*.d.ts"
|
|
71
|
-
],
|
|
72
|
-
"exports": {
|
|
73
|
-
".": {
|
|
74
|
-
"import": "./index.js"
|
|
75
|
-
},
|
|
76
|
-
"./checks": {
|
|
77
|
-
"import": "./checks.js"
|
|
78
|
-
},
|
|
79
|
-
"./circle": {
|
|
80
|
-
"import": "./circle.js"
|
|
81
|
-
},
|
|
82
|
-
"./flood-fill": {
|
|
83
|
-
"import": "./flood-fill.js"
|
|
84
|
-
},
|
|
85
|
-
"./line": {
|
|
86
|
-
"import": "./line.js"
|
|
87
|
-
},
|
|
88
|
-
"./rect": {
|
|
89
|
-
"import": "./rect.js"
|
|
90
|
-
}
|
|
99
|
+
"./poly": {
|
|
100
|
+
"import": "./poly.js"
|
|
91
101
|
},
|
|
92
|
-
"
|
|
93
|
-
|
|
94
|
-
"grid-iterators",
|
|
95
|
-
"pixel",
|
|
96
|
-
"text-canvas"
|
|
97
|
-
],
|
|
98
|
-
"status": "alpha",
|
|
99
|
-
"year": 2021
|
|
102
|
+
"./polyline": {
|
|
103
|
+
"import": "./polyline.js"
|
|
100
104
|
},
|
|
101
|
-
"
|
|
102
|
-
|
|
105
|
+
"./rect": {
|
|
106
|
+
"import": "./rect.js"
|
|
107
|
+
},
|
|
108
|
+
"./shader": {
|
|
109
|
+
"import": "./shader.js"
|
|
110
|
+
}
|
|
111
|
+
},
|
|
112
|
+
"thi.ng": {
|
|
113
|
+
"related": [
|
|
114
|
+
"grid-iterators",
|
|
115
|
+
"pixel",
|
|
116
|
+
"text-canvas"
|
|
117
|
+
],
|
|
118
|
+
"status": "alpha",
|
|
119
|
+
"year": 2021
|
|
120
|
+
},
|
|
121
|
+
"gitHead": "e8a7c2a40191b391cef182c2978e5a6c85987a87\n"
|
|
122
|
+
}
|
package/poly.d.ts
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { IGrid2D, TypedArray } from "@thi.ng/api";
|
|
2
|
+
import type { Shader2D } from "./api.js";
|
|
3
|
+
/**
|
|
4
|
+
* Draws a filled polygon (simple, no holes) into given grid. Each grid cell's
|
|
5
|
+
* value is obtained from user supplied shader function which will be called
|
|
6
|
+
* with the pixel's `x,y` coords.
|
|
7
|
+
*
|
|
8
|
+
* Based on Efficient Polygon Fill Algorithm by Darel Rex Finley
|
|
9
|
+
* http://alienryderflex.com/polygon_fill/
|
|
10
|
+
*
|
|
11
|
+
* Bounds calculation and clipping added by Karsten Schmidt
|
|
12
|
+
*
|
|
13
|
+
* @param grid
|
|
14
|
+
* @param pts
|
|
15
|
+
* @param val
|
|
16
|
+
*/
|
|
17
|
+
export declare const fillPoly: <T extends any[] | TypedArray, P>(grid: IGrid2D<T, P>, pts: number[][], val: P | Shader2D<P>) => void;
|
|
18
|
+
//# sourceMappingURL=poly.d.ts.map
|
package/poly.js
ADDED
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { ensureShader2D } from "./checks.js";
|
|
2
|
+
/**
|
|
3
|
+
* Draws a filled polygon (simple, no holes) into given grid. Each grid cell's
|
|
4
|
+
* value is obtained from user supplied shader function which will be called
|
|
5
|
+
* with the pixel's `x,y` coords.
|
|
6
|
+
*
|
|
7
|
+
* Based on Efficient Polygon Fill Algorithm by Darel Rex Finley
|
|
8
|
+
* http://alienryderflex.com/polygon_fill/
|
|
9
|
+
*
|
|
10
|
+
* Bounds calculation and clipping added by Karsten Schmidt
|
|
11
|
+
*
|
|
12
|
+
* @param grid
|
|
13
|
+
* @param pts
|
|
14
|
+
* @param val
|
|
15
|
+
*/
|
|
16
|
+
export const fillPoly = (grid, pts, val) => {
|
|
17
|
+
const numP = pts.length;
|
|
18
|
+
const [width, height] = grid.size;
|
|
19
|
+
const shader = ensureShader2D(val);
|
|
20
|
+
let minX = Infinity;
|
|
21
|
+
let minY = Infinity;
|
|
22
|
+
let maxX = -Infinity;
|
|
23
|
+
let maxY = -Infinity;
|
|
24
|
+
for (let i = numP; i-- > 0;) {
|
|
25
|
+
const { 0: x, 1: y } = pts[i];
|
|
26
|
+
minX = Math.min(minX, x);
|
|
27
|
+
maxX = Math.max(maxX, x);
|
|
28
|
+
minY = Math.min(minY, y);
|
|
29
|
+
maxY = Math.max(maxY, y);
|
|
30
|
+
}
|
|
31
|
+
minX = Math.max(minX | 0, 0);
|
|
32
|
+
maxX = Math.min(maxX | 0, width - 1);
|
|
33
|
+
minY = Math.max(minY | 0, 0);
|
|
34
|
+
maxY = Math.min(maxY | 0, height - 1);
|
|
35
|
+
if (minX >= width || maxX < 0 || minY >= height || maxY < 0)
|
|
36
|
+
return;
|
|
37
|
+
let i = 0;
|
|
38
|
+
let k = 0;
|
|
39
|
+
let j;
|
|
40
|
+
const isec = [];
|
|
41
|
+
for (let y = Math.max(0, minY); y <= maxY; y++) {
|
|
42
|
+
i = k = 0;
|
|
43
|
+
j = numP - 1;
|
|
44
|
+
isec.length = 0;
|
|
45
|
+
for (; i < numP; j = i, i++) {
|
|
46
|
+
const { 0: pix, 1: piy } = pts[i];
|
|
47
|
+
const { 0: pjx, 1: pjy } = pts[j];
|
|
48
|
+
if ((piy < y && pjy >= y) || (pjy < y && piy >= y)) {
|
|
49
|
+
isec[k++] = (pix + ((y - piy) / (pjy - piy)) * (pjx - pix)) | 0;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
isec.sort((a, b) => a - b);
|
|
53
|
+
for (i = 0; i < k; i += 2) {
|
|
54
|
+
let x1 = isec[i];
|
|
55
|
+
if (x1 > maxX)
|
|
56
|
+
break;
|
|
57
|
+
let x2 = isec[i + 1];
|
|
58
|
+
if (x2 > minX) {
|
|
59
|
+
x1 < minX && (x1 = minX);
|
|
60
|
+
x2 > maxX && (x2 = maxX);
|
|
61
|
+
for (let x = x1; x <= x2; x++) {
|
|
62
|
+
grid.setAtUnsafe(x, y, shader(x, y));
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
};
|
package/polyline.d.ts
ADDED
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { IGrid2D, TypedArray } from "@thi.ng/api";
|
|
2
|
+
import type { Shader2D } from "./api.js";
|
|
3
|
+
export declare const drawPolyLine: <T extends any[] | TypedArray, P>(grid: IGrid2D<T, P>, pts: number[][], val: P | Shader2D<P>, closed?: boolean) => void;
|
|
4
|
+
//# sourceMappingURL=polyline.d.ts.map
|
package/polyline.js
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { ensureShader2D } from "./checks.js";
|
|
2
|
+
import { drawLine } from "./line.js";
|
|
3
|
+
export const drawPolyLine = (grid, pts, val, closed = false) => {
|
|
4
|
+
val = ensureShader2D(val);
|
|
5
|
+
const n = pts.length;
|
|
6
|
+
let [i, j] = closed ? [0, n - 1] : [1, 0];
|
|
7
|
+
for (; i < n; j = i, i++) {
|
|
8
|
+
const a = pts[j];
|
|
9
|
+
const b = pts[i];
|
|
10
|
+
drawLine(grid, a[0], a[1], b[0], b[1], val);
|
|
11
|
+
}
|
|
12
|
+
};
|
package/rect.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
1
|
import type { IGrid2D, TypedArray } from "@thi.ng/api";
|
|
2
|
-
|
|
2
|
+
import type { Shader2D } from "./api.js";
|
|
3
|
+
export declare const drawRect: <T extends any[] | TypedArray, P>(grid: IGrid2D<T, P>, x: number, y: number, w: number, h: number, val: P | Shader2D<P>, fill?: boolean) => IGrid2D<T, P>;
|
|
3
4
|
//# sourceMappingURL=rect.d.ts.map
|
package/rect.js
CHANGED
|
@@ -1,9 +1,15 @@
|
|
|
1
|
+
import { isPrimitive } from "@thi.ng/checks";
|
|
1
2
|
import { hlineClipped, vlineClipped } from "@thi.ng/grid-iterators/hvline";
|
|
2
3
|
import { rows2d } from "@thi.ng/grid-iterators/rows";
|
|
3
4
|
import { concat } from "@thi.ng/transducers/concat";
|
|
4
|
-
import {
|
|
5
|
+
import { ensureShader2D } from "./checks.js";
|
|
6
|
+
import { __draw2D } from "./draw.js";
|
|
5
7
|
export const drawRect = (grid, x, y, w, h, val, fill = false) => {
|
|
6
|
-
|
|
8
|
+
x |= 0;
|
|
9
|
+
y |= 0;
|
|
10
|
+
w |= 0;
|
|
11
|
+
h |= 0;
|
|
12
|
+
const { data, offset, size: [width, height], stride: [sx, sy], } = grid;
|
|
7
13
|
if (fill) {
|
|
8
14
|
if (x < 0) {
|
|
9
15
|
w += x;
|
|
@@ -13,10 +19,23 @@ export const drawRect = (grid, x, y, w, h, val, fill = false) => {
|
|
|
13
19
|
h += y;
|
|
14
20
|
y = 0;
|
|
15
21
|
}
|
|
16
|
-
|
|
17
|
-
|
|
22
|
+
const pts = rows2d(Math.min(w, width - x), Math.min(h, height - y));
|
|
23
|
+
const shader = ensureShader2D(val);
|
|
24
|
+
if (isPrimitive(val)) {
|
|
25
|
+
for (let { 0: xx, 1: yy } of pts) {
|
|
26
|
+
xx += x;
|
|
27
|
+
yy += y;
|
|
28
|
+
data[offset + xx * sx + yy * sy] = shader(xx, yy);
|
|
29
|
+
}
|
|
18
30
|
}
|
|
19
|
-
|
|
31
|
+
else {
|
|
32
|
+
for (let { 0: xx, 1: yy } of pts) {
|
|
33
|
+
xx += x;
|
|
34
|
+
yy += y;
|
|
35
|
+
grid.setAtUnsafe(xx, yy, shader(xx, yy));
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
return grid;
|
|
20
39
|
}
|
|
21
|
-
return
|
|
40
|
+
return __draw2D(concat(hlineClipped(x, y, w, 0, 0, width, height), vlineClipped(x, y + 1, h - 2, 0, 0, width, height), hlineClipped(x, y + h - 1, w, 0, 0, width, height), vlineClipped(x + w - 1, y + 1, h - 2, 0, 0, width, height)), grid, val);
|
|
22
41
|
};
|
package/shader.d.ts
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { IGrid2D, TypedArray } from "@thi.ng/api";
|
|
2
|
+
import type { IRandom } from "@thi.ng/random";
|
|
3
|
+
import type { Shader2D } from "./api.js";
|
|
4
|
+
export declare const defPattern: <T extends any[] | TypedArray, P>(pattern: IGrid2D<T, P>) => Shader2D<P>;
|
|
5
|
+
export interface StripeShaderOpts<T> {
|
|
6
|
+
dir: "h" | "v" | "d";
|
|
7
|
+
size: number;
|
|
8
|
+
sizeA: number;
|
|
9
|
+
a: T;
|
|
10
|
+
b: T;
|
|
11
|
+
}
|
|
12
|
+
export declare const defStripes: <T = number>({ dir, size, sizeA, a, b, }: StripeShaderOpts<T>) => Shader2D<T>;
|
|
13
|
+
export interface RandomShaderOpts<T> {
|
|
14
|
+
probability?: number;
|
|
15
|
+
rnd?: IRandom;
|
|
16
|
+
a: T;
|
|
17
|
+
b: T;
|
|
18
|
+
}
|
|
19
|
+
export declare const defNoise: <T = number>(opts: RandomShaderOpts<T>) => Shader2D<T>;
|
|
20
|
+
//# sourceMappingURL=shader.d.ts.map
|
package/shader.js
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { SYSTEM } from "@thi.ng/random/system";
|
|
2
|
+
export const defPattern = (pattern) => {
|
|
3
|
+
const [w, h] = pattern.size;
|
|
4
|
+
return (x, y) => pattern.getAtUnsafe(x % w, y % h);
|
|
5
|
+
};
|
|
6
|
+
export const defStripes = ({ dir, size, sizeA, a, b, }) => dir === "h"
|
|
7
|
+
? (x) => (x % size < sizeA ? a : b)
|
|
8
|
+
: dir === "v"
|
|
9
|
+
? (_, y) => (y % size < sizeA ? a : b)
|
|
10
|
+
: (x, y) => ((x + y) % size < sizeA ? a : b);
|
|
11
|
+
export const defNoise = (opts) => {
|
|
12
|
+
const { probability, rnd, a, b } = {
|
|
13
|
+
probability: 0.5,
|
|
14
|
+
rnd: SYSTEM,
|
|
15
|
+
...opts,
|
|
16
|
+
};
|
|
17
|
+
return () => (rnd.float() < probability ? a : b);
|
|
18
|
+
};
|