/*
FILE:     plot.C
*/
/*
VERSION:  1.600
*/
/*
DATE:     2/3/2005
*/
/*
  Comments and Questions to: sw-help@rcsb.rutgers.edu
*/
/*
COPYRIGHT 1999-2005 Rutgers - The State University of New Jersey

This software is provided WITHOUT WARRANTY OF MERCHANTABILITY OR
FITNESS FOR A PARTICULAR PURPOSE OR ANY OTHER WARRANTY, EXPRESS OR
IMPLIED.  RUTGERS MAKE NO REPRESENTATION OR WARRANTY THAT THE
SOFTWARE WILL NOT INFRINGE ANY PATENT, COPYRIGHT OR OTHER
PROPRIETARY RIGHT.

The user of this software shall indemnify, hold harmless and defend
Rutgers, its governors, trustees, officers, employees, students,
agents and the authors against any and all claims, suits,
losses, liabilities, damages, costs, fees, and expenses including
reasonable attorneys' fees resulting from or arising out of the
use of this software.  This indemnification shall include, but is
not limited to, any and all claims alleging products liability.
*/
/*
               PDB SOFTWARE LICENSE AGREEMENT

BY CLICKING THE ACCEPTANCE BUTTON OR INSTALLING OR USING 
THIS "SOFTWARE, THE INDIVIDUAL OR ENTITY LICENSING THE  
SOFTWARE ("LICENSEE") IS CONSENTING TO BE BOUND BY AND IS 
BECOMING A PARTY TO THIS AGREEMENT.  IF LICENSEE DOES NOT 
AGREE TO ALL OF THE TERMS OF THIS AGREEMENT
THE LICENSEE MUST NOT INSTALL OR USE THE SOFTWARE.

1. LICENSE AGREEMENT

This is a license between you ("Licensee") and the Protein Data Bank (PDB) 
at Rutgers, The State University of New Jersey (hereafter referred to 
as "RUTGERS").   The software is owned by RUTGERS and protected by 
copyright laws, and some elements are protected by laws governing 
trademarks, trade dress and trade secrets, and may be protected by 
patent laws. 

2. LICENSE GRANT

RUTGERS grants you, and you hereby accept, non-exclusive, royalty-free 
perpetual license to install, use, modify, prepare derivative works, 
incorporate into other computer software, and distribute in binary 
and source code format, or any derivative work thereof, together with 
any associated media, printed materials, and on-line or electronic 
documentation (if any) provided by RUTGERS (collectively, the "SOFTWARE"), 
subject to the following terms and conditions: (i) any distribution 
of the SOFTWARE shall bind the receiver to the terms and conditions 
of this Agreement; (ii) any distribution of the SOFTWARE in modified 
form shall clearly state that the SOFTWARE has been modified from 
the version originally obtained from RUTGERS.  

2. COPYRIGHT; RETENTION OF RIGHTS.  

The above license grant is conditioned on the following: (i) you must 
reproduce all copyright notices and other proprietary notices on any 
copies of the SOFTWARE and you must not remove such notices; (ii) in 
the event you compile the SOFTWARE, you will include the copyright 
notice with the binary in such a manner as to allow it to be easily 
viewable; (iii) if you incorporate the SOFTWARE into other code, you 
must provide notice that the code contains the SOFTWARE and include 
a copy of the copyright notices and other proprietary notices.  All 
copies of the SOFTWARE shall be subject to the terms of this Agreement.  

3. NO MAINTENANCE OR SUPPORT; TREATMENT OF ENHANCEMENTS 

RUTGERS is under no obligation whatsoever to: (i) provide maintenance 
or support for the SOFTWARE; or (ii) to notify you of bug fixes, patches, 
or upgrades to the features, functionality or performance of the 
SOFTWARE ("Enhancements") (if any), whether developed by RUTGERS 
or third parties.  If, in its sole discretion, RUTGERS makes an 
Enhancement available to you and RUTGERS does not separately enter 
into a written license agreement with you relating to such bug fix, 
patch or upgrade, then it shall be deemed incorporated into the SOFTWARE 
and subject to this Agreement. You are under no obligation whatsoever 
to provide any Enhancements to RUTGERS or the public that you may 
develop over time; however, if you choose to provide your Enhancements 
to RUTGERS, or if you choose to otherwise publish or distribute your 
Enhancements, in source code form without contemporaneously requiring 
end users or RUTGERS to enter into a separate written license agreement 
for such Enhancements, then you hereby grant RUTGERS a non-exclusive,
royalty-free perpetual license to install, use, modify, prepare
derivative works, incorporate into the SOFTWARE or other computer
software, distribute, and sublicense your Enhancements or derivative
works thereof, in binary and source code form.

4. FEES.  There is no license fee for the SOFTWARE.  If Licensee
wishes to receive the SOFTWARE on media, there may be a small charge
for the media and for shipping and handling.  Licensee is
responsible for any and all taxes.

5. TERMINATION.  Without prejudice to any other rights, Licensor
may terminate this Agreement if Licensee breaches any of its terms
and conditions.  Upon termination, Licensee shall destroy all
copies of the SOFTWARE.

6. PROPRIETARY RIGHTS.  Title, ownership rights, and intellectual
property rights in the Product shall remain with RUTGERS.  Licensee 
acknowledges such ownership and intellectual property rights and will 
not take any action to jeopardize, limit or interfere in any manner 
with RUTGERS' ownership of or rights with respect to the SOFTWARE.  
The SOFTWARE is protected by copyright and other intellectual 
property laws and by international treaties.  Title and related 
rights in the content accessed through the SOFTWARE is the property 
of the applicable content owner and is protected by applicable law.  
The license granted under this Agreement gives Licensee no rights to such
content.

7. DISCLAIMER OF WARRANTY.  THE SOFTWARE IS PROVIDED FREE OF 
CHARGE, AND, THEREFORE, ON AN "AS IS" BASIS, WITHOUT WARRANTY OF 
ANY KIND, INCLUDING WITHOUT LIMITATION THE WARRANTIES THAT IT 
IS FREE OF DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE 
OR NON-INFRINGING.  THE ENTIRE RISK AS TO THE QUALITY AND 
PERFORMANCE OF THE SOFTWARE IS BORNE BY LICENSEE.  SHOULD THE 
SOFTWARE PROVE DEFECTIVE IN ANY RESPECT, THE LICENSEE AND NOT 
LICENSOR ASSUMES THE ENTIRE COST OF ANY SERVICE AND REPAIR.  
THIS DISCLAIMER OF WARRANTY CONSTITUTES AN ESSENTIAL PART OF 
THIS AGREEMENT.  NO USE OF THE PRODUCT IS AUTHORIZED HEREUNDER 
EXCEPT UNDER THIS DISCLAIMER.

8. LIMITATION OF LIABILITY.  TO THE MAXIMUM EXTENT PERMITTED BY
APPLICABLE LAW,  IN NO EVENT WILL LICENSOR BE LIABLE FOR ANY 
INDIRECT, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING 
OUT OF THE USE OF OR INABILITY TO USE THE SOFTWARE, INCLUDING, 
WITHOUT LIMITATION, DAMAGES FOR LOSS OF GOODWILL, WORK 
STOPPAGE, COMPUTER FAILURE OR MALFUNCTION, OR ANY AND ALL 
OTHER COMMERCIAL DAMAGES OR LOSSES, EVEN IF ADVISED OF THE
POSSIBILITY THEREOF. 
*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>

#include "plot.h"

static COLOR black = {0.0, 0.0, 0.0};

static void postscript_head(FILE *ps)
{
       fprintf(ps, "%%!PS-Adobe-3.0\n");
       fprintf(ps, "%%%%BoundingBox: (atend)\n");
       fprintf(ps, "%%%%DocumentNeededResources: font Times-Roman Symbol\n");
       fprintf(ps, "%%%%Pages: (atend)\n");
       fprintf(ps, "%%%%EndComments\n");
       fprintf(ps, "%%%%BeginProlog\n");
       fprintf(ps, "/R { setrgbcolor } bind def\n");
       fprintf(ps, "/G { setgray } bind def\n");
       fprintf(ps, "/H { sethsbcolor } bind def\n");
       fprintf(ps, "/LW { setlinewidth } bind def\n");
       fprintf(ps, "/D { 0 setdash 0 setlinecap } bind def\n");
       fprintf(ps, "/ND { [] 0 setdash 1 setlinecap } bind def\n");
       fprintf(ps, "/RS { gsave setrgbcolor } bind def\n");
       fprintf(ps, "/HS { gsave sethsbcolor } bind def\n");
       fprintf(ps, "/GS { gsave setgray } bind def\n");
       fprintf(ps, "/M { moveto } bind def\n");
       fprintf(ps, "/L { moveto lineto stroke } bind def\n");
       fprintf(ps, "/PT { 2 copy moveto lineto stroke } bind def\n");
       fprintf(ps, "/SC { 1 G } def\n");
       fprintf(ps, "/SS { newpath 0 360 arc gsave SC fill grestore stroke } bind def\n");
       fprintf(ps, "/SD {\n");
       fprintf(ps, "  3 copy newpath 0 360 arc gsave SC fill 0 setgray 0.5 setlinewidth\n");
       fprintf(ps, "  3 copy 0.94 mul 260 350 arc stroke 3 copy 0.87 mul 275 335 arc stroke\n");
       fprintf(ps, "  3 copy 0.79 mul 295 315 arc stroke 3 copy 0.8 mul 115 135 arc\n");
       fprintf(ps, "  3 copy 0.6 mul 135 115 arcn closepath gsave 1 setgray fill grestore stroke\n");
       fprintf(ps, "  3 copy 0.7 mul 115 135 arc stroke 3 copy 0.6 mul 124.9 125 arc\n");
       fprintf(ps, "  0.8 mul 125 125.1 arc stroke grestore stroke\n");
       fprintf(ps, " } bind def\n");
       fprintf(ps, "/T { moveto lineto lineto fill grestore } bind def\n");
       fprintf(ps, "/TB { moveto lineto lineto closepath stroke grestore } bind def\n");
       fprintf(ps, "/T1 { 4 copy 10 4 roll T moveto lineto stroke } bind def\n");
       fprintf(ps, "/B { moveto lineto lineto lineto closepath stroke grestore } bind def\n");
       fprintf(ps, "/P { moveto lineto lineto lineto fill grestore } bind def\n");
       fprintf(ps, "/P1 { 4 copy 12 4 roll P moveto lineto stroke } bind def\n");
       fprintf(ps, "/P2 { 8 2 roll P1 } bind def\n");
       fprintf(ps, "/P3 { 8 4 roll P1 } bind def\n");
       fprintf(ps, "/P4 { 8 -2 roll P1 } bind def\n");
       fprintf(ps, "/P12 { 8 copy P moveto lineto lineto stroke pop pop } bind def\n");
       fprintf(ps, "/P13 { 8 copy P moveto lineto moveto lineto stroke } bind def\n");
       fprintf(ps, "/P14 { 8 copy P 8 -2 roll moveto lineto lineto stroke pop pop } bind def\n");
       fprintf(ps, "/P23 { 8 2 roll P12 } bind def\n");
       fprintf(ps, "/P34 { 8 4 roll P12 } bind def\n");
       fprintf(ps, "/P123 { 8 copy P moveto lineto lineto lineto stroke } bind def\n");
       fprintf(ps, "/P134 { 8 copy P 4 2 roll moveto lineto 4 2 roll lineto lineto stroke } bind def\n");
       fprintf(ps, "/P1234 { 8 copy P moveto lineto lineto lineto closepath stroke } bind def\n");
       fprintf(ps, "/FR { /Times-Roman findfont } bind def\n");
       fprintf(ps, "/FG { /Symbol findfont } bind def\n");
       fprintf(ps, "/PR { scalefont setfont show } bind def\n");
       fprintf(ps, "/C {\n");
       fprintf(ps, "  1 index scalefont setfont\n");
       fprintf(ps, "  exch stringwidth pop -2 div exch -3 div rmoveto\n");
       fprintf(ps, " } bind def\n");
       fprintf(ps, "/CR90 {\n");
       fprintf(ps, "  1 index scalefont setfont\n");
       fprintf(ps, "  exch stringwidth pop -2 div exch 3 div exch rmoveto\n");
       fprintf(ps, " } bind def\n");
       fprintf(ps, "/R90 { gsave currentpoint translate 90 rotate } bind def\n");
       fprintf(ps, "/PRB { gsave setlinewidth 3 copy scalefont setfont\n");
       fprintf(ps, "  false charpath BC stroke grestore } bind def\n");
       fprintf(ps, "/EA {\n");
       fprintf(ps, "  matrix currentmatrix 8 1 roll 7 -2 roll translate\n");
       fprintf(ps, "  4 -1 roll rotate 3 -1 roll 1 scale 0 0 5 2 roll arc setmatrix\n");
       fprintf(ps, " } bind def\n");
       fprintf(ps, "/SP { moveto lineto -90 90 EA closepath gsave } bind def\n");
       fprintf(ps, "/SF { fill grestore stroke } bind def\n");
       fprintf(ps, "%%%%EndProlog\n");
       fprintf(ps, "%%%%BeginSetup\n");
       fprintf(ps, "%%%%IncludeResource: font Times-Roman\n");
       fprintf(ps, "%%%%IncludeResource: font Symbol\n");
       fprintf(ps, "%%%%EndSetup\n");
       fprintf(ps, "save\n");
}

void _plot::axes(const double xlim1, const double xlim2, const double ylim1,
          const double ylim2, const int nptsx, const int nptsy, const double xmin,
          const double xmax, const double ymin, const double ymax,
          const double sizlab, const int intrl_x, const int intrl_y, const double tsize)
{
       int i, imark, ivalue, len;
       double xgap = 0, ugap = 0, ygap = 0, vgap = 0, x, y, value, y1, y2, x1, x2;
       char label[10];

       if (nptsx > 0) {
           xgap = (xlim2 - xlim1) / nptsx;
           ugap = (xmax - xmin) / nptsx;
       }
       if (nptsy > 0) {
           ygap = (ylim2 - ylim1) / nptsy;
           vgap = (ymax - ymin) / nptsy;
       }

       setline_width(0.2);
       line(xlim1, ylim1, xlim1, ylim2);
       line(xlim1, ylim2, xlim2, ylim2);
       line(xlim2, ylim2, xlim2, ylim1);
       line(xlim2, ylim1, xlim1, ylim1);

       x = xlim1;
       y = ylim1 - tsize;
       if (nptsx > 0) {
            for (imark = 0; imark <= nptsx; imark++) {
                 value = xmin + (double) imark * ugap;
                 if (value >= 0.0) ivalue = (int) (value + 0.5);
                 else              ivalue = (int) (value - 0.5);
                 if (intrl_x == 0) sprintf(label, "%d", ivalue);
                 else if (intrl_x == 1) sprintf(label, "%6.1f", value);
                 else if (intrl_x == 2) sprintf(label, "%6.2f", value);
                 else if (intrl_x == 3) sprintf(label, "%6.3f", value);
                 len = strlen(label);
                 for (i = 0; i < len; i++)
                      if (label[i] != ' ') break;
                 strcpy(label, &label[i]);
                 y1 = ylim1;
                 y2 = ylim1 - sizlab / 3.0;
                 setfont(FONT_HELVETICA, sizlab, 0.0);
                 wrt_litstr_xy(label, x, y, CENTERX);
                 line(x, y1, x, y2);

                 x += xgap;
            }
       }
       x = xlim1 - tsize / 2.0;
       y = ylim1;
       if (nptsy > 0) {
            for (imark = 0; imark <= nptsy; imark++) {
                 value = ymin + (double) imark* vgap;
                 if (value >= 0.0) ivalue = (int) (value + 0.5);
                 else              ivalue = (int) (value - 0.5);
                 if (intrl_y == 0) sprintf(label, "%d", ivalue);
                 else if (intrl_y == 1) sprintf(label, "%6.1f", value);
                 else if (intrl_y == 2) sprintf(label, "%6.2f", value);
                 else if (intrl_y == 3) sprintf(label, "%6.3f", value);
                 len = strlen(label);
                 for (i = 0; i < len; i++)
                      if (label[i] != ' ') break;
                 strcpy(label, &label[i]);
                 x1 = xlim1 - sizlab / 3.0;
                 x2 = xlim1;
                 setfont(FONT_HELVETICA, sizlab, 0.0);
                 wrt_litstr_xy(label, x, y, RJUSTIFY_CENTERY);
                 line(x1, y, x2, y);
                 y += ygap;
            }
       }
}

static char *escape_special_chars(const char *string)
{
       int i, j = 0, len;
       char special[5], *ok;

       len = strlen(string);
       strcpy(special, "()\\");
       for (i = len; i >=0; i--) if (string[i] > 32) break;
       len = i + 1;

       ok = (char *) malloc(2*len*sizeof(char));
       for (i=0; i < len; i++) {
         if (strchr(special,string[i]) != NULL ) {
           ok[j] = '\\';
           j++;
         }
         ok[j]=string[i];
         j++;
       }
       ok[j] = '\0';
       len = j;
       return(ok);
}

static void display_string(FILE *ps, const char *string, const double font_rotation,
           const double font_size, const int option)
{
     double offset;

     if (font_rotation != 0.0) {
          fprintf(ps, "gsave currentpoint translate\n");
          fprintf(ps, "%12.5f rotate\n", font_rotation);
     }
     switch (option) {
          case LJUSTIFY:
               fprintf(ps, "(%s) show\n",string);
               break;
          case RJUSTIFY:
               fprintf(ps, "(%s) dup stringwidth pop -1.0 mul\n",string);
               fprintf(ps, "0 rmoveto show\n");
               break;
          case RJUSTIFY_CENTERY:
               offset = -font_size / 2.0;
               fprintf(ps, "(%s) dup stringwidth pop -1.0 mul\n",string);
               fprintf(ps, "%12.5f rmoveto show\n",offset);
               break;
          case CENTERX:
               fprintf(ps, "(%s) dup stringwidth pop -0.5 mul\n",string);
               fprintf(ps, "0 rmoveto show\n");
               break;
          case CENTERY:
               offset = -font_size / 2.0;
               fprintf(ps, "(%s) 0.0 %12.5f rmoveto show\n",string,offset);
               break;
          case CENTERXY:
               offset = -font_size / 2.0;
               fprintf(ps, "(%s) dup stringwidth pop -0.5 mul\n",string);
               fprintf(ps, " %12.5f rmoveto show\n",offset);
               break;
     }
     if (font_rotation != 0.0) fprintf(ps, "grestore\n");
}

_plot::_plot()
{
     strcpy(filename, "plot.ps");
     strcpy(x_axis_title, "Phi (degrees)");
     strcpy(y_axis_title, "Psi (degrees)");

     ps = fopen(filename, "w");
     pages = 0;
     is_new_page = 0;
     line_type = LINE_SOLID;
     linewidth = 0.2;
     color.r = color.g = color.b = 0;
     postscript_head(ps);

     user_define_page_xmin = BBOXX1;
     user_define_page_xmax = BBOXX2;
     user_define_page_ymin = BBOXY1;
     user_define_page_ymax = BBOXY2;
     newpage(0);

     user_define_view_xmin = XRAMC1;
     user_define_view_xmax = XRAMC2;
     user_define_view_ymin = YRAMC1;
     user_define_view_ymax = YRAMC2;
     user_define_actual_value_xmin = -180.0;
     user_define_actual_value_xmax =  180.0;
     user_define_actual_value_ymin = -180.0;
     user_define_actual_value_ymax =  180.0;
     x_axis_interval = y_axis_interval = 8;
     x_axis_grid_num = y_axis_grid_num = MAPSIZ;
     x_axis_grid_size = (user_define_view_xmax - user_define_view_xmin)
                      / (double) x_axis_grid_num;
     y_axis_grid_size = (user_define_view_ymax - user_define_view_ymin)
                      / (double) y_axis_grid_num;
     intrlx = intrly = 0;
}

_plot::_plot(const char* file_name, const int head)
{
     strcpy(filename, file_name);
     strcpy(x_axis_title, "Phi (degrees)");
     strcpy(y_axis_title, "Psi (degrees)");

     ps = fopen(filename, "w");
     pages = 0;
     is_new_page = 0;
     line_type = LINE_SOLID;
     linewidth = 0.2;
     color.r = color.g = color.b = 0;
     postscript_head(ps);

     user_define_page_xmin = BBOXX1;
     user_define_page_xmax = BBOXX2;
     user_define_page_ymin = BBOXY1;
     user_define_page_ymax = BBOXY2;
     newpage(head);

     user_define_view_xmin = XRAMC1;
     user_define_view_xmax = XRAMC2;
     user_define_view_ymin = YRAMC1;
     user_define_view_ymax = YRAMC2;
     user_define_actual_value_xmin = -180.0;
     user_define_actual_value_xmax =  180.0;
     user_define_actual_value_ymin = -180.0;
     user_define_actual_value_ymax =  180.0;
     x_axis_interval = y_axis_interval = 8;
     x_axis_grid_num = y_axis_grid_num = MAPSIZ;
     x_axis_grid_size = (user_define_view_xmax - user_define_view_xmin)
                      / (double) x_axis_grid_num;
     y_axis_grid_size = (user_define_view_ymax - user_define_view_ymin)
                      / (double) y_axis_grid_num;
     intrlx = intrly = 0;
}

_plot::_plot(const char* file_name, const double udp_xmin, const double udp_xmax,
                      const double udp_ymin, const double udp_ymax)
{
     strcpy(filename, file_name);
     strcpy(x_axis_title, "Phi (degrees)");
     strcpy(y_axis_title, "Psi (degrees)");

     ps = fopen(filename, "w");
     pages = 0;
     is_new_page = 0;
     line_type = LINE_SOLID;
     linewidth = 0.2;
     color.r = color.g = color.b = 0;
     postscript_head(ps);

     user_define_page_xmin = udp_xmin;
     user_define_page_xmax = udp_xmax;
     user_define_page_ymin = udp_ymin;
     user_define_page_ymax = udp_ymax;
     newpage(0);

     user_define_view_xmin = XRAMC1;
     user_define_view_xmax = XRAMC2;
     user_define_view_ymin = YRAMC1;
     user_define_view_ymax = YRAMC2;
     if (user_define_view_xmin <= user_define_page_xmin) 
          user_define_view_xmin = user_define_page_xmin + 30;
     if (user_define_view_xmax >= user_define_page_xmax)
          user_define_view_xmax = user_define_page_xmax - 30;
     if (user_define_view_ymin <= user_define_page_ymin)
          user_define_view_ymin = user_define_page_ymin + 30;
     if (user_define_view_ymax >= user_define_page_ymax)
          user_define_view_ymax = user_define_page_ymax - 30;
     user_define_actual_value_xmin = -180.0;
     user_define_actual_value_xmax =  180.0;
     user_define_actual_value_ymin = -180.0;
     user_define_actual_value_ymax =  180.0;
     x_axis_interval = y_axis_interval = 8;
     x_axis_grid_num = y_axis_grid_num = MAPSIZ;
     x_axis_grid_size = (user_define_view_xmax - user_define_view_xmin)
                      / (double) x_axis_grid_num;
     y_axis_grid_size = (user_define_view_ymax - user_define_view_ymin)
                      / (double) y_axis_grid_num;
     intrlx = intrly = 0;
}

_plot::_plot(const char* file_name, const double udp_xmin, const double udp_xmax,
           const double udp_ymin, const double udp_ymax, const double ap_xmin,
           const double ap_xmax, const double ap_ymin, const double ap_ymax)
{
     strcpy(filename, file_name);
     strcpy(x_axis_title, "Phi (degrees)");
     strcpy(y_axis_title, "Psi (degrees)");

     ps = fopen(filename, "w");
     pages = 0;
     is_new_page = 0;
     line_type = LINE_SOLID;
     linewidth = 0.2;
     color.r = color.g = color.b = 0;
     postscript_head(ps);

     user_define_page_xmin = udp_xmin;
     user_define_page_xmax = udp_xmax;
     user_define_page_ymin = udp_ymin;
     user_define_page_ymax = udp_ymax;
     newpage(0);

     user_define_view_xmin = XRAMC1;
     user_define_view_xmax = XRAMC2;
     user_define_view_ymin = YRAMC1;
     user_define_view_ymax = YRAMC2;
     if (user_define_view_xmin <= user_define_page_xmin) 
          user_define_view_xmin = user_define_page_xmin + 30;
     if (user_define_view_xmax >= user_define_page_xmax)
          user_define_view_xmax = user_define_page_xmax - 30;
     if (user_define_view_ymin <= user_define_page_ymin)
          user_define_view_ymin = user_define_page_ymin + 30;
     if (user_define_view_ymax >= user_define_page_ymax)
          user_define_view_ymax = user_define_page_ymax - 30;
     user_define_actual_value_xmin = -180.0;
     user_define_actual_value_xmax =  180.0;
     user_define_actual_value_ymin = -180.0;
     user_define_actual_value_ymax =  180.0;
     x_axis_interval = y_axis_interval = 8;
     x_axis_grid_num = y_axis_grid_num = MAPSIZ;
     x_axis_grid_size = (user_define_view_xmax - user_define_view_xmin)
                      / (double) x_axis_grid_num;
     y_axis_grid_size = (user_define_view_ymax - user_define_view_ymin)
                      / (double) y_axis_grid_num;
     intrlx = intrly = 0;
}

void _plot::set_view_xmin_and_max(const double xmin, const double xmax)
{
     user_define_view_xmin = xmin;
     user_define_view_xmax = xmax;
     if (user_define_view_xmin <= user_define_page_xmin) 
          user_define_view_xmin = user_define_page_xmin + 30;
     if (user_define_view_xmax >= user_define_page_xmax)
          user_define_view_xmax = user_define_page_xmax - 30;
     x_axis_grid_size = (user_define_view_xmax - user_define_view_xmin)
                      / (double) x_axis_grid_num;
}

void _plot::set_view_ymin_and_max(const double ymin, const double ymax)
{
     user_define_view_ymin = ymin;
     user_define_view_ymax = ymax;
     if (user_define_view_ymin <= user_define_page_ymin) 
          user_define_view_ymin = user_define_page_ymin + 30;
     if (user_define_view_ymax >= user_define_page_ymax)
          user_define_view_ymax = user_define_page_ymax - 30;
     y_axis_grid_size = (user_define_view_ymax - user_define_view_ymin)
                      / (double) y_axis_grid_num;
}

void _plot::set_actual_value_xmin_and_max(const double xmin, const double xmax)
{
     user_define_actual_value_xmin = xmin;
     user_define_actual_value_xmax = xmax;
}

void _plot::set_actual_value_ymin_and_max(const double ymin, const double ymax)
{
     user_define_actual_value_ymin = ymin;
     user_define_actual_value_ymax = ymax;
}

void _plot::set_axes_grid_num(const int x_grid_num, const int y_grid_num)
{
     x_axis_grid_num = x_grid_num;
     y_axis_grid_num = y_grid_num;
     x_axis_grid_size = (user_define_view_xmax - user_define_view_xmin)
                      / (double) x_axis_grid_num;
     y_axis_grid_size = (user_define_view_ymax - user_define_view_ymin)
                      / (double) y_axis_grid_num;
}

void _plot::set_axes_interval(const int x_interval, const int y_interval)
{
     x_axis_interval = x_interval;
     y_axis_interval = y_interval;
}

void _plot::set_axes_label_precision(const int x_axis, const int y_axis)
{
     intrlx = x_axis; intrly = y_axis;
}

void _plot::draw_view_window(const double xmin, const double xmax, 
              const double ymin, const double ymax, const char *label)
{
     user_define_view_xmin = xmin;
     user_define_view_xmax = xmax;
     user_define_view_ymin = ymin;
     user_define_view_ymax = ymax;
     
     setline_width(0.2);
     box(xmin, ymin, xmax, ymax, black, 0);
     if (strcmp(label, "")) {
          setfont(FONT_HELVETICA, 10, 0.0);
          wrt_litstr_xy(label, xmin+5, ymax-10, LJUSTIFY); 
     }
}

void _plot::draw_view_window(const int draw_grid, const int fonts, 
          const double title_font_size, const double label_font_size, 
          const double x_title_distance, const double y_title_distance,
          const int fill)
{
     int i;
     double tsize, xcenter, ycenter, xgrid, ygrid, x, y;

     tsize = 22.0 * label_font_size / 15.0;
     if (fill) {
          COLOR col;
          get_rgb_color_from_name("cream", col);
          box(user_define_view_xmin, user_define_view_ymin,
             user_define_view_xmax, user_define_view_ymax, col, 1);
     } else box(user_define_view_xmin, user_define_view_ymin,
            user_define_view_xmax, user_define_view_ymax, black, 0);

     axes(user_define_view_xmin, user_define_view_xmax, 
              user_define_view_ymin, user_define_view_ymax,
              x_axis_interval, y_axis_interval, 
              user_define_actual_value_xmin, user_define_actual_value_xmax,
              user_define_actual_value_ymin, user_define_actual_value_ymax,
              /* label_size, */ label_font_size,  intrlx, intrly, tsize);

     xcenter = (user_define_view_xmin +
                       user_define_view_xmax) / 2.0;
     ycenter = (user_define_view_ymin +
                       user_define_view_ymax) / 2.0;

     if (draw_grid) {
          line_style(LINE_DASH1);
          xgrid = (user_define_view_xmax - user_define_view_xmin) 
                       / (double) x_axis_interval;
          ygrid = (user_define_view_ymax - user_define_view_ymin)
                       / (double) y_axis_interval;
          for (i = 1; i < x_axis_interval; i++) {
               x = user_define_view_xmin + (double) i * xgrid;
               line(x, user_define_view_ymin, 
                             x, user_define_view_ymax);
          }
          for (i = 1; i < y_axis_interval; i++) {
               y = user_define_view_ymin + (double) i * ygrid;
               line(user_define_view_xmin, y,
                             user_define_view_xmax, y);
          }
          line_style(LINE_SOLID);
     }

     if (strcmp(x_axis_title, "")) {
          setfont(fonts, title_font_size, 0.0);
          y = user_define_view_ymin - 35.0 * (user_define_view_ymax -
                     user_define_view_ymin) / (YRAMC2 - YRAMC1);
          if (x_title_distance > 0)
               y = user_define_view_ymin - x_title_distance;
          wrt_litstr_xy(x_axis_title, xcenter, y, CENTERX);
     }
     if (strcmp(y_axis_title, "")) {
          setfont(fonts, title_font_size, 90.0);
          x = user_define_view_xmin - 48.0 * (user_define_view_xmax -
                              user_define_view_xmin) / (XRAMC2 - XRAMC1);
          if (y_title_distance > 0)
               x = user_define_view_xmin - y_title_distance;
          wrt_litstr_xy(y_axis_title, x, ycenter, CENTERXY);
     }
     if (strcmp(title, "")) {
          setfont(fonts, title_font_size, 0.0);
          y = user_define_view_ymax + 35.0 * (user_define_view_ymax -
                     user_define_view_ymin) / (YRAMC2 - YRAMC1);
          wrt_litstr_xy(title, xcenter, y, CENTERX);
     }
}

void _plot::project_map_on_view_window(int map[SIZE][SIZE])
{
     int i, j, color_mode = COLOR_BLACK;
     double x, y, xgap, ygap;
     COLOR col;

     xgap = (user_define_view_xmax - user_define_view_xmin) / SIZE;
     ygap = (user_define_view_ymax - user_define_view_ymin) / SIZE;

     x = user_define_view_xmin;
     for (i = 0; i < SIZE; i++) {
          y = user_define_view_ymin;
          for (j = 0; j < SIZE; j++) {
               if (map[i][j]) {
                    if (map[i][j] & ADNA && map[i][j] & BDNA && map[i][j] & ZDNA)
                         color_mode = COLOR_BROWN;
                    else if (map[i][j] & ADNA && map[i][j] & BDNA)
                         color_mode = COLOR_LIGHT_GREEN;
                    else if (map[i][j] & BDNA && map[i][j] & ZDNA)
                         color_mode = COLOR_PURPLE;
                    else if (map[i][j] & ADNA && map[i][j] & ZDNA)
                         color_mode = COLOR_ORANGE;
                    else if (map[i][j] & ADNA)
                         color_mode = COLOR_YELLOW;
                    else if (map[i][j] & BDNA)
                         color_mode = COLOR_LIGHT_BLUE;
                    else if (map[i][j] & ZDNA)
                         color_mode = COLOR_RED;
                    get_rgb_color_from_index(color_mode, col);
                    box(x, y, x + xgap, y + ygap, col, 1);
               }
               y += ygap;
          }
          x += xgap;
     }
}

void _plot::plot_a_point(const double x, const double y, const COLOR rgb,
           const int type, const int fill, const char *label)
{
     double xx = user_define_view_xmin + (x - user_define_actual_value_xmin)
               * (user_define_view_xmax - user_define_view_xmin) 
               / (user_define_actual_value_xmax - user_define_actual_value_xmin);
     double yy = user_define_view_ymin + (y - user_define_actual_value_ymin)
               * (user_define_view_ymax - user_define_view_ymin) 
               / (user_define_actual_value_ymax - user_define_actual_value_ymin);
     if (label) {
          setfont(FONT_HELVETICA, 8, 0.0);
          wrt_litstr_xy(label, xx, yy, CENTERXY);
     } else {
          double dx = (user_define_view_xmax - user_define_view_xmin) / 200.0;
          double dy = (user_define_view_ymax - user_define_view_ymin) / 200.0;
     
          setline_width(0.2);
     
          if (type == BOX)
               box(xx - dx, yy - dy, xx + dx, yy + dy, rgb, fill);
          else if (type == TRIANGLE)
               triangle(xx - dx, yy - 0.6 * dy, xx + dx, yy - 0.6 * dy, xx,
                     yy + 1.2 * dy, rgb, fill);
          else if (type == DIAMOND)
               diamond(xx - 1.2 * dx, yy, xx, yy + 1.6 * dx, xx + 1.2 * dx, yy, 
                      xx, yy - 1.6 * dx, rgb, fill);
          else if (type == CIRCLE)
               curve(xx, yy, 1.1 * (dx + dy) / 2.0, 360.0, 0.0, rgb, fill);
     }
}

void _plot::plot_a_point(const double x, const double y, const double r, const  double g,
        const double b, const int type, const int fill, const char *label)
{
     COLOR col;
     col.r = r; col.g = g; col.b = b;
     plot_a_point(x, y, col, type, fill, label);
}

void _plot::plot_a_bar(const double xmin, const double xmax, const double ymin,
          const double ymax, const COLOR rgb)
{
     double x_min = user_define_view_xmin + (xmin - user_define_actual_value_xmin)
                  * (user_define_view_xmax - user_define_view_xmin)
                  / (user_define_actual_value_xmax - user_define_actual_value_xmin);
     double x_max = user_define_view_xmin + (xmax - user_define_actual_value_xmin)
                  * (user_define_view_xmax - user_define_view_xmin)
                  / (user_define_actual_value_xmax - user_define_actual_value_xmin);
     double y_min = user_define_view_ymin + (ymin - user_define_actual_value_ymin)
                  * (user_define_view_ymax - user_define_view_ymin)
                  / (user_define_actual_value_ymax - user_define_actual_value_ymin);
     double y_max = user_define_view_ymin + (ymax - user_define_actual_value_ymin)
                  * (user_define_view_ymax - user_define_view_ymin)
                  / (user_define_actual_value_ymax - user_define_actual_value_ymin);
     box(x_min, y_min, x_max, y_max, rgb, 1);
     box(x_min, y_min, x_max, y_max, black, 0);
}

void _plot::plot_a_bar(const double xmin, const double xmax, const double ymin,
          const double ymax, const double r, const double g, const double b)
{
     COLOR col;
     col.r = r; col.g = g; col.b = b;
     plot_a_bar(xmin, xmax, ymin, ymax, col);
}

void _plot::plot_a_line(const double x1, const double y1, const double x2,
           const double y2, const int type)
{
     double x_1 = user_define_view_xmin + (x1 - user_define_actual_value_xmin)
                  * (user_define_view_xmax - user_define_view_xmin)
                  / (user_define_actual_value_xmax - user_define_actual_value_xmin);
     double x_2 = user_define_view_xmin + (x2 - user_define_actual_value_xmin)
                  * (user_define_view_xmax - user_define_view_xmin)
                  / (user_define_actual_value_xmax - user_define_actual_value_xmin);
     double y_1 = user_define_view_ymin + (y1 - user_define_actual_value_ymin)
                  * (user_define_view_ymax - user_define_view_ymin)
                  / (user_define_actual_value_ymax - user_define_actual_value_ymin);
     double y_2 = user_define_view_ymin + (y2 - user_define_actual_value_ymin)
                  * (user_define_view_ymax - user_define_view_ymin)
                  / (user_define_actual_value_ymax - user_define_actual_value_ymin);
     line_style(type);
     line(x_1, y_1, x_2, y_2);
     line_style(LINE_SOLID);
}

void _plot::print_string(const char *string, const int fonts, const double fontsize,
        const double x, const double y, const int option)
{
     setfont(fonts, fontsize, 0.0);
     wrt_litstr_xy(string, x, y, option);
}

void _plot::newpage(const int head)
{
     if (is_new_page) return;

     if (pages) {
          fprintf(ps, "cleartomark\n");
          fprintf(ps, "saveobjp restore\n");
          fprintf(ps, "showpage\n");
     }

     pages++;
     fprintf(ps, "%%%%Page: %d %d\n", pages, pages);
     fprintf(ps, "/saveobjp save def\n");
     fprintf(ps, "mark\n");
     fprintf(ps, "1 setlinecap 1 setlinejoin 0.2 setlinewidth 0 setgray [ ] 0 setdash newpath\n");
     setline_width(0.2);
     if (head) {
          box(user_define_page_xmin, user_define_page_ymin, user_define_page_xmax,
              user_define_page_ymax, black, 0);
          setfont(FONT_HELVETICA, 10, 0.0);
          wrt_litstr_xy("NUCHECK", user_define_page_xmin + 10.0,
                       user_define_page_ymax - 10.0, LJUSTIFY);
     }
     is_new_page = 1;
}

void _plot::close(void)
{
     fprintf(ps, "showpage\n");
     fprintf(ps, "cleartomark\n");
     fprintf(ps, "saveobjp restore\n");
     fprintf(ps, "%%%%Trailer\n");
     fprintf(ps, "restore\n");
     fprintf(ps, "%%%%Page: %d %d\n", pages, pages);
     fclose(ps);
}

void _plot::line(const double x1, const double y1, const double x2, const double y2)
{
     fprintf(ps, "%.2f %.2f %.2f %.2f L\n", x1, y1, x2, y2);
     is_new_page = 0;
}

void _plot::line_style(const int option)
{
     if (line_type == option) return;

     line_type = option;
     switch (option) {
          case LINE_SOLID:
               fprintf(ps, "[] 0 setdash\n");
               break;
          case LINE_DASH1:
               fprintf(ps, "[1 1] 0 setdash\n");
               break;
          case LINE_DASH2:
               fprintf(ps, "[3 4 3] 0 setdash\n");
               break;
          case LINE_DASH3:
               fprintf(ps, "[0.3 2.5] 0 setdash\n");
               break;
          default:
               fprintf(ps, "[] 0 setdash\n");
               break;
     }
     is_new_page = 0;
}

void _plot::setline_width(const double line_width)
{
     if (fabs(line_width - linewidth) > 0.01) {
          linewidth = line_width;
          fprintf(ps, "%.3g LW\n", line_width);
     }
     is_new_page = 0;
}

void _plot::box(const double xll, const double yll, const double xur,
         const double yur, const COLOR rgb, const int fill)
{
     fprintf(ps, "%.2f %.2f %.2f RS ", rgb.r, rgb.g, rgb.b);
     if (fill) fprintf(ps, "%.2f %.2f %.2f %.2f %.2f %.2f %.2f %.2f P\n",
                 xll, yll, xll, yur, xur, yur, xur, yll);
     else fprintf(ps, "%.2f %.2f %.2f %.2f %.2f %.2f %.2f %.2f B\n",
                 xll, yll, xll, yur, xur, yur, xur, yll);
     is_new_page = 0;
}

void _plot::box(const double xll, const double yll, const double xur,
         const double yur, const double r, const double g, const double b,
         const int fill)
{
     fprintf(ps, "%.2f %.2f %.2f RS ", r, g, b);
     if (fill) fprintf(ps, "%.2f %.2f %.2f %.2f %.2f %.2f %.2f %.2f P\n",
                 xll, yll, xll, yur, xur, yur, xur, yll);
     else fprintf(ps, "%.2f %.2f %.2f %.2f %.2f %.2f %.2f %.2f B\n",
                 xll, yll, xll, yur, xur, yur, xur, yll);
     is_new_page = 0;
}

void _plot::box(const COLOR rgb, const double xll, const double yll, const double xul,
         const double yul, const double xur, const double yur, const double xlr,
         const double ylr, const char *type)
{
     fprintf(ps, "%.2f %.2f %.2f RS ", rgb.r, rgb.g, rgb.b);
     fprintf(ps, "%.2f %.2f %.2f %.2f %.2f %.2f %.2f %.2f %s\n",
            xll, yll, xul, yul, xur, yur, xlr, ylr, type);
     is_new_page = 0;
}

void _plot::curve(const double xc, const double yc, const double radius,
         const double ang1, const double ang2, const COLOR rgb, const int fill)
{
     fprintf(ps, "%.2f %.2f %.2f RS\n", rgb.r, rgb.g, rgb.b);
     fprintf(ps, "newpath\n");
     if (fill) fprintf(ps, "%.2f %.2f moveto\n", xc, yc);
     fprintf(ps, "%.2f %.2f %.2f %.2f %.2f arc\n", xc, yc, radius, ang1, ang2);
     if (fill) fprintf(ps, "fill\n");
     else      fprintf(ps, "stroke\n");
     fprintf(ps, "grestore\n");
     is_new_page = 0;
}

void _plot::curve(const double xc, const double yc, const double radius,
         const double ang1, const double ang2, const double r, const double g,
         const double b, const int fill)
{
     fprintf(ps, "%.2f %.2f %.2f RS\n", r, g, b);
     fprintf(ps, "newpath\n");
     if (fill) fprintf(ps, "%.2f %.2f moveto\n", xc, yc);
     fprintf(ps, "%.2f %.2f %.2f %.2f %.2f arc\n", xc, yc, radius, ang1, ang2);
     if (fill) fprintf(ps, "fill\n");
     else      fprintf(ps, "stroke\n");
     fprintf(ps, "grestore\n");
     is_new_page = 0;
}

void _plot::triangle(const double x1, const double y1, const double x2, 
       const double y2, const double x3, const double y3, const COLOR rgb, 
         const int fill) 
{
     fprintf(ps, "%.2f %.2f %.2f RS ", rgb.r, rgb.g, rgb.b);
     if (fill) 
          fprintf(ps, "%.2f %.2f %.2f %.2f %.2f %.2f T\n", x1, y1, x2, y2, x3, y3);
     else fprintf(ps, "%.2f %.2f %.2f %.2f %.2f %.2f TB\n", x1, y1, x2, y2, x3, y3);
     is_new_page = 0;
}

void _plot::triangle(const double x1, const double y1, const double x2,
       const double y2, const double x3, const double y3, const double r,
       const double g, const double b, const int fill)
{
     fprintf(ps, "%.2f %.2f %.2f RS ", r, g, b);
     if (fill)
          fprintf(ps, "%.2f %.2f %.2f %.2f %.2f %.2f T\n", x1, y1, x2, y2, x3, y3);
     else fprintf(ps, "%.2f %.2f %.2f %.2f %.2f %.2f TB\n", x1, y1, x2, y2, x3, y3);
     is_new_page = 0;
}

void _plot::diamond(const double xll, const double yll, const double xul,
         const double yul, const double xur, const double yur, const double xlr,
         const double ylr, const COLOR rgb, const int fill)
{
     fprintf(ps, "%.2f %.2f %.2f RS ", rgb.r, rgb.g, rgb.b);
     if (fill) fprintf(ps, "%.2f %.2f %.2f %.2f %.2f %.2f %.2f %.2f P\n",
            xll, yll, xul, yul, xur, yur, xlr, ylr);
     else fprintf(ps, "%.2f %.2f %.2f %.2f %.2f %.2f %.2f %.2f B\n",
            xll, yll, xul, yul, xur, yur, xlr, ylr);
     is_new_page = 0;
}

void _plot::diamond(const double xll, const double yll, const double xul,
         const double yul, const double xur, const double yur, const double xlr,
         const double ylr, const double r, const double g, const double b,
         const int fill)
{
     fprintf(ps, "%.2f %.2f %.2f RS ", r, g, b);
     if (fill) fprintf(ps, "%.2f %.2f %.2f %.2f %.2f %.2f %.2f %.2f P\n",
            xll, yll, xul, yul, xur, yur, xlr, ylr);
     else fprintf(ps, "%.2f %.2f %.2f %.2f %.2f %.2f %.2f %.2f B\n",
            xll, yll, xul, yul, xur, yur, xlr, ylr);
     is_new_page = 0;
}

void _plot::setcolor(COLOR col)
{
     if (color_unequal(color, col)) {
          fprintf(ps, "%.3g %.3g %.3g R\n", col.r, col.g, col.b);
          color_copy(color, col);
          is_new_page = 0;
     }
}

void _plot::setcolor(const double r, const double g, const double b)
{
     COLOR col;
     col.r = r; col.g = g; col.b = b;
     setcolor(col);
}

void _plot::setfont(const int font, const double size, const double angle)
{
     font_size = size;
     font_rotation = angle;

     switch (font) {
          case FONT_TIMES_BOLD:
               fprintf(ps, "/Times-Bold findfont %10.5f scalefont setfont\n",
                            font_size);
               break;
          case FONT_HELVETICA_OBL:
               fprintf(ps, "/Helvetica-Oblique findfont %10.5f scalefont setfont\n",
                            font_size) ;
               break;
          case FONT_HELVETICA:
               fprintf(ps, "/Helvetica findfont %10.5f scalefont setfont\n",
                            font_size) ;
               break;
          case FONT_COURIER_BOLD:
               fprintf(ps, "/Courier-Bold findfont %10.5f scalefont setfont\n",
                            font_size);
               break;
          case FONT_SYMBOL:
               fprintf(ps, "/Symbol findfont %10.5f scalefont setfont\n",
                            font_size);
               break;
          case FONT_TIMES_ROMAN:
               fprintf(ps, "/Times-Roman findfont %10.5f scalefont setfont\n",
                            font_size);
               break;
     }
     fprintf(ps, "/Baselineskip 10 def\n");
     is_new_page = 0;
}

void _plot::wrtstr_xy(const char *string, const double x, const double y,
             const int option)
{
     char *ok = escape_special_chars(string);
     fprintf(ps, "%.2f %.2f moveto\n", x, y);
     display_string(ps, ok, font_rotation, font_size, option);
     free(ok);
     is_new_page = 0;
}

void _plot::wrt_litstr_xy(const char *string, const double x, const double y,
             const int option)
{
     fprintf(ps, "%.2f %.2f moveto\n", x, y);
     display_string(ps, string, font_rotation, font_size, option);
     is_new_page = 0;
}

