[comp.sources.misc] v06i007: HPGL to PostScript converter

allbery@uunet.UU.NET (Brandon S. Allbery - comp.sources.misc) (01/22/89)

Posting-number: Volume 6, Issue 7
Submitted-by: federico@actisb.UUCP (Federico Heinz)
Archive-name: yahp2ps/part05

#! /bin/sh
# This is a shell archive.  Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file".  To overwrite existing
# files, type "sh file -c".  You can also feed this as standard input via
# unshar, or by typing "sh <file", e.g..  If this archive is complete, you
# will see the following message at the end:
#		"End of archive 5 (of 6)."
# Contents:  io.c penctrl.c
# Wrapped by federico@actisb on Wed Jan  4 13:34:49 1989
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f 'io.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'io.c'\"
else
echo shar: Extracting \"'io.c'\" \(12654 characters\)
sed "s/^X//" >'io.c' <<'END_OF_FILE'
X/*
X        HPGL to PostScript converter
X   Copyright (C) 1988 (and following) Federico Heinz
X
Xyahp2ps is distributed in the hope that it will be useful, but WITHOUT ANY
XWARRANTY.  No author or distributor accepts responsibility to anyone
Xfor the consequences of using it or for whether it serves any
Xparticular purpose or works at all, unless he says so in writing.
XRefer to the Free Software Foundation's General Public License for full details.
X
XEveryone is granted permission to copy, modify and redistribute yahp2ps,
Xbut only under the conditions described in the GNU General Public
XLicense.  A copy of this license is supposed to have been given to you
Xalong with yahp2ps so you can know your rights and responsibilities.  It
Xshould be in a file named COPYING.  Among other things, the copyright
Xnotice and this notice must be preserved on all copies.
X
XIn other words, go ahead and share yahp2ps, but don't try to stop
Xanyone else from sharing it farther.  Help stamp out software hoarding!
X
Xyahp2ps is TOTALLY unrelated to GNU or the Free Software Foundation,
Xit is only released under the same conditions.
X
X    For bug reports, wishes, etc. send e-mail to
X
X    ...!mcvax!unido!tub!actisb!federico  (from Europe)
X    ...!uunet!pyramid!actisb!federico    (from anywhere else)
X
X    For Physical mail:
X
X    Federico Heinz
X    Beusselstr. 21
X    1000 Berlin 21
X
X    Tel. (+49 30) 396 77 92
X
X*/
X/**************************************************************************
X
X  Input/Output functions.
X
X**************************************************************************/
X
X#include <stdio.h>
X#include <ctype.h>
X#include "defs.h"
X#include "dispatch.h"
X#include "io.h"
X
Xint LookAhead = 0;	/* Lookahead feature buffer */
X
X/*************************************************************************
X
X    Error handling
X
X*************************************************************************/
X
X
X
X/*
X
X  Put a non-fatal warning trough stderr.
X
X*/
X
Xvoid warning(text)
X
Xchar *text;
X
X{ fprintf(stderr, "hpgl2ps WARNING: %s\n", text);
X}
X
X
X
X/*
X
X  Report a fatal error trough stderr.
X
X*/
X
Xvoid error(text)
X
Xchar *text;
X
X{ fprintf(stderr, "hpgl2ps ERROR: %s\n", text);
X  exit(1);
X}
X
X
X/**************************************************************************
X
X    Basic file I/O
X
X**************************************************************************/
X
X
Xstatic FILE *input = stdin;
X
Xstatic FILE *output = stdout;
X
X
X/*
X
X  Get the next usable char from the file, skipping escape sequences.
X
X*/
X
Xstatic int getNextC()
X
X{ int c;
X
X  c = getc(input);
X  while (c == '\033')
X  { (void)getc(input); /* Ignore dot */
X    switch (getc(input))
X    { case '@':
X      case 'H':
X      case 'I':
X      case 'M':
X      case 'N': while (getc(input) != ':') ;
X      case '(':
X      case 'Y':
X      case ')':
X      case 'Z':
X      case 'B':
X      case 'E':
X      case 'J':
X      case 'K':
X      case 'L':
X      case 'O':
X      case 'R': break;
X      default: warning("Illegal escape sequence.");
X    }
X    c = getc(input);
X    while(isTerminator(c)) c = getc(input);
X  }
X  return(c);
X}
X 
X          
X
X/*
X
X  Get the next char from the input stream with lookahead
X
X*/
X
Xint getChar()
X
X{ int   aChar;
X
X  if (!LookAhead) LookAhead = getNextC();
X  aChar = LookAhead;
X  if (LookAhead != EOF) LookAhead = getNextC();
X  return(aChar);
X}
X
X
X
X
X/*
X
X  Put a char to the output stream.
X
X*/
X
Xvoid putChar(c)
X
Xchar c;
X
X{ putc(c, output); }
X
X
X
X/*************************************************************************
X
X   HPGL syntax sensitive stuff
X
X*************************************************************************/
X
X
X
X/*
X
X  Skip over optional separator.
X
X*/
X
Xvoid skipSeparator()
X
X{ while (isSeparator(LookAhead)) (void)getChar(); }
X
X
X
X/*
X
X  Skip over statement terminator.
X
X*/
X
Xvoid skipTerminator()
X
X{ while (isTerminator(LookAhead))
X  { (void)getChar();
X    skipSeparator();
X  }
X}
X
X
X/*************************************************************************
X
X  Number input
X
X*************************************************************************/
X
X
X/* Powers of ten */
X
Xstatic  long int TenToThe[] = { 1L, 10L, 100L, 1000L, 10000L };
X
X
X
X/*
X
X  Read a Number from the input stream.
X
X*/
X
X
XBoolean getNumber(target)
X
XNumber *target;
X
X{ Number result;
X  int    placesLeft, decimalsLeft;
X  Boolean negative;
X
X  if (LookAhead == '+')
X  { negative = False;
X    getChar();
X  }
X  else if (LookAhead == '-')
X  { negative = True;
X    getChar();
X  }
X  if (!isdigit(LookAhead) && (LookAhead != '.'))
X  { warning("Number expected.");
X    return(False);
X  }
X  result = 0; placesLeft = IntPlaces;
X  while (isdigit(LookAhead) && placesLeft)
X  { result = result * 10L + (Number)(getChar() - '0');
X    placesLeft--;
X  }
X  if (isdigit(LookAhead)) 
X  { warning("Number out of range.");
X    return(False);
X  }
X  decimalsLeft = DecPlaces;
X  if (LookAhead == '.')
X  { (void)getChar();
X    while(isdigit(LookAhead) && decimalsLeft)
X    { result = result * 10L + (Number)(getChar() - '0');
X      decimalsLeft--;
X    }
X    if (isdigit(LookAhead))
X    { warning("Extra decimal places skipped.");
X      while(isdigit(LookAhead)) (void)getChar();
X    }
X  }
X  skipSeparator();
X  *target = (negative ? -result : result) * TenToThe[decimalsLeft];
X  return(True);
X}
X
X
X/*
X
X  Convert from ASCII to Number.
X
X*/
X
XBoolean ASCIIToNumber(target, source)
X
XNumber *target;
Xchar **source;
X
X{ Number result;
X  int    placesLeft, decimalsLeft;
X
X  result = 0; placesLeft = IntPlaces;
X  while (isdigit(**source) && placesLeft)
X  { result = result * 10L + (Number)((*((*source)++)) - '0');
X    placesLeft--;
X  }
X  if (isdigit(**source))
X    return(False);
X  decimalsLeft = DecPlaces;
X  if (**source == '.')
X  { (*source)++;
X    while(isdigit(**source) && decimalsLeft)
X    { result = result * 10L + (Number)((*((*source)++)) - '0');
X      decimalsLeft--;
X    }
X    while(isdigit(**source)) (*source)++;
X  }
X  *target = result * TenToThe[decimalsLeft];
X  return(True);
X}
X
X
X
X/*
X
X  Read an Integer
X
X*/
X
XBoolean getInteger(target)
X
XNumber *target;
X
X{ Number result;
X
X  if (getNumber(&result))
X  { *target = trunc(result);
X    return(True);
X  }
X  else
X    return(False);
X}
X
X
X
X/*
X
X  Read a CoordinatePair.
X
X*/
X
XBoolean getCoordinatePair(target)
X
XCoordinatePair target;
X
X{ if (!getNumber(&target[X])) return(False);
X  skipSeparator();
X  if (!isNumeric(LookAhead))
X  { warning("Uneven number of coordinates.");
X    return(False);
X  }
X  return(getNumber(&target[Y]));
X}
X
X
X/***************************************************************************
X
X   Number output
X
X**************************************************************************/
X
X   
X
X
X/*
X
X  Private routine to put a positive integer to the output stream. A zero
X  produces no output at all. No space is appended at the end.
X
X*/
X
Xstatic void putInt(n)
X
Xint n;
X
X{ if (n)
X  { putInt(n / 10);
X    putChar((n % 10) + '0');
X  }
X}
X
X
X
X/*
X
X  Write a Number to the output stream.
X
X*/
X
Xvoid writeNumber(n)
X
XNumber n;
X
X{ int integerPart, fractionalPart;
X
X  if (n == Zero)
X    putChar('0');
X  else
X  { if (n < Zero)
X    { putChar('-');
X      n = -n;
X    }
X    integerPart = (int)(n / One);
X    fractionalPart = (int)(n % One);
X    putInt(integerPart);
X    if (fractionalPart)
X    { putChar('.');
X      while (!(fractionalPart % 10)) fractionalPart /= 10;
X      putInt(fractionalPart);
X    }
X  }
X  putChar(' ');
X}
X
X
X
X/*
X
X  Write a CoordinatePair to the output stream.
X
X*/
X
Xvoid writeCoordinatePair(source)
X
XCoordinatePair  source;
X
X{ writeNumber(source[X]);
X  writeNumber(source[Y]);
X}
X
X
X
X/*
X
X  Write an integer to the output string.
X
X*/
X
Xvoid writeInt(n)
X
Xint n;
X
X{ if (n = 0)
X    putChar('0');
X  else
X    if (n < 0)
X    { putChar('-');
X      n = -n;
X    }
X    putInt(n);
X  putChar(' ');
X}
X
X
X/**************************************************************************
X
X  String output.
X
X**************************************************************************/
X
X
X
X/*
X
X  Write a string to the output stream.
X
X*/
X
Xvoid writeString(x)
X
Xchar *x;
X
X{ while (*x) putChar(*(x++)); }
X
X
X/*************************************************************************
X
X   Command input
X
X*************************************************************************/
X
X
X
X/*
X
X  Get and decode a command from the input stream.
X
X*/
X
Xstatic struct CommandItem
X{ int           key;
X  Command       code;
X} ACommands[] =
X  { {'A', ArcAbsolute },
X    {'R', ArcRelative },
X    { 0, 0 }
X  },
X
X  CCommands[] =
X  { {'A', SetAlternateChar },
X    {'I', Circle },
X    {'P', CharacterPlot },
X    {'S', SetStandardChar },
X    { 0, 0 }
X  },
X
X  DCommands[] =
X  { {'C', NotImplemented },             /* Digitize Clear */
X    {'F', SetDefaults },
X    {'I', SetAbsoluteDirection },
X    {'P', NotImplemented },             /* Digitize Point */
X    {'R', SetRelativeDirection },
X    {'T', SetLabelTerminator },
X    { 0, 0 }
X  },
X
X  ECommands[] =
X  { {'A', RectangleAbsolute },
X    {'R', RectangleRelative },
X    {'W', Wedge },
X    { 0, 0 }
X  },
X
X  FCommands[] =
X  { {'T', SetFillType },
X    { 0, 0 }
X  },
X
X  ICommands[] =
X  { {'M', NotImplemented },             /* Input Mask */
X    {'N', Initialize },
X    {'P', InputP1P2 },
X    {'W', InputWindow },
X    { 0, 0 }
X  },
X
X  LCommands[] =
X  { {'B', PutASCIILabel },
X    {'T', SetLineType },
X    { 0, 0 }
X  },
X
X  OCommands[] =
X  { {'A', Interactive },                /* Output Position  */
X    {'C', Interactive },                /* Output Commanded */
X    {'D', Interactive },                /* Output Point     */
X    {'E', Interactive },                /* Output Error     */
X    {'F', Interactive },                /* Output Factors   */
X    {'H', Interactive },                /* Output Hard Clip */
X    {'I', Interactive },                /* Output Ident     */
X    {'O', Interactive },                /* Output Options   */
X    {'P', Interactive },                /* Output P1 and P2 */
X    {'S', Interactive },                /* Output Status    */
X    {'W', Interactive },                /* Output Window    */
X    { 0, 0 }
X  },
X
X  PCommands[] =
X  { {'A', SetAbsolutePlot },
X    {'D', PenDown },
X    {'R', SetRelativePlot },
X    {'S', SetPaperSize },
X    {'T', PenThickness },             /* Pen Thickness */
X    {'U', PenUp },
X    { 0, 0 }
X  },
X
X  RCommands[] =
X  { {'A', ShadeRectAbsolute },
X    {'O', RotateCoordSys },
X    {'R', ShadeRectRelative },
X    { 0, 0 }
X  },
X
X  SCommands[] =
X  { {'A', SelectAlternate },
X    {'C', SetScale },
X    {'I', SetAbsoluteCharSize },
X    {'L', SetAbsoluteCharSlant },
X    {'M', SetSymbolMode },
X    {'P', SelectPen },
X    {'R', SetRelativeCharSize },
X    {'S', SelectStandard },
X    { 0, 0 }
X  },
X
X  TCommands[] =
X  { {'L', SetTickLength },
X    { 0, 0 }
X  },
X
X  UCommands[] =
X  { {'C', UserChar },
X    { 0, 0 }
X  },
X
X  VCommands[] =
X  { {'S', NotImplemented },             /* Set Velocity */
X    { 0, 0 }
X  },
X
X  WCommands[] =
X  { {'G', ShadeWedge },
X    { 0, 0 }
X  },
X
X  XCommands[] =
X  { {'T', XTick },
X    { 0, 0 }
X  },
X
X  YCommands[] =
X  { {'T', YTick },
X    { 0, 0 }
X  },
X
X  *CommandIndex[] =
X    {   ACommands,
X        NULL, 
X        CCommands, 
X        DCommands, 
X        ECommands,
X        FCommands, 
X        NULL, 
X        NULL, 
X        ICommands, 
X        NULL, 
X        NULL, 
X        LCommands,
X        NULL, 
X        NULL, 
X        OCommands, 
X        PCommands, 
X        NULL, 
X        RCommands,
X        SCommands, 
X        TCommands, 
X        UCommands, 
X        VCommands,
X        WCommands, 
X        XCommands, 
X        YCommands, 
X        NULL
X    };
X
X
X
XCommand getCommand()
X
X{ int                   c;
X  struct CommandItem    *tablePointer;
X
X  c = getChar();
X  if (isalpha(c) &&
X     ((tablePointer = CommandIndex[islower(c) ? (c - 'a') : (c - 'A')]) != NULL))
X  { skipSeparator();
X    c = getChar();
X    if (isalpha(c))
X    { if (islower(c)) c = toupper(c);
X      while (tablePointer->key)
X        if (tablePointer->key == c)
X        { skipSeparator();
X          return(tablePointer->code);
X        }
X        else
X          tablePointer++;
X    }
X  }
X  error("Illegal HPGL command.");
X}
X
X
X
X/*
X
X  Handle extra parameters to a command.
X
X*/
X
Xvoid endCommand()
X
X{ Number dummy;
X
X  if (!isTerminator(LookAhead))
X  { warning("Extra parameters ignored");
X    while (!isTerminator(LookAhead))
X      (void)getChar();
X  }
X  skipTerminator();
X}
X
X
X
X/*************************************************************************
X
X  Internal I/O redirection
X
X*************************************************************************/
X
X
X/*
X
X  Get input chars from specified file.
X
X*/
X
XBoolean setInput(fileName)
X
Xchar *fileName;
X
X{ return((input = fopen(fileName,"r")) != NULL); }
X
X
X
X/*
X
X  Put output chars to specified file.
X
X*/
X
XBoolean setOutput(fileName)
X
Xchar *fileName;
X
X{ return((output = fopen(fileName,"w")) != NULL); }
X
END_OF_FILE
if test 12654 -ne `wc -c <'io.c'`; then
    echo shar: \"'io.c'\" unpacked with wrong size!
fi
# end of 'io.c'
fi
if test -f 'penctrl.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'penctrl.c'\"
else
echo shar: Extracting \"'penctrl.c'\" \(11891 characters\)
sed "s/^X//" >'penctrl.c' <<'END_OF_FILE'
X/*
X        HPGL to PostScript converter
X   Copyright (C) 1988 (and following) Federico Heinz
X
Xyahp2ps is distributed in the hope that it will be useful, but WITHOUT ANY
XWARRANTY.  No author or distributor accepts responsibility to anyone
Xfor the consequences of using it or for whether it serves any
Xparticular purpose or works at all, unless he says so in writing.
XRefer to the Free Software Foundation's General Public License for full details.
X
XEveryone is granted permission to copy, modify and redistribute yahp2ps,
Xbut only under the conditions described in the GNU General Public
XLicense.  A copy of this license is supposed to have been given to you
Xalong with yahp2ps so you can know your rights and responsibilities.  It
Xshould be in a file named COPYING.  Among other things, the copyright
Xnotice and this notice must be preserved on all copies.
X
XIn other words, go ahead and share yahp2ps, but don't try to stop
Xanyone else from sharing it farther.  Help stamp out software hoarding!
X
Xyahp2ps is TOTALLY unrelated to GNU or the Free Software Foundation,
Xit is only released under the same conditions.
X
X    For bug reports, wishes, etc. send e-mail to
X
X    ...!mcvax!unido!tub!actisb!federico  (from Europe)
X    ...!uunet!pyramid!actisb!federico    (from anywhere else)
X
X    For Physical mail:
X
X    Federico Heinz
X    Beusselstr. 21
X    1000 Berlin 21
X
X    Tel. (+49 30) 396 77 92
X
X*/
X
X/***************************************************************************
X
X  Primitive pen control routines. Provides the interface between the
X  ideal plotter and the machinery.
X
X****************************************************************************/
X
X#include "defs.h"
X#include "mchinery.h"
X#include "penctrl.h"
X#include "circle.h"
X#include "tick.h"
X#include "io.h"
X
X
X/***************************************************************************
X
X   Data defining the plotter's status.
X
X***************************************************************************/
X
X
X				    /* Current plotting pen's coordinates */
XCoordinatePair PenPosition = { Zero, Zero };
X
X                                     /* Pn's position in User Space */
Xstatic CoordinatePair UserP1, UserP2;
X
X                                     /* Pn's coords in Plotter Space */
XCoordinatePair PlotterP1, PlotterP2;
X
X				     /* P1-P2 distance              */
XNumber      P1P2Diagonal;
X
X				     /* Size of paper in use        */
Xstatic int	    PaperSize = A4;
X
Xstatic Number LineType;            /* Line type used for stroking */
Xstatic Number LinePatternLength;   /* Length of a pattern cicle   */
Xstatic Number PenHeld = Zero;      /* Pen we're holding           */
X
X
X       Boolean UserMode = False;     /* Plotting in User Space?           */
Xstatic Boolean Rotated = False;      /* Is the plot rotated 90 degrees?   */
X       Boolean PenIsUp = True;       /* Is the plotting pen up?           */
Xstatic Boolean LineDrawn = False;    /* Have we drawn a line?		  */
X
XCoordinatePair FurthestPoint[] = { { MaxXA,  MaxYA },
X                                   { MaxXA4, MaxYA4 },
X                                   { MaxXB,  MaxYB },
X                                   { MaxXA3, MaxXA3 } };
X
XCoordinatePair FurthestPointRotated[] =
X                                 { { MaxYA,  MaxXA },
X                                   { MaxYA4, MaxXA4 },
X                                   { MaxYB,  MaxXB },
X                                   { MaxXA3, MaxXA3 } };
X
XCoordinatePair DefaultP1[] = { {InitialP1XA,  InitialP1YA},
X			       {InitialP1XA4, InitialP1YA4},
X			       {InitialP1XB,  InitialP1YB},
X			       {InitialP1XA3, InitialP1YA3} };
X
XCoordinatePair DefaultP2[] = { {InitialP2XA,  InitialP2YA},
X			       {InitialP2XA4, InitialP2YA4},
X			       {InitialP2XB,  InitialP2YB},
X			       {InitialP2XA3, InitialP2YA3} };
X
XCoordinatePair DefaultP1Rotated[] =
X                             { {InitialP1XAR,  InitialP1YAR},
X			       {InitialP1XA4R, InitialP1YA4R},
X			       {InitialP1XBR,  InitialP1YBR},
X			       {InitialP1XA3R, InitialP1YA3R} };
X
XCoordinatePair DefaultP2Rotated[] =
X                             { {InitialP2XAR,  InitialP2YAR},
X			       {InitialP2XA4R, InitialP2YA4R},
X			       {InitialP2XBR,  InitialP2YBR},
X			       {InitialP2XA3R, InitialP2YA3R} };
X
X
X/**************************************************************************
X
X   Paper size.
X
X/*************************************************************************/
X
X
Xvoid changePaperSize(newPaperSize)
X
Xint newPaperSize;
X
X{ PaperSize = newPaperSize; }
X
X
X
X/***************************************************************************
X
X   Pen changing.
X
X***************************************************************************/
X
X/*
X
X  Each pen's width and color.
X
X*/
X  
Xstatic Number PenWidth[MaxPen/One] = { 2500, 3500, 5000,
X				       7500, 10000, 20000 };
Xstatic Number PenColor[MaxPen/One] = { Zero, Zero, Zero, Zero, Zero, Zero };
X
X
X
X/*
X
X  Change the pen sizes.
X
X*/
X
Xvoid getPenSizes(string)
X
Xchar *string;
X
X{ int i;
X
X  i = 0;
X  while (*string && (i < (MaxPen/One)))
X    if (!ASCIIToNumber(&PenWidth[i++], &string))
X      error("Illegal pen width.");
X}
X
X
X
X/*
X
X  Get a new pen
X
X */
X
Xvoid changePen(pen)
X
XNumber pen;
X
X{ Boolean penWasDown;
X  int oldPen;
X
X  if (pen == PenHeld)
X    return;
X  if ((penWasDown = !PenIsUp)) liftPen();
X  if ((pen > Zero) && (pen <= MaxPen))
X  { oldPen = (PenHeld/One) - 1;
X    PenHeld = pen;
X    pen = (pen / One ) - 1;
X    if (PenWidth[pen] != PenWidth[oldPen])
X      setPenWidth(PenWidth[pen]);
X    if (PenColor[pen] != PenColor[oldPen])
X      setPenColor(PenColor[pen]);
X  }
X  else if (!pen)
X    PenHeld = Zero;
X  else
X    warning("Pen number out of range.");
X  if (penWasDown) lowerPen();
X}
X
X
X
X/*
X
X  Update the pattern to new parameters.
X
X*/
X
Xstatic void updateLinePattern()
X
X{ Boolean penWasDown;
X
X  if ((penWasDown = !PenIsUp)) liftPen();
X  setPattern(LineType, mulNum(LinePatternLength, P1P2Diagonal)/100);
X  if (penWasDown) lowerPen();
X}
X
X
X
X/*
X
X  Change the line pattern
X
X */
X
Xvoid setDash(pattern, patternLength)
X
XNumber pattern, patternLength;
X
X{ Boolean penWasDown;
X
X  if ((LineType == pattern) &&
X      ((patternLength <= 0) ||
X       (patternLength >= (128*One)) ||
X       (patternLength == LinePatternLength)))
X    return;
X  if ((patternLength > 0) && (patternLength < (128*One)))
X    LinePatternLength = patternLength;
X  LineType = pattern;
X  updateLinePattern();
X}
X
X
X
X/**************************************************************************
X
X   Clipping rectangle.
X
X**************************************************************************/
X
Xstatic CoordinatePair Origin = { Zero, Zero };
X
X
X/*
X
X  Set a new clipping rectangle.
X
X*/
X
Xvoid setWindow(corner1, corner2)
X
XCoordinatePair corner1, corner2;
X
X{ setClip(corner1, corner2); }
X
X
X
X/*
X
X  Set the clipping rectangle to the whole plotting area.
X
X*/
X
Xvoid resetWindow()
X
X{ 
X  if (Rotated)
X    setWindow(Origin, FurthestPointRotated[PaperSize]);
X  else
X    setWindow(Origin, FurthestPoint[PaperSize]);
X}
X
X
X
X/**************************************************************************
X
X  Scaling of User Space.
X
X**************************************************************************/
X
X
X/* Parameters for scaling */
X
XNumber XScaleFactor = One, YScaleFactor = One;
XNumber XOrigin = Zero, YOrigin = Zero;
X
X
X
X/*
X
X  Convert from plotter coordinates to user coordinates.
X
X*/
X
Xstatic void plotterToUser(target, plotterPoint)
X
XCoordinatePair target, plotterPoint;
X
X{
X  target[X] = divNum(plotterPoint[X] - XOrigin, XScaleFactor);
X  target[Y] = divNum(plotterPoint[Y] - YOrigin, YScaleFactor);
X}
X
X
X
X/*
X
X  Set the scaling parameters to the appropriate values.
X
X*/
X
Xvoid updateScaling()
X
X{ CoordinatePair plotterPenPosition;
X
X  if (UserMode)
X  { plotterPenPosition[X] = plotterXCoord(PenPosition[X]);
X    plotterPenPosition[Y] = plotterYCoord(PenPosition[Y]);
X    XScaleFactor = divNum((PlotterP2[X] - PlotterP1[X]),
X                          (UserP2[X] - UserP1[X]));
X    XOrigin = PlotterP1[X] - mulNum(XScaleFactor, UserP1[X]);
X    YScaleFactor = divNum((PlotterP2[Y] - PlotterP1[Y]),
X                          (UserP2[Y] - UserP1[Y]));
X    YOrigin = PlotterP1[Y] - mulNum(YScaleFactor, UserP1[Y]);
X    plotterToUser(PenPosition, plotterPenPosition);
X  }
X}
X
X
X
X/*
X
X  From now on, coordinates won't be scaled any more.
X
X*/
X
Xvoid turnScalingOff()
X
X{ PenPosition[X] = plotterXCoord(PenPosition[X]);
X  PenPosition[Y] = plotterYCoord(PenPosition[Y]);
X  UserMode = False;
X}
X
X
X
X/*
X
X  From now on, coordinates will be scaled according to the user's taste.
X
X*/
X
Xvoid turnScalingOn(newUserP1, newUserP2)
X
XCoordinatePair newUserP1, newUserP2;
X
X{ if ((newUserP1[X] == newUserP2[X]) || (newUserP1[Y] == newUserP2[Y]))
X    warning("Invalid scale parameters.");
X  else
X  { UserMode = True;
X    UserP1[X] = newUserP1[X];
X    UserP1[Y] = newUserP1[Y];
X    UserP2[X] = newUserP2[X];
X    UserP2[Y] = newUserP2[Y];
X    updateScaling();
X  }
X}
X
X
X
X/*
X
X  Change the scaling points and update everything needed.
X
X*/
X
Xvoid changeP1P2(newP1, newP2)
X
XCoordinatePair newP1, newP2;
X
X{ Number dummy;
X  CoordinatePair delta;
X  
X  PlotterP1[X] = newP1[X];
X  PlotterP1[Y] = newP1[Y];
X  PlotterP2[X] = newP2[X];
X  PlotterP2[Y] = newP2[Y];
X  delta[X] = PlotterP2[X] - PlotterP1[X];
X  delta[Y] = PlotterP2[Y] - PlotterP1[Y];
X  cartesianToPolar(&P1P2Diagonal, &dummy, delta);
X  updateScaling();
X  updateTicks();
X  updateLinePattern();
X}
X
X
X
X/*
X
X  Rotate the coordinate system.
X
X*/
X
Xvoid rotate()
X
X{ CoordinatePair plotterPenPosition;
X  
X  if (!Rotated)
X  { plotterPenPosition[Y] = plotterXCoord(PenPosition[X]);
X    plotterPenPosition[X] = FurthestPoint[PaperSize][Y] -
X                                plotterYCoord(PenPosition[Y]);
X    plotterToUser(PenPosition, plotterPenPosition);
X    doRotation();
X    correctClip();
X    Rotated = True;
X  }
X}
X
X
X
X/*
X
X  Return paper to default orientation.
X
X*/
X
Xvoid unRotate()
X
X{ CoordinatePair plotterPenPosition;
X  
X  if (Rotated)
X  { plotterPenPosition[X] = plotterYCoord(PenPosition[Y]);
X    plotterPenPosition[Y] = FurthestPoint[PaperSize][Y] -
X                                plotterXCoord(PenPosition[X]);
X    plotterToUser(PenPosition, plotterPenPosition);
X    undoRotation();
X    correctClip();
X    Rotated = False;
X  }
X}
X
X
X/**************************************************************************
X
X  Plotter status initialization.
X
X**************************************************************************/
X
X
X
X/*
X
X  Set the scaling points to the default values.
X
X*/
X
Xvoid resetP1P2()
X
X{ if (Rotated)
X    changeP1P2(DefaultP1Rotated[PaperSize], DefaultP2Rotated[PaperSize]);
X  else
X    changeP1P2(DefaultP1[PaperSize], DefaultP2[PaperSize]);
X}
X
X
X/*
X
X  Set default parameters of this module's stuff.
X
X*/
X
Xvoid penctrlInit()
X
X{ liftPen();
X  resetP1P2();
X  unRotate();
X}
X
X
X
X/**************************************************************************
X
X  Moving the pen around.
X
X**************************************************************************/
X
X
X
X/*
X
X  Move the logical pen in it's current state to some place in User Space.
X
X*/
X
Xvoid doLine(targetX, targetY)
X
XNumber targetX, targetY;
X
X{ Number absoluteTargetX, absoluteTargetY;
X
X  if (!PenIsUp && PenHeld)
X  { LineDrawn = True; 
X    if (LineType)
X      drawLine(plotterXCoord(targetX),
X               plotterYCoord(targetY));
X    else			/* Linetype 0: just dots at coords */
X    { liftPen();
X      PenPosition[X] = targetX;
X      PenPosition[Y] = targetY;
X      lowerPen();
X      return;
X    }
X  }
X  PenPosition[X] = targetX;
X  PenPosition[Y] = targetY;
X}
X
X
X
X/*
X
X  Lift the plotting pen.
X
X*/
X
Xvoid liftPen()
X
X{ if (!PenIsUp)
X  { if (LineDrawn)
X      LineDrawn = False;
X    else
X      if (PenHeld)
X        drawDot();
X    stroke();
X    PenIsUp = True;
X  }
X}
X
X
X
X/*
X
X  Lower the plotting pen. At least a dot is plotted.
X
X*/
X
Xvoid lowerPen()
X
X{ if (PenIsUp)
X  { setCurrentPoint(plotterXCoord(PenPosition[X]),
X                    plotterYCoord(PenPosition[Y]));
X    PenIsUp = False;
X  }
X}
END_OF_FILE
if test 11891 -ne `wc -c <'penctrl.c'`; then
    echo shar: \"'penctrl.c'\" unpacked with wrong size!
fi
# end of 'penctrl.c'
fi
echo shar: End of archive 5 \(of 6\).
cp /dev/null ark5isdone
MISSING=""
for I in 1 2 3 4 5 6 ; do
    if test ! -f ark${I}isdone ; then
	MISSING="${MISSING} ${I}"
    fi
done
if test "${MISSING}" = "" ; then
    echo You have unpacked all 6 archives.
    rm -f ark[1-9]isdone
else
    echo You still need to unpack the following archives:
    echo "        " ${MISSING}
fi
##  End of shell archive.
exit 0