Started versioning my asymptote libraries.
authorW. Trevor King <wking@drexel.edu>
Tue, 30 Jun 2009 20:22:06 +0000 (16:22 -0400)
committerW. Trevor King <wking@drexel.edu>
Wed, 1 Jul 2009 21:30:27 +0000 (17:30 -0400)
asymptote/Circ.asy [new file with mode: 0644]
asymptote/ElectroMag.asy [new file with mode: 0644]
asymptote/Mechanics.asy [new file with mode: 0644]
asymptote/stickfigure.asy [new file with mode: 0644]

diff --git a/asymptote/Circ.asy b/asymptote/Circ.asy
new file mode 100644 (file)
index 0000000..3cb26cc
--- /dev/null
@@ -0,0 +1,1000 @@
+// Circ.asy
+//
+// Version 0.1
+// An Asymptote library for drawing electical circuit diagrams.
+// Strongly based on makecirc.mp by GS Bustamante Argañaraz.
+// Copyright (c) 2003 GS Bustamante Argañaraz, 2008 WT King.
+//
+// This program may be distributed and/or modified under the conditions
+// of the LaTeX Project Public License, either version 1.3c of this
+// license or (at your option) any later version.  The latest version
+// of this license is in http://www.latex-project.org/lppl.txt.
+//
+// This program consists of the file Circ.asy
+
+// Command definitions for easier labeling
+
+texpreamble("\def\ohm{\ensuremath{\,\Omega}}");
+texpreamble("\def\kohm{\,k\ensuremath{\Omega}}");
+texpreamble("\def\modarg#1#2{\setbox0=\hbox{$\mkern-1mu/#2^\circ$}\dp0=.21ex $#1\underline{\box0}$}");
+
+int rotatelabel = 0;
+int norotatelabel = 1;
+int labeling = rotatelabel;
+
+// Macros for the pens, I define them as such so when they expand,
+// look for the last value assigned to linewd and use it
+// (thanks to JLD). The linewd value assigns it as newinternal to
+// be able to change it «from out».
+
+real linewd = 0.25mm;
+
+pen line = makepen(scale(0.5*linewd)*unitcircle);
+pen misc = makepen(scale(0.4*linewd)*unitcircle);
+
+// Arrowhead definitions
+
+real ahlength = 4bp; // Arrowhead length
+real ahangle = 30;   // Arrowhead angle
+
+path miscahead (path p)
+{
+  real t = reltime(p, 1.0);
+  pair A = point(p,t);
+  pair u = -dir(p,t);
+  path a = shift(A)*((0,0)--(scale(ahlength)*rotate(15)*u));
+  path b = shift(A)*((0,0)--(scale(ahlength)*rotate(-15)*u));
+  return (a & reverse(a) & b & reverse(b))--cycle;
+}
+
+path fullhead (path p, real length=ahlength, real angle=ahangle)
+{
+  real t = reltime(p, 1.0);
+  pair A = point(p,t);
+  pair u = -dir(p,t);
+  path a = shift(A)*((0,0)--(scale(length)*rotate(angle/2)*u));
+  path b = shift(A)*((0,0)--(scale(length)*rotate(-angle/2)*u));
+  return (A -- a -- reverse(b) --cycle);
+}
+
+path bjtahead (path p)
+{
+  pair A = point(p,reltime(p,0.7));
+  pair u = -dir(p,reltime(p,0.5));
+  path a = shift(A)*((0,0)--(scale(ahlength)*rotate(20)*u));
+  path b = shift(A)*((0,0)--(scale(ahlength)*rotate(-20)*u));
+  return (a & reverse(a) & b & reverse(b))--cycle;
+}
+
+path txtahead (path p)
+{
+  pair A = point(p,reltime(p,1.0));
+  pair B = point(p,reltime(p,0.97));
+  pair u = dirtime(p,reltime(p,1.0));
+  return A{-u}..(A - scale(7)*rotate(15)*u)--B
+                 --(A - scale(7)*rotate(-15)*u)..A{u}--cycle;
+}
+
+// function to wire the symbols together
+
+int nsq=0, udsq=2, rlsq=3, usq=4;
+
+void wire(pair pin_beg, pair pin_end, int type)
+{
+  if (type==nsq) {
+    draw(pin_beg--pin_end, line);
+  } else if (type==udsq) {
+    draw(pin_beg--(pin_beg.x,pin_end.y)--pin_end, line);
+  } else if (type==rlsq) {
+    draw(pin_beg--(pin_end.x,pin_beg.y)--pin_end, line);
+  } else {
+    write("Error, unrecognized wire type",type);
+  }
+}
+
+// function to connect two branches in parallel
+
+void wireU(pair pin_beg, pair pin_end, real dist, int type)
+{
+  if (type==udsq) {
+    draw(pin_beg--(pin_beg+(0,dist))--(pin_end.x,pin_beg.y + dist)
+        --pin_end, line);
+  } else if (type==rlsq) {
+    draw(pin_beg--(pin_beg+(dist,0))--(pin_beg.x + dist,pin_end.y)
+        --pin_end, line);
+  } else {
+    write("Error, unrecognized wireU type",type);
+  }
+}
+
+// Macro to center text among two pins
+
+bool witharrow=false, noarrow=true;
+
+void ctext(pair pin_beg, pair pin_end, string txt, bool type)
+{
+  picture ctxt;
+  if (type==noarrow) {
+    ; // pass
+  } else if (type==witharrow) {
+    draw(ctxt, pin_beg--pin_end);
+    draw(ctxt, txtahead(pin_beg--pin_end));
+    draw(ctxt, txtahead(reverse(pin_beg--pin_end)));
+  } else {
+    write("Error, unrecognized ctext type",type);
+  }
+  label(ctxt, txt, 0.5(pin_beg+pin_end));
+  add(currentpicture, ctxt);
+}
+
+// Definition of lbsep (label separation), distance among symbol and label.
+
+real lbsep=3mm;
+
+
+// ----- Here the symbols begin --------
+
+struct TwoTerminal {
+  pair beg;
+  pair end;
+  pair mid;
+  real len;
+  real ang;
+  real lchar;
+  real lcharv;
+  string name;
+  string val;
+  path pLine[]; // cyclic paths are filled in
+  path pMisc[];
+  
+  void operator init(pair beg, real len, real ang, real lchar, real lcharv, string name, string val, path pLine[]={}, path pMisc[]={}) {
+    this.beg = beg;
+    this.end = beg+rotate(ang)*(len,0);
+    this.mid = (this.beg + this.end)/2;
+    this.len = len;
+    this.ang = ang % 360;
+    this.lchar = lchar;
+    this.lcharv = lcharv;
+    this.name = name;
+    this.val = val;
+    this.pLine = pLine;
+    this.pMisc = pMisc;
+  }
+
+  void putlabel(picture pic=currentpicture) {
+    picture picL;
+    pair pName, pVal; // point
+    real rName, rVal; // rotated by
+    align aName, aVal;
+    if (labeling==rotatelabel) {
+      pName = (lchar+lbsep)*dir (90+ang);
+      pVal = (lcharv+lbsep)*dir (270+ang);
+      aName = NoAlign;
+      aVal = NoAlign;
+      if (ang <= 90 || ang > 270) {
+       rName = ang;
+       rVal = ang;
+      } else if (ang > 90 && ang <= 270) {
+       rName = 180+ang;
+       rVal = 180+ang;
+      }
+    } else if (labeling==norotatelabel) {
+      rName = 0;
+      rVal = 0;
+      if (ang == 0) {
+       pName = (lchar+.25lbsep)*dir (90+ang);
+       pVal = (lcharv+.25lbsep)*dir (270+ang);
+       aName = N;
+       aVal = S;
+      } else if (ang < 90) {
+       pName = (lchar)*dir (90+ang);
+       pVal = (lcharv)*dir (270+ang);
+       aName = NW;
+       aVal = SE;
+      } else if (ang == 90) {
+       pName = (lchar+.25lbsep)*dir (90+ang);
+       pVal = (lcharv+.25lbsep)*dir (270+ang);
+       aName = W;
+       aVal = E;
+      } else if (90 < ang && ang < 180) {
+       pName = (lchar)*dir (90+ang);
+       pVal = (lcharv)*dir (270+ang);
+       aName = SW;
+       aVal = NE;
+      } else if (ang == 180) {
+       pName = (lchar+.25lbsep)*dir (90+ang);
+       pVal = (lcharv+.25lbsep)*dir (270+ang);
+       aName = S;
+       aVal = N;
+      } else if (ang > 180 && ang < 270) {
+       pName = (lchar)*dir (90+ang);
+       pVal = (lcharv)*dir (270+ang);
+       aName = SE;
+       aVal = NW;
+      } else if (ang == 270) {
+       pName = (lchar+.25lbsep)*dir (90+ang);
+       pVal = (lcharv+.25lbsep)*dir (270+ang);
+       aName = E;
+       aVal = W;
+      } else if (270 < ang && ang < 360) {
+       pName = (lchar)*dir (90+ang);
+       pVal = (lcharv)*dir (270+ang);
+       aName = NE;
+       aVal = SW;
+      }
+    }
+    Label lName = rotate(rName)*Label(name);
+    label(picL, lName, pName, aName);    
+    Label lVal = rotate(rVal)*Label(val);
+    label(picL, lVal, pVal, aVal);
+    add(pic, picL, (end-beg)/2);
+  }
+  
+  void draw(picture pic=currentpicture) {
+    picture picT;
+    for (int i=0; i< pLine.length; i+=1) {
+      draw(picT, rotate(ang)*pLine[i], line);
+      if (cyclic(pLine[i]))
+       fill(picT, rotate(ang)*pLine[i], line);
+    }
+    for (int i=0; i< pMisc.length; i+=1) {
+      draw(picT, rotate(ang)*pMisc[i], misc);
+      if (cyclic(pMisc[i]))
+       fill(picT, rotate(ang)*pMisc[i], misc);
+    }
+    putlabel(picT);
+    add(pic, picT, beg);
+  }
+}
+
+// --- Resistor (Resistencia) ---
+
+real rstlth=2mm;
+int normal=0, variable=2;
+
+TwoTerminal resistor(pair beg, int type, real ang, string name, string val)
+{
+  path pLine, pMisc[]={};
+  TwoTerminal term;
+
+  pLine = (0,0)--(2rstlth,0)--(2.25rstlth,.75rstlth);
+  for (real i=.5; i<=2.5; i+=0.5)
+    pLine = pLine--((2.25+i)*rstlth,((-1)**(2i))*.75rstlth);
+  pLine = pLine -- (5rstlth,0)--(7rstlth,0);
+  if (type==normal) {
+    ; //pass
+  } else if (type==variable) {
+    ahlength=.8rstlth;
+    pMisc.push((2rstlth,-rstlth)--(5.5rstlth,rstlth));
+    pMisc.push(miscahead((2rstlth,-rstlth)--(5.5rstlth,rstlth)));
+  } else {
+    write("Error, unrecognized resistor type",type);    
+  }
+  term = TwoTerminal(beg, 7rstlth, ang, .8rstlth, .8rstlth, name, val, pLine, pMisc);
+  term.draw();
+  return term;
+}
+
+// --- Inductor (bobina) ---
+
+real coil=2mm;
+int Up=0, Down=1;
+
+TwoTerminal inductor(pair beg, int type, real ang, string name, string val)
+{
+  path pLine;
+  TwoTerminal term;
+  
+  if (type==Up) {
+    pLine = (0,0)--(coil,0);
+    for (int i=2; i<=4; i+=1)
+      pLine = pLine{N}..{S}(i*coil,0);
+    pLine = pLine{N}..{S}(5coil,0)--(6coil,0);
+  } else if (type==Down) {
+    pLine = (0,0)--(coil,0);
+    for (int i=2; i<=4; i+=1)
+      pLine = pLine{S}..{N}(i*coil,0);
+    pLine = pLine{S}..{N}(5coil,0)--(6coil,0);
+    // the original makecirc changed labelangle to ang-180
+  } else {
+    write("Error, unrecognized inductor type",type);
+  }
+  term = TwoTerminal(beg, 6coil, ang, coil, coil, name, val, pLine);
+  // the original makecirc used .5coil for lcharv
+  term.draw();
+  return term;
+}
+
+// --- Capacitor (condensador) ---
+
+real platsep=1mm;
+int normal=0, electrolytic=1, variable=2, variant=3;
+
+TwoTerminal capacitor(pair beg, int type, real ang, string name, string val)
+{
+  path pLine[]={}, pMisc[]={};
+  TwoTerminal term;
+
+  pLine.push((0,0)--(3platsep,0));
+  pLine.push((4platsep,0)--(7platsep,0));
+
+  if (type==normal) {
+    pLine.push((3platsep,-2.5platsep)--(3platsep,2.5platsep));
+    pLine.push((4platsep,-2.5platsep)--(4platsep,2.5platsep));
+  } else if (type==electrolytic) {
+    pLine.push((3platsep,-1.8platsep)--(3platsep,1.8platsep));
+    pLine.push((2platsep,-2.5platsep)--(4platsep,-2.5platsep)
+              --(4platsep,+2.5platsep)--(2platsep,2.5platsep));
+  } else if (type==variable) {
+    pLine.push((3platsep,-2.5platsep)--(3platsep,2.5platsep));
+    pLine.push((4platsep,-2.5platsep)--(4platsep,2.5platsep));
+    pMisc.push((platsep,-2.5platsep)--(6platsep,2.5platsep));
+    ahlength=1.7platsep;
+    pMisc.push(miscahead((platsep,-2.5platsep)--(6platsep,2.5platsep)));
+  } else if (type==variant) {
+    pLine.push((3platsep,-2.5platsep)--(3platsep,2.5platsep));
+    pLine.push((4.5platsep,-2.5platsep)..(4platsep,0)..(4.5platsep,2.5platsep));
+  } else {
+    write("Error, unrecognized capacitor type",type);
+  }
+  term = TwoTerminal(beg, 7platsep, ang, 2.5platsep, 2.5platsep, name, val, pLine, pMisc);
+  term.draw();
+  return term;
+}
+
+// --- Diode (diodo) ---
+
+real diodeht=3.5mm;
+int zener=1, LED=2;
+// I droped the pin parameters, since other device (e.g. electrolytic
+// capacitors) are also polarized.  The positioning macros centerof,
+// etc provide enough flexibility.
+
+TwoTerminal diode(pair beg, int type, real ang, string name, string val)
+{
+  path pLine[]={}, pMisc[]={};
+  real lchar, lcharv;
+  TwoTerminal term;
+
+  pLine.push((0,0)--(diodeht,0)--(diodeht,.5diodeht)--(2diodeht,0)--(diodeht,-.5diodeht)--(diodeht,0));
+  pLine.push((2diodeht,0)--(3diodeht,0));
+  lchar = 0.6diodeht; lcharv = 0.6diodeht;
+  
+  if (type==normal) {
+    pLine.push((2diodeht,-.5diodeht)--(2diodeht,.5diodeht));
+  } else if (type==zener) {
+    pLine.push((2.5diodeht,-.5diodeht)--(2diodeht,-.5diodeht)--(2diodeht,.5diodeht)--(1.5diodeht,.5diodeht));
+  } else if (type==LED) {
+    path a = (diodeht,.5diodeht)--(2diodeht,0);
+    pair u = unit((.5,1)); // perpendicular to a
+    path b = (0,0)--diodeht*u;
+    pLine.push((2diodeht,-.5diodeht)--(2diodeht,.5diodeht));
+    lchar = 1.5diodeht;
+    pMisc.push(shift(point(a,reltime(a,0.25))+point(b,0.33))*((0,0)--diodeht*u));
+    pMisc.push(shift(point(a,reltime(a,0.60))+point(b,0.33))*((0,0)--diodeht*u));
+    pMisc.push(fullhead(pMisc[0], 0.4diodeht, 30));
+    pMisc.push(fullhead(pMisc[1], 0.4diodeht, 30));
+  } else {
+    write("Error, unrecognized capacitor type",type);
+  }
+  term = TwoTerminal(beg, 3diodeht, ang, lchar, lcharv, name, val, pLine, pMisc);
+  term.draw();
+  return term;
+}
+
+//--- Battery (bater'ia) ---
+
+real bsize = 6mm;
+
+TwoTerminal battery(pair beg, real ang, string name, string val)
+{
+  path pLine[]={}, pMisc[]={};
+  real lchar, lcharv;
+  TwoTerminal term;
+
+  pLine.push((0,0)--(0.4bsize,0));
+  pLine.push((1.4bsize,0)--(1.8bsize,0));
+  
+  for (int i=0; i<3; i+=1) {
+    pLine.push(((0.4+0.4i)*bsize, -0.2bsize)--((0.4+0.4i)*bsize, 0.2bsize));
+    pLine.push(((0.6+0.4i)*bsize, -0.6bsize)--((0.6+0.4i)*bsize, 0.6bsize));    
+  }
+  lchar = 0.6bsize; lcharv = 0.6bsize;
+
+  term = TwoTerminal(beg, 1.8bsize, ang, lchar, lcharv, name, val, pLine, pMisc);
+  term.draw();
+  return term;
+}
+
+//--- Switches (Llaves) ---
+
+int NO=0, NC=1;
+real ssep=3mm, swt=1.2ssep; // TODO remove swt?
+
+/* `switch' is a Asymptote keyword (or it should be), so append SPST
+ * for Single Pole Single Throw.
+ */
+TwoTerminal switchSPST(pair beg, int type, real ang, string name, string val)
+{
+  path pLine[]={}, pMisc[]={};
+  real lchar, lcharv;
+  TwoTerminal term;
+
+  pLine.push((0,0)--(0.7ssep,0));
+  pLine.push((1.7ssep,ssep/3)--(1.7ssep,0)--(2.4ssep,0));
+  lchar = 0.6ssep; lcharv = 0.6ssep;
+
+  if (type==NO) {
+    pLine.push((0.7ssep,0)--(1.8ssep,0.7ssep));
+  } else if (type==NC) {
+    pLine.push((0.7ssep,0)--(2ssep,ssep/3));
+  } else {
+    write("Error, unrecognized switchSPST type",type);
+  }
+  term = TwoTerminal(beg, 2.4ssep, ang, lchar, lcharv, name, val, pLine, pMisc);
+  term.draw();
+  return term;
+}
+
+//--- Current (Corriente) ---
+
+real isize=2mm;
+
+// adjusted from makecirc original to center arrowhead under text
+TwoTerminal current(pair beg, real ang, string name, string val)
+{
+  path pLine[]={}, pMisc[]={};
+  real lchar, lcharv;
+  TwoTerminal term;
+  lchar = 0.4isize; lcharv = 0.4isize;
+  pLine.push((0,0)--(1.5isize,0));
+  pLine.push((1.5isize,0)--(2isize,0));
+  pMisc.push(fullhead(pLine[0], isize, 45));
+  term = TwoTerminal(beg, 2isize, ang, lchar, lcharv, name, val, pLine, pMisc);
+  term.draw();
+  return term;
+}
+
+//--- Sources (fuentes de alimentaci'on) ---
+
+real ssize=6mm;
+int AC=0,DC=1,I=2,V=3;
+
+TwoTerminal source(pair beg, int type, real ang, string name, string val)
+{
+  path pLine[]={}, pMisc[]={};
+  real len, lchar, lcharv;
+  TwoTerminal term;
+
+
+  if (type == AC || type == I || type == V) {
+    len = 2ssize;
+    lchar = 0.5ssize; lcharv = 0.5ssize;
+    pLine.push((0,0)--(.5ssize,0));
+    pLine.push(shift((ssize,0))*scale(ssize/2)*unitcircle);
+    pLine.push((1.5ssize,0)--(2ssize,0));
+    if (type == AC) {
+      pLine.push((2ssize/3,0ssize){NE}..{E}((1/3+.5)*ssize,.2ssize)..{SE}(ssize,0)..{E}((2/3+.5)*ssize,-.2ssize)..{NE}(4ssize/3,0));
+    } else if (type == I) {
+      pLine.push((2ssize/3,0)--(4ssize/3,0));
+      pLine.push(fullhead(pLine[3], 4ssize/15, 30));
+    } else if (type == V) {
+      pLine.push((1.05ssize,0)--(1.45ssize,0));
+      pLine.push((1.25ssize,-.2ssize)--(1.25ssize,.2ssize));
+      pLine.push((.95ssize,0)--(.55ssize,0));      
+    }
+  } else if (type == DC) {
+    len = ssize;
+    lchar = 0.6ssize; lcharv = .6ssize;
+    pLine.push((0,0)--(0.4ssize,0));
+    pLine.push((.6ssize,0)--(ssize,0));
+    pLine.push((.4ssize,-.2ssize)--(.4ssize,.2ssize));
+    pLine.push((.6ssize,-.6ssize)--(.6ssize,.6ssize));
+  }
+  term = TwoTerminal(beg, len, ang, lchar, lcharv, name, val, pLine, pMisc);
+  term.draw();
+  return term;
+}
+
+/*
+
+//%%<--- Transistor --->%%%
+newinternal npn, pnp, cnpn, cpnp, bjtlth;
+npn=1; pnp=-1; cnpn=0; cpnp=2; bjtlth=7mm;
+
+vardef transistor@#(expr z,type,ang)=
+       save BJT;
+       pair T@#.B,T@#.E,T@#.C; % pines: Base, Emisor, Colector %
+       T@#.B=z;
+       T@#.E=(z+(bjtlth,-.75bjtlth)) rotatedaround(z,ang);
+       T@#.C=(z+(bjtlth,.75bjtlth)) rotatedaround(z,ang);
+       picture BJT;
+       BJT=nullpicture;
+       
+       addto BJT doublepath z--(z+(.5bjtlth,0)) withpen line;
+       addto BJT doublepath (z+(.5bjtlth,-.5bjtlth))--(z+(.5bjtlth,.5bjtlth)) withpen line;
+       addto BJT doublepath (z+(.5bjtlth,.2bjtlth))--(z+(bjtlth,.5bjtlth))
+       --(z+(bjtlth,.75bjtlth)) withpen line;
+       
+       if type=npn:
+               addto BJT doublepath (z+(.5bjtlth,-.2bjtlth))--(z+(bjtlth,-.5bjtlth))
+               --(z+(bjtlth,-.75bjtlth)) withpen line;
+               addto BJT contour bjtahead (z+(.5bjtlth,-.2bjtlth))
+               --(z+(bjtlth,-.5bjtlth)) withpen line;
+       elseif type=cnpn:
+               addto BJT doublepath (z+(.5bjtlth,-.2bjtlth))--(z+(bjtlth,-.5bjtlth))
+               --(z+(bjtlth,-.75bjtlth)) withpen line;
+               addto BJT contour bjtahead (z+(.5bjtlth,-.2bjtlth))
+               --(z+(bjtlth,-.5bjtlth)) withpen line;
+               addto BJT doublepath fullcircle scaled 1.3bjtlth shifted (z+(.65bjtlth,0))
+                withpen line;
+       elseif type=pnp:
+               addto BJT doublepath (z+(bjtlth,-.75bjtlth))--(z+(bjtlth,-.5bjtlth))
+               --(z+(.5bjtlth,-.2bjtlth)) withpen line;
+               addto BJT contour bjtahead (z+(bjtlth,-.5bjtlth))
+               --(z+(.5bjtlth,-.2bjtlth)) withpen line;
+       elseif type=cpnp:
+               addto BJT doublepath (z+(bjtlth,-.75bjtlth))--(z+(bjtlth,-.5bjtlth))
+               --(z+(.5bjtlth,-.2bjtlth)) withpen line;
+               addto BJT contour bjtahead (z+(bjtlth,-.5bjtlth))
+               --(z+(.5bjtlth,-.2bjtlth)) withpen line;
+               addto BJT doublepath fullcircle scaled 1.3bjtlth shifted (z+(.65bjtlth,0)) withpen line;
+       fi;
+       
+       draw BJT rotatedaround(z,ang);
+enddef;
+
+//%%<--- Measurement instruments (Intrumentos de medicion)--->%%%
+newinternal volt, ampere, watt;
+volt=0; ampere=1; watt=2;
+
+vardef meains@#(expr z,type,ang,name)=
+       save meter;
+       pair mi@#.l, mi@#.r, mi@#.p; % pines %
+       mi@#.l=z; mi@#.r=(z+(2ssize,0)) rotatedaround(z,ang);
+       
+       picture meter; meter=nullpicture;
+       addto meter doublepath z--(z+(.5ssize,0));
+       addto meter doublepath (z+(1.5ssize,0))--(z+(2ssize,0));
+       if (type=volt) || (type=ampere):        
+               addto meter doublepath fullcircle scaled ssize shifted (z+(ssize,0));
+               if type=volt:
+                       addto meter also thelabel(latex("\textsf{V}") scaled (ssize/6mm) 
+                       rotated (-ang), (z+(ssize,0)));
+               elseif type=ampere:
+                       addto meter also thelabel(latex("\textsf{A}") scaled (ssize/6mm) 
+                       rotated (-ang), (z+(ssize,0)));
+               fi;
+       elseif (type=watt):
+               mi@#.p=(z+(ssize,-ssize)) rotatedaround(z,ang);
+               addto meter doublepath (z+(.5ssize,-.5ssize))--(z+(.5ssize,.5ssize))
+               --(z+(1.5ssize,.5ssize))--(z+(1.5ssize,-.5ssize))--cycle;
+               addto meter doublepath (z+(ssize,-.5ssize))--(z+(ssize,-ssize));
+               addto meter also thelabel(latex("\textsf{W}") scaled (ssize/6mm) 
+               rotated (-ang), (z+(ssize,0)));
+       fi;
+       
+       draw meter rotatedaround(z,ang) withpen line;
+       
+       if labeling=rotatelabel:
+               if ((ang > (-90)) && (ang <= 90)) || ((ang > 270) && (ang <= 450)):
+                       label(latex(name) rotatedaround (.5[mi@#.l,mi@#.r],ang), 
+                       (.5ssize+lbsep)*dir (90+ang) shifted .5[mi@#.l,mi@#.r]);
+               elseif ((ang > 90) && (ang <= 270)) || ((ang > (-270)) && (ang <= (-90))):
+                       label(latex(name) rotatedaround (.5[mi@#.l,mi@#.r],180+ang), 
+                       (.5ssize+lbsep)*dir (90+ang) shifted .5[mi@#.l,mi@#.r]);
+               fi;
+       elseif labeling=norotatelabel:
+               if (ang = 0):
+                       label.top(latex(name), (.5ssize+.25lbsep)*dir (90+ang) 
+                       shifted .5[mi@#.l,mi@#.r]);
+               elseif (ang > 0) && (ang < 90):
+                       label.ulft(latex(name), (.5ssize)*dir (90+ang) 
+                       shifted .5[mi@#.l,mi@#.r]);
+               elseif (ang = 90):
+                       label.lft(latex(name),(.5ssize+.25lbsep)*dir (90+ang)
+                       shifted .5[mi@#.l,mi@#.r]);
+               elseif (90 < ang) && (ang < 180):
+                       label.llft(latex(name),(.5ssize)*dir (90+ang)
+                       shifted .5[mi@#.l,mi@#.r]);
+               elseif (ang = 180) || (ang = (-180)):
+                       label.bot(latex(name), (.5ssize+.25lbsep)*dir (90+ang) 
+                       shifted .5[mi@#.l,mi@#.r]);
+               elseif ((ang > 180) && (ang < 270)) || ((ang > (-180)) && (ang < (-90))):
+                       label.lrt(latex(name),(.5ssize)*dir (90+ang)
+                       shifted .5[mi@#.l,mi@#.r]);
+               elseif (ang = 270) || (ang = (-90)):
+                       label.rt(latex(name), (.5ssize+.25lbsep)*dir (90+ang) 
+                       shifted .5[mi@#.l,mi@#.r]);
+               elseif ((270 < ang) && (ang < 360)) || ((ang < 0) && (ang > (-90))):
+                       label.urt(latex(name),(.5ssize)*dir (90+ang)
+                       shifted .5[mi@#.l,mi@#.r]);
+               fi;
+       fi;
+enddef;
+
+// --- Electrical machines (maquinas electricas) ---
+
+TwoTerminal motor(pair beg, real ang, string name, string val)
+{
+  path pLine;
+  TwoTerminal term;
+  
+  if (type==Up) {
+    pLine = (0,0)--(coil,0);
+    for (int i=2; i<=4; i+=1)
+      pLine = pLine{N}..{S}(i*coil,0);
+    pLine = pLine{N}..{S}(5coil,0)--(6coil,0);
+  } else if (type==Down) {
+    pLine = (0,0)--(coil,0);
+    for (int i=2; i<=4; i+=1)
+      pLine = pLine{S}..{N}(i*coil,0);
+    pLine = pLine{S}..{N}(5coil,0)--(6coil,0);
+    // original makecirc changed labelangle to ang-180
+  }
+  term = TwoTerminal(beg, 6coil, ang, coil, coil, name, val, pLine);
+  // original makecirc used .5coil for lcharv
+  term.draw();
+  return term;
+}
+       M@#.D=z; M@#.B=(z+(2ssize,0)) rotatedaround(z,ang);
+       picture mot; mot=nullpicture;
+       
+       addto mot doublepath z--(z+(.4ssize,0));
+       addto mot doublepath (z+(1.6ssize,0))--(z+(2ssize,0));
+       addto mot doublepath fullcircle scaled ssize shifted (z+(ssize,0));
+       addto mot also thelabel(latex("\textsf{M}") scaled (ssize/6mm) 
+       rotated (-ang), (z+(ssize,0)));
+       
+       path p,q,r,s,ca,cb,c,hc;
+       p=(z+(.6ssize,.075ssize))--(z+(.4ssize,.075ssize));
+       q=(z+(.4ssize,.075ssize))--(z+(.4ssize,-.075ssize));
+       ca=(z+(.4ssize,-.075ssize))--(z+(.6ssize,-.075ssize));
+       
+       
+       r=(z+(1.4ssize,.075ssize))--(z+(1.6ssize,.075ssize));
+       s=(z+(1.6ssize,.075ssize))--(z+(1.6ssize,-.075ssize));
+       cb=(z+(1.6ssize,-.075ssize))--(z+(1.4ssize,-.075ssize));
+       
+       c=fullcircle scaled ssize shifted (z+(ssize,0));
+       hc=halfcircle scaled ssize rotated 270 shifted (z+(ssize,0));
+       
+       addto mot contour buildcycle(p,q,ca,c);
+       addto mot doublepath buildcycle(p,q,ca,c);
+       
+       addto mot contour buildcycle(cb,s,r,hc);
+       addto mot doublepath buildcycle(cb,s,r,hc);
+       
+       draw mot rotatedaround(z,ang) withpen line;
+       
+       putlabel(M@#.D,M@#.B,.5ssize,.5ssize,ang,name,val);
+enddef;
+
+vardef generator@#(expr z,ang,name,val)=
+       save gen;
+       pair G@#.D, G@#.B; % pines %
+       G@#.D=z; G@#.B=(z+(2ssize,0)) rotatedaround(z,ang);
+       picture gen; gen=nullpicture;
+       
+       addto gen doublepath z--(z+(.5ssize,0));
+       addto gen doublepath (z+(1.5ssize,0))--(z+(2ssize,0));
+       addto gen doublepath fullcircle scaled ssize shifted (z+(ssize,0));
+       addto gen also thelabel(latex("\textsf{G}") scaled (ssize/6mm) 
+       rotated (-ang), (z+(ssize,0)));
+       
+       draw gen rotatedaround(z,ang) withpen line;
+       
+       putlabel(G@#.D,G@#.B,.5ssize,.5ssize,ang,name,val);
+enddef;
+
+newinternal mid, Fe, auto;
+mid=1; Fe=2; auto=3;
+
+vardef transformer@#(expr z,type,ang)=
+       save trafo;
+       pair tf@#.pi, tf@#.ps, tf@#.si, tf@#.ss, tf@#.m;
+       tf@#.pi=z; tf@#.ps=(z+(0,8coil)) rotatedaround(z,ang);
+       tf@#.si=(z+(2.4coil,0)) rotatedaround(z,ang);
+       tf@#.ss=(z+(2.4coil,8coil)) rotatedaround(z,ang);
+       tf@#.m=(z+(3.4coil,4coil)) rotatedaround(z,ang);
+       
+       picture trafo; trafo=nullpicture;
+       
+       if type=normal:
+       tf@#.pi=z; tf@#.ps=(z+(0,8coil)) rotatedaround(z,ang);
+       tf@#.si=(z+(2.4coil,0)) rotatedaround(z,ang);
+       tf@#.ss=(z+(2.4coil,8coil)) rotatedaround(z,ang);
+               addto trafo doublepath z--(z+(0,coil)){right}..
+               for i=2 upto 6: {left}(z+(0,i*coil)){right}.. endfor
+               {left}(z+(0,7coil))--(z+(0,8coil));
+               addto trafo doublepath (z+(coil,coil))--(z+(coil,7coil));
+               addto trafo doublepath (z+(1.4coil,coil))--(z+(1.4coil,7coil));
+               addto trafo doublepath (z+(2.4coil,0))--(z+(2.4coil,coil)){left}..
+               for i=2 upto 6: {right}(z+(2.4coil,i*coil)){left}.. endfor
+               {right}(z+(2.4coil,7coil))--(z+(2.4coil,8coil));
+       elseif type=mid:
+       tf@#.pi=z; tf@#.ps=(z+(0,8coil)) rotatedaround(z,ang);
+       tf@#.si=(z+(2.4coil,0)) rotatedaround(z,ang);
+       tf@#.ss=(z+(2.4coil,8coil)) rotatedaround(z,ang);
+       tf@#.m=(z+(3.4coil,4coil)) rotatedaround(z,ang);
+               addto trafo doublepath z--(z+(0,coil)){right}..
+               for i=2 upto 6: {left}(z+(0,i*coil)){right}.. endfor
+               {left}(z+(0,7coil))--(z+(0,8coil));
+               addto trafo doublepath (z+(coil,coil))--(z+(coil,7coil));
+               addto trafo doublepath (z+(1.4coil,coil))--(z+(1.4coil,7coil));
+               addto trafo doublepath (z+(2.4coil,0))--(z+(2.4coil,coil)){left}..
+               for i=2 upto 6: {right}(z+(2.4coil,i*coil)){left}.. endfor
+               {right}(z+(2.4coil,7coil))--(z+(2.4coil,8coil));
+               addto trafo doublepath (z+(2.4coil,4coil))--(z+(3.4coil,4coil));
+       elseif type=Fe:
+       tf@#.pi=z rotatedaround(z,ang); tf@#.ps=(z+(0,5.3coil)) rotatedaround(z,ang);
+       tf@#.si=(z+(14coil,0)) rotatedaround(z,ang);
+       tf@#.ss=(z+(14coil,5.228coil)) rotatedaround(z,ang);
+               addto trafo doublepath z+(2coil,-2.5coil)--z+(12coil,-2.5coil)
+               --z+(12coil,7.5coil)--z+(2coil,7.5coil)--cycle;
+               addto trafo doublepath z+(4coil,-.5coil)--z+(10coil,-.5coil)
+               --z+(10coil,5.5coil)--z+(4coil,5.5coil)--cycle;
+               addto trafo doublepath z--z+(2coil,0)--z+(4coil,0.728coil)
+               {right}..{left}z+(4coil,1.3*coil);
+               for i=1 upto 4:
+                       addto trafo doublepath z+(2coil,(i+.5)*coil){left}..
+                       {right}z+(2coil,i*coil)--z+(4coil,(i+0.728)*coil)
+                       {right}..{left}z+(4coil,(i+1.3)*coil);
+               endfor;
+               addto trafo doublepath z+(2coil,5.3coil)--z+(0,5.3coil);
+               for i=0 upto 3:
+                       addto trafo doublepath z+(10coil,i*coil){left}..
+                       {right}z+(10coil,(i+.5)*coil)--z+(12coil,(i+.5+0.728)*coil)
+                       {right}..{left}z+(12coil,(i+.656)*coil);
+               endfor;
+               addto trafo doublepath z+(10coil,4coil){left}..{right}
+               z+(10coil,4.5coil)--z+(12coil,5.228coil)--z+(14coil,5.228coil);
+               addto trafo doublepath z+(12coil,0)--z+(14coil,0);
+       elseif type=auto:
+       tf@#.pi=z rotatedaround(z,ang); tf@#.ps=(z+(0,4coil)) rotatedaround(z,ang);
+       tf@#.si=(z+(4coil,-6coil)) rotatedaround(z,ang);
+       tf@#.ss=(z+(4coil,4coil)) rotatedaround(z,ang);
+               addto trafo doublepath z--z+(2coil,0);
+               addto trafo doublepath z+(2coil,-6coil)--z+(2coil,-5coil){right}..
+               for i=2 upto 10: {left}(z+(2coil,(i-6)*coil)){right}.. endfor
+               {left}(z+(2coil,5coil))--z+(2coil,6coil)--z+(0,6coil);
+               addto trafo doublepath z+(2coil,6coil)--z+(4coil,6coil);
+               addto trafo doublepath z+(2coil,-6coil)--z+(4coil,-6coil);
+       fi;
+       
+       draw trafo rotatedaround(z,ang) withpen line;
+enddef;
+
+//%%<--- Miscellaneous symbols --->%%%
+
+newinternal gndlth, implth, simple, shield;
+gndlth=5mm; implth=7mm; simple=1; shield=2;
+
+vardef ground@#(expr z,type,ang)=
+       save GND;
+       pair gnd@#; % unico pin %
+       gnd@#=z;
+       picture GND; GND=nullpicture;
+       addto GND doublepath z--(z+(0,-.5gndlth)) withpen line;
+       if type=shield:
+               addto GND doublepath (z+(-.5gndlth,-.5gndlth))--(z+(.5gndlth,-.5gndlth)) withpen line;
+               addto GND doublepath (z+(-.35gndlth,-.6gndlth))--(z+(.35gndlth,-.6gndlth)) withpen line;
+               addto GND doublepath (z+(-.2gndlth,-.7gndlth))--(z+(.2gndlth,-.7gndlth)) withpen line;
+       elseif type=simple:
+               addto GND doublepath (z+(-.5gndlth,-.5gndlth))--(z+(.5gndlth,-.5gndlth)) 
+               withpen pencircle scaled 2linewd;
+       fi;
+       draw GND rotatedaround(z,ang);
+enddef;
+
+newinternal junctiondiam;
+junctiondiam=1.25mm;
+
+vardef junction@#(expr z,name)(suffix $)=
+       pair J@#; J@#=z;
+       draw z withpen pencircle scaled junctiondiam;
+       label.$(latex(name),z);
+enddef;
+
+vardef impedance@#(expr z,ang,name,val)=
+       save imp;
+       pair Z@#.l, Z@#.r; % pines %
+       Z@#.l=z;
+       Z@#.r=(z+(1.5implth,0)) rotatedaround(z,ang);
+       picture imp; imp=nullpicture;
+       
+       addto imp doublepath z--(z+(.25implth,0));
+       addto imp doublepath (z+(.25implth,-.18implth))--(z+(.25implth,.18implth))
+       --(z+(1.25implth,.18implth))--(z+(1.25implth,-.18implth))--cycle;
+       addto imp doublepath (z+(1.25implth,0))--(z+(1.5implth,0));
+               
+       draw imp rotatedaround(z,ang) withpen line;
+       
+       putlabel(Z@#.l,Z@#.r,.2implth,.2implth,ang,name,val);
+enddef;
+
+vardef lamp@#(expr z,ang,name,val)=
+       save ampl, p, q, r, s;
+       pair La@#.l,La@#.r; % pines %
+       La@#.l=z; La@#.r=(z+(2ssize,0)) rotatedaround(z,ang);
+       
+       picture ampl; ampl=nullpicture;
+       
+       addto ampl doublepath z--(z+(.5ssize,0));
+       addto ampl doublepath fullcircle scaled ssize shifted (z+(ssize,0));
+       addto ampl doublepath (z+(1.5ssize,0))--(z+(2ssize,0));
+       
+       pair p, q, r, s;
+       p=(-ssize*dir 45 shifted (z+(ssize,0))--(z+(ssize,0))) intersectionpoint
+       (fullcircle scaled ssize shifted (z+(ssize,0)));
+       q=(ssize*dir 45 shifted (z+(ssize,0))--(z+(ssize,0))) intersectionpoint
+       (fullcircle scaled ssize shifted (z+(ssize,0)));
+       r=(-ssize*dir (-45) shifted (z+(ssize,0))--(z+(ssize,0))) intersectionpoint
+       (fullcircle scaled ssize shifted (z+(ssize,0)));
+       s=(ssize*dir (-45) shifted (z+(ssize,0))--(z+(ssize,0))) intersectionpoint
+       (fullcircle scaled ssize shifted (z+(ssize,0)));
+       
+       addto ampl doublepath p--q;
+       addto ampl doublepath r--s;
+       
+       draw ampl rotatedaround(z,ang) withpen line;
+       
+       putlabel(La@#.l,La@#.r,.5ssize,.5ssize,ang,name,val);
+enddef;
+
+
+//%%<--- Mesh current (corriente de malla) --->%%%
+
+newinternal cw, ccw;
+cw=0; ccw=1;
+
+def imesh(expr c,wd,ht,dire,ang,name)=
+       save im,r; picture im; numeric r;
+       ahlength=3platsep; ahangle=20;
+       if ht > wd: r=.2wd elseif ht < wd: r=.2ht fi;
+       im=nullpicture;
+       if dire=cw:
+               addto im doublepath (xpart c - .5wd, ypart c - .5ht)
+               --(xpart c - .5wd, ypart c + .5ht-r){up}
+               ..{right}(xpart c - .5wd + r, ypart c + .5ht)
+               --(xpart c + .5wd - r, ypart c + .5ht){right}
+               ..{down}(xpart c + .5wd,ypart c + .5ht - r)
+               --(xpart c + .5wd,ypart c - .5ht + r){down}
+               ..{left}(xpart c + .5wd - r,ypart c - .5ht)
+               --(xpart c - .25wd, ypart c - .5ht);
+               addto im contour arrowhead (xpart c - .5wd, ypart c - .5ht)
+               --(xpart c - .5wd, ypart c + .5ht-r){up}
+               ..{right}(xpart c - .5wd + r, ypart c + .5ht)
+               --(xpart c + .5wd - r, ypart c + .5ht){right}
+               ..{down}(xpart c + .5wd,ypart c + .5ht - r)
+               --(xpart c + .5wd,ypart c - .5ht + r){down}
+               ..{left}(xpart c + .5wd - r,ypart c - .5ht)
+               --(xpart c - .25wd, ypart c - .5ht);
+       elseif dire=ccw:
+               addto im doublepath (xpart c + .5wd, ypart c - .5ht)
+               --(xpart c + .5wd, ypart c + .5ht-r){up}
+               ..{left}(xpart c + .5wd - r, ypart c + .5ht)
+               --(xpart c - .5wd + r, ypart c + .5ht){left}
+               ..{down}(xpart c - .5wd,ypart c + .5ht - r)
+               --(xpart c - .5wd,ypart c - .5ht + r){down}
+               ..{right}(xpart c - .5wd + r,ypart c - .5ht)
+               --(xpart c + .25wd, ypart c - .5ht);
+               addto im contour arrowhead (xpart c + .5wd, ypart c - .5ht)
+               --(xpart c + .5wd, ypart c + .5ht-r){up}
+               ..{left}(xpart c + .5wd - r, ypart c + .5ht)
+               --(xpart c - .5wd + r, ypart c + .5ht){left}
+               ..{down}(xpart c + .5wd,ypart c + .5ht - r)
+               --(xpart c - .5wd,ypart c - .5ht + r){down}
+               ..{right}(xpart c - .5wd + r,ypart c - .5ht)
+               --(xpart c + .25wd, ypart c - .5ht);
+       fi;
+       
+       if labeling=rotatelabel:
+               addto im also thelabel(latex("$" & name & "$"),c);
+       elseif labeling=norotatelabel:
+               addto im also thelabel(latex("$" & name & "$") rotatedaround(c,-ang),c);
+       fi;
+       
+       draw im rotatedaround (c,ang) withpen line;
+enddef;
+
+//%%<--- Reostatos --->%%%
+
+newinternal rheolth, Rrheo, Lrheo; 
+rheolth=2mm; Rrheo=1; Lrheo=2;
+
+vardef rheostat@#(expr z,type,ang)=
+       save reo; picture reo; reo=nullpicture;
+       pair rh@#.i, rh@#.s, rh@#.r;
+       rh@#.i=z; rh@#.s=(z+(0,6rheolth)) rotatedaround(z,ang);
+       rh@#.r=(z+(3rheolth,6rheolth)) rotatedaround(z,ang);
+       
+       ahangle=20; ahlength=rheolth;
+
+       if type=Lrheo:
+               addto reo doublepath (z+(6rheolth,-3rheolth))--(z+(4rheolth,-3rheolth))
+               --(z+(4rheolth,-.7rheolth));
+               addto reo contour arrowhead (z+(6rheolth,-3rheolth))--(z+(4rheolth,-3rheolth))
+               --(z+(4rheolth,-.9rheolth));
+       
+               addto reo doublepath z--(z+(rheolth,0)){down}.. for i=2 upto 4:
+               {up}(z+(i*rheolth,0)){down}.. endfor {up}(z+(5rheolth,0))--(z+(6rheolth,0));
+       
+               reo=reo rotatedaround(z,90);
+       elseif type=Rrheo:
+               addto reo doublepath (z+(6rheolth,-3rheolth))--(z+(4rheolth,-3rheolth))
+               --(z+(4rheolth,-.7rheolth));
+               addto reo contour arrowhead (z+(6rheolth,-3rheolth))--(z+(4rheolth,-3rheolth))
+               --(z+(4rheolth,-.9rheolth));
+       
+               addto reo doublepath z--(z+(1.5rheolth,0))--(z+(1.75rheolth,.75rheolth))--
+               for i=.5 step .5 until 2.5:     (z+((1.75+i)*rheolth,((-1)**(2i))*.75rheolth))--
+               endfor (z+(4.5rheolth,0))--(z+(6rheolth,0)) withpen line;
+       
+               reo=reo rotatedaround(z,90);
+       fi;
+       draw reo rotatedaround(z,ang) withpen line;
+enddef;
+
+// Definiciones de las longitudes de centrado,
+// las hago como macros para que cambien de
+// valor cuando lo hagan las dimensiones
+// caracter'isticas de cada s'imbolo.
+
+def res = 3.5rstlth enddef;            % 1
+def ind = 3coil enddef;                        % 2
+def cap = 3.5platsep enddef;   % 3
+def sac = ssize enddef;                        % 4
+def sv = ssize enddef;                 % 5
+def si = ssize enddef;                 % 6
+def sdc = .5ssize enddef;              % 7
+def mot = ssize enddef;                        % 8
+def gen = ssize enddef;                        % 9
+def tra = 4coil enddef;                        %10
+def ins = ssize enddef;                        %11
+def dio = 1.5diodeht enddef;   %12
+def bjt = .5bjtlth enddef;             %13
+def imp = .75implth enddef;            %14
+def lam = ssize enddef;                        %15
+def swt = 1.2ssep enddef;              %16
+def bat = .9ssize enddef;              %17
+def cur = 1.5platsep enddef;   %18
+
+// Variable to find the center of two pins, for aligning symbols. It returns the point
+// and the input angle for the symbol that we want to place.
+
+struct Align {
+  pair c;
+  numeric phi;
+}
+
+Align centreof@#(pair pin_beg, pair pin_end, lchar)=
+       pair c@#; numeric phi@#;
+               c@#= -lchar*dir angle(xpart(pin_end)-xpart(pin_beg),
+               ypart(pin_end)-ypart(pin_beg)) shifted .5[pin_beg,pin_end];
+               phi@#=angle(xpart(pin_end)-xpart(pin_beg),
+               ypart(pin_end)-ypart(pin_beg));
+enddef;
+
+// Variable to center an element regarding the pins of another, at 
+// a distance «dist» of the same one. It returns the point in which we should
+// place the symbol that we want to center.
+
+vardef centerto.@#(expr pinref_beg,pinref_end)(expr dist,elem)=
+       pair @#;
+       if (xpart(pinref_beg)=xpart(pinref_end)):
+               @#=(.5[pinref_beg,pinref_end]+(dist,-elem))
+       elseif (ypart(pinref_beg)=ypart(pinref_end)):
+               @#=(.5[pinref_beg,pinref_end]+(-elem,dist))
+       fi
+enddef;
+
+// Macro to scale the circuit when it is concluded.
+
+def scalecirc expr factor =
+       currentpicture=currentpicture scaled factor
+enddef;
+
+// END
+
+*/
diff --git a/asymptote/ElectroMag.asy b/asymptote/ElectroMag.asy
new file mode 100644 (file)
index 0000000..7db486c
--- /dev/null
@@ -0,0 +1,173 @@
+import geometry;
+import Mechanics;
+
+// ---------------------- Charges -------------------------
+
+struct Charge {
+  pair center;
+  real q;
+  real radius;
+  pen outline;
+  pen fill;
+  Label L;
+  
+  void operator init(pair center=(0,0), real q=1, real radius=2mm, pen outline=currentpen, pen fill=red, Label L="") {
+    this.center = center;
+    this.q = q;
+    this.radius = radius;
+    this.outline = outline;
+    this.fill = fill;
+    this.L = L;
+  }
+  
+  void draw(picture pic=currentpicture) {
+    frame picF;
+    path c = scale(radius)*unitcircle;
+    filldraw(picF, c, fill, outline);
+    // TODO: label
+    add(pic, picF, center);
+  }
+}
+
+Charge pCharge(pair center=(0,0), real q=1, real radius=2mm, pen outline=currentpen, Label L="")
+{
+  Charge c = Charge(center=center, q=q, radius=radius, outline=outline, L=L, fill=red);
+  return c;
+}
+
+Charge nCharge(pair center=(0,0), real q=-1, real radius=2mm, pen outline=currentpen, Label L="")
+{
+  Charge c = Charge(center=center, q=q, radius=radius, outline=outline, L=L, fill=blue);
+  return c;
+}
+
+// ---------------------- Vectors -------------------------
+
+Vector EField(pair center=(0,0), real mag=5mm, real dir=0, Label L="")
+{
+  Vector v = Vector(center=center, mag=mag, dir=dir, L=L, outline=rgb(1,0.5,0.2)); // orange
+  return v;
+}
+
+Vector BField(pair center=(0,0), real mag=5mm, real dir=0, Label L="")
+{
+  Vector v = Vector(center=center, mag=mag, dir=dir, L=L, outline=rgb(0.1,1,0.2)); // green
+  return v;
+}
+
+Vector Velocity(pair center=(0,0), real mag=5mm, real dir=0, Label L="")
+{
+  Vector v = Vector(center=center, mag=mag, dir=dir, L=L, outline=rgb(1,0.1,0.2)); // red
+  return v;
+}
+
+// ---------------------- Forces -------------------------
+
+Vector Force(pair center=(0,0), real mag=5mm, real dir=0, Label L="")
+{
+  Vector v = Vector(center=center, mag=mag, dir=dir, L=L, outline=rgb(0.1,0.2,1)); // blue
+  return v;
+}
+
+// Force of a on b
+Vector CoulombForce(Charge a, Charge b, Label L="", real scale=1mm, real unit=1mm)
+{
+  pair r = b.center - a.center;
+  real mag, dir;
+  mag = ((a.q*b.q)*(scale/length(r))^2)*unit;
+  dir = degrees(r);
+  Vector v = Force(center=b.center, mag=mag, dir=dir, L=L);
+  return v;
+}
+
+void CoulombForces(Charge c[], real scale=1mm, real unit=1mm)
+{
+  Vector F;
+  string s;
+  for (int i=0; i<c.length; i+=1) {
+    for(int j=0; j<c.length; j+=1) {
+      if (i==j) continue;
+      s = "$F_{" + format("%d", i+1) + "," + format("%d", j+1) + "}$";
+      F = CoulombForce(c[i], c[j], L=s, scale=scale, unit=unit);
+      F.draw();
+    }
+  }
+}
+
+// ---------------------- Measures -------------------------
+
+// Distance derived from CAD.MeasuredLine
+struct Distance {
+  pair pFrom;
+  pair pTo;
+  real scale;
+  pen outline;
+  Label L;
+  
+  void operator init(pair pFrom=(0,0), pair pTo=(5mm,0), real scale=5mm, pen outline=currentpen, Label L="") {
+    this.pFrom = pFrom;
+    this.pTo = pTo;
+    this.outline = outline;
+    this.L = L;
+  }
+  
+  void draw(picture pic=currentpicture) {
+    picture picF;
+    picture picL;
+    label(picL, L);
+    pair pLabelSize = 1.2 * (max(picL)-min(picL));
+    pair pDiff = pTo - pFrom;
+    path p = (0,0)--pDiff;
+    draw(picF, p, outline, Arrows);
+    label(pic = picF,
+         L = rotate(degrees(pDiff)) * L,
+         position =
+         pDiff/2
+         + unit(rotate(90)*pDiff) * pLabelSize.y / 2);
+    add(pic, picF, pFrom);
+  }
+}
+
+struct Angle {
+  pair B;
+  pair A;
+  pair C;
+  real radius; // radius < 0 for exterior angles.
+  pen outline;
+  Label L;
+
+  void operator init(pair B, pair A, pair C, real radius=5mm, pen outline=currentpen, Label L="") {
+    this.B = B;
+    this.A = A;
+    this.C = C;
+    this.radius = radius;
+    this.outline = outline;
+    this.L = L;
+  }
+  
+  void draw(picture pic=currentpicture) {
+    picture picF;
+    picture picL;
+    label(picL, L);
+    pair pLabelSize = 1.2 * (max(picL)-min(picL));
+    path p = arc(B-A, (0,0), C-A, radius);
+    real t = reltime(p, 0.5);
+    pair P = midpoint(p);
+    pair tang = dir(p, t);
+    
+    draw(picF, p, outline);    
+    label(pic = picF,
+         L = rotate(tang) * L,
+         position =
+         P + unit(P) * pLabelSize.y / 2);
+    add(pic, picF, A);
+  }
+}
+
+// TODO: ihat, ijhat
+
+// ---------------------- Shapes -------------------------
+
+// TODO: ring, plate, block, cylinder, spring, table
+
+
diff --git a/asymptote/Mechanics.asy b/asymptote/Mechanics.asy
new file mode 100644 (file)
index 0000000..f3f3e01
--- /dev/null
@@ -0,0 +1,390 @@
+import geometry;
+
+// ---------------------- Mass -------------------------
+
+struct Mass {
+  pair center;
+  real m;
+  real radius;
+  pen outline;
+  pen fill;
+  Label L;
+  
+  void operator init(pair center=(0,0), real m=1, real radius=2mm, pen outline=currentpen, pen fill=grey, Label L="") {
+    this.center = center;
+    this.m = m;
+    this.radius = radius;
+    this.outline = outline;
+    this.fill = fill;
+    this.L = L;
+  }
+  
+  void draw(picture pic=currentpicture) {
+    picture picF;
+    path c = scale(radius)*unitcircle;
+    filldraw(picF, c, fill, outline);
+    label(pic=picF, L=L, position=(0,0));
+    add(pic, picF, center);
+  }
+}
+
+struct Block {
+  pair center;
+  real m;
+  real width;
+  real height;
+  real direction;
+  pen outline;
+  pen fill;
+  Label L;
+  
+  void operator init(pair center=(0,0), real m=1, real width=5mm, real height=-1, real direction=0, pen outline=currentpen, pen fill=grey, Label L="") {
+    this.center = center;
+    this.m = m;
+    this.width = width;
+    if (height == -1)
+      this.height = width;
+    else
+      this.height = height;
+    this.direction = direction;
+    this.outline = outline;
+    this.fill = fill;
+    this.L = L;
+  }
+  
+  void draw(picture pic=currentpicture) {
+    picture picF;
+    path c = rotate(direction)*scale(width,height)*shift(-.5,-.5)*unitsquare;
+    filldraw(picF, c, fill, outline);
+    label(pic=picF, L=L, position=(0,0));
+    add(pic, picF, center);
+  }
+}
+
+// ---------------------- Vectors -------------------------
+
+struct Vector {
+  pair center;
+  real mag;
+  real dir;
+  pen outline;
+  Label L;
+  
+  void operator init(pair center=(0,0), real mag=5mm, real dir=0, pen outline=currentpen, Label L="") {
+    this.center = center;
+    this.mag = mag;
+    this.dir = dir;
+    this.outline = outline;
+    this.L = L;
+  }
+
+  pair pTip() {
+    return this.mag*dir(this.dir)+this.center;
+  }
+  
+  void draw(picture pic=currentpicture, bool rotateLabel=false, pair labelOffset=(0,0)) {
+    picture picF;
+    pair p = this.mag*dir(this.dir);
+    path P = (0,0)--p;
+    pair label_rotate = p;
+    draw(picF, P, outline, Arrow);
+    if (rotateLabel == false)
+      label_rotate = (1,0);
+    label(pic = picF,
+         L = rotate(degrees(label_rotate)) * L,
+         position = p+labelOffset,
+         align = unit(rotate(90)*p));
+    add(pic, picF, center);
+  }
+}
+
+Vector Velocity(pair center=(0,0), real mag=5mm, real dir=0, Label L="")
+{
+  Vector v = Vector(center=center, mag=mag, dir=dir, L=L, outline=rgb(1,0.1,0.2)); // red
+  return v;
+}
+
+// ---------------------- Forces -------------------------
+
+Vector Force(pair center=(0,0), real mag=5mm, real dir=0, Label L="")
+{
+  Vector v = Vector(center=center, mag=mag, dir=dir, L=L, outline=rgb(0.1,0.2,1)); // blue
+  return v;
+}
+
+// ---------------------- Measures -------------------------
+
+// Distance derived from CAD.MeasuredLine
+struct Distance {
+  pair pFrom;
+  pair pTo;
+  real scale;
+  pen outline;
+  Label L;
+  
+  void operator init(pair pFrom=(0,0), pair pTo=(5mm,0), real scale=5mm, pen outline=currentpen, Label L="") {
+    this.pFrom = pFrom;
+    this.pTo = pTo;
+    this.scale = scale;
+    this.outline = outline;
+    this.L = L;
+  }
+  
+  void draw(picture pic=currentpicture, bool rotateLabel=true) {
+    picture picF;
+    picture picL;
+    label(picL, L);
+    pair pLabelSize = 1.2 * (max(picL)-min(picL));
+    pair pDiff = pTo - pFrom;
+    path p = (0,0)--pDiff;
+    pair label_rotate=pDiff;
+    if (rotateLabel == false)
+      label_rotate=(1,0);
+    draw(picF, p, outline, Arrows);
+    label(pic = picF,
+         L = rotate(degrees(label_rotate)) * L,
+         position =  pDiff/2
+           + unit(rotate(90)*pDiff) * pLabelSize.y / 2);
+    //label(pic=picF, L = rotate(degrees(label_rotate)) format("%g", pDiff/scale), position = TODO);
+    add(pic, picF, pFrom);
+  }
+}
+
+struct Angle {
+  pair B;
+  pair A; // center of angle
+  pair C;
+  real radius; // radius < 0 for exterior angles.
+  pen outline;
+  Label L;
+
+  void operator init(pair B, pair A, pair C, real radius=5mm, pen outline=currentpen, Label L="") {
+    this.B = B;
+    this.A = A;
+    this.C = C;
+    this.radius = radius;
+    this.outline = outline;
+    this.L = L;
+  }
+  
+  void draw(picture pic=currentpicture, bool rotateLabel=false) {
+    picture picF;
+    picture picL;
+    bool direction;
+    label(picL, L);
+    
+    pair pLabelSize = 1.2 * (max(picL)-min(picL));
+    real ccw_angle = degrees(C-A)-degrees(B-A);
+    bool direction = CCW;
+    if (ccw_angle < 0) ccw_angle += 360.0;
+    if (ccw_angle > 180)
+      direction = CW;
+    if (radius < 0)
+      direction = !direction;
+    path p = arc((0,0), fabs(radius), degrees(B-A), degrees(C-A), direction);
+    real t = reltime(p, 0.5);
+    pair P = midpoint(p);
+    pair tangent = dir(p, t);
+    if (direction == CW) tangent *= -1.0;
+    
+    pair label_rotate = tangent;
+    if (rotateLabel == false)
+      label_rotate = (1,0);
+    
+    draw(picF, p, outline);    
+    label(pic = picF,
+         L = rotate(degrees(label_rotate)) * L,
+         position = P + unit(P) * pLabelSize.y / 2);
+    add(pic, picF, A);
+  }
+}
+
+// TODO: ihat, ijhat
+Vector hatVect (string name,  pair center=(0,0), real dir=0) {
+  string L = replace("$\mathbf{\hat{X}}$", "X", name);
+  Vector v = Vector(center=center, mag=5mm, dir=dir, L=L, outline=rgb(0,0,0));
+  return v;
+}
+
+Vector ihat (pair center=(0,0), real dir=0) {
+  Vector v = hatVect(name="i", center=center, dir=dir);
+  return v;
+}
+
+Vector jhat (pair center=(0,0), real dir=90) {
+  Vector v = hatVect(name="j", center=center, dir=dir);
+  return v;
+}
+
+// ---------------------- Shapes -------------------------
+
+struct Wire {
+  pair pFrom;
+  pair pTo;
+  pen outline;
+  Label L;
+  
+  void operator init(pair pFrom=(0,0), pair pTo=(5mm,0), pen outline=currentpen, Label L="") {
+    this.pFrom = pFrom;
+    this.pTo = pTo;
+    this.outline = outline;
+    this.L = L;
+  }
+  
+  void draw(picture pic=currentpicture, bool rotateLabel=true) {
+    picture picF;
+    picture picL;
+    label(picL, L);
+    pair pLabelSize = 1.2 * (max(picL)-min(picL));
+    pair pDiff = pTo - pFrom;
+    path p = (0,0)--pDiff;
+    pair label_rotate=pDiff;
+    if (rotateLabel == false)
+      label_rotate=(1,0);
+    draw(picF, p, outline);
+    label(pic = picF,
+         L = rotate(degrees(label_rotate)) * L,
+         position =  pDiff/2
+           + unit(rotate(90)*pDiff) * pLabelSize.y / 2);
+    add(pic, picF, pFrom);
+  }
+}
+
+struct Surface {
+  pair pFrom;
+  pair pTo;
+  real thickness;
+  pen outline;
+  pen filla;
+  pen fillb;
+  Label L;
+  
+  void operator init(pair pFrom=(0,0), pair pTo=(5mm,0), real thickness=5mm, pen outline=currentpen, pen filla=rgb(.5,.5,.5), pen fillb=rgb(.7,.7,.7), Label L="") {
+    this.pFrom = pFrom;
+    this.pTo = pTo;
+    this.thickness = thickness;
+    this.outline = outline;
+    this.filla = filla;
+    this.fillb = fillb;
+    this.L = L;
+  }
+  
+  void draw(picture pic=currentpicture, bool rotateLabel=true) {
+    picture picF;
+    picture picL;
+    label(picL, L);
+    pair pLabelSize = 1.2 * (max(picL)-min(picL));
+    pair pDiff = pTo - pFrom;
+    pair pDepth = rotate(-90)*unit(pDiff)*thickness;
+    path p = (0,0) -- pDiff -- (pDiff+pDepth) -- pDepth -- cycle;
+    pair label_rotate=pDiff;
+    if (rotateLabel == false)
+      label_rotate=(1,0);
+    axialshade(pic=picF, g=p, pena=filla, a=(0,0), penb=fillb,
+              b=pDepth);
+    draw(picF, p, outline);
+    label(pic = picF,
+         L = rotate(degrees(label_rotate)) * L,
+         position = (pDiff+pDepth)/2);
+    add(pic, picF, pFrom);
+  }
+}
+
+struct Spring {
+  pair pFrom;
+  pair pTo;
+  real k;
+  real width;
+  real dLength; // length of a single loop (when unstretched)
+  real deadLength; // length before loops start on each end
+  real unstretchedLength;
+  int nLoops;
+  pen outline;
+  Label L;
+  
+  void operator init(pair pFrom=(0,0), pair pTo=(5mm,0), real k=1, real width=3mm, real dLength=1mm, real deadLength=3mm, real unstretchedLength=12mm, pen outline=currentpen, Label L="") {
+    this.pFrom = pFrom;
+    this.pTo = pTo;
+    this.k = k;
+    this.width = width;
+    this.dLength = dLength;
+    this.unstretchedLength = unstretchedLength;
+    this.outline = outline;
+    this.L = L;
+
+    this.nLoops = floor((unstretchedLength-2*deadLength)/dLength);
+    if (this.nLoops == 0)
+      this.nLoops = 1;
+    this.deadLength = (unstretchedLength-this.nLoops*dLength)/2;
+  }
+  
+  void draw(picture pic=currentpicture, bool rotateLabel=true) {
+    picture picF;
+    picture picL;
+    label(picL, L);
+    pair pLabelSize = 1.2 * (max(picL)-min(picL));
+    pair pDiff = pTo - pFrom;
+    
+    real working_dLength = (length(pDiff) - 2*deadLength) / nLoops;
+    path p = (0,0)--(deadLength,0);
+    path loop = (0,0)
+      --(working_dLength/4, width/2)
+      --(working_dLength*3/4, -width/2)
+      --(working_dLength, 0);
+    pair loopStart;
+    for (int i=0; i<nLoops; ++i) {
+      loopStart = point(p, length(p));
+      p = p--(shift(loopStart)*loop);
+    }
+    loopStart = point(p, length(p));
+    p = p--(loopStart+(deadLength,0));
+    p = rotate(degrees(pDiff)) * p;
+    
+    pair label_rotate=pDiff;
+    if (rotateLabel == false)
+      label_rotate=(1,0);
+    draw(picF, p, outline);
+    label(pic = picF,
+         L = rotate(degrees(label_rotate)) * L,
+         position =  pDiff/2
+         + unit(rotate(90)*pDiff) * (width + pLabelSize.y) / 2);
+    add(pic, picF, pFrom);
+  }
+}
+
+struct Pendulum {
+  pair pivot;
+  Mass mass;
+  Angle angle;
+  Wire str;
+  
+  void operator init(pair pivot=(0,0), Mass mass=Mass()) {
+    this.pivot = pivot;
+    this.mass = mass;
+    this.angle = Angle(mass.center, pivot, pivot-(0,1));
+    this.str = Wire(pivot, mass.center);
+  }
+  
+  void draw(picture pic=currentpicture, bool drawVertical=false) {
+    str.draw(pic=pic, rotateLabel=false);
+    if (drawVertical == true) {
+      pair final = pivot + realmult((0,0.5),(mass.center-pivot));
+      draw(pic=pic, pivot--final, p=currentpen+dashed);
+    }
+    draw(pic=pic, pivot);
+    mass.draw(pic=pic);
+    angle.draw(pic=pic);
+  }
+}
+
+// The angle argument is deflection from straight down (i.e. 0 degrees = plumb)
+Pendulum makePendulum(pair pivot=(0,0), Mass mass=Mass(), real length=15mm, real angleDeg=0, Label angleL="", Label stringL="") {
+  mass.center = pivot + length*dir(angleDeg-90);
+  Pendulum p = Pendulum(pivot=pivot, mass=mass);
+  p.angle.L = angleL;
+  p.str.L = stringL;
+  return p;
+}
+
+
+// TODO: ring, plate, block, cylinder, table
diff --git a/asymptote/stickfigure.asy b/asymptote/stickfigure.asy
new file mode 100644 (file)
index 0000000..2ad15f6
--- /dev/null
@@ -0,0 +1,91 @@
+struct StickFigure {
+  pair center;
+  real height;
+  real headHeightRatio;
+  real neckHeightRatio;
+  real torsoHeightRatio;
+  real shoulderHeightRatio;
+  real armTorsoRatio;
+  real armAngle;
+  pen outline;
+  pen fill;
+  
+  void operator init(pair standsOn=(0,0), real height=10mm) {
+    this.center = standsOn+(0,height/2);
+    this.height = height;
+    this.headHeightRatio = 0.2;
+    this.neckHeightRatio = 0.1;
+    this.torsoHeightRatio = 0.28;
+    this.shoulderHeightRatio = 0.1;
+    this.armTorsoRatio = 1.2;
+    this.armAngle = -70;
+    this.outline = currentpen;
+    this.fill = currentpen;
+  }
+
+  pair crownPos() {
+    return this.center + (0,this.height/2);
+  }
+  
+  pair chinPos() {
+    return this.crownPos() - (0,this.height*this.headHeightRatio);
+  }
+  
+  pair headPos() {
+    return (this.crownPos() + this.chinPos())/2;
+  }
+  
+  pair neckBasePos() {
+    return this.chinPos() - (0,this.height*this.neckHeightRatio);
+  }
+
+  pair shoulderPos(bool rightSide=true) {
+    real sign = 1;
+    if (rightSide == false)
+      sign = -1;
+    return this.neckBasePos() + (sign*this.height*this.shoulderHeightRatio/2,0);
+  }
+  
+  pair handPos(bool rightSide=true) {
+    pair dArm = this.height*this.torsoHeightRatio*this.armTorsoRatio * dir(armAngle);
+    if (rightSide == false)
+      dArm = (-dArm.x, dArm.y);
+    return this.shoulderPos(rightSide=rightSide) + dArm;
+  }
+
+  pair tailPos() {
+    return this.neckBasePos() - (0,this.height*this.torsoHeightRatio);
+  }    
+  
+  pair footPos(bool rightSide=true) {
+    real legHeightRatio = 1.0 - this.headHeightRatio - this.neckHeightRatio - torsoHeightRatio;
+    pair dLeg = (this.height*this.shoulderHeightRatio/2, -this.height*legHeightRatio);
+    if (rightSide == false)
+      dLeg = (-dLeg.x, dLeg.y);
+    return this.tailPos() + dLeg;
+  }
+
+  void draw(picture pic=currentpicture) {
+    path head =
+      shift(this.headPos())
+      *scale(this.height*this.headHeightRatio/2)
+      *unitcircle;
+    path neckAndTorso =
+      this.chinPos()
+      --this.neckBasePos()
+      --this.tailPos();
+    path armsAndShoulders =
+      this.handPos(rightSide=true)
+      --this.shoulderPos(rightSide=true)
+      --this.shoulderPos(rightSide=false)
+      --this.handPos(rightSide=false);
+    path legs =
+      this.footPos(rightSide=true)
+      --this.tailPos()
+      --this.footPos(rightSide=false);
+    draw(pic, armsAndShoulders, outline);
+    draw(pic, legs, outline);
+    draw(pic, neckAndTorso, outline);
+    filldraw(pic, head, fill, outline);
+  }
+}