PLplot
5.10.0
|
00001 // All routines that help to create a discrete legend (pllegend) or 00002 // a continuous legend (plcolorbar). 00003 // 00004 // Copyright (C) 2010-2013 Hezekiah M. Carty 00005 // Copyright (C) 2010-2014 Alan W. Irwin 00006 // 00007 // This file is part of PLplot. 00008 // 00009 // PLplot is free software; you can redistribute it and/or modify 00010 // it under the terms of the GNU Library General Public License as published 00011 // by the Free Software Foundation; either version 2 of the License, or 00012 // (at your option) any later version. 00013 // 00014 // PLplot is distributed in the hope that it will be useful, 00015 // but WITHOUT ANY WARRANTY; without even the implied warranty of 00016 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00017 // GNU Library General Public License for more details. 00018 // 00019 // You should have received a copy of the GNU Library General Public License 00020 // along with PLplot; if not, write to the Free Software 00021 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 00022 // 00023 00028 #include "plplotP.h" 00029 00030 //-------------------------------------------------------------------------- 00045 00046 static void plgvpsp( PLFLT *p_xmin, PLFLT *p_xmax, PLFLT *p_ymin, PLFLT *p_ymax ) 00047 { 00048 if ( plsc->level < 1 ) 00049 { 00050 plabort( "plgvpsp: Please call plinit first" ); 00051 return; 00052 } 00053 if ( ( plsc->cursub <= 0 ) || ( plsc->cursub > ( plsc->nsubx * plsc->nsuby ) ) ) 00054 { 00055 plabort( "plgvpsp: Please call pladv or plenv to go to a subpage" ); 00056 return; 00057 } 00058 *p_xmin = ( plsc->vpdxmi - plsc->spdxmi ) / ( plsc->spdxma - plsc->spdxmi ); 00059 *p_xmax = ( plsc->vpdxma - plsc->spdxmi ) / ( plsc->spdxma - plsc->spdxmi ); 00060 *p_ymin = ( plsc->vpdymi - plsc->spdymi ) / ( plsc->spdyma - plsc->spdymi ); 00061 *p_ymax = ( plsc->vpdyma - plsc->spdymi ) / ( plsc->spdyma - plsc->spdymi ); 00062 } 00063 00064 //-------------------------------------------------------------------------- 00086 00087 static void legend_position( PLINT position, PLFLT legend_width, PLFLT legend_height, 00088 PLFLT *x_legend_position, PLFLT *y_legend_position, 00089 PLFLT *xsign, PLFLT *ysign ) 00090 { 00091 // xorigin, yorigin, xlegend, and ylegend are all calculated for 00092 // one of the 16 standard positions specified by position and are 00093 // expressed in adopted coordinates. xorigin is the X value of 00094 // the reference point of the adopted coordinates. yorigin is the 00095 // Y value of the reference point of the adopted coordinates. 00096 // xlegend is the X coordinate of the top-left of the legend box 00097 // relative to the legend box reference point. ylegend is the y 00098 // coordinate of the top-left of the legend box relative to the 00099 // legend box reference point. 00100 00101 PLFLT xorigin = 0.0, yorigin = 0.0, xlegend = 0.0, ylegend = 0.0; 00102 // By default the sign of the x and y offsets is positive. 00103 *xsign = 1.; 00104 *ysign = 1.; 00105 if ( position & PL_POSITION_RIGHT ) 00106 { 00107 xorigin = 1.; 00108 if ( position & PL_POSITION_TOP ) 00109 { 00110 yorigin = 1.; 00111 if ( position & PL_POSITION_INSIDE ) 00112 { 00113 xlegend = -legend_width; 00114 ylegend = 0.; 00115 *xsign = -1.; 00116 *ysign = -1.; 00117 } 00118 else if ( position & PL_POSITION_OUTSIDE ) 00119 { 00120 xlegend = 0.; 00121 ylegend = legend_height; 00122 } 00123 else 00124 { 00125 plexit( "legend_position: internal logic error 1" ); 00126 } 00127 } 00128 else if ( !( position & PL_POSITION_TOP ) && !( position & PL_POSITION_BOTTOM ) ) 00129 { 00130 yorigin = 0.5; 00131 ylegend = 0.5 * legend_height; 00132 if ( position & PL_POSITION_INSIDE ) 00133 { 00134 xlegend = -legend_width; 00135 *xsign = -1.; 00136 } 00137 else if ( position & PL_POSITION_OUTSIDE ) 00138 { 00139 xlegend = 0.; 00140 } 00141 else 00142 { 00143 plexit( "legend_position: internal logic error 2" ); 00144 } 00145 } 00146 else if ( position & PL_POSITION_BOTTOM ) 00147 { 00148 yorigin = 0.; 00149 if ( position & PL_POSITION_INSIDE ) 00150 { 00151 xlegend = -legend_width; 00152 ylegend = legend_height; 00153 *xsign = -1.; 00154 } 00155 else if ( position & PL_POSITION_OUTSIDE ) 00156 { 00157 xlegend = 0.; 00158 ylegend = 0.; 00159 *ysign = -1.; 00160 } 00161 else 00162 { 00163 plexit( "legend_position: internal logic error 3" ); 00164 } 00165 } 00166 else 00167 { 00168 plexit( "legend_position: internal logic error 4" ); 00169 } 00170 } 00171 else if ( !( position & PL_POSITION_RIGHT ) && !( position & PL_POSITION_LEFT ) ) 00172 { 00173 xorigin = 0.5; 00174 xlegend = -0.5 * legend_width; 00175 if ( position & PL_POSITION_TOP ) 00176 { 00177 yorigin = 1.; 00178 if ( position & PL_POSITION_INSIDE ) 00179 { 00180 ylegend = 0.; 00181 *ysign = -1.; 00182 } 00183 else if ( position & PL_POSITION_OUTSIDE ) 00184 { 00185 ylegend = legend_height; 00186 } 00187 else 00188 { 00189 plexit( "legend_position: internal logic error 5" ); 00190 } 00191 } 00192 else if ( position & PL_POSITION_BOTTOM ) 00193 { 00194 yorigin = 0.; 00195 if ( position & PL_POSITION_INSIDE ) 00196 { 00197 ylegend = legend_height; 00198 } 00199 else if ( position & PL_POSITION_OUTSIDE ) 00200 { 00201 ylegend = 0.; 00202 *ysign = -1.; 00203 } 00204 else 00205 { 00206 plexit( "legend_position: internal logic error 6" ); 00207 } 00208 } 00209 else 00210 { 00211 plexit( "legend_position: internal logic error 7" ); 00212 } 00213 } 00214 else if ( position & PL_POSITION_LEFT ) 00215 { 00216 xorigin = 0.; 00217 if ( position & PL_POSITION_TOP ) 00218 { 00219 yorigin = 1.; 00220 if ( position & PL_POSITION_INSIDE ) 00221 { 00222 xlegend = 0.; 00223 ylegend = 0.; 00224 *ysign = -1.; 00225 } 00226 else if ( position & PL_POSITION_OUTSIDE ) 00227 { 00228 xlegend = -legend_width; 00229 ylegend = legend_height; 00230 *xsign = -1.; 00231 } 00232 else 00233 { 00234 plexit( "legend_position: internal logic error 8" ); 00235 } 00236 } 00237 else if ( !( position & PL_POSITION_TOP ) && !( position & PL_POSITION_BOTTOM ) ) 00238 { 00239 yorigin = 0.5; 00240 ylegend = 0.5 * legend_height; 00241 if ( position & PL_POSITION_INSIDE ) 00242 { 00243 xlegend = 0.; 00244 } 00245 else if ( position & PL_POSITION_OUTSIDE ) 00246 { 00247 xlegend = -legend_width; 00248 *xsign = -1.; 00249 } 00250 else 00251 { 00252 plexit( "legend_position: internal logic error 9" ); 00253 } 00254 } 00255 else if ( position & PL_POSITION_BOTTOM ) 00256 { 00257 yorigin = 0.; 00258 if ( position & PL_POSITION_INSIDE ) 00259 { 00260 ylegend = legend_height; 00261 xlegend = 0.; 00262 } 00263 else if ( position & PL_POSITION_OUTSIDE ) 00264 { 00265 xlegend = -legend_width; 00266 ylegend = 0.; 00267 *xsign = -1.; 00268 *ysign = -1.; 00269 } 00270 else 00271 { 00272 plexit( "legend_position: internal logic error 10" ); 00273 } 00274 } 00275 else 00276 { 00277 plexit( "legend_position: internal logic error 11" ); 00278 } 00279 } 00280 else 00281 { 00282 plexit( "legend_position: internal logic error 12" ); 00283 } 00284 *x_legend_position = xorigin + xlegend; 00285 *y_legend_position = yorigin + ylegend; 00286 } 00287 00288 //-------------------------------------------------------------------------- 00294 00295 static void get_subpage_per_mm( PLFLT *x_subpage_per_mm, PLFLT *y_subpage_per_mm ) 00296 { 00297 // Size of subpage in mm 00298 PLFLT mxmin, mxmax, mymin, mymax; 00299 plgspa( &mxmin, &mxmax, &mymin, &mymax ); 00300 *x_subpage_per_mm = 1. / ( mxmax - mxmin ); 00301 *y_subpage_per_mm = 1. / ( mymax - mymin ); 00302 } 00303 00304 //-------------------------------------------------------------------------- 00311 00312 static PLFLT get_character_or_symbol_height( PLBOOL ifcharacter ) 00313 { 00314 // Character height in mm 00315 PLFLT default_mm, char_height_mm; 00316 PLFLT x_subpage_per_mm, y_subpage_per_mm; 00317 00318 if ( ifcharacter ) 00319 { 00320 plgchr( &default_mm, &char_height_mm ); 00321 } 00322 else 00323 { 00324 default_mm = plsc->symdef; 00325 char_height_mm = plsc->symht; 00326 } 00327 get_subpage_per_mm( &x_subpage_per_mm, &y_subpage_per_mm ); 00328 return ( char_height_mm * y_subpage_per_mm ); 00329 } 00330 00331 //-------------------------------------------------------------------------- 00343 00344 #define adopted_to_subpage_x( nx ) ( ( xdmin_adopted ) + ( nx ) * ( ( xdmax_adopted ) - ( xdmin_adopted ) ) ) 00345 00346 //-------------------------------------------------------------------------- 00358 00359 #define subpage_to_adopted_x( nx ) ( ( nx - xdmin_adopted ) / ( ( xdmax_adopted ) - ( xdmin_adopted ) ) ) 00360 00361 //-------------------------------------------------------------------------- 00373 00374 #define adopted_to_subpage_y( ny ) ( ( ydmin_adopted ) + ( ny ) * ( ( ydmax_adopted ) - ( ydmin_adopted ) ) ) 00375 00376 //-------------------------------------------------------------------------- 00388 00389 #define subpage_to_adopted_y( ny ) ( ( ny - ydmin_adopted ) / ( ( ydmax_adopted ) - ( ydmin_adopted ) ) ) 00390 00391 //-------------------------------------------------------------------------- 00529 00530 void 00531 c_pllegend( PLFLT *p_legend_width, PLFLT *p_legend_height, 00532 PLINT opt, PLINT position, PLFLT x, PLFLT y, PLFLT plot_width, 00533 PLINT bg_color, PLINT bb_color, PLINT bb_style, 00534 PLINT nrow, PLINT ncolumn, 00535 PLINT nlegend, const PLINT *opt_array, 00536 PLFLT text_offset, PLFLT text_scale, PLFLT text_spacing, 00537 PLFLT text_justification, 00538 const PLINT *text_colors, const char * const *text, 00539 const PLINT *box_colors, const PLINT *box_patterns, 00540 const PLFLT *box_scales, const PLFLT *box_line_widths, 00541 const PLINT *line_colors, const PLINT *line_styles, 00542 const PLFLT *line_widths, 00543 const PLINT *symbol_colors, const PLFLT *symbol_scales, 00544 const PLINT *symbol_numbers, const char * const *symbols ) 00545 00546 { 00547 // Legend position 00548 PLFLT plot_x, plot_x_end, plot_x_subpage, plot_x_end_subpage; 00549 PLFLT plot_y, plot_y_subpage; 00550 PLFLT text_x, text_y, text_x_subpage, text_y_subpage; 00551 // Character height (normalized subpage coordinates) 00552 PLFLT character_height, character_width, symbol_width = 0.0; 00553 // x, y-position of the current legend entry 00554 PLFLT ty, xshift, drow, dcolumn; 00555 // Positions of the legend entries 00556 PLFLT dxs, *xs = NULL, *ys = NULL, xl[2], yl[2], xbox[4], ybox[4]; 00557 PLINT i, j; 00558 // Active attributes to be saved and restored afterward. 00559 PLINT col0_save = plsc->icol0, 00560 line_style_save = plsc->line_style, 00561 pattern_save = plsc->patt; 00562 PLFLT line_width_save = plsc->width; 00563 PLFLT text_scale_save = plsc->chrht / plsc->chrdef; 00564 // Saved external world coordinates of viewport. 00565 PLFLT xwmin_save, xwmax_save, ywmin_save, ywmax_save; 00566 // Saved external normalized coordinates of viewport. 00567 // (These are actual values used only for the restore.) 00568 PLFLT xdmin_save = 0.0, xdmax_save = 0.0, ydmin_save = 0.0, ydmax_save = 0.0; 00569 // Limits of adopted coordinates used to calculate all coordinate 00570 // transformations. 00571 PLFLT xdmin_adopted = 0.0, xdmax_adopted = 0.0, ydmin_adopted = 0.0, ydmax_adopted = 0.0; 00572 00573 PLFLT x_subpage_per_mm, y_subpage_per_mm, text_width0 = 0., text_width; 00574 PLFLT width_border, column_separation, 00575 legend_width, legend_height, legend_width_ac, legend_height_ac; 00576 PLFLT x_legend_position, y_legend_position, xsign, ysign; 00577 00578 PLINT some_symbols = 0; 00579 PLINT max_symbol_numbers = 0; 00580 PLINT irow = 0, icolumn = 0; 00581 int some_boxes = 0, some_lines = 0; 00582 00583 // Default nrow, ncolumn. 00584 nrow = MAX( nrow, 1 ); 00585 ncolumn = MAX( ncolumn, 1 ); 00586 if ( nrow * ncolumn < nlegend ) 00587 { 00588 // Make smaller one large enough to accomodate nlegend. 00589 if ( ncolumn < nrow ) 00590 ncolumn = ( nlegend % nrow ) ? ( nlegend / nrow ) + 1 : nlegend / nrow; 00591 else 00592 nrow = ( nlegend % ncolumn ) ? ( nlegend / ncolumn ) + 1 : nlegend / ncolumn; 00593 } 00594 // fprintf(stdout, "nrow, ncolumn = %d, %d\n", nrow, ncolumn); 00595 00596 // Default position flags and sanity checks for position flags. 00597 if ( !( position & PL_POSITION_RIGHT ) && !( position & PL_POSITION_LEFT ) && !( position & PL_POSITION_TOP ) && !( position & PL_POSITION_BOTTOM ) ) 00598 { 00599 position = position | PL_POSITION_RIGHT | PL_POSITION_TOP; 00600 } 00601 else if ( ( position & PL_POSITION_RIGHT ) && ( position & PL_POSITION_LEFT ) ) 00602 { 00603 plabort( "pllegend: PL_POSITION_RIGHT and PL_POSITION_LEFT cannot be simultaneously set." ); 00604 return; 00605 } 00606 00607 else if ( ( position & PL_POSITION_TOP ) && ( position & PL_POSITION_BOTTOM ) ) 00608 { 00609 plabort( "pllegend: PL_POSITION_TOP and PL_POSITION_BOTTOM cannot be simultaneously set." ); 00610 return; 00611 } 00612 00613 if ( !( position & PL_POSITION_INSIDE ) && !( position & PL_POSITION_OUTSIDE ) ) 00614 { 00615 position = position | PL_POSITION_INSIDE; 00616 } 00617 else if ( ( position & PL_POSITION_INSIDE ) && ( position & PL_POSITION_OUTSIDE ) ) 00618 { 00619 plabort( "pllegend: PL_POSITION_INSIDE and PL_POSITION_OUTSIDE cannot be simultaneously set." ); 00620 return; 00621 } 00622 00623 if ( !( position & PL_POSITION_VIEWPORT ) && !( position & PL_POSITION_SUBPAGE ) ) 00624 { 00625 position = position | PL_POSITION_VIEWPORT; 00626 } 00627 else if ( ( position & PL_POSITION_VIEWPORT ) && ( position & PL_POSITION_SUBPAGE ) ) 00628 { 00629 plabort( "pllegend: PL_POSITION_VIEWPORT and PL_POSITION_SUBPAGE cannot be simultaneously set." ); 00630 return; 00631 } 00632 00633 // xdmin_save, etc., are the actual external relative viewport 00634 // coordinates within the current sub-page used only for 00635 // restoration at the end. 00636 plgvpsp( &xdmin_save, &xdmax_save, &ydmin_save, &ydmax_save ); 00637 00638 // Choose adopted coordinates. 00639 if ( position & PL_POSITION_SUBPAGE ) 00640 plvpor( 0., 1., 0., 1. ); 00641 00642 // xdmin_adopted, etc., are the adopted limits of the coordinates 00643 // within the current sub-page used for all coordinate 00644 // transformations. 00645 // If position & PL_POSITION_VIEWPORT is true, these limits 00646 // are the external relative viewport limits. 00647 // If position & PL_POSITION_SUBPAGE is true, these 00648 // coordinates are the relative subpage coordinates. 00649 plgvpsp( &xdmin_adopted, &xdmax_adopted, &ydmin_adopted, &ydmax_adopted ); 00650 00651 // xwmin_save, etc., are the external world coordinates corresponding 00652 // to the external viewport boundaries. 00653 plgvpw( &xwmin_save, &xwmax_save, &ywmin_save, &ywmax_save ); 00654 00655 // Internal viewport corresponds to sub-page so that all legends will 00656 // be clipped at sub-page boundaries. 00657 plvpor( 0., 1., 0., 1. ); 00658 00659 // Internal world coordinates are the same as normalized internal 00660 // viewport coordinates which are the same as normalized subpage coordinates. 00661 plwind( 0., 1., 0., 1. ); 00662 00663 for ( i = 0; i < nlegend; i++ ) 00664 { 00665 if ( opt_array[i] & PL_LEGEND_COLOR_BOX ) 00666 some_boxes = 1; 00667 if ( opt_array[i] & PL_LEGEND_LINE ) 00668 some_lines = 1; 00669 if ( opt_array[i] & PL_LEGEND_SYMBOL ) 00670 { 00671 if ( symbol_numbers != NULL ) 00672 max_symbol_numbers = MAX( max_symbol_numbers, symbol_numbers[i] ); 00673 some_symbols = 1; 00674 } 00675 } 00676 00677 // Sanity checks on NULL arrays: 00678 if ( some_boxes && ( box_colors == NULL || box_patterns == NULL || box_scales == NULL || box_line_widths == NULL ) ) 00679 { 00680 plabort( "pllegend: all box_* arrays must be defined when the PL_LEGEND_COLOR_BOX bit is set." ); 00681 return; 00682 } 00683 00684 if ( some_lines && ( line_colors == NULL || line_styles == NULL || line_widths == NULL ) ) 00685 { 00686 plabort( "pllegend: all line_* arrays must be defined when the PL_LEGEND_LINE bit is set." ); 00687 return; 00688 } 00689 00690 if ( some_symbols && ( symbol_colors == NULL || symbol_scales == NULL || symbol_numbers == NULL ) ) 00691 { 00692 plabort( "pllegend: all symbol_* arrays must be defined when the PL_LEGEND_SYMBOL bit is set." ); 00693 return; 00694 } 00695 00696 // Get character height and width in normalized subpage coordinates. 00697 character_height = get_character_or_symbol_height( TRUE ); 00698 character_width = character_height; 00699 00700 // Calculate maximum width of text area. 00701 plschr( 0., text_scale ); 00702 for ( i = 0; i < nlegend; i++ ) 00703 { 00704 // units are mm. 00705 text_width0 = MAX( text_width0, plstrl( text[i] ) ); 00706 } 00707 get_subpage_per_mm( &x_subpage_per_mm, &y_subpage_per_mm ); 00708 00709 // units are normalized subpage coordinates. 00710 text_width0 = x_subpage_per_mm * text_width0; 00711 00712 // Allow gap on end closest to legend plot. 00713 text_width = text_width0 + text_offset * character_width; 00714 00715 // Allow small border area where only the background is plotted 00716 // for left and right of legend. 0.4 seems to be a reasonable factor 00717 // that gives a good-looking result. 00718 width_border = 0.4 * character_width; 00719 // Separate columns (if any) by 2.0 * character_width. 00720 column_separation = 2.0 * character_width; 00721 00722 // Total width and height of legend area in normalized subpage coordinates. 00723 legend_width = 2. * width_border + ( ncolumn - 1 ) * column_separation + 00724 ncolumn * ( text_width + 00725 adopted_to_subpage_x( plot_width ) - adopted_to_subpage_x( 0. ) ); 00726 legend_height = nrow * text_spacing * character_height; 00727 00728 // Total width and height of legend area in adopted coordinates. 00729 00730 legend_width_ac = subpage_to_adopted_x( legend_width ) - subpage_to_adopted_x( 0. ); 00731 legend_height_ac = subpage_to_adopted_y( legend_height ) - subpage_to_adopted_y( 0. ); 00732 *p_legend_width = legend_width_ac; 00733 *p_legend_height = legend_height_ac; 00734 00735 // dcolumn is the spacing from one column to the next and 00736 // drow is the spacing from one row to the next. 00737 dcolumn = column_separation + text_width + 00738 adopted_to_subpage_x( plot_width ) - adopted_to_subpage_x( 0. ); 00739 drow = text_spacing * character_height; 00740 00741 legend_position( position, legend_width_ac, legend_height_ac, &x_legend_position, &y_legend_position, &xsign, &ysign ); 00742 plot_x = x * xsign + x_legend_position; 00743 plot_y = y * ysign + y_legend_position; 00744 plot_x_end = plot_x + plot_width; 00745 // Normalized subpage coordinates for legend plots 00746 plot_x_subpage = adopted_to_subpage_x( plot_x ); 00747 plot_y_subpage = adopted_to_subpage_y( plot_y ); 00748 plot_x_end_subpage = adopted_to_subpage_x( plot_x_end ); 00749 00750 // Get normalized subpage positions of the start of the legend text 00751 text_x = plot_x_end; 00752 text_y = plot_y; 00753 text_x_subpage = adopted_to_subpage_x( text_x ) + 00754 text_offset * character_width; 00755 text_y_subpage = adopted_to_subpage_y( text_y ); 00756 00757 if ( opt & PL_LEGEND_BACKGROUND ) 00758 { 00759 PLFLT xbg[4] = { 00760 plot_x_subpage, 00761 plot_x_subpage, 00762 plot_x_subpage + legend_width, 00763 plot_x_subpage + legend_width, 00764 }; 00765 PLFLT ybg[4] = { 00766 plot_y_subpage, 00767 plot_y_subpage - legend_height, 00768 plot_y_subpage - legend_height, 00769 plot_y_subpage, 00770 }; 00771 plpsty( 0 ); 00772 plcol0( bg_color ); 00773 plfill( 4, xbg, ybg ); 00774 plcol0( col0_save ); 00775 } 00776 00777 if ( opt & PL_LEGEND_BOUNDING_BOX ) 00778 { 00779 PLFLT xbb[5] = { 00780 plot_x_subpage, 00781 plot_x_subpage, 00782 plot_x_subpage + legend_width, 00783 plot_x_subpage + legend_width, 00784 plot_x_subpage, 00785 }; 00786 PLFLT ybb[5] = { 00787 plot_y_subpage, 00788 plot_y_subpage - legend_height, 00789 plot_y_subpage - legend_height, 00790 plot_y_subpage, 00791 plot_y_subpage, 00792 }; 00793 pllsty( bb_style ); 00794 plcol0( bb_color ); 00795 plline( 5, xbb, ybb ); 00796 plcol0( col0_save ); 00797 pllsty( line_style_save ); 00798 } 00799 00800 if ( opt & PL_LEGEND_TEXT_LEFT ) 00801 { 00802 // text area on left, plot area on right. 00803 text_x_subpage = plot_x_subpage; 00804 plot_x_subpage += text_width; 00805 plot_x_end_subpage += text_width; 00806 } 00807 // adjust border after background is drawn. 00808 plot_x_subpage += width_border; 00809 plot_x_end_subpage += width_border; 00810 text_x_subpage += width_border; 00811 00812 if ( some_symbols ) 00813 { 00814 max_symbol_numbers = MAX( 2, max_symbol_numbers ); 00815 if ( ( ( xs = (PLFLT *) malloc( (size_t) max_symbol_numbers * sizeof ( PLFLT ) ) ) == NULL ) || 00816 ( ( ys = (PLFLT *) malloc( (size_t) max_symbol_numbers * sizeof ( PLFLT ) ) ) == NULL ) ) 00817 { 00818 plexit( "pllegend: Insufficient memory" ); 00819 } 00820 00821 // Get symbol width in normalized subpage coordinates if symbols are plotted to 00822 // adjust ends of line of symbols. 00823 // AWI, no idea why must use 0.5 factor to get ends of symbol lines 00824 // to line up approximately correctly with plotted legend lines. 00825 // Factor should be unity. 00826 symbol_width = 0.5 * get_character_or_symbol_height( TRUE ); 00827 } 00828 00829 // Draw each legend entry 00830 for ( i = 0; i < nlegend; i++ ) 00831 { 00832 // y position of text, lines, symbols, and/or centre of cmap0 box. 00833 ty = text_y_subpage - ( (double) irow + 0.5 ) * drow; 00834 xshift = (double) icolumn * dcolumn; 00835 // Label/name for the legend 00836 plcol0( text_colors[i] ); 00837 plschr( 0., text_scale ); 00838 plptex( text_x_subpage + xshift + text_justification * text_width0, ty, 0.1, 0.0, text_justification, text[i] ); 00839 00840 if ( !( opt_array[i] & PL_LEGEND_NONE ) ) 00841 { 00842 if ( opt_array[i] & PL_LEGEND_COLOR_BOX ) 00843 { 00844 plcol0( box_colors[i] ); 00845 plpsty( box_patterns[i] ); 00846 plwidth( box_line_widths[i] ); 00847 xbox[0] = plot_x_subpage + xshift; 00848 xbox[1] = xbox[0]; 00849 xbox[2] = plot_x_end_subpage + xshift; 00850 xbox[3] = xbox[2]; 00851 ybox[0] = ty + 0.5 * drow * box_scales[i]; 00852 ybox[1] = ty - 0.5 * drow * box_scales[i]; 00853 ybox[2] = ty - 0.5 * drow * box_scales[i]; 00854 ybox[3] = ty + 0.5 * drow * box_scales[i]; 00855 plfill( 4, xbox, ybox ); 00856 pllsty( line_style_save ); 00857 plwidth( line_width_save ); 00858 } 00859 if ( opt_array[i] & PL_LEGEND_LINE ) 00860 { 00861 plcol0( line_colors[i] ); 00862 pllsty( line_styles[i] ); 00863 plwidth( line_widths[i] ); 00864 xl[0] = plot_x_subpage + xshift; 00865 xl[1] = plot_x_end_subpage + xshift; 00866 yl[0] = ty; 00867 yl[1] = ty; 00868 plline( 2, xl, yl ); 00869 pllsty( line_style_save ); 00870 plwidth( line_width_save ); 00871 } 00872 00873 if ( opt_array[i] & PL_LEGEND_SYMBOL ) 00874 { 00875 plcol0( symbol_colors[i] ); 00876 plschr( 0., symbol_scales[i] ); 00877 dxs = ( plot_x_end_subpage - plot_x_subpage - symbol_width ) / (double) ( MAX( symbol_numbers[i], 2 ) - 1 ); 00878 for ( j = 0; j < symbol_numbers[i]; j++ ) 00879 { 00880 xs[j] = plot_x_subpage + xshift + 00881 0.5 * symbol_width + dxs * (double) j; 00882 ys[j] = ty; 00883 } 00884 plstring( symbol_numbers[i], xs, ys, symbols[i] ); 00885 } 00886 } 00887 00888 // Set irow, icolumn for next i value. 00889 if ( opt & PL_LEGEND_ROW_MAJOR ) 00890 { 00891 icolumn++; 00892 if ( icolumn >= ncolumn ) 00893 { 00894 icolumn = 0; 00895 irow++; 00896 } 00897 } 00898 else 00899 { 00900 irow++; 00901 if ( irow >= nrow ) 00902 { 00903 irow = 0; 00904 icolumn++; 00905 } 00906 } 00907 } 00908 if ( some_symbols ) 00909 { 00910 free( xs ); 00911 free( ys ); 00912 } 00913 00914 // Restore 00915 plcol0( col0_save ); 00916 plschr( 0., text_scale_save ); 00917 plpsty( pattern_save ); 00918 plvpor( xdmin_save, xdmax_save, ydmin_save, ydmax_save ); 00919 plwind( xwmin_save, xwmax_save, ywmin_save, ywmax_save ); 00920 00921 return; 00922 } 00923 00924 //-------------------------------------------------------------------------- 00931 00932 static void 00933 remove_characters( char *string, const char *characters ) 00934 { 00935 char *src, *dst; 00936 const char *ptr; 00937 for ( src = dst = string; *src != '\0'; src++ ) 00938 { 00939 ptr = characters; 00940 while ( ( *ptr != '\0' ) && ( *src != *ptr ) ) 00941 ptr++; 00942 if ( *src != *ptr ) 00943 { 00944 *dst = *src; 00945 dst++; 00946 } 00947 } 00948 *dst = '\0'; 00949 } 00950 00951 //-------------------------------------------------------------------------- 00971 00972 static void 00973 draw_cap( PLBOOL if_edge, PLINT orientation, PLFLT xmin, PLFLT xmax, 00974 PLFLT ymin, PLFLT ymax, PLFLT color ) 00975 { 00976 // Save current drawing color. 00977 PLINT col0_save = plsc->icol0; 00978 PLFLT xhalf = 0.5 * ( xmin + xmax ); 00979 PLFLT yhalf = 0.5 * ( ymin + ymax ); 00980 00981 // World coordinates for the triangle. Due to setup in the 00982 // plcolorbar routine that calls this, these are also normalized 00983 // subpage coordinates. 00984 PLFLT xs[3]; 00985 PLFLT ys[3]; 00986 00987 if ( orientation == PL_COLORBAR_ORIENT_RIGHT ) 00988 { 00989 xs[0] = xmin; 00990 ys[0] = ymin; 00991 xs[1] = xmax; 00992 ys[1] = yhalf; 00993 xs[2] = xmin; 00994 ys[2] = ymax; 00995 } 00996 else if ( orientation == PL_COLORBAR_ORIENT_TOP ) 00997 { 00998 xs[0] = xmax; 00999 ys[0] = ymin; 01000 xs[1] = xhalf; 01001 ys[1] = ymax; 01002 xs[2] = xmin; 01003 ys[2] = ymin; 01004 } 01005 else if ( orientation == PL_COLORBAR_ORIENT_LEFT ) 01006 { 01007 xs[0] = xmax; 01008 ys[0] = ymax; 01009 xs[1] = xmin; 01010 ys[1] = yhalf; 01011 xs[2] = xmax; 01012 ys[2] = ymin; 01013 } 01014 else if ( orientation == PL_COLORBAR_ORIENT_BOTTOM ) 01015 { 01016 xs[0] = xmin; 01017 ys[0] = ymax; 01018 xs[1] = xhalf; 01019 ys[1] = ymin; 01020 xs[2] = xmax; 01021 ys[2] = ymax; 01022 } 01023 else 01024 { 01025 plexit( "draw_cap: internal error. Incorrect orientation" ); 01026 } 01027 01028 plcol1( color ); 01029 plfill( 3, xs, ys ); 01030 // Restore the drawing color 01031 plcol0( col0_save ); 01032 01033 // Draw cap outline 01034 if ( if_edge ) 01035 plline( 3, xs, ys ); 01036 } 01037 01038 //-------------------------------------------------------------------------- 01060 01061 static void 01062 draw_box( PLBOOL if_bb, PLINT opt, const char *axis_opts, PLBOOL if_edge, 01063 PLFLT ticks, PLINT sub_ticks, PLINT n_values, const PLFLT *values ) 01064 { 01065 // axis option strings. 01066 const char *edge_string; 01067 size_t length_axis_opts = strlen( axis_opts ); 01068 char *local_axis_opts; 01069 01070 // local_axis_opts is local version that can be modified from 01071 // const input version. 01072 if ( ( local_axis_opts = (char *) malloc( ( length_axis_opts + 1 ) * sizeof ( char ) ) ) == NULL ) 01073 { 01074 plexit( "draw_box: Insufficient memory" ); 01075 } 01076 strcpy( local_axis_opts, axis_opts ); 01077 01078 plsc->if_boxbb = if_bb; 01079 // Draw numerical labels and tick marks if this is a shade color bar 01080 // TODO: A better way to handle this would be to update the 01081 // internals of plbox to support custom tick and label positions 01082 // along an axis. 01083 01084 if ( opt & PL_COLORBAR_SHADE && opt & PL_COLORBAR_SHADE_LABEL ) 01085 { 01086 if ( opt & PL_COLORBAR_ORIENT_RIGHT || opt & PL_COLORBAR_ORIENT_LEFT ) 01087 label_box_custom( local_axis_opts, n_values, values, "", 0, NULL ); 01088 else 01089 label_box_custom( "", 0, NULL, local_axis_opts, n_values, values ); 01090 if ( if_bb ) 01091 { 01092 plsc->if_boxbb = FALSE; 01093 free( local_axis_opts ); 01094 return; 01095 } 01096 // Exclude ticks for plbox call below since those tick marks and 01097 // associated labels have already been handled in a custom way above. 01098 remove_characters( local_axis_opts, "TtXx" ); 01099 } 01100 01101 // Draw the outline for the entire color bar, tick marks, tick labels. 01102 01103 if ( if_edge ) 01104 edge_string = "bc"; 01105 else 01106 edge_string = "uw"; 01107 if ( opt & PL_COLORBAR_ORIENT_TOP || opt & PL_COLORBAR_ORIENT_BOTTOM ) 01108 { 01109 plbox( edge_string, 0.0, 0, local_axis_opts, ticks, sub_ticks ); 01110 } 01111 else 01112 { 01113 plbox( local_axis_opts, ticks, sub_ticks, edge_string, 0.0, 0 ); 01114 } 01115 plsc->if_boxbb = FALSE; 01116 01117 free( local_axis_opts ); 01118 } 01119 01120 //-------------------------------------------------------------------------- 01136 01137 static void 01138 draw_label( PLBOOL if_bb, PLINT opt, const char *label ) 01139 { 01140 // Justification of label text 01141 PLFLT just = 0.0; 01142 01143 // How far away from the axis should the label be drawn in units of 01144 // the character height? 01145 PLFLT label_offset = 1.2; 01146 01147 // For building plmtex option string. 01148 #define max_opts 25 01149 char opt_label[max_opts]; 01150 char perp; 01151 01152 // To help sanity check number of specified labels. 01153 PLINT nlabel = 0; 01154 01155 // aspect ratio of physical area of subpage. 01156 //PLFLT aspspp = ( ( plsc->sppxma - plsc->sppxmi ) / plsc->xpmm ) / 01157 // ( ( plsc->sppyma - plsc->sppymi ) / plsc->ypmm ); 01158 01159 // Character height in y and x normalized subpage coordinates. 01160 //PLFLT character_height_y = get_character_or_symbol_height( TRUE ); 01161 // character height _in normalized subpage coordinates_ is smaller 01162 // in the x direction if the subpage aspect ratio is larger than one. 01163 //PLFLT character_height_x = character_height_y / aspspp; 01164 01165 // Ratio of normalized subpage coordinates to mm coordinates in 01166 // x and y. 01167 //PLFLT spxpmm = plsc->xpmm / ( plsc->sppxma - plsc->sppxmi ); 01168 //PLFLT spypmm = plsc->ypmm / ( plsc->sppyma - plsc->sppymi ); 01169 PLFLT label_length_mm = plstrl( label ); 01170 01171 PLFLT parallel_height_mm = 0.0, perpendicular_height_mm = 0.0, 01172 default_mm, char_height_mm; 01173 01174 // Only honor first bit in list of 01175 // PL_COLORBAR_LABEL_(RIGHT|TOP|LEFT|BOTTOM). 01176 if ( opt & PL_COLORBAR_LABEL_RIGHT ) 01177 { 01178 nlabel = 1; 01179 } 01180 if ( opt & PL_COLORBAR_LABEL_TOP ) 01181 { 01182 if ( nlabel == 1 ) 01183 opt = opt & ~PL_COLORBAR_LABEL_TOP; 01184 else 01185 nlabel = 1; 01186 } 01187 if ( opt & PL_COLORBAR_LABEL_LEFT ) 01188 { 01189 if ( nlabel == 1 ) 01190 opt = opt & ~PL_COLORBAR_LABEL_LEFT; 01191 else 01192 nlabel = 1; 01193 } 01194 if ( opt & PL_COLORBAR_LABEL_BOTTOM ) 01195 { 01196 if ( nlabel == 1 ) 01197 opt = opt & ~PL_COLORBAR_LABEL_BOTTOM; 01198 else 01199 nlabel = 1; 01200 } 01201 // If no label wanted, then return. 01202 if ( nlabel == 0 ) 01203 return; 01204 01205 plgchr( &default_mm, &char_height_mm ); 01206 01207 // Start preparing data to help plot the label or 01208 // calculate the corresponding bounding box changes. 01209 01210 if ( if_bb ) 01211 { 01212 // Bounding-box limits are the viewport limits in mm before corrections 01213 // for decorations are applied. 01214 plsc->boxbb_xmin = plsc->vppxmi / plsc->xpmm; 01215 plsc->boxbb_xmax = plsc->vppxma / plsc->xpmm; 01216 plsc->boxbb_ymin = plsc->vppymi / plsc->ypmm; 01217 plsc->boxbb_ymax = plsc->vppyma / plsc->ypmm; 01218 01219 // For labels written parallel to axis, label_offset of zero 01220 // corresponds to character centred on edge so should add 0.5 to 01221 // height to obtain bounding box edge in direction away from 01222 // edge. However, experimentally found 0.8 gave a better 01223 // looking result. 01224 parallel_height_mm = ( label_offset + 0.8 ) * char_height_mm; 01225 01226 // For labels written perpendicular to axis, label_offset of 01227 // zero corresponds to a character whose edge just touches the 01228 // edge of the box so should add 0. to label_offset (corrected 01229 // by -0.5 below) to obtain bounding box edge in direction away 01230 // from edge, and that value apparently works. 01231 perpendicular_height_mm = ( label_offset - 0.5 + 0.0 ) * char_height_mm; 01232 } 01233 if ( opt & PL_COLORBAR_LABEL_LEFT ) 01234 { 01235 if ( opt & PL_COLORBAR_ORIENT_TOP || opt & PL_COLORBAR_ORIENT_BOTTOM ) 01236 { 01237 perp = '\0'; 01238 just = 0.5; 01239 if ( if_bb ) 01240 { 01241 plsc->boxbb_xmin = MIN( plsc->boxbb_xmin, plsc->vppxmi / 01242 plsc->xpmm - parallel_height_mm ); 01243 plsc->boxbb_ymin = MIN( plsc->boxbb_ymin, 01244 0.5 * ( plsc->vppymi + plsc->vppyma ) / 01245 plsc->ypmm - 0.5 * label_length_mm ); 01246 plsc->boxbb_ymax = MAX( plsc->boxbb_ymax, 01247 0.5 * ( plsc->vppymi + plsc->vppyma ) / 01248 plsc->ypmm + 0.5 * label_length_mm ); 01249 } 01250 } 01251 else 01252 { 01253 perp = 'v'; 01254 just = 1.0; 01255 label_offset -= 0.5; 01256 if ( if_bb ) 01257 { 01258 plsc->boxbb_xmin = MIN( plsc->boxbb_xmin, plsc->vppxmi / 01259 plsc->xpmm - perpendicular_height_mm - label_length_mm ); 01260 } 01261 } 01262 snprintf( opt_label, max_opts, "l%c", perp ); 01263 } 01264 else if ( opt & PL_COLORBAR_LABEL_RIGHT ) 01265 { 01266 if ( opt & PL_COLORBAR_ORIENT_TOP || opt & PL_COLORBAR_ORIENT_BOTTOM ) 01267 { 01268 perp = '\0'; 01269 just = 0.5; 01270 if ( if_bb ) 01271 { 01272 plsc->boxbb_xmax = MAX( plsc->boxbb_xmax, plsc->vppxma / 01273 plsc->xpmm + parallel_height_mm ); 01274 plsc->boxbb_ymin = MIN( plsc->boxbb_ymin, 01275 0.5 * ( plsc->vppymi + plsc->vppyma ) / 01276 plsc->ypmm - 0.5 * label_length_mm ); 01277 plsc->boxbb_ymax = MAX( plsc->boxbb_ymax, 01278 0.5 * ( plsc->vppymi + plsc->vppyma ) / 01279 plsc->ypmm + 0.5 * label_length_mm ); 01280 } 01281 } 01282 else 01283 { 01284 perp = 'v'; 01285 just = 0.0; 01286 label_offset -= 0.5; 01287 if ( if_bb ) 01288 { 01289 plsc->boxbb_xmax = MAX( plsc->boxbb_xmax, plsc->vppxma / 01290 plsc->xpmm + perpendicular_height_mm + label_length_mm ); 01291 } 01292 } 01293 snprintf( opt_label, max_opts, "r%c", perp ); 01294 } 01295 else if ( opt & PL_COLORBAR_LABEL_TOP ) 01296 { 01297 perp = '\0'; 01298 just = 0.5; 01299 snprintf( opt_label, max_opts, "t%c", perp ); 01300 if ( if_bb ) 01301 { 01302 plsc->boxbb_ymax = MAX( plsc->boxbb_ymax, plsc->vppyma / 01303 plsc->ypmm + parallel_height_mm ); 01304 plsc->boxbb_xmin = MIN( plsc->boxbb_xmin, 01305 0.5 * ( plsc->vppxmi + plsc->vppxma ) / 01306 plsc->xpmm - 0.5 * label_length_mm ); 01307 plsc->boxbb_xmax = MAX( plsc->boxbb_xmax, 01308 0.5 * ( plsc->vppxmi + plsc->vppxma ) / 01309 plsc->xpmm + 0.5 * label_length_mm ); 01310 } 01311 } 01312 else if ( opt & PL_COLORBAR_LABEL_BOTTOM ) 01313 { 01314 perp = '\0'; 01315 just = 0.5; 01316 snprintf( opt_label, max_opts, "b%c", perp ); 01317 if ( if_bb ) 01318 { 01319 plsc->boxbb_ymin = MIN( plsc->boxbb_ymin, plsc->vppymi / 01320 plsc->ypmm - parallel_height_mm ); 01321 plsc->boxbb_xmin = MIN( plsc->boxbb_xmin, 01322 0.5 * ( plsc->vppxmi + plsc->vppxma ) / 01323 plsc->xpmm - 0.5 * label_length_mm ); 01324 plsc->boxbb_xmax = MAX( plsc->boxbb_xmax, 01325 0.5 * ( plsc->vppxmi + plsc->vppxma ) / 01326 plsc->xpmm + 0.5 * label_length_mm ); 01327 } 01328 } 01329 if ( !if_bb ) 01330 plmtex( opt_label, label_offset, 0.5, just, label ); 01331 } 01332 01333 //-------------------------------------------------------------------------- 01344 // dx_subpage, dy_subpageDifferences between normalized subpage coordinates for the old 01345 // bounding box and the new one. 01346 01347 static void 01348 calculate_limits( PLINT position, PLFLT x, PLFLT y, 01349 PLFLT xdmin_adopted, PLFLT xdmax_adopted, PLFLT ydmin_adopted, PLFLT ydmax_adopted, 01350 PLFLT prior_bb_height, 01351 PLFLT *p_colorbar_width_bb, PLFLT *p_colorbar_height_bb, 01352 PLFLT *p_colorbar_width_ac, PLFLT *p_colorbar_height_ac, 01353 PLFLT *p_plot_x_subpage_bb, PLFLT *p_plot_y_subpage_bb, 01354 PLFLT *p_dx_subpage, PLFLT *p_dy_subpage 01355 ) 01356 { 01357 PLFLT x_colorbar_position, y_colorbar_position, xsign, ysign; 01358 PLFLT plot_x, plot_y; 01359 // Ratio of normalized subpage coordinates to mm coordinates in 01360 // x and y. 01361 PLFLT spxpmm = plsc->xpmm / ( plsc->sppxma - plsc->sppxmi ); 01362 PLFLT spypmm = plsc->ypmm / ( plsc->sppyma - plsc->sppymi ); 01363 01364 // New bounding box width and height in normalized subpage coordinates. 01365 *p_colorbar_width_bb = ( plsc->boxbb_xmax - plsc->boxbb_xmin ) * spxpmm; 01366 *p_colorbar_height_bb = ( plsc->boxbb_ymax - plsc->boxbb_ymin ) * spypmm; 01367 01368 // Offsets (in sense of prior minus current) of upper left corner of prior bounding box 01369 // relative to current bounding box in normalized subpage coordinates. From 01370 // the above comments, the upper left corner of prior bounding box 01371 // has the coordinates (0., prior_bb_height). 01372 *p_dx_subpage = -plsc->boxbb_xmin * spxpmm; 01373 *p_dy_subpage = prior_bb_height - plsc->boxbb_ymax * spypmm; 01374 01375 // Total width and height of new bounding box in adopted 01376 // coordinates. 01377 *p_colorbar_width_ac = subpage_to_adopted_x( *p_colorbar_width_bb ) - 01378 subpage_to_adopted_x( 0. ); 01379 *p_colorbar_height_ac = subpage_to_adopted_y( *p_colorbar_height_bb ) - 01380 subpage_to_adopted_y( 0. ); 01381 01382 // Calculate parameters that help determine the position of the top 01383 // left of the legend in adopted coordinates. See pllegend 01384 // documentation for definition of adopted coordinates. 01385 legend_position( position, *p_colorbar_width_ac, *p_colorbar_height_ac, &x_colorbar_position, &y_colorbar_position, &xsign, &ysign ); 01386 plot_x = x * xsign + x_colorbar_position; 01387 plot_y = y * ysign + y_colorbar_position; 01388 // Calculate normalized subpage coordinates of top left of new bounding box. 01389 *p_plot_x_subpage_bb = adopted_to_subpage_x( plot_x ); 01390 *p_plot_y_subpage_bb = adopted_to_subpage_y( plot_y ); 01391 } 01392 01393 01394 //-------------------------------------------------------------------------- 01523 01524 void 01525 c_plcolorbar( PLFLT *p_colorbar_width, PLFLT *p_colorbar_height, 01526 PLINT opt, PLINT position, PLFLT x, PLFLT y, 01527 PLFLT x_length, PLFLT y_length, 01528 PLINT bg_color, PLINT bb_color, PLINT bb_style, 01529 PLFLT low_cap_color, PLFLT high_cap_color, 01530 PLINT cont_color, PLFLT cont_width, 01531 PLINT n_labels, const PLINT *label_opts, const char * const *labels, 01532 PLINT n_axes, const char * const *axis_opts, 01533 const PLFLT *ticks, const PLINT *sub_ticks, 01534 const PLINT *n_values, const PLFLT * const *values ) 01535 { 01536 // Min and max values 01537 // Assumes that the values array is sorted from smallest to largest 01538 // OR from largest to smallest. 01539 // Unnecessarily initialize min_value, max_value, and max_abs 01540 // to quiet -O1 -Wuninitialized warnings that are false alarms. 01541 // (n_axes is guaranteed to be 1 or greater so that the loops that 01542 // define these values must be executed at least once.) 01543 PLFLT min_value = 0., max_value = 0., max_abs = 0.; 01544 // Length of cap in orientation direction in normalized subpage 01545 // coordinates and mm. 01546 PLFLT cap_extent, cap_extent_mm; 01547 01548 // The color bar cap is an equilateral triangle with cap_angle 01549 // the angle (in degrees) of the unequal angle pointing in the 01550 // direction of the orientation of the cap. In other words, 01551 // cap_angle completely controls the shape of the triangle, but 01552 // not its scale. 01553 PLFLT cap_angle = 45.; 01554 // Ratio of length of cap in orientation direction 01555 // to the width of the bar (and cap) in the direction 01556 // perpendicular to the orientation in physical coordinates 01557 // (i.e., independent of aspect ratio). 01558 PLFLT cap_ratio = 0.5 / tan( PI / 360. * cap_angle ); 01559 01560 // aspect ratio of physical area of subpage. 01561 PLFLT aspspp = ( ( plsc->sppxma - plsc->sppxmi ) / plsc->xpmm ) / 01562 ( ( plsc->sppyma - plsc->sppymi ) / plsc->ypmm ); 01563 01564 // Min and max colors 01565 PLFLT min_color, max_color; 01566 01567 // Saved external world coordinates of viewport. 01568 PLFLT xwmin_save, xwmax_save, ywmin_save, ywmax_save; 01569 // Saved external normalized coordinates of viewport. 01570 // (These are actual values used only for the restore.) 01571 PLFLT xdmin_save = 0.0, xdmax_save = 0.0, ydmin_save = 0.0, ydmax_save = 0.0; 01572 01573 // Limits of adopted coordinates used to calculate all coordinate 01574 // transformations. 01575 PLFLT xdmin_adopted = 0.0, xdmax_adopted = 0.0, ydmin_adopted = 0.0, ydmax_adopted = 0.0; 01576 01577 // Active attributes to be saved and restored afterward. 01578 PLINT col0_save = plsc->icol0, 01579 line_style_save = plsc->line_style; 01580 01581 // Normalized subpage coordinates of top left of the bounding box. 01582 PLFLT plot_x_subpage_bb, plot_y_subpage_bb; 01583 01584 // color bar width and height in normalized subpage coordinates. 01585 // No suffix refers to bonding box of undecorated color bar, d 01586 // suffix refers to bounding box of decorated color bar, and l 01587 // suffix refers to bounding box of labelled and decorated 01588 // color bar. 01589 PLFLT colorbar_width, colorbar_height, 01590 colorbar_width_d, colorbar_height_d, 01591 colorbar_width_l, colorbar_height_l; 01592 01593 // ac suffix refers to latest color bar_width (d or l suffix) converted to 01594 // adopted coordinates. 01595 // mm suffix refers to colorbar_width and colorbar_height (with no suffix) 01596 // converted from normalized subpage coordinates to mm. 01597 PLFLT colorbar_width_ac, colorbar_height_ac, 01598 colorbar_width_mm, colorbar_height_mm; 01599 01600 // Change in normalized subpage coordinates of the top left of 01601 // undecorated color bar. (The omd suffix refers to original 01602 // color bar minus decorated color bar, and the dml suffix refers to 01603 // decorated color bar minus labelled and decorated color bar.) 01604 PLFLT dx_subpage_omd, dy_subpage_omd, dx_subpage_dml, dy_subpage_dml; 01605 PLFLT dx_subpage_omd_accu = 0.0, dy_subpage_omd_accu = 0.0, dx_subpage_dml_accu = 0.0, dy_subpage_dml_accu = 0.0; 01606 // Normalized subpage coordinates of the top left of undecorated 01607 // color bar, 01608 PLFLT plot_x_subpage, plot_y_subpage; 01609 01610 // Position of the undecorated color bar in normalized subpage coordinates. 01611 PLFLT vx_min = 0.0, vx_max = 0.0, vy_min = 0.0, vy_max = 0.0; 01612 01613 // World coordinate limits describing undecorated color bar. 01614 PLFLT wx_min = 0.0, wx_max = 0.0, wy_min = 0.0, wy_max = 0.0; 01615 01616 // The data to plot 01617 PLFLT **color_data; 01618 01619 // Setting up the data for display 01620 PLINT i, j, ni = 0, nj = 0, n_steps; 01621 PLFLT step_size; 01622 01623 PLBOOL if_edge = 0; 01624 PLBOOL if_edge_b = 0, if_edge_c = 0, if_edge_u = 0, if_edge_w = 0; 01625 01626 // Ratio of normalized subpage coordinates to mm coordinates in 01627 // x and y. 01628 PLFLT spxpmm = plsc->xpmm / ( plsc->sppxma - plsc->sppxmi ); 01629 PLFLT spypmm = plsc->ypmm / ( plsc->sppyma - plsc->sppymi ); 01630 01631 // plvpor limits for label. 01632 PLFLT label_vpor_xmin, label_vpor_xmax, label_vpor_ymin, label_vpor_ymax; 01633 01634 // Default position flags and sanity checks for position flags. 01635 if ( !( position & PL_POSITION_RIGHT ) && !( position & PL_POSITION_LEFT ) && !( position & PL_POSITION_TOP ) && !( position & PL_POSITION_BOTTOM ) ) 01636 { 01637 position = position | PL_POSITION_RIGHT; 01638 } 01639 else if ( ( position & PL_POSITION_RIGHT ) && ( position & PL_POSITION_LEFT ) ) 01640 { 01641 plabort( "plcolorbar: PL_POSITION_RIGHT and PL_POSITION_LEFT cannot be simultaneously set." ); 01642 return; 01643 } 01644 01645 else if ( ( position & PL_POSITION_TOP ) && ( position & PL_POSITION_BOTTOM ) ) 01646 { 01647 plabort( "plcolorbar: PL_POSITION_TOP and PL_POSITION_BOTTOM cannot be simultaneously set." ); 01648 return; 01649 } 01650 01651 if ( !( position & PL_POSITION_INSIDE ) && !( position & PL_POSITION_OUTSIDE ) ) 01652 { 01653 position = position | PL_POSITION_OUTSIDE; 01654 } 01655 else if ( ( position & PL_POSITION_INSIDE ) && ( position & PL_POSITION_OUTSIDE ) ) 01656 { 01657 plabort( "plcolorbar: PL_POSITION_INSIDE and PL_POSITION_OUTSIDE cannot be simultaneously set." ); 01658 return; 01659 } 01660 01661 if ( !( position & PL_POSITION_VIEWPORT ) && !( position & PL_POSITION_SUBPAGE ) ) 01662 { 01663 position = position | PL_POSITION_VIEWPORT; 01664 } 01665 else if ( ( position & PL_POSITION_VIEWPORT ) && ( position & PL_POSITION_SUBPAGE ) ) 01666 { 01667 plabort( "plcolorbar: PL_POSITION_VIEWPORT and PL_POSITION_SUBPAGE cannot be simultaneously set." ); 01668 return; 01669 } 01670 01671 // Sanity check for NULL label arrays. 01672 if ( n_labels > 0 && ( label_opts == NULL || labels == NULL ) ) 01673 { 01674 plabort( "plcolorbar: label_opts and labels arrays must be defined when n_labels > 0." ); 01675 return; 01676 } 01677 01678 if ( n_axes < 1 ) 01679 { 01680 plabort( "plcolorbar: At least one axis must be specified" ); 01681 return; 01682 } 01683 01684 // xdmin_save, etc., are the actual external relative viewport 01685 // coordinates within the current sub-page used only for 01686 // restoration at the end. 01687 plgvpsp( &xdmin_save, &xdmax_save, &ydmin_save, &ydmax_save ); 01688 01689 // Choose adopted coordinates. 01690 if ( position & PL_POSITION_SUBPAGE ) 01691 plvpor( 0., 1., 0., 1. ); 01692 01693 // xdmin_adopted, etc., are the adopted limits of the coordinates 01694 // within the current sub-page used for all coordinate 01695 // transformations. 01696 // If position & PL_POSITION_VIEWPORT is true, these limits 01697 // are the external relative viewport limits. 01698 // If position & PL_POSITION_SUBPAGE is true, these 01699 // coordinates are the relative subpage coordinates. 01700 plgvpsp( &xdmin_adopted, &xdmax_adopted, &ydmin_adopted, &ydmax_adopted ); 01701 01702 // xwmin_save, etc., are the external world coordinates corresponding 01703 // to the external viewport boundaries. 01704 plgvpw( &xwmin_save, &xwmax_save, &ywmin_save, &ywmax_save ); 01705 01706 // Default orientation. 01707 if ( !( opt & PL_COLORBAR_ORIENT_RIGHT || 01708 opt & PL_COLORBAR_ORIENT_TOP || 01709 opt & PL_COLORBAR_ORIENT_LEFT || 01710 opt & PL_COLORBAR_ORIENT_BOTTOM ) ) 01711 { 01712 if ( position & PL_POSITION_LEFT || position & PL_POSITION_RIGHT ) 01713 opt = opt | PL_COLORBAR_ORIENT_TOP; 01714 else 01715 opt = opt | PL_COLORBAR_ORIENT_RIGHT; 01716 } 01717 01718 for ( i = 0; i < n_axes; i++ ) 01719 { 01720 if_edge_b = if_edge_b || plP_stsearch( axis_opts[i], 'b' ); 01721 if_edge_c = if_edge_c || plP_stsearch( axis_opts[i], 'c' ); 01722 if_edge_u = if_edge_u || plP_stsearch( axis_opts[i], 'u' ); 01723 if_edge_w = if_edge_w || plP_stsearch( axis_opts[i], 'w' ); 01724 } 01725 if_edge = if_edge_b && if_edge_c && !( if_edge_u || if_edge_w ); 01726 01727 // Assumes that the colors array is sorted from smallest to largest. 01728 plgcmap1_range( &min_color, &max_color ); 01729 01730 // Width and height of the undecorated color bar in normalized 01731 // subpage coordinates and mm. 01732 colorbar_width = adopted_to_subpage_x( x_length ) - 01733 adopted_to_subpage_x( 0. ); 01734 colorbar_height = adopted_to_subpage_y( y_length ) - 01735 adopted_to_subpage_y( 0. ); 01736 colorbar_width_d = colorbar_width; 01737 colorbar_height_d = colorbar_height; 01738 colorbar_width_mm = colorbar_width / spxpmm; 01739 colorbar_height_mm = colorbar_height / spypmm; 01740 // Extent of cap in normalized subpage coordinates in either X or Y 01741 // direction as appropriate in normalized subpage coordinates and mm. 01742 if ( opt & PL_COLORBAR_ORIENT_RIGHT || opt & PL_COLORBAR_ORIENT_LEFT ) 01743 { 01744 cap_extent = cap_ratio * colorbar_height / aspspp; 01745 cap_extent_mm = cap_extent / spxpmm; 01746 } 01747 else 01748 { 01749 cap_extent = cap_ratio * colorbar_width * aspspp; 01750 cap_extent_mm = cap_extent / spypmm; 01751 } 01752 01753 for ( i = n_axes - 1; i >= 0; i-- ) 01754 { 01755 min_value = values[i][0]; 01756 max_value = values[i][ n_values[i] - 1 ]; 01757 max_abs = MAX( fabs( min_value ), fabs( max_value ) ); 01758 01759 // Specify the proper window ranges for color bar depending on 01760 // orientation. 01761 if ( opt & PL_COLORBAR_ORIENT_RIGHT ) 01762 { 01763 wx_min = min_value; 01764 wx_max = max_value; 01765 wy_min = 0.0; 01766 wy_max = max_abs; 01767 } 01768 else if ( opt & PL_COLORBAR_ORIENT_TOP ) 01769 { 01770 wx_min = 0.0; 01771 wx_max = max_abs; 01772 wy_min = min_value; 01773 wy_max = max_value; 01774 } 01775 else if ( opt & PL_COLORBAR_ORIENT_LEFT ) 01776 { 01777 wx_min = max_value; 01778 wx_max = min_value; 01779 wy_min = 0.0; 01780 wy_max = max_abs; 01781 } 01782 else if ( opt & PL_COLORBAR_ORIENT_BOTTOM ) 01783 { 01784 wx_min = 0.0; 01785 wx_max = max_abs; 01786 wy_min = max_value; 01787 wy_max = min_value; 01788 } 01789 else 01790 { 01791 plabort( "plcolorbar: Invalid PL_COLORBAR_ORIENT_* bits" ); 01792 } 01793 01794 // Viewport has correct size but has a shifted zero-point 01795 // convention required by bounding-box calculations in draw_box, 01796 // further bounding-box calculations in the cap_extent section 01797 // below, and also in the calculate_limits call below that. 01798 plvpor( 0., colorbar_width_d, 0., colorbar_height_d ); 01799 plwind( wx_min, wx_max, wy_min, wy_max ); 01800 01801 // Calculate the bounding box for decorated (i.e., including tick 01802 // marks + numerical tick labels) box. 01803 draw_box( TRUE, opt, axis_opts[i], if_edge, 01804 ticks[i], sub_ticks[i], n_values[i], values[i] ); 01805 01806 if ( i == n_axes - 1 ) 01807 { 01808 if ( opt & PL_COLORBAR_CAP_LOW ) 01809 { 01810 if ( opt & PL_COLORBAR_ORIENT_RIGHT ) 01811 plsc->boxbb_xmin = MIN( plsc->boxbb_xmin, -cap_extent_mm ); 01812 if ( opt & PL_COLORBAR_ORIENT_TOP ) 01813 plsc->boxbb_ymin = MIN( plsc->boxbb_ymin, -cap_extent_mm ); 01814 if ( opt & PL_COLORBAR_ORIENT_LEFT ) 01815 plsc->boxbb_xmax = MAX( plsc->boxbb_xmax, colorbar_width_mm + cap_extent_mm ); 01816 if ( opt & PL_COLORBAR_ORIENT_BOTTOM ) 01817 plsc->boxbb_ymax = MAX( plsc->boxbb_ymax, colorbar_height_mm + cap_extent_mm ); 01818 } 01819 if ( opt & PL_COLORBAR_CAP_HIGH ) 01820 { 01821 if ( opt & PL_COLORBAR_ORIENT_RIGHT ) 01822 plsc->boxbb_xmax = MAX( plsc->boxbb_xmax, colorbar_width_mm + cap_extent_mm ); 01823 if ( opt & PL_COLORBAR_ORIENT_TOP ) 01824 plsc->boxbb_ymax = MAX( plsc->boxbb_ymax, colorbar_height_mm + cap_extent_mm ); 01825 if ( opt & PL_COLORBAR_ORIENT_LEFT ) 01826 plsc->boxbb_xmin = MIN( plsc->boxbb_xmin, -cap_extent_mm ); 01827 if ( opt & PL_COLORBAR_ORIENT_BOTTOM ) 01828 plsc->boxbb_ymin = MIN( plsc->boxbb_ymin, -cap_extent_mm ); 01829 } 01830 } 01831 01832 // Calculate limits relevant to label position. 01833 calculate_limits( position, x, y, 01834 xdmin_adopted, xdmax_adopted, ydmin_adopted, ydmax_adopted, 01835 colorbar_height_d, 01836 &colorbar_width_d, &colorbar_height_d, 01837 &colorbar_width_ac, &colorbar_height_ac, 01838 &plot_x_subpage_bb, &plot_y_subpage_bb, 01839 &dx_subpage_omd, &dy_subpage_omd ); 01840 01841 // Viewport has correct size but has a shifted zero point 01842 // convention required by bounding-box calculations in draw_label 01843 // and further calculations in calculate_limits. 01844 plvpor( 0., colorbar_width_d, 0., colorbar_height_d ); 01845 01846 dx_subpage_omd_accu += dx_subpage_omd; 01847 dy_subpage_omd_accu += dy_subpage_omd; 01848 } 01849 01850 // Capture the current bounding box dimensions 01851 colorbar_width_l = colorbar_width_d; 01852 colorbar_height_l = colorbar_height_d; 01853 01854 for ( i = 0; i < n_labels; i++ ) 01855 { 01856 // Viewport has correct size but has a shifted zero-point 01857 // convention required by bounding-box calculations in draw_box, 01858 // further bounding-box calculations in the cap_extent section 01859 // below, and also in the calculate_limits call below that. 01860 plvpor( 0., colorbar_width_l, 0., colorbar_height_l ); 01861 plwind( wx_min, wx_max, wy_min, wy_max ); 01862 01863 // Calculate the bounding box for combined label + decorated box. 01864 draw_label( TRUE, opt | label_opts[i], labels[i] ); 01865 01866 // Calculate overall limits. 01867 calculate_limits( position, x, y, 01868 xdmin_adopted, xdmax_adopted, ydmin_adopted, ydmax_adopted, 01869 colorbar_height_l, 01870 &colorbar_width_l, &colorbar_height_l, 01871 &colorbar_width_ac, &colorbar_height_ac, 01872 &plot_x_subpage_bb, &plot_y_subpage_bb, 01873 &dx_subpage_dml, &dy_subpage_dml ); 01874 01875 dx_subpage_dml_accu += dx_subpage_dml; 01876 dy_subpage_dml_accu += dy_subpage_dml; 01877 } 01878 01879 // Normalized subpage coordinates (top-left corner) for undecorated 01880 // color bar 01881 plot_x_subpage = plot_x_subpage_bb + dx_subpage_omd_accu + dx_subpage_dml_accu; 01882 plot_y_subpage = plot_y_subpage_bb + dy_subpage_omd_accu + dy_subpage_dml_accu; 01883 01884 // Coordinates of bounding box for decorated color bar (without overall label). 01885 label_vpor_xmin = plot_x_subpage_bb + dx_subpage_dml_accu; 01886 label_vpor_xmax = label_vpor_xmin + colorbar_width_d; 01887 label_vpor_ymax = plot_y_subpage_bb + dy_subpage_dml_accu; 01888 label_vpor_ymin = label_vpor_ymax - colorbar_height_d; 01889 01890 // Return bounding box width and height in adopted coordinates for 01891 // labelled and decorated color bar. 01892 *p_colorbar_width = colorbar_width_ac; 01893 *p_colorbar_height = colorbar_height_ac; 01894 01895 // Specify the proper viewport ranges for color bar depending on 01896 // orientation. 01897 if ( opt & PL_COLORBAR_ORIENT_RIGHT ) 01898 { 01899 vx_min = plot_x_subpage; 01900 vx_max = plot_x_subpage + colorbar_width; 01901 vy_min = plot_y_subpage - colorbar_height; 01902 vy_max = plot_y_subpage; 01903 } 01904 else if ( opt & PL_COLORBAR_ORIENT_TOP ) 01905 { 01906 vx_min = plot_x_subpage; 01907 vx_max = plot_x_subpage + colorbar_width; 01908 vy_min = plot_y_subpage - colorbar_height; 01909 vy_max = plot_y_subpage; 01910 } 01911 else if ( opt & PL_COLORBAR_ORIENT_LEFT ) 01912 { 01913 vx_min = plot_x_subpage; 01914 vx_max = plot_x_subpage + colorbar_width; 01915 vy_min = plot_y_subpage - colorbar_height; 01916 vy_max = plot_y_subpage; 01917 } 01918 else if ( opt & PL_COLORBAR_ORIENT_BOTTOM ) 01919 { 01920 vx_min = plot_x_subpage; 01921 vx_max = plot_x_subpage + colorbar_width; 01922 vy_min = plot_y_subpage - colorbar_height; 01923 vy_max = plot_y_subpage; 01924 } 01925 else 01926 { 01927 plabort( "plcolorbar: Invalid PL_COLORBAR_ORIENT_* bits" ); 01928 } 01929 01930 // Viewport and world coordinate ranges for bounding-box. 01931 plvpor( 0., 1., 0., 1. ); 01932 plwind( 0., 1., 0., 1. ); 01933 01934 if ( opt & PL_COLORBAR_BACKGROUND ) 01935 { 01936 PLFLT xbg[4] = { 01937 plot_x_subpage_bb, 01938 plot_x_subpage_bb, 01939 plot_x_subpage_bb + colorbar_width_l, 01940 plot_x_subpage_bb + colorbar_width_l, 01941 }; 01942 PLFLT ybg[4] = { 01943 plot_y_subpage_bb, 01944 plot_y_subpage_bb - colorbar_height_l, 01945 plot_y_subpage_bb - colorbar_height_l, 01946 plot_y_subpage_bb, 01947 }; 01948 plpsty( 0 ); 01949 plcol0( bg_color ); 01950 plfill( 4, xbg, ybg ); 01951 plcol0( col0_save ); 01952 } 01953 01954 // Viewport and world coordinate ranges for color bar. 01955 plvpor( vx_min, vx_max, vy_min, vy_max ); 01956 plwind( wx_min, wx_max, wy_min, wy_max ); 01957 01958 // What kind of color bar are we making? 01959 if ( opt & PL_COLORBAR_IMAGE ) 01960 { 01961 // Interpolate 01962 // TODO: Should this be decided with an extra opt option instead of by 01963 // counting n_values? 01964 if ( n_values[0] == 2 ) 01965 { 01966 // Use the same number of steps as there are steps in 01967 // color palette 1. 01968 // TODO: Determine a better way to specify the steps here? 01969 n_steps = plsc->ncol1; 01970 step_size = ( max_value - min_value ) / (PLFLT) n_steps; 01971 if ( opt & PL_COLORBAR_ORIENT_RIGHT ) 01972 { 01973 ni = n_steps; 01974 nj = 2; 01975 plAlloc2dGrid( &color_data, ni, nj ); 01976 for ( i = 0; i < ni; i++ ) 01977 { 01978 for ( j = 0; j < nj; j++ ) 01979 { 01980 color_data[i][j] = min_value + (PLFLT) i * step_size; 01981 } 01982 } 01983 } 01984 else if ( opt & PL_COLORBAR_ORIENT_TOP ) 01985 { 01986 ni = 2; 01987 nj = n_steps; 01988 plAlloc2dGrid( &color_data, ni, nj ); 01989 for ( i = 0; i < ni; i++ ) 01990 { 01991 for ( j = 0; j < nj; j++ ) 01992 { 01993 color_data[i][j] = min_value + (PLFLT) j * step_size; 01994 } 01995 } 01996 } 01997 else if ( opt & PL_COLORBAR_ORIENT_LEFT ) 01998 { 01999 ni = n_steps; 02000 nj = 2; 02001 plAlloc2dGrid( &color_data, ni, nj ); 02002 for ( i = 0; i < ni; i++ ) 02003 { 02004 for ( j = 0; j < nj; j++ ) 02005 { 02006 color_data[i][j] = max_value - (PLFLT) i * step_size; 02007 } 02008 } 02009 } 02010 else if ( opt & PL_COLORBAR_ORIENT_BOTTOM ) 02011 { 02012 ni = 2; 02013 nj = n_steps; 02014 plAlloc2dGrid( &color_data, ni, nj ); 02015 for ( i = 0; i < ni; i++ ) 02016 { 02017 for ( j = 0; j < nj; j++ ) 02018 { 02019 color_data[i][j] = max_value - (PLFLT) j * step_size; 02020 } 02021 } 02022 } 02023 else 02024 { 02025 plabort( "plcolorbar: Invalid orientation bits" ); 02026 } 02027 } 02028 // No interpolation - use values array as-is 02029 else 02030 { 02031 n_steps = n_values[0]; 02032 // Use the provided values in this case. 02033 if ( opt & PL_COLORBAR_ORIENT_RIGHT ) 02034 { 02035 ni = n_steps; 02036 nj = 2; 02037 plAlloc2dGrid( &color_data, ni, nj ); 02038 for ( i = 0; i < ni; i++ ) 02039 { 02040 for ( j = 0; j < nj; j++ ) 02041 { 02042 color_data[i][j] = values[0][i]; 02043 } 02044 } 02045 } 02046 else if ( opt & PL_COLORBAR_ORIENT_TOP ) 02047 { 02048 ni = 2; 02049 nj = n_steps; 02050 plAlloc2dGrid( &color_data, ni, nj ); 02051 for ( i = 0; i < ni; i++ ) 02052 { 02053 for ( j = 0; j < nj; j++ ) 02054 { 02055 color_data[i][j] = values[0][j]; 02056 } 02057 } 02058 } 02059 else if ( opt & PL_COLORBAR_ORIENT_LEFT ) 02060 { 02061 ni = n_steps; 02062 nj = 2; 02063 plAlloc2dGrid( &color_data, ni, nj ); 02064 for ( i = 0; i < ni; i++ ) 02065 { 02066 for ( j = 0; j < nj; j++ ) 02067 { 02068 color_data[i][j] = values[0][ni - 1 - i]; 02069 } 02070 } 02071 } 02072 else if ( opt & PL_COLORBAR_ORIENT_BOTTOM ) 02073 { 02074 ni = 2; 02075 nj = n_steps; 02076 plAlloc2dGrid( &color_data, ni, nj ); 02077 for ( i = 0; i < ni; i++ ) 02078 { 02079 for ( j = 0; j < nj; j++ ) 02080 { 02081 color_data[i][j] = values[0][nj - 1 - j]; 02082 } 02083 } 02084 } 02085 else 02086 { 02087 plabort( "plcolorbar: Invalid side" ); 02088 } 02089 } 02090 // Draw the color bar 02091 plimage( (const PLFLT * const *) color_data, ni, nj, wx_min, wx_max, wy_min, wy_max, 02092 min_value, max_value, wx_min, wx_max, wy_min, wy_max ); 02093 plFree2dGrid( color_data, ni, nj ); 02094 } 02095 else if ( opt & PL_COLORBAR_SHADE ) 02096 { 02097 // Transform grid 02098 // The transform grid is used to make the size of the shaded segments 02099 // scale relative to other segments. For example, if segment A 02100 // makes up 10% of the scale and segment B makes up 20% of the scale 02101 // then segment B will be twice the length of segment A. 02102 PLcGrid grid; 02103 PLFLT grid_axis[2] = { 0.0, max_abs }; 02104 n_steps = n_values[0]; 02105 // Use the provided values. 02106 if ( opt & PL_COLORBAR_ORIENT_RIGHT ) 02107 { 02108 grid.xg = (PLFLT *) values[0]; 02109 grid.yg = grid_axis; 02110 grid.nx = n_steps; 02111 grid.ny = 2; 02112 ni = n_steps; 02113 nj = 2; 02114 plAlloc2dGrid( &color_data, ni, nj ); 02115 for ( i = 0; i < ni; i++ ) 02116 { 02117 for ( j = 0; j < nj; j++ ) 02118 { 02119 color_data[i][j] = values[0][i]; 02120 } 02121 } 02122 } 02123 else if ( opt & PL_COLORBAR_ORIENT_TOP ) 02124 { 02125 grid.xg = grid_axis; 02126 grid.yg = (PLFLT *) values[0]; 02127 grid.nx = 2; 02128 grid.ny = n_steps; 02129 ni = 2; 02130 nj = n_steps; 02131 plAlloc2dGrid( &color_data, ni, nj ); 02132 for ( i = 0; i < ni; i++ ) 02133 { 02134 for ( j = 0; j < nj; j++ ) 02135 { 02136 color_data[i][j] = values[0][j]; 02137 } 02138 } 02139 } 02140 else if ( opt & PL_COLORBAR_ORIENT_LEFT ) 02141 { 02142 grid.xg = (PLFLT *) values[0]; 02143 grid.yg = grid_axis; 02144 grid.nx = n_steps; 02145 grid.ny = 2; 02146 ni = n_steps; 02147 nj = 2; 02148 plAlloc2dGrid( &color_data, ni, nj ); 02149 for ( i = 0; i < ni; i++ ) 02150 { 02151 for ( j = 0; j < nj; j++ ) 02152 { 02153 color_data[i][j] = values[0][ni - 1 - i]; 02154 } 02155 } 02156 } 02157 else if ( opt & PL_COLORBAR_ORIENT_BOTTOM ) 02158 { 02159 grid.xg = grid_axis; 02160 grid.yg = (PLFLT *) values[0]; 02161 grid.nx = 2; 02162 grid.ny = n_steps; 02163 ni = 2; 02164 nj = n_steps; 02165 plAlloc2dGrid( &color_data, ni, nj ); 02166 for ( i = 0; i < ni; i++ ) 02167 { 02168 for ( j = 0; j < nj; j++ ) 02169 { 02170 color_data[i][j] = values[0][nj - 1 - j]; 02171 } 02172 } 02173 } 02174 else 02175 { 02176 plabort( "plcolorbar: Invalid orientation" ); 02177 } 02178 02179 // Draw the color bar 02180 plshades( (const PLFLT * const *) color_data, ni, nj, NULL, wx_min, wx_max, wy_min, wy_max, 02181 values[0], n_steps, 0, cont_color, cont_width, plfill, TRUE, 02182 pltr1, (void *) ( &grid ) ); 02183 plFree2dGrid( color_data, ni, nj ); 02184 } 02185 else if ( opt & PL_COLORBAR_GRADIENT ) 02186 { 02187 PLFLT xs[4], ys[4]; 02188 PLFLT angle = 0.0; 02189 xs[0] = wx_min; 02190 ys[0] = wy_min; 02191 xs[1] = wx_max; 02192 ys[1] = wy_min; 02193 xs[2] = wx_max; 02194 ys[2] = wy_max; 02195 xs[3] = wx_min; 02196 ys[3] = wy_max; 02197 // Make sure the gradient runs in the proper direction 02198 if ( opt & PL_COLORBAR_ORIENT_RIGHT ) 02199 { 02200 angle = 0.0; 02201 } 02202 else if ( opt & PL_COLORBAR_ORIENT_TOP ) 02203 { 02204 angle = 90.0; 02205 } 02206 else if ( opt & PL_COLORBAR_ORIENT_LEFT ) 02207 { 02208 angle = 180.0; 02209 } 02210 else if ( opt & PL_COLORBAR_ORIENT_BOTTOM ) 02211 { 02212 angle = 270.0; 02213 } 02214 else 02215 { 02216 plabort( "plcolorbar: Invalid orientation" ); 02217 } 02218 plgradient( 4, xs, ys, angle ); 02219 } 02220 else 02221 { 02222 plabort( "plcolorbar: One of PL_COLORBAR_IMAGE, PL_COLORBAR_SHADE, or PL_COLORBAR_GRADIENT bits must be set in opt" ); 02223 } 02224 02225 // Restore the previous drawing color to use for outlines and text 02226 plcol0( col0_save ); 02227 02228 // Draw end-caps 02229 02230 // Viewport and world coordinate ranges for cap. 02231 plvpor( 0., 1., 0., 1. ); 02232 plwind( 0., 1., 0., 1. ); 02233 02234 if ( opt & PL_COLORBAR_CAP_LOW ) 02235 { 02236 // Draw a filled triangle (cap/arrow) at the low end of the scale 02237 if ( opt & PL_COLORBAR_ORIENT_RIGHT ) 02238 draw_cap( if_edge, PL_COLORBAR_ORIENT_LEFT, 02239 plot_x_subpage - cap_extent, plot_x_subpage, 02240 plot_y_subpage - colorbar_height, plot_y_subpage, 02241 low_cap_color ); 02242 else if ( opt & PL_COLORBAR_ORIENT_TOP ) 02243 draw_cap( if_edge, PL_COLORBAR_ORIENT_BOTTOM, 02244 plot_x_subpage, plot_x_subpage + colorbar_width, 02245 plot_y_subpage - colorbar_height - cap_extent, plot_y_subpage - colorbar_height, 02246 low_cap_color ); 02247 else if ( opt & PL_COLORBAR_ORIENT_LEFT ) 02248 draw_cap( if_edge, PL_COLORBAR_ORIENT_RIGHT, 02249 plot_x_subpage + colorbar_width, plot_x_subpage + colorbar_width + cap_extent, 02250 plot_y_subpage - colorbar_height, plot_y_subpage, 02251 low_cap_color ); 02252 else if ( opt & PL_COLORBAR_ORIENT_BOTTOM ) 02253 draw_cap( if_edge, PL_COLORBAR_ORIENT_TOP, 02254 plot_x_subpage, plot_x_subpage + colorbar_width, 02255 plot_y_subpage, plot_y_subpage + cap_extent, 02256 low_cap_color ); 02257 } 02258 if ( opt & PL_COLORBAR_CAP_HIGH ) 02259 { 02260 // Draw a filled triangle (cap/arrow) at the high end of the scale 02261 if ( opt & PL_COLORBAR_ORIENT_RIGHT ) 02262 draw_cap( if_edge, PL_COLORBAR_ORIENT_RIGHT, 02263 plot_x_subpage + colorbar_width, plot_x_subpage + colorbar_width + cap_extent, 02264 plot_y_subpage - colorbar_height, plot_y_subpage, 02265 high_cap_color ); 02266 else if ( opt & PL_COLORBAR_ORIENT_TOP ) 02267 draw_cap( if_edge, PL_COLORBAR_ORIENT_TOP, 02268 plot_x_subpage, plot_x_subpage + colorbar_width, 02269 plot_y_subpage, plot_y_subpage + cap_extent, 02270 high_cap_color ); 02271 else if ( opt & PL_COLORBAR_ORIENT_LEFT ) 02272 draw_cap( if_edge, PL_COLORBAR_ORIENT_LEFT, 02273 plot_x_subpage - cap_extent, plot_x_subpage, 02274 plot_y_subpage - colorbar_height, plot_y_subpage, 02275 high_cap_color ); 02276 else if ( opt & PL_COLORBAR_ORIENT_BOTTOM ) 02277 draw_cap( if_edge, PL_COLORBAR_ORIENT_BOTTOM, 02278 plot_x_subpage, plot_x_subpage + colorbar_width, 02279 plot_y_subpage - colorbar_height - cap_extent, plot_y_subpage - colorbar_height, 02280 high_cap_color ); 02281 } 02282 02283 for ( i = n_axes - 1; i >= 0; i-- ) 02284 { 02285 min_value = values[i][0]; 02286 max_value = values[i][ n_values[i] - 1 ]; 02287 max_abs = MAX( fabs( min_value ), fabs( max_value ) ); 02288 02289 // Specify the proper window ranges for color bar depending on 02290 // orientation. 02291 if ( opt & PL_COLORBAR_ORIENT_RIGHT ) 02292 { 02293 wx_min = min_value; 02294 wx_max = max_value; 02295 wy_min = 0.0; 02296 wy_max = max_abs; 02297 } 02298 else if ( opt & PL_COLORBAR_ORIENT_TOP ) 02299 { 02300 wx_min = 0.0; 02301 wx_max = max_abs; 02302 wy_min = min_value; 02303 wy_max = max_value; 02304 } 02305 else if ( opt & PL_COLORBAR_ORIENT_LEFT ) 02306 { 02307 wx_min = max_value; 02308 wx_max = min_value; 02309 wy_min = 0.0; 02310 wy_max = max_abs; 02311 } 02312 else if ( opt & PL_COLORBAR_ORIENT_BOTTOM ) 02313 { 02314 wx_min = 0.0; 02315 wx_max = max_abs; 02316 wy_min = max_value; 02317 wy_max = min_value; 02318 } 02319 else 02320 { 02321 plabort( "plcolorbar: Invalid PL_COLORBAR_ORIENT_* bits" ); 02322 } 02323 02324 // Viewport and world coordinate ranges for box. 02325 plvpor( vx_min, vx_max, vy_min, vy_max ); 02326 plwind( wx_min, wx_max, wy_min, wy_max ); 02327 02328 // draw decorated (i.e., including tick marks + numerical tick 02329 // labels) box. 02330 draw_box( FALSE, opt, axis_opts[i], if_edge, 02331 ticks[i], sub_ticks[i], n_values[i], values[i] ); 02332 } 02333 02334 // Viewport and world coordinate ranges for bounding-box. 02335 plvpor( 0., 1., 0., 1. ); 02336 plwind( 0., 1., 0., 1. ); 02337 02338 if ( opt & PL_COLORBAR_BOUNDING_BOX ) 02339 { 02340 PLFLT xbb[5] = { 02341 plot_x_subpage_bb, 02342 plot_x_subpage_bb, 02343 plot_x_subpage_bb + colorbar_width_l, 02344 plot_x_subpage_bb + colorbar_width_l, 02345 plot_x_subpage_bb, 02346 }; 02347 PLFLT ybb[5] = { 02348 plot_y_subpage_bb, 02349 plot_y_subpage_bb - colorbar_height_l, 02350 plot_y_subpage_bb - colorbar_height_l, 02351 plot_y_subpage_bb, 02352 plot_y_subpage_bb, 02353 }; 02354 pllsty( bb_style ); 02355 plcol0( bb_color ); 02356 plline( 5, xbb, ybb ); 02357 plcol0( col0_save ); 02358 pllsty( line_style_save ); 02359 } 02360 02361 // Write label. 02362 // Viewport coordinate ranges for label. 02363 plvpor( label_vpor_xmin, label_vpor_xmax, label_vpor_ymin, label_vpor_ymax ); 02364 for ( i = 0; i < n_labels; i++ ) 02365 { 02366 draw_label( FALSE, opt | label_opts[i], labels[i] ); 02367 } 02368 02369 // Restore previous plot characteristics. 02370 plcol0( col0_save ); 02371 plvpor( xdmin_save, xdmax_save, ydmin_save, ydmax_save ); 02372 plwind( xwmin_save, xwmax_save, ywmin_save, ywmax_save ); 02373 02374 return; 02375 }