7f6cc9113975a2cd0f9b57d2930c8158e0856463
[course.git] / asymptote / Circ.asy
1 /* Useful functions for drawing circuit diagrams.
2  * Version 0.1
3  *
4  * Copyright (C) 2003 GS Bustamante Argañaraz
5  *               2008-2011 W. Trevor King <wking@drexel.edu>
6  *
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.
11  *
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.
16  *
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.
20  *
21  *
22  * Based on MetaPost's MakeCirc by Gustavo Sebastian Bustamante Argañaraz.
23  *   http://www.ctan.org/tex-archive/help/Catalogue/entries/makecirc.html
24  */
25
26 // Command definitions for easier labeling
27
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}$}");
31
32 int rotatelabel = 0;
33 int norotatelabel = 1;
34 int labeling = rotatelabel;
35
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».
40
41 real linewd = 0.25mm;
42
43 pen line = linewidth(linewd);
44 pen misc = linewidth(0.8*linewd);
45 pen kirchhoff_pen = linewidth(10*linewd)+gray(0.7);
46
47 // Arrowhead definitions
48
49 real ahlength = 4bp; // Arrowhead length
50 real ahangle = 30;   // Arrowhead angle
51
52 path miscahead (path p)
53 {
54   real t = reltime(p, 1.0);
55   pair A = point(p,t);
56   pair u = -dir(p,t);
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;
60 }
61
62 path fullhead (path p, real length=ahlength, real angle=ahangle)
63 {
64   real t = reltime(p, 1.0);
65   pair A = point(p,t);
66   pair u = -dir(p,t);
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);
70 }
71
72 path bjtahead (path p)
73 {
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;
79 }
80
81 path txtahead (path p)
82 {
83   pair A = point(p,reltime(p,1.0));
84   pair B = point(p,reltime(p,0.97));
85   pair u = dirtime(p,reltime(p,1.0));
86   return A{-u}..(A - scale(7)*rotate(15)*u)--B
87                   --(A - scale(7)*rotate(-15)*u)..A{u}--cycle;
88 }
89
90 // function to wire the symbols together
91
92 int nsq=0, udsq=2, rlsq=3;
93
94 void wire(pair pin_beg, pair pin_end, int type=nsq, real dist=0)
95 {
96   if (dist == 0) {
97     if (type==nsq) {
98       draw(pin_beg--pin_end, line);
99     } else if (type==udsq) {
100       draw(pin_beg--(pin_beg.x,pin_end.y)--pin_end, line);
101     } else if (type==rlsq) {
102       draw(pin_beg--(pin_end.x,pin_beg.y)--pin_end, line);
103     } else {
104       write("Error, unrecognized wire type ",type);
105     }
106   } else {
107     if (type==udsq) {
108       draw(pin_beg--(pin_beg+(0,dist))--(pin_end.x,pin_beg.y + dist)
109            --pin_end, line);
110     } else if (type==rlsq) {
111       draw(pin_beg--(pin_beg+(dist,0))--(pin_beg.x + dist,pin_end.y)
112            --pin_end, line);
113     } else {
114       write("Error, unrecognized wire type ",type);
115     }
116   }
117 }
118
119 // Macro to center text among two pins
120
121 bool witharrow=false, noarrow=true;
122
123 void ctext(pair pin_beg, pair pin_end, string txt, bool type)
124 {
125   picture ctxt;
126   if (type==noarrow) {
127     ; // pass
128   } else if (type==witharrow) {
129     draw(ctxt, pin_beg--pin_end);
130     draw(ctxt, txtahead(pin_beg--pin_end));
131     draw(ctxt, txtahead(reverse(pin_beg--pin_end)));
132   } else {
133     write("Error, unrecognized ctext type ",type);
134   }
135   label(ctxt, txt, 0.5(pin_beg+pin_end));
136   add(currentpicture, ctxt);
137 }
138
139 // Definition of lbsep (label separation), distance among symbol and label.
140
141 real lbsep=3mm;
142
143
144 // ----- Here the symbols begin --------
145
146 struct TwoTerminal {
147   pair beg;
148   pair end;
149   pair mid;
150   real len;
151   real ang;
152   real lchar;
153   real lcharv;
154   string name;
155   string val;
156   path pLine[]; // cyclic paths are filled in
157   path pMisc[];
158   
159   void operator init(pair beg, real len, real ang, real lchar, real lcharv, string name, string val, path pLine[]={}, path pMisc[]={}) {
160     this.beg = beg;
161     this.end = beg+rotate(ang)*(len,0);
162     this.mid = (this.beg + this.end)/2;
163     this.len = len;
164     this.ang = ang % 360;
165     this.lchar = lchar;
166     this.lcharv = lcharv;
167     this.name = name;
168     this.val = val;
169     this.pLine = pLine;
170     this.pMisc = pMisc;
171   }
172
173   void putlabel(picture pic=currentpicture) {
174     picture picL;
175     pair pName, pVal; // point
176     real rName, rVal; // rotated by
177     align aName, aVal;
178     if (labeling==rotatelabel) {
179       pName = (lchar+lbsep)*dir (90+ang);
180       pVal = (lcharv+lbsep)*dir (270+ang);
181       aName = NoAlign;
182       aVal = NoAlign;
183       if (ang <= 90 || ang > 270) {
184         rName = ang;
185         rVal = ang;
186       } else if (ang > 90 && ang <= 270) {
187         rName = 180+ang;
188         rVal = 180+ang;
189       }
190     } else if (labeling==norotatelabel) {
191       rName = 0;
192       rVal = 0;
193       if (ang == 0) {
194         pName = (lchar+.25lbsep)*dir (90+ang);
195         pVal = (lcharv+.25lbsep)*dir (270+ang);
196         aName = N;
197         aVal = S;
198       } else if (ang < 90) {
199         pName = (lchar)*dir (90+ang);
200         pVal = (lcharv)*dir (270+ang);
201         aName = NW;
202         aVal = SE;
203       } else if (ang == 90) {
204         pName = (lchar+.25lbsep)*dir (90+ang);
205         pVal = (lcharv+.25lbsep)*dir (270+ang);
206         aName = W;
207         aVal = E;
208       } else if (90 < ang && ang < 180) {
209         pName = (lchar)*dir (90+ang);
210         pVal = (lcharv)*dir (270+ang);
211         aName = SW;
212         aVal = NE;
213       } else if (ang == 180) {
214         pName = (lchar+.25lbsep)*dir (90+ang);
215         pVal = (lcharv+.25lbsep)*dir (270+ang);
216         aName = S;
217         aVal = N;
218       } else if (ang > 180 && ang < 270) {
219         pName = (lchar)*dir (90+ang);
220         pVal = (lcharv)*dir (270+ang);
221         aName = SE;
222         aVal = NW;
223       } else if (ang == 270) {
224         pName = (lchar+.25lbsep)*dir (90+ang);
225         pVal = (lcharv+.25lbsep)*dir (270+ang);
226         aName = E;
227         aVal = W;
228       } else if (270 < ang && ang < 360) {
229         pName = (lchar)*dir (90+ang);
230         pVal = (lcharv)*dir (270+ang);
231         aName = NE;
232         aVal = SW;
233       }
234     }
235     Label lName = rotate(rName)*Label(name);
236     label(picL, lName, pName, aName);    
237     Label lVal = rotate(rVal)*Label(val);
238     label(picL, lVal, pVal, aVal);
239     add(pic, picL, (end-beg)/2);
240   }
241
242   /* Shift position by a */
243   void shift(pair a) {
244     this.beg += a;
245     this.end += a;
246     this.mid += a;
247   }
248
249   /* Rather than placing the element with a point and direction (beg,
250    * ang), center an element between the pairs a and b.  The optional
251    * offset shifts the element in the direction rotated(90)*(b-a)
252    * (i.e. up for offset > 0 if b is directly right of a).
253    */
254   void centerto(pair a, pair b, real offset=0) {
255     this.ang = degrees(b-a);
256     this.beg = (a+b)/2
257       - unit(b-a)*this.len/2 + offset*dir(this.ang+90);
258     this.end = this.beg+rotate(ang)*(this.len,0);
259     this.mid = (this.beg + this.end)/2;
260   }
261
262   void draw(picture pic=currentpicture) {
263     picture picT;
264     for (int i=0; i< pLine.length; i+=1) {
265       draw(picT, rotate(ang)*pLine[i], line);
266       if (cyclic(pLine[i]))
267         fill(picT, rotate(ang)*pLine[i], line);
268     }
269     for (int i=0; i< pMisc.length; i+=1) {
270       draw(picT, rotate(ang)*pMisc[i], misc);
271       if (cyclic(pMisc[i]))
272         fill(picT, rotate(ang)*pMisc[i], misc);
273     }
274     putlabel(picT);
275     add(pic, picT, beg);
276   }
277 }
278
279 void centerto(TwoTerminal reference, TwoTerminal target, real offset=0,
280               bool reverse=false)
281 {
282   if (reverse == false)
283     target.centerto(reference.beg, reference.end, offset);
284   else
285     target.centerto(reference.end, reference.beg, offset);
286 }
287
288 // --- Resistor (Resistencia) ---
289
290 real rstlth=2mm;
291 int normal=0, variable=2;
292
293 TwoTerminal resistor(pair beg=(0,0), real ang=0, int type=normal,
294                      string name="", string val="", bool draw=true)
295 {
296   path pLine, pMisc[]={};
297   TwoTerminal term;
298
299   pLine = (0,0)--(2rstlth,0)--(2.25rstlth,.75rstlth);
300   for (real i=.5; i<=2.5; i+=0.5)
301     pLine = pLine--((2.25+i)*rstlth,((-1)**(2i))*.75rstlth);
302   pLine = pLine -- (5rstlth,0)--(7rstlth,0);
303   if (type==normal) {
304     ; //pass
305   } else if (type==variable) {
306     ahlength=.8rstlth;
307     pMisc.push((2rstlth,-rstlth)--(5.5rstlth,rstlth));
308     pMisc.push(miscahead((2rstlth,-rstlth)--(5.5rstlth,rstlth)));
309   } else {
310     write("Error, unrecognized resistor type ",type);    
311   }
312   term = TwoTerminal(beg, 7rstlth, ang, .8rstlth, .8rstlth, name, val, pLine, pMisc);
313   if (draw == true)
314     term.draw();
315   return term;
316 }
317
318 // --- Inductor (bobina) ---
319
320 real coil=2mm;
321 int Up=0, Down=1;
322
323 TwoTerminal inductor(pair beg=(0,0), real ang=0, int type=Up, string name="",
324                      string val="", bool draw=true)
325 {
326   path pLine;
327   TwoTerminal term;
328   
329   if (type==Up) {
330     pLine = (0,0)--(coil,0);
331     for (int i=2; i<=4; i+=1)
332       pLine = pLine{N}..{S}(i*coil,0);
333     pLine = pLine{N}..{S}(5coil,0)--(6coil,0);
334   } else if (type==Down) {
335     pLine = (0,0)--(coil,0);
336     for (int i=2; i<=4; i+=1)
337       pLine = pLine{S}..{N}(i*coil,0);
338     pLine = pLine{S}..{N}(5coil,0)--(6coil,0);
339     // the original makecirc changed labelangle to ang-180
340   } else {
341     write("Error, unrecognized inductor type ",type);
342   }
343   term = TwoTerminal(beg, 6coil, ang, coil, coil, name, val, pLine);
344   // the original makecirc used .5coil for lcharv
345   if (draw == true)
346     term.draw();
347   return term;
348 }
349
350 // --- Capacitor (condensador) ---
351
352 real platsep=1mm;
353 int normal=0, electrolytic=1, variable=2, variant=3;
354
355 TwoTerminal capacitor(pair beg=(0,0), real ang=0, int type=normal,
356                       string name="", string val="", bool draw=true)
357 {
358   path pLine[]={}, pMisc[]={};
359   TwoTerminal term;
360
361   pLine.push((0,0)--(3platsep,0));
362   pLine.push((4platsep,0)--(7platsep,0));
363
364   if (type==normal) {
365     pLine.push((3platsep,-2.5platsep)--(3platsep,2.5platsep));
366     pLine.push((4platsep,-2.5platsep)--(4platsep,2.5platsep));
367   } else if (type==electrolytic) {
368     pLine.push((3platsep,-1.8platsep)--(3platsep,1.8platsep));
369     pLine.push((2platsep,-2.5platsep)--(4platsep,-2.5platsep)
370                --(4platsep,+2.5platsep)--(2platsep,2.5platsep));
371   } else if (type==variable) {
372     pLine.push((3platsep,-2.5platsep)--(3platsep,2.5platsep));
373     pLine.push((4platsep,-2.5platsep)--(4platsep,2.5platsep));
374     pMisc.push((platsep,-2.5platsep)--(6platsep,2.5platsep));
375     ahlength=1.7platsep;
376     pMisc.push(miscahead((platsep,-2.5platsep)--(6platsep,2.5platsep)));
377   } else if (type==variant) {
378     pLine.push((3platsep,-2.5platsep)--(3platsep,2.5platsep));
379     pLine.push((4.5platsep,-2.5platsep)..(4platsep,0)..(4.5platsep,2.5platsep));
380   } else {
381     write("Error, unrecognized capacitor type ",type);
382   }
383   term = TwoTerminal(beg, 7platsep, ang, 2.5platsep, 2.5platsep, name, val, pLine, pMisc);
384   if (draw == true)
385     term.draw();
386   return term;
387 }
388
389 // --- Diode (diodo) ---
390
391 real diodeht=3.5mm;
392 int zener=1, LED=2;
393 // I droped the pin parameters, since other device (e.g. electrolytic
394 // capacitors) are also polarized.  The positioning method centerto(),
395 // provides enough flexibility.
396
397 TwoTerminal diode(pair beg=(0,0), real ang=0, int type=normal, string name="",
398                   string val="", bool draw=true)
399 {
400   path pLine[]={}, pMisc[]={};
401   real lchar, lcharv;
402   TwoTerminal term;
403
404   pLine.push((0,0)--(diodeht,0)--(diodeht,.5diodeht)--(2diodeht,0)--(diodeht,-.5diodeht)--(diodeht,0));
405   pLine.push((2diodeht,0)--(3diodeht,0));
406   lchar = 0.6diodeht; lcharv = 0.6diodeht;
407   
408   if (type==normal) {
409     pLine.push((2diodeht,-.5diodeht)--(2diodeht,.5diodeht));
410   } else if (type==zener) {
411     pLine.push((2.5diodeht,-.5diodeht)--(2diodeht,-.5diodeht)--(2diodeht,.5diodeht)--(1.5diodeht,.5diodeht));
412   } else if (type==LED) {
413     path a = (diodeht,.5diodeht)--(2diodeht,0);
414     pair u = unit((.5,1)); // perpendicular to a
415     path b = (0,0)--diodeht*u;
416     pLine.push((2diodeht,-.5diodeht)--(2diodeht,.5diodeht));
417     lchar = 1.5diodeht;
418     pMisc.push(shift(point(a,reltime(a,0.25))+point(b,0.33))*((0,0)--diodeht*u));
419     pMisc.push(shift(point(a,reltime(a,0.60))+point(b,0.33))*((0,0)--diodeht*u));
420     pMisc.push(fullhead(pMisc[0], 0.4diodeht, 30));
421     pMisc.push(fullhead(pMisc[1], 0.4diodeht, 30));
422   } else {
423     write("Error, unrecognized capacitor type ",type);
424   }
425   term = TwoTerminal(beg, 3diodeht, ang, lchar, lcharv, name, val,pLine,pMisc);
426   if (draw == true)
427     term.draw();
428   return term;
429 }
430
431 //--- Battery (bater'ia) ---
432
433 real bsize = 6mm;
434
435 TwoTerminal battery(pair beg=(0,0), real ang=0, string name="", string val="",
436                     bool draw=true)
437 {
438   path pLine[]={}, pMisc[]={};
439   real lchar, lcharv;
440   TwoTerminal term;
441
442   pLine.push((0,0)--(0.4bsize,0));
443   pLine.push((1.4bsize,0)--(1.8bsize,0));
444   
445   for (int i=0; i<3; i+=1) {
446     pLine.push(((0.4+0.4i)*bsize, -0.2bsize)--((0.4+0.4i)*bsize, 0.2bsize));
447     pLine.push(((0.6+0.4i)*bsize, -0.6bsize)--((0.6+0.4i)*bsize, 0.6bsize));
448   }
449   lchar = 0.6bsize; lcharv = 0.6bsize;
450
451   term = TwoTerminal(beg, 1.8bsize, ang, lchar, lcharv, name, val,pLine,pMisc);
452   if (draw == true)
453     term.draw();
454   return term;
455 }
456
457 //--- Switches (Llaves) ---
458
459 int NO=0, NC=1;
460 real ssep=3mm, swt=1.2ssep; // TODO remove swt?
461
462 /* `switch' is a Asymptote keyword (or it should be), so append SPST
463  * for Single Pole Single Throw.
464  */
465 TwoTerminal switchSPST(pair beg=(0,0), real ang=0, int type=NO, string name="",
466                        string val="", bool draw=true)
467 {
468   path pLine[]={}, pMisc[]={};
469   real lchar, lcharv;
470   TwoTerminal term;
471
472   pLine.push((0,0)--(0.7ssep,0));
473   pLine.push((1.7ssep,ssep/3)--(1.7ssep,0)--(2.4ssep,0));
474   lchar = 0.6ssep; lcharv = 0.6ssep;
475
476   if (type==NO) {
477     pLine.push((0.7ssep,0)--(1.8ssep,0.7ssep));
478   } else if (type==NC) {
479     pLine.push((0.7ssep,0)--(2ssep,ssep/3));
480   } else {
481     write("Error, unrecognized switchSPST type ",type);
482   }
483   term = TwoTerminal(beg, 2.4ssep, ang, lchar, lcharv, name, val, pLine,pMisc);
484   if (draw == true)
485     term.draw();
486   return term;
487 }
488
489 //--- Current (Corriente) ---
490
491 real isize=2mm;
492
493 // adjusted from makecirc original to center arrowhead under text
494 TwoTerminal current(pair beg=(0,0), real ang=0, string name="", string val="",
495                     bool draw=true)
496 {
497   path pLine[]={}, pMisc[]={};
498   real lchar, lcharv;
499   TwoTerminal term;
500   lchar = 0.4isize; lcharv = 0.4isize;
501   pLine.push((0,0)--(1.5isize,0));
502   pLine.push((1.5isize,0)--(2isize,0));
503   pMisc.push(fullhead(pLine[0], isize, 45));
504   term = TwoTerminal(beg, 2isize, ang, lchar, lcharv, name, val, pLine, pMisc);
505   if (draw == true)
506     term.draw();
507   return term;
508 }
509
510 //--- Circle-based symbols (for internal use) --
511
512 real circle_size=6mm;
513
514 TwoTerminal _two_terminal_circle(pair beg=(0,0), real ang=0, string name="",
515                                  string val="")
516 {
517   path pLine[]={}, pMisc[]={};
518   real len, lchar, lcharv, r = circle_size/2;
519   pair c = (2r,0);
520   TwoTerminal term;
521
522   len = 2*circle_size;
523   lchar = lcharv = r;
524   c = (circle_size, 0);
525   pLine.push((0,0)--(r,0));
526   pLine.push(shift(c)*scale(r)*(E..N..W..S..E));
527   pLine.push((3r,0)--(4r,0));
528   term = TwoTerminal(beg, len, ang, lchar, lcharv, name, val, pLine, pMisc);
529   return term;
530 }
531
532 //--- Sources (fuentes de alimentaci'on) ---
533
534 int AC=0,DC=1,I=2,V=3;
535
536 TwoTerminal source(pair beg=(0,0), real ang=0, int type=AC, string name="",
537                    string val="", bool draw=true)
538 {
539   TwoTerminal term;
540
541   if (type == AC || type == I || type == V) {
542     real s = circle_size;
543     term = _two_terminal_circle(beg=beg, ang=ang, name=name, val=val);
544     if (type == AC) {
545       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));
546     } else if (type == I) {
547       term.pLine.push((2s/3,0)--(4s/3,0));
548       term.pLine.push(fullhead(term.pLine[3], 4s/15, 30));
549     } else if (type == V) {
550       term.pLine.push((1.05s,0)--(1.45s,0));
551       term.pLine.push((1.25s,-.2s)--(1.25s,.2s));
552       term.pLine.push((.95s,0)--(.55s,0));      
553     }
554   } else if (type == DC) {
555     path pLine[] = {};
556     real len, lchar, lcharv;
557     len = circle_size;
558     lchar = 0.6len; lcharv = .6len;
559     pLine.push((0,0)--(0.4len,0));
560     pLine.push((.6len,0)--(len,0));
561     pLine.push((.4len,-.2len)--(.4len,.2len));
562     pLine.push((.6len,-.6len)--(.6len,.6len));
563     term = TwoTerminal(beg, len, ang, lchar, lcharv, name, val, pLine);
564   }
565   if (draw == true)
566     term.draw();
567   return term;
568 }
569
570 /*
571
572 //%%<--- Transistor --->%%%
573 newinternal npn, pnp, cnpn, cpnp, bjtlth;
574 npn=1; pnp=-1; cnpn=0; cpnp=2; bjtlth=7mm;
575
576 vardef transistor@#(expr z,type,ang)=
577         save BJT;
578         pair T@#.B,T@#.E,T@#.C; % pines: Base, Emisor, Colector %
579         T@#.B=z;
580         T@#.E=(z+(bjtlth,-.75bjtlth)) rotatedaround(z,ang);
581         T@#.C=(z+(bjtlth,.75bjtlth)) rotatedaround(z,ang);
582         picture BJT;
583         BJT=nullpicture;
584         
585         addto BJT doublepath z--(z+(.5bjtlth,0)) withpen line;
586         addto BJT doublepath (z+(.5bjtlth,-.5bjtlth))--(z+(.5bjtlth,.5bjtlth)) withpen line;
587         addto BJT doublepath (z+(.5bjtlth,.2bjtlth))--(z+(bjtlth,.5bjtlth))
588         --(z+(bjtlth,.75bjtlth)) withpen line;
589         
590         if type=npn:
591                 addto BJT doublepath (z+(.5bjtlth,-.2bjtlth))--(z+(bjtlth,-.5bjtlth))
592                 --(z+(bjtlth,-.75bjtlth)) withpen line;
593                 addto BJT contour bjtahead (z+(.5bjtlth,-.2bjtlth))
594                 --(z+(bjtlth,-.5bjtlth)) withpen line;
595         elseif type=cnpn:
596                 addto BJT doublepath (z+(.5bjtlth,-.2bjtlth))--(z+(bjtlth,-.5bjtlth))
597                 --(z+(bjtlth,-.75bjtlth)) withpen line;
598                 addto BJT contour bjtahead (z+(.5bjtlth,-.2bjtlth))
599                 --(z+(bjtlth,-.5bjtlth)) withpen line;
600                 addto BJT doublepath fullcircle scaled 1.3bjtlth shifted (z+(.65bjtlth,0))
601                  withpen line;
602         elseif type=pnp:
603                 addto BJT doublepath (z+(bjtlth,-.75bjtlth))--(z+(bjtlth,-.5bjtlth))
604                 --(z+(.5bjtlth,-.2bjtlth)) withpen line;
605                 addto BJT contour bjtahead (z+(bjtlth,-.5bjtlth))
606                 --(z+(.5bjtlth,-.2bjtlth)) withpen line;
607         elseif type=cpnp:
608                 addto BJT doublepath (z+(bjtlth,-.75bjtlth))--(z+(bjtlth,-.5bjtlth))
609                 --(z+(.5bjtlth,-.2bjtlth)) withpen line;
610                 addto BJT contour bjtahead (z+(bjtlth,-.5bjtlth))
611                 --(z+(.5bjtlth,-.2bjtlth)) withpen line;
612                 addto BJT doublepath fullcircle scaled 1.3bjtlth shifted (z+(.65bjtlth,0)) withpen line;
613         fi;
614         
615         draw BJT rotatedaround(z,ang);
616 enddef;
617
618 //%%<--- Measurement instruments (Intrumentos de medicion)--->%%%
619 newinternal volt, ampere, watt;
620 volt=0; ampere=1; watt=2;
621
622 vardef meains@#(expr z,type,ang,name)=
623         save meter;
624         pair mi@#.l, mi@#.r, mi@#.p; % pines %
625         mi@#.l=z; mi@#.r=(z+(2ssize,0)) rotatedaround(z,ang);
626         
627         picture meter; meter=nullpicture;
628         addto meter doublepath z--(z+(.5ssize,0));
629         addto meter doublepath (z+(1.5ssize,0))--(z+(2ssize,0));
630         if (type=volt) || (type=ampere):        
631                 addto meter doublepath fullcircle scaled ssize shifted (z+(ssize,0));
632                 if type=volt:
633                         addto meter also thelabel(latex("\textsf{V}") scaled (ssize/6mm) 
634                         rotated (-ang), (z+(ssize,0)));
635                 elseif type=ampere:
636                         addto meter also thelabel(latex("\textsf{A}") scaled (ssize/6mm) 
637                         rotated (-ang), (z+(ssize,0)));
638                 fi;
639         elseif (type=watt):
640                 mi@#.p=(z+(ssize,-ssize)) rotatedaround(z,ang);
641                 addto meter doublepath (z+(.5ssize,-.5ssize))--(z+(.5ssize,.5ssize))
642                 --(z+(1.5ssize,.5ssize))--(z+(1.5ssize,-.5ssize))--cycle;
643                 addto meter doublepath (z+(ssize,-.5ssize))--(z+(ssize,-ssize));
644                 addto meter also thelabel(latex("\textsf{W}") scaled (ssize/6mm) 
645                 rotated (-ang), (z+(ssize,0)));
646         fi;
647         
648         draw meter rotatedaround(z,ang) withpen line;
649         
650         if labeling=rotatelabel:
651                 if ((ang > (-90)) && (ang <= 90)) || ((ang > 270) && (ang <= 450)):
652                         label(latex(name) rotatedaround (.5[mi@#.l,mi@#.r],ang), 
653                         (.5ssize+lbsep)*dir (90+ang) shifted .5[mi@#.l,mi@#.r]);
654                 elseif ((ang > 90) && (ang <= 270)) || ((ang > (-270)) && (ang <= (-90))):
655                         label(latex(name) rotatedaround (.5[mi@#.l,mi@#.r],180+ang), 
656                         (.5ssize+lbsep)*dir (90+ang) shifted .5[mi@#.l,mi@#.r]);
657                 fi;
658         elseif labeling=norotatelabel:
659                 if (ang = 0):
660                         label.top(latex(name), (.5ssize+.25lbsep)*dir (90+ang) 
661                         shifted .5[mi@#.l,mi@#.r]);
662                 elseif (ang > 0) && (ang < 90):
663                         label.ulft(latex(name), (.5ssize)*dir (90+ang) 
664                         shifted .5[mi@#.l,mi@#.r]);
665                 elseif (ang = 90):
666                         label.lft(latex(name),(.5ssize+.25lbsep)*dir (90+ang)
667                         shifted .5[mi@#.l,mi@#.r]);
668                 elseif (90 < ang) && (ang < 180):
669                         label.llft(latex(name),(.5ssize)*dir (90+ang)
670                         shifted .5[mi@#.l,mi@#.r]);
671                 elseif (ang = 180) || (ang = (-180)):
672                         label.bot(latex(name), (.5ssize+.25lbsep)*dir (90+ang) 
673                         shifted .5[mi@#.l,mi@#.r]);
674                 elseif ((ang > 180) && (ang < 270)) || ((ang > (-180)) && (ang < (-90))):
675                         label.lrt(latex(name),(.5ssize)*dir (90+ang)
676                         shifted .5[mi@#.l,mi@#.r]);
677                 elseif (ang = 270) || (ang = (-90)):
678                         label.rt(latex(name), (.5ssize+.25lbsep)*dir (90+ang) 
679                         shifted .5[mi@#.l,mi@#.r]);
680                 elseif ((270 < ang) && (ang < 360)) || ((ang < 0) && (ang > (-90))):
681                         label.urt(latex(name),(.5ssize)*dir (90+ang)
682                         shifted .5[mi@#.l,mi@#.r]);
683                 fi;
684         fi;
685 enddef;
686
687 // --- Electrical machines (maquinas electricas) ---
688
689 TwoTerminal motor(pair beg, real ang, string name, string val)
690 {
691   path pLine;
692   TwoTerminal term;
693   
694   if (type==Up) {
695     pLine = (0,0)--(coil,0);
696     for (int i=2; i<=4; i+=1)
697       pLine = pLine{N}..{S}(i*coil,0);
698     pLine = pLine{N}..{S}(5coil,0)--(6coil,0);
699   } else if (type==Down) {
700     pLine = (0,0)--(coil,0);
701     for (int i=2; i<=4; i+=1)
702       pLine = pLine{S}..{N}(i*coil,0);
703     pLine = pLine{S}..{N}(5coil,0)--(6coil,0);
704     // original makecirc changed labelangle to ang-180
705   }
706   term = TwoTerminal(beg, 6coil, ang, coil, coil, name, val, pLine);
707   // original makecirc used .5coil for lcharv
708   term.draw();
709   return term;
710 }
711         M@#.D=z; M@#.B=(z+(2ssize,0)) rotatedaround(z,ang);
712         picture mot; mot=nullpicture;
713         
714         addto mot doublepath z--(z+(.4ssize,0));
715         addto mot doublepath (z+(1.6ssize,0))--(z+(2ssize,0));
716         addto mot doublepath fullcircle scaled ssize shifted (z+(ssize,0));
717         addto mot also thelabel(latex("\textsf{M}") scaled (ssize/6mm) 
718         rotated (-ang), (z+(ssize,0)));
719         
720         path p,q,r,s,ca,cb,c,hc;
721         p=(z+(.6ssize,.075ssize))--(z+(.4ssize,.075ssize));
722         q=(z+(.4ssize,.075ssize))--(z+(.4ssize,-.075ssize));
723         ca=(z+(.4ssize,-.075ssize))--(z+(.6ssize,-.075ssize));
724         
725         
726         r=(z+(1.4ssize,.075ssize))--(z+(1.6ssize,.075ssize));
727         s=(z+(1.6ssize,.075ssize))--(z+(1.6ssize,-.075ssize));
728         cb=(z+(1.6ssize,-.075ssize))--(z+(1.4ssize,-.075ssize));
729         
730         c=fullcircle scaled ssize shifted (z+(ssize,0));
731         hc=halfcircle scaled ssize rotated 270 shifted (z+(ssize,0));
732         
733         addto mot contour buildcycle(p,q,ca,c);
734         addto mot doublepath buildcycle(p,q,ca,c);
735         
736         addto mot contour buildcycle(cb,s,r,hc);
737         addto mot doublepath buildcycle(cb,s,r,hc);
738         
739         draw mot rotatedaround(z,ang) withpen line;
740         
741         putlabel(M@#.D,M@#.B,.5ssize,.5ssize,ang,name,val);
742 enddef;
743
744 vardef generator@#(expr z,ang,name,val)=
745         save gen;
746         pair G@#.D, G@#.B; % pines %
747         G@#.D=z; G@#.B=(z+(2ssize,0)) rotatedaround(z,ang);
748         picture gen; gen=nullpicture;
749         
750         addto gen doublepath z--(z+(.5ssize,0));
751         addto gen doublepath (z+(1.5ssize,0))--(z+(2ssize,0));
752         addto gen doublepath fullcircle scaled ssize shifted (z+(ssize,0));
753         addto gen also thelabel(latex("\textsf{G}") scaled (ssize/6mm) 
754         rotated (-ang), (z+(ssize,0)));
755         
756         draw gen rotatedaround(z,ang) withpen line;
757         
758         putlabel(G@#.D,G@#.B,.5ssize,.5ssize,ang,name,val);
759 enddef;
760
761 newinternal mid, Fe, auto;
762 mid=1; Fe=2; auto=3;
763
764 vardef transformer@#(expr z,type,ang)=
765         save trafo;
766         pair tf@#.pi, tf@#.ps, tf@#.si, tf@#.ss, tf@#.m;
767         tf@#.pi=z; tf@#.ps=(z+(0,8coil)) rotatedaround(z,ang);
768         tf@#.si=(z+(2.4coil,0)) rotatedaround(z,ang);
769         tf@#.ss=(z+(2.4coil,8coil)) rotatedaround(z,ang);
770         tf@#.m=(z+(3.4coil,4coil)) rotatedaround(z,ang);
771         
772         picture trafo; trafo=nullpicture;
773         
774         if type=normal:
775         tf@#.pi=z; tf@#.ps=(z+(0,8coil)) rotatedaround(z,ang);
776         tf@#.si=(z+(2.4coil,0)) rotatedaround(z,ang);
777         tf@#.ss=(z+(2.4coil,8coil)) rotatedaround(z,ang);
778                 addto trafo doublepath z--(z+(0,coil)){right}..
779                 for i=2 upto 6: {left}(z+(0,i*coil)){right}.. endfor
780                 {left}(z+(0,7coil))--(z+(0,8coil));
781                 addto trafo doublepath (z+(coil,coil))--(z+(coil,7coil));
782                 addto trafo doublepath (z+(1.4coil,coil))--(z+(1.4coil,7coil));
783                 addto trafo doublepath (z+(2.4coil,0))--(z+(2.4coil,coil)){left}..
784                 for i=2 upto 6: {right}(z+(2.4coil,i*coil)){left}.. endfor
785                 {right}(z+(2.4coil,7coil))--(z+(2.4coil,8coil));
786         elseif type=mid:
787         tf@#.pi=z; tf@#.ps=(z+(0,8coil)) rotatedaround(z,ang);
788         tf@#.si=(z+(2.4coil,0)) rotatedaround(z,ang);
789         tf@#.ss=(z+(2.4coil,8coil)) rotatedaround(z,ang);
790         tf@#.m=(z+(3.4coil,4coil)) rotatedaround(z,ang);
791                 addto trafo doublepath z--(z+(0,coil)){right}..
792                 for i=2 upto 6: {left}(z+(0,i*coil)){right}.. endfor
793                 {left}(z+(0,7coil))--(z+(0,8coil));
794                 addto trafo doublepath (z+(coil,coil))--(z+(coil,7coil));
795                 addto trafo doublepath (z+(1.4coil,coil))--(z+(1.4coil,7coil));
796                 addto trafo doublepath (z+(2.4coil,0))--(z+(2.4coil,coil)){left}..
797                 for i=2 upto 6: {right}(z+(2.4coil,i*coil)){left}.. endfor
798                 {right}(z+(2.4coil,7coil))--(z+(2.4coil,8coil));
799                 addto trafo doublepath (z+(2.4coil,4coil))--(z+(3.4coil,4coil));
800         elseif type=Fe:
801         tf@#.pi=z rotatedaround(z,ang); tf@#.ps=(z+(0,5.3coil)) rotatedaround(z,ang);
802         tf@#.si=(z+(14coil,0)) rotatedaround(z,ang);
803         tf@#.ss=(z+(14coil,5.228coil)) rotatedaround(z,ang);
804                 addto trafo doublepath z+(2coil,-2.5coil)--z+(12coil,-2.5coil)
805                 --z+(12coil,7.5coil)--z+(2coil,7.5coil)--cycle;
806                 addto trafo doublepath z+(4coil,-.5coil)--z+(10coil,-.5coil)
807                 --z+(10coil,5.5coil)--z+(4coil,5.5coil)--cycle;
808                 addto trafo doublepath z--z+(2coil,0)--z+(4coil,0.728coil)
809                 {right}..{left}z+(4coil,1.3*coil);
810                 for i=1 upto 4:
811                         addto trafo doublepath z+(2coil,(i+.5)*coil){left}..
812                         {right}z+(2coil,i*coil)--z+(4coil,(i+0.728)*coil)
813                         {right}..{left}z+(4coil,(i+1.3)*coil);
814                 endfor;
815                 addto trafo doublepath z+(2coil,5.3coil)--z+(0,5.3coil);
816                 for i=0 upto 3:
817                         addto trafo doublepath z+(10coil,i*coil){left}..
818                         {right}z+(10coil,(i+.5)*coil)--z+(12coil,(i+.5+0.728)*coil)
819                         {right}..{left}z+(12coil,(i+.656)*coil);
820                 endfor;
821                 addto trafo doublepath z+(10coil,4coil){left}..{right}
822                 z+(10coil,4.5coil)--z+(12coil,5.228coil)--z+(14coil,5.228coil);
823                 addto trafo doublepath z+(12coil,0)--z+(14coil,0);
824         elseif type=auto:
825         tf@#.pi=z rotatedaround(z,ang); tf@#.ps=(z+(0,4coil)) rotatedaround(z,ang);
826         tf@#.si=(z+(4coil,-6coil)) rotatedaround(z,ang);
827         tf@#.ss=(z+(4coil,4coil)) rotatedaround(z,ang);
828                 addto trafo doublepath z--z+(2coil,0);
829                 addto trafo doublepath z+(2coil,-6coil)--z+(2coil,-5coil){right}..
830                 for i=2 upto 10: {left}(z+(2coil,(i-6)*coil)){right}.. endfor
831                 {left}(z+(2coil,5coil))--z+(2coil,6coil)--z+(0,6coil);
832                 addto trafo doublepath z+(2coil,6coil)--z+(4coil,6coil);
833                 addto trafo doublepath z+(2coil,-6coil)--z+(4coil,-6coil);
834         fi;
835         
836         draw trafo rotatedaround(z,ang) withpen line;
837 enddef;
838
839 //%%<--- Miscellaneous symbols --->%%%
840
841 newinternal gndlth, implth, simple, shield;
842 gndlth=5mm; implth=7mm; simple=1; shield=2;
843
844 vardef ground@#(expr z,type,ang)=
845         save GND;
846         pair gnd@#; % unico pin %
847         gnd@#=z;
848         picture GND; GND=nullpicture;
849         addto GND doublepath z--(z+(0,-.5gndlth)) withpen line;
850         if type=shield:
851                 addto GND doublepath (z+(-.5gndlth,-.5gndlth))--(z+(.5gndlth,-.5gndlth)) withpen line;
852                 addto GND doublepath (z+(-.35gndlth,-.6gndlth))--(z+(.35gndlth,-.6gndlth)) withpen line;
853                 addto GND doublepath (z+(-.2gndlth,-.7gndlth))--(z+(.2gndlth,-.7gndlth)) withpen line;
854         elseif type=simple:
855                 addto GND doublepath (z+(-.5gndlth,-.5gndlth))--(z+(.5gndlth,-.5gndlth)) 
856                 withpen pencircle scaled 2linewd;
857         fi;
858         draw GND rotatedaround(z,ang);
859 enddef;
860
861 newinternal junctiondiam;
862 junctiondiam=1.25mm;
863
864 vardef junction@#(expr z,name)(suffix $)=
865         pair J@#; J@#=z;
866         draw z withpen pencircle scaled junctiondiam;
867         label.$(latex(name),z);
868 enddef;
869
870 vardef impedance@#(expr z,ang,name,val)=
871         save imp;
872         pair Z@#.l, Z@#.r; % pines %
873         Z@#.l=z;
874         Z@#.r=(z+(1.5implth,0)) rotatedaround(z,ang);
875         picture imp; imp=nullpicture;
876         
877         addto imp doublepath z--(z+(.25implth,0));
878         addto imp doublepath (z+(.25implth,-.18implth))--(z+(.25implth,.18implth))
879         --(z+(1.25implth,.18implth))--(z+(1.25implth,-.18implth))--cycle;
880         addto imp doublepath (z+(1.25implth,0))--(z+(1.5implth,0));
881                 
882         draw imp rotatedaround(z,ang) withpen line;
883         
884         putlabel(Z@#.l,Z@#.r,.2implth,.2implth,ang,name,val);
885 enddef;
886
887 */
888
889 int illuminating = 1;
890
891 TwoTerminal lamp(pair beg=(0,0), real ang=0, int type=normal,
892                  string name="", string val="", bool draw=true)
893 {
894   real r = 0.5*circle_size;
895   pair c;
896   TwoTerminal term;
897
898   term = _two_terminal_circle(beg=beg, ang=ang, name=name, val=val);
899   pair c = (2r, 0);
900   if (type==normal) {
901     term.pLine.push((c - r*dir(45)) -- (c + r*dir(45)));
902     term.pLine.push((c - r*dir(-45)) -- (c + r*dir(-45)));
903   } else if (type==illuminating) {
904     term.pLine.push((c - (r,0)) -- (c - (r/2,0)));
905     term.pLine.push((c + (r/2,0)) -- (c + (r,0)));    
906     term.pLine.push(shift(c)*scale(r/2)*(E..N..W));
907   }
908   if (draw == true)
909     term.draw();
910   return term;
911 }
912
913 /*
914
915 //%%<--- Mesh current (corriente de malla) --->%%%
916
917 newinternal cw, ccw;
918 cw=0; ccw=1;
919
920 def imesh(expr c,wd,ht,dire,ang,name)=
921         save im,r; picture im; numeric r;
922         ahlength=3platsep; ahangle=20;
923         if ht > wd: r=.2wd elseif ht < wd: r=.2ht fi;
924         im=nullpicture;
925         if dire=cw:
926                 addto im doublepath (xpart c - .5wd, ypart c - .5ht)
927                 --(xpart c - .5wd, ypart c + .5ht-r){up}
928                 ..{right}(xpart c - .5wd + r, ypart c + .5ht)
929                 --(xpart c + .5wd - r, ypart c + .5ht){right}
930                 ..{down}(xpart c + .5wd,ypart c + .5ht - r)
931                 --(xpart c + .5wd,ypart c - .5ht + r){down}
932                 ..{left}(xpart c + .5wd - r,ypart c - .5ht)
933                 --(xpart c - .25wd, ypart c - .5ht);
934                 addto im contour arrowhead (xpart c - .5wd, ypart c - .5ht)
935                 --(xpart c - .5wd, ypart c + .5ht-r){up}
936                 ..{right}(xpart c - .5wd + r, ypart c + .5ht)
937                 --(xpart c + .5wd - r, ypart c + .5ht){right}
938                 ..{down}(xpart c + .5wd,ypart c + .5ht - r)
939                 --(xpart c + .5wd,ypart c - .5ht + r){down}
940                 ..{left}(xpart c + .5wd - r,ypart c - .5ht)
941                 --(xpart c - .25wd, ypart c - .5ht);
942         elseif dire=ccw:
943                 addto im doublepath (xpart c + .5wd, ypart c - .5ht)
944                 --(xpart c + .5wd, ypart c + .5ht-r){up}
945                 ..{left}(xpart c + .5wd - r, ypart c + .5ht)
946                 --(xpart c - .5wd + r, ypart c + .5ht){left}
947                 ..{down}(xpart c - .5wd,ypart c + .5ht - r)
948                 --(xpart c - .5wd,ypart c - .5ht + r){down}
949                 ..{right}(xpart c - .5wd + r,ypart c - .5ht)
950                 --(xpart c + .25wd, ypart c - .5ht);
951                 addto im contour arrowhead (xpart c + .5wd, ypart c - .5ht)
952                 --(xpart c + .5wd, ypart c + .5ht-r){up}
953                 ..{left}(xpart c + .5wd - r, ypart c + .5ht)
954                 --(xpart c - .5wd + r, ypart c + .5ht){left}
955                 ..{down}(xpart c + .5wd,ypart c + .5ht - r)
956                 --(xpart c - .5wd,ypart c - .5ht + r){down}
957                 ..{right}(xpart c - .5wd + r,ypart c - .5ht)
958                 --(xpart c + .25wd, ypart c - .5ht);
959         fi;
960         
961         if labeling=rotatelabel:
962                 addto im also thelabel(latex("$" & name & "$"),c);
963         elseif labeling=norotatelabel:
964                 addto im also thelabel(latex("$" & name & "$") rotatedaround(c,-ang),c);
965         fi;
966         
967         draw im rotatedaround (c,ang) withpen line;
968 enddef;
969
970 //%%<--- Reostatos --->%%%
971
972 newinternal rheolth, Rrheo, Lrheo; 
973 rheolth=2mm; Rrheo=1; Lrheo=2;
974
975 vardef rheostat@#(expr z,type,ang)=
976         save reo; picture reo; reo=nullpicture;
977         pair rh@#.i, rh@#.s, rh@#.r;
978         rh@#.i=z; rh@#.s=(z+(0,6rheolth)) rotatedaround(z,ang);
979         rh@#.r=(z+(3rheolth,6rheolth)) rotatedaround(z,ang);
980         
981         ahangle=20; ahlength=rheolth;
982
983         if type=Lrheo:
984                 addto reo doublepath (z+(6rheolth,-3rheolth))--(z+(4rheolth,-3rheolth))
985                 --(z+(4rheolth,-.7rheolth));
986                 addto reo contour arrowhead (z+(6rheolth,-3rheolth))--(z+(4rheolth,-3rheolth))
987                 --(z+(4rheolth,-.9rheolth));
988         
989                 addto reo doublepath z--(z+(rheolth,0)){down}.. for i=2 upto 4:
990                 {up}(z+(i*rheolth,0)){down}.. endfor {up}(z+(5rheolth,0))--(z+(6rheolth,0));
991         
992                 reo=reo rotatedaround(z,90);
993         elseif type=Rrheo:
994                 addto reo doublepath (z+(6rheolth,-3rheolth))--(z+(4rheolth,-3rheolth))
995                 --(z+(4rheolth,-.7rheolth));
996                 addto reo contour arrowhead (z+(6rheolth,-3rheolth))--(z+(4rheolth,-3rheolth))
997                 --(z+(4rheolth,-.9rheolth));
998         
999                 addto reo doublepath z--(z+(1.5rheolth,0))--(z+(1.75rheolth,.75rheolth))--
1000                 for i=.5 step .5 until 2.5:     (z+((1.75+i)*rheolth,((-1)**(2i))*.75rheolth))--
1001                 endfor (z+(4.5rheolth,0))--(z+(6rheolth,0)) withpen line;
1002         
1003                 reo=reo rotatedaround(z,90);
1004         fi;
1005         draw reo rotatedaround(z,ang) withpen line;
1006 enddef;
1007
1008 */
1009
1010 // Loop symbols for Kirchhoff's rules.
1011
1012 void kirchhoff_loop(picture pic=currentpicture, pair points[],
1013                     pen outline=kirchhoff_pen, real aspace=-1) {
1014   // draw kirchhoff loop underneath currentpicture
1015   picture newpic;
1016   int i;
1017   guide g;
1018   pair a = points[0] - points[points.length-1];  // arrow distance
1019   if (aspace < 0)
1020     aspace = 3*linewidth(outline);  // one dot diameter
1021   real alength = max(0.5*length(a), length(a) - aspace - linewidth(outline)/2);
1022   a = alength*unit(a);
1023   pair astop = points[points.length-1] + a;
1024   dot(newpic, points[0], scale(3)*outline);
1025   for (int i=0; i < points.length; ++i)
1026     g = g--points[i];
1027   g = g -- astop;
1028   draw(newpic, g, outline, Arrow(size=3*linewidth(outline)));
1029   add(pic, newpic, above=false);
1030 }