From: <ai...@us...> - 2010-11-05 23:44:29
|
Revision: 11307 http://plplot.svn.sourceforge.net/plplot/?rev=11307&view=rev Author: airwin Date: 2010-11-05 23:44:23 +0000 (Fri, 05 Nov 2010) Log Message: ----------- Rename *world* variables and functions to something more appropriate (typically *subpage*) when the units are relative subpage units. x, y, and plot_width now in relative viewport coordinates. Implement new legend positioning scheme as discussed on list which consists of specifying 16 different standard positions of the legend which are customized by x and y (the offsets in relative viewport coordinates from those positions). ToDo: change x and y sign interpretation depending on which position flag bits are set. Modified Paths: -------------- trunk/src/pllegend.c Modified: trunk/src/pllegend.c =================================================================== --- trunk/src/pllegend.c 2010-11-05 23:38:35 UTC (rev 11306) +++ trunk/src/pllegend.c 2010-11-05 23:44:23 UTC (rev 11307) @@ -26,14 +26,199 @@ //! #include "plplotP.h" +// xorigin is the X coordinate of the viewport reference point. +// yorigin is the Y coordinate of the viewport reference point. +// xlegend is the X coordinate of the top-left of the legend box +// relative to the legend box reference point. +// ylegend is the y coordinate of the top-left of the legend box +// relative to the legend box reference point. +// N.B. xorigin, yorigin, xlegend, and ylegend are all expressed +// in normalized external viewport coordinates to be consistent +// with the coordinate system used for x and y. + +static void legend_position( PLINT opt, PLFLT legend_width, PLFLT legend_height, + PLFLT *x_legend_position, PLFLT *y_legend_position ) +{ + PLFLT xorigin, yorigin, xlegend, ylegend; + if ( opt & PL_LEGEND_RIGHT ) + { + xorigin = 1.; + if ( opt & PL_LEGEND_UPPER ) + { + yorigin = 1.; + if ( opt & PL_LEGEND_INSIDE ) + { + xlegend = -legend_width; + ylegend = 0.; + } + else if ( opt & PL_LEGEND_OUTSIDE ) + { + xlegend = 0.; + ylegend = legend_height; + } + else + { + plexit( "legend_position: internal logic error 1" ); + } + } + else if ( !( opt & PL_LEGEND_UPPER ) && !( opt & PL_LEGEND_LOWER ) ) + { + yorigin = 0.5; + ylegend = 0.5 * legend_height; + if ( opt & PL_LEGEND_INSIDE ) + { + xlegend = -legend_width; + } + else if ( opt & PL_LEGEND_OUTSIDE ) + { + xlegend = 0.; + } + else + { + plexit( "legend_position: internal logic error 2" ); + } + } + else if ( opt & PL_LEGEND_LOWER ) + { + yorigin = 0.; + if ( opt & PL_LEGEND_INSIDE ) + { + xlegend = -legend_width; + ylegend = legend_height; + } + else if ( opt & PL_LEGEND_OUTSIDE ) + { + xlegend = 0.; + ylegend = 0.; + } + else + { + plexit( "legend_position: internal logic error 3" ); + } + } + else + { + plexit( "legend_position: internal logic error 4" ); + } + } + else if ( !( opt & PL_LEGEND_RIGHT ) && !( opt & PL_LEGEND_LEFT ) ) + { + xorigin = 0.5; + xlegend = -0.5 * legend_width; + if ( opt & PL_LEGEND_UPPER ) + { + yorigin = 1.; + if ( opt & PL_LEGEND_INSIDE ) + { + ylegend = 0.; + } + else if ( opt & PL_LEGEND_OUTSIDE ) + { + ylegend = legend_height; + } + else + { + plexit( "legend_position: internal logic error 5" ); + } + } + else if ( opt & PL_LEGEND_LOWER ) + { + yorigin = 0.; + if ( opt & PL_LEGEND_INSIDE ) + { + ylegend = legend_height; + } + else if ( opt & PL_LEGEND_OUTSIDE ) + { + ylegend = 0.; + } + else + { + plexit( "legend_position: internal logic error 6" ); + } + } + else + { + plexit( "legend_position: internal logic error 7" ); + } + } + else if ( opt & PL_LEGEND_LEFT ) + { + xorigin = 0.; + if ( opt & PL_LEGEND_UPPER ) + { + yorigin = 1.; + if ( opt & PL_LEGEND_INSIDE ) + { + xlegend = 0.; + ylegend = 0.; + } + else if ( opt & PL_LEGEND_OUTSIDE ) + { + xlegend = -legend_width; + ylegend = legend_height; + } + else + { + plexit( "legend_position: internal logic error 8" ); + } + } + else if ( !( opt & PL_LEGEND_UPPER ) && !( opt & PL_LEGEND_LOWER ) ) + { + yorigin = 0.5; + ylegend = 0.5 * legend_height; + if ( opt & PL_LEGEND_INSIDE ) + { + xlegend = 0.; + } + else if ( opt & PL_LEGEND_OUTSIDE ) + { + xlegend = -legend_width; + } + else + { + plexit( "legend_position: internal logic error 9" ); + } + } + else if ( opt & PL_LEGEND_LOWER ) + { + yorigin = 0.; + if ( opt & PL_LEGEND_INSIDE ) + { + ylegend = legend_height; + xlegend = 0.; + } + else if ( opt & PL_LEGEND_OUTSIDE ) + { + xlegend = -legend_width; + ylegend = 0.; + } + else + { + plexit( "legend_position: internal logic error 10" ); + } + } + else + { + plexit( "legend_position: internal logic error 11" ); + } + } + else + { + plexit( "legend_position: internal logic error 12" ); + } + *x_legend_position = xorigin + xlegend; + *y_legend_position = yorigin + ylegend; +} + //-------------------------------------------------------------------------- -//! Obtain ratio of world to mm coordinates in both x and y. +//! Obtain ratio of normalized subpage to mm coordinates in both x and y. //! -//! @param x_world_per_mm : pointer to PLFLT containing x ratio after call -//! @param y_world_per_mm : pointer to PLFLT containing y ratio after call +//! @param x_subpage_per_mm : pointer to PLFLT containing x ratio after call +//! @param y_subpage_per_mm : pointer to PLFLT containing y ratio after call //! -static void get_world_per_mm( PLFLT *x_world_per_mm, PLFLT *y_world_per_mm ) +static void get_subpage_per_mm( PLFLT *x_subpage_per_mm, PLFLT *y_subpage_per_mm ) { // Normalized viewport limits PLFLT vxmin, vxmax, vymin, vymax; @@ -44,12 +229,12 @@ plgvpd( &vxmin, &vxmax, &vymin, &vymax ); plgspa( &mxmin, &mxmax, &mymin, &mymax ); plgvpw( &wxmin, &wxmax, &wymin, &wymax ); - *x_world_per_mm = ( wxmax - wxmin ) / ( ( vxmax - vxmin ) * ( mxmax - mxmin ) ); - *y_world_per_mm = ( wymax - wymin ) / ( ( vymax - vymin ) * ( mymax - mymin ) ); + *x_subpage_per_mm = ( wxmax - wxmin ) / ( ( vxmax - vxmin ) * ( mxmax - mxmin ) ); + *y_subpage_per_mm = ( wymax - wymin ) / ( ( vymax - vymin ) * ( mymax - mymin ) ); } //-------------------------------------------------------------------------- -//! Obtain character or symbol height in (y) world coordinates. +//! Obtain character or symbol height in (y) subpage coordinates. //! //! @param ifcharacter : TRUE obtain character height, FALSE obtain symbol //! height @@ -60,7 +245,7 @@ { // Character height in mm PLFLT default_mm, char_height_mm; - PLFLT x_world_per_mm, y_world_per_mm; + PLFLT x_subpage_per_mm, y_subpage_per_mm; if ( ifcharacter ) { @@ -71,29 +256,47 @@ default_mm = plsc->symdef; char_height_mm = plsc->symht; } - get_world_per_mm( &x_world_per_mm, &y_world_per_mm ); - return ( char_height_mm * y_world_per_mm ); + get_subpage_per_mm( &x_subpage_per_mm, &y_subpage_per_mm ); + return ( char_height_mm * y_subpage_per_mm ); } //-------------------------------------------------------------------------- -//! Convert from normalized sub-page (or internal viewport) X -//! coordinate to X world coordinate. +//! Convert from external normalized viewport X coordinate to normalized +//! subpage X coordinate. //! -//! @param nx : normalized X coordinate +//! @param nx : external normalized viewport X coordinate //! -#define normalized_to_world_x( nx ) ( ( xmin ) + ( nx ) * ( ( xmax ) - ( xmin ) ) ) +#define viewport_to_subpage_x( nx ) ( ( xdmin_save ) + ( nx ) * ( ( xdmax_save ) - ( xdmin_save ) ) ) //-------------------------------------------------------------------------- -//! Convert from normalized sub-page (or internal viewport) Y -//! coordinate to Y world coordinate. +//! Convert from normalized subpage X coordinate to external normalized +//! viewport X coordinate. //! -//! @param ny : normalized Y coordinate +//! @param nx : normalized subpage X coordinate //! -#define normalized_to_world_y( ny ) ( ( ymin ) + ( ny ) * ( ( ymax ) - ( ymin ) ) ) +#define subpage_to_viewport_x( nx ) ( ( nx - xdmin_save ) / ( ( xdmax_save ) - ( xdmin_save ) ) ) //-------------------------------------------------------------------------- +//! Convert from external normalized viewport Y coordinate to normalized +//! subpage Y coordinate. +//! +//! @param ny : external normalized viewport Y coordinate +//! + +#define viewport_to_subpage_y( ny ) ( ( ydmin_save ) + ( ny ) * ( ( ydmax_save ) - ( ydmin_save ) ) ) + +//-------------------------------------------------------------------------- +//! Convert from normalized subpage Y coordinate to external normalized +//! viewport Y coordinate. +//! +//! @param ny : normalized subpage Y coordinate +//! + +#define subpage_to_viewport_y( ny ) ( ( ny - ydmin_save ) / ( ( ydmax_save ) - ( ydmin_save ) ) ) + +//-------------------------------------------------------------------------- //! Plot discrete legend using lines, symbols, cmap0 colors, and/or //! cmap1 colors. //! @@ -103,11 +306,11 @@ //! put the text area on the left of the legend and the plotted area //! on the right. Otherwise, put the text area on the right of the //! legend and the plotted area on the left -//! @param x : normalized sub-page X position of the upper-left corner of the +//! @param x : normalized viewport X position of the upper-left corner of the //! legend -//! @param y : normalized sub-page Y position of the upper-left corner of the +//! @param y : normalized viewport Y position of the upper-left corner of the //! legend -//! @param plot_width : width in normalized subpage units of the plot +//! @param plot_width : width in normalized viewport units of the plot //! area (where lines, symbols, and/or colored boxes are drawn in the //! legend) //! @param bg_color : cmap0 index of the background color for the legend @@ -179,13 +382,11 @@ const PLINT *symbol_numbers, const PLINT *symbols ) { - // Viewport world-coordinate limits - PLFLT xmin, xmax, ymin, ymax; // Legend position - PLFLT plot_x, plot_x_end, plot_x_world, plot_x_end_world; - PLFLT plot_y, plot_y_world; - PLFLT text_x, text_y, text_x_world, text_y_world; - // Character height (world coordinates) + PLFLT plot_x, plot_x_end, plot_x_subpage, plot_x_end_subpage; + PLFLT plot_y, plot_y_subpage; + PLFLT text_x, text_y, text_x_subpage, text_y_subpage; + // Character height (normalized subpage coordinates) PLFLT character_height, character_width, symbol_width; // x, y-position of the current legend entry PLFLT ty, xshift, drow, dcolumn; @@ -199,13 +400,15 @@ pattern_save = plsc->patt; PLFLT text_scale_save = plsc->chrht / plsc->chrdef, symbol_scale_save = plsc->symht / plsc->symdef; - // Saved world coordinates of viewport. + // Saved external world coordinates of viewport. PLFLT xwmin_save, xwmax_save, ywmin_save, ywmax_save; - // Saved normalized coordinates of viewport. + // Saved external normalized coordinates of viewport. PLFLT xdmin_save, xdmax_save, ydmin_save, ydmax_save; - PLFLT x_world_per_mm, y_world_per_mm, text_width0 = 0., text_width; - PLFLT width_border, column_separation, total_width, total_height; + PLFLT x_subpage_per_mm, y_subpage_per_mm, text_width0 = 0., text_width; + PLFLT width_border, column_separation, + total_width, total_height, total_width_vc, total_height_vc; + PLFLT x_legend_position, y_legend_position; PLINT some_boxes = 0, some_lines = 0, some_symbols = 0; PLINT max_symbol_numbers = 0; @@ -224,11 +427,47 @@ } // fprintf(stdout, "nrow, ncolumn = %d, %d\n", nrow, ncolumn); + // Default position flags and sanity checks for position flags. + if ( !( opt & PL_LEGEND_RIGHT ) && !( opt & PL_LEGEND_LEFT ) && !( opt & PL_LEGEND_UPPER ) && !( opt & PL_LEGEND_LOWER ) ) + { + opt = opt | PL_LEGEND_RIGHT | PL_LEGEND_UPPER; + } + else if ( ( opt & PL_LEGEND_RIGHT ) && ( opt & PL_LEGEND_LEFT ) ) + { + plabort( "pllegend: PL_LEGEND_RIGHT and PL_LEGEND_LEFT cannot be simultaneously set." ); + return; + } + + else if ( ( opt & PL_LEGEND_UPPER ) && ( opt & PL_LEGEND_LOWER ) ) + { + plabort( "pllegend: PL_LEGEND_UPPER and PL_LEGEND_LOWER cannot be simultaneously set." ); + return; + } + + if ( !( opt & PL_LEGEND_INSIDE ) && !( opt & PL_LEGEND_OUTSIDE ) ) + { + opt = opt | PL_LEGEND_INSIDE; + } + else if ( ( opt & PL_LEGEND_INSIDE ) && ( opt & PL_LEGEND_OUTSIDE ) ) + { + plabort( "pllegend: PL_LEGEND_INSIDE and PL_LEGEND_OUTSIDE cannot be simultaneously set." ); + return; + } + + // xdmin_save, etc., are the external relative viewport + // coordinates within the current sub-page. plgvpd( &xdmin_save, &xdmax_save, &ydmin_save, &ydmax_save ); + + // xwmin_save, etc., are the external world coordinates corresponding + // to the external viewport boundaries. plgvpw( &xwmin_save, &xwmax_save, &ywmin_save, &ywmax_save ); - // viewport corresponds to sub-page so that all legends will + + // Internal viewport corresponds to sub-page so that all legends will // be clipped at sub-page boundaries. plvpor( 0., 1., 0., 1. ); + + // Internal window coordinates are the same as normalized internal + // viewport coordinates which are the same as normalized subpage coordinates. plwind( 0., 1., 0., 1. ); plschr( 0., text_scale ); @@ -246,62 +485,78 @@ } } - plgvpw( &xmin, &xmax, &ymin, &ymax ); - - // World coordinates for legend plots - plot_x = x; - plot_y = y; - plot_x_end = plot_x + plot_width; - plot_x_world = normalized_to_world_x( plot_x ); - plot_y_world = normalized_to_world_y( plot_y ); - plot_x_end_world = normalized_to_world_x( plot_x_end ); - - // Get character height and width in world coordinates + // Get character height and width in normalized subpage coordinates. character_height = get_character_or_symbol_height( TRUE ); - character_width = character_height * fabs( ( xmax - xmin ) / ( ymax - ymin ) ); - // Get world-coordinate positions of the start of the legend text - text_x = plot_x_end; - text_y = plot_y; - text_x_world = normalized_to_world_x( text_x ) + - text_offset * character_width; - text_y_world = normalized_to_world_y( text_y ); + character_width = character_height; - // Calculate maximum width of text area (first in mm, then converted - // to x world coordinates) including text_offset area. + // Calculate maximum width of text area. for ( i = 0; i < nlegend; i++ ) { + // units are mm. text_width0 = MAX( text_width0, plstrl( text[i] ) ); } - get_world_per_mm( &x_world_per_mm, &y_world_per_mm ); - text_width0 = x_world_per_mm * text_width0; - text_width = text_width0 + text_offset * character_width; - // make small border area where only the background is plotted + get_subpage_per_mm( &x_subpage_per_mm, &y_subpage_per_mm ); + + // units are normalized subpage coordinates. + text_width0 = x_subpage_per_mm * text_width0; + + // Allow gap on end closest to legend plot. + text_width = text_width0 + text_offset * character_width; + + // Allow small border area where only the background is plotted // for left and right of legend. 0.4 seems to be a reasonable factor // that gives a good-looking result. width_border = 0.4 * character_width; // Separate columns (if any) by 2.0 * character_width. column_separation = 2.0 * character_width; - total_width = 2. * width_border + ( ncolumn - 1 ) * column_separation + - ncolumn * ( text_width + ( xmax - xmin ) * plot_width ); + + // Total width and height of legend area in normalized subpage coordinates. + total_width = 2. * width_border + ( ncolumn - 1 ) * column_separation + + ncolumn * ( text_width + + viewport_to_subpage_x( plot_width ) - viewport_to_subpage_x( 0. ) ); total_height = nrow * text_spacing * character_height; + + // Total width and height of legend area in normalized external viewport + // coordinates. + + total_width_vc = subpage_to_viewport_x( total_width ) - subpage_to_viewport_x( 0. ); + total_height_vc = subpage_to_viewport_y( total_height ) - subpage_to_viewport_y( 0. ); + // dcolumn is the spacing from one column to the next and // drow is the spacing from one row to the next. - dcolumn = column_separation + text_width + ( xmax - xmin ) * plot_width; - drow = text_spacing * character_height; + dcolumn = column_separation + text_width + + viewport_to_subpage_x( plot_width ) - viewport_to_subpage_x( 0. ); + drow = text_spacing * character_height; + legend_position( opt, total_width_vc, total_height_vc, &x_legend_position, &y_legend_position ); + plot_x = x + x_legend_position; + plot_y = y + y_legend_position; + plot_x_end = plot_x + plot_width; + // Normalized subpage coordinates for legend plots + plot_x_subpage = viewport_to_subpage_x( plot_x ); + plot_y_subpage = viewport_to_subpage_y( plot_y ); + plot_x_end_subpage = viewport_to_subpage_x( plot_x_end ); + + // Get normalized subpage positions of the start of the legend text + text_x = plot_x_end; + text_y = plot_y; + text_x_subpage = viewport_to_subpage_x( text_x ) + + text_offset * character_width; + text_y_subpage = viewport_to_subpage_y( text_y ); + if ( opt & PL_LEGEND_BACKGROUND ) { PLFLT xbg[4] = { - plot_x_world, - plot_x_world, - plot_x_world + total_width, - plot_x_world + total_width, + plot_x_subpage, + plot_x_subpage, + plot_x_subpage + total_width, + plot_x_subpage + total_width, }; PLFLT ybg[4] = { - plot_y_world, - plot_y_world - total_height, - plot_y_world - total_height, - plot_y_world, + plot_y_subpage, + plot_y_subpage - total_height, + plot_y_subpage - total_height, + plot_y_subpage, }; plpsty( 0 ); plcol0( bg_color ); @@ -312,18 +567,18 @@ if ( opt & PL_LEGEND_BOUNDING_BOX ) { PLFLT xbb[5] = { - plot_x_world, - plot_x_world, - plot_x_world + total_width, - plot_x_world + total_width, - plot_x_world, + plot_x_subpage, + plot_x_subpage, + plot_x_subpage + total_width, + plot_x_subpage + total_width, + plot_x_subpage, }; PLFLT ybb[5] = { - plot_y_world, - plot_y_world - total_height, - plot_y_world - total_height, - plot_y_world, - plot_y_world, + plot_y_subpage, + plot_y_subpage - total_height, + plot_y_subpage - total_height, + plot_y_subpage, + plot_y_subpage, }; pllsty( bb_style ); plcol0( bb_color ); @@ -334,14 +589,14 @@ if ( opt & PL_LEGEND_TEXT_LEFT ) { // text area on left, plot area on right. - text_x_world = plot_x_world; - plot_x_world += text_width; - plot_x_end_world += text_width; + text_x_subpage = plot_x_subpage; + plot_x_subpage += text_width; + plot_x_end_subpage += text_width; } // adjust border after background is drawn. - plot_x_world += width_border; - plot_x_end_world += width_border; - text_x_world += width_border; + plot_x_subpage += width_border; + plot_x_end_subpage += width_border; + text_x_subpage += width_border; if ( some_symbols ) { @@ -352,24 +607,23 @@ plexit( "pllegend: Insufficient memory" ); } - // Get symbol width in world coordinates if symbols are plotted to + // Get symbol width in normalized subpage coordinates if symbols are plotted to // adjust ends of line of symbols. // AWI, no idea why must use 0.5 factor to get ends of symbol lines // to line up approximately correctly with plotted legend lines. // Factor should be unity. - symbol_width = 0.5 * get_character_or_symbol_height( FALSE ) * - fabs( ( xmax - xmin ) / ( ymax - ymin ) ); + symbol_width = 0.5 * get_character_or_symbol_height( FALSE ); } // Draw each legend entry for ( i = 0; i < nlegend; i++ ) { // y position of text, lines, symbols, and/or centre of cmap0 box. - ty = text_y_world - ( (double) irow + 0.5 ) * drow; + ty = text_y_subpage - ( (double) irow + 0.5 ) * drow; xshift = (double) icolumn * dcolumn; // Label/name for the legend plcol0( text_colors[i] ); - plptex( text_x_world + xshift + text_justification * text_width0, ty, 0.1, 0.0, text_justification, text[i] ); + plptex( text_x_subpage + xshift + text_justification * text_width0, ty, 0.1, 0.0, text_justification, text[i] ); if ( !( opt_array[i] & PL_LEGEND_NONE ) ) { @@ -377,9 +631,9 @@ { plcol0( box_colors[i] ); plpsty( box_patterns[i] ); - xbox[0] = plot_x_world + xshift; + xbox[0] = plot_x_subpage + xshift; xbox[1] = xbox[0]; - xbox[2] = plot_x_end_world + xshift; + xbox[2] = plot_x_end_subpage + xshift; xbox[3] = xbox[2]; ybox[0] = ty + 0.5 * drow * box_scales[i]; ybox[1] = ty - 0.5 * drow * box_scales[i]; @@ -392,8 +646,8 @@ plcol0( line_colors[i] ); pllsty( line_styles[i] ); plwid( line_widths[i] ); - xl[0] = plot_x_world + xshift; - xl[1] = plot_x_end_world + xshift; + xl[0] = plot_x_subpage + xshift; + xl[1] = plot_x_end_subpage + xshift; yl[0] = ty; yl[1] = ty; plline( 2, xl, yl ); @@ -405,10 +659,10 @@ { plcol0( symbol_colors[i] ); plssym( 0., symbol_scales[i] ); - dxs = ( plot_x_end_world - plot_x_world - symbol_width ) / (double) ( MAX( symbol_numbers[i], 2 ) - 1 ); + dxs = ( plot_x_end_subpage - plot_x_subpage - symbol_width ) / (double) ( MAX( symbol_numbers[i], 2 ) - 1 ); for ( j = 0; j < symbol_numbers[i]; j++ ) { - xs[j] = plot_x_world + xshift + + xs[j] = plot_x_subpage + xshift + 0.5 * symbol_width + dxs * (double) j; ys[j] = ty; } This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |