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