circuitscript 0.1.2 → 0.1.3

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.
@@ -2,16 +2,15 @@ import { Graph, alg } from '@dagrejs/graphlib';
2
2
  import { SymbolCustom, SymbolDrawing, SymbolCustomModule, SymbolPlaceholder, SymbolText, PlaceHolderCommands } from "./draw_symbols.mjs";
3
3
  import { FrameAction, SequenceAction } from "./objects/ExecutionScope.mjs";
4
4
  import { ComponentTypes, defaultFrameTitleTextSize, defaultGridSizeUnits, FrameType, ParamKeys, SymbolPinSide, WireAutoDirection } from './globals.mjs';
5
- import { Geometry } from './geometry.mjs';
5
+ import { Geometry, HorizontalAlign, VerticalAlign } from './geometry.mjs';
6
6
  import { Logger } from './logger.mjs';
7
- import { Frame, FrameParamKeys, FramePlotDirection } from './objects/Frame.mjs';
8
- import { combineMaps, getBoundsSize, printBounds, resizeBounds, resizeToNearestGrid, roundValue, toNearestGrid } from './utils.mjs';
7
+ import { FixedFrameIds, Frame, FrameParamKeys, FramePlotDirection } from './objects/Frame.mjs';
8
+ import { areasOverlap, combineMaps, getBoundsSize, printBounds, resizeBounds, resizeToNearestGrid, roundValue, toNearestGrid } from './utils.mjs';
9
9
  import { Direction } from './objects/types.mjs';
10
10
  import { milsToMM, UnitDimension } from './helpers.mjs';
11
11
  import { numeric, NumericValue } from './objects/ParamDefinition.mjs';
12
12
  export class LayoutEngine {
13
13
  logger;
14
- placeSubgraphVersion = 2;
15
14
  layoutWarnings = [];
16
15
  showBaseFrame = false;
17
16
  constructor(options = { showBaseFrame: false }) {
@@ -140,17 +139,17 @@ export class LayoutEngine {
140
139
  baseFrame.borderWidth = numeric(0);
141
140
  if (this.showBaseFrame) {
142
141
  baseFrame.borderWidth = numeric(5);
143
- baseFrame.width = 11692 - 400 * 2;
144
- baseFrame.height = 8267 - 400 * 2;
142
+ baseFrame.width = numeric(11692 - 400 * 2);
143
+ baseFrame.height = numeric(8267 - 400 * 2);
145
144
  }
146
145
  baseFrame.x = numeric(0);
147
146
  baseFrame.y = numeric(0);
148
- let textObjects = [];
149
- let elementFrames = [];
150
147
  baseFrame.bounds = {
151
148
  xmin: 0, ymin: 0,
152
149
  xmax: 0, ymax: 0,
153
150
  };
151
+ let textObjects = [];
152
+ let elementFrames = [];
154
153
  if (subgraphInfo.length > 0) {
155
154
  const result = this.prepareFrames(graph, subgraphInfo, baseFrame);
156
155
  textObjects = result.textObjects;
@@ -175,10 +174,10 @@ export class LayoutEngine {
175
174
  const innerItems = frame.innerItems;
176
175
  const frames = [];
177
176
  innerItems.forEach(item => {
178
- if (item.type === RenderFrameType.Elements) {
177
+ if (item.renderType === RenderFrameType.Elements) {
179
178
  frames.push(item);
180
179
  }
181
- else if (item.type === RenderFrameType.Container) {
180
+ else if (item.renderType === RenderFrameType.Container) {
182
181
  const innerFrames = this.collectElementFrames(item, level + 1);
183
182
  frames.push(...innerFrames);
184
183
  }
@@ -197,11 +196,13 @@ export class LayoutEngine {
197
196
  innerFrame.x = innerFrame.x.add(frame.x);
198
197
  innerFrame.y = innerFrame.y.add(frame.y);
199
198
  }
200
- if (innerFrame.type === RenderFrameType.Elements) {
199
+ if (innerFrame.renderType === RenderFrameType.Elements) {
201
200
  this.print(level, "".padStart(level * 4), 'element frame', innerFrame.x, innerFrame.y);
202
- innerFrame.innerItems.forEach(item2 => {
203
- item2.x = item2.x.add(innerFrame.x).sub(innerFrame.translateX);
204
- item2.y = item2.y.add(innerFrame.y).sub(innerFrame.translateY);
201
+ const diffX = innerFrame.x.sub(innerFrame.translateX);
202
+ const diffY = innerFrame.y.sub(innerFrame.translateY);
203
+ innerFrame.innerItems.forEach(item => {
204
+ item.x = item.x.add(diffX);
205
+ item.y = item.y.add(diffY);
205
206
  });
206
207
  }
207
208
  else {
@@ -213,11 +214,10 @@ export class LayoutEngine {
213
214
  placeAndSizeFrame(frame, level = 0) {
214
215
  const innerFrames = frame.innerItems;
215
216
  const gridSize = defaultGridSizeUnits;
216
- let accumX = numeric(0);
217
- let accumY = numeric(0);
217
+ const frameDirection = frame.direction;
218
218
  const boundPoints = [];
219
219
  const frameSizes = innerFrames.map(innerFrame => {
220
- if (innerFrame.type === RenderFrameType.Elements) {
220
+ if (innerFrame.renderType === RenderFrameType.Elements) {
221
221
  innerFrame.bounds = resizeToNearestGrid(innerFrame.bounds, gridSize);
222
222
  innerFrame.translateX = innerFrame.bounds.xmin;
223
223
  innerFrame.translateY = innerFrame.bounds.ymin;
@@ -231,10 +231,14 @@ export class LayoutEngine {
231
231
  const { width } = getBoundsSize(item);
232
232
  return width;
233
233
  }));
234
+ const maxHeight = Math.max(...frameSizes.map(item => {
235
+ const { height } = getBoundsSize(item);
236
+ return height;
237
+ }));
234
238
  let accumRowWidth = 0;
235
- let titleFrameWidth = null;
239
+ let titleFrameWidth = 0;
236
240
  const inRowShouldCenterInnerFrames = true;
237
- if (frame.direction === FramePlotDirection.Row) {
241
+ if (frameDirection === FramePlotDirection.Row) {
238
242
  accumRowWidth = frameSizes.reduce((accum, item, index) => {
239
243
  const { width } = getBoundsSize(item);
240
244
  if (frame.innerItems[index].containsTitle) {
@@ -248,85 +252,246 @@ export class LayoutEngine {
248
252
  else {
249
253
  accumRowWidth = maxWidth;
250
254
  }
255
+ let frameWidth = numeric(0);
256
+ let frameHeight = numeric(0);
257
+ let frameXMin = numeric(0);
258
+ let frameYMin = numeric(0);
259
+ const frameParams = frame.frame.parameters;
260
+ const avoidAreas = [];
261
+ if (frameParams.has(FrameParamKeys.SheetType)) {
262
+ const frameComponent = frameParams.get(FrameParamKeys.SheetType);
263
+ const frameDrawing = frameComponent.displayProp;
264
+ frameDrawing.variables = combineMaps(frameComponent.parameters, frameParams);
265
+ const rects = ExtractDrawingRects(frameDrawing);
266
+ const drawableRect = rects.find(rect => rect.className === 'plot-area');
267
+ let frameMinX = numeric(0);
268
+ let frameMinY = numeric(0);
269
+ if (drawableRect) {
270
+ frameMinX = milsToMM(drawableRect.x);
271
+ frameMinY = milsToMM(drawableRect.y);
272
+ frameWidth = milsToMM(drawableRect.width);
273
+ frameHeight = milsToMM(drawableRect.height);
274
+ }
275
+ const infoAreaRect = rects.filter(rect => rect.className === 'keepout-area');
276
+ infoAreaRect.forEach(area => {
277
+ const x1 = area.x;
278
+ const y1 = area.y;
279
+ const x2 = area.x.add(area.width);
280
+ const y2 = area.y.add(area.height);
281
+ avoidAreas.push([
282
+ milsToMM(x1).sub(frameMinX).toNumber(),
283
+ milsToMM(y1).sub(frameMinY).toNumber(),
284
+ milsToMM(x2).sub(frameMinX).toNumber(),
285
+ milsToMM(y2).sub(frameMinY).toNumber(),
286
+ ]);
287
+ });
288
+ }
289
+ else {
290
+ if (frame.width !== null) {
291
+ frameWidth = frame.width;
292
+ }
293
+ if (frame.height !== null) {
294
+ frameHeight = frame.height;
295
+ }
296
+ }
251
297
  const offsetX = frame.padding;
252
298
  const offsetY = frame.padding;
253
299
  let centeredOffsetX = 0;
254
300
  let widthForTitle;
255
- if (titleFrameWidth > accumRowWidth) {
301
+ if (frameWidth.toNumber() !== 0) {
302
+ widthForTitle = frameWidth.toNumber();
303
+ }
304
+ else if (titleFrameWidth > accumRowWidth) {
256
305
  widthForTitle = titleFrameWidth;
257
306
  }
258
307
  else {
259
308
  widthForTitle = accumRowWidth;
260
309
  }
261
- if (frame.direction === FramePlotDirection.Row &&
310
+ if (frameDirection === FramePlotDirection.Row &&
262
311
  inRowShouldCenterInnerFrames &&
263
312
  titleFrameWidth !== null && titleFrameWidth > accumRowWidth) {
264
- centeredOffsetX = toNearestGrid(titleFrameWidth / 2 - accumRowWidth / 2, gridSize);
313
+ centeredOffsetX =
314
+ toNearestGrid(titleFrameWidth / 2 - accumRowWidth / 2, gridSize);
265
315
  }
266
- innerFrames.forEach(innerFrame => {
267
- const { width: frameWidth, height: frameHeight } = getBoundsSize(innerFrame.bounds);
316
+ let title_align = HorizontalAlign.Middle;
317
+ if (frameParams.has(FrameParamKeys.TitleAlign)) {
318
+ title_align = frameParams.get(FrameParamKeys.TitleAlign);
319
+ }
320
+ let accumX = numeric(0);
321
+ let accumY = numeric(0);
322
+ innerFrames.forEach((innerFrame, index) => {
323
+ const { width: innerFrameWidth, height: innerFrameHeight } = getBoundsSize(innerFrame.bounds);
324
+ let arrangeLineAttempts = 0;
325
+ const maxAttempts = 10;
326
+ let innerFrameX = numeric(0);
327
+ let innerFrameY = numeric(0);
268
328
  if (innerFrame.containsTitle) {
269
- innerFrame.x = offsetX.add(accumX).add(toNearestGrid(widthForTitle / 2 - frameWidth / 2, gridSize));
329
+ innerFrame.x = offsetX.add(accumX);
270
330
  innerFrame.y = offsetY.add(accumY);
271
- accumY = accumY.add(frameHeight).add(frame.gap);
331
+ accumY = accumY.add(innerFrameHeight).add(frame.gap);
272
332
  }
273
333
  else {
274
- if (frame.direction === FramePlotDirection.Column) {
275
- innerFrame.x = offsetX.add(accumX).add(toNearestGrid(maxWidth / 2 - frameWidth / 2, gridSize));
276
- innerFrame.y = offsetY.add(accumY);
277
- accumY = accumY.add(frameHeight).add(frame.gap);
334
+ if (frameDirection === FramePlotDirection.Column) {
335
+ innerFrameX = offsetX.add(accumX);
336
+ innerFrameY = offsetY.add(accumY);
337
+ while (arrangeLineAttempts < maxAttempts) {
338
+ const innerFrameY2 = innerFrameY.toNumber() + innerFrameHeight;
339
+ const doesExceedFrameHeight = (frameHeight.toNumber() > 0
340
+ && innerFrameY2 > frameHeight.toNumber());
341
+ const { xmax } = getBoundsFromPoints(boundPoints);
342
+ const tmpX1 = innerFrameX.toNumber();
343
+ const tmpY1 = innerFrameY.toNumber();
344
+ const tmpX2 = tmpX1 + innerFrameWidth;
345
+ const tmpY2 = tmpY1 + innerFrameHeight;
346
+ const frameArea = [tmpX1, tmpY1, tmpX2, tmpY2];
347
+ const overlaps = avoidAreas.filter(area => areasOverlap(frameArea, area));
348
+ const doesOverlapAreasToAvoid = overlaps.length > 0;
349
+ if (doesExceedFrameHeight || doesOverlapAreasToAvoid) {
350
+ innerFrameY = offsetY;
351
+ const nextX = numeric(xmax).sub(offsetX).add(frame.gap);
352
+ innerFrameX = offsetX.add(nextX);
353
+ accumY = numeric(0);
354
+ accumX = nextX;
355
+ }
356
+ arrangeLineAttempts++;
357
+ if (arrangeLineAttempts > maxAttempts) {
358
+ throw "Failed to place inner frame";
359
+ }
360
+ }
361
+ innerFrame.x = innerFrameX;
362
+ innerFrame.y = innerFrameY;
363
+ accumY = accumY.add(innerFrameHeight).add(frame.gap);
278
364
  }
279
- else if (frame.direction === FramePlotDirection.Row) {
280
- innerFrame.x = offsetX.add(centeredOffsetX).add(accumX);
281
- innerFrame.y = offsetY.add(accumY);
282
- accumX = accumX.add(frameWidth).add(frame.gap);
365
+ else if (frameDirection === FramePlotDirection.Row) {
366
+ innerFrameX = offsetX.add(centeredOffsetX).add(accumX);
367
+ innerFrameY = offsetY.add(accumY);
368
+ while (arrangeLineAttempts < maxAttempts) {
369
+ const innerFrameX2 = innerFrameX.toNumber() + innerFrameWidth;
370
+ const doesExceedFrameWidth = (frameWidth.toNumber() > 0
371
+ && innerFrameX2 > frameWidth.toNumber());
372
+ const tmpX1 = innerFrameX.toNumber();
373
+ const tmpY1 = innerFrameY.toNumber();
374
+ const tmpX2 = tmpX1 + innerFrameWidth;
375
+ const tmpY2 = tmpY1 + innerFrameHeight;
376
+ const frameArea = [tmpX1, tmpY1, tmpX2, tmpY2];
377
+ const overlaps = avoidAreas.filter(area => areasOverlap(frameArea, area));
378
+ const doesOverlapAreasToAvoid = overlaps.length > 0;
379
+ if (doesExceedFrameWidth || doesOverlapAreasToAvoid) {
380
+ innerFrameX = offsetX.add(centeredOffsetX);
381
+ const { ymax } = getBoundsFromPoints(boundPoints);
382
+ const nextY = numeric(ymax).sub(offsetY).add(frame.gap);
383
+ innerFrameY = offsetY.add(nextY);
384
+ accumX = numeric(0);
385
+ accumY = nextY;
386
+ }
387
+ else {
388
+ break;
389
+ }
390
+ arrangeLineAttempts++;
391
+ if (arrangeLineAttempts > maxAttempts) {
392
+ throw "Failed to place inner frame";
393
+ }
394
+ }
395
+ innerFrame.x = innerFrameX;
396
+ innerFrame.y = innerFrameY;
397
+ accumX = accumX.add(innerFrameWidth).add(frame.gap);
283
398
  }
284
399
  }
285
- boundPoints.push([innerFrame.x, innerFrame.y], [innerFrame.x.add(frameWidth), innerFrame.y.add(frameHeight)]);
400
+ boundPoints.push([
401
+ innerFrame.x.toNumber(),
402
+ innerFrame.y.toNumber()
403
+ ], [
404
+ innerFrame.x.add(innerFrameWidth).toNumber(),
405
+ innerFrame.y.add(innerFrameHeight).toNumber()
406
+ ]);
286
407
  });
287
- const tmpBoundPoints = boundPoints.map(item => {
288
- return [
289
- item[0].toNumber(),
290
- item[1].toNumber(),
291
- ];
408
+ const contentsBounds = resizeBounds(getBoundsFromPoints(boundPoints), frame.padding.toNumber());
409
+ const contentsWidth = contentsBounds.xmax - contentsBounds.xmin;
410
+ const contentsHeight = contentsBounds.ymax - contentsBounds.ymin;
411
+ let hAlign = HorizontalAlign.Middle;
412
+ let vAlign = VerticalAlign.Middle;
413
+ if (frameParams.has(FrameParamKeys.HorizontalAlign)) {
414
+ hAlign =
415
+ frameParams.get(FrameParamKeys.HorizontalAlign);
416
+ }
417
+ if (frameParams.has(FrameParamKeys.VerticalAlign)) {
418
+ vAlign =
419
+ frameParams.get(FrameParamKeys.VerticalAlign);
420
+ }
421
+ if (frameParams.has(FrameParamKeys.SheetType)) {
422
+ frameXMin = numeric(0);
423
+ frameYMin = numeric(0);
424
+ }
425
+ else {
426
+ frameXMin = numeric(contentsBounds.xmin);
427
+ frameYMin = numeric(contentsBounds.ymin);
428
+ }
429
+ if (frameWidth.toNumber() === 0) {
430
+ frameWidth = numeric(contentsWidth);
431
+ }
432
+ if (frameHeight.toNumber() === 0) {
433
+ frameHeight = numeric(contentsHeight);
434
+ }
435
+ const titleFrame = innerFrames.find(frame => {
436
+ return frame.containsTitle;
292
437
  });
293
- const contentsBounds = resizeBounds(getBoundsFromPoints(tmpBoundPoints), frame.padding.toNumber());
294
- if (frame.frame.parameters.has(FrameParamKeys.SheetType)) {
295
- const frameComponent = frame.frame.parameters.get(FrameParamKeys.SheetType);
296
- const frameDrawing = frameComponent.displayProp;
297
- frameDrawing.variables = combineMaps(frameComponent.parameters, frame.frame.parameters);
298
- const rects = ExtractDrawingRects(frameDrawing);
299
- let frameWidth = numeric(0);
300
- let frameHeight = numeric(0);
301
- if (rects[1]) {
302
- frameWidth = milsToMM(rects[1].width);
303
- frameHeight = milsToMM(rects[1].height);
438
+ if (titleFrame) {
439
+ const { width: innerFrameWidth } = getBoundsSize(titleFrame.bounds);
440
+ let titleOffset = 0;
441
+ switch (title_align) {
442
+ case HorizontalAlign.Left:
443
+ titleOffset = 0;
444
+ break;
445
+ case HorizontalAlign.Middle:
446
+ titleOffset = toNearestGrid(widthForTitle / 2 - innerFrameWidth / 2, gridSize);
447
+ break;
448
+ case HorizontalAlign.Right:
449
+ titleOffset = frameWidth.toNumber() - innerFrameWidth;
450
+ break;
304
451
  }
305
- const contentsWidth = contentsBounds.xmax - contentsBounds.xmin;
306
- const contentsHeight = contentsBounds.ymax - contentsBounds.ymin;
307
- const frameOffsetX = toNearestGrid((frameWidth.toNumber() - contentsWidth) / 2, gridSize);
308
- const frameOffsetY = toNearestGrid((frameHeight.toNumber() - contentsHeight) / 2, gridSize);
309
- innerFrames.forEach(innerFrame => {
310
- innerFrame.x = innerFrame.x.add(frameOffsetX);
311
- innerFrame.y = innerFrame.y.add(frameOffsetY);
312
- });
313
- frame.bounds = {
314
- xmin: 0,
315
- ymin: 0,
316
- xmax: frameWidth.toNumber(),
317
- ymax: frameHeight.toNumber(),
318
- };
452
+ titleFrame.x = titleFrame.x.add(titleOffset);
319
453
  }
320
- else {
321
- frame.bounds = contentsBounds;
454
+ let frameOffsetX = 0;
455
+ let frameOffsetY = 0;
456
+ switch (hAlign) {
457
+ case HorizontalAlign.Left:
458
+ frameOffsetX = 0;
459
+ break;
460
+ case HorizontalAlign.Middle:
461
+ frameOffsetX = toNearestGrid((frameWidth.toNumber() - contentsWidth) / 2, gridSize);
462
+ break;
463
+ case HorizontalAlign.Right:
464
+ frameOffsetX = toNearestGrid(frameWidth.toNumber() - contentsWidth, gridSize);
465
+ break;
466
+ }
467
+ switch (vAlign) {
468
+ case VerticalAlign.Top:
469
+ frameOffsetY = 0;
470
+ break;
471
+ case VerticalAlign.Middle:
472
+ frameOffsetY = toNearestGrid((frameHeight.toNumber() - contentsHeight) / 2, gridSize);
473
+ break;
474
+ case VerticalAlign.Bottom:
475
+ frameOffsetY = toNearestGrid(frameHeight.toNumber() - contentsHeight, gridSize);
476
+ break;
322
477
  }
478
+ innerFrames.forEach(innerFrame => {
479
+ innerFrame.x = innerFrame.x.add(frameOffsetX);
480
+ innerFrame.y = innerFrame.y.add(frameOffsetY);
481
+ });
482
+ frame.bounds = {
483
+ xmin: frameXMin.toNumber(),
484
+ ymin: frameYMin.toNumber(),
485
+ xmax: frameXMin.toNumber() + frameWidth.toNumber(),
486
+ ymax: frameYMin.toNumber() + frameHeight.toNumber(),
487
+ };
323
488
  }
324
489
  dumpFrame(frame, level = 0) {
325
490
  this.print(level, "".padStart(level * 4), 'frame, items:', frame.innerItems.length);
326
491
  frame.innerItems.forEach(item => {
327
492
  item = item;
328
- if (item.type === RenderFrameType.Elements) {
329
- this.print(level, "".padStart(level * 4), 'element frame, items:', item.innerItems.map(item => {
493
+ if (item.renderType === RenderFrameType.Elements) {
494
+ this.print(level, "".padStart(level * 4), '- element frame, items:', item.innerItems.map(item => {
330
495
  if (item instanceof RenderComponent) {
331
496
  return item.component.instanceName;
332
497
  }
@@ -337,7 +502,7 @@ export class LayoutEngine {
337
502
  }));
338
503
  }
339
504
  else {
340
- this.print(level, "".padStart(level * 4), 'container');
505
+ this.print(level, "".padStart(level * 4), '- container');
341
506
  this.dumpFrame(item, level + 1);
342
507
  }
343
508
  });
@@ -354,21 +519,21 @@ export class LayoutEngine {
354
519
  accum.push(item);
355
520
  }
356
521
  else if (item instanceof RenderComponent) {
357
- const instanceName = item.component.instanceName;
522
+ const { instanceName } = item.component;
358
523
  if (ignoreItems.indexOf(instanceName) === -1) {
359
- const subgraph = subgraphInfo.find(item => {
360
- return item.components.indexOf(instanceName) !== -1;
524
+ const withinSubgraph = subgraphInfo.find(subgraphInfo => {
525
+ return subgraphInfo.components.indexOf(instanceName) !== -1;
361
526
  });
362
- if (subgraph !== undefined) {
363
- const tmpFrame = new RenderFrame(new Frame(-2), RenderFrameType.Elements);
527
+ if (withinSubgraph !== undefined) {
528
+ const tmpFrame = new RenderFrame(new Frame(FixedFrameIds.FrameIdNotUsed), RenderFrameType.Elements);
364
529
  tmpFrame.subgraphId = instanceName;
365
530
  tmpFrame.innerItems =
366
- subgraph.components.map(instanceName => {
531
+ withinSubgraph.components.map(instanceName => {
367
532
  const [, component,] = graph.node(instanceName);
368
533
  return component;
369
534
  });
370
- tmpFrame.bounds = subgraph.bounds;
371
- ignoreItems.push(...subgraph.components);
535
+ tmpFrame.bounds = withinSubgraph.bounds;
536
+ ignoreItems.push(...withinSubgraph.components);
372
537
  accum.push(tmpFrame);
373
538
  elementFrames.push(tmpFrame);
374
539
  }
@@ -379,12 +544,19 @@ export class LayoutEngine {
379
544
  }
380
545
  return accum;
381
546
  }, []);
382
- if (frame.type === RenderFrameType.Container) {
547
+ this.checkAddFrameTitle(frame, elementFrames, textObjects, level);
548
+ return {
549
+ elementFrames,
550
+ textObjects,
551
+ };
552
+ }
553
+ checkAddFrameTitle(frame, elementFrames, textObjects, level) {
554
+ if (frame.renderType === RenderFrameType.Container) {
383
555
  const frameObject = frame.frame;
384
556
  const isSheetFrame = frameObject.frameType === FrameType.Sheet;
385
557
  if (frameObject.parameters.has(FrameParamKeys.Title) && !isSheetFrame) {
386
558
  const title = frameObject.parameters.get(FrameParamKeys.Title);
387
- const tmpFrame = new RenderFrame(new Frame(-2), RenderFrameType.Elements);
559
+ const tmpFrame = new RenderFrame(new Frame(FixedFrameIds.FrameIdNotUsed), RenderFrameType.Elements);
388
560
  tmpFrame.containsTitle = true;
389
561
  tmpFrame.subgraphId = title.replace(/\s/g, "_");
390
562
  const textObject = new RenderText(title);
@@ -407,10 +579,6 @@ export class LayoutEngine {
407
579
  elementFrames.splice(0, 0, tmpFrame);
408
580
  }
409
581
  }
410
- return {
411
- elementFrames,
412
- textObjects,
413
- };
414
582
  }
415
583
  generateLayoutGraph(sequence, nets) {
416
584
  let previousNode = null;
@@ -420,158 +588,155 @@ export class LayoutEngine {
420
588
  compound: true,
421
589
  });
422
590
  this.print('sequence length:', sequence.length);
423
- const baseRenderFrame = new RenderFrame(new Frame(-1));
424
- const frameStack = [baseRenderFrame];
425
- const containerFrames = [baseRenderFrame];
426
- for (let i = 0; i < sequence.length; i++) {
427
- const action = sequence[i][0];
591
+ const baseFrame = new RenderFrame(new Frame(FixedFrameIds.BaseFrame));
592
+ const frameStack = [baseFrame];
593
+ const containerFrames = [baseFrame];
594
+ sequence.forEach((sequenceStep, index) => {
595
+ const action = sequenceStep[0];
428
596
  let tmpComponent;
429
- if (action === SequenceAction.At || action === SequenceAction.To) {
430
- this.print(...sequence[i]);
431
- const component = sequence[i][1];
432
- const pin = sequence[i][2];
433
- const tmpInstanceName = component.instanceName;
434
- if (!graph.hasNode(tmpInstanceName)) {
435
- this.print('create instance', tmpInstanceName);
436
- const { displayProp = null, widthProp = null, heightProp = null } = component;
437
- let tmpSymbol;
438
- if (displayProp instanceof SymbolDrawing) {
439
- tmpSymbol = new SymbolPlaceholder(displayProp);
440
- tmpSymbol.drawing.logger = this.logger;
441
- }
442
- else {
443
- const symbolPinDefinitions = generateLayoutPinDefinition(component);
444
- if (component.typeProp === ComponentTypes.module) {
445
- tmpSymbol = new SymbolCustomModule(symbolPinDefinitions, component.pinsMaxPositions);
597
+ switch (action) {
598
+ case SequenceAction.To:
599
+ case SequenceAction.At: {
600
+ this.print(...sequenceStep);
601
+ const [, component, pin] = sequenceStep;
602
+ const tmpInstanceName = component.instanceName;
603
+ if (!graph.hasNode(tmpInstanceName)) {
604
+ this.print('create instance', tmpInstanceName);
605
+ const { displayProp = null, widthProp = null, heightProp = null } = component;
606
+ let tmpSymbol;
607
+ if (displayProp instanceof SymbolDrawing) {
608
+ tmpSymbol = new SymbolPlaceholder(displayProp);
609
+ tmpSymbol.drawing.logger = this.logger;
446
610
  }
447
611
  else {
448
- tmpSymbol = new SymbolCustom(symbolPinDefinitions, component.pinsMaxPositions);
612
+ const symbolPinDefinitions = generateLayoutPinDefinition(component);
613
+ if (component.typeProp === ComponentTypes.module) {
614
+ tmpSymbol = new SymbolCustomModule(symbolPinDefinitions, component.pinsMaxPositions);
615
+ }
616
+ else {
617
+ tmpSymbol = new SymbolCustom(symbolPinDefinitions, component.pinsMaxPositions);
618
+ }
449
619
  }
450
- }
451
- applyComponentParamsToSymbol(component, tmpSymbol);
452
- let didSetAngle = false;
453
- if (component.parameters.has(ParamKeys.angle)) {
454
- didSetAngle = true;
455
- const value = component.parameters.get(ParamKeys.angle).toNumber();
456
- tmpSymbol.angle = value;
457
- }
458
- if (component.parameters.has(ParamKeys.flipX)) {
459
- tmpSymbol.flipX =
460
- component.parameters.get(ParamKeys.flipX);
461
- }
462
- if (component.parameters.has(ParamKeys.flipY)) {
463
- tmpSymbol.flipY =
464
- component.parameters.get(ParamKeys.flipY);
465
- }
466
- if (tmpSymbol instanceof SymbolCustom) {
467
- if (widthProp) {
468
- tmpSymbol.bodyWidth = milsToMM(widthProp);
620
+ applyComponentParamsToSymbol(component, tmpSymbol);
621
+ if (component.parameters.has(ParamKeys.angle)) {
622
+ const value = component.parameters.get(ParamKeys.angle).toNumber();
623
+ tmpSymbol.angle = value;
624
+ }
625
+ if (component.parameters.has(ParamKeys.flipX)) {
626
+ tmpSymbol.flipX =
627
+ component.parameters.get(ParamKeys.flipX);
628
+ }
629
+ if (component.parameters.has(ParamKeys.flipY)) {
630
+ tmpSymbol.flipY =
631
+ component.parameters.get(ParamKeys.flipY);
469
632
  }
470
- if (heightProp) {
471
- tmpSymbol.bodyHeight = milsToMM(heightProp);
633
+ if (tmpSymbol instanceof SymbolCustom) {
634
+ if (widthProp) {
635
+ tmpSymbol.bodyWidth = milsToMM(widthProp);
636
+ }
637
+ if (heightProp) {
638
+ tmpSymbol.bodyHeight = milsToMM(heightProp);
639
+ }
472
640
  }
641
+ tmpSymbol.refreshDrawing();
642
+ const { width: useWidth, height: useHeight } = tmpSymbol.size();
643
+ tmpComponent = new RenderComponent(component, useWidth, useHeight);
644
+ tmpComponent.symbol = tmpSymbol;
645
+ graph.setNode(tmpInstanceName, [RenderItemType.Component, tmpComponent, index]);
646
+ const currentFrame = frameStack[frameStack.length - 1];
647
+ currentFrame && currentFrame.innerItems.push(tmpComponent);
473
648
  }
474
- if (!didSetAngle && component.parameters.has('_addDirection')) {
475
- tmpSymbol.refreshDrawing(false);
476
- tmpSymbol.angle = calculateSymbolAngle(tmpSymbol, component.parameters.get('_addPin'), component.parameters.get('_addDirection'));
649
+ if (action === SequenceAction.To && previousNode && previousPin) {
650
+ this.setGraphEdge(graph, previousNode, tmpInstanceName, makeEdgeValue(previousNode, previousPin, tmpInstanceName, pin, index));
477
651
  }
478
- tmpSymbol.refreshDrawing();
479
- const { width: useWidth, height: useHeight } = tmpSymbol.size();
480
- tmpComponent = new RenderComponent(component, useWidth, useHeight);
481
- tmpComponent.symbol = tmpSymbol;
482
- graph.setNode(tmpInstanceName, [RenderItemType.Component, tmpComponent, i]);
483
- const currentFrame = frameStack[frameStack.length - 1];
484
- currentFrame && currentFrame.innerItems.push(tmpComponent);
652
+ previousNode = tmpInstanceName;
653
+ previousPin = pin;
654
+ break;
485
655
  }
486
- if (action === SequenceAction.To) {
487
- this.setGraphEdge(graph, previousNode, tmpInstanceName, makeEdgeValue(previousNode, previousPin, tmpInstanceName, pin, i));
488
- }
489
- previousNode = tmpInstanceName;
490
- previousPin = pin;
491
- }
492
- else if (action === SequenceAction.Wire) {
493
- const [, wireId, wireSegments] = sequence[i];
494
- const wire = new RenderWire(numeric(0), numeric(0), wireSegments);
495
- wire.id = wireId;
496
- let useNetName = null;
497
- if (previousNode !== null) {
498
- const [prevNodeType, prevNodeItem] = graph.node(previousNode);
499
- if (prevNodeType === RenderItemType.Component) {
500
- const matchingItem = nets.find(([comp, pin]) => {
501
- return comp.instanceName === previousNode && pin === previousPin;
502
- });
503
- useNetName = matchingItem !== undefined ? matchingItem[2].name : null;
504
- }
505
- else if (prevNodeType === RenderItemType.Wire) {
506
- useNetName = prevNodeItem.netName;
656
+ case SequenceAction.Wire: {
657
+ const [, wireId, wireSegments] = sequenceStep;
658
+ const wire = new RenderWire(numeric(0), numeric(0), wireSegments);
659
+ wire.id = wireId;
660
+ let useNetName = null;
661
+ if (previousNode !== null) {
662
+ const [prevNodeType, prevNodeItem] = graph.node(previousNode);
663
+ if (prevNodeType === RenderItemType.Component) {
664
+ const matchingItem = nets.find(([comp, pin]) => {
665
+ return comp.instanceName === previousNode && pin === previousPin;
666
+ });
667
+ useNetName = matchingItem !== undefined ? matchingItem[2].name : null;
668
+ }
669
+ else if (prevNodeType === RenderItemType.Wire) {
670
+ useNetName = prevNodeItem.netName;
671
+ }
507
672
  }
673
+ wire.netName = useNetName;
674
+ const wireName = getWireName(wire.id);
675
+ graph.setNode(wireName, [RenderItemType.Wire, wire, index]);
676
+ this.setGraphEdge(graph, previousNode, wireName, makeEdgeValue(previousNode, previousPin, wireName, 0, index));
677
+ previousNode = wireName;
678
+ previousPin = 1;
679
+ const wireSegmentsInfo = wireSegments.map(item => {
680
+ const tmp = {
681
+ direction: item.direction,
682
+ value: item.value,
683
+ };
684
+ if (item.valueXY) {
685
+ tmp.valueXY = item.valueXY;
686
+ }
687
+ if (item.until) {
688
+ tmp.until = [item.until[0].toString(), item.until[1]];
689
+ }
690
+ return tmp;
691
+ });
692
+ this.print(SequenceAction.Wire, wireId, JSON.stringify(wireSegmentsInfo));
693
+ break;
508
694
  }
509
- wire.netName = useNetName;
510
- const wireName = getWireName(wire.id);
511
- graph.setNode(wireName, [RenderItemType.Wire, wire, i]);
512
- this.setGraphEdge(graph, previousNode, wireName, makeEdgeValue(previousNode, previousPin, wireName, 0, i));
513
- previousNode = wireName;
514
- previousPin = 1;
515
- const wireSegmentsInfo = wireSegments.map(item => {
516
- const tmp = {
517
- direction: item.direction,
518
- value: item.value,
519
- };
520
- if (item.valueXY) {
521
- tmp.valueXY = item.valueXY;
695
+ case SequenceAction.WireJump: {
696
+ this.print(...sequenceStep);
697
+ const wireId = sequenceStep[1];
698
+ const wireName = getWireName(wireId);
699
+ let wirePin = 1;
700
+ if (sequenceStep.length === 3) {
701
+ wirePin = sequenceStep[2];
522
702
  }
523
- if (item.until) {
524
- tmp.until = [item.until[0].toString(), item.until[1]];
525
- }
526
- return tmp;
527
- });
528
- this.print(SequenceAction.Wire, wireId, JSON.stringify(wireSegmentsInfo));
529
- }
530
- else if (action === SequenceAction.WireJump) {
531
- this.print(...sequence[i]);
532
- const wireId = sequence[i][1];
533
- const wireName = getWireName(wireId);
534
- let wirePin = 1;
535
- if (sequence[i].length === 3) {
536
- wirePin = sequence[i][2];
703
+ previousNode = wireName;
704
+ previousPin = wirePin;
705
+ break;
537
706
  }
538
- previousNode = wireName;
539
- previousPin = wirePin;
540
- }
541
- else if (action === SequenceAction.Frame) {
542
- const [, frameObject, frameAction] = sequence[i];
543
- if (frameAction === FrameAction.Enter) {
544
- const prevFrame = frameStack[frameStack.length - 1];
545
- const newFrame = new RenderFrame(frameObject);
546
- if (frameObject.parameters.has(FrameParamKeys.Direction)) {
547
- newFrame.direction =
548
- frameObject.parameters.get(FrameParamKeys.Direction);
549
- }
550
- if (frameObject.parameters.has(FrameParamKeys.Padding)) {
551
- newFrame.padding =
552
- frameObject.parameters.get(FrameParamKeys.Padding);
553
- }
554
- if (frameObject.parameters.has(FrameParamKeys.Border)) {
555
- newFrame.borderWidth =
556
- frameObject.parameters.get(FrameParamKeys.Border);
557
- }
558
- if (frameObject.parameters.has(FrameParamKeys.Width)) {
559
- newFrame.width =
560
- frameObject.parameters.get(FrameParamKeys.Width);
707
+ case SequenceAction.Frame: {
708
+ const [, frameObject, frameAction] = sequenceStep;
709
+ if (frameAction === FrameAction.Enter) {
710
+ const prevFrame = frameStack[frameStack.length - 1];
711
+ const newFrame = new RenderFrame(frameObject);
712
+ if (frameObject.parameters.has(FrameParamKeys.Direction)) {
713
+ newFrame.direction =
714
+ frameObject.parameters.get(FrameParamKeys.Direction);
715
+ }
716
+ if (frameObject.parameters.has(FrameParamKeys.Padding)) {
717
+ newFrame.padding = milsToMM(frameObject.parameters.get(FrameParamKeys.Padding));
718
+ }
719
+ if (frameObject.parameters.has(FrameParamKeys.Border)) {
720
+ newFrame.borderWidth =
721
+ frameObject.parameters.get(FrameParamKeys.Border);
722
+ }
723
+ if (frameObject.parameters.has(FrameParamKeys.Width)) {
724
+ newFrame.width = milsToMM(frameObject.parameters.get(FrameParamKeys.Width));
725
+ }
726
+ if (frameObject.parameters.has(FrameParamKeys.Height)) {
727
+ newFrame.height = milsToMM(frameObject.parameters.get(FrameParamKeys.Height));
728
+ }
729
+ containerFrames.push(newFrame);
730
+ frameStack.push(newFrame);
731
+ prevFrame && prevFrame.innerItems.push(newFrame);
561
732
  }
562
- if (frameObject.parameters.has(FrameParamKeys.Height)) {
563
- newFrame.height =
564
- frameObject.parameters.get(FrameParamKeys.Height);
733
+ else if (frameAction === FrameAction.Exit) {
734
+ frameStack.pop();
565
735
  }
566
- containerFrames.push(newFrame);
567
- frameStack.push(newFrame);
568
- prevFrame && prevFrame.innerItems.push(newFrame);
569
- }
570
- else if (frameAction === FrameAction.Exit) {
571
- frameStack.pop();
736
+ break;
572
737
  }
573
738
  }
574
- }
739
+ });
575
740
  return {
576
741
  graph,
577
742
  containerFrames,
@@ -586,10 +751,10 @@ export class LayoutEngine {
586
751
  this.print('===== placing subgraphs =====');
587
752
  this.print('number of subgraphs: ', subGraphs.length);
588
753
  const subgraphInfo = [];
589
- subGraphs.forEach(innerGraph => {
754
+ subGraphs.forEach(subGraph => {
590
755
  let smallestNodeIdLevel = Number.POSITIVE_INFINITY;
591
- let smallestNodeId = null;
592
- innerGraph.forEach(nodeId => {
756
+ let smallestNodeId = "";
757
+ subGraph.forEach(nodeId => {
593
758
  const [, , sequenceId] = graph.node(nodeId);
594
759
  if (sequenceId < smallestNodeIdLevel) {
595
760
  smallestNodeIdLevel = sequenceId;
@@ -632,12 +797,7 @@ export class LayoutEngine {
632
797
  }
633
798
  return accum;
634
799
  }, []);
635
- if (this.placeSubgraphVersion === 1) {
636
- this.placeSubgraph(graph, firstNodeId, subgraphEdges);
637
- }
638
- else if (this.placeSubgraphVersion === 2) {
639
- this.placeSubgraphV2(graph, firstNodeId, subgraphEdges);
640
- }
800
+ this.placeSubgraphV2(graph, firstNodeId, subgraphEdges);
641
801
  }
642
802
  placeSubgraphV2(graph, firstNodeId, subgraphEdges) {
643
803
  let firstNodePlaced = false;
@@ -800,59 +960,6 @@ export class LayoutEngine {
800
960
  this.print('removed other origin');
801
961
  this.print('merge completed');
802
962
  }
803
- placeSubgraph(graph, firstNodeId, subgraphEdges) {
804
- let firstNodePlaced = false;
805
- subgraphEdges.forEach(edge => {
806
- const [nodeId1, pin1, nodeId2, pin2] = graph.edge(edge);
807
- const [, node1] = graph.node(nodeId1);
808
- const [, node2] = graph.node(nodeId2);
809
- if (nodeId1 === firstNodeId && !firstNodePlaced) {
810
- this.print('first node placed at origin');
811
- this.placeNodeAtPosition(numeric(0), numeric(0), node1, pin1);
812
- firstNodePlaced = true;
813
- node1.isFloating = false;
814
- }
815
- let fixedNode;
816
- let fixedNodePin;
817
- let floatingNode;
818
- let floatingNodePin;
819
- this.print('edge:', '[', node1, pin1, node1.isFloating, ']', '[', node2, pin2, node2.isFloating, ']');
820
- if (!node1.isFloating && node2.isFloating) {
821
- fixedNode = node1;
822
- fixedNodePin = pin1;
823
- floatingNode = node2;
824
- floatingNodePin = pin2;
825
- }
826
- else if (node1.isFloating && !node2.isFloating) {
827
- fixedNode = node2;
828
- fixedNodePin = pin2;
829
- floatingNode = node1;
830
- floatingNodePin = pin1;
831
- }
832
- else if (node1.isFloating && node2.isFloating) {
833
- this.print('both nodes are floating', node1, 'pin', pin1, 'and', node2, 'pin', pin2);
834
- node1.floatingRelativeTo.push([pin1, nodeId2, pin2]);
835
- node2.floatingRelativeTo.push([pin2, nodeId1, pin1]);
836
- }
837
- if (fixedNode && floatingNode) {
838
- this.print('place floating node', floatingNode, 'pin', floatingNodePin, 'to', fixedNode, 'pin', fixedNodePin);
839
- const [x, y] = getNodePositionAtPin(fixedNode, fixedNodePin);
840
- this.placeNodeAtPosition(x, y, floatingNode, floatingNodePin);
841
- floatingNode.isFloating = false;
842
- this.placeFloatingItems(graph, floatingNode);
843
- }
844
- [node1, node2].forEach(item => {
845
- if (item instanceof RenderWire) {
846
- if (item.isEndAutoLength()) {
847
- const [instance, pin] = item.getEndAuto();
848
- const [, targetNode] = graph.node(instance.instanceName);
849
- const [untilX, untilY] = getNodePositionAtPin(targetNode, pin);
850
- item.setEndAuto(untilX, untilY);
851
- }
852
- }
853
- });
854
- });
855
- }
856
963
  translateNodeBy(offsetX, offsetY, item) {
857
964
  item.x = item.x.add(offsetX);
858
965
  item.y = item.y.add(offsetY);
@@ -1288,19 +1395,19 @@ export class RenderFrame extends RenderObject {
1288
1395
  width = null;
1289
1396
  height = null;
1290
1397
  subgraphId = "";
1291
- type;
1398
+ renderType;
1292
1399
  containsTitle = false;
1293
1400
  constructor(frame, type = RenderFrameType.Container) {
1294
1401
  super();
1295
1402
  this.frame = frame;
1296
- this.type = type;
1403
+ this.renderType = type;
1297
1404
  }
1298
1405
  toString() {
1299
1406
  let name = "";
1300
- if (this.type === RenderFrameType.Container) {
1407
+ if (this.renderType === RenderFrameType.Container) {
1301
1408
  name = 'container_' + this.frame.frameId;
1302
1409
  }
1303
- else if (this.type === RenderFrameType.Elements) {
1410
+ else if (this.renderType === RenderFrameType.Elements) {
1304
1411
  name = 'elements_' + this.subgraphId;
1305
1412
  }
1306
1413
  return name + ": " + this.x + "," + this.y
@@ -1343,9 +1450,17 @@ export function ExtractDrawingRects(drawing) {
1343
1450
  return drawing.getCommands().filter(item => {
1344
1451
  return (item[0] === PlaceHolderCommands.rect);
1345
1452
  }).map(item => {
1453
+ const map = item[2];
1454
+ let className = undefined;
1455
+ if (map.has('class')) {
1456
+ className = map.get('class');
1457
+ }
1346
1458
  return {
1459
+ x: item[1][0],
1460
+ y: item[1][1],
1347
1461
  width: item[1][2],
1348
1462
  height: item[1][3],
1463
+ className
1349
1464
  };
1350
1465
  });
1351
1466
  }