@thi.ng/axidraw 0.5.8 → 1.0.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-19T14:07:45Z
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,38 @@ 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
+ # [1.0.0](https://github.com/thi-ng/umbrella/tree/@thi.ng/axidraw@1.0.0) (2023-03-19)
13
+
14
+ #### 🛑 Breaking changes
15
+
16
+ - add/update command presets ([610f873](https://github.com/thi-ng/umbrella/commit/610f873))
17
+ - BREAKING CHANGE: update DrawCommands and cmd presets
18
+ - update MoveXYCommand to use `"M"`
19
+ - add MoveRelCommand (using `"m"`)
20
+ - add/update AxiDraw.moveTo()/moveRelative()
21
+ - migrate command presets to commands.ts
22
+ - refactor parametric command type presets as functions:
23
+ - PEN(), UP(), DOWN(), MOVE(), MOVE_REL(), WAIT(), COMMENT()
24
+ - add DIP() command sequence gen
25
+
26
+ #### 🚀 Features
27
+
28
+ - add command fns, add COMMENT cmd ([0d64b55](https://github.com/thi-ng/umbrella/commit/0d64b55))
29
+ - add MOVE(), WAIT(), COMMENT()
30
+ - add CommentCommand
31
+ - update AxiDraw.draw() to log comments
32
+ - add disconnect() ([af93177](https://github.com/thi-ng/umbrella/commit/af93177))
33
+ - add disconnect() for ISerial & AxiDraw
34
+ - update MockSerial impl
35
+ - update commands, docs & pkg exports ([1324cb8](https://github.com/thi-ng/umbrella/commit/1324cb8))
36
+ - update dip(), update imports. restructure /src ([b108760](https://github.com/thi-ng/umbrella/commit/b108760))
37
+ - add DipOpts, extend dip() functionality
38
+ - move dip() to own file dip.ts
39
+ - move complete() to commands.ts
40
+ - move registrationMark() to own file registration.ts
41
+ - update all imports
42
+ - update pkg exports map
43
+
12
44
  ## [0.5.0](https://github.com/thi-ng/umbrella/tree/@thi.ng/axidraw@0.5.0) (2023-02-05)
13
45
 
14
46
  #### 🚀 Features
package/README.md CHANGED
@@ -25,6 +25,8 @@ This project is part of the
25
25
  - [Example usage](#example-usage)
26
26
  - [Basics](#basics)
27
27
  - [geom-axidraw example](#geom-axidraw-example)
28
+ - [Available draw commands](#available-draw-commands)
29
+ - [Command sequence generators](#command-sequence-generators)
28
30
  - [Authors](#authors)
29
31
  - [License](#license)
30
32
 
@@ -164,7 +166,7 @@ For Node.js REPL:
164
166
  const axidraw = await import("@thi.ng/axidraw");
165
167
  ```
166
168
 
167
- Package sizes (brotli'd, pre-treeshake): ESM: 2.15 KB
169
+ Package sizes (brotli'd, pre-treeshake): ESM: 2.46 KB
168
170
 
169
171
  ## Dependencies
170
172
 
@@ -259,14 +261,46 @@ import { map, range } from "@thi.ng/transducers";
259
261
 
260
262
  Other selected toots/tweets:
261
263
 
262
- - https://mastodon.thi.ng/@toxi/109490174709589253
263
- - https://mastodon.thi.ng/@toxi/109473655772673067
264
- - https://mastodon.thi.ng/@toxi/109474947869078797
265
- - https://mastodon.thi.ng/@toxi/109483553358349473
266
- - https://mastodon.thi.ng/@toxi/109570540391689321
267
- - https://mastodon.thi.ng/@toxi/109586780630493994
264
+ - [Project announcement](https://mastodon.thi.ng/@toxi/109490174709589253)
265
+ - [Geometry conversion basics](https://mastodon.thi.ng/@toxi/109473655772673067)
266
+ - [Shape group conversion and stippling](https://mastodon.thi.ng/@toxi/109474947869078797)
267
+ - [Per-shape & on-the-fly polyline clipping](https://mastodon.thi.ng/@toxi/109483553358349473)
268
+ - [Bitmap-to-vector conversions & shape sorting](https://mastodon.thi.ng/@toxi/109570540391689321)
269
+ - [Multi-color plotting](https://mastodon.thi.ng/@toxi/109586780630493994)
270
+ - [Using water color & paintbrush](https://mastodon.thi.ng/@toxi/110044424626641749)
268
271
  - more to come...
269
272
 
273
+ ### Available draw commands
274
+
275
+ All
276
+ [`DrawCommand`s](https://docs.thi.ng/umbrella/axidraw/types/DrawCommand.html)
277
+ are expressed as S-expression-like, [thi.ng/hiccup]()-style elements, aka JS
278
+ arrays/tuples of `[command, ...args]`. The following commands are supported. All
279
+ also as predefined constants or factory functions for the parametric ones:
280
+
281
+ | Command | Preset/factory |
282
+ |-----------------------------------|-------------------------------------------------------------------------------------------------------------------------------------|
283
+ | `["comment", msg]` | [`COMMENT`](https://docs.thi.ng/umbrella/axidraw/functions/COMMENT.html) |
284
+ | `["d", delay?]` / `["u", delay?]` | [`DOWN`](https://docs.thi.ng/umbrella/axidraw/functions/DOWN.html) / [`UP`](https://docs.thi.ng/umbrella/axidraw/functions/UP.html) |
285
+ | `["home"]` | `HOME` |
286
+ | `["m", [x,y], speed?]` | [`MOVE_REL`](https://docs.thi.ng/umbrella/axidraw/functions/MOVE_REL.html) |
287
+ | `["M", [x,y], speed?]` | [`MOVE`](https://docs.thi.ng/umbrella/axidraw/functions/MOVE.html) |
288
+ | `["on"]` / `["off"]` | `ON` / `OFF` |
289
+ | `["pen", down, up]` | [`PEN`](https://docs.thi.ng/umbrella/axidraw/functions/PEN.html) |
290
+ | `["reset"]` | `RESET` |
291
+ | `["start"]` | `START` |
292
+ | `["stop"]` | `STOP` |
293
+ | `["w", delay]` | [`WAIT`](https://docs.thi.ng/umbrella/axidraw/functions/WAIT.html) |
294
+
295
+ #### Command sequence generators
296
+
297
+ Additionally, the following command sequence generators are provided (see their docs for code examples):
298
+
299
+ - [`complete`](https://docs.thi.ng/umbrella/axidraw/functions/complete.html)
300
+ - [`dip`](https://docs.thi.ng/umbrella/axidraw/functions/dip.html)
301
+ - [`polyline`](https://docs.thi.ng/umbrella/axidraw/functions/polyline.html)
302
+ - [`registrationMark`](https://docs.thi.ng/umbrella/axidraw/functions/registrationMark.html)
303
+
270
304
  ## Authors
271
305
 
272
306
  - [Karsten Schmidt](https://thi.ng)
package/api.d.ts CHANGED
@@ -23,10 +23,17 @@ export type PenUpDownCommand = ["u" | "d", number?, number?];
23
23
  * Move to abs pos (in worldspace coords, default mm), optional speed factor
24
24
  * (default: 1)
25
25
  */
26
- export type MoveXYCommand = ["m", ReadonlyVec, number?];
26
+ export type MoveXYCommand = ["M", ReadonlyVec, number?];
27
+ /**
28
+ * Move to **relative** pos (based on curr plotter position, im worldspace
29
+ * units, default mm), optional speed factor (default: 1)
30
+ */
31
+ export type MoveRelCommand = ["m", ReadonlyVec, number?];
27
32
  /** Explicit delay (in ms) */
28
33
  export type WaitCommand = ["w", number];
29
- export type DrawCommand = StartCommand | StopCommand | HomeCommand | ResetCommand | MotorCommand | PenConfigCommand | PenUpDownCommand | MoveXYCommand | WaitCommand;
34
+ /** Ignored, but will be logged (if logging enabled) */
35
+ export type CommentCommand = ["comment", string];
36
+ export type DrawCommand = StartCommand | StopCommand | HomeCommand | ResetCommand | MotorCommand | PenConfigCommand | PenUpDownCommand | MoveXYCommand | MoveRelCommand | WaitCommand | CommentCommand;
30
37
  /**
31
38
  * Global plotter drawing configuration. Also see {@link DEFAULT_OPTS}.
32
39
  */
@@ -137,15 +144,6 @@ export interface AxiDrawOpts {
137
144
  */
138
145
  sigint: boolean;
139
146
  }
140
- export declare const START: StartCommand;
141
- export declare const STOP: StopCommand;
142
- export declare const HOME: HomeCommand;
143
- export declare const RESET: ResetCommand;
144
- export declare const PEN: PenConfigCommand;
145
- export declare const UP: PenUpDownCommand;
146
- export declare const DOWN: PenUpDownCommand;
147
- export declare const ON: MotorCommand;
148
- export declare const OFF: MotorCommand;
149
147
  /**
150
148
  * FSM state enum for (interactive) control for processing of drawing commands.
151
149
  * See {@link AxiDraw.draw} and {@link AxiDrawControl} for details.
@@ -245,6 +243,7 @@ export interface SerialConnection {
245
243
  ctor(path: string, baudRate: number): ISerial;
246
244
  }
247
245
  export interface ISerial {
246
+ close(): void;
248
247
  /**
249
248
  * Writes given string to the port.
250
249
  *
package/api.js CHANGED
@@ -1,12 +1,3 @@
1
- export const START = ["start"];
2
- export const STOP = ["stop"];
3
- export const HOME = ["home"];
4
- export const RESET = ["reset"];
5
- export const PEN = ["pen"];
6
- export const UP = ["u"];
7
- export const DOWN = ["d"];
8
- export const ON = ["on"];
9
- export const OFF = ["off"];
10
1
  /**
11
2
  * FSM state enum for (interactive) control for processing of drawing commands.
12
3
  * See {@link AxiDraw.draw} and {@link AxiDrawControl} for details.
package/axidraw.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import type { IReset } from "@thi.ng/api";
2
- import { ReadonlyVec, Vec } from "@thi.ng/vectors";
2
+ import { ReadonlyVec, Vec } from "@thi.ng/vectors/api";
3
3
  import { AxiDrawOpts, DrawCommand, ISerial, Metrics } from "./api.js";
4
4
  export declare const DEFAULT_OPTS: AxiDrawOpts;
5
5
  export declare class AxiDraw implements IReset {
@@ -25,6 +25,7 @@ export declare class AxiDraw implements IReset {
25
25
  * @param path
26
26
  */
27
27
  connect(path?: string | RegExp): Promise<void>;
28
+ disconnect(): void;
28
29
  /**
29
30
  * Async function. Converts sequence of {@link DrawCommand}s into actual EBB
30
31
  * commands and sends them via configured serial port to the AxiDraw. If
@@ -85,12 +86,20 @@ export declare class AxiDraw implements IReset {
85
86
  * @param tempo
86
87
  */
87
88
  moveTo(p: ReadonlyVec, tempo?: number): number[];
89
+ /**
90
+ * Similar to {@link AxiDraw.moveTo}, but using **relative** coordinates.
91
+ *
92
+ * @param delta
93
+ * @param tempo
94
+ */
95
+ moveRelative(delta: ReadonlyVec, tempo?: number): number[];
88
96
  /**
89
97
  * Syntax sugar for {@link AxiDraw.moveTo}([0, 0]).
90
98
  */
91
99
  home(): number[];
92
100
  protected onSignal(): Promise<void>;
93
101
  protected send(msg: string): void;
102
+ protected sendMove(tempo?: number): number[];
94
103
  /**
95
104
  * Sends pen up/down config
96
105
  *
package/axidraw.js CHANGED
@@ -1,12 +1,21 @@
1
- import { isString } from "@thi.ng/checks";
2
- import { delayed } from "@thi.ng/compose";
3
- import { formatDuration } from "@thi.ng/date";
4
- import { assert, ioerror, unsupported } from "@thi.ng/errors";
5
- import { ConsoleLogger } from "@thi.ng/logger";
6
- import { abs2, mag, mulN2, set2, sub2, zero, ZERO2, } from "@thi.ng/vectors";
7
- import { AxiDrawState, HOME, OFF, ON, PEN, UP, } from "./api.js";
1
+ import { isString } from "@thi.ng/checks/is-string";
2
+ import { delayed } from "@thi.ng/compose/delayed";
3
+ import { formatDuration } from "@thi.ng/date/format";
4
+ import { assert } from "@thi.ng/errors/assert";
5
+ import { ioerror } from "@thi.ng/errors/io";
6
+ import { unsupported } from "@thi.ng/errors/unsupported";
7
+ import { ConsoleLogger } from "@thi.ng/logger/console";
8
+ import { abs2 } from "@thi.ng/vectors/abs";
9
+ import { ZERO2 } from "@thi.ng/vectors/api";
10
+ import { maddN2 } from "@thi.ng/vectors/maddn";
11
+ import { mag } from "@thi.ng/vectors/mag";
12
+ import { mulN2 } from "@thi.ng/vectors/muln";
13
+ import { set2 } from "@thi.ng/vectors/set";
14
+ import { zero } from "@thi.ng/vectors/setn";
15
+ import { sub2 } from "@thi.ng/vectors/sub";
16
+ import { AxiDrawState, } from "./api.js";
17
+ import { complete, HOME, OFF, ON, PEN, UP } from "./commands.js";
8
18
  import { AxiDrawControl } from "./control.js";
9
- import { complete } from "./polyline.js";
10
19
  import { SERIAL_PORT } from "./serial.js";
11
20
  export const DEFAULT_OPTS = {
12
21
  serial: SERIAL_PORT,
@@ -22,8 +31,8 @@ export const DEFAULT_OPTS = {
22
31
  delayUp: 150,
23
32
  delayDown: 150,
24
33
  preDelay: 0,
25
- start: [ON, PEN, UP],
26
- stop: [UP, HOME, OFF],
34
+ start: [ON, PEN(), UP()],
35
+ stop: [UP(), HOME, OFF],
27
36
  sigint: true,
28
37
  };
29
38
  export class AxiDraw {
@@ -70,6 +79,9 @@ export class AxiDraw {
70
79
  }
71
80
  ioerror(`no matching device for ${path}`);
72
81
  }
82
+ disconnect() {
83
+ this.serial.close();
84
+ }
73
85
  /**
74
86
  * Async function. Converts sequence of {@link DrawCommand}s into actual EBB
75
87
  * commands and sends them via configured serial port to the AxiDraw. If
@@ -176,10 +188,17 @@ export class AxiDraw {
176
188
  case "w":
177
189
  wait = a;
178
190
  break;
179
- case "m":
191
+ case "M":
180
192
  [wait, dist] = this.moveTo(a, b);
181
193
  $recordDist(dist);
182
194
  break;
195
+ case "m":
196
+ [wait, dist] = this.moveRelative(a, b);
197
+ $recordDist(dist);
198
+ break;
199
+ case "comment":
200
+ logger.info(`comment: ${a}`);
201
+ break;
183
202
  default:
184
203
  unsupported(`unknown command: ${$cmd}`);
185
204
  }
@@ -258,17 +277,23 @@ export class AxiDraw {
258
277
  * @param p
259
278
  * @param tempo
260
279
  */
261
- moveTo(p, tempo = 1) {
262
- const { pos, targetPos, opts, isPenDown } = this;
280
+ moveTo(p, tempo) {
281
+ const { targetPos, opts } = this;
263
282
  // apply scale factor: worldspace units -> motor steps
264
283
  mulN2(targetPos, p, opts.stepsPerInch / opts.unitsPerInch);
265
- const delta = sub2([], targetPos, pos);
266
- set2(pos, targetPos);
267
- const maxAxis = Math.max(...abs2([], delta));
268
- const duration = (1000 * maxAxis) /
269
- ((isPenDown ? opts.speedDown : opts.speedUp) * tempo);
270
- this.send(`XM,${duration | 0},${delta[0] | 0},${delta[1] | 0}\r`);
271
- return [duration, (mag(delta) * opts.unitsPerInch) / opts.stepsPerInch];
284
+ return this.sendMove(tempo);
285
+ }
286
+ /**
287
+ * Similar to {@link AxiDraw.moveTo}, but using **relative** coordinates.
288
+ *
289
+ * @param delta
290
+ * @param tempo
291
+ */
292
+ moveRelative(delta, tempo) {
293
+ const { pos, targetPos, opts } = this;
294
+ // apply scale factor: worldspace units -> motor steps
295
+ maddN2(targetPos, delta, opts.stepsPerInch / opts.unitsPerInch, pos);
296
+ return this.sendMove(tempo);
272
297
  }
273
298
  /**
274
299
  * Syntax sugar for {@link AxiDraw.moveTo}([0, 0]).
@@ -287,6 +312,16 @@ export class AxiDraw {
287
312
  this.opts.logger.debug(msg);
288
313
  this.serial.write(msg);
289
314
  }
315
+ sendMove(tempo = 1) {
316
+ const { pos, targetPos, opts, isPenDown } = this;
317
+ const delta = sub2([], targetPos, pos);
318
+ set2(pos, targetPos);
319
+ const maxAxis = Math.max(...abs2([], delta));
320
+ const duration = (1000 * maxAxis) /
321
+ ((isPenDown ? opts.speedDown : opts.speedUp) * tempo);
322
+ this.send(`XM,${duration | 0},${delta[0] | 0},${delta[1] | 0}\r`);
323
+ return [duration, (mag(delta) * opts.unitsPerInch) / opts.stepsPerInch];
324
+ }
290
325
  /**
291
326
  * Sends pen up/down config
292
327
  *
package/commands.d.ts ADDED
@@ -0,0 +1,67 @@
1
+ import type { ReadonlyVec } from "@thi.ng/vectors";
2
+ import type { CommentCommand, DrawCommand, HomeCommand, MotorCommand, MoveRelCommand, MoveXYCommand, PenConfigCommand, PenUpDownCommand, ResetCommand, StartCommand, StopCommand, WaitCommand } from "./api.js";
3
+ export declare const START: StartCommand;
4
+ export declare const STOP: StopCommand;
5
+ export declare const HOME: HomeCommand;
6
+ export declare const RESET: ResetCommand;
7
+ /**
8
+ * Creates a {@link PenConfigCommand} using provided down/up positions.
9
+ *
10
+ * @param posDown
11
+ * @param posUp
12
+ */
13
+ export declare const PEN: (posDown?: number, posUp?: number) => PenConfigCommand;
14
+ /**
15
+ * Creates a {@link PenUpDownCommand} to move the pen up.
16
+ *
17
+ * @param delay
18
+ */
19
+ export declare const UP: (delay?: number) => PenUpDownCommand;
20
+ /**
21
+ * Creates a {@link PenUpDownCommand} to move the pen down.
22
+ *
23
+ * @param delay
24
+ */
25
+ export declare const DOWN: (delay?: number) => PenUpDownCommand;
26
+ export declare const ON: MotorCommand;
27
+ export declare const OFF: MotorCommand;
28
+ /**
29
+ * Creates a {@link MoveXYCommand} command (absolute coordinates).
30
+ *
31
+ * @param pos
32
+ * @param speed
33
+ */
34
+ export declare const MOVE: (pos: ReadonlyVec, speed?: number) => MoveXYCommand;
35
+ /**
36
+ * Creates a {@link MoveRelCommand} command (relative coordinates).
37
+ *
38
+ * @param delta
39
+ * @param speed
40
+ */
41
+ export declare const MOVE_REL: (delta: ReadonlyVec, speed?: number) => MoveRelCommand;
42
+ /**
43
+ * Creates a {@link WaitCommand}. Default delay is 1000 ms.
44
+ *
45
+ * @param delay
46
+ */
47
+ export declare const WAIT: (delay?: number) => WaitCommand;
48
+ /**
49
+ * Creates a {@link CommentCommand}.
50
+ *
51
+ * @param msg
52
+ */
53
+ export declare const COMMENT: (msg: string) => CommentCommand;
54
+ /**
55
+ * Syntax sugar. Takes an iterable of draw commands, adds {@link START} as
56
+ * prefix and {@link STOP} as suffix. I.e. it creates a "complete" drawing...
57
+ *
58
+ * @example
59
+ * ```ts
60
+ * [...complete([ MOVE([0, 0]) ])]
61
+ * // [ ["start"], ["M", [0, 0]], ["stop"] ]
62
+ * ```
63
+ *
64
+ * @param commands
65
+ */
66
+ export declare function complete(commands: Iterable<DrawCommand>): Generator<DrawCommand, void, undefined>;
67
+ //# sourceMappingURL=commands.d.ts.map
package/commands.js ADDED
@@ -0,0 +1,80 @@
1
+ export const START = ["start"];
2
+ export const STOP = ["stop"];
3
+ export const HOME = ["home"];
4
+ export const RESET = ["reset"];
5
+ /**
6
+ * Creates a {@link PenConfigCommand} using provided down/up positions.
7
+ *
8
+ * @param posDown
9
+ * @param posUp
10
+ */
11
+ export const PEN = (posDown, posUp) => [
12
+ "pen",
13
+ posDown,
14
+ posUp,
15
+ ];
16
+ /**
17
+ * Creates a {@link PenUpDownCommand} to move the pen up.
18
+ *
19
+ * @param delay
20
+ */
21
+ export const UP = (delay) => ["u", delay];
22
+ /**
23
+ * Creates a {@link PenUpDownCommand} to move the pen down.
24
+ *
25
+ * @param delay
26
+ */
27
+ export const DOWN = (delay) => ["d", delay];
28
+ export const ON = ["on"];
29
+ export const OFF = ["off"];
30
+ /**
31
+ * Creates a {@link MoveXYCommand} command (absolute coordinates).
32
+ *
33
+ * @param pos
34
+ * @param speed
35
+ */
36
+ export const MOVE = (pos, speed = 1) => [
37
+ "M",
38
+ pos,
39
+ speed,
40
+ ];
41
+ /**
42
+ * Creates a {@link MoveRelCommand} command (relative coordinates).
43
+ *
44
+ * @param delta
45
+ * @param speed
46
+ */
47
+ export const MOVE_REL = (delta, speed = 1) => [
48
+ "m",
49
+ delta,
50
+ speed,
51
+ ];
52
+ /**
53
+ * Creates a {@link WaitCommand}. Default delay is 1000 ms.
54
+ *
55
+ * @param delay
56
+ */
57
+ export const WAIT = (delay = 1000) => ["w", delay];
58
+ /**
59
+ * Creates a {@link CommentCommand}.
60
+ *
61
+ * @param msg
62
+ */
63
+ export const COMMENT = (msg) => ["comment", msg];
64
+ /**
65
+ * Syntax sugar. Takes an iterable of draw commands, adds {@link START} as
66
+ * prefix and {@link STOP} as suffix. I.e. it creates a "complete" drawing...
67
+ *
68
+ * @example
69
+ * ```ts
70
+ * [...complete([ MOVE([0, 0]) ])]
71
+ * // [ ["start"], ["M", [0, 0]], ["stop"] ]
72
+ * ```
73
+ *
74
+ * @param commands
75
+ */
76
+ export function* complete(commands) {
77
+ yield START;
78
+ yield* commands;
79
+ yield STOP;
80
+ }
package/dip.d.ts ADDED
@@ -0,0 +1,60 @@
1
+ import type { Fn0 } from "@thi.ng/api";
2
+ import type { DrawCommand } from "./api.js";
3
+ export interface DipOpts {
4
+ /**
5
+ * Delay for emitted {@link DOWN} commands. If omitted, uses globally
6
+ * configured default.
7
+ */
8
+ up: number;
9
+ /**
10
+ * Delay for emitted {@link UP} commands. If omitted, uses globally
11
+ * configured default.
12
+ */
13
+ down: number;
14
+ /**
15
+ * No-arg function to inject custom commands between each down - up command.
16
+ * See example in {@link DIP} docs.
17
+ */
18
+ commands: Fn0<Iterable<DrawCommand>>;
19
+ }
20
+ /**
21
+ * Yields a **sequence** of `n` repetitions of {@link DOWN}, {@link UP}
22
+ * commands, optionally interspersed with other user provided
23
+ * {@link DrawCommand}s, e.g. for dipping & moving a brush a few times into a
24
+ * paint reservoir to refill.
25
+ *
26
+ * @example
27
+ * ```ts
28
+ * // simple 2x up/down
29
+ * [...DIP(2)]
30
+ * // [
31
+ * // [ "d", undefined ],
32
+ * // [ "u", undefined ],
33
+ * // [ "d", undefined ],
34
+ * // [ "u", undefined ],
35
+ * // ]
36
+ *
37
+ * // 3x dipping with custom up/down delays, each time at a random position
38
+ * [...DIP(3, {
39
+ * down: 300,
40
+ * up: 400,
41
+ * commands: () => [ MOVE([Math.random()* 5, Math.random()* 5]) ]
42
+ * })]
43
+ * // [
44
+ * // [ "d", 300 ],
45
+ * // [ "M", [ 3.996, 1.707 ], 1 ],
46
+ * // [ "u", 400 ],
47
+ * // [ "d", 300 ],
48
+ * // [ "M", [ 4.747, 4.925 ], 1 ],
49
+ * // [ "u", 400 ],
50
+ * // [ "d", 300 ],
51
+ * // [ "M", [ 1.751, 0.670 ], 1 ],
52
+ * // [ "u", 400 ]
53
+ * // ]
54
+ * ```
55
+ *
56
+ * @param n
57
+ * @param opts
58
+ */
59
+ export declare const dip: (n: number, opts?: Partial<DipOpts>) => IterableIterator<DrawCommand>;
60
+ //# sourceMappingURL=dip.d.ts.map
package/dip.js ADDED
@@ -0,0 +1,45 @@
1
+ import { flatten1 } from "@thi.ng/transducers/flatten1";
2
+ import { repeatedly } from "@thi.ng/transducers/repeatedly";
3
+ import { DOWN, UP } from "./commands.js";
4
+ /**
5
+ * Yields a **sequence** of `n` repetitions of {@link DOWN}, {@link UP}
6
+ * commands, optionally interspersed with other user provided
7
+ * {@link DrawCommand}s, e.g. for dipping & moving a brush a few times into a
8
+ * paint reservoir to refill.
9
+ *
10
+ * @example
11
+ * ```ts
12
+ * // simple 2x up/down
13
+ * [...DIP(2)]
14
+ * // [
15
+ * // [ "d", undefined ],
16
+ * // [ "u", undefined ],
17
+ * // [ "d", undefined ],
18
+ * // [ "u", undefined ],
19
+ * // ]
20
+ *
21
+ * // 3x dipping with custom up/down delays, each time at a random position
22
+ * [...DIP(3, {
23
+ * down: 300,
24
+ * up: 400,
25
+ * commands: () => [ MOVE([Math.random()* 5, Math.random()* 5]) ]
26
+ * })]
27
+ * // [
28
+ * // [ "d", 300 ],
29
+ * // [ "M", [ 3.996, 1.707 ], 1 ],
30
+ * // [ "u", 400 ],
31
+ * // [ "d", 300 ],
32
+ * // [ "M", [ 4.747, 4.925 ], 1 ],
33
+ * // [ "u", 400 ],
34
+ * // [ "d", 300 ],
35
+ * // [ "M", [ 1.751, 0.670 ], 1 ],
36
+ * // [ "u", 400 ]
37
+ * // ]
38
+ * ```
39
+ *
40
+ * @param n
41
+ * @param opts
42
+ */
43
+ export const dip = (n, opts = {}) => flatten1(repeatedly(opts.commands
44
+ ? () => [DOWN(opts.down), ...opts.commands(), UP(opts.up)]
45
+ : () => [DOWN(opts.down), UP(opts.up)], n));
package/index.d.ts CHANGED
@@ -1,7 +1,9 @@
1
1
  export * from "./api.js";
2
2
  export * from "./axidraw.js";
3
+ export * from "./commands.js";
3
4
  export * from "./control.js";
5
+ export * from "./dip.js";
4
6
  export * from "./polyline.js";
7
+ export * from "./registration.js";
5
8
  export * from "./serial.js";
6
- export * from "./utils.js";
7
9
  //# sourceMappingURL=index.d.ts.map
package/index.js CHANGED
@@ -1,6 +1,8 @@
1
1
  export * from "./api.js";
2
2
  export * from "./axidraw.js";
3
+ export * from "./commands.js";
3
4
  export * from "./control.js";
5
+ export * from "./dip.js";
4
6
  export * from "./polyline.js";
7
+ export * from "./registration.js";
5
8
  export * from "./serial.js";
6
- export * from "./utils.js";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@thi.ng/axidraw",
3
- "version": "0.5.8",
3
+ "version": "1.0.0",
4
4
  "description": "Minimal AxiDraw plotter/drawing machine controller for Node.js",
5
5
  "type": "module",
6
6
  "module": "./index.js",
@@ -40,8 +40,8 @@
40
40
  "@thi.ng/date": "^2.4.8",
41
41
  "@thi.ng/errors": "^2.2.13",
42
42
  "@thi.ng/logger": "^1.4.11",
43
- "@thi.ng/transducers": "^8.3.38",
44
- "@thi.ng/vectors": "^7.6.8",
43
+ "@thi.ng/transducers": "^8.4.0",
44
+ "@thi.ng/vectors": "^7.6.9",
45
45
  "serialport": "^10.5.0"
46
46
  },
47
47
  "devDependencies": {
@@ -87,22 +87,28 @@
87
87
  "./axidraw": {
88
88
  "default": "./axidraw.js"
89
89
  },
90
+ "./commands": {
91
+ "default": "./commands.js"
92
+ },
90
93
  "./control": {
91
94
  "default": "./control.js"
92
95
  },
96
+ "./dip": {
97
+ "default": "./dip.js"
98
+ },
93
99
  "./polyline": {
94
100
  "default": "./polyline.js"
95
101
  },
102
+ "./registration": {
103
+ "default": "./registration.js"
104
+ },
96
105
  "./serial": {
97
106
  "default": "./serial.js"
98
- },
99
- "./utils": {
100
- "default": "./utils.js"
101
107
  }
102
108
  },
103
109
  "thi.ng": {
104
110
  "status": "alpha",
105
111
  "year": 2022
106
112
  },
107
- "gitHead": "cc46c097a3a173fb1ef41f57a858d03037063141\n"
113
+ "gitHead": "1359645f3af8a7d0d43fe7944ea5cd865832f8ee\n"
108
114
  }
package/polyline.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import type { ReadonlyVec } from "@thi.ng/vectors";
2
- import { DrawCommand, PolylineOpts } from "./api.js";
2
+ import type { DrawCommand, PolylineOpts } from "./api.js";
3
3
  /**
4
4
  * Takes an array of 2D points and yields an iterable of {@link DrawCommand}s.
5
5
  * The drawing behavior can be customized via additional {@link PolylineOpts}
@@ -13,17 +13,4 @@ import { DrawCommand, PolylineOpts } from "./api.js";
13
13
  * @param opts
14
14
  */
15
15
  export declare function polyline(pts: ReadonlyVec[], opts: Partial<PolylineOpts>): IterableIterator<DrawCommand>;
16
- /**
17
- * Syntax sugar. Takes an iterable of draw commands, adds {@link START} as
18
- * prefix and {@link STOP} as suffix. I.e. it creates a "complete" drawing...
19
- *
20
- * @example
21
- * ```ts
22
- * [...complete([ ["m", [0, 0]] ])]
23
- * // [ ["start"], ["m", [0, 0]], ["stop"] ]
24
- * ```
25
- *
26
- * @param commands
27
- */
28
- export declare function complete(commands: Iterable<DrawCommand>): Generator<DrawCommand, void, undefined>;
29
16
  //# sourceMappingURL=polyline.d.ts.map
package/polyline.js CHANGED
@@ -1,4 +1,4 @@
1
- import { DOWN, START, STOP, UP } from "./api.js";
1
+ import { DOWN, MOVE, PEN, UP } from "./commands.js";
2
2
  /**
3
3
  * Takes an array of 2D points and yields an iterable of {@link DrawCommand}s.
4
4
  * The drawing behavior can be customized via additional {@link PolylineOpts}
@@ -21,34 +21,17 @@ export function* polyline(pts, opts) {
21
21
  };
22
22
  if (onlyGeo) {
23
23
  for (let p of pts)
24
- yield ["m", p, speed];
24
+ yield MOVE(p, speed);
25
25
  return;
26
26
  }
27
- yield ["m", pts[0]];
27
+ yield MOVE(pts[0]);
28
28
  if (down !== undefined)
29
- yield ["pen", down];
30
- yield delayDown != undefined ? ["d", delayDown] : DOWN;
29
+ yield PEN(down);
30
+ yield DOWN(delayDown);
31
31
  for (let i = 1, n = pts.length; i < n; i++)
32
- yield ["m", pts[i], speed];
33
- yield delayUp != undefined ? ["u", delayUp] : UP;
32
+ yield MOVE(pts[i], speed);
33
+ yield UP(delayUp);
34
34
  // reset pen to configured defaults
35
35
  if (down !== undefined)
36
- yield ["pen"];
37
- }
38
- /**
39
- * Syntax sugar. Takes an iterable of draw commands, adds {@link START} as
40
- * prefix and {@link STOP} as suffix. I.e. it creates a "complete" drawing...
41
- *
42
- * @example
43
- * ```ts
44
- * [...complete([ ["m", [0, 0]] ])]
45
- * // [ ["start"], ["m", [0, 0]], ["stop"] ]
46
- * ```
47
- *
48
- * @param commands
49
- */
50
- export function* complete(commands) {
51
- yield START;
52
- yield* commands;
53
- yield STOP;
36
+ yield PEN();
54
37
  }
@@ -1,4 +1,4 @@
1
- import { ReadonlyVec } from "@thi.ng/vectors";
1
+ import type { ReadonlyVec } from "@thi.ng/vectors";
2
2
  import type { DrawCommand } from "./api.js";
3
3
  /**
4
4
  * Generates a {@link DrawCommand} sequence to draw a registration mark
@@ -14,4 +14,4 @@ import type { DrawCommand } from "./api.js";
14
14
  * @param r
15
15
  */
16
16
  export declare const registrationMark: ([x, y]: ReadonlyVec, size?: number, r?: number) => DrawCommand[];
17
- //# sourceMappingURL=utils.d.ts.map
17
+ //# sourceMappingURL=registration.d.ts.map
@@ -0,0 +1,36 @@
1
+ import { map } from "@thi.ng/transducers/map";
2
+ import { normRange } from "@thi.ng/transducers/norm-range";
3
+ import { cartesian2 } from "@thi.ng/vectors/cartesian";
4
+ import { DOWN, MOVE, UP } from "./commands.js";
5
+ /**
6
+ * Generates a {@link DrawCommand} sequence to draw a registration mark
7
+ * (crosshair + circle) centered around `pos`.
8
+ *
9
+ * @example
10
+ * ```ts
11
+ * axi.draw(registrationMark([20, 20]))
12
+ * ```
13
+ *
14
+ * @param pos
15
+ * @param size
16
+ * @param r
17
+ */
18
+ export const registrationMark = ([x, y], size = 5, r = size * 0.75) => [
19
+ // crosshair
20
+ // horizontal
21
+ MOVE([x - size, y]),
22
+ DOWN(),
23
+ MOVE([x + size, y]),
24
+ UP(),
25
+ // vertical
26
+ MOVE([x, y - size]),
27
+ DOWN(),
28
+ MOVE([x, y + size]),
29
+ UP(),
30
+ // circle
31
+ MOVE([x + r, y]),
32
+ DOWN(),
33
+ ...map((t) => MOVE(cartesian2([], [r, t * Math.PI * 2], [x, y])), normRange(40)),
34
+ UP(),
35
+ MOVE([x, y]),
36
+ ];
package/serial.d.ts CHANGED
@@ -14,10 +14,12 @@ export declare const MOCK_SERIAL: SerialConnection;
14
14
  */
15
15
  export declare class MockSerial implements ISerial {
16
16
  sent: string[];
17
+ isClosed: boolean;
17
18
  /**
18
19
  * Clears internal log of "sent" message.
19
20
  */
20
21
  clear(): void;
22
+ close(): void;
21
23
  /**
22
24
  * Appends
23
25
  * @param msg
package/serial.js CHANGED
@@ -1,3 +1,4 @@
1
+ import { illegalState } from "@thi.ng/errors/illegal-state";
1
2
  import { SerialPort } from "serialport";
2
3
  /**
3
4
  * Default connection using the actual serial port.
@@ -21,6 +22,7 @@ export const MOCK_SERIAL = {
21
22
  export class MockSerial {
22
23
  constructor() {
23
24
  this.sent = [];
25
+ this.isClosed = false;
24
26
  }
25
27
  /**
26
28
  * Clears internal log of "sent" message.
@@ -28,11 +30,15 @@ export class MockSerial {
28
30
  clear() {
29
31
  this.sent = [];
30
32
  }
33
+ close() {
34
+ this.isClosed = true;
35
+ }
31
36
  /**
32
37
  * Appends
33
38
  * @param msg
34
39
  */
35
40
  write(msg) {
41
+ this.isClosed && illegalState("connection already closed");
36
42
  this.sent.push(msg);
37
43
  }
38
44
  }
package/utils.js DELETED
@@ -1,34 +0,0 @@
1
- import { map, normRange } from "@thi.ng/transducers";
2
- import { cartesian2 } from "@thi.ng/vectors";
3
- /**
4
- * Generates a {@link DrawCommand} sequence to draw a registration mark
5
- * (crosshair + circle) centered around `pos`.
6
- *
7
- * @example
8
- * ```ts
9
- * axi.draw(registrationMark([20, 20]))
10
- * ```
11
- *
12
- * @param pos
13
- * @param size
14
- * @param r
15
- */
16
- export const registrationMark = ([x, y], size = 5, r = size * 0.75) => [
17
- // crosshair
18
- // horizontal
19
- ["m", [x - size, y]],
20
- ["d"],
21
- ["m", [x + size, y]],
22
- ["u"],
23
- // vertical
24
- ["m", [x, y - size]],
25
- ["d"],
26
- ["m", [x, y + size]],
27
- ["u"],
28
- // circle
29
- ["m", [x + r, y]],
30
- ["d"],
31
- ...map((t) => ["m", cartesian2([], [r, t * Math.PI * 2], [x, y])], normRange(40)),
32
- ["u"],
33
- ["m", [x, y]],
34
- ];