PLplot 5.9.6
pllegend.c
00001 /* pllegend()
00002  *
00003  * Author: Hezekiah Carty 2010
00004  *
00005  * Copyright (C) 2010  Hezekiah M. Carty
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 General Library 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 
00024 #include "plplotP.h"
00025 
00026 static PLFLT get_character_or_symbol_height( PLINT ifcharacter )
00027 {
00028     // Character height in mm
00029     PLFLT default_mm, char_height_mm;
00030     // Normalized viewport limits
00031     PLFLT vxmin, vxmax, vymin, vymax;
00032     PLFLT vy;
00033     // Size of subpage in mm
00034     PLFLT mxmin, mxmax, mymin, mymax;
00035     PLFLT mm_y;
00036     // World height in mm
00037     PLFLT world_height_mm;
00038     // Normalized character height
00039     PLFLT char_height_norm;
00040     // Window dimensions
00041     PLFLT wxmin, wxmax, wymin, wymax;
00042     PLFLT world_y;
00043 
00044     if ( ifcharacter )
00045     {
00046         plgchr( &default_mm, &char_height_mm );
00047     }
00048     else
00049     {
00050         default_mm     = plsc->symdef;
00051         char_height_mm = plsc->symht;
00052     }
00053     plgvpd( &vxmin, &vxmax, &vymin, &vymax );
00054     vy = vymax - vymin;
00055 
00056     plgspa( &mxmin, &mxmax, &mymin, &mymax );
00057     mm_y = mymax - mymin;
00058 
00059     world_height_mm = mm_y * vy;
00060 
00061     // Character height (mm) / World height (mm) = Normalized char height
00062     char_height_norm = char_height_mm / world_height_mm;
00063 
00064     // Normalized character height * World height (world) =
00065     // Character height (world)
00066     plgvpw( &wxmin, &wxmax, &wymin, &wymax );
00067     world_y = wymax - wymin;
00068 
00069     return ( char_height_norm * world_y );
00070 }
00071 
00072 #define normalized_to_world_x( nx )    ( ( xmin ) + ( nx ) * ( ( xmax ) - ( xmin ) ) )
00073 #define normalized_to_world_y( ny )    ( ( ymin ) + ( ny ) * ( ( ymax ) - ( ymin ) ) )
00074 
00075 // pllegend - Draw a legend using lines (nsymbols <=1 or symbols == NULL) or
00076 // points/symbols.
00077 // plot_width: width of plotted areas (lines, symbols, or colour boxes) in legend
00078 // x, y: Normalized position of the legend in the plot window
00079 // nlegend: Number of legend entries
00080 // text_colors: Color map 0 indices of the colors to use for label text
00081 // text: text string for each legend entry
00082 // cmap0_colors: cmap0 color index for each legend entry
00083 // nsymbols: number of points/symbols to be drawn for each plot_width
00084 // symbols: Symbol to draw for each legend entry.
00085 
00086 void
00087 c_pllegend( PLINT opt, PLFLT plot_width, PLFLT x, PLFLT y, PLINT nlegend,
00088             PLINT *text_colors, char **text, PLINT *cmap0_colors,
00089             PLINT *line_style, PLINT *line_width,
00090             PLINT nsymbols, PLINT *symbols )
00091 
00092 {
00093     // Viewport world-coordinate limits
00094     PLFLT xmin, xmax, ymin, ymax;
00095     // Legend position
00096     PLFLT plot_x, plot_x_end, plot_x_world, plot_x_end_world;
00097     PLFLT plot_y, plot_y_world;
00098     PLFLT text_x, text_y, text_x_world, text_y_world;
00099     // Character height (world coordinates)
00100     PLFLT character_height, character_width, symbol_width;
00101     // y-position of the current legend entry
00102     PLFLT ty;
00103     // Positions of the legend entries
00104     PLFLT dxs, *xs, *ys, xl[2], yl[2];
00105     PLINT i, j;
00106     // opt_plot is the kind of plot made for the legend.
00107     PLINT opt_plot = opt & ( PL_LEGEND_LINE | PL_LEGEND_SYMBOL |
00108                              PL_LEGEND_CMAP0 | PL_LEGEND_CMAP1 );
00109     // Active attributes to be saved and restored afterward.
00110     PLINT old_col0 = plsc->icol0, old_line_style = plsc->line_style,
00111         old_line_width = plsc->width;
00112     // Sanity checks.
00113     // Check opt_plot for a valid combination of kind of plots.
00114     if ( !( ( opt_plot & ( PL_LEGEND_LINE | PL_LEGEND_SYMBOL ) ) ||
00115             opt_plot == PL_LEGEND_CMAP0 || opt_plot == PL_LEGEND_CMAP1 ) )
00116     {
00117         plabort( "pllegend: invalid opt" );
00118         return;
00119     }
00120 
00121     if ( ( symbols == NULL ) && ( opt & PL_LEGEND_SYMBOL ) )
00122     {
00123         plabort( "pllegend: invalid combination of opt requesting a symbols style of legend while symbols are not properly defined." );
00124         return;
00125     }
00126     nsymbols = MAX( 2, nsymbols );
00127 
00128     plgvpw( &xmin, &xmax, &ymin, &ymax );
00129 
00130     // World coordinates for legend plots
00131     plot_x           = x;
00132     plot_y           = y;
00133     plot_x_end       = plot_x + plot_width;
00134     plot_x_world     = normalized_to_world_x( plot_x );
00135     plot_y_world     = normalized_to_world_y( plot_y );
00136     plot_x_end_world = normalized_to_world_x( plot_x_end );
00137 
00138     // Get character height and width in world coordinates
00139     character_height = get_character_or_symbol_height( 1 );
00140     character_width  = character_height * fabs( ( xmax - xmin ) / ( ymax - ymin ) );
00141     // Get world-coordinate positions of the start of the legend text
00142     text_x       = plot_x_end;
00143     text_y       = plot_y;
00144     text_x_world = normalized_to_world_x( text_x ) + character_width;
00145     text_y_world = normalized_to_world_y( text_y );
00146 
00147     //    if (opt & PL_LEGEND_TEXT_LEFT)
00148     {
00149       //
00150     }
00151 
00152     // Starting y position for legend entries
00153     ty = text_y_world - character_height;
00154 
00155     if ( opt & PL_LEGEND_LINE )
00156     {
00157         xl[0] = plot_x_world;
00158         xl[1] = plot_x_end_world;
00159         yl[0] = ty;
00160         yl[1] = ty;
00161     }
00162 
00163     if ( opt & PL_LEGEND_SYMBOL )
00164     {
00165         if ( ( ( xs = (PLFLT *) malloc( nsymbols * sizeof ( PLFLT ) ) ) == NULL ) ||
00166              ( ( ys = (PLFLT *) malloc( nsymbols * sizeof ( PLFLT ) ) ) == NULL ) )
00167         {
00168             plexit( "pllegend: Insufficient memory" );
00169         }
00170 
00171         // Get symbol width in world coordinates if symbols are plotted to
00172         // adjust ends of line of symbols.
00173         // AWI, no idea why must use 0.5 factor to get ends of symbol lines
00174         // to line up approximately correctly with plotted legend lines.
00175         // Factor should be unity.
00176         symbol_width = 0.5 * get_character_or_symbol_height( 0 ) *
00177                        fabs( ( xmax - xmin ) / ( ymax - ymin ) );
00178         dxs = ( plot_x_end_world - plot_x_world - symbol_width ) / (double) ( nsymbols - 1 );
00179         for ( j = 0; j < nsymbols; j++ )
00180         {
00181             xs[j] = plot_x_world + 0.5 * symbol_width + dxs * (double) j;
00182             ys[j] = ty;
00183         }
00184     }
00185 
00186     // Draw each legend entry
00187     for ( i = 0; i < nlegend; i++ )
00188     {
00189         // Label/name for the legend
00190         plcol0( text_colors[i] );
00191         plptex( text_x_world, ty, 0.0, 0.0, 0.0, text[i] );
00192 
00193         // prepare for the next position
00194         ty = ty - ( 1.5 * character_height );
00195         plcol0( cmap0_colors[i] );
00196         if ( opt & PL_LEGEND_LINE )
00197         {
00198             pllsty( line_style[i]) ;
00199             plwid( line_width[i] );
00200             plline( 2, xl, yl );
00201             // prepare for the next position
00202             yl[0] = ty;
00203             yl[1] = ty;
00204             pllsty( old_line_style );
00205             plwid( old_line_width );
00206         }
00207         if ( opt & PL_LEGEND_SYMBOL )
00208         {
00209             plpoin( nsymbols, xs, ys, symbols[i] );
00210             // prepare for the next position
00211             for ( j = 0; j < nsymbols; j++ )
00212             {
00213                 ys[j] = ty;
00214             }
00215         }
00216     }
00217     if ( opt & PL_LEGEND_SYMBOL )
00218     {
00219         free( xs );
00220         free( ys );
00221     }
00222 
00223     // Restore the previously active drawing color
00224     plcol0( old_col0 );
00225 
00226     return;
00227 }
00228 
 All Data Structures Files Functions