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