circuitscript 0.0.26 → 0.0.28
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/BaseVisitor.js +7 -1
- package/dist/cjs/antlr/CircuitScriptParser.js +736 -677
- package/dist/cjs/draw_symbols.js +37 -15
- package/dist/cjs/execute.js +67 -0
- package/dist/cjs/geometry.js +45 -26
- package/dist/cjs/helpers.js +1 -0
- package/dist/cjs/layout.js +37 -17
- package/dist/cjs/objects/ClassComponent.js +7 -0
- package/dist/cjs/objects/types.js +8 -1
- package/dist/cjs/visitor.js +49 -10
- package/dist/esm/BaseVisitor.mjs +8 -2
- package/dist/esm/antlr/CircuitScriptParser.mjs +734 -676
- package/dist/esm/antlr/CircuitScriptVisitor.mjs +1 -0
- package/dist/esm/draw_symbols.mjs +38 -16
- package/dist/esm/execute.mjs +67 -0
- package/dist/esm/geometry.mjs +44 -25
- package/dist/esm/helpers.mjs +1 -0
- package/dist/esm/layout.mjs +35 -16
- package/dist/esm/objects/ClassComponent.mjs +7 -0
- package/dist/esm/objects/types.mjs +7 -0
- package/dist/esm/visitor.mjs +50 -11
- package/dist/types/BaseVisitor.d.ts +2 -2
- package/dist/types/antlr/CircuitScriptParser.d.ts +28 -19
- package/dist/types/antlr/CircuitScriptVisitor.d.ts +2 -0
- package/dist/types/draw_symbols.d.ts +8 -3
- package/dist/types/execute.d.ts +4 -0
- package/dist/types/geometry.d.ts +12 -9
- package/dist/types/layout.d.ts +5 -0
- package/dist/types/objects/ClassComponent.d.ts +4 -0
- package/dist/types/objects/Wire.d.ts +2 -1
- package/dist/types/objects/types.d.ts +6 -0
- package/dist/types/visitor.d.ts +3 -2
- package/libs/lib.cst +19 -4
- package/package.json +1 -1
|
@@ -50,6 +50,7 @@ export class CircuitScriptVisitor extends AbstractParseTreeVisitor {
|
|
|
50
50
|
visitFunction_return_expr;
|
|
51
51
|
visitCreate_component_expr;
|
|
52
52
|
visitCreate_graphic_expr;
|
|
53
|
+
visitNested_properties_inner;
|
|
53
54
|
visitGraphic_expr;
|
|
54
55
|
visitProperty_expr;
|
|
55
56
|
visitProperty_key_expr;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { ReferenceTypes, SymbolPinSide, defaultFont } from "./globals.mjs";
|
|
2
|
-
import { Geometry, GeometryProp, HorizontalAlign,
|
|
2
|
+
import { Geometry, GeometryProp, HorizontalAlign, Textbox, VerticalAlign } from "./geometry.mjs";
|
|
3
3
|
import { PinTypes } from "./objects/PinTypes.mjs";
|
|
4
4
|
const defaultSymbolLineWidth = 2;
|
|
5
5
|
export class SymbolGraphic {
|
|
@@ -252,7 +252,7 @@ export class SymbolText extends SymbolGraphic {
|
|
|
252
252
|
}
|
|
253
253
|
generateDrawing() {
|
|
254
254
|
const drawing = new SymbolDrawing();
|
|
255
|
-
drawing.
|
|
255
|
+
drawing.addTextbox(0, 0, this.text, {
|
|
256
256
|
fontSize: this.fontSize,
|
|
257
257
|
anchor: HorizontalAlign.Middle,
|
|
258
258
|
fontWeight: this.fontWeight,
|
|
@@ -317,13 +317,7 @@ export class SymbolPlaceholder extends SymbolGraphic {
|
|
|
317
317
|
break;
|
|
318
318
|
}
|
|
319
319
|
case PlaceHolderCommands.label: {
|
|
320
|
-
const
|
|
321
|
-
const style = {};
|
|
322
|
-
keywords.forEach(item => {
|
|
323
|
-
if (keywordParams.has(item)) {
|
|
324
|
-
style[item] = keywordParams.get(item);
|
|
325
|
-
}
|
|
326
|
-
});
|
|
320
|
+
const style = this.parseLabelStyle(keywordParams);
|
|
327
321
|
positionParams = [...positionParams];
|
|
328
322
|
positionParams.push(style);
|
|
329
323
|
const labelId = positionParams[0];
|
|
@@ -336,10 +330,33 @@ export class SymbolPlaceholder extends SymbolGraphic {
|
|
|
336
330
|
drawing.addLabelId(...tmpPositionParams);
|
|
337
331
|
break;
|
|
338
332
|
}
|
|
333
|
+
case PlaceHolderCommands.text: {
|
|
334
|
+
const style = this.parseLabelStyle(keywordParams);
|
|
335
|
+
const content = keywordParams.get('content');
|
|
336
|
+
let offsetX = 0;
|
|
337
|
+
let offsetY = 0;
|
|
338
|
+
if (keywordParams.has('offset')) {
|
|
339
|
+
const offset = keywordParams.get('offset');
|
|
340
|
+
offsetX = offset[0];
|
|
341
|
+
offsetY = offset[1];
|
|
342
|
+
}
|
|
343
|
+
drawing.addTextbox(offsetX, offsetY, content, style);
|
|
344
|
+
break;
|
|
345
|
+
}
|
|
339
346
|
}
|
|
340
347
|
});
|
|
341
348
|
drawing.log("=== end generate drawing ===");
|
|
342
349
|
}
|
|
350
|
+
parseLabelStyle(keywordParams) {
|
|
351
|
+
const keywords = ['fontSize', 'anchor', 'vanchor', 'angle'];
|
|
352
|
+
const style = {};
|
|
353
|
+
keywords.forEach(item => {
|
|
354
|
+
if (keywordParams.has(item)) {
|
|
355
|
+
style[item] = keywordParams.get(item);
|
|
356
|
+
}
|
|
357
|
+
});
|
|
358
|
+
return style;
|
|
359
|
+
}
|
|
343
360
|
drawPinParams(drawing, commandName, keywordParams, positionParams) {
|
|
344
361
|
drawing.log('add pin', ...positionParams);
|
|
345
362
|
const keywordDisplayPinId = 'display_pin_id';
|
|
@@ -449,6 +466,7 @@ export var PlaceHolderCommands;
|
|
|
449
466
|
PlaceHolderCommands["lineWidth"] = "lineWidth";
|
|
450
467
|
PlaceHolderCommands["fill"] = "fill";
|
|
451
468
|
PlaceHolderCommands["lineColor"] = "lineColor";
|
|
469
|
+
PlaceHolderCommands["text"] = "text";
|
|
452
470
|
})(PlaceHolderCommands || (PlaceHolderCommands = {}));
|
|
453
471
|
export class SymbolCustom extends SymbolGraphic {
|
|
454
472
|
pinDefinition = [];
|
|
@@ -636,6 +654,10 @@ export class SymbolDrawing {
|
|
|
636
654
|
this.items.push(Geometry.label(id, x, y, textValue, style));
|
|
637
655
|
return this;
|
|
638
656
|
}
|
|
657
|
+
addTextbox(x, y, textValue, style) {
|
|
658
|
+
this.items.push(Geometry.textbox(null, x, y, textValue, style));
|
|
659
|
+
return this;
|
|
660
|
+
}
|
|
639
661
|
addPath(...pathParts) {
|
|
640
662
|
const parts = pathParts.reduce((accum, tmp) => {
|
|
641
663
|
if (typeof tmp === "string") {
|
|
@@ -710,7 +732,7 @@ export class SymbolDrawing {
|
|
|
710
732
|
let currentLineColor = '#333';
|
|
711
733
|
const pathItems = [];
|
|
712
734
|
this.items.forEach(item => {
|
|
713
|
-
if (!(item instanceof
|
|
735
|
+
if (!(item instanceof Textbox)) {
|
|
714
736
|
if (item instanceof GeometryProp) {
|
|
715
737
|
if (item.name === 'lineWidth') {
|
|
716
738
|
currentLineWidth = item.value;
|
|
@@ -725,7 +747,7 @@ export class SymbolDrawing {
|
|
|
725
747
|
else {
|
|
726
748
|
let tmpResult = Geometry.groupFlip([item], this.flipX, this.flipY);
|
|
727
749
|
tmpResult = Geometry.groupRotate(tmpResult, this.angle, this.mainOrigin);
|
|
728
|
-
const { path, isClosedPolygon } = this.featuresToPath(tmpResult);
|
|
750
|
+
const { path, isClosedPolygon } = this.featuresToPath(tmpResult, this.flipX, this.flipY);
|
|
729
751
|
pathItems.push({
|
|
730
752
|
path: path,
|
|
731
753
|
lineWidth: currentLineWidth,
|
|
@@ -741,21 +763,21 @@ export class SymbolDrawing {
|
|
|
741
763
|
let features = this.pins.map(item => item[1]);
|
|
742
764
|
features = Geometry.groupFlip(features, this.flipX, this.flipY);
|
|
743
765
|
features = Geometry.groupRotate(features, this.angle, this.mainOrigin);
|
|
744
|
-
const { path } = this.featuresToPath(features);
|
|
766
|
+
const { path } = this.featuresToPath(features, this.flipX, this.flipY);
|
|
745
767
|
return path;
|
|
746
768
|
}
|
|
747
769
|
getLabels() {
|
|
748
|
-
return this.items.filter(item => item instanceof
|
|
770
|
+
return this.items.filter(item => item instanceof Textbox);
|
|
749
771
|
}
|
|
750
|
-
featuresToPath(items) {
|
|
751
|
-
return Geometry.featuresToPath(items);
|
|
772
|
+
featuresToPath(items, flipX, flipY) {
|
|
773
|
+
return Geometry.featuresToPath(items, flipX, flipY);
|
|
752
774
|
}
|
|
753
775
|
getBoundingBox(excludeLabels = false) {
|
|
754
776
|
const pinFeatures = this.pins.map(pin => {
|
|
755
777
|
return pin[1];
|
|
756
778
|
});
|
|
757
779
|
const drawingFeatures = this.items.reduce((accum, item) => {
|
|
758
|
-
if (!excludeLabels || (excludeLabels && !(item instanceof
|
|
780
|
+
if (!excludeLabels || (excludeLabels && !(item instanceof Textbox && item.label))) {
|
|
759
781
|
if (!(item instanceof GeometryProp)) {
|
|
760
782
|
accum.push(item);
|
|
761
783
|
}
|
package/dist/esm/execute.mjs
CHANGED
|
@@ -3,8 +3,10 @@ import { ClassComponent } from './objects/ClassComponent.mjs';
|
|
|
3
3
|
import { ActiveObject, ExecutionScope, FrameAction, SequenceAction } from './objects/ExecutionScope.mjs';
|
|
4
4
|
import { Net } from './objects/Net.mjs';
|
|
5
5
|
import { PortSide } from './objects/PinDefinition.mjs';
|
|
6
|
+
import { Direction } from './objects/types.mjs';
|
|
6
7
|
import { Wire } from './objects/Wire.mjs';
|
|
7
8
|
import { Frame } from './objects/Frame.mjs';
|
|
9
|
+
import { CalculatePinPositions } from './layout.mjs';
|
|
8
10
|
export class ExecutionContext {
|
|
9
11
|
name;
|
|
10
12
|
namespace;
|
|
@@ -19,6 +21,7 @@ export class ExecutionContext {
|
|
|
19
21
|
logger;
|
|
20
22
|
__functionCache = {};
|
|
21
23
|
parentContext;
|
|
24
|
+
componentAngleFollowsWire = true;
|
|
22
25
|
constructor(name, namespace, netNamespace, executionLevel = 0, indentLevel = 0, silent = false, logger, parent) {
|
|
23
26
|
this.name = name;
|
|
24
27
|
this.namespace = namespace;
|
|
@@ -149,6 +152,15 @@ export class ExecutionContext {
|
|
|
149
152
|
component.widthProp = props.width ?? null;
|
|
150
153
|
component.typeProp = props.type ?? null;
|
|
151
154
|
component.copyProp = props.copy ?? false;
|
|
155
|
+
let useAngle = null;
|
|
156
|
+
if (props.angle) {
|
|
157
|
+
useAngle = props.angle % 360;
|
|
158
|
+
if (useAngle < 0) {
|
|
159
|
+
useAngle += 360;
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
component.angleProp = useAngle ?? 0;
|
|
163
|
+
component.followWireOrientationProp = props.followWireOrientation;
|
|
152
164
|
const paramsMap = new Map();
|
|
153
165
|
params.forEach((param) => {
|
|
154
166
|
component.parameters.set(param.paramName, param.paramValue);
|
|
@@ -205,6 +217,7 @@ export class ExecutionContext {
|
|
|
205
217
|
addComponentExisting(component, pin) {
|
|
206
218
|
const startPin = pin;
|
|
207
219
|
const nextPin = component.getNextPinAfter(startPin);
|
|
220
|
+
this.applyComponentAngleFromWire(component, pin);
|
|
208
221
|
this.toComponent(component, startPin, { addSequence: true });
|
|
209
222
|
this.log('move to next pin: ' + nextPin);
|
|
210
223
|
this.atComponent(component, nextPin, {
|
|
@@ -240,6 +253,7 @@ export class ExecutionContext {
|
|
|
240
253
|
.toString());
|
|
241
254
|
}
|
|
242
255
|
const linkedNet = this.linkComponentPinNet(this.scope.currentComponent, this.scope.currentPin, component, pinId);
|
|
256
|
+
this.applyComponentAngleFromWire(component, pinId);
|
|
243
257
|
this.scope.currentComponent = component;
|
|
244
258
|
this.scope.currentPin = pinId;
|
|
245
259
|
this.scope.clearActive();
|
|
@@ -688,6 +702,59 @@ export class ExecutionContext {
|
|
|
688
702
|
this.scope.currentComponent.styles[key] = styles[key];
|
|
689
703
|
}
|
|
690
704
|
}
|
|
705
|
+
applyComponentAngleFromWire(component, pin) {
|
|
706
|
+
if (this.componentAngleFollowsWire
|
|
707
|
+
&& component.followWireOrientationProp
|
|
708
|
+
&& component.useWireOrientationAngle
|
|
709
|
+
&& this.scope.currentWireId !== -1) {
|
|
710
|
+
const currentWire = this.scope.wires[this.scope.currentWireId];
|
|
711
|
+
const lastSegment = currentWire.path[currentWire.path.length - 1];
|
|
712
|
+
const pinPositions = CalculatePinPositions(component);
|
|
713
|
+
if (pinPositions.has(pin)) {
|
|
714
|
+
const connectedPinPos = pinPositions.get(pin);
|
|
715
|
+
let targetAngle = null;
|
|
716
|
+
switch (lastSegment.direction) {
|
|
717
|
+
case Direction.Down:
|
|
718
|
+
targetAngle = 90;
|
|
719
|
+
break;
|
|
720
|
+
case Direction.Up:
|
|
721
|
+
targetAngle = 270;
|
|
722
|
+
break;
|
|
723
|
+
case Direction.Right:
|
|
724
|
+
targetAngle = 0;
|
|
725
|
+
break;
|
|
726
|
+
case Direction.Left:
|
|
727
|
+
targetAngle = 180;
|
|
728
|
+
break;
|
|
729
|
+
default:
|
|
730
|
+
targetAngle = null;
|
|
731
|
+
}
|
|
732
|
+
if (targetAngle === null) {
|
|
733
|
+
return;
|
|
734
|
+
}
|
|
735
|
+
this.log('set component angle from wire, target angle:', targetAngle, ', component angle:', component.angleProp, 'pin angle:', connectedPinPos.angle);
|
|
736
|
+
let useAngle = (targetAngle - connectedPinPos.angle) % 360;
|
|
737
|
+
if (useAngle < 0) {
|
|
738
|
+
useAngle += 360;
|
|
739
|
+
}
|
|
740
|
+
if (useAngle === 90) {
|
|
741
|
+
component.setParam('angle', 90);
|
|
742
|
+
}
|
|
743
|
+
else if (useAngle === 180) {
|
|
744
|
+
if (component.angleProp === 0 || component.angleProp === 180) {
|
|
745
|
+
component.setParam('flipX', 1);
|
|
746
|
+
}
|
|
747
|
+
else if (component.angleProp === 90 || component.angleProp === 270) {
|
|
748
|
+
component.setParam('flipY', 1);
|
|
749
|
+
}
|
|
750
|
+
}
|
|
751
|
+
else if (useAngle === 270) {
|
|
752
|
+
component.setParam('angle', 270);
|
|
753
|
+
}
|
|
754
|
+
component.wireOrientationAngle = useAngle;
|
|
755
|
+
}
|
|
756
|
+
}
|
|
757
|
+
}
|
|
691
758
|
enterFrame() {
|
|
692
759
|
const frameId = this.scope.frames.length + 1;
|
|
693
760
|
const frameObject = new Frame(frameId);
|
package/dist/esm/geometry.mjs
CHANGED
|
@@ -2,7 +2,7 @@ import Flatten from '@flatten-js/core';
|
|
|
2
2
|
import { measureTextSize2 } from './sizing.mjs';
|
|
3
3
|
import { defaultFont } from './globals.mjs';
|
|
4
4
|
import { NumericValue } from './objects/ParamDefinition.mjs';
|
|
5
|
-
export class
|
|
5
|
+
export class Textbox extends Flatten.Polygon {
|
|
6
6
|
id;
|
|
7
7
|
text;
|
|
8
8
|
anchorPoint = [0, 0];
|
|
@@ -11,10 +11,11 @@ export class Label extends Flatten.Polygon {
|
|
|
11
11
|
font = 'default';
|
|
12
12
|
style;
|
|
13
13
|
textMeasurementBounds;
|
|
14
|
+
label;
|
|
14
15
|
get box() {
|
|
15
16
|
return this.polygon.box;
|
|
16
17
|
}
|
|
17
|
-
constructor(id, text, anchorPoint, polygon, style, bounds) {
|
|
18
|
+
constructor(id, text, anchorPoint, polygon, style, bounds, label) {
|
|
18
19
|
super(polygon.vertices);
|
|
19
20
|
this.id = id;
|
|
20
21
|
this.text = text;
|
|
@@ -23,8 +24,9 @@ export class Label extends Flatten.Polygon {
|
|
|
23
24
|
this.boundingBox = polygon.box;
|
|
24
25
|
this.polygon = polygon;
|
|
25
26
|
this.textMeasurementBounds = bounds;
|
|
27
|
+
this.label = label;
|
|
26
28
|
}
|
|
27
|
-
static fromPoint(id, x, y, text, style) {
|
|
29
|
+
static fromPoint(id, x, y, text, style, label) {
|
|
28
30
|
let useText;
|
|
29
31
|
if (typeof text === 'number') {
|
|
30
32
|
useText = text.toString();
|
|
@@ -37,7 +39,7 @@ export class Label extends Flatten.Polygon {
|
|
|
37
39
|
useText = text;
|
|
38
40
|
}
|
|
39
41
|
else {
|
|
40
|
-
throw 'Invalid string passed into
|
|
42
|
+
throw 'Invalid string passed into textbox';
|
|
41
43
|
}
|
|
42
44
|
const { fontSize = 10, anchor = HorizontalAlign.Left, vanchor = VerticalAlign.Bottom, fontWeight = 'regular', } = style ?? {};
|
|
43
45
|
const { width, height, box } = measureTextSize2(useText, defaultFont, fontSize, fontWeight, anchor, vanchor);
|
|
@@ -49,20 +51,22 @@ export class Label extends Flatten.Polygon {
|
|
|
49
51
|
[box.x, box.y],
|
|
50
52
|
];
|
|
51
53
|
const polygon = new Flatten.Polygon(polygonCoords);
|
|
52
|
-
return new
|
|
54
|
+
return new Textbox(id, useText, [x, y], polygon, style, box, label);
|
|
53
55
|
}
|
|
54
56
|
rotate(angle, origin) {
|
|
55
57
|
const feature = super.rotate(angle, origin);
|
|
56
|
-
return new
|
|
58
|
+
return new Textbox(this.id, this.text, this.anchorPoint, feature, this.style, this.textMeasurementBounds, this.label);
|
|
57
59
|
}
|
|
58
60
|
transform(matrix) {
|
|
59
61
|
const feature = super.transform(matrix);
|
|
60
|
-
return new
|
|
62
|
+
return new Textbox(this.id, this.text, this.anchorPoint, feature, this.style, this.textMeasurementBounds, this.label);
|
|
61
63
|
}
|
|
62
64
|
getLabelPosition() {
|
|
63
65
|
return this.anchorPoint;
|
|
64
66
|
}
|
|
65
67
|
}
|
|
68
|
+
export class Label extends Textbox {
|
|
69
|
+
}
|
|
66
70
|
export class GeometryProp {
|
|
67
71
|
name;
|
|
68
72
|
value;
|
|
@@ -79,7 +83,10 @@ export class Geometry {
|
|
|
79
83
|
return new Flatten.Line(Geometry.point(x1, y1), Geometry.point(x2, y2));
|
|
80
84
|
}
|
|
81
85
|
static label(id, x, y, text, style) {
|
|
82
|
-
return
|
|
86
|
+
return Textbox.fromPoint(id, x, y, text, style, true);
|
|
87
|
+
}
|
|
88
|
+
static textbox(id, x, y, text, style) {
|
|
89
|
+
return Textbox.fromPoint(id, x, y, text, style, false);
|
|
83
90
|
}
|
|
84
91
|
static segment(start, end) {
|
|
85
92
|
return new Flatten.Segment(Geometry.point(start[0], start[1]), Geometry.point(end[0], end[1]));
|
|
@@ -130,12 +137,28 @@ export class Geometry {
|
|
|
130
137
|
let maxX = Number.NEGATIVE_INFINITY;
|
|
131
138
|
let maxY = Number.NEGATIVE_INFINITY;
|
|
132
139
|
features.forEach(feature => {
|
|
133
|
-
const
|
|
134
|
-
|
|
140
|
+
const tmpBox = feature.box;
|
|
141
|
+
let box = {
|
|
142
|
+
xmin: tmpBox.xmin,
|
|
143
|
+
ymin: tmpBox.ymin,
|
|
144
|
+
xmax: tmpBox.xmax,
|
|
145
|
+
ymax: tmpBox.ymax
|
|
146
|
+
};
|
|
147
|
+
if (feature instanceof Textbox
|
|
148
|
+
&& feature.label
|
|
135
149
|
&& typeof feature.text === 'string'
|
|
136
150
|
&& feature.text.trim().length === 0) {
|
|
137
151
|
return;
|
|
138
152
|
}
|
|
153
|
+
if (feature instanceof Textbox && !feature.label) {
|
|
154
|
+
const [x, y] = feature.anchorPoint;
|
|
155
|
+
box = {
|
|
156
|
+
xmin: box.xmin + x,
|
|
157
|
+
ymin: box.ymin + y,
|
|
158
|
+
xmax: box.xmax + x,
|
|
159
|
+
ymax: box.ymax + y
|
|
160
|
+
};
|
|
161
|
+
}
|
|
139
162
|
if (box.xmin === undefined) {
|
|
140
163
|
throw "Invalid box!";
|
|
141
164
|
}
|
|
@@ -151,24 +174,12 @@ export class Geometry {
|
|
|
151
174
|
height: maxY - minY,
|
|
152
175
|
};
|
|
153
176
|
}
|
|
154
|
-
static getType(feature) {
|
|
155
|
-
if (feature instanceof Label) {
|
|
156
|
-
return 'label';
|
|
157
|
-
}
|
|
158
|
-
else if (feature instanceof Flatten.Polygon) {
|
|
159
|
-
return 'polygon';
|
|
160
|
-
}
|
|
161
|
-
else if (feature instanceof Flatten.Segment) {
|
|
162
|
-
return 'segment';
|
|
163
|
-
}
|
|
164
|
-
console.log('unknown type', feature);
|
|
165
|
-
}
|
|
166
177
|
static FullCircleRadians = 2 * Math.PI;
|
|
167
|
-
static featuresToPath(items) {
|
|
178
|
+
static featuresToPath(items, flipX, flipY) {
|
|
168
179
|
const paths = [];
|
|
169
180
|
let isClosedPolygon = false;
|
|
170
181
|
items.forEach(item => {
|
|
171
|
-
if (item instanceof
|
|
182
|
+
if (item instanceof Textbox) {
|
|
172
183
|
return;
|
|
173
184
|
}
|
|
174
185
|
const path = [];
|
|
@@ -185,7 +196,15 @@ export class Geometry {
|
|
|
185
196
|
}
|
|
186
197
|
const startPoint = getArcPointRadians(x, y, radius, item.startAngle);
|
|
187
198
|
const endPoint = getArcPointRadians(x, y, radius, useEndAngle);
|
|
188
|
-
|
|
199
|
+
let largeArcSweepFlag = 0;
|
|
200
|
+
if (useEndAngle - item.startAngle > Math.PI) {
|
|
201
|
+
largeArcSweepFlag = 1;
|
|
202
|
+
}
|
|
203
|
+
let sweepFlag = 1;
|
|
204
|
+
if (flipX === 1 && flipY === 0) {
|
|
205
|
+
sweepFlag = 0;
|
|
206
|
+
}
|
|
207
|
+
paths.push('M', startPoint[0], startPoint[1], 'A', radius, radius, 0, largeArcSweepFlag, sweepFlag, endPoint[0], endPoint[1], extraEnd);
|
|
189
208
|
}
|
|
190
209
|
else {
|
|
191
210
|
const coords = Geometry.getCoords(item);
|
package/dist/esm/helpers.mjs
CHANGED
|
@@ -215,6 +215,7 @@ export function renderScript(scriptData, outputPath, options) {
|
|
|
215
215
|
showStats && console.log('Render took:', generateSvgTimer.lap());
|
|
216
216
|
if (outputPath) {
|
|
217
217
|
writeFileSync(outputPath, svgOutput);
|
|
218
|
+
console.log('Generated file', outputPath);
|
|
218
219
|
}
|
|
219
220
|
}
|
|
220
221
|
catch (err) {
|
package/dist/esm/layout.mjs
CHANGED
|
@@ -7,6 +7,7 @@ import { Geometry } from './geometry.mjs';
|
|
|
7
7
|
import { Logger } from './logger.mjs';
|
|
8
8
|
import { Frame, FrameParamKeys, FramePlotDirection } from './objects/Frame.mjs';
|
|
9
9
|
import { getBoundsSize, printBounds, resizeBounds, resizeToNearestGrid, toNearestGrid } from './utils.mjs';
|
|
10
|
+
import { Direction } from './objects/types.mjs';
|
|
10
11
|
export class LayoutEngine {
|
|
11
12
|
logger;
|
|
12
13
|
placeSubgraphVersion = 2;
|
|
@@ -935,16 +936,16 @@ function applyComponentParamsToSymbol(typeProp, component, symbol) {
|
|
|
935
936
|
function calculateSymbolAngle(symbol, pin, direction) {
|
|
936
937
|
let directionVector = 0;
|
|
937
938
|
switch (direction) {
|
|
938
|
-
case
|
|
939
|
+
case Direction.Right:
|
|
939
940
|
directionVector = 0;
|
|
940
941
|
break;
|
|
941
|
-
case
|
|
942
|
+
case Direction.Down:
|
|
942
943
|
directionVector = 90;
|
|
943
944
|
break;
|
|
944
|
-
case
|
|
945
|
+
case Direction.Left:
|
|
945
946
|
directionVector = 180;
|
|
946
947
|
break;
|
|
947
|
-
case
|
|
948
|
+
case Direction.Up:
|
|
948
949
|
directionVector = 270;
|
|
949
950
|
break;
|
|
950
951
|
}
|
|
@@ -1012,16 +1013,16 @@ export class RenderWire extends RenderObject {
|
|
|
1012
1013
|
this.segments.forEach(segment => {
|
|
1013
1014
|
const { direction, value } = segment;
|
|
1014
1015
|
let didAddPoint = false;
|
|
1015
|
-
if (direction ===
|
|
1016
|
+
if (direction === Direction.Down) {
|
|
1016
1017
|
tmpY += value;
|
|
1017
1018
|
}
|
|
1018
|
-
else if (direction ===
|
|
1019
|
+
else if (direction === Direction.Up) {
|
|
1019
1020
|
tmpY -= value;
|
|
1020
1021
|
}
|
|
1021
|
-
else if (direction ===
|
|
1022
|
+
else if (direction === Direction.Left) {
|
|
1022
1023
|
tmpX -= value;
|
|
1023
1024
|
}
|
|
1024
|
-
else if (direction ===
|
|
1025
|
+
else if (direction === Direction.Right) {
|
|
1025
1026
|
tmpX += value;
|
|
1026
1027
|
}
|
|
1027
1028
|
else if (direction === 'auto' || direction === "auto_") {
|
|
@@ -1090,16 +1091,16 @@ export class RenderWire extends RenderObject {
|
|
|
1090
1091
|
let tmpY = this.y;
|
|
1091
1092
|
excludeLastSegment.forEach(segment => {
|
|
1092
1093
|
const { direction, value } = segment;
|
|
1093
|
-
if (direction ===
|
|
1094
|
+
if (direction === Direction.Down) {
|
|
1094
1095
|
tmpY += value;
|
|
1095
1096
|
}
|
|
1096
|
-
else if (direction ===
|
|
1097
|
+
else if (direction === Direction.Up) {
|
|
1097
1098
|
tmpY -= value;
|
|
1098
1099
|
}
|
|
1099
|
-
else if (direction ===
|
|
1100
|
+
else if (direction === Direction.Left) {
|
|
1100
1101
|
tmpX -= value;
|
|
1101
1102
|
}
|
|
1102
|
-
else if (direction ===
|
|
1103
|
+
else if (direction === Direction.Right) {
|
|
1103
1104
|
tmpX += value;
|
|
1104
1105
|
}
|
|
1105
1106
|
});
|
|
@@ -1107,16 +1108,16 @@ export class RenderWire extends RenderObject {
|
|
|
1107
1108
|
let valueXY = null;
|
|
1108
1109
|
const lastSegment = this.segments[this.segments.length - 1];
|
|
1109
1110
|
switch (lastSegment.direction) {
|
|
1110
|
-
case
|
|
1111
|
+
case Direction.Left:
|
|
1111
1112
|
useValue = tmpX - untilX;
|
|
1112
1113
|
break;
|
|
1113
|
-
case
|
|
1114
|
+
case Direction.Right:
|
|
1114
1115
|
useValue = untilX - tmpX;
|
|
1115
1116
|
break;
|
|
1116
|
-
case
|
|
1117
|
+
case Direction.Up:
|
|
1117
1118
|
useValue = untilY - tmpY;
|
|
1118
1119
|
break;
|
|
1119
|
-
case
|
|
1120
|
+
case Direction.Down:
|
|
1120
1121
|
useValue = tmpY - untilY;
|
|
1121
1122
|
break;
|
|
1122
1123
|
case 'auto':
|
|
@@ -1224,6 +1225,24 @@ export class RenderJunction {
|
|
|
1224
1225
|
this.y = y;
|
|
1225
1226
|
}
|
|
1226
1227
|
}
|
|
1228
|
+
export function CalculatePinPositions(component) {
|
|
1229
|
+
const pinPositionMapping = new Map();
|
|
1230
|
+
let tmpSymbol;
|
|
1231
|
+
if (component.displayProp !== null
|
|
1232
|
+
&& component.displayProp instanceof SymbolDrawing) {
|
|
1233
|
+
tmpSymbol = new SymbolPlaceholder(component.displayProp);
|
|
1234
|
+
}
|
|
1235
|
+
else {
|
|
1236
|
+
const symbolPinDefinitions = generateLayoutPinDefinition(component);
|
|
1237
|
+
tmpSymbol = new SymbolCustom(symbolPinDefinitions);
|
|
1238
|
+
}
|
|
1239
|
+
tmpSymbol.refreshDrawing();
|
|
1240
|
+
const pins = component.pins;
|
|
1241
|
+
pins.forEach((value, key) => {
|
|
1242
|
+
pinPositionMapping.set(key, tmpSymbol.pinPosition(key));
|
|
1243
|
+
});
|
|
1244
|
+
return pinPositionMapping;
|
|
1245
|
+
}
|
|
1227
1246
|
function isPointOverlap(x, y, other) {
|
|
1228
1247
|
return (x >= other.x && y >= other.y && x <= (other.x + other.width) && y <= (other.y + other.height));
|
|
1229
1248
|
}
|
|
@@ -18,6 +18,10 @@ export class ClassComponent {
|
|
|
18
18
|
widthProp = null;
|
|
19
19
|
typeProp = null;
|
|
20
20
|
copyProp = false;
|
|
21
|
+
angleProp = 0;
|
|
22
|
+
followWireOrientationProp = true;
|
|
23
|
+
wireOrientationAngle = 0;
|
|
24
|
+
useWireOrientationAngle = true;
|
|
21
25
|
styles = {};
|
|
22
26
|
assignedRefDes = null;
|
|
23
27
|
constructor(instanceName, numPins, className) {
|
|
@@ -120,6 +124,9 @@ export class ClassComponent {
|
|
|
120
124
|
component.arrangeProps = this.arrangeProps;
|
|
121
125
|
component.widthProp = this.widthProp;
|
|
122
126
|
component.typeProp = this.typeProp;
|
|
127
|
+
component.angleProp = this.angleProp;
|
|
128
|
+
component.followWireOrientationProp = this.followWireOrientationProp;
|
|
129
|
+
component.useWireOrientationAngle = this.useWireOrientationAngle;
|
|
123
130
|
if (this.displayProp) {
|
|
124
131
|
if (typeof this.displayProp === "string") {
|
|
125
132
|
component.displayProp = this.displayProp;
|
|
@@ -10,3 +10,10 @@ export var ParseSymbolType;
|
|
|
10
10
|
ParseSymbolType["Function"] = "function";
|
|
11
11
|
ParseSymbolType["Undefined"] = "undefined";
|
|
12
12
|
})(ParseSymbolType || (ParseSymbolType = {}));
|
|
13
|
+
export var Direction;
|
|
14
|
+
(function (Direction) {
|
|
15
|
+
Direction["Left"] = "left";
|
|
16
|
+
Direction["Right"] = "right";
|
|
17
|
+
Direction["Down"] = "down";
|
|
18
|
+
Direction["Up"] = "up";
|
|
19
|
+
})(Direction || (Direction = {}));
|
package/dist/esm/visitor.mjs
CHANGED
|
@@ -4,7 +4,7 @@ import { PinDefinition, PinIdType } from './objects/PinDefinition.mjs';
|
|
|
4
4
|
import { PinTypes } from './objects/PinTypes.mjs';
|
|
5
5
|
import { UndeclaredReference } from './objects/types.mjs';
|
|
6
6
|
import { BlockTypes, ComponentTypes, NoNetText, ReferenceTypes } from './globals.mjs';
|
|
7
|
-
import { SymbolDrawingCommands } from './draw_symbols.mjs';
|
|
7
|
+
import { PlaceHolderCommands, SymbolDrawingCommands } from './draw_symbols.mjs';
|
|
8
8
|
import { BaseVisitor } from './BaseVisitor.mjs';
|
|
9
9
|
export class ParserVisitor extends BaseVisitor {
|
|
10
10
|
visitKeyword_assignment_expr = (ctx) => {
|
|
@@ -30,7 +30,7 @@ export class ParserVisitor extends BaseVisitor {
|
|
|
30
30
|
const ctxDataWithAssignmentExpr = ctx.data_expr_with_assignment();
|
|
31
31
|
this.visit(ctxDataWithAssignmentExpr);
|
|
32
32
|
const [component, pinValue] = this.getResult(ctxDataWithAssignmentExpr);
|
|
33
|
-
|
|
33
|
+
this.getExecutor().addComponentExisting(component, pinValue);
|
|
34
34
|
};
|
|
35
35
|
visitAt_component_expr = (ctx) => {
|
|
36
36
|
if (ctx.Point()) {
|
|
@@ -137,12 +137,13 @@ export class ParserVisitor extends BaseVisitor {
|
|
|
137
137
|
properties.get('copy') : false;
|
|
138
138
|
const width = properties.has('width') ?
|
|
139
139
|
properties.get('width') : null;
|
|
140
|
+
const angle = properties.has('angle') ?
|
|
141
|
+
properties.get('angle') : null;
|
|
142
|
+
const followWireOrientation = properties.has('followWireOrientation') ?
|
|
143
|
+
properties.get('followWireOrientation') : true;
|
|
140
144
|
const props = {
|
|
141
|
-
arrange,
|
|
142
|
-
|
|
143
|
-
type,
|
|
144
|
-
width,
|
|
145
|
-
copy
|
|
145
|
+
arrange, display, type, width, copy,
|
|
146
|
+
angle, followWireOrientation
|
|
146
147
|
};
|
|
147
148
|
this.setResult(ctx, this.getExecutor().createComponent(instanceName, pins, params, props));
|
|
148
149
|
};
|
|
@@ -176,9 +177,20 @@ export class ParserVisitor extends BaseVisitor {
|
|
|
176
177
|
else {
|
|
177
178
|
throw "Invalid command!";
|
|
178
179
|
}
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
180
|
+
let parameters = [];
|
|
181
|
+
const ctxNestedProperties = ctx.nested_properties_inner();
|
|
182
|
+
if (ctxNestedProperties) {
|
|
183
|
+
this.visit(ctxNestedProperties);
|
|
184
|
+
const nestedKeyValues = this.getResult(ctxNestedProperties);
|
|
185
|
+
nestedKeyValues.forEach((value, key) => {
|
|
186
|
+
parameters.push(['keyword', key, value]);
|
|
187
|
+
});
|
|
188
|
+
}
|
|
189
|
+
else {
|
|
190
|
+
const ctxParameters = ctx.parameters();
|
|
191
|
+
this.visit(ctxParameters);
|
|
192
|
+
parameters = this.getResult(ctxParameters);
|
|
193
|
+
}
|
|
182
194
|
this.setResult(ctx, [commandName, parameters]);
|
|
183
195
|
};
|
|
184
196
|
visitProperty_expr = (ctx) => {
|
|
@@ -207,7 +219,7 @@ export class ParserVisitor extends BaseVisitor {
|
|
|
207
219
|
}
|
|
208
220
|
this.setResult(ctx, value);
|
|
209
221
|
};
|
|
210
|
-
|
|
222
|
+
visitNested_properties_inner = (ctx) => {
|
|
211
223
|
const result = new Map();
|
|
212
224
|
ctx.property_expr().forEach((item) => {
|
|
213
225
|
this.visit(item);
|
|
@@ -218,6 +230,11 @@ export class ParserVisitor extends BaseVisitor {
|
|
|
218
230
|
});
|
|
219
231
|
this.setResult(ctx, result);
|
|
220
232
|
};
|
|
233
|
+
visitNested_properties = (ctx) => {
|
|
234
|
+
const ctxNested = ctx.nested_properties_inner();
|
|
235
|
+
this.visit(ctxNested);
|
|
236
|
+
this.setResult(ctx, this.getResult(ctxNested));
|
|
237
|
+
};
|
|
221
238
|
visitProperty_key_expr = (ctx) => {
|
|
222
239
|
const ctxID = ctx.ID();
|
|
223
240
|
const ctxIntegerValue = ctx.INTEGER_VALUE();
|
|
@@ -267,18 +284,40 @@ export class ParserVisitor extends BaseVisitor {
|
|
|
267
284
|
else if (ctxID2) {
|
|
268
285
|
result = ctxID2.getText();
|
|
269
286
|
}
|
|
287
|
+
let shouldIgnoreWireOrientation = false;
|
|
270
288
|
if (modifierText === 'flip') {
|
|
271
289
|
const flipValue = result;
|
|
272
290
|
if (flipValue.indexOf('x') !== -1) {
|
|
273
291
|
component.setParam('flipX', 1);
|
|
292
|
+
shouldIgnoreWireOrientation = true;
|
|
274
293
|
}
|
|
275
294
|
if (flipValue.indexOf('y') !== -1) {
|
|
276
295
|
component.setParam('flipY', 1);
|
|
296
|
+
shouldIgnoreWireOrientation = true;
|
|
277
297
|
}
|
|
278
298
|
}
|
|
279
299
|
else if (modifierText === 'angle') {
|
|
280
300
|
const angleValue = Number(result);
|
|
281
301
|
component.setParam('angle', angleValue);
|
|
302
|
+
shouldIgnoreWireOrientation = true;
|
|
303
|
+
}
|
|
304
|
+
else if (modifierText === 'anchor') {
|
|
305
|
+
if (component.displayProp
|
|
306
|
+
&& component.displayProp instanceof SymbolDrawingCommands) {
|
|
307
|
+
const commands = (component.displayProp)
|
|
308
|
+
.getCommands();
|
|
309
|
+
commands.forEach(command => {
|
|
310
|
+
const positionParams = command[1];
|
|
311
|
+
const keywordParams = command[2];
|
|
312
|
+
if (command[0] === PlaceHolderCommands.label
|
|
313
|
+
&& positionParams[0] === 'value') {
|
|
314
|
+
keywordParams.set('anchor', result);
|
|
315
|
+
}
|
|
316
|
+
});
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
if (shouldIgnoreWireOrientation) {
|
|
320
|
+
component.useWireOrientationAngle = false;
|
|
282
321
|
}
|
|
283
322
|
});
|
|
284
323
|
}
|