schematex 0.4.3 → 0.5.2
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/README.md +36 -7
- package/dist/ai/ai-sdk.cjs +19 -13
- package/dist/ai/ai-sdk.cjs.map +1 -1
- package/dist/ai/ai-sdk.d.cts +4 -3
- package/dist/ai/ai-sdk.d.ts +4 -3
- package/dist/ai/ai-sdk.js +15 -9
- package/dist/ai/ai-sdk.js.map +1 -1
- package/dist/ai/index.cjs +16 -12
- package/dist/ai/index.d.cts +20 -153
- package/dist/ai/index.d.ts +20 -153
- package/dist/ai/index.js +4 -4
- package/dist/api-C5SECOxZ.d.cts +69 -0
- package/dist/api-Cr_MxttI.d.ts +69 -0
- package/dist/browser.cjs +24 -6
- package/dist/browser.cjs.map +1 -1
- package/dist/browser.d.cts +12 -3
- package/dist/browser.d.ts +12 -3
- package/dist/browser.js +14 -6
- package/dist/browser.js.map +1 -1
- package/dist/{chunk-SMXU3KYA.cjs → chunk-4QPDZJAL.cjs} +6337 -120
- package/dist/chunk-4QPDZJAL.cjs.map +1 -0
- package/dist/{chunk-N3SLYVNW.cjs → chunk-HK56GQQP.cjs} +751 -80
- package/dist/chunk-HK56GQQP.cjs.map +1 -0
- package/dist/{chunk-KWQTF6ZL.js → chunk-OK5ZS3LU.js} +6330 -119
- package/dist/chunk-OK5ZS3LU.js.map +1 -0
- package/dist/{chunk-2Z543TC3.cjs → chunk-QMTWG6JL.cjs} +1297 -1151
- package/dist/chunk-QMTWG6JL.cjs.map +1 -0
- package/dist/{chunk-VITE3MZQ.cjs → chunk-QTNPMIO2.cjs} +99 -5
- package/dist/chunk-QTNPMIO2.cjs.map +1 -0
- package/dist/{chunk-6IGSKU6D.js → chunk-UFTYX73U.js} +99 -5
- package/dist/chunk-UFTYX73U.js.map +1 -0
- package/dist/{chunk-J7JWMQD5.js → chunk-VCH7RI5H.js} +1297 -1151
- package/dist/chunk-VCH7RI5H.js.map +1 -0
- package/dist/{chunk-UBTKM2TB.js → chunk-VKPCR7BG.js} +751 -81
- package/dist/chunk-VKPCR7BG.js.map +1 -0
- package/dist/diagrams/blockdiagram/index.d.cts +1 -1
- package/dist/diagrams/blockdiagram/index.d.ts +1 -1
- package/dist/diagrams/circuit/index.cjs +7 -7
- package/dist/diagrams/circuit/index.d.cts +1 -1
- package/dist/diagrams/circuit/index.d.ts +1 -1
- package/dist/diagrams/circuit/index.js +1 -1
- package/dist/diagrams/ecomap/index.d.cts +1 -1
- package/dist/diagrams/ecomap/index.d.ts +1 -1
- package/dist/diagrams/entity/index.d.cts +1 -1
- package/dist/diagrams/entity/index.d.ts +1 -1
- package/dist/diagrams/fishbone/index.d.cts +1 -1
- package/dist/diagrams/fishbone/index.d.ts +1 -1
- package/dist/diagrams/flowchart/index.cjs +7 -7
- package/dist/diagrams/flowchart/index.d.cts +2 -2
- package/dist/diagrams/flowchart/index.d.ts +2 -2
- package/dist/diagrams/flowchart/index.js +1 -1
- package/dist/diagrams/genogram/index.d.cts +1 -1
- package/dist/diagrams/genogram/index.d.ts +1 -1
- package/dist/diagrams/ladder/index.d.cts +1 -1
- package/dist/diagrams/ladder/index.d.ts +1 -1
- package/dist/diagrams/logic/index.d.cts +1 -1
- package/dist/diagrams/logic/index.d.ts +1 -1
- package/dist/diagrams/orgchart/index.d.cts +1 -1
- package/dist/diagrams/orgchart/index.d.ts +1 -1
- package/dist/diagrams/pedigree/index.d.cts +1 -1
- package/dist/diagrams/pedigree/index.d.ts +1 -1
- package/dist/diagrams/phylo/index.d.cts +1 -1
- package/dist/diagrams/phylo/index.d.ts +1 -1
- package/dist/diagrams/sld/index.d.cts +1 -1
- package/dist/diagrams/sld/index.d.ts +1 -1
- package/dist/diagrams/sociogram/index.d.cts +1 -1
- package/dist/diagrams/sociogram/index.d.ts +1 -1
- package/dist/diagrams/timing/index.d.cts +1 -1
- package/dist/diagrams/timing/index.d.ts +1 -1
- package/dist/diagrams/venn/index.d.cts +1 -1
- package/dist/diagrams/venn/index.d.ts +1 -1
- package/dist/{index-DYpJXJcy.d.cts → index-BD2yDfQM.d.cts} +1 -1
- package/dist/{index-BeUVaQiD.d.ts → index-C30zQWZI.d.ts} +1 -1
- package/dist/index.cjs +35 -11
- package/dist/index.d.cts +10 -4
- package/dist/index.d.ts +10 -4
- package/dist/index.js +3 -3
- package/dist/react.cjs +8 -10
- package/dist/react.cjs.map +1 -1
- package/dist/react.d.cts +3 -2
- package/dist/react.d.ts +3 -2
- package/dist/react.js +8 -10
- package/dist/react.js.map +1 -1
- package/dist/tools-BHWaJPOl.d.ts +153 -0
- package/dist/tools-DlpuE76u.d.cts +153 -0
- package/dist/{types-DKdo-Ua_.d.cts → types-WTr9W5Ud.d.cts} +3 -3
- package/dist/{types-DKdo-Ua_.d.ts → types-WTr9W5Ud.d.ts} +3 -3
- package/package.json +2 -2
- package/dist/api-BIj9t4Oc.d.cts +0 -22
- package/dist/api-BIj9t4Oc.d.ts +0 -22
- package/dist/chunk-2Z543TC3.cjs.map +0 -1
- package/dist/chunk-6IGSKU6D.js.map +0 -1
- package/dist/chunk-J7JWMQD5.js.map +0 -1
- package/dist/chunk-KWQTF6ZL.js.map +0 -1
- package/dist/chunk-N3SLYVNW.cjs.map +0 -1
- package/dist/chunk-SMXU3KYA.cjs.map +0 -1
- package/dist/chunk-UBTKM2TB.js.map +0 -1
- package/dist/chunk-VITE3MZQ.cjs.map +0 -1
|
@@ -4,582 +4,6 @@ var chunkD7EHZFK4_cjs = require('./chunk-D7EHZFK4.cjs');
|
|
|
4
4
|
var chunkNAGUZFXX_cjs = require('./chunk-NAGUZFXX.cjs');
|
|
5
5
|
var chunk3WNW5Y7P_cjs = require('./chunk-3WNW5Y7P.cjs');
|
|
6
6
|
|
|
7
|
-
// src/diagrams/circuit/netlist.ts
|
|
8
|
-
var NetlistParseError = class extends Error {
|
|
9
|
-
constructor(message, line) {
|
|
10
|
-
super(message);
|
|
11
|
-
this.line = line;
|
|
12
|
-
this.name = "NetlistParseError";
|
|
13
|
-
}
|
|
14
|
-
line;
|
|
15
|
-
};
|
|
16
|
-
var PREFIX_MAP = {
|
|
17
|
-
R: { type: "resistor", pins: ["start", "end"] },
|
|
18
|
-
C: { type: "capacitor", pins: ["start", "end"] },
|
|
19
|
-
L: { type: "inductor", pins: ["start", "end"] },
|
|
20
|
-
D: { type: "diode", pins: ["start", "end"] },
|
|
21
|
-
// anode → start, cathode → end
|
|
22
|
-
V: { type: "voltage_source", pins: ["plus", "minus"] },
|
|
23
|
-
I: { type: "current_source", pins: ["plus", "minus"] },
|
|
24
|
-
Q: { type: "npn", pins: ["c", "b", "e"] },
|
|
25
|
-
M: { type: "nmos", pins: ["d", "g", "s"] },
|
|
26
|
-
J: { type: "jfet_n", pins: ["d", "g", "s"] },
|
|
27
|
-
S: { type: "switch_spst", pins: ["start", "end"] },
|
|
28
|
-
F: { type: "fuse", pins: ["start", "end"] },
|
|
29
|
-
B: { type: "battery", pins: ["plus", "minus"] },
|
|
30
|
-
K: { type: "relay_coil", pins: ["start", "end"] },
|
|
31
|
-
U: { type: "generic_ic", pins: [] },
|
|
32
|
-
// pins declared via pins="..." attr
|
|
33
|
-
X: { type: "generic_ic", pins: [] },
|
|
34
|
-
W: { type: "wire", pins: ["start", "end"] },
|
|
35
|
-
// explicit wire (non-SPICE convention, common in EE textbooks)
|
|
36
|
-
T: { type: "terminal_block", pins: [] }
|
|
37
|
-
// pins via pins="..."
|
|
38
|
-
};
|
|
39
|
-
var TYPE_ALIASES = {
|
|
40
|
-
vsource: "voltage_source",
|
|
41
|
-
isource: "current_source",
|
|
42
|
-
acsource: "ac_source",
|
|
43
|
-
ecap: "electrolytic_cap",
|
|
44
|
-
pot: "potentiometer",
|
|
45
|
-
gnd: "ground",
|
|
46
|
-
ic: "generic_ic",
|
|
47
|
-
reg: "voltage_regulator",
|
|
48
|
-
timer555: "555_timer",
|
|
49
|
-
transistor: "npn",
|
|
50
|
-
tb: "terminal_block",
|
|
51
|
-
junction_box: "terminal_block",
|
|
52
|
-
jbox: "terminal_block",
|
|
53
|
-
enclosure: "terminal_block"
|
|
54
|
-
};
|
|
55
|
-
var GROUND_REF = /^(0|gnd|ground|earth|pe|agnd|dgnd|gnda|gndd|vss|com)(_\w+|\d+)?$/i;
|
|
56
|
-
function isGroundRef(s) {
|
|
57
|
-
return GROUND_REF.test(s);
|
|
58
|
-
}
|
|
59
|
-
function tokenize(line) {
|
|
60
|
-
const tokens = [];
|
|
61
|
-
let i = 0;
|
|
62
|
-
while (i < line.length) {
|
|
63
|
-
const ch = line[i];
|
|
64
|
-
if (ch === " " || ch === " ") {
|
|
65
|
-
i++;
|
|
66
|
-
continue;
|
|
67
|
-
}
|
|
68
|
-
if (ch === '"') {
|
|
69
|
-
const end = line.indexOf('"', i + 1);
|
|
70
|
-
tokens.push(line.slice(i, end < 0 ? line.length : end + 1));
|
|
71
|
-
i = end < 0 ? line.length : end + 1;
|
|
72
|
-
continue;
|
|
73
|
-
}
|
|
74
|
-
let j = i;
|
|
75
|
-
while (j < line.length && line[j] !== " " && line[j] !== " ") {
|
|
76
|
-
if (line[j] === "=" && line[j + 1] === '"') {
|
|
77
|
-
const end = line.indexOf('"', j + 2);
|
|
78
|
-
j = end < 0 ? line.length : end + 1;
|
|
79
|
-
break;
|
|
80
|
-
}
|
|
81
|
-
j++;
|
|
82
|
-
}
|
|
83
|
-
tokens.push(line.slice(i, j));
|
|
84
|
-
i = j;
|
|
85
|
-
}
|
|
86
|
-
return tokens;
|
|
87
|
-
}
|
|
88
|
-
function isKeyEqVal(tok) {
|
|
89
|
-
const eq = tok.indexOf("=");
|
|
90
|
-
return eq > 0 && /^[a-zA-Z_][\w]*$/.test(tok.slice(0, eq));
|
|
91
|
-
}
|
|
92
|
-
function parseKV(tok) {
|
|
93
|
-
const eq = tok.indexOf("=");
|
|
94
|
-
const key = tok.slice(0, eq).trim();
|
|
95
|
-
let val = tok.slice(eq + 1).trim();
|
|
96
|
-
if (val.startsWith('"') && val.endsWith('"')) val = val.slice(1, -1);
|
|
97
|
-
return [key, val];
|
|
98
|
-
}
|
|
99
|
-
function parseNetlist(body, title2) {
|
|
100
|
-
const components = [];
|
|
101
|
-
const netByName = /* @__PURE__ */ new Map();
|
|
102
|
-
const pinMap = {};
|
|
103
|
-
let autoGnd = 0;
|
|
104
|
-
const ensureNet = (name) => {
|
|
105
|
-
let n = netByName.get(name);
|
|
106
|
-
if (!n) {
|
|
107
|
-
n = { id: name, anchors: [] };
|
|
108
|
-
netByName.set(name, n);
|
|
109
|
-
}
|
|
110
|
-
return n;
|
|
111
|
-
};
|
|
112
|
-
const lines = body.split("\n").map((l) => l.replace(/\r$/, ""));
|
|
113
|
-
for (let lineIdx = 0; lineIdx < lines.length; lineIdx++) {
|
|
114
|
-
const raw = lines[lineIdx];
|
|
115
|
-
const stripped = raw.replace(/#.*$/, "").trim();
|
|
116
|
-
if (!stripped) continue;
|
|
117
|
-
const tokens = tokenize(stripped);
|
|
118
|
-
if (tokens.length < 2) {
|
|
119
|
-
throw new NetlistParseError(
|
|
120
|
-
`Netlist line must have at least ID + one net: "${stripped}"`,
|
|
121
|
-
lineIdx + 1
|
|
122
|
-
);
|
|
123
|
-
}
|
|
124
|
-
const id = tokens[0];
|
|
125
|
-
if (!/^[a-zA-Z_][\w]*$/.test(id)) {
|
|
126
|
-
throw new NetlistParseError(`Invalid component id: "${id}"`, lineIdx + 1);
|
|
127
|
-
}
|
|
128
|
-
let cursor = 1;
|
|
129
|
-
const netRefs = [];
|
|
130
|
-
while (cursor < tokens.length && !isKeyEqVal(tokens[cursor])) {
|
|
131
|
-
netRefs.push(tokens[cursor]);
|
|
132
|
-
cursor++;
|
|
133
|
-
}
|
|
134
|
-
const kv = {};
|
|
135
|
-
for (; cursor < tokens.length; cursor++) {
|
|
136
|
-
if (!isKeyEqVal(tokens[cursor])) {
|
|
137
|
-
throw new NetlistParseError(
|
|
138
|
-
`Expected key=value after nets, got "${tokens[cursor]}"`,
|
|
139
|
-
lineIdx + 1
|
|
140
|
-
);
|
|
141
|
-
}
|
|
142
|
-
const [k, v] = parseKV(tokens[cursor]);
|
|
143
|
-
kv[k] = v;
|
|
144
|
-
}
|
|
145
|
-
const prefix = id[0].toUpperCase();
|
|
146
|
-
const defaults = PREFIX_MAP[prefix];
|
|
147
|
-
let cType;
|
|
148
|
-
let pinOrder;
|
|
149
|
-
if (kv.type) {
|
|
150
|
-
const t = kv.type.toLowerCase();
|
|
151
|
-
cType = TYPE_ALIASES[t] ?? t;
|
|
152
|
-
pinOrder = defaults?.pins ?? ["p1", "p2"];
|
|
153
|
-
} else if (defaults) {
|
|
154
|
-
cType = defaults.type;
|
|
155
|
-
pinOrder = defaults.pins;
|
|
156
|
-
} else if (isGroundRef(id)) {
|
|
157
|
-
cType = "ground";
|
|
158
|
-
pinOrder = ["start"];
|
|
159
|
-
} else {
|
|
160
|
-
throw new NetlistParseError(
|
|
161
|
-
`Cannot infer type from id "${id}". Either rename to a SPICE-prefix id (R*, C*, L*, D*, V*, I*, Q*, M*, J*, S*, F*, B*, K*, U*, X*, W*, T*) or pass an explicit \`type=<name>\` attribute (e.g. \`${id} ... type=resistor\`). Schematex circuit covers electrical schematics only \u2014 hydraulic/pneumatic prefixes (EV*, BOMBA*, TANK*, etc.) are not supported.`,
|
|
162
|
-
lineIdx + 1
|
|
163
|
-
);
|
|
164
|
-
}
|
|
165
|
-
const expectedPins = pinOrder.length;
|
|
166
|
-
let valueFromTail;
|
|
167
|
-
if (netRefs.length > expectedPins && expectedPins > 0) {
|
|
168
|
-
const tail = netRefs.slice(expectedPins);
|
|
169
|
-
netRefs.length = expectedPins;
|
|
170
|
-
const first = tail[0].toLowerCase();
|
|
171
|
-
if (TYPE_ALIASES[first]) {
|
|
172
|
-
cType = TYPE_ALIASES[first];
|
|
173
|
-
} else if (first === "npn" || first === "pnp" || first === "nmos" || first === "pmos" || first === "jfet_n" || first === "jfet_p" || first === "zener" || first === "schottky" || first === "led" || first === "photodiode") {
|
|
174
|
-
cType = first;
|
|
175
|
-
if (first === "pnp") pinOrder = ["c", "b", "e"];
|
|
176
|
-
if (first === "pmos" || first === "jfet_p") pinOrder = ["d", "g", "s"];
|
|
177
|
-
} else {
|
|
178
|
-
valueFromTail = tail.join(" ");
|
|
179
|
-
}
|
|
180
|
-
if (tail.length > 1 && !valueFromTail) {
|
|
181
|
-
valueFromTail = tail.slice(1).join(" ");
|
|
182
|
-
}
|
|
183
|
-
}
|
|
184
|
-
if (cType === "ground" || cType === "gnd_signal" || cType === "gnd_chassis" || cType === "gnd_digital") {
|
|
185
|
-
pinOrder = ["start"];
|
|
186
|
-
}
|
|
187
|
-
if (cType === "terminal_block") {
|
|
188
|
-
const pinsAttr = kv.pins ?? kv.terminals;
|
|
189
|
-
const labels = pinsAttr ? pinsAttr.split(",").map((s) => s.trim()).filter(Boolean) : Array.from({ length: Math.max(netRefs.length, 1) }, (_, i) => `t${i + 1}`);
|
|
190
|
-
pinOrder = labels.map(
|
|
191
|
-
(label, idx) => label.toLowerCase().replace(/[^a-z0-9]+/g, "_") || `t${idx + 1}`
|
|
192
|
-
);
|
|
193
|
-
}
|
|
194
|
-
if (netRefs.length < pinOrder.length) {
|
|
195
|
-
throw new NetlistParseError(
|
|
196
|
-
`Component ${id} (${cType}) expects ${pinOrder.length} nets, got ${netRefs.length}`,
|
|
197
|
-
lineIdx + 1
|
|
198
|
-
);
|
|
199
|
-
}
|
|
200
|
-
const pins = {};
|
|
201
|
-
for (let p = 0; p < pinOrder.length; p++) {
|
|
202
|
-
let net = netRefs[p];
|
|
203
|
-
if (isGroundRef(net)) net = "GND";
|
|
204
|
-
pins[pinOrder[p]] = net;
|
|
205
|
-
ensureNet(net).anchors.push(`${id}.${pinOrder[p]}`);
|
|
206
|
-
}
|
|
207
|
-
pinMap[id] = pins;
|
|
208
|
-
const comp = {
|
|
209
|
-
id,
|
|
210
|
-
componentType: cType,
|
|
211
|
-
direction: "right",
|
|
212
|
-
label: kv.label ?? id,
|
|
213
|
-
value: kv.value ?? valueFromTail,
|
|
214
|
-
attrs: {}
|
|
215
|
-
};
|
|
216
|
-
for (const [k, v] of Object.entries(kv)) {
|
|
217
|
-
if (k === "label" || k === "value" || k === "type") continue;
|
|
218
|
-
comp.attrs[k] = v;
|
|
219
|
-
}
|
|
220
|
-
components.push(comp);
|
|
221
|
-
}
|
|
222
|
-
if (netByName.has("GND")) {
|
|
223
|
-
const hasGroundSym = components.some(
|
|
224
|
-
(c) => c.componentType === "ground" || c.componentType === "gnd_signal" || c.componentType === "gnd_chassis" || c.componentType === "gnd_digital"
|
|
225
|
-
);
|
|
226
|
-
if (!hasGroundSym) {
|
|
227
|
-
const gId = `_GND${autoGnd++}`;
|
|
228
|
-
components.push({
|
|
229
|
-
id: gId,
|
|
230
|
-
componentType: "ground",
|
|
231
|
-
direction: "down",
|
|
232
|
-
label: void 0,
|
|
233
|
-
value: void 0,
|
|
234
|
-
attrs: { auto: "true" }
|
|
235
|
-
});
|
|
236
|
-
pinMap[gId] = { start: "GND" };
|
|
237
|
-
ensureNet("GND").anchors.push(`${gId}.start`);
|
|
238
|
-
}
|
|
239
|
-
}
|
|
240
|
-
const nets = Array.from(netByName.values());
|
|
241
|
-
return {
|
|
242
|
-
type: "circuit",
|
|
243
|
-
title: title2,
|
|
244
|
-
components,
|
|
245
|
-
nets,
|
|
246
|
-
pinMap,
|
|
247
|
-
mode: "netlist"
|
|
248
|
-
};
|
|
249
|
-
}
|
|
250
|
-
|
|
251
|
-
// src/diagrams/circuit/parser.ts
|
|
252
|
-
var CircuitParseError = class extends Error {
|
|
253
|
-
constructor(message) {
|
|
254
|
-
super(message);
|
|
255
|
-
this.name = "CircuitParseError";
|
|
256
|
-
}
|
|
257
|
-
};
|
|
258
|
-
var COMPONENT_TYPES = /* @__PURE__ */ new Set([
|
|
259
|
-
"resistor",
|
|
260
|
-
"potentiometer",
|
|
261
|
-
"rheostat",
|
|
262
|
-
"thermistor_ntc",
|
|
263
|
-
"thermistor_ptc",
|
|
264
|
-
"ldr",
|
|
265
|
-
"varistor",
|
|
266
|
-
"fuse",
|
|
267
|
-
"fuse_slow",
|
|
268
|
-
"capacitor",
|
|
269
|
-
"electrolytic_cap",
|
|
270
|
-
"variable_cap",
|
|
271
|
-
"inductor",
|
|
272
|
-
"inductor_iron",
|
|
273
|
-
"inductor_ferrite",
|
|
274
|
-
"variable_inductor",
|
|
275
|
-
"ferrite_bead",
|
|
276
|
-
"crystal",
|
|
277
|
-
"transformer",
|
|
278
|
-
"diode",
|
|
279
|
-
"zener",
|
|
280
|
-
"schottky",
|
|
281
|
-
"led",
|
|
282
|
-
"photodiode",
|
|
283
|
-
"varactor",
|
|
284
|
-
"tvs_diode",
|
|
285
|
-
"bridge_rectifier",
|
|
286
|
-
"npn",
|
|
287
|
-
"pnp",
|
|
288
|
-
"darlington_npn",
|
|
289
|
-
"darlington_pnp",
|
|
290
|
-
"nmos",
|
|
291
|
-
"pmos",
|
|
292
|
-
"nmos_depletion",
|
|
293
|
-
"jfet_n",
|
|
294
|
-
"jfet_p",
|
|
295
|
-
"igbt",
|
|
296
|
-
"scr",
|
|
297
|
-
"triac",
|
|
298
|
-
"diac",
|
|
299
|
-
"phototransistor",
|
|
300
|
-
"optocoupler",
|
|
301
|
-
"opamp",
|
|
302
|
-
"comparator",
|
|
303
|
-
"schmitt_buffer",
|
|
304
|
-
"tri_state_buffer",
|
|
305
|
-
"instrumentation_amp",
|
|
306
|
-
"generic_ic",
|
|
307
|
-
"voltage_regulator",
|
|
308
|
-
"dc_dc_converter",
|
|
309
|
-
"555_timer",
|
|
310
|
-
"voltage_source",
|
|
311
|
-
"current_source",
|
|
312
|
-
"ac_source",
|
|
313
|
-
"battery",
|
|
314
|
-
"vcc",
|
|
315
|
-
"ground",
|
|
316
|
-
"gnd_signal",
|
|
317
|
-
"gnd_chassis",
|
|
318
|
-
"gnd_digital",
|
|
319
|
-
"switch_spst",
|
|
320
|
-
"switch_spdt",
|
|
321
|
-
"switch_dpdt",
|
|
322
|
-
"push_no",
|
|
323
|
-
"push_nc",
|
|
324
|
-
"relay_coil",
|
|
325
|
-
"relay_no",
|
|
326
|
-
"relay_nc",
|
|
327
|
-
"motor",
|
|
328
|
-
"speaker",
|
|
329
|
-
"microphone",
|
|
330
|
-
"buzzer",
|
|
331
|
-
"ammeter",
|
|
332
|
-
"voltmeter",
|
|
333
|
-
"wattmeter",
|
|
334
|
-
"oscilloscope",
|
|
335
|
-
"wire",
|
|
336
|
-
"dot",
|
|
337
|
-
"label",
|
|
338
|
-
"port",
|
|
339
|
-
"test_point",
|
|
340
|
-
"no_connect",
|
|
341
|
-
"antenna"
|
|
342
|
-
]);
|
|
343
|
-
var ALIASES = {
|
|
344
|
-
vsource: "voltage_source",
|
|
345
|
-
isource: "current_source",
|
|
346
|
-
acsource: "ac_source",
|
|
347
|
-
ecap: "electrolytic_cap",
|
|
348
|
-
pot: "potentiometer",
|
|
349
|
-
xtal: "crystal",
|
|
350
|
-
xfmr: "transformer",
|
|
351
|
-
transistor: "npn",
|
|
352
|
-
bjt_npn: "npn",
|
|
353
|
-
bjt_pnp: "pnp",
|
|
354
|
-
mosfet_n: "nmos",
|
|
355
|
-
mosfet_p: "pmos",
|
|
356
|
-
gnd: "ground",
|
|
357
|
-
ic: "generic_ic",
|
|
358
|
-
reg: "voltage_regulator",
|
|
359
|
-
timer555: "555_timer",
|
|
360
|
-
therm: "thermistor_ntc",
|
|
361
|
-
ntc: "thermistor_ntc",
|
|
362
|
-
ptc: "thermistor_ptc",
|
|
363
|
-
ths: "thermistor_ntc"
|
|
364
|
-
};
|
|
365
|
-
var EXTRA_TYPES = /* @__PURE__ */ new Set(["lamp"]);
|
|
366
|
-
function normalizeType(raw) {
|
|
367
|
-
const lower = raw.toLowerCase();
|
|
368
|
-
if (ALIASES[lower]) return ALIASES[lower];
|
|
369
|
-
if (COMPONENT_TYPES.has(lower)) {
|
|
370
|
-
return lower;
|
|
371
|
-
}
|
|
372
|
-
if (EXTRA_TYPES.has(lower)) {
|
|
373
|
-
return lower;
|
|
374
|
-
}
|
|
375
|
-
return null;
|
|
376
|
-
}
|
|
377
|
-
var DIRECTIONS = /* @__PURE__ */ new Set(["right", "left", "up", "down"]);
|
|
378
|
-
function parseAttrs(rest) {
|
|
379
|
-
const out = { attrs: {} };
|
|
380
|
-
const tokens = [];
|
|
381
|
-
let i = 0;
|
|
382
|
-
while (i < rest.length) {
|
|
383
|
-
const ch = rest[i];
|
|
384
|
-
if (ch === " " || ch === " ") {
|
|
385
|
-
i++;
|
|
386
|
-
continue;
|
|
387
|
-
}
|
|
388
|
-
if (ch === '"') {
|
|
389
|
-
const end = rest.indexOf('"', i + 1);
|
|
390
|
-
const tok = rest.slice(i, end < 0 ? rest.length : end + 1);
|
|
391
|
-
tokens.push(tok);
|
|
392
|
-
i = end < 0 ? rest.length : end + 1;
|
|
393
|
-
continue;
|
|
394
|
-
}
|
|
395
|
-
let j = i;
|
|
396
|
-
while (j < rest.length && rest[j] !== " " && rest[j] !== " ") {
|
|
397
|
-
if (rest[j] === "=" && rest[j + 1] === '"') {
|
|
398
|
-
const end = rest.indexOf('"', j + 2);
|
|
399
|
-
j = end < 0 ? rest.length : end + 1;
|
|
400
|
-
break;
|
|
401
|
-
}
|
|
402
|
-
j++;
|
|
403
|
-
}
|
|
404
|
-
tokens.push(rest.slice(i, j));
|
|
405
|
-
i = j;
|
|
406
|
-
}
|
|
407
|
-
for (const tok of tokens) {
|
|
408
|
-
if (!tok) continue;
|
|
409
|
-
if (DIRECTIONS.has(tok.toLowerCase())) {
|
|
410
|
-
out.direction = tok.toLowerCase();
|
|
411
|
-
continue;
|
|
412
|
-
}
|
|
413
|
-
const eq = tok.indexOf("=");
|
|
414
|
-
if (eq > 0) {
|
|
415
|
-
const key = tok.slice(0, eq).trim();
|
|
416
|
-
let val = tok.slice(eq + 1).trim();
|
|
417
|
-
if (val.startsWith('"') && val.endsWith('"')) {
|
|
418
|
-
val = val.slice(1, -1);
|
|
419
|
-
}
|
|
420
|
-
if (key === "label") out.label = val;
|
|
421
|
-
else if (key === "value") out.value = val;
|
|
422
|
-
else if (key === "at") out.at = val;
|
|
423
|
-
else if (key === "length") out.length = val;
|
|
424
|
-
else out.attrs[key] = val;
|
|
425
|
-
continue;
|
|
426
|
-
}
|
|
427
|
-
out.attrs[tok] = "true";
|
|
428
|
-
}
|
|
429
|
-
return out;
|
|
430
|
-
}
|
|
431
|
-
function parseCircuit(text2) {
|
|
432
|
-
const rawLines = text2.split("\n");
|
|
433
|
-
const firstMeaningful = rawLines.map((l) => l.replace(/#.*$/, "").trim()).find((l) => l.length > 0) ?? "";
|
|
434
|
-
if (/^circuit\b.*\bnetlist\s*$/i.test(firstMeaningful)) {
|
|
435
|
-
const netlistTitle = chunkNAGUZFXX_cjs.matchQuotedTitle(firstMeaningful);
|
|
436
|
-
let headerIdx = -1;
|
|
437
|
-
for (let i = 0; i < rawLines.length; i++) {
|
|
438
|
-
const s = rawLines[i].replace(/#.*$/, "").trim();
|
|
439
|
-
if (s.length > 0) {
|
|
440
|
-
headerIdx = i;
|
|
441
|
-
break;
|
|
442
|
-
}
|
|
443
|
-
}
|
|
444
|
-
const body = rawLines.slice(headerIdx + 1).join("\n");
|
|
445
|
-
return parseNetlist(body, netlistTitle);
|
|
446
|
-
}
|
|
447
|
-
const lines = text2.split("\n").map((l) => l.replace(/\r$/, ""));
|
|
448
|
-
let title2;
|
|
449
|
-
const components = [];
|
|
450
|
-
const nets = [];
|
|
451
|
-
const netByName = /* @__PURE__ */ new Map();
|
|
452
|
-
let autoId = 0;
|
|
453
|
-
let pendingAt;
|
|
454
|
-
const mkId = (prefix) => `${prefix}_${autoId++}`;
|
|
455
|
-
for (const rawLine of lines) {
|
|
456
|
-
const stripped = rawLine.replace(/#.*$/, "").trim();
|
|
457
|
-
if (!stripped) continue;
|
|
458
|
-
if (/^circuit\b/i.test(stripped)) {
|
|
459
|
-
const t = chunkNAGUZFXX_cjs.matchQuotedTitle(stripped);
|
|
460
|
-
if (t !== void 0) title2 = t;
|
|
461
|
-
continue;
|
|
462
|
-
}
|
|
463
|
-
const atMatch = stripped.match(/^at:\s*(.+)$/i);
|
|
464
|
-
if (atMatch) {
|
|
465
|
-
pendingAt = atMatch[1].trim();
|
|
466
|
-
continue;
|
|
467
|
-
}
|
|
468
|
-
const netDecl = stripped.match(/^net\s+([a-zA-Z_][\w]*)\s*$/i);
|
|
469
|
-
if (netDecl) {
|
|
470
|
-
const name = netDecl[1];
|
|
471
|
-
if (!netByName.has(name)) {
|
|
472
|
-
const n = { id: name, anchors: [] };
|
|
473
|
-
netByName.set(name, n);
|
|
474
|
-
nets.push(n);
|
|
475
|
-
}
|
|
476
|
-
continue;
|
|
477
|
-
}
|
|
478
|
-
const netDotMatch = stripped.match(/^net\s+([a-zA-Z_][\w]*)\s*:\s*dot\s*$/i);
|
|
479
|
-
if (netDotMatch) {
|
|
480
|
-
const name = netDotMatch[1];
|
|
481
|
-
let n = netByName.get(name);
|
|
482
|
-
if (!n) {
|
|
483
|
-
n = { id: name, anchors: [] };
|
|
484
|
-
netByName.set(name, n);
|
|
485
|
-
nets.push(n);
|
|
486
|
-
}
|
|
487
|
-
const id = mkId("dot");
|
|
488
|
-
components.push({
|
|
489
|
-
id,
|
|
490
|
-
componentType: "dot",
|
|
491
|
-
direction: "right",
|
|
492
|
-
at: pendingAt,
|
|
493
|
-
attrs: { net: name }
|
|
494
|
-
});
|
|
495
|
-
n.anchors.push(`${id}.end`);
|
|
496
|
-
pendingAt = `${id}.end`;
|
|
497
|
-
continue;
|
|
498
|
-
}
|
|
499
|
-
const labelMatch = stripped.match(/^label\s+"([^"]*)"(?:\s+(right|left|up|down))?\s*$/i);
|
|
500
|
-
if (labelMatch) {
|
|
501
|
-
const id = mkId("lbl");
|
|
502
|
-
components.push({
|
|
503
|
-
id,
|
|
504
|
-
componentType: "label",
|
|
505
|
-
direction: labelMatch[2]?.toLowerCase() ?? "right",
|
|
506
|
-
at: pendingAt,
|
|
507
|
-
label: labelMatch[1]
|
|
508
|
-
});
|
|
509
|
-
continue;
|
|
510
|
-
}
|
|
511
|
-
const wireMatch = stripped.match(/^wire(?:\s+(right|left|up|down))?(?:\s+(\d+)(?:px)?)?\s*$/i);
|
|
512
|
-
if (wireMatch) {
|
|
513
|
-
const id = mkId("w");
|
|
514
|
-
components.push({
|
|
515
|
-
id,
|
|
516
|
-
componentType: "wire",
|
|
517
|
-
direction: wireMatch[1]?.toLowerCase() ?? "right",
|
|
518
|
-
at: pendingAt,
|
|
519
|
-
attrs: wireMatch[2] ? { length: wireMatch[2] } : {}
|
|
520
|
-
});
|
|
521
|
-
pendingAt = `${id}.end`;
|
|
522
|
-
continue;
|
|
523
|
-
}
|
|
524
|
-
const bareMatch = stripped.match(/^([a-zA-Z_][\w]*)(\s+.*)?$/);
|
|
525
|
-
const colonMatch = stripped.match(/^([a-zA-Z_][\w]*)\s*:\s*([a-zA-Z_][\w]*)(\s+.*)?$/);
|
|
526
|
-
if (colonMatch) {
|
|
527
|
-
const id = colonMatch[1];
|
|
528
|
-
const typeStr = colonMatch[2];
|
|
529
|
-
const norm = normalizeType(typeStr);
|
|
530
|
-
if (!norm) {
|
|
531
|
-
throw new CircuitParseError(`Unknown component type: ${typeStr}`);
|
|
532
|
-
}
|
|
533
|
-
const rest = colonMatch[3] ?? "";
|
|
534
|
-
const parsed = parseAttrs(rest);
|
|
535
|
-
const comp = {
|
|
536
|
-
id,
|
|
537
|
-
componentType: norm,
|
|
538
|
-
direction: parsed.direction ?? "right",
|
|
539
|
-
at: parsed.at ?? pendingAt,
|
|
540
|
-
label: parsed.label,
|
|
541
|
-
value: parsed.value,
|
|
542
|
-
attrs: parsed.attrs
|
|
543
|
-
};
|
|
544
|
-
if (parsed.length) {
|
|
545
|
-
comp.attrs = { ...comp.attrs, length: parsed.length };
|
|
546
|
-
}
|
|
547
|
-
components.push(comp);
|
|
548
|
-
pendingAt = `${id}.end`;
|
|
549
|
-
continue;
|
|
550
|
-
}
|
|
551
|
-
if (bareMatch) {
|
|
552
|
-
const typeStr = bareMatch[1];
|
|
553
|
-
const norm = normalizeType(typeStr);
|
|
554
|
-
if (!norm) {
|
|
555
|
-
continue;
|
|
556
|
-
}
|
|
557
|
-
const rest = bareMatch[2] ?? "";
|
|
558
|
-
const parsed = parseAttrs(rest);
|
|
559
|
-
const id = mkId(norm);
|
|
560
|
-
const comp = {
|
|
561
|
-
id,
|
|
562
|
-
componentType: norm,
|
|
563
|
-
direction: parsed.direction ?? "right",
|
|
564
|
-
at: parsed.at ?? pendingAt,
|
|
565
|
-
label: parsed.label,
|
|
566
|
-
value: parsed.value,
|
|
567
|
-
attrs: parsed.attrs
|
|
568
|
-
};
|
|
569
|
-
components.push(comp);
|
|
570
|
-
pendingAt = `${id}.end`;
|
|
571
|
-
continue;
|
|
572
|
-
}
|
|
573
|
-
}
|
|
574
|
-
return {
|
|
575
|
-
type: "circuit",
|
|
576
|
-
title: title2,
|
|
577
|
-
components,
|
|
578
|
-
nets,
|
|
579
|
-
mode: "positional"
|
|
580
|
-
};
|
|
581
|
-
}
|
|
582
|
-
|
|
583
7
|
// src/diagrams/circuit/symbols.ts
|
|
584
8
|
var BODY = 'class="schematex-circuit-body"';
|
|
585
9
|
var FILL = 'class="schematex-circuit-fill"';
|
|
@@ -642,6 +66,7 @@ var crystal = {
|
|
|
642
66
|
};
|
|
643
67
|
var transformer = {
|
|
644
68
|
length: 60,
|
|
69
|
+
netlistPins: ["p1", "p2", "s1", "s2"],
|
|
645
70
|
anchors: {
|
|
646
71
|
start: { x: 0, y: 0 },
|
|
647
72
|
end: { x: 60, y: 0 },
|
|
@@ -662,717 +87,1438 @@ var transformer = {
|
|
|
662
87
|
lineWire(55, 0, 60, 0)
|
|
663
88
|
].join("")
|
|
664
89
|
};
|
|
665
|
-
var voltage_source = {
|
|
90
|
+
var voltage_source = {
|
|
91
|
+
length: 40,
|
|
92
|
+
netlistPins: ["plus", "minus"],
|
|
93
|
+
// plus/minus aliases: end = +, start = − (matches on-symbol label)
|
|
94
|
+
anchors: {
|
|
95
|
+
start: { x: 0, y: 0 },
|
|
96
|
+
end: { x: 40, y: 0 },
|
|
97
|
+
minus: { x: 0, y: 0 },
|
|
98
|
+
plus: { x: 40, y: 0 }
|
|
99
|
+
},
|
|
100
|
+
svg: () => [
|
|
101
|
+
lineWire(0, 0, 8, 0),
|
|
102
|
+
`<circle cx="20" cy="0" r="12" fill="white" ${BODY}/>`,
|
|
103
|
+
`<text x="16" y="-2" class="schematex-circuit-pol">+</text>`,
|
|
104
|
+
`<text x="23" y="8" class="schematex-circuit-pol">\u2212</text>`,
|
|
105
|
+
lineWire(32, 0, 40, 0)
|
|
106
|
+
].join("")
|
|
107
|
+
};
|
|
108
|
+
var current_source = {
|
|
109
|
+
length: 40,
|
|
110
|
+
netlistPins: ["plus", "minus"],
|
|
111
|
+
anchors: {
|
|
112
|
+
start: { x: 0, y: 0 },
|
|
113
|
+
end: { x: 40, y: 0 },
|
|
114
|
+
minus: { x: 0, y: 0 },
|
|
115
|
+
plus: { x: 40, y: 0 }
|
|
116
|
+
},
|
|
117
|
+
svg: () => [
|
|
118
|
+
lineWire(0, 0, 8, 0),
|
|
119
|
+
`<circle cx="20" cy="0" r="12" fill="white" ${BODY}/>`,
|
|
120
|
+
`<line x1="14" y1="0" x2="24" y2="0" ${BODY}/>`,
|
|
121
|
+
`<polygon points="26,0 20,-4 20,4" ${FILL}/>`,
|
|
122
|
+
lineWire(32, 0, 40, 0)
|
|
123
|
+
].join("")
|
|
124
|
+
};
|
|
125
|
+
var ac_source = {
|
|
126
|
+
length: 40,
|
|
127
|
+
netlistPins: ["plus", "minus"],
|
|
128
|
+
anchors: {
|
|
129
|
+
start: { x: 0, y: 0 },
|
|
130
|
+
end: { x: 40, y: 0 },
|
|
131
|
+
minus: { x: 0, y: 0 },
|
|
132
|
+
plus: { x: 40, y: 0 }
|
|
133
|
+
},
|
|
134
|
+
svg: () => [
|
|
135
|
+
lineWire(0, 0, 8, 0),
|
|
136
|
+
`<circle cx="20" cy="0" r="12" fill="white" ${BODY}/>`,
|
|
137
|
+
`<path d="M 14,0 Q 17,-6 20,0 Q 23,6 26,0" fill="none" ${BODY}/>`,
|
|
138
|
+
lineWire(32, 0, 40, 0)
|
|
139
|
+
].join("")
|
|
140
|
+
};
|
|
141
|
+
var battery = {
|
|
142
|
+
length: 24,
|
|
143
|
+
netlistPins: ["plus", "minus"],
|
|
144
|
+
anchors: {
|
|
145
|
+
start: { x: 0, y: 0 },
|
|
146
|
+
end: { x: 24, y: 0 },
|
|
147
|
+
minus: { x: 0, y: 0 },
|
|
148
|
+
plus: { x: 24, y: 0 }
|
|
149
|
+
},
|
|
150
|
+
svg: () => [
|
|
151
|
+
lineWire(0, 0, 8, 0),
|
|
152
|
+
`<line x1="8" y1="-8" x2="8" y2="8" ${BODY}/>`,
|
|
153
|
+
`<line x1="12" y1="-4" x2="12" y2="4" ${BODY}/>`,
|
|
154
|
+
`<line x1="14" y1="-8" x2="14" y2="8" ${BODY}/>`,
|
|
155
|
+
`<line x1="18" y1="-4" x2="18" y2="4" ${BODY}/>`,
|
|
156
|
+
lineWire(18, 0, 24, 0)
|
|
157
|
+
].join("")
|
|
158
|
+
};
|
|
159
|
+
var ground = {
|
|
160
|
+
length: 20,
|
|
161
|
+
anchors: { start: { x: 0, y: 0 }, end: { x: 20, y: 0 } },
|
|
162
|
+
// Drawn as a "terminal" — vertical connection at start, earth lines below
|
|
163
|
+
svg: () => [
|
|
164
|
+
`<line x1="0" y1="0" x2="10" y2="0" ${WIRE}/>`,
|
|
165
|
+
`<line x1="10" y1="-8" x2="10" y2="8" ${BODY}/>`,
|
|
166
|
+
`<line x1="6" y1="4" x2="14" y2="4" ${BODY}/>`,
|
|
167
|
+
`<line x1="8" y1="8" x2="12" y2="8" ${BODY}/>`
|
|
168
|
+
].join("")
|
|
169
|
+
};
|
|
170
|
+
var gnd_signal = {
|
|
171
|
+
length: 20,
|
|
172
|
+
anchors: { start: { x: 0, y: 0 }, end: { x: 20, y: 0 } },
|
|
173
|
+
svg: () => [
|
|
174
|
+
`<line x1="0" y1="0" x2="8" y2="0" ${WIRE}/>`,
|
|
175
|
+
`<polygon points="8,-6 8,6 16,0" ${FILL}/>`
|
|
176
|
+
].join("")
|
|
177
|
+
};
|
|
178
|
+
var vcc = {
|
|
179
|
+
length: 20,
|
|
180
|
+
anchors: { start: { x: 0, y: 0 }, end: { x: 20, y: 0 } },
|
|
181
|
+
svg: () => [
|
|
182
|
+
`<line x1="0" y1="0" x2="10" y2="0" ${WIRE}/>`,
|
|
183
|
+
`<line x1="4" y1="-6" x2="16" y2="-6" ${BODY}/>`
|
|
184
|
+
].join("")
|
|
185
|
+
};
|
|
186
|
+
var diode = {
|
|
187
|
+
length: 30,
|
|
188
|
+
anchors: { start: { x: 0, y: 0 }, end: { x: 30, y: 0 } },
|
|
189
|
+
svg: () => [
|
|
190
|
+
lineWire(0, 0, 8, 0),
|
|
191
|
+
`<polygon points="8,-8 8,8 22,0" ${FILL}/>`,
|
|
192
|
+
`<line x1="22" y1="-8" x2="22" y2="8" ${BODY}/>`,
|
|
193
|
+
lineWire(22, 0, 30, 0)
|
|
194
|
+
].join("")
|
|
195
|
+
};
|
|
196
|
+
var zener = {
|
|
197
|
+
length: 30,
|
|
198
|
+
anchors: { start: { x: 0, y: 0 }, end: { x: 30, y: 0 } },
|
|
199
|
+
svg: () => [
|
|
200
|
+
lineWire(0, 0, 8, 0),
|
|
201
|
+
`<polygon points="8,-8 8,8 22,0" ${FILL}/>`,
|
|
202
|
+
`<path d="M 18,-10 L 22,-8 L 22,8 L 26,10" fill="none" ${BODY}/>`,
|
|
203
|
+
lineWire(22, 0, 30, 0)
|
|
204
|
+
].join("")
|
|
205
|
+
};
|
|
206
|
+
var schottky = {
|
|
207
|
+
length: 30,
|
|
208
|
+
anchors: { start: { x: 0, y: 0 }, end: { x: 30, y: 0 } },
|
|
209
|
+
svg: () => [
|
|
210
|
+
lineWire(0, 0, 8, 0),
|
|
211
|
+
`<polygon points="8,-8 8,8 22,0" ${FILL}/>`,
|
|
212
|
+
`<path d="M 18,-4 L 18,-8 L 22,-8 L 22,8 L 26,8 L 26,4" fill="none" ${BODY}/>`,
|
|
213
|
+
lineWire(22, 0, 30, 0)
|
|
214
|
+
].join("")
|
|
215
|
+
};
|
|
216
|
+
var led = {
|
|
217
|
+
length: 30,
|
|
218
|
+
anchors: { start: { x: 0, y: 0 }, end: { x: 30, y: 0 } },
|
|
219
|
+
svg: () => [
|
|
220
|
+
lineWire(0, 0, 8, 0),
|
|
221
|
+
`<polygon points="8,-8 8,8 22,0" ${FILL}/>`,
|
|
222
|
+
`<line x1="22" y1="-8" x2="22" y2="8" ${BODY}/>`,
|
|
223
|
+
lineWire(22, 0, 30, 0),
|
|
224
|
+
// outward light arrows
|
|
225
|
+
`<path d="M 12,-10 L 20,-18 M 18,-18 L 20,-18 L 20,-16" fill="none" ${BODY}/>`,
|
|
226
|
+
`<path d="M 16,-10 L 24,-18 M 22,-18 L 24,-18 L 24,-16" fill="none" ${BODY}/>`
|
|
227
|
+
].join("")
|
|
228
|
+
};
|
|
229
|
+
var photodiode = {
|
|
230
|
+
length: 30,
|
|
231
|
+
anchors: { start: { x: 0, y: 0 }, end: { x: 30, y: 0 } },
|
|
232
|
+
svg: () => [
|
|
233
|
+
lineWire(0, 0, 8, 0),
|
|
234
|
+
`<polygon points="8,-8 8,8 22,0" ${FILL}/>`,
|
|
235
|
+
`<line x1="22" y1="-8" x2="22" y2="8" ${BODY}/>`,
|
|
236
|
+
lineWire(22, 0, 30, 0),
|
|
237
|
+
// inward light arrows
|
|
238
|
+
`<path d="M 20,-18 L 12,-10 M 12,-12 L 12,-10 L 14,-10" fill="none" ${BODY}/>`,
|
|
239
|
+
`<path d="M 24,-18 L 16,-10 M 16,-12 L 16,-10 L 18,-10" fill="none" ${BODY}/>`
|
|
240
|
+
].join("")
|
|
241
|
+
};
|
|
242
|
+
var npn = {
|
|
243
|
+
length: 40,
|
|
244
|
+
netlistPins: ["c", "b", "e"],
|
|
245
|
+
// base at left, collector up-right, emitter down-right
|
|
246
|
+
anchors: {
|
|
247
|
+
start: { x: 0, y: 0 },
|
|
248
|
+
end: { x: 40, y: -16 },
|
|
249
|
+
base: { x: 0, y: 0 },
|
|
250
|
+
collector: { x: 40, y: -16 },
|
|
251
|
+
emitter: { x: 40, y: 16 },
|
|
252
|
+
b: { x: 0, y: 0 },
|
|
253
|
+
c: { x: 40, y: -16 },
|
|
254
|
+
e: { x: 40, y: 16 }
|
|
255
|
+
},
|
|
256
|
+
svg: () => [
|
|
257
|
+
`<circle cx="20" cy="0" r="16" fill="white" ${BODY}/>`,
|
|
258
|
+
`<line x1="14" y1="-10" x2="14" y2="10" ${BODY}/>`,
|
|
259
|
+
lineWire(0, 0, 14, 0),
|
|
260
|
+
`<line x1="14" y1="-6" x2="30" y2="-12" ${BODY}/>`,
|
|
261
|
+
lineWire(30, -12, 40, -16),
|
|
262
|
+
`<line x1="14" y1="6" x2="30" y2="12" ${BODY}/>`,
|
|
263
|
+
lineWire(30, 12, 40, 16),
|
|
264
|
+
// NPN arrow (outward on emitter)
|
|
265
|
+
`<polygon points="30,12 24,10 26,16" ${FILL}/>`
|
|
266
|
+
].join("")
|
|
267
|
+
};
|
|
268
|
+
var pnp = {
|
|
269
|
+
length: 40,
|
|
270
|
+
netlistPins: ["c", "b", "e"],
|
|
271
|
+
anchors: {
|
|
272
|
+
start: { x: 0, y: 0 },
|
|
273
|
+
end: { x: 40, y: -16 },
|
|
274
|
+
base: { x: 0, y: 0 },
|
|
275
|
+
collector: { x: 40, y: 16 },
|
|
276
|
+
emitter: { x: 40, y: -16 },
|
|
277
|
+
b: { x: 0, y: 0 },
|
|
278
|
+
c: { x: 40, y: 16 },
|
|
279
|
+
e: { x: 40, y: -16 }
|
|
280
|
+
},
|
|
281
|
+
svg: () => [
|
|
282
|
+
`<circle cx="20" cy="0" r="16" fill="white" ${BODY}/>`,
|
|
283
|
+
`<line x1="14" y1="-10" x2="14" y2="10" ${BODY}/>`,
|
|
284
|
+
lineWire(0, 0, 14, 0),
|
|
285
|
+
`<line x1="14" y1="-6" x2="30" y2="-12" ${BODY}/>`,
|
|
286
|
+
lineWire(30, -12, 40, -16),
|
|
287
|
+
`<line x1="14" y1="6" x2="30" y2="12" ${BODY}/>`,
|
|
288
|
+
lineWire(30, 12, 40, 16),
|
|
289
|
+
// PNP arrow (inward on emitter → toward base line)
|
|
290
|
+
`<polygon points="14,-6 20,-4 18,-10" ${FILL}/>`
|
|
291
|
+
].join("")
|
|
292
|
+
};
|
|
293
|
+
var nmos = {
|
|
294
|
+
length: 40,
|
|
295
|
+
netlistPins: ["d", "g", "s"],
|
|
296
|
+
anchors: {
|
|
297
|
+
start: { x: 0, y: 0 },
|
|
298
|
+
end: { x: 40, y: -16 },
|
|
299
|
+
gate: { x: 0, y: 0 },
|
|
300
|
+
drain: { x: 40, y: -16 },
|
|
301
|
+
source: { x: 40, y: 16 },
|
|
302
|
+
g: { x: 0, y: 0 },
|
|
303
|
+
d: { x: 40, y: -16 },
|
|
304
|
+
s: { x: 40, y: 16 }
|
|
305
|
+
},
|
|
306
|
+
svg: () => [
|
|
307
|
+
lineWire(0, 0, 14, 0),
|
|
308
|
+
`<line x1="14" y1="-12" x2="14" y2="12" ${BODY}/>`,
|
|
309
|
+
`<line x1="18" y1="-10" x2="18" y2="-4" ${BODY}/>`,
|
|
310
|
+
`<line x1="18" y1="-2" x2="18" y2="2" ${BODY}/>`,
|
|
311
|
+
`<line x1="18" y1="4" x2="18" y2="10" ${BODY}/>`,
|
|
312
|
+
`<line x1="18" y1="-8" x2="32" y2="-8" ${BODY}/>`,
|
|
313
|
+
lineWire(32, -8, 40, -16),
|
|
314
|
+
`<line x1="18" y1="8" x2="32" y2="8" ${BODY}/>`,
|
|
315
|
+
lineWire(32, 8, 40, 16),
|
|
316
|
+
`<polygon points="22,0 18,-4 18,4" ${FILL}/>`
|
|
317
|
+
].join("")
|
|
318
|
+
};
|
|
319
|
+
var pmos = {
|
|
320
|
+
length: 40,
|
|
321
|
+
netlistPins: ["d", "g", "s"],
|
|
322
|
+
anchors: {
|
|
323
|
+
start: { x: 0, y: 0 },
|
|
324
|
+
end: { x: 40, y: -16 },
|
|
325
|
+
gate: { x: 0, y: 0 },
|
|
326
|
+
source: { x: 40, y: -16 },
|
|
327
|
+
drain: { x: 40, y: 16 },
|
|
328
|
+
g: { x: 0, y: 0 },
|
|
329
|
+
s: { x: 40, y: -16 },
|
|
330
|
+
d: { x: 40, y: 16 }
|
|
331
|
+
},
|
|
332
|
+
svg: () => [
|
|
333
|
+
lineWire(0, 0, 14, 0),
|
|
334
|
+
`<line x1="14" y1="-12" x2="14" y2="12" ${BODY}/>`,
|
|
335
|
+
`<line x1="18" y1="-10" x2="18" y2="-4" ${BODY}/>`,
|
|
336
|
+
`<line x1="18" y1="-2" x2="18" y2="2" ${BODY}/>`,
|
|
337
|
+
`<line x1="18" y1="4" x2="18" y2="10" ${BODY}/>`,
|
|
338
|
+
`<line x1="18" y1="-8" x2="32" y2="-8" ${BODY}/>`,
|
|
339
|
+
lineWire(32, -8, 40, -16),
|
|
340
|
+
`<line x1="18" y1="8" x2="32" y2="8" ${BODY}/>`,
|
|
341
|
+
lineWire(32, 8, 40, 16),
|
|
342
|
+
`<polygon points="14,0 18,-4 18,4" ${FILL}/>`
|
|
343
|
+
].join("")
|
|
344
|
+
};
|
|
345
|
+
var jfet_n = {
|
|
666
346
|
length: 40,
|
|
667
|
-
|
|
347
|
+
netlistPins: ["d", "g", "s"],
|
|
668
348
|
anchors: {
|
|
669
349
|
start: { x: 0, y: 0 },
|
|
670
|
-
end: { x: 40, y:
|
|
671
|
-
|
|
672
|
-
|
|
350
|
+
end: { x: 40, y: -16 },
|
|
351
|
+
gate: { x: 0, y: 0 },
|
|
352
|
+
drain: { x: 40, y: -16 },
|
|
353
|
+
source: { x: 40, y: 16 },
|
|
354
|
+
g: { x: 0, y: 0 },
|
|
355
|
+
d: { x: 40, y: -16 },
|
|
356
|
+
s: { x: 40, y: 16 }
|
|
673
357
|
},
|
|
674
358
|
svg: () => [
|
|
675
|
-
lineWire(0, 0,
|
|
676
|
-
`<
|
|
677
|
-
`<
|
|
678
|
-
|
|
679
|
-
|
|
359
|
+
lineWire(0, 0, 14, 0),
|
|
360
|
+
`<line x1="14" y1="-12" x2="14" y2="12" ${BODY}/>`,
|
|
361
|
+
`<line x1="14" y1="-8" x2="32" y2="-8" ${BODY}/>`,
|
|
362
|
+
lineWire(32, -8, 40, -16),
|
|
363
|
+
`<line x1="14" y1="8" x2="32" y2="8" ${BODY}/>`,
|
|
364
|
+
lineWire(32, 8, 40, 16),
|
|
365
|
+
`<polygon points="14,0 10,-4 10,4" ${FILL}/>`
|
|
680
366
|
].join("")
|
|
681
367
|
};
|
|
682
|
-
var
|
|
368
|
+
var jfet_p = {
|
|
683
369
|
length: 40,
|
|
370
|
+
netlistPins: ["d", "g", "s"],
|
|
684
371
|
anchors: {
|
|
685
372
|
start: { x: 0, y: 0 },
|
|
686
|
-
end: { x: 40, y:
|
|
687
|
-
|
|
688
|
-
|
|
373
|
+
end: { x: 40, y: -16 },
|
|
374
|
+
gate: { x: 0, y: 0 },
|
|
375
|
+
drain: { x: 40, y: -16 },
|
|
376
|
+
source: { x: 40, y: 16 },
|
|
377
|
+
g: { x: 0, y: 0 },
|
|
378
|
+
d: { x: 40, y: -16 },
|
|
379
|
+
s: { x: 40, y: 16 }
|
|
689
380
|
},
|
|
690
381
|
svg: () => [
|
|
691
|
-
lineWire(0, 0,
|
|
692
|
-
`<
|
|
693
|
-
`<line x1="14" y1="
|
|
694
|
-
|
|
695
|
-
|
|
382
|
+
lineWire(0, 0, 14, 0),
|
|
383
|
+
`<line x1="14" y1="-12" x2="14" y2="12" ${BODY}/>`,
|
|
384
|
+
`<line x1="14" y1="-8" x2="32" y2="-8" ${BODY}/>`,
|
|
385
|
+
lineWire(32, -8, 40, -16),
|
|
386
|
+
`<line x1="14" y1="8" x2="32" y2="8" ${BODY}/>`,
|
|
387
|
+
lineWire(32, 8, 40, 16),
|
|
388
|
+
`<polygon points="10,0 14,-4 14,4" ${FILL}/>`
|
|
696
389
|
].join("")
|
|
697
390
|
};
|
|
698
|
-
var
|
|
699
|
-
length:
|
|
391
|
+
var opamp = {
|
|
392
|
+
length: 50,
|
|
393
|
+
netlistPins: ["plus", "minus", "out"],
|
|
700
394
|
anchors: {
|
|
701
395
|
start: { x: 0, y: 0 },
|
|
702
|
-
end: { x:
|
|
703
|
-
|
|
704
|
-
|
|
396
|
+
end: { x: 50, y: 0 },
|
|
397
|
+
plus: { x: 0, y: -10 },
|
|
398
|
+
minus: { x: 0, y: 10 },
|
|
399
|
+
out: { x: 50, y: 0 },
|
|
400
|
+
"supply+": { x: 25, y: -20 },
|
|
401
|
+
"supply-": { x: 25, y: 20 }
|
|
705
402
|
},
|
|
706
403
|
svg: () => [
|
|
707
|
-
|
|
708
|
-
`<
|
|
709
|
-
`<
|
|
710
|
-
lineWire(32, 0, 40, 0)
|
|
404
|
+
`<polygon points="0,-20 0,20 50,0" fill="white" ${BODY}/>`,
|
|
405
|
+
`<text x="5" y="-6" class="schematex-circuit-pol">+</text>`,
|
|
406
|
+
`<text x="5" y="14" class="schematex-circuit-pol">\u2212</text>`
|
|
711
407
|
].join("")
|
|
712
408
|
};
|
|
713
|
-
var
|
|
714
|
-
length:
|
|
409
|
+
var comparator = {
|
|
410
|
+
length: 50,
|
|
411
|
+
netlistPins: ["plus", "minus", "out"],
|
|
715
412
|
anchors: {
|
|
716
413
|
start: { x: 0, y: 0 },
|
|
717
|
-
end: { x:
|
|
718
|
-
|
|
719
|
-
|
|
414
|
+
end: { x: 50, y: 0 },
|
|
415
|
+
plus: { x: 0, y: -10 },
|
|
416
|
+
minus: { x: 0, y: 10 },
|
|
417
|
+
out: { x: 50, y: 0 }
|
|
720
418
|
},
|
|
721
419
|
svg: () => [
|
|
722
|
-
|
|
723
|
-
`<
|
|
724
|
-
`<
|
|
725
|
-
`<
|
|
726
|
-
`<line x1="18" y1="-4" x2="18" y2="4" ${BODY}/>`,
|
|
727
|
-
lineWire(18, 0, 24, 0)
|
|
420
|
+
`<polygon points="0,-20 0,20 50,0" fill="white" ${BODY}/>`,
|
|
421
|
+
`<text x="5" y="-6" class="schematex-circuit-pol">+</text>`,
|
|
422
|
+
`<text x="5" y="14" class="schematex-circuit-pol">\u2212</text>`,
|
|
423
|
+
`<circle cx="48" cy="0" r="3" fill="white" ${BODY}/>`
|
|
728
424
|
].join("")
|
|
729
425
|
};
|
|
730
|
-
var
|
|
731
|
-
length:
|
|
732
|
-
anchors: { start: { x: 0, y: 0 }, end: { x:
|
|
733
|
-
// Drawn as a "terminal" — vertical connection at start, earth lines below
|
|
426
|
+
var switch_spst = {
|
|
427
|
+
length: 40,
|
|
428
|
+
anchors: { start: { x: 0, y: 0 }, end: { x: 40, y: 0 } },
|
|
734
429
|
svg: () => [
|
|
735
|
-
|
|
736
|
-
`<line x1="10" y1="
|
|
737
|
-
`<
|
|
738
|
-
`<
|
|
430
|
+
lineWire(0, 0, 10, 0),
|
|
431
|
+
`<line x1="10" y1="0" x2="30" y2="-10" ${BODY}/>`,
|
|
432
|
+
`<circle cx="10" cy="0" r="2" ${FILL}/>`,
|
|
433
|
+
`<circle cx="30" cy="0" r="2" ${FILL}/>`,
|
|
434
|
+
lineWire(30, 0, 40, 0)
|
|
739
435
|
].join("")
|
|
740
436
|
};
|
|
741
|
-
var
|
|
742
|
-
length:
|
|
743
|
-
anchors: { start: { x: 0, y: 0 }, end: { x:
|
|
437
|
+
var push_no = {
|
|
438
|
+
length: 40,
|
|
439
|
+
anchors: { start: { x: 0, y: 0 }, end: { x: 40, y: 0 } },
|
|
744
440
|
svg: () => [
|
|
745
|
-
|
|
746
|
-
|
|
441
|
+
lineWire(0, 0, 12, 0),
|
|
442
|
+
lineWire(28, 0, 40, 0),
|
|
443
|
+
`<circle cx="12" cy="0" r="2" ${FILL}/>`,
|
|
444
|
+
`<circle cx="28" cy="0" r="2" ${FILL}/>`,
|
|
445
|
+
`<line x1="12" y1="-4" x2="28" y2="-4" ${BODY}/>`,
|
|
446
|
+
`<line x1="20" y1="-4" x2="20" y2="-12" ${BODY}/>`,
|
|
447
|
+
`<line x1="14" y1="-12" x2="26" y2="-12" ${BODY}/>`
|
|
747
448
|
].join("")
|
|
748
449
|
};
|
|
749
|
-
var
|
|
750
|
-
|
|
751
|
-
|
|
450
|
+
var meterSvg = (letter) => () => [
|
|
451
|
+
lineWire(0, 0, 8, 0),
|
|
452
|
+
`<circle cx="20" cy="0" r="12" fill="white" ${BODY}/>`,
|
|
453
|
+
`<text x="20" y="4" text-anchor="middle" class="schematex-circuit-meter">${letter}</text>`,
|
|
454
|
+
lineWire(32, 0, 40, 0)
|
|
455
|
+
].join("");
|
|
456
|
+
var ammeter = { length: 40, anchors: { start: { x: 0, y: 0 }, end: { x: 40, y: 0 } }, svg: meterSvg("A") };
|
|
457
|
+
var voltmeter = { length: 40, anchors: { start: { x: 0, y: 0 }, end: { x: 40, y: 0 } }, svg: meterSvg("V") };
|
|
458
|
+
var wattmeter = { length: 40, anchors: { start: { x: 0, y: 0 }, end: { x: 40, y: 0 } }, svg: meterSvg("W") };
|
|
459
|
+
var motor = { length: 40, anchors: { start: { x: 0, y: 0 }, end: { x: 40, y: 0 } }, svg: meterSvg("M") };
|
|
460
|
+
var lamp = {
|
|
461
|
+
length: 40,
|
|
462
|
+
anchors: { start: { x: 0, y: 0 }, end: { x: 40, y: 0 } },
|
|
752
463
|
svg: () => [
|
|
753
|
-
|
|
754
|
-
`<
|
|
464
|
+
lineWire(0, 0, 8, 0),
|
|
465
|
+
`<circle cx="20" cy="0" r="12" fill="white" ${BODY}/>`,
|
|
466
|
+
`<line x1="12" y1="-8" x2="28" y2="8" ${BODY}/>`,
|
|
467
|
+
`<line x1="12" y1="8" x2="28" y2="-8" ${BODY}/>`,
|
|
468
|
+
lineWire(32, 0, 40, 0)
|
|
755
469
|
].join("")
|
|
756
470
|
};
|
|
757
|
-
var
|
|
758
|
-
length:
|
|
759
|
-
anchors: { start: { x: 0, y: 0 }, end: { x:
|
|
471
|
+
var buzzer = {
|
|
472
|
+
length: 40,
|
|
473
|
+
anchors: { start: { x: 0, y: 0 }, end: { x: 40, y: 0 } },
|
|
760
474
|
svg: () => [
|
|
761
475
|
lineWire(0, 0, 8, 0),
|
|
762
|
-
`<
|
|
763
|
-
|
|
764
|
-
lineWire(22, 0, 30, 0)
|
|
476
|
+
`<path d="M 8,0 A 12,12 0 0 1 32,0 L 8,0 Z" fill="white" ${BODY}/>`,
|
|
477
|
+
lineWire(32, 0, 40, 0)
|
|
765
478
|
].join("")
|
|
766
479
|
};
|
|
767
|
-
var
|
|
768
|
-
length:
|
|
769
|
-
anchors: { start: { x: 0, y: 0 }, end: { x:
|
|
480
|
+
var speaker = {
|
|
481
|
+
length: 40,
|
|
482
|
+
anchors: { start: { x: 0, y: 0 }, end: { x: 40, y: 0 } },
|
|
770
483
|
svg: () => [
|
|
771
|
-
lineWire(0, 0,
|
|
772
|
-
`<
|
|
773
|
-
`<path d="M
|
|
774
|
-
lineWire(
|
|
484
|
+
lineWire(0, 0, 6, 0),
|
|
485
|
+
`<rect x="6" y="-8" width="10" height="16" fill="white" ${BODY}/>`,
|
|
486
|
+
`<path d="M 16,-8 L 28,-16 L 28,16 L 16,8 Z" fill="white" ${BODY}/>`,
|
|
487
|
+
lineWire(0, 8, 6, 8)
|
|
775
488
|
].join("")
|
|
776
489
|
};
|
|
777
|
-
var
|
|
778
|
-
length:
|
|
779
|
-
anchors: { start: { x: 0, y: 0 }, end: { x:
|
|
490
|
+
var microphone = {
|
|
491
|
+
length: 40,
|
|
492
|
+
anchors: { start: { x: 0, y: 0 }, end: { x: 40, y: 0 } },
|
|
780
493
|
svg: () => [
|
|
781
494
|
lineWire(0, 0, 8, 0),
|
|
782
|
-
`<
|
|
783
|
-
`<
|
|
784
|
-
lineWire(
|
|
495
|
+
`<circle cx="20" cy="0" r="12" fill="white" ${BODY}/>`,
|
|
496
|
+
`<line x1="20" y1="-10" x2="20" y2="10" ${BODY}/>`,
|
|
497
|
+
lineWire(32, 0, 40, 0)
|
|
785
498
|
].join("")
|
|
786
499
|
};
|
|
787
|
-
var
|
|
788
|
-
length:
|
|
789
|
-
anchors: { start: { x: 0, y: 0 }, end: { x:
|
|
500
|
+
var rheostat = {
|
|
501
|
+
length: 50,
|
|
502
|
+
anchors: { start: { x: 0, y: 0 }, end: { x: 50, y: 0 } },
|
|
790
503
|
svg: () => [
|
|
791
|
-
|
|
792
|
-
`<
|
|
793
|
-
`<
|
|
794
|
-
lineWire(22, 0, 30, 0),
|
|
795
|
-
// outward light arrows
|
|
796
|
-
`<path d="M 12,-10 L 20,-18 M 18,-18 L 20,-18 L 20,-16" fill="none" ${BODY}/>`,
|
|
797
|
-
`<path d="M 16,-10 L 24,-18 M 22,-18 L 24,-18 L 24,-16" fill="none" ${BODY}/>`
|
|
504
|
+
`<path d="M 0,0 L 10,0 L 13,-8 L 18,8 L 23,-8 L 28,8 L 33,-8 L 38,8 L 40,0 L 50,0" ${BODY}/>`,
|
|
505
|
+
`<line x1="5" y1="12" x2="45" y2="-12" ${BODY}/>`,
|
|
506
|
+
`<polygon points="45,-12 40,-9 44,-5" ${FILL}/>`
|
|
798
507
|
].join("")
|
|
799
508
|
};
|
|
800
|
-
var
|
|
801
|
-
length:
|
|
802
|
-
anchors: { start: { x: 0, y: 0 }, end: { x:
|
|
509
|
+
var thermistor_ntc = {
|
|
510
|
+
length: 50,
|
|
511
|
+
anchors: { start: { x: 0, y: 0 }, end: { x: 50, y: 0 } },
|
|
803
512
|
svg: () => [
|
|
804
|
-
|
|
805
|
-
`<
|
|
806
|
-
`<
|
|
807
|
-
lineWire(22, 0, 30, 0),
|
|
808
|
-
// inward light arrows
|
|
809
|
-
`<path d="M 20,-18 L 12,-10 M 12,-12 L 12,-10 L 14,-10" fill="none" ${BODY}/>`,
|
|
810
|
-
`<path d="M 24,-18 L 16,-10 M 16,-12 L 16,-10 L 18,-10" fill="none" ${BODY}/>`
|
|
513
|
+
`<path d="M 0,0 L 10,0 L 13,-8 L 18,8 L 23,-8 L 28,8 L 33,-8 L 38,8 L 40,0 L 50,0" ${BODY}/>`,
|
|
514
|
+
`<line x1="5" y1="10" x2="45" y2="-10" ${BODY}/>`,
|
|
515
|
+
`<text x="40" y="-14" class="schematex-circuit-pol">-t\xB0</text>`
|
|
811
516
|
].join("")
|
|
812
517
|
};
|
|
813
|
-
var
|
|
814
|
-
length:
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
518
|
+
var thermistor_ptc = {
|
|
519
|
+
length: 50,
|
|
520
|
+
anchors: { start: { x: 0, y: 0 }, end: { x: 50, y: 0 } },
|
|
521
|
+
svg: () => [
|
|
522
|
+
`<path d="M 0,0 L 10,0 L 13,-8 L 18,8 L 23,-8 L 28,8 L 33,-8 L 38,8 L 40,0 L 50,0" ${BODY}/>`,
|
|
523
|
+
`<line x1="5" y1="10" x2="45" y2="-10" ${BODY}/>`,
|
|
524
|
+
`<text x="40" y="-14" class="schematex-circuit-pol">+t\xB0</text>`
|
|
525
|
+
].join("")
|
|
526
|
+
};
|
|
527
|
+
var ldr = {
|
|
528
|
+
length: 50,
|
|
529
|
+
anchors: { start: { x: 0, y: 0 }, end: { x: 50, y: 0 } },
|
|
530
|
+
svg: () => [
|
|
531
|
+
`<path d="M 0,0 L 10,0 L 13,-8 L 18,8 L 23,-8 L 28,8 L 33,-8 L 38,8 L 40,0 L 50,0" ${BODY}/>`,
|
|
532
|
+
`<circle cx="25" cy="-2" r="14" fill="none" ${BODY}/>`,
|
|
533
|
+
`<path d="M 10,-24 L 18,-16 M 14,-16 L 18,-16 L 18,-20" fill="none" ${BODY}/>`,
|
|
534
|
+
`<path d="M 20,-24 L 28,-16 M 24,-16 L 28,-16 L 28,-20" fill="none" ${BODY}/>`
|
|
535
|
+
].join("")
|
|
536
|
+
};
|
|
537
|
+
var variable_cap = {
|
|
538
|
+
length: 24,
|
|
539
|
+
anchors: { start: { x: 0, y: 0 }, end: { x: 24, y: 0 } },
|
|
826
540
|
svg: () => [
|
|
827
|
-
|
|
541
|
+
lineWire(0, 0, 10, 0),
|
|
542
|
+
`<line x1="10" y1="-10" x2="10" y2="10" ${BODY}/>`,
|
|
828
543
|
`<line x1="14" y1="-10" x2="14" y2="10" ${BODY}/>`,
|
|
829
|
-
lineWire(
|
|
830
|
-
`<line x1="
|
|
831
|
-
|
|
832
|
-
`<line x1="14" y1="6" x2="30" y2="12" ${BODY}/>`,
|
|
833
|
-
lineWire(30, 12, 40, 16),
|
|
834
|
-
// NPN arrow (outward on emitter)
|
|
835
|
-
`<polygon points="30,12 24,10 26,16" ${FILL}/>`
|
|
544
|
+
lineWire(14, 0, 24, 0),
|
|
545
|
+
`<line x1="3" y1="10" x2="21" y2="-12" ${BODY}/>`,
|
|
546
|
+
`<polygon points="21,-12 15,-10 19,-6" ${FILL}/>`
|
|
836
547
|
].join("")
|
|
837
548
|
};
|
|
838
|
-
var
|
|
549
|
+
var variable_inductor = {
|
|
839
550
|
length: 40,
|
|
840
|
-
anchors: {
|
|
841
|
-
start: { x: 0, y: 0 },
|
|
842
|
-
end: { x: 40, y: -16 },
|
|
843
|
-
base: { x: 0, y: 0 },
|
|
844
|
-
collector: { x: 40, y: 16 },
|
|
845
|
-
emitter: { x: 40, y: -16 },
|
|
846
|
-
b: { x: 0, y: 0 },
|
|
847
|
-
c: { x: 40, y: 16 },
|
|
848
|
-
e: { x: 40, y: -16 }
|
|
849
|
-
},
|
|
551
|
+
anchors: { start: { x: 0, y: 0 }, end: { x: 40, y: 0 } },
|
|
850
552
|
svg: () => [
|
|
851
|
-
`<
|
|
852
|
-
`<line x1="
|
|
853
|
-
|
|
854
|
-
`<line x1="14" y1="-6" x2="30" y2="-12" ${BODY}/>`,
|
|
855
|
-
lineWire(30, -12, 40, -16),
|
|
856
|
-
`<line x1="14" y1="6" x2="30" y2="12" ${BODY}/>`,
|
|
857
|
-
lineWire(30, 12, 40, 16),
|
|
858
|
-
// PNP arrow (inward on emitter → toward base line)
|
|
859
|
-
`<polygon points="14,-6 20,-4 18,-10" ${FILL}/>`
|
|
553
|
+
`<path d="M 0,0 L 5,0 A 5,5 0 0 1 15,0 A 5,5 0 0 1 25,0 A 5,5 0 0 1 35,0 L 40,0" fill="none" ${BODY}/>`,
|
|
554
|
+
`<line x1="0" y1="10" x2="38" y2="-14" ${BODY}/>`,
|
|
555
|
+
`<polygon points="38,-14 32,-12 36,-8" ${FILL}/>`
|
|
860
556
|
].join("")
|
|
861
557
|
};
|
|
862
|
-
var
|
|
863
|
-
length:
|
|
558
|
+
var switch_spdt = {
|
|
559
|
+
length: 50,
|
|
560
|
+
netlistPins: ["common", "nc", "no"],
|
|
864
561
|
anchors: {
|
|
865
562
|
start: { x: 0, y: 0 },
|
|
866
|
-
end: { x:
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
g: { x: 0, y: 0 },
|
|
871
|
-
d: { x: 40, y: -16 },
|
|
872
|
-
s: { x: 40, y: 16 }
|
|
563
|
+
end: { x: 50, y: 0 },
|
|
564
|
+
common: { x: 0, y: 0 },
|
|
565
|
+
nc: { x: 50, y: -12 },
|
|
566
|
+
no: { x: 50, y: 12 }
|
|
873
567
|
},
|
|
874
568
|
svg: () => [
|
|
875
|
-
lineWire(0, 0,
|
|
876
|
-
`<
|
|
877
|
-
`<line x1="
|
|
878
|
-
`<
|
|
879
|
-
|
|
880
|
-
`<
|
|
881
|
-
lineWire(
|
|
882
|
-
`<line x1="18" y1="8" x2="32" y2="8" ${BODY}/>`,
|
|
883
|
-
lineWire(32, 8, 40, 16),
|
|
884
|
-
`<polygon points="22,0 18,-4 18,4" ${FILL}/>`
|
|
569
|
+
lineWire(0, 0, 10, 0),
|
|
570
|
+
`<circle cx="10" cy="0" r="2" ${FILL}/>`,
|
|
571
|
+
`<line x1="10" y1="0" x2="40" y2="-12" ${BODY}/>`,
|
|
572
|
+
`<circle cx="42" cy="-12" r="2" ${FILL}/>`,
|
|
573
|
+
lineWire(42, -12, 50, -12),
|
|
574
|
+
`<circle cx="42" cy="12" r="2" ${FILL}/>`,
|
|
575
|
+
lineWire(42, 12, 50, 12)
|
|
885
576
|
].join("")
|
|
886
577
|
};
|
|
887
|
-
var
|
|
578
|
+
var push_nc = {
|
|
888
579
|
length: 40,
|
|
889
|
-
anchors: {
|
|
890
|
-
start: { x: 0, y: 0 },
|
|
891
|
-
end: { x: 40, y: -16 },
|
|
892
|
-
gate: { x: 0, y: 0 },
|
|
893
|
-
source: { x: 40, y: -16 },
|
|
894
|
-
drain: { x: 40, y: 16 },
|
|
895
|
-
g: { x: 0, y: 0 },
|
|
896
|
-
s: { x: 40, y: -16 },
|
|
897
|
-
d: { x: 40, y: 16 }
|
|
898
|
-
},
|
|
580
|
+
anchors: { start: { x: 0, y: 0 }, end: { x: 40, y: 0 } },
|
|
899
581
|
svg: () => [
|
|
900
|
-
lineWire(0, 0,
|
|
901
|
-
|
|
902
|
-
`<
|
|
903
|
-
`<
|
|
904
|
-
`<line x1="
|
|
905
|
-
`<line x1="
|
|
906
|
-
|
|
907
|
-
`<line x1="18" y1="8" x2="32" y2="8" ${BODY}/>`,
|
|
908
|
-
lineWire(32, 8, 40, 16),
|
|
909
|
-
`<polygon points="14,0 18,-4 18,4" ${FILL}/>`
|
|
582
|
+
lineWire(0, 0, 12, 0),
|
|
583
|
+
lineWire(28, 0, 40, 0),
|
|
584
|
+
`<circle cx="12" cy="0" r="2" ${FILL}/>`,
|
|
585
|
+
`<circle cx="28" cy="0" r="2" ${FILL}/>`,
|
|
586
|
+
`<line x1="10" y1="0" x2="30" y2="0" ${BODY}/>`,
|
|
587
|
+
`<line x1="20" y1="0" x2="20" y2="-10" ${BODY}/>`,
|
|
588
|
+
`<line x1="14" y1="-10" x2="26" y2="-10" ${BODY}/>`
|
|
910
589
|
].join("")
|
|
911
590
|
};
|
|
912
|
-
var
|
|
913
|
-
length:
|
|
914
|
-
anchors: {
|
|
915
|
-
start: { x: 0, y: 0 },
|
|
916
|
-
end: { x: 40, y: -16 },
|
|
917
|
-
gate: { x: 0, y: 0 },
|
|
918
|
-
drain: { x: 40, y: -16 },
|
|
919
|
-
source: { x: 40, y: 16 }
|
|
920
|
-
},
|
|
591
|
+
var gnd_chassis = {
|
|
592
|
+
length: 20,
|
|
593
|
+
anchors: { start: { x: 0, y: 0 }, end: { x: 20, y: 0 } },
|
|
921
594
|
svg: () => [
|
|
922
|
-
|
|
923
|
-
`<line x1="
|
|
924
|
-
`<line x1="
|
|
925
|
-
|
|
926
|
-
`<line x1="
|
|
927
|
-
lineWire(32, 8, 40, 16),
|
|
928
|
-
`<polygon points="14,0 10,-4 10,4" ${FILL}/>`
|
|
595
|
+
`<line x1="0" y1="0" x2="10" y2="0" ${WIRE}/>`,
|
|
596
|
+
`<line x1="10" y1="-6" x2="10" y2="6" ${BODY}/>`,
|
|
597
|
+
`<line x1="10" y1="6" x2="14" y2="10" ${BODY}/>`,
|
|
598
|
+
`<line x1="10" y1="2" x2="14" y2="6" ${BODY}/>`,
|
|
599
|
+
`<line x1="10" y1="-2" x2="14" y2="2" ${BODY}/>`
|
|
929
600
|
].join("")
|
|
930
601
|
};
|
|
931
|
-
var
|
|
932
|
-
length:
|
|
933
|
-
anchors: {
|
|
934
|
-
start: { x: 0, y: 0 },
|
|
935
|
-
end: { x: 40, y: -16 },
|
|
936
|
-
gate: { x: 0, y: 0 },
|
|
937
|
-
drain: { x: 40, y: -16 },
|
|
938
|
-
source: { x: 40, y: 16 }
|
|
939
|
-
},
|
|
602
|
+
var gnd_digital = {
|
|
603
|
+
length: 20,
|
|
604
|
+
anchors: { start: { x: 0, y: 0 }, end: { x: 20, y: 0 } },
|
|
940
605
|
svg: () => [
|
|
941
|
-
|
|
942
|
-
`<
|
|
943
|
-
`<line x1="14" y1="-8" x2="32" y2="-8" ${BODY}/>`,
|
|
944
|
-
lineWire(32, -8, 40, -16),
|
|
945
|
-
`<line x1="14" y1="8" x2="32" y2="8" ${BODY}/>`,
|
|
946
|
-
lineWire(32, 8, 40, 16),
|
|
947
|
-
`<polygon points="10,0 14,-4 14,4" ${FILL}/>`
|
|
606
|
+
`<line x1="0" y1="0" x2="10" y2="0" ${WIRE}/>`,
|
|
607
|
+
`<polygon points="8,-6 8,6 16,0" fill="none" ${BODY}/>`
|
|
948
608
|
].join("")
|
|
949
609
|
};
|
|
950
|
-
var
|
|
951
|
-
length:
|
|
610
|
+
var test_point = {
|
|
611
|
+
length: 16,
|
|
612
|
+
anchors: { start: { x: 0, y: 0 }, end: { x: 16, y: 0 } },
|
|
613
|
+
svg: () => [
|
|
614
|
+
lineWire(0, 0, 6, 0),
|
|
615
|
+
`<circle cx="10" cy="0" r="4" fill="white" ${BODY}/>`
|
|
616
|
+
].join("")
|
|
617
|
+
};
|
|
618
|
+
var no_connect = {
|
|
619
|
+
length: 0,
|
|
620
|
+
anchors: { start: { x: 0, y: 0 }, end: { x: 0, y: 0 } },
|
|
621
|
+
svg: () => [
|
|
622
|
+
`<line x1="-5" y1="-5" x2="5" y2="5" ${BODY}/>`,
|
|
623
|
+
`<line x1="5" y1="-5" x2="-5" y2="5" ${BODY}/>`
|
|
624
|
+
].join("")
|
|
625
|
+
};
|
|
626
|
+
var antenna = {
|
|
627
|
+
length: 30,
|
|
628
|
+
anchors: { start: { x: 0, y: 0 }, end: { x: 30, y: 0 } },
|
|
629
|
+
svg: () => [
|
|
630
|
+
lineWire(0, 0, 0, -10),
|
|
631
|
+
`<line x1="0" y1="-10" x2="-10" y2="-24" ${BODY}/>`,
|
|
632
|
+
`<line x1="0" y1="-10" x2="10" y2="-24" ${BODY}/>`
|
|
633
|
+
].join("")
|
|
634
|
+
};
|
|
635
|
+
function icSymbol(defaultLeft, defaultRight, bodyLabel) {
|
|
636
|
+
const BODY_W = 80;
|
|
637
|
+
return {
|
|
638
|
+
length: BODY_W,
|
|
639
|
+
netlistPins: [],
|
|
640
|
+
anchors: {
|
|
641
|
+
start: { x: 0, y: 0 },
|
|
642
|
+
end: { x: BODY_W, y: 0 }
|
|
643
|
+
},
|
|
644
|
+
svg: (_label, _value, attrs) => {
|
|
645
|
+
const left = attrs?.pins_left ? attrs.pins_left.split(",").map((s) => s.trim()) : defaultLeft;
|
|
646
|
+
const right = attrs?.pins_right ? attrs.pins_right.split(",").map((s) => s.trim()) : defaultRight;
|
|
647
|
+
const n = Math.max(left.length, right.length, 2);
|
|
648
|
+
const pitch = 16;
|
|
649
|
+
const bodyH = pitch * (n + 1);
|
|
650
|
+
const topY = -bodyH / 2;
|
|
651
|
+
const parts = [];
|
|
652
|
+
parts.push(`<rect x="0" y="${topY}" width="${BODY_W}" height="${bodyH}" fill="white" ${BODY}/>`);
|
|
653
|
+
const labelText = attrs?.ic_label ?? bodyLabel ?? "";
|
|
654
|
+
if (labelText) {
|
|
655
|
+
parts.push(`<text x="${BODY_W / 2}" y="3" text-anchor="middle" class="schematex-circuit-meter">${labelText}</text>`);
|
|
656
|
+
}
|
|
657
|
+
for (let i = 0; i < left.length; i++) {
|
|
658
|
+
const y = topY + pitch * (i + 1);
|
|
659
|
+
parts.push(`<line x1="-8" y1="${y}" x2="0" y2="${y}" ${WIRE}/>`);
|
|
660
|
+
parts.push(`<text x="4" y="${y + 3}" class="schematex-circuit-pol">${left[i]}</text>`);
|
|
661
|
+
}
|
|
662
|
+
for (let i = 0; i < right.length; i++) {
|
|
663
|
+
const y = topY + pitch * (i + 1);
|
|
664
|
+
parts.push(`<line x1="${BODY_W}" y1="${y}" x2="${BODY_W + 8}" y2="${y}" ${WIRE}/>`);
|
|
665
|
+
parts.push(`<text x="${BODY_W - 4}" y="${y + 3}" text-anchor="end" class="schematex-circuit-pol">${right[i]}</text>`);
|
|
666
|
+
}
|
|
667
|
+
return parts.join("");
|
|
668
|
+
}
|
|
669
|
+
};
|
|
670
|
+
}
|
|
671
|
+
var generic_ic = icSymbol(
|
|
672
|
+
["1", "2", "3", "4"],
|
|
673
|
+
["8", "7", "6", "5"],
|
|
674
|
+
"IC"
|
|
675
|
+
);
|
|
676
|
+
var timer_555 = (() => {
|
|
677
|
+
const left = ["GND", "TRG", "OUT", "RST"];
|
|
678
|
+
const right = ["VCC", "DIS", "THR", "CTL"];
|
|
679
|
+
const sym = icSymbol(left, right, "555");
|
|
680
|
+
const BODY_W = 80;
|
|
681
|
+
const pitch = 16;
|
|
682
|
+
const n = 4;
|
|
683
|
+
const topY = -80 / 2;
|
|
684
|
+
const anchors = {
|
|
685
|
+
start: { x: 0, y: 0 },
|
|
686
|
+
end: { x: BODY_W, y: 0 }
|
|
687
|
+
};
|
|
688
|
+
const leftNames = ["gnd", "trg", "out", "rst"];
|
|
689
|
+
const rightNames = ["vcc", "dis", "thr", "ctl"];
|
|
690
|
+
for (let i = 0; i < n; i++) {
|
|
691
|
+
const y = topY + pitch * (i + 1);
|
|
692
|
+
anchors[leftNames[i]] = { x: -8, y };
|
|
693
|
+
anchors[rightNames[i]] = { x: BODY_W + 8, y };
|
|
694
|
+
}
|
|
695
|
+
return { ...sym, anchors };
|
|
696
|
+
})();
|
|
697
|
+
var voltage_regulator = {
|
|
698
|
+
length: 60,
|
|
699
|
+
netlistPins: ["in", "gnd", "out"],
|
|
952
700
|
anchors: {
|
|
953
701
|
start: { x: 0, y: 0 },
|
|
954
|
-
end: { x:
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
"supply+": { x: 25, y: -20 },
|
|
959
|
-
"supply-": { x: 25, y: 20 }
|
|
702
|
+
end: { x: 60, y: 0 },
|
|
703
|
+
in: { x: 0, y: 0 },
|
|
704
|
+
out: { x: 60, y: 0 },
|
|
705
|
+
gnd: { x: 30, y: 20 }
|
|
960
706
|
},
|
|
961
|
-
svg: () => [
|
|
962
|
-
|
|
963
|
-
`<
|
|
964
|
-
`<text x="
|
|
707
|
+
svg: (_l, _v, attrs) => [
|
|
708
|
+
lineWire(0, 0, 10, 0),
|
|
709
|
+
`<rect x="10" y="-15" width="40" height="30" fill="white" ${BODY}/>`,
|
|
710
|
+
`<text x="30" y="4" text-anchor="middle" class="schematex-circuit-meter">${attrs?.model ?? "REG"}</text>`,
|
|
711
|
+
lineWire(50, 0, 60, 0),
|
|
712
|
+
lineWire(30, 15, 30, 20)
|
|
965
713
|
].join("")
|
|
966
714
|
};
|
|
967
|
-
var
|
|
715
|
+
var potentiometer = {
|
|
968
716
|
length: 50,
|
|
717
|
+
netlistPins: ["start", "wiper", "end"],
|
|
969
718
|
anchors: {
|
|
970
719
|
start: { x: 0, y: 0 },
|
|
971
720
|
end: { x: 50, y: 0 },
|
|
972
|
-
|
|
973
|
-
minus: { x: 0, y: 10 },
|
|
974
|
-
out: { x: 50, y: 0 }
|
|
721
|
+
wiper: { x: 25, y: -22 }
|
|
975
722
|
},
|
|
976
723
|
svg: () => [
|
|
977
|
-
`<
|
|
978
|
-
`<
|
|
979
|
-
`<
|
|
980
|
-
`<circle cx="48" cy="0" r="3" fill="white" ${BODY}/>`
|
|
981
|
-
].join("")
|
|
982
|
-
};
|
|
983
|
-
var switch_spst = {
|
|
984
|
-
length: 40,
|
|
985
|
-
anchors: { start: { x: 0, y: 0 }, end: { x: 40, y: 0 } },
|
|
986
|
-
svg: () => [
|
|
987
|
-
lineWire(0, 0, 10, 0),
|
|
988
|
-
`<line x1="10" y1="0" x2="30" y2="-10" ${BODY}/>`,
|
|
989
|
-
`<circle cx="10" cy="0" r="2" ${FILL}/>`,
|
|
990
|
-
`<circle cx="30" cy="0" r="2" ${FILL}/>`,
|
|
991
|
-
lineWire(30, 0, 40, 0)
|
|
992
|
-
].join("")
|
|
993
|
-
};
|
|
994
|
-
var push_no = {
|
|
995
|
-
length: 40,
|
|
996
|
-
anchors: { start: { x: 0, y: 0 }, end: { x: 40, y: 0 } },
|
|
997
|
-
svg: () => [
|
|
998
|
-
lineWire(0, 0, 12, 0),
|
|
999
|
-
lineWire(28, 0, 40, 0),
|
|
1000
|
-
`<circle cx="12" cy="0" r="2" ${FILL}/>`,
|
|
1001
|
-
`<circle cx="28" cy="0" r="2" ${FILL}/>`,
|
|
1002
|
-
`<line x1="12" y1="-4" x2="28" y2="-4" ${BODY}/>`,
|
|
1003
|
-
`<line x1="20" y1="-4" x2="20" y2="-12" ${BODY}/>`,
|
|
1004
|
-
`<line x1="14" y1="-12" x2="26" y2="-12" ${BODY}/>`
|
|
724
|
+
`<path d="M 0,0 L 10,0 L 13,-8 L 18,8 L 23,-8 L 28,8 L 33,-8 L 38,8 L 40,0 L 50,0" ${BODY}/>`,
|
|
725
|
+
`<line x1="25" y1="-22" x2="25" y2="-10" ${BODY}/>`,
|
|
726
|
+
`<polygon points="25,-10 21,-16 29,-16" ${FILL}/>`
|
|
1005
727
|
].join("")
|
|
1006
728
|
};
|
|
1007
|
-
var
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
729
|
+
var terminal_block = {
|
|
730
|
+
length: 80,
|
|
731
|
+
netlistPins: [],
|
|
732
|
+
anchors: { start: { x: 0, y: 0 }, end: { x: 80, y: 0 } },
|
|
733
|
+
svg: (label, _value, attrs) => {
|
|
734
|
+
const pinsAttr = attrs?.pins ?? attrs?.terminals ?? "1,2,3,4";
|
|
735
|
+
const pins = pinsAttr.split(",").map((s) => s.trim()).filter(Boolean);
|
|
736
|
+
const n = Math.max(pins.length, 1);
|
|
737
|
+
const BODY_W = 80;
|
|
738
|
+
const pitch = 18;
|
|
739
|
+
const bodyH = pitch * (n + 1);
|
|
740
|
+
const topY = -bodyH / 2;
|
|
741
|
+
const parts = [];
|
|
742
|
+
parts.push(
|
|
743
|
+
`<rect x="0" y="${topY}" width="${BODY_W}" height="${bodyH}" rx="3" fill="white" stroke-width="2" ${BODY}/>`
|
|
744
|
+
);
|
|
745
|
+
if (label) {
|
|
746
|
+
parts.push(
|
|
747
|
+
`<text x="${BODY_W / 2}" y="${topY + 14}" text-anchor="middle" class="schematex-circuit-meter">${label}</text>`
|
|
748
|
+
);
|
|
749
|
+
}
|
|
750
|
+
for (let i = 0; i < n; i++) {
|
|
751
|
+
const y = topY + pitch * (i + 1) + (label ? 8 : 0);
|
|
752
|
+
parts.push(`<line x1="-8" y1="${y}" x2="0" y2="${y}" ${WIRE}/>`);
|
|
753
|
+
parts.push(`<circle cx="6" cy="${y}" r="2" ${FILL}/>`);
|
|
754
|
+
parts.push(
|
|
755
|
+
`<text x="12" y="${y + 3}" class="schematex-circuit-pol">${pins[i] ?? `T${i + 1}`}</text>`
|
|
756
|
+
);
|
|
757
|
+
}
|
|
758
|
+
return parts.join("");
|
|
759
|
+
}
|
|
1027
760
|
};
|
|
1028
|
-
var
|
|
761
|
+
var relay_coil = {
|
|
1029
762
|
length: 40,
|
|
1030
763
|
anchors: { start: { x: 0, y: 0 }, end: { x: 40, y: 0 } },
|
|
1031
764
|
svg: () => [
|
|
1032
765
|
lineWire(0, 0, 8, 0),
|
|
1033
|
-
`<
|
|
766
|
+
`<rect x="8" y="-10" width="24" height="20" fill="white" ${BODY}/>`,
|
|
767
|
+
// Diagonal slash inside the box = coil winding indicator
|
|
768
|
+
`<line x1="8" y1="-10" x2="32" y2="10" ${BODY}/>`,
|
|
1034
769
|
lineWire(32, 0, 40, 0)
|
|
1035
770
|
].join("")
|
|
1036
771
|
};
|
|
1037
|
-
var
|
|
772
|
+
var relay_no = {
|
|
1038
773
|
length: 40,
|
|
1039
774
|
anchors: { start: { x: 0, y: 0 }, end: { x: 40, y: 0 } },
|
|
1040
775
|
svg: () => [
|
|
1041
|
-
lineWire(0, 0,
|
|
1042
|
-
`<
|
|
1043
|
-
`<
|
|
1044
|
-
|
|
776
|
+
lineWire(0, 0, 10, 0),
|
|
777
|
+
`<line x1="10" y1="0" x2="30" y2="-10" ${BODY}/>`,
|
|
778
|
+
`<circle cx="10" cy="0" r="2" ${FILL}/>`,
|
|
779
|
+
`<circle cx="30" cy="0" r="2" ${FILL}/>`,
|
|
780
|
+
// Small dashed bar above to denote actuator-driven (vs hand switch)
|
|
781
|
+
`<line x1="14" y1="-14" x2="26" y2="-14" stroke-dasharray="2,2" ${BODY}/>`,
|
|
782
|
+
lineWire(30, 0, 40, 0)
|
|
1045
783
|
].join("")
|
|
1046
784
|
};
|
|
1047
|
-
var
|
|
785
|
+
var relay_nc = {
|
|
1048
786
|
length: 40,
|
|
1049
787
|
anchors: { start: { x: 0, y: 0 }, end: { x: 40, y: 0 } },
|
|
1050
788
|
svg: () => [
|
|
1051
|
-
lineWire(0, 0,
|
|
1052
|
-
`<
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
}
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
anchors: { start: { x: 0, y: 0 }, end: { x: 50, y: 0 } },
|
|
1060
|
-
svg: () => [
|
|
1061
|
-
`<path d="M 0,0 L 10,0 L 13,-8 L 18,8 L 23,-8 L 28,8 L 33,-8 L 38,8 L 40,0 L 50,0" ${BODY}/>`,
|
|
1062
|
-
`<line x1="5" y1="12" x2="45" y2="-12" ${BODY}/>`,
|
|
1063
|
-
`<polygon points="45,-12 40,-9 44,-5" ${FILL}/>`
|
|
1064
|
-
].join("")
|
|
1065
|
-
};
|
|
1066
|
-
var thermistor_ntc = {
|
|
1067
|
-
length: 50,
|
|
1068
|
-
anchors: { start: { x: 0, y: 0 }, end: { x: 50, y: 0 } },
|
|
1069
|
-
svg: () => [
|
|
1070
|
-
`<path d="M 0,0 L 10,0 L 13,-8 L 18,8 L 23,-8 L 28,8 L 33,-8 L 38,8 L 40,0 L 50,0" ${BODY}/>`,
|
|
1071
|
-
`<line x1="5" y1="10" x2="45" y2="-10" ${BODY}/>`,
|
|
1072
|
-
`<text x="40" y="-14" class="schematex-circuit-pol">-t\xB0</text>`
|
|
789
|
+
lineWire(0, 0, 10, 0),
|
|
790
|
+
`<line x1="10" y1="-10" x2="30" y2="-10" ${BODY}/>`,
|
|
791
|
+
// NC slash: line crosses both contact endpoints (closed by default)
|
|
792
|
+
`<line x1="8" y1="2" x2="32" y2="-12" ${BODY}/>`,
|
|
793
|
+
`<circle cx="10" cy="0" r="2" ${FILL}/>`,
|
|
794
|
+
`<circle cx="30" cy="0" r="2" ${FILL}/>`,
|
|
795
|
+
`<line x1="14" y1="-14" x2="26" y2="-14" stroke-dasharray="2,2" ${BODY}/>`,
|
|
796
|
+
lineWire(30, 0, 40, 0)
|
|
1073
797
|
].join("")
|
|
1074
798
|
};
|
|
1075
|
-
var
|
|
1076
|
-
length:
|
|
1077
|
-
anchors: { start: { x: 0, y: 0 }, end: { x:
|
|
799
|
+
var contactor = {
|
|
800
|
+
length: 44,
|
|
801
|
+
anchors: { start: { x: 0, y: 0 }, end: { x: 44, y: 0 } },
|
|
1078
802
|
svg: () => [
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
`<
|
|
803
|
+
lineWire(0, 0, 10, 0),
|
|
804
|
+
// Two parallel diagonal contacts = double-break (typical of contactors)
|
|
805
|
+
`<line x1="10" y1="0" x2="30" y2="-10" stroke-width="2.5" ${BODY}/>`,
|
|
806
|
+
`<line x1="14" y1="2" x2="34" y2="-8" stroke-width="2.5" ${BODY}/>`,
|
|
807
|
+
`<circle cx="10" cy="0" r="2" ${FILL}/>`,
|
|
808
|
+
`<circle cx="34" cy="0" r="2" ${FILL}/>`,
|
|
809
|
+
// Solid bar above = electromagnetic-driven actuator
|
|
810
|
+
`<line x1="14" y1="-14" x2="30" y2="-14" stroke-width="2" ${BODY}/>`,
|
|
811
|
+
lineWire(34, 0, 44, 0)
|
|
1082
812
|
].join("")
|
|
1083
813
|
};
|
|
1084
|
-
var
|
|
814
|
+
var solenoid_valve = {
|
|
1085
815
|
length: 50,
|
|
1086
816
|
anchors: { start: { x: 0, y: 0 }, end: { x: 50, y: 0 } },
|
|
1087
817
|
svg: () => [
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
`<
|
|
1091
|
-
`<
|
|
1092
|
-
|
|
1093
|
-
}
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
lineWire(0, 0, 10, 0),
|
|
1099
|
-
`<line x1="10" y1="-10" x2="10" y2="10" ${BODY}/>`,
|
|
1100
|
-
`<line x1="14" y1="-10" x2="14" y2="10" ${BODY}/>`,
|
|
1101
|
-
lineWire(14, 0, 24, 0),
|
|
1102
|
-
`<line x1="3" y1="10" x2="21" y2="-12" ${BODY}/>`,
|
|
1103
|
-
`<polygon points="21,-12 15,-10 19,-6" ${FILL}/>`
|
|
818
|
+
lineWire(0, 0, 8, 0),
|
|
819
|
+
// Solenoid box on top
|
|
820
|
+
`<rect x="8" y="-22" width="14" height="12" fill="white" ${BODY}/>`,
|
|
821
|
+
`<line x1="8" y1="-22" x2="22" y2="-10" ${BODY}/>`,
|
|
822
|
+
// Valve body (triangle pair = IEC valve symbol)
|
|
823
|
+
`<polygon points="22,0 38,-8 38,8" fill="white" ${BODY}/>`,
|
|
824
|
+
`<polygon points="22,0 8,-8 8,8" fill="white" ${BODY}/>`,
|
|
825
|
+
// Connect solenoid to valve body (actuator line)
|
|
826
|
+
`<line x1="15" y1="-10" x2="22" y2="0" ${BODY}/>`,
|
|
827
|
+
lineWire(38, 0, 50, 0)
|
|
1104
828
|
].join("")
|
|
1105
829
|
};
|
|
1106
|
-
var
|
|
830
|
+
var thermal_overload = {
|
|
1107
831
|
length: 40,
|
|
1108
832
|
anchors: { start: { x: 0, y: 0 }, end: { x: 40, y: 0 } },
|
|
1109
833
|
svg: () => [
|
|
1110
|
-
|
|
1111
|
-
`<
|
|
1112
|
-
|
|
834
|
+
lineWire(0, 0, 8, 0),
|
|
835
|
+
`<rect x="8" y="-12" width="24" height="24" fill="white" ${BODY}/>`,
|
|
836
|
+
// Bimetal element: bent line inside box
|
|
837
|
+
`<path d="M 12,-6 L 16,4 L 20,-6 L 24,4 L 28,-6" fill="none" ${BODY}/>`,
|
|
838
|
+
lineWire(32, 0, 40, 0)
|
|
1113
839
|
].join("")
|
|
1114
840
|
};
|
|
1115
|
-
var
|
|
1116
|
-
length:
|
|
1117
|
-
anchors: {
|
|
1118
|
-
start: { x: 0, y: 0 },
|
|
1119
|
-
end: { x: 50, y: 0 },
|
|
1120
|
-
common: { x: 0, y: 0 },
|
|
1121
|
-
nc: { x: 50, y: -12 },
|
|
1122
|
-
no: { x: 50, y: 12 }
|
|
1123
|
-
},
|
|
841
|
+
var disconnect_switch = {
|
|
842
|
+
length: 48,
|
|
843
|
+
anchors: { start: { x: 0, y: 0 }, end: { x: 48, y: 0 } },
|
|
1124
844
|
svg: () => [
|
|
1125
845
|
lineWire(0, 0, 10, 0),
|
|
846
|
+
`<line x1="10" y1="0" x2="34" y2="-12" ${BODY}/>`,
|
|
1126
847
|
`<circle cx="10" cy="0" r="2" ${FILL}/>`,
|
|
1127
|
-
|
|
1128
|
-
`<
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
lineWire(42, 12, 50, 12)
|
|
848
|
+
// Hollow square at top of arm = visible-isolation indicator
|
|
849
|
+
`<rect x="30" y="-16" width="8" height="8" fill="white" ${BODY}/>`,
|
|
850
|
+
`<circle cx="38" cy="0" r="2" ${FILL}/>`,
|
|
851
|
+
lineWire(38, 0, 48, 0)
|
|
1132
852
|
].join("")
|
|
1133
853
|
};
|
|
1134
|
-
var
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
854
|
+
var SYMBOLS = {
|
|
855
|
+
resistor,
|
|
856
|
+
capacitor,
|
|
857
|
+
electrolytic_cap,
|
|
858
|
+
inductor,
|
|
859
|
+
fuse,
|
|
860
|
+
crystal,
|
|
861
|
+
transformer,
|
|
862
|
+
voltage_source,
|
|
863
|
+
current_source,
|
|
864
|
+
ac_source,
|
|
865
|
+
battery,
|
|
866
|
+
ground,
|
|
867
|
+
gnd_signal,
|
|
868
|
+
vcc,
|
|
869
|
+
diode,
|
|
870
|
+
zener,
|
|
871
|
+
schottky,
|
|
872
|
+
led,
|
|
873
|
+
photodiode,
|
|
874
|
+
npn,
|
|
875
|
+
pnp,
|
|
876
|
+
nmos,
|
|
877
|
+
pmos,
|
|
878
|
+
jfet_n,
|
|
879
|
+
jfet_p,
|
|
880
|
+
opamp,
|
|
881
|
+
comparator,
|
|
882
|
+
switch_spst,
|
|
883
|
+
push_no,
|
|
884
|
+
ammeter,
|
|
885
|
+
voltmeter,
|
|
886
|
+
wattmeter,
|
|
887
|
+
motor,
|
|
888
|
+
speaker,
|
|
889
|
+
microphone,
|
|
890
|
+
buzzer,
|
|
891
|
+
potentiometer,
|
|
892
|
+
rheostat,
|
|
893
|
+
thermistor_ntc,
|
|
894
|
+
thermistor_ptc,
|
|
895
|
+
ldr,
|
|
896
|
+
variable_cap,
|
|
897
|
+
variable_inductor,
|
|
898
|
+
switch_spdt,
|
|
899
|
+
push_nc,
|
|
900
|
+
gnd_chassis,
|
|
901
|
+
gnd_digital,
|
|
902
|
+
test_point,
|
|
903
|
+
no_connect,
|
|
904
|
+
antenna,
|
|
905
|
+
generic_ic,
|
|
906
|
+
terminal_block,
|
|
907
|
+
"555_timer": timer_555,
|
|
908
|
+
voltage_regulator,
|
|
909
|
+
// Industrial control / power electrical (IEC 60617)
|
|
910
|
+
relay_coil,
|
|
911
|
+
relay_no,
|
|
912
|
+
relay_nc,
|
|
913
|
+
contactor,
|
|
914
|
+
solenoid_valve,
|
|
915
|
+
thermal_overload,
|
|
916
|
+
disconnect_switch
|
|
917
|
+
// Lamp reuses buzzer slot? No, needs its own entry but our CircuitComponentType
|
|
918
|
+
// doesn't have "lamp". We map it via parser alias to "buzzer" or add specifically.
|
|
1146
919
|
};
|
|
1147
|
-
var
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
920
|
+
var EXTRA_SYMBOLS = {
|
|
921
|
+
lamp
|
|
922
|
+
};
|
|
923
|
+
function getSymbol(t) {
|
|
924
|
+
return SYMBOLS[t] ?? EXTRA_SYMBOLS[t];
|
|
925
|
+
}
|
|
926
|
+
function getNetlistPinOrder(t) {
|
|
927
|
+
const sym = getSymbol(t);
|
|
928
|
+
if (!sym) return void 0;
|
|
929
|
+
if (sym.netlistPins) return [...sym.netlistPins];
|
|
930
|
+
if (sym.anchors.start && sym.anchors.end) return ["start", "end"];
|
|
931
|
+
return Object.keys(sym.anchors);
|
|
932
|
+
}
|
|
933
|
+
|
|
934
|
+
// src/diagrams/circuit/netlist.ts
|
|
935
|
+
var NetlistParseError = class extends Error {
|
|
936
|
+
constructor(message, line) {
|
|
937
|
+
super(message);
|
|
938
|
+
this.line = line;
|
|
939
|
+
this.name = "NetlistParseError";
|
|
940
|
+
}
|
|
941
|
+
line;
|
|
1157
942
|
};
|
|
1158
|
-
var
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
943
|
+
var PREFIX_MAP = {
|
|
944
|
+
R: { type: "resistor", pins: ["start", "end"] },
|
|
945
|
+
C: { type: "capacitor", pins: ["start", "end"] },
|
|
946
|
+
L: { type: "inductor", pins: ["start", "end"] },
|
|
947
|
+
D: { type: "diode", pins: ["start", "end"] },
|
|
948
|
+
// anode → start, cathode → end
|
|
949
|
+
V: { type: "voltage_source", pins: ["plus", "minus"] },
|
|
950
|
+
I: { type: "current_source", pins: ["plus", "minus"] },
|
|
951
|
+
Q: { type: "npn", pins: ["c", "b", "e"] },
|
|
952
|
+
M: { type: "nmos", pins: ["d", "g", "s"] },
|
|
953
|
+
J: { type: "jfet_n", pins: ["d", "g", "s"] },
|
|
954
|
+
S: { type: "switch_spst", pins: ["start", "end"] },
|
|
955
|
+
F: { type: "fuse", pins: ["start", "end"] },
|
|
956
|
+
B: { type: "battery", pins: ["plus", "minus"] },
|
|
957
|
+
K: { type: "relay_coil", pins: ["start", "end"] },
|
|
958
|
+
U: { type: "generic_ic", pins: [] },
|
|
959
|
+
// pins declared via pins="..." attr
|
|
960
|
+
X: { type: "generic_ic", pins: [] },
|
|
961
|
+
W: { type: "wire", pins: ["start", "end"] },
|
|
962
|
+
// explicit wire (non-SPICE convention, common in EE textbooks)
|
|
963
|
+
T: { type: "terminal_block", pins: [] }
|
|
964
|
+
// pins via pins="..."
|
|
1165
965
|
};
|
|
1166
|
-
var
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
966
|
+
var TYPE_ALIASES = {
|
|
967
|
+
vsource: "voltage_source",
|
|
968
|
+
isource: "current_source",
|
|
969
|
+
acsource: "ac_source",
|
|
970
|
+
ecap: "electrolytic_cap",
|
|
971
|
+
pot: "potentiometer",
|
|
972
|
+
gnd: "ground",
|
|
973
|
+
ic: "generic_ic",
|
|
974
|
+
reg: "voltage_regulator",
|
|
975
|
+
timer555: "555_timer",
|
|
976
|
+
transistor: "npn",
|
|
977
|
+
tb: "terminal_block",
|
|
978
|
+
junction_box: "terminal_block",
|
|
979
|
+
jbox: "terminal_block",
|
|
980
|
+
enclosure: "terminal_block"
|
|
1173
981
|
};
|
|
1174
|
-
var
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
|
|
982
|
+
var GROUND_REF = /^(0|gnd|ground|earth|pe|agnd|dgnd|gnda|gndd|vss|com)(_\w+|\d+)?$/i;
|
|
983
|
+
function isGroundRef(s) {
|
|
984
|
+
return GROUND_REF.test(s);
|
|
985
|
+
}
|
|
986
|
+
function tokenize(line) {
|
|
987
|
+
const tokens = [];
|
|
988
|
+
let i = 0;
|
|
989
|
+
while (i < line.length) {
|
|
990
|
+
const ch = line[i];
|
|
991
|
+
if (ch === " " || ch === " ") {
|
|
992
|
+
i++;
|
|
993
|
+
continue;
|
|
994
|
+
}
|
|
995
|
+
if (ch === '"') {
|
|
996
|
+
const end = line.indexOf('"', i + 1);
|
|
997
|
+
tokens.push(line.slice(i, end < 0 ? line.length : end + 1));
|
|
998
|
+
i = end < 0 ? line.length : end + 1;
|
|
999
|
+
continue;
|
|
1000
|
+
}
|
|
1001
|
+
let j = i;
|
|
1002
|
+
while (j < line.length && line[j] !== " " && line[j] !== " ") {
|
|
1003
|
+
if (line[j] === "=" && line[j + 1] === '"') {
|
|
1004
|
+
const end = line.indexOf('"', j + 2);
|
|
1005
|
+
j = end < 0 ? line.length : end + 1;
|
|
1006
|
+
break;
|
|
1007
|
+
}
|
|
1008
|
+
j++;
|
|
1009
|
+
}
|
|
1010
|
+
tokens.push(line.slice(i, j));
|
|
1011
|
+
i = j;
|
|
1012
|
+
}
|
|
1013
|
+
return tokens;
|
|
1014
|
+
}
|
|
1015
|
+
function isKeyEqVal(tok) {
|
|
1016
|
+
const eq = tok.indexOf("=");
|
|
1017
|
+
return eq > 0 && /^[a-zA-Z_][\w]*$/.test(tok.slice(0, eq));
|
|
1018
|
+
}
|
|
1019
|
+
function parseKV(tok) {
|
|
1020
|
+
const eq = tok.indexOf("=");
|
|
1021
|
+
const key = tok.slice(0, eq).trim();
|
|
1022
|
+
let val = tok.slice(eq + 1).trim();
|
|
1023
|
+
if (val.startsWith('"') && val.endsWith('"')) val = val.slice(1, -1);
|
|
1024
|
+
return [key, val];
|
|
1025
|
+
}
|
|
1026
|
+
function parseNetlist(body, title2) {
|
|
1027
|
+
const components = [];
|
|
1028
|
+
const netByName = /* @__PURE__ */ new Map();
|
|
1029
|
+
const pinMap = {};
|
|
1030
|
+
let autoGnd = 0;
|
|
1031
|
+
const ensureNet = (name) => {
|
|
1032
|
+
let n = netByName.get(name);
|
|
1033
|
+
if (!n) {
|
|
1034
|
+
n = { id: name, anchors: [] };
|
|
1035
|
+
netByName.set(name, n);
|
|
1036
|
+
}
|
|
1037
|
+
return n;
|
|
1038
|
+
};
|
|
1039
|
+
const lines = body.split("\n").map((l) => l.replace(/\r$/, ""));
|
|
1040
|
+
for (let lineIdx = 0; lineIdx < lines.length; lineIdx++) {
|
|
1041
|
+
const raw = lines[lineIdx];
|
|
1042
|
+
const stripped = raw.replace(/#.*$/, "").trim();
|
|
1043
|
+
if (!stripped) continue;
|
|
1044
|
+
const tokens = tokenize(stripped);
|
|
1045
|
+
if (tokens.length < 2) {
|
|
1046
|
+
throw new NetlistParseError(
|
|
1047
|
+
`Netlist line must have at least ID + one net: "${stripped}"`,
|
|
1048
|
+
lineIdx + 1
|
|
1049
|
+
);
|
|
1050
|
+
}
|
|
1051
|
+
const id = tokens[0];
|
|
1052
|
+
if (!/^[a-zA-Z_][\w]*$/.test(id)) {
|
|
1053
|
+
throw new NetlistParseError(`Invalid component id: "${id}"`, lineIdx + 1);
|
|
1054
|
+
}
|
|
1055
|
+
let cursor = 1;
|
|
1056
|
+
const netRefs = [];
|
|
1057
|
+
while (cursor < tokens.length && !isKeyEqVal(tokens[cursor])) {
|
|
1058
|
+
netRefs.push(tokens[cursor]);
|
|
1059
|
+
cursor++;
|
|
1060
|
+
}
|
|
1061
|
+
const kv = {};
|
|
1062
|
+
for (; cursor < tokens.length; cursor++) {
|
|
1063
|
+
if (!isKeyEqVal(tokens[cursor])) {
|
|
1064
|
+
throw new NetlistParseError(
|
|
1065
|
+
`Expected key=value after nets, got "${tokens[cursor]}"`,
|
|
1066
|
+
lineIdx + 1
|
|
1067
|
+
);
|
|
1068
|
+
}
|
|
1069
|
+
const [k, v] = parseKV(tokens[cursor]);
|
|
1070
|
+
kv[k] = v;
|
|
1071
|
+
}
|
|
1072
|
+
const prefix = id[0].toUpperCase();
|
|
1073
|
+
const defaults = PREFIX_MAP[prefix];
|
|
1074
|
+
let cType;
|
|
1075
|
+
let pinOrder;
|
|
1076
|
+
if (kv.type) {
|
|
1077
|
+
const t = kv.type.toLowerCase();
|
|
1078
|
+
cType = TYPE_ALIASES[t] ?? t;
|
|
1079
|
+
pinOrder = getNetlistPinOrder(cType) ?? defaults?.pins ?? ["start", "end"];
|
|
1080
|
+
} else if (defaults) {
|
|
1081
|
+
cType = defaults.type;
|
|
1082
|
+
pinOrder = defaults.pins;
|
|
1083
|
+
} else if (isGroundRef(id)) {
|
|
1084
|
+
cType = "ground";
|
|
1085
|
+
pinOrder = ["start"];
|
|
1086
|
+
} else {
|
|
1087
|
+
throw new NetlistParseError(
|
|
1088
|
+
`Cannot infer type from id "${id}". Either rename to a SPICE-prefix id (R*, C*, L*, D*, V*, I*, Q*, M*, J*, S*, F*, B*, K*, U*, X*, W*, T*) or pass an explicit \`type=<name>\` attribute (e.g. \`${id} ... type=resistor\`). Schematex circuit covers electrical schematics only \u2014 hydraulic/pneumatic prefixes (EV*, BOMBA*, TANK*, etc.) are not supported.`,
|
|
1089
|
+
lineIdx + 1
|
|
1090
|
+
);
|
|
1091
|
+
}
|
|
1092
|
+
const expectedPins = pinOrder.length;
|
|
1093
|
+
let valueFromTail;
|
|
1094
|
+
if (netRefs.length > expectedPins && expectedPins > 0) {
|
|
1095
|
+
const tail = netRefs.slice(expectedPins);
|
|
1096
|
+
netRefs.length = expectedPins;
|
|
1097
|
+
const first = tail[0].toLowerCase();
|
|
1098
|
+
if (TYPE_ALIASES[first]) {
|
|
1099
|
+
cType = TYPE_ALIASES[first];
|
|
1100
|
+
pinOrder = getNetlistPinOrder(cType) ?? pinOrder;
|
|
1101
|
+
} else if (first === "npn" || first === "pnp" || first === "nmos" || first === "pmos" || first === "jfet_n" || first === "jfet_p" || first === "zener" || first === "schottky" || first === "led" || first === "photodiode") {
|
|
1102
|
+
cType = first;
|
|
1103
|
+
pinOrder = getNetlistPinOrder(cType) ?? pinOrder;
|
|
1104
|
+
} else {
|
|
1105
|
+
valueFromTail = tail.join(" ");
|
|
1106
|
+
}
|
|
1107
|
+
if (tail.length > 1 && !valueFromTail) {
|
|
1108
|
+
valueFromTail = tail.slice(1).join(" ");
|
|
1109
|
+
}
|
|
1110
|
+
}
|
|
1111
|
+
if (cType === "ground" || cType === "gnd_signal" || cType === "gnd_chassis" || cType === "gnd_digital") {
|
|
1112
|
+
pinOrder = ["start"];
|
|
1113
|
+
}
|
|
1114
|
+
if (cType === "terminal_block") {
|
|
1115
|
+
const pinsAttr = kv.pins ?? kv.terminals;
|
|
1116
|
+
const labels = pinsAttr ? pinsAttr.split(",").map((s) => s.trim()).filter(Boolean) : Array.from({ length: Math.max(netRefs.length, 1) }, (_, i) => `t${i + 1}`);
|
|
1117
|
+
pinOrder = labels.map(
|
|
1118
|
+
(label, idx) => label.toLowerCase().replace(/[^a-z0-9]+/g, "_") || `t${idx + 1}`
|
|
1119
|
+
);
|
|
1120
|
+
}
|
|
1121
|
+
if (netRefs.length < pinOrder.length) {
|
|
1122
|
+
throw new NetlistParseError(
|
|
1123
|
+
`Component ${id} (${cType}) expects ${pinOrder.length} nets, got ${netRefs.length}`,
|
|
1124
|
+
lineIdx + 1
|
|
1125
|
+
);
|
|
1126
|
+
}
|
|
1127
|
+
const pins = {};
|
|
1128
|
+
for (let p = 0; p < pinOrder.length; p++) {
|
|
1129
|
+
let net = netRefs[p];
|
|
1130
|
+
if (isGroundRef(net)) net = "GND";
|
|
1131
|
+
pins[pinOrder[p]] = net;
|
|
1132
|
+
ensureNet(net).anchors.push(`${id}.${pinOrder[p]}`);
|
|
1133
|
+
}
|
|
1134
|
+
pinMap[id] = pins;
|
|
1135
|
+
const comp = {
|
|
1136
|
+
id,
|
|
1137
|
+
componentType: cType,
|
|
1138
|
+
direction: "right",
|
|
1139
|
+
label: kv.label ?? id,
|
|
1140
|
+
value: kv.value ?? valueFromTail,
|
|
1141
|
+
attrs: {}
|
|
1142
|
+
};
|
|
1143
|
+
for (const [k, v] of Object.entries(kv)) {
|
|
1144
|
+
if (k === "label" || k === "value" || k === "type") continue;
|
|
1145
|
+
comp.attrs[k] = v;
|
|
1146
|
+
}
|
|
1147
|
+
components.push(comp);
|
|
1148
|
+
}
|
|
1149
|
+
if (netByName.has("GND")) {
|
|
1150
|
+
const hasGroundSym = components.some(
|
|
1151
|
+
(c) => c.componentType === "ground" || c.componentType === "gnd_signal" || c.componentType === "gnd_chassis" || c.componentType === "gnd_digital"
|
|
1152
|
+
);
|
|
1153
|
+
if (!hasGroundSym) {
|
|
1154
|
+
const gId = `_GND${autoGnd++}`;
|
|
1155
|
+
components.push({
|
|
1156
|
+
id: gId,
|
|
1157
|
+
componentType: "ground",
|
|
1158
|
+
direction: "down",
|
|
1159
|
+
label: void 0,
|
|
1160
|
+
value: void 0,
|
|
1161
|
+
attrs: { auto: "true" }
|
|
1162
|
+
});
|
|
1163
|
+
pinMap[gId] = { start: "GND" };
|
|
1164
|
+
ensureNet("GND").anchors.push(`${gId}.start`);
|
|
1165
|
+
}
|
|
1166
|
+
}
|
|
1167
|
+
const nets = Array.from(netByName.values());
|
|
1168
|
+
return {
|
|
1169
|
+
type: "circuit",
|
|
1170
|
+
title: title2,
|
|
1171
|
+
components,
|
|
1172
|
+
nets,
|
|
1173
|
+
pinMap,
|
|
1174
|
+
mode: "netlist"
|
|
1175
|
+
};
|
|
1176
|
+
}
|
|
1177
|
+
|
|
1178
|
+
// src/diagrams/circuit/parser.ts
|
|
1179
|
+
var CircuitParseError = class extends Error {
|
|
1180
|
+
constructor(message) {
|
|
1181
|
+
super(message);
|
|
1182
|
+
this.name = "CircuitParseError";
|
|
1183
|
+
}
|
|
1181
1184
|
};
|
|
1182
|
-
var
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
1185
|
+
var COMPONENT_TYPES = /* @__PURE__ */ new Set([
|
|
1186
|
+
"resistor",
|
|
1187
|
+
"potentiometer",
|
|
1188
|
+
"rheostat",
|
|
1189
|
+
"thermistor_ntc",
|
|
1190
|
+
"thermistor_ptc",
|
|
1191
|
+
"ldr",
|
|
1192
|
+
"varistor",
|
|
1193
|
+
"fuse",
|
|
1194
|
+
"fuse_slow",
|
|
1195
|
+
"capacitor",
|
|
1196
|
+
"electrolytic_cap",
|
|
1197
|
+
"variable_cap",
|
|
1198
|
+
"inductor",
|
|
1199
|
+
"inductor_iron",
|
|
1200
|
+
"inductor_ferrite",
|
|
1201
|
+
"variable_inductor",
|
|
1202
|
+
"ferrite_bead",
|
|
1203
|
+
"crystal",
|
|
1204
|
+
"transformer",
|
|
1205
|
+
"diode",
|
|
1206
|
+
"zener",
|
|
1207
|
+
"schottky",
|
|
1208
|
+
"led",
|
|
1209
|
+
"photodiode",
|
|
1210
|
+
"varactor",
|
|
1211
|
+
"tvs_diode",
|
|
1212
|
+
"bridge_rectifier",
|
|
1213
|
+
"npn",
|
|
1214
|
+
"pnp",
|
|
1215
|
+
"darlington_npn",
|
|
1216
|
+
"darlington_pnp",
|
|
1217
|
+
"nmos",
|
|
1218
|
+
"pmos",
|
|
1219
|
+
"nmos_depletion",
|
|
1220
|
+
"jfet_n",
|
|
1221
|
+
"jfet_p",
|
|
1222
|
+
"igbt",
|
|
1223
|
+
"scr",
|
|
1224
|
+
"triac",
|
|
1225
|
+
"diac",
|
|
1226
|
+
"phototransistor",
|
|
1227
|
+
"optocoupler",
|
|
1228
|
+
"opamp",
|
|
1229
|
+
"comparator",
|
|
1230
|
+
"schmitt_buffer",
|
|
1231
|
+
"tri_state_buffer",
|
|
1232
|
+
"instrumentation_amp",
|
|
1233
|
+
"generic_ic",
|
|
1234
|
+
"voltage_regulator",
|
|
1235
|
+
"dc_dc_converter",
|
|
1236
|
+
"555_timer",
|
|
1237
|
+
"voltage_source",
|
|
1238
|
+
"current_source",
|
|
1239
|
+
"ac_source",
|
|
1240
|
+
"battery",
|
|
1241
|
+
"vcc",
|
|
1242
|
+
"ground",
|
|
1243
|
+
"gnd_signal",
|
|
1244
|
+
"gnd_chassis",
|
|
1245
|
+
"gnd_digital",
|
|
1246
|
+
"switch_spst",
|
|
1247
|
+
"switch_spdt",
|
|
1248
|
+
"switch_dpdt",
|
|
1249
|
+
"push_no",
|
|
1250
|
+
"push_nc",
|
|
1251
|
+
"relay_coil",
|
|
1252
|
+
"relay_no",
|
|
1253
|
+
"relay_nc",
|
|
1254
|
+
"contactor",
|
|
1255
|
+
"solenoid_valve",
|
|
1256
|
+
"thermal_overload",
|
|
1257
|
+
"disconnect_switch",
|
|
1258
|
+
"motor",
|
|
1259
|
+
"speaker",
|
|
1260
|
+
"microphone",
|
|
1261
|
+
"buzzer",
|
|
1262
|
+
"ammeter",
|
|
1263
|
+
"voltmeter",
|
|
1264
|
+
"wattmeter",
|
|
1265
|
+
"oscilloscope",
|
|
1266
|
+
"wire",
|
|
1267
|
+
"dot",
|
|
1268
|
+
"label",
|
|
1269
|
+
"port",
|
|
1270
|
+
"test_point",
|
|
1271
|
+
"no_connect",
|
|
1272
|
+
"antenna"
|
|
1273
|
+
]);
|
|
1274
|
+
var ALIASES = {
|
|
1275
|
+
vsource: "voltage_source",
|
|
1276
|
+
isource: "current_source",
|
|
1277
|
+
acsource: "ac_source",
|
|
1278
|
+
ecap: "electrolytic_cap",
|
|
1279
|
+
pot: "potentiometer",
|
|
1280
|
+
xtal: "crystal",
|
|
1281
|
+
xfmr: "transformer",
|
|
1282
|
+
transistor: "npn",
|
|
1283
|
+
bjt_npn: "npn",
|
|
1284
|
+
bjt_pnp: "pnp",
|
|
1285
|
+
mosfet_n: "nmos",
|
|
1286
|
+
mosfet_p: "pmos",
|
|
1287
|
+
gnd: "ground",
|
|
1288
|
+
ic: "generic_ic",
|
|
1289
|
+
reg: "voltage_regulator",
|
|
1290
|
+
timer555: "555_timer",
|
|
1291
|
+
therm: "thermistor_ntc",
|
|
1292
|
+
ntc: "thermistor_ntc",
|
|
1293
|
+
ptc: "thermistor_ptc",
|
|
1294
|
+
ths: "thermistor_ntc",
|
|
1295
|
+
// Industrial control aliases (IEC letter codes)
|
|
1296
|
+
coil: "relay_coil",
|
|
1297
|
+
relay: "relay_coil",
|
|
1298
|
+
km: "contactor",
|
|
1299
|
+
solenoid: "solenoid_valve",
|
|
1300
|
+
ev: "solenoid_valve",
|
|
1301
|
+
overload: "thermal_overload",
|
|
1302
|
+
thermal: "thermal_overload",
|
|
1303
|
+
disconnect: "disconnect_switch",
|
|
1304
|
+
isolator: "disconnect_switch"
|
|
1190
1305
|
};
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
|
|
1306
|
+
var EXTRA_TYPES = /* @__PURE__ */ new Set(["lamp"]);
|
|
1307
|
+
function normalizeType(raw) {
|
|
1308
|
+
const lower = raw.toLowerCase();
|
|
1309
|
+
if (ALIASES[lower]) return ALIASES[lower];
|
|
1310
|
+
if (COMPONENT_TYPES.has(lower)) {
|
|
1311
|
+
return lower;
|
|
1312
|
+
}
|
|
1313
|
+
if (EXTRA_TYPES.has(lower)) {
|
|
1314
|
+
return lower;
|
|
1315
|
+
}
|
|
1316
|
+
return null;
|
|
1317
|
+
}
|
|
1318
|
+
var DIRECTIONS = /* @__PURE__ */ new Set(["right", "left", "up", "down"]);
|
|
1319
|
+
function parseAttrs(rest) {
|
|
1320
|
+
const out = { attrs: {} };
|
|
1321
|
+
const tokens = [];
|
|
1322
|
+
let i = 0;
|
|
1323
|
+
while (i < rest.length) {
|
|
1324
|
+
const ch = rest[i];
|
|
1325
|
+
if (ch === " " || ch === " ") {
|
|
1326
|
+
i++;
|
|
1327
|
+
continue;
|
|
1328
|
+
}
|
|
1329
|
+
if (ch === '"') {
|
|
1330
|
+
const end = rest.indexOf('"', i + 1);
|
|
1331
|
+
const tok = rest.slice(i, end < 0 ? rest.length : end + 1);
|
|
1332
|
+
tokens.push(tok);
|
|
1333
|
+
i = end < 0 ? rest.length : end + 1;
|
|
1334
|
+
continue;
|
|
1335
|
+
}
|
|
1336
|
+
let j = i;
|
|
1337
|
+
while (j < rest.length && rest[j] !== " " && rest[j] !== " ") {
|
|
1338
|
+
if (rest[j] === "=" && rest[j + 1] === '"') {
|
|
1339
|
+
const end = rest.indexOf('"', j + 2);
|
|
1340
|
+
j = end < 0 ? rest.length : end + 1;
|
|
1341
|
+
break;
|
|
1211
1342
|
}
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1343
|
+
j++;
|
|
1344
|
+
}
|
|
1345
|
+
tokens.push(rest.slice(i, j));
|
|
1346
|
+
i = j;
|
|
1347
|
+
}
|
|
1348
|
+
for (const tok of tokens) {
|
|
1349
|
+
if (!tok) continue;
|
|
1350
|
+
if (DIRECTIONS.has(tok.toLowerCase())) {
|
|
1351
|
+
out.direction = tok.toLowerCase();
|
|
1352
|
+
continue;
|
|
1353
|
+
}
|
|
1354
|
+
const eq = tok.indexOf("=");
|
|
1355
|
+
if (eq > 0) {
|
|
1356
|
+
const key = tok.slice(0, eq).trim();
|
|
1357
|
+
let val = tok.slice(eq + 1).trim();
|
|
1358
|
+
if (val.startsWith('"') && val.endsWith('"')) {
|
|
1359
|
+
val = val.slice(1, -1);
|
|
1360
|
+
}
|
|
1361
|
+
if (key === "label") out.label = val;
|
|
1362
|
+
else if (key === "value") out.value = val;
|
|
1363
|
+
else if (key === "at") out.at = val;
|
|
1364
|
+
else if (key === "length") out.length = val;
|
|
1365
|
+
else out.attrs[key] = val;
|
|
1366
|
+
continue;
|
|
1367
|
+
}
|
|
1368
|
+
out.attrs[tok] = "true";
|
|
1369
|
+
}
|
|
1370
|
+
return out;
|
|
1371
|
+
}
|
|
1372
|
+
function parseCircuit(text2) {
|
|
1373
|
+
const rawLines = text2.split("\n");
|
|
1374
|
+
const firstMeaningful = rawLines.map((l) => l.replace(/#.*$/, "").trim()).find((l) => l.length > 0) ?? "";
|
|
1375
|
+
if (/^circuit\b.*\bnetlist\s*$/i.test(firstMeaningful)) {
|
|
1376
|
+
const netlistTitle = chunkNAGUZFXX_cjs.matchQuotedTitle(firstMeaningful);
|
|
1377
|
+
let headerIdx = -1;
|
|
1378
|
+
for (let i = 0; i < rawLines.length; i++) {
|
|
1379
|
+
const s = rawLines[i].replace(/#.*$/, "").trim();
|
|
1380
|
+
if (s.length > 0) {
|
|
1381
|
+
headerIdx = i;
|
|
1382
|
+
break;
|
|
1383
|
+
}
|
|
1384
|
+
}
|
|
1385
|
+
const body = rawLines.slice(headerIdx + 1).join("\n");
|
|
1386
|
+
return parseNetlist(body, netlistTitle);
|
|
1387
|
+
}
|
|
1388
|
+
const lines = text2.split("\n").map((l) => l.replace(/\r$/, ""));
|
|
1389
|
+
let title2;
|
|
1390
|
+
const components = [];
|
|
1391
|
+
const nets = [];
|
|
1392
|
+
const netByName = /* @__PURE__ */ new Map();
|
|
1393
|
+
let autoId = 0;
|
|
1394
|
+
let pendingAt;
|
|
1395
|
+
const mkId = (prefix) => `${prefix}_${autoId++}`;
|
|
1396
|
+
for (const rawLine of lines) {
|
|
1397
|
+
const stripped = rawLine.replace(/#.*$/, "").trim();
|
|
1398
|
+
if (!stripped) continue;
|
|
1399
|
+
if (/^circuit\b/i.test(stripped)) {
|
|
1400
|
+
const t = chunkNAGUZFXX_cjs.matchQuotedTitle(stripped);
|
|
1401
|
+
if (t !== void 0) title2 = t;
|
|
1402
|
+
continue;
|
|
1403
|
+
}
|
|
1404
|
+
const atMatch = stripped.match(/^at:\s*(.+)$/i);
|
|
1405
|
+
if (atMatch) {
|
|
1406
|
+
pendingAt = atMatch[1].trim();
|
|
1407
|
+
continue;
|
|
1408
|
+
}
|
|
1409
|
+
const netDecl = stripped.match(/^net\s+([a-zA-Z_][\w]*)\s*$/i);
|
|
1410
|
+
if (netDecl) {
|
|
1411
|
+
const name = netDecl[1];
|
|
1412
|
+
if (!netByName.has(name)) {
|
|
1413
|
+
const n = { id: name, anchors: [] };
|
|
1414
|
+
netByName.set(name, n);
|
|
1415
|
+
nets.push(n);
|
|
1216
1416
|
}
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
|
|
1417
|
+
continue;
|
|
1418
|
+
}
|
|
1419
|
+
const netDotMatch = stripped.match(/^net\s+([a-zA-Z_][\w]*)\s*:\s*dot\s*$/i);
|
|
1420
|
+
if (netDotMatch) {
|
|
1421
|
+
const name = netDotMatch[1];
|
|
1422
|
+
let n = netByName.get(name);
|
|
1423
|
+
if (!n) {
|
|
1424
|
+
n = { id: name, anchors: [] };
|
|
1425
|
+
netByName.set(name, n);
|
|
1426
|
+
nets.push(n);
|
|
1221
1427
|
}
|
|
1222
|
-
|
|
1428
|
+
const id = mkId("dot");
|
|
1429
|
+
components.push({
|
|
1430
|
+
id,
|
|
1431
|
+
componentType: "dot",
|
|
1432
|
+
direction: "right",
|
|
1433
|
+
at: pendingAt,
|
|
1434
|
+
attrs: { net: name }
|
|
1435
|
+
});
|
|
1436
|
+
n.anchors.push(`${id}.end`);
|
|
1437
|
+
pendingAt = `${id}.end`;
|
|
1438
|
+
continue;
|
|
1223
1439
|
}
|
|
1224
|
-
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
1230
|
-
)
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
const BODY_W = 80;
|
|
1236
|
-
const pitch = 16;
|
|
1237
|
-
const n = 4;
|
|
1238
|
-
const topY = -80 / 2;
|
|
1239
|
-
const anchors = {
|
|
1240
|
-
start: { x: 0, y: 0 },
|
|
1241
|
-
end: { x: BODY_W, y: 0 }
|
|
1242
|
-
};
|
|
1243
|
-
const leftNames = ["gnd", "trg", "out", "rst"];
|
|
1244
|
-
const rightNames = ["vcc", "dis", "thr", "ctl"];
|
|
1245
|
-
for (let i = 0; i < n; i++) {
|
|
1246
|
-
const y = topY + pitch * (i + 1);
|
|
1247
|
-
anchors[leftNames[i]] = { x: -8, y };
|
|
1248
|
-
anchors[rightNames[i]] = { x: BODY_W + 8, y };
|
|
1249
|
-
}
|
|
1250
|
-
return { ...sym, anchors };
|
|
1251
|
-
})();
|
|
1252
|
-
var voltage_regulator = {
|
|
1253
|
-
length: 60,
|
|
1254
|
-
anchors: {
|
|
1255
|
-
start: { x: 0, y: 0 },
|
|
1256
|
-
end: { x: 60, y: 0 },
|
|
1257
|
-
in: { x: 0, y: 0 },
|
|
1258
|
-
out: { x: 60, y: 0 },
|
|
1259
|
-
gnd: { x: 30, y: 20 }
|
|
1260
|
-
},
|
|
1261
|
-
svg: (_l, _v, attrs) => [
|
|
1262
|
-
lineWire(0, 0, 10, 0),
|
|
1263
|
-
`<rect x="10" y="-15" width="40" height="30" fill="white" ${BODY}/>`,
|
|
1264
|
-
`<text x="30" y="4" text-anchor="middle" class="schematex-circuit-meter">${attrs?.model ?? "REG"}</text>`,
|
|
1265
|
-
lineWire(50, 0, 60, 0),
|
|
1266
|
-
lineWire(30, 15, 30, 20)
|
|
1267
|
-
].join("")
|
|
1268
|
-
};
|
|
1269
|
-
var potentiometer = {
|
|
1270
|
-
length: 50,
|
|
1271
|
-
anchors: {
|
|
1272
|
-
start: { x: 0, y: 0 },
|
|
1273
|
-
end: { x: 50, y: 0 },
|
|
1274
|
-
wiper: { x: 25, y: -22 }
|
|
1275
|
-
},
|
|
1276
|
-
svg: () => [
|
|
1277
|
-
`<path d="M 0,0 L 10,0 L 13,-8 L 18,8 L 23,-8 L 28,8 L 33,-8 L 38,8 L 40,0 L 50,0" ${BODY}/>`,
|
|
1278
|
-
`<line x1="25" y1="-22" x2="25" y2="-10" ${BODY}/>`,
|
|
1279
|
-
`<polygon points="25,-10 21,-16 29,-16" ${FILL}/>`
|
|
1280
|
-
].join("")
|
|
1281
|
-
};
|
|
1282
|
-
var terminal_block = {
|
|
1283
|
-
length: 80,
|
|
1284
|
-
anchors: { start: { x: 0, y: 0 }, end: { x: 80, y: 0 } },
|
|
1285
|
-
svg: (label, _value, attrs) => {
|
|
1286
|
-
const pinsAttr = attrs?.pins ?? attrs?.terminals ?? "1,2,3,4";
|
|
1287
|
-
const pins = pinsAttr.split(",").map((s) => s.trim()).filter(Boolean);
|
|
1288
|
-
const n = Math.max(pins.length, 1);
|
|
1289
|
-
const BODY_W = 80;
|
|
1290
|
-
const pitch = 18;
|
|
1291
|
-
const bodyH = pitch * (n + 1);
|
|
1292
|
-
const topY = -bodyH / 2;
|
|
1293
|
-
const parts = [];
|
|
1294
|
-
parts.push(
|
|
1295
|
-
`<rect x="0" y="${topY}" width="${BODY_W}" height="${bodyH}" rx="3" fill="white" stroke-width="2" ${BODY}/>`
|
|
1296
|
-
);
|
|
1297
|
-
if (label) {
|
|
1298
|
-
parts.push(
|
|
1299
|
-
`<text x="${BODY_W / 2}" y="${topY + 14}" text-anchor="middle" class="schematex-circuit-meter">${label}</text>`
|
|
1300
|
-
);
|
|
1440
|
+
const labelMatch = stripped.match(/^label\s+"([^"]*)"(?:\s+(right|left|up|down))?\s*$/i);
|
|
1441
|
+
if (labelMatch) {
|
|
1442
|
+
const id = mkId("lbl");
|
|
1443
|
+
components.push({
|
|
1444
|
+
id,
|
|
1445
|
+
componentType: "label",
|
|
1446
|
+
direction: labelMatch[2]?.toLowerCase() ?? "right",
|
|
1447
|
+
at: pendingAt,
|
|
1448
|
+
label: labelMatch[1]
|
|
1449
|
+
});
|
|
1450
|
+
continue;
|
|
1301
1451
|
}
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
|
|
1452
|
+
const wireMatch = stripped.match(/^wire(?:\s+(right|left|up|down))?(?:\s+(\d+)(?:px)?)?\s*$/i);
|
|
1453
|
+
if (wireMatch) {
|
|
1454
|
+
const id = mkId("w");
|
|
1455
|
+
components.push({
|
|
1456
|
+
id,
|
|
1457
|
+
componentType: "wire",
|
|
1458
|
+
direction: wireMatch[1]?.toLowerCase() ?? "right",
|
|
1459
|
+
at: pendingAt,
|
|
1460
|
+
attrs: wireMatch[2] ? { length: wireMatch[2] } : {}
|
|
1461
|
+
});
|
|
1462
|
+
pendingAt = `${id}.end`;
|
|
1463
|
+
continue;
|
|
1464
|
+
}
|
|
1465
|
+
const bareMatch = stripped.match(/^([a-zA-Z_][\w]*)(\s+.*)?$/);
|
|
1466
|
+
const colonMatch = stripped.match(/^([a-zA-Z_][\w]*)\s*:\s*([a-zA-Z_][\w]*)(\s+.*)?$/);
|
|
1467
|
+
if (colonMatch) {
|
|
1468
|
+
const id = colonMatch[1];
|
|
1469
|
+
const typeStr = colonMatch[2];
|
|
1470
|
+
const norm = normalizeType(typeStr);
|
|
1471
|
+
if (!norm) {
|
|
1472
|
+
throw new CircuitParseError(`Unknown component type: ${typeStr}`);
|
|
1473
|
+
}
|
|
1474
|
+
const rest = colonMatch[3] ?? "";
|
|
1475
|
+
const parsed = parseAttrs(rest);
|
|
1476
|
+
const comp = {
|
|
1477
|
+
id,
|
|
1478
|
+
componentType: norm,
|
|
1479
|
+
direction: parsed.direction ?? "right",
|
|
1480
|
+
at: parsed.at ?? pendingAt,
|
|
1481
|
+
label: parsed.label,
|
|
1482
|
+
value: parsed.value,
|
|
1483
|
+
attrs: parsed.attrs
|
|
1484
|
+
};
|
|
1485
|
+
if (parsed.length) {
|
|
1486
|
+
comp.attrs = { ...comp.attrs, length: parsed.length };
|
|
1487
|
+
}
|
|
1488
|
+
components.push(comp);
|
|
1489
|
+
pendingAt = `${id}.end`;
|
|
1490
|
+
continue;
|
|
1491
|
+
}
|
|
1492
|
+
if (bareMatch) {
|
|
1493
|
+
const typeStr = bareMatch[1];
|
|
1494
|
+
const norm = normalizeType(typeStr);
|
|
1495
|
+
if (!norm) {
|
|
1496
|
+
continue;
|
|
1497
|
+
}
|
|
1498
|
+
const rest = bareMatch[2] ?? "";
|
|
1499
|
+
const parsed = parseAttrs(rest);
|
|
1500
|
+
const id = mkId(norm);
|
|
1501
|
+
const comp = {
|
|
1502
|
+
id,
|
|
1503
|
+
componentType: norm,
|
|
1504
|
+
direction: parsed.direction ?? "right",
|
|
1505
|
+
at: parsed.at ?? pendingAt,
|
|
1506
|
+
label: parsed.label,
|
|
1507
|
+
value: parsed.value,
|
|
1508
|
+
attrs: parsed.attrs
|
|
1509
|
+
};
|
|
1510
|
+
components.push(comp);
|
|
1511
|
+
pendingAt = `${id}.end`;
|
|
1512
|
+
continue;
|
|
1309
1513
|
}
|
|
1310
|
-
return parts.join("");
|
|
1311
1514
|
}
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
|
|
1319
|
-
crystal,
|
|
1320
|
-
transformer,
|
|
1321
|
-
voltage_source,
|
|
1322
|
-
current_source,
|
|
1323
|
-
ac_source,
|
|
1324
|
-
battery,
|
|
1325
|
-
ground,
|
|
1326
|
-
gnd_signal,
|
|
1327
|
-
vcc,
|
|
1328
|
-
diode,
|
|
1329
|
-
zener,
|
|
1330
|
-
schottky,
|
|
1331
|
-
led,
|
|
1332
|
-
photodiode,
|
|
1333
|
-
npn,
|
|
1334
|
-
pnp,
|
|
1335
|
-
nmos,
|
|
1336
|
-
pmos,
|
|
1337
|
-
jfet_n,
|
|
1338
|
-
jfet_p,
|
|
1339
|
-
opamp,
|
|
1340
|
-
comparator,
|
|
1341
|
-
switch_spst,
|
|
1342
|
-
push_no,
|
|
1343
|
-
ammeter,
|
|
1344
|
-
voltmeter,
|
|
1345
|
-
wattmeter,
|
|
1346
|
-
motor,
|
|
1347
|
-
speaker,
|
|
1348
|
-
microphone,
|
|
1349
|
-
buzzer,
|
|
1350
|
-
potentiometer,
|
|
1351
|
-
rheostat,
|
|
1352
|
-
thermistor_ntc,
|
|
1353
|
-
thermistor_ptc,
|
|
1354
|
-
ldr,
|
|
1355
|
-
variable_cap,
|
|
1356
|
-
variable_inductor,
|
|
1357
|
-
switch_spdt,
|
|
1358
|
-
push_nc,
|
|
1359
|
-
gnd_chassis,
|
|
1360
|
-
gnd_digital,
|
|
1361
|
-
test_point,
|
|
1362
|
-
no_connect,
|
|
1363
|
-
antenna,
|
|
1364
|
-
generic_ic,
|
|
1365
|
-
terminal_block,
|
|
1366
|
-
"555_timer": timer_555,
|
|
1367
|
-
voltage_regulator
|
|
1368
|
-
// Lamp reuses buzzer slot? No, needs its own entry but our CircuitComponentType
|
|
1369
|
-
// doesn't have "lamp". We map it via parser alias to "buzzer" or add specifically.
|
|
1370
|
-
};
|
|
1371
|
-
var EXTRA_SYMBOLS = {
|
|
1372
|
-
lamp
|
|
1373
|
-
};
|
|
1374
|
-
function getSymbol(t) {
|
|
1375
|
-
return SYMBOLS[t] ?? EXTRA_SYMBOLS[t];
|
|
1515
|
+
return {
|
|
1516
|
+
type: "circuit",
|
|
1517
|
+
title: title2,
|
|
1518
|
+
components,
|
|
1519
|
+
nets,
|
|
1520
|
+
mode: "positional"
|
|
1521
|
+
};
|
|
1376
1522
|
}
|
|
1377
1523
|
|
|
1378
1524
|
// src/diagrams/circuit/layout.ts
|
|
@@ -1902,5 +2048,5 @@ exports.layoutCircuitNetlist = layoutCircuitNetlist;
|
|
|
1902
2048
|
exports.parseCircuit = parseCircuit;
|
|
1903
2049
|
exports.parseNetlist = parseNetlist;
|
|
1904
2050
|
exports.renderCircuit = renderCircuit;
|
|
1905
|
-
//# sourceMappingURL=chunk-
|
|
1906
|
-
//# sourceMappingURL=chunk-
|
|
2051
|
+
//# sourceMappingURL=chunk-QMTWG6JL.cjs.map
|
|
2052
|
+
//# sourceMappingURL=chunk-QMTWG6JL.cjs.map
|