asymptote: Pens

 
 6.3 Pens
 ========
 
 In 'Asymptote', pens provide a context for the four basic drawing
 commands (SeeDrawing commands).  They are used to specify the
 following drawing attributes: color, line type, line width, line cap,
 line join, fill rule, text alignment, font, font size, pattern,
 overwrite mode, and calligraphic transforms on the pen nib.  The default
 pen used by the drawing routines is called 'currentpen'.  This provides
 the same functionality as the 'MetaPost' command 'pickup'.  The implicit
 initializer for pens is 'defaultpen'.
 
    Pens may be added together with the nonassociative binary operator
 '+'.  This will add the colors of the two pens.  All other non-default
 attributes of the rightmost pen will override those of the leftmost pen.
 Thus, one can obtain a yellow dashed pen by saying 'dashed+red+green' or
 'red+green+dashed' or 'red+dashed+green'.  The binary operator '*' can
 be used to scale the color of a pen by a real number, until it saturates
 with one or more color components equal to 1.
 
    * Colors are specified using one of the following colorspaces:
      'pen gray(real g);'
           This produces a grayscale color, where the intensity 'g' lies
           in the interval [0,1], with 0.0 denoting black and 1.0
           denoting white.
 
      'pen rgb(real r, real g, real b);'
           This produces an RGB color, where each of the red, green, and
           blue intensities 'r', 'g', 'b', lies in the interval [0,1].
 
      'pen cmyk(real c, real m, real y, real k);'
           This produces a CMYK color, where each of the cyan, magenta,
           yellow, and black intensities 'c', 'm', 'y', 'k', lies in the
           interval [0,1].
 
      'pen invisible;'
           This special pen writes in invisible ink, but adjusts the
           bounding box as if something had been drawn (like the
           '\phantom' command in TeX).  The function 'bool
           invisible(pen)' can be used to test whether a pen is
           invisible.
 
      The default color is 'black'; this may be changed with the routine
      'defaultpen(pen)'.  The function 'colorspace(pen p)' returns the
      colorspace of pen 'p' as a string ('"gray"', '"rgb"', '"cmyk"', or
      '""').
 
      The function 'real[] colors(pen)' returns the color components of a
      pen.  The functions 'pen gray(pen)', 'pen rgb(pen)', and 'pen
      cmyk(pen)' return new pens obtained by converting their arguments
      to the respective color spaces.  The function
      'colorless(pen=currentpen)' returns a copy of its argument with the
      color attributes stripped (to avoid color mixing).
 
      A 6-character RGB hexidecimal string can be converted to a pen with
      the routine
      pen rgb(string s);
      A pen can be converted to a hexidecimal string with
    * string hex(pen p);
 
      Various shades and mixtures of the grayscale primary colors 'black'
      and 'white', RGB primary colors 'red', 'green', and 'blue', and RGB
      secondary colors 'cyan', 'magenta', and 'yellow' are defined as
      named colors, along with the CMYK primary colors 'Cyan', 'Magenta',
      'Yellow', and 'Black', in the module 'plain':
 
                                [colors]
 
      The standard 140 RGB 'X11' colors can be imported with the command
      import x11colors;
      and the standard 68 CMYK TeX colors can be imported with the
      command
      import texcolors;
      Note that there is some overlap between these two standards and the
      definitions of some colors (e.g. 'Green') actually disagree.
 
      'Asymptote' also comes with a 'asycolors.sty' 'LaTeX' package that
      defines to 'LaTeX' CMYK versions of 'Asymptote''s predefined
      colors, so that they can be used directly within 'LaTeX' strings.
      Normally, such colors are passed to 'LaTeX' via a pen argument;
      however, to change the color of only a portion of a string, say for
      a slide presentation, (Seeslide) it may be desirable to
      specify the color directly to 'LaTeX'.  This file can be passed to
      'LaTeX' with the 'Asymptote' command
      usepackage("asycolors");
 
      The structure 'hsv' defined in 'plain_pens.asy' may be used to
      convert between HSV and RGB spaces, where the hue 'h' is an angle
      in [0,360) and the saturation 's' and value 'v' lie in '[0,1]':
      pen p=hsv(180,0.5,0.75);
      write(p);           // ([default], red=0.375, green=0.75, blue=0.75)
      hsv q=p;
      write(q.h,q.s,q.v); // 180     0.5     0.75
 
    * Line types are specified with the function 'pen linetype(real[] a,
      real offset=0, bool scale=true, bool adjust=true)', where 'a' is an
      array of real array numbers.  The optional parameter 'offset'
      specifies where in the pattern to begin.  The first number
      specifies how far (if 'scale' is 'true', in units of the pen line
      width; otherwise in 'PostScript' units) to draw with the pen on,
      the second number specifies how far to draw with the pen off, and
      so on.  If 'adjust' is 'true', these spacings are automatically
      adjusted by 'Asymptote' to fit the arclength of the path.  Here are
      the predefined line types:
      pen solid=linetype(new real[]);
      pen dotted=linetype(new real[] {0,4});
      pen dashed=linetype(new real[] {8,8});
      pen longdashed=linetype(new real[] {24,8});
      pen dashdotted=linetype(new real[] {8,8,0,8});
      pen longdashdotted=linetype(new real[] {24,8,0,8});
      pen Dotted(pen p=currentpen) {return linetype(new real[] {0,3})+2*linewidth(p);}
      pen Dotted=Dotted();
 
                               [linetype]
 
      The default line type is 'solid'; this may be changed with
      'defaultpen(pen)'.  The line type of a pen can be determined with
      the functions 'real[] linetype(pen p=currentpen)', 'real offset(pen
      p)', 'bool scale(pen p)', and 'bool adjust(pen p)'.
 
    * The pen line width is specified in 'PostScript' units with 'pen
      linewidth(real)'.  The default line width is 0.5 bp; this value may
      be changed with 'defaultpen(pen)'.  The line width of a pen is
      returned by 'real linewidth(pen p=currentpen)'.  For convenience,
      in the module 'plain_pens' we define
      void defaultpen(real w) {defaultpen(linewidth(w));}
      pen operator +(pen p, real w) {return p+linewidth(w);}
      pen operator +(real w, pen p) {return linewidth(w)+p;}
      so that one may set the line width like this:
      defaultpen(2);
      pen p=red+0.5;
 
    * A pen with a specific 'PostScript' line cap is returned on calling
      'linecap' with an integer argument:
      pen squarecap=linecap(0);
      pen roundcap=linecap(1);
      pen extendcap=linecap(2);
 
      The default line cap, 'roundcap', may be changed with
      'defaultpen(pen)'.  The line cap of a pen is returned by 'int
      linecap(pen p=currentpen)'.
 
    * A pen with a specific 'PostScript' join style is returned on
      calling 'linejoin' with an integer argument:
      pen miterjoin=linejoin(0);
      pen roundjoin=linejoin(1);
      pen beveljoin=linejoin(2);
 
      The default join style, 'roundjoin', may be changed with
      'defaultpen(pen)'.The join style of a pen is returned by 'int
      linejoin(pen p=currentpen)'.
 
    * A pen with a specific 'PostScript' miter limit is returned by
      calling 'miterlimit(real)'.  The default miterlimit, '10.0', may be
      changed with 'defaultpen(pen)'.  The miter limit of a pen is
      returned by 'real miterlimit(pen p=currentpen)'.
 
    * A pen with a specific 'PostScript' fill rule is returned on calling
      'fillrule' with an integer argument:
      pen zerowinding=fillrule(0);
      pen evenodd=fillrule(1);
 
      The fill rule, which identifies the algorithm used to determine the
      insideness of a path or array of paths, only affects the 'clip',
      'fill', and 'inside' functions.  For the 'zerowinding' fill rule, a
      point 'z' is outside the region bounded by a path if the number of
      upward intersections of the path with the horizontal line
      'z--z+infinity' minus the number of downward intersections is zero.
      For the 'evenodd' fill rule, 'z' is considered to be outside the
      region if the total number of such intersections is even.  The
      default fill rule, 'zerowinding', may be changed with
      'defaultpen(pen)'.  The fill rule of a pen is returned by 'int
      fillrule(pen p=currentpen)'.
 
    * A pen with a specific text alignment setting is returned on calling
      'basealign' with an integer argument:
      pen nobasealign=basealign(0);
      pen basealign=basealign(1);
 
      The default setting, 'nobasealign',which may be changed with
      'defaultpen(pen)', causes the label alignment routines to use the
      full label bounding box for alignment.  In contrast, 'basealign'
      requests that the TeX baseline be respected.  The base align
      setting of a pen is returned by 'int basealigin(pen p=currentpen)'.
 
    * The font size is specified in TeX points (1 pt = 1/72.27 inches)
      with the function 'pen fontsize(real size, real
      lineskip=1.2*size)'.  The default font size, 12pt, may be changed
      with 'defaultpen(pen)'.  Nonstandard font sizes may require
      inserting
      import fontsize;
      at the beginning of the file (this requires the 'type1cm' package
      available from
           <http://mirror.ctan.org/macros/latex/contrib/type1cm/>
      and included in recent 'LaTeX' distributions).  The font size and
      line skip of a pen can be examined with the routines 'real
      fontsize(pen p=currentpen)' and 'real lineskip(pen p=currentpen)',
      respectively.
 
    * A pen using a specific 'LaTeX' 'NFSS' font is returned by calling
      the function 'pen font(string encoding, string family, string
      series, string shape)'.  The default setting,
      'font("OT1","cmr","m","n")', corresponds to 12pt Computer Modern
      Roman; this may be changed with 'defaultpen(pen)'.  The font
      setting of a pen is returned by 'string font(pen p=currentpen)'.
      Support for standardized international characters is provided by
      the 'unicode' package (Seeunicode).
 
      Alternatively, one may select a fixed-size TeX font (on which
      'fontsize' has no effect) like '"cmr12"' (12pt Computer Modern
      Roman) or '"pcrr"' (Courier) using the function 'pen font(string
      name)'.  An optional size argument can also be given to scale the
      font to the requested size: 'pen font(string name, real size)'.
 
      A nonstandard font command can be generated with 'pen
      fontcommand(string)'.
 
      A convenient interface to the following standard 'PostScript' fonts
      is also provided:
      pen AvantGarde(string series="m", string shape="n");
      pen Bookman(string series="m", string shape="n");
      pen Courier(string series="m", string shape="n");
      pen Helvetica(string series="m", string shape="n");
      pen NewCenturySchoolBook(string series="m", string shape="n");
      pen Palatino(string series="m", string shape="n");
      pen TimesRoman(string series="m", string shape="n");
      pen ZapfChancery(string series="m", string shape="n");
      pen Symbol(string series="m", string shape="n");
      pen ZapfDingbats(string series="m", string shape="n");
 
    * The transparency of a pen can be changed with the command:
      pen opacity(real opacity=1, string blend="Compatible");
      The opacity can be varied from '0' (fully transparent) to the
      default value of '1' (opaque), and 'blend' specifies one of the
      following foreground-background blending operations:
      "Compatible","Normal","Multiply","Screen","Overlay","SoftLight",
      "HardLight","ColorDodge","ColorBurn","Darken","Lighten","Difference",
      "Exclusion","Hue","Saturation","Color","Luminosity",
      as described in
 
      <http://partners.adobe.com/public/developer/en/pdf/PDFReference16.pdf>.
      Since 'PostScript' does not support transparency, this feature is
      only effective with the '-f pdf' output format option; other
      formats can be produced from the resulting PDF file with the
      'ImageMagick' 'convert' program.  Labels are always drawn with an
      'opacity' of 1.  A simple example of transparent filling is
      provided in the example file 'transparency.asy'.
 
    * 'PostScript' commands within a 'picture' may be used to create a
      tiling pattern, identified by the string 'name', for 'fill' and
      'draw' operations by adding it to the global 'PostScript' frame
      'currentpatterns', with optional left-bottom margin 'lb' and
      right-top margin 'rt'.
      import patterns;
      void add(string name, picture pic, pair lb=0, pair rt=0);
 
      To 'fill' or 'draw' using pattern 'name', use the pen
      'pattern("name")'.  For example, rectangular tilings can be
      constructed using the routines 'picture tile(real Hx=5mm, real
      Hy=0, pen p=currentpen, filltype filltype=NoFill)', 'picture
      checker(real Hx=5mm, real Hy=0, pen p=currentpen)', and 'picture
      brick(real Hx=5mm, real Hy=0, pen p=currentpen)' defined in
      'patterns.asy':
      size(0,90);
      import patterns;
 
      add("tile",tile());
      add("filledtilewithmargin",tile(6mm,4mm,red,Fill),(1mm,1mm),(1mm,1mm));
      add("checker",checker());
      add("brick",brick());
 
      real s=2.5;
      filldraw(unitcircle,pattern("tile"));
      filldraw(shift(s,0)*unitcircle,pattern("filledtilewithmargin"));
      filldraw(shift(2s,0)*unitcircle,pattern("checker"));
      filldraw(shift(3s,0)*unitcircle,pattern("brick"));
 
                                 [tile]
 
      Hatch patterns can be generated with the routines 'picture
      hatch(real H=5mm, pair dir=NE, pen p=currentpen)', 'picture
      crosshatch(real H=5mm, pen p=currentpen)':
      size(0,100);
      import patterns;
 
      add("hatch",hatch());
      add("hatchback",hatch(NW));
      add("crosshatch",crosshatch(3mm));
 
      real s=1.25;
      filldraw(unitsquare,pattern("hatch"));
      filldraw(shift(s,0)*unitsquare,pattern("hatchback"));
      filldraw(shift(2s,0)*unitsquare,pattern("crosshatch"));
 
                                 [hatch]
 
      You may need to turn off aliasing in your 'PostScript' viewer for
      patterns to appear correctly.  Custom patterns can easily be
      constructed, following the examples in 'patterns.asy'.  The tiled
      pattern can even incorporate shading (Seegradient shading), as
      illustrated in this example (not included in the manual because not
      all printers support 'PostScript' 3):
      size(0,100);
      import patterns;
 
      real d=4mm;
      picture tiling;
      path square=scale(d)*unitsquare;
      axialshade(tiling,square,white,(0,0),black,(d,d));
      fill(tiling,shift(d,d)*square,blue);
      add("shadedtiling",tiling);
 
      filldraw(unitcircle,pattern("shadedtiling"));
 
 
    * One can specify a custom pen nib as an arbitrary polygonal path
      with 'pen makepen(path)'; this path represents the mark to be drawn
      for paths containing a single point.  This pen nib path can be
      recovered from a pen with 'path nib(pen)'.  Unlike in 'MetaPost',
      the path need not be convex:
 
      size(200);
      pen convex=makepen(scale(10)*polygon(8))+grey;
      draw((1,0.4),convex);
      draw((0,0)---(1,1)..(2,0)--cycle,convex);
 
      pen nonconvex=scale(10)*
        makepen((0,0)--(0.25,-1)--(0.5,0.25)--(1,0)--(0.5,1.25)--cycle)+red;
      draw((0.5,-1.5),nonconvex);
      draw((0,-1.5)..(1,-0.5)..(2,-1.5),nonconvex);
 
                                [makepen]
 
      The value 'nullpath' represents a circular pen nib (the default);
      an elliptical pen can be achieved simply by multiplying the pen by
      a transform: 'yscale(2)*currentpen'.
 
    * One can prevent labels from overwriting one another by using the
      pen attribute 'overwrite', which takes a single argument:
 
      'Allow'
           Allow labels to overwrite one another.  This is the default
           behaviour (unless overridden with 'defaultpen(pen)'.
 
      'Suppress'
           Suppress, with a warning, each label that would overwrite
           another label.
 
      'SuppressQuiet'
           Suppress, without warning, each label that would overwrite
           another label.
 
      'Move'
           Move a label that would overwrite another out of the way and
           issue a warning.  As this adjustment is during the final
           output phase (in 'PostScript' coordinates) it could result in
           a larger figure than requested.
 
      'MoveQuiet'
           Move a label that would overwrite another out of the way,
           without warning.  As this adjustment is during the final
           output phase (in 'PostScript' coordinates) it could result in
           a larger figure than requested.
 
    The routine 'defaultpen()' returns the current default pen
 attributes.  Calling the routine 'resetdefaultpen()' resets all pen
 default attributes to their initial values.