@packtrack/layout 1.0.13 → 1.2.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.
Files changed (41) hide show
  1. package/.built/device/channel.d.ts +1 -1
  2. package/.built/device/index.d.ts +11 -0
  3. package/.built/device/index.js +20 -0
  4. package/.built/district.d.ts +2 -0
  5. package/.built/district.js +4 -3
  6. package/.built/index.d.ts +8 -2
  7. package/.built/index.js +8 -2
  8. package/.built/layout.d.ts +7 -1
  9. package/.built/layout.js +61 -12
  10. package/.built/monitor.d.ts +9 -0
  11. package/.built/monitor.js +15 -0
  12. package/.built/position.d.ts +3 -1
  13. package/.built/position.js +16 -0
  14. package/.built/positioner/point.d.ts +1 -1
  15. package/.built/power-district/activator.d.ts +7 -0
  16. package/.built/power-district/activator.js +8 -0
  17. package/.built/power-district/index.d.ts +14 -0
  18. package/.built/power-district/index.js +17 -0
  19. package/.built/power-district/monitor.d.ts +7 -0
  20. package/.built/power-district/monitor.js +8 -0
  21. package/.built/power-district/reverser.d.ts +7 -0
  22. package/.built/power-district/reverser.js +8 -0
  23. package/.built/span.d.ts +12 -0
  24. package/.built/span.js +77 -0
  25. package/.built/throttle.d.ts +9 -0
  26. package/.built/throttle.js +15 -0
  27. package/package.json +1 -1
  28. package/source/device/channel.ts +2 -2
  29. package/source/district.ts +21 -18
  30. package/source/index.ts +9 -2
  31. package/source/layout.ts +148 -82
  32. package/source/monitor.ts +19 -0
  33. package/source/position.ts +52 -32
  34. package/source/power-district/activator.ts +9 -0
  35. package/source/power-district/index.ts +24 -0
  36. package/source/power-district/monitor.ts +9 -0
  37. package/source/power-district/reverser.ts +9 -0
  38. package/source/span.ts +88 -0
  39. package/source/throttle.ts +19 -0
  40. package/source/power-district.ts +0 -16
  41. /package/source/device/{device.ts → index.ts} +0 -0
@@ -1,15 +1,18 @@
1
1
  import { Layout } from "./layout";
2
+ import { Monitor } from "./monitor";
2
3
  import { PowerDistrict } from "./power-district";
3
4
  import { Router } from "./router";
4
5
  import { Section } from "./section";
5
6
 
6
7
  export class District {
7
8
  children: District[] = [];
8
-
9
+
9
10
  powerDistricts: PowerDistrict[] = [];
10
11
  sections: Section[] = [];
11
12
  routers: Router[] = [];
12
-
13
+
14
+ monitors: Monitor[] = [];
15
+
13
16
  constructor(
14
17
  public name: string,
15
18
  public parent: District | Layout
@@ -22,65 +25,65 @@ export class District {
22
25
 
23
26
  return `${this.name}.${this.parent.domainName}`;
24
27
  }
25
-
28
+
26
29
  dump() {
27
30
  console.group(`District ${this.domainName}`);
28
-
31
+
29
32
  if (this.powerDistricts.length) {
30
33
  console.group('power districts');
31
-
34
+
32
35
  for (let district of this.powerDistricts) {
33
36
  district.dump();
34
37
  }
35
38
 
36
39
  console.groupEnd();
37
40
  }
38
-
41
+
39
42
  if (this.sections.length) {
40
43
  console.group('sections');
41
-
44
+
42
45
  for (let section of this.sections) {
43
46
  section.dump();
44
47
  }
45
48
 
46
49
  console.groupEnd();
47
50
  }
48
-
51
+
49
52
  if (this.children.length) {
50
53
  console.group('children');
51
-
54
+
52
55
  for (let district of this.children) {
53
56
  district.dump();
54
57
  }
55
58
 
56
59
  console.groupEnd();
57
60
  }
58
-
61
+
59
62
  console.groupEnd();
60
63
  }
61
-
64
+
62
65
  toDotReference() {
63
66
  return `cluster_${this.name.replace(/-/g, '_')}${this.parent instanceof District ? this.parent.toDotReference() : ''}`;
64
67
  }
65
-
68
+
66
69
  toDotDefinition() {
67
70
  return `
68
71
  subgraph ${this.toDotReference()} {
69
72
  label = ${JSON.stringify(this.name)}
70
-
73
+
71
74
  ${this.sections.map(section => section.toDotDefinition()).join('')}
72
75
  ${this.routers.map(router => router.toDotDefinition()).join('')}
73
-
76
+
74
77
  ${this.children.map(child => child.toDotDefinition()).join('')}
75
78
  }
76
79
  `;
77
80
  }
78
-
81
+
79
82
  toDotConnection() {
80
83
  return `
81
84
  ${this.sections.map(section => section.toDotConnection()).join('')}
82
85
  ${this.routers.map(router => router.toDotConnection()).join('')}
83
-
86
+
84
87
  ${this.children.map(child => child.toDotConnection()).join('')}
85
88
  `;
86
89
  }
@@ -97,8 +100,8 @@ export class District {
97
100
 
98
101
  findSVGPositions() {
99
102
  return [
100
- ...this.sections.map(section => section.findSVGPositions()),
103
+ ...this.sections.map(section => section.findSVGPositions()),
101
104
  ...this.children.map(child => child.findSVGPositions())
102
105
  ];
103
106
  }
104
- }
107
+ }
package/source/index.ts CHANGED
@@ -1,16 +1,23 @@
1
1
  export * from './district';
2
2
  export * from './layout';
3
3
  export * from './position';
4
- export * from './power-district';
5
4
  export * from './route';
6
5
  export * from './router';
7
6
  export * from './section';
7
+ export * from './span';
8
8
  export * from './tile';
9
9
  export * from './track';
10
+ export * from './monitor';
11
+ export * from './throttle';
12
+
13
+ export * from './power-district/index';
14
+ export * from './power-district/activator';
15
+ export * from './power-district/monitor';
16
+ export * from './power-district/reverser';
10
17
 
11
18
  export * from './positioner/index';
12
19
  export * from './positioner/point';
13
20
  export * from './positioner/responder-type';
14
21
 
15
- export * from './device/device';
22
+ export * from './device/index';
16
23
  export * from './device/channel';
package/source/layout.ts CHANGED
@@ -5,19 +5,27 @@ 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 { Device } from "./device/device";
8
+ import { Device } from "./device/index";
9
9
  import { ResponderType } from "./positioner/responder-type";
10
10
  import { Channel } from "./device/channel";
11
11
  import { PointPositioner } from "./positioner/point";
12
+ import { PowerDistrictActivator } from "./power-district/activator";
13
+ import { PowerDistrictReverser } from "./power-district/reverser";
14
+ import { PowerDistrictMonitor } from "./power-district/monitor";
15
+ import { Monitor } from "./monitor";
16
+ import { Throttle } from "./throttle";
12
17
 
13
18
  export class Layout {
14
19
  name: string;
15
-
20
+
16
21
  districts: District[] = [];
17
-
22
+
18
23
  devices: Device[] = [];
19
24
  responderType: ResponderType[] = [];
20
25
 
26
+ monitors: Monitor[] = [];
27
+ throttles: Throttle[] = [];
28
+
21
29
  get allDistricts() {
22
30
  const districts: District[] = [];
23
31
 
@@ -43,120 +51,144 @@ export class Layout {
43
51
  layout.name = railway.getAttribute('name');
44
52
 
45
53
  const version = railway.getAttribute('version');
46
-
54
+
47
55
  if (version == '1') {
48
- let district = railway.firstChild;
49
-
50
- while (district) {
51
- if (district.tagName == 'district') {
52
- layout.districts.push(layout.loadDistrict(district, layout));
56
+ let child = railway.firstChild;
57
+
58
+ while (child) {
59
+ if (child.tagName == 'district') {
60
+ layout.districts.push(layout.loadDistrict(child, layout));
61
+ }
62
+
63
+ if (child.tagName == 'monitor') {
64
+ layout.monitors.push(layout.loadMonitor(child, layout));
65
+ }
66
+
67
+ if (child.tagName == 'throttle') {
68
+ layout.throttles.push(layout.loadThrottle(child, layout));
53
69
  }
54
-
55
- district = district.nextSibling;
70
+
71
+ child = child.nextSibling;
56
72
  }
57
-
58
- district = railway.firstChild;
73
+
74
+ child = railway.firstChild;
59
75
  let index = 0;
60
-
61
- while (district) {
62
- if (district.tagName == 'district') {
63
- layout.linkDistrict(district, layout.districts[index]);
64
-
76
+
77
+ while (child) {
78
+ if (child.tagName == 'district') {
79
+ layout.linkDistrict(child, layout.districts[index]);
80
+
65
81
  index++;
66
82
  }
67
-
68
- district = district.nextSibling;
83
+
84
+ child = child.nextSibling;
69
85
  }
70
86
  } else {
71
- throw new Error(`unsupported railway definition file version '${version}'`);
87
+ throw new Error(`Unsupported railway definition file version '${version}'`);
72
88
  }
73
89
 
74
90
  return layout;
75
91
  }
76
-
92
+
93
+ loadMonitor(source, parent: District | Layout) {
94
+ const montior = new Monitor(this.findDevice(source.getAttribute('device')), parent);
95
+
96
+ return montior;
97
+ }
98
+
99
+ loadThrottle(source, parent: District | Layout) {
100
+ const throttle = new Throttle(this.findDevice(source.getAttribute('device')), parent);
101
+
102
+ return throttle;
103
+ }
104
+
77
105
  loadDistrict(source, parent: District | Layout) {
78
106
  const district = new District(source.getAttribute('name'), parent);
79
-
107
+
80
108
  let child = source.firstChild;
81
-
109
+
82
110
  while (child) {
83
111
  if (child.tagName == 'power-districts') {
84
112
  let powerDistrict = child.firstChild;
85
-
113
+
86
114
  while (powerDistrict) {
87
115
  if (powerDistrict.tagName == 'power-district') {
88
116
  district.powerDistricts.push(this.loadPowerDistrict(powerDistrict, district));
89
117
  }
90
-
118
+
91
119
  powerDistrict = powerDistrict.nextSibling;
92
120
  }
93
121
  }
94
-
122
+
95
123
  if (child.tagName == 'section') {
96
124
  this.loadSection(child, district);
97
125
  }
98
-
126
+
99
127
  if (child.tagName == 'router') {
100
128
  district.routers.push(this.loadRouter(child, district));
101
129
  }
102
-
130
+
103
131
  if (child.tagName == 'district') {
104
132
  district.children.push(this.loadDistrict(child, district));
105
133
  }
106
-
134
+
135
+ if (child.tagName == 'monitor') {
136
+ district.monitors.push(this.loadMonitor(child, district));
137
+ }
138
+
107
139
  child = child.nextSibling;
108
140
  }
109
-
141
+
110
142
  return district;
111
143
  }
112
-
144
+
113
145
  linkDistrict(source, district: District) {
114
146
  let child = source.firstChild;
115
-
147
+
116
148
  let sectionIndex = 0;
117
149
  let childIndex = 0;
118
-
150
+
119
151
  while (child) {
120
152
  if (child.tagName == 'section') {
121
153
  this.linkSection(child, district.sections[sectionIndex]);
122
-
154
+
123
155
  sectionIndex++;
124
156
  }
125
-
157
+
126
158
  if (child.tagName == 'router') {
127
159
  this.linkRouter(child, district.routers.find(router => router.name == child.getAttribute('name'))!);
128
160
  }
129
-
161
+
130
162
  if (child.tagName == 'district') {
131
163
  this.linkDistrict(child, district.children[childIndex]);
132
-
164
+
133
165
  childIndex++;
134
166
  }
135
-
167
+
136
168
  child = child.nextSibling;
137
169
  }
138
170
  }
139
-
171
+
140
172
  loadSection(source, district: District) {
141
173
  const section = new Section(source.getAttribute('name'), district);
142
174
  district.sections.push(section);
143
-
175
+
144
176
  let child = source.firstChild;
145
-
177
+
146
178
  while (child) {
147
179
  if (child.tagName == 'tracks') {
148
180
  let trackNode = child.firstChild;
149
-
181
+
150
182
  while (trackNode) {
151
183
  if (trackNode.tagName == 'track') {
152
184
  const track = new Track(
153
- section,
154
- +trackNode.getAttribute('length'),
185
+ section,
186
+ +trackNode.getAttribute('length'),
155
187
  trackNode.getAttribute('path')
156
188
  );
157
189
 
158
190
  section.tracks.push(track);
159
-
191
+
160
192
  let trackChild = trackNode.firstChild;
161
193
 
162
194
  while (trackChild) {
@@ -170,7 +202,7 @@ export class Layout {
170
202
  const responderType = this.findResponderType(positioner.getAttribute('responder'));
171
203
 
172
204
  track.positioners.push(new PointPositioner(
173
- track,
205
+ track,
174
206
  +positioner.getAttribute('offset'),
175
207
  channel,
176
208
  responderType
@@ -184,7 +216,7 @@ export class Layout {
184
216
  trackChild = trackChild.nextSibling;
185
217
  }
186
218
  }
187
-
219
+
188
220
  trackNode = trackNode.nextSibling;
189
221
  }
190
222
  }
@@ -198,7 +230,7 @@ export class Layout {
198
230
 
199
231
  section.tiles.push(new Tile(section, +child.getAttribute('x'), +child.getAttribute('y'), TilePattern.patterns[pattern]))
200
232
  }
201
-
233
+
202
234
  child = child.nextSibling;
203
235
  }
204
236
  }
@@ -241,111 +273,145 @@ export class Layout {
241
273
 
242
274
  return type;
243
275
  }
244
-
276
+
245
277
  linkSection(source, section: Section) {
246
278
  let child = source.firstChild;
247
-
279
+
248
280
  while (child) {
249
281
  if (child.tagName == 'out') {
250
282
  const out = this.findSection(child.getAttribute('section'), section.district);
251
-
283
+
252
284
  section.out = out;
253
285
  out.in = section;
254
286
  }
255
-
287
+
256
288
  child = child.nextSibling;
257
289
  }
258
290
  }
259
-
291
+
260
292
  findSection(path: string, base: District, source = base) {
261
293
  const parts = path.split('.');
262
-
294
+
263
295
  if (parts.length == 0) {
264
296
  throw `section '${path}' not found from '${source.name}': invalid name`;
265
297
  }
266
-
298
+
267
299
  if (parts.length == 1) {
268
300
  const localSection = base.sections.find(section => section.name == parts[0]);
269
-
301
+
270
302
  if (!localSection) {
271
303
  throw new Error(`Section '${path}' not found from '${source.name}': section does not exist in '${base.name}'`);
272
304
  }
273
-
305
+
274
306
  return localSection;
275
307
  }
276
-
308
+
277
309
  const sectionName = parts.pop()!;
278
-
310
+
279
311
  let pool: District | Layout = base;
280
-
312
+
281
313
  for (let index = 0; index < parts.length; index++) {
282
314
  if (pool instanceof Layout || !pool.parent) {
283
315
  throw new Error(`Section '${path}' could not be found from '${source.name}': district '${pool.name}' does not have a parent`);
284
316
  }
285
-
317
+
286
318
  pool = pool.parent!;
287
319
  }
288
-
320
+
289
321
  for (let part of parts) {
290
322
  const child = (pool instanceof District ? pool.children : pool.districts).find(child => child.name == part);
291
-
323
+
292
324
  if (!child) {
293
325
  throw new Error(`Section '${path}' could not be found from '${source.name}': district '${pool.name}' does not have a child named '${part}'`);
294
326
  }
295
-
327
+
296
328
  pool = child;
297
329
  }
298
330
 
299
331
  if (pool instanceof Layout) {
300
332
  throw new Error(`Section '${path}' could not be found from '${source.name}': a layout cannot directly include a section`);
301
333
  }
302
-
334
+
303
335
  return this.findSection(sectionName, pool, source);
304
336
  }
305
-
337
+
306
338
  loadRouter(source, district: District) {
307
339
  const router = new Router(source.getAttribute('name'), district);
308
-
340
+
309
341
  return router;
310
342
  }
311
-
343
+
312
344
  linkRouter(source, router: Router) {
313
345
  let child = source.firstChild;
314
-
346
+ let active: Route;
347
+
315
348
  while (child) {
316
349
  if (child.tagName == 'route') {
317
350
  const route = new Route(child.getAttribute('name'), router);
318
-
351
+
319
352
  route.in = this.findSection(child.getAttribute('in'), router.district);
320
353
  route.in.out = router;
321
-
354
+
322
355
  route.out = this.findSection(child.getAttribute('out'), router.district);
323
356
  route.out.in = router;
324
-
357
+
358
+ if (child.hasAttribute('active')) {
359
+ if (active) {
360
+ throw new Error(`Router '${router.domainName}' has multiple active routes (${active.name}, ${route.name}).`);
361
+ }
362
+
363
+ active = route;
364
+ }
365
+
325
366
  router.routes.push(route);
326
367
  }
327
-
368
+
328
369
  child = child.nextSibling;
329
370
  }
371
+
372
+ router.activeRoute = active;
330
373
  }
331
-
374
+
332
375
  loadPowerDistrict(source, district: District) {
333
376
  const powerDistrict = new PowerDistrict(source.getAttribute('name'), district);
334
-
377
+
378
+ let actor = source.firstChild;
379
+
380
+ while (actor) {
381
+ if (actor.tagName == 'activator' || actor.tagName == 'reverser' || actor.tagName == 'monitor') {
382
+ const device = this.findDevice(actor.getAttribute('device'));
383
+ const channel = this.findChannel(device, actor.getAttribute('channel'));
384
+
385
+ if (actor.tagName == 'activator') {
386
+ powerDistrict.activator = new PowerDistrictActivator(device, channel);
387
+ }
388
+
389
+ if (actor.tagName == 'reverser') {
390
+ powerDistrict.reverser = new PowerDistrictReverser(device, channel);
391
+ }
392
+
393
+ if (actor.tagName == 'monitor') {
394
+ powerDistrict.monitor = new PowerDistrictMonitor(device, channel);
395
+ }
396
+ }
397
+
398
+ actor = actor.nextSibling;
399
+ }
400
+
335
401
  return powerDistrict;
336
402
  }
337
403
 
338
404
  toDot() {
339
405
  let dot = 'digraph G {';
340
-
406
+
341
407
  for (let district of this.districts) {
342
408
  dot += district.toDotDefinition();
343
409
  }
344
-
410
+
345
411
  for (let district of this.districts) {
346
412
  dot += district.toDotConnection();
347
413
  }
348
-
414
+
349
415
  return `${dot}}`;
350
416
  }
351
417
 
@@ -366,11 +432,11 @@ export class Layout {
366
432
 
367
433
  </style>
368
434
  `;
369
-
435
+
370
436
  for (let district of this.districts) {
371
437
  svg += district.toSVG();
372
438
  }
373
-
439
+
374
440
  return `${svg}${inject}</svg>`;
375
441
  }
376
442
 
@@ -396,4 +462,4 @@ export class Layout {
396
462
 
397
463
  console.groupEnd();
398
464
  }
399
- }
465
+ }
@@ -0,0 +1,19 @@
1
+ import { Device } from "./device";
2
+ import { District } from "./district";
3
+ import { Layout } from "./layout";
4
+
5
+ export class Monitor {
6
+ constructor(
7
+ public device: Device,
8
+ public scope: District | Layout
9
+ ) { }
10
+
11
+ dump() {
12
+ console.group('Monitor');
13
+ console.log('scope:', this.scope instanceof Layout ? '*' : this.scope.domainName);
14
+
15
+ this.device.dump();
16
+
17
+ console.groupEnd();
18
+ }
19
+ }
@@ -1,35 +1,55 @@
1
1
  import { Section } from './section.js';
2
2
 
3
3
  export class SectionPosition {
4
- constructor(
5
- public section: Section,
6
- public offset: number,
7
- public reversed: boolean
8
- ) {}
9
-
10
- get absolutePosition() {
11
- if (this.reversed) {
12
- return this.section.length - this.offset;
13
- }
14
-
15
- return this.offset;
16
- }
17
-
18
- advance(distance: number) {
19
- if (this.offset + distance > this.section.length) {
20
- const next = this.section.next(this.reversed);
21
-
22
- if (!next) {
23
- throw new Error(`Illegal advancement ${this} + ${distance}`);
24
- }
25
-
26
- return new SectionPosition(next, 0, this.reversed).advance(this.offset + distance - this.section.length);
27
- }
28
-
29
- return new SectionPosition(this.section, this.offset + distance, this.reversed);
30
- }
31
-
32
- toString() {
33
- return `${this.section.name} @ ${this.offset.toFixed(1)} ${this.reversed ? 'backward' : 'forward'}`;
34
- }
35
- }
4
+ constructor(
5
+ public section: Section,
6
+ public offset: number,
7
+ public reversed: boolean
8
+ ) {
9
+ if (offset > section.length || offset < 0) {
10
+ throw new Error(`Offset ${offset} out of range for section '${section.domainName}' (0 - ${section.length})`);
11
+ }
12
+ }
13
+
14
+ // returns the absolute position of the point inside the section
15
+ // regardless of direction
16
+ get absolutePosition() {
17
+ if (this.reversed) {
18
+ return this.section.length - this.offset;
19
+ }
20
+
21
+ return this.offset;
22
+ }
23
+
24
+ // TODO verify reverse
25
+ advance(distance: number): SectionPosition {
26
+ if (distance < 0) {
27
+ return this.invert().advance(-distance).invert();
28
+ }
29
+
30
+ if (this.offset + distance > this.section.length) {
31
+ const next = this.section.next(this.reversed);
32
+
33
+ if (!next) {
34
+ throw new Error(`Illegal advancement ${this} + ${distance}`);
35
+ }
36
+
37
+ return new SectionPosition(next, 0, this.reversed).advance(this.offset + distance - this.section.length);
38
+ }
39
+
40
+ return new SectionPosition(this.section, this.offset + distance, this.reversed);
41
+ }
42
+
43
+ // reverse direction
44
+ private invert() {
45
+ return new SectionPosition(this.section, this.section.length - this.offset, !this.reversed);
46
+ }
47
+
48
+ toString() {
49
+ return `${this.section.name} @ ${this.offset.toFixed(1)} ${this.reversed ? 'backward' : 'forward'}`;
50
+ }
51
+
52
+ toPackTrackValue() {
53
+ return `${this.section.domainName}@${this.offset}${this.reversed ? 'R' : 'F'}`;
54
+ }
55
+ }
@@ -0,0 +1,9 @@
1
+ import { Channel } from "../device/channel";
2
+ import { Device } from "../device/index";
3
+
4
+ export class PowerDistrictActivator {
5
+ constructor(
6
+ public device: Device,
7
+ public channel: Channel
8
+ ) {}
9
+ }