From: W. Trevor King Date: Wed, 2 May 2012 19:15:37 +0000 (-0400) Subject: Convert TwoTerminal to a more general MultiTerminal in Circ.asy. X-Git-Url: http://git.tremily.us/?a=commitdiff_plain;h=f78c7b3e0089b4c0908de9114e0706fbe101b99b;p=course.git Convert TwoTerminal to a more general MultiTerminal in Circ.asy. This allows me to add switchSPDT, which has three terminals. Label handling is also more flexible in the new system. By default, labels will stay in their current positions (above/below in element coordinates for label/value). However, the label text is no longer rotated along with the element. If you want rotated text, you'll have to rotate it yourself: MultiTerminal Rpos = resistor(..., dir=90, ... label=rotate(90)*Label("my label", align=W), ...); The benefit to this approach is that you can now set your own alignment, which will override the default above/below positioning. This commit also makes some whitespace normalizations and bumps Circ.asy to version 0.2. To upgrade code using Circ 0.1, make the following changes: * Replace TwoTerminal with MultiTerminal. * Replace ang=... with dir=... in MultiTerminal initializations. * Replace x.beg with x.terminal[0] and x.end with x.terminal[1]. * Adjust labeling as described above. * Replace centerto with two_terminal_centerto. --- diff --git a/asymptote/Circ-test.asy b/asymptote/Circ-test.asy index 44bfc7c..b57a643 100644 --- a/asymptote/Circ-test.asy +++ b/asymptote/Circ-test.asy @@ -1,6 +1,6 @@ /* Test suite for Circ.asy. * - * Copyright (C) 2008-2009 W. Trevor King + * Copyright (C) 2008-2012 W. Trevor King * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -22,67 +22,80 @@ import Circ; real u = 2cm, v=0; write("resistor"); -TwoTerminal Rn = resistor((0,v), 0, normal, "$R_{normal}$", "30\ohm"); -dot("beg", Rn.beg, NW, red); -dot("end", Rn.end, NE, red); -dot("mid", Rn.mid, S, red); -TwoTerminal Rvb = resistor((2u,v), 0, variable, "$R_{variable}$", "30\kohm"); +MultiTerminal Rn = resistor(beg=(0,v), dir=0, type=normal, + label=Label("$R_{normal}$", align=N), value=Label("$30\ohm$", align=S)); +dot("beg", Rn.terminal[0], NW, red); +dot("end", Rn.terminal[1], NE, red); +dot("center", Rn.center, S, red); + +MultiTerminal Rvb = resistor(beg=(2u,v), dir=0, type=variable, + label=Label("$R_{variable}$", align=NW), + value=Label("$30\kohm$", align=SE)); v -= u; write("capacitor"); -TwoTerminal Cn = capacitor((0,v), 0, normal, "$C_{normal}$", "30 $\mu$F"); -TwoTerminal Ce = capacitor((u,v), 0, electrolytic, "$C_{electrolytic}$", "30 $\mu$F"); -TwoTerminal Cvb = capacitor((2u,v), 0, variable, "$C_{variable}$", "30 $\mu$F"); -TwoTerminal Cvt = capacitor((3u,v), 0, variant, "$C_{variant}$", "30 $\mu$F"); +MultiTerminal Cn = capacitor((0,v), type=normal, "$C_{normal}$", + "30 $\mu$F"); +MultiTerminal Ce = capacitor((u,v), type=electrolytic, "$C_{electrolytic}$", + "30 $\mu$F"); +MultiTerminal Cvb = capacitor((2u,v), type=variable, "$C_{variable}$", + "30 $\mu$F"); +MultiTerminal Cvt = capacitor((3u,v), type=variant, "$C_{variant}$", + "30 $\mu$F"); v -= u; write("inductor"); -TwoTerminal Lup = inductor((0,v), 0, Up, "$L_{Up}$", "30 H"); -TwoTerminal Ldown = inductor((u,v), 0, Down, "$L_{Down}$", "30 H"); +MultiTerminal Lup = inductor((0,v), type=Up, "$L_{Up}$", "30 H"); +MultiTerminal Ldown = inductor((u,v), type=Down, "$L_{Down}$", "30 H"); v -= u; write("diode"); -TwoTerminal Dn = diode((0,v), 0, normal, "$D_{normal}$", "1.3 V"); -TwoTerminal Dz = diode((u,v), 0, zener, "$D_{zener}$", "1.3 V"); -TwoTerminal Dled = diode((2u,v), 0, LED, "$D_{LED}$", "1.7 V"); +MultiTerminal Dn = diode((0,v), type=normal, "$D_{normal}$", "1.3 V"); +MultiTerminal Dz = diode((u,v), type=zener, "$D_{zener}$", "1.3 V"); +MultiTerminal Dled = diode((2u,v), type=LED, "$D_{LED}$", "1.7 V"); v -= u; write("battery"); -TwoTerminal B = battery((0,v), 0, "Battery", "1.5 V"); +MultiTerminal B = battery((0,v), "Battery", "1.5 V"); v -= u; write("switch"); -TwoTerminal B = switchSPST((0,v), 0, NO, "$S_{NO}$", "Open"); -TwoTerminal B = switchSPST((u,v), 0, NC, "$S_{NC}$", "Closed"); +MultiTerminal So = switchSPST((0,v), type=open, "$S$", "Open"); +MultiTerminal Sc = switchSPST((u,v), type=closed, "$S$", "Closed"); +MultiTerminal SPDT_o = switchSPDT((2u,v), type=open, "$S$", "Open"); +MultiTerminal SPDT_a = switchSPDT((3u,v), type=closed_a, "$S$", "Closed-A"); +MultiTerminal SPDT_b = switchSPDT((4u,v), type=closed_b, "$S$", "Closed-B"); v -= u; write("current"); -TwoTerminal Icurr = current((0,v), 0, "I", "10 A"); +MultiTerminal Icurr = current((0,v), "I", "10 A"); v -= u; write("source"); -TwoTerminal Sdc = source((0,v), 0, DC, "DC", "5 V"); -TwoTerminal Sac = source((u,v), 0, AC, "AC", "5 V$_{pp}$"); -TwoTerminal Si = source((2u,v), 0, I, "I", "5 A"); -TwoTerminal Sv = source((3u,v), 0, V, "V", "5 V"); +MultiTerminal Sdc = source((0,v), type=DC, "DC", "5 V"); +MultiTerminal Sac = source((u,v), type=AC, "AC", "5 V$_{pp}$"); +MultiTerminal Si = source((2u,v), type=I, "I", "5 A"); +MultiTerminal Sv = source((3u,v), type=V, "V", "5 V"); v -= u; write("lamp"); -TwoTerminal Ln = lamp((0,v), 0, normal, "indicator", "5\ohm"); -TwoTerminal Li = lamp((u,v), 0, illuminating, "illuminator", "5\ohm"); +MultiTerminal Ln = lamp((0,v), 0, normal, "indicator", "5\ohm"); +MultiTerminal Li = lamp((u,v), 0, illuminating, "illuminator", "5\ohm"); v -= 1.5u; write("positioning"); -TwoTerminal Spos = source((u,v), 90, DC, "DC", "5 V"); -TwoTerminal Rpos = resistor((0,0), 0, normal, "+offset", "5 \ohm", draw=false); -Rpos.centerto(Spos.beg, Spos.end, offset=u); +MultiTerminal Spos = source((u,v), dir=90, type=DC, "DC", "5 V"); +MultiTerminal Rpos = resistor(type=normal, + label=rotate(90)*Label("+offset", align=W), + value=rotate(90)*Label("5 \ohm", align=E), draw=false); +Rpos.centerto(Spos.terminal[0], Spos.terminal[1], offset=u); Rpos.draw(); -dot("Sa", Spos.beg, S); -dot("Sb", Spos.end, N); -dot("Ra", Rpos.beg, S); -dot("Rb", Rpos.end, N); -TwoTerminal Cpos = capacitor((0,0), 0, normal, "-2offset", "4 F",draw=false); -Cpos.centerto(Spos.beg, Spos.end, offset=-2u); +dot("Sa", Spos.terminal[0], S); +dot("Sb", Spos.terminal[1], N); +dot("Ra", Rpos.terminal[0], S); +dot("Rb", Rpos.terminal[1], N); +MultiTerminal Cpos = capacitor(type=normal, "-2offset", "4 F",draw=false); +Cpos.centerto(Spos.terminal[0], Spos.terminal[1], offset=-2u); Cpos.draw(); v -= u; @@ -106,17 +119,19 @@ v -= u; write("circuit"); v -= u/2; // this circuit takes up more height than the previous lines. -TwoTerminal Ccirc = capacitor((0,v), ang=90); -TwoTerminal Rcirc = resistor(draw=false); -Rcirc.centerto(Ccirc.beg, Ccirc.end); +MultiTerminal Ccirc = capacitor((0,v), dir=90); +MultiTerminal Rcirc = resistor(draw=false); +two_terminal_centerto(Ccirc, Rcirc); Rcirc.shift((u,0)); // gratuitous use of shift, but whatever... Rcirc.draw(); // In the following, we assume the resistor is longer than the // capacitor. If that is not true, you can find the corners of the // circuit programatically and use those corners. -wire(Rcirc.end, Ccirc.end, rlsq); -wire(Rcirc.beg, Ccirc.beg, rlsq); -pair Pcirc[] = {(Ccirc.beg.x,Rcirc.beg.y), (Ccirc.end.x,Rcirc.end.y), - Rcirc.end, Rcirc.beg}; +wire(Rcirc.terminal[1], Ccirc.terminal[1], rlsq); +wire(Rcirc.terminal[0], Ccirc.terminal[0], rlsq); +pair Pcirc[] = { + (Ccirc.terminal[0].x,Rcirc.terminal[0].y), + (Ccirc.terminal[1].x,Rcirc.terminal[1].y), + Rcirc.terminal[1], Rcirc.terminal[0]}; kirchhoff_loop(Pcirc); v -= u; diff --git a/asymptote/Circ.asy b/asymptote/Circ.asy index 7f6cc91..078ea9c 100644 --- a/asymptote/Circ.asy +++ b/asymptote/Circ.asy @@ -1,8 +1,8 @@ /* Useful functions for drawing circuit diagrams. - * Version 0.1 + * Version 0.2 * * Copyright (C) 2003 GS Bustamante Argañaraz - * 2008-2011 W. Trevor King + * 2008-2012 W. Trevor King * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -78,15 +78,6 @@ path bjtahead (path p) return (a & reverse(a) & b & reverse(b))--cycle; } -path txtahead (path p) -{ - pair A = point(p,reltime(p,1.0)); - pair B = point(p,reltime(p,0.97)); - pair u = dirtime(p,reltime(p,1.0)); - return A{-u}..(A - scale(7)*rotate(15)*u)--B - --(A - scale(7)*rotate(-15)*u)..A{u}--cycle; -} - // function to wire the symbols together int nsq=0, udsq=2, rlsq=3; @@ -106,183 +97,136 @@ void wire(pair pin_beg, pair pin_end, int type=nsq, real dist=0) } else { if (type==udsq) { draw(pin_beg--(pin_beg+(0,dist))--(pin_end.x,pin_beg.y + dist) - --pin_end, line); + --pin_end, line); } else if (type==rlsq) { draw(pin_beg--(pin_beg+(dist,0))--(pin_beg.x + dist,pin_end.y) - --pin_end, line); + --pin_end, line); } else { write("Error, unrecognized wire type ",type); } } } -// Macro to center text among two pins - -bool witharrow=false, noarrow=true; - -void ctext(pair pin_beg, pair pin_end, string txt, bool type) -{ - picture ctxt; - if (type==noarrow) { - ; // pass - } else if (type==witharrow) { - draw(ctxt, pin_beg--pin_end); - draw(ctxt, txtahead(pin_beg--pin_end)); - draw(ctxt, txtahead(reverse(pin_beg--pin_end))); - } else { - write("Error, unrecognized ctext type ",type); - } - label(ctxt, txt, 0.5(pin_beg+pin_end)); - add(currentpicture, ctxt); -} - -// Definition of lbsep (label separation), distance among symbol and label. - -real lbsep=3mm; - - // ----- Here the symbols begin -------- -struct TwoTerminal { - pair beg; - pair end; - pair mid; - real len; - real ang; - real lchar; - real lcharv; - string name; - string val; +transform _shift_transform(pair z) = shift; + +struct MultiTerminal { + pair center; + real dir; + pair terminal[]; + pair terminal_offset[]; + Label label; + Label value; + real label_offset; + real value_offset; path pLine[]; // cyclic paths are filled in path pMisc[]; - - void operator init(pair beg, real len, real ang, real lchar, real lcharv, string name, string val, path pLine[]={}, path pMisc[]={}) { - this.beg = beg; - this.end = beg+rotate(ang)*(len,0); - this.mid = (this.beg + this.end)/2; - this.len = len; - this.ang = ang % 360; - this.lchar = lchar; - this.lcharv = lcharv; - this.name = name; - this.val = val; - this.pLine = pLine; - this.pMisc = pMisc; - } + pen line; + pen misc; - void putlabel(picture pic=currentpicture) { - picture picL; - pair pName, pVal; // point - real rName, rVal; // rotated by - align aName, aVal; - if (labeling==rotatelabel) { - pName = (lchar+lbsep)*dir (90+ang); - pVal = (lcharv+lbsep)*dir (270+ang); - aName = NoAlign; - aVal = NoAlign; - if (ang <= 90 || ang > 270) { - rName = ang; - rVal = ang; - } else if (ang > 90 && ang <= 270) { - rName = 180+ang; - rVal = 180+ang; - } - } else if (labeling==norotatelabel) { - rName = 0; - rVal = 0; - if (ang == 0) { - pName = (lchar+.25lbsep)*dir (90+ang); - pVal = (lcharv+.25lbsep)*dir (270+ang); - aName = N; - aVal = S; - } else if (ang < 90) { - pName = (lchar)*dir (90+ang); - pVal = (lcharv)*dir (270+ang); - aName = NW; - aVal = SE; - } else if (ang == 90) { - pName = (lchar+.25lbsep)*dir (90+ang); - pVal = (lcharv+.25lbsep)*dir (270+ang); - aName = W; - aVal = E; - } else if (90 < ang && ang < 180) { - pName = (lchar)*dir (90+ang); - pVal = (lcharv)*dir (270+ang); - aName = SW; - aVal = NE; - } else if (ang == 180) { - pName = (lchar+.25lbsep)*dir (90+ang); - pVal = (lcharv+.25lbsep)*dir (270+ang); - aName = S; - aVal = N; - } else if (ang > 180 && ang < 270) { - pName = (lchar)*dir (90+ang); - pVal = (lcharv)*dir (270+ang); - aName = SE; - aVal = NW; - } else if (ang == 270) { - pName = (lchar+.25lbsep)*dir (90+ang); - pVal = (lcharv+.25lbsep)*dir (270+ang); - aName = E; - aVal = W; - } else if (270 < ang && ang < 360) { - pName = (lchar)*dir (90+ang); - pVal = (lcharv)*dir (270+ang); - aName = NE; - aVal = SW; - } + void set_terminals() { + for (int i=0; i < this.terminal_offset.length; i+=1) { + this.terminal[i] = this.center + + rotate(this.dir)*this.terminal_offset[i]; } - Label lName = rotate(rName)*Label(name); - label(picL, lName, pName, aName); - Label lVal = rotate(rVal)*Label(val); - label(picL, lVal, pVal, aVal); - add(pic, picL, (end-beg)/2); + } + + void operator init(pair center=(0,0), real dir=0, + pair terminal[]={}, pair terminal_offset[]={}, + Label label="", Label value="", + real label_offset=0, real value_offset=0, + path pLine[]={}, path pMisc[]={}, + pen line=line, pen misc=misc) { + this.center = center; + this.dir = dir % 360; + this.terminal = terminal; + this.terminal_offset = terminal_offset; + this.set_terminals(); + this.label = label; + this.value = value; + this.label_offset = label_offset; + this.value_offset = value_offset; + this.pLine = pLine; + this.pMisc = pMisc; + this.line = line; + this.misc = misc; } /* Shift position by a */ void shift(pair a) { - this.beg += a; - this.end += a; - this.mid += a; + this.center += a; + this.set_terminals(); } - /* Rather than placing the element with a point and direction (beg, - * ang), center an element between the pairs a and b. The optional + void draw_label(picture pic=currentpicture, Label L=null, real offset=0, + pair default_direction=(0,0)) { + align a; + if (L == null) { + L = this.label; + } + a = L.align; + if ((L.align == NoAlign || L.align.dir == (0,0)) && + default_direction != (0,0)) { + L.align = rotate(this.dir)*default_direction; + } + if (L.align != NoAlign && L.align != Align) { + real m = labelmargin(L.p); + real scale = (m + offset)/m; + if (L.align.is3D) { + L.align.dir3 *= scale; + } else { + L.align.dir *= scale; + } + } + label(pic=pic, L=L, position=this.center); + L.align = a; + } + + /* Rather than placing the element with a point and direction (mid, + * dir), center an element between the pairs a and b. The optional * offset shifts the element in the direction rotated(90)*(b-a) * (i.e. up for offset > 0 if b is directly right of a). */ void centerto(pair a, pair b, real offset=0) { - this.ang = degrees(b-a); - this.beg = (a+b)/2 - - unit(b-a)*this.len/2 + offset*dir(this.ang+90); - this.end = this.beg+rotate(ang)*(this.len,0); - this.mid = (this.beg + this.end)/2; + this.dir = degrees(b-a); + this.center = (a+b)/2 + offset*dir(this.dir+90); + this.set_terminals(); } void draw(picture pic=currentpicture) { - picture picT; for (int i=0; i< pLine.length; i+=1) { - draw(picT, rotate(ang)*pLine[i], line); - if (cyclic(pLine[i])) - fill(picT, rotate(ang)*pLine[i], line); + path p = _shift_transform(this.center)*rotate(this.dir)*pLine[i]; + if (cyclic(p)) + filldraw(pic, p, this.line, this.line); + else + draw(pic, p, this.line); } for (int i=0; i< pMisc.length; i+=1) { - draw(picT, rotate(ang)*pMisc[i], misc); - if (cyclic(pMisc[i])) - fill(picT, rotate(ang)*pMisc[i], misc); + path p = _shift_transform(this.center)*rotate(this.dir)*pMisc[i]; + if (cyclic(p)) + filldraw(pic, p, this.misc, this.misc); + else + draw(pic, p, this.misc); } - putlabel(picT); - add(pic, picT, beg); + this.draw_label(pic=pic, L=this.label, offset=this.label_offset, + default_direction=N); + this.draw_label(pic=pic, L=this.value, offset=this.value_offset, + default_direction=S); } } -void centerto(TwoTerminal reference, TwoTerminal target, real offset=0, - bool reverse=false) +pair _offset(pair beg=(0,0), real length=1, real dir=0) { + return beg + rotate(dir)*(length, 0); +} + +void two_terminal_centerto(MultiTerminal reference, MultiTerminal target, + real offset=0, bool reverse=false) { if (reverse == false) - target.centerto(reference.beg, reference.end, offset); + target.centerto(reference.terminal[0], reference.terminal[1], offset); else - target.centerto(reference.end, reference.beg, offset); + target.centerto(reference.terminal[1], reference.terminal[0], offset); } // --- Resistor (Resistencia) --- @@ -290,26 +234,34 @@ void centerto(TwoTerminal reference, TwoTerminal target, real offset=0, real rstlth=2mm; int normal=0, variable=2; -TwoTerminal resistor(pair beg=(0,0), real ang=0, int type=normal, - string name="", string val="", bool draw=true) +MultiTerminal resistor(pair beg=(0,0), real dir=0, int type=normal, + Label label="", Label value="", bool draw=true) { - path pLine, pMisc[]={}; - TwoTerminal term; - - pLine = (0,0)--(2rstlth,0)--(2.25rstlth,.75rstlth); + path pLine, pLines[]={}, pMisc[]={}; + real len = 7rstlth; + MultiTerminal term; + pair center = _offset(beg=beg, length=len/2, dir=dir); + pair terminal_offset[] = { + (-len/2, 0), + (len/2, 0)}; + + pLine = (-len/2,0)--(-1.5rstlth,0)--(-1.25rstlth,.75rstlth); for (real i=.5; i<=2.5; i+=0.5) - pLine = pLine--((2.25+i)*rstlth,((-1)**(2i))*.75rstlth); - pLine = pLine -- (5rstlth,0)--(7rstlth,0); + pLine = pLine--((-1.25+i)*rstlth,((-1)**(2i))*.75rstlth); + pLine = pLine -- (1.5rstlth,0)--(len/2,0); if (type==normal) { ; //pass } else if (type==variable) { ahlength=.8rstlth; - pMisc.push((2rstlth,-rstlth)--(5.5rstlth,rstlth)); - pMisc.push(miscahead((2rstlth,-rstlth)--(5.5rstlth,rstlth))); + pMisc.push((-1.5rstlth,-rstlth)--(1.5rstlth,rstlth)); + pMisc.push(miscahead((-1.5rstlth,-rstlth)--(1.5rstlth,rstlth))); } else { - write("Error, unrecognized resistor type ",type); + write("Error, unrecognized resistor type ",type); } - term = TwoTerminal(beg, 7rstlth, ang, .8rstlth, .8rstlth, name, val, pLine, pMisc); + pLines.push(pLine); + term = MultiTerminal(center=center, dir=dir, terminal_offset=terminal_offset, + label=label, value=value, label_offset=.8rstlth, value_offset=.8rstlth, + pLine=pLines, pMisc=pMisc); if (draw == true) term.draw(); return term; @@ -320,28 +272,33 @@ TwoTerminal resistor(pair beg=(0,0), real ang=0, int type=normal, real coil=2mm; int Up=0, Down=1; -TwoTerminal inductor(pair beg=(0,0), real ang=0, int type=Up, string name="", - string val="", bool draw=true) +MultiTerminal inductor(pair beg=(0,0), real dir=0, int type=Up, + Label label="", Label value="", bool draw=true) { path pLine; - TwoTerminal term; - + real len = 6coil; + MultiTerminal term; + pair center = _offset(beg=beg, length=len/2, dir=dir); + pair terminal_offset[] = { + (-len/2, 0), + (len/2, 0)}; + + pLine = (-len/2,0) -- (-2coil,0); + if (type==Up) { - pLine = (0,0)--(coil,0); - for (int i=2; i<=4; i+=1) + for (int i=-1; i<=2; i+=1) pLine = pLine{N}..{S}(i*coil,0); - pLine = pLine{N}..{S}(5coil,0)--(6coil,0); } else if (type==Down) { - pLine = (0,0)--(coil,0); - for (int i=2; i<=4; i+=1) + for (int i=-1; i<=2; i+=1) pLine = pLine{S}..{N}(i*coil,0); - pLine = pLine{S}..{N}(5coil,0)--(6coil,0); - // the original makecirc changed labelangle to ang-180 } else { write("Error, unrecognized inductor type ",type); } - term = TwoTerminal(beg, 6coil, ang, coil, coil, name, val, pLine); - // the original makecirc used .5coil for lcharv + pLine = pLine -- (len/2,0); + + term = MultiTerminal(center=center, dir=dir, terminal_offset=terminal_offset, + label=label, value=value, label_offset=.8rstlth, value_offset=.8rstlth, + pLine=pLine); if (draw == true) term.draw(); return term; @@ -352,35 +309,42 @@ TwoTerminal inductor(pair beg=(0,0), real ang=0, int type=Up, string name="", real platsep=1mm; int normal=0, electrolytic=1, variable=2, variant=3; -TwoTerminal capacitor(pair beg=(0,0), real ang=0, int type=normal, - string name="", string val="", bool draw=true) +MultiTerminal capacitor(pair beg=(0,0), real dir=0, int type=normal, + Label label="", Label value="", bool draw=true) { path pLine[]={}, pMisc[]={}; - TwoTerminal term; + real len = 7platsep; + MultiTerminal term; + pair center = _offset(beg=beg, length=len/2, dir=dir); + pair terminal_offset[] = { + (-len/2, 0), + (len/2, 0)}; - pLine.push((0,0)--(3platsep,0)); - pLine.push((4platsep,0)--(7platsep,0)); + pLine.push((-len/2,0)--(-platsep/2,0)); + pLine.push((platsep/2,0)--(len/2,0)); if (type==normal) { - pLine.push((3platsep,-2.5platsep)--(3platsep,2.5platsep)); - pLine.push((4platsep,-2.5platsep)--(4platsep,2.5platsep)); + pLine.push((-platsep/2,-2.5platsep)--(-platsep/2,2.5platsep)); + pLine.push((platsep/2,-2.5platsep)--(platsep/2,2.5platsep)); } else if (type==electrolytic) { - pLine.push((3platsep,-1.8platsep)--(3platsep,1.8platsep)); - pLine.push((2platsep,-2.5platsep)--(4platsep,-2.5platsep) - --(4platsep,+2.5platsep)--(2platsep,2.5platsep)); + pLine.push((-platsep/2,-1.8platsep)--(-platsep/2,1.8platsep)); + pLine.push((-1.5platsep,-2.5platsep)--(platsep/2,-2.5platsep) + --(platsep/2,+2.5platsep)--(-1.5platsep,2.5platsep)); } else if (type==variable) { - pLine.push((3platsep,-2.5platsep)--(3platsep,2.5platsep)); - pLine.push((4platsep,-2.5platsep)--(4platsep,2.5platsep)); - pMisc.push((platsep,-2.5platsep)--(6platsep,2.5platsep)); + pLine.push((-platsep/2,-2.5platsep)--(-platsep/2,2.5platsep)); + pLine.push((platsep/2,-2.5platsep)--(platsep/2,2.5platsep)); + pMisc.push((-2.5platsep,-2.5platsep)--(2.5platsep,2.5platsep)); ahlength=1.7platsep; - pMisc.push(miscahead((platsep,-2.5platsep)--(6platsep,2.5platsep))); + pMisc.push(miscahead((-2.5platsep,-2.5platsep)--(2.5platsep,2.5platsep))); } else if (type==variant) { - pLine.push((3platsep,-2.5platsep)--(3platsep,2.5platsep)); - pLine.push((4.5platsep,-2.5platsep)..(4platsep,0)..(4.5platsep,2.5platsep)); + pLine.push((-platsep/2,-2.5platsep)--(-platsep/2,2.5platsep)); + pLine.push((platsep,-2.5platsep)..(platsep/2,0)..(platsep,2.5platsep)); } else { write("Error, unrecognized capacitor type ",type); } - term = TwoTerminal(beg, 7platsep, ang, 2.5platsep, 2.5platsep, name, val, pLine, pMisc); + term = MultiTerminal(center=center, dir=dir, terminal_offset=terminal_offset, + label=label, value=value, label_offset=2.5platsep, + value_offset=2.5platsep, pLine=pLine, pMisc=pMisc); if (draw == true) term.draw(); return term; @@ -388,41 +352,49 @@ TwoTerminal capacitor(pair beg=(0,0), real ang=0, int type=normal, // --- Diode (diodo) --- -real diodeht=3.5mm; +real diode_height = 3.5mm; int zener=1, LED=2; // I droped the pin parameters, since other device (e.g. electrolytic // capacitors) are also polarized. The positioning method centerto(), // provides enough flexibility. -TwoTerminal diode(pair beg=(0,0), real ang=0, int type=normal, string name="", - string val="", bool draw=true) +MultiTerminal diode(pair beg=(0,0), real dir=0, int type=normal, + Label label="", Label value="", bool draw=true) { path pLine[]={}, pMisc[]={}; - real lchar, lcharv; - TwoTerminal term; + real len = 3*diode_height; + real r = diode_height/2; + real label_offset, value_offset; + MultiTerminal term; + pair center = _offset(beg=beg, length=len/2, dir=dir); + pair terminal_offset[] = { + (-len/2, 0), + (len/2, 0)}; + + label_offset = value_offset = r; + pLine.push((-len/2,0)--(-r,0)--(-r,r)--(r,0)--(-r,-r)--(-r,0)); + pLine.push((r,0)--(len/2,0)); - pLine.push((0,0)--(diodeht,0)--(diodeht,.5diodeht)--(2diodeht,0)--(diodeht,-.5diodeht)--(diodeht,0)); - pLine.push((2diodeht,0)--(3diodeht,0)); - lchar = 0.6diodeht; lcharv = 0.6diodeht; - if (type==normal) { - pLine.push((2diodeht,-.5diodeht)--(2diodeht,.5diodeht)); + pLine.push((r,-r)--(r,r)); } else if (type==zener) { - pLine.push((2.5diodeht,-.5diodeht)--(2diodeht,-.5diodeht)--(2diodeht,.5diodeht)--(1.5diodeht,.5diodeht)); + pLine.push((2r,-r)--(r,-r)--(r,r)--(0,r)); } else if (type==LED) { - path a = (diodeht,.5diodeht)--(2diodeht,0); - pair u = unit((.5,1)); // perpendicular to a - path b = (0,0)--diodeht*u; - pLine.push((2diodeht,-.5diodeht)--(2diodeht,.5diodeht)); - lchar = 1.5diodeht; - pMisc.push(shift(point(a,reltime(a,0.25))+point(b,0.33))*((0,0)--diodeht*u)); - pMisc.push(shift(point(a,reltime(a,0.60))+point(b,0.33))*((0,0)--diodeht*u)); - pMisc.push(fullhead(pMisc[0], 0.4diodeht, 30)); - pMisc.push(fullhead(pMisc[1], 0.4diodeht, 30)); + path a = (-r,r)--(r,0); + pair u = unit((0.5, 1)); // perpendicular to a + path b = (0,0)--diode_height*u; + pLine.push((r,-r)--(r,r)); + label_offset = 1.5*diode_height; + pMisc.push(shift(point(a,reltime(a,0.25))+point(b,0.33))*((0,0)--diode_height*u)); + pMisc.push(shift(point(a,reltime(a,0.60))+point(b,0.33))*((0,0)--diode_height*u)); + pMisc.push(fullhead(pMisc[0], 0.4*diode_height, 30)); + pMisc.push(fullhead(pMisc[1], 0.4*diode_height, 30)); } else { - write("Error, unrecognized capacitor type ",type); + write("Error, unrecognized diode type ",type); } - term = TwoTerminal(beg, 3diodeht, ang, lchar, lcharv, name, val,pLine,pMisc); + term = MultiTerminal(center=center, dir=dir, terminal_offset=terminal_offset, + label=label, value=value, label_offset=label_offset, + value_offset=value_offset, pLine=pLine, pMisc=pMisc); if (draw == true) term.draw(); return term; @@ -430,25 +402,34 @@ TwoTerminal diode(pair beg=(0,0), real ang=0, int type=normal, string name="", //--- Battery (bater'ia) --- -real bsize = 6mm; +real battery_size = 6mm; -TwoTerminal battery(pair beg=(0,0), real ang=0, string name="", string val="", - bool draw=true) +MultiTerminal battery(pair beg=(0,0), real dir=0, + Label label="", Label value="", bool draw=true) { path pLine[]={}, pMisc[]={}; - real lchar, lcharv; - TwoTerminal term; - - pLine.push((0,0)--(0.4bsize,0)); - pLine.push((1.4bsize,0)--(1.8bsize,0)); - + real len = 1.8*battery_size; + real r = battery_size/2; + real x = 0.4*battery_size; + real Y = 0.6*battery_size; + real y = 0.2*battery_size; + real label_offset, value_offset; + MultiTerminal term; + pair center = _offset(beg=beg, length=len/2, dir=dir); + pair terminal_offset[] = { + (-len/2, 0), + (len/2, 0)}; + + label_offset = value_offset = Y; + pLine.push((-len/2,0)--(-r,0)); + pLine.push((r,0)--(len/2,0)); for (int i=0; i<3; i+=1) { - pLine.push(((0.4+0.4i)*bsize, -0.2bsize)--((0.4+0.4i)*bsize, 0.2bsize)); - pLine.push(((0.6+0.4i)*bsize, -0.6bsize)--((0.6+0.4i)*bsize, 0.6bsize)); + pLine.push((-r+x*i, -y)--(-r+x*i, y)); + pLine.push((-r+x*(i+0.5), -Y)--(-r+x*(i+0.5), Y)); } - lchar = 0.6bsize; lcharv = 0.6bsize; - - term = TwoTerminal(beg, 1.8bsize, ang, lchar, lcharv, name, val,pLine,pMisc); + term = MultiTerminal(center=center, dir=dir, terminal_offset=terminal_offset, + label=label, value=value, label_offset=label_offset, + value_offset=value_offset, pLine=pLine, pMisc=pMisc); if (draw == true) term.draw(); return term; @@ -456,31 +437,83 @@ TwoTerminal battery(pair beg=(0,0), real ang=0, string name="", string val="", //--- Switches (Llaves) --- -int NO=0, NC=1; -real ssep=3mm, swt=1.2ssep; // TODO remove swt? +int open=0, closed=1; +real switch_size = 3mm; + +/* Helper function for constructing switch paths. */ +path[] _switch_lines(pair terminal_offset[], real theta) +{ + path pLine[] = {}; + real r = switch_size/2; + real dy = switch_size/6; // little nub where the switch closes + pLine.push((-r,0)--((-r,0)+switch_size*dir(theta))); + for (int i=0; i < terminal_offset.length; i+=1) { + pLine.push(shift(terminal_offset[i])*scale(dy)*unitcircle); + } + return pLine; +} /* `switch' is a Asymptote keyword (or it should be), so append SPST * for Single Pole Single Throw. */ -TwoTerminal switchSPST(pair beg=(0,0), real ang=0, int type=NO, string name="", - string val="", bool draw=true) +MultiTerminal switchSPST(pair beg=(0,0), real dir=0, int type=closed, + Label label="", Label value="", bool draw=true) { - path pLine[]={}, pMisc[]={}; - real lchar, lcharv; - TwoTerminal term; + path pLine[] = {}; + real theta, label_offset, value_offset; + MultiTerminal term; + pair center = _offset(beg=beg, length=switch_size/2, dir=dir); + pair terminal_offset[] = { + (-switch_size/2, 0), + (switch_size/2, 0)}; + + value_offset = 0; + if (type==open) { + theta = 35; + } else if (type==closed) { + theta = 10; + } else { + write("Error, unrecognized switchSPST type ",type); + } + pLine = _switch_lines(terminal_offset=terminal_offset, theta=theta); + label_offset = switch_size*Sin(theta); + term = MultiTerminal(center=center, dir=dir, terminal_offset=terminal_offset, + label=label, value=value, label_offset=label_offset, + value_offset=value_offset, pLine=pLine); + if (draw == true) + term.draw(); + return term; +} - pLine.push((0,0)--(0.7ssep,0)); - pLine.push((1.7ssep,ssep/3)--(1.7ssep,0)--(2.4ssep,0)); - lchar = 0.6ssep; lcharv = 0.6ssep; +int closed_a=1, closed_b=2; - if (type==NO) { - pLine.push((0.7ssep,0)--(1.8ssep,0.7ssep)); - } else if (type==NC) { - pLine.push((0.7ssep,0)--(2ssep,ssep/3)); +/* A Single Pole Double Throw switch. */ +MultiTerminal switchSPDT(pair beg=(0,0), real dir=0, int type=open, + Label label="", Label value="", bool draw=true) +{ + path pLine[] = {}; + real theta, label_offset, value_offset; + MultiTerminal term; + pair center = _offset(beg=beg, length=switch_size/2, dir=dir); + pair terminal_offset[] = { + (-switch_size/2, 0), + (switch_size*sqrt(3)/4, switch_size/2), + (switch_size*sqrt(3)/4, -switch_size/2)}; + + label_offset = value_offset = switch_size/2; + if (type==open) { + theta = 0; + } else if (type==closed_a) { + theta = 20; + } else if (type==closed_b) { + theta = -20; } else { write("Error, unrecognized switchSPST type ",type); } - term = TwoTerminal(beg, 2.4ssep, ang, lchar, lcharv, name, val, pLine,pMisc); + pLine = _switch_lines(terminal_offset=terminal_offset, theta=theta); + term = MultiTerminal(center=center, dir=dir, terminal_offset=terminal_offset, + label=label, value=value, label_offset=label_offset, + value_offset=value_offset, pLine=pLine); if (draw == true) term.draw(); return term; @@ -488,20 +521,27 @@ TwoTerminal switchSPST(pair beg=(0,0), real ang=0, int type=NO, string name="", //--- Current (Corriente) --- -real isize=2mm; +real current_size = 2mm; -// adjusted from makecirc original to center arrowhead under text -TwoTerminal current(pair beg=(0,0), real ang=0, string name="", string val="", - bool draw=true) +MultiTerminal current(pair beg=(0,0), real dir=0, + Label label="", Label value="", bool draw=true) { path pLine[]={}, pMisc[]={}; - real lchar, lcharv; - TwoTerminal term; - lchar = 0.4isize; lcharv = 0.4isize; - pLine.push((0,0)--(1.5isize,0)); - pLine.push((1.5isize,0)--(2isize,0)); - pMisc.push(fullhead(pLine[0], isize, 45)); - term = TwoTerminal(beg, 2isize, ang, lchar, lcharv, name, val, pLine, pMisc); + real label_offset, value_offset; + real len = 2*current_size; + MultiTerminal term; + pair center = _offset(beg=beg, length=len/2, dir=dir); + pair terminal_offset[] = { + (-len/2, 0), + (len/2, 0)}; + + label_offset = value_offset = 0.4*current_size; + pLine.push((-len/2, 0) -- (current_size/2, 0)); + pLine.push((current_size/2, 0) -- (len/2, 0)); + pMisc.push(fullhead(pLine[0], current_size, 45)); + term = MultiTerminal(center=center, dir=dir, terminal_offset=terminal_offset, + label=label, value=value, label_offset=label_offset, + value_offset=value_offset, pLine=pLine, pMisc=pMisc); if (draw == true) term.draw(); return term; @@ -509,23 +549,28 @@ TwoTerminal current(pair beg=(0,0), real ang=0, string name="", string val="", //--- Circle-based symbols (for internal use) -- -real circle_size=6mm; +real circle_size = 6mm; -TwoTerminal _two_terminal_circle(pair beg=(0,0), real ang=0, string name="", - string val="") +MultiTerminal _circle_symbol(pair beg=(0,0), real dir=0, + Label label="", Label value="") { - path pLine[]={}, pMisc[]={}; - real len, lchar, lcharv, r = circle_size/2; - pair c = (2r,0); - TwoTerminal term; - - len = 2*circle_size; - lchar = lcharv = r; - c = (circle_size, 0); - pLine.push((0,0)--(r,0)); - pLine.push(shift(c)*scale(r)*(E..N..W..S..E)); - pLine.push((3r,0)--(4r,0)); - term = TwoTerminal(beg, len, ang, lchar, lcharv, name, val, pLine, pMisc); + path pLine[]={}; + real label_offset, value_offset; + real len = 2*circle_size; + real r = circle_size/2; + MultiTerminal term; + pair center = _offset(beg=beg, length=r, dir=dir); + pair terminal_offset[] = { + (-len/2, 0), + (len/2, 0)}; + + label_offset = value_offset = r; + pLine.push((-len/2, 0) -- (-r, 0)); + pLine.push((r, 0) -- (len/2, 0)); + pLine.push(scale(r)*(E..N..W..S..E)); + term = MultiTerminal(center=center, dir=dir, terminal_offset=terminal_offset, + label=label, value=value, label_offset=label_offset, + value_offset=value_offset, pLine=pLine); return term; } @@ -533,34 +578,45 @@ TwoTerminal _two_terminal_circle(pair beg=(0,0), real ang=0, string name="", int AC=0,DC=1,I=2,V=3; -TwoTerminal source(pair beg=(0,0), real ang=0, int type=AC, string name="", - string val="", bool draw=true) +MultiTerminal source(pair beg=(0,0), real dir=0, int type=AC, + Label label="", Label value="", bool draw=true) { - TwoTerminal term; + MultiTerminal term; if (type == AC || type == I || type == V) { - real s = circle_size; - term = _two_terminal_circle(beg=beg, ang=ang, name=name, val=val); + real r = circle_size/2; + term = _circle_symbol(beg=beg, dir=dir, label=label, value=value); if (type == AC) { - term.pLine.push((2s/3,0){NE}..{E}((1/3+.5)*s,.2s)..{SE}(s,0)..{E}((2/3+.5)*s,-.2s)..{NE}(4s/3,0)); + term.pLine.push((-2r/3,0){NE}..{E}(-r/3,.4r)..{SE}(0,0)..{E}(r/3,-.4r)..{NE}(2r/3,0)); } else if (type == I) { - term.pLine.push((2s/3,0)--(4s/3,0)); - term.pLine.push(fullhead(term.pLine[3], 4s/15, 30)); + term.pLine.push((-2r/3,0)--(2r/3,0)); + term.pLine.push(fullhead(term.pLine[3], 8r/15, 30)); } else if (type == V) { - term.pLine.push((1.05s,0)--(1.45s,0)); - term.pLine.push((1.25s,-.2s)--(1.25s,.2s)); - term.pLine.push((.95s,0)--(.55s,0)); + term.pLine.push((-0.9r,0)--(-0.1r,0)); + term.pLine.push((0.5r,-.4r)--(0.5r,.4r)); + term.pLine.push((0.1r,0)--(0.9r,0)); } } else if (type == DC) { - path pLine[] = {}; - real len, lchar, lcharv; - len = circle_size; - lchar = 0.6len; lcharv = .6len; - pLine.push((0,0)--(0.4len,0)); - pLine.push((.6len,0)--(len,0)); - pLine.push((.4len,-.2len)--(.4len,.2len)); - pLine.push((.6len,-.6len)--(.6len,.6len)); - term = TwoTerminal(beg, len, ang, lchar, lcharv, name, val, pLine); + path pLine[]={}; + real label_offset, value_offset; + real len = battery_size; + real x = 0.2*battery_size; + real Y = 0.6*battery_size; + real y = 0.2*battery_size; + pair center = _offset(beg=beg, length=len/2, dir=dir); + pair terminal_offset[] = { + (-len/2, 0), + (len/2, 0)}; + + label_offset = value_offset = Y; + pLine.push((-len/2,0)--(-x/2,0)); + pLine.push((x/2,0)--(len/2,0)); + pLine.push((-x/2, -y)--(-x/2, y)); + pLine.push((x/2, -Y)--(x/2, Y)); + term = MultiTerminal(center=center, dir=dir, + terminal_offset=terminal_offset, + label=label, value=value, label_offset=label_offset, + value_offset=value_offset, pLine=pLine); } if (draw == true) term.draw(); @@ -690,7 +746,7 @@ TwoTerminal motor(pair beg, real ang, string name, string val) { path pLine; TwoTerminal term; - + if (type==Up) { pLine = (0,0)--(coil,0); for (int i=2; i<=4; i+=1) @@ -888,22 +944,20 @@ enddef; int illuminating = 1; -TwoTerminal lamp(pair beg=(0,0), real ang=0, int type=normal, - string name="", string val="", bool draw=true) +MultiTerminal lamp(pair beg=(0,0), real dir=0, int type=normal, + Label label="", Label value="", bool draw=true) { real r = 0.5*circle_size; - pair c; - TwoTerminal term; + MultiTerminal term; - term = _two_terminal_circle(beg=beg, ang=ang, name=name, val=val); - pair c = (2r, 0); + term = _circle_symbol(beg=beg, dir=dir, label=label, value=value); if (type==normal) { - term.pLine.push((c - r*dir(45)) -- (c + r*dir(45))); - term.pLine.push((c - r*dir(-45)) -- (c + r*dir(-45))); + term.pLine.push(-r*dir(45) -- r*dir(45)); + term.pLine.push(-r*dir(-45) -- r*dir(-45)); } else if (type==illuminating) { - term.pLine.push((c - (r,0)) -- (c - (r/2,0))); - term.pLine.push((c + (r/2,0)) -- (c + (r,0))); - term.pLine.push(shift(c)*scale(r/2)*(E..N..W)); + term.pLine.push((-r,0) -- (-r/2,0)); + term.pLine.push((r/2,0) -- (r,0)); + term.pLine.push(scale(r/2)*(E..N..W)); } if (draw == true) term.draw(); @@ -1010,7 +1064,7 @@ enddef; // Loop symbols for Kirchhoff's rules. void kirchhoff_loop(picture pic=currentpicture, pair points[], - pen outline=kirchhoff_pen, real aspace=-1) { + pen outline=kirchhoff_pen, real aspace=-1) { // draw kirchhoff loop underneath currentpicture picture newpic; int i;