home *** CD-ROM | disk | FTP | other *** search
- #include <owl\owlpch.h>
- #include <owl\applicat.h>
- #include <owl\framewin.h>
- #include <owl\dc.h>
- #include <string.h>
- #include <math.h>
- #include <stdlib.h>
- #include "plot3d.h"
-
- #ifndef TRUE
- #define TRUE -1
- #endif
- #ifndef FALSE
- #define FALSE 0
- #endif
-
- plot3d::plot3d(TFrameWindow *ptr)
- {
- window_ptr=ptr;
- TClientDC *dc=new TClientDC(*window_ptr);
- long num_colors_free=1L
- << (long(dc->GetDeviceCaps(PLANES))*long(dc->GetDeviceCaps(BITSPIXEL)));
- num_colors_free-=long(dc->GetDeviceCaps(NUMCOLORS));
- delete dc;
- if (num_colors_free < 16L)
- {
- use_palette=FALSE;
- num_colors=256;
- }
- else
- {
- use_palette=TRUE;
- if (num_colors_free > 256L)
- num_colors=256;
- else
- num_colors=int(num_colors_free);
- }
- corner_allocated=FALSE;
- plot_prepared=FALSE;
- prepare_plot_state='B';
- plot_state='B';
- int color_num;
- for (int color_index=0; color_index < (num_colors-1); color_index++)
- {
- color_num=int((255L*long(color_index))/long(num_colors-2));
- palette_entry[color_index].peRed=(BYTE) color_num;
- palette_entry[color_index].peGreen=(BYTE) color_num;
- palette_entry[color_index].peBlue=(BYTE) color_num;
- palette_entry[color_index].peFlags=(BYTE) PC_NOCOLLAPSE;
- }
- palette_entry[color_index].peRed=(BYTE) 255;
- palette_entry[color_index].peGreen=(BYTE) 0;
- palette_entry[color_index].peBlue=(BYTE) 0;
- palette_entry[color_index].peFlags=(BYTE) PC_NOCOLLAPSE;
- palette=new TPalette(&palette_entry[0],num_colors);
- lightest_gray=int((240L*long(num_colors-2))/254L);
- darkest_gray=(19*(num_colors-2))/254;
- }
-
- plot3d::~plot3d()
- {
- delete palette;
- if (corner_allocated)
- {
- for (x_division_num=(num_x_divisions-1); x_division_num >= 0;
- x_division_num--)
- delete[] corner[x_division_num--];
- delete[] corner;
- }
- }
-
- char plot3d::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.
- {
- char result;
-
- result='C';
- switch (prepare_plot_state)
- {
- case 'B': // begin
- plot_prepared=FALSE;
- if (corner_allocated)
- {
- for (x_division_num=(num_x_divisions-1); x_division_num >= 0;
- x_division_num--)
- delete[] corner[x_division_num--];
- delete[] corner;
- corner_allocated=FALSE;
- }
- num_x_divisions=x_division_count;
- num_y_divisions=y_division_count;
- corner_allocated
- =((corner=new corner_rec_ptr [num_x_divisions]) != NULL);
- for (x_division_num=0;
- ((corner_allocated) && (x_division_num < num_x_divisions));
- x_division_num++)
- if (corner_allocated=
- ((corner [x_division_num]=new corner_rec [num_y_divisions])
- != NULL))
- for (y_division_num=0; y_division_num < num_y_divisions;
- y_division_num++)
- {
- corner[x_division_num][y_division_num].base_z
- =(unsigned char) '\0';
- corner[x_division_num][y_division_num].color
- =(unsigned char) '\0';
- corner[x_division_num][y_division_num].x=(float) 0.0;
- corner[x_division_num][y_division_num].y=(float) 0.0;
- corner[x_division_num][y_division_num].z=(float) 0.0;
- corner[x_division_num][y_division_num].x_division_index=0;
- corner[x_division_num][y_division_num].y_division_index=0;
- };
- if (corner_allocated)
- {
- rotation=rotation_in_degrees;
- tilt=tilt_in_degrees;
- light.x=light_x;
- light.y=light_y;
- light.z=light_z;
- prepare_plot_state='E';
- TClientDC *dc=new TClientDC(*window_ptr);
- dc->PatBlt(window_ptr->GetClientRect(),WHITENESS);
- dc->TextOut(0,0,"Evaluating...");
- delete dc;
- x_division_num=0;
- y_division_num=0;
- }
- else
- {
- x_division_num--;
- while (x_division_num >= 0)
- delete[] corner[x_division_num--];
- delete[] corner;
- prepare_plot_state='F';
- result='F';
- }
- break;
- case 'E': // evaluate and transform
- evaluate_and_transform(f,x_min,x_max,y_min,y_max,
- num_x_divisions,num_y_divisions,rotation,tilt,
- external_to_plot,red);
- // Compute the vertices, etc. of the quadrilaterals composing the
- // plot.
- if (x_division_num >= num_x_divisions)
- {
- prepare_plot_state='H';
- TClientDC *dc=new TClientDC(*window_ptr);
- dc->PatBlt(window_ptr->GetClientRect(),WHITENESS);
- dc->TextOut(0,0,"Shading...");
- delete dc;
- x_division_num=num_x_divisions-1;
- y_division_num=num_y_divisions-1;
- }
- break;
- case 'H': // shade
- shade();
- // Compute the shade of gray for each quadrilateral composing the
- // plot.
- if (x_division_num < 0)
- {
- if (((y_corner_max-y_corner_min) > (z_corner_max-z_corner_min))
- || (z_corner_max != z_corner_min))
- {
- if ((y_corner_max-y_corner_min)
- > (z_corner_max-z_corner_min))
- x_eye=1.1*(y_corner_max-y_corner_min)+x_corner_max;
- else
- x_eye=1.1*(z_corner_max-z_corner_min)+x_corner_max;
- prepare_plot_state='A';
- TClientDC *dc=new TClientDC(*window_ptr);
- dc->PatBlt(window_ptr->GetClientRect(),WHITENESS);
- dc->TextOut(0,0,"Adjusting perspective...");
- delete dc;
- x_division_num=0;
- y_division_num=0;
- }
- else
- {
- stacked_bound_head=new sort_stack_rec;
- stacked_bound_head->bound.lower_x=0;
- stacked_bound_head->bound.lower_y=0;
- stacked_bound_head->bound.upper_x=(num_x_divisions-1);
- stacked_bound_head->bound.upper_y=(num_y_divisions-1);
- stacked_bound_head->previous=NULL;
- prepare_plot_state='S';
- TClientDC *dc=new TClientDC(*window_ptr);
- dc->PatBlt(window_ptr->GetClientRect(),WHITENESS);
- dc->TextOut(0,0,"Sorting...");
- delete dc;
- }
- }
- break;
- case 'A': // adjust perspective
- adjust_perspective();
- // Force parallel lines running away from the viewer to converge
- // at the horizon.
- if (x_division_num >= num_x_divisions)
- {
- stacked_bound_head=new sort_stack_rec;
- stacked_bound_head->bound.lower_x=0;
- stacked_bound_head->bound.lower_y=0;
- stacked_bound_head->bound.upper_x=(num_x_divisions-1);
- stacked_bound_head->bound.upper_y=(num_y_divisions-1);
- stacked_bound_head->previous=NULL;
- prepare_plot_state='S';
- TClientDC *dc=new TClientDC(*window_ptr);
- dc->PatBlt(window_ptr->GetClientRect(),WHITENESS);
- dc->TextOut(0,0,"Sorting...");
- delete dc;
- }
- break;
- case 'S': // sort back to front
- sort_back_to_front();
- if (stacked_bound_head == NULL)
- {
- prepare_plot_state='D';
- TClientDC *dc=new TClientDC(*window_ptr);
- dc->PatBlt(window_ptr->GetClientRect(),WHITENESS);
- delete dc;
- }
- break;
- case 'F': // failed
- result='F';
- break;
- default: // done
- plot_prepared=TRUE;
- result='S';
- break;
- }
- return result;
- }
-
- void plot3d::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))
- // Compute the vertices, etc. for each quadrilateral composing the plot.
- {
- double tem_x;
- double tem_y;
- double tem_z;
- double x_rotated;
- double z;
-
- if ((x_division_num == 0) && (y_division_num == 0))
- {
- double degrees_per_radian=45.0/atan(1.0);
- radians=tilt/degrees_per_radian;
- cos_tilt=cos(radians);
- sin_tilt=sin(radians);
- radians=rotation/degrees_per_radian;
- cos_rotation=cos(radians);
- sin_rotation=sin(radians);
- z=f(x_min,y_min);
- x_rotated=x_min*cos_rotation+y_min*sin_rotation;
- y_corner_min=-x_min*sin_rotation+y_min*cos_rotation;
- z_corner_min=-x_rotated*sin_tilt+z*cos_tilt;
- y_corner_max=y_corner_min;
- z_corner_max=z_corner_min;
- x_corner_max=x_rotated*cos_tilt+z*sin_tilt;
- x_delta=(double) (num_x_divisions-1);
- x_delta=(x_max-x_min)/x_delta;
- y_delta=(double) (num_y_divisions-1);
- y_delta=(y_max-y_min)/y_delta;
- x=x_min;
- y=y_min;
- }
- int finished=FALSE;
- DWORD start_time=GetTickCount();
- DWORD current_time;
- while ((! finished) && (x_division_num < num_x_divisions))
- {
- z=f(x,y);
- if (external_to_plot(x,y))
- corner[x_division_num][y_division_num].base_z=(unsigned char) 3;
- else
- if (red(x,y))
- corner[x_division_num][y_division_num].base_z=(unsigned char) 2;
- else
- corner[x_division_num][y_division_num].base_z=(unsigned char) 1;
- corner[x_division_num][y_division_num].x_division_index
- =x_division_num;
- corner[x_division_num][y_division_num].y_division_index
- =y_division_num;
- x_rotated=x*cos_rotation+y*sin_rotation;
- tem_y=(-x*sin_rotation+y*cos_rotation);
- corner[x_division_num][y_division_num].y=(float) tem_y;
- tem_x=(x_rotated*cos_tilt+z*sin_tilt);
- corner[x_division_num][y_division_num].x=(float) tem_x;
- tem_z=(-x_rotated*sin_tilt+z*cos_tilt);
- corner[x_division_num][y_division_num].z=(float) tem_z;
- if (tem_x > x_corner_max)
- x_corner_max=tem_x;
- if (tem_y < y_corner_min)
- y_corner_min=tem_y;
- if (tem_y > y_corner_max)
- y_corner_max=tem_y;
- if (tem_z < z_corner_min)
- z_corner_min=tem_z;
- if (tem_z > z_corner_max)
- z_corner_max=tem_z;
- y+=y_delta;
- y_division_num++;
- if (y_division_num >= num_y_divisions)
- {
- y_division_num=0;
- y=y_min;
- x+=x_delta;
- x_division_num++;
- }
- current_time=GetTickCount();
- finished=((current_time < start_time)
- || ((current_time-start_time) > 100));
- }
- if (x_division_num >= num_x_divisions)
- {
- double magnitude=light.x*light.x+light.y*light.y+light.z*light.z;
- magnitude=sqrt(magnitude);
- light.x=light.x/magnitude;
- light.y=light.y/magnitude;
- light.z=light.z/magnitude;
- }
- return;
- }
-
- void plot3d::shade()
- // Compute the shade of gray for each quadrilateral composing the plot.
- {
- int color_num;
- double magnitude;
- vertex_rec normal;
- vertex_rec vertex [4];
-
- if ((x_division_num == (num_x_divisions-1))
- && (y_division_num == (num_y_divisions-1)))
- {
- color_min=(unsigned char) (num_colors-1);
- color_max=(unsigned char) '\0';
- }
- int finished=FALSE;
- DWORD start_time=GetTickCount();
- DWORD current_time;
- while ((! finished) && (x_division_num >= 0))
- {
- vertex[0].x=(double) (corner[x_division_num][y_division_num].x);
- vertex[0].y=(double) (corner[x_division_num][y_division_num].y);
- vertex[0].z=(double) (corner[x_division_num][y_division_num].z);
- if (x_division_num < (num_x_divisions-1))
- if (y_division_num < (num_y_divisions-1))
- {
- x_division_num++;
- vertex[1].x=(double) (corner[x_division_num][y_division_num].x);
- vertex[1].y=(double) (corner[x_division_num][y_division_num].y);
- vertex[1].z=(double) (corner[x_division_num][y_division_num].z);
- y_division_num++;
- vertex[2].x=(double) (corner[x_division_num][y_division_num].x);
- vertex[2].y=(double) (corner[x_division_num][y_division_num].y);
- vertex[2].z=(double) (corner[x_division_num][y_division_num].z);
- x_division_num--;
- vertex[3].x=(double) (corner[x_division_num][y_division_num].x);
- vertex[3].y=(double) (corner[x_division_num][y_division_num].y);
- vertex[3].z=(double) (corner[x_division_num][y_division_num].z);
- y_division_num--;
- }
- else
- {
- y_division_num--;
- vertex[1].x=(double) (corner[x_division_num][y_division_num].x);
- vertex[1].y=(double) (corner[x_division_num][y_division_num].y);
- vertex[1].z=(double) (corner[x_division_num][y_division_num].z);
- x_division_num++;
- vertex[2].x=(double) (corner[x_division_num][y_division_num].x);
- vertex[2].y=(double) (corner[x_division_num][y_division_num].y);
- vertex[2].z=(double) (corner[x_division_num][y_division_num].z);
- y_division_num++;
- vertex[3].x=(double) (corner[x_division_num][y_division_num].x);
- vertex[3].y=(double) (corner[x_division_num][y_division_num].y);
- vertex[3].z=(double) (corner[x_division_num][y_division_num].z);
- x_division_num--;
- }
- else
- if (y_division_num < (num_y_divisions-1))
- {
- y_division_num++;
- vertex[1].x=(double) (corner[x_division_num][y_division_num].x);
- vertex[1].y=(double) (corner[x_division_num][y_division_num].y);
- vertex[1].z=(double) (corner[x_division_num][y_division_num].z);
- x_division_num--;
- vertex[2].x=(double) (corner[x_division_num][y_division_num].x);
- vertex[2].y=(double) (corner[x_division_num][y_division_num].y);
- vertex[2].z=(double) (corner[x_division_num][y_division_num].z);
- y_division_num--;
- vertex[3].x=(double) (corner[x_division_num][y_division_num].x);
- vertex[3].y=(double) (corner[x_division_num][y_division_num].y);
- vertex[3].z=(double) (corner[x_division_num][y_division_num].z);
- x_division_num++;
- }
- else
- {
- x_division_num--;
- vertex[1].x=(double) (corner[x_division_num][y_division_num].x);
- vertex[1].y=(double) (corner[x_division_num][y_division_num].y);
- vertex[1].z=(double) (corner[x_division_num][y_division_num].z);
- y_division_num--;
- vertex[2].x=(double) (corner[x_division_num][y_division_num].x);
- vertex[2].y=(double) (corner[x_division_num][y_division_num].y);
- vertex[2].z=(double) (corner[x_division_num][y_division_num].z);
- x_division_num++;
- vertex[3].x=(double) (corner[x_division_num][y_division_num].x);
- vertex[3].y=(double) (corner[x_division_num][y_division_num].y);
- vertex[3].z=(double) (corner[x_division_num][y_division_num].z);
- y_division_num++;
- }
- // Compute the normal to a quadrilateral by averaging the
- // normals to each vertex of the quadrilateral.
- normal.x
- =(vertex[1].y-vertex[0].y)*(vertex[3].z-vertex[0].z)
- -(vertex[3].y-vertex[0].y)*(vertex[1].z-vertex[0].z)
- +(vertex[2].y-vertex[1].y)*(vertex[0].z-vertex[1].z)
- -(vertex[0].y-vertex[1].y)*(vertex[2].z-vertex[1].z)
- +(vertex[3].y-vertex[2].y)*(vertex[1].z-vertex[2].z)
- -(vertex[1].y-vertex[2].y)*(vertex[3].z-vertex[2].z)
- +(vertex[0].y-vertex[3].y)*(vertex[2].z-vertex[3].z)
- -(vertex[2].y-vertex[3].y)*(vertex[0].z-vertex[3].z);
- normal.y
- =(vertex[3].x-vertex[0].x)*(vertex[1].z-vertex[0].z)
- -(vertex[1].x-vertex[0].x)*(vertex[3].z-vertex[0].z)
- +(vertex[0].x-vertex[1].x)*(vertex[2].z-vertex[1].z)
- -(vertex[2].x-vertex[1].x)*(vertex[0].z-vertex[1].z)
- +(vertex[1].x-vertex[2].x)*(vertex[3].z-vertex[2].z)
- -(vertex[3].x-vertex[2].x)*(vertex[1].z-vertex[2].z)
- +(vertex[2].x-vertex[3].x)*(vertex[0].z-vertex[3].z)
- -(vertex[0].x-vertex[3].x)*(vertex[2].z-vertex[3].z);
- normal.z
- =(vertex[1].x-vertex[0].x)*(vertex[3].y-vertex[0].y)
- -(vertex[3].x-vertex[0].x)*(vertex[1].y-vertex[0].y)
- +(vertex[2].x-vertex[1].x)*(vertex[0].y-vertex[1].y)
- -(vertex[0].x-vertex[1].x)*(vertex[2].y-vertex[1].y)
- +(vertex[3].x-vertex[2].x)*(vertex[1].y-vertex[2].y)
- -(vertex[1].x-vertex[2].x)*(vertex[3].y-vertex[2].y)
- +(vertex[0].x-vertex[3].x)*(vertex[2].y-vertex[3].y)
- -(vertex[2].x-vertex[3].x)*(vertex[0].y-vertex[3].y);
- magnitude
- =sqrt(normal.x*normal.x+normal.y*normal.y+normal.z*normal.z);
- if (magnitude == 0.0)
- {
- color_min=(unsigned char) '\0';
- corner[x_division_num][y_division_num].color=(unsigned char) '\0';
- }
- else
- {
- color_num=int((double(num_colors)/2.0)
- *(1.0+(light.x*normal.x+light.y*normal.y
- +light.z*normal.z)/magnitude)); // shadows not absolute
- if (color_num >= num_colors)
- color_num=num_colors-1;
- corner[x_division_num][y_division_num].color
- =(unsigned char) color_num;
- if ((corner[x_division_num][y_division_num].color) < color_min)
- color_min=(corner[x_division_num][y_division_num].color);
- if ((corner[x_division_num][y_division_num].color) > color_max)
- color_max=(corner[x_division_num][y_division_num].color);
- }
- y_division_num--;
- if (y_division_num < 0)
- {
- y_division_num=num_y_divisions-1;
- x_division_num--;
- }
- current_time=GetTickCount();
- finished=((current_time < start_time)
- || ((current_time-start_time) > 100));
- }
- return;
- }
-
- void plot3d::adjust_perspective()
- // Make parallel lines running away from the viewer appear to converge at the
- // horizon.
- {
- double tem;
- vertex_rec vertex [4];
-
- if ((x_division_num == 0) && (y_division_num == 0))
- {
- y_center=(y_corner_max+y_corner_min)/2.0;
- z_center=(z_corner_max+z_corner_min)/2.0;
- }
- int finished=FALSE;
- DWORD start_time=GetTickCount();
- DWORD current_time;
- while ((! finished) && (x_division_num < num_x_divisions))
- {
- vertex[0].x=(double) (corner[x_division_num][y_division_num].x);
- vertex[0].y=(double) (corner[x_division_num][y_division_num].y);
- vertex[0].z=(double) (corner[x_division_num][y_division_num].z);
- if (x_division_num < (num_x_divisions-1))
- if (y_division_num < (num_y_divisions-1))
- {
- x_division_num++;
- vertex[1].x=(double) (corner[x_division_num][y_division_num].x);
- vertex[1].y=(double) (corner[x_division_num][y_division_num].y);
- vertex[1].z=(double) (corner[x_division_num][y_division_num].z);
- y_division_num++;
- vertex[2].x=(double) (corner[x_division_num][y_division_num].x);
- vertex[2].y=(double) (corner[x_division_num][y_division_num].y);
- vertex[2].z=(double) (corner[x_division_num][y_division_num].z);
- x_division_num--;
- vertex[3].x=(double) (corner[x_division_num][y_division_num].x);
- vertex[3].y=(double) (corner[x_division_num][y_division_num].y);
- vertex[3].z=(double) (corner[x_division_num][y_division_num].z);
- y_division_num--;
- }
- else
- {
- y_division_num--;
- vertex[1].x=(double) (corner[x_division_num][y_division_num].x);
- vertex[1].y=(double) (corner[x_division_num][y_division_num].y);
- vertex[1].z=(double) (corner[x_division_num][y_division_num].z);
- x_division_num++;
- vertex[2].x=(double) (corner[x_division_num][y_division_num].x);
- vertex[2].y=(double) (corner[x_division_num][y_division_num].y);
- vertex[2].z=(double) (corner[x_division_num][y_division_num].z);
- y_division_num++;
- vertex[3].x=(double) (corner[x_division_num][y_division_num].x);
- vertex[3].y=(double) (corner[x_division_num][y_division_num].y);
- vertex[3].z=(double) (corner[x_division_num][y_division_num].z);
- x_division_num--;
- }
- else
- if (y_division_num < (num_y_divisions-1))
- {
- y_division_num++;
- vertex[1].x=(double) (corner[x_division_num][y_division_num].x);
- vertex[1].y=(double) (corner[x_division_num][y_division_num].y);
- vertex[1].z=(double) (corner[x_division_num][y_division_num].z);
- x_division_num--;
- vertex[2].x=(double) (corner[x_division_num][y_division_num].x);
- vertex[2].y=(double) (corner[x_division_num][y_division_num].y);
- vertex[2].z=(double) (corner[x_division_num][y_division_num].z);
- y_division_num--;
- vertex[3].x=(double) (corner[x_division_num][y_division_num].x);
- vertex[3].y=(double) (corner[x_division_num][y_division_num].y);
- vertex[3].z=(double) (corner[x_division_num][y_division_num].z);
- x_division_num++;
- }
- else
- {
- x_division_num--;
- vertex[1].x=(double) (corner[x_division_num][y_division_num].x);
- vertex[1].y=(double) (corner[x_division_num][y_division_num].y);
- vertex[1].z=(double) (corner[x_division_num][y_division_num].z);
- y_division_num--;
- vertex[2].x=(double) (corner[x_division_num][y_division_num].x);
- vertex[2].y=(double) (corner[x_division_num][y_division_num].y);
- vertex[2].z=(double) (corner[x_division_num][y_division_num].z);
- x_division_num++;
- vertex[3].x=(double) (corner[x_division_num][y_division_num].x);
- vertex[3].y=(double) (corner[x_division_num][y_division_num].y);
- vertex[3].z=(double) (corner[x_division_num][y_division_num].z);
- y_division_num++;
- }
- tem=y_center
- +(vertex[0].y-y_center)*(x_eye-x_corner_max)
- /(x_eye-vertex[0].x);
- corner[x_division_num][y_division_num].y=(float) tem;
- tem=z_center
- +(vertex[0].z-z_center)*(x_eye-x_corner_max)
- /(x_eye-vertex[0].x);
- corner[x_division_num][y_division_num].z=(float) tem;
- tem=(vertex[0].x+vertex[1].x+vertex[2].x+vertex[3].x)/4.0;
- corner[x_division_num][y_division_num].x=(float) tem;
- y_division_num++;
- if (y_division_num >= num_y_divisions)
- {
- y_division_num=0;
- x_division_num++;
- }
- current_time=GetTickCount();
- finished=((current_time < start_time)
- || ((current_time-start_time) > 100));
- }
- return;
- }
-
- void plot3d::rearrange(
- int lower_bound_x,
- int lower_bound_y,
- int upper_bound_x,
- int upper_bound_y,
- int *j_x,
- int *j_y)
- {
- int down_x;
- int down_y;
- int finished;
- int up_x;
- int up_y;
- float x1;
- int x_division_index1;
- int y_division_index1;
-
- x1=corner[lower_bound_x][lower_bound_y].x;
- x_division_index1=corner[lower_bound_x][lower_bound_y].x_division_index;
- y_division_index1=corner[lower_bound_x][lower_bound_y].y_division_index;
- *j_x=lower_bound_x;
- *j_y=lower_bound_y;
- up_x=upper_bound_x;
- up_y=upper_bound_y;
- down_x=lower_bound_x;
- down_y=lower_bound_y;
- do
- {
- finished=FALSE;
- while (! finished)
- {
- if ((up_x < down_x)
- || ((up_x == down_x) && (up_y <= down_y)))
- finished=TRUE;
- else
- if (corner[up_x][up_y].x < x1)
- finished=TRUE;
- else
- {
- if (--up_y < 0)
- {
- up_y=num_y_divisions-1;
- up_x--;
- }
- }
- }
- *j_x=up_x;
- *j_y=up_y;
- if ((up_x != down_x) || (up_y != down_y))
- {
- corner[down_x][down_y].x=corner[up_x][up_y].x;
- corner[down_x][down_y].x_division_index
- =corner[up_x][up_y].x_division_index;
- corner[down_x][down_y].y_division_index
- =corner[up_x][up_y].y_division_index;
- finished=FALSE;
- while (! finished)
- {
- if ((down_x > up_x)
- || ((down_x == up_x) && (down_y >= up_y)))
- finished=TRUE;
- else
- if (corner[down_x][down_y].x > x1)
- finished=TRUE;
- else
- {
- if (++down_y >= num_y_divisions)
- {
- down_y=0;
- down_x++;
- }
- }
- }
- *j_x=down_x;
- *j_y=down_y;
- if ((down_x != up_x) || (down_y != up_y))
- {
- corner[up_x][up_y].x=corner[down_x][down_y].x;
- corner[up_x][up_y].x_division_index
- =corner[down_x][down_y].x_division_index;
- corner[up_x][up_y].y_division_index
- =corner[down_x][down_y].y_division_index;
- }
- }
- }
- while ((down_x != up_x) || (down_y != up_y));
- corner[*j_x][*j_y].x=x1;
- corner[*j_x][*j_y].x_division_index=x_division_index1;
- corner[*j_x][*j_y].y_division_index=y_division_index1;
- return;
- }
-
- void plot3d::sort_back_to_front()
- // The painter's algorithm is used; items farther from the viewer are drawn
- // earlier.
- {
- int i_x;
- int i_y;
- int j_x;
- int j_y;
- sort_bound_rec stacked_bound;
- sort_stack_rec *stacked_bound_ptr;
-
- int finished=FALSE;
- DWORD start_time=GetTickCount();
- DWORD current_time;
- while ((! finished) && (stacked_bound_head != NULL))
- {
- stacked_bound.lower_x=stacked_bound_head->bound.lower_x;
- stacked_bound.lower_y=stacked_bound_head->bound.lower_y;
- stacked_bound.upper_x=stacked_bound_head->bound.upper_x;
- stacked_bound.upper_y=stacked_bound_head->bound.upper_y;
- stacked_bound_ptr=stacked_bound_head;
- stacked_bound_head=stacked_bound_head->previous;
- delete stacked_bound_ptr;
- while ((stacked_bound.upper_x > stacked_bound.lower_x)
- || ((stacked_bound.upper_x == stacked_bound.lower_x)
- && (stacked_bound.upper_y > stacked_bound.lower_y)))
- {
- rearrange(stacked_bound.lower_x,stacked_bound.lower_y,
- stacked_bound.upper_x,stacked_bound.upper_y,&j_x,&j_y);
- if (long(num_y_divisions)*long(j_x-stacked_bound.lower_x)
- +(j_y-stacked_bound.lower_y)
- > long(num_y_divisions)*long(stacked_bound.upper_x-j_x)
- +(stacked_bound.upper_y-j_y))
- {
- i_x=stacked_bound.upper_x;
- i_y=stacked_bound.upper_y;
- stacked_bound.upper_y=j_y-1;
- stacked_bound.upper_x=j_x;
- if (stacked_bound.upper_y < 0)
- {
- stacked_bound.upper_y=num_y_divisions-1;
- (stacked_bound.upper_x)--;
- }
- stacked_bound_ptr=new sort_stack_rec;
- stacked_bound_ptr->bound.lower_x=stacked_bound.lower_x;
- stacked_bound_ptr->bound.lower_y=stacked_bound.lower_y;
- stacked_bound_ptr->bound.upper_x=stacked_bound.upper_x;
- stacked_bound_ptr->bound.upper_y=stacked_bound.upper_y;
- stacked_bound_ptr->previous=stacked_bound_head;
- stacked_bound_head=stacked_bound_ptr;
- stacked_bound.lower_y=j_y+1;
- stacked_bound.lower_x=j_x;
- if (stacked_bound.lower_y >= num_y_divisions)
- {
- stacked_bound.lower_y=0;
- (stacked_bound.lower_x)++;
- }
- stacked_bound.upper_x=i_x;
- stacked_bound.upper_y=i_y;
- }
- else
- {
- i_x=stacked_bound.lower_x;
- i_y=stacked_bound.lower_y;
- stacked_bound.lower_y=j_y+1;
- stacked_bound.lower_x=j_x;
- if (stacked_bound.lower_y >= num_y_divisions)
- {
- stacked_bound.lower_y=0;
- (stacked_bound.lower_x)++;
- }
- stacked_bound_ptr=new sort_stack_rec;
- stacked_bound_ptr->bound.lower_x=stacked_bound.lower_x;
- stacked_bound_ptr->bound.lower_y=stacked_bound.lower_y;
- stacked_bound_ptr->bound.upper_x=stacked_bound.upper_x;
- stacked_bound_ptr->bound.upper_y=stacked_bound.upper_y;
- stacked_bound_ptr->previous=stacked_bound_head;
- stacked_bound_head=stacked_bound_ptr;
- stacked_bound.lower_x=i_x;
- stacked_bound.lower_y=i_y;
- stacked_bound.upper_y=j_y-1;
- stacked_bound.upper_x=j_x;
- if (stacked_bound.upper_y < 0)
- {
- stacked_bound.upper_y=num_y_divisions-1;
- (stacked_bound.upper_x)--;
- }
- }
- }
- current_time=GetTickCount();
- finished=((current_time < start_time)
- || ((current_time-start_time) > 100));
- }
- return;
- }
-
- char plot3d::plot(
- TRect ®ion_to_paint,
- int show_red,
- int only_plot_red,
- double bias)
- // 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.
- {
- TPoint box [4];
- int box_num;
- int color_num;
- DWORD current_time;
- int finished;
- double fraction;
- int outside_maze;
- int red_showing;
- char result;
- DWORD start_time;
- vertex_rec vertex [4];
- int x_division_index;
- int y_division_index;
- double y_out_max;
-
- if (plot_prepared)
- {
- result='C';
- TClientDC *dc=new TClientDC(*window_ptr);
- TRect ClipBox;
- if (dc->GetClipBox(ClipBox) != NULLREGION)
- switch (plot_state)
- {
- case 'B': // begin
- aspect_ratio
- =(double(dc->GetDeviceCaps(VERTSIZE))
- /double(dc->GetDeviceCaps(HORZSIZE)))
- /(double(dc->GetDeviceCaps(VERTRES))
- /double(dc->GetDeviceCaps(HORZRES)));
- y_out_max=double(window_ptr->GetClientRect().Width()-1);
- z_out_max=double(window_ptr->GetClientRect().Height()-1);
- if (aspect_ratio*z_out_max*(y_corner_max-y_corner_min)
- > y_out_max*(z_corner_max-z_corner_min))
- {
- pixels_per_unit
- =y_out_max/(aspect_ratio*(y_corner_max-y_corner_min));
- y_offset=0.0;
- z_offset
- =-(z_out_max-pixels_per_unit*(z_corner_max-z_corner_min))
- /2.0;
- }
- else
- if (aspect_ratio*z_out_max*(y_corner_max-y_corner_min)
- < y_out_max*(z_corner_max-z_corner_min))
- {
- pixels_per_unit=z_out_max/(z_corner_max-z_corner_min);
- y_offset=(y_out_max
- -aspect_ratio*pixels_per_unit
- *(y_corner_max-y_corner_min))/2.0;
- z_offset=0.0;
- }
- else
- {
- pixels_per_unit=1.0;
- y_offset=y_out_max/2.0;
- z_offset=-z_out_max/2.0;
- }
- x_division_num=y_division_num=0;
- plot_state='P';
- break;
- case 'P': // plot
- finished=FALSE;
- start_time=GetTickCount();
- while ((! finished) && (x_division_num < num_x_divisions))
- {
- x_division_index
- =corner[x_division_num][y_division_num].x_division_index;
- if (x_division_index < (num_x_divisions-1))
- {
- y_division_index=corner[x_division_num][
- y_division_num].y_division_index;
- if (y_division_index < (num_y_divisions-1))
- {
- color_num=int(corner[x_division_index][
- y_division_index].color);
- // Adjust contrast.
- fraction=((double) (color_num-int(color_min)))
- /((double) (color_max-color_min));
- if (fraction > 0.0)
- {
- fraction=exp(bias*log(fraction));
- color_num=(int)
- (((double) (lightest_gray-darkest_gray))
- *fraction
- +((double) darkest_gray));
- }
- else
- color_num=darkest_gray;
- vertex[0].y=(double)
- (corner[x_division_index][y_division_index].y);
- vertex[0].z=(double)
- (corner[x_division_index][y_division_index].z);
- red_showing=(corner[x_division_index][
- y_division_index].base_z == (unsigned char) 2);
- outside_maze=(corner[x_division_index][
- y_division_index].base_z == (unsigned char) 3);
- x_division_index++;
- vertex[1].y=(double)
- (corner[x_division_index][y_division_index].y);
- vertex[1].z=(double)
- (corner[x_division_index][y_division_index].z);
- if (red_showing)
- red_showing=(corner[x_division_index][
- y_division_index].base_z == (unsigned char) 2);
- if (outside_maze)
- outside_maze=(corner[x_division_index][
- y_division_index].base_z == (unsigned char) 3);
- y_division_index++;
- vertex[2].y=(double)
- (corner[x_division_index][y_division_index].y);
- vertex[2].z=(double)
- (corner[x_division_index][y_division_index].z);
- if (red_showing)
- red_showing=(corner[x_division_index][
- y_division_index].base_z == (unsigned char) 2);
- if (outside_maze)
- outside_maze=(corner[x_division_index][
- y_division_index].base_z == (unsigned char) 3);
- x_division_index--;
- vertex[3].y=(double)
- (corner[x_division_index][y_division_index].y);
- vertex[3].z=(double)
- (corner[x_division_index][y_division_index].z);
- if (red_showing)
- red_showing=(corner[x_division_index][
- y_division_index].base_z == (unsigned char) 2);
- if (outside_maze)
- outside_maze=(corner[x_division_index][
- y_division_index].base_z == (unsigned char) 3);
- if (((! only_plot_red) || (red_showing))
- && (! outside_maze))
- // Plot each point in a quadrilateral.
- {
- for (box_num=0; box_num < 4; box_num++)
- {
- box[box_num].x=(int) (y_offset
- +pixels_per_unit*aspect_ratio
- *(vertex[box_num].y-y_corner_min));
- box[box_num].y
- =(int) (z_offset+z_out_max
- -pixels_per_unit
- *(vertex[box_num].z-z_corner_min));
- }
- dc->SelectClipRgn(region_to_paint);
- if (use_palette)
- {
- dc->SelectObject(*palette);
- dc->RealizePalette();
- if ((show_red) && (red_showing))
- {
- TColor palColor(num_colors-1);
- TBrush brush(palColor);
- dc->SelectObject(brush);
- TPen pen(palColor,1,PS_NULL);
- dc->SelectObject(pen);
- dc->Polygon(&box[0],4);
- dc->RestorePen();
- dc->RestoreBrush();
- }
- else
- {
- TColor palColor(color_num);
- TBrush brush(palColor);
- dc->SelectObject(brush);
- TPen pen(palColor,1,PS_NULL);
- dc->SelectObject(pen);
- dc->Polygon(&box[0],4);
- dc->RestorePen();
- dc->RestoreBrush();
- }
- dc->RestorePalette();
- }
- else
- {
- if ((show_red) && (red_showing))
- {
- TBrush brush(RGB(255,0,0));
- dc->SelectObject(brush);
- TPen pen(RGB(255,0,0),1,PS_NULL);
- dc->SelectObject(pen);
- dc->Polygon(&box[0],4);
- dc->RestorePen();
- dc->RestoreBrush();
- }
- else
- {
- TBrush brush(RGB(color_num,color_num,
- color_num));
- dc->SelectObject(brush);
- TPen pen(RGB(color_num,color_num,
- color_num),1,PS_NULL);
- dc->SelectObject(pen);
- dc->Polygon(&box[0],4);
- dc->RestorePen();
- dc->RestoreBrush();
- }
- }
- }
- }
- }
- if (++y_division_num >= num_y_divisions)
- {
- y_division_num=0;
- x_division_num++;
- }
- current_time=GetTickCount();
- finished=((current_time < start_time)
- || ((current_time-start_time) > 100));
- }
- if (x_division_num >= num_x_divisions)
- plot_state='S';
- break;
- case 'F': // failed
- result='F';
- break;
- default: // done
- result='S';
- break;
- }
- delete dc;
- }
- else
- {
- result='F'; // attempt to plot before prepared
- window_ptr->MessageBox("Attempt to plot before prepared!",
- window_ptr->GetApplication()->GetName(),
- MB_OK | MB_ICONEXCLAMATION);
- }
- return result;
- }
-
-
- void plot3d::restart_plot()
- {
- if (plot_prepared)
- plot_state='B';
- }
-