• Main Page
  • Namespaces
  • Classes
  • Files
  • File List
  • File Members

pllegend.c

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

Generated on Wed Oct 12 2011 20:42:22 for PLplot by  doxygen 1.7.1