00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025 #include "plplotP.h"
00026
00027
00028
00029 static int foo;
00030
00031 static void
00032 plgradient_soft( PLINT n, const PLFLT *x, const PLFLT *y, PLFLT angle );
00033
00034
00035
00036
00037 static PLINT
00038 gradient_defined( PLFLT x, PLFLT y );
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
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
00088
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
00111
00112
00113
00114
00115
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
00162
00163
00164
00165
00166 if ( npts > PL_MAXPOLY - 1 )
00167 {
00168 free( xpoly );
00169 free( ypoly );
00170 }
00171 }
00172 }
00173
00174
00175
00176
00177
00178
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
00197 plsc->n_polygon = n;
00198 plsc->x_polygon = (PLFLT *) x;
00199 plsc->y_polygon = (PLFLT *) y;
00200
00201
00202 xmin = x[0];
00203 xmax = xmin;
00204 ymin = y[0];
00205 ymax = ymin;
00206
00207
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
00233
00234
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
00249 #define NEDGE 101
00250
00251
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 }