1 /* Useful functions for drawing circuit diagrams.
4 * Copyright (C) 2003 GS Bustamante Argañaraz
5 * 2008-2012 W. Trevor King <wking@drexel.edu>
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License along
18 * with this program; if not, write to the Free Software Foundation, Inc.,
19 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
22 * Based on MetaPost's MakeCirc by Gustavo Sebastian Bustamante Argañaraz.
23 * http://www.ctan.org/tex-archive/help/Catalogue/entries/makecirc.html
26 // Command definitions for easier labeling
28 texpreamble("\def\ohm{\ensuremath{\,\Omega}}");
29 texpreamble("\def\kohm{\,k\ensuremath{\Omega}}");
30 texpreamble("\def\modarg#1#2{\setbox0=\hbox{$\mkern-1mu/#2^\circ$}\dp0=.21ex $#1\underline{\box0}$}");
33 int norotatelabel = 1;
34 int labeling = rotatelabel;
36 // Macros for the pens, I define them as such so when they expand,
37 // look for the last value assigned to linewd and use it
38 // (thanks to JLD). The linewd value assigns it as newinternal to
39 // be able to change it «from out».
43 pen line = linewidth(linewd);
44 pen misc = linewidth(0.8*linewd);
45 pen kirchhoff_pen = linewidth(10*linewd)+gray(0.7);
47 // Arrowhead definitions
49 real ahlength = 4bp; // Arrowhead length
50 real ahangle = 30; // Arrowhead angle
52 path miscahead (path p)
54 real t = reltime(p, 1.0);
57 path a = shift(A)*((0,0)--(scale(ahlength)*rotate(15)*u));
58 path b = shift(A)*((0,0)--(scale(ahlength)*rotate(-15)*u));
59 return (a & reverse(a) & b & reverse(b))--cycle;
62 path fullhead (path p, real length=ahlength, real angle=ahangle)
64 real t = reltime(p, 1.0);
67 path a = shift(A)*((0,0)--(scale(length)*rotate(angle/2)*u));
68 path b = shift(A)*((0,0)--(scale(length)*rotate(-angle/2)*u));
69 return (A -- a -- reverse(b) --cycle);
72 path bjtahead (path p)
74 pair A = point(p,reltime(p,0.7));
75 pair u = -dir(p,reltime(p,0.5));
76 path a = shift(A)*((0,0)--(scale(ahlength)*rotate(20)*u));
77 path b = shift(A)*((0,0)--(scale(ahlength)*rotate(-20)*u));
78 return (a & reverse(a) & b & reverse(b))--cycle;
81 // function to wire the symbols together
83 int nsq=0, udsq=2, rlsq=3;
85 void wire(pair pin_beg, pair pin_end, int type=nsq, real dist=0)
89 draw(pin_beg--pin_end, line);
90 } else if (type==udsq) {
91 draw(pin_beg--(pin_beg.x,pin_end.y)--pin_end, line);
92 } else if (type==rlsq) {
93 draw(pin_beg--(pin_end.x,pin_beg.y)--pin_end, line);
95 write("Error, unrecognized wire type ",type);
99 draw(pin_beg--(pin_beg+(0,dist))--(pin_end.x,pin_beg.y + dist)
101 } else if (type==rlsq) {
102 draw(pin_beg--(pin_beg+(dist,0))--(pin_beg.x + dist,pin_end.y)
105 write("Error, unrecognized wire type ",type);
110 // ----- Here the symbols begin --------
112 transform _shift_transform(pair z) = shift;
114 struct MultiTerminal {
118 pair terminal_offset[];
123 path pLine[]; // cyclic paths are filled in
128 void set_terminals() {
129 for (int i=0; i < this.terminal_offset.length; i+=1) {
130 this.terminal[i] = this.center +
131 rotate(this.dir)*this.terminal_offset[i];
135 void operator init(pair center=(0,0), real dir=0,
136 pair terminal[]={}, pair terminal_offset[]={},
137 Label label="", Label value="",
138 real label_offset=0, real value_offset=0,
139 path pLine[]={}, path pMisc[]={},
140 pen line=line, pen misc=misc) {
141 this.center = center;
142 this.dir = dir % 360;
143 this.terminal = terminal;
144 this.terminal_offset = terminal_offset;
145 this.set_terminals();
148 this.label_offset = label_offset;
149 this.value_offset = value_offset;
156 /* Shift position by a */
159 this.set_terminals();
162 void draw_label(picture pic=currentpicture, Label L=null, real offset=0,
163 pair default_direction=(0,0)) {
169 if ((L.align == NoAlign || L.align.dir == (0,0)) &&
170 default_direction != (0,0)) {
171 L.align = rotate(this.dir)*default_direction;
173 if (L.align != NoAlign && L.align != Align) {
174 real m = labelmargin(L.p);
175 real scale = (m + offset)/m;
177 L.align.dir3 *= scale;
179 L.align.dir *= scale;
182 label(pic=pic, L=L, position=this.center);
186 /* Rather than placing the element with a point and direction (mid,
187 * dir), center an element between the pairs a and b. The optional
188 * offset shifts the element in the direction rotated(90)*(b-a)
189 * (i.e. up for offset > 0 if b is directly right of a).
191 void centerto(pair a, pair b, real offset=0) {
192 this.dir = degrees(b-a);
193 this.center = (a+b)/2 + offset*dir(this.dir+90);
194 this.set_terminals();
197 void draw(picture pic=currentpicture) {
198 for (int i=0; i< pLine.length; i+=1) {
199 path p = _shift_transform(this.center)*rotate(this.dir)*pLine[i];
201 filldraw(pic, p, this.line, this.line);
203 draw(pic, p, this.line);
205 for (int i=0; i< pMisc.length; i+=1) {
206 path p = _shift_transform(this.center)*rotate(this.dir)*pMisc[i];
208 filldraw(pic, p, this.misc, this.misc);
210 draw(pic, p, this.misc);
212 this.draw_label(pic=pic, L=this.label, offset=this.label_offset,
213 default_direction=N);
214 this.draw_label(pic=pic, L=this.value, offset=this.value_offset,
215 default_direction=S);
219 pair _offset(pair beg=(0,0), real length=1, real dir=0) {
220 return beg + rotate(dir)*(length, 0);
223 void two_terminal_centerto(MultiTerminal reference, MultiTerminal target,
224 real offset=0, bool reverse=false)
226 if (reverse == false)
227 target.centerto(reference.terminal[0], reference.terminal[1], offset);
229 target.centerto(reference.terminal[1], reference.terminal[0], offset);
232 // --- Resistor (Resistencia) ---
235 int normal=0, variable=2;
237 MultiTerminal resistor(pair beg=(0,0), real dir=0, int type=normal,
238 Label label="", Label value="", bool draw=true)
240 path pLine, pLines[]={}, pMisc[]={};
243 pair center = _offset(beg=beg, length=len/2, dir=dir);
244 pair terminal_offset[] = {
248 pLine = (-len/2,0)--(-1.5rstlth,0)--(-1.25rstlth,.75rstlth);
249 for (real i=.5; i<=2.5; i+=0.5)
250 pLine = pLine--((-1.25+i)*rstlth,((-1)**(2i))*.75rstlth);
251 pLine = pLine -- (1.5rstlth,0)--(len/2,0);
254 } else if (type==variable) {
256 pMisc.push((-1.5rstlth,-rstlth)--(1.5rstlth,rstlth));
257 pMisc.push(miscahead((-1.5rstlth,-rstlth)--(1.5rstlth,rstlth)));
259 write("Error, unrecognized resistor type ",type);
262 term = MultiTerminal(center=center, dir=dir, terminal_offset=terminal_offset,
263 label=label, value=value, label_offset=.8rstlth, value_offset=.8rstlth,
264 pLine=pLines, pMisc=pMisc);
270 // --- Inductor (bobina) ---
275 MultiTerminal inductor(pair beg=(0,0), real dir=0, int type=Up,
276 Label label="", Label value="", bool draw=true)
281 pair center = _offset(beg=beg, length=len/2, dir=dir);
282 pair terminal_offset[] = {
286 pLine = (-len/2,0) -- (-2coil,0);
289 for (int i=-1; i<=2; i+=1)
290 pLine = pLine{N}..{S}(i*coil,0);
291 } else if (type==Down) {
292 for (int i=-1; i<=2; i+=1)
293 pLine = pLine{S}..{N}(i*coil,0);
295 write("Error, unrecognized inductor type ",type);
297 pLine = pLine -- (len/2,0);
299 term = MultiTerminal(center=center, dir=dir, terminal_offset=terminal_offset,
300 label=label, value=value, label_offset=.8rstlth, value_offset=.8rstlth,
307 // --- Capacitor (condensador) ---
310 int normal=0, electrolytic=1, variable=2, variant=3;
312 MultiTerminal capacitor(pair beg=(0,0), real dir=0, int type=normal,
313 Label label="", Label value="", bool draw=true)
315 path pLine[]={}, pMisc[]={};
318 pair center = _offset(beg=beg, length=len/2, dir=dir);
319 pair terminal_offset[] = {
323 pLine.push((-len/2,0)--(-platsep/2,0));
324 pLine.push((platsep/2,0)--(len/2,0));
327 pLine.push((-platsep/2,-2.5platsep)--(-platsep/2,2.5platsep));
328 pLine.push((platsep/2,-2.5platsep)--(platsep/2,2.5platsep));
329 } else if (type==electrolytic) {
330 pLine.push((-platsep/2,-1.8platsep)--(-platsep/2,1.8platsep));
331 pLine.push((-1.5platsep,-2.5platsep)--(platsep/2,-2.5platsep)
332 --(platsep/2,+2.5platsep)--(-1.5platsep,2.5platsep));
333 } else if (type==variable) {
334 pLine.push((-platsep/2,-2.5platsep)--(-platsep/2,2.5platsep));
335 pLine.push((platsep/2,-2.5platsep)--(platsep/2,2.5platsep));
336 pMisc.push((-2.5platsep,-2.5platsep)--(2.5platsep,2.5platsep));
338 pMisc.push(miscahead((-2.5platsep,-2.5platsep)--(2.5platsep,2.5platsep)));
339 } else if (type==variant) {
340 pLine.push((-platsep/2,-2.5platsep)--(-platsep/2,2.5platsep));
341 pLine.push((platsep,-2.5platsep)..(platsep/2,0)..(platsep,2.5platsep));
343 write("Error, unrecognized capacitor type ",type);
345 term = MultiTerminal(center=center, dir=dir, terminal_offset=terminal_offset,
346 label=label, value=value, label_offset=2.5platsep,
347 value_offset=2.5platsep, pLine=pLine, pMisc=pMisc);
353 // --- Diode (diodo) ---
355 real diode_height = 3.5mm;
357 // I droped the pin parameters, since other device (e.g. electrolytic
358 // capacitors) are also polarized. The positioning method centerto(),
359 // provides enough flexibility.
361 MultiTerminal diode(pair beg=(0,0), real dir=0, int type=normal,
362 Label label="", Label value="", bool draw=true)
364 path pLine[]={}, pMisc[]={};
365 real len = 3*diode_height;
366 real r = diode_height/2;
367 real label_offset, value_offset;
369 pair center = _offset(beg=beg, length=len/2, dir=dir);
370 pair terminal_offset[] = {
374 label_offset = value_offset = r;
375 pLine.push((-len/2,0)--(-r,0)--(-r,r)--(r,0)--(-r,-r)--(-r,0));
376 pLine.push((r,0)--(len/2,0));
379 pLine.push((r,-r)--(r,r));
380 } else if (type==zener) {
381 pLine.push((2r,-r)--(r,-r)--(r,r)--(0,r));
382 } else if (type==LED) {
383 path a = (-r,r)--(r,0);
384 pair u = unit((0.5, 1)); // perpendicular to a
385 path b = (0,0)--diode_height*u;
386 pLine.push((r,-r)--(r,r));
387 label_offset = 1.5*diode_height;
388 pMisc.push(shift(point(a,reltime(a,0.25))+point(b,0.33))*((0,0)--diode_height*u));
389 pMisc.push(shift(point(a,reltime(a,0.60))+point(b,0.33))*((0,0)--diode_height*u));
390 pMisc.push(fullhead(pMisc[0], 0.4*diode_height, 30));
391 pMisc.push(fullhead(pMisc[1], 0.4*diode_height, 30));
393 write("Error, unrecognized diode type ",type);
395 term = MultiTerminal(center=center, dir=dir, terminal_offset=terminal_offset,
396 label=label, value=value, label_offset=label_offset,
397 value_offset=value_offset, pLine=pLine, pMisc=pMisc);
403 //--- Battery (bater'ia) ---
405 real battery_size = 6mm;
407 MultiTerminal battery(pair beg=(0,0), real dir=0,
408 Label label="", Label value="", bool draw=true)
410 path pLine[]={}, pMisc[]={};
411 real len = 1.8*battery_size;
412 real r = battery_size/2;
413 real x = 0.4*battery_size;
414 real Y = 0.6*battery_size;
415 real y = 0.2*battery_size;
416 real label_offset, value_offset;
418 pair center = _offset(beg=beg, length=len/2, dir=dir);
419 pair terminal_offset[] = {
423 label_offset = value_offset = Y;
424 pLine.push((-len/2,0)--(-r,0));
425 pLine.push((r,0)--(len/2,0));
426 for (int i=0; i<3; i+=1) {
427 pLine.push((-r+x*i, -y)--(-r+x*i, y));
428 pLine.push((-r+x*(i+0.5), -Y)--(-r+x*(i+0.5), Y));
430 term = MultiTerminal(center=center, dir=dir, terminal_offset=terminal_offset,
431 label=label, value=value, label_offset=label_offset,
432 value_offset=value_offset, pLine=pLine, pMisc=pMisc);
438 //--- Switches (Llaves) ---
440 int open=0, closed=1;
441 real switch_size = 3mm;
443 /* Helper function for constructing switch paths. */
444 path[] _switch_lines(pair terminal_offset[], real theta)
447 real r = switch_size/2;
448 real dy = switch_size/6; // little nub where the switch closes
449 pLine.push((-r,0)--((-r,0)+switch_size*dir(theta)));
450 for (int i=0; i < terminal_offset.length; i+=1) {
451 pLine.push(shift(terminal_offset[i])*scale(dy)*unitcircle);
456 /* `switch' is a Asymptote keyword (or it should be), so append SPST
457 * for Single Pole Single Throw.
459 MultiTerminal switchSPST(pair beg=(0,0), real dir=0, int type=open,
460 Label label="", Label value="", bool draw=true)
463 real theta, label_offset, value_offset;
465 pair center = _offset(beg=beg, length=switch_size/2, dir=dir);
466 pair terminal_offset[] = {
473 } else if (type==closed) {
476 write("Error, unrecognized switchSPST type ",type);
478 pLine = _switch_lines(terminal_offset=terminal_offset, theta=theta);
479 label_offset = switch_size*Sin(theta);
480 term = MultiTerminal(center=center, dir=dir, terminal_offset=terminal_offset,
481 label=label, value=value, label_offset=label_offset,
482 value_offset=value_offset, pLine=pLine);
488 int closed_a=1, closed_b=2;
490 /* A Single Pole Double Throw switch. */
491 MultiTerminal switchSPDT(pair beg=(0,0), real dir=0, int type=open,
492 Label label="", Label value="", bool draw=true)
495 real theta, label_offset, value_offset;
497 pair center = _offset(beg=beg, length=switch_size/2, dir=dir);
498 pair terminal_offset[] = {
500 (switch_size*sqrt(3)/4, switch_size/2),
501 (switch_size*sqrt(3)/4, -switch_size/2)};
503 label_offset = value_offset = switch_size/2;
506 } else if (type==closed_a) {
508 } else if (type==closed_b) {
511 write("Error, unrecognized switchSPST type ",type);
513 pLine = _switch_lines(terminal_offset=terminal_offset, theta=theta);
514 term = MultiTerminal(center=center, dir=dir, terminal_offset=terminal_offset,
515 label=label, value=value, label_offset=label_offset,
516 value_offset=value_offset, pLine=pLine);
522 //--- Current (Corriente) ---
524 real current_size = 2mm;
526 MultiTerminal current(pair beg=(0,0), real dir=0,
527 Label label="", Label value="", bool draw=true)
529 path pLine[]={}, pMisc[]={};
530 real label_offset, value_offset;
531 real len = 2*current_size;
533 pair center = _offset(beg=beg, length=len/2, dir=dir);
534 pair terminal_offset[] = {
538 label_offset = value_offset = 0.4*current_size;
539 pLine.push((-len/2, 0) -- (current_size/2, 0));
540 pLine.push((current_size/2, 0) -- (len/2, 0));
541 pMisc.push(fullhead(pLine[0], current_size, 45));
542 term = MultiTerminal(center=center, dir=dir, terminal_offset=terminal_offset,
543 label=label, value=value, label_offset=label_offset,
544 value_offset=value_offset, pLine=pLine, pMisc=pMisc);
550 //--- Circle-based symbols (for internal use) --
552 real circle_size = 6mm;
554 MultiTerminal _circle_symbol(pair beg=(0,0), real dir=0,
555 Label label="", Label value="")
558 real label_offset, value_offset;
559 real len = 2*circle_size;
560 real r = circle_size/2;
562 pair center = _offset(beg=beg, length=r, dir=dir);
563 pair terminal_offset[] = {
567 label_offset = value_offset = r;
568 pLine.push((-len/2, 0) -- (-r, 0));
569 pLine.push((r, 0) -- (len/2, 0));
570 pLine.push(scale(r)*(E..N..W..S..E));
571 term = MultiTerminal(center=center, dir=dir, terminal_offset=terminal_offset,
572 label=label, value=value, label_offset=label_offset,
573 value_offset=value_offset, pLine=pLine);
577 //--- Sources (fuentes de alimentaci'on) ---
579 int AC=0,DC=1,I=2,V=3;
581 MultiTerminal source(pair beg=(0,0), real dir=0, int type=AC,
582 Label label="", Label value="", bool draw=true)
586 if (type == AC || type == I || type == V) {
587 real r = circle_size/2;
588 term = _circle_symbol(beg=beg, dir=dir, label=label, value=value);
590 term.pLine.push((-2r/3,0){NE}..{E}(-r/3,.4r)..{SE}(0,0)..{E}(r/3,-.4r)..{NE}(2r/3,0));
591 } else if (type == I) {
592 term.pLine.push((-2r/3,0)--(2r/3,0));
593 term.pLine.push(fullhead(term.pLine[3], 8r/15, 30));
594 } else if (type == V) {
595 term.pLine.push((-0.9r,0)--(-0.1r,0));
596 term.pLine.push((0.5r,-.4r)--(0.5r,.4r));
597 term.pLine.push((0.1r,0)--(0.9r,0));
599 } else if (type == DC) {
601 real label_offset, value_offset;
602 real len = battery_size;
603 real x = 0.2*battery_size;
604 real Y = 0.6*battery_size;
605 real y = 0.2*battery_size;
606 pair center = _offset(beg=beg, length=len/2, dir=dir);
607 pair terminal_offset[] = {
611 label_offset = value_offset = Y;
612 pLine.push((-len/2,0)--(-x/2,0));
613 pLine.push((x/2,0)--(len/2,0));
614 pLine.push((-x/2, -y)--(-x/2, y));
615 pLine.push((x/2, -Y)--(x/2, Y));
616 term = MultiTerminal(center=center, dir=dir,
617 terminal_offset=terminal_offset,
618 label=label, value=value, label_offset=label_offset,
619 value_offset=value_offset, pLine=pLine);
628 //%%<--- Transistor --->%%%
629 newinternal npn, pnp, cnpn, cpnp, bjtlth;
630 npn=1; pnp=-1; cnpn=0; cpnp=2; bjtlth=7mm;
632 vardef transistor@#(expr z,type,ang)=
634 pair T@#.B,T@#.E,T@#.C; % pines: Base, Emisor, Colector %
636 T@#.E=(z+(bjtlth,-.75bjtlth)) rotatedaround(z,ang);
637 T@#.C=(z+(bjtlth,.75bjtlth)) rotatedaround(z,ang);
641 addto BJT doublepath z--(z+(.5bjtlth,0)) withpen line;
642 addto BJT doublepath (z+(.5bjtlth,-.5bjtlth))--(z+(.5bjtlth,.5bjtlth)) withpen line;
643 addto BJT doublepath (z+(.5bjtlth,.2bjtlth))--(z+(bjtlth,.5bjtlth))
644 --(z+(bjtlth,.75bjtlth)) withpen line;
647 addto BJT doublepath (z+(.5bjtlth,-.2bjtlth))--(z+(bjtlth,-.5bjtlth))
648 --(z+(bjtlth,-.75bjtlth)) withpen line;
649 addto BJT contour bjtahead (z+(.5bjtlth,-.2bjtlth))
650 --(z+(bjtlth,-.5bjtlth)) withpen line;
652 addto BJT doublepath (z+(.5bjtlth,-.2bjtlth))--(z+(bjtlth,-.5bjtlth))
653 --(z+(bjtlth,-.75bjtlth)) withpen line;
654 addto BJT contour bjtahead (z+(.5bjtlth,-.2bjtlth))
655 --(z+(bjtlth,-.5bjtlth)) withpen line;
656 addto BJT doublepath fullcircle scaled 1.3bjtlth shifted (z+(.65bjtlth,0))
659 addto BJT doublepath (z+(bjtlth,-.75bjtlth))--(z+(bjtlth,-.5bjtlth))
660 --(z+(.5bjtlth,-.2bjtlth)) withpen line;
661 addto BJT contour bjtahead (z+(bjtlth,-.5bjtlth))
662 --(z+(.5bjtlth,-.2bjtlth)) withpen line;
664 addto BJT doublepath (z+(bjtlth,-.75bjtlth))--(z+(bjtlth,-.5bjtlth))
665 --(z+(.5bjtlth,-.2bjtlth)) withpen line;
666 addto BJT contour bjtahead (z+(bjtlth,-.5bjtlth))
667 --(z+(.5bjtlth,-.2bjtlth)) withpen line;
668 addto BJT doublepath fullcircle scaled 1.3bjtlth shifted (z+(.65bjtlth,0)) withpen line;
671 draw BJT rotatedaround(z,ang);
674 //%%<--- Measurement instruments (Intrumentos de medicion)--->%%%
675 newinternal volt, ampere, watt;
676 volt=0; ampere=1; watt=2;
678 vardef meains@#(expr z,type,ang,name)=
680 pair mi@#.l, mi@#.r, mi@#.p; % pines %
681 mi@#.l=z; mi@#.r=(z+(2ssize,0)) rotatedaround(z,ang);
683 picture meter; meter=nullpicture;
684 addto meter doublepath z--(z+(.5ssize,0));
685 addto meter doublepath (z+(1.5ssize,0))--(z+(2ssize,0));
686 if (type=volt) || (type=ampere):
687 addto meter doublepath fullcircle scaled ssize shifted (z+(ssize,0));
689 addto meter also thelabel(latex("\textsf{V}") scaled (ssize/6mm)
690 rotated (-ang), (z+(ssize,0)));
692 addto meter also thelabel(latex("\textsf{A}") scaled (ssize/6mm)
693 rotated (-ang), (z+(ssize,0)));
696 mi@#.p=(z+(ssize,-ssize)) rotatedaround(z,ang);
697 addto meter doublepath (z+(.5ssize,-.5ssize))--(z+(.5ssize,.5ssize))
698 --(z+(1.5ssize,.5ssize))--(z+(1.5ssize,-.5ssize))--cycle;
699 addto meter doublepath (z+(ssize,-.5ssize))--(z+(ssize,-ssize));
700 addto meter also thelabel(latex("\textsf{W}") scaled (ssize/6mm)
701 rotated (-ang), (z+(ssize,0)));
704 draw meter rotatedaround(z,ang) withpen line;
706 if labeling=rotatelabel:
707 if ((ang > (-90)) && (ang <= 90)) || ((ang > 270) && (ang <= 450)):
708 label(latex(name) rotatedaround (.5[mi@#.l,mi@#.r],ang),
709 (.5ssize+lbsep)*dir (90+ang) shifted .5[mi@#.l,mi@#.r]);
710 elseif ((ang > 90) && (ang <= 270)) || ((ang > (-270)) && (ang <= (-90))):
711 label(latex(name) rotatedaround (.5[mi@#.l,mi@#.r],180+ang),
712 (.5ssize+lbsep)*dir (90+ang) shifted .5[mi@#.l,mi@#.r]);
714 elseif labeling=norotatelabel:
716 label.top(latex(name), (.5ssize+.25lbsep)*dir (90+ang)
717 shifted .5[mi@#.l,mi@#.r]);
718 elseif (ang > 0) && (ang < 90):
719 label.ulft(latex(name), (.5ssize)*dir (90+ang)
720 shifted .5[mi@#.l,mi@#.r]);
722 label.lft(latex(name),(.5ssize+.25lbsep)*dir (90+ang)
723 shifted .5[mi@#.l,mi@#.r]);
724 elseif (90 < ang) && (ang < 180):
725 label.llft(latex(name),(.5ssize)*dir (90+ang)
726 shifted .5[mi@#.l,mi@#.r]);
727 elseif (ang = 180) || (ang = (-180)):
728 label.bot(latex(name), (.5ssize+.25lbsep)*dir (90+ang)
729 shifted .5[mi@#.l,mi@#.r]);
730 elseif ((ang > 180) && (ang < 270)) || ((ang > (-180)) && (ang < (-90))):
731 label.lrt(latex(name),(.5ssize)*dir (90+ang)
732 shifted .5[mi@#.l,mi@#.r]);
733 elseif (ang = 270) || (ang = (-90)):
734 label.rt(latex(name), (.5ssize+.25lbsep)*dir (90+ang)
735 shifted .5[mi@#.l,mi@#.r]);
736 elseif ((270 < ang) && (ang < 360)) || ((ang < 0) && (ang > (-90))):
737 label.urt(latex(name),(.5ssize)*dir (90+ang)
738 shifted .5[mi@#.l,mi@#.r]);
743 // --- Electrical machines (maquinas electricas) ---
745 TwoTerminal motor(pair beg, real ang, string name, string val)
751 pLine = (0,0)--(coil,0);
752 for (int i=2; i<=4; i+=1)
753 pLine = pLine{N}..{S}(i*coil,0);
754 pLine = pLine{N}..{S}(5coil,0)--(6coil,0);
755 } else if (type==Down) {
756 pLine = (0,0)--(coil,0);
757 for (int i=2; i<=4; i+=1)
758 pLine = pLine{S}..{N}(i*coil,0);
759 pLine = pLine{S}..{N}(5coil,0)--(6coil,0);
760 // original makecirc changed labelangle to ang-180
762 term = TwoTerminal(beg, 6coil, ang, coil, coil, name, val, pLine);
763 // original makecirc used .5coil for lcharv
767 M@#.D=z; M@#.B=(z+(2ssize,0)) rotatedaround(z,ang);
768 picture mot; mot=nullpicture;
770 addto mot doublepath z--(z+(.4ssize,0));
771 addto mot doublepath (z+(1.6ssize,0))--(z+(2ssize,0));
772 addto mot doublepath fullcircle scaled ssize shifted (z+(ssize,0));
773 addto mot also thelabel(latex("\textsf{M}") scaled (ssize/6mm)
774 rotated (-ang), (z+(ssize,0)));
776 path p,q,r,s,ca,cb,c,hc;
777 p=(z+(.6ssize,.075ssize))--(z+(.4ssize,.075ssize));
778 q=(z+(.4ssize,.075ssize))--(z+(.4ssize,-.075ssize));
779 ca=(z+(.4ssize,-.075ssize))--(z+(.6ssize,-.075ssize));
782 r=(z+(1.4ssize,.075ssize))--(z+(1.6ssize,.075ssize));
783 s=(z+(1.6ssize,.075ssize))--(z+(1.6ssize,-.075ssize));
784 cb=(z+(1.6ssize,-.075ssize))--(z+(1.4ssize,-.075ssize));
786 c=fullcircle scaled ssize shifted (z+(ssize,0));
787 hc=halfcircle scaled ssize rotated 270 shifted (z+(ssize,0));
789 addto mot contour buildcycle(p,q,ca,c);
790 addto mot doublepath buildcycle(p,q,ca,c);
792 addto mot contour buildcycle(cb,s,r,hc);
793 addto mot doublepath buildcycle(cb,s,r,hc);
795 draw mot rotatedaround(z,ang) withpen line;
797 putlabel(M@#.D,M@#.B,.5ssize,.5ssize,ang,name,val);
800 vardef generator@#(expr z,ang,name,val)=
802 pair G@#.D, G@#.B; % pines %
803 G@#.D=z; G@#.B=(z+(2ssize,0)) rotatedaround(z,ang);
804 picture gen; gen=nullpicture;
806 addto gen doublepath z--(z+(.5ssize,0));
807 addto gen doublepath (z+(1.5ssize,0))--(z+(2ssize,0));
808 addto gen doublepath fullcircle scaled ssize shifted (z+(ssize,0));
809 addto gen also thelabel(latex("\textsf{G}") scaled (ssize/6mm)
810 rotated (-ang), (z+(ssize,0)));
812 draw gen rotatedaround(z,ang) withpen line;
814 putlabel(G@#.D,G@#.B,.5ssize,.5ssize,ang,name,val);
817 newinternal mid, Fe, auto;
820 vardef transformer@#(expr z,type,ang)=
822 pair tf@#.pi, tf@#.ps, tf@#.si, tf@#.ss, tf@#.m;
823 tf@#.pi=z; tf@#.ps=(z+(0,8coil)) rotatedaround(z,ang);
824 tf@#.si=(z+(2.4coil,0)) rotatedaround(z,ang);
825 tf@#.ss=(z+(2.4coil,8coil)) rotatedaround(z,ang);
826 tf@#.m=(z+(3.4coil,4coil)) rotatedaround(z,ang);
828 picture trafo; trafo=nullpicture;
831 tf@#.pi=z; tf@#.ps=(z+(0,8coil)) rotatedaround(z,ang);
832 tf@#.si=(z+(2.4coil,0)) rotatedaround(z,ang);
833 tf@#.ss=(z+(2.4coil,8coil)) rotatedaround(z,ang);
834 addto trafo doublepath z--(z+(0,coil)){right}..
835 for i=2 upto 6: {left}(z+(0,i*coil)){right}.. endfor
836 {left}(z+(0,7coil))--(z+(0,8coil));
837 addto trafo doublepath (z+(coil,coil))--(z+(coil,7coil));
838 addto trafo doublepath (z+(1.4coil,coil))--(z+(1.4coil,7coil));
839 addto trafo doublepath (z+(2.4coil,0))--(z+(2.4coil,coil)){left}..
840 for i=2 upto 6: {right}(z+(2.4coil,i*coil)){left}.. endfor
841 {right}(z+(2.4coil,7coil))--(z+(2.4coil,8coil));
843 tf@#.pi=z; tf@#.ps=(z+(0,8coil)) rotatedaround(z,ang);
844 tf@#.si=(z+(2.4coil,0)) rotatedaround(z,ang);
845 tf@#.ss=(z+(2.4coil,8coil)) rotatedaround(z,ang);
846 tf@#.m=(z+(3.4coil,4coil)) rotatedaround(z,ang);
847 addto trafo doublepath z--(z+(0,coil)){right}..
848 for i=2 upto 6: {left}(z+(0,i*coil)){right}.. endfor
849 {left}(z+(0,7coil))--(z+(0,8coil));
850 addto trafo doublepath (z+(coil,coil))--(z+(coil,7coil));
851 addto trafo doublepath (z+(1.4coil,coil))--(z+(1.4coil,7coil));
852 addto trafo doublepath (z+(2.4coil,0))--(z+(2.4coil,coil)){left}..
853 for i=2 upto 6: {right}(z+(2.4coil,i*coil)){left}.. endfor
854 {right}(z+(2.4coil,7coil))--(z+(2.4coil,8coil));
855 addto trafo doublepath (z+(2.4coil,4coil))--(z+(3.4coil,4coil));
857 tf@#.pi=z rotatedaround(z,ang); tf@#.ps=(z+(0,5.3coil)) rotatedaround(z,ang);
858 tf@#.si=(z+(14coil,0)) rotatedaround(z,ang);
859 tf@#.ss=(z+(14coil,5.228coil)) rotatedaround(z,ang);
860 addto trafo doublepath z+(2coil,-2.5coil)--z+(12coil,-2.5coil)
861 --z+(12coil,7.5coil)--z+(2coil,7.5coil)--cycle;
862 addto trafo doublepath z+(4coil,-.5coil)--z+(10coil,-.5coil)
863 --z+(10coil,5.5coil)--z+(4coil,5.5coil)--cycle;
864 addto trafo doublepath z--z+(2coil,0)--z+(4coil,0.728coil)
865 {right}..{left}z+(4coil,1.3*coil);
867 addto trafo doublepath z+(2coil,(i+.5)*coil){left}..
868 {right}z+(2coil,i*coil)--z+(4coil,(i+0.728)*coil)
869 {right}..{left}z+(4coil,(i+1.3)*coil);
871 addto trafo doublepath z+(2coil,5.3coil)--z+(0,5.3coil);
873 addto trafo doublepath z+(10coil,i*coil){left}..
874 {right}z+(10coil,(i+.5)*coil)--z+(12coil,(i+.5+0.728)*coil)
875 {right}..{left}z+(12coil,(i+.656)*coil);
877 addto trafo doublepath z+(10coil,4coil){left}..{right}
878 z+(10coil,4.5coil)--z+(12coil,5.228coil)--z+(14coil,5.228coil);
879 addto trafo doublepath z+(12coil,0)--z+(14coil,0);
881 tf@#.pi=z rotatedaround(z,ang); tf@#.ps=(z+(0,4coil)) rotatedaround(z,ang);
882 tf@#.si=(z+(4coil,-6coil)) rotatedaround(z,ang);
883 tf@#.ss=(z+(4coil,4coil)) rotatedaround(z,ang);
884 addto trafo doublepath z--z+(2coil,0);
885 addto trafo doublepath z+(2coil,-6coil)--z+(2coil,-5coil){right}..
886 for i=2 upto 10: {left}(z+(2coil,(i-6)*coil)){right}.. endfor
887 {left}(z+(2coil,5coil))--z+(2coil,6coil)--z+(0,6coil);
888 addto trafo doublepath z+(2coil,6coil)--z+(4coil,6coil);
889 addto trafo doublepath z+(2coil,-6coil)--z+(4coil,-6coil);
892 draw trafo rotatedaround(z,ang) withpen line;
895 //%%<--- Miscellaneous symbols --->%%%
897 newinternal gndlth, implth, simple, shield;
898 gndlth=5mm; implth=7mm; simple=1; shield=2;
900 vardef ground@#(expr z,type,ang)=
902 pair gnd@#; % unico pin %
904 picture GND; GND=nullpicture;
905 addto GND doublepath z--(z+(0,-.5gndlth)) withpen line;
907 addto GND doublepath (z+(-.5gndlth,-.5gndlth))--(z+(.5gndlth,-.5gndlth)) withpen line;
908 addto GND doublepath (z+(-.35gndlth,-.6gndlth))--(z+(.35gndlth,-.6gndlth)) withpen line;
909 addto GND doublepath (z+(-.2gndlth,-.7gndlth))--(z+(.2gndlth,-.7gndlth)) withpen line;
911 addto GND doublepath (z+(-.5gndlth,-.5gndlth))--(z+(.5gndlth,-.5gndlth))
912 withpen pencircle scaled 2linewd;
914 draw GND rotatedaround(z,ang);
917 newinternal junctiondiam;
920 vardef junction@#(expr z,name)(suffix $)=
922 draw z withpen pencircle scaled junctiondiam;
923 label.$(latex(name),z);
926 vardef impedance@#(expr z,ang,name,val)=
928 pair Z@#.l, Z@#.r; % pines %
930 Z@#.r=(z+(1.5implth,0)) rotatedaround(z,ang);
931 picture imp; imp=nullpicture;
933 addto imp doublepath z--(z+(.25implth,0));
934 addto imp doublepath (z+(.25implth,-.18implth))--(z+(.25implth,.18implth))
935 --(z+(1.25implth,.18implth))--(z+(1.25implth,-.18implth))--cycle;
936 addto imp doublepath (z+(1.25implth,0))--(z+(1.5implth,0));
938 draw imp rotatedaround(z,ang) withpen line;
940 putlabel(Z@#.l,Z@#.r,.2implth,.2implth,ang,name,val);
945 int illuminating = 1;
947 MultiTerminal lamp(pair beg=(0,0), real dir=0, int type=normal,
948 Label label="", Label value="", bool draw=true)
950 real r = 0.5*circle_size;
953 term = _circle_symbol(beg=beg, dir=dir, label=label, value=value);
955 term.pLine.push(-r*dir(45) -- r*dir(45));
956 term.pLine.push(-r*dir(-45) -- r*dir(-45));
957 } else if (type==illuminating) {
958 term.pLine.push((-r,0) -- (-r/2,0));
959 term.pLine.push((r/2,0) -- (r,0));
960 term.pLine.push(scale(r/2)*(E..N..W));
969 //%%<--- Mesh current (corriente de malla) --->%%%
974 def imesh(expr c,wd,ht,dire,ang,name)=
975 save im,r; picture im; numeric r;
976 ahlength=3platsep; ahangle=20;
977 if ht > wd: r=.2wd elseif ht < wd: r=.2ht fi;
980 addto im doublepath (xpart c - .5wd, ypart c - .5ht)
981 --(xpart c - .5wd, ypart c + .5ht-r){up}
982 ..{right}(xpart c - .5wd + r, ypart c + .5ht)
983 --(xpart c + .5wd - r, ypart c + .5ht){right}
984 ..{down}(xpart c + .5wd,ypart c + .5ht - r)
985 --(xpart c + .5wd,ypart c - .5ht + r){down}
986 ..{left}(xpart c + .5wd - r,ypart c - .5ht)
987 --(xpart c - .25wd, ypart c - .5ht);
988 addto im contour arrowhead (xpart c - .5wd, ypart c - .5ht)
989 --(xpart c - .5wd, ypart c + .5ht-r){up}
990 ..{right}(xpart c - .5wd + r, ypart c + .5ht)
991 --(xpart c + .5wd - r, ypart c + .5ht){right}
992 ..{down}(xpart c + .5wd,ypart c + .5ht - r)
993 --(xpart c + .5wd,ypart c - .5ht + r){down}
994 ..{left}(xpart c + .5wd - r,ypart c - .5ht)
995 --(xpart c - .25wd, ypart c - .5ht);
997 addto im doublepath (xpart c + .5wd, ypart c - .5ht)
998 --(xpart c + .5wd, ypart c + .5ht-r){up}
999 ..{left}(xpart c + .5wd - r, ypart c + .5ht)
1000 --(xpart c - .5wd + r, ypart c + .5ht){left}
1001 ..{down}(xpart c - .5wd,ypart c + .5ht - r)
1002 --(xpart c - .5wd,ypart c - .5ht + r){down}
1003 ..{right}(xpart c - .5wd + r,ypart c - .5ht)
1004 --(xpart c + .25wd, ypart c - .5ht);
1005 addto im contour arrowhead (xpart c + .5wd, ypart c - .5ht)
1006 --(xpart c + .5wd, ypart c + .5ht-r){up}
1007 ..{left}(xpart c + .5wd - r, ypart c + .5ht)
1008 --(xpart c - .5wd + r, ypart c + .5ht){left}
1009 ..{down}(xpart c + .5wd,ypart c + .5ht - r)
1010 --(xpart c - .5wd,ypart c - .5ht + r){down}
1011 ..{right}(xpart c - .5wd + r,ypart c - .5ht)
1012 --(xpart c + .25wd, ypart c - .5ht);
1015 if labeling=rotatelabel:
1016 addto im also thelabel(latex("$" & name & "$"),c);
1017 elseif labeling=norotatelabel:
1018 addto im also thelabel(latex("$" & name & "$") rotatedaround(c,-ang),c);
1021 draw im rotatedaround (c,ang) withpen line;
1024 //%%<--- Reostatos --->%%%
1026 newinternal rheolth, Rrheo, Lrheo;
1027 rheolth=2mm; Rrheo=1; Lrheo=2;
1029 vardef rheostat@#(expr z,type,ang)=
1030 save reo; picture reo; reo=nullpicture;
1031 pair rh@#.i, rh@#.s, rh@#.r;
1032 rh@#.i=z; rh@#.s=(z+(0,6rheolth)) rotatedaround(z,ang);
1033 rh@#.r=(z+(3rheolth,6rheolth)) rotatedaround(z,ang);
1035 ahangle=20; ahlength=rheolth;
1038 addto reo doublepath (z+(6rheolth,-3rheolth))--(z+(4rheolth,-3rheolth))
1039 --(z+(4rheolth,-.7rheolth));
1040 addto reo contour arrowhead (z+(6rheolth,-3rheolth))--(z+(4rheolth,-3rheolth))
1041 --(z+(4rheolth,-.9rheolth));
1043 addto reo doublepath z--(z+(rheolth,0)){down}.. for i=2 upto 4:
1044 {up}(z+(i*rheolth,0)){down}.. endfor {up}(z+(5rheolth,0))--(z+(6rheolth,0));
1046 reo=reo rotatedaround(z,90);
1048 addto reo doublepath (z+(6rheolth,-3rheolth))--(z+(4rheolth,-3rheolth))
1049 --(z+(4rheolth,-.7rheolth));
1050 addto reo contour arrowhead (z+(6rheolth,-3rheolth))--(z+(4rheolth,-3rheolth))
1051 --(z+(4rheolth,-.9rheolth));
1053 addto reo doublepath z--(z+(1.5rheolth,0))--(z+(1.75rheolth,.75rheolth))--
1054 for i=.5 step .5 until 2.5: (z+((1.75+i)*rheolth,((-1)**(2i))*.75rheolth))--
1055 endfor (z+(4.5rheolth,0))--(z+(6rheolth,0)) withpen line;
1057 reo=reo rotatedaround(z,90);
1059 draw reo rotatedaround(z,ang) withpen line;
1064 // Loop symbols for Kirchhoff's rules.
1066 void kirchhoff_loop(picture pic=currentpicture, pair points[],
1067 pen outline=kirchhoff_pen, real aspace=-1) {
1068 // draw kirchhoff loop underneath currentpicture
1072 pair a = points[0] - points[points.length-1]; // arrow distance
1074 aspace = 3*linewidth(outline); // one dot diameter
1075 real alength = max(0.5*length(a), length(a) - aspace - linewidth(outline)/2);
1076 a = alength*unit(a);
1077 pair astop = points[points.length-1] + a;
1078 dot(newpic, points[0], scale(3)*outline);
1079 for (int i=0; i < points.length; ++i)
1082 draw(newpic, g, outline, Arrow(size=3*linewidth(outline)));
1083 add(pic, newpic, above=false);