#include <string.h>
#include <math.h>
#include "grafprt.h"
#include "grafstr.h"

#define PI 3.141592653589793238

/*--------------------------------------------------------------------*/
/*  module grafstr.c in turbo c version 2.0, large code model.        */
/*                                                                    */
/*  a set of graphics string routines for high-resolution printer     */
/*  graphics on epson FX, LX and other IBM Graphics Printer           */
/*  compatibles.  it is intented for use with module grafprt.         */
/*  the whole thing is a bit of a kludge, but it will work if you     */
/*  don't have anything better.                                       */
/*                                                                    */
/*  sample usage:                                                     */
/*                                                                    */
/*  initgrafprt();                                                    */
/*  portrait();                                                       */
/*  frame();                                                          */
/*  defreg(0.0,1.0,0.5,2.0,200,860,700,1500);                         */
/*  framxy();                                                         */
/*  prtstr("This is a test",0.5,1.2,0,4,2);                           */
/*  prntgr(0);                                                        */
/*                                                                    */
/*  released to the public domain by Gregory K. Landheim on January   */
/*  1, 1989, (c) all rights reserved.  anybody is authorized to use   */
/*  this code for any purpose whatsoever on the condition that they   */
/*  realize I assume absolutely no liability and give no warrantee    */
/*  for its use or performance.  it is distributed "as is", and if    */
/*  you use it you assume full liability for its use.                 */
/*                                                                    */
/*--------------------------------------------------------------------*/
/*                                                                    */
/*  aspect_and_                                                       */
/*  rotate()     aspect ratio correction and rotation for strings.    */
/*  swapmode()   swaps between portrait and landscape modes.          */
/*  intprntstr() prints a string at (ix,iy) in integer world coords.  */
/*  prtstr()     prints a string at (x,y) in real world coordinates.  */
/*                                                                    */
/*--------------------------------------------------------------------*/

float Cos_rot,Sin_rot;

/*--------------------------------------------------------------------*/
/*     The global array, F, is a font description table for drawing   */
/*     vector graphics characters.  The characters form a 5 by 10     */
/*     matrix:                                                        */
/*                                                                    */
/*     0  1  2  3  4       ---         A B C D E                      */
/*     5  6  7  8  9        |          F G H I J                      */
/*    10 11 12 13 14        |          K L M N O                      */
/*    15 16 17 18 19        |          P Q R S T                      */
/*    20 21 22 23 24        |          U V W X Y                      */
/*    25 26 27 28 29        |          Z [ \ ] ^                      */
/*    30 31 32 33 34       ---         _ ` a b c                      */
/*    35 36 37 38 39                   d e f g h                      */
/*    40 41 42 43 44                   i j k l m                      */
/*    45 46 47 48 49                   n o p q r                      */
/*                                                                    */
/*    Each position in the 5 by 10 grid is represented by a number    */
/*    which has an equivalent ascii character representation.  In the */
/*    example given above, the letter 'I' is drawn by drawing the     */
/*    lines  1-3, 2-32, 31-33.  This translates to the ascii charac-  */
/*    ters B-D, C-a, `-b.  Thus, the character 'I' is represented by  */
/*    the string "BDCa`b".  The rest of the printable ascii characters*/
/*    are likewise represented below.                                 */
/*--------------------------------------------------------------------*/

static char *F[94] = {
/*   */   "",
/* ! */   "CW\\a",
/* " */   "BLDN",
/* # */   "B`DbKOUY",
/* $ */   "OIIGGKKQQSSYY]][[UCa",
/* % */   "BFFLLHHBBEE_X\\\\bb^^X",
/* & */   "Yaa``ZZUUIIDDCCGGLLc",
/* ' */   "CHHL",
/* ( */   "DGG[[b",
/* ) */   "BII]]`",
/* * */   "CaF^JZ",
/* + */   "H\\PT",
/* , */   "affj",
/* - */   "PT",
/* . */   "`a",
/* / */   "E_",
/* 0 */   "BFFZZ``bb^^JJDDB",
/* 1 */   "GCCa`b",
/* 2 */   "FBBDDJJOOZZ__c",
/* 3 */   "FBBDDJJOOSSQSYY^^bb``Z",
/* 4 */   "YUUDDbac",
/* 5 */   "EAAKKNNTT^^bb``Z",
/* 6 */   "JDDBBFFZZ``bb^^YYSSQQU",
/* 7 */   "FAAEEZZ_",
/* 8 */   "BFFKKQQUUZZ``bb^^YYSSOOJJDDBQS",
/* 9 */   "TQQKKFFBBDDJJ^^bb``Z",
/* : */   "MR\\a",
/* ; */   "RWaffj",
/* < */   "EPPc",
/* = */   "KOUY",
/* > */   "ATT_",
/* ? */   "FBBDDJJOOSSRRW\\a",
/* @ */   "c``ZZFFBBDDJJYYVVLLN",
/* A */   "_CCcQS",
/* B */   "_AADDJJOOSSPSYY^^bb_",
/* C */   "JDDBBFFZZ``bb^",
/* D */   "_AADDJJ^^bb_",
/* E */   "EAA__cPR",
/* F */   "EAA_PR",
/* G */   "JDDBBFFZZ``bb^^YYX",
/* H */   "A_EcPT",
/* I */   "BDCa`b",
/* J */   "CED]]aa``Z",
/* K */   "A_EPPc",
/* L */   "A__cc^",
/* M */   "_AARREEc",
/* N */   "_AAccE",
/* O */   "BFFZZ``bb^^JJDDB",
/* P */   "_AADDJJOOSSP",
/* Q */   "BFFZZ``bb^^JJDDB]h",
/* R */   "_AADDJJOOSSPRc",
/* S */   "JDDBBFFKKQQSSYY^^bb``Z",
/* T */   "AECa",
/* U */   "AZZ``bb^^E",
/* V */   "AaaE",
/* W */   "A__WWccE",
/* X */   "Ac_E",
/* Y */   "ARRERa",
/* Z */   "AEE__c",
/* [ */   "CBB``a",
/* \ */   "Ac",
/* ] */   "CDDbba",
/* ^ */   "KCCO",
/* _ */   "dh",
/* ` */   "CHHN",
/* a */   "PLLNNTT^^bb``ZZUUY^c",
/* b */   "A_PSSYY^^bb_",
/* c */   "TNNLLPPZZ``bb^",
/* d */   "EcTQQUUZZ``c",
/* e */   "UYYTTNNLLPPZZ``bb^",
/* f */   "JDDCCGG`PR",
/* g */   "^bb``ZZPPLLNNTTmmqqooi",
/* h */   "A_UQQSSYYc",
/* i */   "Ra`bCH",
/* j */   "OmmqqooiidEJ",
/* k */   "A_HPPc",
/* l */   "BCCa`b",
/* m */   "_PPLLRRWRNNTTc",
/* n */   "K_PLLNNTTc",
/* o */   "LPPZZ``bb^^TTNNL",
/* p */   "KnPLLNNTT^^bb_",
/* q */   "OrTNNLLPPZZ``c",
/* r */   "K_PLLNNT",
/* s */   "TNNLLPPVVXX^^bb``Z",
/* t */   "C\\\\bb^LN",
/* u */   "KZZ``bb^^O^c",
/* v */   "KaaO",
/* w */   "K__WWccO",
/* x */   "KcO_",
/* y */   "KZZ``bb^^O^mmqqooi",
/* z */   "KOO__c",
/* { */   "DCCGGLLPPVV[[aab",
/* | */   "Ca",
/* } */   "BCCIINNTTXX]]aa`"};

/*--------------------------------------------------------------------*/
/*                                                                    */
/*  void aspect_and_rotate(int angle,int ix0,int iy0,                 */
/*                         int *ix2,int *iy2)                         */
/*                                                                    */
/*  Rotates a character string pixel located at integer position      */
/*  (ix2,iy2) through an angle, with the pixel at integer position    */
/*  (ix0,iy0) serving as the pivot point.  also performs scaling as a */
/*  function of aspect ratio.                                         */
/*                                                                    */
/*--------------------------------------------------------------------*/

void aspect_and_rotate(int angle,int ix0,int iy0,int *ix2,int *iy2)

{
   extern int Arx,Ary;                  /* declared in module grafprt */

   int idelta_x,idelta_y;
   float delta_x, delta_y;

   idelta_x = *ix2-ix0;
   idelta_y = *iy2-iy0;

/* for the cardinal directions, just exchange coordinates and make    */
/* aspect ratio correction:                                           */

   switch (angle)
     {

     case (90)  :  {
		     *ix2 = ix0 - idelta_y;
		     *iy2 = iy0 + (idelta_x * Ary) / Arx;
		     break;
		   }
     case (180)  :  {
		      *ix2 = ix0 - idelta_x;
		      *iy2 = iy0 - (idelta_y * Ary) / Arx;
		      break;
		    }
     case (270)  :  {
		      *ix2 = ix0 + idelta_y;
		      *iy2 = iy0 - (idelta_x * Ary) / Arx;
		      break;
		    }
     case (0)    :
     case (360)  :  {
		      *ix2 = ix0 + idelta_x;
		      *iy2 = iy0 + (idelta_y * Ary) / Arx;
		      break;
		    }

     default     :  {
		      delta_x = idelta_x*Cos_rot - idelta_y*Sin_rot;
		      delta_y = idelta_y*Cos_rot + idelta_x*Sin_rot;
		      *ix2     = ix0 + (int) delta_x;
		      *iy2     = iy0 + (int) ((delta_y * Ary) / Arx);
		      break;
		    }
   } /* end, case of angle */

}  /* void aspect_and_rotate() */

/*--------------------------------------------------------------------*/
/*                                                                    */
/*  void swapmode(int toportrait)                                     */
/*                                                                    */
/*  The string routines were designed for portrait mode.  When used   */
/*  in landscape mode the easiest kludge I came up with involved      */
/*  swapping the appropriate globals from module grafprt and doing    */
/*  the string drawing in portrait mode, after a suitable rotation,   */
/*  performed in the calling function.                                */
/*  It is called either to switch to portrait mode constant values    */
/*  or to switch back to landscape mode constants.                    */
/*                                                                    */
/*--------------------------------------------------------------------*/

void swapmode(int toportrait)

{
/* externals are declared in module grafprt                           */

   extern int IX_min,IX_max,IY_min,IY_max,IDw,IDh,Maxheight;
   extern float X_min,X_max,Y_min,Y_max,Dw,Dh;

   int temp1,temp2;
   float temp;

   if (toportrait)
     {
       temp1 = IX_min;
       temp2 = IX_max;

       IX_min = IY_min;
       IX_max = IY_max;

       IY_min = Maxheight - temp2;
       IY_max = Maxheight - temp1;
     }
   else
     {
       temp1 = IY_min;
       temp2 = IY_max;

       IY_min = IX_min;
       IY_max = IX_max;

       IX_min = Maxheight - temp2;
       IX_max = Maxheight - temp1;
     }

   temp = X_min;
   X_min = Y_min;
   Y_min = temp;

   temp = X_max;
   X_max = Y_max;
   Y_max = temp;

   Dw  = X_max - X_min;
   Dh  = Y_max - Y_min;

   IDw = IX_max - IX_min;
   IDh = IY_max - IY_min;

}  /* void swapmode() */

/*--------------------------------------------------------------------*/
/*                                                                    */
/*  void intprntstr(char *astring,int ix0,int iy0,                    */
/*                  int angle,int size,int center)                    */
/*                                                                    */
/*  Prints a string of ASCII characters (ASCII 32 through 125) at     */
/*  integer world position (ix0,iy0).                                 */
/*                                                                    */
/*  initgrafprt() must be called before calling intprntstr()          */
/*  defreg() must be called before calling intprntstr()               */
/*  colorset() must be called before calling intprntstr()             */
/*                                                                    */
/*--------------------------------------------------------------------*/
/*                                                                    */
/*  char *astring  String of ASCII characters to draw.                */
/*  int   ix0      X-coordinate at which to print string.             */
/*  int   iy0      Y-coordinate at which to print string.             */
/*  int   angle    Angle (in degrees) through which to rotate the     */
/*                 string counterclockwise from the x-axis.           */
/*  int   size     size of character to draw. 1 through whatever.     */
/*  int   center   Determines how to center the string with respect   */
/*                 to the integer world coordinates (ix0,iy0).        */
/*                 = 0 : (ix0,iy0) is center of left edge of string.  */
/*                 = 1 : (ix0,iy0) is center of string.               */
/*                 = 2 : (ix0,iy0) is center of right edge of string. */
/*                                                                    */
/*--------------------------------------------------------------------*/

void intprntstr(char *astring,int ix0,int iy0,
                int angle,int size,int center)

{
   extern int Arx,Ary;                  /* declared in module grafprt */
   extern int Portrait;                 /* declared in module grafprt */

   int char_num,i;
   int ix,iy,n1,n2;
   int ix1,iy1,ix2,iy2;
   int string_length;
   int character;
   int nypixels,npixels;
   int char_spacing;
   float theta;
   int savmode,swapped;

   swapped = 0;
   if (!Portrait)
     {
       savmode = Portrait;
       Portrait = 1;
       swapped = 1;
       angle = angle + 270;
       swapmode(1);
     }

   char_spacing = 6;
   string_length = (int)strlen(astring);

   theta = angle * PI / 180.0;         /* converts degrees to radians */

/* get the (global) rotation parameters:                              */

   Sin_rot = (float) sin(theta);
   Cos_rot = (float) cos(theta);

/* perform the string centering by moving the string pivot point as   */
/* a function of 'theta' and 'center':                                */

   switch (center)
     {
      case (1) : {
                   npixels = size * (char_spacing * string_length - 2);
                   nypixels = (npixels * Ary) / Arx;
                   iy0 = iy0 - nypixels * Sin_rot / 2;
                   ix0 = ix0 - npixels  * Cos_rot / 2;
                   break;
                  }
      case (2) : {
                   npixels = size * (char_spacing * string_length - 2);
                   nypixels = (int)((npixels * Ary) / Arx);
                   iy0 = iy0 - nypixels * Sin_rot;
                   ix0 = ix0 - npixels  * Cos_rot;
                   break;
                 }
     } /* case of center  */

   iy  = iy0 + (int)(((3 * size * Ary) * Cos_rot) / Arx);
   ix0 = ix0 - (int)((3 * size) * Sin_rot);

/* plot the characters one at a time, looping over the string         */

   for (character=0; character<string_length; character++)
     {
       char_num = astring[character] - 32;
       ix = ix0 + character * size * char_spacing;

       i = 0;
       while (F[char_num][i])
	 {
	   n1 = F[char_num][i++] - 65;
	   n2 = F[char_num][i++] - 65;

	   ix1 = ix + (n1 % 5) * size;
	   iy1 = iy - (n1 / 5) * size;
	   ix2 = ix + (n2 % 5) * size;
	   iy2 = iy - (n2 / 5) * size;

	   aspect_and_rotate(angle,ix0,iy,&ix1,&iy1);
           itransf(&ix1,&iy1);

	   aspect_and_rotate(angle,ix0,iy,&ix2,&iy2);
           itransf(&ix2,&iy2);

	   iprtln(ix1,iy1,ix2,iy2);
	 }
     }
   if (swapped)
     {
       Portrait = savmode;
       swapmode(0);
     }
}  /* void intprntstr() */

/*--------------------------------------------------------------------*/
/*                                                                    */
/*  void prtstr(char *astring,float x,float y,                        */
/*              int angle,int size,int center)                        */
/*                                                                    */
/*  Plots a string of characters (ascii numbers 32 through 125,       */
/*  inclusive) at real world position (x,y).                          */
/*                                                                    */
/*  initgrafprt() must be called before calling prtstr()              */
/*  defreg() must be called before calling prtstr()                   */
/*  colorset() must be called before calling prtstr()                 */
/*                                                                    */
/*--------------------------------------------------------------------*/
/*                                                                    */
/*  char *Astring  String of ASCII characters to draw.                */
/*  float x        X-coordinate at which to print string.             */
/*  float y        Y-coordinate at which to print string.             */
/*  int   angle    Angle (in degrees) through which to rotate the     */
/*                 string counterclockwise.                           */
/*  int   size     size of character to draw.  1 through whatever.    */
/*  int   center   Determines how to center the string with respect   */
/*                 to the integer world coordinates (ix0,iy0).        */
/*                 = 0 : (ix0,iy0) is center of left edge of string.  */
/*                 = 1 : (ix0,iy0) is center of string.               */
/*                 = 2 : (ix0,iy0) is center of right edge of string. */
/*                                                                    */
/*--------------------------------------------------------------------*/

void prtstr(char *astring,float x,float y,int angle,int size,int center)

{
   int ix,iy,savmode;

/* convert real world coordinates, (x,y) to integer world             */
/* coordinates (ix,iy):                                               */

   if (!Portrait)
     {
       savmode = Portrait;
       Portrait = 1;
       swapmode(1);
       transf(y,X_max - x,&ix,&iy);
       swapmode(0);
       Portrait = savmode;
     }
   else
     transf(x,y,&ix,&iy);

/* call the integer world coordinate character drawing function:      */

   intprntstr(astring,ix,iy,angle,size,center);

}  /* void prtstr() */

/*-------------------------end of module grafstr----------------------*/


