Convert TwoTerminal to a more general MultiTerminal in Circ.asy.
[course.git] / asymptote / Circ.asy
1 /* Useful functions for drawing circuit diagrams.
2  * Version 0.2
3  *
4  * Copyright (C) 2003 GS Bustamante Argañaraz
5  *               2008-2012 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 // function to wire the symbols together
82
83 int nsq=0, udsq=2, rlsq=3;
84
85 void wire(pair pin_beg, pair pin_end, int type=nsq, real dist=0)
86 {
87   if (dist == 0) {
88     if (type==nsq) {
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);
94     } else {
95       write("Error, unrecognized wire type ",type);
96     }
97   } else {
98     if (type==udsq) {
99       draw(pin_beg--(pin_beg+(0,dist))--(pin_end.x,pin_beg.y + dist)
100            --pin_end, line);
101     } else if (type==rlsq) {
102       draw(pin_beg--(pin_beg+(dist,0))--(pin_beg.x + dist,pin_end.y)
103            --pin_end, line);
104     } else {
105       write("Error, unrecognized wire type ",type);
106     }
107   }
108 }
109
110 // ----- Here the symbols begin --------
111
112 transform _shift_transform(pair z) = shift;
113
114 struct MultiTerminal {
115   pair center;
116   real dir;
117   pair terminal[];
118   pair terminal_offset[];
119   Label label;
120   Label value;
121   real label_offset;
122   real value_offset;
123   path pLine[]; // cyclic paths are filled in
124   path pMisc[];
125   pen line;
126   pen misc;
127
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];
132     }
133   }
134
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();
146     this.label = label;
147     this.value = value;
148     this.label_offset = label_offset;
149     this.value_offset = value_offset;
150     this.pLine = pLine;
151     this.pMisc = pMisc;
152     this.line = line;
153     this.misc = misc;
154   }
155
156   /* Shift position by a */
157   void shift(pair a) {
158     this.center += a;
159     this.set_terminals();
160   }
161
162   void draw_label(picture pic=currentpicture, Label L=null, real offset=0,
163                   pair default_direction=(0,0)) {
164     align a;
165     if (L == null) {
166       L = this.label;
167     }
168     a = L.align;
169     if ((L.align == NoAlign || L.align.dir == (0,0)) &&
170         default_direction != (0,0)) {
171       L.align = rotate(this.dir)*default_direction;
172     }
173     if (L.align != NoAlign && L.align != Align) {
174       real m = labelmargin(L.p);
175       real scale = (m + offset)/m;
176       if (L.align.is3D) {
177         L.align.dir3 *= scale;
178       } else {
179         L.align.dir *= scale;
180       }
181     }
182     label(pic=pic, L=L, position=this.center);
183     L.align = a;
184   }
185
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).
190    */
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();
195   }
196
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];
200       if (cyclic(p))
201         filldraw(pic, p, this.line, this.line);
202       else
203         draw(pic, p, this.line);
204     }
205     for (int i=0; i< pMisc.length; i+=1) {
206       path p = _shift_transform(this.center)*rotate(this.dir)*pMisc[i];
207       if (cyclic(p))
208         filldraw(pic, p, this.misc, this.misc);
209       else
210         draw(pic, p, this.misc);
211     }
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);
216   }
217 }
218
219 pair _offset(pair beg=(0,0), real length=1, real dir=0) {
220   return beg + rotate(dir)*(length, 0);
221 }
222
223 void two_terminal_centerto(MultiTerminal reference, MultiTerminal target,
224                            real offset=0, bool reverse=false)
225 {
226   if (reverse == false)
227     target.centerto(reference.terminal[0], reference.terminal[1], offset);
228   else
229     target.centerto(reference.terminal[1], reference.terminal[0], offset);
230 }
231
232 // --- Resistor (Resistencia) ---
233
234 real rstlth=2mm;
235 int normal=0, variable=2;
236
237 MultiTerminal resistor(pair beg=(0,0), real dir=0, int type=normal,
238                        Label label="", Label value="", bool draw=true)
239 {
240   path pLine, pLines[]={}, pMisc[]={};
241   real len = 7rstlth;
242   MultiTerminal term;
243   pair center = _offset(beg=beg, length=len/2, dir=dir);
244   pair terminal_offset[] = {
245       (-len/2, 0),
246       (len/2, 0)};
247
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);
252   if (type==normal) {
253     ; //pass
254   } else if (type==variable) {
255     ahlength=.8rstlth;
256     pMisc.push((-1.5rstlth,-rstlth)--(1.5rstlth,rstlth));
257     pMisc.push(miscahead((-1.5rstlth,-rstlth)--(1.5rstlth,rstlth)));
258   } else {
259     write("Error, unrecognized resistor type ",type);
260   }
261   pLines.push(pLine);
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);
265   if (draw == true)
266     term.draw();
267   return term;
268 }
269
270 // --- Inductor (bobina) ---
271
272 real coil=2mm;
273 int Up=0, Down=1;
274
275 MultiTerminal inductor(pair beg=(0,0), real dir=0, int type=Up,
276                        Label label="", Label value="", bool draw=true)
277 {
278   path pLine;
279   real len = 6coil;
280   MultiTerminal term;
281   pair center = _offset(beg=beg, length=len/2, dir=dir);
282   pair terminal_offset[] = {
283       (-len/2, 0),
284       (len/2, 0)};
285
286   pLine = (-len/2,0) -- (-2coil,0);
287
288   if (type==Up) {
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);
294   } else {
295     write("Error, unrecognized inductor type ",type);
296   }
297   pLine = pLine -- (len/2,0);
298
299   term = MultiTerminal(center=center, dir=dir, terminal_offset=terminal_offset,
300       label=label, value=value, label_offset=.8rstlth, value_offset=.8rstlth,
301       pLine=pLine);
302   if (draw == true)
303     term.draw();
304   return term;
305 }
306
307 // --- Capacitor (condensador) ---
308
309 real platsep=1mm;
310 int normal=0, electrolytic=1, variable=2, variant=3;
311
312 MultiTerminal capacitor(pair beg=(0,0), real dir=0, int type=normal,
313                         Label label="", Label value="", bool draw=true)
314 {
315   path pLine[]={}, pMisc[]={};
316   real len = 7platsep;
317   MultiTerminal term;
318   pair center = _offset(beg=beg, length=len/2, dir=dir);
319   pair terminal_offset[] = {
320       (-len/2, 0),
321       (len/2, 0)};
322
323   pLine.push((-len/2,0)--(-platsep/2,0));
324   pLine.push((platsep/2,0)--(len/2,0));
325
326   if (type==normal) {
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));
337     ahlength=1.7platsep;
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));
342   } else {
343     write("Error, unrecognized capacitor type ",type);
344   }
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);
348   if (draw == true)
349     term.draw();
350   return term;
351 }
352
353 // --- Diode (diodo) ---
354
355 real diode_height = 3.5mm;
356 int zener=1, LED=2;
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.
360
361 MultiTerminal diode(pair beg=(0,0), real dir=0, int type=normal,
362                     Label label="", Label value="", bool draw=true)
363 {
364   path pLine[]={}, pMisc[]={};
365   real len = 3*diode_height;
366   real r = diode_height/2;
367   real label_offset, value_offset;
368   MultiTerminal term;
369   pair center = _offset(beg=beg, length=len/2, dir=dir);
370   pair terminal_offset[] = {
371       (-len/2, 0),
372       (len/2, 0)};
373
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));
377
378   if (type==normal) {
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));
392   } else {
393     write("Error, unrecognized diode type ",type);
394   }
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);
398   if (draw == true)
399     term.draw();
400   return term;
401 }
402
403 //--- Battery (bater'ia) ---
404
405 real battery_size = 6mm;
406
407 MultiTerminal battery(pair beg=(0,0), real dir=0,
408                       Label label="", Label value="", bool draw=true)
409 {
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;
417   MultiTerminal term;
418   pair center = _offset(beg=beg, length=len/2, dir=dir);
419   pair terminal_offset[] = {
420       (-len/2, 0),
421       (len/2, 0)};
422
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));
429   }
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);
433   if (draw == true)
434     term.draw();
435   return term;
436 }
437
438 //--- Switches (Llaves) ---
439
440 int open=0, closed=1;
441 real switch_size = 3mm;
442
443 /* Helper function for constructing switch paths. */
444 path[] _switch_lines(pair terminal_offset[], real theta)
445 {
446   path pLine[] = {};
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);
452   }
453   return pLine;
454 }
455
456 /* `switch' is a Asymptote keyword (or it should be), so append SPST
457  * for Single Pole Single Throw.
458  */
459 MultiTerminal switchSPST(pair beg=(0,0), real dir=0, int type=closed,
460                          Label label="", Label value="", bool draw=true)
461 {
462   path pLine[] = {};
463   real theta, label_offset, value_offset;
464   MultiTerminal term;
465   pair center = _offset(beg=beg, length=switch_size/2, dir=dir);
466   pair terminal_offset[] = {
467       (-switch_size/2, 0),
468       (switch_size/2, 0)};
469
470   value_offset = 0;
471   if (type==open) {
472     theta = 35;
473   } else if (type==closed) {
474     theta = 10;
475   } else {
476     write("Error, unrecognized switchSPST type ",type);
477   }
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);
483   if (draw == true)
484     term.draw();
485   return term;
486 }
487
488 int closed_a=1, closed_b=2;
489
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)
493 {
494   path pLine[] = {};
495   real theta, label_offset, value_offset;
496   MultiTerminal term;
497   pair center = _offset(beg=beg, length=switch_size/2, dir=dir);
498   pair terminal_offset[] = {
499       (-switch_size/2, 0),
500       (switch_size*sqrt(3)/4, switch_size/2),
501       (switch_size*sqrt(3)/4, -switch_size/2)};
502
503   label_offset = value_offset = switch_size/2;
504   if (type==open) {
505     theta = 0;
506   } else if (type==closed_a) {
507     theta = 20;
508   } else if (type==closed_b) {
509     theta = -20;
510   } else {
511     write("Error, unrecognized switchSPST type ",type);
512   }
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);
517   if (draw == true)
518     term.draw();
519   return term;
520 }
521
522 //--- Current (Corriente) ---
523
524 real current_size = 2mm;
525
526 MultiTerminal current(pair beg=(0,0), real dir=0,
527                       Label label="", Label value="", bool draw=true)
528 {
529   path pLine[]={}, pMisc[]={};
530   real label_offset, value_offset;
531   real len = 2*current_size;
532   MultiTerminal term;
533   pair center = _offset(beg=beg, length=len/2, dir=dir);
534   pair terminal_offset[] = {
535       (-len/2, 0),
536       (len/2, 0)};
537
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);
545   if (draw == true)
546     term.draw();
547   return term;
548 }
549
550 //--- Circle-based symbols (for internal use) --
551
552 real circle_size = 6mm;
553
554 MultiTerminal _circle_symbol(pair beg=(0,0), real dir=0,
555                              Label label="", Label value="")
556 {
557   path pLine[]={};
558   real label_offset, value_offset;
559   real len = 2*circle_size;
560   real r = circle_size/2;
561   MultiTerminal term;
562   pair center = _offset(beg=beg, length=r, dir=dir);
563   pair terminal_offset[] = {
564       (-len/2, 0),
565       (len/2, 0)};
566
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);
574   return term;
575 }
576
577 //--- Sources (fuentes de alimentaci'on) ---
578
579 int AC=0,DC=1,I=2,V=3;
580
581 MultiTerminal source(pair beg=(0,0), real dir=0, int type=AC,
582                      Label label="", Label value="", bool draw=true)
583 {
584   MultiTerminal term;
585
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);
589     if (type == AC) {
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));
598     }
599   } else if (type == DC) {
600     path pLine[]={};
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[] = {
608         (-len/2, 0),
609         (len/2, 0)};
610
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);
620   }
621   if (draw == true)
622     term.draw();
623   return term;
624 }
625
626 /*
627
628 //%%<--- Transistor --->%%%
629 newinternal npn, pnp, cnpn, cpnp, bjtlth;
630 npn=1; pnp=-1; cnpn=0; cpnp=2; bjtlth=7mm;
631
632 vardef transistor@#(expr z,type,ang)=
633         save BJT;
634         pair T@#.B,T@#.E,T@#.C; % pines: Base, Emisor, Colector %
635         T@#.B=z;
636         T@#.E=(z+(bjtlth,-.75bjtlth)) rotatedaround(z,ang);
637         T@#.C=(z+(bjtlth,.75bjtlth)) rotatedaround(z,ang);
638         picture BJT;
639         BJT=nullpicture;
640         
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;
645         
646         if type=npn:
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;
651         elseif type=cnpn:
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))
657                  withpen line;
658         elseif type=pnp:
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;
663         elseif type=cpnp:
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;
669         fi;
670         
671         draw BJT rotatedaround(z,ang);
672 enddef;
673
674 //%%<--- Measurement instruments (Intrumentos de medicion)--->%%%
675 newinternal volt, ampere, watt;
676 volt=0; ampere=1; watt=2;
677
678 vardef meains@#(expr z,type,ang,name)=
679         save meter;
680         pair mi@#.l, mi@#.r, mi@#.p; % pines %
681         mi@#.l=z; mi@#.r=(z+(2ssize,0)) rotatedaround(z,ang);
682         
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));
688                 if type=volt:
689                         addto meter also thelabel(latex("\textsf{V}") scaled (ssize/6mm) 
690                         rotated (-ang), (z+(ssize,0)));
691                 elseif type=ampere:
692                         addto meter also thelabel(latex("\textsf{A}") scaled (ssize/6mm) 
693                         rotated (-ang), (z+(ssize,0)));
694                 fi;
695         elseif (type=watt):
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)));
702         fi;
703         
704         draw meter rotatedaround(z,ang) withpen line;
705         
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]);
713                 fi;
714         elseif labeling=norotatelabel:
715                 if (ang = 0):
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]);
721                 elseif (ang = 90):
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]);
739                 fi;
740         fi;
741 enddef;
742
743 // --- Electrical machines (maquinas electricas) ---
744
745 TwoTerminal motor(pair beg, real ang, string name, string val)
746 {
747   path pLine;
748   TwoTerminal term;
749
750   if (type==Up) {
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
761   }
762   term = TwoTerminal(beg, 6coil, ang, coil, coil, name, val, pLine);
763   // original makecirc used .5coil for lcharv
764   term.draw();
765   return term;
766 }
767         M@#.D=z; M@#.B=(z+(2ssize,0)) rotatedaround(z,ang);
768         picture mot; mot=nullpicture;
769         
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)));
775         
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));
780         
781         
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));
785         
786         c=fullcircle scaled ssize shifted (z+(ssize,0));
787         hc=halfcircle scaled ssize rotated 270 shifted (z+(ssize,0));
788         
789         addto mot contour buildcycle(p,q,ca,c);
790         addto mot doublepath buildcycle(p,q,ca,c);
791         
792         addto mot contour buildcycle(cb,s,r,hc);
793         addto mot doublepath buildcycle(cb,s,r,hc);
794         
795         draw mot rotatedaround(z,ang) withpen line;
796         
797         putlabel(M@#.D,M@#.B,.5ssize,.5ssize,ang,name,val);
798 enddef;
799
800 vardef generator@#(expr z,ang,name,val)=
801         save gen;
802         pair G@#.D, G@#.B; % pines %
803         G@#.D=z; G@#.B=(z+(2ssize,0)) rotatedaround(z,ang);
804         picture gen; gen=nullpicture;
805         
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)));
811         
812         draw gen rotatedaround(z,ang) withpen line;
813         
814         putlabel(G@#.D,G@#.B,.5ssize,.5ssize,ang,name,val);
815 enddef;
816
817 newinternal mid, Fe, auto;
818 mid=1; Fe=2; auto=3;
819
820 vardef transformer@#(expr z,type,ang)=
821         save trafo;
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);
827         
828         picture trafo; trafo=nullpicture;
829         
830         if type=normal:
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));
842         elseif type=mid:
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));
856         elseif type=Fe:
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);
866                 for i=1 upto 4:
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);
870                 endfor;
871                 addto trafo doublepath z+(2coil,5.3coil)--z+(0,5.3coil);
872                 for i=0 upto 3:
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);
876                 endfor;
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);
880         elseif type=auto:
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);
890         fi;
891         
892         draw trafo rotatedaround(z,ang) withpen line;
893 enddef;
894
895 //%%<--- Miscellaneous symbols --->%%%
896
897 newinternal gndlth, implth, simple, shield;
898 gndlth=5mm; implth=7mm; simple=1; shield=2;
899
900 vardef ground@#(expr z,type,ang)=
901         save GND;
902         pair gnd@#; % unico pin %
903         gnd@#=z;
904         picture GND; GND=nullpicture;
905         addto GND doublepath z--(z+(0,-.5gndlth)) withpen line;
906         if type=shield:
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;
910         elseif type=simple:
911                 addto GND doublepath (z+(-.5gndlth,-.5gndlth))--(z+(.5gndlth,-.5gndlth)) 
912                 withpen pencircle scaled 2linewd;
913         fi;
914         draw GND rotatedaround(z,ang);
915 enddef;
916
917 newinternal junctiondiam;
918 junctiondiam=1.25mm;
919
920 vardef junction@#(expr z,name)(suffix $)=
921         pair J@#; J@#=z;
922         draw z withpen pencircle scaled junctiondiam;
923         label.$(latex(name),z);
924 enddef;
925
926 vardef impedance@#(expr z,ang,name,val)=
927         save imp;
928         pair Z@#.l, Z@#.r; % pines %
929         Z@#.l=z;
930         Z@#.r=(z+(1.5implth,0)) rotatedaround(z,ang);
931         picture imp; imp=nullpicture;
932         
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));
937                 
938         draw imp rotatedaround(z,ang) withpen line;
939         
940         putlabel(Z@#.l,Z@#.r,.2implth,.2implth,ang,name,val);
941 enddef;
942
943 */
944
945 int illuminating = 1;
946
947 MultiTerminal lamp(pair beg=(0,0), real dir=0, int type=normal,
948                    Label label="", Label value="", bool draw=true)
949 {
950   real r = 0.5*circle_size;
951   MultiTerminal term;
952
953   term = _circle_symbol(beg=beg, dir=dir, label=label, value=value);
954   if (type==normal) {
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));
961   }
962   if (draw == true)
963     term.draw();
964   return term;
965 }
966
967 /*
968
969 //%%<--- Mesh current (corriente de malla) --->%%%
970
971 newinternal cw, ccw;
972 cw=0; ccw=1;
973
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;
978         im=nullpicture;
979         if dire=cw:
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);
996         elseif dire=ccw:
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);
1013         fi;
1014         
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);
1019         fi;
1020         
1021         draw im rotatedaround (c,ang) withpen line;
1022 enddef;
1023
1024 //%%<--- Reostatos --->%%%
1025
1026 newinternal rheolth, Rrheo, Lrheo; 
1027 rheolth=2mm; Rrheo=1; Lrheo=2;
1028
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);
1034         
1035         ahangle=20; ahlength=rheolth;
1036
1037         if type=Lrheo:
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));
1042         
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));
1045         
1046                 reo=reo rotatedaround(z,90);
1047         elseif type=Rrheo:
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));
1052         
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;
1056         
1057                 reo=reo rotatedaround(z,90);
1058         fi;
1059         draw reo rotatedaround(z,ang) withpen line;
1060 enddef;
1061
1062 */
1063
1064 // Loop symbols for Kirchhoff's rules.
1065
1066 void kirchhoff_loop(picture pic=currentpicture, pair points[],
1067                     pen outline=kirchhoff_pen, real aspace=-1) {
1068   // draw kirchhoff loop underneath currentpicture
1069   picture newpic;
1070   int i;
1071   guide g;
1072   pair a = points[0] - points[points.length-1];  // arrow distance
1073   if (aspace < 0)
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)
1080     g = g--points[i];
1081   g = g -- astop;
1082   draw(newpic, g, outline, Arrow(size=3*linewidth(outline)));
1083   add(pic, newpic, above=false);
1084 }