PLplot 5.9.6
|
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