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

plgradient.c

Go to the documentation of this file.
00001 // $Id: plgradient.c 11738 2011-05-01 19:14:40Z airwin $
00002 //
00003 //      Implement linear gradients for PLplot.
00004 //
00005 // Copyright (C) 2009  Alan W. Irwin
00006 //
00007 // This file is part of PLplot.
00008 //
00009 // PLplot is free software; you can redistribute it and/or modify
00010 // it under the terms of the GNU Library General Public License as published
00011 // by the Free Software Foundation; either version 2 of the License, or
00012 // (at your option) any later version.
00013 //
00014 // PLplot is distributed in the hope that it will be useful,
00015 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00016 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00017 // GNU Library General Public License for more details.
00018 //
00019 // You should have received a copy of the GNU Library General Public License
00020 // along with PLplot; if not, write to the Free Software
00021 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
00022 //
00023 //
00024 
00025 #include "plplotP.h"
00026 
00027 // To keep track of whether a sofware fallback warning has been issued.
00028 
00029 static int foo;
00030 // software fallback for gradient.
00031 static void
00032 plgradient_soft( PLINT n, const PLFLT *x, const PLFLT *y, PLFLT angle );
00033 
00034 // define where plshades plots gradient for software fallback for
00035 // gradient.
00036 
00037 static PLINT
00038 gradient_defined( PLFLT x, PLFLT y );
00039 
00040 //--------------------------------------------------------------------------
00041 // void plgradient()
00042 //
00043 // Draws a linear gradient at an angle relative to the increasing x
00044 // direction for the polygon bounded by the x and y vertices.  x, and
00045 // y are expressed in world coordinates, and angle (in the world
00046 // coordinate system) is expressed in degrees.  The gradient is
00047 // expressed using colour and transparency information from cmap1.  The
00048 // geometrical gradient direction is specified by the angle argument.
00049 // The 0. to 1. range of the independent variable of cmap1 corresponds
00050 // to the range of the polygon in the direction specified by angle.
00051 //--------------------------------------------------------------------------
00052 
00053 void
00054 c_plgradient( PLINT n, const PLFLT *x, const PLFLT *y, PLFLT angle )
00055 {
00056     if ( plsc->level < 3 )
00057     {
00058         plabort( "plgradient: Please set up window first" );
00059         return;
00060     }
00061     if ( n < 3 )
00062     {
00063         plabort( "plgradient: Not enough vertices in polygon" );
00064         return;
00065     }
00066 
00067     if ( !plsc->dev_gradient )
00068     {
00069         if ( !foo )
00070         {
00071             plwarn( "Driver does not support native gradients, switching to software fallback gradient.\n" );
00072             foo = 1;
00073         }
00074 
00075         plgradient_soft( n, x, y, angle );
00076     }
00077     else
00078     {
00079       #define NGRAD    2
00080         int   i, irot_min, irot_max;
00081         PLINT _xpoly[PL_MAXPOLY], _ypoly[PL_MAXPOLY];
00082         PLINT *xpoly, *ypoly;
00083         PLINT xgrad[NGRAD], ygrad[NGRAD], clpxmi, clpxma, clpymi, clpyma;
00084         PLFLT dxgrad[NGRAD], dygrad[NGRAD], xrot, xrot_min, xrot_max;
00085         PLINT npts;
00086 
00087         // Find (x1, y1) and (x2, y2) corresponding to beginning and end
00088         // of gradient vector.
00089         double cosangle = cos( PI * angle / 180. );
00090         double sinangle = sin( PI * angle / 180. );
00091         xrot     = x[0] * cosangle + y[0] * sinangle;
00092         xrot_min = xrot;
00093         xrot_max = xrot;
00094         irot_min = 0;
00095         irot_max = 0;
00096         for ( i = 1; i < n; i++ )
00097         {
00098             xrot = x[i] * cosangle + y[i] * sinangle;
00099             if ( xrot < xrot_min )
00100             {
00101                 xrot_min = xrot;
00102                 irot_min = i;
00103             }
00104             else if ( xrot > xrot_max )
00105             {
00106                 xrot_max = xrot;
00107                 irot_max = i;
00108             }
00109         }
00110         // xrot_min and xrot_max are the minimum and maximum rotated x
00111         // coordinate of polygon vertices. Use the vertex corresponding
00112         // to the minimum  as the (xgrad[0], ygrad[0]) base of the
00113         // gradient vector, and calculate the (xgrad[1], ygrad[1]) tip of
00114         // the gradient vector from the range in rotated x coordinate and
00115         // the angle of the gradient.
00116         dxgrad[0] = x[irot_min];
00117         dxgrad[1] = dxgrad[0] + ( xrot_max - xrot_min ) * cosangle;
00118         dygrad[0] = y[irot_min];
00119         dygrad[1] = dygrad[0] + ( xrot_max - xrot_min ) * sinangle;
00120         for ( i = 0; i < NGRAD; i++ )
00121         {
00122             xgrad[i] = plP_wcpcx( dxgrad[i] );
00123             ygrad[i] = plP_wcpcy( dygrad[i] );
00124         }
00125         if ( plsc->difilt )
00126             difilt( xgrad, ygrad, NGRAD, &clpxmi, &clpxma, &clpymi, &clpyma );
00127         plsc->xgradient = xgrad;
00128         plsc->ygradient = ygrad;
00129         plsc->ngradient = NGRAD;
00130 
00131         npts = n;
00132         if ( n > PL_MAXPOLY - 1 )
00133         {
00134             xpoly = (PLINT *) malloc( ( n + 1 ) * sizeof ( PLINT ) );
00135             ypoly = (PLINT *) malloc( ( n + 1 ) * sizeof ( PLINT ) );
00136 
00137             if ( ( xpoly == NULL ) || ( ypoly == NULL ) )
00138             {
00139                 plexit( "plgradient: Insufficient memory for large polygon" );
00140             }
00141         }
00142         else
00143         {
00144             xpoly = _xpoly;
00145             ypoly = _ypoly;
00146         }
00147 
00148         for ( i = 0; i < n; i++ )
00149         {
00150             xpoly[i] = plP_wcpcx( x[i] );
00151             ypoly[i] = plP_wcpcy( y[i] );
00152         }
00153         if ( x[0] != x[n - 1] || y[0] != y[n - 1] )
00154         {
00155             n++;
00156             xpoly[n - 1] = plP_wcpcx( x[0] );
00157             ypoly[n - 1] = plP_wcpcy( y[0] );
00158         }
00159         plP_plfclp( xpoly, ypoly, n, plsc->clpxmi, plsc->clpxma,
00160             plsc->clpymi, plsc->clpyma, plP_gradient );
00161         // Plot line corresponding to gradient to give visual
00162         // debugging cue.
00163         //plline( NGRAD, dxgrad, dygrad );
00164 
00165         // Check the original number of points
00166         if ( npts > PL_MAXPOLY - 1 )
00167         {
00168             free( xpoly );
00169             free( ypoly );
00170         }
00171     }
00172 }
00173 
00174 //--------------------------------------------------------------------------
00175 // void plgradient_soft()
00176 //
00177 // Software fallback for gradient.  See c_plgradient for an explanation
00178 // of the arguments.
00179 //--------------------------------------------------------------------------
00180 
00181 void
00182 plgradient_soft( PLINT n, const PLFLT *x, const PLFLT *y, PLFLT angle )
00183 {
00184     PLFLT xrot, xrot_min, xrot_max, cosangle, sinangle;
00185     PLFLT xmin, xmax, ymin, ymax;
00186     PLFLT **z, *edge, xcoord, ycoord;
00187     PLINT i, j;
00188 
00189     if ( n < 3 )
00190     {
00191         plabort( "plgradient_soft: Not enough vertices in polygon" );
00192         return;
00193     }
00194 
00195 
00196     // Define polygon boundary so it is accessible from gradient_defined.
00197     plsc->n_polygon = n;
00198     plsc->x_polygon = (PLFLT *) x;
00199     plsc->y_polygon = (PLFLT *) y;
00200 
00201     // Find x and y range of polygon.
00202     xmin = x[0];
00203     xmax = xmin;
00204     ymin = y[0];
00205     ymax = ymin;
00206     // Also find x range in rotated coordinate system where
00207     // xrot = x*cosangle + y*sinangle.
00208     cosangle = cos( PI / 180. * angle );
00209     sinangle = sin( PI / 180. * angle );
00210     xrot     = x[0] * cosangle + y[0] * sinangle;
00211     xrot_min = xrot;
00212     xrot_max = xrot;
00213     for ( i = 1; i < n; i++ )
00214     {
00215         if ( x[i] < xmin )
00216             xmin = x[i];
00217         else if ( x[i] > xmax )
00218             xmax = x[i];
00219 
00220         if ( y[i] < ymin )
00221             ymin = y[i];
00222         else if ( y[i] > ymax )
00223             ymax = y[i];
00224 
00225         xrot = x[i] * cosangle + y[i] * sinangle;
00226         if ( xrot < xrot_min )
00227             xrot_min = xrot;
00228         else if ( xrot > xrot_max )
00229             xrot_max = xrot;
00230     }
00231 
00232     // 2 x 2 array more than sufficient to define plane.
00233     // Temporarily use more to overcome irregular edge issue on defined
00234     // region.
00235     #define NX    20
00236     #define NY    20
00237     plAlloc2dGrid( &z, NX, NY );
00238     for ( i = 0; i < NX; i++ )
00239     {
00240         xcoord = xmin + ( (PLFLT) i ) * ( xmax - xmin ) / (PLFLT) ( NX - 1 );
00241         for ( j = 0; j < NY; j++ )
00242         {
00243             ycoord  = ymin + ( (PLFLT) j ) * ( ymax - ymin ) / (PLFLT) ( NY - 1 );
00244             xrot    = xcoord * cosangle + ycoord * sinangle;
00245             z[i][j] = ( xrot - xrot_min ) / ( xrot_max - xrot_min );
00246         }
00247     }
00248     // 101 edges gives reasonably smooth results for example 30.
00249     #define NEDGE    101
00250     // Define NEDGE shade edges (or NEDGE-1 shade levels)
00251     // from 0. to 1.
00252     if ( ( edge = (PLFLT *) malloc( NEDGE * sizeof ( PLFLT ) ) ) == NULL )
00253         plexit( "plgradient_soft: Insufficient memory for large polygon"
00254             );
00255     for ( i = 0; i < NEDGE; i++ )
00256         edge[i] = (PLFLT) i / (PLFLT) ( NEDGE - 1 );
00257 
00258     plshades( (const PLFLT **) z, NX, NY, gradient_defined, xmin, xmax, ymin, ymax,
00259         edge, NEDGE, 0, 0, 0, plfill, 1, NULL, NULL );
00260     free( (void *) edge );
00261     plFree2dGrid( z, NX, NY );
00262 }
00263 
00264 static PLINT
00265 gradient_defined( PLFLT x, PLFLT y )
00266 {
00267     return plP_pointinpolygon( plsc->n_polygon, plsc->x_polygon, plsc->y_polygon,
00268         x, y );
00269 }

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