divert(-1)
   libgen.m4                    Base macros for dpic and gpic diagrams

* Circuit_macros Version 5.0, copyright (c) 2001 J. D. Aplevich.       *
* The files of this distribution can be redistributed or modified,     *
* provided that this copyright notice is included, and provided that   *
* modifications are clearly marked to distinguish them from this       *
* distribution.  There is no warranty whatsoever for these files.      *

                                Installation directory.  You can set this to
                                the null string if you use an environment
                                variable to tell m4 where to search:
ifdef(`HOMELIB_',,
  `define(`HOMELIB_',`')')
#  `define(`HOMELIB_',`/u/aplevich/lib/')')

                                Default pic processor: gpic.
                                To make dpic -p the default, change gpic.m4
                                to pstricks.m4.
ifdef(`gpic_',,
  `ifdef(`pstricks_',,
  `ifdef(`mfpic_',,
  `include(HOMELIB_`'gpic.m4)')')')dnl
divert(-1)
                                Set environment direction
define(`right_',`define(`m4dir',right) manhattan m4dir')
define(`left_',`define(`m4dir',left) manhattan m4dir')
define(`up_',`define(`m4dir',up) manhattan m4dir')
define(`down_',`define(`m4dir',down) manhattan m4dir')

                                Direction cosines
define(`manhattan',`dnl
 define(`m4x_',`ifelse(m4dir,left,-1,m4dir,up,0,m4dir,down,0,1)')dnl
 define(`m4y_',`ifelse(m4dir,left,0,m4dir,up,1,m4dir,down,-1,0)')')

                                Coordinate numbers for arbitrary direction:
                                `Point_(integer degrees)'
define(`Point_',`define(`m4x_',`cosd($1)')define(`m4y_',`sind($1)')')
                                `point_(radians)'
define(`point_',`define(`m4x_',`cos($1)')define(`m4y_',`sin($1)')')
                                `rpoint_(linespec)'
                                (Gpic returns NaN for atan2(0,0)):
define(`rpoint_',`line invis $1
  rp_wid=last line.end.x-last line.start.x
  rp_ht=last line.end.y-last line.start.y
  ifdef(`gpic_',`if (rp_ht == 0) && (rp_wid == 0) then {rp_ang=0} else {')dnl
  rp_ang = atan2(rp_ht,rp_wid) ifdef(`gpic_',`}')
  rp_len=sqrt(rp_wid*rp_wid+rp_ht*rp_ht); move to last line.start
  point_(rp_ang)' )

                                Polar to rectangular coords, returning a pair
                                `rect_(radius,radians)'
define(`rect_',`vscal_(`$1',cos(`$2'),sin(`$2'))')
                                `Rect_(radius,degrees)'
define(`Rect_',`rect_(`$1',(`$2')*dtor_)')

                                Rectangular to polar coords, returning a pair
                                `polar_(x,y)'
define(`polar_',`sqrt((`$1')*(`$1')+(`$2')*(`$2')),atan2(`$2',`$1')')

                                Intersection of this line with another
                                `Intersect_(Name1,Name2)'
define(`Intersect_',`intersect_($1.start,$1.end,$2.start,$2.end)')
                                `intersect_(Start1,End1,Start2,End2)'
define(`intersect_',`(($3.x-$1.x)*($3.y-$4.y)-($3.y-$1.y)*($3.x-$4.x))/\
   (($2.x-$1.x)*($3.y-$4.y)-($2.y-$1.y)*($3.x-$4.x)) between `$1' and `$2'')

                                Generalized attributes and coordinates that work
                                exactly provided the current direction is up,
                                down, left or right.  Macros for elements need
                                only be written once assuming a default
                                direction of right, say.

                                String attributes, default right
define(`above_',`ifelse(m4dir,right,above,m4dir,left,below,m4dir,up,rjust,ljust)')
define(`below_',`ifelse(m4dir,right,below,m4dir,left,above,m4dir,up,ljust,rjust)')
define(`ljust_',`ifelse(m4dir,right,ljust,m4dir,left,rjust,m4dir,up,above,below)')
define(`rjust_',`ifelse(m4dir,right,rjust,m4dir,left,ljust,m4dir,up,below,above)')
                                Dimensions: wid, ht
define(`wid_',`ifelse(m4dir,right,wid,m4dir,left,wid,m4dir,up,ht,ht)')
define(`ht_',`ifelse(m4dir,right,ht,m4dir,left,ht,m4dir,up,wid,wid)')
                                Compass corners
define(`n_',`ifelse(m4dir,right,n,m4dir,left,s,m4dir,up,w,e)')
define(`s_',`ifelse(m4dir,right,s,m4dir,left,t,m4dir,up,r,l)')
define(`w_',`ifelse(m4dir,right,w,m4dir,left,e,m4dir,up,s,n)')
define(`e_',`ifelse(m4dir,right,e,m4dir,left,w,m4dir,up,n,s)')
define(`ne_',`ifelse(m4dir,right,ne,m4dir,left,sw,m4dir,up,nw,se)')
define(`nw_',`ifelse(m4dir,right,nw,m4dir,left,se,m4dir,up,sw,ne)')
define(`sw_',`ifelse(m4dir,right,sw,m4dir,left,ne,m4dir,up,se,nw)')
define(`se_',`ifelse(m4dir,right,se,m4dir,left,nw,m4dir,up,ne,sw)')
define(`loc_',`ifelse(m4dir,right,($1,$2),m4dir,left,($1,$2),($2,$1))')
                                Directions
define(`rt_',`ifelse(m4dir,right,right,m4dir,left,left,m4dir,up,up,down)')
define(`dn_',`ifelse(m4dir,right,down,m4dir,left,up,m4dir,up,right,left)')
define(`lt_',`ifelse(m4dir,right,left,m4dir,left,right,m4dir,up,down,up)')
define(`up__',`ifelse(m4dir,right,up,m4dir,left,down,m4dir,up,left,right)')

                                Binary operations giving simplified readable
                                expressions when possible.
define(`prod_',`ifelse($1,0,0,$2,0,0,$1,1,`$2',$2,1,`$1',
   $1,-1,`-($2)',$2,-1,`-($1)',`($1)*($2)')')
define(`sum_',`ifelse($1,0,`$2',$2,0,`$1',index($2,-),0,`$1$2',`$1+$2')')
define(`diff_',`ifelse($2,0,`$1',$1,0,`-($2)',`$1-($2)')')

                                Unary arithmetic operations (for single terms,
                                              use parentheses when necessary!)
define(`abs_',`ifelse(index($1,-),0,`substr($1,1)',`$1')')
define(`neg_',`ifelse(index($1,-),0,`substr($1,1)',-`$1')')
define(`sign_',`ifelse(index($1,-),0,-,)')

                                Vector rotation and scaling (returns a pair)
                                `vrot_(x,y,cos(ang),sin(ang))'
define(`vrot_',
  `diff_(prod_($3,$1),prod_($4,$2)),sum_(prod_($4,$1),prod_($3,$2))')
                                `vscal_(scalefactor,x,y)'
define(`vscal_',`prod_($1,$2),prod_($1,$3)')
                                Relative position
define(`rpos_',`Here+`$1'')
                                Absolute and relative vector determined by
                                current direction numbers
define(`vec_',`(vrot_($1,$2,m4x_,m4y_))')
define(`rvec_',`Here+vec_($1,$2)')

                                Sine and cosine of integer degrees with
                                simplified values for special cases
define(`Sin',`ifelse(eval(`$1'<0),1,`neg_(Sin(abs_(`$1')))',dnl
eval(`$1'>180),1,`Sin(eval(`$1'-360))',dnl
eval(`$1'>90),1,`Sin(eval(180-`$1'))',dnl
eval(`$1'==90),1,1,eval(`$1'==30),1,0.5,eval(`$1'==0),1,0,sin((`$1')*dtor_))')
define(`Cos',`Sin(eval($1+90))')

                                Sine and cosine of arbitrary argument in degrees
define(`sind',`sin((`$1')*dtor_)')
define(`cosd',`cos((`$1')*dtor_)')

                                Constants
define(`dtor_',`ifdef(`dtor__',`dtor`'_',`0.017453292519943295')') Deg to rad
define(`rtod_',`ifdef(`rtod__',`rtod`'_',`57.295779513082323')') Rad to deg
define(`twopi_',`6.2831853071795862')      2*pi
define(`pi_',`twopi_/2')
define(`E_',     `2.718281828459045')       e
define(`log10E_',`0.434294481903252')      log10(E_)

                                Why does pic not have these?
define(`abs',`max(`$1',-(`$1'))')
define(`loge',`(log(`$1')/log10E_)')
define(`expe',`exp((`$1')*log10E_)')
define(`acos',`atan2(sqrt(1-(`$1')^2),`$1')') `acos(ratio)'
define(`asin',`atan2(`$1',sqrt(1-(`$1')^2))') `asin(ratio)'
define(`pmod',`((((`$1')%(`$2'))+`$2')%(`$2'))') `+ve mod(M,N) eg pmod(-3,5)=2'

define(`pt_', `*scale/72')            Adobe scaled inches/point
define(`pt__', `*scale/72.27')        TeX scaled inches/point

                      `Use with \boxdim to get the dimensions of a TeX \hbox
                       boxdim(label,[h,w,d,v],default length)'
define(`boxdim',`ifelse(`$2',v,`sum_(boxdim(`$1',h,`$3'),boxdim(`$1',d,0))',
  ifdef(`$1_$2',`$1_$2',ifelse(`$3',,0,`$3')))')

                                `String with exact typeset dimensions
                                (Requires s_init, sinclude(filename.dim)
                                 and processing twice)'
define(`s_box',`define(`m4_k',ifdef(`m4_k',incr(m4_k),1))dnl
  "ifdef(`s_name',,`{\bf !!}')\boxdims{s_name`'_`'m4_k}{`$1'}" \
   wid boxdim(s_name`'_`'m4_k,w,.1) ht boxdim(s_name`'_`'m4_k,v,.1) ')
                                Initialize string index
define(`s_init',`define(`s_name',`$1')')

                                `dot(at location,radius,fill)'
define(`dotrad_',0.02*scale)
define(`dot',`[circle rad ifelse(`$2',,`dotrad_',`$2') \
  fill_(ifelse(`$3',,0,`$3'))] with .c ifelse(`$1',,`at Here',`$1')
  move to last [].c')
                                `cross(at location)'
define(`crosswd_',0.05*scale)
define(`cross',`[manhattan {line from rvec_(0,-crosswd_) to rvec_(0,crosswd_)}
  line from rvec_(-crosswd_,0) to rvec_(crosswd_,0) ] \
     with .c ifelse(`$1',,`at Here',`$1'); move to last [].c')

                                `shadebox(box boxspec,shadewid)' Shaded box
define(`shadebox',` $1
  ifdef(`pstricks_',`m4t1 = linethick; command "{\psset{linecolor=gray}%"',
    `if linethick < 0 then { m4t1 = 0.8 } else { m4t1 = linethick }')
  define(`m4h',`ifelse(`$2',,m4t1*5/4,`($2)')')dnl
  define(`m4v',`(m4h+m4t1)/2 pt_')dnl
  {line thickness m4h from last box.sw+(m4v,-m4v) \
    to last box.se+(m4v,-m4v) then to last box.ne+(m4v,-m4v)}
  {move to last box.se+(m4v,-m4v)+(m4h/2 pt_,-m4h/2 pt_)}
  ifdef(`pstricks_',`command "}%"')
  ')

                                Small space for string justification
define(`sp_',`ifdef(`pstricks_',,`\hbox{$\:$}')')

                                Dimensioning for diagrams
                `dimension_(linespec,vert offset,label,blank width,tic offset)'
define(`dimension_',`rpoint_(`$1') ; {
  ifelse(`$2',,,`$2',0,,`dnl
    {move to rvec_(0,     ifelse(`$5',,sign_(`$2')0.05*scale,`$5'))
    line to rvec_(0,`$2')}
    {move to rvec_(rp_len,ifelse(`$5',,sign_(`$2')0.05*scale,`$5'))
    line to rvec_(0,`$2')}
    move to rvec_(0,`$2')')
  ifelse(`$3',,,
    `{ifelse(substr(`$3',0,1),",`$3',"`$3'") at rvec_(rp_len/2,0)}')
  if rp_len > (2*arrowht ifelse(`$4',,,+abs(`$4'))) then {
    arrow <- to rvec_((rp_len ifelse(`$4',,,-(`$4')))/2,0)
    move to rvec_(ifelse(`$4',,0,`$4'),0)
    arrow to rvec_((rp_len ifelse(`$4',,,-(`$4')))/2,0)
  } else {
    arrow from rvec_(-arrowht*1.5,0) to Here
    arrow from rvec_(rp_len+arrowht*1.5,0) to rvec_(rp_len,0)
    }
  }')
                                `shade(gray value,closed line specs)
                                 Fill an arbitray closed curve with a gray value
                                 (requires gpic or pstricks)'
define(`shade',`define(`m4_shade',`ifelse(`$1',,`fillval',`($1)')')dnl
 command ifdef(`gpic_',`sprintf("\special{sh %g}",1-m4_shade)',
 `ifdef(`pstricks_',`sprintf("\newgray{m4fillv}{%g}",m4_shade)
  command "\pscustom[fillstyle=solid`,'fillcolor=m4fillv]{"')')
 `$2' ifdef(`pstricks_',`
  command "}%"')')
                                `m4_arrow(linespec, ht, wid)'
define(`m4_arrow',
  ifdef(`gpic_',    `arrow `$1' ifelse(`$2',,,ht `$2') ifelse(`$3',,,wid `$3')',
  ifdef(`pstricks_',`arrow `$1' ifelse(`$2',,,ht `$2') ifelse(`$3',,,wid `$3')',
    `open_arrow(`$1',`$2',`$3')')))

                                `open_arrow(linespec, ht, wid)'
                                arrow with outlined head
define(`open_arrow',`arrow invis `$1'
     m4t1 = Here.x - last arrow.start.x; m4t2 = Here.y - last arrow.start.y
     m4t3 = (ifelse(`$3',,arrowwid,`$3'))/sqrt(m4t1*m4t1 + m4t2*m4t2)/2
     line from last arrow.start to Here chop 0 chop ifelse(`$2',,arrowht,`$2')
     line from last arrow.end to Here+(-m4t2*m4t3,m4t1*m4t3) \
       then to Here-(-m4t2*m4t3,m4t1*m4t3) then to last arrow.end ')

                                `elchop(E,A) chop for ellipses
                                evaluates to "chop r" where r is the distance
                                from the centre of ellipse E to the intersection
                                of E with a line to location A'
define(`elchop',`chop 0.5 * `$1'.wid * `$1'.ht * sqrt(\
        ((`$2'.x-`$1'.x)^2 + (`$2'.y-`$1'.y)^2) /\
        ( ((`$2'.x-`$1'.x)*`$1'.ht)^2 + ((`$2'.y-`$1'.y)*`$1'.wid)^2 ) ) ')

                                `distance(Pos1,Pos2)' distance between positions
define(`distance',`sqrt((`$1'.x-`$2'.x)^2+(`$1'.y-`$2'.y)^2)')
                                `lin_leng(linear object)' calculates length
define(`lin_leng',`distance(`$1'.start,`$1'.end)')
                                `inner_prod(linear obj,linear obj)'
define(`inner_prod',`(sum_(dnl
  prod_(`$1'.end.x-`$1'.start.x,`$2'.end.x-`$2'.start.x),dnl
  prod_(`$1'.end.y-`$1'.start.y,`$2'.end.y-`$2'.start.y)))')

                                `Draw a spline through V[m],...V[n]
                                Works only with dpic:
                                V[m]:<position>; ... V[n]:<position>
                                fitcurve(V,n,[e.g. dotted],m [default 0])'
ifdef(`gpic_',,
`define(`fitcurve',`{[ n = `$2';  m = ifelse(`$4',,0,`$4')
  M4P_[0]: `$1'[m]
  j = 1
  for i=m+1 to n-1 do {M4P_[j]: 4/3*`$1'[i].x, 4/3*`$1'[i].y ; j = j+1}
  M4P_[j]: `$1'[n]
  n = j
                                # forward substitution
  M4P_[1]: M4P_[1].x-M4P_[0].x/6, M4P_[1].y-M4P_[0].y/6
  d[1] = 1
  for i=2 to n-1 do {
    M4P_[i]: M4P_[i].x-M4P_[i-1].x/d[i-1]/6, M4P_[i].y-M4P_[i-1].y/d[i-1]/6
    d[i] = 1-1/d[i-1]/36 }
                                # backward substitution
  for i= n-1 to 1 by -1 do {
    M4P_[i]: (M4P_[i].x-M4P_[i+1].x/6)/d[i], (M4P_[i].y-M4P_[i+1].y/6)/d[i] }
                                # draw using computed control points
  spline `$3' from M4P_[0] to 0.01 between M4P_[0] and M4P_[1]
  for i=1 to n-1 do { continue to M4P_[i] }
  continue to 0.99 between M4P_[n-1] and M4P_[n] then to M4P_[n]
  ] with .M4P_[0] at `$1'[ifelse(`$4',,0,`$4')]} ') ')

                                `Useful macros for drawing sinusoids and
                                 lollipop signals.  sinuoid works only with
                                 dpic'
                                `Cosine( amplitude, freq, time, phase )'
define(`Cosine',`(`$1')*cos((`$2')*(`$3')+`$4')')
                                `lpop(x coord, ycoord) for lollipop graphs'
define(`lpop',`dot(at (`$1',`$2')); line to (`$1',0)')
                                `sinc(x) the sinc function'
define(`sinc',`sin(max(pi_*abs(`$1'),1e-6))/max(pi_*abs(`$1'),1e-6)')

                              `sinusoid( amplitude, frequency, phase, tmin,tmax)
                               (uses dpic subscripted positions), e.g.
                               sinusoid( 1,twopi_,0,0,1) with .Origin at (1,0)'
ifdef(`gpic_',,
`define(`sinusoid',
 `[ Tmin: (`$4'),0 ; Tmax: `$5',0
  if ((`$4') <= 0) && (`$5' >= 0) then { Origin: 0,0 }
  h = `$5'-(`$4')
  m4_tm = 2*(`$2')
  w0 = m4_tm*(`$4') + 2*(`$3')
  h0 = -m4_t_fun(-1,h,(`$1')/2)/h;
  n = (int(h/(twopi_/(m4_tm/2)))+1)*7
  for i = 0 to n do {
    t = `$4'+m4_t_fun(h0,h*i/n,(`$1')/2);
    M4S_[i]: t,Cosine(`$1',`$2',t,`$3') }
  fitcurve(M4S_,n)
  ]')
  define(`m4_t_fun',`((`$1'+`$3')*`$2'-`$3'/m4_tm*dnl
    (sin(m4_tm*(`$2')+w0)-sin(w0)))') ')

                                Normally redefined in initialization macros:
ifdef(`gpic_',,
  `ifdef(`pstricks_',,
    `ifdef(`mfpic_',,`

define(`thinlines_',`
\thinlines%
')                              TeX commands are written on separate lines
define(`thicklines_',`
\thicklines%
')

')')')
                                Pstricks conditional command
define(`psset_',`ifdef(`pstricks_',`dnl
\psset{$1}%
')')
                                Adjust fill value if gpic is used
define(`fill_',`dnl
 fill ifdef(`gpic_',`1-(')ifelse(`$1',,fillval,`$1') ifdef(`gpic_',`)')')

                                Initialization
define(`m4dir',right)

define(`gen_init',`dnl
`#' `$0': ifdef(`gpic_',`Gpic',
  `ifdef(`pstricks_',`PSTricks',
  `ifdef(`mfpic_',`mfpic',`default')')') m4 macro settings detected.
   rp_ang = 0
   define(`rtod__',`57.295779513082323')`rtod_' = rtod__
   define(`dtor__',`0.017453292519943295')`dtor_' = dtor__
thicklines_
   ')
                                Define m4x_ etc for horiz and vert lines
manhattan
divert(0)dnl
