circuitscript 0.0.25 → 0.0.27
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/LICENSE +1 -1
- package/dist/cjs/BaseVisitor.js +16 -12
- package/dist/cjs/SemanticTokenVisitor.js +3 -3
- package/dist/cjs/antlr/CircuitScriptLexer.js +189 -166
- package/dist/cjs/antlr/CircuitScriptParser.js +1295 -719
- package/dist/cjs/draw_symbols.js +42 -14
- package/dist/cjs/execute.js +91 -30
- package/dist/cjs/export.js +91 -5
- package/dist/cjs/geometry.js +45 -26
- package/dist/cjs/globals.js +1 -2
- package/dist/cjs/helpers.js +6 -2
- package/dist/cjs/layout.js +37 -17
- package/dist/cjs/main.js +21 -9
- package/dist/cjs/objects/ClassComponent.js +8 -0
- package/dist/cjs/objects/types.js +8 -1
- package/dist/cjs/render.js +1 -1
- package/dist/cjs/visitor.js +131 -23
- package/dist/esm/BaseVisitor.mjs +17 -13
- package/dist/esm/SemanticTokenVisitor.mjs +3 -3
- package/dist/esm/antlr/CircuitScriptLexer.mjs +189 -166
- package/dist/esm/antlr/CircuitScriptParser.mjs +1287 -716
- package/dist/esm/antlr/CircuitScriptVisitor.mjs +6 -1
- package/dist/esm/draw_symbols.mjs +44 -16
- package/dist/esm/execute.mjs +90 -26
- package/dist/esm/export.mjs +89 -6
- package/dist/esm/geometry.mjs +44 -25
- package/dist/esm/globals.mjs +1 -2
- package/dist/esm/helpers.mjs +7 -3
- package/dist/esm/layout.mjs +35 -16
- package/dist/esm/main.mjs +21 -9
- package/dist/esm/objects/ClassComponent.mjs +8 -0
- package/dist/esm/objects/types.mjs +7 -0
- package/dist/esm/render.mjs +2 -2
- package/dist/esm/visitor.mjs +133 -25
- package/dist/types/BaseVisitor.d.ts +2 -5
- package/dist/types/SemanticTokenVisitor.d.ts +2 -2
- package/dist/types/antlr/CircuitScriptLexer.d.ts +29 -22
- package/dist/types/antlr/CircuitScriptParser.d.ts +121 -44
- package/dist/types/antlr/CircuitScriptVisitor.d.ts +12 -2
- package/dist/types/draw_symbols.d.ts +11 -6
- package/dist/types/execute.d.ts +6 -4
- package/dist/types/export.d.ts +27 -1
- package/dist/types/geometry.d.ts +12 -9
- package/dist/types/globals.d.ts +2 -3
- package/dist/types/layout.d.ts +5 -0
- package/dist/types/objects/ClassComponent.d.ts +5 -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 +7 -3
- package/libs/lib.cst +28 -10
- package/package.json +1 -1
|
@@ -31,6 +31,7 @@ export class CircuitScriptVisitor extends AbstractParseTreeVisitor {
|
|
|
31
31
|
visitFunctionCallExpr;
|
|
32
32
|
visitAdditionExpr;
|
|
33
33
|
visitMultiplyExpr;
|
|
34
|
+
visitLogicalOperatorExpr;
|
|
34
35
|
visitDataExpr;
|
|
35
36
|
visitUnaryOperatorExpr;
|
|
36
37
|
visitValueAtomExpr;
|
|
@@ -49,7 +50,8 @@ export class CircuitScriptVisitor extends AbstractParseTreeVisitor {
|
|
|
49
50
|
visitFunction_return_expr;
|
|
50
51
|
visitCreate_component_expr;
|
|
51
52
|
visitCreate_graphic_expr;
|
|
52
|
-
|
|
53
|
+
visitNested_properties_inner;
|
|
54
|
+
visitGraphic_expr;
|
|
53
55
|
visitProperty_expr;
|
|
54
56
|
visitProperty_key_expr;
|
|
55
57
|
visitNested_properties;
|
|
@@ -61,4 +63,7 @@ export class CircuitScriptVisitor extends AbstractParseTreeVisitor {
|
|
|
61
63
|
visitPoint_expr;
|
|
62
64
|
visitImport_expr;
|
|
63
65
|
visitFrame_expr;
|
|
66
|
+
visitIf_expr;
|
|
67
|
+
visitIf_inner_expr;
|
|
68
|
+
visitElse_expr;
|
|
64
69
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import { SymbolPinSide, defaultFont } from "./globals.mjs";
|
|
2
|
-
import { Geometry, GeometryProp, HorizontalAlign, Label, VerticalAlign } from "./geometry.mjs";
|
|
1
|
+
import { ReferenceTypes, SymbolPinSide, defaultFont } from "./globals.mjs";
|
|
2
|
+
import { Geometry, GeometryProp, HorizontalAlign, Label, Textbox, VerticalAlign } from "./geometry.mjs";
|
|
3
|
+
import { PinTypes } from "./objects/PinTypes.mjs";
|
|
3
4
|
const defaultSymbolLineWidth = 2;
|
|
4
5
|
export class SymbolGraphic {
|
|
5
6
|
drawPortsName = true;
|
|
@@ -251,7 +252,7 @@ export class SymbolText extends SymbolGraphic {
|
|
|
251
252
|
}
|
|
252
253
|
generateDrawing() {
|
|
253
254
|
const drawing = new SymbolDrawing();
|
|
254
|
-
drawing.
|
|
255
|
+
drawing.addTextbox(0, 0, this.text, {
|
|
255
256
|
fontSize: this.fontSize,
|
|
256
257
|
anchor: HorizontalAlign.Middle,
|
|
257
258
|
fontWeight: this.fontWeight,
|
|
@@ -316,13 +317,7 @@ export class SymbolPlaceholder extends SymbolGraphic {
|
|
|
316
317
|
break;
|
|
317
318
|
}
|
|
318
319
|
case PlaceHolderCommands.label: {
|
|
319
|
-
const
|
|
320
|
-
const style = {};
|
|
321
|
-
keywords.forEach(item => {
|
|
322
|
-
if (keywordParams.has(item)) {
|
|
323
|
-
style[item] = keywordParams.get(item);
|
|
324
|
-
}
|
|
325
|
-
});
|
|
320
|
+
const style = this.parseLabelStyle(keywordParams);
|
|
326
321
|
positionParams = [...positionParams];
|
|
327
322
|
positionParams.push(style);
|
|
328
323
|
const labelId = positionParams[0];
|
|
@@ -335,10 +330,33 @@ export class SymbolPlaceholder extends SymbolGraphic {
|
|
|
335
330
|
drawing.addLabelId(...tmpPositionParams);
|
|
336
331
|
break;
|
|
337
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
|
+
}
|
|
338
346
|
}
|
|
339
347
|
});
|
|
340
348
|
drawing.log("=== end generate drawing ===");
|
|
341
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
|
+
}
|
|
342
360
|
drawPinParams(drawing, commandName, keywordParams, positionParams) {
|
|
343
361
|
drawing.log('add pin', ...positionParams);
|
|
344
362
|
const keywordDisplayPinId = 'display_pin_id';
|
|
@@ -348,6 +366,11 @@ export class SymbolPlaceholder extends SymbolGraphic {
|
|
|
348
366
|
displayPinId = false;
|
|
349
367
|
}
|
|
350
368
|
let pinNameParam = null;
|
|
369
|
+
let pinType = PinTypes.Any;
|
|
370
|
+
if (positionParams[1].type && positionParams[1].type === ReferenceTypes.pinType) {
|
|
371
|
+
pinType = positionParams[1].value;
|
|
372
|
+
positionParams = [positionParams[0], ...positionParams.slice(2)];
|
|
373
|
+
}
|
|
351
374
|
if (typeof positionParams[1] === 'string') {
|
|
352
375
|
pinNameParam = positionParams[1];
|
|
353
376
|
positionParams = [positionParams[0], ...positionParams.slice(2)];
|
|
@@ -443,6 +466,7 @@ export var PlaceHolderCommands;
|
|
|
443
466
|
PlaceHolderCommands["lineWidth"] = "lineWidth";
|
|
444
467
|
PlaceHolderCommands["fill"] = "fill";
|
|
445
468
|
PlaceHolderCommands["lineColor"] = "lineColor";
|
|
469
|
+
PlaceHolderCommands["text"] = "text";
|
|
446
470
|
})(PlaceHolderCommands || (PlaceHolderCommands = {}));
|
|
447
471
|
export class SymbolCustom extends SymbolGraphic {
|
|
448
472
|
pinDefinition = [];
|
|
@@ -630,6 +654,10 @@ export class SymbolDrawing {
|
|
|
630
654
|
this.items.push(Geometry.label(id, x, y, textValue, style));
|
|
631
655
|
return this;
|
|
632
656
|
}
|
|
657
|
+
addTextbox(x, y, textValue, style) {
|
|
658
|
+
this.items.push(Geometry.textbox(null, x, y, textValue, style));
|
|
659
|
+
return this;
|
|
660
|
+
}
|
|
633
661
|
addPath(...pathParts) {
|
|
634
662
|
const parts = pathParts.reduce((accum, tmp) => {
|
|
635
663
|
if (typeof tmp === "string") {
|
|
@@ -704,7 +732,7 @@ export class SymbolDrawing {
|
|
|
704
732
|
let currentLineColor = '#333';
|
|
705
733
|
const pathItems = [];
|
|
706
734
|
this.items.forEach(item => {
|
|
707
|
-
if (!(item instanceof
|
|
735
|
+
if (!(item instanceof Textbox)) {
|
|
708
736
|
if (item instanceof GeometryProp) {
|
|
709
737
|
if (item.name === 'lineWidth') {
|
|
710
738
|
currentLineWidth = item.value;
|
|
@@ -719,7 +747,7 @@ export class SymbolDrawing {
|
|
|
719
747
|
else {
|
|
720
748
|
let tmpResult = Geometry.groupFlip([item], this.flipX, this.flipY);
|
|
721
749
|
tmpResult = Geometry.groupRotate(tmpResult, this.angle, this.mainOrigin);
|
|
722
|
-
const { path, isClosedPolygon } = this.featuresToPath(tmpResult);
|
|
750
|
+
const { path, isClosedPolygon } = this.featuresToPath(tmpResult, this.flipX, this.flipY);
|
|
723
751
|
pathItems.push({
|
|
724
752
|
path: path,
|
|
725
753
|
lineWidth: currentLineWidth,
|
|
@@ -735,14 +763,14 @@ export class SymbolDrawing {
|
|
|
735
763
|
let features = this.pins.map(item => item[1]);
|
|
736
764
|
features = Geometry.groupFlip(features, this.flipX, this.flipY);
|
|
737
765
|
features = Geometry.groupRotate(features, this.angle, this.mainOrigin);
|
|
738
|
-
const { path } = this.featuresToPath(features);
|
|
766
|
+
const { path } = this.featuresToPath(features, this.flipX, this.flipY);
|
|
739
767
|
return path;
|
|
740
768
|
}
|
|
741
769
|
getLabels() {
|
|
742
|
-
return this.items.filter(item => item instanceof
|
|
770
|
+
return this.items.filter(item => item instanceof Textbox);
|
|
743
771
|
}
|
|
744
|
-
featuresToPath(items) {
|
|
745
|
-
return Geometry.featuresToPath(items);
|
|
772
|
+
featuresToPath(items, flipX, flipY) {
|
|
773
|
+
return Geometry.featuresToPath(items, flipX, flipY);
|
|
746
774
|
}
|
|
747
775
|
getBoundingBox(excludeLabels = false) {
|
|
748
776
|
const pinFeatures = this.pins.map(pin => {
|
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;
|
|
@@ -144,12 +147,27 @@ export class ExecutionContext {
|
|
|
144
147
|
pins.forEach((pin) => {
|
|
145
148
|
component.pins.set(pin.id, pin);
|
|
146
149
|
});
|
|
150
|
+
component.arrangeProps = props.arrange ?? null;
|
|
151
|
+
component.displayProp = props.display ?? null;
|
|
152
|
+
component.widthProp = props.width ?? null;
|
|
153
|
+
component.typeProp = props.type ?? null;
|
|
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;
|
|
147
164
|
const paramsMap = new Map();
|
|
148
165
|
params.forEach((param) => {
|
|
149
166
|
component.parameters.set(param.paramName, param.paramValue);
|
|
150
167
|
paramsMap.set(param.paramName, param.paramValue);
|
|
151
168
|
});
|
|
152
|
-
if (
|
|
169
|
+
if (component.typeProp === ComponentTypes.net
|
|
170
|
+
|| component.typeProp === ComponentTypes.label) {
|
|
153
171
|
const netName = paramsMap.get(ParamKeys.net_name);
|
|
154
172
|
const priority = paramsMap.get(ParamKeys.priority);
|
|
155
173
|
const result = this.resolveNet(netName, this.netNamespace);
|
|
@@ -165,12 +183,7 @@ export class ExecutionContext {
|
|
|
165
183
|
this.scope.setNet(component, 1, tmpNet);
|
|
166
184
|
this.log('set net', netName, 'component', component);
|
|
167
185
|
}
|
|
168
|
-
const
|
|
169
|
-
component.arrangeProps = arrange;
|
|
170
|
-
component.displayProp = props.display ?? null;
|
|
171
|
-
component.widthProp = props.width ?? null;
|
|
172
|
-
component.typeProp = props.type ?? null;
|
|
173
|
-
const portSides = getPortSide(component.pins, arrange);
|
|
186
|
+
const portSides = getPortSide(component.pins, component.arrangeProps);
|
|
174
187
|
portSides.forEach(({ pinId, side, position }) => {
|
|
175
188
|
if (component.pins.has(pinId)) {
|
|
176
189
|
const tmpPin = component.pins.get(pinId);
|
|
@@ -187,6 +200,10 @@ export class ExecutionContext {
|
|
|
187
200
|
}
|
|
188
201
|
printPoint(extra = '') {
|
|
189
202
|
let netName = NoNetText;
|
|
203
|
+
if (this.scope.currentComponent === null || this.scope.currentPin === null) {
|
|
204
|
+
this.log((extra !== '' ? (extra + ' ') : '') + 'point is null');
|
|
205
|
+
return;
|
|
206
|
+
}
|
|
190
207
|
if (this.scope.hasNet(this.scope.currentComponent, this.scope.currentPin)) {
|
|
191
208
|
netName = this.scope
|
|
192
209
|
.getNet(this.scope.currentComponent, this.scope.currentPin)
|
|
@@ -200,6 +217,7 @@ export class ExecutionContext {
|
|
|
200
217
|
addComponentExisting(component, pin) {
|
|
201
218
|
const startPin = pin;
|
|
202
219
|
const nextPin = component.getNextPinAfter(startPin);
|
|
220
|
+
this.applyComponentAngleFromWire(component, pin);
|
|
203
221
|
this.toComponent(component, startPin, { addSequence: true });
|
|
204
222
|
this.log('move to next pin: ' + nextPin);
|
|
205
223
|
this.atComponent(component, nextPin, {
|
|
@@ -235,6 +253,7 @@ export class ExecutionContext {
|
|
|
235
253
|
.toString());
|
|
236
254
|
}
|
|
237
255
|
const linkedNet = this.linkComponentPinNet(this.scope.currentComponent, this.scope.currentPin, component, pinId);
|
|
256
|
+
this.applyComponentAngleFromWire(component, pinId);
|
|
238
257
|
this.scope.currentComponent = component;
|
|
239
258
|
this.scope.currentPin = pinId;
|
|
240
259
|
this.scope.clearActive();
|
|
@@ -283,22 +302,22 @@ export class ExecutionContext {
|
|
|
283
302
|
this.printPoint();
|
|
284
303
|
return this.getCurrentPoint();
|
|
285
304
|
}
|
|
286
|
-
|
|
287
|
-
let
|
|
305
|
+
copyComponent(component) {
|
|
306
|
+
let componentCopy = null;
|
|
288
307
|
if (!this.scope.copyIDs.has(component.instanceName)) {
|
|
289
308
|
this.scope.copyIDs.set(component.instanceName, 0);
|
|
290
309
|
}
|
|
291
310
|
const idNum = this.scope.copyIDs.get(component.instanceName);
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
311
|
+
componentCopy = component.clone();
|
|
312
|
+
componentCopy._copyID = idNum;
|
|
313
|
+
componentCopy._copyFrom = component;
|
|
295
314
|
this.scope.copyIDs.set(component.instanceName, idNum + 1);
|
|
296
315
|
const cloneInstanceName = component.instanceName + ':' + idNum;
|
|
297
|
-
this.scope.instances.set(cloneInstanceName,
|
|
298
|
-
|
|
299
|
-
this.linkComponentPinNet(component, 1,
|
|
316
|
+
this.scope.instances.set(cloneInstanceName, componentCopy);
|
|
317
|
+
componentCopy.instanceName = cloneInstanceName;
|
|
318
|
+
this.linkComponentPinNet(component, 1, componentCopy, 1);
|
|
300
319
|
this.log('created clone of net component:', cloneInstanceName);
|
|
301
|
-
return
|
|
320
|
+
return componentCopy;
|
|
302
321
|
}
|
|
303
322
|
enterBlocks(blockType) {
|
|
304
323
|
if (blockType === BlockTypes.Point) {
|
|
@@ -565,7 +584,8 @@ export class ExecutionContext {
|
|
|
565
584
|
}
|
|
566
585
|
else if (action === SequenceAction.At || action === SequenceAction.To) {
|
|
567
586
|
const tmpComponent = sequenceAction[1];
|
|
568
|
-
if (
|
|
587
|
+
if (tmpComponent.typeProp === ComponentTypes.net
|
|
588
|
+
&& tmpComponent.parameters.get(ParamKeys.net_name) === 'gnd') {
|
|
569
589
|
tmpComponent._copyID = gndCopyIdOffset + incrementGndLinkId;
|
|
570
590
|
incrementGndLinkId += 1;
|
|
571
591
|
}
|
|
@@ -682,6 +702,59 @@ export class ExecutionContext {
|
|
|
682
702
|
this.scope.currentComponent.styles[key] = styles[key];
|
|
683
703
|
}
|
|
684
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
|
+
}
|
|
685
758
|
enterFrame() {
|
|
686
759
|
const frameId = this.scope.frames.length + 1;
|
|
687
760
|
const frameObject = new Frame(frameId);
|
|
@@ -706,15 +779,6 @@ function isWireSegmentsEndAuto(segments) {
|
|
|
706
779
|
}
|
|
707
780
|
return false;
|
|
708
781
|
}
|
|
709
|
-
export function isNetComponent(component) {
|
|
710
|
-
return component.parameters.has(ParamKeys.__is_net);
|
|
711
|
-
}
|
|
712
|
-
export function isLabelComponent(component) {
|
|
713
|
-
return component.parameters.has(ParamKeys.__is_label);
|
|
714
|
-
}
|
|
715
|
-
export function isNetOnlyComponent(component) {
|
|
716
|
-
return isNetComponent(component) && !isLabelComponent(component);
|
|
717
|
-
}
|
|
718
782
|
export function getPortSide(pins, arrangeProps) {
|
|
719
783
|
const result = [];
|
|
720
784
|
if (arrangeProps === null) {
|
package/dist/esm/export.mjs
CHANGED
|
@@ -3,6 +3,7 @@ import { NumericValue } from "./objects/ParamDefinition.mjs";
|
|
|
3
3
|
export function generateKiCADNetList(netlist) {
|
|
4
4
|
const componentsList = [];
|
|
5
5
|
const nets = {};
|
|
6
|
+
const missingFootprints = [];
|
|
6
7
|
netlist.forEach(entry => {
|
|
7
8
|
const { instance, pins } = entry;
|
|
8
9
|
if (instance.assignedRefDes !== null) {
|
|
@@ -22,7 +23,10 @@ export function generateKiCADNetList(netlist) {
|
|
|
22
23
|
instance.parameters.get('footprint')]);
|
|
23
24
|
}
|
|
24
25
|
else {
|
|
25
|
-
|
|
26
|
+
missingFootprints.push({
|
|
27
|
+
refdes: instance.assignedRefDes,
|
|
28
|
+
instanceName: instance.instanceName
|
|
29
|
+
});
|
|
26
30
|
}
|
|
27
31
|
componentsList.push(instanceDetails);
|
|
28
32
|
for (const key in pins) {
|
|
@@ -63,20 +67,24 @@ export function generateKiCADNetList(netlist) {
|
|
|
63
67
|
]);
|
|
64
68
|
counter++;
|
|
65
69
|
}
|
|
70
|
+
const dateString = new Date().toISOString().slice(0, 10);
|
|
66
71
|
const tree = [
|
|
67
72
|
Id("export"),
|
|
68
73
|
[Id("version"), "E"],
|
|
69
74
|
[Id("design"),
|
|
70
|
-
[Id("source"), "/
|
|
71
|
-
[Id("date"),
|
|
75
|
+
[Id("source"), "/unknown-file"],
|
|
76
|
+
[Id("date"), dateString],
|
|
72
77
|
[Id("tool"), "circuitscript-to-kicad"]
|
|
73
78
|
],
|
|
74
79
|
[Id('components'), ...componentsList],
|
|
75
80
|
[Id('nets'), ...netItems]
|
|
76
81
|
];
|
|
77
|
-
return
|
|
82
|
+
return {
|
|
83
|
+
tree,
|
|
84
|
+
missingFootprints
|
|
85
|
+
};
|
|
78
86
|
}
|
|
79
|
-
function printTree(tree, level = 0) {
|
|
87
|
+
export function printTree(tree, level = 0) {
|
|
80
88
|
const output = [];
|
|
81
89
|
if (!Array.isArray(tree)) {
|
|
82
90
|
return "\"" + tree + "\"";
|
|
@@ -98,9 +106,84 @@ function printTree(tree, level = 0) {
|
|
|
98
106
|
function Id(name) {
|
|
99
107
|
return new IdObject(name);
|
|
100
108
|
}
|
|
101
|
-
class IdObject {
|
|
109
|
+
export class IdObject {
|
|
102
110
|
keyName;
|
|
103
111
|
constructor(keyName) {
|
|
104
112
|
this.keyName = keyName;
|
|
105
113
|
}
|
|
106
114
|
}
|
|
115
|
+
export function _id(key) {
|
|
116
|
+
return new IdObject(key);
|
|
117
|
+
}
|
|
118
|
+
export class SExpObject {
|
|
119
|
+
object;
|
|
120
|
+
constructor(object) {
|
|
121
|
+
this.object = object;
|
|
122
|
+
}
|
|
123
|
+
getKey(object = null) {
|
|
124
|
+
object = object ?? this.object;
|
|
125
|
+
return object[0];
|
|
126
|
+
}
|
|
127
|
+
getValue(object = null) {
|
|
128
|
+
object = object ?? this.object;
|
|
129
|
+
return object.slice(1);
|
|
130
|
+
}
|
|
131
|
+
getJSON(object = null) {
|
|
132
|
+
object = object ?? this.object;
|
|
133
|
+
if (!Array.isArray(object)) {
|
|
134
|
+
return object;
|
|
135
|
+
}
|
|
136
|
+
const properties = {};
|
|
137
|
+
const keyName = object[0].keyName;
|
|
138
|
+
if (object.length === 2) {
|
|
139
|
+
properties[keyName] = this.getJSON(object[1]);
|
|
140
|
+
}
|
|
141
|
+
else {
|
|
142
|
+
const innerProps = {};
|
|
143
|
+
this.getValue(object).forEach(item => {
|
|
144
|
+
const tmpValue = this.getJSON(item);
|
|
145
|
+
if (typeof tmpValue === "object") {
|
|
146
|
+
for (const key in tmpValue) {
|
|
147
|
+
if (innerProps[key]) {
|
|
148
|
+
if (!Array.isArray(innerProps[key])) {
|
|
149
|
+
innerProps[key] = [innerProps[key]];
|
|
150
|
+
}
|
|
151
|
+
innerProps[key].push(tmpValue[key]);
|
|
152
|
+
}
|
|
153
|
+
else {
|
|
154
|
+
innerProps[key] = tmpValue[key];
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
else {
|
|
159
|
+
innerProps[item[0].keyName] = tmpValue;
|
|
160
|
+
}
|
|
161
|
+
});
|
|
162
|
+
properties[keyName] = innerProps;
|
|
163
|
+
}
|
|
164
|
+
return properties;
|
|
165
|
+
}
|
|
166
|
+
getWithId(id, object = null) {
|
|
167
|
+
object = object ?? this.object;
|
|
168
|
+
let result = null;
|
|
169
|
+
const key = object[0];
|
|
170
|
+
if (key.keyName === id) {
|
|
171
|
+
return object;
|
|
172
|
+
}
|
|
173
|
+
else {
|
|
174
|
+
this.getValue(object).some(item => {
|
|
175
|
+
if (Array.isArray(item)) {
|
|
176
|
+
result = this.getWithId(id, item);
|
|
177
|
+
if (result !== null) {
|
|
178
|
+
return true;
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
return false;
|
|
182
|
+
});
|
|
183
|
+
}
|
|
184
|
+
return result;
|
|
185
|
+
}
|
|
186
|
+
print() {
|
|
187
|
+
console.log(printTree(this.object));
|
|
188
|
+
}
|
|
189
|
+
}
|
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/globals.mjs
CHANGED
|
@@ -10,8 +10,6 @@ export var GlobalNames;
|
|
|
10
10
|
export const NoNetText = 'NO_NET';
|
|
11
11
|
export var ParamKeys;
|
|
12
12
|
(function (ParamKeys) {
|
|
13
|
-
ParamKeys["__is_net"] = "__is_net";
|
|
14
|
-
ParamKeys["__is_label"] = "__is_label";
|
|
15
13
|
ParamKeys["priority"] = "priority";
|
|
16
14
|
ParamKeys["net_name"] = "net_name";
|
|
17
15
|
})(ParamKeys || (ParamKeys = {}));
|
|
@@ -47,6 +45,7 @@ export var ReferenceTypes;
|
|
|
47
45
|
ReferenceTypes["value"] = "value";
|
|
48
46
|
ReferenceTypes["variable"] = "variable";
|
|
49
47
|
ReferenceTypes["instance"] = "instance";
|
|
48
|
+
ReferenceTypes["pinType"] = "pinType";
|
|
50
49
|
})(ReferenceTypes || (ReferenceTypes = {}));
|
|
51
50
|
export var BlockTypes;
|
|
52
51
|
(function (BlockTypes) {
|