@thi.ng/geom-axidraw 0.3.12 → 0.5.0

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  # Change Log
2
2
 
3
- - **Last updated**: 2023-03-14T13:27:19Z
3
+ - **Last updated**: 2023-03-22T22:24:21Z
4
4
  - **Generator**: [thi.ng/monopub](https://thi.ng/monopub)
5
5
 
6
6
  All notable changes to this project will be documented in this file.
@@ -9,6 +9,29 @@ See [Conventional Commits](https://conventionalcommits.org/) for commit guidelin
9
9
  **Note:** Unlisted _patch_ versions only involve non-code or otherwise excluded changes
10
10
  and/or version bumps of transitive dependencies.
11
11
 
12
+ ## [0.5.0](https://github.com/thi-ng/umbrella/tree/@thi.ng/geom-axidraw@0.5.0) (2023-03-22)
13
+
14
+ #### 🚀 Features
15
+
16
+ - add support for new draw commands ([e5e994c](https://github.com/thi-ng/umbrella/commit/e5e994c))
17
+ - update asGeometry() to handle new move commands
18
+
19
+ ## [0.4.0](https://github.com/thi-ng/umbrella/tree/@thi.ng/geom-axidraw@0.4.0) (2023-03-19)
20
+
21
+ #### 🚀 Features
22
+
23
+ - add InterleaveOpts for point clouds ([78012a0](https://github.com/thi-ng/umbrella/commit/78012a0))
24
+ - add InterleaveOpts & docs
25
+ - update AxiDrawAttribs
26
+ - update point cloud processing to support command sequence interleaving
27
+ - add interleave opts support for shape groups ([57783ff](https://github.com/thi-ng/umbrella/commit/57783ff))
28
+ - update asAxiDraw() impl for shape groups
29
+
30
+ #### ♻️ Refactoring
31
+
32
+ - update draw command handling ([18cd5bc](https://github.com/thi-ng/umbrella/commit/18cd5bc))
33
+ - update InterleaveOpts ([0866f9f](https://github.com/thi-ng/umbrella/commit/0866f9f))
34
+
12
35
  ## [0.3.0](https://github.com/thi-ng/umbrella/tree/@thi.ng/geom-axidraw@0.3.0) (2023-01-10)
13
36
 
14
37
  #### 🚀 Features
package/README.md CHANGED
@@ -18,6 +18,7 @@ This project is part of the
18
18
  - [Basic usage & examples](#basic-usage--examples)
19
19
  - [Interpolated polygons](#interpolated-polygons)
20
20
  - [Clipping](#clipping)
21
+ - [Supporting custom drawing tools](#supporting-custom-drawing-tools)
21
22
  - [Status](#status)
22
23
  - [Related packages](#related-packages)
23
24
  - [Installation](#installation)
@@ -43,10 +44,10 @@ package is responsible for the actual plotter output...
43
44
  | circle | circle<sup>(1)</sup> |
44
45
  | cubic | cubic bezier segment<sup>(1)</sup> |
45
46
  | ellipse | ellipse<sup>(1)</sup> |
46
- | group | shape group (possibly nested) |
47
+ | group | shape group (possibly nested)<sup>(3)</sup> |
47
48
  | line | line segment<sup>(2)</sup> |
48
49
  | path | single outline only, no holes |
49
- | points | point cloud (stippling) |
50
+ | points | point cloud (stippling)<sup>(3)</sup> |
50
51
  | polyline | polyline (any number of vertices)<sup>(2)</sup> |
51
52
  | polygon | simple polygon, no holes<sup>(2)</sup> |
52
53
  | quad | arbitrary 4-gon<sup>(2)</sup> |
@@ -56,6 +57,7 @@ package is responsible for the actual plotter output...
56
57
 
57
58
  - <sup>(1)</sup> always interpolated/sampled
58
59
  - <sup>(2)</sup> only interpolated if forced via attrib
60
+ - <sup>(3)</sup> supports command sequence interleaving
59
61
 
60
62
  ### AxiDraw specific shape attributes
61
63
 
@@ -81,6 +83,8 @@ any package-specific attribs must be stored under the `__axi` key:
81
83
  - `sort`: Ordering function (in lieu of full path planning/optimization, which
82
84
  is planned for a later stage). For shapes other than `points()`, order of
83
85
  appearance is used by default.
86
+ - `interleave`: Currently only supported for point clouds. See [Supporting
87
+ custom drawing tools](#supporting-custom-drawing-tools).
84
88
 
85
89
  ```ts
86
90
  // a circle which will be plotted at only 10% of the normal speed
@@ -220,6 +224,55 @@ import { writeFileSync } from "fs";
220
224
  })();
221
225
  ```
222
226
 
227
+ ### Supporting custom drawing tools
228
+
229
+ AxiDraw (and other pen plotters) are not restricted to just using pens, but can
230
+ be used with all sorts of custom drawing tools, some of which (like paint
231
+ brushes) require regular "refills" every N strokes/dots. For that reason, some
232
+ shape types (currently **only** shape groups and point clouds) are supporting
233
+ config & behavior options for interleaving their normal shape command sequence
234
+ with additional tool-specific arbitrary utility command sequences (e.g. to
235
+ regularly dip a brush into a paint pot/palette).
236
+
237
+ ```ts tangle:export/readme-interleave.ts
238
+ import { AxiDraw, COMMENT, dip, MOVE } from "@thi.ng/axidraw";
239
+ import { circle, points, vertices } from "@thi.ng/geom";
240
+ import { asAxiDraw } from "@thi.ng/geom-axidraw";
241
+
242
+ (async () => {
243
+ // create point cloud container
244
+ const pts = points(
245
+ // using 24 points on a circle w/ origin @ 150,150, radius=100
246
+ vertices(circle([150, 150], 100), 24),
247
+ { __axi: {
248
+ // use command interleaving
249
+ interleave: {
250
+ // every 5 points/dots
251
+ num: 5,
252
+ // insert these draw commands:
253
+ // (this function is being re-called every `num` points and
254
+ // can produce different commands to insert each time...)
255
+ commands: (n) => [
256
+ // no-op command, but will be logged during plotting
257
+ COMMENT(`--- refill brush (@ ${n} points) ---`),
258
+ // move to XY pos (i.e. position of paint reservoir)
259
+ MOVE([10,50]),
260
+ // dip the brush 3x times down & up (each time wait 200ms whilst down)
261
+ // (dip() creates a cmd sequence, so need to use the spread operator `...` here)
262
+ ...dip(3, { downDelay: 200 }),
263
+ // (...and then drawing continues w/ next 5 points)
264
+ ]
265
+ }
266
+ }
267
+ });
268
+
269
+ // actually connect & send to plotter
270
+ const axi = new AxiDraw();
271
+ await axi.connect();
272
+ await axi.draw(asAxiDraw(pts));
273
+ })();
274
+ ```
275
+
223
276
  ## Status
224
277
 
225
278
  **ALPHA** - bleeding edge / work-in-progress
@@ -250,7 +303,7 @@ For Node.js REPL:
250
303
  const geomAxidraw = await import("@thi.ng/geom-axidraw");
251
304
  ```
252
305
 
253
- Package sizes (brotli'd, pre-treeshake): ESM: 1.32 KB
306
+ Package sizes (brotli'd, pre-treeshake): ESM: 1.50 KB
254
307
 
255
308
  ## Dependencies
256
309
 
package/api.d.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  import type { Fn } from "@thi.ng/api";
2
+ import type { DrawCommand } from "@thi.ng/axidraw";
2
3
  import type { IShape, SamplingOpts } from "@thi.ng/geom-api";
3
4
  import type { ReadonlyVec } from "@thi.ng/vectors";
4
5
  /**
@@ -58,6 +59,11 @@ export interface AxiDrawAttribs {
58
59
  * detail test runs.
59
60
  */
60
61
  skip: number;
62
+ /**
63
+ * Currently only supported for shape groups and point clouds. See
64
+ * {@link InterleaveOpts} for details.
65
+ */
66
+ interleave: InterleaveOpts;
61
67
  }
62
68
  export interface AsAxiDrawOpts {
63
69
  /**
@@ -76,6 +82,37 @@ export interface AsAxiDrawOpts {
76
82
  */
77
83
  clip: ReadonlyVec[];
78
84
  }
85
+ /**
86
+ * Config & behavior options for interleaving the normal shape command sequence
87
+ * with tool-specific arbitrary utility command sequences (e.g. to regularly dip
88
+ * a brush into a paint pot/palette).
89
+ */
90
+ export interface InterleaveOpts {
91
+ /**
92
+ * Number of elements after which to insert the interleave command sequence
93
+ */
94
+ num: number;
95
+ /**
96
+ * Single arg function which is called every `num` elements (with the count
97
+ * of elements already processed given as arg) and each time yielding a
98
+ * [`DrawCommand`](https://docs.thi.ng/umbrella/axidraw/types/DrawCommand.html)
99
+ * sequence, which will be inserted as-is into the generated main command
100
+ * sequence of the currently processed shape.
101
+ *
102
+ * @param num
103
+ */
104
+ commands: Fn<number, Iterable<DrawCommand>>;
105
+ /**
106
+ * If true (default), call the given `commands` fn at the beginning of the
107
+ * shape processing (with arg=0).
108
+ */
109
+ start?: boolean;
110
+ /**
111
+ * If true (default: false), call the given `commands` fn at the end of the
112
+ * shape processing (with arg=number of points/elements in the shape).
113
+ */
114
+ end?: boolean;
115
+ }
79
116
  export type PointOrdering = Fn<ReadonlyVec[], Iterable<ReadonlyVec>>;
80
117
  export type ShapeOrdering = Fn<IShape[], Iterable<IShape>>;
81
118
  //# sourceMappingURL=api.d.ts.map
package/as-axidraw.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { DrawCommand } from "@thi.ng/axidraw/api";
1
+ import type { DrawCommand } from "@thi.ng/axidraw/api";
2
2
  import type { MultiFn1O } from "@thi.ng/defmulti";
3
3
  import type { IShape } from "@thi.ng/geom-api";
4
4
  import type { AsAxiDrawOpts } from "./api.js";
package/as-axidraw.js CHANGED
@@ -1,4 +1,4 @@
1
- import { UP } from "@thi.ng/axidraw/api";
1
+ import { DOWN, MOVE, UP } from "@thi.ng/axidraw/commands";
2
2
  import { polyline } from "@thi.ng/axidraw/polyline";
3
3
  import { defmulti } from "@thi.ng/defmulti/defmulti";
4
4
  import { clipPolylinePoly } from "@thi.ng/geom-clip-line/clip-poly";
@@ -69,24 +69,42 @@ export const asAxiDraw = defmulti(__dispatch, {
69
69
  group: ($, opts) => __group($, opts),
70
70
  });
71
71
  function* __group($, opts) {
72
- const { skip, sort } = __axiAttribs($.attribs);
73
- const sopts = __sampleAttribs(opts?.samples, $.attribs);
72
+ const $sampleOpts = __sampleAttribs(opts?.samples, $.attribs);
73
+ const { skip, sort, interleave } = __axiAttribs($.attribs);
74
74
  const children = skip ? [...takeNth(skip + 1, $.children)] : $.children;
75
- const childrenIter = sort ? sort(children) : children;
76
- for (let child of childrenIter) {
77
- const shape = applyTransforms(child);
78
- shape.attribs = {
79
- ...$.attribs,
80
- ...shape.attribs,
81
- __samples: __sampleAttribs(sopts, shape.attribs),
82
- };
83
- yield* asAxiDraw(shape, opts);
75
+ function* emitChunk(chunk) {
76
+ const iter = sort ? sort(chunk) : chunk;
77
+ for (let child of iter) {
78
+ const shape = applyTransforms(child);
79
+ shape.attribs = {
80
+ ...$.attribs,
81
+ ...shape.attribs,
82
+ __samples: __sampleAttribs($sampleOpts, shape.attribs),
83
+ };
84
+ yield* asAxiDraw(shape, opts);
85
+ }
86
+ }
87
+ if (interleave) {
88
+ const { num, commands } = interleave;
89
+ if (interleave.start !== false)
90
+ yield* commands(0);
91
+ for (let i = 0, n = children.length; i < n;) {
92
+ yield* emitChunk(children.slice(i, i + num));
93
+ i += num;
94
+ if (i < n)
95
+ yield* commands(i);
96
+ }
97
+ if (interleave.end)
98
+ yield* interleave.commands(children.length);
99
+ }
100
+ else {
101
+ yield* emitChunk(children);
84
102
  }
85
103
  }
86
104
  function* __points(pts, attribs, opts) {
87
105
  if (!pts.length)
88
106
  return;
89
- const { clip, delayDown, delayUp, down, skip, speed, sort } = {
107
+ const { clip, delayDown, delayUp, down, skip, speed, sort, interleave } = {
90
108
  sort: pointsByNearestNeighbor(),
91
109
  ...__axiAttribs(attribs),
92
110
  };
@@ -99,18 +117,34 @@ function* __points(pts, attribs, opts) {
99
117
  if (skip) {
100
118
  pts = [...takeNth(skip + 1, pts)];
101
119
  }
102
- yield UP;
103
- if (down != undefined)
104
- yield ["pen", down];
105
- for (let p of sort ? sort(pts) : pts) {
106
- yield* [
107
- ["m", p, speed],
108
- ["d", delayDown],
109
- ["u", delayUp],
110
- ];
120
+ function* emitChunk($pts) {
121
+ if (down != undefined)
122
+ yield ["pen", down];
123
+ for (let p of sort ? sort($pts) : $pts) {
124
+ yield MOVE(p, speed);
125
+ yield DOWN(delayDown);
126
+ yield UP(delayUp);
127
+ }
128
+ if (down != undefined)
129
+ yield ["pen"];
130
+ }
131
+ yield UP();
132
+ if (interleave) {
133
+ const { num, commands } = interleave;
134
+ if (interleave.start !== false)
135
+ yield* commands(0);
136
+ for (let i = 0, n = pts.length; i < n;) {
137
+ yield* emitChunk(pts.slice(i, i + num));
138
+ i += num;
139
+ if (i < n)
140
+ yield* commands(i);
141
+ }
142
+ if (interleave.end)
143
+ yield* interleave.commands(pts.length);
144
+ }
145
+ else {
146
+ yield* emitChunk(pts);
111
147
  }
112
- if (down != undefined)
113
- yield ["pen"];
114
148
  }
115
149
  function* __polyline(pts, attribs, opts) {
116
150
  if (!pts.length)
package/as-geometry.js CHANGED
@@ -1,7 +1,8 @@
1
1
  import { group } from "@thi.ng/geom/group";
2
2
  import { points } from "@thi.ng/geom/points";
3
3
  import { polyline } from "@thi.ng/geom/polyline";
4
- import { copy } from "@thi.ng/vectors";
4
+ import { add2 } from "@thi.ng/vectors/add";
5
+ import { copy } from "@thi.ng/vectors/copy";
5
6
  const DEFAULT_ATTRIBS = {
6
7
  paths: { stroke: "#000" },
7
8
  rapids: { stroke: "#0ff" },
@@ -40,19 +41,24 @@ export const asGeometry = (src, opts = {}) => {
40
41
  let penDown = false;
41
42
  let pts = null;
42
43
  let currPos = [0, 0];
44
+ const $move = (newPos) => {
45
+ if (penDown || opts.rapids) {
46
+ if (!pts)
47
+ pts = [copy(currPos), newPos];
48
+ else
49
+ pts.push(newPos);
50
+ }
51
+ currPos = newPos;
52
+ };
43
53
  for (let cmd of src) {
44
54
  switch (cmd[0]) {
55
+ // absolute
56
+ case "M":
57
+ $move(copy(cmd[1]));
58
+ break;
59
+ // relative
45
60
  case "m":
46
- {
47
- const newPos = copy(cmd[1]);
48
- if (penDown || opts.rapids) {
49
- if (!pts)
50
- pts = [copy(currPos), newPos];
51
- else
52
- pts.push(newPos);
53
- }
54
- currPos = newPos;
55
- }
61
+ $move(add2([], currPos, cmd[1]));
56
62
  break;
57
63
  case "u":
58
64
  if (pts) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@thi.ng/geom-axidraw",
3
- "version": "0.3.12",
3
+ "version": "0.5.0",
4
4
  "description": "Conversion and preparation of thi.ng/geom shapes & shape groups to/from AxiDraw pen plotter draw commands",
5
5
  "type": "module",
6
6
  "module": "./index.js",
@@ -36,16 +36,16 @@
36
36
  "dependencies": {
37
37
  "@thi.ng/api": "^8.7.4",
38
38
  "@thi.ng/arrays": "^2.5.8",
39
- "@thi.ng/axidraw": "^0.5.8",
39
+ "@thi.ng/axidraw": "^1.1.0",
40
40
  "@thi.ng/compare": "^2.1.27",
41
41
  "@thi.ng/defmulti": "^2.1.33",
42
- "@thi.ng/geom": "^4.2.11",
43
- "@thi.ng/geom-accel": "^3.3.8",
44
- "@thi.ng/geom-api": "^3.4.9",
45
- "@thi.ng/geom-clip-line": "^2.3.9",
46
- "@thi.ng/geom-isec": "^2.1.51",
47
- "@thi.ng/transducers": "^8.3.38",
48
- "@thi.ng/vectors": "^7.6.8"
42
+ "@thi.ng/geom": "^4.3.0",
43
+ "@thi.ng/geom-accel": "^3.3.9",
44
+ "@thi.ng/geom-api": "^3.4.10",
45
+ "@thi.ng/geom-clip-line": "^2.3.10",
46
+ "@thi.ng/geom-isec": "^2.1.52",
47
+ "@thi.ng/transducers": "^8.4.0",
48
+ "@thi.ng/vectors": "^7.6.9"
49
49
  },
50
50
  "devDependencies": {
51
51
  "@microsoft/api-extractor": "^7.34.4",
@@ -121,5 +121,5 @@
121
121
  "status": "alpha",
122
122
  "year": 2022
123
123
  },
124
- "gitHead": "cc46c097a3a173fb1ef41f57a858d03037063141\n"
124
+ "gitHead": "5b3d731c0e192c53f65efb4baed97be0e4029a33\n"
125
125
  }