// plot_parab.java  plot parabola ortho with height colors

import java.io.*;
import java.*;
import java.awt.*;
import java.awt.event.*;

public class plot_parab extends Frame
{
  // mouse and display variables
  int xm, ym, bm; // mouse position 
  int height = 700;
  int width = 700;
  double xmin = -1.0; // typically determined from data
  double xmax = 1.0;
  double ymin = -1.0;
  double ymax = 1.0;
  double zmin = 0.0;
  double zmax = 2.0;
  double tmin = 0.0;
  double tmax = 1.0;
  double t = tmin;
  int nx = 20;
  int ny = 20;
  int nz = 20;
  int nt = 20;
  double hx = (xmax-xmin)/nx;
  double hy = (ymax-ymin)/ny;
  double hz = (zmax-zmin)/nz;
  double ht = (tmax-tmin)/nt;

  double ya = 0.5;     //  orthographic typ 0.1 to 0.5 
  double xs = (0.666*(width-100))/(xmax-xmin);
  double ys = (0.666*(height-100))/(ymax-ymin);
  int xp, yp; // computed by parab

  public plot_parab()
  {
    System.out.println("plot_parab.java running");
    setTitle("plot_parab");
    setSize(width,height);
    setBackground(Color.white);
    setForeground(Color.black);
    addWindowListener(new WindowAdapter()
    {
      public void windowClosing(WindowEvent e)
      {
        System.exit(0);
      }
    });
    setVisible(true);
    this.addMouseListener (new mousePressHandler());

    do_plot();
  } // plot_parab constructor

  void do_plot()
  {
    // set up here

    // plot
    repaint(); // wait for mouse events
  } // end do_program


  class mousePressHandler extends MouseAdapter
  {
    public void mousePressed (MouseEvent e)
    {
      xm = e.getX();
      ym = e.getY();
      bm = e.getButton();
      // System.out.println("down xm="+xm+", ym="+ym+", bm="+bm); // debug

      if(in_rect(width-70, height-20, 30, 20))
      {
	// do something, run
	requestFocus();
        MyThread do_run = new MyThread(); // allocate do_run thread
        do_run.start(); // terminates
      }
      else if(in_rect(width-105, height-20, 30, 20))
      {
	// do something, next
	t = t + ht;
	requestFocus();
        repaint();
      }
      else if(in_rect(width-145, height-20, 35, 20))
      {
	// do something, back
        t = t - ht;
	requestFocus();
        repaint();
      }
      if(in_rect(width-35, height-20, 30, 20)) System.exit(0);
    } // end mousePressed 
  } // end mousePressHandler

  boolean in_rect(int x, int y, int w, int h)
  {
    return xm>x && xm<x+w && ym>y && ym<y+h;
  }
 
  public void paint(Graphics g)
  {
    double x, y, z;
    double z1, z2, hz;
    int xp1, yp1, xp2, yp2; // line segment

    // buttons
    g.setColor(Color.red);
    g.fillRect(width-35,height-20,30,15);
    g.setColor(Color.black);
    g.drawString("quit", width-30, height-10);
    g.setColor(Color.green);
    g.fillRect(width-70,height-20,30,15);
    g.setColor(Color.black);
    g.drawString("run", width-65, height-10);
    g.setColor(Color.yellow);
    g.fillRect(width-105,height-20,30,15);
    g.setColor(Color.black);
    g.drawString("next", width-100, height-10);
    g.setColor(Color.orange);
    g.fillRect(width-145,height-20,35,15);
    g.setColor(Color.black);
    g.drawString("back", width-140, height-10);

    // axis labels
    g.drawString("xmin", 25, height-15);
    g.drawString("xmax", (int)(0.66*width-70), height-15);
    g.drawString("ymin", (int)(0.66*width-30), height-25);
    g.drawString("ymax", (int)(width-80), (int)(0.66*height+25));
    g.drawString("zmin", (int)(width-75), (int)(0.66*height+5));
    g.drawString("zmax", (int)(width-75), (int)(85));

    // height color scale
    int hgt = 210;
    int ncol = 10;
    for(int i=0; i<ncol; i++)
    {
      set_color(i, g);
      g.fillRect(20,hgt-20*i,50,15);
    }
    g.drawString("z value", 80, 40);

    // draw box, bottom
    set_color(0, g);
    ortho(xmin, ymin, zmin); xp1=xp; yp1=yp;
    ortho(xmax, ymin, zmin); xp2=xp; yp2=yp;
    g.drawLine(xp1, yp1, xp2, yp2);
    ortho(xmax, ymax, zmin); xp1=xp; yp1=yp;
    g.drawLine(xp2, yp2, xp1, yp1);
    ortho(xmin, ymax, zmin); xp2=xp; yp2=yp;
    g.drawLine(xp1, yp1, xp2, yp2);
    ortho(xmin, ymin, zmin); xp1=xp; yp1=yp;
    g.drawLine(xp2, yp2, xp1, yp1);
    set_color(ncol-1, g); // top
    ortho(xmin, ymin, zmax); xp1=xp; yp1=yp;
    ortho(xmax, ymin, zmax); xp2=xp; yp2=yp;
    g.drawLine(xp1, yp1, xp2, yp2);
    ortho(xmax, ymax, zmax); xp1=xp; yp1=yp;
    g.drawLine(xp2, yp2, xp1, yp1);
    ortho(xmin, ymax, zmax); xp2=xp; yp2=yp;
    g.drawLine(xp1, yp1, xp2, yp2);
    ortho(xmin, ymin, zmax); xp1=xp; yp1=yp;
    g.drawLine(xp2, yp2, xp1, yp1);
    // draw box edges with z value colors
    z1 = zmin;
    hz = (zmax-zmin)/(ncol);
    for(int i=0; i<ncol; i++)
    {
      z2 = z1+hz;
      set_color(i,g);
      ortho(xmin, ymin, z1); xp1=xp; yp1=yp;
      ortho(xmin, ymin, z2); xp2=xp; yp2=yp;
      g.drawLine(xp1, yp1, xp2, yp2);
      ortho(xmin, ymax, z1); xp1=xp; yp1=yp;
      ortho(xmin, ymax, z2); xp2=xp; yp2=yp;
      g.drawLine(xp1, yp1, xp2, yp2);
      ortho(xmax, ymax, z1); xp1=xp; yp1=yp;
      ortho(xmax, ymax, z2); xp2=xp; yp2=yp;
      g.drawLine(xp1, yp1, xp2, yp2);
      ortho(xmax, ymin, z1); xp1=xp; yp1=yp;
      ortho(xmax, ymin, z2); xp2=xp; yp2=yp;
      g.drawLine(xp1, yp1, xp2, yp2);
      z1 = z2;
    }

    // plot function or data with z value colors
    for(int i=0; i<nx; i++)
    {
      x = xmin+(double)i*hx;
      for(int j=0; j<ny; j++)
      {
	y = ymin+(double)j*hy;
        z1 = parab(x, y);
        ortho(x, y, z1); xp1=xp; yp1=yp;
        z2 = parab(x+hx, y);
        ortho(x+hx, y, z2); xp2=xp; yp2=yp;
        set_color((int)((ncol*(((z1+z2)/2.0)-zmin)/(zmax-zmin))+0.5), g);
        g.drawLine(xp1, yp1, xp2, yp2);
        z2 = parab(x, y+hy);
        ortho(x, y+hy, z2); xp2=xp; yp2=yp;
        set_color((int)((ncol*(((z1+z2)/2.0)-zmin)/(zmax-zmin))+0.5), g);
        g.drawLine(xp1, yp1, xp2, yp2);
      }
    }
    for(int i=0; i<nx; i++)
    {
      x = xmin+(double)i*hx;
      y = ymax;
      z1 = parab(x, y);
      ortho(x, y, z1); xp1=xp; yp1=yp;
      z2 = parab(x+hx, y);
      ortho(x+hx, y, z2); xp2=xp; yp2=yp;
      set_color((int)((ncol*(((z1+z2)/2.0)-zmin)/(zmax-zmin))+0.5), g);
      g.drawLine(xp1, yp1, xp2, yp2);
    }
    for(int j=0; j<ny; j++)
    {
      y = ymin+(double)j*hy;
      x = xmax;
      z1 = parab(x, y);
      ortho(x, y, z1); xp1=xp; yp1=yp;
      z2 = parab(x, y+hy);
      ortho(x, y+hy, z2); xp2=xp; yp2=yp;
      set_color((int)((ncol*(((z1+z2)/2.0)-zmin)/(zmax-zmin))+0.5), g);
      g.drawLine(xp1, yp1, xp2, yp2);
    }

  } // end paint

  // orthographic projection, sets xp,yp
  void ortho(double x, double y, double z)
  {
    double x1, y1, z1, x2, y2, x3, y3;
    x1 = x-xmin;   // zero base
    y1 = y-ymin; 
    z1 = z-zmin;
    x2 = x1+y1*ya; // ortho z is up, y is back
    y2 = z1+y1*ya;
    x3 = x2*xs;    // scale 
    y3 = y2*ys;
    x3 = x3+25;
    y3 = height-y3-25; // away from boarder
    xp = (int)x3;
    yp = (int)y3;
  }

  void set_color(int i, Graphics g)
  {
    if(i<0) {g.setColor(Color.black); return;}
    if(i>9) {g.setColor(Color.gray); return; }
    switch(i)
    {
      case 0: g.setColor(Color.black); break;
      case 1: g.setColor(Color.pink); break; // should be brown
      case 2: g.setColor(Color.red); break;
      case 3: g.setColor(Color.orange); break;
      case 4: g.setColor(Color.yellow); break;
      case 5: g.setColor(Color.green); break;
      case 6: g.setColor(Color.blue); break;
      case 7: g.setColor(Color.magenta); break;
      case 8: g.setColor(Color.cyan); break;
      case 9: g.setColor(Color.gray); break;
    }
  } // end set_color
 
  class MyThread extends Thread
  {
    MyThread()
    {
    } // end MyThread constructor
    
    public void run()
    {
      t = tmin;
      try
      {
	for(int i=0; i<nt; i++)
	{        
          repaint();
          sleep(250);
          t = t + ht;
	}
      } // end try
      catch(InterruptedException e)
      {
	System.out.println(" InterruptedException");
      }
    } // end Run
  } // end class MyThread


  // function to plot
  double parab(double x, double y)
  {
      return 0.666*(x*x+y*y+t);
  }

  public static void main(String[] args)
  {
    new plot_parab();
  }
} // end class  plot_parab.java 

