/*
 *  Eukleides  version 1.0.3
 *  Copyright (c) Christian Obrecht 2000-2004
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <math.h>
#include "types.h"
#include "geometry.h"
#include "parser.tab.h"

extern symrec *tracevar;

extern double tracebegin;

extern int strokes;

double X1, Y1, X2, Y2, Unit;

int undefined = 1;

void frame (double x1, double y1, double x2, double y2, double unit)
{
    X1 = x1<x2 ? x1 : x2;
    Y1 = y1<y2 ? y1 : y2;
    X2 = x2>x1 ? x2 : x1;
    Y2 = y2>y1 ? y2 : y1;
    Unit = unit;
    undefined = 0;
    printf ("\\psset{unit=%.4fcm}\n\\pspicture*(%.4f,%.4f)(%.4f,%.4f)\n",
	    unit, X1, Y1, X2, Y2);
}

void default_frame (void)
{
    if (undefined)
	frame (-2, -2, 8, 6, 1);
}

void setcolor_string (char *col)
{
    printf ("\\psset{linecolor=%s}\n", col);
}

void setcolor_flag (int flag)
{
    char *col;

    switch (flag)
      {
      case BLACK:
	  col = "black";
	  break;
      case DARKGRAY:
	  col = "darkgray";
	  break;
      case GRAY:
	  col = "gray";
	  break;
      case LIGHTGRAY:
	  col = "lightgray";
	  break;
      case WHITE:
	  col = "white";
	  break;
      case RED:
	  col = "red";
	  break;
      case GREEN:
	  col = "green";
	  break;
      case BLUE:
	  col = "blue";
	  break;
      case CYAN:
	  col = "cyan";
	  break;
      case MAGENTA:
	  col = "magenta";
	  break;
      case YELLOW:
	  col = "yellow";
      }
    printf ("\\psset{linecolor=%s}\n", col);
}

void setthickness (float ratio)
{
    float w;
    w = .5 * ratio;
    printf ("\\psset{linewidth=%.4fpt}\n", w);
}

void puttricks (char *t)
{
    printf ("\\%s\n", t);
}

void draw_point (_point * A, int flag, double s)
{
    double scale;
    char *opt;

    default_frame ();
    scale = s * ((flag == CROSS || flag == PLUS) ? 2 : 1);
    switch (flag)
      {
      case DOT:
	  opt = "*";
	  break;
      case DISC:
	  opt = "o";
	  break;
      case BOX:
	  opt = "square*";
	  break;
      case CROSS:
	  opt = "x";
	  break;
      case PLUS:
	  opt = "+";
      }
    printf ("\\psdots[dotstyle=%s, dotscale=%.4f](%.4f,%.4f)\n", opt, scale,
	    A->x, A->y);
}

char *d_flag (int flag)
{
    switch (flag)
      {
      case FULL:
	  return "";
      case DOTTED:
	  return "[linestyle=dotted]";
      case DASHED:
	  return "[linestyle=dashed]";
      }
    return "";
}

void draw_vector (_vector * v, _point * A, int flag)
{
    default_frame ();
    printf ("\\psline%s{->}(%.4f,%.4f)(%.4f,%.4f)\n", d_flag (flag), A->x,
	    A->y, A->x + v->x, A->y + v->y);
}

void draw_line (_line * l, int flag1, int flag2)
{
    double x1, y1, x2, y2, m;

    default_frame ();
    if (ZERO (Sin (l->angle)))
      {
	  x1 = X1;
	  y1 = l->y;
	  x2 = X2;
	  y2 = l->y;
      }
    else if (ZERO (Cos (l->angle)))
      {
	  x1 = l->x;
	  y1 = Y1;
	  x2 = l->x;
	  y2 = Y2;
      }
    else
      {
	  m = Tan (l->angle);
	  x1 = (Y1 - l->y) / m + l->x;
	  y1 = Y1;
	  if (x1 < X1)
	    {
		x1 = X1;
		y1 = m * (X1 - l->x) + l->y;
	    }
	  if (x1 > X2)
	    {
		x1 = X2;
		y1 = m * (X2 - l->x) + l->y;
	    }
	  x2 = (Y2 - l->y) / m + l->x;
	  y2 = Y2;
	  if (x2 < X1)
	    {
		x2 = X1;
		y2 = m * (X1 - l->x) + l->y;
	    }
	  if (x2 > X2)
	    {
		x2 = X2;
		y2 = m * (X2 - l->x) + l->y;
	    }
      }
    switch (flag2)
      {
      case HALFLINE:
	  if (l->angle >= 0)
	    {
		x1 = l->x;
		y1 = l->y;
	    }
	  else
	    {
		x2 = l->x;
		y2 = l->y;
	    }
	  break;
      case BACKHALFLINE:
	  if (l->angle >= 0)
	    {
		x2 = l->x;
		y2 = l->y;
	    }
	  else
	    {
		x1 = l->x;
		y1 = l->y;
	    }
      }
    if ((x1 >= X1) && (x2 <= X2) && (y1 >= Y1) && (y2 <= Y2))
	printf ("\\psline%s(%.4f,%.4f)(%.4f,%.4f)\n", d_flag (flag1), x1, y1,
		x2, y2);
}

char *s_flag (int flag)
{
    switch (flag)
      {
      case NOARROW:
	  return "";
      case ARROW:
	  return "{->}";
      case BACKARROW:
	  return "{<-}";
      case DOUBLEARROW:
	  return "{<->}";
      }
    return "";
}

void draw_segment (_segment * s, int flag1, int flag2)
{
    default_frame ();
    printf ("\\psline%s%s(%.4f,%.4f)(%.4f,%.4f)\n", d_flag (flag1),
	    s_flag (flag2), s->x1, s->y1, s->x2, s->y2);
}

void draw_circle (_circle * c, int flag)
{
    default_frame ();
    printf ("\\pscircle%s(%.4f,%.4f){%.4f}\n", d_flag (flag), c->x, c->y,
	    c->radius);
}

void draw_arc (_circle * c, double a1, double a2, int flag1, int flag2)
{
    default_frame ();
    printf ("\\psarc%s%s(%.4f,%.4f){%.4f}{%.4f}{%.4f}\n", d_flag (flag1),
	    s_flag (flag2), c->x, c->y, c->radius, a1, a2);
}

void draw_parabola_arc (_conic * C, double min, double max, int flag)
{
    double c0, s0, d, t, x, b, e;

    c0 = Cos (C->d);
    s0 = Sin (C->d);
    d = sqrt (pow ((X1 + X2) / 2 - C->x, 2) + pow ((Y1 + Y2) / 2 - C->y, 2)) +
	sqrt (pow (X2 - X1, 2) + pow (Y2 - Y1, 2));

    Snd_degree (&x, &x, 4 * C->a * C->a, 1, -d * d);
    t = sqrt (fabs (x));
    b = (min < -t) ? -t : min;
    e = (max > t) ? t : max;

    printf
	("\\parametricplot%s{%.4f}{%.4f}"
	 "{%.4f t %.4f mul t dup %.4f mul mul add add "
	 "%.4f t %.4f mul t dup %.4f mul mul add add}\n",
	 d_flag (flag), b, e, C->x, c0, -2*s0*C->a, C->y, s0, 2*c0*C->a);

}

void draw_ellipse_arc (_conic * C, double min, double max, int flag)
{
    double c0, s0;

    c0 = Cos (C->d);
    s0 = Sin (C->d);

    printf
	("\\parametricplot%s{%.4f}{%.4f}"
	 "{%.4f %.4f t cos mul %.4f t sin mul add add "
	 "%.4f %.4f t cos mul %.4f t sin mul add add }\n", d_flag (flag),
	 DEG (min), DEG (max), C->x, C->a * c0, -C->b * s0, C->y, C->a * s0,
	 C->b * c0);
}

void draw_hyperbola_arc (_conic * C, double b, double e, int flag)
{
    double c0, s0;

    c0 = Cos (C->d);
    s0 = Sin (C->d);
    printf
	("\\parametricplot%s{%.4f}{%.4f}"
	 "{%.4f %.4f t cos div %.4f t sin t cos div mul add add "
	 "%.4f %.4f t cos div %.4f t sin t cos div mul add add }\n",
	 d_flag (flag), DEG (b), DEG (e), C->x, C->a * c0, -C->b * s0, C->y,
	 C->a * s0, C->b * c0);
}

void draw_conic_arc (_conic * C, double first, double last, int flag)
{
    double min, max, d, t, b, e;
    default_frame ();
    if (first < last)
      {
	  min = first;
	  max = last;
      }
    else
      {
	  min = last;
	  max = first;
      }
    switch (C->kind)
      {
      case PARABOLA:
	  draw_parabola_arc (C, min, max, flag);
	  break;
      case ELLIPSE:
	  draw_ellipse_arc (C, min, max, flag);
	  break;
      case HYPERBOLA:
	  d = sqrt (pow ((X1 + X2) / 2 - C->x, 2) +
		    pow ((Y1 + Y2) / 2 - C->y, 2))
	      + sqrt (pow (X2 - X1, 2) + pow (Y2 -  Y1, 2));
	  if (C->a < d)
	    {
		t = atan (sqrt ((d * d - C->a * C->a)
			        / (C->a * C->a + C->b * C->b))) / 2 + M_PI_4;
		b = (min < -t) ? (-t) : min;
		e = (t < max) ? t : max;
		if (b < e)
		    draw_hyperbola_arc (C, b, e, flag);
		b = (min < -t + M_PI) ? (-t + M_PI) : min;
		e = (t + M_PI < max) ? (t + M_PI) : max;
		if (b < e)
		    draw_hyperbola_arc (C, b, e, flag);
	    }
      }
}

void draw_conic (_conic * C, int flag)
{
    double d, t;
    default_frame ();
    switch (C->kind)
      {
      case PARABOLA:
	  draw_parabola_arc (C, -1e8, 1e8, flag);
	  break;
      case ELLIPSE:
	  draw_ellipse_arc (C, 0, 2 * M_PI, flag);
	  break;
      case HYPERBOLA:
	  d = sqrt (pow ((X1 + X2) / 2 - C->x, 2) +
		    pow ((Y1 + Y2) / 2 - C->y, 2))
	      + sqrt (pow (X2 - X1, 2) + pow (Y2 - Y1, 2));
	  if (C->a < d)
	    {
		t = atan (sqrt
			  ((d * d - C->a * C->a)
			   / (C->a * C->a + C->b * C->b))) / 2 + M_PI_4;
		draw_hyperbola_arc (C, -t, t, flag);
		draw_hyperbola_arc (C, -t + M_PI, t + M_PI, flag);
	    }
      }
}

void draw_digon (_point * A, _point * B, int flag1, int flag2)
{
    default_frame ();
    printf ("\\psline%s%s(%.4f,%.4f)(%.4f,%.4f)\n", d_flag (flag1),
	    s_flag (flag2), A->x, A->y, B->x, B->y);
}

void draw_triangle (_point * A, _point * B, _point * C, int flag)
{
    default_frame ();
    printf ("\\pspolygon%s(%.4f,%.4f)(%.4f,%.4f)(%.4f,%.4f)\n",
	    d_flag (flag), A->x, A->y, B->x, B->y, C->x, C->y);
}

void draw_quadrilateral (_point * A, _point * B, _point * C, _point * D,
			 int flag)
{
    default_frame ();
    printf ("\\pspolygon%s(%.4f,%.4f)(%.4f,%.4f)(%.4f,%.4f)(%.4f,%.4f)\n",
	    d_flag (flag), A->x, A->y, B->x, B->y, C->x, C->y, D->x, D->y);
}

void draw_pentagon (_point * A, _point * B, _point * C, _point * D,
		    _point * E, int flag)
{
    default_frame ();
    printf
	("\\pspolygon%s(%.4f,%.4f)(%.4f,%.4f)(%.4f,%.4f)"
	 "(%.4f,%.4f)(%.4f,%.4f)\n",
	 d_flag (flag), A->x, A->y, B->x, B->y, C->x, C->y, D->x, D->y, E->x,
	 E->y);
}

void draw_hexagon (_point * A, _point * B, _point * C, _point * D, _point * E,
		   _point * F, int flag)
{
    default_frame ();
    printf
	("\\pspolygon%s(%.4f,%.4f)(%.4f,%.4f)(%.4f,%.4f)"
	 "(%.4f,%.4f)(%.4f,%.4f)(%.4f,%.4f)\n",
	 d_flag (flag), A->x, A->y, B->x, B->y, C->x, C->y, D->x, D->y, E->x,
	 E->y, F->x, F->y);
}

void draw_label (char *s, _point * A, double l, double a)
{
    default_frame ();
    printf ("\\uput{%.4f}[%.4f](%.4f,%.4f){$%s$}\n", l, a, A->x, A->y, s);
}

void draw_P_label (char *s, _point * A, double l, double a)
{
    default_frame ();
    printf ("\\uput{%.4f}[%.4f](%.4f,%.4f){%s}\n", l, a, A->x, A->y, s);
}

void draw_S_label (char *s, _segment * sg, double l, double a)
{
    default_frame ();
    printf ("\\uput{%.4f}[%.4f](%.4f,%.4f){%s}\n", l, a,
	    (sg->x1 + sg->x2) / 2, (sg->y1 + sg->y2) / 2, s);
}

void draw_P_N (double v, char *s, _point * A, double l, double a)
{
    char *fmt;

    default_frame ();
    fmt = (char *) malloc (40 + strlen (s));
    sprintf (fmt, "\\uput{%%.4f}[%%.4f](%%.4f,%%.4f){%s}\n", s);
    printf (fmt, l, a, A->x, A->y, v);
    free (fmt);
}

void draw_S_N (double v, char *s, _segment * sg, double l, double a)
{
    char *fmt;

    default_frame ();
    fmt = (char *) malloc (40 + strlen (s));
    sprintf (fmt, "\\uput{%%.4f}[%%.4f](%%.4f,%%.4f){%s}\n", s);
    printf (fmt, l, a, (sg->x1 + sg->x2) / 2, (sg->y1 + sg->y2) / 2, v);
    free (fmt);
}

void draw_P_NN (double v1, double v2, char *s, _point * A, double l, double a)
{
    char *fmt;

    default_frame ();
    fmt = (char *) malloc (40 + strlen (s));
    sprintf (fmt, "\\uput{%%.4f}[%%.4f](%%.4f,%%.4f){%s}\n", s);
    printf (fmt, l, a, A->x, A->y, v1, v2);
    free (fmt);
}

void draw_S_NN (double v1, double v2, char *s, _segment * sg, double l,
		double a)
{
    char *fmt;

    default_frame ();
    fmt = (char *) malloc (40 + strlen (s));
    sprintf (fmt, "\\uput{%%.4f}[%%.4f](%%.4f,%%.4f){%s}\n", s);
    printf (fmt, l, a, (sg->x1 + sg->x2) / 2, (sg->y1 + sg->y2) / 2, v1, v2);
    free (fmt);
}

void mark_S (_segment * sg, int flag, double sr)
{
    double x, y, a, c, s;

    default_frame ();
    x = (sg->x1 + sg->x2) / 2;
    y = (sg->y1 + sg->y2) / 2;
    a = S_angle (sg);
    s = .15 * Sin (a) * sr;
    c = .15 * Cos (a) * sr;
    switch (flag)
      {
      case SIMPLE:
	  printf ("\\psline(%.4f,%.4f)(%.4f,%.4f)\n", x - s, y + c, x + s,
		  y - c);
	  break;
      case DOUBLE:
	  printf ("\\psline(%.4f,%.4f)(%.4f,%.4f)\n", x - s - .2 * c,
		  y + c - .2 * s, x + s - .2 * c, y - c - .2 * s);
	  printf ("\\psline(%.4f,%.4f)(%.4f,%.4f)\n", x - s + .2 * c,
		  y + c + .2 * s, x + s + .2 * c, y - c + .2 * s);
	  break;
      case TRIPLE:
	  printf ("\\psline(%.4f,%.4f)(%.4f,%.4f)\n", x - s - .4 * c,
		  y + c - .4 * s, x + s - .4 * c, y - c - .4 * s);
	  printf ("\\psline(%.4f,%.4f)(%.4f,%.4f)\n", x - s, y + c, x + s,
		  y - c);
	  printf ("\\psline(%.4f,%.4f)(%.4f,%.4f)\n", x - s + .4 * c,
		  y + c + .4 * s, x + s + .4 * c, y - c + .4 * s);
	  break;
      case CROSS:
	  printf ("\\psline(%.4f,%.4f)(%.4f,%.4f)\n", x - .7 * (s + c),
		  y + .7 * (c - s), x + .7 * (s + c), y - .7 * (c - s));
	  printf ("\\psline(%.4f,%.4f)(%.4f,%.4f)\n", x - .7 * (s - c),
		  y + .7 * (c + s), x + .7 * (s - c), y - .7 * (c + s));
      }
}

void mark_A (_point * A, _point * B, _point * C, int flag, double sr)
{
    double a1, a2, a, s;

    default_frame ();
    a1 = angle (A->x - B->x, A->y - B->y);
    a2 = angle (C->x - B->x, C->y - B->y);
    a = (a1 + a2) / 2 - ((a1 > a2) ? 180 : 0);
    s = .5 * sr;
    switch (flag)
      {
      case DOT:
	  printf ("\\psdots[dotstyle=*, dotscale=1.2](%.4f,%.4f)\n",
		  B->x + .2 * sr * (Cos (a1) + Cos (a2)),
		  B->y + .2 * sr * (Sin (a1) + Sin (a2)));
      case SIMPLE:
	  printf ("\\psarc(%.4f,%.4f){%.4f}{%.4f}{%.4f}\n", B->x, B->y, s, a1,
		  a2);
	  break;
      case DOUBLE:
	  printf ("\\psarc(%.4f,%.4f){%.4f}{%.4f}{%.4f}\n", B->x, B->y,
		  s - .05, a1, a2);
	  printf ("\\psarc(%.4f,%.4f){%.4f}{%.4f}{%.4f}\n", B->x, B->y,
		  s + .05, a1, a2);
	  break;
      case TRIPLE:
	  printf ("\\psarc(%.4f,%.4f){%.4f}{%.4f}{%.4f}\n", B->x, B->y,
		  s - .08, a1, a2);
	  printf ("\\psarc(%.4f,%.4f){%.4f}{%.4f}{%.4f}\n", B->x, B->y, s, a1,
		  a2);
	  printf ("\\psarc(%.4f,%.4f){%.4f}{%.4f}{%.4f}\n", B->x, B->y,
		  s + .08, a1, a2);
	  break;
      case ARROW:
	  printf ("\\psarc{->}(%.4f,%.4f){%.4f}{%.4f}{%.4f}\n", B->x, B->y, s,
		  a1, a2);
	  break;
      case BACKARROW:
	  printf ("\\psarc{<-}(%.4f,%.4f){%.4f}{%.4f}{%.4f}\n", B->x, B->y, s,
		  a1, a2);
	  break;
      case DASHED:
	  printf ("\\psarc(%.4f,%.4f){%.4f}{%.4f}{%.4f}\n", B->x, B->y, s, a1,
		  a2);
	  printf ("\\psline(%.4f,%.4f)(%.4f,%.4f)\n",
		  B->x + (s - .075) * Cos (a), B->y + (s - .075) * Sin (a),
		  B->x + (s + .075) * Cos (a), B->y + (s + .075) * Sin (a));
	  break;
      case DOTTED:
	  printf ("\\psdots[dotstyle=*, dotscale=1.2](%.4f,%.4f)\n",
		  B->x + .15 * sr * (Cos (a1) + Cos (a2)),
		  B->y + .15 * sr * (Sin (a1) + Sin (a2)));
      case RIGHT:
	  printf ("\\psline(%.4f,%.4f)(%.4f,%.4f)(%.4f,%.4f)\n",
		  B->x + .3 * sr * Cos (a1), B->y + .3 * sr * Sin (a1),
		  B->x + .3 * sr * (Cos (a1) + Cos (a2)),
		  B->y + .3 * sr * (Sin (a1) + Sin (a2)),
		  B->x + .3 * sr * Cos (a2), B->y + .3 * sr * Sin (a2));

      }
}

void add_point (_point * A, int flag)
{
    static int ind = 0;

    if (ind == 0)
      {
	  default_frame ();
	  printf ("\\psline%s\n", d_flag (flag));
      }
    if (fabs (A->x) <= 500 && fabs (A->y) <= 500)
	printf ("(%.4f,%.4f)", A->x, A->y);
    ind++;
    if (ind%4 == 0) printf ("\n");
    if (ind == strokes) {
	  ind = 0;
	  tracevar->object.number = tracebegin;
    }
}


syntax highlighted by Code2HTML, v. 0.9.1