#include<iostream>
#include<cstdlib>
#include<fstream>
#include<cmath>

using namespace std;

#include "postscript.h"


void PostScript::fill(void)
{
   *this << "fill\n";
}

void PostScript::setcolor(double r, double g, double b)
{
   *this << "stroke\n";
   *this << r << " " << g << " " << b << " setrgbcolor\n";
}


PostScript::PostScript(const char nombre[]) : ofstream(nombre)
{
    *this << "%!PS\n"
             "72 8.5 2 div mul\n" 
             "72 11  2 div mul\n"
             "translate\n"
             "72 2.54 div dup scale\n"
             "0.01 setlinewidth\n";

    for (int i=0; i<3; i++)
      for (int j=0; j<3; j++)
        R3[i][j]= i==j ? 1 : 0;
    
    for (int i=0; i<4; i++)
      for (int j=0; j<4; j++)
        R4[i][j]= i==j ? 1 : 0;
    
    To= 50;
    Tp= 30;
    Zo= 50;
    Zp= 30;
}

void PostScript::rotacion3(char eje, double ang)
{
    double m[3][3];
    double t[3][3];

    for (int i=0; i<3; i++)
       for (int j=0; j<3; j++)
         m[i][j]= i==j ? 1.0 : 0.0;

    ang*= M_PI/180.0;

    switch (eje)
      {
       case 'x': case 'X':
          m[1][1]= cos(ang);  m[1][2]= -sin(ang);
          m[2][1]= sin(ang);  m[2][2]=  cos(ang);
          break;

       case 'y': case 'Y':
          m[0][0]= cos(ang);  m[0][2]= -sin(ang); 
          m[2][0]= sin(ang);  m[2][2]=  cos(ang);
          break;

       case 'z': case 'Z':
          m[0][0]= cos(ang);  m[0][1]=-sin(ang);
          m[1][0]= sin(ang);  m[1][1]= cos(ang);
          break;
      }

    for (int i=0; i<3; i++)
       for (int j=0; j<3; j++)
         {
          double s=0;
          for (int k=0; k<3; k++)
             s+= R3[i][k] * m[k][j];
          t[i][j]= s;
         }

    for (int i=0; i<3; i++)
       for (int j=0; j<3; j++)
        R3[i][j]= t[i][j]; 
}


void PostScript::rotacion4(int e0, int e1, int e2, int e3,
                           double phi, double psi )
{
    double m[4][4];
    double t[4][4];

    phi*= M_PI/180.0;
    psi*= M_PI/180.0;

    for (int i=0; i<4; i++)
       for (int j=0; j<4; j++)
         m[i][j]=  i==j? 1.0 : 0.0;

    m[e0][e0]=cos(phi);  m[e0][e1]= -sin(phi);
    m[e1][e0]=sin(phi);  m[e1][e1]=  cos(phi);

    m[e2][e2]=cos(psi);  m[e2][e3]= -sin(psi);
    m[e3][e2]=sin(psi);  m[e3][e3]=  cos(psi);

    for (int i=0; i<4; i++)
       for (int j=0; j<4; j++)
         {
          double s=0;
          for (int k=0; k<4; k++)
             s+= R4[i][k] * m[k][j];
          t[i][j]= s;
         }

    for (int i=0; i<4; i++)
       for (int j=0; j<4; j++)
        R4[i][j]= t[i][j]; 
}



void PostScript::transf(double x, double y, double z,
                double& xp, double& yp, double& zp)
{
    xp= R3[0][0] * x + R3[0][1] * y + R3[0][2] * z; 
    yp= R3[1][0] * x + R3[1][1] * y + R3[1][2] * z; 
    zp= R3[2][0] * x + R3[2][1] * y + R3[2][2] * z; 
}

void PostScript::transf(double x, double y, double z, double t,
                double& xp, double& yp, double& zp, double& tp)
{
    xp= R4[0][0] * x + R4[0][1] * y + R4[0][2] * z + R4[0][3] * t; 
    yp= R4[1][0] * x + R4[1][1] * y + R4[1][2] * z + R4[1][3] * t; 
    zp= R4[2][0] * x + R4[2][1] * y + R4[2][2] * z + R4[2][3] * t; 
    tp= R4[2][0] * x + R4[2][1] * y + R4[2][2] * z + R4[3][3] * t; 
}


PostScript::~PostScript(void)
{
    *this << "stroke\n"
             "showpage\n";
    close();
}

void PostScript::moveto(double x, double y)
{
    *this << x << " " << y << " moveto\n";
}

void PostScript::lineto(double x, double y)
{
    *this << x << " " << y << " lineto\n";
}

void PostScript::pers32(double zo, double zp)
{
    Zo= zo;
    Zp= zp;
}

void PostScript::pers43(double to, double tp)
{
    To= to;
    Tp= tp;
}

void PostScript::moveto(double x, double y, double z)
{
   transf(x,y,z, x,y,z);
   double xp= (Zo-Zp) / (Zo-z)  * x;
   double yp= (Zo-Zp) / (Zo-z)  * y;
   moveto(xp, yp);
}

void PostScript::lineto(double x, double y, double z)
{
   transf(x,y,z, x,y,z);
   double xp= (Zo-Zp) / (Zo-z)  * x;
   double yp= (Zo-Zp) / (Zo-z)  * y;
   lineto(xp, yp);
}

void PostScript::lineto(double x, double y, double z, double t)
{
   transf(x,y,z,t, x,y,z,t);
   double xp= (To-Tp) / (To-t)  * x;
   double yp= (To-Tp) / (To-t)  * y;
   double zp= (To-Tp) / (To-t)  * z;
   lineto(xp, yp, zp);
}

void PostScript::moveto(double x, double y, double z, double t)
{
   transf(x,y,z,t, x,y,z,t);
   double xp= (To-Tp) / (To-t)  * x;
   double yp= (To-Tp) / (To-t)  * y;
   double zp= (To-Tp) / (To-t)  * z;
   moveto(xp, yp, zp);
}


