summaryrefslogtreecommitdiff
path: root/support/mkpic/mkpic
diff options
context:
space:
mode:
authorNorbert Preining <norbert@preining.info>2019-09-02 13:46:59 +0900
committerNorbert Preining <norbert@preining.info>2019-09-02 13:46:59 +0900
commite0c6872cf40896c7be36b11dcc744620f10adf1d (patch)
tree60335e10d2f4354b0674ec22d7b53f0f8abee672 /support/mkpic/mkpic
Initial commit
Diffstat (limited to 'support/mkpic/mkpic')
-rwxr-xr-xsupport/mkpic/mkpic864
1 files changed, 864 insertions, 0 deletions
diff --git a/support/mkpic/mkpic b/support/mkpic/mkpic
new file mode 100755
index 0000000000..2625171b37
--- /dev/null
+++ b/support/mkpic/mkpic
@@ -0,0 +1,864 @@
+#!/usr/bin/env perl
+
+use constant
+Version => '1.02';
+
+my $help =
+<<'DOC'
+= mkpic - interface for making pictures with mfpic
+
+= Synopsis
+mkpic [options] [picfile]
+
+Options:
+-c,--clean remove all but the input file and die
+-p,--pdfsample create pdf file with sample images
+-f,--font=<font command> set default font for labels
+ --[no]box produce framed boxes
+-V,--version report version number and die
+-h,--help display help info and die
+ --[no]debug display debugging information
+-l,--log=<logfile> file for warning messages
+
+Without an input file, the DATA section is used.
+
+= Command overview
+begin name xl yl xmin ymin xmax ymax xlabel ylabel
+end
+stop
+var=value
+# comment
+
+arccst xcenter ycenter xstart ystart theta
+arcset xstart ystart xend yend theta
+arccrtt xcenter ycenter radius theta1 theta2
+arc3 x1 y1 x2 y2 x3 y3
+
+xmark [label1] x1 [label2] x2 ...
+Xmark [label1] x1 [label2] x2 ...
+ymark [label1] y1 [label2] y2 ...
+Ymark [label1] y1 [label2] y2 ...
+
+xdrop x y
+ydrop x y
+xydrop x y
+
+arrow x1 y1 x2 y2 label
+label YX x y label
+xlabels YX x y dx label ...
+ylabels YX x y dy label ...
+
+point x1 y1 x2 y2 ...
+dpoint x1 y1 dx1 dy1 ...
+lines x1 y1 x2 y2 ...
+dlines x1 y1 dx1 dy1 ...
+curve x1 y1 x2 y2 ...
+dcurve x1 y1 dx1 dy1 ...
+
+rect x1 y1 x2 y2
+drect x y dx dy
+dcrect x y dx dy
+crect x1 y1 x2 y2
+arect xc yc width height theta
+bar x xdev height
+
+func xmin xmax step expression-in-x
+
+grid dx dy xgap ygap
+hatch
+bhat
+ehat
+
+= Description
+mkpic provides an easy interface for making small pictures with mfpic. To
+this end you create an input file has to be created consisting of
+commands, one per line, with space separated parameters (or you modify the
+DATA section of the mkpic script, which is used if you run it without an
+input file). For an extensive description see the file mkpicdoc.pdf, which
+is part of the distribution.
+
+mkpic produces two files. Assuming an input file named |picfile| defaulting
+to |mkpic| these are:
+
+picfile.mac
+ a macro file which will contain |TeX| commands for every picture
+picfile.sty
+ a style file for latex, defining the same |TeX| commands for every picture.
+
+With the |--pdfsample| option, two other files are produced:
+
+picfile.pdf
+ a PDF file containing all pictures.
+ This lets you easily check the results of your designs.
+
+picfile.tex
+ the |TeX| source used for creating this PDF file.
+
+In |LaTeX|, you have to include |\usepackage{picfile}| and to include
+commands like |\Fig|/name/ in your source, where /name/ is the
+name you gave one of your pictures in an mkpic |begin| command.
+
+In TeX and ConTeXt, you have to |\input picfile.mac| and to
+include commands like |\Fig|/name/ in your source, where /name/ is
+the name you gave one of your pictures in an mkpic |begin| command.
+
+In TeX, you must use the |\bye| command (/not/ |\end| to finish your TeX source
+
+See the RUNNING section for how to run mkpic and TeX, LaTeX, or ConTeXt.
+
+= Commands
+The source is set up so that it is easy to add your own commands,
+Currently the following commands have been implemented (the arguments
+are not listed here; for those, refer to the SYNOPSIS section):
+
+begin, end
+ Every picture begins with the |begin| command and ends with the |end|
+ command. The |begin| command defines a name for the picture and
+ defines a tex command with that name, prefixed with 'Fig'. The
+ resulting command is written to a |.mac| file. Thus the command
+
+ begin aa ...
+
+ starts writing |\def\Figaa{...| to the |.mac| file, and the
+ picture can be reproduced in a |TeX| document by importing the |.mac| file
+ and using the |\Figaa| command.
+
+ xl and yl are the lengths of the x- and y-axes. xlabel and ylabel are
+ the label that are placed at the ends of those axes. Use a space to
+ suppress labeling, or "-" to suppress drawing the axes at all.
+
+stop
+ stops further reading of the input. Useful if you have many pictures,
+ but want to see only the first few for testing purposes.
+
+var=value
+ sets the variable var to value. This variable, or an expression containing it,
+ can be used instead of any numerical parameter. Variable names may contain
+ lower and uppercase letters, digits or underscores, with the restriction that
+ they must start with a letter and may not end in an underscore.
+
+#
+ denotes a comment
+
+xmark, ymark, Xmark, Ymark
+ These commands place one or more labels along the x- or y-axes, either
+ below (|xmark| and |ymark|) or above (|Xmark| and |Ymark|) the axis.
+
+ For the |[xXyY]mark| commands a parameter containing any character
+ other than [-.0-9] is interpreted as the label (this implies that you
+ cannot use expressions here!) to be placed and its position is expected
+ in the next parameter. If a parameter is just a number, it is placed at
+ that x-position. If you want a number to be interpreted as a label, put
+ it in braces: |{1950}|.
+
+arccst
+ (Mnemonic: |c|enter |s|tart |t|heta.)
+ Draws an arc with its center in |xcenter,ycenter|, starting in |xstart,ystart|
+ and with an arc length of |theta| degrees.
+
+arcset
+ (Mnemonic: |s|tart |e|nd |t|heta.)
+ Draws an arc starting in |xstart,ystart|end ending in |xend,yend|
+ and with an arc length of |theta| degrees.
+
+arccrtt
+ (Mnemonic: |c|enter |r|adius |t|heta1 |t|heta2.)
+ Draws an arc with its center in |xcenter,ycenter|, a radius |radius|
+ starting at |theta1| degrees and ending at |theta2| degrees.
+
+arc3
+ (Mnemonic: |3| points.)
+ Draws an arc starting at |(x1,y1)|, through |(x2,y2)| and ending in |(x3,y3)|.
+
+xdrop, ydrop, xydrop
+ These commands draw dotted arrows perpendicularly to the x-axis, the
+ y-axis and both axes, respectively, ending on the axes with the
+ arrow head.
+
+arrow
+ draws an arrow from |(x1,y1)| to |(x2,y2)| labeled on its tail with
+ |label|
+
+label
+ draws a label at |(x,y)|. |YX| tells how it will be adjusted: for
+ Y=t,b,c |(x,y)| will be, in the y-direction, on top, bottom or center
+ of the label respectively, for X=l,r,c it will be, in the x-direction,
+ left, right or center adjusted on |(x,y)|. Thus
+
+ label tl 0 0 Hello World!
+
+ will draw the string "Hello World" with its lower left corner at (0,0)
+
+xlabels
+ draws many labels, starting at |(x,y)|, and incrementing |x| with |dx|
+ after every label. |YX|: see |label|. Labels may not contain spaces;
+ if you need spaces, use - instead.
+
+ylabels
+ Same as |xlabels|, but incrementing |y| with |dy| instead.
+
+point
+ draws points (dots) at |(x1,y1)|, |(x2,y2)| et cetera.
+
+dpoint
+ draws points (dots) starting at |(x1,y1)| and then moving by
+ |(dx1,dy1)|, |(dx2,dy2)| et cetera.
+
+lines
+ draws line segments from |(x1,y1)| to |(x2,y2)|, |(x3,y3)| et cetera.
+
+dlines
+ draws line segments starting at |(x1,y1)| and then moving by
+ |(dx1,dy1)|, |(dx2,dy2)| et cetera.
+
+curve
+ draws a bezier curve from |(x1,y1)| to |(x2,y2)|, |(x3,y3)| et cetera.
+
+dcurve
+ draws a bezier curve starting at |(x1,y1)| and then moving by
+ |(dx1,dy1)|, |(dx2,dy2)| et cetera.
+
+rect
+ draws a rectangle with diagonal points at |(x1,y1)| and |(x2,y2)|.
+
+drect
+ draws a rectangle with diagonal points at |(x,y)| and |(x+dx,y+dy)|.
+
+crect
+ clears a rectangle with diagonal points at |(x1,y1)| and |(x2,y2)|.
+
+dcrect
+ clears a rectangle with diagonal points at |(x,y)| and |(x+dx,y+dy)|.
+
+arect
+ draws a rectangle with a widdh |width| and a height |height|;
+ the middle of the bottom is at |(xc,yc)| and the centerline through
+ |(xc,yc)| makes an angle |theta| with the x-axis.
+
+bar
+ draws a equivalent with |rect x-xdev 0 x+xdev height|
+
+func
+ draws the function given by |expression-in-x| between |xmin| and
+ |xmax|, stepping with |step| units in the x-direction.
+ Note that the |expression-in-x| will be evaluated by |Metafont|, so
+ you will have to use metafont syntax.
+
+grid
+ draw dotted grid lines at distances dx and dy in the x- and y
+ directions; the gaps between the dots are set to |xgap| an |ygap|
+ respectively. For an esthetic appearance, be sure to use integer
+ |dx/xgap| and |dy/ygap| ratios.
+
+hatch
+ hatch the closed curve that follows.
+
+bhat
+ starts a path that will eventually be closed, and then hatched.
+
+ehat
+ ends a path started with |bhat|, closes it and then hatches it.
+
+anything else
+ will be inserted as is in the macro file, and therefore should be a
+ valid |mfpic| statement. You use this when you need such a statement
+ only once, or a few times and therefore see no need to define a proper
+ command for it.
+
+= Running mkpic/TeX
+The effect of running
+ mkpic picfile
+is the creation of |picfile.mac|, which you can |\input| into a TeX or
+ConTeXt source, and |picfile.sty| which can be input into a LaTeX
+source using the |\usepackage| command.
+
+After running TeX (or LaTeX or ConTeXt), you will find a file
+|picfile.mf| and you will have to run Metafont on it, which
+(assuming you configured TeX for 600 dpi) produces picfile.600gf. This
+file will have to be converted to a pk file with gftopk. Finally, you
+need to run TeX, normally at least twice, again. So for pdfLaTeX the sequence is:
+
+ mkpic picfile
+ pdflatex file.tex
+ mf picfile
+ gftopk picfile.600gf
+ pdflatex file
+ pdflatex file
+
+= Bug
+Currently only up to 256 pictures can be generated. In the future this
+problem will probably be solved by introducing more than one font and
+generating tex-command names that have the font name in front.
+
+= Changes
+Changes with respect to version 0.1:
+- added mkpicdoc.tex to the distribution
+
+= Author and copyright
+Author Wybo Dekker
+Email U{Wybo@dekkerdocumenten.nl}{wybo@dekkerdocumenten.nl}
+License Released under the U{www.gnu.org/copyleft/gpl.html}{GNU General Public License}
+DOC
+;
+
+use vars
+ qw/$xgap $ygap $dx $dy $xl $yl $x3 $y3 $height $Z $d $F $r $theta1 $theta2/;
+
+sub evaluate {
+ defined or die "Missing parameter at line $.\n";
+ if ( !m|^[0-9.]+$| ) {
+ my $x = ''; # we build up the expression with $-ized variable names in $x
+ while ($_) {
+ unless (/[A-Za-z0-9]+/) { $x .= $_; last }
+ my ( $left, $middle, $right ) = ( $`, $&, $' );
+ $x .= $left
+ . ( ( $middle =~ m|^[0-9.]+$| || $fun{$middle} ) ? "" : '$' )
+ . $middle;
+ $_ = $right;
+ }
+ $_ = $x;
+ eval "\$_=$_" while m|[^0-9.-]|;
+ }
+ $_;
+}
+
+sub parse {
+ my @x;
+ ( $command_name, @x ) =
+ split ( /\s+/, $_, scalar @_ + 1 ); # input values/expressions in @x
+ print LOG "command: $command_name\n" if $debug;
+ for ( my $i = 0 ; $i < @_ ; $i++ ) { # each variable to be set
+ $_ = $x[$i]; # take the expression
+ if ( $_[$i] !~ /^[A-Z]/ )
+ { # if name of receiving var not capitalized: await numerical
+ evaluate;
+ }
+ my $varname = "$_[$i]";
+ $$varname = $_;
+ print LOG "$varname=$_\n" if $debug;
+ }
+}
+
+sub parse_array {
+ my @x;
+ ( $command_name, @x ) = split ( /\s+/, $_[0] );
+ print LOG "command: $command_name\n" if $debug;
+ unless ( $command_name =~ /mark/ ) {
+ for (@x) {
+ evaluate;
+ }
+ }
+ print LOG "parse_array returns: @x\n" if $debug;
+ @x;
+}
+
+sub open_macrofile {
+ my $rerun = 0;
+ # we need to rerun if:
+ # - one of the needed files is missing or else
+ # - the input file is newer than the .mac file or else
+ # - the present options differ from/keep the previous ones
+
+ # check the presence of needed files:
+ chomp( $_ = -f $tex ? $tex : `which mkpic` );
+ my $inputtime = ( stat($_) )[9];
+ for ( "mac", "sty" ) {
+ -f "$tex.$_" or $rerun = 1, last;
+ }
+ # if all are there, test if the input is older than the .mac file:
+ !$rerun && ( stat("$tex.mac") )[9] > $inputtime or $rerun = 1;
+
+ # if that's true too, check that the previous option were the same:
+ unless ($rerun) {
+ open( MAC, "$tex.mac" );
+ $_ = <MAC>;
+ $_ eq $options or $rerun = 1;
+ close MAC;
+ }
+ $rerun or return (0);
+ open( MAC, ">$tex.mac" );
+ select MAC;
+ $_ = <<'EOF'
+ % vim: syntax=tex
+ \input mfpic
+ \let\circle\undefinedcs
+ \mfpicunit.01mm
+ \opengraphsfile{TX}
+ \def\ifundefined#1{\expandafter\ifx\csname#1\endcsname\relax}
+ \def\doatend{\closegraphsfile}
+ \ifundefined{typefile}\else\appendtoks\doatend\to\everystoptext\fi % for context
+ \ifundefined{documentclass}\else\AtEndDocument{\doatend}\fi % for latex
+ \def\bye{\doatend\par\vfill\supereject\end} % plain
+ \def\ruledhbox#1{\vbox{\hrule\hbox{\vrule\kern3pt
+ \vbox{\kern3pt#1\kern3pt}\kern3pt\vrule}\hrule}}
+
+EOF
+ ;
+ s/^\s+//gm;
+ s/TX/$tex/gm;
+ print MAC $options,$_;
+
+ open( STY, ">$tex.sty" ) or die "Could not open $tex.sty: $!\n";
+ $_ = <<'EOF'
+ \ProvidesPackage{TX}
+ \input TX.mac
+ \endinput
+EOF
+ ;
+ s/^\s+//gm;
+ s/TX/$tex/gm;
+ print STY;
+ 1;
+}
+
+sub sys {
+ system("@_") and die "@_: $?\n";
+}
+
+sub parse_input {
+ while (<$input>) {
+ chomp;
+ s/\s*#.*//; # remove comment
+ next unless $_; # skip empty lines
+ /^begin/ and do {
+ parse qw(Name xl yl xmin ymin xmax ymax Xlabel Ylabel);
+ $names{$Name} and die "multiple occurrences of picture named $Name\n";
+ $names{$Name} = 1;
+
+ $Xlabel = "" if $Xlabel eq '-';
+ $Ylabel = "" if $Ylabel eq '-';
+ $xscale = int( 100 * $xl / ( $xmax - $xmin ) + .5 );
+ $yscale = int( 100 * $yl / ( $ymax - $ymin ) + .5 );
+ $sx = sprintf( "%.2f", 100 / $xscale );
+ $sy = sprintf( "%.2f", 100 / $yscale );
+ $yx = $ymin > 0 ? $ymin : 0; # y-position of the x-axis
+ $xy = $xmin > 0 ? $xmin : 0; # x-position of the y-axis
+ $xlo = $xy - $sx; # x-pos of right side of y-markers
+ $ylo = $yx - $sy; # y-pos of top side of x-markers
+ $xhi = $xmax + 3 * $sx; # x-pos of left side of x-labels
+ $yhi = $ymax + 3 * $sy; # y-pos of bottom side of y-labels
+ print "%\n%====$Name====\n"
+ . "\\def\\Fig$Name\{\\$box\{\\mftitle{$Name}%\n"
+ . "\\def\\xlo{$xlo}\\def\\xhi{$xhi}%\n"
+ . "\\def\\ylo{$ylo}\\def\\yhi{$yhi}%\n"
+ . "\\def\\xy{$xy}\\def\\yx{$yx}%\n"
+ . "\\mfpic[$xscale][$yscale]{$xmin}{$xmax}{$ymin}{$ymax}%\n"
+ . "\\hatchwd{2}%\n"
+ . ( $Xlabel ? "\\tlabel[bc]($xy,$yhi){$font $Ylabel}%\n" : '' )
+ . ( $Ylabel ? "\\tlabel[cl]($xhi,$yx){$font $Xlabel}%\n" : '' );
+ print TEX "\\Fig$Name\\par{\\bf $Name}\\eject\n" if $pdfsample;
+ }, next;
+
+ /^arccst/ and do { # arc center start theta
+ parse qw(xc yc x1 y1 theta);
+ print "\\arc[c]{($xc,$yc),($x1,$y1),$theta}\n";
+ }, next;
+
+ /^arcset/ and do { # arc start end theta
+ parse qw(x1 y1 x2 y2 theta);
+ print "\\arc[s]{($x1,$y1),($x2,$y2),$theta}\n";
+ }, next;
+
+ /^arccrtt/ and do { # arc center radius theta1 theta2
+ parse qw(xc yc r theta1 theta2);
+ print "\\arc[p]{($xc,$yc),$theta1,$theta2,$r}\n";
+ }, next;
+
+ /^arc3/ and do { # arc three points
+ parse qw(x1 y1 x2 y2 x3 y3);
+ print "\\arc[t]{($x1,$y1),($x2,$y2),($x3,$y3)}\n";
+ }, next;
+
+ /^arrow/ and do {
+ parse qw(x1 y1 x2 y2 Label);
+ my $yd = $y1 > $y2 ? -3 : 3;
+ print "\\tlabel[bc]($x1,$y1){$font $Label}%\n"
+ . "\\arrow\\lines{($x1,"
+ . ( $y1 + $yd * $sy )
+ . "),($x2,$y2)}%\n";
+ }, next;
+
+ /^[xyXY]mark/ and do {
+ @z = parse_array($_);
+ for ( $i = 0 ; $i < @z ; $i++ ) {
+ $label = $z[$i];
+ if ( $label =~ /^[-.\d]+$/ ) {
+ $label = "\$$label\$";
+ } else {
+ $i++;
+ }
+ $x =
+ $command_name =~ /x/i ? $z[$i]
+ : $command_name =~ /y/ ? $xlo
+ : -$xlo;
+ $y =
+ $command_name =~ /y/i ? $z[$i]
+ : $command_name =~ /x/ ? $ylo
+ : -$ylo;
+ print "\\tlabel[$pos{$command_name}]($x,$y)"
+ . "{\\rm \\strut $label}%\n";
+ }
+ }, next;
+
+ /^grid/ and do {
+ parse qw(xdist ydist xgap ygap);
+ $topmaxy = ( int( $ymax / $ydist ) * $ydist );
+ $lftmaxx = ( int( $xmin / $xdist ) * $xdist );
+ $botmaxy = ( int( $ymin / $ydist ) * $ydist );
+ $rtmaxx = ( int( $xmax / $xdist ) * $xdist );
+ for ( $t = $lftmaxx ; $t <= $rtmaxx ; $t += $xdist ) {
+ print
+ "\\dotted[.5pt,$xgap mm]\\lines{($t,$botmaxy),($t,$topmaxy)}%\n";
+ }
+ for ( $t = $botmaxy ; $t <= $topmaxy ; $t += $ydist ) {
+ print
+ "\\dotted[.5pt,$ygap mm]\\lines{($lftmaxx,$t),($rtmaxx,$t)}%\n";
+ }
+ }, next;
+
+ /^bar/ and do {
+ parse qw(x xdev height);
+ $x1 = $x - $xdev;
+ $x2 = $x + $xdev;
+ $y1 = 0;
+ $y2 = $height;
+ print "\\rect{($x1,$y1),($x2,$y2)}%\n";
+ }, next;
+
+ /^d?(point|lines|curve|rect|crect)/ and do {
+ @z = parse_array($_);
+ $command_name =~ /^d/ and do { # relative points
+ for ( $i = 3 ; $i < @z ; $i += 2 ) {
+ $z[$i] += $z[ $i - 2 ];
+ $z[ $i - 1 ] += $z[ $i - 3 ];
+ }
+ $command_name =~ s/^d//;
+ };
+ $_ = "$command_name @z";
+ # for example: crect 5 20 20 5
+ s/^/\\/; # \crect 5 20 20 5
+ s/\s+/{(/; # \crect{(5 20 20 5
+ while (/ +/) {
+ s/ +([-.\d]+)(\s+)?/,$1),\n(/;
+ } # \crect{(5,20),(20,5)
+ s/,\n\($/}/; # \crect{(5,20),(20,5)}
+ s/crect/gclear\\rect/;
+ # \gclear\rect{(5,20),(20,5)}
+ print "$_\n";
+ }, next;
+
+ /^func/ and do {
+ parse qw(x y d F);
+ print "\\function{$x,$y,$d}{$F}%\n";
+ }, next;
+
+ /^hatch/ and do {
+ print '\rhatch\draw\lclosed';
+ }, next;
+
+ /^bhat/ and do {
+ print '\rhatch\lclosed\connect', "\n";
+ }, next;
+
+ /^ehat/ and do {
+ print '\endconnect', "\n";
+ }, next;
+
+ /^xdrop/ and do {
+ parse qw(x y);
+ print "\\dotted\\arrow" . "\\lines{($x,$y),($xy,$y)}%\n";
+ }, next;
+
+ /^ydrop/ and do {
+ parse qw(x y);
+ print "\\dotted\\arrow" . "\\lines{($x,$y),($x,$yx)}%\n";
+ }, next;
+
+ /^xydrop/ and do {
+ parse qw(x y);
+ print "\\dashed\\arrow" . "\\lines{($x,$y),($xy,$y)}%\n";
+ print "\\dashed\\arrow" . "\\lines{($x,$y),($x,$yx)}%\n";
+ }, next;
+
+ /^xlabels/ and do {
+ parse qw(M x y dx Z);
+ @z = split ( /\s+/, $Z );
+ for (@z) {
+ print "\\tlabel[$M]($x,$y){$font $_}%\n";
+ $x += $dx;
+ }
+ }, next;
+
+ /^ylabels/ and do {
+ parse qw(M x y dy Z);
+ @z = split ( /\s+/, $Z );
+ for (@z) {
+ print "\\tlabel[$M]($x,$y){$font $_}%\n";
+ $y += $dy;
+ }
+ }, next;
+
+ /^label/ and do {
+ parse qw(M x y Label);
+ $M =~ /^[bct][lcr]$/ or die "illegal label in $_\n";
+ print "\\tlabel[$M]($x,$y){$font $Label}%\n";
+ }, next;
+
+ /^end/ and do {
+ # axes drawn last for easier rect clears:
+ print "\\arrow[\\axisheadlen]\\lines" . "{($xmin,$yx),($xmax,$yx)}%\n"
+ if $Xlabel;
+ print "\\arrow[\\axisheadlen]\\lines" . "{($xy,$ymin),($xy,$ymax)}%\n"
+ if $Ylabel;
+ print "\\endmfpic}}%\n";
+ }, next;
+
+ /^arect/ and do {
+ parse qw/xc yc w h theta/;
+ $theta *= 3.141592 / 180;
+ $ws = $w / 2 * sin($theta);
+ $wc = $w / 2 * cos($theta);
+ $hs = $h * sin($theta);
+ $hc = $h * cos($theta);
+ print "\\lines{($xc-$ws,$yc+$wc),($xc-$ws+$hc,$yc+$wc+$hs),($xc+$ws+$hc,$yc-$wc+$hs),($xc+$ws,$yc-$wc),($xc-$ws,$yc+$wc)}\n";
+ }, next;
+
+ /^(\w+)\s*=/ and do {
+ $var = $1;
+ evaluate;
+ print LOG "$var=$$var\n" if $debug;
+ }, next;
+
+ /^stop/ and do { last }; # stop reading the input
+
+ print "$_\n" if $_; # anything else printed literally
+
+ }
+ print MAC "\\endinput\n";
+ close(MAC);
+ if ($pdfsample) {
+ print TEX "\\bye\n";
+ close(TEX);
+ sys("pdftex --interaction batchmode $tex 2>/dev/null");
+ sys("mf $tex; gftopk $tex.${dpi}gf");
+ sys("pdftex --interaction batchmode $tex 2>/dev/null");
+ for ( ( "log", "mf", "tfm", "${dpi}pk", "${dpi}gf", ) ) {
+ unlink "$tex.$_";
+ }
+ }
+}
+
+sub help { undef $/; open(FH,$0); print "Usage:".[split(/= .*\n/,<FH>)]->[3]; exit 1 }
+sub install { system('instscript --extras=mkpicdoc.tex,mkpicdoc.pdf -zp mkpic'); exit 0; }
+
+use Getopt::Long;
+Getopt::Long::Configure("bundling_override");
+
+GetOptions(
+ 'c|clean' => \$clean, # remove all but input file and don't run
+ 'p|pdfsample' => \$pdfsample, # create pdf file with sample images
+ 'b|box!' => \$box, # produce framed boxes
+ 'f|font=s' => \$font, # default font instead of rm
+ 'V|version' => \$version, # report version number and die
+ 'h|help' => \&help, # display help info and die
+ 'd|debug!' => \$debug, # print debug information
+ 'l|log=s' => \$log, # file for warning messages
+ 'I' => \&install # not for general use
+);
+
+if ($version) { print Version."\n"; exit; };
+$font = $font || '\rm';
+$box ||= '';
+$pdfsample ||= 0;
+if ($log) {
+ open( LOG, ">>$log" ) or die "Could not open $log for output: $!\n";
+} else {
+ *LOG = *STDERR;
+}
+
+# find printer density
+if ( open( IN, `kpsewhich --format="web2c files" mktex.cnf` ) ) {
+ while (<IN>) {
+ /BDPI=(\d+)/ and $dpi = $1, last;
+ }
+} else {
+ print LOG "could not find mktex.cnf; forcing 600dpi\n";
+ $dpi = 600;
+}
+
+# we'll place the options in the .mac file so that, in the next run,
+# we can see if the previous run had the same options; if so and if
+# the input file is older than the .mac file, we won't rerun mkpic:
+$options = "% font:$font box:$box dpi=$dpi pdfsample:$pdfsample\n";
+
+$tex = shift;
+if ($tex) {
+ open( IN, $tex ) or die "Could not open $tex\n";
+ $input = *IN;
+} else {
+ $input = *DATA;
+ $tex = 'mkpic';
+}
+
+$clean and do {
+ for ( eval "qw(mf ${dpi}gf ${dpi}pk log dvi pdf mac tex tfm sty)" ) {
+ unlink "$tex.$_";
+ }
+ exit 0;
+};
+
+open_macrofile() or die "mkpic: no new run needed\n";
+print LOG "Mkpic Warning: Rerun (La)TeX\n" if $log;
+
+$box = $box ? 'ruledhbox' : 'hbox';
+if ($pdfsample) {
+ open( TEX, ">$tex.tex" );
+ ($_ = <<EOF ) =~ s/^\s+//gm;
+ \\input $tex.mac
+ \\parindent0pt\\parskip2ex
+ \\nopagenumbers\\vsize=260mm
+EOF
+ print TEX;
+}
+
+%pos = (
+ 'xmark' => 'tc', # positions for [xyXY]marks
+ 'ymark' => 'cr',
+ 'Xmark' => 'bc',
+ 'Ymark' => 'cl'
+);
+%fun = (
+ sin => 1,
+ cos => 1,
+ sqrt => 1,
+ atan2 => 1,
+ abs => 1,
+ exp => 1,
+ int => 1,
+ log => 1,
+ not => 1
+);
+
+%names = ();
+
+parse_input;
+
+__DATA__
+l=20
+begin steps l l 0 0 l l - -
+\pen{2pt}
+dlines 10 10 1 0 0 1 1 0 0 1 1 0 0 1 1 0 0 1 1 0 0 1 1 0 0 1 1 0 0 1 1 0 0 1 1 0 0 1 1 0 0 1
+end
+
+begin rectangle 64 64 0 0 10 10 $x$ $y$
+arect 5 5 3 2 60
+lines 0 0 10 10 0 10 10 0
+end
+
+begin parabola 64 64 0 -6 4 5 $x$ $y$
+xmark 2
+Xmark 3
+ymark -5 0 4
+bhat
+lines 0 0 0 4
+func 0 3 .05 4-x*x
+lines 3 -5 3 0
+ehat
+func 0 3.2 .05 4-x*x
+xydrop 3 -5
+arrow 3 4 1.7 1.1 $f(x)=4-x^2$
+arrow 2 5 1 2 Area $O_1$
+arrow 4 2 2.8 -2 Area $O_2$
+end
+
+begin droparrows 64 64 0 3 12 8 $x$ $y$
+xmark $a$ 2 $x_1$ 4 $x_2$ 8 $b$ 10
+ydrop 2 4.414
+ydrop 4 5
+ydrop 8 5.828
+ydrop 10 6.162
+label cc 4 4 $f(x_1)$
+label cc 8 4 $f(x_2)$
+label cc 7 8 $f(x)$ increasing on $[a,b]$
+label cc 7 7.5 $x_1<x_2\Rightarrow f(x_1)<F(x_2)$
+func 1 11 .1 x**(.5)+3
+end
+
+begin asymptotes 64 64 0 0 10 10 $x$ $y$
+curve 1 1 2 3 4 5.7 7 8.1 9 9
+point 2 3 4 5.7 7 8.1
+\shift{(-.05,.05)}
+func 1.4 2.6 .1 1.65*x-.3
+func 3.2 4.8 .1 1.025*x+1.6
+func 6.1 7.9 .1 .62*x+3.76
+label cl 9.5 9 $f(x)$
+label tl 5 5 $f^\prime(x)>0$
+label tl 5 4 $f^\prime(x)$ decreasing
+end
+
+# the previous diagram was made when expression were not yet available
+# with them, it's easier to use a defined curve and its calculated slopes
+# and positions:
+begin droppers 64 64 0 0 10 10 $x$ $y$
+func 0 10 .1 3*(sqrt(x))
+point 2 3*sqrt(2) 4 3*sqrt(4) 7 3*sqrt(7)
+\shift{(-.05,.05)}
+func 1.5 2.5 .1 3/2*(x/sqrt(2)+sqrt(2))
+func 3.5 4.5 .1 3/2*(x/sqrt(4)+sqrt(4))
+func 6.5 7.5 .1 3/2*(x/sqrt(7)+sqrt(7))
+label cl 9.5 9 $f(x)$
+label tl 5 5 $f^\prime(x)>0$
+label tl 5 4 $f^\prime(x)$ decreasing
+end
+
+begin inflections 64 64 -.85 -1.5 1.5 5 $x$ $y$
+func -.6 1.5 .05 6*(x**4)-8*(x**3)+1
+lines -.2 1 .2 1
+label cr -.25 1 horizontal
+arrow .5 2 0 1 inflection point
+arrow .8 1 .65 0 inflection point
+arrow 1 5 1.5 4.375 $f(x)=6x^4-8x^3+1$
+Xmark 1
+ymark \raise-8pt\hbox{0} 0 -1
+xydrop 1 -1
+end
+
+begin paraboloid 64 64 -4 -4 4 4 - -
+\dashed
+lines -4 0 0 0 0 0 0 -4 # neg z and neg y
+\dashed
+lines 0 0 3 1.73 # neg x
+\arrow
+lines 0 0 0 4 # pos z
+\arrow
+lines 0 0 4 0 # pos y
+\arrow
+lines 0 0 -3 -1.73 # pos x
+\dotted
+lines -1 4 -1 0 -4 -1.73 # intersections y=-1 plane
+\dotted
+lines -1 -.577 -4 -.577 # intersection x=2 plane with xy-plane
+% extra helplines
+\dotted
+lines -2 .423 -2 -.577 0 0 0 1 -2 .423
+Ymark 3
+% end of extras
+\dotted
+lines 0 3 -1 3 -4 1.27
+\dashed\sclosed
+curve -3 2.42 -1.5 2.711 -1 2.42 -2.5 2.134
+label bc 0 yhi $z$
+label cl xhi 0 $y$
+label tr -3.1 -1.8 $x$
+label cl -.85 -.577 2
+label tc 0 5.5 $f(x,y)=x^2-4x+2y^2+4y+7$
+xmark -1
+Ymark 1
+\shift{(-2,.42)}
+\dashed
+func 0 .5 .1 9*x*x
+func -.5 0 .1 7*x*x
+\dashed
+func -1 0 .1 2*x*x
+func 0 1 .1 2*x*x
+end