Skip to content

Commit d0d3f2d

Browse files
add switches -> 0.2.3
1 parent 3bfd925 commit d0d3f2d

11 files changed

+184
-12
lines changed
45.6 KB
Binary file not shown.

dist/schemascii-0.2.3.tar.gz

55.7 KB
Binary file not shown.

index.html

+96
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
<!doctype html>
2+
<html>
3+
4+
<head>
5+
<title>Schemascii</title>
6+
<script src="https://cdn.jsdelivr.net/pyodide/v0.23.2/full/pyodide.js"></script>
7+
<style>
8+
.flex {
9+
display: flex;
10+
}
11+
12+
.flex.row {
13+
flex-direction: row;
14+
}
15+
16+
.flex.column {
17+
flex-direction: column;
18+
}
19+
20+
textarea {
21+
min-height: 10ch;
22+
}
23+
24+
#errors {
25+
color: red;
26+
}
27+
</style>
28+
<style id="custom-css"></style>
29+
</head>
30+
31+
<body>
32+
<h1>Schemascii Playground</h1>
33+
<div class="flex row">
34+
<div class="flex column">
35+
<div class="flex row">
36+
<p style="flex: 1">Schemascii Source</p>
37+
<button id="render">Render</button>
38+
</div><textarea id="schemascii"></textarea>
39+
</div>
40+
<div class="flex column">
41+
<p>CSS</p><textarea id="css"></textarea>
42+
</div>
43+
</div>
44+
<div id="output"></div>
45+
<pre id="console"></pre>
46+
<div id="errors"></div>
47+
</body>
48+
<script>
49+
// cSpell:ignore pyodide pyproject pyimport
50+
var pyodide;
51+
var output = document.getElementById("output");
52+
var css = document.getElementById("css");
53+
var console = document.getElementById("console");
54+
var source = document.getElementById("schemascii");
55+
var style_elem = document.getElementById("custom-css");
56+
var render_button = document.getElementById("render");
57+
var schemascii;
58+
async function main() {
59+
info("Loading Python... ");
60+
pyodide = await loadPyodide({ stdout: info, stderr: error });
61+
info("done\n");
62+
info("Fetching current Schemascii version... ");
63+
var pyproject_toml = await fetch("pyproject.toml").then(x => x.text());
64+
var ver = /version = "([\d.]+)"/.exec(pyproject_toml)[1];
65+
info(ver + "\n");
66+
info(`Installing schemascii-${ver}... `);
67+
await pyodide.runPythonAsync(`import micropip\nawait micropip.install("https://dragoncoder047.github.io/schemascii/dist/schemascii-${ver}-py3-none-any.whl")`);
68+
schemascii = pyodide.pyimport("schemascii");
69+
setup();
70+
console.textContent = "ready\n";
71+
}
72+
function info(line) {
73+
console.textContent += line;
74+
}
75+
function error(text) {
76+
errors.textContent += text;
77+
}
78+
function setup() {
79+
css.addEventListener("input", () => {
80+
style_elem.innerHTML = css.value;
81+
});
82+
render_button.addEventListener("click", async () => {
83+
console.textContent = "";
84+
errors.textContent = "";
85+
try {
86+
output.innerHTML = await schemascii.render(source.value);
87+
} catch (e) {
88+
error(`\nJS Error:\n${e.stack}\n`);
89+
throw e;
90+
}
91+
});
92+
}
93+
main();
94+
</script>
95+
96+
</html>

pyproject.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
44

55
[project]
66
name = "schemascii"
7-
version = "0.2.2"
7+
version = "0.2.3"
88
description = "Render ASCII-art schematics to SVG"
99
readme = "README.md"
1010
authors = [{ name = "dragoncoder047", email = "[email protected]" }]

schemascii/__init__.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
from .utils import XML
99
from .errors import *
1010

11-
__version__ = "0.2.2"
11+
__version__ = "0.2.3"
1212

1313

1414
def render(filename: str, text: str = None, **options) -> str:

schemascii/components_render.py

+67-6
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,8 @@ def de_ambiguous(
6969
box: Cbox, terminals: list[Terminal], bom_data: list[BOMData], **options
7070
):
7171
if len(bom_data) > 1:
72-
raise BOMError(f"Ambiguous BOM data for {box.type}{box.id}: {bom_data!r}")
72+
raise BOMError(
73+
f"Ambiguous BOM data for {box.type}{box.id}: {bom_data!r}")
7374
if not bom_data:
7475
bom_data = [BOMData(box.type, box.id, "")]
7576
return func(box, terminals, bom_data[0], **options)
@@ -111,7 +112,8 @@ def resistor(box: Cbox, terminals: list[Terminal], bom_data: BOMData, **options)
111112
quad_angle = angle + pi / 2
112113
points = [t1]
113114
for i in range(1, 4 * int(length)):
114-
points.append(t1 - rect(i / 4, angle) + pow(-1, i) * rect(1, quad_angle) / 4)
115+
points.append(t1 - rect(i / 4, angle) + pow(-1, i)
116+
* rect(1, quad_angle) / 4)
115117
points.append(t2)
116118
return (
117119
polylinegon(points, **options)
@@ -323,7 +325,8 @@ def integrated_circuit(
323325
x=sc_text_pt.real,
324326
y=sc_text_pt.imag,
325327
text__anchor=(
326-
"start" if (terminal.side in (Side.TOP, Side.BOTTOM)) else "middle"
328+
"start" if (terminal.side in (
329+
Side.TOP, Side.BOTTOM)) else "middle"
327330
),
328331
font__size=options["scale"],
329332
fill=options["stroke"],
@@ -415,7 +418,8 @@ def transistor(box: Cbox, terminals: list[Terminal], bom_data: BOMData, **option
415418
(sp, mid - rect(0.8, theta)), # Lead out
416419
]
417420
if "fet" in silicon_type:
418-
arr = mid + rect(0.8, theta), mid + rect(0.8, theta) + rect(0.7, thetaquarter)
421+
arr = mid + rect(0.8, theta), mid + \
422+
rect(0.8, theta) + rect(0.7, thetaquarter)
419423
if "nfet" == silicon_type:
420424
arr = arr[1], arr[0]
421425
out_lines.extend(
@@ -436,7 +440,8 @@ def transistor(box: Cbox, terminals: list[Terminal], bom_data: BOMData, **option
436440
]
437441
)
438442
else:
439-
arr = mid + rect(0.8, theta), mid + rect(0.4, theta) + rect(1, thetaquarter)
443+
arr = mid + rect(0.8, theta), mid + \
444+
rect(0.4, theta) + rect(1, thetaquarter)
440445
if "npn" == silicon_type:
441446
arr = arr[1], arr[0]
442447
out_lines.extend(
@@ -468,7 +473,8 @@ def ground(box: Cbox, terminals: list[Terminal], bom_data: BOMData, **options):
468473
points = [(0, 1j), (-0.5 + 1j, 0.5 + 1j)]
469474
match icon_type:
470475
case "earth":
471-
points += [(-0.33 + 1.25j, 0.33 + 1.25j), (-0.16 + 1.5j, 0.16 + 1.5j)]
476+
points += [(-0.33 + 1.25j, 0.33 + 1.25j),
477+
(-0.16 + 1.5j, 0.16 + 1.5j)]
472478
case "chassis":
473479
points += [
474480
(-0.5 + 1j, -0.25 + 1.5j),
@@ -485,6 +491,61 @@ def ground(box: Cbox, terminals: list[Terminal], bom_data: BOMData, **options):
485491
return bunch_o_lines(points, **options)
486492

487493

494+
@component("S", "SW", "PB")
495+
@n_terminal(2)
496+
@no_ambiguous
497+
def switch(box: Cbox, terminals: list[Terminal], bom_data: BOMData, **options):
498+
"""Draw a mechanical switch symbol.
499+
bom:{nc/no}[m][:label]"""
500+
icon_type = bom_data.data or "no"
501+
if ":" in icon_type:
502+
icon_type, *b = icon_type.split(":")
503+
bom_data = BOMData(bom_data.type, bom_data.id, ":".join(b))
504+
else:
505+
bom_data = BOMData(bom_data.type, bom_data.id, "")
506+
t1, t2 = terminals[0].pt, terminals[1].pt
507+
mid = (t1 + t2) / 2
508+
angle = phase(t1 - t2)
509+
quad_angle = angle + pi / 2
510+
scale = options["scale"]
511+
out = (XML.circle(
512+
cx=(rect(-scale, angle) + mid * scale).real,
513+
cy=(rect(-scale, angle) + mid * scale).imag,
514+
r=scale / 4,
515+
stroke="transparent",
516+
fill=options["stroke"],
517+
class_="filled",
518+
) + XML.circle(
519+
cx=(rect(scale, angle) + mid * scale).real,
520+
cy=(rect(scale, angle) + mid * scale).imag,
521+
r=scale / 4,
522+
stroke="transparent",
523+
fill=options["stroke"],
524+
class_="filled",
525+
) + bunch_o_lines([(t1, mid + rect(1, angle)), (t2, mid + rect(-1, angle))], **options))
526+
sc = 1
527+
match icon_type:
528+
case "nc":
529+
points = [(-1j, -.3+1j)]
530+
case "no":
531+
points = [(-1j, -.8+1j)]
532+
sc = 1.9
533+
case "ncm":
534+
points = [(.3-1j, .3+1j)]
535+
out += polylinegon(deep_transform([-.5+.6j, -.5-.6j, .3-.6j, .3+.6j], mid, angle), True, **options)
536+
sc = 1.3
537+
case "nom":
538+
points = [(-.5-1j, -.5+1j)]
539+
out += polylinegon(deep_transform([-1+.6j, -1-.6j, -.5-.6j, -.5+.6j], mid, angle), True, **options)
540+
sc = 2.5
541+
case _:
542+
raise BOMError(f"Unknown switch symbol type: {icon_type}")
543+
points = deep_transform(points, mid, angle)
544+
return bunch_o_lines(points, **options) + out + id_text(
545+
box, bom_data, terminals, None, make_text_point(
546+
t1, t2, **(options | {"offset_scaler": sc})), **options)
547+
548+
488549
# code for drawing stuff
489550
# https://github.com/pfalstad/circuitjs1/tree/master/src/com/lushprojects/circuitjs1/client
490551
# https://github.com/KenKundert/svg_schematic/blob/0abb5dc/svg_schematic.py

schemascii/utils.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,7 @@ def polylinegon(points: list[complex], is_polygon: bool = False, **options):
133133
c = options["stroke"]
134134
pts = " ".join(f"{x.real * scale},{x.imag * scale}" for x in points)
135135
if is_polygon:
136-
return XML.polygon(points=pts, fill=c)
136+
return XML.polygon(points=pts, fill=c, class_="filled")
137137
return XML.polyline(points=pts, fill="transparent", stroke__width=w, stroke=c)
138138

139139

@@ -233,7 +233,7 @@ def make_text_point(t1: complex, t2: complex, **options) -> complex:
233233
quad_angle = phase(t1 - t2) + pi / 2
234234
scale = options["scale"]
235235
text_pt = (t1 + t2) * scale / 2
236-
offset = rect(scale / 2, quad_angle)
236+
offset = rect(scale / 2 * options.get("offset_scaler", 1), quad_angle)
237237
text_pt += complex(abs(offset.real), -abs(offset.imag))
238238
return text_pt
239239

schemascii_example.css

+8-1
Original file line numberDiff line numberDiff line change
@@ -18,14 +18,21 @@ svg.schemascii :is(.wire, .component):hover {
1818
--sch-color: lime;
1919
}
2020

21-
svg.schemascii .component :is(polyline, path, line, polygon, rect, circle) {
21+
svg.schemascii .component :is(polyline, path, line, polygon, rect, circle):not(.filled) {
2222
stroke: var(--sch-color, red);
2323
stroke-width: 2;
2424
stroke-linecap: round;
2525
transition-duration: 0.2s;
2626
fill: transparent;
2727
}
2828

29+
svg.schemascii .component :is(polyline, path, line, polygon, rect, circle).filled {
30+
fill: var(--sch-color, red);
31+
stroke: none;
32+
transition-duration: 0.2s;
33+
}
34+
35+
2936
svg.schemascii .component .plus :is(polyline, path, line) {
3037
stroke-width: 1;
3138
}

supported-components.md

+2
Original file line numberDiff line numberDiff line change
@@ -18,3 +18,5 @@ and run scripts/docs.py to re-generate this file.
1818
| `U`, `IC` | Draw an IC. | `part-number[,pin1-label[,pin2-label[,...]]]` | |
1919
| `J`, `P` | Draw a jack connector or plug. | `label[,{circle/input/output}]` | |
2020
| `Q`, `MOSFET`, `MOS`, `FET` | Draw a bipolar transistor (PNP/NPN) or FET (NFET/PFET). | `{npn/pnp/nfet/pfet}:part-number` | `s` = source<br>`d` = drain<br>`g` = gate<br>`e` = emitter<br>`c` = collector<br>`b` = base |
21+
| `G`, `GND` | Draw a ground symbol. | `[{earth/chassis/signal/common}]` | |
22+
| `S`, `SW`, `PB` | Draw a mechanical switch symbol. | `{nc/no}[m][:label]` | |

0 commit comments

Comments
 (0)