#ifndef PLOT3D_H
#define PLOT3D_H

//      Objects instantiated from this class may be used to plot z=f(x,y) in
// in three dimensions.

typedef struct
          {
            unsigned char base_z;    // '1' - normal, '2' -- highlight, or
                                     // '3' -- don't display; external to plot.
            unsigned char color;     // shade of gray for this quadrilateral.
            float         x;         // coordinates of corner of this
            float         y;         // quadrilateral.
            float         z;
            int           x_division_index;
            int           y_division_index;
          } corner_rec, *corner_rec_ptr;
//     One of the many vertices of quadrilaterals composing the plot.

typedef struct
          {
            double x;
            double y;
            double z;
          } vertex_rec;
//     A point or vector.

typedef struct sort_bound
          {
            int  lower_x;
            int  lower_y;
            int  upper_x;
            int  upper_y;
          } sort_bound_rec;

typedef struct sort_stack
          {
            sort_bound_rec    bound;
            struct sort_stack *previous;
          } sort_stack_rec;

class plot3d
  {
    private:
      void              adjust_perspective(void);
                          // Make parallel lines running away from the viewer
                          // appear to converge at the horizon.
      double            aspect_ratio;
      unsigned char     color_max;
                          // Maximum shade of gray for a quadrilateral
                          // (before adjusted between darkest_gray and
                          // lightest_gray).
      unsigned char     color_min;
                          // Minimum shade of gray for a quadrilateral
                          // (before adjusted between darkest_gray and
                          // lightest_gray).
      corner_rec        **corner;
                          // Vertices of quadrilaterals composing the plot.
      int               corner_allocated;
                          // TRUE if "corner" is allocated.
      double            cos_rotation;
      double            cos_tilt;
      int               darkest_gray;
                          // This is the darkest shade of gray that will
                          // actually be displayed (for parts that can be seen).
      void              evaluate_and_transform(double (*f)(double,double),
                         double x_min,double x_max,double y_min,double y_max,
                         int num_x_divisions,int num_y_divisions,
                         double rotation,double tilt,
                         int (*external_to_plot)(double,double),
                         int (*red)(double,double));
                          // Computes the vertices, etc. for each quadrilateral
                          // composing the plot.
      vertex_rec        light;
                          // Vector pointing to the source of light. 
      int               lightest_gray; 
                          // This is the lightest shade of gray that will
                          // actually be displayed.
      int               num_colors;
                          // Colors 0 through num_colors-2 represent shades of
                          // gray from black to white.  num_colors-1 represents
                          // red and is (optionally) used to highlight areas.
      int               num_x_divisions;
                          // Number of divisions of the x-axis used to define
                          // the quadrilaterals composing the plot.
      int               num_y_divisions;
                          // Number of divisions of the y-axis used to define  
                          // the quadrilaterals composing the plot.
      TPalette          *palette;
      PALETTEENTRY      palette_entry [256];
      double            pixels_per_unit;
      char              prepare_plot_state;
                          // Internal state of "prepare_plot".
      int               plot_prepared;
                          // TRUE if the last call to "prepare_plot" was
                          // successful.
      char              plot_state;
                          // Internal state of "plot".
      double            radians;
      void              rearrange(int,int,int,int,int *,int *);
                          // Called by "sort_back_to_front".
      double            rotation;
                          // Degrees the plot is rotated about the z-axis.
      void              shade(void);
                          // Computes the shade of gray for each quadrilateral
                          // composing the plot.
      double            sin_rotation;
      double            sin_tilt;
      void              sort_back_to_front();
                          // The painter's algorithm is used; items farther
                          // from the viewer are drawn earlier.
      sort_stack_rec    *stacked_bound_head;
      double            tilt;
                          // Degrees the plot is tilted after it is rotated.
      int               use_palette;
      TFrameWindow      *window_ptr;
      double            x;
      double            y_center;
      double            x_delta;
      int               x_division_num;
      double            x_eye;
      double            x_corner_max;
      double            y;
      double            y_delta;
      int               y_division_num;
      double            y_offset;
      double            y_corner_max;
      double            y_corner_min;
      double            z_center;
      double            z_offset;
      double            z_out_max;
      double            z_corner_max;
      double            z_corner_min;
    public:
                     plot3d(TFrameWindow *);

                     ~plot3d(void);

              char   plot(TRect &region_to_paint,int show_red,int only_plot_red,
               double bias=1.0);
//     This function returns 'S' if it is successful in generating the 3D plot.
//  It returns 'C' if it should be called again (because more work must be done
//  on the plot).  Otherwise, it returns 'F' indicating a failure.  Its
//  parameters are as follow:
//
//           region_to_paint -- only points in this rectangle will be plotted.
//
//           show_red -- highlight quadrilaterals having each vertex flagged
//      to be highlighted.  
//
//           only_plot_red -- only plot the quadrilaterals having each vertex
//      flagged to be highlighted.
//
//           bias -- a positive number used to adjust the contrast.
//
// "prepare_plot" must be called before "plot", after which "plot" may be called
// as many times as desired.

              char   prepare_plot(double (*f)(double,double),double x_min,
                      double x_max,double y_min,double y_max,
                      int (*external_to_plot)(double,double),
                      int (*red)(double,double),int x_division_count,
                      int y_division_count,double rotation_in_degrees,
                      double tilt_in_degrees,double light_x,double light_y,
                      double light_z);
//     This function returns 'S' if it is successful in preparing the plot for
//  generation.  It returns 'C' if it should be called again (because more work
//  must be done).  Otherwise, it returns 'F' indicating a failure.  Its
//  parameters are as follow:
//
//           f -- z=f(x,y), the function to be plotted.  Before the plot is
//      tilted or rotated, the z-axis runs from the bottom to the top of the
//      display, the y-axis runs from the left to the right of the display,
//      and the x-axis runs out of the display.
//
//           x_min -- the minimum value of x to be plotted.
//
//           x_max -- the maximum value of x to be plotted.
//
//           y_min -- the minimum value of y to be plotted.
//
//           y_max -- the maximum value of y to be plotted.
//
//           external_to_plot -- a function that returns TRUE if and only if a
//      point should be omitted from the plot.
//
//           red -- a function that returns TRUE if and only if a point should
//      be flagged for highlighting.  A point should be so flagged only if it
//      can be seen in the final plot.
//
//           x_division_count -- the number of x divisions to be used in
//      constructing the plot.  At least two must be specified.
//
//           y_division_count -- the number of y divisions to be used in
//      constructing the plot.  At least two must be specified.
//
//           rotation_in_degrees -- rotation (degrees) about an axis parallel to
//      the z-axis and through the center of the surface.
//
//           tilt_in_degrees -- tilt (degrees) about an axis through the center
//      of the surface and parallel to a line from the lower left hand corner of
//      the display to the lower right hand corner of the display.  The plot is
//      tilted after it is rotated.
//
//           (light_x,light_y,light_z) -- a vector pointing to the light source
//      (at infinity).  The light source remains fixed while the plot is rotated
//      or tilted.

              void   restart_plot(void);
  };

#endif
