@packtrack/layout 1.0.4 → 1.0.5

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.
@@ -0,0 +1,20 @@
1
+ import { Layout } from "./layout";
2
+ import { PowerDistrict } from "./power-district";
3
+ import { Router } from "./router";
4
+ import { Section } from "./section";
5
+ export declare class District {
6
+ name: string;
7
+ parent: District | Layout;
8
+ children: District[];
9
+ powerDistricts: PowerDistrict[];
10
+ sections: Section[];
11
+ routers: Router[];
12
+ constructor(name: string, parent: District | Layout);
13
+ get domainName(): string;
14
+ dump(): void;
15
+ toDotReference(): any;
16
+ toDotDefinition(): any;
17
+ toDotConnection(): any;
18
+ toSVG(): any;
19
+ findSVGPositions(): any;
20
+ }
@@ -0,0 +1,86 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.District = void 0;
4
+ const layout_1 = require("./layout");
5
+ class District {
6
+ name;
7
+ parent;
8
+ children = [];
9
+ powerDistricts = [];
10
+ sections = [];
11
+ routers = [];
12
+ constructor(name, parent) {
13
+ this.name = name;
14
+ this.parent = parent;
15
+ }
16
+ get domainName() {
17
+ if (this.parent instanceof layout_1.Layout) {
18
+ return `${this.name}.${this.parent.name}`;
19
+ }
20
+ return `${this.name}.${this.parent.domainName}`;
21
+ }
22
+ dump() {
23
+ console.group(`District ${this.domainName}`);
24
+ if (this.powerDistricts.length) {
25
+ console.group('power districts');
26
+ for (let district of this.powerDistricts) {
27
+ district.dump();
28
+ }
29
+ console.groupEnd();
30
+ }
31
+ if (this.sections.length) {
32
+ console.group('sections');
33
+ for (let section of this.sections) {
34
+ section.dump();
35
+ }
36
+ console.groupEnd();
37
+ }
38
+ if (this.children.length) {
39
+ console.group('children');
40
+ for (let district of this.children) {
41
+ district.dump();
42
+ }
43
+ console.groupEnd();
44
+ }
45
+ console.groupEnd();
46
+ }
47
+ toDotReference() {
48
+ return `cluster_${this.name.replace(/-/g, '_')}${this.parent instanceof District ? this.parent.toDotReference() : ''}`;
49
+ }
50
+ toDotDefinition() {
51
+ return `
52
+ subgraph ${this.toDotReference()} {
53
+ label = ${JSON.stringify(this.name)}
54
+
55
+ ${this.sections.map(section => section.toDotDefinition()).join('')}
56
+ ${this.routers.map(router => router.toDotDefinition()).join('')}
57
+
58
+ ${this.children.map(child => child.toDotDefinition()).join('')}
59
+ }
60
+ `;
61
+ }
62
+ toDotConnection() {
63
+ return `
64
+ ${this.sections.map(section => section.toDotConnection()).join('')}
65
+ ${this.routers.map(router => router.toDotConnection()).join('')}
66
+
67
+ ${this.children.map(child => child.toDotConnection()).join('')}
68
+ `;
69
+ }
70
+ toSVG() {
71
+ return `
72
+ <g id=${JSON.stringify(this.domainName)}>
73
+ ${this.sections.map(section => section.toSVG()).join('')}
74
+
75
+ ${this.children.map(child => child.toSVG()).join('')}
76
+ </g>
77
+ `;
78
+ }
79
+ findSVGPositions() {
80
+ return [
81
+ ...this.sections.map(section => section.findSVGPositions()),
82
+ ...this.children.map(child => child.findSVGPositions())
83
+ ];
84
+ }
85
+ }
86
+ exports.District = District;
@@ -0,0 +1,29 @@
1
+ import { District } from "./district";
2
+ import { PowerDistrict } from "./power-district";
3
+ import { Router } from "./router";
4
+ import { Section } from "./section";
5
+ import { Device } from "./device/device";
6
+ import { ResponderType } from "./positioner/responder-type";
7
+ import { Channel } from "./device/channel";
8
+ export declare class Layout {
9
+ name: string;
10
+ districts: District[];
11
+ devices: Device[];
12
+ responderType: ResponderType[];
13
+ get allDistricts(): District[];
14
+ static from(document: any): Layout;
15
+ loadDistrict(source: any, parent: District | Layout): District;
16
+ linkDistrict(source: any, district: District): void;
17
+ loadSection(source: any, district: District): void;
18
+ findDevice(identifier: string): Device;
19
+ findChannel(device: Device, name: string): Channel;
20
+ findResponderType(name: string): ResponderType;
21
+ linkSection(source: any, section: Section): void;
22
+ findSection(path: string, base: District, source?: District): any;
23
+ loadRouter(source: any, district: District): Router;
24
+ linkRouter(source: any, router: Router): void;
25
+ loadPowerDistrict(source: any, district: District): PowerDistrict;
26
+ toDot(): string;
27
+ toSVG(inject?: string): string;
28
+ dump(): void;
29
+ }
@@ -0,0 +1,286 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.Layout = void 0;
4
+ const district_1 = require("./district");
5
+ const power_district_1 = require("./power-district");
6
+ const route_1 = require("./route");
7
+ const router_1 = require("./router");
8
+ const section_1 = require("./section");
9
+ const tile_1 = require("./tile");
10
+ const track_1 = require("./track");
11
+ const device_1 = require("./device/device");
12
+ const responder_type_1 = require("./positioner/responder-type");
13
+ const channel_1 = require("./device/channel");
14
+ const point_1 = require("./positioner/point");
15
+ class Layout {
16
+ name;
17
+ districts = [];
18
+ devices = [];
19
+ responderType = [];
20
+ get allDistricts() {
21
+ const districts = [];
22
+ function walkDistrict(district) {
23
+ districts.push(district);
24
+ for (let child of district.children) {
25
+ walkDistrict(child);
26
+ }
27
+ }
28
+ for (let district of this.districts) {
29
+ walkDistrict(district);
30
+ }
31
+ return districts;
32
+ }
33
+ static from(document) {
34
+ const layout = new Layout();
35
+ const railway = document.firstChild;
36
+ layout.name = railway.getAttribute('name');
37
+ const version = railway.getAttribute('version');
38
+ if (version == '1') {
39
+ let district = railway.firstChild;
40
+ while (district) {
41
+ if (district.tagName == 'district') {
42
+ layout.districts.push(layout.loadDistrict(district, layout));
43
+ }
44
+ district = district.nextSibling;
45
+ }
46
+ district = railway.firstChild;
47
+ let index = 0;
48
+ while (district) {
49
+ if (district.tagName == 'district') {
50
+ layout.linkDistrict(district, layout.districts[index]);
51
+ index++;
52
+ }
53
+ district = district.nextSibling;
54
+ }
55
+ }
56
+ else {
57
+ throw new Error(`unsupported railway definition file version '${version}'`);
58
+ }
59
+ return layout;
60
+ }
61
+ loadDistrict(source, parent) {
62
+ const district = new district_1.District(source.getAttribute('name'), parent);
63
+ let child = source.firstChild;
64
+ while (child) {
65
+ if (child.tagName == 'power-districts') {
66
+ let powerDistrict = child.firstChild;
67
+ while (powerDistrict) {
68
+ if (powerDistrict.tagName == 'power-district') {
69
+ district.powerDistricts.push(this.loadPowerDistrict(powerDistrict, district));
70
+ }
71
+ powerDistrict = powerDistrict.nextSibling;
72
+ }
73
+ }
74
+ if (child.tagName == 'section') {
75
+ this.loadSection(child, district);
76
+ }
77
+ if (child.tagName == 'router') {
78
+ district.routers.push(this.loadRouter(child, district));
79
+ }
80
+ if (child.tagName == 'district') {
81
+ district.children.push(this.loadDistrict(child, district));
82
+ }
83
+ child = child.nextSibling;
84
+ }
85
+ return district;
86
+ }
87
+ linkDistrict(source, district) {
88
+ let child = source.firstChild;
89
+ let sectionIndex = 0;
90
+ let childIndex = 0;
91
+ while (child) {
92
+ if (child.tagName == 'section') {
93
+ this.linkSection(child, district.sections[sectionIndex]);
94
+ sectionIndex++;
95
+ }
96
+ if (child.tagName == 'router') {
97
+ this.linkRouter(child, district.routers.find(router => router.name == child.getAttribute('name')));
98
+ }
99
+ if (child.tagName == 'district') {
100
+ this.linkDistrict(child, district.children[childIndex]);
101
+ childIndex++;
102
+ }
103
+ child = child.nextSibling;
104
+ }
105
+ }
106
+ loadSection(source, district) {
107
+ const section = new section_1.Section(source.getAttribute('name'), district);
108
+ district.sections.push(section);
109
+ let child = source.firstChild;
110
+ while (child) {
111
+ if (child.tagName == 'tracks') {
112
+ let trackNode = child.firstChild;
113
+ while (trackNode) {
114
+ if (trackNode.tagName == 'track') {
115
+ const track = new track_1.Track(section, +trackNode.getAttribute('length'), trackNode.getAttribute('path'));
116
+ section.tracks.push(track);
117
+ let trackChild = trackNode.firstChild;
118
+ while (trackChild) {
119
+ if (trackChild.tagName == 'positioners') {
120
+ let positioner = trackChild.firstChild;
121
+ while (positioner) {
122
+ if (positioner.tagName == 'point') {
123
+ const device = this.findDevice(positioner.getAttribute('device'));
124
+ const channel = this.findChannel(device, positioner.getAttribute('channel'));
125
+ const responderType = this.findResponderType(positioner.getAttribute('responder'));
126
+ track.positioners.push(new point_1.PointPositioner(track, +positioner.getAttribute('offset'), channel, responderType));
127
+ }
128
+ positioner = positioner.nextSibling;
129
+ }
130
+ }
131
+ trackChild = trackChild.nextSibling;
132
+ }
133
+ }
134
+ trackNode = trackNode.nextSibling;
135
+ }
136
+ }
137
+ if (child.tagName == 'tile') {
138
+ const pattern = child.getAttribute('pattern');
139
+ if (!(pattern in tile_1.TilePattern.patterns)) {
140
+ throw new Error(`Unknown tile pattern '${pattern}' in tile ${section.tiles.length + 1} in ${section.domainName}`);
141
+ }
142
+ section.tiles.push(new tile_1.Tile(section, +child.getAttribute('x'), +child.getAttribute('y'), tile_1.TilePattern.patterns[pattern]));
143
+ }
144
+ child = child.nextSibling;
145
+ }
146
+ }
147
+ findDevice(identifier) {
148
+ let device = this.devices.find(device => device.identifier == identifier);
149
+ if (device) {
150
+ return device;
151
+ }
152
+ device = new device_1.Device(identifier);
153
+ this.devices.push(device);
154
+ return device;
155
+ }
156
+ findChannel(device, name) {
157
+ let channel = device.channels.find(channel => channel.name == name);
158
+ if (channel) {
159
+ return channel;
160
+ }
161
+ channel = new channel_1.Channel(device, name);
162
+ device.channels.push(channel);
163
+ return channel;
164
+ }
165
+ findResponderType(name) {
166
+ let type = this.responderType.find(type => type.name == name);
167
+ if (type) {
168
+ return type;
169
+ }
170
+ type = new responder_type_1.ResponderType(name);
171
+ this.responderType.push(type);
172
+ return type;
173
+ }
174
+ linkSection(source, section) {
175
+ let child = source.firstChild;
176
+ while (child) {
177
+ if (child.tagName == 'out') {
178
+ const out = this.findSection(child.getAttribute('section'), section.district);
179
+ section.out = out;
180
+ out.in = section;
181
+ }
182
+ child = child.nextSibling;
183
+ }
184
+ }
185
+ findSection(path, base, source = base) {
186
+ const parts = path.split('.');
187
+ if (parts.length == 0) {
188
+ throw `section '${path}' not found from '${source.name}': invalid name`;
189
+ }
190
+ if (parts.length == 1) {
191
+ const localSection = base.sections.find(section => section.name == parts[0]);
192
+ if (!localSection) {
193
+ throw new Error(`Section '${path}' not found from '${source.name}': section does not exist in '${base.name}'`);
194
+ }
195
+ return localSection;
196
+ }
197
+ const sectionName = parts.pop();
198
+ let pool = base;
199
+ for (let index = 0; index < parts.length; index++) {
200
+ if (pool instanceof Layout || !pool.parent) {
201
+ throw new Error(`Section '${path}' could not be found from '${source.name}': district '${pool.name}' does not have a parent`);
202
+ }
203
+ pool = pool.parent;
204
+ }
205
+ for (let part of parts) {
206
+ const child = (pool instanceof district_1.District ? pool.children : pool.districts).find(child => child.name == part);
207
+ if (!child) {
208
+ throw new Error(`Section '${path}' could not be found from '${source.name}': district '${pool.name}' does not have a child named '${part}'`);
209
+ }
210
+ pool = child;
211
+ }
212
+ if (pool instanceof Layout) {
213
+ throw new Error(`Section '${path}' could not be found from '${source.name}': a layout cannot directly include a section`);
214
+ }
215
+ return this.findSection(sectionName, pool, source);
216
+ }
217
+ loadRouter(source, district) {
218
+ const router = new router_1.Router(source.getAttribute('name'), district);
219
+ return router;
220
+ }
221
+ linkRouter(source, router) {
222
+ let child = source.firstChild;
223
+ while (child) {
224
+ if (child.tagName == 'route') {
225
+ const route = new route_1.Route(child.getAttribute('name'), router);
226
+ route.in = this.findSection(child.getAttribute('in'), router.district);
227
+ route.in.out = router;
228
+ route.out = this.findSection(child.getAttribute('out'), router.district);
229
+ route.out.in = router;
230
+ router.routes.push(route);
231
+ }
232
+ child = child.nextSibling;
233
+ }
234
+ }
235
+ loadPowerDistrict(source, district) {
236
+ const powerDistrict = new power_district_1.PowerDistrict(source.getAttribute('name'), district);
237
+ return powerDistrict;
238
+ }
239
+ toDot() {
240
+ let dot = 'digraph G {';
241
+ for (let district of this.districts) {
242
+ dot += district.toDotDefinition();
243
+ }
244
+ for (let district of this.districts) {
245
+ dot += district.toDotConnection();
246
+ }
247
+ return `${dot}}`;
248
+ }
249
+ toSVG(inject = '') {
250
+ const positons = this.districts.map(district => district.findSVGPositions()).flat(Infinity);
251
+ const width = Math.max(...positons.map(position => position.x));
252
+ const height = Math.max(...positons.map(position => position.y));
253
+ let svg = `<svg width="100vw" height="100vh" viewBox="0 0 ${width + 1} ${height + 1}" xmlns="http://www.w3.org/2000/svg">
254
+ <style>
255
+
256
+ path {
257
+ fill: none;
258
+ stroke: #000;
259
+ stroke-width: 0.2;
260
+ }
261
+
262
+ </style>
263
+ `;
264
+ for (let district of this.districts) {
265
+ svg += district.toSVG();
266
+ }
267
+ return `${svg}${inject}</svg>`;
268
+ }
269
+ dump() {
270
+ console.group(`Layout ${this.name}`);
271
+ console.log('devices');
272
+ for (let device of this.devices) {
273
+ device.dump();
274
+ }
275
+ console.log('responder types');
276
+ for (let type of this.responderType) {
277
+ type.dump();
278
+ }
279
+ console.log('districts');
280
+ for (let district of this.districts) {
281
+ district.dump();
282
+ }
283
+ console.groupEnd();
284
+ }
285
+ }
286
+ exports.Layout = Layout;
@@ -0,0 +1,10 @@
1
+ import { Section } from './section.js';
2
+ export declare class SectionPosition {
3
+ section: Section;
4
+ offset: number;
5
+ reversed: boolean;
6
+ constructor(section: Section, offset: number, reversed: boolean);
7
+ get absolutePosition(): number;
8
+ advance(distance: number): any;
9
+ toString(): string;
10
+ }
@@ -0,0 +1,33 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.SectionPosition = void 0;
4
+ class SectionPosition {
5
+ section;
6
+ offset;
7
+ reversed;
8
+ constructor(section, offset, reversed) {
9
+ this.section = section;
10
+ this.offset = offset;
11
+ this.reversed = reversed;
12
+ }
13
+ get absolutePosition() {
14
+ if (this.reversed) {
15
+ return this.section.length - this.offset;
16
+ }
17
+ return this.offset;
18
+ }
19
+ advance(distance) {
20
+ if (this.offset + distance > this.section.length) {
21
+ const next = this.section.next(this.reversed);
22
+ if (!next) {
23
+ throw new Error(`Illegal advancement ${this} + ${distance}`);
24
+ }
25
+ return new SectionPosition(next, 0, this.reversed).advance(this.offset + distance - this.section.length);
26
+ }
27
+ return new SectionPosition(this.section, this.offset + distance, this.reversed);
28
+ }
29
+ toString() {
30
+ return `${this.section.name} @ ${this.offset.toFixed(1)} ${this.reversed ? 'backward' : 'forward'}`;
31
+ }
32
+ }
33
+ exports.SectionPosition = SectionPosition;
@@ -1,6 +1,6 @@
1
1
  import { Positioner } from ".";
2
- import { Channel } from "../source/device/channel";
3
- import { Track } from "../source/track";
2
+ import { Channel } from "../device/channel";
3
+ import { Track } from "../track";
4
4
  import { ResponderType } from "./responder-type";
5
5
  export declare class PointPositioner extends Positioner {
6
6
  track: Track;
@@ -0,0 +1,8 @@
1
+ import { District } from "./district";
2
+ export declare class PowerDistrict {
3
+ name: string;
4
+ district: District;
5
+ constructor(name: string, district: District);
6
+ get domainName(): string;
7
+ dump(): void;
8
+ }
@@ -0,0 +1,18 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.PowerDistrict = void 0;
4
+ class PowerDistrict {
5
+ name;
6
+ district;
7
+ constructor(name, district) {
8
+ this.name = name;
9
+ this.district = district;
10
+ }
11
+ get domainName() {
12
+ return `${this.name}.${this.district.domainName}`;
13
+ }
14
+ dump() {
15
+ console.log(this.name);
16
+ }
17
+ }
18
+ exports.PowerDistrict = PowerDistrict;
@@ -0,0 +1,10 @@
1
+ import { Router } from "./router";
2
+ import { Section } from "./section";
3
+ export declare class Route {
4
+ name: string;
5
+ router: Router;
6
+ in: Section;
7
+ out: Section;
8
+ constructor(name: string, router: Router);
9
+ dump(): void;
10
+ }
@@ -0,0 +1,17 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.Route = void 0;
4
+ class Route {
5
+ name;
6
+ router;
7
+ in;
8
+ out;
9
+ constructor(name, router) {
10
+ this.name = name;
11
+ this.router = router;
12
+ }
13
+ dump() {
14
+ console.log(`Route ${this.name}: ${this.in.domainName} → ${this.out.domainName}`);
15
+ }
16
+ }
17
+ exports.Route = Route;
@@ -0,0 +1,14 @@
1
+ import { District } from "./district";
2
+ import { Route } from "./route";
3
+ export declare class Router {
4
+ name: string;
5
+ district: District;
6
+ activeRoute?: Route;
7
+ routes: Route[];
8
+ constructor(name: string, district: District);
9
+ get domainName(): string;
10
+ dump(): void;
11
+ toDotReference(): string;
12
+ toDotDefinition(): string;
13
+ toDotConnection(): string;
14
+ }
@@ -0,0 +1,40 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.Router = void 0;
4
+ class Router {
5
+ name;
6
+ district;
7
+ activeRoute;
8
+ routes = [];
9
+ constructor(name, district) {
10
+ this.name = name;
11
+ this.district = district;
12
+ }
13
+ get domainName() {
14
+ return `${this.name}.${this.district.domainName}`;
15
+ }
16
+ dump() {
17
+ console.group(`Router ${this.domainName}`);
18
+ for (let route of this.routes) {
19
+ route.dump();
20
+ }
21
+ console.groupEnd();
22
+ }
23
+ toDotReference() {
24
+ return `router_${this.name.replace(/-/g, '_')}_${this.district.toDotReference()}`;
25
+ }
26
+ toDotDefinition() {
27
+ return `
28
+ ${this.toDotReference()} [ label = ${JSON.stringify(this.name)}, shape = diamond ]
29
+ `;
30
+ }
31
+ toDotConnection() {
32
+ return `
33
+ ${this.routes.map(route => `
34
+ ${route.in.toDotReference()} -> ${this.toDotReference()} [ headlabel = ${JSON.stringify(route.name)} ]
35
+ ${this.toDotReference()} -> ${route.out.toDotReference()} [ taillabel = ${JSON.stringify(route.name)} ]
36
+ `).join('')}
37
+ `;
38
+ }
39
+ }
40
+ exports.Router = Router;
@@ -0,0 +1,40 @@
1
+ import { District } from "./district";
2
+ import { SectionPosition } from "./position";
3
+ import { PowerDistrict } from "./power-district";
4
+ import { Router } from "./router";
5
+ import { Tile } from "./tile";
6
+ import { Track } from "./track";
7
+ export declare class Section {
8
+ name: string;
9
+ district: District;
10
+ powerDistrict: PowerDistrict;
11
+ tracks: Track[];
12
+ tiles: Tile[];
13
+ in?: Router | Section;
14
+ out?: Router | Section;
15
+ constructor(name: string, district: District);
16
+ get domainName(): string;
17
+ next(reverse: boolean): Section;
18
+ getTilesInRange(startPosition: SectionPosition, endPosition: SectionPosition): {
19
+ offset: {
20
+ start: number;
21
+ end: number;
22
+ };
23
+ tiles: Tile[];
24
+ };
25
+ dump(): void;
26
+ get length(): number;
27
+ get tileLength(): number;
28
+ trail(offset: number, reversed: boolean, length: number): {
29
+ sections: Section[];
30
+ tip: SectionPosition;
31
+ };
32
+ toDotReference(): string;
33
+ toDotDefinition(): string;
34
+ toDotConnection(): string;
35
+ toSVG(): string;
36
+ findSVGPositions(): {
37
+ x: number;
38
+ y: number;
39
+ }[];
40
+ }
@@ -0,0 +1,217 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.Section = void 0;
4
+ const position_1 = require("./position");
5
+ const router_1 = require("./router");
6
+ class Section {
7
+ name;
8
+ district;
9
+ powerDistrict;
10
+ tracks = [];
11
+ tiles = [];
12
+ in;
13
+ out;
14
+ constructor(name, district) {
15
+ this.name = name;
16
+ this.district = district;
17
+ }
18
+ get domainName() {
19
+ return `${this.name}.${this.district.domainName}`;
20
+ }
21
+ // returns the next currently set section
22
+ next(reverse) {
23
+ if (reverse) {
24
+ if (!this.in) {
25
+ return null;
26
+ }
27
+ if (this.in instanceof Section) {
28
+ return this.in;
29
+ }
30
+ if (this.in instanceof router_1.Router) {
31
+ const activeRoute = this.in.activeRoute;
32
+ if (!activeRoute) {
33
+ throw new Error(`Router '${this.in.domainName}' has no active route`);
34
+ }
35
+ if (activeRoute.in == this) {
36
+ return activeRoute.out;
37
+ }
38
+ if (activeRoute.out == this) {
39
+ return activeRoute.in;
40
+ }
41
+ throw new Error(`Router '${this.in.domainName}' is not routing from '${this.domainName}'`);
42
+ }
43
+ }
44
+ else {
45
+ if (!this.out) {
46
+ return null;
47
+ }
48
+ if (this.out instanceof Section) {
49
+ return this.out;
50
+ }
51
+ if (this.out instanceof router_1.Router) {
52
+ const activeRoute = this.out.activeRoute;
53
+ if (!activeRoute) {
54
+ throw new Error(`Router '${this.out.domainName}' has no active route`);
55
+ }
56
+ if (activeRoute.in == this) {
57
+ return activeRoute.out;
58
+ }
59
+ if (activeRoute.out == this) {
60
+ return activeRoute.in;
61
+ }
62
+ throw new Error(`Router '${this.in?.domainName}' is not routing from '${this.domainName}'`);
63
+ }
64
+ }
65
+ }
66
+ getTilesInRange(startPosition, endPosition) {
67
+ if (startPosition.section != this && endPosition.section != this) {
68
+ return {
69
+ offset: {
70
+ start: 0,
71
+ end: this.tiles[this.tiles.length - 1].pattern.length
72
+ },
73
+ tiles: [...this.tiles]
74
+ };
75
+ }
76
+ let start = 0;
77
+ let end = this.length;
78
+ // only use the position limit if it is within our section
79
+ if (startPosition.section == this) {
80
+ end = startPosition.absolutePosition;
81
+ }
82
+ if (endPosition.section == this) {
83
+ start = endPosition.absolutePosition;
84
+ }
85
+ // flip if the range was reversed
86
+ if (end < start) {
87
+ const small = end;
88
+ end = start;
89
+ start = small;
90
+ }
91
+ let passed = 0;
92
+ const tiles = [];
93
+ const tileUnitLength = this.length / this.tileLength;
94
+ const offset = {
95
+ start: 0,
96
+ end: 0
97
+ };
98
+ for (let tile of this.tiles) {
99
+ const length = tile.pattern.length * tileUnitLength;
100
+ if (start - length <= passed && end + length >= passed) {
101
+ tiles.push(tile);
102
+ if (start <= passed) {
103
+ offset.start = (start + length - passed) * tile.pattern.length / length;
104
+ }
105
+ if (end >= passed) {
106
+ offset.end = 0.5; // (start + length - passed) * tile.pattern.length / length;
107
+ }
108
+ }
109
+ passed += length;
110
+ }
111
+ return {
112
+ offset,
113
+ tiles
114
+ };
115
+ }
116
+ dump() {
117
+ console.group(`Section ${this.domainName}`);
118
+ console.log('in', this.in?.name ?? 'buffer');
119
+ console.log('out', this.out?.name ?? 'buffer');
120
+ console.group(`tracks`);
121
+ for (let track of this.tracks) {
122
+ track.dump();
123
+ }
124
+ console.groupEnd();
125
+ console.groupEnd();
126
+ }
127
+ get length() {
128
+ return this.tracks.reduce((accumulator, track) => accumulator + track.length, 0);
129
+ }
130
+ get tileLength() {
131
+ return this.tiles.reduce((accumulator, tile) => accumulator + tile.pattern.length, 0);
132
+ }
133
+ // follow the active path ahead (reverse = true = back)
134
+ // uses the currently set routes
135
+ // returns all touched sections
136
+ trail(offset, reversed, length) {
137
+ let tip = this;
138
+ const sections = [this];
139
+ if (reversed) {
140
+ length -= offset;
141
+ }
142
+ else {
143
+ length -= this.length - offset;
144
+ }
145
+ while (length > 0) {
146
+ let next;
147
+ if (reversed) {
148
+ next = tip.in;
149
+ }
150
+ else {
151
+ next = tip.out;
152
+ }
153
+ if (!next) {
154
+ return {
155
+ sections,
156
+ tip: new position_1.SectionPosition(tip, tip.length, false)
157
+ };
158
+ }
159
+ if (next instanceof Section) {
160
+ tip = next;
161
+ }
162
+ if (next instanceof router_1.Router) {
163
+ if (!next.activeRoute) {
164
+ throw new Error(`Router '${next.domainName}' has no active route (routes: ${next.routes.map(route => `'${route.name}'`).join(', ')})`);
165
+ }
166
+ // TODO: handle flipped cases
167
+ if (reversed) {
168
+ tip = next.activeRoute.in;
169
+ }
170
+ else {
171
+ tip = next.activeRoute.out;
172
+ }
173
+ }
174
+ sections.push(tip);
175
+ length -= tip.length;
176
+ }
177
+ return {
178
+ sections,
179
+ tip: new position_1.SectionPosition(tip, reversed ? -length : tip.length + length, false)
180
+ };
181
+ }
182
+ toDotReference() {
183
+ return `section_${this.name.replace(/-/g, '_')}_${this.district.toDotReference()}`;
184
+ }
185
+ toDotDefinition() {
186
+ return `
187
+ ${this.toDotReference()} [ label = ${JSON.stringify(`${this.name}\n${this.length}`)}, shape = box ]
188
+ `;
189
+ }
190
+ toDotConnection() {
191
+ return `
192
+ ${this.out instanceof Section ? `${this.toDotReference()} -> ${this.out.toDotReference()}` : ''}
193
+ `;
194
+ }
195
+ toSVG() {
196
+ return `
197
+ <g id=${JSON.stringify(this.domainName).split('.').join('_')}>
198
+ <style>
199
+
200
+ g#${this.domainName.split('.').join('_')} path {
201
+ stroke: hsl(${(this.length / this.tileLength)}deg, 100%, 50%);
202
+ }
203
+
204
+ </style>
205
+
206
+ ${this.tiles.map(tile => tile.toSVG()).join('')}
207
+ </g>
208
+ `;
209
+ }
210
+ findSVGPositions() {
211
+ return this.tiles.map(tile => ({
212
+ x: tile.x,
213
+ y: tile.y
214
+ }));
215
+ }
216
+ }
217
+ exports.Section = Section;
@@ -0,0 +1,57 @@
1
+ import { Section } from './section.js';
2
+ export declare class TilePattern {
3
+ length: number;
4
+ path: (continuous: boolean, x: number, y: number) => string;
5
+ static patterns: {
6
+ 'tl-cc': TilePattern;
7
+ 'tc-cc': TilePattern;
8
+ 'tr-cc': TilePattern;
9
+ 'cl-cc': TilePattern;
10
+ 'cr-cc': TilePattern;
11
+ 'bl-cc': TilePattern;
12
+ 'bc-cc': TilePattern;
13
+ 'br-cc': TilePattern;
14
+ 'cc-tl': TilePattern;
15
+ 'cc-tc': TilePattern;
16
+ 'cc-tr': TilePattern;
17
+ 'cc-cl': TilePattern;
18
+ 'cc-cr': TilePattern;
19
+ 'cc-bl': TilePattern;
20
+ 'cc-bc': TilePattern;
21
+ 'cc-br': TilePattern;
22
+ 'cr-cl': TilePattern;
23
+ 'cr-tl': TilePattern;
24
+ 'cr-bl': TilePattern;
25
+ 'cl-cr': TilePattern;
26
+ 'cl-tr': TilePattern;
27
+ 'cl-bl': TilePattern;
28
+ 'tl-bc': TilePattern;
29
+ 'tl-br': TilePattern;
30
+ 'tl-cr': TilePattern;
31
+ 'tc-bc': TilePattern;
32
+ 'tc-br': TilePattern;
33
+ 'tc-bl': TilePattern;
34
+ 'tr-cl': TilePattern;
35
+ 'tr-bc': TilePattern;
36
+ 'bl-tr': TilePattern;
37
+ 'bl-tc': TilePattern;
38
+ 'bl-cr': TilePattern;
39
+ 'bc-tc': TilePattern;
40
+ 'bc-tr': TilePattern;
41
+ 'bc-tl': TilePattern;
42
+ 'br-cl': TilePattern;
43
+ 'br-tc': TilePattern;
44
+ 'br-tl': TilePattern;
45
+ 'cl-bc': TilePattern;
46
+ };
47
+ constructor(length: number, path: (continuous: boolean, x: number, y: number) => string);
48
+ }
49
+ export declare class Tile {
50
+ section: Section;
51
+ x: number;
52
+ y: number;
53
+ pattern: TilePattern;
54
+ constructor(section: Section, x: number, y: number, pattern: TilePattern);
55
+ toSVGPath(continuous?: boolean): string;
56
+ toSVG(): string;
57
+ }
package/.built/tile.js ADDED
@@ -0,0 +1,78 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.Tile = exports.TilePattern = void 0;
4
+ class TilePattern {
5
+ length;
6
+ path;
7
+ // TODO: replace simple paths with rounded versions
8
+ static patterns = {
9
+ 'tl-cc': new TilePattern(0.7, (continuous, x, y) => `${continuous ? 'L' : 'M'} ${x + 0} ${y + 0}, L ${x + 0.5} ${y + 0.5}`),
10
+ 'tc-cc': new TilePattern(0.5, (continuous, x, y) => `${continuous ? 'L' : 'M'} ${x + 0.5} ${y + 0}, L ${x + 0.5} ${y + 0.5}`),
11
+ 'tr-cc': new TilePattern(0.7, (continuous, x, y) => `${continuous ? 'L' : 'M'} ${x + 1} ${y + 0}, L ${x + 0.5} ${y + 0.5}`),
12
+ 'cl-cc': new TilePattern(0.5, (continuous, x, y) => `${continuous ? 'L' : 'M'} ${x + 0} ${y + 0.5}, L ${x + 0.5} ${y + 0.5}`),
13
+ 'cr-cc': new TilePattern(0.5, (continuous, x, y) => `${continuous ? 'L' : 'M'} ${x + 1} ${y + 0.5}, L ${x + 0.5} ${y + 0.5}`),
14
+ 'bl-cc': new TilePattern(0.7, (continuous, x, y) => `${continuous ? 'L' : 'M'} ${x + 0} ${y + 1}, L ${x + 0.5} ${y + 0.5}`),
15
+ 'bc-cc': new TilePattern(0.5, (continuous, x, y) => `${continuous ? 'L' : 'M'} ${x + 0.5} ${y + 1}, L ${x + 0.5} ${y + 0.5}`),
16
+ 'br-cc': new TilePattern(0.7, (continuous, x, y) => `${continuous ? 'L' : 'M'} ${x + 1} ${y + 1}, L ${x + 0.5} ${y + 0.5}`),
17
+ 'cc-tl': new TilePattern(0.7, (continuous, x, y) => `${continuous ? 'L' : 'M'} ${x + 0.5} ${y + 0.5}, L ${x + 0} ${y + 0}`),
18
+ 'cc-tc': new TilePattern(0.5, (continuous, x, y) => `${continuous ? 'L' : 'M'} ${x + 0.5} ${y + 0.5}, L ${x + 0.5} ${y + 0}`),
19
+ 'cc-tr': new TilePattern(0.7, (continuous, x, y) => `${continuous ? 'L' : 'M'} ${x + 0.5} ${y + 0.5}, L ${x + 1} ${y + 0}`),
20
+ 'cc-cl': new TilePattern(0.5, (continuous, x, y) => `${continuous ? 'L' : 'M'} ${x + 0.5} ${y + 0.5}, L ${x + 0} ${y + 0.5}`),
21
+ 'cc-cr': new TilePattern(0.5, (continuous, x, y) => `${continuous ? 'L' : 'M'} ${x + 0.5} ${y + 0.5}, L ${x + 1} ${y + 0.5}`),
22
+ 'cc-bl': new TilePattern(0.7, (continuous, x, y) => `${continuous ? 'L' : 'M'} ${x + 0.5} ${y + 0.5}, L ${x + 0} ${y + 1}`),
23
+ 'cc-bc': new TilePattern(0.5, (continuous, x, y) => `${continuous ? 'L' : 'M'} ${x + 0.5} ${y + 0.5}, L ${x + 0.5} ${y + 1}`),
24
+ 'cc-br': new TilePattern(0.7, (continuous, x, y) => `${continuous ? 'L' : 'M'} ${x + 0.5} ${y + 0.5}, L ${x + 1} ${y + 1}`),
25
+ 'cr-cl': new TilePattern(1, (continuous, x, y) => `${continuous ? 'L' : 'M'} ${x + 1} ${y + 0.5}, L ${x + 0} ${y + 0.5}`),
26
+ 'cr-tl': new TilePattern(1.2, (continuous, x, y) => `${continuous ? 'L' : 'M'} ${x + 1} ${y + 0.5}, L ${x + 0.5} ${y + 0.5}, L ${x + 0} ${y + 0}`),
27
+ 'cr-bl': new TilePattern(1.2, (continuous, x, y) => `${continuous ? 'L' : 'M'} ${x + 1} ${y + 0.5}, L ${x + 0.5} ${y + 0.5}, L ${x + 0} ${y + 1}`),
28
+ 'cl-cr': new TilePattern(1, (continuous, x, y) => `${continuous ? 'L' : 'M'} ${x + 0} ${y + 0.5}, L ${x + 1} ${y + 0.5}`),
29
+ 'cl-tr': new TilePattern(1.2, (continuous, x, y) => `${continuous ? 'L' : 'M'} ${x + 0} ${y + 0.5}, L ${x + 0.5} ${y + 0.5}, L ${x + 1} ${y + 0}`),
30
+ 'cl-bl': new TilePattern(1.2, (continuous, x, y) => `${continuous ? 'L' : 'M'} ${x + 0} ${y + 0.5}, L ${x + 0.5} ${y + 0.5}, L ${x + 1} ${y + 1}`),
31
+ 'tl-bc': new TilePattern(1.2, (continuous, x, y) => `${continuous ? 'L' : 'M'} ${x + 0} ${y + 0}, L ${x + 0.5} ${y + 0.5}, L ${x + 0.5} ${y + 1}`),
32
+ 'tl-br': new TilePattern(1.4, (continuous, x, y) => `${continuous ? 'L' : 'M'} ${x + 0} ${y + 0}, L ${x + 0.5} ${y + 0.5}, L ${x + 1} ${y + 1}`),
33
+ 'tl-cr': new TilePattern(1.2, (continuous, x, y) => `${continuous ? 'L' : 'M'} ${x + 0} ${y + 0}, L ${x + 0.5} ${y + 0.5}, L ${x + 1} ${y + 0.5}`),
34
+ 'tc-bc': new TilePattern(1, (continuous, x, y) => `${continuous ? 'L' : 'M'} ${x + 0.5} ${y + 0}, L ${x + 0.5} ${y + 1}`),
35
+ 'tc-br': new TilePattern(1.2, (continuous, x, y) => `${continuous ? 'L' : 'M'} ${x + 0.5} ${y + 0}, L ${x + 0.5} ${y + 0.5}, L ${x + 1} ${y + 1}`),
36
+ 'tc-bl': new TilePattern(1.2, (continuous, x, y) => `${continuous ? 'L' : 'M'} ${x + 0.5} ${y + 0}, L ${x + 0.5} ${y + 0.5}, L ${x + 0} ${y + 1}`),
37
+ 'tr-cl': new TilePattern(1.2, (continuous, x, y) => `${continuous ? 'L' : 'M'} ${x + 1} ${y + 0}, L ${x + 0.5} ${y + 0.5}, L ${x + 0} ${y + 0.5}`),
38
+ 'tr-bc': new TilePattern(1.2, (continuous, x, y) => `${continuous ? 'L' : 'M'} ${x + 1} ${y + 0}, L ${x + 0.5} ${y + 0.5}, L ${x + 0.5} ${y + 1}`),
39
+ 'bl-tr': new TilePattern(1.4, (continuous, x, y) => `${continuous ? 'L' : 'M'} ${x + 0} ${y + 1}, L ${x + 0.5} ${y + 0.5}, L ${x + 1} ${y + 0}`),
40
+ 'bl-tc': new TilePattern(1.2, (continuous, x, y) => `${continuous ? 'L' : 'M'} ${x + 0} ${y + 1}, L ${x + 0.5} ${y + 0.5}, L ${x + 0.5} ${y + 0}`),
41
+ 'bl-cr': new TilePattern(1.2, (continuous, x, y) => `${continuous ? 'L' : 'M'} ${x + 0} ${y + 1}, L ${x + 0.5} ${y + 0.5}, L ${x + 1} ${y + 0.5}`),
42
+ 'bc-tc': new TilePattern(1, (continuous, x, y) => `${continuous ? 'L' : 'M'} ${x + 0.5} ${y + 1}, L ${x + 0.5} ${y + 0.5}, L ${x + 0.5} ${y + 0}`),
43
+ 'bc-tr': new TilePattern(1.2, (continuous, x, y) => `${continuous ? 'L' : 'M'} ${x + 0.5} ${y + 1}, L ${x + 0.5} ${y + 0.5}, L ${x + 1} ${y + 0}`),
44
+ 'bc-tl': new TilePattern(1.2, (continuous, x, y) => `${continuous ? 'L' : 'M'} ${x + 0.5} ${y + 1}, L ${x + 0.5} ${y + 0.5}, L ${x + 0} ${y + 0}`),
45
+ 'br-cl': new TilePattern(1.2, (continuous, x, y) => `${continuous ? 'L' : 'M'} ${x + 1} ${y + 1}, L ${x + 0.5} ${y + 0.5}, L ${x + 0} ${y + 0.5}`),
46
+ 'br-tc': new TilePattern(1.2, (continuous, x, y) => `${continuous ? 'L' : 'M'} ${x + 1} ${y + 1}, L ${x + 0.5} ${y + 0.5}, L ${x + 0.5} ${y + 0}`),
47
+ 'br-tl': new TilePattern(1.4, (continuous, x, y) => `${continuous ? 'L' : 'M'} ${x + 1} ${y + 1}, L ${x + 0.5} ${y + 0.5}, L ${x + 0} ${y + 0}`),
48
+ // oddities
49
+ 'cl-bc': new TilePattern(0.7, (continuous, x, y) => `${continuous ? 'L' : 'M'} ${x + 0} ${y + 0.5}, L ${x + 0.5} ${y + 1}`)
50
+ };
51
+ constructor(length, path) {
52
+ this.length = length;
53
+ this.path = path;
54
+ }
55
+ }
56
+ exports.TilePattern = TilePattern;
57
+ class Tile {
58
+ section;
59
+ x;
60
+ y;
61
+ pattern;
62
+ constructor(section, x, y, pattern) {
63
+ this.section = section;
64
+ this.x = x;
65
+ this.y = y;
66
+ this.pattern = pattern;
67
+ }
68
+ toSVGPath(continuous = false) {
69
+ return this.pattern.path(continuous, this.x, this.y);
70
+ }
71
+ toSVG() {
72
+ return `
73
+ <path d="${this.toSVGPath()}" />
74
+ ${this.section.tiles[0] == this ? `<text x="${this.x}" y="${this.y}" font-size="0.2">${this.section.name}</text>` : ''}
75
+ `;
76
+ }
77
+ }
78
+ exports.Tile = Tile;
@@ -0,0 +1,12 @@
1
+ import { Positioner } from "./positioner";
2
+ import { Section } from "./section";
3
+ import { SectionPosition } from "./position";
4
+ export declare class Track {
5
+ section: Section;
6
+ length: number;
7
+ path: string;
8
+ positioners: Positioner[];
9
+ constructor(section: Section, length: number, path: string);
10
+ get head(): SectionPosition;
11
+ dump(): void;
12
+ }
@@ -0,0 +1,29 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.Track = void 0;
4
+ const position_1 = require("./position");
5
+ class Track {
6
+ section;
7
+ length;
8
+ path;
9
+ positioners = [];
10
+ constructor(section, length, path) {
11
+ this.section = section;
12
+ this.length = length;
13
+ this.path = path;
14
+ }
15
+ // the start of the track within the section
16
+ get head() {
17
+ let offset = 0;
18
+ for (let track of this.section.tracks) {
19
+ if (track == this) {
20
+ return new position_1.SectionPosition(this.section, offset, false);
21
+ }
22
+ offset += track.length;
23
+ }
24
+ }
25
+ dump() {
26
+ console.log(this.length);
27
+ }
28
+ }
29
+ exports.Track = Track;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@packtrack/layout",
3
- "version": "1.0.4",
3
+ "version": "1.0.5",
4
4
  "main": ".built/index.js",
5
5
  "typings": ".built/index.d.ts",
6
6
  "scripts": {
package/source/layout.ts CHANGED
@@ -5,10 +5,10 @@ import { Router } from "./router";
5
5
  import { Section } from "./section";
6
6
  import { TilePattern, Tile } from "./tile";
7
7
  import { Track } from "./track";
8
- import { PointPositioner } from "../positioner/point";
9
8
  import { Device } from "./device/device";
10
- import { ResponderType } from "../positioner/responder-type";
9
+ import { ResponderType } from "./positioner/responder-type";
11
10
  import { Channel } from "./device/channel";
11
+ import { PointPositioner } from "./positioner/point";
12
12
 
13
13
  export class Layout {
14
14
  name: string;
@@ -1,6 +1,6 @@
1
1
  import { Positioner } from ".";
2
- import { Channel } from "../source/device/channel";
3
- import { Track } from "../source/track";
2
+ import { Channel } from "../device/channel";
3
+ import { Track } from "../track";
4
4
  import { ResponderType } from "./responder-type";
5
5
 
6
6
  export class PointPositioner extends Positioner {
package/source/track.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { Positioner } from "../positioner";
1
+ import { Positioner } from "./positioner";
2
2
  import { Section } from "./section";
3
3
  import { SectionPosition } from "./position";
4
4
 
File without changes