home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 22 gnu / 22-gnu.zip / gnuplapi.zip / gnuplot-api-os2 / build / pm3d.c < prev    next >
Encoding:
C/C++ Source or Header  |  1999-07-21  |  10.0 KB  |  330 lines

  1. /* GNUPLOT - pm3d.c */
  2.  
  3. /*[
  4.  *
  5.  * Petr Mikulik, December 1998 -- July 1999
  6.  * Copyright: open source as much as possible
  7.  *
  8.  * 
  9.  * What is here: global variables and routines for the pm3d splotting mode
  10.  * This file is included only if PM3D is defined
  11.  *
  12. ]*/
  13.  
  14.  
  15. #include "plot.h"
  16. #include "pm3d.h"
  17.  
  18.  
  19. /********************************************************************/
  20.  
  21. /*
  22.   Global options for pm3d algorithm (to be accessed by set / show)
  23. */
  24.  
  25. pm3d_struct pm3d = {
  26.   "",            /* where[6] */
  27.   PM3D_FLUSH_BEGIN,    /* flush */
  28.   PM3D_SCANS_FORWARD,   /* scans taken in forward direction */
  29.   PM3D_CLIP_1IN,    /* clipping: at least 1 point in the ranges */
  30.   0, 0,         /* use zmin, zmax from `set zrange` */
  31.   0.0, 100.0        /* pm3d's zmin, zmax */
  32.   };
  33.  
  34.  
  35. /* global variables */
  36. double used_pm3d_zmin, used_pm3d_zmax;
  37.  
  38.  
  39. /****************************************************************/
  40. /* Now the routines which are really those exactly for pm3d.c
  41. */
  42.  
  43. /* declare variables and routines from external files */
  44. extern struct surface_points *first_3dplot;
  45.  
  46. void map3d_xy(double x, double y, double z, /* from graph3d.c */
  47.   unsigned int *xt, unsigned int *yt);
  48.  
  49. extern double min_array[], max_array[];
  50.  
  51.  
  52. /*
  53.    Check and set the z-range for use by pm3d
  54.    Return 0 on wrong range, otherwise 1
  55. */
  56. int set_pm3d_zminmax ()
  57. {
  58. extern double log_base_array[];
  59. extern TBOOLEAN is_log_z;
  60. if (!pm3d.pm3d_zmin)
  61.     used_pm3d_zmin = min_array[FIRST_Z_AXIS];
  62.   else {
  63.     used_pm3d_zmin = pm3d.zmin;
  64.     if (is_log_z) {
  65.       if (used_pm3d_zmin<0) {
  66.     fprintf(stderr,"pm3d: log of negative z-min?\n");
  67.     return 0;
  68.     }
  69.       used_pm3d_zmin = log(used_pm3d_zmin)/log_base_array[FIRST_Z_AXIS];
  70.       }
  71.     }
  72. if (!pm3d.pm3d_zmax)
  73.     used_pm3d_zmax = max_array[FIRST_Z_AXIS];
  74.   else {
  75.     used_pm3d_zmax = pm3d.zmax;
  76.     if (is_log_z) {
  77.       if (used_pm3d_zmax<0) {
  78.     fprintf(stderr,"p3md: log of negative z-max?\n");
  79.     return 0;
  80.     }
  81.       used_pm3d_zmax = log(used_pm3d_zmax)/log_base_array[FIRST_Z_AXIS];
  82.       }
  83.     }
  84. if (used_pm3d_zmin == used_pm3d_zmax) {
  85.   fprintf(stderr,"pm3d: colouring requires not equal zmin and zmax\n");
  86.   return 0;
  87.   }
  88. if (used_pm3d_zmin > used_pm3d_zmax) { /* exchange min and max values */
  89.   double tmp = used_pm3d_zmax;
  90.   used_pm3d_zmax = used_pm3d_zmin;
  91.   used_pm3d_zmin = tmp;
  92.   }
  93. return 1;
  94. }
  95.  
  96.  
  97. /*
  98.   Rescale z into the interval [0,1]. It's OK also for logarithmic z axis too
  99. */
  100. double z2gray ( double z )
  101. {
  102. if ( z <= used_pm3d_zmin ) return 0;
  103. if ( z >= used_pm3d_zmax ) return 1;
  104. z = ( z - used_pm3d_zmin ) / ( used_pm3d_zmax - used_pm3d_zmin );
  105. return z;
  106. }
  107.  
  108.  
  109.  
  110.  
  111.  
  112. /*
  113.    Now the implementation of the pm3d (s)plotting mode
  114. */
  115.  
  116. void pm3d_plot ( this_plot, at_which_z )
  117. struct surface_points *this_plot;
  118. char at_which_z;
  119. {
  120. int i, ii, from, curve, scan, up_to;
  121. struct iso_curve *scanA, *scanB;
  122. struct coordinate GPHUGE *pointsA, *pointsB;
  123. struct iso_curve **scan_array;
  124. double avgZ, gray;
  125. gpdPoint corners[4];
  126. extern double base_z, ceiling_z; /* defined in graph3d.c */
  127.  
  128. if (this_plot == NULL)
  129.   return;
  130.  
  131. if (at_which_z != PM3D_AT_BASE && at_which_z != PM3D_AT_TOP && at_which_z != PM3D_AT_SURFACE)
  132.   return;
  133.  
  134. /* return if the terminal does not support filled polygons */
  135. if (!term->filled_polygon) return;
  136.  
  137. switch (at_which_z) {
  138.   case PM3D_AT_BASE:
  139.     corners[0].z = corners[1].z = corners[2].z = corners[3].z = base_z;
  140.     break;
  141.   case PM3D_AT_TOP:
  142.     corners[0].z = corners[1].z = corners[2].z = corners[3].z = ceiling_z;
  143.     break;
  144.   /* the 3rd possibility is surface, PM3D_AT_SURFACE, and it'll come later */
  145.   }
  146.  
  147. scanA = this_plot->iso_crvs;
  148. curve = 0;
  149.  
  150. /* loop over scans in one surface
  151.    Scans are linked from this_plot->iso_crvs in the opposite order than
  152.    they are in the datafile.
  153.    Therefore it is necessary to make vector scan_array of iso_curves.
  154.    Scans are sorted in scan_array according to pm3d.direction (this can
  155.    be PM3D_SCANS_FORWARD or PM3D_SCANS_BACKWARD).
  156. */
  157. scan_array = malloc( this_plot->num_iso_read * sizeof(scanA) );
  158. scanA = this_plot->iso_crvs;
  159. for ( scan=this_plot->num_iso_read, i=0; --scan>=0; ) {
  160.   if (pm3d.direction == PM3D_SCANS_FORWARD)
  161.       scan_array[scan] = scanA;
  162.     else /* PM3D_SCANS_BACKWARD: i counts scans */
  163.       scan_array[ i++ ] = scanA;
  164.   scanA = scanA->next;
  165.   }
  166.  
  167. #if 0
  168. /* debugging: print scan_array */
  169. for ( scan=0; scan<this_plot->num_iso_read; scan++ ) {
  170.   printf("**** SCAN=%d  points=%d\n", scan, scan_array[scan]->p_count );
  171.   }
  172. #endif
  173.  
  174. #if 0
  175. /* debugging: this loop prints properties of all scans */
  176. for ( scan=0; scan<this_plot->num_iso_read; scan++ ) {
  177.   scanA = scan_array[scan];
  178.   printf( "\n#IsoCurve = scan nb %d, %d points\n#x y z type(in,out,undef)\n", scan, scanA->p_count );
  179.   for ( i = 0, points = scanA->points; i < scanA->p_count; i++ ) {
  180.     printf("%g %g %g %c\n",
  181.       points[i].x, points[i].y, points[i].z,
  182.       points[i].type == INRANGE ? 'i' : points[i].type == OUTRANGE ? 'o' : 'u');
  183.       /* Note: INRANGE, OUTRANGE, UNDEFINED */
  184.     }
  185.   }
  186. printf("\n");
  187. #endif
  188.  
  189. /*
  190. this loop does the pm3d draw of joining two curves
  191.  
  192. How the loop below works:
  193.    * scanB = scan last read; scanA = the previous one
  194.    * link the scan from A to B, then move B to A, then read B, then draw
  195. */
  196. for ( scan=0; scan<this_plot->num_iso_read-1; scan++ ) {
  197.   scanA = scan_array[scan];
  198.   scanB = scan_array[scan+1];
  199. #if 0
  200.   printf( "\n#IsoCurveA = scan nb %d has %d points   ScanB has %d points\n", scan, scanA->p_count, scanB->p_count );
  201. #endif
  202.   pointsA = scanA->points; pointsB = scanB->points;
  203.   /* if the number of points in both scans is not the same, then the starting
  204.      index (offset) of scan B according to the flushing setting has to be
  205.      determined
  206.   */
  207.   from = 0; /* default is pm3d.flush==PM3D_FLUSH_BEGIN */
  208.   if (pm3d.flush == PM3D_FLUSH_END)
  209.       from = abs( scanA->p_count - scanB->p_count );
  210.     else if (pm3d.flush == PM3D_FLUSH_CENTER)
  211.       from = abs( scanA->p_count - scanB->p_count ) / 2;
  212.   /* find the minimal number of points in both scans */
  213.   up_to = GPMIN(scanA->p_count,scanB->p_count) - 1;
  214.   /* go over the minimal number of points from both scans.
  215.      Notice: if it would be once necessary to go over points in `backward'
  216.      direction, then the loop body below would require to replace the data
  217.      point indices `i' by `up_to-i' and `i+1' by `up_to-i-1'.
  218.   */
  219.   for ( i = 0; i < up_to; i++ ) {
  220.     ii = i + from; /* index to the B array */
  221.     /* choose the clipping method */
  222.     if (pm3d.clip == PM3D_CLIP_4IN) {
  223.     /* (1) all 4 points of the quadrangle must be in x and y range */
  224.     if (!( pointsA[i].type == INRANGE && pointsA[i+1].type == INRANGE &&
  225.            pointsB[ii].type == INRANGE && pointsB[ii+1].type == INRANGE ))
  226.     continue;
  227.     }
  228.       else { /* (pm3d.clip == PM3D_CLIP_1IN) */
  229.     /* (2) all 4 points of the quadrangle must be defined */
  230.     if ( pointsA[i].type == UNDEFINED || pointsA[i+1].type == UNDEFINED ||
  231.          pointsB[ii].type == UNDEFINED || pointsB[ii+1].type == UNDEFINED )
  232.       continue;
  233.     /* and at least 1 point of the quadrangle must be in x and y range */
  234.     if ( pointsA[i].type == OUTRANGE && pointsA[i+1].type == OUTRANGE &&
  235.          pointsB[ii].type == OUTRANGE && pointsB[ii+1].type == OUTRANGE )
  236.       continue;
  237.     }
  238.     /* get the gray as the average of the corner z positions (note: log already in)
  239.        I always wonder what is faster: d*0.25 or d/4? Someone knows? */
  240.     avgZ = ( pointsA[i].z + pointsA[i+1].z + pointsB[ii].z + pointsB[ii+1].z )/4;
  241.     /* transform z value to gray, i.e. to interval [0,1] */
  242.     gray = z2gray ( avgZ );
  243.     /* print the quadrangle with the given colour */
  244. #if 0
  245.     printf( "averageZ %g\tgray=%g\tM %g %g L %g %g L %g %g L %g %g\n",
  246.       avgZ,
  247.       gray,
  248.       pointsA[i].x, pointsA[i].y,
  249.       pointsB[ii].x, pointsB[ii].y,
  250.       pointsB[ii+1].x, pointsB[ii+1].y,
  251.       pointsA[i+1].x, pointsA[i+1].y );
  252. #endif
  253.     set_color( gray );
  254.     corners[0].x = pointsA[i].x;    corners[0].y = pointsA[i].y;
  255.     corners[1].x = pointsB[ii].x;   corners[1].y = pointsB[ii].y;
  256.     corners[2].x = pointsB[ii+1].x; corners[2].y = pointsB[ii+1].y;
  257.     corners[3].x = pointsA[i+1].x;  corners[3].y = pointsA[i+1].y;
  258.     if (at_which_z == PM3D_AT_SURFACE) {
  259.       corners[0].z = pointsA[i].z;
  260.       corners[1].z = pointsB[ii].z;
  261.       corners[2].z = pointsB[ii+1].z;
  262.       corners[3].z = pointsA[i+1].z;
  263.       }
  264.  
  265.     /* filled_polygon( 4, corners ); */
  266.     filled_quadrangle( corners );
  267.     } /* loop over points of two subsequent scans */
  268.   } /* loop over scans */
  269. printf("\n");
  270.  
  271. /* free memory allocated by scan_array */
  272. free( scan_array );
  273.  
  274. } /* end of pm3d splotting mode */
  275.  
  276.  
  277.  
  278. /*
  279.    Now the implementation of the filled colour contour plot
  280.  
  281. contours_where: equals either CONTOUR_SRF or CONTOUR_BASE
  282.  
  283. Note: z2gray() uses used_pm3d_zmin, used_pm3d_zmax
  284. Check that if accessing this routine otherwise then via `set pm3d at`
  285.   code block in graph3d.c
  286. */
  287.  
  288. void filled_color_contour_plot ( this_plot, contours_where )
  289. struct surface_points *this_plot;
  290. int contours_where;
  291. {
  292. double gray;
  293. extern double base_z; /* defined in graph3d.c */
  294. struct gnuplot_contours *cntr;
  295.  
  296. if (this_plot == NULL || this_plot->contours == NULL)
  297.   return;
  298. if (contours_where != CONTOUR_SRF && contours_where != CONTOUR_BASE)
  299.   return;
  300.  
  301. /* return if the terminal does not support filled polygons */
  302. if (!term->filled_polygon) return;
  303.  
  304. /* TODO: CHECK FOR NUMBER OF POINTS IN CONTOUR: IF TOO SMALL, THEN IGNORE! */
  305. cntr = this_plot->contours;
  306. while (cntr) {
  307.   printf("# Contour: points %i, z %g, label: %s\n", cntr->num_pts, cntr->coords[0].z, (cntr->label)?cntr->label:"<no>");
  308.   if (cntr->isNewLevel) {
  309.      printf("\t...it isNewLevel\n");
  310.      /* contour split across chunks */
  311.      /* fprintf(gpoutfile, "\n# Contour %d, label: %s\n", number++, c->label); */
  312.      /* What is the colour? */
  313.      /* get the z-coordinate
  314.      /* transform contour z-coordinate value to gray, i.e. to interval [0,1] */
  315.      gray = z2gray ( cntr->coords[0].z );
  316.      set_color( gray );
  317.      }
  318.   /* draw one countour */
  319.   if (contours_where == CONTOUR_SRF) /* at CONTOUR_SRF */
  320.       filled_polygon_3dcoords ( cntr->num_pts, cntr->coords );
  321.     else /* at CONTOUR_BASE */
  322.       filled_polygon_3dcoords_zfixed ( cntr->num_pts, cntr->coords, base_z );
  323.   /* next contour */
  324.   cntr = cntr->next;
  325.   }
  326. } /* end of filled colour contour plot splot mode */
  327.  
  328.  
  329. /* eof pm3d.c */
  330.