home *** CD-ROM | disk | FTP | other *** search
/ The World of Computer Software / World_Of_Computer_Software-02-385-Vol-1of3.iso / i / iv26_w_3.zip / EXAMPLES / IDRAW / SLPICT.C < prev    next >
C/C++ Source or Header  |  1992-01-17  |  25KB  |  750 lines

  1. /*
  2.  * Copyright (c) 1987, 1988, 1989 Stanford University
  3.  *
  4.  * Permission to use, copy, modify, distribute, and sell this software and its
  5.  * documentation for any purpose is hereby granted without fee, provided
  6.  * that the above copyright notice appear in all copies and that both that
  7.  * copyright notice and this permission notice appear in supporting
  8.  * documentation, and that the name of Stanford not be used in advertising or
  9.  * publicity pertaining to distribution of the software without specific,
  10.  * written prior permission.  Stanford makes no representations about
  11.  * the suitability of this software for any purpose.  It is provided "as is"
  12.  * without express or implied warranty.
  13.  *
  14.  * STANFORD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
  15.  * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS.
  16.  * IN NO EVENT SHALL STANFORD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
  17.  * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
  18.  * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
  19.  * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
  20.  * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  21.  */
  22.  
  23. // $Header: slpict.c,v 1.19 89/10/09 14:49:34 linton Exp $
  24. // implements class PictSelection.
  25.  
  26. #include "ipaint.h"
  27. #include "istring.h"
  28. #include "listifont.h"
  29. #include "slellipses.h"
  30. #include "sllines.h"
  31. #include "slpict.h"
  32. #include "slpolygons.h"
  33. #include "slsplines.h"
  34. #include "sltext.h"
  35. #include <InterViews/transformer.h>
  36. #include <iostream.h>
  37. #include <fstream.h>
  38.  
  39. // PictSelection initializes its graphic state.
  40.  
  41. PictSelection::PictSelection (Graphic* gs) : (gs) {
  42.     valid = true;
  43. }
  44.  
  45. // PictSelection knows it's the outermost PictSelection because it was
  46. // called with a FILE* pointer, so it must read a version number, skip
  47. // over its name, read its graphic state and children, and scale
  48. // itself back to screen coordinates when it's finished.
  49.  
  50. PictSelection::PictSelection (FILE* stream, State* state) : (nil) {
  51.     int fd = fileno(stream);
  52.     istream from(fd);
  53.     ReadVersion(from);
  54.     ReadGridSpacing(from, state);
  55.     if (versionnumber < NONREDUNDANTVERSION) {
  56.     Skip(from);
  57.     }
  58.     ReadPictGS(from, state);
  59.     ReadChildren(from, state);
  60.     ScaleToScreenCoords();
  61.     Transformer* t = GetTransformer();
  62.     if (versionnumber < NONROTATEDVERSION && t != nil && t->Rotated90()) {
  63.     *t = identity;
  64.     Translate(0.0, -8.5*inches);
  65.     Rotate(90.0, 0.0, 0.0);
  66.     Picture::Propagate();
  67.     }
  68.     valid = from.good();
  69. }
  70.  
  71. // Copy returns a copy of the PictSelection.
  72.  
  73. Graphic* PictSelection::Copy () {
  74.     Selection* copy = new PictSelection(this);
  75.     for (First(); !AtEnd(); Next()) {
  76.     copy->Append(GetCurrent()->Copy());
  77.     }
  78.     return copy;
  79. }
  80.  
  81. // HasChildren returns true so Idraw can ungroup this Picture.
  82.  
  83. boolean PictSelection::HasChildren () {
  84.     return Picture::HasChildren();
  85. }
  86.  
  87. // Propagate must preserve the PictSelection's transformation matrix
  88. // if it has any.
  89.  
  90. void PictSelection::Propagate () {
  91.     Transformer* original = GetTransformer();
  92.     if (original != nil) {
  93.     original->Reference();
  94.     Picture::Propagate();
  95.     SetTransformer(original);
  96.     Unref(original);
  97.     } else {
  98.     Picture::Propagate();
  99.     }
  100. }
  101.  
  102. // WritePicture writes the picture and returns true if the write
  103. // succeeded or false if some IO error occurred.  It omits the
  104. // Postscript prologue and trailer if called with verbose false to
  105. // speed up cutting and pasting pictures between drawings.
  106.  
  107. boolean PictSelection::WritePicture (
  108.     FILE* stream, State* state, boolean verbose
  109. ) {
  110. #if !defined(__GNUG__)
  111.     // incompatible with g++, but works around a cfront bug
  112.     filebuf fb(stream->fd);
  113.     ostream to(&fb);
  114. #else
  115.     int fd = fileno(stream);
  116.     ostream to(fd);
  117. #endif
  118.     WritePicture(to, state, verbose);
  119.     return to.good();
  120. }
  121.  
  122. // PictSelection knows it's not the outermost PictSelection so it only
  123. // reads data to initialize its graphic state and create its children
  124. // Selections.
  125.  
  126. PictSelection::PictSelection (istream& from, State* state) : (nil) {
  127.     ReadPictGS(from, state);
  128.     ReadChildren(from, state);
  129.     valid = from.good();
  130. }
  131.  
  132. // ReadChildren loops determining which kind of Selection follows and
  133. // creating it until it reads "end" which means all of the children
  134. // have been created.
  135.  
  136. void PictSelection::ReadChildren (istream& from, State* state) {
  137.     while (from.good()) {
  138.     Skip(from);
  139.     Selection* child = nil;
  140.     from >> buf;
  141.     if (strcmp(buf, "BSpl") == 0) {
  142.         child = new BSplineSelection(from, state);
  143.     } else if (strcmp(buf, "Circ") == 0) {
  144.         child = new    CircleSelection(from, state);
  145.     } else if (strcmp(buf, "CBSpl") == 0) {
  146.         child = new    ClosedBSplineSelection(from, state);
  147.     } else if (strcmp(buf, "Elli") == 0) {
  148.         child = new    EllipseSelection(from, state);
  149.     } else if (strcmp(buf, "Line") == 0) {
  150.         child = new    LineSelection(from, state);
  151.     } else if (strcmp(buf, "MLine") == 0) {
  152.         child = new    MultiLineSelection(from, state);
  153.     } else if (strcmp(buf, "Pict") == 0) {
  154.         child = new    PictSelection(from, state);
  155.     } else if (strcmp(buf, "Poly") == 0) {
  156.         child = new    PolygonSelection(from, state);
  157.     } else if (strcmp(buf, "Rect") == 0) {
  158.         child = new    RectSelection(from, state);
  159.     } else if (strcmp(buf, "Text") == 0) {
  160.         child = new    TextSelection(from, state);
  161.     } else if (strcmp(buf, "eop") == 0) {
  162.         break;
  163.     } else {
  164.         fprintf(stderr, "unknown Selection %s, skipping\n", buf);
  165.         continue;
  166.     }
  167.     if (from.good()) {
  168.         Append(child);
  169.     } else {
  170.         delete child;
  171.     }
  172.     }
  173. }
  174.  
  175. // WritePicture writes the picture's data and Postscript code to print
  176. // it wrapped in Postscript comments that minimally conform to version
  177. // 1.0 of Adobe Systems's structuring conventions for Postscript.  The
  178. // picture must remove itself from its parent if it has a parent to
  179. // prevent the parent's transformation from affecting the picture's
  180. // calculation of its bounding box.
  181.  
  182. void PictSelection::WritePicture (ostream& to, State* state, boolean verbose) {
  183.     Picture* parent = (Picture*) Parent();
  184.     if (parent != nil) {
  185.     parent->SetCurrent(this);
  186.     parent->Remove(this);
  187.     }
  188.  
  189.     ScaleToPostscriptCoords();
  190.     if (verbose) {
  191.     WriteComments(to);
  192.     WritePrologue(to);
  193.     WriteVersion(to);
  194.     WriteGridSpacing(to, state);
  195.     WriteDrawing(to);
  196.     WriteTrailer(to);
  197.     } else {
  198.     WriteVersion(to);
  199.     WriteDrawing(to);
  200.     }
  201.     ScaleToScreenCoords();
  202.  
  203.     if (parent != nil) {
  204.     parent->InsertBeforeCur(this);
  205.     }
  206. }
  207.  
  208. // WriteComments writes information about the picture such as the
  209. // fonts used in it and the smallest bounding box enclosing it.
  210.  
  211. void PictSelection::WriteComments (ostream& to) {
  212.     to << "%!PS-Adobe-2.0 EPSF-1.2\n";
  213.  
  214.     to << "%%DocumentFonts:";
  215.     int linelen = strlen("%%DocumentFonts:");
  216.     const int MAXLINELEN = 256;
  217.     IFontList* fontlist = new IFontList;
  218.     CollectFonts(fontlist);
  219.     for (fontlist->First(); !fontlist->AtEnd(); fontlist->Next()) {
  220.     IFont* font = fontlist->GetCur()->GetFont();
  221.     if (linelen + strlen(font->GetPrintFont()) + 2 <= MAXLINELEN) {
  222.         to << " ";
  223.         ++linelen;
  224.     } else {
  225.         to << "\n%%+ ";
  226.         linelen = strlen("%%+ ");
  227.     }
  228.     to << font->GetPrintFont();
  229.     linelen += strlen(font->GetPrintFont());
  230.     }
  231.     to << "\n";
  232.     delete fontlist;
  233.  
  234.     to << "%%Pages: 1\n";
  235.  
  236.     Coord l, b, r, t;
  237.     GetBox(l, b, r, t);
  238.     to << "%%BoundingBox: " << l << " " << b << " " << r << " " << t << "\n";
  239.  
  240.     to << "%%EndComments\n\n";
  241.     to << "50 dict begin\n\n";
  242. }
  243.  
  244. // WritePrologue writes definitions of Postscript procedures to draw
  245. // Selections.  You should not rename or delete the "exported"
  246. // capitalized procedures because old drawings rely on them, but you
  247. // can rename or delete the "internal" uncapitalized procedures.
  248.  
  249. void PictSelection::WritePrologue (ostream& to) {
  250.     to << "/arrowHeight " << ARROWHEIGHT << " def\n";
  251.     to << "/arrowWidth " << ARROWWIDTH << " def\n";
  252.     to << "/none null def\n";
  253.     to << "/numGraphicParameters 17 def\n";
  254.     to << "/stringLimit 65535 def\n\n";
  255.     to << "/Begin {\n";
  256.     to << "save\n";
  257.     to << "numGraphicParameters dict begin\n";
  258.     to << "} def\n\n";
  259.     to << "/End {\n";
  260.     to << "end\n";
  261.     to << "restore\n";
  262.     to << "} def\n\n";
  263.     to << "/SetB {\n";
  264.     to << "dup type /nulltype eq {\n";
  265.     to << "pop\n";
  266.     to << "false /brushRightArrow idef\n";
  267.     to << "false /brushLeftArrow idef\n";
  268.     to << "true /brushNone idef\n";
  269.     to << "} {\n";
  270.     to << "/brushDashOffset idef\n";
  271.     to << "/brushDashArray idef\n";
  272.     to << "0 ne /brushRightArrow idef\n";
  273.     to << "0 ne /brushLeftArrow idef\n";
  274.     to << "/brushWidth idef\n";
  275.     to << "false /brushNone idef\n";
  276.     to << "} ifelse\n";
  277.     to << "} def\n\n";
  278.     to << "/SetCFg {\n";
  279.     to << "/fgblue idef\n";
  280.     to << "/fggreen idef\n";
  281.     to << "/fgred idef\n";
  282.     to << "} def\n\n";
  283.     to << "/SetCBg {\n";
  284.     to << "/bgblue idef\n";
  285.     to << "/bggreen idef\n";
  286.     to << "/bgred idef\n";
  287.     to << "} def\n\n";
  288.     to << "/SetF {\n";
  289.     to << "/printSize idef\n";
  290.     to << "/printFont idef\n";
  291.     to << "} def\n\n";
  292.     to << "/SetP {\n";
  293.     to << "dup type /nulltype eq {\n";
  294.     to << "pop true /patternNone idef\n";
  295.     to << "} {\n";
  296.     to << "/patternGrayLevel idef\n";
  297.     to << "patternGrayLevel -1 eq {\n";
  298.     to << "/patternString idef\n";
  299.     to << "} if\n";
  300.     to << "false /patternNone idef\n";
  301.     to << "} ifelse\n";
  302.     to << "} def\n\n";
  303.     to << "/BSpl {\n";
  304.     to << "0 begin\n";
  305.     to << "storexyn\n";
  306.     to << "newpath\n";
  307.     to << "n 1 gt {\n";
  308.     to << "0 0 0 0 0 0 1 1 true subspline\n";
  309.     to << "n 2 gt {\n";
  310.     to << "0 0 0 0 1 1 2 2 false subspline\n";
  311.     to << "1 1 n 3 sub {\n";
  312.     to << "/i exch def\n";
  313.     to << "i 1 sub dup i dup i 1 add dup i 2 add dup false subspline\n";
  314.     to << "} for\n";
  315.     to << "n 3 sub dup n 2 sub dup n 1 sub dup 2 copy false subspline\n";
  316.     to << "} if\n";
  317.     to << "n 2 sub dup n 1 sub dup 2 copy 2 copy false subspline\n";
  318.     to << "patternNone not brushLeftArrow not brushRightArrow not and and { ";
  319.     to << "ifill } if\n";
  320.     to << "brushNone not { istroke } if\n";
  321.     to << "0 0 1 1 leftarrow\n";
  322.     to << "n 2 sub dup n 1 sub dup rightarrow\n";
  323.     to << "} if\n";
  324.     to << "end\n";
  325.     to << "} dup 0 4 dict put def\n\n";
  326.     to << "/Circ {\n";
  327.     to << "newpath\n";
  328.     to << "0 360 arc\n";
  329.     to << "patternNone not { ifill } if\n";
  330.     to << "brushNone not { istroke } if\n";
  331.     to << "} def\n\n";
  332.     to << "/CBSpl {\n";
  333.     to << "0 begin\n";
  334.     to << "dup 2 gt {\n";
  335.     to << "storexyn\n";
  336.     to << "newpath\n";
  337.     to << "n 1 sub dup 0 0 1 1 2 2 true subspline\n";
  338.     to << "1 1 n 3 sub {\n";
  339.     to << "/i exch def\n";
  340.     to << "i 1 sub dup i dup i 1 add dup i 2 add dup false subspline\n";
  341.     to << "} for\n";
  342.     to << "n 3 sub dup n 2 sub dup n 1 sub dup 0 0 false subspline\n";
  343.     to << "n 2 sub dup n 1 sub dup 0 0 1 1 false subspline\n";
  344.     to << "patternNone not { ifill } if\n";
  345.     to << "brushNone not { istroke } if\n";
  346.     to << "} {\n";
  347.     to << "Poly\n";
  348.     to << "} ifelse\n";
  349.     to << "end\n";
  350.     to << "} dup 0 4 dict put def\n\n";
  351.     to << "/Elli {\n";
  352.     to << "0 begin\n";
  353.     to << "newpath\n";
  354.     to << "4 2 roll\n";
  355.     to << "translate\n";
  356.     to << "scale\n";
  357.     to << "0 0 1 0 360 arc\n";
  358.     to << "patternNone not { ifill } if\n";
  359.     to << "brushNone not { istroke } if\n";
  360.     to << "end\n";
  361.     to << "} dup 0 1 dict put def\n\n";
  362.     to << "/Line {\n";
  363.     to << "0 begin\n";
  364.     to << "2 storexyn\n";
  365.     to << "newpath\n";
  366.     to << "x 0 get y 0 get moveto\n";
  367.     to << "x 1 get y 1 get lineto\n";
  368.     to << "brushNone not { istroke } if\n";
  369.     to << "0 0 1 1 leftarrow\n";
  370.     to << "0 0 1 1 rightarrow\n";
  371.     to << "end\n";
  372.     to << "} dup 0 4 dict put def\n\n";
  373.     to << "/MLine {\n";
  374.     to << "0 begin\n";
  375.     to << "storexyn\n";
  376.     to << "newpath\n";
  377.     to << "n 1 gt {\n";
  378.     to << "x 0 get y 0 get moveto\n";
  379.     to << "1 1 n 1 sub {\n";
  380.     to << "/i exch def\n";
  381.     to << "x i get y i get lineto\n";
  382.     to << "} for\n";
  383.     to << "patternNone not brushLeftArrow not brushRightArrow not and and { ";
  384.     to << "ifill } if\n";
  385.     to << "brushNone not { istroke } if\n";
  386.     to << "0 0 1 1 leftarrow\n";
  387.     to << "n 2 sub dup n 1 sub dup rightarrow\n";
  388.     to << "} if\n";
  389.     to << "end\n";
  390.     to << "} dup 0 4 dict put def\n\n";
  391.     to << "/Poly {\n";
  392.     to << "3 1 roll\n";
  393.     to << "newpath\n";
  394.     to << "moveto\n";
  395.     to << "-1 add\n";
  396.     to << "{ lineto } repeat\n";
  397.     to << "closepath\n";
  398.     to << "patternNone not { ifill } if\n";
  399.     to << "brushNone not { istroke } if\n";
  400.     to << "} def\n\n";
  401.     to << "/Rect {\n";
  402.     to << "0 begin\n";
  403.     to << "/t exch def\n";
  404.     to << "/r exch def\n";
  405.     to << "/b exch def\n";
  406.     to << "/l exch def\n";
  407.     to << "newpath\n";
  408.     to << "l b moveto\n";
  409.     to << "l t lineto\n";
  410.     to << "r t lineto\n";
  411.     to << "r b lineto\n";
  412.     to << "closepath\n";
  413.     to << "patternNone not { ifill } if\n";
  414.     to << "brushNone not { istroke } if\n";
  415.     to << "end\n";
  416.     to << "} dup 0 4 dict put def\n\n";
  417.     to << "/Text {\n";
  418.     to << "ishow\n";
  419.     to << "} def\n\n";
  420.     to << "/idef {\n";
  421.     to << "dup where { pop pop pop } { exch def } ifelse\n";
  422.     to << "} def\n\n";
  423.     to << "/ifill {\n";
  424.     to << "0 begin\n";
  425.     to << "gsave\n";
  426.     to << "patternGrayLevel -1 ne {\n";
  427.     to << "fgred bgred fgred sub patternGrayLevel mul add\n";
  428.     to << "fggreen bggreen fggreen sub patternGrayLevel mul add\n";
  429.     to << "fgblue bgblue fgblue sub patternGrayLevel mul add setrgbcolor\n";
  430.     to << "eofill\n";
  431.     to << "} {\n";
  432.     to << "eoclip\n";
  433.     to << "originalCTM setmatrix\n";
  434.     to << "pathbbox /t exch def /r exch def /b exch def /l exch def\n";
  435.     to << "/w r l sub ceiling cvi def\n";
  436.     to << "/h t b sub ceiling cvi def\n";
  437.     to << "/imageByteWidth w 8 div ceiling cvi def\n";
  438.     to << "/imageHeight h def\n";
  439.     to << "bgred bggreen bgblue setrgbcolor\n";
  440.     to << "eofill\n";
  441.     to << "fgred fggreen fgblue setrgbcolor\n";
  442.     to << "w 0 gt h 0 gt and {\n";
  443.     to << "l b translate w h scale\n";
  444.     to << "w h true [w 0 0 h neg 0 h] { patternproc } imagemask\n";
  445.     to << "} if\n";
  446.     to << "} ifelse\n";
  447.     to << "grestore\n";
  448.     to << "end\n";
  449.     to << "} dup 0 8 dict put def\n\n";
  450.     to << "/istroke {\n";
  451.     to << "gsave\n";
  452.     to << "brushDashOffset -1 eq {\n";
  453.     to << "[] 0 setdash\n";
  454.     to << "1 setgray\n";
  455.     to << "} {\n";
  456.     to << "brushDashArray brushDashOffset setdash\n";
  457.     to << "fgred fggreen fgblue setrgbcolor\n";
  458.     to << "} ifelse\n";
  459.     to << "brushWidth setlinewidth\n";
  460.     to << "originalCTM setmatrix\n";
  461.     to << "stroke\n";
  462.     to << "grestore\n";
  463.     to << "} def\n\n";
  464.     to << "/ishow {\n";
  465.     to << "0 begin\n";
  466.     to << "gsave\n";
  467.     to << "fgred fggreen fgblue setrgbcolor\n";
  468.     to << "/fontDict printFont findfont printSize scalefont dup setfont def\n";
  469.     to << "/descender fontDict begin 0 [FontBBox] 1 get FontMatrix end\n";
  470.     to << "transform exch pop def\n";
  471.     to << "/vertoffset 0 descender sub printSize sub printFont /Courier ne\n";
  472.     to << "printFont /Courier-Bold ne and { 1 add } if def {\n";
  473.     to << "0 vertoffset moveto show\n";
  474.     to << "/vertoffset vertoffset printSize sub def\n";
  475.     to << "} forall\n";
  476.     to << "grestore\n";
  477.     to << "end\n";
  478.     to << "} dup 0 3 dict put def\n\n";
  479.     to << "/patternproc {\n";
  480.     to << "0 begin\n";
  481.     to << "/patternByteLength patternString length def\n";
  482.     to << "/patternHeight patternByteLength 8 mul sqrt cvi def\n";
  483.     to << "/patternWidth patternHeight def\n";
  484.     to << "/patternByteWidth patternWidth 8 idiv def\n";
  485.     to << "/imageByteMaxLength imageByteWidth imageHeight mul\n";
  486.     to << "stringLimit patternByteWidth sub min def\n";
  487.     to << "/imageMaxHeight imageByteMaxLength imageByteWidth idiv ";
  488.     to << "patternHeight idiv\n";
  489.     to << "patternHeight mul patternHeight max def\n";
  490.     to << "/imageHeight imageHeight imageMaxHeight sub store\n";
  491.     to << "/imageString imageByteWidth imageMaxHeight mul patternByteWidth ";
  492.     to << "add string def\n";
  493.     to << "0 1 imageMaxHeight 1 sub {\n";
  494.     to << "/y exch def\n";
  495.     to << "/patternRow y patternByteWidth mul patternByteLength mod def\n";
  496.     to << "/patternRowString patternString patternRow patternByteWidth ";
  497.     to << "getinterval def\n";
  498.     to << "/imageRow y imageByteWidth mul def\n";
  499.     to << "0 patternByteWidth imageByteWidth 1 sub {\n";
  500.     to << "/x exch def\n";
  501.     to << "imageString imageRow x add patternRowString putinterval\n";
  502.     to << "} for\n";
  503.     to << "} for\n";
  504.     to << "imageString\n";
  505.     to << "end\n";
  506.     to << "} dup 0 12 dict put def\n\n";
  507.     to << "/min {\n";
  508.     to << "dup 3 2 roll dup 4 3 roll lt { exch } if pop\n";
  509.     to << "} def\n\n";
  510.     to << "/max {\n";
  511.     to << "dup 3 2 roll dup 4 3 roll gt { exch } if pop\n";
  512.     to << "} def\n\n";
  513.     to << "/arrowhead {\n";
  514.     to << "0 begin\n";
  515.     to << "transform originalCTM itransform\n";
  516.     to << "/taily exch def\n";
  517.     to << "/tailx exch def\n";
  518.     to << "transform originalCTM itransform\n";
  519.     to << "/tipy exch def\n";
  520.     to << "/tipx exch def\n";
  521.     to << "/dy tipy taily sub def\n";
  522.     to << "/dx tipx tailx sub def\n";
  523.     to << "/angle dx 0 ne dy 0 ne or { dy dx atan } { 90 } ifelse def\n";
  524.     to << "gsave\n";
  525.     to << "originalCTM setmatrix\n";
  526.     to << "tipx tipy translate\n";
  527.     to << "angle rotate\n";
  528.     to << "newpath\n";
  529.     to << "0 0 moveto\n";
  530.     to << "arrowHeight neg arrowWidth 2 div lineto\n";
  531.     to << "arrowHeight neg arrowWidth 2 div neg lineto\n";
  532.     to << "closepath\n";
  533.     to << "patternNone not {\n";
  534.     to << "originalCTM setmatrix\n";
  535.     to << "/padtip arrowHeight 2 exp 0.25 arrowWidth 2 exp mul add sqrt ";
  536.     to << "brushWidth mul\n";
  537.     to << "arrowWidth div def\n";
  538.     to << "/padtail brushWidth 2 div def\n";
  539.     to << "tipx tipy translate\n";
  540.     to << "angle rotate\n";
  541.     to << "padtip 0 translate\n";
  542.     to << "arrowHeight padtip add padtail add arrowHeight div dup scale\n";
  543.     to << "arrowheadpath\n";
  544.     to << "ifill\n";
  545.     to << "} if\n";
  546.     to << "brushNone not {\n";
  547.     to << "originalCTM setmatrix\n";
  548.     to << "tipx tipy translate\n";
  549.     to << "angle rotate\n";
  550.     to << "arrowheadpath\n";
  551.     to << "istroke\n";
  552.     to << "} if\n";
  553.     to << "grestore\n";
  554.     to << "end\n";
  555.     to << "} dup 0 9 dict put def\n\n";
  556.     to << "/arrowheadpath {\n";
  557.     to << "newpath\n";
  558.     to << "0 0 moveto\n";
  559.     to << "arrowHeight neg arrowWidth 2 div lineto\n";
  560.     to << "arrowHeight neg arrowWidth 2 div neg lineto\n";
  561.     to << "closepath\n";
  562.     to << "} def\n\n";
  563.     to << "/leftarrow {\n";
  564.     to << "0 begin\n";
  565.     to << "y exch get /taily exch def\n";
  566.     to << "x exch get /tailx exch def\n";
  567.     to << "y exch get /tipy exch def\n";
  568.     to << "x exch get /tipx exch def\n";
  569.     to << "brushLeftArrow { tipx tipy tailx taily arrowhead } if\n";
  570.     to << "end\n";
  571.     to << "} dup 0 4 dict put def\n\n";
  572.     to << "/rightarrow {\n";
  573.     to << "0 begin\n";
  574.     to << "y exch get /tipy exch def\n";
  575.     to << "x exch get /tipx exch def\n";
  576.     to << "y exch get /taily exch def\n";
  577.     to << "x exch get /tailx exch def\n";
  578.     to << "brushRightArrow { tipx tipy tailx taily arrowhead } if\n";
  579.     to << "end\n";
  580.     to << "} dup 0 4 dict put def\n\n";
  581.     to << "/midpoint {\n";
  582.     to << "0 begin\n";
  583.     to << "/y1 exch def\n";
  584.     to << "/x1 exch def\n";
  585.     to << "/y0 exch def\n";
  586.     to << "/x0 exch def\n";
  587.     to << "x0 x1 add 2 div\n";
  588.     to << "y0 y1 add 2 div\n";
  589.     to << "end\n";
  590.     to << "} dup 0 4 dict put def\n\n";
  591.     to << "/thirdpoint {\n";
  592.     to << "0 begin\n";
  593.     to << "/y1 exch def\n";
  594.     to << "/x1 exch def\n";
  595.     to << "/y0 exch def\n";
  596.     to << "/x0 exch def\n";
  597.     to << "x0 2 mul x1 add 3 div\n";
  598.     to << "y0 2 mul y1 add 3 div\n";
  599.     to << "end\n";
  600.     to << "} dup 0 4 dict put def\n\n";
  601.     to << "/subspline {\n";
  602.     to << "0 begin\n";
  603.     to << "/movetoNeeded exch def\n";
  604.     to << "y exch get /y3 exch def\n";
  605.     to << "x exch get /x3 exch def\n";
  606.     to << "y exch get /y2 exch def\n";
  607.     to << "x exch get /x2 exch def\n";
  608.     to << "y exch get /y1 exch def\n";
  609.     to << "x exch get /x1 exch def\n";
  610.     to << "y exch get /y0 exch def\n";
  611.     to << "x exch get /x0 exch def\n";
  612.     to << "x1 y1 x2 y2 thirdpoint\n";
  613.     to << "/p1y exch def\n";
  614.     to << "/p1x exch def\n";
  615.     to << "x2 y2 x1 y1 thirdpoint\n";
  616.     to << "/p2y exch def\n";
  617.     to << "/p2x exch def\n";
  618.     to << "x1 y1 x0 y0 thirdpoint\n";
  619.     to << "p1x p1y midpoint\n";
  620.     to << "/p0y exch def\n";
  621.     to << "/p0x exch def\n";
  622.     to << "x2 y2 x3 y3 thirdpoint\n";
  623.     to << "p2x p2y midpoint\n";
  624.     to << "/p3y exch def\n";
  625.     to << "/p3x exch def\n";
  626.     to << "movetoNeeded { p0x p0y moveto } if\n";
  627.     to << "p1x p1y p2x p2y p3x p3y curveto\n";
  628.     to << "end\n";
  629.     to << "} dup 0 17 dict put def\n\n";
  630.     to << "/storexyn {\n";
  631.     to << "/n exch def\n";
  632.     to << "/y n array def\n";
  633.     to << "/x n array def\n";
  634.     to << "n 1 sub -1 0 {\n";
  635.     to << "/i exch def\n";
  636.     to << "y i 3 2 roll put\n";
  637.     to << "x i 3 2 roll put\n";
  638.     to << "} for\n";
  639.     to << "} def\n\n";
  640.     to << "%%EndProlog\n\n";
  641. }
  642.  
  643. // WriteDrawing writes code to store the picture's transformation
  644. // matrix in a Postscript variable and code to draw the picture.
  645.  
  646. void PictSelection::WriteDrawing (ostream& to) {
  647.     to << "\n\n%%Page: 1 1\n\n";
  648.     to << "Begin\n";
  649.     WritePictGS(to);
  650.     to << "/originalCTM matrix currentmatrix def\n\n";
  651.  
  652.     for (First(); !AtEnd(); Next()) {
  653.     Selection* s = GetCurrent();
  654.     s->WriteData(to);
  655.     }
  656.  
  657.     to << "End " << startdata << " eop\n\n";
  658.     to << "showpage\n\n";
  659. }
  660.  
  661. // WriteData writes the PictSelection's data and its children
  662. // Selections' data with Postscript code to draw them.
  663.  
  664. void PictSelection::WriteData (ostream& to) {
  665.     to << "Begin " << startdata << " Pict\n";
  666.     WritePictGS(to);
  667.     to << "\n";
  668.  
  669.     for (First(); !AtEnd(); Next()) {
  670.     Selection* s = GetCurrent();
  671.     s->WriteData(to);
  672.     }
  673.  
  674.     to << "End " << startdata << " eop\n\n";
  675. }
  676.  
  677. // WriteTrailer writes clean up code.
  678.  
  679. void PictSelection::WriteTrailer (ostream& to) {
  680.     to << "%%Trailer\n\n";
  681.     to << "end\n";
  682. }
  683.  
  684. // ScaleToPostscriptCoords scales the picture to Postscript
  685. // coordinates if screen and Postscript inches are different.
  686.  
  687. void PictSelection::ScaleToPostscriptCoords () {
  688.     const double postscriptinch = 72.;
  689.  
  690.     if (inch != postscriptinch) {
  691.     double topostscript = postscriptinch / inch;
  692.     Scale(topostscript, topostscript);
  693.     }
  694. }
  695.  
  696. // ScaleToScreenCoords scales the picture back to screen coordinates
  697. // if screen and Postscript inches are different.
  698.  
  699. void PictSelection::ScaleToScreenCoords () {
  700.     const double postscriptinch = 72.;
  701.  
  702.     if (inch != postscriptinch) {
  703.     double toscreen = inch / postscriptinch;
  704.     Scale(toscreen, toscreen);
  705.     }
  706. }
  707.  
  708. // CollectFonts adds its font, if it has one, to the list without
  709. // checking if the PictSelection contains any TextSelections.  If it
  710. // doesn't have a font, it collects its children TextSelection's
  711. // fonts.
  712.  
  713. void PictSelection::CollectFonts (IFontList* fontlist) {
  714.     if (GetFont() != nil) {
  715.     Merge((IFont*) GetFont(), fontlist);
  716.     } else {
  717.     for (First(); !AtEnd(); Next()) {
  718.         Selection* s = GetCurrent();
  719.         if (s->HasChildren()) {
  720.         ((PictSelection*) s)->CollectFonts(fontlist);
  721.         } else if (s->IsA(TEXTSELECTION)) {
  722.         Merge((IFont*) s->GetFont(), fontlist);
  723.         }
  724.     }
  725.     }
  726. }
  727.  
  728. // Merge merges the print font with the list of all print fonts unless
  729. // the list already has it.
  730.  
  731. void PictSelection::Merge (IFont* font, IFontList* fontlist) {
  732.     boolean found = false;
  733.     if (font == nil) {
  734.     found = true;
  735.     } else if (fontlist->Find(font)) {
  736.     found = true;
  737.     } else {
  738.     for (fontlist->First(); !fontlist->AtEnd(); fontlist->Next()) {
  739.         IFont* cmp = fontlist->GetCur()->GetFont();
  740.         if (strcmp(font->GetPrintFont(), cmp->GetPrintFont()) == 0) {
  741.         found = true;
  742.         break;
  743.         }
  744.     }
  745.     }
  746.     if (!found) {
  747.     fontlist->Append(new IFontNode(font));
  748.     }
  749. }
  750.